From b4b7d0f263b1ac6f2df17a7e5ca0ce58a493082e Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Tue, 1 Nov 2022 20:37:29 -0600 Subject: [PATCH 01/55] Add slide element transition and timeout --- .../Containers/Slides/CityInfo/index.tsx | 15 ++---- .../Containers/Slides/CityIntro/index.tsx | 48 +++++++++++++------ .../Slides/Containers/SlidesContainer.tsx | 9 ++-- 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/components/Slides/Containers/Slides/CityInfo/index.tsx b/components/Slides/Containers/Slides/CityInfo/index.tsx index d00c4a7..cc32c48 100644 --- a/components/Slides/Containers/Slides/CityInfo/index.tsx +++ b/components/Slides/Containers/Slides/CityInfo/index.tsx @@ -37,21 +37,14 @@ const SlideCityInfo = ({ next }: SlideProps) => { React.useEffect(() => { let timeout = setTimeout(() => { - if (slideState.index >= 1) { - next(); - } else { - slideDispatch({ type: ActionType.INCREASE, payload: 1 }); - } + slideDispatch({ type: ActionType.INCREASE, payload: 1 }); + if (slideState.index >= 1) setTimeout(next, 1000); }, 8000); return () => clearTimeout(timeout); }, [slideState.index]); return ( - @@ -72,7 +65,7 @@ const SlideCityInfo = ({ next }: SlideProps) => { {currentSlide} - + ); }; diff --git a/components/Slides/Containers/Slides/CityIntro/index.tsx b/components/Slides/Containers/Slides/CityIntro/index.tsx index e7af6c7..7b35e74 100644 --- a/components/Slides/Containers/Slides/CityIntro/index.tsx +++ b/components/Slides/Containers/Slides/CityIntro/index.tsx @@ -1,32 +1,50 @@ import * as React from "react"; import type { SlideProps } from "../../../../../hooks/useSlides"; -import { motion } from "framer-motion"; +import { motion, useAnimation } from "framer-motion"; + +type SlideState = "active" | "inactive"; const CityIntro = ({ next }: SlideProps) => { + const [slideState, setSlideState] = React.useState("active"); + + const variants = { + active: { + opacity: 1 + }, + inactive: { + opacity: 0, + transition: { duration: 0.5 } + } + }; + React.useEffect(() => { - let timeout = setTimeout(next, 8000); - return () => clearTimeout(timeout); + let timeout: NodeJS.Timer; + let waitTimeout: NodeJS.Timer; + timeout = setTimeout(() => { + setSlideState("inactive"); + waitTimeout = setTimeout(next, 500); + }, 8000); + return () => { + clearTimeout(timeout); + clearTimeout(waitTimeout); + } }, []); return ( - - -
-
-
-
-
+ + + + + + ); }; diff --git a/components/Slides/Containers/SlidesContainer.tsx b/components/Slides/Containers/SlidesContainer.tsx index 75a921a..4f6b220 100644 --- a/components/Slides/Containers/SlidesContainer.tsx +++ b/components/Slides/Containers/SlidesContainer.tsx @@ -3,7 +3,6 @@ import SlideHeader from "./Headers/SlideHeader"; import { AudioPlayerProvider } from "react-use-audio-player"; import { VocalMale, VocalFemale } from "../../../components/VocalAudio"; import VocalAudio from "../../../components/VocalAudio"; -import { AnimatePresence } from "framer-motion"; import { SlideshowReducer, Slides, ActionType } from "../../../hooks/useSlides"; import CityIntro from "./Slides/CityIntro"; @@ -36,9 +35,9 @@ const SlidesContainer = ({ setMainVol }: SlidesContainerProps) => { console.log("Rendering new slide"); switch (slideState.index) { case Slides.INTRO: - return ; + return ; case Slides.INFO: - return ; + return ; default: return null; } @@ -62,9 +61,7 @@ const SlidesContainer = ({ setMainVol }: SlidesContainerProps) => { - - {currentSlide} - + {currentSlide} ); From 6596d21c555ea124b61d45635d58df78ac9760ff Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Thu, 3 Nov 2022 13:14:42 -0600 Subject: [PATCH 02/55] Organize slides --- .../Slides/{SlideBulletin.tsx => Bulletin/index.tsx} | 4 ++-- .../{SlideSevereCityInfo.tsx => CityInfo/Severe/index.tsx} | 2 +- .../Containers/Slides/{FrostPane.tsx => FrostPane/index.tsx} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename components/Slides/Containers/Slides/{SlideBulletin.tsx => Bulletin/index.tsx} (97%) rename components/Slides/Containers/Slides/{SlideSevereCityInfo.tsx => CityInfo/Severe/index.tsx} (98%) rename components/Slides/Containers/Slides/{FrostPane.tsx => FrostPane/index.tsx} (100%) diff --git a/components/Slides/Containers/Slides/SlideBulletin.tsx b/components/Slides/Containers/Slides/Bulletin/index.tsx similarity index 97% rename from components/Slides/Containers/Slides/SlideBulletin.tsx rename to components/Slides/Containers/Slides/Bulletin/index.tsx index 17c9186..f7e1374 100644 --- a/components/Slides/Containers/Slides/SlideBulletin.tsx +++ b/components/Slides/Containers/Slides/Bulletin/index.tsx @@ -1,6 +1,6 @@ import * as React from "react"; -const SlideBulletin = () => ( +const Bulletin = () => ( <>
( ); -export default SlideBulletin; +export default Bulletin; diff --git a/components/Slides/Containers/Slides/SlideSevereCityInfo.tsx b/components/Slides/Containers/Slides/CityInfo/Severe/index.tsx similarity index 98% rename from components/Slides/Containers/Slides/SlideSevereCityInfo.tsx rename to components/Slides/Containers/Slides/CityInfo/Severe/index.tsx index f32dcf4..f1794a8 100644 --- a/components/Slides/Containers/Slides/SlideSevereCityInfo.tsx +++ b/components/Slides/Containers/Slides/CityInfo/Severe/index.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import FrostPane from "./FrostPane"; +import FrostPane from "../../FrostPane"; const SlideSevereCityInfo = () => ( <> diff --git a/components/Slides/Containers/Slides/FrostPane.tsx b/components/Slides/Containers/Slides/FrostPane/index.tsx similarity index 100% rename from components/Slides/Containers/Slides/FrostPane.tsx rename to components/Slides/Containers/Slides/FrostPane/index.tsx From b55aa6eb59e5ec1e7650b7629b0e357ac864b4df Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Fri, 4 Nov 2022 16:15:25 -0600 Subject: [PATCH 03/55] Add city info local forecast --- components/CCIcon.tsx | 2 +- .../Containers/Slides/CityInfo/Detailed.tsx | 104 +++++++++++++++++- .../Containers/Slides/CityInfo/index.tsx | 19 +--- .../Containers/Slides/FrostPane/index.tsx | 11 +- hooks/useSlides.ts | 2 +- pages/index.tsx | 8 +- styles/global.scss | 4 + tailwind.config.js | 7 +- 8 files changed, 131 insertions(+), 26 deletions(-) diff --git a/components/CCIcon.tsx b/components/CCIcon.tsx index 25396a6..eb5e8ea 100644 --- a/components/CCIcon.tsx +++ b/components/CCIcon.tsx @@ -7,7 +7,7 @@ interface CCIconProps { } const CCIcon = ({ iconCode, windData }: CCIconProps) => { - const [icon, setIcon] = React.useState(Icons2010.UNK); + const [icon, setIcon] = React.useState(Icons2010.UNK); React.useEffect(() => { if (typeof iconCode === "number" && typeof windData === "number") { diff --git a/components/Slides/Containers/Slides/CityInfo/Detailed.tsx b/components/Slides/Containers/Slides/CityInfo/Detailed.tsx index df5666e..aa642c3 100644 --- a/components/Slides/Containers/Slides/CityInfo/Detailed.tsx +++ b/components/Slides/Containers/Slides/CityInfo/Detailed.tsx @@ -1,7 +1,107 @@ import * as React from "react"; +import { Icons2010, getIcon } from "../../../../../hooks/useIconMap"; +import { motion } from "framer-motion"; +import FrostPane from "../FrostPane"; const Detailed = () => { - return null; -} + const [icon, setIcon] = React.useState(Icons2010.UNK); + + return ( + <> + + + Hello + + + Hello World + + + +
+ Humidity +
+ Dew Point +
+ Pressure +
+ Wind +
+ Gusts +
+ Wind Chill +
+
+ 82% +
+ 39 +
+ 30.22 +
+ S 7 +
+ none +
+ 40 +
+
+ +
+
N/A
+
NaN
+ + + + ); +}; export default Detailed; diff --git a/components/Slides/Containers/Slides/CityInfo/index.tsx b/components/Slides/Containers/Slides/CityInfo/index.tsx index cc32c48..69c938c 100644 --- a/components/Slides/Containers/Slides/CityInfo/index.tsx +++ b/components/Slides/Containers/Slides/CityInfo/index.tsx @@ -3,6 +3,7 @@ import type { SlideProps } from "../../../../../hooks/useSlides"; import { SlideshowReducer, Slides, ActionType } from "../../../../../hooks/useSlides"; import { motion, AnimatePresence } from "framer-motion"; import Forecast from "./Forecast"; +import Detailed from "./Detailed"; const SlideCityInfo = ({ next }: SlideProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0 }); @@ -30,6 +31,8 @@ const SlideCityInfo = ({ next }: SlideProps) => { id="tempunavailable" className="transform translate-x-0 translate-y-60px scale-x-114-5 scale-y-100 origin-left absolute whitespace-nowrap font-frutiger57-cond pt-noreport-t pl-tempunavailable-l text-white text-tempunavailable text-shadow z-noreport" >Temporarily Unavailable; + case 2: + return ; default: return null; } @@ -38,7 +41,7 @@ const SlideCityInfo = ({ next }: SlideProps) => { React.useEffect(() => { let timeout = setTimeout(() => { slideDispatch({ type: ActionType.INCREASE, payload: 1 }); - if (slideState.index >= 1) setTimeout(next, 1000); + if (slideState.index >= 2) setTimeout(next, 800); }, 8000); return () => clearTimeout(timeout); }, [slideState.index]); @@ -48,20 +51,6 @@ const SlideCityInfo = ({ next }: SlideProps) => { id="city-info-slide" className="relative bg-city-info-slide bg-no-repeat w-full min-h-infoslide max-h-infoslide overflow-hidden flex flex-col" > -
- - -
-
{currentSlide} diff --git a/components/Slides/Containers/Slides/FrostPane/index.tsx b/components/Slides/Containers/Slides/FrostPane/index.tsx index a6219a2..600f96f 100644 --- a/components/Slides/Containers/Slides/FrostPane/index.tsx +++ b/components/Slides/Containers/Slides/FrostPane/index.tsx @@ -1,18 +1,23 @@ import * as React from "react"; interface FrostPaneProps { - extraParent: string[] - children: any + id?: string + extraParent?: string[] + style?: React.CSSProperties + children: React.ReactNode } const FrostPane = ({ + id, extraParent, + style, children }: FrostPaneProps) => ( <>
{children}
diff --git a/hooks/useSlides.ts b/hooks/useSlides.ts index 916132a..e9a0b4a 100644 --- a/hooks/useSlides.ts +++ b/hooks/useSlides.ts @@ -4,7 +4,7 @@ export const enum Slides { } export interface SlideProps { - next: () => void + next?: () => void } export const enum ActionType { diff --git a/pages/index.tsx b/pages/index.tsx index 0d688dc..cf36934 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -43,11 +43,13 @@ const Index = () => { if (loading) return
Loading...
; + /* + + + + */ return ( <> - - - Date: Fri, 4 Nov 2022 16:20:43 -0600 Subject: [PATCH 04/55] Add music back --- pages/index.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index cf36934..0d688dc 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -43,13 +43,11 @@ const Index = () => { if (loading) return
Loading...
; - /* - - - - */ return ( <> + + + Date: Fri, 4 Nov 2022 16:27:18 -0600 Subject: [PATCH 05/55] Insert header info --- components/Slides/Containers/Slides/CityInfo/Detailed.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/Slides/Containers/Slides/CityInfo/Detailed.tsx b/components/Slides/Containers/Slides/CityInfo/Detailed.tsx index aa642c3..236ac23 100644 --- a/components/Slides/Containers/Slides/CityInfo/Detailed.tsx +++ b/components/Slides/Containers/Slides/CityInfo/Detailed.tsx @@ -21,7 +21,7 @@ const Detailed = () => { Hello + >N/A { id="info-subheadershadowfix" className="font-normal font-frutiger57-cond text-white flex flex-row flex-nowrap justify-between text-subhead h-subhead z-subheader-shadow whitespace-nowrap text-shadow-subhead absolute min-w-subhead-shadow" > - Hello World + Local Forecast Date: Fri, 4 Nov 2022 16:40:08 -0600 Subject: [PATCH 06/55] Add tailwind CSS classes to city info local forecast --- components/Slides/Containers/Slides/CityInfo/Detailed.tsx | 2 +- tailwind.config.js | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/components/Slides/Containers/Slides/CityInfo/Detailed.tsx b/components/Slides/Containers/Slides/CityInfo/Detailed.tsx index 236ac23..4deee8b 100644 --- a/components/Slides/Containers/Slides/CityInfo/Detailed.tsx +++ b/components/Slides/Containers/Slides/CityInfo/Detailed.tsx @@ -32,7 +32,7 @@ const Detailed = () => { id="info-subheadershadowfix" className="font-normal font-frutiger57-cond text-white flex flex-row flex-nowrap justify-between text-subhead h-subhead z-subheader-shadow whitespace-nowrap text-shadow-subhead absolute min-w-subhead-shadow" > - Local Forecast + Local Forecast Date: Fri, 4 Nov 2022 18:24:28 -0600 Subject: [PATCH 07/55] Add weather info to city info local forecast --- components/CCIcon.tsx | 6 +-- components/Display.tsx | 3 +- .../Containers/Slides/CityInfo/Detailed.tsx | 47 ++++++++++++------- .../Containers/Slides/CityInfo/index.tsx | 4 +- .../Slides/Containers/SlidesContainer.tsx | 6 ++- hooks/useIconMap.ts | 2 +- hooks/useSlides.ts | 3 ++ hooks/useWeather.ts | 25 ++++++++-- 8 files changed, 66 insertions(+), 30 deletions(-) diff --git a/components/CCIcon.tsx b/components/CCIcon.tsx index eb5e8ea..eb645ae 100644 --- a/components/CCIcon.tsx +++ b/components/CCIcon.tsx @@ -10,10 +10,8 @@ const CCIcon = ({ iconCode, windData }: CCIconProps) => { const [icon, setIcon] = React.useState(Icons2010.UNK); React.useEffect(() => { - if (typeof iconCode === "number" && typeof windData === "number") { - const mapped = getIcon(iconCode, windData); - setIcon(mapped); - } + const mapped = getIcon(iconCode, windData); + setIcon(mapped); }, [iconCode, windData]); return ( diff --git a/components/Display.tsx b/components/Display.tsx index 9bc3f3e..8a8b7b1 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -69,6 +69,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr const [locInfo, setLocInfo] = React.useState>(defaults); const [currentInfo, setCurrentInfo] = React.useState>(currentDefaults); + const [extraInfo, setExtraInfo] = React.useState>>(new Map>()); const [alerts, setAlerts] = React.useState([]); const [focusedAlert, setFocusedAlert] = React.useState(null); @@ -152,7 +153,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr
background - {isReady && } + {isReady && } {locInfo.timezone !== "" && } {locInfo.city !== "" &&
{ +interface DetailedProps { + city?: string + info?: Partial +} + +const Detailed = ({ city, info }: DetailedProps) => { const [icon, setIcon] = React.useState(Icons2010.UNK); + React.useEffect(() => { + const mapped = getIcon(info.icon, info.windSpeed); + setIcon(mapped); + }, [info]); + return ( <> { N/A + >{city} {
Wind Chill
-
- 82% + {info &&
+ {`${info.humidity}%`}
- 39 + {info.dewpt}
- 30.22 + {info.pres}
- S 7 + {info.wind}
none
- 40 -
+ {info.chill.toString()} +
} { className="bg-no-repeat bg-cover bg-info-icon w-[212px] h-[212px] transform -translate-y-[5px]" style={{ backgroundImage: `url(/images/icons2010/${icon}.png)` }} /> -
N/A
-
NaN
+ {info && <> +
{info.phrase}
+
{info.temp}
+ }
diff --git a/components/Slides/Containers/Slides/CityInfo/index.tsx b/components/Slides/Containers/Slides/CityInfo/index.tsx index 69c938c..018969d 100644 --- a/components/Slides/Containers/Slides/CityInfo/index.tsx +++ b/components/Slides/Containers/Slides/CityInfo/index.tsx @@ -5,7 +5,7 @@ import { motion, AnimatePresence } from "framer-motion"; import Forecast from "./Forecast"; import Detailed from "./Detailed"; -const SlideCityInfo = ({ next }: SlideProps) => { +const SlideCityInfo = ({ next, currentCityInfo }: SlideProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0 }); const currentSlide = React.useMemo(() => { @@ -32,7 +32,7 @@ const SlideCityInfo = ({ next }: SlideProps) => { className="transform translate-x-0 translate-y-60px scale-x-114-5 scale-y-100 origin-left absolute whitespace-nowrap font-frutiger57-cond pt-noreport-t pl-tempunavailable-l text-white text-tempunavailable text-shadow z-noreport" >Temporarily Unavailable; case 2: - return ; + return ; default: return null; } diff --git a/components/Slides/Containers/SlidesContainer.tsx b/components/Slides/Containers/SlidesContainer.tsx index 4f6b220..ca131b2 100644 --- a/components/Slides/Containers/SlidesContainer.tsx +++ b/components/Slides/Containers/SlidesContainer.tsx @@ -1,4 +1,5 @@ import * as React from "react"; +import type { CurrentCond } from "../../../hooks/useWeather"; import SlideHeader from "./Headers/SlideHeader"; import { AudioPlayerProvider } from "react-use-audio-player"; import { VocalMale, VocalFemale } from "../../../components/VocalAudio"; @@ -10,9 +11,10 @@ import CityInfo from "./Slides/CityInfo"; interface SlidesContainerProps { setMainVol: React.Dispatch> + currentCityInfo?: Partial } -const SlidesContainer = ({ setMainVol }: SlidesContainerProps) => { +const SlidesContainer = ({ setMainVol, currentCityInfo }: SlidesContainerProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0 }); const [vocal, setVocal] = React.useState(VocalFemale.CURRENT_COND); const [headerWillUpdate, setHeaderUpdate] = React.useState(false); @@ -37,7 +39,7 @@ const SlidesContainer = ({ setMainVol }: SlidesContainerProps) => { case Slides.INTRO: return ; case Slides.INFO: - return ; + return ; default: return null; } diff --git a/hooks/useIconMap.ts b/hooks/useIconMap.ts index 26527fa..674a909 100644 --- a/hooks/useIconMap.ts +++ b/hooks/useIconMap.ts @@ -102,7 +102,7 @@ const Icons2010CodeMap = Object.freeze([ Icons2010.THUNDER_NIGHT // 47 ]); -export const getIcon = (iconCode: number, windData: number) : number => { +export const getIcon = (iconCode: number, windData: number) : Icons2010 => { let icon = Icons2010CodeMap[iconCode]; if (windData >= 20) { if (icon === Icons2010.HEAVY_SNOW || icon === Icons2010.SNOW || icon === Icons2010.SNOW_ALT) { diff --git a/hooks/useSlides.ts b/hooks/useSlides.ts index e9a0b4a..56fa25f 100644 --- a/hooks/useSlides.ts +++ b/hooks/useSlides.ts @@ -1,9 +1,12 @@ +import type { CurrentCond } from "./useWeather"; + export const enum Slides { INTRO, INFO } export interface SlideProps { + currentCityInfo?: Partial next?: () => void } diff --git a/hooks/useWeather.ts b/hooks/useWeather.ts index 8df9607..d8a7fa6 100644 --- a/hooks/useWeather.ts +++ b/hooks/useWeather.ts @@ -23,10 +23,24 @@ interface WeatherAPILocation { ianaTimeZone: string[] } +interface WeatherAPIExtraLoc { + city: string + adminDistrict: string + country: string + countryCode: string + latitude: number + longitude: number + ianaTimeZone: string +} + interface WeatherAPILocResponse { location: Partial } +interface WeatherAPIExtraLocResponse { + location: Partial +} + // ip-api.com enum IPAPIStatus { SUCCESS = "success", @@ -67,6 +81,7 @@ export interface CurrentCond { humidity: number dewpt: number pres: number + chill: number } export const currentDefaults: CurrentCond = Object.freeze({ @@ -79,7 +94,8 @@ export const currentDefaults: CurrentCond = Object.freeze({ phrase: "", humidity: 0, dewpt: 0, - pres: 0 + pres: 0, + chill: NaN }); const memoAsync = (cb) => { @@ -149,8 +165,10 @@ export const getClosestLocation = async () => { export const getExtraLocations = async (lat: number, lon: number) => { return memoizedFetch(`https://api.weather.com/v3/location/near?geocode=${lat},${lon}&product=observation&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) - .then(res => { - + .then(async (res: Response) => { + return res.json().then((data: WeatherAPIExtraLocResponse) => { + const dataLoc = data.location; + }); }); }; @@ -172,6 +190,7 @@ export const getCurrentCond = async (lat: number, lon: number, language?: string current.humidity = dataLoc.relativeHumidity; current.dewpt = dataLoc.temperatureDewPoint; current.pres = dataLoc.pressureAltimeter.toFixed(2); + current.chill = dataLoc.temperatureWindChill; return current; }).catch(err => { From f3e6713b9785f063b815922c3ebc36ea0633e12a Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sat, 5 Nov 2022 18:12:53 -0600 Subject: [PATCH 08/55] Add weather point info --- hooks/useWeather.ts | 91 +++++++++++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/hooks/useWeather.ts b/hooks/useWeather.ts index d8a7fa6..a938098 100644 --- a/hooks/useWeather.ts +++ b/hooks/useWeather.ts @@ -14,31 +14,58 @@ export interface Location { // api.weather.com interface WeatherAPILocation { - city: string[] - adminDistrict: string[] - country: string[] - countryCode: string[] - latitude: number[] - longitude: number[] - ianaTimeZone: string[] + city?: string + displayName?: string + adminDistrict?: string + country?: string + countryCode?: string + latitude?: number + longitude?: number + ianaTimeZone?: string } -interface WeatherAPIExtraLoc { - city: string - adminDistrict: string - country: string - countryCode: string - latitude: number - longitude: number - ianaTimeZone: string +interface WeatherAPISearchLoc { + city?: string[] + adminDistrict?: string[] + country?: string[] + countryCode?: string[] + latitude?: number[] + longitude?: number[] + ianaTimeZone?: string[] +} + +interface WeatherAPINear { + adminDistrictCode?: string[] + stationName?: string[] + countryCode?: string[] + stationId?: string[] + ianaTimeZone?: string[] + obsType?: string[] + latitude?: number[] + longitude?: number[] + distanceKm?: number[] + distanceMi?: number[] +} + +interface WeatherAPISearchLocResponse { + location: WeatherAPISearchLoc +} + +interface WeatherAPINearResponse { + location: WeatherAPINear } -interface WeatherAPILocResponse { - location: Partial +interface WeatherAPIPointResponse { + location: WeatherAPILocation } -interface WeatherAPIExtraLocResponse { - location: Partial +interface ExtraLocation { + lat?: number + lon?: number + distance?: number + stationUrl?: string + name: string + displayName?: string } // ip-api.com @@ -116,7 +143,7 @@ export const getMainLocation = async (location: string, language?: string) => { return memoizedFetch(`https://api.weather.com/v3/location/search?query=${encodeURIComponent(location)}&language=${apiLanguage}&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) .then(async (res: Response) => { - return res.json().then((data: WeatherAPILocResponse) => { + return res.json().then((data: WeatherAPISearchLocResponse) => { const dataLocs = data.location; const loc = Object.assign({}, defaults); @@ -166,10 +193,26 @@ export const getClosestLocation = async () => { export const getExtraLocations = async (lat: number, lon: number) => { return memoizedFetch(`https://api.weather.com/v3/location/near?geocode=${lat},${lon}&product=observation&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) .then(async (res: Response) => { - return res.json().then((data: WeatherAPIExtraLocResponse) => { - const dataLoc = data.location; - }); - }); + return res.json().then((near: WeatherAPINearResponse) => { + const dataLoc = near.location; + const dataLocLength = dataLoc.stationName.length; + const extraLocs: ExtraLocation[] = []; + for (let i = 0; i < dataLocLength; i++) { + memoizedFetch(`https://api.weather.com/v3/location/point?geocode=${dataLoc.latitude[i]},${dataLoc.longitude[i]}&language=en-US&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) + .then(async (res: Response) => { + return res.json().then((point: WeatherAPIPointResponse) => { + const pointData = point.location; + }); + }); + } + + return extraLocs; + }).catch(err => { + console.error(err); + }) + }).catch(err => { + console.error(err); + }) }; export const getCurrentCond = async (lat: number, lon: number, language?: string) => { From 090e8502ea4dae55098d92d1039fa11dabc6d394 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sat, 5 Nov 2022 19:02:19 -0600 Subject: [PATCH 09/55] Push info into extra locations --- hooks/useWeather.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hooks/useWeather.ts b/hooks/useWeather.ts index a938098..e5eebe2 100644 --- a/hooks/useWeather.ts +++ b/hooks/useWeather.ts @@ -202,6 +202,14 @@ export const getExtraLocations = async (lat: number, lon: number) => { .then(async (res: Response) => { return res.json().then((point: WeatherAPIPointResponse) => { const pointData = point.location; + extraLocs.push({ + name: pointData.displayName, + displayName: pointData.displayName, + lat: pointData.latitude, + lon: pointData.longitude, + distance: dataLoc.distanceMi[i], + stationUrl: dataLoc.stationId[i] + }); }); }); } From b1539c3af0d8dbdc82cffbdcfc5bca114805e8f7 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sun, 6 Nov 2022 01:26:53 -0700 Subject: [PATCH 10/55] Add language to extra locations --- hooks/useWeather.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hooks/useWeather.ts b/hooks/useWeather.ts index e5eebe2..e5068fb 100644 --- a/hooks/useWeather.ts +++ b/hooks/useWeather.ts @@ -190,7 +190,9 @@ export const getClosestLocation = async () => { }); }; -export const getExtraLocations = async (lat: number, lon: number) => { +export const getExtraLocations = async (lat: number, lon: number, language?: string) => { + const apiLanguage = language || "en-US"; + return memoizedFetch(`https://api.weather.com/v3/location/near?geocode=${lat},${lon}&product=observation&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) .then(async (res: Response) => { return res.json().then((near: WeatherAPINearResponse) => { @@ -198,7 +200,7 @@ export const getExtraLocations = async (lat: number, lon: number) => { const dataLocLength = dataLoc.stationName.length; const extraLocs: ExtraLocation[] = []; for (let i = 0; i < dataLocLength; i++) { - memoizedFetch(`https://api.weather.com/v3/location/point?geocode=${dataLoc.latitude[i]},${dataLoc.longitude[i]}&language=en-US&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) + memoizedFetch(`https://api.weather.com/v3/location/point?geocode=${dataLoc.latitude[i]},${dataLoc.longitude[i]}&language=${apiLanguage}&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) .then(async (res: Response) => { return res.json().then((point: WeatherAPIPointResponse) => { const pointData = point.location; From cc49c262069842deb5db8f77e3662c88b4770791 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sun, 6 Nov 2022 01:49:12 -0700 Subject: [PATCH 11/55] Fetch extra locations --- components/Display.tsx | 36 ++++++++++++++++++++++++++++++++++-- hooks/useWeather.ts | 10 +++++----- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/components/Display.tsx b/components/Display.tsx index 8a8b7b1..5d1a136 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -1,10 +1,11 @@ import * as React from "react"; -import type { Location, CurrentCond, Alert } from "../hooks/useWeather"; +import type { Location, ExtraLocation, CurrentCond, Alert } from "../hooks/useWeather"; import { defaults, currentDefaults, getMainLocation, getClosestLocation, + getExtraLocations, getCurrentCond, getAlerts, getAlertText @@ -48,6 +49,11 @@ interface DisplayProps { setMainVol: React.Dispatch> } +interface ExtraInfo { + details?: ExtraLocation + current?: Partial +} + const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayProps) => { const [innerWidth, innerHeight] = winSize; const mainRef = React.useRef(); @@ -69,7 +75,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr const [locInfo, setLocInfo] = React.useState>(defaults); const [currentInfo, setCurrentInfo] = React.useState>(currentDefaults); - const [extraInfo, setExtraInfo] = React.useState>>(new Map>()); + const [extraInfo, setExtraInfo] = React.useState>(new Map()); const [alerts, setAlerts] = React.useState([]); const [focusedAlert, setFocusedAlert] = React.useState(null); @@ -94,6 +100,27 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr } }, [isReady, location]); + const fetchExtra = (lat: number, lon: number) => { + getExtraLocations(lat, lon, language).then(data => { + const tempMap = new Map(); + for (let i = 0; i < data.length; i++) { + const location = data[i]; + getCurrentCond(location.lat, location.lon, language).then(current => { + tempMap.set(location.displayName, { + details: location, + current + }); + }).catch(err => { + console.error(err); + }); + } + + setExtraInfo(tempMap); + }).catch(err => { + console.error(err); + }); + }; + const fetchCurrent = (lat: number, lon: number) => { getCurrentCond(lat, lon, language).then(data => { setCurrentInfo(data); @@ -118,6 +145,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr let intervalTimer: NodeJS.Timeout; if (lat && lon) { + fetchExtra(lat, lon); fetchCurrent(lat, lon); fetchAlerts(lat, lon); intervalTimer = setInterval(() => { @@ -143,6 +171,10 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr } }, [alerts.length]); + React.useEffect(() => { + console.log(extraInfo); + }, [extraInfo]); + /* { - console.error(err); - }) + throw new Error(err); + }); }).catch(err => { - console.error(err); - }) + throw new Error(err); + }); }; export const getCurrentCond = async (lat: number, lon: number, language?: string) => { From 2d539ec199f08dbb5bde1686a5b57172816738f4 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sun, 6 Nov 2022 13:16:53 -0700 Subject: [PATCH 12/55] Fetch weather info for extra locations --- components/Display.tsx | 31 ++++++++++++------- hooks/useWeather.ts | 69 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 77 insertions(+), 23 deletions(-) diff --git a/components/Display.tsx b/components/Display.tsx index 5d1a136..ab4c96a 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -7,6 +7,7 @@ import { getClosestLocation, getExtraLocations, getCurrentCond, + getExtraCond, getAlerts, getAlertText } from "../hooks/useWeather"; @@ -75,7 +76,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr const [locInfo, setLocInfo] = React.useState>(defaults); const [currentInfo, setCurrentInfo] = React.useState>(currentDefaults); - const [extraInfo, setExtraInfo] = React.useState>(new Map()); + const [extraInfo, setExtraInfo] = React.useState>>(new Map>()); const [alerts, setAlerts] = React.useState([]); const [focusedAlert, setFocusedAlert] = React.useState(null); @@ -101,18 +102,26 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr }, [isReady, location]); const fetchExtra = (lat: number, lon: number) => { - getExtraLocations(lat, lon, language).then(data => { - const tempMap = new Map(); + getExtraLocations(lat, lon, language).then(async data => { + const tempMap = new Map>(); + const latLonMap = new Map(); + const queryLatLons: string[] = []; + + // Dirty way of doing things for (let i = 0; i < data.length; i++) { const location = data[i]; - getCurrentCond(location.lat, location.lon, language).then(current => { - tempMap.set(location.displayName, { - details: location, - current - }); - }).catch(err => { - console.error(err); - }); + const latLon = `${location.lat},${location.lon}`; + console.log(latLon); + queryLatLons.push(latLon); + latLonMap.set(latLon, location.displayName); + } + + const extras = await getExtraCond(queryLatLons, language); + for (const [key, value] of Object.entries(extras)) { + console.log(key); + const displayName = latLonMap.get(key); + console.log(displayName, value); + tempMap.set(displayName, value); } setExtraInfo(tempMap); diff --git a/hooks/useWeather.ts b/hooks/useWeather.ts index f3feafd..4dc4f3d 100644 --- a/hooks/useWeather.ts +++ b/hooks/useWeather.ts @@ -195,25 +195,26 @@ export const getExtraLocations = async (lat: number, lon: number, language?: str return memoizedFetch(`https://api.weather.com/v3/location/near?geocode=${lat},${lon}&product=observation&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) .then(async (res: Response) => { - return res.json().then((near: WeatherAPINearResponse) => { + return res.json().then(async (near: WeatherAPINearResponse) => { const dataLoc = near.location; const dataLocLength = dataLoc.stationName.length; const extraLocs: ExtraLocation[] = []; for (let i = 0; i < dataLocLength; i++) { - memoizedFetch(`https://api.weather.com/v3/location/point?geocode=${dataLoc.latitude[i]},${dataLoc.longitude[i]}&language=${apiLanguage}&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) + const point = await memoizedFetch(`https://api.weather.com/v3/location/point?geocode=${dataLoc.latitude[i]},${dataLoc.longitude[i]}&language=${apiLanguage}&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) .then(async (res: Response) => { return res.json().then((point: WeatherAPIPointResponse) => { const pointData = point.location; - extraLocs.push({ - name: pointData.displayName, - displayName: pointData.displayName, - lat: pointData.latitude, - lon: pointData.longitude, - distance: dataLoc.distanceMi[i], - stationUrl: dataLoc.stationId[i] - }); + return pointData; }); }); + extraLocs.push({ + name: point.displayName, + displayName: point.displayName, + lat: point.latitude, + lon: point.longitude, + distance: dataLoc.distanceMi[i], + stationUrl: dataLoc.stationId[i] + }); } return extraLocs; @@ -227,10 +228,10 @@ export const getExtraLocations = async (lat: number, lon: number, language?: str export const getCurrentCond = async (lat: number, lon: number, language?: string) => { const apiLanguage = language || "en-US"; - return memoizedFetch(`https://api.weather.com/v3/aggcommon/v3-wx-observations-current?geocodes=${lat},${lon};&language=${apiLanguage}&units=s&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) + return memoizedFetch(`https://api.weather.com/v3/aggcommon/v3-wx-observations-current?geocode=${lat},${lon}&language=${apiLanguage}&units=s&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) .then(async (res: Response) => { return res.json().then(data => { - const dataLoc = data[0]["v3-wx-observations-current"]; + const dataLoc = data["v3-wx-observations-current"]; const current = Object.assign({}, currentDefaults); current.temp = dataLoc.temperature; @@ -254,6 +255,50 @@ export const getCurrentCond = async (lat: number, lon: number, language?: string }); }; +interface CurrentConds { + [latLon: string]: CurrentCond +} + +export const getExtraCond = async (latLons: string[], language?: string) => { + const apiLanguage = language || "en-US"; + let baseUrl = "https://api.weather.com/v3/aggcommon/v3-wx-observations-current?geocodes="; + for (let i = 0; i < latLons.length; i++) { + const latLon = latLons[i]; + baseUrl += `${latLon};`; + } + baseUrl += `&language=${apiLanguage}&units=s&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`; + const conds = await memoizedFetch(baseUrl) + .then(async (res: Response) => { + return res.json().then(data => { + return data; + }); + }); + + const result: CurrentConds = {}; + + for (let i = 0; i < conds.length; i++) { + const cond = conds[i]; + const dataLoc = cond["v3-wx-observations-current"]; + + const current = Object.assign({}, currentDefaults); + current.temp = dataLoc.temperature; + current.icon = dataLoc.iconCode; + current.wind = `${(dataLoc.windDirectionCardinal === "CALM" || dataLoc.windSpeed === 0 ? "Calm" : dataLoc.windDirectionCardinal)} ${dataLoc.windSpeed === 0 ? "" : dataLoc.windSpeed}`; + current.windSpeed = dataLoc.windSpeed; + current.visib = dataLoc.visibility; + current.uvIndex = dataLoc.uvDescription; + current.phrase = dataLoc.wxPhraseLong.toLowerCase(); + current.humidity = dataLoc.relativeHumidity; + current.dewpt = dataLoc.temperatureDewPoint; + current.pres = dataLoc.pressureAltimeter.toFixed(2); + current.chill = dataLoc.temperatureWindChill; + + result[cond.id] = current; + } + + return result; +}; + enum MessageType { New = 1, Update, From ff7d832a5fc6a7a22879d381f98862dc9829d46b Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Mon, 7 Nov 2022 09:57:24 -0700 Subject: [PATCH 13/55] Add hook documentation --- components/Display.tsx | 12 +++---- hooks/useCalc.ts | 6 ++++ hooks/useIconMap.ts | 7 ++++ hooks/usePerlin.ts | 3 ++ hooks/useWeather.ts | 79 +++++++++++++++++++++++++++++++++++------- hooks/useWinSize.ts | 8 +++++ 6 files changed, 97 insertions(+), 18 deletions(-) diff --git a/components/Display.tsx b/components/Display.tsx index ab4c96a..aa8eb9b 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -86,7 +86,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr React.useEffect(() => { if (isReady) { if (location !== "") { - getMainLocation(location, language).then(data => { + getMainLocation(location, { language }).then(data => { setLocInfo(data); }).catch(err => { console.error(err); @@ -102,7 +102,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr }, [isReady, location]); const fetchExtra = (lat: number, lon: number) => { - getExtraLocations(lat, lon, language).then(async data => { + getExtraLocations(lat, lon, { language }).then(async data => { const tempMap = new Map>(); const latLonMap = new Map(); const queryLatLons: string[] = []; @@ -116,7 +116,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr latLonMap.set(latLon, location.displayName); } - const extras = await getExtraCond(queryLatLons, language); + const extras = await getExtraCond(queryLatLons, { language }); for (const [key, value] of Object.entries(extras)) { console.log(key); const displayName = latLonMap.get(key); @@ -131,7 +131,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr }; const fetchCurrent = (lat: number, lon: number) => { - getCurrentCond(lat, lon, language).then(data => { + getCurrentCond(lat, lon, { language }).then(data => { setCurrentInfo(data); }).catch(err => { console.error(err); @@ -139,7 +139,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr }; const fetchAlerts = (lat: number, lon: number) => { - getAlerts(lat, lon, language).then(data => { + getAlerts(lat, lon, { language }).then(data => { setAlerts(data); }).catch(err => { console.error(err); @@ -170,7 +170,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr React.useEffect(() => { if (alerts.length > 0) { setFocusedAlert(alerts[0]); - getAlertText(alerts[0].detailKey, language).then(texts => { + getAlertText(alerts[0].detailKey, { language }).then(texts => { if (texts.length > 0) { setFocusedAlertText(texts[0].description); } diff --git a/hooks/useCalc.ts b/hooks/useCalc.ts index 0d70f2b..b490da4 100644 --- a/hooks/useCalc.ts +++ b/hooks/useCalc.ts @@ -1,5 +1,11 @@ type WidthType = "inner" | "outer" | "width" | "full"; +/** + * Gets the different types of width of an element. + * @param el The {@link HTMLElement} to query the width for. + * @param type The {@link WidthType} to query with. + * @returns The element width of that type. + */ export const getWidth = (el: HTMLElement, type: WidthType) => { if (type === 'inner') // .innerWidth() return el.clientWidth; diff --git a/hooks/useIconMap.ts b/hooks/useIconMap.ts index 674a909..d4d681d 100644 --- a/hooks/useIconMap.ts +++ b/hooks/useIconMap.ts @@ -51,6 +51,7 @@ export enum Icons2010 { HEAVY_WIND_ALT }; +/** @internal */ const Icons2010CodeMap = Object.freeze([ Icons2010.UNUSED, // 0 Icons2010.UNUSED, // 1 @@ -102,6 +103,12 @@ const Icons2010CodeMap = Object.freeze([ Icons2010.THUNDER_NIGHT // 47 ]); +/** + * Gets the mapped icon for the specified code and wind data. + * @param iconCode The icon code to map. + * @param windData The wind data to map. + * @returns An {@link Icons2010} member for the specified code and wind data. + */ export const getIcon = (iconCode: number, windData: number) : Icons2010 => { let icon = Icons2010CodeMap[iconCode]; if (windData >= 20) { diff --git a/hooks/usePerlin.ts b/hooks/usePerlin.ts index b559a30..0c567d5 100644 --- a/hooks/usePerlin.ts +++ b/hooks/usePerlin.ts @@ -1,10 +1,13 @@ /* https://github.com/joeiddon/perlin */ +/** @internal */ type Memory = { [index: string]: number } +/** @internal */ const gradients: Memory = {}; +/** @internal */ const memory: Memory = {}; const perlin = { diff --git a/hooks/useWeather.ts b/hooks/useWeather.ts index 4dc4f3d..be31c97 100644 --- a/hooks/useWeather.ts +++ b/hooks/useWeather.ts @@ -1,6 +1,10 @@ import * as React from "react"; import { Icons2010 } from "./useIconMap"; +interface APIOptions { + language?: string +} + // Mapped location export interface Location { city: string @@ -138,8 +142,14 @@ const memoAsync = (cb) => { const memoizedFetch = memoAsync(fetch); -export const getMainLocation = async (location: string, language?: string) => { - const apiLanguage = language || "en-US"; +/** + * Gets the main location for a query string. + * @param location The query string to look up. + * @param options The options for this request. + * @returns A promise returning a {@link Location} for the query string. + */ +export const getMainLocation = async (location: string, options?: APIOptions) => { + const apiLanguage = options.language || "en-US"; return memoizedFetch(`https://api.weather.com/v3/location/search?query=${encodeURIComponent(location)}&language=${apiLanguage}&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) .then(async (res: Response) => { @@ -164,6 +174,10 @@ export const getMainLocation = async (location: string, language?: string) => { }); }; +/** + * Gets the closest location nearest to the user. + * @returns A promise returning the {@link Location} of the user. + */ export const getClosestLocation = async () => { return memoizedFetch(`https://pro.ip-api.com/json/?key=${process.env.NEXT_PUBLIC_IP_API_KEY}&exposeDate=true`) .then(async (res: Response) => { @@ -190,8 +204,15 @@ export const getClosestLocation = async () => { }); }; -export const getExtraLocations = async (lat: number, lon: number, language?: string) => { - const apiLanguage = language || "en-US"; +/** + * Gets nearby locations for a single location. + * @param lat The latitude of the location. + * @param lon The longitude of the location. + * @param options The options for this request. + * @returns A promise returning an {@link ExtraLocation} array for the specified location. + */ +export const getExtraLocations = async (lat: number, lon: number, options?: APIOptions) => { + const apiLanguage = options.language || "en-US"; return memoizedFetch(`https://api.weather.com/v3/location/near?geocode=${lat},${lon}&product=observation&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) .then(async (res: Response) => { @@ -226,8 +247,15 @@ export const getExtraLocations = async (lat: number, lon: number, language?: str }); }; -export const getCurrentCond = async (lat: number, lon: number, language?: string) => { - const apiLanguage = language || "en-US"; +/** + * Gets the current conditions for a single location. + * @param lat The latitude of the location. + * @param lon The longitude of the location. + * @param options The options for this request. + * @returns A promise returning a {@link CurrentCond} object for the specified location. + */ +export const getCurrentCond = async (lat: number, lon: number, options?: APIOptions) => { + const apiLanguage = options.language || "en-US"; return memoizedFetch(`https://api.weather.com/v3/aggcommon/v3-wx-observations-current?geocode=${lat},${lon}&language=${apiLanguage}&units=s&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) .then(async (res: Response) => { return res.json().then(data => { @@ -255,12 +283,19 @@ export const getCurrentCond = async (lat: number, lon: number, language?: string }); }; +/** @internal */ interface CurrentConds { [latLon: string]: CurrentCond } -export const getExtraCond = async (latLons: string[], language?: string) => { - const apiLanguage = language || "en-US"; +/** + * Gets the current conditions for a list of locations. + * @param latLons An array of locations (latitudes and longitudes). + * @param options The options for this request. + * @returns A promise returning a {@link CurrentConds} object for the specified locations. + */ +export const getExtraCond = async (latLons: string[], options?: APIOptions) => { + const apiLanguage = options.language || "en-US"; let baseUrl = "https://api.weather.com/v3/aggcommon/v3-wx-observations-current?geocodes="; for (let i = 0; i < latLons.length; i++) { const latLon = latLons[i]; @@ -387,11 +422,13 @@ enum ResponseTypeCode { None } +/** @internal */ interface ResponseType { responseType: string responseTypeCode: ResponseTypeCode } +/** @internal */ interface Text { languageCode: string description: string @@ -452,15 +489,18 @@ export interface Alert { texts: Text[] } +/** @internal */ interface AlertsMetadata { next: any } +/** @internal */ interface AlertsResponse { metadata?: AlertsMetadata alerts: Alert[] } +/** @internal */ const alertsFallback: AlertsResponse = Object.freeze({ metadata: { next: null @@ -468,8 +508,15 @@ const alertsFallback: AlertsResponse = Object.freeze({ alerts: [] }); -export const getAlerts = async (lat: number, lon: number, language?: string) => { - const apiLanguage = language || "en-US"; +/** + * Gets the alerts for a specified latitude and longitude. + * @param lat The latitude of the location. + * @param lon The longitude of the location. + * @param options The options for this request. + * @returns A promise returning an {@link Alert} array for the specified latitude and longitude. + */ +export const getAlerts = async (lat: number, lon: number, options?: APIOptions) => { + const apiLanguage = options.language || "en-US"; return memoizedFetch(`https://api.weather.com/v3/alerts/headlines?geocode=${lat},${lon}&language=${apiLanguage}&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) .then(async (res: Response) => { return res.json().then((data: AlertsResponse) => { @@ -482,12 +529,20 @@ export const getAlerts = async (lat: number, lon: number, language?: string) => }); }; +/** @internal */ interface AlertDetailResponse { alertDetail: Alert } -export const getAlertText = async (alertId: string, language?: string) : Promise => { - const apiLanguage = language || "en-US"; +/** + * Gets the alert text for a specified alert ID. This should be ran after getAlerts. + * @param alertId The alert ID to fetch the text for. + * @param options The options for this request. + * @returns A promise returning a {@link Text} array for the specified alert ID. + */ + +export const getAlertText = async (alertId: string, options?: APIOptions) : Promise => { + const apiLanguage = options.language || "en-US"; return memoizedFetch(`https://api.weather.com/v3/alerts/detail?alertId=${alertId}&language=${apiLanguage}&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) .then(async (res: Response) => { return res.json().then((data: AlertDetailResponse) => { diff --git a/hooks/useWinSize.ts b/hooks/useWinSize.ts index f0883b2..b0045f7 100644 --- a/hooks/useWinSize.ts +++ b/hooks/useWinSize.ts @@ -1,5 +1,9 @@ import * as React from "react"; +/** + * Gets the inner size of the window. + * @returns A number array with the first index being the inner width and the second index being the inner height. + */ export const useWinSizeInner = () => { const [size, setSize] = React.useState([0, 0]); React.useEffect(() => { @@ -19,6 +23,10 @@ export const useWinSizeInner = () => { return size; }; +/** + * Gets the outer size of the window. + * @returns A number array with the first index being the outer width and the second index being the outer height. + */ export const useWinSizeOuter = () => { const [size, setSize] = React.useState([0, 0]); React.useEffect(() => { From bd05f69e536eb90450933cc8547a81eab018ea0c Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Mon, 7 Nov 2022 12:52:08 -0700 Subject: [PATCH 14/55] Add extra locations to header --- components/Display.tsx | 9 ++- .../Slides/Containers/Headers/SlideHeader.tsx | 2 +- .../Containers/Headers/SlideHeaderScroll.tsx | 5 +- .../Slides/{ => City}/CityInfo/Detailed.tsx | 6 +- .../Slides/{ => City}/CityInfo/Forecast.tsx | 0 .../{ => City}/CityInfo/Severe/index.tsx | 0 .../Slides/{ => City}/CityInfo/index.tsx | 8 +- .../Slides/{ => City}/CityIntro/index.tsx | 2 +- .../Slides/Containers/Slides/City/index.tsx | 37 +++++++++ .../Slides/Containers/SlidesContainer.tsx | 77 +++++++++++-------- hooks/useSlides.ts | 26 ++++++- 11 files changed, 124 insertions(+), 48 deletions(-) rename components/Slides/Containers/Slides/{ => City}/CityInfo/Detailed.tsx (96%) rename components/Slides/Containers/Slides/{ => City}/CityInfo/Forecast.tsx (100%) rename components/Slides/Containers/Slides/{ => City}/CityInfo/Severe/index.tsx (100%) rename components/Slides/Containers/Slides/{ => City}/CityInfo/index.tsx (90%) rename components/Slides/Containers/Slides/{ => City}/CityIntro/index.tsx (97%) create mode 100644 components/Slides/Containers/Slides/City/index.tsx diff --git a/components/Display.tsx b/components/Display.tsx index aa8eb9b..e221d6d 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -104,6 +104,8 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr const fetchExtra = (lat: number, lon: number) => { getExtraLocations(lat, lon, { language }).then(async data => { const tempMap = new Map>(); + tempMap.set(locInfo.city, currentInfo); + const latLonMap = new Map(); const queryLatLons: string[] = []; @@ -194,7 +196,12 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr
background - {isReady && } + {(isReady && locInfo && currentInfo && extraInfo.size !== 0) && } {locInfo.timezone !== "" && } {locInfo.city !== "" &&
void + cycleCallback: (selected: string) => void } const SlideHeader = ({ locations, willUpdate, cycleCallback }: SlideHeaderProps) => ( diff --git a/components/Slides/Containers/Headers/SlideHeaderScroll.tsx b/components/Slides/Containers/Headers/SlideHeaderScroll.tsx index 4b788a7..11a40ff 100644 --- a/components/Slides/Containers/Headers/SlideHeaderScroll.tsx +++ b/components/Slides/Containers/Headers/SlideHeaderScroll.tsx @@ -14,7 +14,7 @@ interface ItemsRef { interface SlideHeaderScrollProps { locations: string[] willUpdate: boolean - cycleCallback: () => void + cycleCallback: (selected: string) => void } const SlideHeaderScroll = ({ locations, willUpdate, cycleCallback }: SlideHeaderScrollProps) => { @@ -52,11 +52,10 @@ const SlideHeaderScroll = ({ locations, willUpdate, cycleCallback }: SlideHeader left: `${-1.06*(cityRefWidth + arrowRefWidth)}px`, transition: { duration: 0.9 } }).then(() => { + cycleCallback(items[1].city.innerHTML); setShiftNeeded(true); controls.set({ left: null }); }); - - cycleCallback(); } } }, [willUpdate, itemsRef]); diff --git a/components/Slides/Containers/Slides/CityInfo/Detailed.tsx b/components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx similarity index 96% rename from components/Slides/Containers/Slides/CityInfo/Detailed.tsx rename to components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx index 821fed4..14777e6 100644 --- a/components/Slides/Containers/Slides/CityInfo/Detailed.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx @@ -1,8 +1,8 @@ import * as React from "react"; -import type { CurrentCond } from "../../../../../hooks/useWeather"; -import { Icons2010, getIcon } from "../../../../../hooks/useIconMap"; +import type { CurrentCond } from "../../../../../../hooks/useWeather"; +import { Icons2010, getIcon } from "../../../../../../hooks/useIconMap"; import { motion } from "framer-motion"; -import FrostPane from "../FrostPane"; +import FrostPane from "../../FrostPane"; interface DetailedProps { city?: string diff --git a/components/Slides/Containers/Slides/CityInfo/Forecast.tsx b/components/Slides/Containers/Slides/City/CityInfo/Forecast.tsx similarity index 100% rename from components/Slides/Containers/Slides/CityInfo/Forecast.tsx rename to components/Slides/Containers/Slides/City/CityInfo/Forecast.tsx diff --git a/components/Slides/Containers/Slides/CityInfo/Severe/index.tsx b/components/Slides/Containers/Slides/City/CityInfo/Severe/index.tsx similarity index 100% rename from components/Slides/Containers/Slides/CityInfo/Severe/index.tsx rename to components/Slides/Containers/Slides/City/CityInfo/Severe/index.tsx diff --git a/components/Slides/Containers/Slides/CityInfo/index.tsx b/components/Slides/Containers/Slides/City/CityInfo/index.tsx similarity index 90% rename from components/Slides/Containers/Slides/CityInfo/index.tsx rename to components/Slides/Containers/Slides/City/CityInfo/index.tsx index 018969d..84d0c45 100644 --- a/components/Slides/Containers/Slides/CityInfo/index.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/index.tsx @@ -1,11 +1,11 @@ import * as React from "react"; -import type { SlideProps } from "../../../../../hooks/useSlides"; -import { SlideshowReducer, Slides, ActionType } from "../../../../../hooks/useSlides"; +import type { SlideProps } from "../../../../../../hooks/useSlides"; +import { SlideshowReducer, Slides, ActionType } from "../../../../../../hooks/useSlides"; import { motion, AnimatePresence } from "framer-motion"; import Forecast from "./Forecast"; import Detailed from "./Detailed"; -const SlideCityInfo = ({ next, currentCityInfo }: SlideProps) => { +const SlideCityInfo = ({ next, location, currentCityInfo }: SlideProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0 }); const currentSlide = React.useMemo(() => { @@ -32,7 +32,7 @@ const SlideCityInfo = ({ next, currentCityInfo }: SlideProps) => { className="transform translate-x-0 translate-y-60px scale-x-114-5 scale-y-100 origin-left absolute whitespace-nowrap font-frutiger57-cond pt-noreport-t pl-tempunavailable-l text-white text-tempunavailable text-shadow z-noreport" >Temporarily Unavailable; case 2: - return ; + return ; default: return null; } diff --git a/components/Slides/Containers/Slides/CityIntro/index.tsx b/components/Slides/Containers/Slides/City/CityIntro/index.tsx similarity index 97% rename from components/Slides/Containers/Slides/CityIntro/index.tsx rename to components/Slides/Containers/Slides/City/CityIntro/index.tsx index 7b35e74..cf09a28 100644 --- a/components/Slides/Containers/Slides/CityIntro/index.tsx +++ b/components/Slides/Containers/Slides/City/CityIntro/index.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import type { SlideProps } from "../../../../../hooks/useSlides"; +import type { SlideProps } from "../../../../../../hooks/useSlides"; import { motion, useAnimation } from "framer-motion"; type SlideState = "active" | "inactive"; diff --git a/components/Slides/Containers/Slides/City/index.tsx b/components/Slides/Containers/Slides/City/index.tsx new file mode 100644 index 0000000..b351d43 --- /dev/null +++ b/components/Slides/Containers/Slides/City/index.tsx @@ -0,0 +1,37 @@ +import * as React from "react"; +import type { MainSlideProps } from "../../../../../hooks/useSlides"; +import { SlideshowReducer, SlidesCity, ActionType } from "../../../../../hooks/useSlides"; + +import CityIntro from "./CityIntro"; +import CityInfo from "./CityInfo"; + +const City = ({ next, location, currentCityInfo, introNeeded }: MainSlideProps) => { + const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0 }); + + const SlideCallback = React.useCallback(() => { + if (slideState.index >= 1) { + next(); + slideDispatch({ type: ActionType.SET, payload: 1 }); + } else { + slideDispatch({ type: ActionType.INCREASE, payload: 1 }); + } + }, [slideState.index]); + + const currentSlide = React.useMemo(() => { + console.log("Rendering new city slide"); + switch (slideState.index) { + case SlidesCity.INTRO: + return ; + case SlidesCity.INFO: + return ; + } + }, [slideState.index, SlideCallback, location, currentCityInfo]); + + return currentSlide; +}; + +export default City; diff --git a/components/Slides/Containers/SlidesContainer.tsx b/components/Slides/Containers/SlidesContainer.tsx index ca131b2..b620540 100644 --- a/components/Slides/Containers/SlidesContainer.tsx +++ b/components/Slides/Containers/SlidesContainer.tsx @@ -1,64 +1,79 @@ import * as React from "react"; -import type { CurrentCond } from "../../../hooks/useWeather"; +import type { Location, CurrentCond } from "../../../hooks/useWeather"; import SlideHeader from "./Headers/SlideHeader"; import { AudioPlayerProvider } from "react-use-audio-player"; import { VocalMale, VocalFemale } from "../../../components/VocalAudio"; import VocalAudio from "../../../components/VocalAudio"; import { SlideshowReducer, Slides, ActionType } from "../../../hooks/useSlides"; -import CityIntro from "./Slides/CityIntro"; -import CityInfo from "./Slides/CityInfo"; +import City from "./Slides/City"; interface SlidesContainerProps { setMainVol: React.Dispatch> - currentCityInfo?: Partial + locInfo?: Partial + mainCityInfo?: Partial + extraCityInfo?: Map> } -const SlidesContainer = ({ setMainVol, currentCityInfo }: SlidesContainerProps) => { - const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0 }); +const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo }: SlidesContainerProps) => { + const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0, isCity: true }); const [vocal, setVocal] = React.useState(VocalFemale.CURRENT_COND); const [headerWillUpdate, setHeaderUpdate] = React.useState(false); - const SlideCallback = React.useCallback(() => { - if (slideState.index >= 1) { - slideDispatch({ type: ActionType.SET, payload: 0 }); + const [cityInfo, setCityInfo] = React.useState>>(extraCityInfo); + const [currentCity, setCurrentCity] = React.useState(locInfo.city); + const [currentInfo, setCurrentInfo] = React.useState>(mainCityInfo); + const [header, setHeader] = React.useState([]); + + const SlideCallback = React.useCallback(() => setHeaderUpdate(true), [slideState.index]); + + const HeaderCallback = (selected: string) => { + console.log("Header cycle complete"); + const selectedInfo = cityInfo.get(selected); + if (selectedInfo !== undefined) { + setCurrentCity(selected); + setCurrentInfo(selectedInfo); + slideDispatch({ type: ActionType.SET, payload: 0, payloadCity: true }); } else { + slideDispatch({ type: ActionType.SET_CITY, payloadCity: false }); slideDispatch({ type: ActionType.INCREASE, payload: 1 }); } - setHeaderUpdate(true); - }, [slideState.index]); - - const HeaderCallback = () => { - console.log("Header cycle complete"); setHeaderUpdate(false); }; + React.useEffect(() => { + setHeader(Array.from(cityInfo.keys())); + }, [cityInfo]); + const currentSlide = React.useMemo(() => { console.log("Rendering new slide"); switch (slideState.index) { - case Slides.INTRO: - return ; - case Slides.INFO: - return ; + case Slides.CITY: + return ; default: return null; } - }, [slideState.index]); + }, [slideState.index, SlideCallback, currentCity, currentInfo]); return (
- + {(cityInfo && header.length > 0) && }
diff --git a/hooks/useSlides.ts b/hooks/useSlides.ts index 56fa25f..cd2d33e 100644 --- a/hooks/useSlides.ts +++ b/hooks/useSlides.ts @@ -1,6 +1,11 @@ import type { CurrentCond } from "./useWeather"; export const enum Slides { + CITY +} + +// City slides +export const enum SlidesCity { INTRO, INFO } @@ -8,32 +13,45 @@ export const enum Slides { export interface SlideProps { currentCityInfo?: Partial next?: () => void + location?: string +} + +export interface MainSlideProps extends SlideProps { + introNeeded?: boolean } export const enum ActionType { INCREASE = "INCREASE", DECREASE = "DECREASE", - SET = "SET" + SET = "SET", + TOGGLE_CITY = "TOGGLE_CITY", + SET_CITY = "SET_CITY" } interface Action { type: ActionType - payload: number + payload?: number + payloadCity?: boolean } interface State { index: number + isCity?: boolean // Used for header, nullable } export const SlideshowReducer = (state: State, action: Action) => { - const { type, payload } = action; + const { type, payload, payloadCity } = action; switch (type) { case ActionType.INCREASE: return { index: state.index + payload }; case ActionType.DECREASE: return { index: state.index - payload }; case ActionType.SET: - return { index: payload }; + return { index: payload, isCity: payloadCity || false }; + case ActionType.TOGGLE_CITY: + return { index: state.index, isCity: !state.isCity } + case ActionType.SET_CITY: + return { index: state.index, isCity: payloadCity || false } default: return state; } From c86eed676520e418738770eee262d5a2102cbe75 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Mon, 7 Nov 2022 12:54:40 -0700 Subject: [PATCH 15/55] Fix imports --- components/Slides/Containers/Slides/City/CityInfo/Forecast.tsx | 2 +- .../Slides/Containers/Slides/City/CityInfo/Severe/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/Slides/Containers/Slides/City/CityInfo/Forecast.tsx b/components/Slides/Containers/Slides/City/CityInfo/Forecast.tsx index 932fc3a..54d6f26 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/Forecast.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/Forecast.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import FrostPane from "../FrostPane"; +import FrostPane from "../../FrostPane"; const Forecast = () => (
diff --git a/components/Slides/Containers/Slides/City/CityInfo/Severe/index.tsx b/components/Slides/Containers/Slides/City/CityInfo/Severe/index.tsx index f1794a8..67f16a7 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/Severe/index.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/Severe/index.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import FrostPane from "../../FrostPane"; +import FrostPane from "../../../FrostPane"; const SlideSevereCityInfo = () => ( <> From e75ea4707f5952413a1a502a54de6118dfae5d00 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Mon, 14 Nov 2022 16:19:06 -0700 Subject: [PATCH 16/55] Fix header bug and add rest of slides --- components/DateTime.tsx | 14 +++++- components/Display.tsx | 46 ++++++++++++----- components/Intro.tsx | 3 +- .../Containers/Headers/SlideHeaderScroll.tsx | 2 +- .../Containers/Slides/Airports/index.tsx | 13 +++++ .../Slides/City/CityInfo/Detailed.tsx | 37 ++++++++------ .../Containers/Slides/City/CityInfo/index.tsx | 9 ++-- .../Slides/Containers/Slides/City/index.tsx | 6 +-- .../Slides/Containers/Slides/Health/index.tsx | 13 +++++ .../Containers/Slides/International/index.tsx | 13 +++++ .../Slides/Containers/Slides/Travel/index.tsx | 13 +++++ .../Slides/Containers/SlidesContainer.tsx | 49 +++++++++++++------ hooks/useSlides.ts | 10 ++-- hooks/useWeather.ts | 27 +++++----- 14 files changed, 188 insertions(+), 67 deletions(-) create mode 100644 components/Slides/Containers/Slides/Airports/index.tsx create mode 100644 components/Slides/Containers/Slides/Health/index.tsx create mode 100644 components/Slides/Containers/Slides/International/index.tsx create mode 100644 components/Slides/Containers/Slides/Travel/index.tsx diff --git a/components/DateTime.tsx b/components/DateTime.tsx index 3d1e1bc..24a1401 100644 --- a/components/DateTime.tsx +++ b/components/DateTime.tsx @@ -1,13 +1,25 @@ import * as React from "react"; +import { useRouter } from "next/router"; interface DateTimeProps { tz: string } const DateTime = ({ tz }: DateTimeProps) => { + const router = useRouter(); const [date, setDate] = React.useState("Jan 01"); const [time, setTime] = React.useState("12:00:00pm"); + const stdTimezoneOffset = (date: Date) => { + var jan = new Date(date.getFullYear(), 0, 1); + var jul = new Date(date.getFullYear(), 6, 1); + return Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset()); + }; + + const isDstObserved = (date: Date) => { + return date.getTimezoneOffset() < stdTimezoneOffset(date); + }; + const updateTime = () => { const date = new Date(); @@ -25,7 +37,7 @@ const DateTime = ({ tz }: DateTimeProps) => { }; React.useEffect(() => { - let interval: NodeJS.Timeout; + let interval: NodeJS.Timer; if (tz !== "") { updateTime(); diff --git a/components/Display.tsx b/components/Display.tsx index e221d6d..2289595 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import type { Location, ExtraLocation, CurrentCond, Alert } from "../hooks/useWeather"; +import type { Location, ExtraLocation, ExtraInfo, CurrentCond, Alert } from "../hooks/useWeather"; import { defaults, currentDefaults, @@ -50,11 +50,6 @@ interface DisplayProps { setMainVol: React.Dispatch> } -interface ExtraInfo { - details?: ExtraLocation - current?: Partial -} - const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayProps) => { const [innerWidth, innerHeight] = winSize; const mainRef = React.useRef(); @@ -76,7 +71,14 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr const [locInfo, setLocInfo] = React.useState>(defaults); const [currentInfo, setCurrentInfo] = React.useState>(currentDefaults); - const [extraInfo, setExtraInfo] = React.useState>>(new Map>()); + const [currentExtra, setCurrentExtra] = React.useState({ + details: { + name: "", + lat: 0, + lon: 0 + } + }); + const [extraInfo, setExtraInfo] = React.useState>(new Map()); const [alerts, setAlerts] = React.useState([]); const [focusedAlert, setFocusedAlert] = React.useState(null); @@ -103,8 +105,16 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr const fetchExtra = (lat: number, lon: number) => { getExtraLocations(lat, lon, { language }).then(async data => { - const tempMap = new Map>(); - tempMap.set(locInfo.city, currentInfo); + const tempMap = new Map(); + const currentEx = { + details: { + name: locInfo.city, + lat, + lon + }, + current: currentInfo + }; + tempMap.set(locInfo.city, currentEx); const latLonMap = new Map(); const queryLatLons: string[] = []; @@ -123,9 +133,18 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr console.log(key); const displayName = latLonMap.get(key); console.log(displayName, value); - tempMap.set(displayName, value); + const latLon = key.split(","); + tempMap.set(displayName, { + details: { + name: displayName, + lat: parseFloat(latLon[0]), + lon: parseFloat(latLon[1]) + }, + current: value + }); } + setCurrentExtra(currentEx); setExtraInfo(tempMap); }).catch(err => { console.error(err); @@ -156,11 +175,12 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr let intervalTimer: NodeJS.Timeout; if (lat && lon) { - fetchExtra(lat, lon); fetchCurrent(lat, lon); + fetchExtra(lat, lon); fetchAlerts(lat, lon); intervalTimer = setInterval(() => { fetchCurrent(lat, lon); + fetchExtra(lat, lon); fetchAlerts(lat, lon); }, 300000); } @@ -196,10 +216,10 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr
background - {(isReady && locInfo && currentInfo && extraInfo.size !== 0) && } {locInfo.timezone !== "" && } diff --git a/components/Intro.tsx b/components/Intro.tsx index e6f3292..c78b21e 100644 --- a/components/Intro.tsx +++ b/components/Intro.tsx @@ -94,7 +94,7 @@ const Intro = ({ winSize, callback }: IntroProps) => { }, [intellistarRef]); return ( -
+
headend id:
@@ -110,6 +110,7 @@ const Intro = ({ winSize, callback }: IntroProps) => {
Save
weatherscan + Now rewritten!
From 960d40815bb5b131b8fb0f28252fef1ed8214b0e Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Tue, 15 Nov 2022 13:44:21 -0700 Subject: [PATCH 18/55] Fix city info slide bug --- components/Display.tsx | 151 ++++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 76 deletions(-) diff --git a/components/Display.tsx b/components/Display.tsx index 2289595..7333849 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -1,4 +1,5 @@ import * as React from "react"; +import { useCallback } from "react"; import type { Location, ExtraLocation, ExtraInfo, CurrentCond, Alert } from "../hooks/useWeather"; import { defaults, @@ -71,13 +72,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr const [locInfo, setLocInfo] = React.useState>(defaults); const [currentInfo, setCurrentInfo] = React.useState>(currentDefaults); - const [currentExtra, setCurrentExtra] = React.useState({ - details: { - name: "", - lat: 0, - lon: 0 - } - }); + const [currentExtra, setCurrentExtra] = React.useState(null); const [extraInfo, setExtraInfo] = React.useState>(new Map()); const [alerts, setAlerts] = React.useState([]); @@ -90,81 +85,64 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr if (location !== "") { getMainLocation(location, { language }).then(data => { setLocInfo(data); - }).catch(err => { - console.error(err); - }); + }).catch(err => console.error(err)); } else { getClosestLocation().then(data => { setLocInfo(data); - }).catch(err => { - console.error(err); - }); + }).catch(err => console.error(err)); } } }, [isReady, location]); - const fetchExtra = (lat: number, lon: number) => { - getExtraLocations(lat, lon, { language }).then(async data => { - const tempMap = new Map(); - const currentEx = { - details: { - name: locInfo.city, - lat, - lon - }, - current: currentInfo - }; - tempMap.set(locInfo.city, currentEx); - - const latLonMap = new Map(); - const queryLatLons: string[] = []; - - // Dirty way of doing things - for (let i = 0; i < data.length; i++) { - const location = data[i]; - const latLon = `${location.lat},${location.lon}`; - console.log(latLon); - queryLatLons.push(latLon); - latLonMap.set(latLon, location.displayName); - } - - const extras = await getExtraCond(queryLatLons, { language }); - for (const [key, value] of Object.entries(extras)) { - console.log(key); - const displayName = latLonMap.get(key); - console.log(displayName, value); - const latLon = key.split(","); - tempMap.set(displayName, { - details: { - name: displayName, - lat: parseFloat(latLon[0]), - lon: parseFloat(latLon[1]) - }, - current: value - }); - } - - setCurrentExtra(currentEx); - setExtraInfo(tempMap); - }).catch(err => { - console.error(err); + const fetchCurrent = (lat: number, lon: number) : Promise => { + return new Promise((resolve, reject) => { + getCurrentCond(lat, lon, { language }).then(data => { + setCurrentInfo(data); + resolve(data); + }).catch(err => reject(err)); }); }; - const fetchCurrent = (lat: number, lon: number) => { - getCurrentCond(lat, lon, { language }).then(data => { - setCurrentInfo(data); - }).catch(err => { - console.error(err); - }); + // Bugged + const fetchExtra = async (lat: number, lon: number, initial?: Map) => { + const data = await getExtraLocations(lat, lon, { language }); + + const tempMap = new Map(initial ?? []); + const latLonMap = new Map(); + const queryLatLons: string[] = []; + + // Dirty way of doing things + for (let i = 0; i < data.length; i++) { + const location = data[i]; + const latLon = `${location.lat},${location.lon}`; + console.log(latLon); + queryLatLons.push(latLon); + latLonMap.set(latLon, location.displayName); + } + + const extras = await getExtraCond(queryLatLons, { language }); + for (const [key, value] of Object.entries(extras)) { + console.log(key); + const displayName = latLonMap.get(key); + console.log(displayName, value); + const latLon = key.split(","); + tempMap.set(displayName, { + details: { + name: displayName, + lat: parseFloat(latLon[0]), + lon: parseFloat(latLon[1]) + }, + current: value + }); + } + + setExtraInfo(tempMap); }; const fetchAlerts = (lat: number, lon: number) => { getAlerts(lat, lon, { language }).then(data => { setAlerts(data); - }).catch(err => { - console.error(err); - }); + }).catch(err => console.error(err)); }; // Current conditions and alerts handler @@ -173,19 +151,36 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr const lat = locInfo.latitude; const lon = locInfo.longitude; - let intervalTimer: NodeJS.Timeout; + let timeoutTimer: NodeJS.Timer; + let intervalTimer: NodeJS.Timer; if (lat && lon) { - fetchCurrent(lat, lon); - fetchExtra(lat, lon); - fetchAlerts(lat, lon); - intervalTimer = setInterval(() => { - fetchCurrent(lat, lon); - fetchExtra(lat, lon); + const fetchCallback = (data: CurrentCond) => { + const tempMap = new Map(); + const currentEx = { + details: { + name: locInfo.city, + lat, + lon + }, + current: data + }; + tempMap.set(locInfo.city, currentEx); + setCurrentExtra(currentEx); + + fetchExtra(lat, lon, tempMap); fetchAlerts(lat, lon); + }; + + fetchCurrent(lat, lon).then(fetchCallback).catch(err => console.error(err)); + intervalTimer = setInterval(() => { + fetchCurrent(lat, lon).then(fetchCallback).catch(err => console.error(err)); }, 300000); } - return () => clearInterval(intervalTimer); + return () => { + clearTimeout(timeoutTimer) + clearInterval(intervalTimer); + }; } }, [isReady, locInfo.latitude, locInfo.longitude]); @@ -202,6 +197,10 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr } }, [alerts.length]); + React.useEffect(() => { + console.log(currentExtra); + }, [currentExtra]); + React.useEffect(() => { console.log(extraInfo); }, [extraInfo]); @@ -216,7 +215,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr
background - {(isReady && locInfo && currentExtra && extraInfo.size !== 0) && 1) && Date: Tue, 15 Nov 2022 13:51:24 -0700 Subject: [PATCH 19/55] Cleanup --- components/Display.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/Display.tsx b/components/Display.tsx index 7333849..7e4fc72 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -1,5 +1,4 @@ import * as React from "react"; -import { useCallback } from "react"; import type { Location, ExtraLocation, ExtraInfo, CurrentCond, Alert } from "../hooks/useWeather"; import { defaults, @@ -72,7 +71,13 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr const [locInfo, setLocInfo] = React.useState>(defaults); const [currentInfo, setCurrentInfo] = React.useState>(currentDefaults); - const [currentExtra, setCurrentExtra] = React.useState(null); + const [currentExtra, setCurrentExtra] = React.useState({ + details: { + name: "", + lat: 0, + lon: 0 + } + }); const [extraInfo, setExtraInfo] = React.useState>(new Map()); const [alerts, setAlerts] = React.useState([]); @@ -103,7 +108,6 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr }); }; - // Bugged const fetchExtra = async (lat: number, lon: number, initial?: Map) => { const data = await getExtraLocations(lat, lon, { language }); @@ -151,7 +155,6 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr const lat = locInfo.latitude; const lon = locInfo.longitude; - let timeoutTimer: NodeJS.Timer; let intervalTimer: NodeJS.Timer; if (lat && lon) { const fetchCallback = (data: CurrentCond) => { @@ -177,10 +180,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr }, 300000); } - return () => { - clearTimeout(timeoutTimer) - clearInterval(intervalTimer); - }; + return () => clearInterval(intervalTimer); } }, [isReady, locInfo.latitude, locInfo.longitude]); @@ -215,7 +215,7 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr
background - {(isReady && locInfo && currentExtra && extraInfo.size > 1) && Date: Tue, 15 Nov 2022 14:13:55 -0700 Subject: [PATCH 20/55] Set vocal in slides --- .../Slides/City/CityInfo/Detailed.tsx | 2 +- .../Slides/City/CityInfo/Forecast.tsx | 23 ------------------- .../Containers/Slides/City/CityInfo/index.tsx | 6 +++-- .../Slides/Containers/Slides/City/index.tsx | 3 ++- .../Slides/Containers/SlidesContainer.tsx | 8 ++++++- hooks/useSlides.ts | 2 ++ 6 files changed, 16 insertions(+), 28 deletions(-) delete mode 100644 components/Slides/Containers/Slides/City/CityInfo/Forecast.tsx diff --git a/components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx b/components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx index 1f0fcc0..84d3c5c 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx @@ -48,7 +48,7 @@ const Detailed = ({ info }: DetailedProps) => { id="info-subheadershadowfix" className="font-normal font-frutiger57-cond text-white flex flex-row flex-nowrap justify-between text-subhead h-subhead z-subheader-shadow whitespace-nowrap text-shadow-subhead absolute min-w-subhead-shadow" > - Local Forecast + Currently ( -
- -
-
- -
-); - -export default Forecast; diff --git a/components/Slides/Containers/Slides/City/CityInfo/index.tsx b/components/Slides/Containers/Slides/City/CityInfo/index.tsx index 7026ee8..377e999 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/index.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/index.tsx @@ -1,11 +1,12 @@ import * as React from "react"; import type { SlideProps } from "../../../../../../hooks/useSlides"; import { SlideshowReducer, Slides, ActionType } from "../../../../../../hooks/useSlides"; +import { VocalMale, VocalFemale } from "../../../../../VocalAudio"; import { motion, AnimatePresence } from "framer-motion"; -import Forecast from "./Forecast"; import Detailed from "./Detailed"; +import Near from "./Near"; -const SlideCityInfo = ({ next, location, currentCityInfo }: SlideProps) => { +const SlideCityInfo = ({ next, location, currentCityInfo, setVocal }: SlideProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0 }); const currentSlide = React.useMemo(() => { @@ -32,6 +33,7 @@ const SlideCityInfo = ({ next, location, currentCityInfo }: SlideProps) => { className="transform translate-x-0 translate-y-60px scale-x-114-5 scale-y-100 origin-left absolute whitespace-nowrap font-frutiger57-cond pt-noreport-t pl-tempunavailable-l text-white text-tempunavailable text-shadow z-noreport" >Temporarily Unavailable; case 2: + setVocal(VocalFemale.CURRENT_COND); return ; default: return null; diff --git a/components/Slides/Containers/Slides/City/index.tsx b/components/Slides/Containers/Slides/City/index.tsx index 6b306b5..c44c4a8 100644 --- a/components/Slides/Containers/Slides/City/index.tsx +++ b/components/Slides/Containers/Slides/City/index.tsx @@ -5,7 +5,7 @@ import { SlideshowReducer, SlidesCity, ActionType } from "../../../../../hooks/u import CityIntro from "./CityIntro"; import CityInfo from "./CityInfo"; -const City = ({ next, location, currentCityInfo, introNeeded }: MainSlideProps) => { +const City = ({ next, location, currentCityInfo, introNeeded, setVocal }: MainSlideProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: introNeeded ? 0 : 1 }); const SlideCallback = React.useCallback(() => { @@ -27,6 +27,7 @@ const City = ({ next, location, currentCityInfo, introNeeded }: MainSlideProps) next={SlideCallback} location={location} currentCityInfo={currentCityInfo} + setVocal={setVocal} />; } }, [slideState.index, SlideCallback, location, currentCityInfo]); diff --git a/components/Slides/Containers/SlidesContainer.tsx b/components/Slides/Containers/SlidesContainer.tsx index 8c2814f..64e3d61 100644 --- a/components/Slides/Containers/SlidesContainer.tsx +++ b/components/Slides/Containers/SlidesContainer.tsx @@ -22,9 +22,14 @@ interface SlidesContainerProps { const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo }: SlidesContainerProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0, isCity: true }); - const [vocal, setVocal] = React.useState(VocalFemale.CURRENT_COND); + const [vocal, setVocal] = React.useState(null); const [headerWillUpdate, setHeaderUpdate] = React.useState(false); + const SetVocalDebounce = (vocal: VocalMale | VocalFemale) => { + setVocal(vocal); + setTimeout(() => setVocal(null), 500); + }; + const [cityInfo, setCityInfo] = React.useState>(extraCityInfo); const [currentCity, setCurrentCity] = React.useState(locInfo.city); const [currentInfo, setCurrentInfo] = React.useState(mainCityInfo); @@ -61,6 +66,7 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo }: S location={currentCity} currentCityInfo={currentInfo} introNeeded={locInfo.city === currentCity} + setVocal={SetVocalDebounce} />; case Slides.HEALTH: return ; diff --git a/hooks/useSlides.ts b/hooks/useSlides.ts index afaf5cf..af7525d 100644 --- a/hooks/useSlides.ts +++ b/hooks/useSlides.ts @@ -1,3 +1,4 @@ +import { VocalMale, VocalFemale } from "../components/VocalAudio"; import type { ExtraInfo } from "./useWeather"; export const enum Slides { @@ -18,6 +19,7 @@ export interface SlideProps { currentCityInfo?: ExtraInfo next?: () => void location?: string + setVocal?: (vocal: VocalMale | VocalFemale) => void } export interface MainSlideProps extends SlideProps { From 88f08f68552febd18e6362c8a7cd3110ecaacbb1 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Tue, 15 Nov 2022 14:15:44 -0700 Subject: [PATCH 21/55] Add missing file --- .../Containers/Slides/City/CityInfo/Near.tsx | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 components/Slides/Containers/Slides/City/CityInfo/Near.tsx diff --git a/components/Slides/Containers/Slides/City/CityInfo/Near.tsx b/components/Slides/Containers/Slides/City/CityInfo/Near.tsx new file mode 100644 index 0000000..54d6f26 --- /dev/null +++ b/components/Slides/Containers/Slides/City/CityInfo/Near.tsx @@ -0,0 +1,23 @@ +import * as React from "react"; +import FrostPane from "../../FrostPane"; + +const Forecast = () => ( +
+ +
+
+ +
+); + +export default Forecast; From eb27d227699fd610652d4daa0f6f448ce8cddf03 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Mon, 21 Nov 2022 16:40:56 -0700 Subject: [PATCH 22/55] Return a promise for vocals and allow custom units --- components/Display.tsx | 22 +++++++++++++++---- .../Slides/City/CityInfo/Detailed.tsx | 8 ++++++- .../Containers/Slides/City/CityInfo/index.tsx | 6 +++-- .../Slides/Containers/SlidesContainer.tsx | 11 +++++++--- hooks/useSlides.ts | 2 +- hooks/useWeather.ts | 14 ++++++++++-- pages/index.tsx | 9 ++++++++ 7 files changed, 59 insertions(+), 13 deletions(-) diff --git a/components/Display.tsx b/components/Display.tsx index 7e4fc72..8e80d6a 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -1,5 +1,12 @@ import * as React from "react"; -import type { Location, ExtraLocation, ExtraInfo, CurrentCond, Alert } from "../hooks/useWeather"; +import type { + TemperatureUnit, + Location, + ExtraLocation, + ExtraInfo, + CurrentCond, + Alert +} from "../hooks/useWeather"; import { defaults, currentDefaults, @@ -47,10 +54,11 @@ interface DisplayProps { winSize: number[] location: string language: string + units: TemperatureUnit setMainVol: React.Dispatch> } -const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayProps) => { +const Display = ({ isReady, winSize, location, language, units, setMainVol }: DisplayProps) => { const [innerWidth, innerHeight] = winSize; const mainRef = React.useRef(); @@ -101,7 +109,10 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr const fetchCurrent = (lat: number, lon: number) : Promise => { return new Promise((resolve, reject) => { - getCurrentCond(lat, lon, { language }).then(data => { + getCurrentCond(lat, lon, { + language, + units + }).then(data => { setCurrentInfo(data); resolve(data); }).catch(err => reject(err)); @@ -124,7 +135,10 @@ const Display = ({ isReady, winSize, location, language, setMainVol }: DisplayPr latLonMap.set(latLon, location.displayName); } - const extras = await getExtraCond(queryLatLons, { language }); + const extras = await getExtraCond(queryLatLons, { + language, + units + }); for (const [key, value] of Object.entries(extras)) { console.log(key); const displayName = latLonMap.get(key); diff --git a/components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx b/components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx index 84d3c5c..585c3d9 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx @@ -1,16 +1,22 @@ import * as React from "react"; import type { ExtraInfo } from "../../../../../../hooks/useWeather"; +import { VocalMale, VocalFemale } from "../../../../../VocalAudio"; import { Icons2010, getIcon } from "../../../../../../hooks/useIconMap"; import { motion } from "framer-motion"; import FrostPane from "../../FrostPane"; interface DetailedProps { info?: ExtraInfo + setVocal?: (vocal: VocalMale | VocalFemale) => Promise } -const Detailed = ({ info }: DetailedProps) => { +const Detailed = ({ info, setVocal }: DetailedProps) => { const [icon, setIcon] = React.useState(Icons2010.UNK); + React.useEffect(() => { + setVocal(VocalFemale.CURRENT_COND); + }, []); + React.useEffect(() => { console.log(info); }, [info]); diff --git a/components/Slides/Containers/Slides/City/CityInfo/index.tsx b/components/Slides/Containers/Slides/City/CityInfo/index.tsx index 377e999..1d4c8fe 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/index.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/index.tsx @@ -33,8 +33,10 @@ const SlideCityInfo = ({ next, location, currentCityInfo, setVocal }: SlideProps className="transform translate-x-0 translate-y-60px scale-x-114-5 scale-y-100 origin-left absolute whitespace-nowrap font-frutiger57-cond pt-noreport-t pl-tempunavailable-l text-white text-tempunavailable text-shadow z-noreport" >Temporarily Unavailable; case 2: - setVocal(VocalFemale.CURRENT_COND); - return ; + return ; default: return null; } diff --git a/components/Slides/Containers/SlidesContainer.tsx b/components/Slides/Containers/SlidesContainer.tsx index 64e3d61..ecfa6e2 100644 --- a/components/Slides/Containers/SlidesContainer.tsx +++ b/components/Slides/Containers/SlidesContainer.tsx @@ -25,9 +25,14 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo }: S const [vocal, setVocal] = React.useState(null); const [headerWillUpdate, setHeaderUpdate] = React.useState(false); - const SetVocalDebounce = (vocal: VocalMale | VocalFemale) => { - setVocal(vocal); - setTimeout(() => setVocal(null), 500); + const SetVocalDebounce = (vocal: VocalMale | VocalFemale) : Promise => { + return new Promise(resolve => { + setVocal(vocal); + setTimeout(() => { + setVocal(null); + resolve(); + }, 500); + }); }; const [cityInfo, setCityInfo] = React.useState>(extraCityInfo); diff --git a/hooks/useSlides.ts b/hooks/useSlides.ts index af7525d..9bb6b48 100644 --- a/hooks/useSlides.ts +++ b/hooks/useSlides.ts @@ -19,7 +19,7 @@ export interface SlideProps { currentCityInfo?: ExtraInfo next?: () => void location?: string - setVocal?: (vocal: VocalMale | VocalFemale) => void + setVocal?: (vocal: VocalMale | VocalFemale) => Promise } export interface MainSlideProps extends SlideProps { diff --git a/hooks/useWeather.ts b/hooks/useWeather.ts index d55e814..568fbba 100644 --- a/hooks/useWeather.ts +++ b/hooks/useWeather.ts @@ -1,8 +1,16 @@ import * as React from "react"; import { Icons2010 } from "./useIconMap"; +export enum TemperatureUnit { + ENGLISH = "e", + METRIC = "m", + HYBRID = "h", + METRIC_SI = "s" +} + interface APIOptions { language?: string + units?: TemperatureUnit } // Mapped location @@ -261,7 +269,8 @@ export const getExtraLocations = async (lat: number, lon: number, options?: APIO */ export const getCurrentCond = async (lat: number, lon: number, options?: APIOptions) => { const apiLanguage = options.language || "en-US"; - return fetch(`https://api.weather.com/v3/aggcommon/v3-wx-observations-current?geocode=${lat},${lon}&language=${apiLanguage}&units=s&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) + const apiUnits = options.units || TemperatureUnit.METRIC_SI; + return fetch(`https://api.weather.com/v3/aggcommon/v3-wx-observations-current?geocode=${lat},${lon}&language=${apiLanguage}&units=${apiUnits}&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) .then(async (res: Response) => { return res.json().then(data => { const dataLoc = data["v3-wx-observations-current"]; @@ -301,12 +310,13 @@ interface CurrentConds { */ export const getExtraCond = async (latLons: string[], options?: APIOptions) => { const apiLanguage = options.language || "en-US"; + const apiUnits = options.units || TemperatureUnit.METRIC_SI; let baseUrl = "https://api.weather.com/v3/aggcommon/v3-wx-observations-current?geocodes="; for (let i = 0; i < latLons.length; i++) { const latLon = latLons[i]; baseUrl += `${latLon};`; } - baseUrl += `&language=${apiLanguage}&units=s&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`; + baseUrl += `&language=${apiLanguage}&units=${apiUnits}&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`; const conds = await fetch(baseUrl) .then(async (res: Response) => { return res.json().then(data => { diff --git a/pages/index.tsx b/pages/index.tsx index 0d688dc..d741cc1 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,5 +1,6 @@ import * as React from "react"; import { useRouter } from "next/router"; +import { TemperatureUnit } from "../hooks/useWeather"; import { AudioPlayerProvider } from "react-use-audio-player"; import MusicAudio from "../components/MusicAudio"; @@ -14,6 +15,7 @@ const Index = () => { const [loading, setLoading] = React.useState(true); const [location, setLocation] = React.useState(""); const [language, setLanguage] = React.useState("en-US"); + const [units, setUnits] = React.useState(TemperatureUnit.METRIC_SI); const [innerWidth, innerHeight] = useWinSizeInner(); const [introDone, setIntroDone] = React.useState(false); @@ -27,6 +29,7 @@ const Index = () => { if (!isReady) return; const location = query.location as string; const language = query.language as string; + const units = query.units as TemperatureUnit; // Custom location if (location !== undefined && location !== null) { @@ -38,6 +41,11 @@ const Index = () => { setLanguage(language); } + // Custom units + if (units !== undefined && units !== null) { + setUnits(units); + } + setLoading(false); }, [isReady]); @@ -54,6 +62,7 @@ const Index = () => { winSize={[innerWidth, innerHeight]} location={location} language={language} + units={units} setMainVol={setMusicVol} /> From 98dba3ebbb692020165fef2c8ab641eefd148dc1 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Thu, 8 Dec 2022 21:37:20 -0700 Subject: [PATCH 23/55] Move unavailable messages into files --- .../Slides/City/CityInfo/NoReport.tsx | 18 +++++++++++++++ .../Slides/City/CityInfo/Unavailable.tsx | 18 +++++++++++++++ .../Containers/Slides/City/CityInfo/index.tsx | 22 ++++--------------- 3 files changed, 40 insertions(+), 18 deletions(-) create mode 100644 components/Slides/Containers/Slides/City/CityInfo/NoReport.tsx create mode 100644 components/Slides/Containers/Slides/City/CityInfo/Unavailable.tsx diff --git a/components/Slides/Containers/Slides/City/CityInfo/NoReport.tsx b/components/Slides/Containers/Slides/City/CityInfo/NoReport.tsx new file mode 100644 index 0000000..7cc1db1 --- /dev/null +++ b/components/Slides/Containers/Slides/City/CityInfo/NoReport.tsx @@ -0,0 +1,18 @@ +import * as React from "react"; +import { motion } from "framer-motion"; + +const NoReport = () => ( + + Temporarily Unavailable + +); + +export default NoReport; diff --git a/components/Slides/Containers/Slides/City/CityInfo/Unavailable.tsx b/components/Slides/Containers/Slides/City/CityInfo/Unavailable.tsx new file mode 100644 index 0000000..7306a78 --- /dev/null +++ b/components/Slides/Containers/Slides/City/CityInfo/Unavailable.tsx @@ -0,0 +1,18 @@ +import * as React from "react"; +import { motion } from "framer-motion"; + +const Unavailable = () => ( + + Temporarily Unavailable + +); + +export default Unavailable; diff --git a/components/Slides/Containers/Slides/City/CityInfo/index.tsx b/components/Slides/Containers/Slides/City/CityInfo/index.tsx index 1d4c8fe..0fa2087 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/index.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/index.tsx @@ -3,6 +3,8 @@ import type { SlideProps } from "../../../../../../hooks/useSlides"; import { SlideshowReducer, Slides, ActionType } from "../../../../../../hooks/useSlides"; import { VocalMale, VocalFemale } from "../../../../../VocalAudio"; import { motion, AnimatePresence } from "framer-motion"; +import NoReport from "./NoReport"; +import Unavailable from "./Unavailable"; import Detailed from "./Detailed"; import Near from "./Near"; @@ -13,25 +15,9 @@ const SlideCityInfo = ({ next, location, currentCityInfo, setVocal }: SlideProps console.log("Rendering new city info slide"); switch (slideState.index) { case 0: - return No Report; + return ; case 1: - return Temporarily Unavailable; + return ; case 2: return Date: Fri, 9 Dec 2022 00:25:15 -0700 Subject: [PATCH 24/55] Better intro handling --- .../Slides/Containers/Headers/SlideHeader.tsx | 7 ++++--- .../Containers/Headers/SlideHeaderScroll.tsx | 9 ++++++--- .../Containers/Slides/City/CityInfo/index.tsx | 20 ++++++++++++------- .../Slides/Containers/Slides/City/index.tsx | 15 +++++++++----- .../Slides/Containers/SlidesContainer.tsx | 16 ++++++++++++--- hooks/useSlides.ts | 4 +++- 6 files changed, 49 insertions(+), 22 deletions(-) diff --git a/components/Slides/Containers/Headers/SlideHeader.tsx b/components/Slides/Containers/Headers/SlideHeader.tsx index 33796db..c941fe6 100644 --- a/components/Slides/Containers/Headers/SlideHeader.tsx +++ b/components/Slides/Containers/Headers/SlideHeader.tsx @@ -4,13 +4,14 @@ import SlideHeaderScroll from "./SlideHeaderScroll"; interface SlideHeaderProps { locations: string[] willUpdate: boolean - cycleCallback: (selected: string) => void + startCallback?: (toSelect: string) => void + finishCallback?: (selected: string) => void } -const SlideHeader = ({ locations, willUpdate, cycleCallback }: SlideHeaderProps) => ( +const SlideHeader = ({ locations, willUpdate, startCallback, finishCallback }: SlideHeaderProps) => ( <>
- +
diff --git a/components/Slides/Containers/Headers/SlideHeaderScroll.tsx b/components/Slides/Containers/Headers/SlideHeaderScroll.tsx index fca5de9..88cec83 100644 --- a/components/Slides/Containers/Headers/SlideHeaderScroll.tsx +++ b/components/Slides/Containers/Headers/SlideHeaderScroll.tsx @@ -14,10 +14,11 @@ interface ItemsRef { interface SlideHeaderScrollProps { locations: string[] willUpdate: boolean - cycleCallback: (selected: string) => void + startCallback?: (toSelect: string) => void + finishCallback?: (selected: string) => void } -const SlideHeaderScroll = ({ locations, willUpdate, cycleCallback }: SlideHeaderScrollProps) => { +const SlideHeaderScroll = ({ locations, willUpdate, startCallback, finishCallback }: SlideHeaderScrollProps) => { const [loaded, setLoaded] = React.useState(false); const [list, setList] = React.useState(locations); const [shiftNeeded, setShiftNeeded] = React.useState(false); @@ -48,11 +49,13 @@ const SlideHeaderScroll = ({ locations, willUpdate, cycleCallback }: SlideHeader const cityRefWidth = getWidth(current.city, "full"); const arrowRefWidth = getWidth(current.arrow, "full"); + startCallback(items[1].city.innerHTML); + controls.start({ left: `${-1.06*(cityRefWidth + arrowRefWidth)}px`, transition: { duration: 0.9 } }).then(() => { - cycleCallback(items[1].city.innerHTML); + finishCallback(items[1].city.innerHTML); setShiftNeeded(true); controls.set({ left: null }); }); diff --git a/components/Slides/Containers/Slides/City/CityInfo/index.tsx b/components/Slides/Containers/Slides/City/CityInfo/index.tsx index 0fa2087..ad5f387 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/index.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/index.tsx @@ -15,14 +15,12 @@ const SlideCityInfo = ({ next, location, currentCityInfo, setVocal }: SlideProps console.log("Rendering new city info slide"); switch (slideState.index) { case 0: - return ; - case 1: - return ; - case 2: return ; + case 1: + return ; default: return null; } @@ -30,11 +28,19 @@ const SlideCityInfo = ({ next, location, currentCityInfo, setVocal }: SlideProps React.useEffect(() => { let timeout = setTimeout(() => { - slideDispatch({ type: ActionType.INCREASE, payload: 1 }); - if (slideState.index >= 2) setTimeout(() => { + /* if (slideState.index >= 1) setTimeout(() => { next(); slideDispatch({ type: ActionType.SET, payload: 0 }); - }, 800); + }, 800); */ + if (slideState.index >= 1) { + console.log("Slide state index is over 1"); + next(); + slideDispatch({ type: ActionType.SET, payload: 0 }); + return; + } + + console.log("Slide state dispatch increase"); + slideDispatch({ type: ActionType.INCREASE, payload: 1 }); }, 8000); return () => clearTimeout(timeout); }, [slideState.index]); diff --git a/components/Slides/Containers/Slides/City/index.tsx b/components/Slides/Containers/Slides/City/index.tsx index c44c4a8..040c542 100644 --- a/components/Slides/Containers/Slides/City/index.tsx +++ b/components/Slides/Containers/Slides/City/index.tsx @@ -1,21 +1,26 @@ import * as React from "react"; import type { MainSlideProps } from "../../../../../hooks/useSlides"; -import { SlideshowReducer, SlidesCity, ActionType } from "../../../../../hooks/useSlides"; +import { SlideshowReducer, SlidesCity, ActionType, SlideProps } from "../../../../../hooks/useSlides"; import CityIntro from "./CityIntro"; import CityInfo from "./CityInfo"; -const City = ({ next, location, currentCityInfo, introNeeded, setVocal }: MainSlideProps) => { - const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: introNeeded ? 0 : 1 }); +const City = ({ next, location, currentCityInfo, isLoaded = false, setLoaded, setVocal }: MainSlideProps) => { + const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0 }); + + React.useEffect(() => { + if (!isLoaded) setLoaded(true); + }, []); const SlideCallback = React.useCallback(() => { if (slideState.index >= 1) { next(); - slideDispatch({ type: ActionType.SET, payload: introNeeded ? 0 : 1 }); + slideDispatch({ type: ActionType.SET, payload: 2 }); + setTimeout(() => slideDispatch({ type: ActionType.SET, payload: isLoaded ? 1 : 0 }), 900); } else { slideDispatch({ type: ActionType.INCREASE, payload: 1 }); } - }, [slideState.index, introNeeded]); + }, [slideState.index, isLoaded]); const currentSlide = React.useMemo(() => { console.log("Rendering new city slide"); diff --git a/components/Slides/Containers/SlidesContainer.tsx b/components/Slides/Containers/SlidesContainer.tsx index ecfa6e2..a89f4a2 100644 --- a/components/Slides/Containers/SlidesContainer.tsx +++ b/components/Slides/Containers/SlidesContainer.tsx @@ -39,10 +39,17 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo }: S const [currentCity, setCurrentCity] = React.useState(locInfo.city); const [currentInfo, setCurrentInfo] = React.useState(mainCityInfo); const [header, setHeader] = React.useState([]); + const [cityIntroLoaded, setCityIntroLoaded] = React.useState(false); const SlideCallback = React.useCallback(() => setHeaderUpdate(true), [slideState.index]); - const HeaderCallback = (selected: string) => { + const HeaderStartCallback = (toSelect: string) => { + //const introNeeded = locInfo.city === toSelect; + //console.log(introNeeded); + //setIntroNeeded(introNeeded); + }; + + const HeaderFinishCallback = (selected: string) => { console.log("Header cycle complete"); console.log(selected); const selectedInfo = cityInfo.get(selected); @@ -54,6 +61,7 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo }: S slideDispatch({ type: ActionType.SET_CITY, payloadCity: false }); slideDispatch({ type: ActionType.INCREASE, payload: 1 }); } + setHeaderUpdate(false); }; @@ -70,7 +78,8 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo }: S next={SlideCallback} location={currentCity} currentCityInfo={currentInfo} - introNeeded={locInfo.city === currentCity} + isLoaded={cityIntroLoaded} + setLoaded={setCityIntroLoaded} setVocal={SetVocalDebounce} />; case Slides.HEALTH: @@ -102,7 +111,8 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo }: S ...header.slice().reverse() ]} willUpdate={headerWillUpdate} - cycleCallback={HeaderCallback} + startCallback={HeaderStartCallback} + finishCallback={HeaderFinishCallback} />}
diff --git a/hooks/useSlides.ts b/hooks/useSlides.ts index 9bb6b48..adbaced 100644 --- a/hooks/useSlides.ts +++ b/hooks/useSlides.ts @@ -1,3 +1,4 @@ +import * as React from "react"; import { VocalMale, VocalFemale } from "../components/VocalAudio"; import type { ExtraInfo } from "./useWeather"; @@ -23,7 +24,8 @@ export interface SlideProps { } export interface MainSlideProps extends SlideProps { - introNeeded?: boolean + isLoaded?: boolean + setLoaded?: React.Dispatch> } export const enum ActionType { From 3368c7d8fe1fcaaa6524e6bb9f90d538953080c5 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Fri, 9 Dec 2022 15:24:27 -0700 Subject: [PATCH 25/55] Use cached init param --- components/Display.tsx | 3 +++ components/Slides/Containers/Slides/City/index.tsx | 2 +- components/Slides/Containers/SlidesContainer.tsx | 9 +++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/components/Display.tsx b/components/Display.tsx index 8e80d6a..9d9edc3 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -59,6 +59,7 @@ interface DisplayProps { } const Display = ({ isReady, winSize, location, language, units, setMainVol }: DisplayProps) => { + const [cityIntroLoaded, setCityIntroLoaded] = React.useState(false); const [innerWidth, innerHeight] = winSize; const mainRef = React.useRef(); @@ -234,6 +235,8 @@ const Display = ({ isReady, winSize, location, language, units, setMainVol }: Di locInfo={locInfo} mainCityInfo={currentExtra} extraCityInfo={extraInfo} + introLoaded={cityIntroLoaded} + setIntroLoaded={setCityIntroLoaded} />} {locInfo.timezone !== "" && } {locInfo.city !== "" &&
{ - const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0 }); + const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: isLoaded ? 1 : 0 }); React.useEffect(() => { if (!isLoaded) setLoaded(true); diff --git a/components/Slides/Containers/SlidesContainer.tsx b/components/Slides/Containers/SlidesContainer.tsx index a89f4a2..471b982 100644 --- a/components/Slides/Containers/SlidesContainer.tsx +++ b/components/Slides/Containers/SlidesContainer.tsx @@ -18,9 +18,11 @@ interface SlidesContainerProps { locInfo?: Partial mainCityInfo?: ExtraInfo extraCityInfo?: Map + introLoaded: boolean + setIntroLoaded: React.Dispatch> } -const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo }: SlidesContainerProps) => { +const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo, introLoaded, setIntroLoaded }: SlidesContainerProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0, isCity: true }); const [vocal, setVocal] = React.useState(null); const [headerWillUpdate, setHeaderUpdate] = React.useState(false); @@ -39,7 +41,6 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo }: S const [currentCity, setCurrentCity] = React.useState(locInfo.city); const [currentInfo, setCurrentInfo] = React.useState(mainCityInfo); const [header, setHeader] = React.useState([]); - const [cityIntroLoaded, setCityIntroLoaded] = React.useState(false); const SlideCallback = React.useCallback(() => setHeaderUpdate(true), [slideState.index]); @@ -78,8 +79,8 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo }: S next={SlideCallback} location={currentCity} currentCityInfo={currentInfo} - isLoaded={cityIntroLoaded} - setLoaded={setCityIntroLoaded} + isLoaded={introLoaded} + setLoaded={setIntroLoaded} setVocal={SetVocalDebounce} />; case Slides.HEALTH: From 1dbe175484e83cdb3656c7ac2710118951a91a6f Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Fri, 9 Dec 2022 17:30:36 -0700 Subject: [PATCH 26/55] Set custom slides dynamically --- .../Containers/Slides/Airports/index.tsx | 2 +- .../Slides/City/CityInfo/Detailed.tsx | 4 ++-- .../Containers/Slides/City/CityInfo/Near.tsx | 4 ++-- .../Containers/Slides/City/CityInfo/index.tsx | 11 +++++---- .../Slides/Containers/Slides/City/index.tsx | 7 +++++- .../Slides/Containers/Slides/Health/index.tsx | 2 +- .../Containers/Slides/International/index.tsx | 2 +- .../Slides/Containers/Slides/Travel/index.tsx | 2 +- .../Slides/Containers/SlidesContainer.tsx | 24 +++++++++++++++---- hooks/useSlides.ts | 2 +- 10 files changed, 41 insertions(+), 19 deletions(-) diff --git a/components/Slides/Containers/Slides/Airports/index.tsx b/components/Slides/Containers/Slides/Airports/index.tsx index d5d4220..f0492b9 100644 --- a/components/Slides/Containers/Slides/Airports/index.tsx +++ b/components/Slides/Containers/Slides/Airports/index.tsx @@ -7,7 +7,7 @@ const Airports = ({ next }: SlideProps) => { return () => clearTimeout(timeout); }, []); - return
; + return
; }; export default Airports; diff --git a/components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx b/components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx index 585c3d9..f243232 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/Detailed.tsx @@ -1,8 +1,8 @@ import * as React from "react"; +import { motion } from "framer-motion"; import type { ExtraInfo } from "../../../../../../hooks/useWeather"; import { VocalMale, VocalFemale } from "../../../../../VocalAudio"; import { Icons2010, getIcon } from "../../../../../../hooks/useIconMap"; -import { motion } from "framer-motion"; import FrostPane from "../../FrostPane"; interface DetailedProps { @@ -110,7 +110,7 @@ const Detailed = ({ info, setVocal }: DetailedProps) => { >
{info.current && <>
( -
+
( id="content" className="font-frutiger57-cond h-frost-pane-content max-h-frost-pane-content transform -translate-x-2.5 -translate-y-2.5 scale-x-115 scale-y-100 origin-left tracking-frost-pane-content" style={{ fontSize: "52px" }} - /> + >This project is open source
); diff --git a/components/Slides/Containers/Slides/City/CityInfo/index.tsx b/components/Slides/Containers/Slides/City/CityInfo/index.tsx index ad5f387..54334b4 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/index.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/index.tsx @@ -33,27 +33,30 @@ const SlideCityInfo = ({ next, location, currentCityInfo, setVocal }: SlideProps slideDispatch({ type: ActionType.SET, payload: 0 }); }, 800); */ if (slideState.index >= 1) { - console.log("Slide state index is over 1"); next(); slideDispatch({ type: ActionType.SET, payload: 0 }); return; } - console.log("Slide state dispatch increase"); slideDispatch({ type: ActionType.INCREASE, payload: 1 }); }, 8000); return () => clearTimeout(timeout); }, [slideState.index]); return ( -
{currentSlide} -
+ ); }; diff --git a/components/Slides/Containers/Slides/City/index.tsx b/components/Slides/Containers/Slides/City/index.tsx index ff9b90d..28a6db8 100644 --- a/components/Slides/Containers/Slides/City/index.tsx +++ b/components/Slides/Containers/Slides/City/index.tsx @@ -1,4 +1,5 @@ import * as React from "react"; +import { AnimatePresence } from "framer-motion"; import type { MainSlideProps } from "../../../../../hooks/useSlides"; import { SlideshowReducer, SlidesCity, ActionType, SlideProps } from "../../../../../hooks/useSlides"; @@ -37,7 +38,11 @@ const City = ({ next, location, currentCityInfo, isLoaded = false, setLoaded, se } }, [slideState.index, SlideCallback, location, currentCityInfo]); - return currentSlide; + return ( + + {currentSlide} + + ); }; export default City; diff --git a/components/Slides/Containers/Slides/Health/index.tsx b/components/Slides/Containers/Slides/Health/index.tsx index 07773e7..30904cd 100644 --- a/components/Slides/Containers/Slides/Health/index.tsx +++ b/components/Slides/Containers/Slides/Health/index.tsx @@ -7,7 +7,7 @@ const Health = ({ next }: SlideProps) => { return () => clearTimeout(timeout); }, []); - return
; + return
; }; export default Health; diff --git a/components/Slides/Containers/Slides/International/index.tsx b/components/Slides/Containers/Slides/International/index.tsx index 80805b6..29b0418 100644 --- a/components/Slides/Containers/Slides/International/index.tsx +++ b/components/Slides/Containers/Slides/International/index.tsx @@ -7,7 +7,7 @@ const International = ({ next }: SlideProps) => { return () => clearTimeout(timeout); }) - return
; + return
; }; export default International; diff --git a/components/Slides/Containers/Slides/Travel/index.tsx b/components/Slides/Containers/Slides/Travel/index.tsx index 3e04c7d..d390cc4 100644 --- a/components/Slides/Containers/Slides/Travel/index.tsx +++ b/components/Slides/Containers/Slides/Travel/index.tsx @@ -7,7 +7,7 @@ const Travel = ({ next }: SlideProps) => { return () => clearTimeout(timeout); }, []); - return
; + return
; }; export default Travel; diff --git a/components/Slides/Containers/SlidesContainer.tsx b/components/Slides/Containers/SlidesContainer.tsx index 471b982..0cf9ae0 100644 --- a/components/Slides/Containers/SlidesContainer.tsx +++ b/components/Slides/Containers/SlidesContainer.tsx @@ -53,17 +53,30 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo, int const HeaderFinishCallback = (selected: string) => { console.log("Header cycle complete"); console.log(selected); + setHeaderUpdate(false); + const selectedInfo = cityInfo.get(selected); if (selectedInfo !== undefined) { setCurrentCity(selected); setCurrentInfo(selectedInfo); slideDispatch({ type: ActionType.SET, payload: 0, payloadCity: true }); - } else { - slideDispatch({ type: ActionType.SET_CITY, payloadCity: false }); - slideDispatch({ type: ActionType.INCREASE, payload: 1 }); + return; } - setHeaderUpdate(false); + // Check for slide currently selected + const found = Object.entries(Slides).find(([key, value]) => key === selected.toUpperCase()); + if (found) { + const [slideKey, slideIdx] = found; + slideDispatch({ + type: ActionType.SET, + payload: slideIdx as number, + payloadCity: false + }); + return; + } + + slideDispatch({ type: ActionType.SET_CITY, payloadCity: false }); + slideDispatch({ type: ActionType.INCREASE, payload: 1 }); }; React.useEffect(() => { @@ -109,7 +122,8 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo, int ...header, "Airports", "International", - ...header.slice().reverse() + ...header.slice().reverse(), + "Travel" ]} willUpdate={headerWillUpdate} startCallback={HeaderStartCallback} diff --git a/hooks/useSlides.ts b/hooks/useSlides.ts index adbaced..4f0f38e 100644 --- a/hooks/useSlides.ts +++ b/hooks/useSlides.ts @@ -2,7 +2,7 @@ import * as React from "react"; import { VocalMale, VocalFemale } from "../components/VocalAudio"; import type { ExtraInfo } from "./useWeather"; -export const enum Slides { +export enum Slides { CITY, HEALTH, TRAVEL, From 03c894eeb705efb6b615c0209c823c73c1f7ede3 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sat, 10 Dec 2022 01:49:02 -0700 Subject: [PATCH 27/55] Marquee changes --- components/Display.tsx | 10 ++++++++-- components/Marquee.tsx | 17 +++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/components/Display.tsx b/components/Display.tsx index 9d9edc3..d8ff519 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -251,8 +251,14 @@ const Display = ({ isReady, winSize, location, language, units, setMainVol }: Di /> {focusedAlert && (
- - {top} + + {top.text} - - {bottom} + + {bottom.text} ); From 517d9b52148b4a7367f0d0f51bc2dc80cafe59a4 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sun, 11 Dec 2022 00:00:59 -0700 Subject: [PATCH 28/55] Insert random extra location in header --- .../Slides/Containers/SlidesContainer.tsx | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/components/Slides/Containers/SlidesContainer.tsx b/components/Slides/Containers/SlidesContainer.tsx index 0cf9ae0..57bfb44 100644 --- a/components/Slides/Containers/SlidesContainer.tsx +++ b/components/Slides/Containers/SlidesContainer.tsx @@ -22,6 +22,12 @@ interface SlidesContainerProps { setIntroLoaded: React.Dispatch> } +const getRandomIdx = (max?: number, min?: number) => { + const minIdx = min ?? 0; + const maxIdx = max ?? 5; + return Math.floor(Math.random() * (maxIdx - minIdx) + minIdx); +}; + const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo, introLoaded, setIntroLoaded }: SlidesContainerProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0, isCity: true }); const [vocal, setVocal] = React.useState(null); @@ -41,6 +47,7 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo, int const [currentCity, setCurrentCity] = React.useState(locInfo.city); const [currentInfo, setCurrentInfo] = React.useState(mainCityInfo); const [header, setHeader] = React.useState([]); + const [random, setRandom] = React.useState(""); const SlideCallback = React.useCallback(() => setHeaderUpdate(true), [slideState.index]); @@ -83,6 +90,21 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo, int setHeader(Array.from(cityInfo.keys())); }, [cityInfo]); + React.useEffect(() => { + if (header && header.length > 0) { + const headLength = header.length; + const idx = getRandomIdx(headLength); + let rand = header[idx]; + + while (rand === locInfo.city) { + const tempIdx = getRandomIdx(headLength); + rand = header[tempIdx]; + } + + setRandom(rand); + } + }, [header]); + const currentSlide = React.useMemo(() => { if (currentCity && currentInfo) { console.log("Rendering new slide"); @@ -114,11 +136,12 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo, int return (
- {(cityInfo && header.length > 0) && 0 && random !== "") && Date: Sun, 11 Dec 2022 00:31:23 -0700 Subject: [PATCH 29/55] Detect extra location function and update severe marquees --- components/Display.tsx | 9 +++++++-- components/Marquee.tsx | 4 ++-- components/MarqueeSevere.tsx | 14 +++++--------- .../Slides/Containers/Slides/Airports/index.tsx | 2 +- .../Slides/Containers/Slides/Health/index.tsx | 2 +- .../Containers/Slides/International/index.tsx | 2 +- .../Slides/Containers/Slides/Travel/index.tsx | 2 +- components/Slides/Containers/SlidesContainer.tsx | 14 +++++++++++++- 8 files changed, 31 insertions(+), 18 deletions(-) diff --git a/components/Display.tsx b/components/Display.tsx index d8ff519..afb97c8 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -261,8 +261,13 @@ const Display = ({ isReady, winSize, location, language, units, setMainVol }: Di }} /> {focusedAlert && }
); diff --git a/components/Marquee.tsx b/components/Marquee.tsx index 7a306f5..f103c4b 100644 --- a/components/Marquee.tsx +++ b/components/Marquee.tsx @@ -32,12 +32,12 @@ import Marquee from "./CustomMarquee"; } */ -interface InfoMarqueeSection { +export interface InfoMarqueeSection { text: string duration?: number } -interface InfoMarqueeProps { +export interface InfoMarqueeProps { top: InfoMarqueeSection bottom: InfoMarqueeSection } diff --git a/components/MarqueeSevere.tsx b/components/MarqueeSevere.tsx index f9c6c43..60f90ae 100644 --- a/components/MarqueeSevere.tsx +++ b/components/MarqueeSevere.tsx @@ -1,20 +1,16 @@ import * as React from "react"; import Marquee from "./CustomMarquee"; +import { InfoMarqueeProps } from "./Marquee"; -interface MarqueeSevereProps { - top: string - bottom: string -} - -const MarqueeSevere = ({ top, bottom }: MarqueeSevereProps) => ( +const MarqueeSevere = ({ top, bottom }: InfoMarqueeProps) => ( <>
- {top} + {top.text}
- + - {bottom} + {bottom.text} diff --git a/components/Slides/Containers/Slides/Airports/index.tsx b/components/Slides/Containers/Slides/Airports/index.tsx index f0492b9..c6b3236 100644 --- a/components/Slides/Containers/Slides/Airports/index.tsx +++ b/components/Slides/Containers/Slides/Airports/index.tsx @@ -7,7 +7,7 @@ const Airports = ({ next }: SlideProps) => { return () => clearTimeout(timeout); }, []); - return
; + return
Airports
; }; export default Airports; diff --git a/components/Slides/Containers/Slides/Health/index.tsx b/components/Slides/Containers/Slides/Health/index.tsx index 30904cd..d8df450 100644 --- a/components/Slides/Containers/Slides/Health/index.tsx +++ b/components/Slides/Containers/Slides/Health/index.tsx @@ -7,7 +7,7 @@ const Health = ({ next }: SlideProps) => { return () => clearTimeout(timeout); }, []); - return
; + return
Health
; }; export default Health; diff --git a/components/Slides/Containers/Slides/International/index.tsx b/components/Slides/Containers/Slides/International/index.tsx index 29b0418..3dbba9b 100644 --- a/components/Slides/Containers/Slides/International/index.tsx +++ b/components/Slides/Containers/Slides/International/index.tsx @@ -7,7 +7,7 @@ const International = ({ next }: SlideProps) => { return () => clearTimeout(timeout); }) - return
; + return
International
; }; export default International; diff --git a/components/Slides/Containers/Slides/Travel/index.tsx b/components/Slides/Containers/Slides/Travel/index.tsx index d390cc4..e4d9754 100644 --- a/components/Slides/Containers/Slides/Travel/index.tsx +++ b/components/Slides/Containers/Slides/Travel/index.tsx @@ -7,7 +7,7 @@ const Travel = ({ next }: SlideProps) => { return () => clearTimeout(timeout); }, []); - return
; + return
Travel
; }; export default Travel; diff --git a/components/Slides/Containers/SlidesContainer.tsx b/components/Slides/Containers/SlidesContainer.tsx index 57bfb44..acee0a5 100644 --- a/components/Slides/Containers/SlidesContainer.tsx +++ b/components/Slides/Containers/SlidesContainer.tsx @@ -49,6 +49,15 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo, int const [header, setHeader] = React.useState([]); const [random, setRandom] = React.useState(""); + const isExtraLoc = (location: string) => { + const extraLoc = extraCityInfo.get(location); + if (extraLoc !== undefined) { + return location !== locInfo.city; + } + + return false; + }; + const SlideCallback = React.useCallback(() => setHeaderUpdate(true), [slideState.index]); const HeaderStartCallback = (toSelect: string) => { @@ -95,10 +104,13 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo, int const headLength = header.length; const idx = getRandomIdx(headLength); let rand = header[idx]; + console.log(rand); - while (rand === locInfo.city) { + while (!isExtraLoc(rand)) { + console.warn("Encountered main location when setting random - rerolling"); const tempIdx = getRandomIdx(headLength); rand = header[tempIdx]; + console.log(rand); } setRandom(rand); From 1881a5fa35a6edee02efe235f86a2ff2931d8621 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sun, 11 Dec 2022 17:59:18 -0700 Subject: [PATCH 30/55] Add TTS to severe marquees and option to mute --- components/Display.tsx | 9 +++-- components/MarqueeSevere.tsx | 65 ++++++++++++++++++++++++++++-------- pages/index.tsx | 9 +++++ 3 files changed, 66 insertions(+), 17 deletions(-) diff --git a/components/Display.tsx b/components/Display.tsx index afb97c8..d2ccc5f 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -55,10 +55,11 @@ interface DisplayProps { location: string language: string units: TemperatureUnit + muteSevere: boolean setMainVol: React.Dispatch> } -const Display = ({ isReady, winSize, location, language, units, setMainVol }: DisplayProps) => { +const Display = ({ isReady, winSize, location, language, units, muteSevere, setMainVol }: DisplayProps) => { const [cityIntroLoaded, setCityIntroLoaded] = React.useState(false); const [innerWidth, innerHeight] = winSize; const mainRef = React.useRef(); @@ -260,14 +261,16 @@ const Display = ({ isReady, winSize, location, language, units, setMainVol }: Di duration: 12 }} /> - {focusedAlert && } ); diff --git a/components/MarqueeSevere.tsx b/components/MarqueeSevere.tsx index 60f90ae..aef74f1 100644 --- a/components/MarqueeSevere.tsx +++ b/components/MarqueeSevere.tsx @@ -2,19 +2,56 @@ import * as React from "react"; import Marquee from "./CustomMarquee"; import { InfoMarqueeProps } from "./Marquee"; -const MarqueeSevere = ({ top, bottom }: InfoMarqueeProps) => ( - <> -
- {top.text} -
-
- - - {bottom.text} - - -
- -); +interface InfoMarqueeSevereProps extends InfoMarqueeProps { + mute: boolean + setMainVol: React.Dispatch> +} + +const MarqueeSevere = ({ top, bottom, mute, setMainVol }: InfoMarqueeSevereProps) => { + const [utterance, setUtterance] = React.useState( + new SpeechSynthesisUtterance() + ); + const [speech, setSpeech] = React.useState("A severe weather warning is in your area."); + + const tts = React.useCallback((message: string) => { + if (utterance) { + utterance.text = message; + //utterance.pitch = 3 / 5; + speechSynthesis.speak(utterance); + + utterance.onstart = () => setMainVol(0.25); + utterance.onend = () => setMainVol(1); + } + }, [utterance, setMainVol]); + + React.useEffect(() => { + let interval: NodeJS.Timer; + if (typeof window !== undefined) { + if (!mute && speech && speech !== "") { + tts(speech); + interval = setInterval(() => tts(speech), 13500); + } + } + return () => { + speechSynthesis.cancel(); + clearInterval(interval); + }; + }, [mute, speech]); + + return ( + <> +
+ {top.text} +
+
+ + + {bottom.text} + + +
+ + ); +}; export default MarqueeSevere; diff --git a/pages/index.tsx b/pages/index.tsx index d741cc1..8a9e99e 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -12,10 +12,13 @@ import { useWinSizeInner } from "../hooks/useWinSize"; const Index = () => { const { isReady, query } = useRouter(); + const [loading, setLoading] = React.useState(true); const [location, setLocation] = React.useState(""); const [language, setLanguage] = React.useState("en-US"); const [units, setUnits] = React.useState(TemperatureUnit.METRIC_SI); + const [muteSevere, setMuteSevere] = React.useState(false); + const [innerWidth, innerHeight] = useWinSizeInner(); const [introDone, setIntroDone] = React.useState(false); @@ -30,6 +33,7 @@ const Index = () => { const location = query.location as string; const language = query.language as string; const units = query.units as TemperatureUnit; + const muteSevere = query.muteSevere as string; // Custom location if (location !== undefined && location !== null) { @@ -46,6 +50,10 @@ const Index = () => { setUnits(units); } + if (muteSevere !== undefined && muteSevere !== null) { + setMuteSevere(Boolean(muteSevere)); + } + setLoading(false); }, [isReady]); @@ -63,6 +71,7 @@ const Index = () => { location={location} language={language} units={units} + muteSevere={muteSevere} setMainVol={setMusicVol} /> From 06cf4b7f2274771acc1739e38577827d921fbc55 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sun, 11 Dec 2022 21:44:25 -0700 Subject: [PATCH 31/55] Add window check inside of cleanup function --- components/MarqueeSevere.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/MarqueeSevere.tsx b/components/MarqueeSevere.tsx index aef74f1..5b295c4 100644 --- a/components/MarqueeSevere.tsx +++ b/components/MarqueeSevere.tsx @@ -29,11 +29,13 @@ const MarqueeSevere = ({ top, bottom, mute, setMainVol }: InfoMarqueeSevereProps if (typeof window !== undefined) { if (!mute && speech && speech !== "") { tts(speech); - interval = setInterval(() => tts(speech), 13500); + interval = setInterval(() => tts(speech), 21500); } } return () => { - speechSynthesis.cancel(); + if (typeof window !== undefined) { + speechSynthesis.cancel(); + } clearInterval(interval); }; }, [mute, speech]); From c0552d73275329929f2f4b29d7374005f640835f Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sun, 11 Dec 2022 22:19:25 -0700 Subject: [PATCH 32/55] Lazy load individual slides --- .../Slides/Containers/SlidesContainer.tsx | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/components/Slides/Containers/SlidesContainer.tsx b/components/Slides/Containers/SlidesContainer.tsx index acee0a5..57f47da 100644 --- a/components/Slides/Containers/SlidesContainer.tsx +++ b/components/Slides/Containers/SlidesContainer.tsx @@ -7,11 +7,22 @@ import VocalAudio from "../../../components/VocalAudio"; import { SlideshowReducer, Slides, ActionType } from "../../../hooks/useSlides"; -import City from "./Slides/City"; -import Health from "./Slides/Health"; -import Travel from "./Slides/Travel"; -import Airports from "./Slides/Airports"; -import International from "./Slides/International"; +// Lazy load individual slides +const City = React.lazy(() => import( + "./Slides/City" /* webpackChunkName: "citySlide", webpackPreload: true */ +)); +const Health = React.lazy(() => import( + "./Slides/Health" /* webpackChunkName: "healthSlide", webpackPreload: true */ +)); +const Travel = React.lazy(() => import( + "./Slides/Travel" /* webpackChunkName: "travelSlide", webpackPreload: true */ +)); +const Airports = React.lazy(() => import( + "./Slides/Airports" /* webpackChunkName: "airportsSlide", webpackPreload: true */ +)); +const International = React.lazy(() => import( + "./Slides/International" /* webpackChunkName: "intSlide", webpackPreload: true */ +)); interface SlidesContainerProps { setMainVol: React.Dispatch> From 4b516fb2b015c5a88bd712758a7ad265ec31b16f Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sun, 11 Dec 2022 22:45:43 -0700 Subject: [PATCH 33/55] Add suspense to lazy loading slides --- components/Slides/Containers/SlidesContainer.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/Slides/Containers/SlidesContainer.tsx b/components/Slides/Containers/SlidesContainer.tsx index 57f47da..222ec01 100644 --- a/components/Slides/Containers/SlidesContainer.tsx +++ b/components/Slides/Containers/SlidesContainer.tsx @@ -179,7 +179,9 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo, int - {currentSlide} + Loading...}> + {currentSlide} + ); From 9d4406b03187c21ee2114591bf3d4b823e902dbf Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sun, 11 Dec 2022 23:14:32 -0700 Subject: [PATCH 34/55] Add extended forecast boilerplate --- .../Slides/Containers/Slides/City/CityInfo/Extended.tsx | 8 ++++++++ .../Slides/Containers/Slides/City/CityInfo/index.tsx | 7 +++++-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 components/Slides/Containers/Slides/City/CityInfo/Extended.tsx diff --git a/components/Slides/Containers/Slides/City/CityInfo/Extended.tsx b/components/Slides/Containers/Slides/City/CityInfo/Extended.tsx new file mode 100644 index 0000000..8cae2e5 --- /dev/null +++ b/components/Slides/Containers/Slides/City/CityInfo/Extended.tsx @@ -0,0 +1,8 @@ +import * as React from "react"; + +// Extended forecasts +const Extended = () => ( +
Extended
+); + +export default Extended; diff --git a/components/Slides/Containers/Slides/City/CityInfo/index.tsx b/components/Slides/Containers/Slides/City/CityInfo/index.tsx index 54334b4..87b3380 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/index.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/index.tsx @@ -7,6 +7,7 @@ import NoReport from "./NoReport"; import Unavailable from "./Unavailable"; import Detailed from "./Detailed"; import Near from "./Near"; +import Extended from "./Extended"; const SlideCityInfo = ({ next, location, currentCityInfo, setVocal }: SlideProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0 }); @@ -21,6 +22,8 @@ const SlideCityInfo = ({ next, location, currentCityInfo, setVocal }: SlideProps />; case 1: return ; + case 2: + return ; default: return null; } @@ -28,11 +31,11 @@ const SlideCityInfo = ({ next, location, currentCityInfo, setVocal }: SlideProps React.useEffect(() => { let timeout = setTimeout(() => { - /* if (slideState.index >= 1) setTimeout(() => { + /* if (slideState.index >= 2) setTimeout(() => { next(); slideDispatch({ type: ActionType.SET, payload: 0 }); }, 800); */ - if (slideState.index >= 1) { + if (slideState.index >= 2) { next(); slideDispatch({ type: ActionType.SET, payload: 0 }); return; From 9a85cc7fcd05764d176614a7c19e4aee4ecc4a35 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Mon, 12 Dec 2022 14:17:32 -0700 Subject: [PATCH 35/55] Add more lazy loading and severe beeps --- components/Display.tsx | 21 +++++++---- components/MarqueeSevere.tsx | 21 ++++++++--- .../Slides/City/CityInfo/Extended.tsx | 5 +++ .../Containers/Slides/City/CityInfo/Near.tsx | 2 +- .../Containers/Slides/City/CityInfo/index.tsx | 35 ++++++++++++------ .../Slides/Containers/Slides/City/index.tsx | 10 +++-- .../Slides/Containers/SlidesContainer.tsx | 16 +++++--- hooks/useSlides.ts | 9 ++++- pages/index.tsx | 4 ++ public/vocals/beepmuffled.mp3 | Bin 0 -> 113324 bytes 10 files changed, 87 insertions(+), 36 deletions(-) create mode 100644 public/vocals/beepmuffled.mp3 diff --git a/components/Display.tsx b/components/Display.tsx index d2ccc5f..b1d3d05 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -26,7 +26,10 @@ import CCIcon from "./CCIcon"; import Current from "./Current"; import LogoArea from "./LogoArea"; import InfoMarquee from "./Marquee"; -import MarqueeSevere from "./MarqueeSevere"; +//import MarqueeSevere from "./MarqueeSevere"; +const MarqueeSevere = React.lazy(() => import( + "./MarqueeSevere" /* webpackChunkName: "marqueeSevere" */ +)); const resizeWindow = ( mainRef: React.MutableRefObject, @@ -51,6 +54,7 @@ const resizeWindow = ( interface DisplayProps { isReady: boolean + debug: boolean winSize: number[] location: string language: string @@ -59,7 +63,7 @@ interface DisplayProps { setMainVol: React.Dispatch> } -const Display = ({ isReady, winSize, location, language, units, muteSevere, setMainVol }: DisplayProps) => { +const Display = ({ isReady, debug, winSize, location, language, units, muteSevere, setMainVol }: DisplayProps) => { const [cityIntroLoaded, setCityIntroLoaded] = React.useState(false); const [innerWidth, innerHeight] = winSize; const mainRef = React.useRef(); @@ -132,7 +136,7 @@ const Display = ({ isReady, winSize, location, language, units, muteSevere, setM for (let i = 0; i < data.length; i++) { const location = data[i]; const latLon = `${location.lat},${location.lon}`; - console.log(latLon); + if (debug) console.log(latLon); queryLatLons.push(latLon); latLonMap.set(latLon, location.displayName); } @@ -142,9 +146,11 @@ const Display = ({ isReady, winSize, location, language, units, muteSevere, setM units }); for (const [key, value] of Object.entries(extras)) { - console.log(key); const displayName = latLonMap.get(key); - console.log(displayName, value); + if (debug) { + console.log(key); + console.log(displayName, value); + } const latLon = key.split(","); tempMap.set(displayName, { details: { @@ -214,11 +220,11 @@ const Display = ({ isReady, winSize, location, language, units, muteSevere, setM }, [alerts.length]); React.useEffect(() => { - console.log(currentExtra); + if (debug) console.log(currentExtra); }, [currentExtra]); React.useEffect(() => { - console.log(extraInfo); + if (debug) console.log(extraInfo); }, [extraInfo]); /* @@ -232,6 +238,7 @@ const Display = ({ isReady, winSize, location, language, units, muteSevere, setM background {(isReady && locInfo && currentExtra && extraInfo.size !== 0) && { + const beep = new Audio("/vocals/beepmuffled.mp3"); const [utterance, setUtterance] = React.useState( new SpeechSynthesisUtterance() ); @@ -15,21 +16,29 @@ const MarqueeSevere = ({ top, bottom, mute, setMainVol }: InfoMarqueeSevereProps const tts = React.useCallback((message: string) => { if (utterance) { - utterance.text = message; - //utterance.pitch = 3 / 5; - speechSynthesis.speak(utterance); + setMainVol(0.25); - utterance.onstart = () => setMainVol(0.25); - utterance.onend = () => setMainVol(1); + beep.play(); + beep.onended = () => { + utterance.text = message; + //utterance.pitch = 3 / 5; + speechSynthesis.speak(utterance); + + utterance.onend = () => setMainVol(1); + }; } }, [utterance, setMainVol]); + React.useEffect(() => { + if (top.text !== "") setSpeech(`A ${top.text.toLowerCase()} is in your area.`); + }, [top.text]); + React.useEffect(() => { let interval: NodeJS.Timer; if (typeof window !== undefined) { if (!mute && speech && speech !== "") { tts(speech); - interval = setInterval(() => tts(speech), 21500); + interval = setInterval(() => tts(speech), 31500); } } return () => { diff --git a/components/Slides/Containers/Slides/City/CityInfo/Extended.tsx b/components/Slides/Containers/Slides/City/CityInfo/Extended.tsx index 8cae2e5..87fad68 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/Extended.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/Extended.tsx @@ -1,4 +1,9 @@ import * as React from "react"; +import type { ExtraInfo } from "../../../../../../hooks/useWeather"; + +interface ExtendedProps { + info?: ExtraInfo +} // Extended forecasts const Extended = () => ( diff --git a/components/Slides/Containers/Slides/City/CityInfo/Near.tsx b/components/Slides/Containers/Slides/City/CityInfo/Near.tsx index d17fe1f..87cfbfa 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/Near.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/Near.tsx @@ -15,7 +15,7 @@ const Forecast = () => ( id="content" className="font-frutiger57-cond h-frost-pane-content max-h-frost-pane-content transform -translate-x-2.5 -translate-y-2.5 scale-x-115 scale-y-100 origin-left tracking-frost-pane-content" style={{ fontSize: "52px" }} - >This project is open source + >Near ); diff --git a/components/Slides/Containers/Slides/City/CityInfo/index.tsx b/components/Slides/Containers/Slides/City/CityInfo/index.tsx index 87b3380..74e4f83 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/index.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/index.tsx @@ -1,28 +1,38 @@ import * as React from "react"; import type { SlideProps } from "../../../../../../hooks/useSlides"; +import { SlidesCityInfo } from "../../../../../../hooks/useSlides"; import { SlideshowReducer, Slides, ActionType } from "../../../../../../hooks/useSlides"; import { VocalMale, VocalFemale } from "../../../../../VocalAudio"; import { motion, AnimatePresence } from "framer-motion"; -import NoReport from "./NoReport"; -import Unavailable from "./Unavailable"; -import Detailed from "./Detailed"; -import Near from "./Near"; -import Extended from "./Extended"; +// import NoReport from "./NoReport"; +// import Unavailable from "./Unavailable"; +// import Detailed from "./Detailed"; +// import Near from "./Near"; +// import Extended from "./Extended"; +const Detailed = React.lazy(() => import( + "./Detailed" /* webpackChunkName: "citySlideCurrent" */ +)); +const Near = React.lazy(() => import( + "./Near" /* webpackChunkName: "citySlideNear" */ +)); +const Extended = React.lazy(() => import( + "./Extended" /* webpackChunkName: "citySlideExtended" */ +)); -const SlideCityInfo = ({ next, location, currentCityInfo, setVocal }: SlideProps) => { +const SlideCityInfo = ({ next, debug, location, currentCityInfo, setVocal }: SlideProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0 }); const currentSlide = React.useMemo(() => { - console.log("Rendering new city info slide"); + if (debug) console.log("Rendering new city info slide"); switch (slideState.index) { - case 0: + case SlidesCityInfo.DETAILED: return ; - case 1: + case SlidesCityInfo.NEAR: return ; - case 2: + case SlidesCityInfo.EXTENDED: return ; default: return null; @@ -31,11 +41,12 @@ const SlideCityInfo = ({ next, location, currentCityInfo, setVocal }: SlideProps React.useEffect(() => { let timeout = setTimeout(() => { - /* if (slideState.index >= 2) setTimeout(() => { + const numSlides = Object.keys(SlidesCityInfo).length / 2; + /* if (slideState.index >= (numSlides - 1)) setTimeout(() => { next(); slideDispatch({ type: ActionType.SET, payload: 0 }); }, 800); */ - if (slideState.index >= 2) { + if (slideState.index >= (numSlides - 1)) { next(); slideDispatch({ type: ActionType.SET, payload: 0 }); return; diff --git a/components/Slides/Containers/Slides/City/index.tsx b/components/Slides/Containers/Slides/City/index.tsx index 28a6db8..9a579ce 100644 --- a/components/Slides/Containers/Slides/City/index.tsx +++ b/components/Slides/Containers/Slides/City/index.tsx @@ -6,7 +6,7 @@ import { SlideshowReducer, SlidesCity, ActionType, SlideProps } from "../../../. import CityIntro from "./CityIntro"; import CityInfo from "./CityInfo"; -const City = ({ next, location, currentCityInfo, isLoaded = false, setLoaded, setVocal }: MainSlideProps) => { +const City = ({ next, debug, location, currentCityInfo, isLoaded = false, setLoaded, setVocal }: MainSlideProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: isLoaded ? 1 : 0 }); React.useEffect(() => { @@ -14,7 +14,8 @@ const City = ({ next, location, currentCityInfo, isLoaded = false, setLoaded, se }, []); const SlideCallback = React.useCallback(() => { - if (slideState.index >= 1) { + const numSlides = Object.keys(SlidesCity).length / 2; + if (slideState.index >= (numSlides - 1)) { next(); slideDispatch({ type: ActionType.SET, payload: 2 }); setTimeout(() => slideDispatch({ type: ActionType.SET, payload: isLoaded ? 1 : 0 }), 900); @@ -24,17 +25,20 @@ const City = ({ next, location, currentCityInfo, isLoaded = false, setLoaded, se }, [slideState.index, isLoaded]); const currentSlide = React.useMemo(() => { - console.log("Rendering new city slide"); + if (debug) console.log("Rendering new city slide"); switch (slideState.index) { case SlidesCity.INTRO: return ; case SlidesCity.INFO: return ; + default: + return null; } }, [slideState.index, SlideCallback, location, currentCityInfo]); diff --git a/components/Slides/Containers/SlidesContainer.tsx b/components/Slides/Containers/SlidesContainer.tsx index 222ec01..6bc440b 100644 --- a/components/Slides/Containers/SlidesContainer.tsx +++ b/components/Slides/Containers/SlidesContainer.tsx @@ -25,6 +25,7 @@ const International = React.lazy(() => import( )); interface SlidesContainerProps { + debug: boolean setMainVol: React.Dispatch> locInfo?: Partial mainCityInfo?: ExtraInfo @@ -39,7 +40,7 @@ const getRandomIdx = (max?: number, min?: number) => { return Math.floor(Math.random() * (maxIdx - minIdx) + minIdx); }; -const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo, introLoaded, setIntroLoaded }: SlidesContainerProps) => { +const SlidesContainer = ({ debug, setMainVol, locInfo, mainCityInfo, extraCityInfo, introLoaded, setIntroLoaded }: SlidesContainerProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0, isCity: true }); const [vocal, setVocal] = React.useState(null); const [headerWillUpdate, setHeaderUpdate] = React.useState(false); @@ -78,8 +79,10 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo, int }; const HeaderFinishCallback = (selected: string) => { - console.log("Header cycle complete"); - console.log(selected); + if (debug) { + console.log("Header cycle complete"); + console.log(selected); + } setHeaderUpdate(false); const selectedInfo = cityInfo.get(selected); @@ -115,13 +118,13 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo, int const headLength = header.length; const idx = getRandomIdx(headLength); let rand = header[idx]; - console.log(rand); + if (debug) console.log(rand); while (!isExtraLoc(rand)) { console.warn("Encountered main location when setting random - rerolling"); const tempIdx = getRandomIdx(headLength); rand = header[tempIdx]; - console.log(rand); + if (debug) console.log(rand); } setRandom(rand); @@ -130,11 +133,12 @@ const SlidesContainer = ({ setMainVol, locInfo, mainCityInfo, extraCityInfo, int const currentSlide = React.useMemo(() => { if (currentCity && currentInfo) { - console.log("Rendering new slide"); + if (debug) console.log("Rendering new slide"); switch (slideState.index) { case Slides.CITY: return void + debug?: boolean location?: string setVocal?: (vocal: VocalMale | VocalFemale) => Promise } diff --git a/pages/index.tsx b/pages/index.tsx index 8a9e99e..d281ee4 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -67,6 +67,10 @@ const Index = () => { 1{`JLTiKKq0KfIS2N1PW(lW@A6c z#m&o)5f&Afl$N`ssI01?rE^8!(A3=0%G&OxqqD1rm#=?dNLWN9AtsKLoR*Q5lUG#y zprov#w!X2swY{sS_gUY-$k@d6?ELb|>g%@~+k5Xnem*!n`u+FhpCo4@JD-UxEA_AO zKMDpS{9n~GIsWe7_#apQbN-J8{(q@~Gk#qF%m)B~=h@$f0sxF?004M)RGc->s&WJX z0BodTtRs8IJ@(pv%Kvd1_>Xb^k2A^tPJ#Zz@BdD1|1WsffB5}hpw$0+e)2#3{@-J( z|5nof@cZAY<^L}i|66{sMtcCJqY(-{00*Q1z;Zr9a;=x;TV-#lUi#$`|jr1+kt8`)+AXxfq`ROvFbXPqS zb2g?{PUf38GFptTc5pD0E@sHvn2dTc-Ly5qF{eM5X4t>dGOOop3?HbOHDyZurQI-X z>d7##8$7vwF?E-cIlC5_b^%&3f6G5jGInwS!#*WVYdzoVYb+JFw}_E8w!G4^)KX%M z*IQq1u`&+96~FLzN%J4eUG}I*yFQ*eza~D#5wkdRd@=P10GQsoJo%P(W%8q)(FBn^ zUBSo5JBnHe51vvPpe!izG4cn^H_6%|-0V52N#&Z4E&y0LVSH{r}MqLBelOnW} z!~K(!ik1wWx|3rocT>G+4+hr^CPm^1T*5*~Cu=7c-W_?zHJ9* z={4QP*m3V{b`nJsbxTUUYA_CPD^y*G!f)x_qAS$pg7WSasCwqeU8DsMqZ=q zsj5O(l@%7C$SAS8|4)(q_6W!%Td9TjxU{{Auuv|Rt-gVE)9Q?uVHv<6WSsl07v^H+ zCd=diV*z{4R{XL7kIa2R{YB%_BV3$+BJv7~(4LP<3Um5O`R_A$rdFPJYAs;kG)L&z zl*^xI#VN6x;&*5CC6BkknBg+*dglTZtE49nb`rbZ!_Nq1d(7YzDnXoPm^ zNXnT$P+eUqKd0FHoB)!jV;7ogLEg~5!!-o$C(nllUW*Oq-a#7 z#f(;HJSgP&O(c0unJL-#eXbv`p1WZTE4`=;1=U*O50AO^j?hZp1Ztq?6QWkmt1wEx z>w|-T2L~L;j8f(h+{vHt#7|3cYtgk5YJcSrW z$+k9!af&?&#xQ4{&1Gi?9NFR~Sd)l^y}{xzjlug`@8kzwgVoU5HY`5!L?l6VkU< z@q$ScwbYHc!goCWPQc0AcsF4wZ^i(-a}~uXmPq3mWMn)7qWZgUuA%ljJW4G1iDlNg zFV?(((SjCszdz&TFdNT2N63DnAi2*BVo8uZ4<}xe=U$K=7p$ z;{iha2pChno%Od$W^2ki_VA;Vi~}KkRcf?BeLQjWS*jpSE1CksI^n=mW$$XV48SuG z>H4&Jwxf^hbAsA#bqU&fe2NOD(vEBl7&;)QIcGyA5HvMjvYs3V@LYFx8lLq`6oKDu zkvTl(564QtQOi)7aoPryZ1oIhd@^qw0KDRXy*_gy>&pmdERi;))RZ{tWLc7yQf;wv zx8A%|?C0o?b8#Ya?UT^m1f%x8_(83K1bP~o1?CDZwPJ+o&VtN`4AmS~)L0HJSf*`C zl&|kw#RGAZ6f^-e2igUZCZXlXl69IFpA3ZnMjq*~2;iM553F?GmQ5ma7U-64ZEG<| z({%p+(4L)_&$Xtp_hti3Wp5p&uRU0o?{d#PbQ_)#-_~Jz@`bzdWqkj;4|CsR9)==% zZiK!55V#f`;D7-VO(QGmus%x`SKTZ$|-FS(pslu3r=iADD*YB#+516 zaq&)t*H7YX_(CH!wN+1g%&J2%YDdW5l7dy8IG9;>s@IbJv0PP}_cru$AUOKnr`Of* z{$6Syi|W`&cs=0xtrB3QGlxF@J3~D_!kwzHaC8a>b8XI;i?e&0%5D}9mQqcJ#cA3f zJBr$fcNhpZNPE#kbrQS21bYGFwVG7?UGrUkATz~3{^()pTuN%VvYpTvE}u}6xGXwo z@6Rrl+bD09i6hiJxGtM*BeLH5_}5gbY-^`jR?<&F?f1bwC^fNbLK9vt$Cu{fczhIR z)yL(_?<4F|bpPHPM9!`pX7B1jew*pUrCiVHFcao?eCVS$r46oFeSG7v4NXebu|KC_ zWAPEHUj<8@dsF*j|3NoNze=f5CX%`4E010Ro5r$#a2+F71&6Dq1(p$DD}XY0PTY>s zfy!3QYkZkjw$V_Vs(EUw06(gRd+8s)5(HR{{(z4=4peEFFk8J25Po^*!pqkHP*ml+ zYIz)>Nd9QjF^CWQ6QrnX^g8I_+M8I}t0sj932rT|J=W~HdPX6955V@NA4#PFvIwvC zKs1J36Wb0)j05y7J7_tuLns_vzd}w~WFW?X1_2#Ny^6rGff0N;-^e>2h^$~R%F$^! zUW){CZ@q3rp>(L>n*pkvgi{(rCXoip2_>!2ASwAl49VuT^uMKI#`u*m-=62 zLh5C`JC|3NbDES~r=Rna<<=3~4$ieI9MBQ*R?o@Z{MG9>*FU^$BrTusZmY48cHvmG(sDEA*t56CLb&~Ld>s==bFweERD<7oqub`upiO5 z_Q~O8xA7|*U)6z7U)wk8e@?CiuHa_5j3}wZI1~^d-!jo6F+v#y@socsaOzzyjIu)k zE}+_kQDgc|GiwQ7@I)?l+FW~{?c-Ez*MuBgT)KP;C(X^a96X)GW(p$F zYBJ4xPt@>z;SYbnhLC-qS`?xU6Y^QUXI6$B2B1;vS%-Ugkd_d>HB*zF7e7+?Xved* z7{kG3baxSY(OF)fcF&H4CntSmXT^h2*bQ9S%gHSCZ5=19K#EJev!(_x`>R`viz!O( zru=tE6YYAPAy~#N@tkElUgD$l`in^7Vxrh0(sN2nzf6~W|} zdHE6inmdY%M~pU$0JYG#ryv45uwTb=Gg{!43>3d`(<8tp%|}O6>d_q}!llql_+@T@ z3)U6bnkM`!Z%~ zIy%1BIUfamkU(g7Gu)N(S9-UjPu|a#RHKmM}U7Cf3pfTsdQ*pIkyF}UmBFK;kxS3sY{vNkyJq5vSvsf;} z!imDGymb9y(_z)QRvHzvF0H$P+N$%QfC@coPzSbZ!l3%5_RRRFMxQ;4UKPi#?R~-1 zJ`9L9^l}_IPoRKWtfMYGRk)by(0RUK-*e36V;ggaJgjL;n#t2+xhVN?bGmS?kv*Dv z8g!G2F9;Z>2*lX(Mcd-{Xh;<@Ns_q!;a47Lr8qPOF_vr&Sc$$GG|QIg()+=QOSW(chz$9#A4>4vBp`M zi^>TCyTJ*AOM;w8(v)oQf&Xt^te2j zkv4YLZ8Gr|S`hrBWZkr6Ka-cc3y1RZ7n7*`z`&=iSjvA|CF3n>%+(H)k`xx@(gZrK zXVNGrGhH^>K35sAtRHhBK~~ffx^a2zmL}4)ro&!Ar>O^z1Bk=~2`;=)PkDAu!r7n$ z&pWsgrmgKGI^(}{qqXUO0K_4qTxIzgV7$3>P~DI@*=nXXjC^cd;A4~LJWb(#$~VykFk=d|1{IQ}nYP8cIE0pi*b3 zr=8ZXzIpNcU5M!AxccyP{>9tZcTyui*#3&7J3ov`cu1Wj|E8KoJ$s%b76GC?Qz0-G zP>Zw0lieJxOZaIgp**x`3yn1zK!1xrld1{I1xyA3m=*TbWdDNNkjt8SPEJ!IDg7pzI_%Yn%YP^ ziKLl?!A*Pn{VN-VIdgHVNPVH2j&nkQ(l;m!z|chz*dT+?WT^u+d`zp78+PZTMSL#% zVDFpqQHG`HPEbr`dn)+Jh(*|q;p{4LV|IhbO-Q+%&V8ZRP)4rC<3C z-7G5o!}ErjOUY`_pN3iKQU8q}o7AsPX|<-OS7y)0pa1n}CyO=c)5pKL`*y8gx9mt? zjh$&8E8CdNqHh5RyB9RSd#JAF$;>d{i9HVvqLL_~lv2kBFjV09?`v9wW2gfZ763*o z67(373DcVSv?=FK_+IUkOnAc2-jMc?s>1OfVh&#GdxL%E`m3ZDU$sDYP@^_JX0r_Z zNGP2y$u12fU-RRBryju~$K)EVU)>_tOA=95P~QAc*c($<7v{Xf$&TywKN)CrFFmfj zoYL8kICQd}&;=EREkq&mHHDEX0w#=iO zQ9UwqL6L|v9$HVlRR4>C!ELc+=TeE_58}~!_g=?K;s&I4EYi-0lE`5*PJekSv-frV zMsqh-H_gQ7rdYUdHukT`dJHg*6CjAKHk|A`2*zF4PQ2>~JjtJMG!c-b9rpmkW2VAj@zuh8kR7O?&U6!sguhMe~%Dxag3N2ErQS8_@ z`gH$t-h1b_C-2?P8$K|a52XTMI8^KaxnI5feB+#yuX(ww_KWKdqOA&lzZUxL`n{c8 z`qVQ`yHj(WsLrlu*nHToH5d(6M=09TGLV$-e48E(dNz)Y(ITLXV3M*>u!f^5loh3m zA@IjKJqTi@jfD_OF(~BK0+w5x@RT?Rj&fN90?2{%q4khXoCvr8=PRdz2;)p7&I^z$ zKm+^+pdBNS0| zS+OsLPI0M(kF;>(mAlDzqf(7*;Tv|wACWU008^`Gj&$6ucQV?tU6WNF?|jjvV>i%` z#2Z#C4zlIT4kUk-eY<$y#Q5_XWt4OJP5E|Mz~k0X@Y?%{2c5YEa1ie76VZ{I`P z{H3uy@_**GM<45UHjn`TquuNd(rnobg!D~b0hl`nx^=XZPRkiJ(_22gHGFP%r#V5fiMFiIEI&8^NTG`n%f zh%IMwTX`MJB-p1Twi!@~7VElNu05W+l+tM~e~G8*Q=*?( ze&W#mH~cD8ztAxIt&N!<9E1q^Z26R0c50%b8AH0FdWVg zE%cIe!g&%X0LLdf*8mN)8%x(Lr6o5`^5e&UOZAG?M>R{#yr@z7( z^)>)?y_C|h-UOY^(r}qO%v`f^fs4su4eQnl2ll2Q6R(DaE-Ff3}7Oj##2NzSaPG5-q5LNHn-LsE;|7TdKHY#1tfBa&I5qAS;R=d^KbKn2g z^VM6dI+?iab4O>~PpV>Raw?qLAOaXmz_Ku@84lfN*Wwc(O4(uVzszecXV5%zW~Arm zWJ#8$CNacne871ut3PoJBr za$Tcz7;P7~LWbxBYYq{KIXX!VM{&9|3JrYlMkpGa*b%dI$R)r%ae>WuWh@EpFM z-rQL=Untnqd3m8_O2RXoPVHd$ow;71gN(O+l97z#mpvQ@3rlRq}U?%Celi$8A^be`KS%?nO) zJzP9aa9u@fz(4L=snPi@Nd2`e>q}Dg4Hf|T3hUK^1>mvSTsZQLhCZTXa3`tpJqazQ zQn1wD^>Rf^?0q;|>Jf{z!ntP%q895@TG7*!x4$LqPcC9naWEKKsN&ZB^JgI+lllQV z4Nf^L1c36C9zenQqr`x9^up^%!&Ew4w|FW&fyZ!>Y!6E&=2oQ*Ss(%3Ua!{oh%~X< zBJx@AGz}~Oom%)=rk%ytGhU9g<63DZQz?P3mlAUgfg$~n@mx#__@0tsiN+fpmt2rc zj93@lS7G@%@)kCnWtWQDp+b3`LiTOBWuOe@)G0Yb23U4?{dS9d?awY$Jc(cBYBM$$ zVr^7=7*a4XdR!pL-gc9{oOy4QFx2#;@sm$MaxaJZ_}e>XwKp_{>$8r61;1Dlu!d=3 z_aAmGUmq7#Q1#$vmi3SbQ7AD~ny97$j67kfdLDtbd#_09w#t*OuG8`QbZT=vE$&Rc zd0#60$mW~Mm6Nw8v?)c@Q@yjX_fy(w+uIP2g6BG>sj?nhJvjSvD95zF5ig=89${>4 zYK?6-7q|XAnCpK>Df&xLF_k*p@I-M)B_QPy3va_?{^^bPFRaodZ+nT#yk2xNzxceN z_wc>m3T3pI$C-sx)!H^pbkDCZ3>ASZuibzcI14DIbrf+LUE-&4h!jkp6#Qn~hnE#G z%CP86X1rgRcCA{=GepfwjVLI{UDVl~w0*@J>R|unl!fuegx$2+;BtYge0BzA*+qX=D}xec zm3MUa%NXWc@S1QOf`iHKk!8Dv=>ivaEA7z&$CALt%tAbrC9{w$noGbU^W>v8d8A}P zG&Jn7=GG`Kmlpzkt{;8J*M=7`L+deS488W5Xf%3Qi>RYx=C6o^yrXzue$Nt1{%sa9 z8+qCGJHII|o-cSZAJLHG|Qxn+{pDEQ|d z1i7K@0ymRq$}~4QX(Fpw&*lqBy1K$fQ}g0STQ;^d1pq-*U`RMkYvxINm+du-#do}? zyf@cf-(mXi?9bVrI`CKQ-sjLOEEzH+?=T3OXfnHa>B3erN$FC?*>{;;CfWrnj)X*l}5AJZwb3wr`$USLF z(si!19ts;yLdwel$}jVakO2DiHO3rF=q|i|G{0lXIPJdnA@cF`%dgO>$?)qFU48Q& zVumt_EViE4NOdEUg}FfQR)upK?s*KEW`Jr3rxf6wp@tL2j|fHt!d@a(k?d-ACC*>>Jw^QFQDmO9IL)|g3wW?mf&EkG zGPgX9yw!IOCdfMndWtTYA=$wB!_v-e; zI}P_HURsz0pAF9}IbGlMLanw?&{|Z{2hw&+lGata7|Gt~-)#Al6Kjd9nX*~);>f=P z49_(zs?#J-&6m=p6qikxvj~KJyZHs3$&rpjwp&dz_`?SiEK!bz2a6kx?lp3TF5I~UtR?*>m@yB*TIpAJ* z$Nd;h-Me(0D1HQ8@KtdM5UWuPgK^)PD-9xHXt^dQRR^)*C{q9!E@p;k=x=LL6oi?I zVCBI>6Igd5>HsR(;q1{=1_TZ7JZnjeDZ;OB;O9`V`^M#E-=Y`*N_U|Bak|c0#$!Gt z5Cq2ml5j6Y0|Yedu%8v)1AwP>Uj^Ybx7aQvE5ngem$1u{p1?l0iVqdm!G>15Uo&Y^ zY_(Qil*nmHY!pJ9N!hPC#E&OZTUhezv{?rWoh3nO)v-Oj91zW4@a!zGns?TlsQvL+ z!Tb=uo&)_3a^)|c&lRm2X z9TrVV5EzfsCMsU6mlC+Y&V=@kyTz*(s)SKpq@uV$=9y5>5u`-~{v z)qQ~C;aYR7KRMpnNVw&!6Lf_25rs=jmm;|Ll6D1^Qw69AeofuMkdTEYPXN|+cCKRd&<0pqMr zf}lA$G1^X<$+S>nLX|Wb!L1CFT>X}aDGlP%H&fMvmN@sB;u!wRe~wqK3Nx`=n|l{R zZ{y}C=^$qF_EP%(Jz~31wNhC%y1#GsnahwS#|CX{yfz%dxEBJ72V+uFUr8b!<@kv_ z^<`nzMR4Q#h?mr}_L~LYIbtDR&LjbI6{*9PAw+w2VJ)Cp8+|@@Yw9iT^BDKn`Vr12 z6!5^?5p#N{X{R~G_XBZFp-%JHTCFD@WHdC)k=Z zs;ooy$9HF2A&R`#mR@$q8P*10U|Pwmxh-jx(;L>@9^dF?qb1Z~C-Gd!+pSSbap8&L zZb7tP)zM_g-4Ea%tw17clK_nO-1a`dmNTA?=i zz1WOJ^O~;!hG{I^>*$Te_pBh=a)I;L#5!*Q``Dqd7B8{qak_<|B?q7aLmk zKlLn!%`)}cY9wN)V-NLmBOb*go*O@L2oG?P)V67m>&{hZEvrFnXTfgQT73wnp$UDc zL}vC`WaY1D;|~3nhnCj7|9ZhU(;qWg&M9}=`P%KJYwJQNBJ$RVNq5YPBhhD^PbSr+ zv-$lTdj*m)%9O#6r;_VvI3AQa@U6a%wPuU0SeMj-_2=Im&S9Z<`sH_f_49AVeYU14 z!AE0$jPG+ZxdhEWP(P2gKO#PB+A|`Kj|s5YYh)^N`{kU$TA|9v)N}dy`@^2x4ae2mOovqO+KDq1oh9oIN6F#Ik9!o<*dU#!s{LIPhO;PAJMD{UBm5&la zzI|6^8wW8HKVeJj&773O56BcOm31Ue2y*H+KP2Is_$FcmT!Fp{c7EUWL2)LELm|0~ ztCq%C@Hs8}x_3>(6fvCwgWa{2$OLGd!rVF0H#g>35q+c!Rk@$uX15@=m@7MDrf$(D z>G(gD`m?=JFtPvUqnO|$)BCG#BMmUKm+e#sDs{E|%HNr<=>z%H=r~P_=-&^$M=rX? zH!spWKlN+2QhD*_^z`PHvrQa0?LCxPW=6J)d6)0Size^7hgz#|n%AT%7T=TC#f!%U zpXgjLA7}hp3~^6-l>d`;2sS?3&Z(yPyzr^#ce?5hm%#sQ1`SR#JoT~ zlO)?B$ioM15^n)?foY;dU{|IVLSLJO2{_DKMN*(i^D#zy zh17|531~f6tDFjPN_>FI4%EGea;UlVVAota5wbSF7(Omqrk`VD%U{dNa-(jOmpi$l zm0Q3#tN7XWxr)zu0-qPJ&t@)1O?wo$Uh&_^wvvwxvtMSX1A@9uxP3Ytzv5X8*ab*< zP6iBV^ONuNVr%OhW$V57xN=Y9;w@bAY9yDlm9xwvnhFmynF$Ao7j6rpEvC@ULIlRw z)0(NVndX)7pk#n|8n*>`E4EX(o`~_W{Z=uw_*M3)==O( zk}eAUTIbO0nl~hC-N!bA*nU~?eRR$1i`w=EME|v4eTgJ#b8&%lCfL)G}0ig=t|EwXbV{=U2$wp3jSF)U3HMZr_eAq*JM5@M9sMdTQC%7^01yt%2YM?ow8 ziUrwt(sLO+H5Qvw6b0|p*Xa__nSy3&!W(26&ztlanmcWeEO-jzfhcP!T7)G~1XvnC z!>l8@#|C_(?T=<<_XNGDu{$qUoKE+TUrm7GVX*0k%X8QWgO|CUHBtO&BUe6eb@y!x z@0eA}*9g_Bc$u;J@!ko&Fm^{a5vdWscBfPCROp8iYG}1yPLnf3E60LEm^E*x!(8n| zWkM2Wy5>cfJ4snLHJysU9InFHRRZOGPsHQ2A)$s2`L_FPfG1qhf;~k{bn>_9pT9~z z{rsr233FGa=EKXW>bvGqy-MQ;&XLgyI8f%uT8%Jl;&Pe*@t}SPZ`G`@OqXEVu{Qi+WZ|lp&0Pm7H^JpHHR{U{Rzq2 z+`!Cfm_5X;&0%`l@j`if!l8fnOPyu6A^9k3&^`Tokp+=mKFwb3yU~J|gWkXTa$SPa zVpDzpZ&Xm=!%E+*Ud1^FJT?FiE`K&pP3{_v-NCITM({w@DbrS>T#){*b}SQ$AKHH>GL>?k#Rk5MEcA` zbrdE7OJv&7AgqXc6%QTCnpc392F4eW^}xoB4#NloleY0onwi6;@Feg?K`&Sh5U1@( zBk3qzi~r^3OCxh#!+u#aDBmUg4=3un4y$1B46?}{i-8dIz?>JoMW0d6yMDHlhnnJJ zV=~Zki-{L!_eyGIHp&FC3xLd9+<0L4{ap`7#Bz8AQ|6S-DakQi10msX{;Gu>=gYgb zJc$*R($0Qpt$chP2T3vczBW8?r}^pn683hB-qdXzeEagMP>xeqSw0j0tcc{J8GBU$ zesd1gcNOdKlq5A5(cM9YW2o%7)m{5fir-<`_l$Ts7JN?Cj$i}o^8fga1Son1%zY@j z>mQozS>afn&c|MF_}TMo->*hD$8NRo!-vPt?~Z;~e|bKvUM1Z?WvtywB47b<1Ffsy z+;pW0x3;Yebc2aXETj6ViL!$ACGK~gvO1>Y@qzX z24I>|K;;Y#6K-ZS4mWdtgyt%M9_Gg(<~mfFcmP0u<049;3)t;S>0PAI{ldhG)Yrdk ze2~lS1|v{^Hm1Cq^-U|@A9XcI_$yzGKw_aX^AGTQoM+dHbmn;dl=e0H-(rP{2Iq)b ztPRrp3^Dp}H26p>!{cM)fb_?(t6MSrrYOOL3!tr5RpYA+>L$0J58g<5tQz*%9%Dr6 zBo7L-V_&UteWUEzzoCRZ7Y)(;3cs4Q=A(N18(1(xEa)$Tp06YWaeCtV^YC zQK^ODm&W^rK-RuLXt+K?%lJ1vM+CLLn!^4#;X9SFuhD6zRQpEPpYH|Yncy!YwWc|I{2Wd8(j{9`E17?SYa1kS3*54Y zUwvJSbkKrdlxM2)4*yamTTi8rMW0i5I6hGiO!NMyJrl3NkP=NrG{|v&LW_=R5_<_8 zLy6f03>YWBleXTXtecg=aE_0iA+B;{Ia4N)WSaA41k*SJN6p_+YjmHcLyFJRyQIOe zU~N{EoD-jkn)bGn$-AZWhAx-itZNUX(S3H>R@?rA;0eXt1vx&u;WkarWB|;KL^j+@ zu5lOPk1`VzxF6osvQ9a$Gs(z>SYCV0S z#Vh{H_RXl2|BI$qXOo8d+_%&#s;kuXUFvb}2zBCW^XZM=!>aQJKnA|Vv+xu^$>czA zv#DI0vq+pLG zv56iddQ9N=w zQEbUduKwC+Ed<+^YQ4`tP)9#>Jbr9X{`llaZnvVQr`r$U<`J}7!8e|`;f5lhhKlALRdju zQnx+giBK8%r7WGy8fE zS4c%`+*hJN?i#5V^5TN+Fx^H;Oo~_g!{-AF@mFH|3ZHlVVd!R)`!e*`Y8*5@eqlxJ zhiXpSQMSOHhxO4ZZcn)%1wLp$cji)jSm!)FeUdXGF}_3ntXlB=`78MO`3GnKP@&SG zOcQi0fg(~qv-MHn&~o&K{2)6kwjuz}sYl8DhLksufOod6RZWy7HZ0XC8bDOJfY+EF zLCVVO0od*KTsLDRWB%Pjr#U0B6wlY7%$FM1D=Hq2Rq%8VpSk9~hdom@UV8HtqTa@R zfstIz0eNy>ZTqTalKj05_ngEUuUz;f_U3Z5{owTeQEpS~jlWWN6mXe|P!5Plj4N_!a8Jmli4%d-()l;JtP&z=@7PkN6mr7I?4VvEUom($3^wjaa*s$w3q2Bc6N{n3N zwqxgmv%JU}3KrSvc19U4pf5K8K+q@wgWQzr9Pv^)@W6Z?1Hi>Nx7y4FZ~-fX1A8kY z3;pQk7_A0oQgQZyihut=7FX1(ADWo8vOZe;y#P^+JeyvX z*L%(N+tb`GiH0(rLIdl$P6e;ZKdFWYxw7Rh2bK6$_AI6^h3@UXI2xbsB>g=%{Wwgv zUL$Hpy>U6`^!fK;W0E@c+tcrM10p{m1gM;X=_75lkW64PQ6?DsDt_+kO2iVv>NN)Kso5n)R8_#{@La zSq6LzREixe>hK3>63#$IbM{f>@cED(Fr@|03aX+Z6g$e8301hvI!ZySASG6g)&LR& zr>83JI$S&)6U&d_OT+0hg2`ZOBrBH<-UDlzi6J0IHGw5)ggi#5l9r}GG>EKxhYZbi z3iuj6;lhMACV{|w1DdFpWzGt6!~homA<<#~E%rod7dlN6jS$!=rWzZk=|scD zM_SK5(_^yCk7x#MSCEnL*Zoi{cCfQ~UY>lE{o<}CHk#gylIf7ix&geTi23Gr1X`Hz)@shoI{Q|nL~*-ANr(4 zZemJZd7Fi8+VaI0zt66zR#)Fpr)1%t-AUBn1CQbEn3_eUmL$1f;FYUO z7iq;4Jbpwa#}&8$flB8b_~KJKenS6d^wm;>fGJIn&E$4Jeg4PqU*H|7z^To(`ES|c zo_f9_4Z__Emz%zb_j8B|&UL7@EUj{ZAviS75mAEgV!+ZTY778@Y%p!DbL2<+`I{GF zrJ;&&ZUzi+Fm{;8bmgEgX_DJRij|uq6HlZOoD?y|*=0&_k8}O11DwSD_H!^LAPMZe zmjD&%*Mh+pP~I-?7%0j|QXboWzsRuPV?!>W zEHQk2wN>kN-EVUMF3cWsJ@jEWC*HAqb>C9<-T;st=(-@cz$!F;&A9S<=tig7%KPTk zSpH_o1Q7L;Kcc*>~V5?=X(q4+Lu1-x4RJz zmvx>`oL+x(`uk1K;={Lp9xeYRJ^L6n-QY0W0{;0D5tmG>4badda@R^vMEouva$-4X&$rMu2#_sS z2hRPTP*an7PW>JiN|P2Kk8!oN7>O20soIjTrY}R3kfQ6}jua9ZBtLRdsrOF49B)!j z`6Bhl#DW1dXdnPc49B9N03yKygHj-J5(o^ab1^m~N89t3EH9rhkTgX(e?YlY49>F9 zS7h8I&Y|SwkRTf1I$p#Y;i=r60hVlQsSOhrT*Q^FbRAt@0E3Wb3>~0=zch3Z zypGfS))xO}vf!z7DXp|%S5n&0d^}1NbX&WShS{iFpTI@WD4J{_pQPey89VVoKUcu+ zrWOF76q79U{g%U_s4J6xDx>HlR;PNN9EBi8hN~Qt4a^f5QaqT3RO03SC0ur{-0dkM z*d>HZQI79)?8)3>CXj~LUAgD5qBHeMJAD;6{X^dF%NzPab>`Q6JIaoNJ_&5Xs!!aH z?oIA~-ZlU3wroD`%_6aR=s0?}50*}@l;Rw?WE(>fTSN+a9-Pp8|J@8r*D|+jBE|#a z7`wjzGB-DeoBaKg2`$AFELmJWtGg|JkC~9oY=ev@C*EoHa9}G680J;wIm^opN7I?3 zs_Xvo`vG`oAb84o?d5ucSOnhZYL7_A)IWa5DlkGUWTCy52TzrkGRQ2qL^VW0GH`|E zu$PM)jHsPr!L5Ggztk7e)a@5k>ZS7TJL?!-Ac*D+VIq1Ef#~Ox>oc7l?7ua14*E58 za%dJ`2PH285a3KEY3Q$@mc(fmAo04xq~TG%L&rY_7MBtFWXNEVFP1ar)J*FaMx zqoEl_+`XNqA_#W;%k0~nFYockQT+QG*a6acfB>3Q#3)$D9L|IrYjR3RmxAa;m|^s+ zY07#qzUBKg1-IZIa;uH%t}=_EKREu0OJV|xp`bhB{ZBz@;K5pCnd13&TK;+JG$2Doh|hWGMa=c@ z25#@cn9U^YLC-uUjTW~r8{Qrmp8&fcy0~>>E%7v0x%-N-L276D9rCYNol;!41TMAB zgd8$!`fp42HuRiKSRFe49k}qtZDTt6`)$He^u-hP`AKv|yg@Vi7Hg4iHXoTf$-_FL z`Q3;M+M4b>)va^)z;VVmR7rK8*2vJPdH%(lJZjAnKgf&m;8I_*e=$1kr~F%I$W3$K z=X^`IubhR!Tew+c7V^(&bo)xzE1CuP<5G<-@WyUU`W) zw?vnz#|`i}fOXl=qS1X?Tp}QoO{mJ|;?za+ma{+@f-o=TQTbH&`kW5ut6^S1{S{ix z%ws}?qee5w%BE+2Ew55J23FUeAHri8`T%b$@our9>fI=dwq~&&e8M5^JCIh(WY5C3n4)X!~1H(4>%Zzxz_3a(N>B6JN%z=waARdYF%g?%CMYym?vO9W^;Q zWaRnzRR`0J&gS7Ksuf8uc1~$>tWF*8?>w~1^jw1i{%trpzf|0r`;@YcHmgQH5-vyp zf&fWRK^lI(jkoqL6v!$U+T54wMqD%dm8Hq%;r1xH*KI+Z`y$kyiIy`p^uEm%jTh7( z(KA#5UVo*vEi>YbuFCJRU;p^sAkxbRO*^m62l_(0pL%XrN&a3?$Otm*dr~fRQr&St z33VzJQBb}+D69py7%MYHYouW8Rb;1FJK})zdJ+Q63Diy45jza$ftWfG0GsN595254 z7Sc%vy-*pg%`6#Xv8blUWbVNxX7gOl(jqDngJ%QeH=+O$E#Y7(I9b+QDI<~$X3By0 z(p|Bsu*ecOxZ?WhfR4^a@0kooA~O@8*CHv~2yi;<#W%^z)+3G>VA3y)MfLeQlzsp% z^ar}Wf6{z*Efl%a_Ap+io00q~M%s%Yq@$=_(82sT)|e96f!HRHV=`{e(M>+@#)acV zPy5PUI(cXc*TA3-)o+LFyJ%mWY(0}GALHa#YOO=Xc(2W4K6KKDV_Q(<1%ITqBXW5< zylYn88fg7w-9&d|%TXIxuhv&GeE$9Yay$LEy}leBu5za|d(nzF8}Hs}>|6?MQ*EvL z8TMmvRSem7^0GE3fG+^y@qh^I^3YIcqDLnO{jYD!@0hN{e+T)yyqYMvrAoQQoBKYX zKH5U`f$Hhqwri)qAHNE6kky5rkG|d#pZKut(Za%o4=1!DF7Lf6NH>!YS~by4)aVur z49tCFB6h(heB`TPoBF=yw(WiffhMX^!lV@vk&z3JrR*>y(S{1`oJeCiM*I}6$fWkV zf@#4h5m?xZ0)#t?qkRXm0sk}!O**Y^C`YdTRrhv=;MW!eAxjr1%4PKo7ZA(Fg+ihg z(RdXhC01)VkVcp7kC{crml)1)#IYXpG^o?H04MRGRnk)9z-$aDBuG>j5DV6Dz`~dy z^jZ#?%Uoa;klCkfltQo$G}`bO0c9qT`WElUW!HH#wNIA zU*Fb1mE@h397m_2=h34W=}YUUdqX+j-^{^xl+pn;a_Bh{=6%e06g#{Kd=5K_MRmc* zBc6|K8hjH<PP@{W^qbpZx17f5+LLb5_`CzF6U``s{z z+GV67J%S~HEmk1i^Cxce;kVUl71d(>E}ev!sJTztq7x*1!!z9D{<@enS%z=L}}Lz3J^m3a~1@Hc+PqY&IdZ-i&3K6%1dHe8oVWnphrSvF)6J{EuG ziWLdZL=sZ^gq2F__k>zH$a56m(BQ)QqHf0U9Peu}PQRi}wyyKjvG}%y+DO$>+;$X3 zJObAmq4FP?1Ujznvrwtk6ad1mXC^ezRnUwR=4BnYiF~7Um*t{y(tR0Y6@E%FITkIg zK^zKpt-uC8Dy>!bM5C7iV>*R}RpQy$2$V0qTamZ2{Ylp1U6{d7{QA+7W<=UdA{v3i ze%C|Fk-qatq6DSqfimlY*X4F(OdZBL! z;_=ELo)R&HJQR-xkjq;qrUAMvUMyz{F6%~$WbVPaZL|e{0o0tAN7m?t{tB#DssG&0 z7Yj*4oL%6rhEnYV9m$F=BnBlJbZWiI@GCT)pd!v$;Z@aVX=Sb#-+KPLks^W&eBP)wdi*0*BxYhyvi+>h^MWsiQn#~^af z@0y~mDw>qKd)*84T9Ey`1LWa7qaBspJ0cARk-cv*=Q!*k2Kw=nHV#s|*1vPptr9V8 z$Uej4+IDy`ZZ4RCso4Fw7mA-dLKKT$+f*qRc^XNch}FJ9c-k^W*l`Yo z33C#bZV-NAfR`62kV`C7jR#$!H^UL2YCdu}%VCl*Mn*C^#vocq%*4P$C<+Xh2V6Qt zMinS%GDij-Ck!`i&H$E2Q)5Q9oG8!5n&K)eXXBpOt!yJrZ$H;FZ~=)(c8Zrq&B5=Yqu6%NqUq9f|x=$MYi#}$+^VObEMpsJ`crRXy9EDMdW|t%6;(!_iW0D_;(jG5v1VePA zO2ufFEBDyBx#)I^&lP#RCmF~|5vfgijsg{=rxUh|F{l**%`Le8F>9BWW-}PTRT6NA z1m^i3X_`bfbt)JI#ZLTEsZA!0bHiW|y|lCx&{c^8n>ZoKw{@ja zX9F7iE`iW#bw`TllqKY2RR?s7z)4$7d6I^CU*v-k<|3J8mJRiVovsD z5LPfPn+WVzwPKrkZ=$1A^}bc^M4Xf9J8Z{U>MCQU0y&(1qpl}Jte3n5dhhm?B_FVxqlbs$(D1E-u5lncsPuelQfbu zK!GFOs>JuYCY6XOWYR;Ll-5eNg$70!IV|J*$Ut(6L*!TaMdYJ58N5=6W+~rTG*3+q zI1%ZYGDd;5_>lb5Fvjv6%yhOL4zd&1ZAD+&ajsmmFz6Exb}UNoKKJfHl{43HivxiS zJAsy%(-Ox&%f5vPoZ{pzs6a8Qo}P8JvR*3mlDQ%Yq-YTd<(8Mu#D*xQFVgcG5NjoD zlX_XS7!95oxOCZJVJ8*02qN1b6u-F6xsL2&c213m%)q(>f4viPtWY(TymLzCZmFRU7NIVUvLCfy(SeLQ%nR6XcEaO!?UEb3=lrTV+0 zmiIS|H|(BPOt+5F*3qE(32AU_gEHy4&}VXu!KaaOi|W|AhX*4Lx$mj3H6K>J&3twk zG1Vpfhu^0$IeS;|oin|}YYg-T{t`vP0dv1jIDYOY)d*_6D^>X+;mJhbNVUxUZ4d6* zH5|p4<;6-%Tht;v)t}n1F=U7|dOl&dR{E4Clk65Yh!skm65b0xq*60SFD}$s=ISOI zBunHGeAgC`bvXLrbm9_0&=`z&8UfvXAq6S`=VSGP?=iZo6u9ytuE!@8NYEKPqhDSY zdRF%s>QiuO<>um3Jvv{`N#1zWMSwkpU>3Kkf}XR+3Jqi+V~e}cD+^lMddFdMzhct5 z_?Vb^6Zpb$r#hNbQ!vwmCaExw-*&7VY{qs2kxs&1j)?`D7P`M|nLde=5!&oV`liR- z%AnFqrpSl3=_W!V$Mjn`pv(N&FRQA^rwnBSK9c^Y1WyXEI8Ri|dKag^K;Ll=*{-%4 z$oI-S)RQl^wocEgWK33=fN_R)1*z*R#{_{hg|$ta4ByeMEbLp2%|I{E-|{0!#i*z7 zW#^q}8NOp3`s!OtiFL0|)X%<0Ll5xz9gUUjOPEfc0Jp&%Q`I3Pof!1~Q?s{~8I1S) z>m&OhU^%pzjN9X@uL6u$qF-cZe(*etAMKxdrS4B#Bq7urs5`Dm{ru6)P@*bU?H262 zck2Fq&5Tf4KUa0pvW&D|Bje3?8L_J)S7JFL`%j5JSMqi#OF1XT1<%d^Pf{hna$acLRhvD(vTaO*kmNznTDQ}? zUo~e6w(Xg5XdZrSB;PC5_Ls`F;+ai~H47Mwfrmuf{o%Lw&g4$mX~<-FV8Yj|`GBZi zXST&1R>!3dyBY`31g}bwH|*OAH;<2W$BQwP8=p=9IYBLtNcpTnI+6xN!FWCh_Ia>4 zw+B9U0_9^&<{P4apGsgCIr}sd5PB=gLiuW#kN4VaG3-nUXC!_`xmMIgM+!#G^9y&^ zNeD{!V-R7$8j};^w!P59r>d#GEN0Q&CIWhsN8C#wS?pp%w2sR!x38ML|8u{!f;jbZ_10X-@jJN@wK6Q%W`omRaPKye|Gf@$dfU{h{%TS#F4z@w#Mz(^y&C>-SGf{ELRg){q2o@|D#49wV~{VNefJ zEW=2U;**XT<~nX`qw>Uc+pWnxewh@ea>sLJmNi_46G}!a79~rc_=~QUDY^Ph9SlAa zsc;L`Mm#v45xK8z$I-QtJ>o#9%pDqU4-AW)_p^!NrrHltLd;^G1r-DbQTZ7oUkkf84Sm;)wX{uLGm>GqLyHe3f?c>*0=q45CY&{Y z7+PUbqDUUScIk%E>oX~8DePRSF?dhHCp$5oW5&_K0odoZw!u~XDAr=tva=fV7P}zH zQ(Z!*z+XjlTg20TeZpkFS}T$#t6@xcX1pu~d>X3uu(?kA!mAI}*`kGJcX`}RK`?mkeC@i9!07F51g zik*F8sk&lpKXZRL@N?_~R&r&wM1dE7qG-&}M9OOlA|}9~=v>FUL{YjKzs-b{?4v@~2Y$fB(DhV$`ttqY`oS}KH$2~D zDlQn^rUq?{eUScmb-m@>Tk34N%9Hu2smUh`7v1uowE9`36P&4QtC=V&b-m3-_ab}! z$+l`XiAXo<)G5qA3zh%#`jP(@cl<~G0<2s5@TZV{3etQ@ABc!zfu?hhuxM zYEe;OD)$xUzwS3b-F_irpB6JL!sa_Yk7raGom{tkZuzEWY!ier$|A_3M&dHfU71Ro zAvyX;-Dhnmn58Y!)@Nz&njX9@!#W&I7t>F(O!lt_F(gR_zPSBoq0i9D*aHOO20c1pNaG!Rw$0*(&HTe(mtGJOQL*0I6o5x5!oF`dH2H z=p~U8kU)<7Z_z9M7v97_ z`28=u=D#lW-=+or=+89ys}6q>MdMc--HoI13*$WA`-k8Bs7W$S{%Rs2?YKb7zM5;$ z8Of8a$`pDLbCvqd^(yT_u|LEO)AlCnQPc)S{Vsfm)w#$-VcS`Bpp?biHsC^xOp#+@ z;rd5fnQyechDr@MK(g~hHNu3Z<+80mL5#mKaml`aCwu=Mzwhk_e^ylf1L60ign{EY zDHfVl8fm7LhDWA<^-wAeT>eaw_*3lv&u+|ruIu{eDE$w9|2ZD#Ur+I$Yk|MyuO2;( zUmQ+hKBgcd8w~R~-p%?I0NP_SwGR2kHF%;P;;itSryt!_MdKESa49%uS0y^s_qy&C z6L%U&M|b|ZzN`-{~#bbwrGRk7*#bAps-pe(~hnN)Pg{NUyN|(aZl*k~OCzoZuaf z43WAnWe;+@)0%e|)GatIpuw_|x%M*6li$2z)$aZg$$yFY*8NeWxvBB%Bx3~Ef38jb zN0t5;zyG6N*Z=FA{fpmIbahd`DS*s;MoNSy96F2Y`Xhha<0n9e@!}dbk$pH5$}_bE za|wAm&TmdTt%FH);OXURrbmD9-KPObLz1ooY2(K5g*(pL$yHRli&TLj#mzRl*74W` z0>h1N-&OZ7??(LFV3~FfYaMBBfE%a89BDV$AG_+#Zjh>WvD{bT4pVL=t+v09Rs~ht z%d>?Gynt}ym-LglB%@ADVRs+k=s0Yhajdl;9>&q$8X-tK;V&g1x{GtnTz-KA0{eg6 zQvXfs`xn3eO<&A^&29aqKN~RALiSO3arBS52x|Z)e*7it1{$b|KBje;jnYVlp1~R8 zhg3;-ygTgEl!HOPKCo$ z-DioT-pj``M``8$$mzp2>W-j2s4QElfOve2Aumsm>E0p=R4bO$T=T~7h9i40tsu3S zwqK@o2|v&zQKn{e&zB?D&#_lJB+*2YbRVg(47#Mn%|&zV`rjsP|KmsTFMj`HoBS_2 z@)y6l@EXWIZTvg;it>kF>Eq8>zoUU7$UD%V@vmf*CC&j)QQ~b>?04JWVwJx?bpNuM zaBPs@8{7wqM?73@xNQNe|a%pZ|4JVuCN+6%q>PsVKceDsSBGEiI-_I3ZAo*Pq}O%(-D$ryX|(;}mu61Vyab}d zt!e42ajK7tJDVDrfKh79YC|EZ)saujeX1m3hoAlQKK_nw`7=tT0Zp6L`Q28vk7m$q zZ-StHNGX&=ufo{;45C{v+T0ktG4FWtPqlvye_8A269y0jtt6ziQW<4AuJ~G{$>v=r z{~@+hukLCjW>WAMb|p@KJZP0Ww={p}=;ME|ZvB&5rZpv*`f%2IR=5pP6ix>pfIFux zfb*qHiG$TC*^p++Am|Il2sUXbKoWQs@D33L}6<1KBZVAHAjirm0p`&tF$8Y)BI)w&E$kFnI#f7u63kj7emk ziX353C3Qmr$kNc^NET2Z=@Re-59k9(AQnIaTK=FU01ZOWTy>E{JY9K4ni72Z5AFw# z}8niUL2L0O$VAou_K_QNlG)=n4OZ>Zp=LJg8A1#^Et#v{gQTR0b_4E;Pqlz#CIwc z$4%eKIA?)dq?;%4naxpDaLgbDA^CIi+8o~{z6ar489Sl=2}qW`)cAR7#Bb^X1x|bn zFCZ}DxB&=wlP*w;!c8m%N`;8h&Xe4+3XWF9GA4ccPtTnij>odMTez~oKT>JiG7R{e z{}q)4(L+|p+?WH1pRjW^wSXoIW|3zDfWmbJqEzvKIye>%=wd+ybF5O}PB1}O3P2(` zs-kF@#Ki;OWw%*zEyy4iLIBNaJ&2wtE+@ud24In-rau>h)kjYx9Br{JRl3e+H}aiP&_bhiL(G~kWhdxPldn`+X+P) z&V6)42wDCJ9Z4!smP~FNi;T+lk98zC>)R#76G#?ER0Thum zqou*NpbYQwhnN7C1&RoZ&RD^?y=|83LoY9@s8S>VJ_B$P9EpU2<48df2Z_8aj`F&_ zEk9zh+;~!C2-40CPk}AJ9oDMgK{Mc(=B$}Q9brRejQ+q6Tv->3e>Ni~GJY;Vn&^*_X3EfkIKK(%k=1eI$|_@I$krFg3Z?+* z9ks?winFT*z^espC(ea36pex;fJ6asN8xbf97C{HhYcBM$t~zhaSVuxoVr`+nQRnD zk)5ZI8R%cq0-O~D@(<9_e5(EFucq=tr+KAM@=BNTqKr||aMUU`4qT%3ge8%DPG^^d z6o(SautWnGYl)5jFa>{-=ZY#%Ka6Lygg4rjCz(4N$Ag&)>LfQ9n2ev$UId*$qrqx0 zF^-8ROaPNBZjK)ZWtRhP%A;i!t3J!+q28yeTF$P&3<6 ztsErp4Ab7kZKCM4YP+81cYc|?6#cf2^#k?uU*GayzXopxB)svasjR=eS^qk;t16oa z1#h)A89H5HezkPB5K8MFp?~D>R}xD~tp0~<1>hZ=%JV@2pzOq_v-bf2ADs{rQ=s{x z1GJI=sPjj#w7eNW>`NW2TEF*5JDwL2OUKQh#f^>ZS0xl9=Gg@*v(pW??twai*8sD%piuVbTR0-B1-~z<-H2K4 z%?~W&aRQ)tHGCt)!WMFQ^sZB`ID5hNMSJ~d^(QisuX)U!&Y`Mg5XzgpfFAovo7Ry1 zlpvUV#Sa;94%+hv`tPlGG$FM!R!b5GvV~AU0g@hSA=T@`CwXJh$1~-*Pfiy~ng>|P z-;^gA)@SzLMI=D{Pz&6895Q@5b{(6By+ph?@k_i5QXB_X5?Aah{VthB0!B3;N!F}N zNzJeEcQItd1sw>?I2wDhOZ;`wrvo52-bgmPUe_NW7I{eYqrh_F6ziK9X*#+j3_FhC zgTr7%&?)*LIeH=*VadbF&fd`HT!&7LdM!?e1=DdNwCSU?K;w^-bUM?pXZ^F0Dw(y_cM*IRIz*G$Y&n4=RK-U|0~B`CSLSv3V*W$`r%_ScM-vkS^#)D` zM{%p!58Qb$_d0gh+V<;eHmDIce}5}9w}Iugg)rN1 zwkYi2pP@>!^K9G{|Ls%*K+)^3CQ>PdqQ>Y=hNHDlo|t==Z;^V;yXpO-{OD~u$L zKYSzqo!nxcZ3X60Yp`#ySHp-wWny@#Fif^zqPfkUI8u>tj&K2SIZdZ^Wq?r4x>Rbswoe zsZ`r|0E7lah2i*l&R{m&6;>u7mOD1~^jkV}O}8-iWy#y^blF?ywBaaaAyi3D41@zt z+QN%S#pwQ9{xUFcN#NkeFcNUJx4ds%9gt{wqjD$6uy00O)Uhdx7Y64U$G8wD{h{#~ zB2LS5Kv@MhU@%1D#L8;nJ)=pU6~q#owBCn+)pG~TjO>_&9OZ_QS-uI=cfs?*;t!0~ z*)VVB{~$J+9%#C2gnlwbUjI<@0W^4<&M-d36i z3ivHGU@&c5s1gqa1K^*$_K4It`p>+SA}t5^XI#eB?XMhj?ZSMizS^zxB&S#7A-Ci- zjz^Lj<(um-eWZOR^P=}2|M<>wcKK;hF4mVif3D+xsO)(|L#)MV--heY-Q#Mg34d$_ z^J19=9ZkCp4%B+i%eKEY0wEA>!cotcZxj2oL}Waio@4+Ab57xS!L{NL)CmYrj7lHx z-P@{BlW<1zRHn9@7=#&2F4S?Eivbf;Bi9_XBH7CnU!6CXk1_-?Vo~s`S*m0wl0O3y zOVQG`#!>hU5RSm!%MOO;q@B-NYFV_@NnHlpcDmb4FbIN?tY+C$R~&fFh)m*qWAhfR z`&>Hro2A#A$gmPe*Mmer4&2%EIn0Ts%|J{Zq)!6J0h-;lSf#QB2sO6B@jEPe>Wg)#A~13F`6f zemm3~{l||vxhWhTez*LT+llZxJ9jnvsJ5E%Z3HzhcY^oOrc&?2O;q=z9ZZlr4gk2N zk{~^SVOnBzqQ_s)H@?q5Sx1>yK6>=|&ClOACjujpP+})*>m)N5(=Qwn1rQ62M!p5_ z9i>yLA&%$6GHUv6u|_PM$9R9(I7H2O)s{kWY4r>8KNN*N@=-S%txP}>3X-Lmqry(M z@|G_njBPAlH_xV$AO(WHg<9RW11LnFfovIlmG;k%pXyGEYX+rNwc$X_9lq+d!JWU-hw5WI)si!SpTJ`3J$D#SKY1{ z-?@7{Q2L}^0VjhWi?J%E9)m-dc&+*UMisJw8CXWUgyes5U1wr?^-aHGP=?fw;vQ{_ z`L$^cdgQM4e!|C~zP$I;3P;Ed%k=)XAJj{H`P7Nvba}Ps)cy-HpEZxZ{&*QgJ%8!+ zA+-zh6e=4z;WC}lX+um(b zOfL(%gSi?=*3leT;k^M(Kk~fLx(OlL6r}*9t>TM(W52ign|N%n~91+CrF(j#nmKnx~g%4Z_+QA z02_}u)QO@3<+L|+ZYVQVvva@wvn$b>dl^FmD9oPr}i!#~);($E%G(kjz z3r63qGYhr0UbV~618cuQHMpQS*g?`I>|~O`bJrpNE!b7*rmZG>M^i(&hqkE?9W9nF z(*x0c8CghsXA0bmRE%cibA7~>QFa<});}x&6}o%gxt952cXw{h-z3rS;XY4eLdnhn6O)#-GaYXeV>F zu$iLiYva+`x=+SUW;1J-lk?8vCOj^5ikmCWFx&iJ{RwyUrM#|H28ZB_BX ze96h=GE5y^fWX9hQeL0Z%`kQQ*}y~N?}2L(PgUiYFK+yldh2_jdfy^7{@qtT#Z8wV zzu&)@X}<89=_-^qq+p;gXtT}e2cI|%<-a#5Txr~bXy%9)w|<73YS@p|&I*<35B<#| z&{ni@qThP*`9mchr54@Q74Aq#Ns{Ic2UGUC(-LmGUmS@1dY{aswj~$w=zD}idCgvg z;feY~`v#pMyQf|p8xw081TYN1!#e`l14`h*d$FAEpRzUB$)*0g_t2Bh+T?rMx;=r8 z;M4q9oj$~IC0S{nh`dGzH-5H`E6~G61906QtMY{2SHchogfL!Ws7ESgmdN?TuO#T~ zMBw1XOY`6mDNk45xDmCT=$i?qs!)CewJ9*B|xbgRWZidoUu)p<4kM}Y? zz04OK29G=74kV~EcE^XDHGL_PWDW-jO>Z~L^#o|?>02+Ih;3Mr-$LHT&4$`52nWXi zo%k=&0v8{@)?{Zmxy#q}+crM>aPgI=QO8K$dP1(vxoftJ@Ynqd(L|AjYkCw^K~ zbA-?CkB-k={Mqz7w^FnECf9?A*6DZOrmKaPzGnh3poGWIV*6Db4yrRJd;)^-TE8hL ziAH*8p5Mwmcy&9Q>%@3z?5)Y6N7r7S$F&pP?wzZC+-l^fqjxz7f91j9>h6uVxuVHI zHLrd)g?^?dDzz5{gv31{H5)EpDfi%d28Yt3tGex{LF!T{*aF>m zvo5RgipvLAQgZ6_7Z4P$0+bZ_z4)kjX<`h(bhva^BE%3xKqvSHBoCU|I=g7mrCk-X z#eNb#HQLLPWzR-B7QGV~x!wmAqNKk0sQ#n~i zaL~{4hknALJ57l2YTMGPlK=>)zq1pHev6mtxm5bJ)XcZ=oP04Ovr9v>O{T&qpQyOR z^BfhE3*Hwy zm)DJnEQOF4^o3$c;79tMSbB31K4mVti_)bJhLBBB1fnB?1$bo7^m?CSaRDM+2yNGf z!No?>V?c4Gj>A98|L}VPD7Oh5T6lKDKU^Y5FW^%bcBxM@dF4mntU}4F=jHo-5hbDp z&bHTGWRyn8%;EAbw*wOD^Z!8e<+aSnL93nKm(N{uZ|Hx>y14(i>I2Q`+Mwkg)#l`bAB}rYsf}VnTCOBKSlHGN zRq75uCX=^wosp|}8dGHmR-^C2ql=Mb5k@TOF5SbjnO7HG_deJ3tEH5rgt>mtSfq~_Z>=aT0kaqzU04LeAGq_-GB7?uno4O zHJm?oC~)+~Z+L$f%~ngZZ8@ewiM@9H18_z#iGe&{7?+gu&WIdKN~BLR11G6LEc#T9 z7qF3_SHFlUSYa5Ox`C>k3!3{l@6~$Ec#vN=B*T&6tQWRk+9IA##OEw|>f+{4>!N$S z={^iI;oth#b0i&sNiRXMR-qV#1n=|K*%0i&7?M{pceYgEs`F*0$KVKDjcc;6r4$^v zJsn%V=ryT5Rjl-g(c!8lz{GsZz$IyYIuvx~l1(p*67)2wkVPP?UiH+jyuhz3`By~Z zjpNA``i^RAyXeBDPmv!G<%K^9PzHt|&kNm`x##0|KHE#vg3gro`x@qyF}POOIS137 z%2R9E)A4=8=lODA)K6+T{6$;;15LJ#ki*vxUcNANZ|Z_4UEEmFI@0iHcJRm>&$(5E z1RyILxPF);08Q*pc=y#Z@CqmIqn3q-|TTGrb*AEGDVM?GoqtH;;O?11G{j?P(U z_Wo&#n_CDICWb!Sh^d0XlHEyb}Lp7@uYWOHia|f-gxfe%T)_# z`t1FJa&C>qGS4(l=_x*fzOhKcF$(FHdHPh`HfgGZ^>k2Og~U6aI7iG)o@D>|?NbUNThB^9S5JHv@sqjMv`3Q+nQnjhy+}ItgE)H4ZWth~ zuK4+ij9}RMbRK*DNZ71)jVUcAR)2H2esRjr`m3bg>8qhip}DRyzV_jJGFf6J&)gD! z%3q!4@*6)?3>iP^yYr#kD(0Ge!g{~0OR~aAu?>ZZih-MeRLWSs`lJ8}^e4hK%)4T} zO-WSPw3U%jptfR%bS$W`mrlock1Lh(eq4#dP%K(<|Hv}z(KRX+{xaNI=|p=Db}cqn z&v~tAEq3LM=d0DDn+j5WBVRz+ZJSu7-Y_*fK5LTygTJjW+5^G}``5W_Q_RfN3!B@T9Jb9?)~y?jyJ|>jTM{=i}xD!e2A9J$Y6!u z<*KVG+`HXVf{)Wlxk<(6Yko#0nB{riBUE^+SM5!0yU0%D9dSm5Nmt(Pa*-%dZEB@{ zhF+~FTT#ducr<`Z8;2PofH(`_TNpC94|Dz+#v0(Z585o!&98| zA{T9DXZ&-7mFW8OAF>ev4|F~4)|T>uYkB9p-Wz&(!7g7aDpJ6tr3UG;l}4gFo#ppE zc+$COLwo8DH!(q0D{_rUfxngZBQ=i++KK0%+A1~qNU1R$r|&ZS>H0e)cvo^ZMFdWy z&yofYINeZ`n6xl3K2Su>4)=6&B%CkB$W2N!GT{7u+9Sme2+%Pw9Rd#Fgd#}bd9yK; ziva=pkmRLb#u&AYX-#F61o3fb;~3Q8#!q4)!2-cwK}Xb4CB@}Hiz}<9`>S>LutF>8 zrmd7FSg-rCkQ>suoiXu9sVw?bAhzyxr=})n_FYS(=B}Nc#A==tGbV!k$*Ypo(p7^e z=WU-J+v<8Hn^Rr4@;;*>bJ6vyGv6%bB*J4aMB(D_z3jGKd0+K25}|8ntXyCDbxUu$ z+P;)?%H4lAHOYJo_4bBUS6{zdUm>BeT5x3dZH+tL#9iRxX19IrP*ygL1W{uVL1LqS zeAkWK**2crFTtc+6JLGKvQ6%OJj(d>bV>`wK6U5FOj@OyIBoWs`dGG|{eGKpQlIFz zI~#@~MG1!Q|L|K3xE~PBe&^hvgiCp*d#?Kl<+S{X-`>7jUFw_F^~ItjQHnO(#B5c+ zZoVwGYpdN=a!diJ<#0@MQSp8%_u=V-?TmXWrftSAT!Wr&A5Q<)yx0#)Q6rVM;!%#@ zfg}&2uysIi1s9w1O-k7 z+(&8TTE8}g3r(XR=%9Kx1B6qKnu ztD+le9eT}cH1{{cTN%!Lhy7Ysy=W`YR=sxL<`PTz)GtOQ_w7uxPn0P19M8No-i_Y& zbiLQ%8JvDAhm@>f|4p$^mdip6cb9*?3!Tt-Tdm}ELGHs_u)2yVCfaIdimzBHnNE3J zmzvzO@x7*S6~p~eykVM2J~h!iKT3b@MAdXl71Ks|s=%GCrG4rFZB^7q>Op^E*C!HK zJScoN$%YJFWDy%*E<%>D;SC!$P#Kr_3|wYbg!)~O=A?sH=mr!91uuQ=$5^@$!4M9w?&F7oxTJga_||UVVn%PPT(; z_d-Q>6Q&z;#lUQ8O@smYW<`*@abD_binVj1s8hP<7E93+Fhl-vo7F`=(@Tksv4bVQ z@tH4`M&PQ5ZXx9B6hR#}T9VN3uYFL^@L%bsgYt{W1D#=W%QW~l0WG>8T}*d7BljJ=V;~r8BVLCA~YUL&4T7RmUA_3%<%7_QZ9Q z@DzYIy&@)0Hru0}{%sk9wqq2hy!`x>Ifp_(_X!iDyb)M-uNi)tO0Bu`RWi+S*ki4` zwpt=N>)Vm(%tjK@W5FoVRv80WBOgrM=I6Kqas)0jbbJgP4#+56+!*ed{VGq;I;wZO;&%zH&b; zg_q=g^&R&qzrkaL*_bRfMve)NR}{+{Y|xO`!8=JofEQw%+M->N!J z{R(oBd7ZOyB=+KFoBfNp@T`S{weceuo|Rvd<*}*I0zwd;DS(?Mo`gStcHg2#iIhfc z+;;Gj6I4LIlfMvHU6vYg?BUA@Z$>)o`<&nJ{FE%b+VVx#RwxC8!LP&DxwoACmaoQR zpsLOddFe*(BH{KAN{}Q}TT!B>98HtJg_m@ROMf3#YPDalvDaoB`4u3iddxY=Exk+# zfp)9El?VCJDmC-|%f!0C^s05FHW5Suz7Xyb(Tm;fRqaR*N+Gs87yX0Vr;|XzL$doJ z*=bB-2K1uAN~UoXQBEj5L=;BH%w)S)0bl46F@XUjhFpLyhg;u`#2BUY&gyI*xO=n1 z=#kXfINnQYYI40Hw)ygCa}$02NVin25LX}_(Ud+0*c>KimD^gNWvs==*~%JAvKCBSWzCh@*gq zv`<-=-IhLQKV5CT5x>Ti5tG>C2Z{hrl0RnJX?I){BlEdtVzVCp~H2m~7eeoc?Na z4eZGaLC;-&pYG0*AI8Wz=G0SqDP_-AD{8;aMPB-WHabeDBRRh{9~J!{YP5plM^*{{GCu_D8zZT+uG>3OoVkzl$C!q0?6Qh65? z!O3X4h-6WyG=M7Nf37ReY7q?M#Y#O9rRJRs0R%ukf?)PjJ-z%Z3QE#4b-S9iMKECY zj>NlNr-dQBINu~w{T$A~EmSORtxxE|%$ZK6>ZMaEWS`om%;g!V?|5m!OvJ9mfV50( z0hdaIv*Y#r8>U(&LW3^-lur~R%Td3=05!Wd(|BdNFLUZwPRibM-wF$9=M|O{bM>2> zUFt?4Mq9QMl!X1+;`v0ErTag3Yh&88XV!)8Ui1_0*mvK%_-TyUf>X58_+>=>T#CsH zbzI(8p{VM!E1?@A{cL8H<=1M8p+oWftXFK*)du2ZLkZxy7`Y`w+ zTbiDe^QMlQm&JNAHZ1S>q2EZUA1c(Ti%^jM(sTe$FhOzR$sc)qv{L13{jD0e5Dk`r#>O{b{Oo~psnTI!LiZINCw7EZ(MUHzi;j^F-Okh=7o^MM{yiQ z$rr>D+xz{zbkDrsv*eu6Ep$g)Ik0qA?fB2WsOk}6J1(V)Tj{-JcvG^T)1^93F5PuS zI{l@b`UIBymd3%%^`*fY`ZJyBiuH}(aKNW=&ySwvJ+mshgZ?6iPSMHRX&YW8A)MXS z?)SQTJX^w;pPPDqmE&(|I~;mdOI>E$zkc#f;JVnxJ!+QwVg38AwTO+Qs-NWxcoe{3 zA6;%x;1B39KE3C0c4-k0G4x~hXHTr_Uf)oU*DdXCQ?jvO6eGD>6*LkJMmo;^h}%{b z{HE$~zd~0}#IEkcr>(PDD?Z~QEMd(z61wqu#xl?E7=6G!CldnA+)l*U+`WLQkD%_Y z)?D}?Z2Bxey7!U$2fGK;20b(l332AP>h%2pf7)_^!?s6FRvS>#kra__@j2T!Po^0%6JtoSbdau(*Kq{5K<3-XKC?CC9fFts@Bc+~PasB9X zS<#0ctTf$gN4LJ9@3eaVg0hv9ccyT>+ya85+{IOHMBWHy(8c_J*n97=rk-{0d!-Np z1W2f%hfo9rOlZ=S(7S{p0-^*2q=|IIM(9OAdROTkrAk#ouOeMUM37=Z5Jf~($Q$?m z?S0Ps$NSH7J?A<5dG}ddNiMF;tTk&g-?{IZHFJMb#=JCxE3l#X%6*-xR(`ds*q(mL z2L`Yvj-&Rw9>YR`#fG2cW0qLY49%?l#tYn&ec#}_U-T{0@tEGDYeJ*nGMYrIO*-WL zN*Q9A&ZkUyT+fH|UKkN;wD?s7OeB>!<*ABhO7Q%mF`|zQ@+|zoOA7E9uAkS{ThkhN zs;3YE#Xh2gLJ6nZl~YF=1wQ+22a4_c{cZ`;U-Y9MurxnBl7CF4hPsAsuV)_J`Yj6< zIIKMz$d`<<-)2rk8=!Say<|;8)t`9LzKZVV3tm%eP+5MgxZO7D&er%b$4YQ7&j zlFNOAYJHrec5&}jUCtHH;5NM>+b5z+?3Q;v9Qrx^szjl|-Q(_>kivEPf)Y%Uti2~;x)CD`ksc8sCz)APS^fa>v&~k1wcq}7&TSo0CKUO zE!x2qucx1@BrXh(MnL-p%xRoBByJ>u-eiKz3&awFc|_>KwMDcrJuc5dKx|T)k(HyW z0i&k)5J+wGLmgTC-WT_Y4joOg#GC!G^0iY^0++S|&!_Bc%*LR7C9Kio=cgGf`<$_b zvu(rIGWpei#&pznPx_UJ+GeLel$yBwD%H1T{F}81q_{AT$d5YzX^3B$BOsihG7c^D ztUAk$z2b6R#+%o4&eqVCdA5R1!YQ*^#Tu-4 zZd;$Nxaaklx8=zf2MgJxZx_o;dqYl7Js_Q8IEQHNyO z>_w5-L7ghJ1cgajRGg{;yO^nt-W@J{w)Tv4iow6}9F?$(gG2>MWX1z9g7ME!FtYTcHJ zCko#s?8Vp^gWP-{(ifg-l^+Z0lVVYjF1CQzgPr8yYn3KtkN%e2yv1p~P4Igffb;_h z6PIkxFiPuShGQt8h-LGbaFsh%np09 z4=KN!#9;-A=_AB5qIk?76W^W^skGd;tWXnV zaj{U+Fpf|-rMW5DG)nTG7}bFw*IU&1(ocwK^QAofVtZr2aVkw_M4&kCu>~=$2YMNo zdn5Ma6Y1{hnzpXn381wz9}hA+*@~>3y-szsvwHMnG*KA$_Ph5~tJ9B}oya=PI=$cm zVd)cjbog$bKm8O}?1D!(2tgOSP%yA0NFT7zF{ zfbKLW13mzD!}m(_D_-Je_N{zZV{QX=v1uW}n7GCoDi!{mx|y2l_~fzlOl2!}FSO{1 z`GdlMxR&zJ)loqvi#+o~O*6g-Z2iS?e<#$FMyn@}v?lNOT2rYe@yW!i670!u=%Dmk z+!RnrK4@GgW;)?oVvgEexC1_vwha9pRb>2Z3IHY}Y1WpT%}%*M5RO2gASM_T;)4Bi zZDYh)rZE(~$vposB=s8-?!zO}AC6RbK>(4-*>2{gT2M(5yAfwDt61L~8S<5Y3}UqDYzi1~yadWGxG5`Rz-#2oxTJ98_34`|O-3ZSNg-K4pK=;}p zV*ZJ`Et}OK&rP-C?`G3ipd}+>?1tuwLXO*ABMWIJiLiw%Q=+CsB&aNH&1!{NEQ}fa z`|@y_?ZkWCxH0ofSg5y0O0DirpJ>SHJ1>0{+eZ!Rx032gzvU$CWI5~ z1vzP}WEJv8g^H>7=<7us*}M})>_Phod>^IjF0hEn_$X5^M_NDdKiBrK=bpvmF1bnR z96e#8d*`0t7}Tk(oNF|cdxJgRzG@&AVs!S}sk{+;ZALCW>)GwYI&MVOm6G;5iP`NB zQ;4}O3LCcciY+hgGhg;!vp%cV0?NT5nMCdVeR}*k5Wa8YDBm3wru1UE8`;Kf-L?AG zcg@wm#&XN*%3i;6K3BW?`~HaYkMGTkry5_>SMxS)POe;ikl&D$$A7XyPCtp~v%eM9 zv!mB%Yh+FoATZoJuHRE|Jlp^PPN@%Q7GylkjV4;1pDkg$t{rd^iQvHjK5QipDY1Qx z=!JATD8ILbcb@Uq{`0fa?%yu3F<-i;|AnXQM)W3ygi;{IZ)+y}&|bM2V|Wzbwe=fX<1TB>=D)qzX zOt3ZyBSG_*T^R@z6i$h@98@h^04yAdCT8m}`j!{m&!xmVId*4ghxOJi5Bcz~jZ7jr zbol9zvA_yNlSikLn}e=tgt)A&044X6HoRdCw6J1enN>8VmvWknG?dlR`Dsib`HQ)S zpZK<8cZZ`6E^{Cy0#o?mL?(+lrVfpVF&4?`5e?{&I$nfQ;Q508$OTuYuRMMeo9BJp zv(K;}*3QAHO;tHVnhB8hD9}Wa`<+j1X>eB&>n}|}`cP>{Psh!G!x0(j0Oxf~y z029;0KvHgqhz1v(qD=JX`3wX&6noM+=tIiX2|w@aA_)s(+t?#d>CjtYC+&{Tuko45 zpSv+rWv2F1U0v*J>QLzR?7J2H^_Qw(*r3lMYuyS>Z?*DMYju3@#B) z#`Z*)Y=d>fK!esPM~(hU{hExpYo<0{OP^&ZQlaXkYc;0l$%SayK5qwRo$ey*u8VjL zQ|7F|^e3!ahE_^oIhDxPZ?A>+=Dhoqoh6Ezb5mb=RdF}()OcL=7+_tlG4D#Xy(ptK z)z&%b<$r@w@e$poFZUn)?t-N91I}zNPA+G{CB^-&z7>5ks=e*LH~g$hd@?KJ2h9_Y zE&(B3fT(4sM)xpq*+oJ0w@hX>wDO!2FX)|f86T&pVG5yG+qJ#(nYDq05S{h_Hwql- z3T95D@752)%3puQ8J2Go;3!Tc;YnqQ%8s7o^e5?IZ>@^R=RBQwZTYVJF)hU z?^N;mmmEenN3eiXwJ09x)u>VuE6Ps1OW-zJWmz6SvS&K}|q znV^>j9LW?BG=ErS6kv?LpW603dzV*LH@oL#_6$>Yz%j74JPTRm-d#&*gf@iYAqPlw zlhnI`oo+PHykn_LKielW5#@M>iA!qq5!B{}xXF7O`q!DD=zU z^@UgP<^ZpW^;-FprZHTv;I??@vK>4sF`7&UgkSEX{8hXuqSDKnsZV;fkixe($r6|k zSFIi@E^X3AYV)b+>8omUit#t!xh8#RKb8^cZezCEe#MzNRq{znToe;)Z)B*%N$T&- z&_{O8Eo%#D<*JRs$+0V^oiL>*WpgD&SG#cwfA^o&3j@ZqU(@(yMsev^w!EdzK37Tl zkQcXle8W7wg}?$k!7-M8%PpD1KeADK76L}sFajIAfD_0GB_irb)SYF4 zcR*RAL9B2=(Ks!Da;YG@$NYlMY|O&-3=k8KCPJ)yFRAH!_NIJbC0NrmMQlvLr|%=_ zgH%Ifr*HuKXU2v$L!fT81aVFAfL^-1`K5lNjw#sWutOD|{ERS?i82*-Z4sq)hdL zo11FzqgVHi34d8pNUO8AT<{1F!&tLctrffKQ(LVLA3;HHtRJifUOCQCwSk%)56F)eYAIVQ`i!^!)o%4zNqu&LPI^qw1aLUKG zQnJZ?D<9uHDSy@9Yq+MQtgt*&HC{as3Yu#6LmqX58azh#Bjz^~jY97^gicRoJ^9R> zc>mXnC2y+!w@`=gyM@ODz+O0=lsy@t@lWQ5>MGUo6#$rk!NUAOb$mEJ=p~@eSQ>-` zgiTQ6ZqIa~CJdVM7*2#TMcRNcOjbl7BD;4glq9%fxDYHXxSikKm}0`2#2^-Ns6=aB z)b@#x$S9*ut3 zIt(WxV_j;q9Mx&-N1W~@=(ae(8?dY=ts>9p?Zf#wpiFv=;MKthRx|@N z4C5YZKpw3lg}cJf_!MgcOmg|s+=xuD3CT?w9yzF6fmY_VMcWyHjN_3~)5+p7epN_G zks6ADGzZiHyUAN%9s@>W;#^bJCAgfzqLVI35WAPZ{wS}qOse9d6E>D?m))B|oJ448 z8i@V0O8DdqsJgoBJSeoFP}tc7!(JpZsfQF^D%<+z0mKc^rT~2dp6*P`knd;E(ea&P z-PC>}VzvurYogXN2yDvbjKD$_Wy^a63NudF+P5qEJ@uMAIQ+aJ#8u4lE=zf!xbE=Y z_j4S!Gkj&~6bfS3o$;y1X(Pf!Ve>Uk{udi2+|XWD_h!X}g<|Fs@27!uysNa;9R^pO zjzcpmPhZzqQOD?Th%|EOxI^US9=B3AFP|H%kr6m@cj=sexY@2$ZYHU?d~osD^j;|S zCqEra3w1Ea^V8=U9{@yv!yx2&(rIuBrH>Qixr0O3^+$&nxSl4$ zM8##W>`r56_50%tR)K-23N8kwxM)}kGBsas@Lq=cWHJ{;#l)i3XR{?jl)6KFU zU`vpQLKqXJ&~a~(c*?FiF9vLOb}@ET3Xq#1h8gn4XgC$n?E@Ln@^Rc{QZ-q}QWz%5 z@FLo-P$glQLl0T+w1%YrOL<`|oDK@k6kmx(QU}+Iu>9SIFNX?6_%`ZMXmPozxHQ^_r+N0q*#FPyBB$1RpzU2G@ur3RV25%}pNq9)%6G zcCg$Oz1P|T?k(nQCx}THDj~`Rl0&UYvz-uRhrz}3JdiheQb+V@LxbGW z=u0B5&K#nEgF?qSaN#l%tOJ7Ua6BZPWRM-Re@{eJ=;=o0mnsK@vlX0$xO-N9M1?c( z#egbr9IDR042y^_KL~jR&RQZT04~>hUa=26eA6$<%kEz&wSM?q-S26aONQ7Bmo$@u zpDl~k&hu~mp6&0FUp5_AX1sF^znPZ1WSz+(lHnc{yt}<^@&b|!fWGddCX|>VN3nh3 z;e>_}uJi*+bniuHPyfXehc|J~wOvt0T?vgm#1$JUyu-19)ae`v=R2V1&zfMNUv{k@ zg(UHb2+tM-3Zr7RXHhrz?p-G^g>_S6-x+p1?1 z`2!~LED3I7&?-`IS!BESNEy_|&4q&TXMsq;(6M2y^XA3-6dMYei1vDa6DPA>HY+6!Qd;ohE3Y zt-_$9KSfrGJ?&GEjv>)_kPl?>Od$-DM~owQ&B%O7pZ_MVHb7o0=XDYLAz{uCeQoHr zvy^jW!TKNl`p2mC`J0M#jB5G885T~#revRtaZG24!341RqpOCqsOGq>uQS_Oxsd7fuF_%RxlFLl2&2O^AosgL{194$Y%^Px zEe~>Lw6ZS^Jb9ZZ%$6-ed3pJJ-mMDbngSA9EpR$kOq}d5jnpgCMHoYF6K5jDkGwO>^2W$2X*?Wz(C0~M_%U&uCowH z7Y&2D3V@=q4_t%ud$jNgBus-Af}6&FjtoyrlPu;WLl_A@K7J;*q1?!O_u0dqMr78| zesHX-ldGNUW&da=y-SYb;#M4n5*7dg%`n^|lhcNA?oN$?4{PdZ7Xx+LY9JQiyzUEe zV;%{7YBDex4b6^|BuNtt9JMx#I%%0PdZY?+ggJrywh_TVGXjc?aoK=yRCsy)T`an; z&MH6;$-oWeN5R-0Gr0Nt7%W5kQSz*(7?n^e578yh(1I^r2%_PEN^cQ|;b<{>ivVd( z2{6DA5nx`p7+{9X)lPolE)Nn*PK_94M8~aJVJEVf`!Eq4m@vI4tc3D8A1TLhs}xgf zvZl)-42E$gTpO1CJt0b;-!!~?tm25`{i!VXcFOx(#Z+y)=wOIW~qJ6-~YX}z4>PXfO>Sf>1mOkGXRJ5Tmi7* z5P%1xIk=#v+Qn)hUi9q1nY#(X8FqDX``%A`H-|0$PK#=oxkD&YaO57hwTPwn%UU5~ z;#~djkH$Y!zOF{?BKs&>E&Yq{EN}n1@vb`({a*Sgn!gccAkAN?aM^XnP?3#;jt-rz z2nRsXHwrt%e3LLMk%c5H6}+-EZgEu+h@yk&@xeBbx!o#V9q3x1XGdY6d%$8IfuKj8_9zxD9V>|mKn zi(!QV91R_0z}F_cpS%on4u_;bhlS)dC*C7zq+ei#09-N~>SnhJpnzDwWfCLKG1<

~x^6p$@sq?3*XY-^)@uMa~9l1s!eUB507$Pjw%ojFQ1Qy7%dP>d5vm zN3g6|^Yu^l7km1*`)`_YHQzk=#Qn&v)F< z%gWX39f*0V#*G8&Zx8uRVU7Y2%p{Bx6j9VrR#n=(&#GH=#dk9Oe7*a(HBXt}d)kGs zHpV748|E_I+RBPsDAh8LX#n02bDVagweW1<7+8MuOwt_#?OL~wmzweF!&^rB+xe4K zJ(~{A)yK@Ij0R{!`H(5qq~x)IV%0>V#U%CT6Sz8ufF(U)2R92q=t*ZGv<0gG`?HB& zKg=K*519Ofh<;<27`UTKNm7jvgAU%|rQt&}j8xJ^ z8gQGZR-kT8O!_OG6nxt=WqjZ2BZ^L!-oS;iMr*CMUwANK)ObV~TUltFz>lt4cS+#l zxw!SrqqwKo!=&&ehvJC>SkJ!3Rkpd{LX#DtQlC>f%vrWS9gOcqOXhkVe>+}MRd74& z61~ZsNzB=TwNsK`R|rz-hq@OedY=i9FR|^rl&+k(v4VWydG+`vTe_0+-lMg`o{*~X z?u@F_Gsv^2-#kw{& zIL)G3WwEII!J~wDbH${0*xg{C@)lIRsr6I2s?aDS3^P)= z$$nxJbuDA|M>lf2s3^=|Cydkz_RGtV+TxxmhbXl#~ss3E8 zVY$KEwe%D50uMwEz6Fn(8u-FgMmNhAzqj%9IS=L)MP$9R)lh%XQ08}oG3^kyWcyL0 zNC%vbaRz5gO~Gfcdj>k=Uzjp}iL953(hDYAQITG@tNBeU9~ z1`mn%rK1_@)%(+K3fj=`myeR90U2k=bhcuxs*$Yjn1LmiVhil{#u+j}@!7Y^A4W1K z*f)HB+|XP)TJ7PGd)~ml%bz%Cu&MS&>GNu??16i5pY$y$*aoRPEP(_75@2vE#R-&j z4F}B3v1%8n#-^V^-Z4&nT)%&FeYV`de1$?1t0HGf%1Gx8DJZT=Uby6W+IFLkI-^K% zv?#2WAf363=o-%IJ%w0v9%0lNmCj(LKA`UZ&K-6+aISDkqqFMzI`91AWq!64Zx6{$ zwf8)KqN@>Q;%vH!Mb*v^8z$-QT}bxk1y1;-gt9uqtka2)?G^Poo3XQVRoWs_!4=vt zs8N*fi)Mcb{b4gwh$l|#)BJk$UP&eEpoN8h@7#m~&rtGn>ZYwp=av9Wpq|15d^%(cMF zC*If}RTEp=AGf~_tW2H$PYcEVT|&?OZ@JGu_Ls(Az|%ec6Mqs1D#L`jFhcWr=l;a6 z8-&@=;>Svyei@;HbEQ00Hy?Wy5t}9*CTx>lX3NRK*CO`E)1mEqJnW(cgI) z2~66C)$>~VW~Q)nRHQLk%(~@1nLnSR1G*`Hm6rT32t)ARgLKVD*{4ajg+?x$ro42W z1gDj$4F$d6=n18z`e#Jii11BZqh`9?vVSpIp8FD%ABRZ;xFNV`#M5T4w@YVpB^|z| z{0XY^SH#LfJe?xPSZg1p`+rOI{Oh0Oe;WS3{%`bOSi(Q{m!@AG`ldhplw+7VpU@D1 zjwm?6`k4UShwy|Qz6UfkpuM;(!qDl}lq;7~&EF>DPcH6l$&?LlW*M(((6lp2d;I~Z z>{RGk!fTjT=hP5SA@P1>h2!4eH7D)7bgH>&DgF@=QuC)W=ZA=GnD5H*+z*aVr(AV_ z=%PR=a&N=-t)VMl1wa3%J|Qjaa<*E5vp`QsbvmDcs}2e7;ct1mZmXK>55eIdoq^xK zE&Zsf>Yw`kmqGIUPeJ|<*1%u(*YNNBGWqUO8ovw-9pj?um&PxHoeMimm(ZAlpl}|P zRuvt~V_d9jTbMop=>^824%>0n*Z)aHG?Tih*_n+e+3}}T7Nql<57$Sd!xem&ljLN0 zM;h|&1_O7fM>C6&T{Pu&&_vor3m!UmGYRHFb4ZbatQ$@yUMrmdxj|yn>-+soc3P7E zh#nhLFlK`G5oKwIjvFC-iK;fzj1Qh;`C1;g;b!_!XP9Oz?!EcD*`}TNpAZJd|ARI8 z-*l<}(eHm##s6zu_AmVsV2u$p|M|G1?nI~|4Eh^8#`=ju?t*854ht}+e?p9LCX{r= zyzcS4hzgEKDNy7c`vGxwo=TQAibZ4GSlEUa zd>{O3=xm{-{Y$rl>!dpytTsG@Yo|T1;2}V?h@}69AgWb9sNV6n6-fFt8NQ+ZWNjDb zHW5PN?zXDaaWJch-==58rLLCr67L&ANS=3%+Jn39ehsA+;mzN9O8vc9LhFN>JhJR|`cf)Tp7Ai_tL4{4UND#uP5 zuqYTxJ5&T+xEr`{`2Vt!1LP?a0ir6)b^96Pq&T@c73_GaWu;e#;Od@XJ8hi&k5Os? zU;v>YF}rkL48=78&ywl+aikPQ@q2SKg7s4h2E7Mxsa<*nW|2=#Gud?Cq(}t4M46a3 zi*0Qvk?XXx{KH|t`@QV{UohYQg@MvP_4~h&_kXhdUta@%*ld#jmi%Y_YLWME z{J|bLjb8?rI4w-$586<^o_e>dA&5Ik&(FcBo!_ri+V*VxuwUbko@myRb`(%qkoMgv zP{NUzsX_{iQ(qsbl%Q*K$(fkzVPrr+3ZrGINAk3UuW2s_8lr6TG;8=FE>IJUM?F{9 zo;ZV5VAeXvlwzG1rvx4fr6u}kg-v3Jm8>Xp84!mt{)_aI|Aoc)r+)tnukk;p{+F$Rzx1mHtN+7K zk<-i|{~7g;a*yTcG3@BvL|f99-dhvs(! zexC3VSbe=o&Vl1jSu!^ETWK6OXW1%!`JeCqapG~n!xcWyOBVE(k3I>HFb9iqvz^u< zN3S!)+!fWR?b6cN`N3UH%kZaTpv`LiJGJS5r+fXERndQ6!T!>(CXB`(90HUbONpUz za5@F--}r-5(N^7ubr=m$geQ(f8B-5GH;ekh2IK0WNn8Lp8Gam0C1HWbj~)tC03tdbQ9Nw(~P z8`4YVk9~ooKl5n8wEp7{KCSluc6HOpAvgv=@=+`LL-+*um&jxW;V>_{6fzkcM;-u$ zkmZ2+1fYk+g#2`Yi~$A!5?BwYgXn<(2n<+;=m8Yk|3m z&$>B;K_P*5Y+iZm9GAKbnH!*pAQQCk@F9qyNwM?->%%s_f(zQnq!TAQ7t$n*lghS# zU!h(`8Mep@)jEb`8wC}1)4g|FPR=oMVYsB5+f4wXM{vNw=vQHYC=LyVfB_gI83P9a1UMNUlG^(DSHXo|0D$7)Krv7N zRVtZEGcr9UmyS^2zVaIUIdieir4dLNZ}c3;t2Avv{1SR(vG3DxID==kr``4%BEW4tmSj_K4Q6Kd)V>t@|!s$pPZzKxJBVcx}Cj z5#h*Rx}L6)aLTew^>~@;py!wCcYkZ}h0b4hC~9}4d~J8FtK<@iyZ+Qa+L$h#r5J&P zo~hq^E@nTaS)OeK%?@JAwMyXqovFQJ7`AN3&6qWS=jQn0kB`#z|D|oBB$A|b@zdy{?kmde858rCd zy5x;57}#dMuM{`-xbj8>ki0_#L;-p_W{zm+-Del4Pr}oMv)x?fV;4#KA6{ls^ys*< z*La=lZG)20X&&?5&L19`ML)dESj0@U#^Xv}9RDe93pQN3?(PyZ(_4@ZI!?yj;-5zJ z3bXShB$W8b{c!FBMX(%0*qF&*v!N8+EUW7H{OSwBh-84|V7<{zIIz?tpd$e=qtxKH zQITnUnCb5cIdk-I_$9u`{wzm7hA?o!3cq{kkVtCCE4gf}K#(MUyzv+F0H2yw&{XB8 zghj{rd*W;(Y=g_92{<=IHitU*{ZR95hkKopCp6IC?>}hDe)Ff#{M+$Sgs1G53iIg7 zogf$Uh2)z&`Vfb|zWNRw=3T2wT}Rj{?@wLuT?-a58=$Roqb+vFpje*wi0H$n`WEJh&*HBH8^b+X}e+HA}lO+d?Teh>b0too}SHT~b=_{D?=_5_RLrYq$w3 z-fq^m>L&G9jPlx*7iR+J=4u@+&M5{tMTa8xueU!5i-w+Lv(7YlaZ;uu>XpFA;nQ99 zUuL2~VrL4k@X7x!KwEy#y7uw1w9LD!c`bfvr{rTD^QG0ueowEYW_*epOWZCs9KF?I z@${NC^>s~0Cw2d4@S8ZVzIMM2>(aZ$DJszcIcMuLHbb+n*fzU;rfx<`(Dtfp2k;7i z8jxX2H1GjzS#-rT$q-kDW7%v(C)Af1*Z_k>4*YcRG2xbTSiEK`c$CE{C2nMP1CC__ z3D4<*1aG>hC$WM47JoyG%%~TB=E$D}E<7%2I@SqD*lqqF>TmZm0!^Kh8 zQJtevi6&zNV%7?wd-_$bznyGRI{!8v00tS>_;9k!s7rx_x;FhUpl`R)*NDz09r?mo)E4GXxBWBM=H4 zvYhmE^gVBauF~tcY{gGEBdYzM8GW@J78$-+92@II`nZ_I(($<^Q^VksGHY4o%0Q`@ z?^R8vDt|R*;U;Igx^s8xEtE1uyZ+uP9Dlr1`Ax&S(W0~WvK~J=(%|=#DEw}SSNW^a z{C|Jk59Qk&+_*?Uk0Aj#6aW(eFMxg^IAJ1feUVY+l)?L&=}CzC6WgDt2{Q52ersHs zy{Ba>K6}H4M`L^+XrmmnYX;8(xCexyYip1t$DZq5BdjpAY_J_q)e zY=Po1EX|<5fsSm>nA@az6Cw)D2#`Vk0NG!e zj3IHrpgok%NG&iatjucMq@?yNJ4$9%Tu94_oTL(>4H^o+BTc6)U(^c%&eEey&2!28 z1Esa@bZ=(&5S%D@7@9Zmq`}kxzm_wOuM%SLy1-2{Hlif{N7zek)(`l0Yh%G7fvvc3 zdgGaG9f5Q8nenJNh}st>4n*_4hJo>esgcoeUS**6X5rI4ry?r+T6$dWu`=eVH7 z{qK--mw;$-mO)-)(b%=J0YR4gtQ}*&$DUN8-}ZY}Fb`~yv>3wQYM>sk3UM+yo6tSI z+~A3b!<=Wo{K-jgtXo)OrbaTeD3en9{W3iYE*u zYcr0IxIYriQ;xlP`szCx`16o&@8lm3bRh;oU*1-AMigXUUvfu?_P#yR2Wz@PY!$C?Ydtejk{B>de#vEJheS=6m7sIVmP6il>X&`#iUI(!! z$InL>^h?}kM&5oqc>L;Rb!=NRr&9cjDx=^fnk%I|7DxdA`nRr}9Ma)@`7ayhc@?0k7QN()$Wugm^81P62*946#RAsq^df@1B&Yyybx0d+$@ho6mO zFOV;dHWkkfr;B7(|Aqp|(?9cP70fR?4zJkul$29i-BK&0-o0gebhe91z3?8&3-n+( z5R3q{TY;lnlSIPOxiSC*M{6PR=9L7ul*$;xvYSHD7y=ngklaWKBNnoAo;h0wwG)T) zm?GT)BnPamKdkmy5Lzl6oX2z=w`SQFP=9Nr@mY-dC9fs|>hR*{;ZdhTcxUAp5(z{O zs*DbFG?X@d7J17VwF1o9o>=(cIDYLts?S8XT=kiIbR0~{*Y?KJD3Q{|yx3FEA{V`R z57%8F5GWuxUi3u~7npZE7{MEz*xjM9ai%Zq1XC+@g~eE?8_3F?Nu0}T`kirKQ$E7l zfkze@r1XIMQ>MTLH^bn!CUN^UTP*jlNL&3_jl~G|Nfu2SdgRE1u<#G^n4VOeFtqBK;@$1?s%4-9{C*$ z^b6x%ojoE_125jpsg;fo>OlcXW#D)hbCp)uGM}7bQwvv?#S~`l&Ze*8O-mcnWsBNX z2Lwx6A|MuB=*Pp*k3}AiE4-mnhqmzhY_o4yWR~LJQT>y4L~52iJQGC*}c_PADJ*cj#gIe zauOIkiCz#g27{Wu;xaLyH(_F9r2FCAlMJMv!pmsj2?C}Iv~9;65EKR3onr*aj#YM4 zrYKMJj{VWEOazmBfN62ZGlIwa%1#&XfOO$Ar9b?^m&Z4FTJHUD)OGx|OboBUs-Qr} z%x^GX)8t7|*3_pIFaqm5=ZGmdjzEyxx3@Ar?xd!-4qO>zk?AUB4shXRGC?tYh@VIT z<%z&h4>ieA0y1?8NP3C;)i!p$mANahho|`f<9Fu67GIKM2hSPT7g}3W3bgs7;VCTh z$sV$c-4TiOvcWw1Z6Hv3{Nt#|n4G{byvsd&xkTC4D;dS}9P4NL3iely+Re4$k$@QLi`1RstD+c9ltMZKDsT@LJ z#AcGh;wb#i>x9tVEFEG0lWNu}o7s(;CztkmqD)tltXHqyx;xT%sW+gry9ggffzoUp z7n>&3;xZk)P(GDKy;bH@?#%Sv%MWTKQ`v&~n_b>opUmqRTtAbiMG|Yaj23_9Md?OR zZunDoR+_z?dR{e2lA)(#^ZM|6!2#!|2Avvcq1h#`R&rF=3G2P*36ZgXq!#-i)(V3n z0tE;3pfBWkE;MHtasq>v2s4bHh~SHdy^JREppjtT46SGgI*RcMMgv}XT zV^q*YeH3s{w|ybQO+YcmhB)31Vl>#j{AOU(Q|+sjK)GjXwo`@O1H2iP`ujM4(KP4C zR```++4-@BOFy+lHX4PCR&#!ggi^oWox1zJXirF-v^?SC0|GDxxbEGf7@>D*8q|W7 z9NhpiZF6$6Iyj=GNtQ1;B1-cUxQ!<_J@Qe*Hx`V|8i@%W94v_G>58MV!ExsrR#{K=_=U(Vet zwPp2>D=WrZcmxx{o8 zs=k?ey+%DUn~NyVF3@B&ZLv3&tCpj2Z3`s&?5^ycnR=tuw0L4_crb&MKH=PO4h@7q z4-^aBaKaYIC%9cWbM-`ZTHvFLmxT5g`j71&U3pSD?!WYqO4aaDvVXDK;#4F+0su0a z>HCGu0M<5fko(2B0W+q|=PVH-?~W?FDs|?K_|>CZ#~J1PY5CMN1%1@Fl&T(DF`Pu16R?vI3q>7p6icW3xHKSGVh2 zF(7+qN*NdlRym_!1p()wujw$IH2m)RY%V1h75O>)Jp;~2+#vbAf|WS#>tmQl=Nu*y zJz)Bh>Ef02m%m-LPJ)o~#zY&dT9Y9LO)@?@DmPu-pq=NKY-`cOx4u|ZHl3U;@7CpN zhCrZUUo2P6asouoK;yKVK@!fspS82=EvH6bi5$1<|IJVL$QyFzCEE`)W1M2lkm>D5jk$?oX!8_m11>V`s_AgF+^5hXg_@T#*DPf@=M(0&|6t$Ae&f+T{ou99+k4i> zvyS+t-)Y2rJ|A!6#U^?fL35CVgV#B(gxOcE?0kRDUS4T!k<=G-t8dx+@~VpGbw=j_ zi5-De%1M|`g?ld&5@F{?`j&A&4T^u*BB3zr@2_mdG#tsyIq-o>oqc-uD~hcbd4)Hb z?o07Ke)}r;)h*j{#gx=P`c(rA z(rEm$9B*5&-72ihsP0y<4(Ma$y71W0jtNo(X@zGB74VnNz7F;&xEvKx6O$SL zEn4szs69xp;vlt&;@ zWdrUtoHxzN1>m(%I6xwMtv~1-_i2cbVEk5u}g528!{6>neMAn<&)~6JEGw zC2etKh@o8O;{B088E32U7IXb=(uac^UvDVZTYzCZ858aZiWE$${W*(B~O#@jTP_fXHwQk6ybwNYT1 zZ{t8e=rVm6*nFIad8VHh3Wgf`{A<=*kzVd#IIKDVH9Dx#bN>nb)gKQ`JRkL6yDT$& zssJ2b2Vn#N@lnlt=&Kxjc32}|EkO@*W*i>21PTkEMrdd901vkHDsM1q1`q?sLLx{7 zaZR|_Zs!8npguye*~tZSs>5O02zH;Z-rrO|bO%fvL`$`C{?wT0TXPN1)>7i_5zMj{ z$1}^%Gk&mTxLApNi}vk&LBnuX;Mf!n&!rgUg_jpS5vZ4E;$blXcb1u=voButG|TLh zxH`^Emu8bOQk=?Rd+U8gdBq2=H0g*3?_TbuReU`x?J{*ey~ri)cP>F*I!d&rU!mV? zb@-~2aKfFBC!&|+F|`NhEc1`veN?S(SX=7IM|`y~ov*Z0-f$R@Jf!~q6uPN#bbip` zSKB!CXzy|^^=S6_3F_A3C;+{3>a~pvn2SC;dB6{2E5|~YX*bXGDM(DeL*qy5=P?NV zP-!RQ|HIyS05$z>`#y~jLV(aiHB{+_Dj-UzQk5=MLod>c6bnh{y+bG}U8>SM5_**m zij5`+0v50!3cPsk|D1bg-pqS%-kUdb&%Nh2!!W?!A-}zUpRBd_UTb}MB&CikSrBxW z$p8YgBqJ4C4}hRoYnV^dc@Vyw#~zKn1U7Yi^v=j-iD^gTFkDN^MS>V-Y8p<7n*a3c zF{vwO2SXgrS|H; z?Xi8jm`nCZZTq$rf6FR|LjVo6fjmvGnrxvCfMli$1Q6_1;8b-?Z`gpcAnicE2W2i( z7m{Vv*>&*)+?BN1I=R%vlJ4WdJf+=A0|Io)eovI`K)v{7xly(9bQ-vTtwcMk5kM25 z7#F-q3S_&%c3YyAF|~>To~HcdS2v>URrZE$LHO$xKB{4s#P)2V5w_Fb_>F}!r1)Zi z+;KZ)^WVF`Wl@7rsSnf{_iHGMpx^b52R>L0HvagOna;~1HrWekXU<`<%(EJx{YYT& zF~e*Jb<*;@i$!Yv{nW$fUaip~E-sZl!~0Kv{Wy$x((~*3>1p4rL-13+uTU&`O7_9* zsTdq_;f!7`k`uVtm9(Y5E{P_%`YlIZ%(5Z=fE&w8D4+hm_BNk5z;!VA#$$j+Tx-Zr z+b;aHxz^?-lNuwJae4fO_|%(9b$M(}-^S){P>xQX?EU(^BIx@1jqHYoM6rRv_lw#a zCgnwL@$gzl$vNe$5jMr;C#~jxPNB^!v3w95XdVWNxms>0$<{OyQ38sYKwrn~eBF~2 z;7KxoGt-Nu(4sC(Bh;eV0N4s=Is*^_4PnIb8w%bk3+$u~WGbSY7U_bM_~VkvLn}LE zH$59K{Kzv`@pi>jt21VnZxk%uTdn|+Q@vO!a}`Esg`g!5u3F%`W;dTnb62odv&)%B z8A}$Vz2w;?J1C-2{@(R#+HB(^Y8^K#alHm2y^wO}YFQS)432v1wf8LbRrZZ)eNHs3 zby6+w=6xU*1+5<3(I3Xmri7y5!;?Cj)l&VNx8`|vXcBK|FE%Y2&@D)?{$8r{uuyni zWYlTXqFNr_&D3-Hn>4BVvnBlG>cf-YufKJ|DUKWELW>!c)DuDWecYPSnoGSZ_q}c8 z2z+gAFi)EBpAVRRpO+R*k}rW^EYaEadk6ErGz35YEK=cave!v6EwJ~|^|h$I7Fv%ejH5IygiUwL;Cd)Lfe!lIawjxXFZWaZR zQ4#lW_r)%d&M;hxM@Ky7!K+~4K;gB^5g-+HXl=+^FPM7tmW`K%&p!5j*!loOARuFD zy^Fc;rb?g%pL9IxmUmOfNy4P+=@0fZr=+FRQ?9iD#oNaM0#n5dg487sziERIn`w;Bktin($=2kCa+JKx zt#A_MBkNl}dcMKV;OnA(y5VTb8i9EYS_?GC~1_9Y{(k5u$=0nin$<;LH(O;``3+a%B#1dIJ$?9B4snZw2F5S0x%WHYpq=4xhp@oh!r#{=lv~rq%bOc^^xTF z9`U=xLS{}Pk6X}8$m>`^5P(o|M!S>4ycg@wD8KM}EZ^c?%sSR}Y0jspHBl471nINB ztrN-@&0-gPybyiuwZe;jus17j00tt`U^0B7y|5Y^n8~}TMjv_pg1K`7*x`rOHPykKPInEF)abOWGm+N)H2r)-ZB6h~Z#^&ht{CEPA z7D6h~#S-8t*P2=fOT5KJ@&<|bv+0XYPj|20aFvgT&I{}O2$c>G$&HM#)J#COYbE)N zzCXHgdeWjRhcu20e4y*zJ}YG>m1C%<#b})Y`J%uZYb%07LQ==U5}I0f>?NYJ0^6VL z_>`xd?pS+%UtG4icl+Qv=XYfgAQgfe$x{cwLDBFS{z9aY7N%uHo@$DN7ts4R`+G|8 zpbozJN5A`_;V9N?ze0p=^@8`dQlFV@ZhGvW_>sstrc!(@wlirSiN)qQhct?X*nJSw@ULjz8KdTl4O z;E{+E?28gph42{&U8r-7gVcw|y&Qael71nVuZJx0&ETfNa#0%az^1J3pt;)ez|(UF zQZ#uNgLrPuJSGtkZ@mdcZ@j69zEW2YMs^2vH4+%_C&_o7_ec?m-d>qHOik;sQJUHi zLjfIL+ke|L^Sb@X`rbzqiE>e!WqnJZ3pODRW5#=_AxgJ9Dq+%8QnJNQDrL>2ChmTu zF3NrK<9pnF7UYB=-9mZuttyQ+rtStU*4qm4@)7U?9h)C7f0A!LrOq@N@aon^i})#e zhxGa3-kG^7z5Hx5)Lri(HXj_rbnQp&myVIT{9>{1VQFUlo)#JAA%Q{=ckQGH#}tpT zTP{7ATZ`6myXc(Sv`)>;{hP|n7|$pJ&F=aj>2~43-PWc&apCj(g0^CX(L3DnA&z$nzp~+g|u!@^|h~n*7%^|Dq4)_w8Rw zJFU&Q$vD7f^;KtH!p}d#RIvWy$?lx()H3EL|I+0PSZ7)-`dn^ro&I&(a_bv&R<*yA zm}9L1b&`g0=0)|^BfiYXq^H&X+5Uq+H_2ncItM?@O_{8I__mi`{dNA#1+xUc%KiTO zZ~6Qa)43=dT-BY zD1C_crCB53zR$yaeK7^D`{5b;>_Rl7fdCcXUZR0 zCZ5-tU<5`0zQD9Kxq#RbSg))o)wFMNVam-w4=21dzG@~C2*h>7Xr?DN;U=k6EO>~b zHHsUFg%>s*uH?B=^_7L#>O6!%CC?wf4_>j4)=TG^J-o(fN)2-_32>vyTzpg9+q<@R z&m(jxwpu91u&(9VU2OV1kfy9It8KOAvXeUf?)u|t?v_42i%%_cjHsSODiPPpIC1$< zP2jl7Tr%Pg#f$D42r)5;5^p@Q{PnSFc#8shVmRXx4VlpcS0{c%gr|!(qsR9 zARX}~3!r|SouF^h?tP<_8f(T%|`dUg* zUizUgi`B%#;_)2f3io)3&uS#C@C}oc(;T}i_M-`mApF;FEF+jj+yc6&kf0oRM~J3> zz!%*xOWwLT8u*Yh>nF`9yb_yV3zcgmNUIls?Zw>x(XCcz`*4+`gba&?!^;9M{thoz z`Ekm(Ectu=#`1p9%Z>{R-Ld^x3bz3Jw(kG{LX%oetql#v)VN3+$6Q2yRT-Gp<*OIq ztY7j6l(~XE9r%O=ktz~ciP-_5c80Hwmdc8x$gdFB?T8hqgp5O-`3T4ojTbJ<(6-Xg z(xa22jck9XXFbIo>$Z_$;_*Vx7k$K&FI^%f!F0u8oSqn{SE>^gXXk&P>3y?nW)vtw zg>hJ|*5K0ibIC+CnV(xaeXO6qpWG4{)B1HY#n$4W7<C}sq5I^Asc&%T;i`ts{mmck!M>Y4djYL7 z$ItHzN@j6VQ9{@#7x2c$v-&y|ZUvTKP-H}}wZ{)VxdA9le9@DoTZenq(qmJ#+THqd zDf2li{9+hYzeEt=Y$5}f^arp;1os!&g}hJo8`ko{Ui+V|=%cCbD5fKFq3qJC6u;^i zxX8&U>?XWQ9%MTc@lh%&6{8;sNl1gLxpIq5M%S=?vE>~cxLTw~n4_BBm>Or;AGTZH=r|AE%dLLRj+*9) z`!TbdSWVvWq2-M4_34)t$()dwQzbnqtl+$9_~72Fd1rEmf!eF+hBhEf5Oh!Cuq!vp zK>ak>+uc_G5k!pR|8)dqsnX#31zz@jsQU0%nd=w4<1iyKjJh2miA+E2` zDr|zWf(CUJHpc)CTzuW|>Q-31n~_O+IBDNm&S}ZVxb>X~y~_R9Vh4{iu8y~R)VM3{ zTJ+W4H(gq^{Z%c@Jn5WS^{eqht;N=Z^n~zhl$jTbatkCDUD*uE*K<7l=6+S&T;d5T zNr6R@346<_BFm|5*hQ!O;Pj{S^V7pSi&igsDwjLOUxpAtSjrJNz`=w?(P70N592c` zMEg73OWXeFBF_s3@WsmrNV}QZt~fbz5o58jP#Z%DPJk>Q4&Bve^hTf6LxIHjQtkrA z4KP^pxlm4up@m!Q0{)dpobAb_>4->!rz!lMWd{7aT%8}e#AqL?Me!$;^VT&uDMj^@ zdPfl%MJ|$6Z~cp!FD<2q=$0tq%ckyTHw@e7e7_NOE1AWSt|j%WiOkQ2FDvw~dti5o z^)f==UW+~1k-7l@q_v7o6nzWsE8`w1NfRfQ@=?Mk-c1L-7GQUB8=#iJSG=3h!Pq>J z?4}wlnynb#Pj}(=+a+Sfhhl%)ENHQs-K`d@53;7aOtWk#ux1g}E`3!~Cq<0^V$khR zYg4Y1)d?lFa^Z>6nuFiI&`g~P`RrA7N)o@&lnVhszB5F;{&qotQQNz`{AwQ~M=WvE zp?CDkx140~J2rc?`}*a{ySj8er)5ufBhm_OJ>NfV+WYY^sp;Lv^XGpE@Vx!}@l|a? zL8YUT2J^jxDdk`g{453DFL*Epi;>fzaUcBb$1NnP8GDcWSzTM|J86c-rLY&;EoMJV zI%~G|o11{0j4}31xS5_x_ngl#2jaGsfHiw(* z8phPVjiFj5p!Yv<;>pt)S2^Jl9Xx{si1w&2zK%$+ALM@n)4d#TJ8DMTx`ZR+CDiIH z3$to7I}S_j7o+*r`UEw6UJu&%vHI{+bu2n_XtHX(EemzE-hb$-L8y15s%oq2@1vt~ zdIEV2!56yl%L%{Spz57vT``hoDNU8Ptr%3h@7Bb@FtX4k#w>cz)|Sst^S0F!*7oCV znZ*-|4w~1NlY*$gPsez-YdyR@HP2OAFJL6?);kZ$FHft#;~oTe9Y0%Im^jT5JnBE~ z5q|#Z^!?LgGRPn8a#d%!l3e$C3+KD4{0T~jK=DM_W^h3niBfDJ_8po!fYg~`kHCZ* z1*jEapq|#*AX03m`FPRPMJK6W3bHB8K#UmA4n!mqa+qi*%hWr-rtVu#ne`KNUqsLY z^M%xkH^ELlPz4nxP80{P+1oJAIBk2~#OD#z@(HtjwxWi!208bxHQu1?A@xv9G!7uc z-oAMGqaBttaBOq0LfBn1 zMb&55;lV_q6XMx$)q~p7?Ry0^=ntNC3kqJFW+C3he(lm$+UFiE*55u@_r!E9emVUu z`r*^LMPI4Cr7j~p0MNKvDx5@#f`IsF}w5eqgr6{qxH^ zL|9_CDE-T?lu4#shbC~-H2zDkwP|o%BKov*Kg;Ul=(`%#y>V(~=H_-HCHvjoN2kZ> zg(w^ZLM^1>!vkb~tts-r1qn!Z_oc>T{_uMQ3_BlqMYfCLKgZEnI$o7Ht2KJD=9d%P zfdAdX#Kj{GdK7IrdzTap#;7W`=BQ?rC2OZuY2b+G=De=MT3)_C{}B`8pl}P2Pv~7q z8{8CgVSHqM$y;Wa^<1JKRYoVdP!8HvQ}8Txwqu9d#Q|?XMn>B{FAYS302Uw#m?aOt z?OiL=dbWrt00O}`=)Wu1wsWT^@Aq{;u)r0*g!nAtIoFTLXX}l=>zo?3*L=K^3mQx4 z%YAokfzw!RytID9ua)X6rY>$^r{+a=-4jnTPz!G4MxED?mqr#*2=r?s;ZAp0$iPTIH#VoiQJb(*oIS=;a>>3G^2RFv`y zX}x`ZTFE+AwzqMew)6gEz#3Z*!_)_zU#CZ7?AKIJcfN*lO zEx9|R%3EnF6Ei&*^KW*qi}s^O+wvqKAK4*j#ASRiF*=cJhmz1 zEqZN*Uk#7lfyxO>BR@|SIz3lUpAxr3LgWPHICNDAWW`y2fvreEb}JMT@D5eKrj8U; zkrT6((qsX^%}6?hk-Ln{RP#4#+WGxWN^OBz4GkogT0@~-mnb=|wF;`kq&0?3Cw*KD zYkj71GBq`tkXv(zfdt}>)A(Oof<`0kqt}FBXn~L^d%0LC#csm8BDlkw$^osIJb{;c zT9!666046m<2)Ch`=K=2aOMn*gwlrXEH8e53QwE#*1LLhO=l+e)H;iP515V6T0vQ> zg$^kXk7~Q&C9`+m56a%nOMPr;9D%cUeHpeo zKlke6ukuxkN2+u~4qppPDV!_y)Y=23Oezztm2zG{kSG{as-kZpGmD*d<^W1a+dAEe zp!_h<@|mf|h%r z^{(0dY>`pRn}}qg)p50t8yvk~N`zUP8%H0uyH-!ZSh}u{T4sBVfGO*;5&&8gz-I)2 z^!a(Rz)4PMl87)3)etYR{9J0xP~y5~svHjxx(O#B*VH)>X7oUu(M7mA0IMTM&t#y) zN$wN({Ez|M;aC%6*0?MkV7BKk6FJ918xaZp3GqlH={gAugT%)0NOvyWkdCm*FJH;Is*XAO1 zbdlL03eBHH3t*(RLkGld*JL+^)989$Z!Y4U**1!j1mqvK;?jM)Ov_OK=&m&TRm9H-8xr3)8 z;;$bM@TY|hwmH7q`(S%Ur<{B827(D+bf@L!#ZxN<4zrVae<73c<#y}aqe7YcHJdu> ztk;isR2E;UDvc}cJ}urQ$UYXxYWCp9qrblQ0xv9AaEmMv3u1LJ@yrd@3g7MoE>1rD z7M2R8=$n~9Qt@H@Kmb}C1tE$Oa5$7jl~qOjb=1`;8se5HDHb4tvINHpKnb#*ZUIO@ z08sq^sTKjk*Wq`2eeaCLXpZ^@nlU2*+j+QHs67hpkOgtKw8X)9QGjxsZvl#fqyWgX zgpuyRlA{F(x-gL@f_f3<*gg`67oJ7952YOmg9h$SL(~xI3i_`?4{WEAm^P;dFceNue{b)9Htz~rXNZn!M;ep} zTR{Tcz90hx(Fr44spRnr%Qjn3*qJpq9tM#LqyQBQlx>$DT3f8m>FW=5;+A7g)@I{9 zj*MHA*LbsWZ({3X2LKZHE=yc@JW(TRS6B(8$vVM)AHwV} z7?&mVEC8-&1~ajaQ(L^XUHhTycgyFC0Y>vJZ_UP9E=aZJj4?OBl6z7q5pKr~zcd$( z%-gOPs}76-GN92U;rA2aE+}BU|IO@vOl)P4JHx&t-`x3>09V39X*plZ)4GZFpNXr-%N)#CT3sdW zt*yEO#=DkJAEZrYJ=Z6Qt-hcXy!sV8k^__7Ge*Uo*A@s%Q)bmV6aiEME^oJXpBI@1Fo$UE#HP97nc5f%Wm46M+kpS$AnpsbQ#6D7bW zjWtU&iJ3`xqIHE-73$jdi8Hyjh*>&}@q17Tp9UHl0mv2*Na=aXiUamKG=Kn2n!6K&#GzU}H#un*x z`dc)c=1pw&O!@m$Jvg3`_co4Co4lUcR?@4yf3G|miJNOyRe z$-7Nsu@}pG>%zJ6z5oDL7*+zni(&-9>mcN13_Tf;NLrf@*@AIt}6r z!l2|Z+yZcV7gCaQmZW_&!A*`<5Zt#?pXkzo5;^okL11K%0Y+kB?HL(>#o`Kku?;8X zA!akOAaaR-3kqbt&WT{8j($Z$hbQ3sM3XUseC+a#KxBJLWYK7LYq=m3fT_5`77Pa& zm?g`$VW-vkbJcbE{Oya8y<%5j1W05*!DyEiB$sV3h;Q@v%K~WP<3I*chgc8}g63-} zx5q^@Ng=s;OmKj)I+DEpQ1WG?#EB+uNFF}`y`uHmc3qcAjn9R1>$3?nOIlPd``tGv zkVGtm@kx%;bF#i99}p~DMS0{A1{**+!3xAM6#xcI?DFHZU&I}2JVwdIqVI0t3>C66 z+2(b5#@f19gFyH{{B{y9CI#yEzj^8FRw%hFMpG}D%pxV6bo7ss^i{&`q2UH^PaW{+8(TLQza6PuDm;b#)_ zM`*x>Nex*B%eDT3pmaT!yc^^ELiOX@jZa>2efq@kFvqF zfXkjZ+I2q1uKu5=H7}2QN^d{ynYghje^VG?c0sDFhR3Jxo0kvL;mA$g#=jZ5XM{Ub zevmu?FaqLG20*ezFM^f|-$c#?Bys=;24A-`2u*l~JWho6{^k~UVOUAE$8w5@bGjFy zgdvOo@^q#ch@=2SK^RFnI=MQ$DF8PKl&okRo}7lCuaEDI13+1*?tfW<^c6}t1x=WVmT3&xK@KGfFsdokQt;{Q7j=goeE;03F{k9grT_Q z&YX9I>nYIq{D z5fUQVN!6w)NCTBdr!!`tWNwJ~OJu?Hrt z=`SqB0)CGj#soc?I>w2H*7(Kba|Kn7XUeZo$!6-V?9}$NXWNqy1Z;yG^2x7zKF1sz zP#^aJp=0k8`=oWWt^Z;*`%%THvALDdJr8h+c^wc7z!*@itoXnQag^jS6g&K zJFG)!jaGDC-I7jkyh8vsqHv=a<3tb#U^v`$H_lXa#d_UVx)jYM<02eyC(Yu-B1SFO9MjIfRFx|?Cx%RI@HetJIe(EU zqSOEr%c;IMu(~vZhsZ})S>Mh6#VpKpvys7hJ7FDNH+5n;@bbeoleq&C9)2Q;{$L znp{JJN2}v3p-|vTDoz9(4aE-NUPuY&_9l9P(xS;wVT!0L-!wk1v<%8Z3&0CAQ?%`y zobjt^+)#OHN@fF+mWgX@S`(PWjOvSuAc~0bHO^|4bGXN`I7XlVH2#qT%fJzh@sZfI zSk00)*%dq^rq90O9T0@3m%+Qwm`USdU3e`raO5&Ww7S2uuyRAE)*M{gqWBeC{YFN$ z05=Rkrk&o#QUQpm2rIrq44j75K%K{webrXU-uK*#x)4GdL;8Dz^Gn>kGyR_OqekDh zdd*k@i`0bQII7${>?(&%2R6SZCJMa`q(ws&YCP*V5^{{cNb}h?KmPGDqyQ;m2CWLc zogx}+Dq0C_c3)YMlqg zV6uOxLsMWCt&6e5s}bX!aIO`>5i`+d&!U=%xIw3v7GTJZYO;XSM;!*6Jo|R#UIZZz z{*CS7`J#7xCJ)1J_c)cw)BQd;ubRr8pdzW7;T1$ZCSccXWE6RjaXI*k&qcSw(*GXzp}_Zo)3Kn*z!;?}0!`2O%KPSiIHc-Egk<{wP0o9mpCe0G7r zMSoLS-~6c`W&aoZOX0O~+vl!R!ZUX6pAf5x`7?T|@% zm5OtLduHLLw0&QzYg4PXQnX0C0htGEZWS>K5alcv&h@#079EOnoqS2&=d!*S8RW<*B8DoF4oltQrPUKIdX>9l5n+0i00Lh@2=xiy6P{mx@t3 z(o}Y^g5}0cPHAdyKPmuGcx4p<0P@*{Ist@6X0< zhPnMd$-I>zO}J#|Eq<6ikR0=}OC0xH8=ydpMo~*z@@<8-pF5C|_5Dg0m>aZovy4CF z;Ullb2hskG*{#BiX|?g=C36|9)mJRQ&bkJ==-3YyVT<{;>4vzGpW=hY5G@I^a{yB7 z0k^)y8Nuthd%MbJV{csZo;RtcmKqP#4w5nr9D}^*oEOh%6F;3|aj`(f-OL521D@=D zC{&C)my!$a5HIh#Y1GgS^za= zA;8J6oi{opM~}3Wfho#3RX_kEFBN1&HFb0OG)V|-;F_GbQI^~_{)GrL31tLk1Trc_ zU!)0-!;5it0jvsVs$fB}W&(p23IUL{kJXOxuAA^E(L~%#s(tf04z!V9Y{Clx4pzct zP?aH4)D@^^tgEYzY1>lfW(f*7=O+q^6!E{CgG6-blAk?`%mQ(`?}s9HBQwLS)qH2) zTtwx1r_04@-6>wvE|!f(b9X=H3{qgR@_O#O)z8nr-(huSj2_*v-T2-4cDJGI2uSFS z{_U{W$9h)gtQ9pTdGefN6WX#4dEFg)sq-G@IS#VE&)y5xa9*UFIz7VTz>OR>ZYLwg zKhu>wTd+%ZkK*?@VAagw$j#%y?RmD8``#hOKT=MDzkJ(YJw532BG_y~YBLtzg?3$B z(>^l$>5MAAcfLx%C+Dp3gCp7ZVy#tt&6CS)=O1AU&CNf}PF{DsVEl>8q&Cp~SKE1^-? zG(5T}0&f`$!+4&NK8%xwQJX->iXy-;JX$R_YC8uc8iOP{iq$O_0|Xc+6#npgE((6= zp;6s2i1T*W!MkRvFwedy{Me{pGb!tz;c7NwWoG=qm#t}ftKIg><17pq=V$)#_M*Ee8_D$*$YUFhR(If)Y&b+tS z&a*kX;vn`}QJ&cTE4#Py<<4#Et}0cgH_C>-wT~=Hiw8A?SAH-aZz%G&&0W%OIGMZR zJoWrE^!M=TY2In>@DJ*Y8a)(@5(aTM6dXy#7Vb3pvMAwNwLYM!A3I^m}5n#7{##n-AA=PfNx1^iqqE(M^#w>gpW8VoRc;S7wH_zwNH~jZ@7} z`-}apHJt>UoA1X^e#gPqaMj}vQj!rp1Xc_S9bwgxvggFiDKeRQo@HVW?edu}!!nhw zD{SX>Mc7_?jW3Y@mGn8eO3@oatj=-r zQm(VlE65&j{5$jVx(7a2|II zmznqYEu4PB$z4P-<%=Q2bWbS=ywmiTo1G z9+Q_*(VS&|x8btVyEq-Yss>Be zKD&HdYN6gE!LF>R@?NdPTS_E8jV(I$9y(-1mo|U8LP!=R9x5-AWcs?Ss}H3-c>8ts zJC%8c;+xwv+UH$b-UQpYB3wS$>Wl|41~Hr8{89f&&s3?Y$@EMNCO@NT7SfiJ)&>+I z6{%Gr*MsawGV7~cn{F+lQmQ#G6*BRkQI)E*zltat(20HcTYdk{!6wpJNd!~&gmzt~ z^z>M*d0;vNXLN+72LUB|S?JSuo1d9)yQf;UnTwra-@l^@V1(?p+7NKf0e1`>9j-)l^7YtPXifJEi-1#)rK(H0~bf=-PJ%Y552XmFt6>!XcNn zAXJqD4DL)@Nz^uIO=sdr=A~+#88I^cSqALJz$kMqn1)Mv=HkP%UZsK%gUMy#+)PJU z{Gvsfu;lEjWr?wjz}n85!TCh*M+#QwP`Ap*KD9Mxk{lVcF~qR^Ur5JL!U+6&-w=JMq2#>U}0aJ)-uSfzXG-&<24m zYMp5$8jB4rwl`s(K(-JZj1I~JjJ0T#OFR6sCW~_`q{fn|(yjvFDwNlRVvU7sqRvJ`R7OOEdg#U)tv85Q1yado4dh;kSZs z7BjHJT{3S@tmh;syE>BkhYs0_uftknWmfntY}0k!fVGwN%MP3hwP z4b3?k75P4C3cu}&`9%zQ@@^REs+GYe7;}80>FQpj?J!yQwJ@n??1!Sp|Lv~Uy$#;3 zHbz#E&X%Vy)ha6=(U=0KnSj9RuJ64@>j570X3;m8%MH|4;J&ZaJ)ZjW8dSUy6yRmQ zso_?8rM*TvXIJ~qW;he`bVY|RBX2gWa-1KtrX$PS)uNIdi@JBm)*dnPQ3k*)(YGxs z{en|gRl~?cAu`})0SPZ%KuwQgd4*LFi&tyleG{og*yyWJkZ5^5x}=r?yYF0oEGn1Y ze8=Z8gIJTOsPwS3mfMNS&cWk?17Ykq#+fNPAwD&Q%{zJP_0Y+3RliwQGpg9CPv$TWm=sl7#=rjM^Zsx|ra`bgFRwu8u z!!z0h>G8-!oPp-&#nzevbwjT2u~K3Z<7Te}&sy1VSFWKZqF%{5Wr!it&c-_4IHjb< zZ4ZB6!*cOk=6Sk{JbH7LzKE~JL}Dlc&r=T4fe@0IeEo0{&&MS)th<4Hzd0-H*XrFx z1$B-1G`}y_o?+K5o0<2Qv;dB1>+@cup~%2yMW(S{-G3)D8Zx-3d-jpKQ5Ki>RZ^{W z^FoWV%%#wvrXlG8&J2frUHK|08K#t4$3k7*>BuX$-S}YhLToh$!opIEG3v(Y>jG!1 zf#2T=%eieVUJZTJoqt>0Eszgv&*39alO)xWK5<#y*yCI6gM~+D>p1L!M$gt1bl!BG zyfZN|b;ZVR((RY~?!@!*DKGz}YP(cQVDth~jl_nRt`Miw8>oJB%eG3{nrdP$Ki;99 zd50bwYN-b?^omwD{$i#pTx;zl#GE?XHS>9&F0y1>9PD&6tXWU6vPDHVx!MHm;J-0t zB`QCjZq|I;`WaJ7k@UsLL64VGp?SuBGil!!VCtGqSCYX(;}5Ey2N)RGjXkev+tRz# zD7E1J$@;l6Q{0r?!A0+EyAjPa!F-w|8m;PDn~dvDgKzWpJVxU_TDKfzEHuAtUOd`p zX_VjW_K~`?Z7MBw*PU3Ty2oPl^1pQj&OiP$MZe4s*8Hdbq)U|%p&bxU zl3kJK^m5usnn=SD3FO{6Izc^A` zk{>5}z?xWnN=bJ=ef1|g<;Lkzceo{YS~!u0DFwS)3rxyIf*ifxM!>qK=tje~Hxf zYe#u=UR{1wyy-jhbi7OtYCHr~l}O)O*VriE*@i>ldfMq5a-d0_5O(e~prr>DQdPq$Rhf|fA}*sm%gbM_7@ z59BCS1SFd<10^y$%PQ$%s;B=_Qu$lvt*n$Z2J=rZ1@f;O_`eu|zxY*$%Kp(WlfZtP z{-eK8ikkStZ&TDY;BlaCl-VKAyeSO*y_j-J z^XgRtq>+45h|1d4q!;gsB-rMZbM%NB4ZERwaPWJ<{{URXE>2Ds`kS_70kYh70db-U zt!A;X()aLBTBf|he!N0)O$V0c(gj!eGu7Wz~giz^PdHM;Hz${xd9_ zaKa*@stUf0vB!?c+dhknzzxjCVm(?^#VrLhJAMuYQsDW!+ey8NbatT+Iiqc()Grd6 z{@_3>O*aFEfVhXv`A4P7iqo9Ls&rGD|HHaEK-w{}*m*@GImly#(*}SPA3FNtmff@G zW7`+cP#XTJ%}H^j)sA$|azy4)6(U3&jY12sn<-#wB-;NV4QcA2<-&tuuJi zYTWZDbAw{#Pbo#-t^a$70{?^G|Np+)zy8C2z7hC~Ut{X}h+oqH8Hc~=mr>cG2mY*o zd!w^~#}X)2j|dISUGi6Dj{qwv`9*^Y+$!H-EoRA}GrvtNhf;{*-xr(rfk`B_!aF?9 zagEtr*@ugD*jQAqDN4~sGNyirHz@8LC*9nDDh1)?f7AOsX*_n5nxmGWE7{F_U8+o@ zs3TEPKdJY!(YYU_sRB~bQK&iKSf6)-70u9v<6`+lnRGu zh2)EBxpW&(%{oHEDIF-QUrN^de*tNQ|D&hnU;O?b4by+sMt|{(q57MCnXH45Z@4o8 za>(1qu#F~nQ&IHGR$!NOBjhRiN3qH=bLRw=AoRtP4I&d_Ox#9l=P0=RP0W*GD^-7k zA7OmRc^9gfud-kc$a17eEuQQO+c4&PXrQN@OELZ@uNg_BS4rU$u+f4cR@)mjm7n8yAC2&#aP#-gXNKk? zjtSn>^C^c-OB3|`B6=a*KrU@tzff#@b&bPbC(6X)Z3?CNUluZD7CUdiGkqc1KXGA# z9{5ZKOvR>Klf&VTX5lNBH#&`fJ&GZLb zJ%(&64rN|{{*cn+FPB^WzlZZou`2)I_rI!z`PY5@uSVc6esy8z{+u7l60)#=_(kw` zG3?>-i_py86A85HQ(`wJ5WA>q@GOsL8LuXGIdj0gs`mUPyBCy|=0A3ug154tx}@_$>epaZ(tF>v&XAa?FOs*wRUmWPUr7Q1eSUIJ7{WO5Imy9KI*hx<=j!e zWVxJJ7^qHzd7GZ1x5ox{G&(o=xZk(-jZ&z?$rl9rb zOo+k^^*4ZLITFS{Bv<8At<6fb3gD)a+?p0mNojc9Y|!&MWL2?*P;~P8kHP+Hf0;tO zL~jsDbj65U{pZ76R9!Ab497V}ZZSDtQyN3h;M)HvcikO^<8D=zeXi4_-#oc6J0||` zNbANVVLp&&xgt5|?>Y6liQWTYE3pOg1Ks+*a5+w8#R`8{68^fJP%nMnp&&=o)-|!H z##n8}<`qTeyypSl_~x?`k2aLH;s5g<_CJr-sH$D;UCfu5&(cKVA?6Nn1tSWS#F%4e zFk<9N3_BTgy_}NJ0>+}Ge{w-E000~V!P8?v03?PAfKcZnmmpcB364mRS-BXmgT4DE z9W|zIj*3dVuFyD{ox{&K352S2Z$~kt0TeZF6~|nZvNr- zJ4T}4b1$y*^RZZKj->d!Q6Ck;&5cEeid8nEUqP6P3B42$Gja`{UXMaPh0<6NjX09zR4j3KXJO42Kr3vrB5)PN|~%mFHd4!Q@a z&v0*xC&vFw+akMToXq0OV_62fy}Qdf-^+xAE}6tSaA*5>t2hj8Z~rn$A3B(77GjJW zwMnDD{$xqxr$oL#&xk+ex2jVe{S3bk`g7ku3^GYSf3CF#v$?&_G~vGPe{_eeF}iAl z3FIhYCWm1zLHdDsSs2xi=}xNW7$gV`TtQI-B7->I6rY?e;RYB%)uub;{s&cW8Q0|Z z$Bkc01`HT5V5B3Z9VID_loDwvafGx;mm(Y8AvHi!T2MfdFc>K=XbLS*Yp;uT84EL=_2^@-xInM~i-EAD*W&g6g0maY)8^ZD^qx&)*8 zH$BfjmuqKV-&W9Mk0}296MEy7!72J+vW?A*giaLU$OX%8QSzrM*=!o(We z*d~ttf{Nj#qsboK+4yN)ZzaL!#kaHinTahSobT!V6Njgft(*I56DpJ5KYzp7Gyod% zNmhGiLKFE0HteCbJDG*3A3e)Ug5i37LsNivsQ$Jt5D{ktz|Y|u2}B0CU=-9D!LF&% z5kq#tbKXxQSNm|!0Wkmp`y^%nH899B{w^xCKi_1e6gRtU-?rL=Xmns;AGsiDRCN_; zCot0J$|zEcnxebi%^7{Wvj`~WUmjT<2_n+SJiN?wh(Vi9 zN_ZTMh#-M(Qho(zoTEo9)+UCC!+%gZb7BTzf!^{^ZEa2!5Luo9hFVh)E=H6j_>~4-Oq--IeR7fQ=FKXyHmj4{KNdR|5_3Mjc-o*Oe?PV-DB{n z@!JbSZr>EojT3=eBv2fue65P3Xub*V2Z@2CfqaE6+cYvHJV66`eLp@0RS{jjoi6P) zyWHcYCI3wM@wwaTgVIAH9^+MXc-#T)nf#_Zx3F`@sEa&$s0=x+67ZPry!^NLWsKv~ zuBi*=A9aHtPVj!CD@qeObz59MyeHkKmSz)1OM}=gb;O`WVDZRG1wliJcjF_DoB1zd$>X4x(rI>d$u@$#sdTIBcwlv&%rwH-Q{a*!mT%LmgA1%m0z7n{JOVakKIhN zU1aXq|GuyiKmT!Vz{kc3YH-AU_DuiZQS$#k_W%3qsn_*NPNlPSCn5^?Z{TqV9w6o@ zsNDJ5zhsTu+HV*WJEEd&!@s`??GrSY!3m<`OSgm{72#@t^Dzkm0Dxfm5d|p|ao~&@ z30Eu*9^5)PfwI+f$-WBZd?{it)Q`>+9)fjGtP@wEWZH~Z4@R!3+>sX^UjO0h*I)Xo zU3+{a>q3Xfmz5>^s9rkGh#T^ADy#yaE-~JUW{)$=;Xk%Tms=J?ReytMfirDIQ+m%V zp4=G6Nf*bJpevlBDC9Qa^$5~~lOTO~0zVdZ|7HM!RaP53g+p)qj%TOqrWJre zCeZrpSD&c^7^t9Py5Rhr4J~5U5%La9c>+;qw`w)ux@Z2()n}^HA@Mg%lB5AN~=Jv zr8R-w)ioi5SU_~`JH$p9w+at8pL+8v+e+2SYz0HKrcWpJkMy&DUytAJP!B@#L(UB9 z&!Fdiq*QY@)!@R;?ik$%T_tpp8l|9IicgMwEh}066J*O*}H5mzPex;@T)m) z#j8wsGUPmUsuY3;kQ_$*K#Zeu423YDPQaBqHB1Mm3^=>55JCkci-~brAdLxdR1eJ! zIhxcIcO(`f{gdA>TEjJo1+6gazU$sy>P#EOBJ>}Ag`>IILq~gFP5AmqgcaSczAwhV ztdepR0~)FmK4>pGq>y_MX(<5HZ6g*sTpOCQB*;?8h-Am%c|vKF^3KdkO_adSdN?eb zQ8#3%RM{FjuH(x*LZE9jc-`w-W~mWJNeYuQ$#`?|IK3;K{co%J&;S~HOH9!f`Sydb zcpNe-7FT9kX`C}Yo}0p!g6A~Ozo#+m{_Fj%#FbwvHN9sNY7#~u$*AaWc41C+CP)iwWve;8wTZnwDS zs0XX^94-4k!X-{WjixI*w>GTYRl9#mbm^VcQ<9smOokQWeFL|!YpLg-KGlsc=96&+EXR){=*Q1eH7S=eG?)*W`yHRZ zKjM!e+$#t`;I&LB5J6seiqVBDUE{cm`;J{$#E1|egh+uI@!$YW=4Gw%Tp>a0C?fx0 zlnxoqE)K_GV63E4Eoh=qg{hH_q+!(i9ufgaAnO6f@&<-3uTUhoMV|>o$XrpM_qtw} zDU*eb%I7={gIY1#|vlj;bk^lKTrX=LYpEimUPEGTse=gTZ9qp8`$E8S{ zdkcS$&)&o7(kfrcyrn8VjQ{TVu9oH&wYZ_viu&g_|Krb}x90!69BChJW|&<_ote5P z8Y&6^x`6NeRUlro6rGMj-TOskIf#+(w*%qJSrIYGo2^?v0{^O)0*A!zi=b!830O{= z^9YT)Fs8^q->MFu^DCOxE@}Vl(a+_D=^!g@;`^YNsrz)w`?5+*#(>(OfyC5yFM{(y56sp>>&4v{EIneg?Q5e-wf`BJ&F42) z=&KYtRR=>7<|@;7HQ#ri7uOR3n8WVUmLsu!Asiv9Id-U_7_t3WSgZQ~k{DDlJARfXB*lE~Pv`Tp>_4tl@-G6w!g8 zZ;hktV9&r9W!Bed*~$@7T-=rhZkEolICv8W|6vU+A7*?v|1WO*AFc8JE+@b*28duR z8kn(qqM)i4X&^ZvPK-_nh*9;j*A~PPm8-3N+*NRZ^jv1F@D!N^E-J9?BmB*Sp$Zqb#6%|V+GNreJiOzQb6~$;V#|9Ms~9}uQ`tSegQxwXDa6bJ?AW&b9U}UcNL#yXU7Z7DOl(pv3BMm9NwK zB@4LKVqT(4bPq8F{A3l@I7}55g0LcsToD)16}2;A>3D|#v{|i#+2dX7)QZe&B^}k@ zrbrUkf1gxx^BBndhhLFcF5w{KM>pnViTbo!x4-tEZyCL`{f%?5{c%-hWin<3SQ3VJ za@k>*AiyONh(&|cm51-g1yNCUqfHUl>!rECQIJgTTmGjAJUfM`9rnwI&oKD7-HD&| zDm}q)L2H_M;Y^wJEf78~B|%2^;CoP*!q_m&Tiy@Jr_dKIn*ve%m;}3&Y1_@#&RrD3 zQeXLkL^(NeQ`VpqHL=AsZR5+S$x|CE6&@tdi4cYq-sP51*~*ZG%pjFBK3Z7Hys!Gs z;aa;(y$y#)%`7M+dV}9EuZ?|tr{hr{57xR^T4!sY97Lm6>!5#Y@^Y@@x%>5dr|Tvs z$*)e9e*AtLDJimK96$~0{^Rzu$?URMQR`9CwbS;48(0VtV7O@MqqJ26ihfaYglh~R z764h%ASgPtCM*8jRNbKzHD1XuH|kI7qDms0h6SIURG_rh+JV4Lf#kXQr^OxAn`hnb zvuohT1F>sdzdk&_;luq{_LFmb-0v;1Th45*kdOwG=Pa@`g zK3}^NTr!?Pzyd@%90m));J^r-Xb_Nv)LG@`FsGtd`9UnDN{&QHIEz`kJ*P-A2FqD% zEh?(9oB>79VuEcjcpC8_D{B{SV=eFi)|{vYQr|xL-AD^ZW&oHvFylPdgT%cs&cN8Acma_P4C^`a{p{Ake0UE5DN_F3LA&{EFHNe@Jd)JTm%mLIkD4M4!F>gDd6{O6Rcy$24lPfKo^N=2Pzu zE$!v+GKHPucy8m)tIAiufSj#%N$M+u@kdt7hMyGd{Ne{m<1kn+&2J&Gkj2vR{vvNi z#m8itSn)HPGeG)g@Y;2E(R;tRtjK$F;GXd;Y0bRL|1y7)q%Pa{sPCO|@%L-4|7z*5 z{`VXqIM6&Ua`E4Ny>qPU5#S{}3fl60U%m6BrJSy8eW<2Z<=#eh5yE$6-=pyNztp39 z4=x6py4^27Exoh5qpkiL0GHy4px0?&&%1~?H{2EEaR6JMb2oazLRtn?`t}hgNKYHW z6GEE|G91=4kS4gmfp8C88QoJ50{tv%upsPWh-sjcaE~-}-95 zgVVq1$lSf}w~Gm2{y5jNR!#KIgZN(l87_k@4GB~zXU+>no9z;QnB9*}i$iDJH!=!h zSd!X^I9Q@!_HoM;rpfUQ)sGN=-h!k_cDU(rgIi5f-PPHG*0e0Mf+zkTZ7$^B5B#v; z;P$6A`%dQ*ueFaoolgd(BGRc%{4>2q=9?n2YE3V8~SPGgUEEF|tPHsHr>itqMkq@t$ZDjW_F zc!^r(-_Nbzq<#-eH;EWg`|Z!gu74d~VUC`F^eIg$aK0&dcS2>ETYrRoX!S2cN@;wn znd75i@Ll{sJ&XW|CBpGUA_f12lHuO1k==v#UC;W`pF#BH#f{K1GG!jzB>y(R@G(`D z;xSR|-5~G?j{Qn>a66!mc|#l*@?f~|ARWtKm#2hPkO>6&E%t{9xojSj^HOVHVoSpv z1Ys~uq5-;cOP0>831gh_W^Ss-#7#(uCUv%5Y;e_{5+uqa2kP5;Ucqd=_AlM5SBXVJ zU+7_Okjv8nMy^f*V{eu4f4OAt%qAF-LORzaPC$%pd$Rdnv}}JoWG+ zbzgOkMrR=Sk(Eq^v5EG4Gnqrmu0Y}Ba_9Pq-ou(7HPRC6$@gP68?pn9EwiZqJQE2r zFcUg9AuuUn8HLTZb#eX~*HdL7g(;H0mkr9*5#eNwimSo*&T8Z%mR4xvDfB9E6sT7d zui?a%r_NN-ql3!OWU66cf!2Xh2@u&ri6{Qhm*C#q0j{`$51gC5#9MClxYYnKyhLuO z4*E(~e!=#A+?+2m<7(000ID*h1okm3Ulp<>b4?RwMcHQJXEfP#+~Z-RroEQI9Lk(w2Jv z!>u=`|ck?4mVkA5Ww|A?smQVG!J$`m=O5N(KF8T-8X{=A)edW0tK8oBMEO-~; znEPie&-8AOX+i2X$LGHtcAV5hwM#ko)0khRna0S}D0L4R|Da`_QSF%KaGI3B-f?_< zPDWExkuASE60U9zpi@ z4|3SQy_Vm4mL6XjHvLQm7NtEm<3e}cE^_K0wR8HK$cu2O6P-pK?$TcM=ZOn*c3ff+ zmpcAMilGPuMhb%{3YPzaz^Fu?eL%~MMT_Hba`#pZR#DIoqSn@u%#o$e_(Vkf5-I~H zfCTbhL6zmp2NNdK6kNZ<6E4Q^d#46nn2n;NljfVc5FzNp?R=puO1IHpe$SJ^@iRLm z;pcFj_4vbHynry1Ql|VnG`Oe_TJ%rU<`Ux6Rn~U(a(1kl9<^8eoVR6*XNBNkejwbvYg+k9n#&}9{xegU#4_51=;bLb zn`DY<6p$I?h>Brw94Q^fBD*Qtc<`uLqL-nuBX%r(yZ0ttrXRB`4|iMkcb%74l0n^A z&2#$X#|eTUqbs1I5Fe`v>+(_c*?8-YHM*F+TzCJt1p-z##}wGcAB-J!8cLR1`n#-P zUIsa$x_`b#w_f!qPpAxBNn`CXo<&I=5${BB6T)>#X_hUQ#hbOSw!!1f|JJahP3xs* zc<9*b^oscmcvAE=^3+LuaYb?CN{h_e0sQ?}_KY*{UQow)NB&f7p6^QZIB7Q1&2?T( zGh`^YGRg9!^3)jC4T}Y-tyIQsjvf{GfTdr*cdmXCe(}b`JM!?>7d3Y|b$@?=OD;P9 zJ8j{50i$}|K>lf9a7m(uDL#9l=C%+dOtrKjMV`deIbf=gL_!AHT29u znR;N7nNo#bPu+WzFIH6k4nkP9UhkcgX<3JV98mOYk|jDShrcG`<1O*P-c%MAzoFl3 z>N8}e#HFSv6tX~e^|iLBF@C82#Q*i}hQ<)KzYNS$H_N*9fI{<4tIT8_FYH;>NVKiP zh%Xo10BU9t+B1IkS5XGp@aIi%?B5{HL-~oPjM^KHWHtu=b|DK57g`mTFE8({|LEap zkC3-r@{|y`{Zdu7jVxk{}H}Ks;9E=on24p z%{spjRc}2`g%C5xl&Ys*XZ6boH|knRB-M~g9c`ta^8Y9<@DL2N{N=M|qnq;z6t(L5 zD-q{s!$jTjy!?*b61+PQ<;rRqW+>|ZL@XpsPsFw%GS&F;pXT-#)+XMCp9aOawnpyp zNtE2IJh~r!a_t~@`0tctl29s5n!$6Utn)oA4E*-YMA?kp)~MPqqkENZL6>x_?l<3V z9b$O#%q#Ld_2G=enZ_CffJhh~5D`r&r8B~S)ViSH5n+&a*Rd*taMy9TF+s*7ad4f9 zUSt<*=2=DD%?Z;+iqPXQBNRNVO5KMF0I+{NdPBl5g+ERLDm}{w#6C6|BMH=xJ~8A{ zWsoAA4jG((A6>OO5M32}ZhjKiH9ho=<eKS?inAOJn_5NzmP2i{atlzqfrYTn)J7NHt^Y z{4DLmoE}2`rPgwEGNkA%sh9R! zI;QGAp<+re+TGp0O!A#n(CGYi06A5AN-`PvGa5H3Hsz)MiT0N#{g2CODOYO67<#u^ zNJHnn?x*kkyZL!tv~*ABA)i#muyFc*k!({eABi0*%D(g(c6!xTpTTug-?$%A5+o)w zc$LkiV6yVdz8uq7=h)GH$QloD)-T>ld>}x$mhYkA>#Dz;v8TNE!!KopGrDvx8Tb#s zC($ZQ0oR;Ay5?AYMlUm@Q)fr~Dr-SXAW?zrZWk$G<|`&E0H!EAJv6atYLvUU4C3C)z`z zC82cwH-Ob|;*UoQMEsaJfd;)v6O*?SjG71CSc4{iNaZbSiAad*R!12hr_jT|LbQGn zkN?He+_61XKW6?W&b!YiO4hjG>=(?9~PEbU4_i64!AI6)ah-<-w9#PKM z#szy-$>nyC!6n-9H{5@UX4t^b?1b7U;#R@@JsMR)3>WXnry}_I;&_nXDxFa0tSZ?R zP4cAT9=CXW3(tOj$ug)FSO20$y8q|9OH)IFS4uo1B)JX8CXXe$s0%wC#Gh-Q+JC0V zOdap0JG4(q$CA!Uno!7vIJ;y)K6pKW-7QD1^Md<@KI^j^0t)m*E8il8Gh4(ysUvZ5 z?LDQj?y8#xuduYktOxZ$=MKXkgl*M~?*rO@r@t51*@Nw?9gMbq(KfgHIRN9G;Ai=t zsozhiI(AMu+Ow9$^&|Mr4g_$5$#JSNwkj6@*RdrVo#ro5r{kpgM+G!;>aC!-3va5%;0IV)$A!b> zBU>=Bd)-F3rruM~yUw!uMu?F4(n6sWZz&{oX@qqf-|B)A0tYN(W@p z@>wL?{xjo-kCMWlYr_tAb`D~~(=^6>W9EOpXKm;fPAk~Fh&lX(OIFX*^l3b6{dw9x zKptWpeWQlQP_QGu7{zc;h=GN*q-_?r9NtliE_drj(5IlUcR%K*F?b$ah&;83q_$r* z(Mwt&$9d1$vTUuIO(_Fbr%`erttrf5g;M>KdV#dxycEwwHJ|rIpZc$cCzaG$HgE~< zCK-(ik3;3~f9b9rU|DB~g#MGbvit~!~TY*G}CnL|A9rBhCvH%H7WB|!Qmp~Bc zUlNfWbD8ul26dn75=_6~Kl~nm!k&d(bM8?0&6Y@X@u>ZMUjN;tJOAaEo#hXfcMin# z1B@6KBLZ`sBMdmN#zBgM17Hl1E~e#FltC6^5vmBftXEzl0AMOUb(J1OyEPcoNH1;k z*FO31E|@UWXz^_hlfJbe4JQhR)27+!%+BO~TsgYRBJSa}99RFMl0$OiAhcqot5vZH zu3a{`%C|KtDEAZ-?40U2P5RP6KNPo;XWhRDiYk6zWk6mZ4;t!p6tBX3u4w7E?bcDAIJ^bw4e6Qtr8@0XH z?tBxvlmDmfjnbZ);xD_|`K~`ALKm?MaYEFF=})4-4LxOz2#)TPa(y8%>6VqpTWm=R-T!eQrq!tu{9Da4}H5P zMG=6IT+S+=r|AkmB_sIvzA~R;wZmA)i<$a9ZGE**{`RVWIOwH66KCEL&&=-^;S!-o zCxL5QolDPaem}WZH1qLE%UL}de72`JBSHzK!P*iSI;mJtH>lpsN2W3vhciRcK@xm@ zx50E8Skr33HoV$%M?64_8G%7k_!M#)(gjs4I=x=?fktd3000%fA=t}^g3_;; zx7-`-UY<(>1&Fya^&TOu@iGOi%tB$$6ig((Loe83$!G)}zJQfp*Ug&~-OJa&I!+Hd zN9XD=d|?e*X8AXsQHFsr%Fvn1w`75i^sb=&JYLrEKbLt_rH^*tJpMHHPs!}95mbXYVk50K(JpFlSmuFDm2@9L?D&( z<|KbO-))L#HV!VX?^tuOFX%LTr>OKWNUEzPa(D4s>=kWSF66d>1vsF`B6{8|lzgwx zmlHOQMO|jNI)WEUOO-j?$AOSwMgDOSu6q03qj-@@es0xTo5H+qq8J;mGG47b^`JGs z3b8V0Jx&%Cy#^iVXNe!7Uy?%1QX)9$>DbG*2IXYidBjZp6Ms&hO(Hcv-}TWT=eS|{ z$|yruWmC#zkz>nE5YC7AYP?j^^ZfVR)SL1nbvxgvR@8%|lbfr{b)TtcapzMLpC2E5 z201mNZ~#d0%}7^(1bTs6z&IRCexrMiU4U3Wf=(H@X7oS&5^aL~-g&j_uH+}%-11~9 zuDmg*(GcQ7XCbz(e3riu*kla_xk=d*Qk-OgGJJwO9TWkPpUR+Qck5Zkdkk7QqvKwn zG2-KikijU_E~*A@9p^9zz0~}Ji%{#!3xnrAl5=CJHg3aEVulk|!=gHL(kC%l)uBl|w2VGR5tFEq_O8wHP)fMda*l8EXFM!xC zD`-4!VR!Yk?+o`ql^Q#u7bcZnANVERGHNt7s*Bh=8Ijv?vvPYfalLWP?hq6Sff(HrH_`$=Fbj-FVB-O>4oXQ=D?uK5El&ET7DUsrA}|y= z&}SaK=plUH3uzpUZ~6XlP>)OHIH8l)N%AKSc+ZLjwuBZ86JFlXYEyIn5x&6 zgEUZXp0hvHmG0grPDM_tLd>s+)O_*X1T))Ev3U*BP{cOwFhbHsGEG(#iq@#oK6(v5}V<};3E&QtNkof$Eet!1{rpc4X9JJ(3 z+pl3MCVHD9M}rTtKmUhh>d6|d@*oEqW+zAmw5+WHQ|Lln=%N8=H4pvi4GBubS8*7a0E zARG`NC?kfQUqyk*pd_(e(Q zTGo1-sWM;g6*HlF%ODrG+xJB+&)Qr$FDzBrt-t6et;Kgc1zT*9)J*OMB@FQpX*FG+ zd2e@aC8nl>&3b}2q^d|7jOLA&a<`35v^01;6iY%6@hp=eOOLm~sRGP67gy_pCF&xd zP?p|0cg%bZoaLE5cmL@v7E#!k^oekl|z1grOrbotg(o3u=8h($YWca z5bFyr{X9It=%ta^a9)1T9K&#zJ4>Z1FDYTBY1G-E-0KhDEx&o@1O`s6S-0Y~t3EH^ z+)JuHW4*b27`*$d?DTx!OE2@B$QN5)EyH@may9!_^48U_QJ1O5?oklf2wVYWBs*YG zuE^SG9Ao@UruY0s7sItEX`#M7%}k@I1reWj2PMZJuV1!Q$d5XEWd=ZnS!Aq79Guf` zE)~NyN}D>~bvQbg8RZwN$(*=kg0J`%tJ%Z-AcHs%3W$K;^YPFCB07nL<>y#-0_>lQ z*N-0AQje5S6klU(H8T-gg@Y$1zI{J;9mdEL_f59L`cR0zG;=A<=f`c}!mAsE$+psg z@mu9i8eNdmel8}(JlWvJef4Oe5mAgRuiLd%xP1d#ZOcdhnkWkSuY`i>>z!5aMMO_3 z%zID%oiVhMnZe1l5q7xov{5eb$ktb4Z1jdRA`W-joEOU{=;&Vww={iFUHSS^7ptYb z9|0lN>J{4=>`;JS4|EnZE)0oijmsbQ5m03zTPf3AIPZr-v?O_-+mKQZFt zfEdlUgo(GxDCz{+w1X_R_h$~*LqhoB7fihPxbkP>_!-jqbmHX1M@UP zUxd16wWQUHtc+^}X-wh%grl00U}w=PS7=su)t$J*{I`p8@p*@PP$|*v$y8Y>3GV*^ z`frO(AMRF}Yu6nyEtkuj!%a@H)*HR5t2hzoL~f3|$x2k}?vt#U_hZko0O^eWLG;ih z;GA6C>j@wMLMXw>QPcT9{2q~1E(DCNM!fgU(@%7{!=!%R@%^RkohwlaUb`;$p4FC z?xpQ8{Pmad)UJFg^*DG&HT`6O<8SAQ-rtf7bf8k4^a_DM>SBU0KudY+W|eFf6fCnI z#(5v`C|fe~i?yL%(VMi7fAuzTqeXD}em<5qoUh5;%iA}iD}w+K_6*5Hl)OF80~!D#u;VU4vSGZ-H;(B#&4L`+G%+#dE*xpqVUUipsz|u6pVC;A!+yrLWE703Vf>k?_-oS zC^2>NhgR}g_oIPSoDB|}3oWI4%Ms@wq%3owDuCvK<3t`^fn3#%d!GM8(nTnAy(mz< z8-Y@SF$9Udg8Ff^bn2`A0d3V{%WZYx7KSeZwTnA`2urEoMSW{ zGOcT5Z1nonr6jP(*SzEJU+{D-rJ=Vf26lA5cGgF&ZJl!V@(g@(eNMGwrN-X7{Mt3U z#c$ez!84%c$o4yTajjW^xKaKOp5Ea@M@yS8rnyL{vBe7a->-JZm`#=2tCf%(F9CiLQxAb5z9|#am z6UiUG{A5RB@Uw_;S!-G2ncT0j+;mJqo@~u4UBwK}|D5o7NV!nj| z{Ce6Dn))8G&?jf!IgA+)P+TkwnEg;xFCi}X3oUx1j)&UAAm5ca*+6O#_BL^4C%Ez! z)>UFRkS145G4{NZmZdUP{7GH;E5nOnnn&?i8n#cN1tW~ZHb3FfT1s2*hwh`dXLmD$ z6PaF)R_-ZXw4SJZ-yxdtD>eM(XYqKxQaxu%t9#aa86+x7?Qu|~^Ydxe*Q&LZCDJ+O z33};@&8^}AGA3-RvI(}S))9JXcDU+aecwbgEdp55My@bRKVd%hxnUJNts`8#AW$?c z;iGeTpLd%@-HJLhIyU<*e>MAD$PH>c_sr$f`YU<6Cnr(|xjb~?Aq&+{We|?hY()=P z77~RAMEPIoYFnGXRA+z}mj%3yOuJ$7a%WRkqseJ}%R8TWOFHX2;UBSriOIY-q(RMq z`StJ@h;duH*ZMTj^@m|h^}pSGzk=iP-N1%VsvtjJdZzuyoxVRVGr^eE4QUq3p7tJ} z-avt{9qhok9vucm3?pWsF>+DglKI1z@DF^L7cMNJ3&M9=|lHlmZ9ihsmxUkItAFZFdTp15*Ga z^uww$qW)*r8^lcCRd_4<#(uMIn+fIDODQYqe@|BF=$(yPA_mIZYGQ(-uk7&wFOkP} z*Z8z;?wMAZ`FHSa+^A~3W42K@R#x;nWjLmhwmp*6R5N8AFD!hM@rl3z}xT8bW_`G1i7%j1`&GvZYKm2ZzE^!AM zCNIqY3iGmg;_SGY3b}Kd_f~mobe{OgsxFykn2= zidSf7fj+=#(Q0Fs+#&Sr5J6ES8_r58kdUAp;~GZNL$!yr!PeLi#zg+FINMugz9|z=e{3 zQ+u!8NiH@8-2Z7<7a0_+dL`i8HcRer(~*PReEY?w)}CA>Hm0=cMm!S)gnXd#b2_o_ zDJ*lQ2N9>L3%j`;o=jLRGrO&U2u#6yZ^9h$%II9&J;%8zjHXKQQ|i~^ z(RZ5XWZpP_{jJtzNDeH0^{n70ru3DGw7^9z!)MPjQF+H2_2Rh|EW99!f*g0 zp9p9Pg~YIs#G)GcFoo%V-_i18a%0+~+%J=&1G`WRIrbP}UB5e=2d&4Kw2D^~05emJ zaAN!r*b+t*gag2|phT|>Yl>*}2sd#_lgB|QU50O8 zEa12Ku`_mn4R^U|m?vW%06ap3;DIg_e8t;exY`}l+mj10*X!dBn{hWf zPqnGnMn%pa7rr;x-3b=h*Q6kD7vNctvkwrk2Qty52PKjax)?myT&>?C=k9MdT6$09 z_+3(*?qYXemMii$XvdZ|U}r z^_sYvh^MZZ%5)J38rchE6Ma+%FG@FG04Jx;018Q`BM+c#Ne7)GfWRq z5KNni%kHk`7(1QzEi7e32i;BLuod92x74&x#kxrA;FyFd=33*5FJCVb&CiKnBZNZ z*{{uoqx&yE#U&-$2N^p2XkmWWd42AU7mb6`)n#0Iz_qTh!WxA*hC`khp;%o>aqlh) zh{Z7r1dDc9BYO~~G!Qd|Vj3F!q_}1QXFeKhoe%X0KnCsSX5pZP!>xvXdauM_^ro~G zEUE@Du*yDz+XTs%F$?_0Xkd4L^;F!0@R|zWVKgX6lC>^KX9UPK3b`2$9B;(r;C)N7 zCd%4L^g-fkwTsoP5kGQ{D|JObg|~WJYdse)c1`LT&rD_PlU5$OHT?Hq(yHBa`*cUK zXOslsjPweC=)Mn(->>L-P5CGNu+)8cRZS@l4l5HxbM$i&r6~E5?Tc|ER5kLU| z1cXw-u|Rrgh|M@X=q@E4XH5rT(J_-BRd`0X>w~MMm2rH)hvqlo#c4pyu`E#BI8uv- zpachMRceD&4kq&%!a8iR15K@Iun71t`x z^nsPP&uCeYcsM|pVk80x4Nn6!qWZB~B5dfi7zQ{}-nUDzi{i8c)9fb2j=StCM|BC6 z;g<;*0u+)!TQLrSf{0jVz@i76iGflyw0L<&=*~ICp-~tB$cY2|^3=V0iS&$5am$mU zld0^B_k}sXfQIo=DYB0Ujd&Bfk@q?BqNCzyLpi6BPpt5K@AiI77g?0iM$bR4qA46I zqz&j4Rcth7$H@s_i6%vh(ANMCVF^8Oi{#Rrb*Na5iMwtBz@M?pj&bf*G`p@rAY|-q zD2=eSjVX8#z_3!QDL$!ozy7>d=xYc4@Ye2S{c@4{`P|MV6CBE;trQBBe-F%6*cH>B z2@&*S>x}M-p7>_V*B5~$iLHi>cQ9Wp2^K@eb6v`pG~3G8*6FiFqF1jtAn%p^S%WzuYJ%D>g8-V-uk_lo!5gXjRE5#h2&gOL^~vGz5Y-q~9qohpyfm!J#Zg|praCf%_16^F3j z!fineLx$(`#OtF6;2P@>H~KmQOcjzD6~6z(1S`EPJ7jCnStd^g2U~i2DhN9^R+)qQ z>*gA~xTZD)Emvjd?G!vb!k$d$8GRjTUMTPid|A1E<8-y&!`nPWsBNw4Y&HPghvH1gxYXYDo4Khj>{q_KSW=u!eo4HEOMx|~Bk{hP8E~-mUTVHL28oyA zC#g}!F){fuwD4>7hu>d-V-u@{xYi3BF}e`kB#*Y4dl3f6M7YMrG1DjtT)X%*EFpoW zy(=URr}0{p4<+b&Nm=7Zk~H1SS@dKnPQL27diZv5 zel4n46M#L1fmm4|7<~wJ_J8$m;>(wJxMz3W7|Zr+k2-j2OkE1QTrfZKN6WIo*u87u zb_rN>--mE$OI!W&qpOqZ^ZSPxlkrP7;d2wU=*yr{AQoKW8q}jO(_`}YT9(D z!P~irivs7QOda_Y?itCtQ}oW|3Tvv&3R^p-$D~BnY$YIf_Y=*^6Jul7_sRr8Sf4CDscu2UIEY;IkXiFAZK&!RsA~d4EyJLk zq)-y*oAt~^^Ey;udEM3mxWY`gsXTY7ol>np$j%lVPdpx=ADDV>L_=VI3K_sq)zM9U zQ2Oy?a@~)H~hA(qq@;bzOri&a+3W8(kac>fB?2NfIbBNJB^f<@hDY* zE*3%IyDZ3cnXR+RibYAab=~D+eG1JXwgyXg69!}!rCzx@)mrSui7i)mrTWyirPSFb zC(%RCC#W(?FPYmN({rkGn<~{`Ag9k})xO+NFaxryS?`Z#51v%b9+{LvPI6C3a9IDMbb+j?r$#-6f931t*vCZto39p zHOD7Y4e45*J?Ry1Z+JC6$@aKu(y$$qQ}?Lu=K)cgqd`s0ji)j}#R8Y}ux7_`6aY|=2dO~GD`i)iM=cC(`k1LZb6tc416;k#_)_jQu3n^>DEzVLF z3F!a3GR7t!$U(BUaFb;gt;3m>HASOdQ^8!aajEE_?B7?{5ftWKY8tJ&rhCr)Vp11r zldqFocUF<@{+F*)Cp*wi)JVgr2PU^`l1xrLx-bITFGE+Zb3>#B?+ZJ){U?-dlz}Xw zk2xaunkH=FsnM6kz}CiwBg62LuyOr0#|oIc&S+`4Bx*lyc9*|GSybO*>3*i*r+~53 zzXy6nUOX|P;_l`1x?R-2WmCXUp05|!X-{r;?YeFDqSw9N=d{LEC8m_2ya}?+A?tk9Ay0X8(wMa&dr$v>1!x%%sZbm#M zK0~mhSyO@A_B=g~$sOv8n0E>dieY zVo*-m8=thZD|>5K_G#osMxCFiy?#(GjnLMI8?a7y)VS{?Bld5j$8-01&RvBlF|K^B zcRwAo+yCs_Gyk0r1S5jOe%)UW8}-MC{;>vD{V!O*%n*5N6@Sv0!z4#JAmL}#hF9yS)WG?m{i3(J z@s5&r3Uh5n9vImT_0OQugV{^AxxXudw;KKzJ2pu;(I;DDnEL5v0x+S2|f(q zeMNhl!X9FMlU*yksnhcr&Z4R!5BaPIeqIF)re=FVs_(1#JI*BHACLGiM)AXb|6&vR z{~OLX`!zNJ4zRvS{91%P)5mA2p5z}8p16mkIVH=CRty|CgB+BD(b zdehymN2Ur^&FveOWXLjk?LA&Odhn%w-Ydw*O)3n0&W0khL#G0s?69%{>Hfzo#j_En zvgq&$WtI^PMNqecMqtC>u^17g9pws~g|W#}JT4LisKteZzPDQaz_{wdF`*1fw4P`qYn`09 zWIi_lieqoHAXyM?*5q*y$+u-=IU5b=NaZeM3rIK*wiOcM3p`R$&HoTc>!X6d(#z2B z@8tqqTqF(rr$u#1haPGUoVL*m4@@__kGs=Da_`fR^}j3d?USQF|CFbielKxk179^} zG`=WhxcTU!!LJWWu$T*2vv7Z2$eS1C)y5jWfxd9nTKuOY;*$s8uZ&F}DO9(h`ga;M zDSqurAbG1l#2-r-za!Ua>;Of_lQ!oiA_HF~x3#iv&EI&%)IjBF zxCa(Pcn-RrD!hzxD_wpSi<7~ETl)rQvXmiG@+eRrOZPMf*j3#VHNj6hv~H^LoB=4+ zp}oy^?vp}{GsEmiIa-Dv!6d*zFh5D30+JHU?iPQ5O3OrOpm3?IO%$%Vzqy|#B`!wH zP9zgKH2oQ@K1LskCs`Mk7Ht4^EtwS;C&V#{fUk`)hWeyJr1Mea_;Z6>v*+$9Xi zCq#3Jqg-C6J_;Jg)KI_&qs?&?tf%zfIV8(rSiqUE_Fy@H;FH%80Wd(DMFjNqiH6V( zh8bjim#X6K)^UF<4Y836PC9JCxL?YL{KCAOeIqi{jsQdeL}5#xlez+;zJ{Q(1ZBeP zOy#yIv(?%N*iE>-w&M}%aNrCSjb-d*$cu5pU@n$M1{RWGrJ2ehr^e@GTQLaz16W#- zCN&Y;lziaA)lDQ=mA7B_jV|-cx`~vbOv!{UGo|ns>ZEg{2^E?-*zZZTcaG|9#~#jT z6*|fkV@a|cB{PcNPW)xvObbaq7D_mvff$mtLPw$uGpM?>?ES<}`w2fSzw({VlBGI& ze|MAj054B5)|pR4_yRkX(I9q=!wV(P@Md2hM*G9=j-;|e-5>b!|K9!n@BSC`wTDsQ t<0$}GLl6THFb7i#t}+4utgbfr_aoZBSCk*U|1%o+F**N?*8Va){{>evO>O`H literal 0 HcmV?d00001 From 10a1fba12832359dbe7cf92fbb65dff5b1572fdc Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Thu, 15 Dec 2022 18:40:21 -0700 Subject: [PATCH 36/55] Add alert colors --- hooks/useWeather.ts | 55 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/hooks/useWeather.ts b/hooks/useWeather.ts index 568fbba..d4a99eb 100644 --- a/hooks/useWeather.ts +++ b/hooks/useWeather.ts @@ -568,4 +568,57 @@ export const getAlertText = async (alertId: string, options?: APIOptions) : Prom }).catch(err => { throw new Error(err); }) -}; \ No newline at end of file +}; + +interface AlertSectionColor { + primary: string + secondary: string +} + +interface AlertColor { + header: AlertSectionColor + body: AlertSectionColor +} + +/** + * Gets the alert color for a specified alert. This should be ran after getAlerts. + * @param alert The alert to fetch the color for. + * @returns The color that the alert should show. + */ + +export const getAlertColor = (alert: Alert) : AlertColor => { + // Header + let headerPrimary = "#510d08"; + let headerSecondary = "#b41a08"; + + // Body + let bodyPrimary = "#d51e08"; + let bodySecondary = "#b41a08"; + + switch (alert.significance) { + case "Y": + case "S": + headerPrimary = "#874901"; + headerSecondary = "#bb631a"; + bodyPrimary = "#f2992e"; + bodySecondary = "#bb631a"; + case "A": + headerPrimary = "#846811"; + headerSecondary = "#9b7d0e"; + bodyPrimary = "#e5dd20"; + bodySecondary = "#9b7d0e"; + } + + const color: AlertColor = { + header: { + primary: headerPrimary, + secondary: headerSecondary + }, + body: { + primary: bodyPrimary, + secondary: bodySecondary + } + }; + + return color; +}; From 16d4ddc4849820875bfdb1ee7577d1609bb811db Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sat, 17 Dec 2022 01:12:49 -0700 Subject: [PATCH 37/55] Update TTS interval --- components/MarqueeSevere.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/MarqueeSevere.tsx b/components/MarqueeSevere.tsx index d7808a4..838ac7f 100644 --- a/components/MarqueeSevere.tsx +++ b/components/MarqueeSevere.tsx @@ -38,7 +38,7 @@ const MarqueeSevere = ({ top, bottom, mute, setMainVol }: InfoMarqueeSevereProps if (typeof window !== undefined) { if (!mute && speech && speech !== "") { tts(speech); - interval = setInterval(() => tts(speech), 31500); + interval = setInterval(() => tts(speech), 41500); } } return () => { From 0e9ca16b11c0169c8e0f01ce59d96c2662580a5a Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sat, 17 Dec 2022 17:56:14 -0700 Subject: [PATCH 38/55] Add base slide component --- .../Containers/Slides/Airports/index.tsx | 14 ++++++-------- .../Slides/Containers/Slides/Health/index.tsx | 14 ++++++-------- .../Containers/Slides/International/index.tsx | 14 ++++++-------- .../Slides/Containers/Slides/Travel/index.tsx | 14 ++++++-------- components/Slides/Containers/Slides/index.tsx | 19 +++++++++++++++++++ hooks/useSlides.ts | 1 + 6 files changed, 44 insertions(+), 32 deletions(-) create mode 100644 components/Slides/Containers/Slides/index.tsx diff --git a/components/Slides/Containers/Slides/Airports/index.tsx b/components/Slides/Containers/Slides/Airports/index.tsx index c6b3236..ef79493 100644 --- a/components/Slides/Containers/Slides/Airports/index.tsx +++ b/components/Slides/Containers/Slides/Airports/index.tsx @@ -1,13 +1,11 @@ import * as React from "react"; import type { SlideProps } from "../../../../../hooks/useSlides"; +import BaseSlide from ".."; -const Airports = ({ next }: SlideProps) => { - React.useEffect(() => { - let timeout = setTimeout(next, 8000); - return () => clearTimeout(timeout); - }, []); - - return

Airports
; -}; +const Airports = ({ next, duration }: SlideProps) => ( + +
Airports
+
+); export default Airports; diff --git a/components/Slides/Containers/Slides/Health/index.tsx b/components/Slides/Containers/Slides/Health/index.tsx index d8df450..7ccbe6e 100644 --- a/components/Slides/Containers/Slides/Health/index.tsx +++ b/components/Slides/Containers/Slides/Health/index.tsx @@ -1,13 +1,11 @@ import * as React from "react"; import type { SlideProps } from "../../../../../hooks/useSlides"; +import BaseSlide from ".."; -const Health = ({ next }: SlideProps) => { - React.useEffect(() => { - let timeout = setTimeout(next, 8000); - return () => clearTimeout(timeout); - }, []); - - return
Health
; -}; +const Health = ({ next, duration }: SlideProps) => ( + +
Health
+
+); export default Health; diff --git a/components/Slides/Containers/Slides/International/index.tsx b/components/Slides/Containers/Slides/International/index.tsx index 3dbba9b..1d7ffb8 100644 --- a/components/Slides/Containers/Slides/International/index.tsx +++ b/components/Slides/Containers/Slides/International/index.tsx @@ -1,13 +1,11 @@ import * as React from "react"; import type { SlideProps } from "../../../../../hooks/useSlides"; +import BaseSlide from ".."; -const International = ({ next }: SlideProps) => { - React.useEffect(() => { - let timeout = setTimeout(next, 8000); - return () => clearTimeout(timeout); - }) - - return
International
; -}; +const International = ({ next, duration }: SlideProps) => ( + +
International
+
+); export default International; diff --git a/components/Slides/Containers/Slides/Travel/index.tsx b/components/Slides/Containers/Slides/Travel/index.tsx index e4d9754..094ae82 100644 --- a/components/Slides/Containers/Slides/Travel/index.tsx +++ b/components/Slides/Containers/Slides/Travel/index.tsx @@ -1,13 +1,11 @@ import * as React from "react"; import type { SlideProps } from "../../../../../hooks/useSlides"; +import BaseSlide from ".."; -const Travel = ({ next }: SlideProps) => { - React.useEffect(() => { - let timeout = setTimeout(next, 8000); - return () => clearTimeout(timeout); - }, []); - - return
Travel
; -}; +const Travel = ({ next, duration }: SlideProps) => ( + +
Travel
+
+); export default Travel; diff --git a/components/Slides/Containers/Slides/index.tsx b/components/Slides/Containers/Slides/index.tsx new file mode 100644 index 0000000..bf2d95e --- /dev/null +++ b/components/Slides/Containers/Slides/index.tsx @@ -0,0 +1,19 @@ +import * as React from "react"; +import type { SlideProps } from "../../../../hooks/useSlides"; + +interface BaseSlideProps extends SlideProps { + children?: React.ReactNode +} + +const BaseSlide = ({ next, duration, children }: BaseSlideProps) => { + React.useEffect(() => { + let timeout = setTimeout(next, duration ?? 8000); + return () => clearTimeout(timeout); + }, []); + + return <> + {children} + ; +}; + +export default BaseSlide; diff --git a/hooks/useSlides.ts b/hooks/useSlides.ts index 7814503..d588e55 100644 --- a/hooks/useSlides.ts +++ b/hooks/useSlides.ts @@ -25,6 +25,7 @@ export enum SlidesCityInfo { export interface SlideProps { currentCityInfo?: ExtraInfo next?: () => void + duration?: number debug?: boolean location?: string setVocal?: (vocal: VocalMale | VocalFemale) => Promise From 463105778509d728a3655abbfdd847c89a9f17cb Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sun, 18 Dec 2022 00:07:06 -0700 Subject: [PATCH 39/55] Add locations to marquees, update API --- components/Display.tsx | 43 ++++++++++++++++++++--- components/Marquee.tsx | 29 ++++++++++++---- components/MarqueeSevere.tsx | 6 ++-- hooks/useWeather.ts | 66 ++++++++++++++++++++++++++++++++++-- 4 files changed, 127 insertions(+), 17 deletions(-) diff --git a/components/Display.tsx b/components/Display.tsx index b1d3d05..48151f9 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -1,11 +1,14 @@ import * as React from "react"; -import type { +import { TemperatureUnit, Location, ExtraLocation, ExtraInfo, CurrentCond, - Alert + CurrentConds, + Alert, + MarqueeLocation, + MarqueeCities } from "../hooks/useWeather"; import { defaults, @@ -98,6 +101,8 @@ const Display = ({ isReady, debug, winSize, location, language, units, muteSever const [focusedAlert, setFocusedAlert] = React.useState(null); const [focusedAlertText, setFocusedAlertText] = React.useState(null); + const [marqueeCities, setMarqueeCities] = React.useState(MarqueeCities); + // Location handler React.useEffect(() => { if (isReady) { @@ -166,7 +171,7 @@ const Display = ({ isReady, debug, winSize, location, language, units, muteSever }; const fetchAlerts = (lat: number, lon: number) => { - getAlerts(lat, lon, { language }).then(data => { + getAlerts(lat, lon, { language, units }).then(data => { setAlerts(data); }).catch(err => console.error(err)); }; @@ -206,6 +211,34 @@ const Display = ({ isReady, debug, winSize, location, language, units, muteSever } }, [isReady, locInfo.latitude, locInfo.longitude]); + React.useEffect(() => { + if (!isReady || !marqueeCities) return; + let latLons: string[] = []; + + for (const city of marqueeCities) { + latLons.push(`${city.latitude},${city.longitude}`); + } + + const ExtraCondCallback = (ret: CurrentConds) => { + for (const latLon of latLons) { + const cond = ret[latLon]; + const [lat, lon] = latLon.split(","); + const parsedLat = parseFloat(lat); + const parsedLon = parseFloat(lon); + + const city = marqueeCities.find(c => c.latitude === parsedLat && c.longitude === parsedLon); + city.observations = cond; + } + }; + + getExtraCond(latLons, { language, units }).then(ExtraCondCallback).catch(err => console.error(err)); + const interval = setInterval(() => { + getExtraCond(latLons, { language, units }).then(ExtraCondCallback).catch(err => console.error(err)); + }, 300000); + + return () => clearInterval(interval); + }, [isReady, marqueeCities]); + React.useEffect(() => { if (alerts.length > 0) { setFocusedAlert(alerts[0]); @@ -260,10 +293,10 @@ const Display = ({ isReady, debug, winSize, location, language, units, muteSever ( +/* {top.text} */ +const InfoMarquee = ({ top, ticker }: InfoMarqueeProps) => (
- {top.text} +
+ {top.locations.map(v => ( + + {`${v.city}: ${v.observations?.temp} ${v.observations?.phrase}`} + + ))} +
- - {bottom.text} + + {ticker.text} ); diff --git a/components/MarqueeSevere.tsx b/components/MarqueeSevere.tsx index 838ac7f..bdc38e4 100644 --- a/components/MarqueeSevere.tsx +++ b/components/MarqueeSevere.tsx @@ -1,8 +1,10 @@ import * as React from "react"; import Marquee from "./CustomMarquee"; -import { InfoMarqueeProps } from "./Marquee"; +import { InfoMarqueeSingle } from "./Marquee"; -interface InfoMarqueeSevereProps extends InfoMarqueeProps { +interface InfoMarqueeSevereProps { + top: InfoMarqueeSingle + bottom: InfoMarqueeSingle mute: boolean setMainVol: React.Dispatch> } diff --git a/hooks/useWeather.ts b/hooks/useWeather.ts index d4a99eb..bb458f0 100644 --- a/hooks/useWeather.ts +++ b/hooks/useWeather.ts @@ -155,6 +155,8 @@ export const currentDefaults: CurrentCond = Object.freeze({ const memoizedFetch = memoAsync(fetch); */ +const baseUrl = "https://api.weather.com"; + /** * Gets the main location for a query string. * @param location The query string to look up. @@ -164,7 +166,7 @@ const memoizedFetch = memoAsync(fetch); */ export const getMainLocation = async (location: string, options?: APIOptions) => { const apiLanguage = options.language || "en-US"; - return fetch(`https://api.weather.com/v3/location/search?query=${encodeURIComponent(location)}&language=${apiLanguage}&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) + return fetch(`${baseUrl}/v3/location/search?query=${encodeURIComponent(location)}&language=${apiLanguage}&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) .then(async (res: Response) => { return res.json().then((data: WeatherAPISearchLocResponse) => { const dataLocs = data.location; @@ -187,6 +189,39 @@ export const getMainLocation = async (location: string, options?: APIOptions) => }); }; +/** + * Gets the location info of a point. + * @param lat The latitude of the point. + * @param lon The longitude of the point. + * @param options The options for this request. + */ +// https://api.weather.com/v3/aggcommon/v3-location-point;v3-wx-observations-current?geocodes=41.881832,-87.623177;44.986656,-93.258133;33.427204,-111.939896;46.877186,-96.789803;34.187042,-118.381256;33.660057,-117.998970;36.114647,-115.172813;21.315603,-157.858093;28.538336,-81.379234;43.0,-75.0;&language=en-US&units=e&format=json&apiKey=e1f10a1e78da46f5b10a1e78da96f525 +export const getPointLocation = async (lat: number, lon: number, options?: APIOptions) => { + const apiLanguage = options.language || "en-US"; + + return fetch(`${baseUrl}/v3/location/point?geocode=${lat},${lon}&language=${apiLanguage}&format=json&apiKey=${process.env.NEXT_PUBLIC_WEATHER_API_KEY}`) + .then(async (res: Response) => { + return res.json().then((data: WeatherAPIPointResponse) => { + const dataLoc = data.location; + + const loc = Object.assign({}, defaults); + loc.city = dataLoc.city; + loc.state = dataLoc.adminDistrict; + loc.country = dataLoc.country; + loc.countryCode = dataLoc.countryCode; + loc.latitude = dataLoc.latitude; + loc.longitude = dataLoc.longitude; + loc.timezone = dataLoc.ianaTimeZone; + + return loc; + }).catch(err => { + throw new Error(err); + }); + }).catch(err => { + throw new Error(err); + }); +}; + /** * Gets the closest location nearest to the user. * @returns A promise returning the {@link Location} of the user. @@ -297,8 +332,7 @@ export const getCurrentCond = async (lat: number, lon: number, options?: APIOpti }); }; -/** @internal */ -interface CurrentConds { +export interface CurrentConds { [latLon: string]: CurrentCond } @@ -622,3 +656,29 @@ export const getAlertColor = (alert: Alert) : AlertColor => { return color; }; + +export interface MarqueeLocation extends Location { + observations?: Partial +} + +// Cities that the marquee should cycle through +export const MarqueeCities: MarqueeLocation[] = [ + { + city: "Chicago", + state: "Illinois", + country: "United States", + countryCode: "US", + latitude: 41.882, + longitude: -87.629, + timezone: "America/Chicago" + }, + { + city: "Minneapolis", + state: "Minnesota", + country: "United States", + countryCode: "US", + latitude: 44.988, + longitude: -93.26, + timezone: "America/Chicago" + } +]; \ No newline at end of file From 5a978b4ae6c2bb0f7235b710da79f942ec406f22 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Sun, 18 Dec 2022 00:11:22 -0700 Subject: [PATCH 40/55] Nullish check --- components/Display.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/Display.tsx b/components/Display.tsx index 48151f9..453a269 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -227,7 +227,7 @@ const Display = ({ isReady, debug, winSize, location, language, units, muteSever const parsedLon = parseFloat(lon); const city = marqueeCities.find(c => c.latitude === parsedLat && c.longitude === parsedLon); - city.observations = cond; + if (city) city.observations = cond; } }; From eac5540c527ad496d6539952ec7699a366c1e5b0 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Tue, 20 Dec 2022 20:12:28 -0700 Subject: [PATCH 41/55] Add extended forecast header --- components/Display.tsx | 11 +++++++- .../Slides/City/CityInfo/Extended.tsx | 13 --------- .../Slides/City/CityInfo/Extended/Header.tsx | 22 +++++++++++++++ .../City/CityInfo/Extended/Linebreak.tsx | 7 +++++ .../Slides/City/CityInfo/Extended/Weekday.tsx | 23 +++++++++++++++ .../Slides/City/CityInfo/Extended/index.tsx | 28 +++++++++++++++++++ .../Containers/Slides/City/CityInfo/index.tsx | 10 ++----- hooks/useWeather.ts | 1 + pages/index.tsx | 1 + tailwind.config.js | 5 +++- 10 files changed, 99 insertions(+), 22 deletions(-) delete mode 100644 components/Slides/Containers/Slides/City/CityInfo/Extended.tsx create mode 100644 components/Slides/Containers/Slides/City/CityInfo/Extended/Header.tsx create mode 100644 components/Slides/Containers/Slides/City/CityInfo/Extended/Linebreak.tsx create mode 100644 components/Slides/Containers/Slides/City/CityInfo/Extended/Weekday.tsx create mode 100644 components/Slides/Containers/Slides/City/CityInfo/Extended/index.tsx diff --git a/components/Display.tsx b/components/Display.tsx index 69334d2..77e71d2 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -66,7 +66,16 @@ interface DisplayProps { setMainVol: React.Dispatch> } -const Display = ({ isReady, debug, winSize, location, language, units, muteSevere, setMainVol }: DisplayProps) => { +const Display = ({ + isReady, + debug, + winSize, + location, + language, + units, + muteSevere, + setMainVol +}: DisplayProps) => { const [cityIntroLoaded, setCityIntroLoaded] = React.useState(false); const [innerWidth, innerHeight] = winSize; const mainRef = React.useRef(); diff --git a/components/Slides/Containers/Slides/City/CityInfo/Extended.tsx b/components/Slides/Containers/Slides/City/CityInfo/Extended.tsx deleted file mode 100644 index 87fad68..0000000 --- a/components/Slides/Containers/Slides/City/CityInfo/Extended.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import * as React from "react"; -import type { ExtraInfo } from "../../../../../../hooks/useWeather"; - -interface ExtendedProps { - info?: ExtraInfo -} - -// Extended forecasts -const Extended = () => ( -
Extended
-); - -export default Extended; diff --git a/components/Slides/Containers/Slides/City/CityInfo/Extended/Header.tsx b/components/Slides/Containers/Slides/City/CityInfo/Extended/Header.tsx new file mode 100644 index 0000000..d0e2be7 --- /dev/null +++ b/components/Slides/Containers/Slides/City/CityInfo/Extended/Header.tsx @@ -0,0 +1,22 @@ +import * as React from "react"; + +interface ExtendedHeaderProps { + days: string[] +} + +const Header = ({ days }: ExtendedHeaderProps) => ( +
+ {days.map(day => ( +
{day}
+ ))} +
+); + +export default Header; diff --git a/components/Slides/Containers/Slides/City/CityInfo/Extended/Linebreak.tsx b/components/Slides/Containers/Slides/City/CityInfo/Extended/Linebreak.tsx new file mode 100644 index 0000000..6bb1e74 --- /dev/null +++ b/components/Slides/Containers/Slides/City/CityInfo/Extended/Linebreak.tsx @@ -0,0 +1,7 @@ +import * as React from "react"; + +const Linebreak = () => ( +
+); + +export default Linebreak; diff --git a/components/Slides/Containers/Slides/City/CityInfo/Extended/Weekday.tsx b/components/Slides/Containers/Slides/City/CityInfo/Extended/Weekday.tsx new file mode 100644 index 0000000..6f30fa0 --- /dev/null +++ b/components/Slides/Containers/Slides/City/CityInfo/Extended/Weekday.tsx @@ -0,0 +1,23 @@ +import * as React from "react"; +import FrostPane from "../../../FrostPane"; + +interface WeekdayProps { + title: string +} + +const Weekday = ({ title }: WeekdayProps) => ( + +
+ +); + +export default Weekday; diff --git a/components/Slides/Containers/Slides/City/CityInfo/Extended/index.tsx b/components/Slides/Containers/Slides/City/CityInfo/Extended/index.tsx new file mode 100644 index 0000000..52875a2 --- /dev/null +++ b/components/Slides/Containers/Slides/City/CityInfo/Extended/index.tsx @@ -0,0 +1,28 @@ +import * as React from "react"; +import type { ExtraInfo } from "../../../../../../../hooks/useWeather"; +const Header = React.lazy(() => import( + "./Header" /* webpackChunkName: "ciExtendedHeader" */ +)); +const Weekday = React.lazy(() => import( + "./Weekday" /* webpackChunkName: "ciExtendedWeekday" */ +)); +const Linebreak = React.lazy(() => import( + "./Linebreak" /* webpackChunkName: "ciExtendedLinebreak" */ +)); + +interface ExtendedProps { + info?: ExtraInfo +} + +// Extended forecasts +const Extended = ({ info }: ExtendedProps) => ( +
+); + +export default Extended; diff --git a/components/Slides/Containers/Slides/City/CityInfo/index.tsx b/components/Slides/Containers/Slides/City/CityInfo/index.tsx index 74e4f83..558edbb 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/index.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/index.tsx @@ -22,7 +22,7 @@ const Extended = React.lazy(() => import( const SlideCityInfo = ({ next, debug, location, currentCityInfo, setVocal }: SlideProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0 }); - const currentSlide = React.useMemo(() => { + /* const currentSlide = React.useMemo(() => { if (debug) console.log("Rendering new city info slide"); switch (slideState.index) { case SlidesCityInfo.DETAILED: @@ -42,10 +42,6 @@ const SlideCityInfo = ({ next, debug, location, currentCityInfo, setVocal }: Sli React.useEffect(() => { let timeout = setTimeout(() => { const numSlides = Object.keys(SlidesCityInfo).length / 2; - /* if (slideState.index >= (numSlides - 1)) setTimeout(() => { - next(); - slideDispatch({ type: ActionType.SET, payload: 0 }); - }, 800); */ if (slideState.index >= (numSlides - 1)) { next(); slideDispatch({ type: ActionType.SET, payload: 0 }); @@ -55,7 +51,7 @@ const SlideCityInfo = ({ next, debug, location, currentCityInfo, setVocal }: Sli slideDispatch({ type: ActionType.INCREASE, payload: 1 }); }, 8000); return () => clearTimeout(timeout); - }, [slideState.index]); + }, [slideState.index]); */ return ( - {currentSlide} + ); diff --git a/hooks/useWeather.ts b/hooks/useWeather.ts index bb458f0..0d2b124 100644 --- a/hooks/useWeather.ts +++ b/hooks/useWeather.ts @@ -83,6 +83,7 @@ export interface ExtraLocation { export interface ExtraInfo { details?: ExtraLocation current?: Partial + fiveDay?: CurrentCond[] } // ip-api.com diff --git a/pages/index.tsx b/pages/index.tsx index d281ee4..4d61470 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -50,6 +50,7 @@ const Index = () => { setUnits(units); } + // Mute severe marquees if (muteSevere !== undefined && muteSevere !== null) { setMuteSevere(Boolean(muteSevere)); } diff --git a/tailwind.config.js b/tailwind.config.js index ecd58f6..c3fe702 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -55,7 +55,8 @@ module.exports = { "severe-city-info-pos": "69% 41.5%", "frost-pane": "-72px -329px", "frost-pane-detailed-right": "-570px -329px", - "city-info-slide": "69% 41.5%" + "city-info-slide": "69% 41.5%", + "city-info-extended": "-72px -364px" }, backgroundSize: { "conditions-icon": "100% 100%", @@ -249,6 +250,8 @@ module.exports = { translate: { "2.5": "2.5px", "6px": "6px", + "10px": "10px", + "45px": "45px", "60px": "60px", "42-5": "42.5%", "43-5": "43.5%", From 6dd158e493781fc02e76d287b7313536c871f057 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Tue, 20 Dec 2022 20:14:31 -0700 Subject: [PATCH 42/55] Cleanup --- components/Slides/Containers/Slides/City/CityInfo/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/Slides/Containers/Slides/City/CityInfo/index.tsx b/components/Slides/Containers/Slides/City/CityInfo/index.tsx index 558edbb..22b2c6d 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/index.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/index.tsx @@ -22,7 +22,7 @@ const Extended = React.lazy(() => import( const SlideCityInfo = ({ next, debug, location, currentCityInfo, setVocal }: SlideProps) => { const [slideState, slideDispatch] = React.useReducer(SlideshowReducer, { index: 0 }); - /* const currentSlide = React.useMemo(() => { + const currentSlide = React.useMemo(() => { if (debug) console.log("Rendering new city info slide"); switch (slideState.index) { case SlidesCityInfo.DETAILED: @@ -51,7 +51,7 @@ const SlideCityInfo = ({ next, debug, location, currentCityInfo, setVocal }: Sli slideDispatch({ type: ActionType.INCREASE, payload: 1 }); }, 8000); return () => clearTimeout(timeout); - }, [slideState.index]); */ + }, [slideState.index]); return ( - + {currentSlide} ); From 53902114efabb4d47af7f4465f12b611f7287311 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Thu, 29 Dec 2022 01:07:01 -0700 Subject: [PATCH 43/55] Add extended forecast header background --- .../Containers/Slides/City/CityInfo/Extended/Header.tsx | 4 ++++ styles/global.scss | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/components/Slides/Containers/Slides/City/CityInfo/Extended/Header.tsx b/components/Slides/Containers/Slides/City/CityInfo/Extended/Header.tsx index d0e2be7..926e6ba 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/Extended/Header.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/Extended/Header.tsx @@ -9,6 +9,10 @@ const Header = ({ days }: ExtendedHeaderProps) => ( id="extendedHeader" className="text-white font-frutiger text-[30px] text-shadow h-[35px] w-full absolute flex top-[70px] z-[388688] text-center" > +
{days.map(day => (
Date: Fri, 30 Dec 2022 03:43:29 -0700 Subject: [PATCH 44/55] [skip build] Update copyright for new year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index afa4bb3..b5c57cb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Ryan Omasta +Copyright (c) 2023 Ryan Omasta Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 6ac942587fa741186ac1238836ff123185e97474 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Mon, 30 Jan 2023 11:53:59 -0700 Subject: [PATCH 45/55] Fade in item upon shift --- components/Slides/Containers/Headers/SlideHeaderScroll.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/Slides/Containers/Headers/SlideHeaderScroll.tsx b/components/Slides/Containers/Headers/SlideHeaderScroll.tsx index 88cec83..bd26e64 100644 --- a/components/Slides/Containers/Headers/SlideHeaderScroll.tsx +++ b/components/Slides/Containers/Headers/SlideHeaderScroll.tsx @@ -49,12 +49,14 @@ const SlideHeaderScroll = ({ locations, willUpdate, startCallback, finishCallbac const cityRefWidth = getWidth(current.city, "full"); const arrowRefWidth = getWidth(current.arrow, "full"); + items[1].city.classList.remove("opacity-half"); startCallback(items[1].city.innerHTML); controls.start({ left: `${-1.06*(cityRefWidth + arrowRefWidth)}px`, transition: { duration: 0.9 } }).then(() => { + items[1].city.classList.add("opacity-half"); finishCallback(items[1].city.innerHTML); setShiftNeeded(true); controls.set({ left: null }); From 64487c0687363651dc48ff020a6196868de65055 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Mon, 30 Jan 2023 12:50:06 -0700 Subject: [PATCH 46/55] Move extended slide into fragment --- .../Slides/City/CityInfo/Extended/index.tsx | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/components/Slides/Containers/Slides/City/CityInfo/Extended/index.tsx b/components/Slides/Containers/Slides/City/CityInfo/Extended/index.tsx index 52875a2..637ff11 100644 --- a/components/Slides/Containers/Slides/City/CityInfo/Extended/index.tsx +++ b/components/Slides/Containers/Slides/City/CityInfo/Extended/index.tsx @@ -1,13 +1,13 @@ import * as React from "react"; import type { ExtraInfo } from "../../../../../../../hooks/useWeather"; const Header = React.lazy(() => import( - "./Header" /* webpackChunkName: "ciExtendedHeader" */ + "./Header" /* webpackChunkName: "cSlideExtendedHeader" */ )); const Weekday = React.lazy(() => import( - "./Weekday" /* webpackChunkName: "ciExtendedWeekday" */ + "./Weekday" /* webpackChunkName: "cSlideExtendedWeekday" */ )); const Linebreak = React.lazy(() => import( - "./Linebreak" /* webpackChunkName: "ciExtendedLinebreak" */ + "./Linebreak" /* webpackChunkName: "cSlideExtendedLinebreak" */ )); interface ExtendedProps { @@ -16,13 +16,15 @@ interface ExtendedProps { // Extended forecasts const Extended = ({ info }: ExtendedProps) => ( -
+ <> +
+ ); export default Extended; From 8732a0e5457d5db5fb6b84c98263310c81dd01dc Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Fri, 17 Feb 2023 09:27:04 -0700 Subject: [PATCH 47/55] [pre] Trigger upload workflow From ac445ddbd62a9ab820b2785e7693179d1baef6c8 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Mon, 19 Jun 2023 11:13:59 -0600 Subject: [PATCH 48/55] Update frozen lockfile --- pnpm-lock.yaml | 1175 ++++++++++++++++++++++++------------------------ 1 file changed, 600 insertions(+), 575 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8d85a09..dc08344 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,72 +1,97 @@ -lockfileVersion: 5.4 - -specifiers: - '@types/node': 18.11.2 - '@types/react': ^18.0.21 - autoprefixer: ^10.4.12 - cssnano: ^5.1.13 - eslint: 8.26.0 - eslint-config-next: 13.0.1 - framer-motion: ^7.6.2 - iso8601-js-period: ^0.2.1 - leaflet: ^1.9.2 - leaflet-timedimension: ^1.1.1 - leaflet.nontiledlayer: ^1.0.9 - mapbox-gl: ^2.10.0 - maplibre-gl: ^2.4.0 - next: ^12.3.1 - postcss: ^8.4.17 - puppeteer: ^19.2.2 - react: ^18.2.0 - react-dom: ^18.2.0 - react-icons: ^4.4.0 - react-use-audio-player: ^1.2.6 - sass: ^1.55.0 - tailwindcss: ^3.1.8 - typescript: ^4.8.4 +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false dependencies: - framer-motion: 7.10.3_biqbaboplfbrettd7655fr4n2y - iso8601-js-period: 0.2.1 - leaflet: 1.9.3 - leaflet-timedimension: 1.1.1 - leaflet.nontiledlayer: 1.0.9 - mapbox-gl: 2.12.0 - maplibre-gl: 2.4.0 - next: 12.3.4_3duxcpitbtplz62feflag7fwby - react: 18.2.0 - react-dom: 18.2.0_react@18.2.0 - react-icons: 4.7.1_react@18.2.0 - react-use-audio-player: 1.2.6_react@18.2.0 - sass: 1.57.1 + framer-motion: + specifier: ^7.6.2 + version: 7.10.3(react-dom@18.2.0)(react@18.2.0) + iso8601-js-period: + specifier: ^0.2.1 + version: 0.2.1 + leaflet: + specifier: ^1.9.2 + version: 1.9.3 + leaflet-timedimension: + specifier: ^1.1.1 + version: 1.1.1 + leaflet.nontiledlayer: + specifier: ^1.0.9 + version: 1.0.9 + mapbox-gl: + specifier: ^2.10.0 + version: 2.12.0 + maplibre-gl: + specifier: ^2.4.0 + version: 2.4.0 + next: + specifier: ^12.3.1 + version: 12.3.4(react-dom@18.2.0)(react@18.2.0)(sass@1.57.1) + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + react-icons: + specifier: ^4.4.0 + version: 4.7.1(react@18.2.0) + react-use-audio-player: + specifier: ^1.2.6 + version: 1.2.6(react@18.2.0) + sass: + specifier: ^1.55.0 + version: 1.57.1 devDependencies: - '@types/node': 18.11.2 - '@types/react': 18.0.27 - autoprefixer: 10.4.13_postcss@8.4.21 - cssnano: 5.1.14_postcss@8.4.21 - eslint: 8.26.0 - eslint-config-next: 13.0.1_y3mxkvgm326kifdc6ztczmtrsu - postcss: 8.4.21 - puppeteer: 19.6.2 - tailwindcss: 3.2.4_postcss@8.4.21 - typescript: 4.9.5 + '@types/node': + specifier: 18.11.2 + version: 18.11.2 + '@types/react': + specifier: ^18.0.21 + version: 18.0.27 + autoprefixer: + specifier: ^10.4.12 + version: 10.4.13(postcss@8.4.21) + cssnano: + specifier: ^5.1.13 + version: 5.1.14(postcss@8.4.21) + eslint: + specifier: 8.26.0 + version: 8.26.0 + eslint-config-next: + specifier: 13.0.1 + version: 13.0.1(eslint@8.26.0)(typescript@4.9.5) + postcss: + specifier: ^8.4.17 + version: 8.4.21 + puppeteer: + specifier: ^19.2.2 + version: 19.6.2 + tailwindcss: + specifier: ^3.1.8 + version: 3.2.4(postcss@8.4.21) + typescript: + specifier: ^4.8.4 + version: 4.9.5 packages: - /@babel/code-frame/7.18.6: + /@babel/code-frame@7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.18.6 dev: true - /@babel/helper-validator-identifier/7.19.1: + /@babel/helper-validator-identifier@7.19.1: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} dev: true - /@babel/highlight/7.18.6: + /@babel/highlight@7.18.6: resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} engines: {node: '>=6.9.0'} dependencies: @@ -75,14 +100,14 @@ packages: js-tokens: 4.0.0 dev: true - /@babel/runtime/7.20.13: + /@babel/runtime@7.20.13: resolution: {integrity: sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.13.11 dev: true - /@emotion/is-prop-valid/0.8.8: + /@emotion/is-prop-valid@0.8.8: resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==} requiresBuild: true dependencies: @@ -90,12 +115,12 @@ packages: dev: false optional: true - /@emotion/memoize/0.7.4: + /@emotion/memoize@0.7.4: resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==} dev: false optional: true - /@eslint/eslintrc/1.4.1: + /@eslint/eslintrc@1.4.1: resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: @@ -112,7 +137,7 @@ packages: - supports-color dev: true - /@humanwhocodes/config-array/0.11.8: + /@humanwhocodes/config-array@0.11.8: resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} engines: {node: '>=10.10.0'} dependencies: @@ -123,16 +148,16 @@ packages: - supports-color dev: true - /@humanwhocodes/module-importer/1.0.1: + /@humanwhocodes/module-importer@1.0.1: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} dev: true - /@humanwhocodes/object-schema/1.2.1: + /@humanwhocodes/object-schema@1.2.1: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true - /@mapbox/geojson-rewind/0.5.2: + /@mapbox/geojson-rewind@0.5.2: resolution: {integrity: sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==} hasBin: true dependencies: @@ -140,39 +165,39 @@ packages: minimist: 1.2.7 dev: false - /@mapbox/jsonlint-lines-primitives/2.0.2: + /@mapbox/jsonlint-lines-primitives@2.0.2: resolution: {integrity: sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==} engines: {node: '>= 0.6'} dev: false - /@mapbox/mapbox-gl-supported/2.0.1: + /@mapbox/mapbox-gl-supported@2.0.1: resolution: {integrity: sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ==} dev: false - /@mapbox/point-geometry/0.1.0: + /@mapbox/point-geometry@0.1.0: resolution: {integrity: sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==} dev: false - /@mapbox/tiny-sdf/2.0.5: + /@mapbox/tiny-sdf@2.0.5: resolution: {integrity: sha512-OhXt2lS//WpLdkqrzo/KwB7SRD8AiNTFFzuo9n14IBupzIMa67yGItcK7I2W9D8Ghpa4T04Sw9FWsKCJG50Bxw==} dev: false - /@mapbox/unitbezier/0.0.1: + /@mapbox/unitbezier@0.0.1: resolution: {integrity: sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==} dev: false - /@mapbox/vector-tile/1.3.1: + /@mapbox/vector-tile@1.3.1: resolution: {integrity: sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==} dependencies: '@mapbox/point-geometry': 0.1.0 dev: false - /@mapbox/whoots-js/3.1.0: + /@mapbox/whoots-js@3.1.0: resolution: {integrity: sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==} engines: {node: '>=6.0.0'} dev: false - /@motionone/animation/10.15.1: + /@motionone/animation@10.15.1: resolution: {integrity: sha512-mZcJxLjHor+bhcPuIFErMDNyrdb2vJur8lSfMCsuCB4UyV8ILZLvK+t+pg56erv8ud9xQGK/1OGPt10agPrCyQ==} dependencies: '@motionone/easing': 10.15.1 @@ -181,7 +206,7 @@ packages: tslib: 2.4.0 dev: false - /@motionone/dom/10.15.5: + /@motionone/dom@10.15.5: resolution: {integrity: sha512-Xc5avlgyh3xukU9tydh9+8mB8+2zAq+WlLsC3eEIp7Ax7DnXgY7Bj/iv0a4X2R9z9ZFZiaXK3BO0xMYHKbAAdA==} dependencies: '@motionone/animation': 10.15.1 @@ -192,14 +217,14 @@ packages: tslib: 2.4.0 dev: false - /@motionone/easing/10.15.1: + /@motionone/easing@10.15.1: resolution: {integrity: sha512-6hIHBSV+ZVehf9dcKZLT7p5PEKHGhDwky2k8RKkmOvUoYP3S+dXsKupyZpqx5apjd9f+php4vXk4LuS+ADsrWw==} dependencies: '@motionone/utils': 10.15.1 tslib: 2.4.0 dev: false - /@motionone/generators/10.15.1: + /@motionone/generators@10.15.1: resolution: {integrity: sha512-67HLsvHJbw6cIbLA/o+gsm7h+6D4Sn7AUrB/GPxvujse1cGZ38F5H7DzoH7PhX+sjvtDnt2IhFYF2Zp1QTMKWQ==} dependencies: '@motionone/types': 10.15.1 @@ -207,11 +232,11 @@ packages: tslib: 2.4.0 dev: false - /@motionone/types/10.15.1: + /@motionone/types@10.15.1: resolution: {integrity: sha512-iIUd/EgUsRZGrvW0jqdst8st7zKTzS9EsKkP+6c6n4MPZoQHwiHuVtTQLD6Kp0bsBLhNzKIBlHXponn/SDT4hA==} dev: false - /@motionone/utils/10.15.1: + /@motionone/utils@10.15.1: resolution: {integrity: sha512-p0YncgU+iklvYr/Dq4NobTRdAPv9PveRDUXabPEeOjBLSO/1FNB2phNTZxOxpi1/GZwYpAoECEa0Wam+nsmhSw==} dependencies: '@motionone/types': 10.15.1 @@ -219,17 +244,17 @@ packages: tslib: 2.4.0 dev: false - /@next/env/12.3.4: + /@next/env@12.3.4: resolution: {integrity: sha512-H/69Lc5Q02dq3o+dxxy5O/oNxFsZpdL6WREtOOtOM1B/weonIwDXkekr1KV5DPVPr12IHFPrMrcJQ6bgPMfn7A==} dev: false - /@next/eslint-plugin-next/13.0.1: + /@next/eslint-plugin-next@13.0.1: resolution: {integrity: sha512-t3bggJhKE/oB4pvMM7hMNnmIpIqsMGJ+OLklk8llOkSeXtfCV+MBQbhImWxf5QODkxNAmMK3IJGAAecQhBTc/Q==} dependencies: glob: 7.1.7 dev: true - /@next/swc-android-arm-eabi/12.3.4: + /@next/swc-android-arm-eabi@12.3.4: resolution: {integrity: sha512-cM42Cw6V4Bz/2+j/xIzO8nK/Q3Ly+VSlZJTa1vHzsocJRYz8KT6MrreXaci2++SIZCF1rVRCDgAg5PpqRibdIA==} engines: {node: '>= 10'} cpu: [arm] @@ -238,7 +263,7 @@ packages: dev: false optional: true - /@next/swc-android-arm64/12.3.4: + /@next/swc-android-arm64@12.3.4: resolution: {integrity: sha512-5jf0dTBjL+rabWjGj3eghpLUxCukRhBcEJgwLedewEA/LJk2HyqCvGIwj5rH+iwmq1llCWbOky2dO3pVljrapg==} engines: {node: '>= 10'} cpu: [arm64] @@ -247,7 +272,7 @@ packages: dev: false optional: true - /@next/swc-darwin-arm64/12.3.4: + /@next/swc-darwin-arm64@12.3.4: resolution: {integrity: sha512-DqsSTd3FRjQUR6ao0E1e2OlOcrF5br+uegcEGPVonKYJpcr0MJrtYmPxd4v5T6UCJZ+XzydF7eQo5wdGvSZAyA==} engines: {node: '>= 10'} cpu: [arm64] @@ -256,7 +281,7 @@ packages: dev: false optional: true - /@next/swc-darwin-x64/12.3.4: + /@next/swc-darwin-x64@12.3.4: resolution: {integrity: sha512-PPF7tbWD4k0dJ2EcUSnOsaOJ5rhT3rlEt/3LhZUGiYNL8KvoqczFrETlUx0cUYaXe11dRA3F80Hpt727QIwByQ==} engines: {node: '>= 10'} cpu: [x64] @@ -265,7 +290,7 @@ packages: dev: false optional: true - /@next/swc-freebsd-x64/12.3.4: + /@next/swc-freebsd-x64@12.3.4: resolution: {integrity: sha512-KM9JXRXi/U2PUM928z7l4tnfQ9u8bTco/jb939pdFUHqc28V43Ohd31MmZD1QzEK4aFlMRaIBQOWQZh4D/E5lQ==} engines: {node: '>= 10'} cpu: [x64] @@ -274,7 +299,7 @@ packages: dev: false optional: true - /@next/swc-linux-arm-gnueabihf/12.3.4: + /@next/swc-linux-arm-gnueabihf@12.3.4: resolution: {integrity: sha512-3zqD3pO+z5CZyxtKDTnOJ2XgFFRUBciOox6EWkoZvJfc9zcidNAQxuwonUeNts6Xbm8Wtm5YGIRC0x+12YH7kw==} engines: {node: '>= 10'} cpu: [arm] @@ -283,7 +308,7 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-gnu/12.3.4: + /@next/swc-linux-arm64-gnu@12.3.4: resolution: {integrity: sha512-kiX0vgJGMZVv+oo1QuObaYulXNvdH/IINmvdZnVzMO/jic/B8EEIGlZ8Bgvw8LCjH3zNVPO3mGrdMvnEEPEhKA==} engines: {node: '>= 10'} cpu: [arm64] @@ -292,7 +317,7 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-musl/12.3.4: + /@next/swc-linux-arm64-musl@12.3.4: resolution: {integrity: sha512-EETZPa1juczrKLWk5okoW2hv7D7WvonU+Cf2CgsSoxgsYbUCZ1voOpL4JZTOb6IbKMDo6ja+SbY0vzXZBUMvkQ==} engines: {node: '>= 10'} cpu: [arm64] @@ -301,7 +326,7 @@ packages: dev: false optional: true - /@next/swc-linux-x64-gnu/12.3.4: + /@next/swc-linux-x64-gnu@12.3.4: resolution: {integrity: sha512-4csPbRbfZbuWOk3ATyWcvVFdD9/Rsdq5YHKvRuEni68OCLkfy4f+4I9OBpyK1SKJ00Cih16NJbHE+k+ljPPpag==} engines: {node: '>= 10'} cpu: [x64] @@ -310,7 +335,7 @@ packages: dev: false optional: true - /@next/swc-linux-x64-musl/12.3.4: + /@next/swc-linux-x64-musl@12.3.4: resolution: {integrity: sha512-YeBmI+63Ro75SUiL/QXEVXQ19T++58aI/IINOyhpsRL1LKdyfK/35iilraZEFz9bLQrwy1LYAR5lK200A9Gjbg==} engines: {node: '>= 10'} cpu: [x64] @@ -319,7 +344,7 @@ packages: dev: false optional: true - /@next/swc-win32-arm64-msvc/12.3.4: + /@next/swc-win32-arm64-msvc@12.3.4: resolution: {integrity: sha512-Sd0qFUJv8Tj0PukAYbCCDbmXcMkbIuhnTeHm9m4ZGjCf6kt7E/RMs55Pd3R5ePjOkN7dJEuxYBehawTR/aPDSQ==} engines: {node: '>= 10'} cpu: [arm64] @@ -328,7 +353,7 @@ packages: dev: false optional: true - /@next/swc-win32-ia32-msvc/12.3.4: + /@next/swc-win32-ia32-msvc@12.3.4: resolution: {integrity: sha512-rt/vv/vg/ZGGkrkKcuJ0LyliRdbskQU+91bje+PgoYmxTZf/tYs6IfbmgudBJk6gH3QnjHWbkphDdRQrseRefQ==} engines: {node: '>= 10'} cpu: [ia32] @@ -337,7 +362,7 @@ packages: dev: false optional: true - /@next/swc-win32-x64-msvc/12.3.4: + /@next/swc-win32-x64-msvc@12.3.4: resolution: {integrity: sha512-DQ20JEfTBZAgF8QCjYfJhv2/279M6onxFjdG/+5B0Cyj00/EdBxiWb2eGGFgQhrBbNv/lsvzFbbi0Ptf8Vw/bg==} engines: {node: '>= 10'} cpu: [x64] @@ -346,7 +371,7 @@ packages: dev: false optional: true - /@nodelib/fs.scandir/2.1.5: + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} dependencies: @@ -354,12 +379,12 @@ packages: run-parallel: 1.2.0 dev: true - /@nodelib/fs.stat/2.0.5: + /@nodelib/fs.stat@2.0.5: resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} dev: true - /@nodelib/fs.walk/1.2.8: + /@nodelib/fs.walk@1.2.8: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} dependencies: @@ -367,34 +392,34 @@ packages: fastq: 1.15.0 dev: true - /@rushstack/eslint-patch/1.2.0: + /@rushstack/eslint-patch@1.2.0: resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==} dev: true - /@swc/helpers/0.4.11: + /@swc/helpers@0.4.11: resolution: {integrity: sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==} dependencies: tslib: 2.5.0 dev: false - /@trysound/sax/0.2.0: + /@trysound/sax@0.2.0: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} dev: true - /@types/geojson/7946.0.10: + /@types/geojson@7946.0.10: resolution: {integrity: sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==} dev: false - /@types/json5/0.0.29: + /@types/json5@0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true - /@types/mapbox__point-geometry/0.1.2: + /@types/mapbox__point-geometry@0.1.2: resolution: {integrity: sha512-D0lgCq+3VWV85ey1MZVkE8ZveyuvW5VAfuahVTQRpXFQTxw03SuIf1/K4UQ87MMIXVKzpFjXFiFMZzLj2kU+iA==} dev: false - /@types/mapbox__vector-tile/1.3.0: + /@types/mapbox__vector-tile@1.3.0: resolution: {integrity: sha512-kDwVreQO5V4c8yAxzZVQLE5tyWF+IPToAanloQaSnwfXmIcJ7cyOrv8z4Ft4y7PsLYmhWXmON8MBV8RX0Rgr8g==} dependencies: '@types/geojson': 7946.0.10 @@ -402,19 +427,19 @@ packages: '@types/pbf': 3.0.2 dev: false - /@types/node/18.11.2: + /@types/node@18.11.2: resolution: {integrity: sha512-BWN3M23gLO2jVG8g/XHIRFWiiV4/GckeFIqbU/C4V3xpoBBWSMk4OZomouN0wCkfQFPqgZikyLr7DOYDysIkkw==} dev: true - /@types/pbf/3.0.2: + /@types/pbf@3.0.2: resolution: {integrity: sha512-EDrLIPaPXOZqDjrkzxxbX7UlJSeQVgah3i0aA4pOSzmK9zq3BIh7/MZIQxED7slJByvKM4Gc6Hypyu2lJzh3SQ==} dev: false - /@types/prop-types/15.7.5: + /@types/prop-types@15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} dev: true - /@types/react/18.0.27: + /@types/react@18.0.27: resolution: {integrity: sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==} dependencies: '@types/prop-types': 15.7.5 @@ -422,11 +447,11 @@ packages: csstype: 3.1.1 dev: true - /@types/scheduler/0.16.2: + /@types/scheduler@0.16.2: resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} dev: true - /@types/yauzl/2.10.0: + /@types/yauzl@2.10.0: resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} requiresBuild: true dependencies: @@ -434,7 +459,7 @@ packages: dev: true optional: true - /@typescript-eslint/parser/5.50.0_y3mxkvgm326kifdc6ztczmtrsu: + /@typescript-eslint/parser@5.50.0(eslint@8.26.0)(typescript@4.9.5): resolution: {integrity: sha512-KCcSyNaogUDftK2G9RXfQyOCt51uB5yqC6pkUYqhYh8Kgt+DwR5M0EwEAxGPy/+DH6hnmKeGsNhiZRQxjH71uQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -446,7 +471,7 @@ packages: dependencies: '@typescript-eslint/scope-manager': 5.50.0 '@typescript-eslint/types': 5.50.0 - '@typescript-eslint/typescript-estree': 5.50.0_typescript@4.9.5 + '@typescript-eslint/typescript-estree': 5.50.0(typescript@4.9.5) debug: 4.3.4 eslint: 8.26.0 typescript: 4.9.5 @@ -454,7 +479,7 @@ packages: - supports-color dev: true - /@typescript-eslint/scope-manager/5.50.0: + /@typescript-eslint/scope-manager@5.50.0: resolution: {integrity: sha512-rt03kaX+iZrhssaT974BCmoUikYtZI24Vp/kwTSy841XhiYShlqoshRFDvN1FKKvU2S3gK+kcBW1EA7kNUrogg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: @@ -462,12 +487,12 @@ packages: '@typescript-eslint/visitor-keys': 5.50.0 dev: true - /@typescript-eslint/types/5.50.0: + /@typescript-eslint/types@5.50.0: resolution: {integrity: sha512-atruOuJpir4OtyNdKahiHZobPKFvZnBnfDiyEaBf6d9vy9visE7gDjlmhl+y29uxZ2ZDgvXijcungGFjGGex7w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree/5.50.0_typescript@4.9.5: + /@typescript-eslint/typescript-estree@5.50.0(typescript@4.9.5): resolution: {integrity: sha512-Gq4zapso+OtIZlv8YNAStFtT6d05zyVCK7Fx3h5inlLBx2hWuc/0465C2mg/EQDDU2LKe52+/jN4f0g9bd+kow==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -482,13 +507,13 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.3.8 - tsutils: 3.21.0_typescript@4.9.5 + tsutils: 3.21.0(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/visitor-keys/5.50.0: + /@typescript-eslint/visitor-keys@5.50.0: resolution: {integrity: sha512-cdMeD9HGu6EXIeGOh2yVW6oGf9wq8asBgZx7nsR/D36gTfQ0odE5kcRYe5M81vjEFAcPeugXrHg78Imu55F6gg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: @@ -496,7 +521,7 @@ packages: eslint-visitor-keys: 3.3.0 dev: true - /acorn-jsx/5.3.2_acorn@8.8.2: + /acorn-jsx@5.3.2(acorn@8.8.2): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -504,7 +529,7 @@ packages: acorn: 8.8.2 dev: true - /acorn-node/1.8.2: + /acorn-node@1.8.2: resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==} dependencies: acorn: 7.4.1 @@ -512,24 +537,24 @@ packages: xtend: 4.0.2 dev: true - /acorn-walk/7.2.0: + /acorn-walk@7.2.0: resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} engines: {node: '>=0.4.0'} dev: true - /acorn/7.4.1: + /acorn@7.4.1: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} engines: {node: '>=0.4.0'} hasBin: true dev: true - /acorn/8.8.2: + /acorn@8.8.2: resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} engines: {node: '>=0.4.0'} hasBin: true dev: true - /agent-base/6.0.2: + /agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: @@ -538,7 +563,7 @@ packages: - supports-color dev: true - /ajv/6.12.6: + /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: fast-deep-equal: 3.1.3 @@ -547,47 +572,47 @@ packages: uri-js: 4.4.1 dev: true - /ansi-regex/5.0.1: + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} dev: true - /ansi-styles/3.2.1: + /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} dependencies: color-convert: 1.9.3 dev: true - /ansi-styles/4.3.0: + /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} dependencies: color-convert: 2.0.1 dev: true - /anymatch/3.1.3: + /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - /arg/5.0.2: + /arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} dev: true - /argparse/2.0.1: + /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true - /aria-query/5.1.3: + /aria-query@5.1.3: resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} dependencies: deep-equal: 2.2.0 dev: true - /array-includes/3.1.6: + /array-includes@3.1.6: resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} engines: {node: '>= 0.4'} dependencies: @@ -598,12 +623,12 @@ packages: is-string: 1.0.7 dev: true - /array-union/2.1.0: + /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} dev: true - /array.prototype.flat/1.3.1: + /array.prototype.flat@1.3.1: resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} engines: {node: '>= 0.4'} dependencies: @@ -613,7 +638,7 @@ packages: es-shim-unscopables: 1.0.0 dev: true - /array.prototype.flatmap/1.3.1: + /array.prototype.flatmap@1.3.1: resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} engines: {node: '>= 0.4'} dependencies: @@ -623,7 +648,7 @@ packages: es-shim-unscopables: 1.0.0 dev: true - /array.prototype.tosorted/1.1.1: + /array.prototype.tosorted@1.1.1: resolution: {integrity: sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==} dependencies: call-bind: 1.0.2 @@ -633,11 +658,11 @@ packages: get-intrinsic: 1.2.0 dev: true - /ast-types-flow/0.0.7: + /ast-types-flow@0.0.7: resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} dev: true - /autoprefixer/10.4.13_postcss@8.4.21: + /autoprefixer@10.4.13(postcss@8.4.21): resolution: {integrity: sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==} engines: {node: ^10 || ^12 || >=14} hasBin: true @@ -653,35 +678,35 @@ packages: postcss-value-parser: 4.2.0 dev: true - /available-typed-arrays/1.0.5: + /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} dev: true - /axe-core/4.6.3: + /axe-core@4.6.3: resolution: {integrity: sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg==} engines: {node: '>=4'} dev: true - /axobject-query/3.1.1: + /axobject-query@3.1.1: resolution: {integrity: sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==} dependencies: deep-equal: 2.2.0 dev: true - /balanced-match/1.0.2: + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true - /base64-js/1.5.1: + /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} dev: true - /binary-extensions/2.2.0: + /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} - /bl/4.1.0: + /bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} dependencies: buffer: 5.7.1 @@ -689,24 +714,24 @@ packages: readable-stream: 3.6.0 dev: true - /boolbase/1.0.0: + /boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} dev: true - /brace-expansion/1.1.11: + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 dev: true - /braces/3.0.2: + /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} dependencies: fill-range: 7.0.1 - /browserslist/4.21.5: + /browserslist@4.21.5: resolution: {integrity: sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -714,38 +739,38 @@ packages: caniuse-lite: 1.0.30001449 electron-to-chromium: 1.4.284 node-releases: 2.0.9 - update-browserslist-db: 1.0.10_browserslist@4.21.5 + update-browserslist-db: 1.0.10(browserslist@4.21.5) dev: true - /buffer-crc32/0.2.13: + /buffer-crc32@0.2.13: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} dev: true - /buffer/5.7.1: + /buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} dependencies: base64-js: 1.5.1 ieee754: 1.2.1 dev: true - /call-bind/1.0.2: + /call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: function-bind: 1.1.1 get-intrinsic: 1.2.0 dev: true - /callsites/3.1.0: + /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} dev: true - /camelcase-css/2.0.1: + /camelcase-css@2.0.1: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} dev: true - /caniuse-api/3.0.0: + /caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} dependencies: browserslist: 4.21.5 @@ -754,10 +779,10 @@ packages: lodash.uniq: 4.5.0 dev: true - /caniuse-lite/1.0.30001449: + /caniuse-lite@1.0.30001449: resolution: {integrity: sha512-CPB+UL9XMT/Av+pJxCKGhdx+yg1hzplvFJQlJ2n68PyQGMz9L/E2zCyLdOL8uasbouTUgnPl+y0tccI/se+BEw==} - /chalk/2.4.2: + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} dependencies: @@ -766,7 +791,7 @@ packages: supports-color: 5.5.0 dev: true - /chalk/4.1.2: + /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} dependencies: @@ -774,7 +799,7 @@ packages: supports-color: 7.2.0 dev: true - /chokidar/3.5.3: + /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} dependencies: @@ -788,45 +813,45 @@ packages: optionalDependencies: fsevents: 2.3.2 - /chownr/1.1.4: + /chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} dev: true - /color-convert/1.9.3: + /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 dev: true - /color-convert/2.0.1: + /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 dev: true - /color-name/1.1.3: + /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} dev: true - /color-name/1.1.4: + /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true - /colord/2.9.3: + /colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} dev: true - /commander/7.2.0: + /commander@7.2.0: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} dev: true - /concat-map/0.0.1: + /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true - /cosmiconfig/8.0.0: + /cosmiconfig@8.0.0: resolution: {integrity: sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==} engines: {node: '>=14'} dependencies: @@ -836,7 +861,7 @@ packages: path-type: 4.0.0 dev: true - /cross-fetch/3.1.5: + /cross-fetch@3.1.5: resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==} dependencies: node-fetch: 2.6.7 @@ -844,7 +869,7 @@ packages: - encoding dev: true - /cross-spawn/7.0.3: + /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} dependencies: @@ -853,7 +878,7 @@ packages: which: 2.0.2 dev: true - /css-declaration-sorter/6.3.1_postcss@8.4.21: + /css-declaration-sorter@6.3.1(postcss@8.4.21): resolution: {integrity: sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==} engines: {node: ^10 || ^12 || >=14} peerDependencies: @@ -862,7 +887,7 @@ packages: postcss: 8.4.21 dev: true - /css-select/4.3.0: + /css-select@4.3.0: resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} dependencies: boolbase: 1.0.0 @@ -872,7 +897,7 @@ packages: nth-check: 2.1.1 dev: true - /css-tree/1.1.3: + /css-tree@1.1.3: resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} engines: {node: '>=8.0.0'} dependencies: @@ -880,60 +905,60 @@ packages: source-map: 0.6.1 dev: true - /css-what/6.1.0: + /css-what@6.1.0: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} dev: true - /csscolorparser/1.0.3: + /csscolorparser@1.0.3: resolution: {integrity: sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==} dev: false - /cssesc/3.0.0: + /cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} hasBin: true dev: true - /cssnano-preset-default/5.2.13_postcss@8.4.21: + /cssnano-preset-default@5.2.13(postcss@8.4.21): resolution: {integrity: sha512-PX7sQ4Pb+UtOWuz8A1d+Rbi+WimBIxJTRyBdgGp1J75VU0r/HFQeLnMYgHiCAp6AR4rqrc7Y4R+1Rjk3KJz6DQ==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - css-declaration-sorter: 6.3.1_postcss@8.4.21 - cssnano-utils: 3.1.0_postcss@8.4.21 + css-declaration-sorter: 6.3.1(postcss@8.4.21) + cssnano-utils: 3.1.0(postcss@8.4.21) postcss: 8.4.21 - postcss-calc: 8.2.4_postcss@8.4.21 - postcss-colormin: 5.3.0_postcss@8.4.21 - postcss-convert-values: 5.1.3_postcss@8.4.21 - postcss-discard-comments: 5.1.2_postcss@8.4.21 - postcss-discard-duplicates: 5.1.0_postcss@8.4.21 - postcss-discard-empty: 5.1.1_postcss@8.4.21 - postcss-discard-overridden: 5.1.0_postcss@8.4.21 - postcss-merge-longhand: 5.1.7_postcss@8.4.21 - postcss-merge-rules: 5.1.3_postcss@8.4.21 - postcss-minify-font-values: 5.1.0_postcss@8.4.21 - postcss-minify-gradients: 5.1.1_postcss@8.4.21 - postcss-minify-params: 5.1.4_postcss@8.4.21 - postcss-minify-selectors: 5.2.1_postcss@8.4.21 - postcss-normalize-charset: 5.1.0_postcss@8.4.21 - postcss-normalize-display-values: 5.1.0_postcss@8.4.21 - postcss-normalize-positions: 5.1.1_postcss@8.4.21 - postcss-normalize-repeat-style: 5.1.1_postcss@8.4.21 - postcss-normalize-string: 5.1.0_postcss@8.4.21 - postcss-normalize-timing-functions: 5.1.0_postcss@8.4.21 - postcss-normalize-unicode: 5.1.1_postcss@8.4.21 - postcss-normalize-url: 5.1.0_postcss@8.4.21 - postcss-normalize-whitespace: 5.1.1_postcss@8.4.21 - postcss-ordered-values: 5.1.3_postcss@8.4.21 - postcss-reduce-initial: 5.1.1_postcss@8.4.21 - postcss-reduce-transforms: 5.1.0_postcss@8.4.21 - postcss-svgo: 5.1.0_postcss@8.4.21 - postcss-unique-selectors: 5.1.1_postcss@8.4.21 - dev: true - - /cssnano-utils/3.1.0_postcss@8.4.21: + postcss-calc: 8.2.4(postcss@8.4.21) + postcss-colormin: 5.3.0(postcss@8.4.21) + postcss-convert-values: 5.1.3(postcss@8.4.21) + postcss-discard-comments: 5.1.2(postcss@8.4.21) + postcss-discard-duplicates: 5.1.0(postcss@8.4.21) + postcss-discard-empty: 5.1.1(postcss@8.4.21) + postcss-discard-overridden: 5.1.0(postcss@8.4.21) + postcss-merge-longhand: 5.1.7(postcss@8.4.21) + postcss-merge-rules: 5.1.3(postcss@8.4.21) + postcss-minify-font-values: 5.1.0(postcss@8.4.21) + postcss-minify-gradients: 5.1.1(postcss@8.4.21) + postcss-minify-params: 5.1.4(postcss@8.4.21) + postcss-minify-selectors: 5.2.1(postcss@8.4.21) + postcss-normalize-charset: 5.1.0(postcss@8.4.21) + postcss-normalize-display-values: 5.1.0(postcss@8.4.21) + postcss-normalize-positions: 5.1.1(postcss@8.4.21) + postcss-normalize-repeat-style: 5.1.1(postcss@8.4.21) + postcss-normalize-string: 5.1.0(postcss@8.4.21) + postcss-normalize-timing-functions: 5.1.0(postcss@8.4.21) + postcss-normalize-unicode: 5.1.1(postcss@8.4.21) + postcss-normalize-url: 5.1.0(postcss@8.4.21) + postcss-normalize-whitespace: 5.1.1(postcss@8.4.21) + postcss-ordered-values: 5.1.3(postcss@8.4.21) + postcss-reduce-initial: 5.1.1(postcss@8.4.21) + postcss-reduce-transforms: 5.1.0(postcss@8.4.21) + postcss-svgo: 5.1.0(postcss@8.4.21) + postcss-unique-selectors: 5.1.1(postcss@8.4.21) + dev: true + + /cssnano-utils@3.1.0(postcss@8.4.21): resolution: {integrity: sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -942,34 +967,34 @@ packages: postcss: 8.4.21 dev: true - /cssnano/5.1.14_postcss@8.4.21: + /cssnano@5.1.14(postcss@8.4.21): resolution: {integrity: sha512-Oou7ihiTocbKqi0J1bB+TRJIQX5RMR3JghA8hcWSw9mjBLQ5Y3RWqEDoYG3sRNlAbCIXpqMoZGbq5KDR3vdzgw==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - cssnano-preset-default: 5.2.13_postcss@8.4.21 + cssnano-preset-default: 5.2.13(postcss@8.4.21) lilconfig: 2.0.6 postcss: 8.4.21 yaml: 1.10.2 dev: true - /csso/4.2.0: + /csso@4.2.0: resolution: {integrity: sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==} engines: {node: '>=8.0.0'} dependencies: css-tree: 1.1.3 dev: true - /csstype/3.1.1: + /csstype@3.1.1: resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} dev: true - /damerau-levenshtein/1.0.8: + /damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} dev: true - /debug/3.2.7: + /debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: supports-color: '*' @@ -980,7 +1005,7 @@ packages: ms: 2.1.3 dev: true - /debug/4.3.4: + /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} peerDependencies: @@ -992,7 +1017,7 @@ packages: ms: 2.1.2 dev: true - /deep-equal/2.2.0: + /deep-equal@2.2.0: resolution: {integrity: sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==} dependencies: call-bind: 1.0.2 @@ -1014,11 +1039,11 @@ packages: which-typed-array: 1.1.9 dev: true - /deep-is/0.1.4: + /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true - /define-properties/1.1.4: + /define-properties@1.1.4: resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} engines: {node: '>= 0.4'} dependencies: @@ -1026,11 +1051,11 @@ packages: object-keys: 1.1.1 dev: true - /defined/1.0.1: + /defined@1.0.1: resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==} dev: true - /detective/5.2.1: + /detective@5.2.1: resolution: {integrity: sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==} engines: {node: '>=0.8.0'} hasBin: true @@ -1040,40 +1065,40 @@ packages: minimist: 1.2.7 dev: true - /devtools-protocol/0.0.1082910: + /devtools-protocol@0.0.1082910: resolution: {integrity: sha512-RqoZ2GmqaNxyx+99L/RemY5CkwG9D0WEfOKxekwCRXOGrDCep62ngezEJUVMq6rISYQ+085fJnWDQqGHlxVNww==} dev: true - /didyoumean/1.2.2: + /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} dev: true - /dir-glob/3.0.1: + /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} dependencies: path-type: 4.0.0 dev: true - /dlv/1.1.3: + /dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} dev: true - /doctrine/2.1.0: + /doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} dependencies: esutils: 2.0.3 dev: true - /doctrine/3.0.0: + /doctrine@3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} dependencies: esutils: 2.0.3 dev: true - /dom-serializer/1.4.1: + /dom-serializer@1.4.1: resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} dependencies: domelementtype: 2.3.0 @@ -1081,18 +1106,18 @@ packages: entities: 2.2.0 dev: true - /domelementtype/2.3.0: + /domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} dev: true - /domhandler/4.3.1: + /domhandler@4.3.1: resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} engines: {node: '>= 4'} dependencies: domelementtype: 2.3.0 dev: true - /domutils/2.8.0: + /domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} dependencies: dom-serializer: 1.4.1 @@ -1100,35 +1125,35 @@ packages: domhandler: 4.3.1 dev: true - /earcut/2.2.4: + /earcut@2.2.4: resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==} dev: false - /electron-to-chromium/1.4.284: + /electron-to-chromium@1.4.284: resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==} dev: true - /emoji-regex/9.2.2: + /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} dev: true - /end-of-stream/1.4.4: + /end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} dependencies: once: 1.4.0 dev: true - /entities/2.2.0: + /entities@2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} dev: true - /error-ex/1.3.2: + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: is-arrayish: 0.2.1 dev: true - /es-abstract/1.21.1: + /es-abstract@1.21.1: resolution: {integrity: sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==} engines: {node: '>= 0.4'} dependencies: @@ -1167,7 +1192,7 @@ packages: which-typed-array: 1.1.9 dev: true - /es-get-iterator/1.1.3: + /es-get-iterator@1.1.3: resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} dependencies: call-bind: 1.0.2 @@ -1181,7 +1206,7 @@ packages: stop-iteration-iterator: 1.0.0 dev: true - /es-set-tostringtag/2.0.1: + /es-set-tostringtag@2.0.1: resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} engines: {node: '>= 0.4'} dependencies: @@ -1190,13 +1215,13 @@ packages: has-tostringtag: 1.0.0 dev: true - /es-shim-unscopables/1.0.0: + /es-shim-unscopables@1.0.0: resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} dependencies: has: 1.0.3 dev: true - /es-to-primitive/1.2.1: + /es-to-primitive@1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} dependencies: @@ -1205,22 +1230,22 @@ packages: is-symbol: 1.0.4 dev: true - /escalade/3.1.1: + /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} dev: true - /escape-string-regexp/1.0.5: + /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} dev: true - /escape-string-regexp/4.0.0: + /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} dev: true - /eslint-config-next/13.0.1_y3mxkvgm326kifdc6ztczmtrsu: + /eslint-config-next@13.0.1(eslint@8.26.0)(typescript@4.9.5): resolution: {integrity: sha512-/N9UpSwkbEMj5pIiB235p7QHaSW08ta/iKVaIHF44wufxr+PuJVLwg5LzlAaQbmCZCBpYvVttl3ZxTusP1g2sg==} peerDependencies: eslint: ^7.23.0 || ^8.0.0 @@ -1231,21 +1256,21 @@ packages: dependencies: '@next/eslint-plugin-next': 13.0.1 '@rushstack/eslint-patch': 1.2.0 - '@typescript-eslint/parser': 5.50.0_y3mxkvgm326kifdc6ztczmtrsu + '@typescript-eslint/parser': 5.50.0(eslint@8.26.0)(typescript@4.9.5) eslint: 8.26.0 eslint-import-resolver-node: 0.3.7 - eslint-import-resolver-typescript: 2.7.1_e55ds5l35gpamu3vxkmffm35ca - eslint-plugin-import: 2.27.5_dut5jefbrkytdmvzoyavqtljf4 - eslint-plugin-jsx-a11y: 6.7.1_eslint@8.26.0 - eslint-plugin-react: 7.32.2_eslint@8.26.0 - eslint-plugin-react-hooks: 4.6.0_eslint@8.26.0 + eslint-import-resolver-typescript: 2.7.1(eslint-plugin-import@2.27.5)(eslint@8.26.0) + eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.50.0)(eslint-import-resolver-typescript@2.7.1)(eslint@8.26.0) + eslint-plugin-jsx-a11y: 6.7.1(eslint@8.26.0) + eslint-plugin-react: 7.32.2(eslint@8.26.0) + eslint-plugin-react-hooks: 4.6.0(eslint@8.26.0) typescript: 4.9.5 transitivePeerDependencies: - eslint-import-resolver-webpack - supports-color dev: true - /eslint-import-resolver-node/0.3.7: + /eslint-import-resolver-node@0.3.7: resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} dependencies: debug: 3.2.7 @@ -1255,7 +1280,7 @@ packages: - supports-color dev: true - /eslint-import-resolver-typescript/2.7.1_e55ds5l35gpamu3vxkmffm35ca: + /eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.27.5)(eslint@8.26.0): resolution: {integrity: sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==} engines: {node: '>=4'} peerDependencies: @@ -1264,7 +1289,7 @@ packages: dependencies: debug: 4.3.4 eslint: 8.26.0 - eslint-plugin-import: 2.27.5_dut5jefbrkytdmvzoyavqtljf4 + eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.50.0)(eslint-import-resolver-typescript@2.7.1)(eslint@8.26.0) glob: 7.2.3 is-glob: 4.0.3 resolve: 1.22.1 @@ -1273,7 +1298,7 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.4_egrw3pfc2lyvzroq5dfm72hzqu: + /eslint-module-utils@2.7.4(@typescript-eslint/parser@5.50.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@2.7.1)(eslint@8.26.0): resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} peerDependencies: @@ -1294,16 +1319,16 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.50.0_y3mxkvgm326kifdc6ztczmtrsu + '@typescript-eslint/parser': 5.50.0(eslint@8.26.0)(typescript@4.9.5) debug: 3.2.7 eslint: 8.26.0 eslint-import-resolver-node: 0.3.7 - eslint-import-resolver-typescript: 2.7.1_e55ds5l35gpamu3vxkmffm35ca + eslint-import-resolver-typescript: 2.7.1(eslint-plugin-import@2.27.5)(eslint@8.26.0) transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import/2.27.5_dut5jefbrkytdmvzoyavqtljf4: + /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.50.0)(eslint-import-resolver-typescript@2.7.1)(eslint@8.26.0): resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} engines: {node: '>=4'} peerDependencies: @@ -1313,7 +1338,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.50.0_y3mxkvgm326kifdc6ztczmtrsu + '@typescript-eslint/parser': 5.50.0(eslint@8.26.0)(typescript@4.9.5) array-includes: 3.1.6 array.prototype.flat: 1.3.1 array.prototype.flatmap: 1.3.1 @@ -1321,7 +1346,7 @@ packages: doctrine: 2.1.0 eslint: 8.26.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.7.4_egrw3pfc2lyvzroq5dfm72hzqu + eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.50.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@2.7.1)(eslint@8.26.0) has: 1.0.3 is-core-module: 2.11.0 is-glob: 4.0.3 @@ -1336,7 +1361,7 @@ packages: - supports-color dev: true - /eslint-plugin-jsx-a11y/6.7.1_eslint@8.26.0: + /eslint-plugin-jsx-a11y@6.7.1(eslint@8.26.0): resolution: {integrity: sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==} engines: {node: '>=4.0'} peerDependencies: @@ -1361,7 +1386,7 @@ packages: semver: 6.3.0 dev: true - /eslint-plugin-react-hooks/4.6.0_eslint@8.26.0: + /eslint-plugin-react-hooks@4.6.0(eslint@8.26.0): resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} engines: {node: '>=10'} peerDependencies: @@ -1370,7 +1395,7 @@ packages: eslint: 8.26.0 dev: true - /eslint-plugin-react/7.32.2_eslint@8.26.0: + /eslint-plugin-react@7.32.2(eslint@8.26.0): resolution: {integrity: sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==} engines: {node: '>=4'} peerDependencies: @@ -1394,7 +1419,7 @@ packages: string.prototype.matchall: 4.0.8 dev: true - /eslint-scope/7.1.1: + /eslint-scope@7.1.1: resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: @@ -1402,7 +1427,7 @@ packages: estraverse: 5.3.0 dev: true - /eslint-utils/3.0.0_eslint@8.26.0: + /eslint-utils@3.0.0(eslint@8.26.0): resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: @@ -1412,17 +1437,17 @@ packages: eslint-visitor-keys: 2.1.0 dev: true - /eslint-visitor-keys/2.1.0: + /eslint-visitor-keys@2.1.0: resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} engines: {node: '>=10'} dev: true - /eslint-visitor-keys/3.3.0: + /eslint-visitor-keys@3.3.0: resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint/8.26.0: + /eslint@8.26.0: resolution: {integrity: sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true @@ -1438,7 +1463,7 @@ packages: doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.1.1 - eslint-utils: 3.0.0_eslint@8.26.0 + eslint-utils: 3.0.0(eslint@8.26.0) eslint-visitor-keys: 3.3.0 espree: 9.4.1 esquery: 1.4.0 @@ -1470,40 +1495,40 @@ packages: - supports-color dev: true - /espree/9.4.1: + /espree@9.4.1: resolution: {integrity: sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: acorn: 8.8.2 - acorn-jsx: 5.3.2_acorn@8.8.2 + acorn-jsx: 5.3.2(acorn@8.8.2) eslint-visitor-keys: 3.3.0 dev: true - /esquery/1.4.0: + /esquery@1.4.0: resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==} engines: {node: '>=0.10'} dependencies: estraverse: 5.3.0 dev: true - /esrecurse/4.3.0: + /esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} dependencies: estraverse: 5.3.0 dev: true - /estraverse/5.3.0: + /estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} dev: true - /esutils/2.0.3: + /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} dev: true - /extract-zip/2.0.1: + /extract-zip@2.0.1: resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} engines: {node: '>= 10.17.0'} hasBin: true @@ -1517,11 +1542,11 @@ packages: - supports-color dev: true - /fast-deep-equal/3.1.3: + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true - /fast-glob/3.2.12: + /fast-glob@3.2.12: resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} engines: {node: '>=8.6.0'} dependencies: @@ -1532,40 +1557,40 @@ packages: micromatch: 4.0.5 dev: true - /fast-json-stable-stringify/2.1.0: + /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} dev: true - /fast-levenshtein/2.0.6: + /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true - /fastq/1.15.0: + /fastq@1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: reusify: 1.0.4 dev: true - /fd-slicer/1.1.0: + /fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} dependencies: pend: 1.2.0 dev: true - /file-entry-cache/6.0.1: + /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: flat-cache: 3.0.4 dev: true - /fill-range/7.0.1: + /fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 - /find-up/5.0.0: + /find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} dependencies: @@ -1573,7 +1598,7 @@ packages: path-exists: 4.0.0 dev: true - /flat-cache/3.0.4: + /flat-cache@3.0.4: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: @@ -1581,21 +1606,21 @@ packages: rimraf: 3.0.2 dev: true - /flatted/3.2.7: + /flatted@3.2.7: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true - /for-each/0.3.3: + /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: is-callable: 1.2.7 dev: true - /fraction.js/4.2.0: + /fraction.js@4.2.0: resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} dev: true - /framer-motion/7.10.3_biqbaboplfbrettd7655fr4n2y: + /framer-motion@7.10.3(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-k2ccYeZNSpPg//HTaqrU+4pRq9f9ZpaaN7rr0+Rx5zA4wZLbk547wtDzge2db1sB+1mnJ6r59P4xb+aEIi/W+w==} peerDependencies: react: ^18.0.0 @@ -1604,32 +1629,32 @@ packages: '@motionone/dom': 10.15.5 hey-listen: 1.0.8 react: 18.2.0 - react-dom: 18.2.0_react@18.2.0 + react-dom: 18.2.0(react@18.2.0) tslib: 2.4.0 optionalDependencies: '@emotion/is-prop-valid': 0.8.8 dev: false - /fs-constants/1.0.0: + /fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} dev: true - /fs.realpath/1.0.0: + /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true - /fsevents/2.3.2: + /fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true optional: true - /function-bind/1.1.1: + /function-bind@1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} dev: true - /function.prototype.name/1.1.5: + /function.prototype.name@1.1.5: resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} engines: {node: '>= 0.4'} dependencies: @@ -1639,15 +1664,15 @@ packages: functions-have-names: 1.2.3 dev: true - /functions-have-names/1.2.3: + /functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true - /geojson-vt/3.2.1: + /geojson-vt@3.2.1: resolution: {integrity: sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==} dev: false - /get-intrinsic/1.2.0: + /get-intrinsic@1.2.0: resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} dependencies: function-bind: 1.1.1 @@ -1655,19 +1680,19 @@ packages: has-symbols: 1.0.3 dev: true - /get-stream/5.2.0: + /get-stream@5.2.0: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} dependencies: pump: 3.0.0 dev: true - /get-stream/6.0.1: + /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} dev: false - /get-symbol-description/1.0.0: + /get-symbol-description@1.0.0: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} engines: {node: '>= 0.4'} dependencies: @@ -1675,24 +1700,24 @@ packages: get-intrinsic: 1.2.0 dev: true - /gl-matrix/3.4.3: + /gl-matrix@3.4.3: resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==} dev: false - /glob-parent/5.1.2: + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 - /glob-parent/6.0.2: + /glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} dependencies: is-glob: 4.0.3 dev: true - /glob/7.1.7: + /glob@7.1.7: resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} dependencies: fs.realpath: 1.0.0 @@ -1703,7 +1728,7 @@ packages: path-is-absolute: 1.0.1 dev: true - /glob/7.2.3: + /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} dependencies: fs.realpath: 1.0.0 @@ -1714,7 +1739,7 @@ packages: path-is-absolute: 1.0.1 dev: true - /global-prefix/3.0.0: + /global-prefix@3.0.0: resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} engines: {node: '>=6'} dependencies: @@ -1723,21 +1748,21 @@ packages: which: 1.3.1 dev: false - /globals/13.20.0: + /globals@13.20.0: resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} engines: {node: '>=8'} dependencies: type-fest: 0.20.2 dev: true - /globalthis/1.0.3: + /globalthis@1.0.3: resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} engines: {node: '>= 0.4'} dependencies: define-properties: 1.1.4 dev: true - /globby/11.1.0: + /globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} dependencies: @@ -1749,73 +1774,73 @@ packages: slash: 3.0.0 dev: true - /gopd/1.0.1: + /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: get-intrinsic: 1.2.0 dev: true - /grapheme-splitter/1.0.4: + /grapheme-splitter@1.0.4: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} dev: true - /grid-index/1.1.0: + /grid-index@1.1.0: resolution: {integrity: sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==} dev: false - /has-bigints/1.0.2: + /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} dev: true - /has-flag/3.0.0: + /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} dev: true - /has-flag/4.0.0: + /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} dev: true - /has-property-descriptors/1.0.0: + /has-property-descriptors@1.0.0: resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} dependencies: get-intrinsic: 1.2.0 dev: true - /has-proto/1.0.1: + /has-proto@1.0.1: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} engines: {node: '>= 0.4'} dev: true - /has-symbols/1.0.3: + /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} dev: true - /has-tostringtag/1.0.0: + /has-tostringtag@1.0.0: resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 dev: true - /has/1.0.3: + /has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} dependencies: function-bind: 1.1.1 dev: true - /hey-listen/1.0.8: + /hey-listen@1.0.8: resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} dev: false - /howler/2.2.3: + /howler@2.2.3: resolution: {integrity: sha512-QM0FFkw0LRX1PR8pNzJVAY25JhIWvbKMBFM4gqk+QdV+kPXOhleWGCB6AiAF/goGjIHK2e/nIElplvjQwhr0jg==} dev: false - /https-proxy-agent/5.0.1: + /https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} dependencies: @@ -1825,19 +1850,19 @@ packages: - supports-color dev: true - /ieee754/1.2.1: + /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - /ignore/5.2.4: + /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} dev: true - /immutable/4.2.2: + /immutable@4.2.2: resolution: {integrity: sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==} dev: false - /import-fresh/3.3.0: + /import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} dependencies: @@ -1845,27 +1870,27 @@ packages: resolve-from: 4.0.0 dev: true - /imurmurhash/0.1.4: + /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} dev: true - /inflight/1.0.6: + /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} dependencies: once: 1.4.0 wrappy: 1.0.2 dev: true - /inherits/2.0.4: + /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} dev: true - /ini/1.3.8: + /ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} dev: false - /internal-slot/1.0.4: + /internal-slot@1.0.4: resolution: {integrity: sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==} engines: {node: '>= 0.4'} dependencies: @@ -1874,7 +1899,7 @@ packages: side-channel: 1.0.4 dev: true - /is-arguments/1.1.1: + /is-arguments@1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} dependencies: @@ -1882,7 +1907,7 @@ packages: has-tostringtag: 1.0.0 dev: true - /is-array-buffer/3.0.1: + /is-array-buffer@3.0.1: resolution: {integrity: sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==} dependencies: call-bind: 1.0.2 @@ -1890,23 +1915,23 @@ packages: is-typed-array: 1.1.10 dev: true - /is-arrayish/0.2.1: + /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true - /is-bigint/1.0.4: + /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: has-bigints: 1.0.2 dev: true - /is-binary-path/2.1.0: + /is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} dependencies: binary-extensions: 2.2.0 - /is-boolean-object/1.1.2: + /is-boolean-object@1.1.2: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} dependencies: @@ -1914,60 +1939,60 @@ packages: has-tostringtag: 1.0.0 dev: true - /is-callable/1.2.7: + /is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} dev: true - /is-core-module/2.11.0: + /is-core-module@2.11.0: resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} dependencies: has: 1.0.3 dev: true - /is-date-object/1.0.5: + /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 dev: true - /is-extglob/2.1.1: + /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - /is-glob/4.0.3: + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 - /is-map/2.0.2: + /is-map@2.0.2: resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} dev: true - /is-negative-zero/2.0.2: + /is-negative-zero@2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} dev: true - /is-number-object/1.0.7: + /is-number-object@1.0.7: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 dev: true - /is-number/7.0.0: + /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - /is-path-inside/3.0.3: + /is-path-inside@3.0.3: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} dev: true - /is-regex/1.1.4: + /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} dependencies: @@ -1975,31 +2000,31 @@ packages: has-tostringtag: 1.0.0 dev: true - /is-set/2.0.2: + /is-set@2.0.2: resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} dev: true - /is-shared-array-buffer/1.0.2: + /is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: call-bind: 1.0.2 dev: true - /is-string/1.0.7: + /is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 dev: true - /is-symbol/1.0.4: + /is-symbol@1.0.4: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 dev: true - /is-typed-array/1.1.10: + /is-typed-array@1.1.10: resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} engines: {node: '>= 0.4'} dependencies: @@ -2010,68 +2035,68 @@ packages: has-tostringtag: 1.0.0 dev: true - /is-weakmap/2.0.1: + /is-weakmap@2.0.1: resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} dev: true - /is-weakref/1.0.2: + /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: call-bind: 1.0.2 dev: true - /is-weakset/2.0.2: + /is-weakset@2.0.2: resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} dependencies: call-bind: 1.0.2 get-intrinsic: 1.2.0 dev: true - /isarray/2.0.5: + /isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} dev: true - /isexe/2.0.0: + /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - /iso8601-js-period/0.2.1: + /iso8601-js-period@0.2.1: resolution: {integrity: sha512-iDyz2TQFBd5WhCZjruOwHj01JkQGu7YbVLCVdpA7lCGEcBzE3ffCPAhLh/M8TAp//kCixPpYN4XU54WHCxvD2Q==} dev: false - /js-sdsl/4.3.0: + /js-sdsl@4.3.0: resolution: {integrity: sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==} dev: true - /js-tokens/4.0.0: + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - /js-yaml/4.1.0: + /js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true dependencies: argparse: 2.0.1 dev: true - /json-parse-even-better-errors/2.3.1: + /json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} dev: true - /json-schema-traverse/0.4.1: + /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true - /json-stable-stringify-without-jsonify/1.0.1: + /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true - /json5/1.0.2: + /json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true dependencies: minimist: 1.2.7 dev: true - /jsx-ast-utils/3.3.3: + /jsx-ast-utils@3.3.3: resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==} engines: {node: '>=4.0'} dependencies: @@ -2079,43 +2104,43 @@ packages: object.assign: 4.1.4 dev: true - /kdbush/3.0.0: + /kdbush@3.0.0: resolution: {integrity: sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==} dev: false - /kind-of/6.0.3: + /kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} dev: false - /language-subtag-registry/0.3.22: + /language-subtag-registry@0.3.22: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} dev: true - /language-tags/1.0.5: + /language-tags@1.0.5: resolution: {integrity: sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==} dependencies: language-subtag-registry: 0.3.22 dev: true - /leaflet-timedimension/1.1.1: + /leaflet-timedimension@1.1.1: resolution: {integrity: sha512-ejXldN94veRsWka1vpC+4rbH+2+3d3ztn2xYx4jcXtjYDrKC/sNnoqCmyH2UEYIy51PI2851aI2k8uGdOEbhlw==} dependencies: iso8601-js-period: 0.2.1 leaflet: 1.9.3 dev: false - /leaflet.nontiledlayer/1.0.9: + /leaflet.nontiledlayer@1.0.9: resolution: {integrity: sha512-w4yeTLNFhTToAmGQ7P9cAiGFVwVLJzuO3A/tFNMWRVYl1BLvrvlqY7hKE33pmmeoQ6m5ZsWd0qbdYq/d+zBuUQ==} dependencies: leaflet: 1.9.3 dev: false - /leaflet/1.9.3: + /leaflet@1.9.3: resolution: {integrity: sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ==} dev: false - /levn/0.4.1: + /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} dependencies: @@ -2123,48 +2148,48 @@ packages: type-check: 0.4.0 dev: true - /lilconfig/2.0.6: + /lilconfig@2.0.6: resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==} engines: {node: '>=10'} dev: true - /lines-and-columns/1.2.4: + /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true - /locate-path/6.0.0: + /locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} dependencies: p-locate: 5.0.0 dev: true - /lodash.memoize/4.1.2: + /lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} dev: true - /lodash.merge/4.6.2: + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true - /lodash.uniq/4.5.0: + /lodash.uniq@4.5.0: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} dev: true - /loose-envify/1.4.0: + /loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true dependencies: js-tokens: 4.0.0 - /lru-cache/6.0.0: + /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} dependencies: yallist: 4.0.0 dev: true - /mapbox-gl/2.12.0: + /mapbox-gl@2.12.0: resolution: {integrity: sha512-T60fbDV1ULikrhwPdRbpeQOF02+Nhv7QgJ4uGfKWybkoH+DdCxNWTmT7OFiKR0uz9ed98TAodYiHZQAQtFdwwQ==} dependencies: '@mapbox/geojson-rewind': 0.5.2 @@ -2190,7 +2215,7 @@ packages: vt-pbf: 3.1.3 dev: false - /maplibre-gl/2.4.0: + /maplibre-gl@2.4.0: resolution: {integrity: sha512-csNFylzntPmHWidczfgCZpvbTSmhaWvLRj9e1ezUDBEPizGgshgm3ea1T5TCNEEBq0roauu7BPuRZjA3wO4KqA==} requiresBuild: true dependencies: @@ -2220,16 +2245,16 @@ packages: vt-pbf: 3.1.3 dev: false - /mdn-data/2.0.14: + /mdn-data@2.0.14: resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} dev: true - /merge2/1.4.1: + /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} dev: true - /micromatch/4.0.5: + /micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} dependencies: @@ -2237,41 +2262,41 @@ packages: picomatch: 2.3.1 dev: true - /minimatch/3.1.2: + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 dev: true - /minimist/1.2.7: + /minimist@1.2.7: resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==} - /mkdirp-classic/0.5.3: + /mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} dev: true - /ms/2.1.2: + /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true - /ms/2.1.3: + /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} dev: true - /murmurhash-js/1.0.0: + /murmurhash-js@1.0.0: resolution: {integrity: sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==} dev: false - /nanoid/3.3.4: + /nanoid@3.3.4: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - /natural-compare/1.4.0: + /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true - /next/12.3.4_3duxcpitbtplz62feflag7fwby: + /next@12.3.4(react-dom@18.2.0)(react@18.2.0)(sass@1.57.1): resolution: {integrity: sha512-VcyMJUtLZBGzLKo3oMxrEF0stxh8HwuW976pAzlHhI3t8qJ4SROjCrSh1T24bhrbjw55wfZXAbXPGwPt5FLRfQ==} engines: {node: '>=12.22.0'} hasBin: true @@ -2294,10 +2319,10 @@ packages: caniuse-lite: 1.0.30001449 postcss: 8.4.14 react: 18.2.0 - react-dom: 18.2.0_react@18.2.0 + react-dom: 18.2.0(react@18.2.0) sass: 1.57.1 - styled-jsx: 5.0.7_react@18.2.0 - use-sync-external-store: 1.2.0_react@18.2.0 + styled-jsx: 5.0.7(react@18.2.0) + use-sync-external-store: 1.2.0(react@18.2.0) optionalDependencies: '@next/swc-android-arm-eabi': 12.3.4 '@next/swc-android-arm64': 12.3.4 @@ -2317,7 +2342,7 @@ packages: - babel-plugin-macros dev: false - /node-fetch/2.6.7: + /node-fetch@2.6.7: resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} engines: {node: 4.x || >=6.0.0} peerDependencies: @@ -2329,45 +2354,45 @@ packages: whatwg-url: 5.0.0 dev: true - /node-releases/2.0.9: + /node-releases@2.0.9: resolution: {integrity: sha512-2xfmOrRkGogbTK9R6Leda0DGiXeY3p2NJpy4+gNCffdUvV6mdEJnaDEic1i3Ec2djAo8jWYoJMR5PB0MSMpxUA==} dev: true - /normalize-path/3.0.0: + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - /normalize-range/0.1.2: + /normalize-range@0.1.2: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} dev: true - /normalize-url/6.1.0: + /normalize-url@6.1.0: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} dev: true - /nth-check/2.1.1: + /nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} dependencies: boolbase: 1.0.0 dev: true - /object-assign/4.1.1: + /object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} dev: true - /object-hash/3.0.0: + /object-hash@3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} dev: true - /object-inspect/1.12.3: + /object-inspect@1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} dev: true - /object-is/1.1.5: + /object-is@1.1.5: resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} engines: {node: '>= 0.4'} dependencies: @@ -2375,12 +2400,12 @@ packages: define-properties: 1.1.4 dev: true - /object-keys/1.1.1: + /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} dev: true - /object.assign/4.1.4: + /object.assign@4.1.4: resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} engines: {node: '>= 0.4'} dependencies: @@ -2390,7 +2415,7 @@ packages: object-keys: 1.1.1 dev: true - /object.entries/1.1.6: + /object.entries@1.1.6: resolution: {integrity: sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==} engines: {node: '>= 0.4'} dependencies: @@ -2399,7 +2424,7 @@ packages: es-abstract: 1.21.1 dev: true - /object.fromentries/2.0.6: + /object.fromentries@2.0.6: resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} engines: {node: '>= 0.4'} dependencies: @@ -2408,14 +2433,14 @@ packages: es-abstract: 1.21.1 dev: true - /object.hasown/1.1.2: + /object.hasown@1.1.2: resolution: {integrity: sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==} dependencies: define-properties: 1.1.4 es-abstract: 1.21.1 dev: true - /object.values/1.1.6: + /object.values@1.1.6: resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} engines: {node: '>= 0.4'} dependencies: @@ -2424,13 +2449,13 @@ packages: es-abstract: 1.21.1 dev: true - /once/1.4.0: + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 dev: true - /optionator/0.9.1: + /optionator@0.9.1: resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} engines: {node: '>= 0.8.0'} dependencies: @@ -2442,28 +2467,28 @@ packages: word-wrap: 1.2.3 dev: true - /p-limit/3.1.0: + /p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} dependencies: yocto-queue: 0.1.0 dev: true - /p-locate/5.0.0: + /p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} dependencies: p-limit: 3.1.0 dev: true - /parent-module/1.0.1: + /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} dependencies: callsites: 3.1.0 dev: true - /parse-json/5.2.0: + /parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: @@ -2473,31 +2498,31 @@ packages: lines-and-columns: 1.2.4 dev: true - /path-exists/4.0.0: + /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} dev: true - /path-is-absolute/1.0.1: + /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} dev: true - /path-key/3.1.1: + /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} dev: true - /path-parse/1.0.7: + /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true - /path-type/4.0.0: + /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} dev: true - /pbf/3.2.1: + /pbf@3.2.1: resolution: {integrity: sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==} hasBin: true dependencies: @@ -2505,23 +2530,23 @@ packages: resolve-protobuf-schema: 2.1.0 dev: false - /pend/1.2.0: + /pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} dev: true - /picocolors/1.0.0: + /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - /picomatch/2.3.1: + /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - /pify/2.3.0: + /pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} dev: true - /postcss-calc/8.2.4_postcss@8.4.21: + /postcss-calc@8.2.4(postcss@8.4.21): resolution: {integrity: sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==} peerDependencies: postcss: ^8.2.2 @@ -2531,7 +2556,7 @@ packages: postcss-value-parser: 4.2.0 dev: true - /postcss-colormin/5.3.0_postcss@8.4.21: + /postcss-colormin@5.3.0(postcss@8.4.21): resolution: {integrity: sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2544,7 +2569,7 @@ packages: postcss-value-parser: 4.2.0 dev: true - /postcss-convert-values/5.1.3_postcss@8.4.21: + /postcss-convert-values@5.1.3(postcss@8.4.21): resolution: {integrity: sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2555,7 +2580,7 @@ packages: postcss-value-parser: 4.2.0 dev: true - /postcss-discard-comments/5.1.2_postcss@8.4.21: + /postcss-discard-comments@5.1.2(postcss@8.4.21): resolution: {integrity: sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2564,7 +2589,7 @@ packages: postcss: 8.4.21 dev: true - /postcss-discard-duplicates/5.1.0_postcss@8.4.21: + /postcss-discard-duplicates@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2573,7 +2598,7 @@ packages: postcss: 8.4.21 dev: true - /postcss-discard-empty/5.1.1_postcss@8.4.21: + /postcss-discard-empty@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2582,7 +2607,7 @@ packages: postcss: 8.4.21 dev: true - /postcss-discard-overridden/5.1.0_postcss@8.4.21: + /postcss-discard-overridden@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2591,7 +2616,7 @@ packages: postcss: 8.4.21 dev: true - /postcss-import/14.1.0_postcss@8.4.21: + /postcss-import@14.1.0(postcss@8.4.21): resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==} engines: {node: '>=10.0.0'} peerDependencies: @@ -2603,7 +2628,7 @@ packages: resolve: 1.22.1 dev: true - /postcss-js/4.0.0_postcss@8.4.21: + /postcss-js@4.0.0(postcss@8.4.21): resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==} engines: {node: ^12 || ^14 || >= 16} peerDependencies: @@ -2613,7 +2638,7 @@ packages: postcss: 8.4.21 dev: true - /postcss-load-config/3.1.4_postcss@8.4.21: + /postcss-load-config@3.1.4(postcss@8.4.21): resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} engines: {node: '>= 10'} peerDependencies: @@ -2630,7 +2655,7 @@ packages: yaml: 1.10.2 dev: true - /postcss-merge-longhand/5.1.7_postcss@8.4.21: + /postcss-merge-longhand@5.1.7(postcss@8.4.21): resolution: {integrity: sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2638,10 +2663,10 @@ packages: dependencies: postcss: 8.4.21 postcss-value-parser: 4.2.0 - stylehacks: 5.1.1_postcss@8.4.21 + stylehacks: 5.1.1(postcss@8.4.21) dev: true - /postcss-merge-rules/5.1.3_postcss@8.4.21: + /postcss-merge-rules@5.1.3(postcss@8.4.21): resolution: {integrity: sha512-LbLd7uFC00vpOuMvyZop8+vvhnfRGpp2S+IMQKeuOZZapPRY4SMq5ErjQeHbHsjCUgJkRNrlU+LmxsKIqPKQlA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2649,12 +2674,12 @@ packages: dependencies: browserslist: 4.21.5 caniuse-api: 3.0.0 - cssnano-utils: 3.1.0_postcss@8.4.21 + cssnano-utils: 3.1.0(postcss@8.4.21) postcss: 8.4.21 postcss-selector-parser: 6.0.11 dev: true - /postcss-minify-font-values/5.1.0_postcss@8.4.21: + /postcss-minify-font-values@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2664,31 +2689,31 @@ packages: postcss-value-parser: 4.2.0 dev: true - /postcss-minify-gradients/5.1.1_postcss@8.4.21: + /postcss-minify-gradients@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: colord: 2.9.3 - cssnano-utils: 3.1.0_postcss@8.4.21 + cssnano-utils: 3.1.0(postcss@8.4.21) postcss: 8.4.21 postcss-value-parser: 4.2.0 dev: true - /postcss-minify-params/5.1.4_postcss@8.4.21: + /postcss-minify-params@5.1.4(postcss@8.4.21): resolution: {integrity: sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: browserslist: 4.21.5 - cssnano-utils: 3.1.0_postcss@8.4.21 + cssnano-utils: 3.1.0(postcss@8.4.21) postcss: 8.4.21 postcss-value-parser: 4.2.0 dev: true - /postcss-minify-selectors/5.2.1_postcss@8.4.21: + /postcss-minify-selectors@5.2.1(postcss@8.4.21): resolution: {integrity: sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2698,7 +2723,7 @@ packages: postcss-selector-parser: 6.0.11 dev: true - /postcss-nested/6.0.0_postcss@8.4.21: + /postcss-nested@6.0.0(postcss@8.4.21): resolution: {integrity: sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==} engines: {node: '>=12.0'} peerDependencies: @@ -2708,7 +2733,7 @@ packages: postcss-selector-parser: 6.0.11 dev: true - /postcss-normalize-charset/5.1.0_postcss@8.4.21: + /postcss-normalize-charset@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2717,7 +2742,7 @@ packages: postcss: 8.4.21 dev: true - /postcss-normalize-display-values/5.1.0_postcss@8.4.21: + /postcss-normalize-display-values@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2727,7 +2752,7 @@ packages: postcss-value-parser: 4.2.0 dev: true - /postcss-normalize-positions/5.1.1_postcss@8.4.21: + /postcss-normalize-positions@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2737,7 +2762,7 @@ packages: postcss-value-parser: 4.2.0 dev: true - /postcss-normalize-repeat-style/5.1.1_postcss@8.4.21: + /postcss-normalize-repeat-style@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2747,7 +2772,7 @@ packages: postcss-value-parser: 4.2.0 dev: true - /postcss-normalize-string/5.1.0_postcss@8.4.21: + /postcss-normalize-string@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2757,7 +2782,7 @@ packages: postcss-value-parser: 4.2.0 dev: true - /postcss-normalize-timing-functions/5.1.0_postcss@8.4.21: + /postcss-normalize-timing-functions@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2767,7 +2792,7 @@ packages: postcss-value-parser: 4.2.0 dev: true - /postcss-normalize-unicode/5.1.1_postcss@8.4.21: + /postcss-normalize-unicode@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2778,7 +2803,7 @@ packages: postcss-value-parser: 4.2.0 dev: true - /postcss-normalize-url/5.1.0_postcss@8.4.21: + /postcss-normalize-url@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2789,7 +2814,7 @@ packages: postcss-value-parser: 4.2.0 dev: true - /postcss-normalize-whitespace/5.1.1_postcss@8.4.21: + /postcss-normalize-whitespace@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2799,18 +2824,18 @@ packages: postcss-value-parser: 4.2.0 dev: true - /postcss-ordered-values/5.1.3_postcss@8.4.21: + /postcss-ordered-values@5.1.3(postcss@8.4.21): resolution: {integrity: sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - cssnano-utils: 3.1.0_postcss@8.4.21 + cssnano-utils: 3.1.0(postcss@8.4.21) postcss: 8.4.21 postcss-value-parser: 4.2.0 dev: true - /postcss-reduce-initial/5.1.1_postcss@8.4.21: + /postcss-reduce-initial@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-//jeDqWcHPuXGZLoolFrUXBDyuEGbr9S2rMo19bkTIjBQ4PqkaO+oI8wua5BOUxpfi97i3PCoInsiFIEBfkm9w==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2821,7 +2846,7 @@ packages: postcss: 8.4.21 dev: true - /postcss-reduce-transforms/5.1.0_postcss@8.4.21: + /postcss-reduce-transforms@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2831,7 +2856,7 @@ packages: postcss-value-parser: 4.2.0 dev: true - /postcss-selector-parser/6.0.11: + /postcss-selector-parser@6.0.11: resolution: {integrity: sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==} engines: {node: '>=4'} dependencies: @@ -2839,7 +2864,7 @@ packages: util-deprecate: 1.0.2 dev: true - /postcss-svgo/5.1.0_postcss@8.4.21: + /postcss-svgo@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2850,7 +2875,7 @@ packages: svgo: 2.8.0 dev: true - /postcss-unique-selectors/5.1.1_postcss@8.4.21: + /postcss-unique-selectors@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -2860,11 +2885,11 @@ packages: postcss-selector-parser: 6.0.11 dev: true - /postcss-value-parser/4.2.0: + /postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} dev: true - /postcss/8.4.14: + /postcss@8.4.14: resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} engines: {node: ^10 || ^12 || >=14} dependencies: @@ -2873,7 +2898,7 @@ packages: source-map-js: 1.0.2 dev: false - /postcss/8.4.21: + /postcss@8.4.21: resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} engines: {node: ^10 || ^12 || >=14} dependencies: @@ -2882,25 +2907,25 @@ packages: source-map-js: 1.0.2 dev: true - /potpack/1.0.2: + /potpack@1.0.2: resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==} dev: false - /potpack/2.0.0: + /potpack@2.0.0: resolution: {integrity: sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==} dev: false - /prelude-ls/1.2.1: + /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} dev: true - /progress/2.0.3: + /progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} dev: true - /prop-types/15.8.1: + /prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} dependencies: loose-envify: 1.4.0 @@ -2908,27 +2933,27 @@ packages: react-is: 16.13.1 dev: true - /protocol-buffers-schema/3.6.0: + /protocol-buffers-schema@3.6.0: resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==} dev: false - /proxy-from-env/1.1.0: + /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: true - /pump/3.0.0: + /pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} dependencies: end-of-stream: 1.4.4 once: 1.4.0 dev: true - /punycode/2.3.0: + /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} dev: true - /puppeteer-core/19.6.2: + /puppeteer-core@19.6.2: resolution: {integrity: sha512-il7uK658MNC1FlxPABvcnv1RdpDa9CaBFHzvtEsl+9Y4tbAJKZurkegpcvWeIWcRYGiuBIVo+t+ZSh3G82CCjw==} engines: {node: '>=14.1.0'} dependencies: @@ -2949,7 +2974,7 @@ packages: - utf-8-validate dev: true - /puppeteer/19.6.2: + /puppeteer@19.6.2: resolution: {integrity: sha512-Y5OAXXwXLfJYbl0dEFg8JKIhvCGxn+UYaBW9yra9ErmIhkVroDnYusM6oYxJCt/YIfC2pQWhvhxoZyf/E5fV6w==} engines: {node: '>=14.1.0'} requiresBuild: true @@ -2966,20 +2991,20 @@ packages: - utf-8-validate dev: true - /queue-microtask/1.2.3: + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true - /quick-lru/5.1.1: + /quick-lru@5.1.1: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} dev: true - /quickselect/2.0.0: + /quickselect@2.0.0: resolution: {integrity: sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==} dev: false - /react-dom/18.2.0_react@18.2.0: + /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: react: ^18.2.0 @@ -2989,7 +3014,7 @@ packages: scheduler: 0.23.0 dev: false - /react-icons/4.7.1_react@18.2.0: + /react-icons@4.7.1(react@18.2.0): resolution: {integrity: sha512-yHd3oKGMgm7zxo3EA7H2n7vxSoiGmHk5t6Ou4bXsfcgWyhfDKMpyKfhHR6Bjnn63c+YXBLBPUql9H4wPJM6sXw==} peerDependencies: react: '*' @@ -2997,11 +3022,11 @@ packages: react: 18.2.0 dev: false - /react-is/16.13.1: + /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} dev: true - /react-use-audio-player/1.2.6_react@18.2.0: + /react-use-audio-player@1.2.6(react@18.2.0): resolution: {integrity: sha512-ukFF5WOxsFYd44AaPXzFI4HltWaPD68+iJ9aDicn9FRBJ5poJUPO/WjFl5nk0tRYiyve3z711Oz79LYzCahhFQ==} peerDependencies: react: '>=16.8' @@ -3010,20 +3035,20 @@ packages: react: 18.2.0 dev: false - /react/18.2.0: + /react@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 dev: false - /read-cache/1.0.0: + /read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} dependencies: pify: 2.3.0 dev: true - /readable-stream/3.6.0: + /readable-stream@3.6.0: resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} engines: {node: '>= 6'} dependencies: @@ -3032,17 +3057,17 @@ packages: util-deprecate: 1.0.2 dev: true - /readdirp/3.6.0: + /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.1 - /regenerator-runtime/0.13.11: + /regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} dev: true - /regexp.prototype.flags/1.4.3: + /regexp.prototype.flags@1.4.3: resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==} engines: {node: '>= 0.4'} dependencies: @@ -3051,23 +3076,23 @@ packages: functions-have-names: 1.2.3 dev: true - /regexpp/3.2.0: + /regexpp@3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} dev: true - /resolve-from/4.0.0: + /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} dev: true - /resolve-protobuf-schema/2.1.0: + /resolve-protobuf-schema@2.1.0: resolution: {integrity: sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==} dependencies: protocol-buffers-schema: 3.6.0 dev: false - /resolve/1.22.1: + /resolve@1.22.1: resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} hasBin: true dependencies: @@ -3076,7 +3101,7 @@ packages: supports-preserve-symlinks-flag: 1.0.0 dev: true - /resolve/2.0.0-next.4: + /resolve@2.0.0-next.4: resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} hasBin: true dependencies: @@ -3085,33 +3110,33 @@ packages: supports-preserve-symlinks-flag: 1.0.0 dev: true - /reusify/1.0.4: + /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true - /rimraf/3.0.2: + /rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} hasBin: true dependencies: glob: 7.2.3 dev: true - /run-parallel/1.2.0: + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: queue-microtask: 1.2.3 dev: true - /rw/1.3.3: + /rw@1.3.3: resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} dev: false - /safe-buffer/5.2.1: + /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} dev: true - /safe-regex-test/1.0.0: + /safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} dependencies: call-bind: 1.0.2 @@ -3119,7 +3144,7 @@ packages: is-regex: 1.1.4 dev: true - /sass/1.57.1: + /sass@1.57.1: resolution: {integrity: sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==} engines: {node: '>=12.0.0'} hasBin: true @@ -3129,18 +3154,18 @@ packages: source-map-js: 1.0.2 dev: false - /scheduler/0.23.0: + /scheduler@0.23.0: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} dependencies: loose-envify: 1.4.0 dev: false - /semver/6.3.0: + /semver@6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true dev: true - /semver/7.3.8: + /semver@7.3.8: resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} engines: {node: '>=10'} hasBin: true @@ -3148,19 +3173,19 @@ packages: lru-cache: 6.0.0 dev: true - /shebang-command/2.0.0: + /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 dev: true - /shebang-regex/3.0.0: + /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} dev: true - /side-channel/1.0.4: + /side-channel@1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: call-bind: 1.0.2 @@ -3168,33 +3193,33 @@ packages: object-inspect: 1.12.3 dev: true - /slash/3.0.0: + /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} dev: true - /source-map-js/1.0.2: + /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} - /source-map/0.6.1: + /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} dev: true - /stable/0.1.8: + /stable@0.1.8: resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==} deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility' dev: true - /stop-iteration-iterator/1.0.0: + /stop-iteration-iterator@1.0.0: resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} engines: {node: '>= 0.4'} dependencies: internal-slot: 1.0.4 dev: true - /string.prototype.matchall/4.0.8: + /string.prototype.matchall@4.0.8: resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==} dependencies: call-bind: 1.0.2 @@ -3207,7 +3232,7 @@ packages: side-channel: 1.0.4 dev: true - /string.prototype.trimend/1.0.6: + /string.prototype.trimend@1.0.6: resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} dependencies: call-bind: 1.0.2 @@ -3215,7 +3240,7 @@ packages: es-abstract: 1.21.1 dev: true - /string.prototype.trimstart/1.0.6: + /string.prototype.trimstart@1.0.6: resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} dependencies: call-bind: 1.0.2 @@ -3223,30 +3248,30 @@ packages: es-abstract: 1.21.1 dev: true - /string_decoder/1.3.0: + /string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} dependencies: safe-buffer: 5.2.1 dev: true - /strip-ansi/6.0.1: + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 dev: true - /strip-bom/3.0.0: + /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} dev: true - /strip-json-comments/3.1.1: + /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} dev: true - /styled-jsx/5.0.7_react@18.2.0: + /styled-jsx@5.0.7(react@18.2.0): resolution: {integrity: sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==} engines: {node: '>= 12.0.0'} peerDependencies: @@ -3262,7 +3287,7 @@ packages: react: 18.2.0 dev: false - /stylehacks/5.1.1_postcss@8.4.21: + /stylehacks@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -3273,32 +3298,32 @@ packages: postcss-selector-parser: 6.0.11 dev: true - /supercluster/7.1.5: + /supercluster@7.1.5: resolution: {integrity: sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==} dependencies: kdbush: 3.0.0 dev: false - /supports-color/5.5.0: + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} dependencies: has-flag: 3.0.0 dev: true - /supports-color/7.2.0: + /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} dependencies: has-flag: 4.0.0 dev: true - /supports-preserve-symlinks-flag/1.0.0: + /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} dev: true - /svgo/2.8.0: + /svgo@2.8.0: resolution: {integrity: sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==} engines: {node: '>=10.13.0'} hasBin: true @@ -3312,7 +3337,7 @@ packages: stable: 0.1.8 dev: true - /tailwindcss/3.2.4_postcss@8.4.21: + /tailwindcss@3.2.4(postcss@8.4.21): resolution: {integrity: sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==} engines: {node: '>=12.13.0'} hasBin: true @@ -3334,10 +3359,10 @@ packages: object-hash: 3.0.0 picocolors: 1.0.0 postcss: 8.4.21 - postcss-import: 14.1.0_postcss@8.4.21 - postcss-js: 4.0.0_postcss@8.4.21 - postcss-load-config: 3.1.4_postcss@8.4.21 - postcss-nested: 6.0.0_postcss@8.4.21 + postcss-import: 14.1.0(postcss@8.4.21) + postcss-js: 4.0.0(postcss@8.4.21) + postcss-load-config: 3.1.4(postcss@8.4.21) + postcss-nested: 6.0.0(postcss@8.4.21) postcss-selector-parser: 6.0.11 postcss-value-parser: 4.2.0 quick-lru: 5.1.1 @@ -3346,7 +3371,7 @@ packages: - ts-node dev: true - /tar-fs/2.1.1: + /tar-fs@2.1.1: resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} dependencies: chownr: 1.1.4 @@ -3355,7 +3380,7 @@ packages: tar-stream: 2.2.0 dev: true - /tar-stream/2.2.0: + /tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} dependencies: @@ -3366,29 +3391,29 @@ packages: readable-stream: 3.6.0 dev: true - /text-table/0.2.0: + /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true - /through/2.3.8: + /through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} dev: true - /tinyqueue/2.0.3: + /tinyqueue@2.0.3: resolution: {integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==} dev: false - /to-regex-range/5.0.1: + /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} dependencies: is-number: 7.0.0 - /tr46/0.0.3: + /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} dev: true - /tsconfig-paths/3.14.1: + /tsconfig-paths@3.14.1: resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} dependencies: '@types/json5': 0.0.29 @@ -3397,19 +3422,19 @@ packages: strip-bom: 3.0.0 dev: true - /tslib/1.14.1: + /tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true - /tslib/2.4.0: + /tslib@2.4.0: resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} dev: false - /tslib/2.5.0: + /tslib@2.5.0: resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} dev: false - /tsutils/3.21.0_typescript@4.9.5: + /tsutils@3.21.0(typescript@4.9.5): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: @@ -3419,19 +3444,19 @@ packages: typescript: 4.9.5 dev: true - /type-check/0.4.0: + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} dependencies: prelude-ls: 1.2.1 dev: true - /type-fest/0.20.2: + /type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} dev: true - /typed-array-length/1.0.4: + /typed-array-length@1.0.4: resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} dependencies: call-bind: 1.0.2 @@ -3439,13 +3464,13 @@ packages: is-typed-array: 1.1.10 dev: true - /typescript/4.9.5: + /typescript@4.9.5: resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} engines: {node: '>=4.2.0'} hasBin: true dev: true - /unbox-primitive/1.0.2: + /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: call-bind: 1.0.2 @@ -3454,14 +3479,14 @@ packages: which-boxed-primitive: 1.0.2 dev: true - /unbzip2-stream/1.4.3: + /unbzip2-stream@1.4.3: resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} dependencies: buffer: 5.7.1 through: 2.3.8 dev: true - /update-browserslist-db/1.0.10_browserslist@4.21.5: + /update-browserslist-db@1.0.10(browserslist@4.21.5): resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} hasBin: true peerDependencies: @@ -3472,13 +3497,13 @@ packages: picocolors: 1.0.0 dev: true - /uri-js/4.4.1: + /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.0 dev: true - /use-sync-external-store/1.2.0_react@18.2.0: + /use-sync-external-store@1.2.0(react@18.2.0): resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -3486,11 +3511,11 @@ packages: react: 18.2.0 dev: false - /util-deprecate/1.0.2: + /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true - /vt-pbf/3.1.3: + /vt-pbf@3.1.3: resolution: {integrity: sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==} dependencies: '@mapbox/point-geometry': 0.1.0 @@ -3498,18 +3523,18 @@ packages: pbf: 3.2.1 dev: false - /webidl-conversions/3.0.1: + /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} dev: true - /whatwg-url/5.0.0: + /whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 dev: true - /which-boxed-primitive/1.0.2: + /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: is-bigint: 1.0.4 @@ -3519,7 +3544,7 @@ packages: is-symbol: 1.0.4 dev: true - /which-collection/1.0.1: + /which-collection@1.0.1: resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} dependencies: is-map: 2.0.2 @@ -3528,7 +3553,7 @@ packages: is-weakset: 2.0.2 dev: true - /which-typed-array/1.1.9: + /which-typed-array@1.1.9: resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} engines: {node: '>= 0.4'} dependencies: @@ -3540,14 +3565,14 @@ packages: is-typed-array: 1.1.10 dev: true - /which/1.3.1: + /which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true dependencies: isexe: 2.0.0 dev: false - /which/2.0.2: + /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} hasBin: true @@ -3555,16 +3580,16 @@ packages: isexe: 2.0.0 dev: true - /word-wrap/1.2.3: + /word-wrap@1.2.3: resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} engines: {node: '>=0.10.0'} dev: true - /wrappy/1.0.2: + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true - /ws/8.11.0: + /ws@8.11.0: resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==} engines: {node: '>=10.0.0'} peerDependencies: @@ -3577,28 +3602,28 @@ packages: optional: true dev: true - /xtend/4.0.2: + /xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} dev: true - /yallist/4.0.0: + /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true - /yaml/1.10.2: + /yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} dev: true - /yauzl/2.10.0: + /yauzl@2.10.0: resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} dependencies: buffer-crc32: 0.2.13 fd-slicer: 1.1.0 dev: true - /yocto-queue/0.1.0: + /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true From 1942a0e7292848d5c8b2a1841796ccfc7889654a Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Mon, 19 Jun 2023 22:00:47 -0600 Subject: [PATCH 49/55] Update username --- components/Display.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/Display.tsx b/components/Display.tsx index 50b2db5..424d387 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -306,7 +306,7 @@ const Display = ({ duration: 4.5 }} ticker={{ - text: "Releasing soon... | This project is open source: github.com/elementemerald/weatherscan-rewritten | NextJs version inspired from https://github.com/buffbears/Weatherscan |", + text: "Releasing soon... | This project is open source: github.com/ryand56/weatherscan-rewritten | NextJs version inspired from https://github.com/buffbears/Weatherscan |", duration: 12 }} /> From 2d0ec4e665cd50b22c3f10494eba83fc192ff1c1 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Mon, 19 Jun 2023 23:01:37 -0600 Subject: [PATCH 50/55] Check for vowels in severe marquee --- components/MarqueeSevere.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/components/MarqueeSevere.tsx b/components/MarqueeSevere.tsx index bdc38e4..e4260c7 100644 --- a/components/MarqueeSevere.tsx +++ b/components/MarqueeSevere.tsx @@ -31,8 +31,20 @@ const MarqueeSevere = ({ top, bottom, mute, setMainVol }: InfoMarqueeSevereProps } }, [utterance, setMainVol]); + const isVowel = (char: string) => { + return char == "a" || char == "e" || char == "i" || char == "o" || char == "u"; + }; + React.useEffect(() => { - if (top.text !== "") setSpeech(`A ${top.text.toLowerCase()} is in your area.`); + if (top.text !== "") { + // A/An + const topText = top.text.toLowerCase(); + const prefixCharCode = topText.charAt(0); + const prefix = isVowel(prefixCharCode) ? "An" : "A"; + const speech = `${prefix} ${topText} is in your area.`; + console.log(speech); + setSpeech(speech); + } }, [top.text]); React.useEffect(() => { From 7028a81f915543e85066d01241bb6282c57f2926 Mon Sep 17 00:00:00 2001 From: Ryan Omasta Date: Mon, 4 May 2026 04:38:03 -0600 Subject: [PATCH 51/55] Update for Node.js 22 --- components/DateTime.tsx | 2 +- components/Display.tsx | 4 +- components/Intro.tsx | 4 +- components/MarqueeSevere.tsx | 2 +- components/MusicAudio.tsx | 212 +- .../Containers/Headers/SlideHeaderScroll.tsx | 12 +- .../Slides/City/CityInfo/Detailed.tsx | 4 +- .../Containers/Slides/City/CityInfo/index.tsx | 3 +- .../Slides/City/CityIntro/index.tsx | 4 +- .../Slides/Containers/SlidesContainer.tsx | 8 +- components/Slides/SlideBg.tsx | 2 +- components/VocalAudio.tsx | 80 +- hooks/audioStore.ts | 17 + hooks/useSlides.ts | 6 +- next-env.d.ts | 3 +- package.json | 41 +- pages/_app.tsx | 1 + pages/index.tsx | 9 +- pnpm-lock.yaml | 7865 +++++++++++------ postcss.config.js | 2 +- styles/global.scss | 7 +- styles/tailwind.css | 316 + tailwind.config.js | 308 - tsconfig.json | 4 +- 24 files changed, 5647 insertions(+), 3269 deletions(-) create mode 100644 hooks/audioStore.ts create mode 100644 styles/tailwind.css delete mode 100644 tailwind.config.js diff --git a/components/DateTime.tsx b/components/DateTime.tsx index 24a1401..6dabb0c 100644 --- a/components/DateTime.tsx +++ b/components/DateTime.tsx @@ -37,7 +37,7 @@ const DateTime = ({ tz }: DateTimeProps) => { }; React.useEffect(() => { - let interval: NodeJS.Timer; + let interval: NodeJS.Timeout; if (tz !== "") { updateTime(); diff --git a/components/Display.tsx b/components/Display.tsx index 424d387..d51a8e8 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -78,7 +78,7 @@ const Display = ({ }: DisplayProps) => { const [cityIntroLoaded, setCityIntroLoaded] = React.useState(false); const [innerWidth, innerHeight] = winSize; - const mainRef = React.useRef(); + const mainRef = React.useRef(null); const resize = () => { resizeWindow(mainRef, innerWidth, innerHeight); @@ -191,7 +191,7 @@ const Display = ({ const lat = locInfo.latitude; const lon = locInfo.longitude; - let intervalTimer: NodeJS.Timer; + let intervalTimer: NodeJS.Timeout; if (lat && lon) { const fetchCallback = (data: CurrentCond) => { const tempMap = new Map(); diff --git a/components/Intro.tsx b/components/Intro.tsx index cf322f8..9933145 100644 --- a/components/Intro.tsx +++ b/components/Intro.tsx @@ -35,8 +35,8 @@ interface IntroProps { const Intro = ({ winSize, callback }: IntroProps) => { const [innerWidth, innerHeight] = winSize; - const mainRef = React.useRef(); - const intellistarRef = React.useRef(); + const mainRef = React.useRef(null); + const intellistarRef = React.useRef(null); function resize() { resizeWindow(mainRef, innerWidth, innerHeight); diff --git a/components/MarqueeSevere.tsx b/components/MarqueeSevere.tsx index e4260c7..b64d0b5 100644 --- a/components/MarqueeSevere.tsx +++ b/components/MarqueeSevere.tsx @@ -48,7 +48,7 @@ const MarqueeSevere = ({ top, bottom, mute, setMainVol }: InfoMarqueeSevereProps }, [top.text]); React.useEffect(() => { - let interval: NodeJS.Timer; + let interval: NodeJS.Timeout; if (typeof window !== undefined) { if (!mute && speech && speech !== "") { tts(speech); diff --git a/components/MusicAudio.tsx b/components/MusicAudio.tsx index d064bcc..996a7ca 100644 --- a/components/MusicAudio.tsx +++ b/components/MusicAudio.tsx @@ -1,103 +1,133 @@ import * as React from "react"; -import { useAudioPlayer, useAudioPosition } from "react-use-audio-player"; import { - MdPlayArrow, - MdPause, - MdReplay10, - MdForward10, - MdRepeatOne, - MdRepeatOneOn + MdPlayArrow, + MdPause, + MdReplay10, + MdForward10, + MdRepeatOne, + MdRepeatOneOn } from "react-icons/md"; -const randNum = (min: number, max: number) => { - return Math.round(Math.random() * (max - min) + min); -}; +import { useSyncExternalStore } from "react"; +import { audioStore } from "../hooks/audioStore"; + +export const useFirstClick = () => + useSyncExternalStore( + audioStore.subscribe, + audioStore.get, + audioStore.get + ); + +const randNum = (min: number, max: number) => + Math.floor(Math.random() * (max - min + 1)) + min; interface MusicAudioProps { - vol: number + vol: number; } const MusicAudio = ({ vol }: MusicAudioProps) => { - const [fileIdx, setFileIdx] = React.useState(randNum(1, 33)); - const [file, setFile] = React.useState(`/music/${encodeURIComponent(`Weatherscan Track ${fileIdx}.mp3`)}`); - const [loop, setLoop] = React.useState(false); - - const { togglePlayPause, ready, loading, playing, load, player, volume } = useAudioPlayer({ - src: file, - format: "mp3", - autoplay: true, - preload: true, - onplay: () => console.log(`Playing ${file}`), - onend: () => { - console.log(`${file} has ended`); - if (!loop) - { - let rand = randNum(1, 33); - while (rand === fileIdx) { - rand = randNum(1, 33); - } - setFileIdx(rand); - } - } - }); - - React.useEffect(() => { - if (!player) return; - player.loop(loop); - }, [player, loop]); - - // Update volume - React.useEffect(() => { - if (!player) return; - volume(vol); - }, [player, volume, vol]); - - const toggleLoop = React.useCallback(() => { - if (!player) return; - - console.log(loop ? "Loop turning off" : "Loop turning on"); - setLoop(!loop); - }, [player, loop]); - - const { position, seek } = useAudioPosition({ highRefreshRate: true }); - - const toggleSkipBackward = React.useCallback(() => { - if (!player) return; - seek(position - 10); - }, [player, position]); - - const toggleSkipForward = React.useCallback(() => { - if (!player) return; - seek(position + 10); - }, [player, position]); - - // File index change - React.useEffect(() => { - setFile(`/music/${encodeURIComponent(`Weatherscan Track ${fileIdx}.mp3`)}`); - }, [fileIdx]); - - return ( - player &&
- - - - -
- ); + const firstClick = useFirstClick(); + const audioRef = React.useRef(null); + + const [fileIdx, setFileIdx] = React.useState(() => randNum(1, 33)); + const [loop, setLoop] = React.useState(false); + const [isPlaying, setIsPlaying] = React.useState(false); + + const src = React.useMemo(() => { + return `/music/${encodeURIComponent( + `Weatherscan Track ${fileIdx}.mp3` + )}`; + }, [fileIdx]); + + React.useEffect(() => { + const audio = audioRef.current; + if (!audio) return; + + if (!firstClick) return; + + audio.src = src; + audio.volume = vol; + audio.load(); + + audio.play() + .then(() => setIsPlaying(true)) + .catch(() => setIsPlaying(false)); + }, [src, firstClick]); + + React.useEffect(() => { + if (audioRef.current) { + audioRef.current.volume = vol; + } + }, [vol]); + + const handleEnded = () => { + if (loop) { + audioRef.current?.play(); + return; + } + + let rand = randNum(1, 33); + while (rand === fileIdx) rand = randNum(1, 33); + + setFileIdx(rand); + }; + + const togglePlayPause = () => { + const audio = audioRef.current; + if (!audio) return; + + if (audio.paused) { + audio.play(); + setIsPlaying(true); + } else { + audio.pause(); + setIsPlaying(false); + } + }; + + const skipBackward = () => { + const audio = audioRef.current; + if (!audio) return; + audio.currentTime = Math.max(0, audio.currentTime - 10); + }; + + const skipForward = () => { + const audio = audioRef.current; + if (!audio) return; + audio.currentTime = Math.min(audio.duration, audio.currentTime + 10); + }; + + return ( + <> +