([]); + const [loading, setLoading] = useState(false); + const [errorMessage, setErrorMessage] = useState (); + const [successMessage, setSuccessMessage] = useState (); + const { address, account } = useAccount(); + //const { balances, l2loading } = useWalletsProviderContext(); + const [selectedToken, setSelectedToken] = useState (SupportedToken.ETH); + + const selectedTokenObj = useMemo(() => { + return supportedTokens[chain][selectedToken]; + }, [selectedToken]); + + const { data, isLoading } = useBalance({ + address, + token: selectedTokenObj?.address as `0x${string}` | undefined, + watch: false, + }); + const isDebouncing = useDebounce(sellAmount, 350) !== sellAmount; + const isBuyInputDebouncing = useDebounce(buyAmount, 350) !== buyAmount; + + useEffect(() => { + if (initialLordsSupply) setBuyAmount(initialLordsSupply); + }, [initialLordsSupply]); + + const fetchSellAmountFromBuyAmount = useCallback(() => { + if (!selectedTokenObj || !buyAmount || isBuyInputDebouncing) return; + setLoading(true); + const params = { + sellTokenAddress: selectedTokenObj.address, + buyTokenAddress: lordsAddress, + sellAmount: parseUnits("1", 18), + takerAddress: address, + size: 1, + }; + + fetchQuotes(params, AVNU_OPTIONS) + .then((quotes) => { + setLoading(false); + if (quotes[0]) { + // cross-multiplication + // For 1 unit of tokenA => you get y amount of tokenB + // Then for x, a specific amount of tokenB => You need to have 1 * x / y + const sellAmountFromBuyAmount = (parseUnits("1", 18) * parseUnits(buyAmount, 18)) / quotes[0]?.buyAmount; + + setSellAmount(formatEther(sellAmountFromBuyAmount)); + } + }) + .catch(() => setLoading(false)); + }, [address, isBuyInputDebouncing, selectedTokenObj, buyAmount]); + + const fetchAvnuQuotes = useCallback(() => { + console.log(sellAmount); + if (!selectedTokenObj || !sellAmount || isDebouncing || parseUnits(sellAmount, selectedTokenObj.decimals) === 0n) + return; + setLoading(true); + const params = { + sellTokenAddress: selectedTokenObj.address ?? "0x", + buyTokenAddress: lordsAddress, + sellAmount: parseUnits(sellAmount, selectedTokenObj.decimals), + takerAddress: address, + size: 1, + }; + console.log(params); + fetchQuotes(params, AVNU_OPTIONS) + .then((quotes) => { + setLoading(false); + setQuotes(quotes); + }) + .catch(() => setLoading(false)); + }, [address, isDebouncing, selectedTokenObj, sellAmount]); + + const sellBalance = data?.value ?? 0; + + const handleChangeBuyInput = (event: ChangeEvent ) => { + setErrorMessage(""); + setQuotes([]); + setBuyAmount(event.target.value); + }; + + const handleTokenSelect = (event: string) => { + setLoading(true); + setQuotes([]); + setSelectedToken(event); + }; + + useEffect(() => { + if (sellAmount && selectedTokenObj && !isDebouncing) { + fetchAvnuQuotes(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedTokenObj, isDebouncing, sellAmount]); + + useEffect(() => { + if (buyAmount && selectedTokenObj && !isBuyInputDebouncing) { + fetchSellAmountFromBuyAmount(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedTokenObj, isBuyInputDebouncing, buyAmount]); + + const handleSwap = () => { + if (!account || !sellAmount || !quotes[0]) return; + setErrorMessage(""); + setSuccessMessage(""); + setLoading(true); + executeSwap(account, quotes[0], {}, AVNU_OPTIONS) + .then(() => { + setSuccessMessage("success"); + setLoading(false); + setQuotes([]); + }) + .catch((error: Error) => { + setLoading(false); + setErrorMessage(error.message); + }); + }; + + /*if (!account) { + return + }*/ + + const renderTokensInput = () => { + return ( + + + + ++ ); + }; + + const renderLordsInput = () => { + return ( ++ + ++ ); + }; + + const buttonContent = () => { + switch (true) { + case sellAmount === "0" || !sellAmount: + return "Enter amount"; + case loading: + return+++ Loading...
; + case parseEther(sellAmount ?? "0") > sellBalance: + return "Insufficient Balance"; + case !!quotes[0]: + return "Swap"; + + default: + return null; // Or any default case you'd like to handle + } + }; + + return ( + + ); +}; diff --git a/landing/src/components/modules/swap-panel.tsx b/landing/src/components/modules/swap-panel.tsx index 0f3f13740..0076deac3 100644 --- a/landing/src/components/modules/swap-panel.tsx +++ b/landing/src/components/modules/swap-panel.tsx @@ -1,7 +1,11 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { useState } from "react"; +import { Button } from "../ui/button"; +import { LordsPurchaseDialog } from "./lords-purchase-dialog"; import { Swap } from "./swap"; export const SwapPanel = () => { + const [isLordsPurchaseDialogOpen, setIsLordsPurchaseDialogOpen] = useState(false); return (); }; diff --git a/landing/src/components/modules/token-balance.tsx b/landing/src/components/modules/token-balance.tsx new file mode 100644 index 000000000..f93a4c7fa --- /dev/null +++ b/landing/src/components/modules/token-balance.tsx @@ -0,0 +1,51 @@ +import { currencyFormat } from "@/lib/utils"; +import { Loader2 } from "lucide-react"; +import { useEffect, useState } from "react"; + + +export const TokenBalance = ({ + balance, + symbol, + isLoading, + onClick, +}: { + balance: bigint | number | string; + symbol: string; + isLoading?: boolean; + onClick?: () => void; +}) => { + const [balanceState, setBalanceState] = useState@@ -20,6 +24,9 @@ export const SwapPanel = () => { + ++ (); + useEffect(() => { + setBalanceState(balance); + }, [balance]); + return ( + ++ ); +}; \ No newline at end of file diff --git a/landing/src/components/providers/cartridge-controller.tsx b/landing/src/components/providers/cartridge-controller.tsx deleted file mode 100644 index 16ca3a125..000000000 --- a/landing/src/components/providers/cartridge-controller.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import ControllerConnector from "@cartridge/connector/controller"; - -export const cartridgeController = new ControllerConnector({ - rpc: "https://api.cartridge.gg/x/starknet/sepolia", - // Uncomment to use a custom theme - // theme: "dope-wars", - // colorMode: "light" -}); diff --git a/landing/src/config.ts b/landing/src/config.ts index 45275ad70..dd7139894 100644 --- a/landing/src/config.ts +++ b/landing/src/config.ts @@ -26,7 +26,7 @@ export const tokens: { } = { [Chain.MAINNET]: { [Token.LORDS]: { - address: "", + address: "0x0124aeb495b947201f5fac96fd1138e326ad86195b98df6dec9009158a533b49", decimals: 18, }, }, @@ -57,8 +57,71 @@ export const tokens: { }, }; -const chain = import.meta.env.VITE_PUBLIC_CHAIN as Chain | Chain.LOCAL; +export const chain = import.meta.env.VITE_PUBLIC_CHAIN as Chain | Chain.LOCAL; export const seasonPassAddress = tokens[chain][Token.SEASON_PASS]?.address as `0x${string}`; export const lordsAddress = tokens[chain][Token.LORDS]?.address as `0x${string}`; export const realmsAddress = tokens[chain][Token.REALMS]?.address as `0x${string}`; + +export enum SupportedToken { + ETH = "ETH", + WETH = "WETH", + USDC = "USDC", + USDT = "USDT", + STRK = "STRK", +} + +export const supportedTokens: { + [key in Chain]: { + [key in SupportedToken]?: { + address: string; + decimals: number; + symbol: string; + name: string; + logoURI: string; + isNative?: boolean; + }; + }; +} = { + [Chain.MAINNET]: { + [SupportedToken.ETH]: { + address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ethereum", + symbol: "ETH", + decimals: 18, + logoURI: "https://raw.githubusercontent.com/SetProtocol/uniswap-tokenlist/0d9233eef112388ef7e261cb88413894fd832679/assets/tokensets/coin-icons/eth.svg", + isNative: true + }, + [SupportedToken.USDC]: { + address: "0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", + name: "USD Coin", + symbol: "USDC", + decimals: 6, + logoURI: "https://raw.githubusercontent.com/SetProtocol/uniswap-tokenlist/0d9233eef112388ef7e261cb88413894fd832679/assets/tokensets/coin-icons/usdc.svg" + }, + [SupportedToken.USDT]: { + address: "0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8", + name: "Tether USD", + symbol: "USDT", + decimals: 6, + logoURI: "https://raw.githubusercontent.com/SetProtocol/uniswap-tokenlist/0d9233eef112388ef7e261cb88413894fd832679/assets/tokensets/coin-icons/usdt.svg" + }, + [SupportedToken.STRK]: { + address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + name: "Starknet Token", + symbol: "STRK", + decimals: 18, + logoURI: "https://raw.githubusercontent.com/SetProtocol/uniswap-tokenlist/0d9233eef112388ef7e261cb88413894fd832679/assets/tokensets/coin-icons/eth.svg" + } + }, + [Chain.SEPOLIA]: { + // Add sepolia tokens here if needed + }, + [Chain.LOCAL]: { + + } +}; + +// Helper exports if needed +export const getSupportedTokenAddress = (token: SupportedToken) => + supportedTokens[chain][token]?.address as `0x${string}`; diff --git a/landing/src/dojo/setupNetwork.ts b/landing/src/dojo/setupNetwork.ts index 73174453a..db9b37a92 100644 --- a/landing/src/dojo/setupNetwork.ts +++ b/landing/src/dojo/setupNetwork.ts @@ -1,6 +1,5 @@ import { EternumProvider } from "@bibliothecadao/eternum"; import { DojoConfig } from "@dojoengine/core"; -import { world } from "./world"; import { BurnerManager } from "@dojoengine/create-burner"; import * as torii from "@dojoengine/torii-client"; @@ -40,7 +39,6 @@ export async function setupNetwork({ ...config }: DojoConfig) { return { toriiClient, provider, - world, burnerManager, }; } diff --git a/landing/src/dojo/world.ts b/landing/src/dojo/world.ts deleted file mode 100644 index 960676e5e..000000000 --- a/landing/src/dojo/world.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { createWorld } from "@dojoengine/recs"; - -export const world = createWorld(); diff --git a/landing/src/hooks/use-debounce.tsx b/landing/src/hooks/use-debounce.tsx new file mode 100644 index 000000000..9f88d4d1a --- /dev/null +++ b/landing/src/hooks/use-debounce.tsx @@ -0,0 +1,26 @@ +import { useEffect, useState } from 'react' + +/** + * Debounces updates to a value. + * Non-primitives *must* wrap the value in useMemo, or the value will be updated due to referential inequality. + */ +// modified from https://usehooks.com/useDebounce/ +export default function useDebounce+++ Balance: + + {isLoading ?? typeof balanceState != "bigint" ? ( ++ {/*+ ) : balanceState ? ( + currencyFormat(Number(balanceState), 3) + .toLocaleString() + .replace(/\B(?=(\d{3})+(?!\d))/g, ",") + ) : ( + "0" + )} + {symbol}+*/} + (value: T, delay: number): T { + const [debouncedValue, setDebouncedValue] = useState (value) + + useEffect(() => { + // Update debounced value after delay + const handler = setTimeout(() => { + setDebouncedValue(value) + }, delay) + + // Cancel the timeout if value changes (also on delay change or unmount) + // This is how we prevent debounced value from updating if value is changed ... + // .. within the delay period. Timeout gets cleared and restarted. + return () => { + clearTimeout(handler) + } + }, [value, delay]) + + return debouncedValue +} \ No newline at end of file diff --git a/landing/tsconfig.app.json b/landing/tsconfig.app.json index d91ce19d4..09b8e4e40 100644 --- a/landing/tsconfig.app.json +++ b/landing/tsconfig.app.json @@ -28,7 +28,8 @@ "baseUrl": ".", "paths": { "@/*": ["./src/*"] - } + }, + "types": ["vite-plugin-svgr/client"] }, "include": ["src"] } diff --git a/landing/tsconfig.app.tsbuildinfo b/landing/tsconfig.app.tsbuildinfo index 5ba5a6185..d185eee51 100644 --- a/landing/tsconfig.app.tsbuildinfo +++ b/landing/tsconfig.app.tsbuildinfo @@ -1 +1 @@ -{"root":["./src/main.tsx","./src/routeTree.gen.ts","./src/vite-env.d.ts","./src/components/layouts/dashboard-layout.tsx","./src/components/modules/animated-grid.tsx","./src/components/modules/app-sidebar.tsx","./src/components/modules/bridge.tsx","./src/components/modules/cartridge-connect-button.tsx","./src/components/modules/data-card.tsx","./src/components/modules/data.tsx","./src/components/modules/filters.tsx","./src/components/modules/mode-toggle.tsx","./src/components/modules/realm-card.tsx","./src/components/modules/realm-mint-dialog.tsx","./src/components/modules/realms-grid.tsx","./src/components/modules/season-pass-mint-dialog.tsx","./src/components/modules/season-pass-row.tsx","./src/components/modules/season-pass.tsx","./src/components/modules/select-nft-actions.tsx","./src/components/modules/sidebar.tsx","./src/components/modules/swap-panel.tsx","./src/components/modules/swap.tsx","./src/components/modules/top-navigation.tsx","./src/components/providers/Starknet.tsx","./src/components/providers/cartridge-controller.tsx","./src/components/providers/theme-provider.tsx","./src/components/typography/type-h1.tsx","./src/components/typography/type-h2.tsx","./src/components/typography/type-h3.tsx","./src/components/typography/type-h4.tsx","./src/components/typography/type-p.tsx","./src/components/ui/badge.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/checkbox.tsx","./src/components/ui/collapsible.tsx","./src/components/ui/command.tsx","./src/components/ui/dialog.tsx","./src/components/ui/dropdown-menu.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/multi-select.tsx","./src/components/ui/popover.tsx","./src/components/ui/select.tsx","./src/components/ui/separator.tsx","./src/components/ui/sheet.tsx","./src/components/ui/sidebar.tsx","./src/components/ui/skeleton.tsx","./src/components/ui/switch.tsx","./src/components/ui/tabs.tsx","./src/components/ui/tooltip.tsx","./src/dojo/createSystemCalls.ts","./src/dojo/setup.ts","./src/dojo/setupNetwork.ts","./src/dojo/world.ts","./src/hooks/use-mobile.tsx","./src/hooks/useAccountOrBurner.tsx","./src/hooks/useCollectionTokens.tsx","./src/hooks/useMintSeasonPass.tsx","./src/hooks/useMintTestRealm.tsx","./src/hooks/useNftSelection.tsx","./src/hooks/context/DojoContext.tsx","./src/hooks/gql/execute.ts","./src/hooks/gql/fragment-masking.ts","./src/hooks/gql/gql.ts","./src/hooks/gql/graphql.ts","./src/hooks/gql/index.ts","./src/hooks/query/players.tsx","./src/hooks/query/realms.tsx","./src/lib/utils.ts","./src/lib/ark/getCollectionTokens.ts","./src/routes/__root.tsx","./src/routes/bridge.lazy.tsx","./src/routes/index.lazy.tsx","./src/routes/mint.lazy.tsx","./src/routes/my-empire.tsx","./src/routes/passes.lazy.tsx","./src/routes/trade.lazy.tsx","./src/stories/button.stories.tsx","./src/stories/dashboard-layout.stories.tsx","./src/stories/data-card.stories.tsx","./src/stories/season-pass-row.stories.tsx","./src/stories/season-pass.stories.tsx","./src/stories/swap-panel.stories.tsx","./src/stories/swap.stories.tsx","./src/stories/top-navigation.stories.tsx","./src/types/index.ts"],"errors":true,"version":"5.6.3"} \ No newline at end of file +{"root":["./src/config.ts","./src/main.tsx","./src/routetree.gen.ts","./src/vite-env.d.ts","./src/components/layouts/dashboard-layout.tsx","./src/components/modules/animated-grid.tsx","./src/components/modules/app-sidebar.tsx","./src/components/modules/bridge.tsx","./src/components/modules/cartridge-connect-button.tsx","./src/components/modules/data-card.tsx","./src/components/modules/data.tsx","./src/components/modules/filters.tsx","./src/components/modules/lords-purchase-dialog.tsx","./src/components/modules/mode-toggle.tsx","./src/components/modules/realm-card.tsx","./src/components/modules/realm-mint-dialog.tsx","./src/components/modules/realms-grid.tsx","./src/components/modules/season-pass-mint-dialog.tsx","./src/components/modules/season-pass-row.tsx","./src/components/modules/season-pass.tsx","./src/components/modules/select-nft-actions.tsx","./src/components/modules/swap-panel.tsx","./src/components/modules/swap.tsx","./src/components/modules/token-balance.tsx","./src/components/modules/top-navigation.tsx","./src/components/providers/starknet.tsx","./src/components/providers/theme-provider.tsx","./src/components/typography/type-h1.tsx","./src/components/typography/type-h2.tsx","./src/components/typography/type-h3.tsx","./src/components/typography/type-h4.tsx","./src/components/typography/type-p.tsx","./src/components/ui/badge.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/checkbox.tsx","./src/components/ui/collapsible.tsx","./src/components/ui/command.tsx","./src/components/ui/dialog.tsx","./src/components/ui/dropdown-menu.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/multi-select.tsx","./src/components/ui/popover.tsx","./src/components/ui/select.tsx","./src/components/ui/separator.tsx","./src/components/ui/sheet.tsx","./src/components/ui/sidebar.tsx","./src/components/ui/skeleton.tsx","./src/components/ui/sonner.tsx","./src/components/ui/switch.tsx","./src/components/ui/tabs.tsx","./src/components/ui/tooltip.tsx","./src/dojo/createsystemcalls.ts","./src/dojo/setup.ts","./src/dojo/setupnetwork.ts","./src/hooks/use-debounce.tsx","./src/hooks/use-lords.tsx","./src/hooks/use-mobile.tsx","./src/hooks/useaccountorburner.tsx","./src/hooks/usecollectiontokens.tsx","./src/hooks/usemintseasonpass.tsx","./src/hooks/useminttestrealm.tsx","./src/hooks/usenftselection.tsx","./src/hooks/context/dojocontext.tsx","./src/hooks/gql/execute.ts","./src/hooks/gql/fragment-masking.ts","./src/hooks/gql/gql.ts","./src/hooks/gql/graphql.ts","./src/hooks/gql/index.ts","./src/hooks/query/players.tsx","./src/hooks/query/realms.tsx","./src/lib/utils.ts","./src/lib/ark/getcollectiontokens.ts","./src/routes/__root.tsx","./src/routes/bridge.lazy.tsx","./src/routes/index.lazy.tsx","./src/routes/mint.lazy.tsx","./src/routes/my-empire.tsx","./src/routes/passes.lazy.tsx","./src/routes/trade.lazy.tsx","./src/stories/button.stories.tsx","./src/stories/dashboard-layout.stories.tsx","./src/stories/data-card.stories.tsx","./src/stories/season-pass-row.stories.tsx","./src/stories/season-pass.stories.tsx","./src/stories/swap-panel.stories.tsx","./src/stories/swap.stories.tsx","./src/stories/top-navigation.stories.tsx","./src/types/index.ts"],"errors":true,"version":"5.6.3"} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 65221b6ec..35f719f5c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -389,6 +389,9 @@ importers: '@ark-project/react': specifier: 2.0.0-beta.2 version: 2.0.0-beta.2(encoding@0.1.13)(typescript@5.6.3)(viem@2.21.45(typescript@5.6.3)(zod@3.23.8)) + '@avnu/avnu-sdk': + specifier: 2.1.1 + version: 2.1.1(ethers@6.13.4)(qs@6.13.0)(starknet@6.11.0(encoding@0.1.13)) '@bibliothecadao/eternum': specifier: workspace:^ version: link:../sdk/packages/eternum @@ -706,6 +709,9 @@ packages: '@adraffy/ens-normalize@1.10.0': resolution: {integrity: sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==} + '@adraffy/ens-normalize@1.10.1': + resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==} + '@adraffy/ens-normalize@1.11.0': resolution: {integrity: sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==} @@ -748,6 +754,14 @@ packages: '@ark-project/react@2.0.0-beta.2': resolution: {integrity: sha512-QmnL2Y5ondgYpMWaIcm8nva7/7HPKonHg7QrAXIsVU2N63pwbCbK6sNrksPoZ4PKUFgPUBRbF7/kOwKvwG/uKA==} + '@avnu/avnu-sdk@2.1.1': + resolution: {integrity: sha512-y/r/pVT2pU33fGHNVE7A5UIAqQhjEXYQhUh7EodY1s5H7mhRd5U8zHOtI5z6vmpuSnUv0hSvOmmgz8HTuwZ7ew==} + engines: {node: '>=18'} + peerDependencies: + ethers: ^6.11.1 + qs: ^6.12.0 + starknet: ^6.6.0 + '@babel/code-frame@7.26.0': resolution: {integrity: sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==} engines: {node: '>=6.9.0'} @@ -4207,6 +4221,9 @@ packages: '@types/node@20.17.1': resolution: {integrity: sha512-j2VlPv1NnwPJbaCNv69FO/1z4lId0QmGvpT41YxitRtWlg96g/j8qcv2RKsLKe2F6OJgyXhupN1Xo17b2m139Q==} + '@types/node@22.7.5': + resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + '@types/node@22.8.1': resolution: {integrity: sha512-k6Gi8Yyo8EtrNtkHXutUu2corfDf9su95VYVP10aGYMMROM6SAItZi0w1XszA6RtWTHSVp5OeFof37w0IEqCQg==} @@ -4610,6 +4627,9 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + aes-js@4.0.0-beta.5: + resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} + agent-base@7.1.1: resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} engines: {node: '>= 14'} @@ -5827,6 +5847,10 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + ethers@6.13.4: + resolution: {integrity: sha512-21YtnZVg4/zKkCQPjrDj38B1r4nQvTZLopUGMLQ1ePU2zV/joCfDC3t3iKQjWRzjjjbzR+mdAIoikeBRNkdllA==} + engines: {node: '>=14.0.0'} + eval@0.1.8: resolution: {integrity: sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==} engines: {node: '>= 0.8'} @@ -8829,6 +8853,9 @@ packages: tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + tslib@2.8.0: resolution: {integrity: sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==} @@ -9480,6 +9507,18 @@ packages: utf-8-validate: optional: true + ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -9587,6 +9626,8 @@ snapshots: '@adraffy/ens-normalize@1.10.0': {} + '@adraffy/ens-normalize@1.10.1': {} + '@adraffy/ens-normalize@1.11.0': {} '@alloc/quick-lru@5.2.0': {} @@ -9660,6 +9701,12 @@ snapshots: - typescript - viem + '@avnu/avnu-sdk@2.1.1(ethers@6.13.4)(qs@6.13.0)(starknet@6.11.0(encoding@0.1.13))': + dependencies: + ethers: 6.13.4 + qs: 6.13.0 + starknet: 6.11.0(encoding@0.1.13) + '@babel/code-frame@7.26.0': dependencies: '@babel/helper-validator-identifier': 7.25.9 @@ -13727,6 +13774,10 @@ snapshots: dependencies: undici-types: 6.19.8 + '@types/node@22.7.5': + dependencies: + undici-types: 6.19.8 + '@types/node@22.8.1': dependencies: undici-types: 6.19.8 @@ -14238,7 +14289,7 @@ snapshots: sirv: 2.0.4 tinyglobby: 0.2.10 tinyrainbow: 1.2.0 - vitest: 2.1.3(@types/node@22.8.1)(@vitest/ui@2.1.3)(jsdom@24.1.3)(terser@5.36.0) + vitest: 2.1.3(@types/node@20.17.1)(@vitest/ui@2.1.3)(jsdom@24.1.3)(terser@5.36.0) '@vitest/utils@1.6.0': dependencies: @@ -14312,6 +14363,8 @@ snapshots: acorn@8.13.0: {} + aes-js@4.0.0-beta.5: {} + agent-base@7.1.1: dependencies: debug: 4.3.7 @@ -15838,6 +15891,19 @@ snapshots: etag@1.8.1: {} + ethers@6.13.4: + dependencies: + '@adraffy/ens-normalize': 1.10.1 + '@noble/curves': 1.2.0 + '@noble/hashes': 1.3.2 + '@types/node': 22.7.5 + aes-js: 4.0.0-beta.5 + tslib: 2.7.0 + ws: 8.17.1 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + eval@0.1.8: dependencies: '@types/node': 20.17.1 @@ -19405,6 +19471,8 @@ snapshots: tslib@2.6.3: {} + tslib@2.7.0: {} + tslib@2.8.0: {} tsup@8.3.5(@swc/core@1.7.40)(jiti@2.3.3)(postcss@8.4.47)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.0): @@ -20402,6 +20470,8 @@ snapshots: ws@8.13.0: {} + ws@8.17.1: {} + ws@8.18.0: {} xml-name-validator@5.0.0: {} From 7c23667dae50365fff016d7f764e81d6cc2265d7 Mon Sep 17 00:00:00 2001 From: "zabanyat.eth" Date: Tue, 19 Nov 2024 00:36:33 +0700 Subject: [PATCH 02/12] feat: three js scene setup --- landing/package.json | 4 + landing/public/models/biomes-opt/bare.glb | Bin 0 -> 6915444 bytes landing/public/models/biomes-opt/beach.glb | Bin 0 -> 133924 bytes .../models/biomes-opt/deciduousForest.glb | Bin 0 -> 109776 bytes .../public/models/biomes-opt/deepOcean.glb | Bin 0 -> 2786188 bytes .../public/models/biomes-opt/grassland.glb | Bin 0 -> 83536 bytes landing/public/models/biomes-opt/ocean.glb | Bin 0 -> 2786104 bytes landing/public/models/biomes-opt/outline.glb | Bin 0 -> 1712 bytes landing/public/models/biomes-opt/scorched.glb | Bin 0 -> 129960 bytes .../models/biomes-opt/scorchedVolcano.glb | Bin 0 -> 2539628 bytes .../public/models/biomes-opt/shrubland.glb | Bin 0 -> 142648 bytes landing/public/models/biomes-opt/snow.glb | Bin 0 -> 6912440 bytes .../models/biomes-opt/subtropicalDesert.glb | Bin 0 -> 300320 bytes landing/public/models/biomes-opt/taiga.glb | Bin 0 -> 1050144 bytes .../models/biomes-opt/temperateDesert.glb | Bin 0 -> 215980 bytes .../models/biomes-opt/temperateRainforest.glb | Bin 0 -> 1061424 bytes .../models/biomes-opt/tropicalRainforest.glb | Bin 0 -> 95584 bytes .../biomes-opt/tropicalSeasonalForest.glb | Bin 0 -> 1757484 bytes landing/public/models/biomes-opt/tundra.glb | Bin 0 -> 2437588 bytes .../models/buildings-opt/archerrange.glb | Bin 0 -> 35876 bytes landing/public/models/buildings-opt/bank.glb | Bin 0 -> 560212 bytes .../public/models/buildings-opt/bank_lite.glb | Bin 0 -> 10184 bytes .../public/models/buildings-opt/barracks.glb | Bin 0 -> 133664 bytes .../public/models/buildings-opt/castle.glb | Bin 0 -> 9016 bytes .../public/models/buildings-opt/castle0.glb | Bin 0 -> 56740 bytes .../public/models/buildings-opt/castle1.glb | Bin 0 -> 325860 bytes .../public/models/buildings-opt/castle2.glb | Bin 0 -> 234732 bytes .../public/models/buildings-opt/castle3.glb | Bin 0 -> 419244 bytes .../models/buildings-opt/castle_lite.glb | Bin 0 -> 9748 bytes .../public/models/buildings-opt/city_tile.glb | Bin 0 -> 1268 bytes .../models/buildings-opt/dragonhide.glb | Bin 0 -> 14176 bytes landing/public/models/buildings-opt/empty.glb | Bin 0 -> 2340 bytes landing/public/models/buildings-opt/farm.glb | Bin 0 -> 126848 bytes .../public/models/buildings-opt/fishery.glb | Bin 0 -> 99840 bytes landing/public/models/buildings-opt/forge.glb | Bin 0 -> 136384 bytes .../models/buildings-opt/hyperstructure.glb | Bin 0 -> 1392872 bytes .../buildings-opt/hyperstructureAnimated.glb | Bin 0 -> 47312 bytes .../buildings-opt/hyperstructure_final.glb | Bin 0 -> 37920 bytes .../buildings-opt/hyperstructure_half.glb | Bin 0 -> 44256 bytes .../buildings-opt/hyperstructure_init.glb | Bin 0 -> 31112 bytes .../models/buildings-opt/lumber_mill.glb | Bin 0 -> 96500 bytes .../public/models/buildings-opt/market.glb | Bin 0 -> 116364 bytes landing/public/models/buildings-opt/mine.glb | Bin 0 -> 85640 bytes .../public/models/buildings-opt/mine_2.glb | Bin 0 -> 62868 bytes .../public/models/buildings-opt/stable.glb | Bin 0 -> 609132 bytes .../models/buildings-opt/storehouse.glb | Bin 0 -> 75084 bytes .../models/buildings-opt/workers_hut.glb | Bin 0 -> 57156 bytes .../textures/environment/models_env.hdr | Bin 0 -> 1659814 bytes landing/public/textures/paper/worldmap-bg.png | Bin 0 -> 2619451 bytes landing/src/main.tsx | 4 + landing/src/three/HexagonScene.ts | 159 +++++++++++ landing/src/three/HexceptionScene.ts | 266 ++++++++++++++++++ landing/src/three/Renderer.ts | 157 +++++++++++ landing/src/three/components/Biome.ts | 115 ++++++++ .../src/three/components/InstancedBiome.ts | 156 ++++++++++ landing/src/three/constants.ts | 218 ++++++++++++++ landing/src/three/geometry/HexagonGeometry.ts | 31 ++ landing/src/three/helpers/utils.ts | 92 ++++++ landing/src/types/index.ts | 9 + 59 files changed, 1211 insertions(+) create mode 100644 landing/public/models/biomes-opt/bare.glb create mode 100644 landing/public/models/biomes-opt/beach.glb create mode 100644 landing/public/models/biomes-opt/deciduousForest.glb create mode 100644 landing/public/models/biomes-opt/deepOcean.glb create mode 100644 landing/public/models/biomes-opt/grassland.glb create mode 100644 landing/public/models/biomes-opt/ocean.glb create mode 100644 landing/public/models/biomes-opt/outline.glb create mode 100644 landing/public/models/biomes-opt/scorched.glb create mode 100644 landing/public/models/biomes-opt/scorchedVolcano.glb create mode 100644 landing/public/models/biomes-opt/shrubland.glb create mode 100644 landing/public/models/biomes-opt/snow.glb create mode 100644 landing/public/models/biomes-opt/subtropicalDesert.glb create mode 100644 landing/public/models/biomes-opt/taiga.glb create mode 100644 landing/public/models/biomes-opt/temperateDesert.glb create mode 100644 landing/public/models/biomes-opt/temperateRainforest.glb create mode 100644 landing/public/models/biomes-opt/tropicalRainforest.glb create mode 100644 landing/public/models/biomes-opt/tropicalSeasonalForest.glb create mode 100644 landing/public/models/biomes-opt/tundra.glb create mode 100644 landing/public/models/buildings-opt/archerrange.glb create mode 100644 landing/public/models/buildings-opt/bank.glb create mode 100644 landing/public/models/buildings-opt/bank_lite.glb create mode 100644 landing/public/models/buildings-opt/barracks.glb create mode 100644 landing/public/models/buildings-opt/castle.glb create mode 100644 landing/public/models/buildings-opt/castle0.glb create mode 100644 landing/public/models/buildings-opt/castle1.glb create mode 100644 landing/public/models/buildings-opt/castle2.glb create mode 100644 landing/public/models/buildings-opt/castle3.glb create mode 100644 landing/public/models/buildings-opt/castle_lite.glb create mode 100644 landing/public/models/buildings-opt/city_tile.glb create mode 100644 landing/public/models/buildings-opt/dragonhide.glb create mode 100644 landing/public/models/buildings-opt/empty.glb create mode 100644 landing/public/models/buildings-opt/farm.glb create mode 100644 landing/public/models/buildings-opt/fishery.glb create mode 100644 landing/public/models/buildings-opt/forge.glb create mode 100644 landing/public/models/buildings-opt/hyperstructure.glb create mode 100644 landing/public/models/buildings-opt/hyperstructureAnimated.glb create mode 100644 landing/public/models/buildings-opt/hyperstructure_final.glb create mode 100644 landing/public/models/buildings-opt/hyperstructure_half.glb create mode 100644 landing/public/models/buildings-opt/hyperstructure_init.glb create mode 100644 landing/public/models/buildings-opt/lumber_mill.glb create mode 100644 landing/public/models/buildings-opt/market.glb create mode 100644 landing/public/models/buildings-opt/mine.glb create mode 100644 landing/public/models/buildings-opt/mine_2.glb create mode 100644 landing/public/models/buildings-opt/stable.glb create mode 100644 landing/public/models/buildings-opt/storehouse.glb create mode 100644 landing/public/models/buildings-opt/workers_hut.glb create mode 100644 landing/public/textures/environment/models_env.hdr create mode 100644 landing/public/textures/paper/worldmap-bg.png create mode 100644 landing/src/three/HexagonScene.ts create mode 100644 landing/src/three/HexceptionScene.ts create mode 100644 landing/src/three/Renderer.ts create mode 100644 landing/src/three/components/Biome.ts create mode 100644 landing/src/three/components/InstancedBiome.ts create mode 100644 landing/src/three/constants.ts create mode 100644 landing/src/three/geometry/HexagonGeometry.ts create mode 100644 landing/src/three/helpers/utils.ts diff --git a/landing/package.json b/landing/package.json index 888de334b..3940643c2 100644 --- a/landing/package.json +++ b/landing/package.json @@ -56,12 +56,15 @@ "lucide-react": "^0.365.0", "next-themes": "^0.4.3", "nuqs": "^2.0.4", + "postprocessing": "^6.36.2", "react": "^18.3.1", "react-dom": "^18.3.1", "sonner": "^1.7.0", "starknet": "^6.8.0", "tailwind-merge": "^2.5.4", "tailwindcss-animate": "^1.0.7", + "three": "^0.166.1", + "three-stdlib": "^2.29.5", "viem": "^2.21.45", "vite-plugin-svgr": "^4.2.0", "vite-plugin-wasm": "^3.3.0" @@ -88,6 +91,7 @@ "@types/node": "^20.11.10", "@types/react": "^18.3.10", "@types/react-dom": "^18.3.0", + "@types/three": "^0.163.0", "@vitejs/plugin-react": "^4.3.2", "autoprefixer": "^10.4.18", "eslint": "^9.11.1", diff --git a/landing/public/models/biomes-opt/bare.glb b/landing/public/models/biomes-opt/bare.glb new file mode 100644 index 0000000000000000000000000000000000000000..34276b3ef3675d4581023f9491461b51f05572f0 GIT binary patch literal 6915444 zcmeFa37ni$_WysfkWK^@BHCUuW&{z{OLZ;XZ613NNsAx|Dw2?lEF}rr*e-$~Mk7ot z8D$w_8B>U)mnt615Ja>HlQEVWV~M>GrfuW*dG403Q%}uT|5Ee+|6ae>?|QYay!+O9 z&b{~Cd(T~;)25F*xHl2ay>uGAu|LsaM~xYM?$C*I=1iG8G=A>T)27UvGJE3OS+j@6 zhn|M0dyktvaps&;XU(1wJgas@)rip0;X}`wGJDRnSu+u%8vj0j_|S=yCQX?$XV&aF zL*pl$J9O?j$tn2TQ3vcdYQM3FK55pB M5EQUp=edD_k~bxOom9PDi*1WMCyhko Kp$d_cr83)aFFp2xJ68I24Ighhnu6o93Dk)nWYOlrv8~b;|5xrcF6}Xgq{} zo-=pKm{U)cg&yjr=+Am=O}H*LeCV9y#MyID(C3=6^t72abMiFUf=9bQv5Gy>*C=2} zXHA@bX7RVH*|*O>znjKAH5sqKL$PRGC{`7TRfnTBwRPdT;USw}A+Pj9p%APpR8=+O7}D&wWV_LXY2GI QGIjE*$esWTYyLic%LrhM@YW zjOeaaZJATa 99j#So# zqSaNQx@dK@E*kSS*jQC4QWdSKu0n29*Pvx%)gJ9eSq+xSD^DW-r&<|9y{ry 5L%#WG?_jvPplR_QYePjsTQSP6)s9;w9Khw^2(ITP+e7B zq^dd`2`O7teXwm`V|D0nLsgNwSY1stRNV5Qiz%zQGI`}lWH=g*L~Cnn!f1J_{Sz5M zgA=U|*G2ImT3cL{RsW$g{@?0GxWICx(=*jD`jA?57GZyrjiMI~qt&TKc~;f=q?5Y< z|2w@~_a?iF2`p1O{|Bc49wjOyY9)SGqwg%Lns7nOYqnfqnbH}m302qDMd1DT*= 6$x`8QdgK9!mb)h;q_*J#Fp-7ES zX)<@EyQ}=aS38-&awM}Z6p7ZrDr=%OF pG+pO9La>y*4EWvgc8=?I8S6vO?4=Y zaWBdePJN`fFqzM?@u_42%aY0}bSAMdM(9 ;` zgt)-+q!Z(gDwLDw3HgnvJ-e;)W*1_iaCL39iqhS0sb+r5Mi(a+SdL`E7Gr3Gsxe4` zt0SA3BD1YQ>M*9Ru7N)kDQ;}x50}?N-~!8$&f2 BN5L}&~{x=H<{bA@yTQY%aBZO(h_|M3e%g=Qr#l2n<2~s zq4r|x57pSGYBINF K>z%~r!Hz|sarDyY4fiS|h*b6Yk(nM`0Al8I)vE`~M;jSMDC z{F Zuhnva ufC-ScYWQVz?QtiPY3#(24b5zuFm%)l}8M1*!^TT#BWL;@Zjl zmW^&~(Ml9#Tp7}dSs-*LXj?GAMkVx3X9OJzCXH%fy!g+jb~49hTArhaYf+VxbyuHP^Q|(F}Q0(wO*) zMWa5+WRA h`%Xg7MIuK}(y_rrpe#MoOIW8NYOeU}#$;3Q! zHO8ArMKq! g_?mDxhBzgtiA=r#DyP6}hUu1<5S8AB3%21^HHnWMauH zjJZ3EJh4pT>mOh}yEck7>u9tFs|>|%P;I&0ATF>BsYDvEU9P4o;#sBcELaPKxq0k^ z!|1vet10mHi>oH{S~lKjnZPonGmL>XwjX#aU-07nY__fn8GzLm%%q@Z*7+DMb6Pe& znM@#(S+Ge*ZJ<>3rg)#8GWbzbW}Y^8>d-ibUfvpdiOBeCVRQ_t|3h@N#D&rSvvds8 z3!{4ub4;_N=FXlr85;w=NyE7lXP@S6EQM2D_n*{7(}MNr^2)4%MrO&+WZK5+S&Qil z)O*?TluITi43PTr%EW{iCJM_d6RWSWXqn3hJtu0ZcACqTp;guBgzCy%N^oVc@3qXu z1aqv$vRHY`362IP3(H+l*jj)E=kjWbQECX@aG8ZxS7Twh%msy&g(y0cGHVJiKNc!; zLBa3Fkhk0g1+S 5vH!0#=uQ0%Y5jCh%aqMWL0 z%Uw{|d5m2cW!4ny0d?heBWf`O!OVJjHN`qN_NkV+px{|YF=ta|P3x+#KdQ_Hg+)f} zGb(e9s*Pc?yxh)27`wu;&{W<$#Xb*=hRR$}5b4cYmRVCQKH;QNnT19$QY^PKfd!#Z ztlZ87CV?@1SmuJlM0yM}Jmt+(tn^|srOX9|-PaN9Wht|!b?UT9Svx*&br*Y43pEW_ zW1I1Y!LS|( K4Qw;iPNV~n>2RTnWs&iiL;8{0kzrY9|upIBo91>Mqqe8 zLr1mneEG;JbEbL+({Q{|KktAuPnm*qVqrXUO7q;=6QxKs+#L;#ytqS8osCZ?<1m?b zYSR9rs{22xyZ^&G`)H%pcK?U>82gvH?*E8%|3|d@KVsefQPo|8s_q(8b=RP(y9QO= zHK^*YK~;ARs=8}X)m?+C?iy5g*Pyz)2G!j)sP3*ob$1P_yK7M0U4!cG8dP`Jpt`#T zHQhC+>8?RdcMWQ~Yf#f&gPQId)O6RNrn?3;-8HD`u0d^g4Qjh Z`T&YY``L^h2%>d
xbn)6~^So-Ni??&o{*CG4Ig9phOc!jx z-taf3i`UWE?=fAx9T( +W4hFI)1`*#;<@eSd$mj# zZwlT1jp^cb`Sx#27i`Yi@HeK5H} -!b}&>`7+ 4N ZX&zOluTQ$gq&Wx8VwBKHo zi8H66MOP``;Dj7L<(&N{c@$m!oQX4%({VF{bW*0xOrD8pcNEI3Gv~^WaBZf|gx{2$ zHC@Vq%QWiH(Ffs%22cE?sS{_;oT5D{ElKtqW&$66kL+2HTgi#u@`KG7 OvdhNzoe$^XNIAw|2tN|4^WK!iM-`r<`%-wAugjcg_z6gXir(jrKou zG;X|Ta_+xxtaJ3yM>|C0@%easJ`tZ2_ J@`1~7uo`KIve4dTZXX0}+KK~Y< z&&Owh-xuNE7vu9he7+Q)FT>~g_ uY7#OE9E`9^$R zgwHqO^Ue5tD?TsA=Re?c3ZHMs=R5HEE`0tYKHrVcOYr$#e7+B#AHe57;q!y|oW|#e z@cChUUW(6;;`1_mZpG&|d~V0*3_fS^`7wNU@%agSeiEOb#^=A_^E3Fo0-vA5=jZWx zB|g81Umc6Q5tk=hgVU2A^NW@8L9_=24p7po(6#y%N0^^lI((Zm&S^hTc zq)>jepmKe+V8D?6&2ML6DlsNNLRdG(YODI{^R>!-2Z|8ul1(^dkz>k;DP~5 z2CN?N!+>9H*0kAgH@j=IRhxBfHgw>qfoBa&4Sas!`hh!dK63Nfo8P+mGn*5F`1Sw$ zDOVnN`6+`ST2%+Tz|W#bHS>Ozk*6WIqK2q)S)u%Lai^9j2>qv470NFcuU$@56((^L ze%m03%EfcgKerTVz>f`(UoQRw@;?UM?`86P%6EtmEsl`57 ^|^oc<)8wB-~QxN$-5VCR)TPf21d&)0CJ`YAd|Blt8p7J`#co1pg^|7Zs zA0~Poc|4lw(^Ebhat1=5)FXxYQ!f4jWY?e^vnT@_1W}o|c)pHA2cGe5q5N`j^77$n z
0d6MMfqN}oSdET3>%QH z5YkhDv@T-LEfv2M7iiyBcrx(Y1_2W-6CaAaKO1Gd1(RPU?*0+-_d?zrkKZ;3Di;@M zBgI~=Xm4O&HlTi$iwB|m#O28DLj6SvPG2J4uw^KFR_-OZa|>i21pNmV#xEBqukA$L z6PZH!W#gYfuIE#%f7Ir_Y(LAy#op*!+K`5E$Wt3ozCGmRhTx-ldBE(vr+hT>@?HEK zTc{89l>fMt=nmNIrN}!Q1W`} yvF43k1`q9O70+5E~Vm^;`1SQ z6!K;iYd_1xMQ`Z;HuQhLP=2{MT>$^*9z5eh{Mdl}UyXEa2FC5S6fY&m8*>am{>%(p z>9T(>7r&y8++LVZc%U$UsB9eiW2{A&G5x;>Ux2*(n(-@2#4p9~gZ=G>@0_^2Fn=&+ z64&783H;3l^k1jp-<~}TL0@abf8b9+zrW%;OAGZBJ>>KYj8T4t{ s%)I%=5Sw`*v_|_kyY-~V2^pMjU=uw9>jbrU+Px mSR+#V%-v`=H(9`Ty0UXbX|HEX$t~yp$YqFV pc_4qi4tr-UDsKp*l~ zw4q*ovH^D3LoP sM>7 zNBT=;;vxgv><8cC5v17$_`N;kv=;fbBkD^h^3MiQKEJ4xf7Mg}r>F5pq8 guxZEr8AZ-25%>HY@{P;-d^CW(rV)Y`7_-Xt+#N;f1-aCTv zad%JoEhs;4?rL-P+@A8ukaIfpxd^{)5JWxX;sw;xAZ*L?A8kOn_mEQ<-#-~?8c-;w zr(9G+AM7h|uP&6+Q||tNG8~Kc>U!jn4Ok!VAs2gLo_`zE3o4Y;Q% Sry{}BH*=vnFIXWfSAvVABMZ-X9vQ0}b$ ziV~crLyskRcA`+9lKhvLOWOke!y-1HStjlTus(&kXJ=laKIP)#Rpd`K+N)0^h56q@ zPW>UrYa_NRltbUbKSx_!wBA%EE^bHv@*(PERbl>=jeF||^CA0mmagGo!^4=zD|{~X zl<$S_W6n~nU~ (O+!{f~ZvdQhXTX{0%bB!fzWOr(FCu zkejc=7>wy(CNA0`*PFvg;l~E_Q)S}rO|buiQNAA{4K|>^C=>VA#Aqqz1}3oifiiL7 z&HJEy#a~$dKZ5kEL%n+iWp4xWtwj7%oc4kI^C9~<$g@FEkNIrq@d5PV`#O5cyWnqo zwi|_CW&`x;DSsOFGzxMYHty>w&p?l>kw0F$VgvN)DL(_cTnRZ{g?3Io<-MTCdi?P7 z1wG}Xk SlI zXy5RR+wt25=wB`#t;QKF$PVJS4Uk_Z?p7=#XK(md3k&rx7pDNmDC^*3HR2gIK>wSO zXU+IoS@_(N@vBgVTfkPPF*`W{{jawsSqWJ-Kz^CH7>EAlW3+qR|0xqE%&pRJ{QM3- zHb8%G&fr$0sTY3R0A4CS_E0z%A?|A|zBjhOK1Q+0aw~;A|9>y!=b;!EY`Kx~z4mtz z+R*u|e=HaO5#{?U*pSQYWaD^n(vSw^hj@D4CXLDV-Lk>>_^g*dsjYYR=hyAv%XOX> z$uWH48j+1Y=w_#Wu(nY%@0Z|Q{G(FJ=RBR-(U<4XQTjNOZ| nKl6XHtJLS`@}{JU?<78n)1t}k&Vs}1J;B4e zRJu4%&+?B?zx>Yoo}h|c8%=#CN-HjD^W@Mgn@W8+uUPNTI}h`hlbHCul<%$z)l=Z_ z@z7&CWIXY?bJqLvz!RIx=koX~-WlY}#pOyL9>3+Opo}ku_Kj11k2V^#N!)ub&GF}* zb5#ED_{L5KKejqc(PP_}-2b>Imzq9QcE!2(Hw3|XV4`|%u2)Mt_U)i;=qKCNmfx!9 za-P1%pGUJw4y{hLQM!K{t$R+Em(cdZd4(=_&b!W2b|QYNs;A_+?Gw^3OZ%av%KkYY zwtNefpDcd!k6ND_cSO2E%W2Ydna}h4?jqw8<8DZ$i}SRr>K84&xSrk}77r~+Nqy3{ zZ>8igp4d<6&*PitI#UAm^mL#-`tZ|IPV-f|UND|N#h-W0QqSdbq8Iq{U~grI!I|&X zQ`fY1=k|5-xz5L`UT~h9r0NCd;yhI^IL|+(>ILVW|5WvYbCWJw_EwyN@3bDY{X0^h zsTZqq Y_zHW(@09*V{yTr}zUt3gR{3)p{*|Yf2)q)`P++eP`q#@+ zexd{qe*T U*h%C0z1 z4OVu(;`*QJY5Z$#^snBso~8$?`p$Xq7G)=#x7_B>lY^8T%Dvl4E02g#Dh=NP{r*(7^zkh93NKND6$?&HgM-t&bH zPyd$fwo~m7;}vssyTtgS-)Vag1UbKY)cLit=X4+49y0F!sLP#kr-Youfx7+<9@9>P z$HeHoeySY%==3t)^1aSa#+_BFJ%Nk@IZbgbf3s6NsN(BbZcCL9!4lm0YI~JGEWX(J zYgtdJ^Sc )Nxb%4?a~#huinvV|kFNw3 z$KPD(KWvM4I u>&Om2aFU4^(<`?p~+!?ZgW^$hoe)@AOr&e47r@^@#D7 zt8{%~+_v-EcD7UExHuhlvCK~^pYfJ|=yrf{@o#^g_)zmvt7G)ty>W5uc&TTuMz>dt zi!F7##JDM!bH2T%kwz}eY(42SSvE$0&J$g#f8;!{g~~T) zVew7>%j1VmQ1+19 {m-(M{Kieb;G`pCJ-XU >%Amb*zxKl*WgQN=QN&c_n4|?M{QL)#oY)fQ7mLk8E_Ryrqah&H)Q}u{*n{WGE zR^Rk_Fxz?f-cn9adGq3JRlm&Sw2al`wPRMdQN>MdG$Jbdi=@_*7`OG2aXa2*oGzN? z*_~(!KGs3=?~J=Ecg}dayKn!|m#0quy)Vy=@{jL^r~1ZsZr{e2i->=G@xHQW@kOMb z@=wNT+e>6SBeqrbh4aubRlhiIG5Pl7M{%0GZ=AYrm2v{#==#FAdyej37&rdE({foo zt$8V)+EUHuxHDA!;ym$$YTr0-O{?cN9k!~2nwGWEoA*n7(kqpmB3`5P;k@%Oe{SvJ zihJWU^~^Xq|B~`;J}_?6%eb{4#?5?)GyBMTTKjO!S$k{2{08T_`ASdD=>pY0bMExj z`Ty}B+9>&OoBP6+9iDwwOx5MZc*}meU1glU)b)t-amt?=H@dU2^P4eQ_sd4lE-Cnw z>K8cgT -osHJYcE)k&2PI+mTtd7rZ=Bc>E%4B z?U{4aZg8GzSAOz@DX_=M2e
ymz;kKEb*B+24J+cy<%n zzVY}$NB2kK#t3~hCN64LOZ#+|`SV~uf1V%g&t+~x&u;x1o9DOv-G7Cj_r|_iXU@^t ziVN jAxfv2>e%;I-# zqWdGxYjnM1Jn!gw$G91%i`Tp2)ck7fpm&tNWX9v1w? 8_k#_xplcli@y^yeX-9aEx9r >6Onm BBu_dd<29=k!{O96uKEO@HUhD?ZWr z|K!avN^jOC(jQAb=a13tIpa%={WEUtA^1<^=Wf4hcP`vQ`8k1pvR&fb*eB=d LSB$%QTt Vwuu>&xw)oUS)j{%{^3)edmpWb*A-_rXWl7jt2|%5_ZBUlZfDzhm6^ z$vnQN6M|@+_d{c-a+_@GNjXnMX8gsu>3=yl<5}?m#!X`1C|&ugoL6)!RJu5C`j;v% z&fTc8bI#3kX?RmRt-U8kiB+CmQc$nIaNd&C?I(-hr00e5ub %n%uI>`9^t(1Jun?F z9T?4@uv3RuUc-d0?~Jdw%b%O}naeTxhCLeXH2Ls&>H+D8QOo{XPsXjCFmCLP%Q1dn zZlA~MsriHU-0VGN`)T|}&P&BN<4PVsc={q~pPU;%lXK%Yy1S=3XwN(2`K(^|*Yo_G z2R~Kq0Ou{b-R9iPmpX1&2MtTq(@Zt5W#&sc7h_cY;@q@X?wXg|D0o~ Iy8RXZ6RFuk6FyS43h{&Lw*HSMd)h4b{Q+CO3OTh3JNjC%(9@8`zW)4pgw z5X?G45!dSuoSXLlncHDE;*z$+(fi8!Zu$$(^LjpwbCFa1KIct4sdkBTQ@=X P0lOq=6debWC1*XT~eXU`)y3 zJfX)OoSSuC&OKQOf^%cf;`-I?wBXP<9f B??-{6GmVez!ulW9|`qHqa5H zIw&+l))z7LOJ5$m%RheNd^Nu2awvF{ubd`59_R6$EB)mgd!}!0?Vy(1<4&Wp|NK?D zzhK v( z>UNv)gq}y@@l!Xeev@-g7J|S$fS%Vbn&19Enj8BJE?C@7`Hy36@2Ip})9-U`{7lY` zJ#+4!uIwtY2K`-rm)MeXDph?H$__af7d|WPkaK6DKTqtS?4QTa9q_HMoZOdc9*M^f zZgY=se6fp~*W&S0GQ&W*p3d?KEq2Lc`L*B8rvB(b%U&$;+q>BD(W%jewLUg^WR zxJ9LxbJ| 7wXqPx2Jv6b(>|KuWst_m{}Jt;(A?@bDE<2ks+1%{z>qao4j>;3fyh{;X2{hQi9270WV-Bn zALo Q+i09TR_4^9H88IJf%{Sp2nm+|A<~e>iyIXtX0E+r>aNA8z)8ac=gH6>*&|&W)c& z;-aOL-Zw@cqI?kSd?4e_zqKF2xScOz+>|euZ`OY~H{$~Lz*jry>oN5-c#SNt%B6b0 zE8`}Ac>LhQsy-%8$9~Em+Tw1$QQDh$(4QyoQ~foMPiH8 G`Rd2)iX2izZx zb&(U725(dQBy-=WaSG>&_5M6Csf3(>>K~miv7Q^45T82#K +q~@K+>Bd`xE`N!Zu}+Ay|f_|$yZp8Q}lXd(Kw}mcV4FKP#hF# zrvroSx9+gJtVc}`>2{uRSMN9G@tu%rpPg4<#{5hyCYpOof64t?wKJTj$0&Q_JT%jv zr%xy$f1>JN@;CmygQ_o$yPK%}OSx&PJ>i^wQtb)n>ARGkoad|6b2(34s`8C<@sX;J zoSXT>-~!ASjbGcAzZSm{O!;zd+5yg|4%YQZzL(_zoK5YL=NUz#KhM|u^X7s6+^n0s z$F+3Of@AB&f#)ba^*TG}raj@@=+C)n$J`Tk%Fx*r^)w(L<>$2jz`4-v8|TK(e`wA% zIJZy9#1H9I{nv0+uQ@mSqc}Hmh&E}Z-aEkuX+@qQ%)CL?-y*KQAbvJ~T av z<0y=o9*@y!dfv&5j~F-SZiw-~bmcd?yP= $b{N`E>BD*AYqg(& z^V~Pe-@v_T7-ybW>pqNmdIa~M%HQDJdC{LIKKGYn_A> zFH>zl7e~#%RsIJ^vC%$5c6TZpN*goB0;^FE`fHu?N<> zXKyY0_s;G0JSXE~vD#0_ K67^W0ggU*kOekm}bsPdumWoO64QX)Vr6I V0W8$8+$@7*=Ii%Z%1mkA?k#jSj zzi#_J*w6o`82$QQIj%J4yf_z!s`i$1bN-j}mbkK8x7Ypk)c#Zan2^f1z(nOIaBlLG zbF 5i&L>s9<~;eZKhF>ImqY6>_xcBsyJ3rlz$XK<>36Y5 z& h~*{))e zp*Rc2@ z?N7RwV!rvc>UuE;`#2CfN9z1%+&xU?509Um?9cP_m7m|d 2BY!E{(?g+krx~vysXEk5PdG1m*-^;mK z$Kl+p`*0rEN6lk%ZuVz#ZqCDUZudE?!M>}vE^c=R%K2+D`#^|sbIy@-yDx&pH~HgS zigqJH^{H*%?(mAs>=)%c_nvAGi@2-olXE++XYxb;QvSdv_w;X|b;IL{ua1<@bq`Sf z1LvZ@vQN&P%auQn+qMe(d~S#*_BvSlOQJ#f1Dv~is`-D;6G62;!nycV*#qan*VTFf z=eb`m@$5@*PS2=$63$J(?Cig^o>qJmcfKgx|IfKOFTlBoO_k5(+ Q zi+X&`xSdC3+`UJ&8`O0h&Twqf;qH|3@`VD=sD6|4CZX(&^YpF$JoKFIFW$fz)6gMp zx#x#;c=E@8rP?uKJg56j&btoPdb0Rt|EhcXp7qqZW1Mb0Qu=|mKV{tP1L5(_{RZN7 z>@%c6aq5uvL5Vw5`^mW(FK}+g7n}zNDSw7eg`RzPYG3lsA=1yJt@Qc` {4cdmE7k^5uFeM$M@oE!g~bK}o*Zv21FOU2I};s0DOZ3yD$o)>WTQ0@7F z-oEx^pZ1$4W8VitZeP{@b540>C!C8vD!bx5r`P2 #`~&UvDj^4mENe&VlB=k6u+ z-%j;MTu#&L$`0LMqQ6*2@nBHyH=>pY{dsVAWuH8L>L03}I;UXY=~|qLtyTN$f>eT^ z;m=c@{@mL0Ta)YQ^#|IM$2}qK)||%?jHmTJTh6_*L=YoeUdf6fm)7sL;uG2aH|zNp z&W&HqdFKM%zubsnP~$1ilhge<&GzS}{h>c!gZAfe%xeW?{+n{) z+}v-&x#<@;$Bj(hJh(_yR%AjGHqW}fcU0q`leUt6ei2`PrY{c-RsA@RzxKI+SC5P3 zufEq;j_vQp_pkTPe|3)a`Zu(bX1vL`9al2GXq4*TS8xAL2c-{eo6vfs%(vv7s$b^3 z^?v0)aGw6HKaZZK{97L1(-lFizvY8$@V$6;-Lc+W>V|!)oSXYnI5+pSaBkM+Q^89h zHx> cyt9^Z_=`ie+~f?r{7N8L|u{1eWNKf}54 ze>g7{-<;Rx@e{kK_WaRfu}>^Fu+4o-osVwaQSE2ue5AeygY&6-`o~Y)sQl{G@#v4w z9M%!oOxgiC6O_NfxqDrS_?P-~@tX3ZxEwRD%el#a&P&BN{y&dz#tWRwRztQM`cvUA zv?soyh&Mf={i} S^b(ZQeJ{e7noI+4seH;7jEPRxBNop?Oo|)HGJsck$$# z-fzKqO5X>_xjmmkkg;Gz8;xv}`q=X cITHUtqm@7cz{SL3oGwiD_x z)?4SP`pCKWH-w`2BBJFdCbv=kQ1sn5%Jns;L-z}e2Q&UWH^N^|*A(4u{NsRndj9(M z^!v}s{LF8o+YQDYJ&!?*hbCx0>Y6<}sP1B%D^%-HO|z67!8pxP`fzUU9cuZ 1Jel^7Z}w5p z%)h`lT+l`bu94+p&Sh}kwY@GE7T-%7f>^QhkD1&)7iXM9AD4chk w&u+_B-uFnOC*Pds<=p!lg7~@I -Z7rq$zM)WrRFE>jDGjo<@7Gb83=Zri}9{sDSv|)H}`;D z@#XrAc<}v9qTzm-pXS^#=Vl)%=iajsg#3TE|FxKP@Z*ofdeE^k@m+7Fr`eCnc#}T= zLW~CoYW*44k1Bd@DV}&s&m$!~za_Pl7GXXTA@`!5M`Apf_2-Ed{&LK7149nYruMDQ zrjA;r=HJvG1n1_yR?bVwN$#%8{aK7B=RXk_yKXDn+omDP-yp_A?`eBu+}x+p^ Xh>d(Kc1DIj2wM zyolgDbiZodO8(NC_PJ|`D z(d|6rW?vAGZ}czX`o6n0bJjMdo;o<2-hE%$FSs|UaSi8Y|2*eLKG7ApZ+suz70%v+ z^Z&S)MWR&xh|UW$xliBBe6sBV*`DN|RrQ5)lg~ZnKcxTG=&m{}n_3uA?X$lBhjY^R z1r>4iV8OZRFT|yu+?QH|n|&+goBoA!vp<&e)?-wC5i>CU55(j2cu3meNaF`G?%u8I zHRI8XwBN`$y|FcXV-n7~TRU1_8JHFKe=pl5bH1K)lg~ew8~;IkgMKG4x=rlq%>xmc z^CO&_^GckX{+)9>50HB?O1X~K(3`)I`D5>U;auM*gO0Btz8$|XZq8GWTyb_bIIC}V z>EA9^?V;Xp%(=;*QhdT6aIWF?TRJ{G_*p5(_>G*K`4G;{J=M-1KCc(IUe)0q|ElZ< z%{o5kX5F82vrm9?Gmhrm(c^B;-OJQE8t1|7)VdqziCy))J=5QLNUw*|(aZ6!o<~S5 z$8Y%0Lri~B$i+7PJdpO6lRQqf+q+C!*+`q5o5|1pqw-Jw^bcwOoVV!n&PCkZ%eVR^ zjD0U|qrOi|Kgz7H5#!OUp4VdB*vX>sXW8^Y2W3ZYrq)x89L~);Ea$<&y1rkA@ynuE zJxyMr#<@G{`p$UTtVb{&H0vOY8#{cm|EfkBxK%tfs7 7%-f zvZ)#GWLm}5vR<3~;oRuM`P6q+y2dB3Xk0fmm3`(AH4oo1SlKh@lzT @9i$W-Uo%k(ZfLiypGlivTv zx$!fbKD`s~J2 Ub2Bf&xv8g|dpaQqY~c6o0Df|(Jpb!K z1o2 H67R z-=D_goAn^hjr{*p?mbxdn(ha`haZ@Dy_MFe`H-%&bU)5Go$b#Zz0Z?aeB-ClX;)`* zE56B$yXaEcE}48t{O!7o`)*fe_#dw*;HkyeWW- zemZ3LgMlL)dOZPrhASbxx&6!lg_-yd>)&icWx-+x(w6WRT zpyvuWx&863s*f;M>_8o`0r$H6mw6uTa77q>#GTTgG5JQE>+^9%Tzx_Gl&^TIGAnLI zKmO41vVAtsUH8;3* qCfAHUANO8vSRck$!)#sU6~!f_^xbv%rTPN z_Gj1Qvf`9%cFA7PH+r(oeTIT@^W2_tcjv1++%HFDQv;8a&oy%Bf=fF>gZ9q4TNI{C zY=31(AT%N?>J>Nsm546rNS+ePro)AD#N696$(MU&U!!Xqv~2H}2>$KnjI*?Fw(F;s z0xtGhoJl;~JNw;UiW~nVx9c4lTK(_L7TexX5P#(9TW15iU=PKy7Z%vz&*i3{+qE z>-psa8e7iXC41xG&VuJ|G=D?+C(bjyu`m7Xw&3Mz-$inyUcX>Gf1+wnc>GSie$BZl z$JF0{Y)E~-P1e0|RDu3QT)$U>bK^I1ZscQxgZZ&0ygx39-!=%M<>&`Dho7)>#8TN0 zM!>GZJAM{-_aP8}1>$c7wnssH=Td6yT(^C8 0 rXSa2a(zxK;O^j~GU;1aXDW}MBDu+baoRB%cel>Wq6ITl{C#jn z2KJC{+6w;sc3Jn8Ss72oR#NM3oL5}!&uQ=wUpZJ%@z!mMUvqQbvxm=ZI_BbrXvMkNrfUYuenBM*{@C9aG=#pLn{E2zV9AaDmJ3|o(6YtZ z+0aJ;$;~{T8$PFj9yl-SzFi@?nV-ykxFC}|=gUmxQ)kL@G57TqbCsVzmz(id%X$B5 zNG#brE5;7j@|B!&ak}GA8F$gU8L{PJIiF_ypFk)4o44M{&|2KTxFLwZe(6l8@x2U< zyS;!1r$3lUZ}UM$jJr|tC1yV7B#a|gd=;ZNhRS-K*hBk!oc}_v3ovfZ=~rHGN@LTw z#%#-^rwhuFb2AUgxlV!*O()f-`i{ub2}fo(Bn$T?{&aeM;=&Qx;JsrcH~xkfzvZ Aka&HnLC z`!@gm ;H>(0PE${T{<-1NVk8$C;LcgdX{?)vI%ZqE~B{_97Ga`B@5sCFLX=e^gU^;LcT z@!-d@iC=D(bvv+s7NIGu%DtI!(O4nviu2By%HQMMq&Ilc){S)U-Py$YdD2b{U%N?V zV_>&CvMsOAm)!VKG Z3ofUxNMH{IiHVdL7Ws zVZT}EfVjI@&gYVQq4IAzCw(rJb91j3IZl)+pJ`2HPM7&+&aZJE`daVzVDW=jsq=9> zzN_zLqIJ)}udH7tPF^kLn|qu%PrRhhPqFx-(Vv@rZnR_u AO;vBtykI88^_i4~D%s(#09LxfYt1x40-iOP0QonBqH+mPuAJ$*{GmP7LY;k-m zH9d`U;v=PeJMYbSdXm <4y~?St7DUBsW&=R;Y1*PO>>+?-D&T88}D8NO<*%zty9k@L wt z_~t%yYP>&A3G7j*t&Mx-Ywkbi+!>+UXBI!VgH9Lc`W|L-kT(x{d7qR1wz;>NbJ|{) zFOUEG^(tMA+xv5ZHEkr$d6be{$oggb1;%YV&$zvBhjDW+Iz8|03%_+K<*^R$1$~b? z=ZSswK1LQ_Y@yqK#?3wL)UXh8mxjr~m<_?U8=RYVfOEah&gGbUGiW}}jkv3$RH4>E z%sm^N2N&q_W$|;@>HKHhmZNwgLiBYlx#!CIW$x=H#+%O4@)@_~&bYZpms+nwy}~<_ z=I$fy)7-nuxs%uJ0E=(?9mcJmv>WQxsM^uXRQqi14=2VG#ts>`>0;d6gG%E^#Yvo6 zM@|1!_NnhX<=px?EPndmI$ewhcToMlb8r6+qIGpNK;1J#`h8NIi@)jlY8Jm~#}aak zox?a`l~p?~e_7h6wOhu8u|vjfy eD2Si zE>r!Q`0*bd?r+}fSi9++a(vhMl4{R6ANjREU-YoQ9BYSSPAkp*Thy7Y{ABAFF>d`F z#;x5lp40D}b5FxL-nEVG;y`sif?iSn66dW6r9bCJ4$+!6n%{)?upcJv(8TAw;&Rj9 z6~=FgX+Mg|8Tq^#7jzvqFDshQYY?Me^4e=M`Omq@PtH^NJRRrGEZr{z7Qp_FUPhu> z+M%@{#;rXtPV@Zbm~{lI`KE)mU)! 0>wIS1_;19xEyu(^A@`(5@vadm-}*m{TYrXeTkecIYjpkkbXW&< z?cYYdv$CF=^Yz5ISY0B%K1a{v(;PK#*>dr_4epn}$k2oiX+P$@Z=C1;t?Z5S`Fg#c zbMt;=8u()yje4$?T4qc8xA$)|-gLGe?=T+J?^)(@a+9=OC00afPn-!}ukJZF`zMKU zddNS1a7#TtV)5@2>vhR0eJYe4Y#< |WvCguvF83JD zk$CoR(#yEb2gZeYUpeD8AD-F)cGG(q@?)dfjCDz9M3^NXx^jExYd*KreCUlip%k2AqWzGfS)rHzS`sXZNtWM{a!`tT!no3 z2>P#-`D5P0Sj0oudg&8Ie6o5!V-eTqBgFWMY;sUrgSh>#vLDwe5I>twcjR+R#V2aS zI1B6DbQgZxAU2kpdpK#`Bs_l;$gXblq`UgPkesKtRQD%v-g2zAA0|g@3O(CVu1V-W z8b3B{G#8ia`I%9@(6+6LQuCc&KGKSJv|q}&^Q=E#G235`u@kp;+eW$|&^Rx4M8W*+ z&*s{$czjz=9kdU$S)H?~^3%+{vc&k>9d!OPZtFGU8|HI_cQ5dR_`zHrb`}0p=L0eR ztv^o;(B;eGd$JHvPtS>vyC>4nPt~t7achTkAM9q|@VcXLUkie5ml(J04CB^rIoJ0* zplztbIOP$dx%iFUDEhsnoI978d|>hK_UE1~1Od6ITizV!%~HOk<=~^u{AyPn-H35C z1!egLKGXXQsgOs_d%ziYNBPS!_guLzd-t8~kG(k$%KDqu`Nnxb=L6?WQ&j$Nz9An5 zBVSzX|4Fm`KO4te^u7Aj>dj;9QAg?1W&03#QunirhaUIm&b$8H-VaG@+i2XYtu)Mg z4v~FtCgb!QV<(02^9}wyakMTM=U(^^upf7TtY7Z&S|7$m!k<$KIrbjQ)Gbk(|6G*r zSNF!)bTMxAWZYe^+YQD|`Q{_}O#a&k8gg$uBF8W099a=>R{dZRSAqoR=DZ>1z?S1o zA#CUaY5(SYBIk(~Jw9UbgOB)gbKfjgz8X(0|G4A%cMehgyWS^X#4Gjt1bKX|KaX$i zB>8K+AM=@3$`6wE*)>bs1LG^k_;YJlEWUl86!k;?tVR1UQsz(6oXciBXx{@~7@v+e z?L#4VtJSz5zu0SU=0$0!I`8kSQue@kYNv96O2;dyYNo*n9QHFYudd+ zE^aTuZ}R7XZ#1XM CY&dt6B zyp9C(3kNNukUS4bW}gG+Edf1VVDaf_J-+5#-vdv9=~xe1|0o4^lXh$Fjpv+>({fn+ z#4g(Z=Ul%hh;mg}Z@pw0{pDIY&tTpY&3RtW-*Vn*-s{cen0&^Ot#+DvL>mPTl=_?Z za~1Kgb$`m@oBZeT%{{&8`8#LD?vHewH-3t2m(0DsoSXgjoHy%z3!K|>%nxj%-Cl~) z^y{Vm=6-%++~zamw%i#v{b~O7mowrwdv(yaXGr@r_iS+P==mtlO}*pXjz^k)6QhCN z+16o7fBpV$V!Y)pZ9k0L@eAkrJ}B{EV?9-1Ed59y*>BQf)edtWJiY|i_t^0GY1@7d z!T4b<{QPn7M=&E$f}4CGDvTc}5#QFMytjVP9H!uh@O8TFXJFipXBoHkj&ZAxvvn&u z192{?57M#Wen`A9qJUdH8Mplf v!wlk7Kbf6ch z$BD<+^;A6I-7~xOGVIro_G#|zDdL}~`pdbg*PPq=WM?GuCAExxze?(F?iVG-(_d@- z8MpJ#j9WSG{maR@3HA3 lCVvXKxetVzMnUiPrFbuvv>$VS2 !Xzevfl= z?|l*1@2jGIZ@^E^)lqH&ej}m!-cinNdRcrYs`G(yTOTW2^ifw}-_aH_pKUwCc=9D( zUX0uN%eec!o)_)vYNHh1HP`$I>;n1ojvnuG{ttiNSwfC^Zx`M{7p2Ew FaL3z1lH(n7 zZ! RP#5__jSx;>{$+&Iz7`OX97`OJ^bqw?#5T;yK zmap9x%DCO<$#`OCoo|er`&w}hAHMdkk6ypbTYtd1OqbrL$GF|c$arE)V~2%u%ss}G z$9?(EkUIKA?Ju?IV%+M YB+ zdh5418tBi1?|rG$RTw`}f?GWY?t*rqJxptFl;s=PLi=xwyPNxSn=TeV@ubo7^a$EA zoQ+-~$IBbi#kkdz@pJv du_-1cjX2aMmlCelvp;LGN3 zk@;ip8zja@exdy+#zSxWb89E`6w39yaB!8<-_{Gpt(`M&?TT@0=c(y&s)TI!V%dM$ za{-*2eg2Hwdck<&?>b$5F&3fUVV&YQW&bAM7`OSrIGJ%A G3EyrQ+TL+x*$+Do5vXS^$?^MP?|w~Sjk z^gt^uIJ%7 0ysrbnmOJCN92pPppr6aQ z$m{*O&9}oYF&+;bAmz8jbpOJ*TUCOWkYmpe(hr!6x)%Fhj+f;dvi?aSPg*~!kcZ|Q z|ABEM$JrxFJ3bdpovO}H34Px_G45=o^MP^uT*gD@ykQI8bNBSJxbw+dvVE}g35?tM z2gdEZ4dbNe>zs?v!TWsOxH}2&pFuF|bex-c9?s2kIXCYwAn_^AX5G>zPJOx6lW*R4 zP{a>6etu#6z!AoN3b`5Yi~I4uy3Dol+$9$({q;I&5nrzA7w2Z(fphb|d)#TgoF=b{ zx>u|A-@Lb-^W@ihJ(|T&-(&pwLODs}U(q1U$L_jJeBCMYCvW^K#zTi2J1mSJ7@_?u z7T>G~rS|&-_ozSCKKCs3zGky8j&rk*j&rkq#JSZoaXjknZjVyx5!F5$KZ Fo9y<^;# `F!&}JI(`J>wIJJL%nppX58-oPk45-Kjy2~$o4s()bSao z3I5!k7hv&or>ge{Q66(A&0gJl2mJuT>Ha);NC|#$2_84~@hgnKPQkvlk<$K~O7P&W zCF0llbF1gNuhBo=SV!N#t^D)zo>Su>#_2h&C*w9 !9y0E3r}KgF+*kf`QXxGaY 4skQi$WDD&+DYfWdVdAuQ%i6f z8b>|BdIXDa?)MfyEvR??g|X21Wm11LKU2gXllx+D9~6s!p7tLYH|M0t`AchXDSU(` z_~KqL=Q21q=PVdE=c>3I^L}J {ri*i U-~YpT!mKwj zIm!MyKTpEFnc@|kbN^E2k1*o}#&d`1ewJ~U{N>nt*X4Z3ndo0$i+Igji}BMK&mE!t zG{ysMx; zXmy>o8%u`}*A`^#}>X#Kr&(YInAwO+l4(e86*Jb9>pe7m2S#kcD$0j#6F z3m?;YqSdpXrWbX38K<@WJo%x{Hx_^Xm8x8v4|>;A)8=vdtC0EM^1Mnf=k$~6$2qs> zd7bofa{Df$pgPCxn(;W}!DDs#GH%cRGVVO6^S_}#{Ne2*)O@8Z$3 T
U=fWN)SM4jHkd9A< zTnzE&EqnNLI#F{c7o{cM9;id5KakV!2O-8&Cun^b4~_MglQ=>1PY!FRMem}%FPHgj z)5W;elkvo8e>p8-t Z$#axO2t}GM`(`x*p?sXG?G0RS@IBPyepQ(fYh7qIhRV z$*!9-Zr8yX?;K&)RY{&ZGIH!aZ^=n*lz9Pdo+Itq<`3s4y^P!Y-xzPz?_ wRnV3i|uuVWPbs^71G5mR_e|+ O^tX9)@DBE_p?~>ay$6{X@7zwGYhc{{ z_FH8SjGO)8@(w}@)wmh&87O7*-eK=Cc_7{N<$kn08<<)OD<* zZRwrSMgAMV$SLI3&tbgfd(+Mo#<%ZNPW6q^uoq)XZtU-s6WRAKGv4$IEr)SBLFXsq zLf_AfyC0A*t;^is-74Fw4eMxy+`ZV;mqH#qNw@z@4lULCbPmCOyuY{QcT?vM()vAI z#CYf-ttaC-*I!QVJ?$?gZbkcoeW7%;)ZckT*GI ;9Zp`t!W$XPF%HUYqpx>l-?M-9Ot}bws0AzGhy9b8}w}=PggE@hRsySL-wU z_sD cLTli8QuZhSJmHIwZE~5?>W^szH|FF zzT6G_$2a>hx%|ZEy4@2u*We66^jAmhBj+urzU$BJy$~$Ey-$E~dp`r?>G`^SVBEGF zN$l}C^@aA_MSIG9P_`XrylDq5hw X!DkS=C>Nx)OZ6%6}fesY2J& z>tk_B4~ !pAYW#W5y#JcXvHRN@xBK}SZyK!RpZ-Ot!#gu{{kiB55juBQ z{U+yuss22*mA@RjezeEp4q9+soIYui>9y-wjN5$zoSX3@<958vxLtQ+Ja?#SKU06k zdUo*GcyMp%g<$*;&dq*%&dvUO&eNy)%QyD}i&IhFxqD-D(ro$Mq@F+Iyi?C7aBk*F zIJbW6i+AF^%)vPIRr{i?f6lnQ@0W4w?=f!uVaDk%s$URSUf)4GE^4Rm+ok>Fu2uaA z=Ph^pb7!T$oYehloucWZXX|N1Chl&6^G^u5Vg5Yfs`U#V-^}lcy+6Tyr`N~n>uaQ* zW zlzlaQ}Gz@>u>e zlrw_4*NbzrF3C9!QTvDzCp=wG(bl%XXQ=kjZBqHkd2XOuPvJaur+<8Ry1#tqHdQWM zPOwJBPmO%9o-Vk%J#@Bgf5{!F{OTe;-=EVue>uS^N`L2;$_$-e+d=cyJ|Fi`)t_?S zS>w-hyZg&A_glJOKZ|v`f3yudLFK2pFSLm3eO#QI{bQV){dLg;4$e^J_c0o`O8F0Z zpBU$6KP2Y~y??TZ>wTe|Z`hYx@hG+2-1gb=N6CJ3!#K2%+x^>A$nCy##?8L{iZ9Tg zR(#f$yz*sLFZ4ct&dqrZ&dvD_&ds?P&h7c8riU gDK{+?~a29cWZzSht|0?HZzbNOyerkTz znes#jC40ql@1 {seM!C-Y3q@d2`Oq`D@NQ_5EX<=UhFG+Y#gcmh0R0PxY7m zti898aeEIT Ej4MplyB~R<=os8%elEH zpL6?u4e>>o@?W Xf^NmyInrU`0n%eVP8Kl?;)&wL)~k{dGm|PU*$ZZ??2%@x23YHb@`ne z>FlYQWaghTe>%@mayX}t)p{l8`AOOipT~M)=iC^bKSqwH$gHO`KL1qz_<@uC`P33T zbgYWsb;0OHcWg)Ii!J*oJJ;)yMO?1~a&GQ5;@sTh#Ch_1l@FW;_4_6SVZOuJCq`qA zlKEiX)4{n}ALrccH{jf?(12 z(>%Qd-GF@#Crz)Xp#hl>?zjG&rl@%>9zVB(%D3jfhBLHoW_#kplcb&Jc2()+JT<_d zJMa7R)XQog;Fs?%sHgL8X&<)k5Sb6DSJnPW&K>uEv354#R!!UgAE=xNr#E#Y)>Y_s zy=>{_?7h#)l92aZLfo(sLUQt&d&5*AgpDo-#dal0*y!c#m%~B`$&ru>%X{K-E^$Nn zk3Hucv)}pd)&KcD&;P%k$KyU9^NzjFTyxDe=a^%B#}@clW5*x5AgRXOSfn@3*3Tt- z%4@nGkgMmT+b{jQ*^dY7Ch-4nr~IfV&3s!GMDx`7(OmqlXeYhKycfvDAMXFcdGuo% z3fbMh)Auj_XXI+K`Ca7RhjzaPcEsO{?P;3npY#hIYRS8)=zlO&|8DvY(?7`7OIzRr z%>ASrdEGR3Q-U^3*7Hwj&+C!LmYVxSo^6WevQD1p^ZI#@^$G8}b;a^~*ZhNNk6g}Q zkY}%sZZGR?Y_Dv7`pfrDYf8`hPieu``)Pl8X!TB!b8VXP_*KZgHfFv;p1sWU+o}_< zFVfoa1$EYP-TySte1DOv7ovG^ceI`C)26-J FzP|D$L- z;wNl=j`xi#RwPsxbN(ymo5+>*cOe(QBJ%pJOuwnK-%8T_OA^_R`aUSdT7u<%Mn17a zbbH^6Ztvop(;Vy9z~>QKhl%I&r0E9&?&8LQrzCD1xQhdSIFnEd?@4l958eNs#IYln zxOd<#ZvW{)Me1;1qR(Bn4y?rC1J89f>nH*q`^-E? oinLv0BIuRT<6ra#kc(~r za?#~L-fVR$kc%Emu>D~6|MyI^6n56XEBYJAMUMix==LBNy(8pKhbmpxM;JSB T Yt;uNsqf@O z`c?CMogNo(r+ WT=VAG_|Q*{5E=3KV${}ZQnj}(LNawS@RS^0a(2l=;`;}KK^*Z* *$<# z(}u7AY3x{?-U@E*{I9vqzX&?Lp7h^-r$pI;eou`VQWf0hH6WLG`++BB>-@zJHPsZ} z*6TEhlSeLb 6rk3MA_|5;r#^(cf^+|!ddZxg|AMOuZ zRiv-$ioq9V{U-h~ M2$73JJTBULQJr#cl0e5}|;NmC2_EN7lbtHc` zPy8g|-}GUz{Cp*DAGxe2k;}Rfxt!-7^&ab{9kz2aHL0_i2QD-F6yy>Ii(Jlsk*iy~ zmft58E;xwycYTv8Ju6YZ|KK&_2S85Y7WmK6c4&?EL#x^KcP44CUlaZaeLh67@#g-K zR}YEi-UC~(WBqJu{Q*Uq-;kg)*yqBRtlyB!dJnne3m}*Hlkf{Zck^y7Oxx)d-T&f; zL@s_y y53x zM-|+DzmSW+w}QWF*S(qYIcsl@JDtyQXS`lL!k!BN7k@7S7ymHwu#5KVt4{4tdUkZj zeV=WZ(x~TcRU6GSr<>o!_7bO*J$zPyI*ce>x|W|OU*b xH}&K?&9KrXKcL&|Id8B z_}|@=>aa#Vk2Swx<`d-Mf1-JANi>hmj^-}D?iSXyo4a43d3aC#ce!&w;O^WIxcH?B zxSaO|{kJL7>T3%V2kfEki@zPY__2}8?;@A)TA$%RlxR*a;mv116JP!|<{SZe&2qDD zK`!S7$ldd5Sj_pPk0lxg7=L^A^`G^3hk%E>+IVK*F76Sy#OL(illP5n8WO=g_Pg^X z@!`lNUK+W?^B|WvoK =(``%GKlhiURk-K0k z-9KUnx%jt{OT8ZCa-V7@pTA~$6tc(9)Auj&)yO5Dyn -!f!JaYM6 b;<*&>+sc<+S0k5oIC8m9 v=3(X2uWl^u^KK z?;dSO&YPD1>5(LT^IgKfu6;@0r_B#SPIiBXT+XMEH+*mU?f41HYiTX#G>5D`!B^PM zoNFM@{1V-M<8bqR$M%v(>81N}-07o ^}2+b00oZqWvyU zF1_PdZ9n|l+$Zw-6U==gZ)u3OBl%p(UstmJ*hvZh-JBjL5_gAO;^>e|oO$s0hXq<% zn@IPYrR_+(A99HgL@sgZ$VK;HSeq+r>0iGT=t1MR6h9Sm@oOO$-H9#n;oE#zM{BMv z{p-o8x}VAFT~u(ZkAYn76S>!IL;3wybncZ&nlnAo`>H)_%i}OR-M**5X?QfxzG%KL zXh*&aUT0qK_2c}A+c+ }qo^iCoSfE4Z!St$KIkdhRzT z(nma^$Ft~nA(wMT +~u>>@wxAYg$Z>v@4xwS`f0$OJ{xeC{{md{R`z`UM~=Ux ze0qCxo+$cq72N7 Fy&&40d z>x}PbCTJY{S^1K4N#t^liCprSkc*CM^+mi+YUz}(`d1r0pGZ6>a?y`PE`Ds}qW7!5 zoWN`6ui~Q~H0ysC?+x6=hXWTqWV9ok_P)1BjbjVp+Z@Nlmz;+pm-AEPa-YcMKK;k} zd$v#8Voq_M3SVLext!Y~cjpLTNA5GX@~$HJojBf}<1F}+b6DhZZi`&b1(1uLfAG}w zBCWqJ5k7H^w(rhcfxGir;PPD1j@RFwzwEUe>rVfer`sM&==+yELF5NSx6jEr4zv%p zz+?MI+X-q7U!%G &POFkEJ$p<;Fp5vTqyhPyf zcb+ea&qprt{KzGL1i94F>wgC4PmS(Th;@Bd+n3+1;5KgsxzydO;8G86;k5}`_i0@H z@~G~A*U!ME-w3#zrz4km;O2*x)ivLJbW`e+UgrMod20nPcOFj%$elkK?btZv*d6E8 zWj}nb <$QTo-=>1wI>pH4K9L8*&G=96IEC{HPma@vCJrz*){GzI*>j`0)Q`sY zk_R0u %65pbLOFRs6$%{cQ`J4XxTNjBnWV8K^eaV+WE_RShz9(|Y z7t5xfWo?gQJQ#7K?tjVqKrVSA$mP3+ylR8ae^P$$&x`cjVZ~tnWNlx57r8r^hxRSS zXghMwuFklI&+A{v*Br0?_$)JJ<2He(E;suZY%lqk$R*A^y%YOc{8cs6h8g=}2f6%i z1^?Rk`H{=-dJ}kmwDO>WKTYrRNq!f(oZlgrbt7`gi)r4oy1X7sWY+f5>q$B9LoV_2 z$R&>kxjdK4?`vP8jo;-nb4)&(#9bhlbu4ljC&(qPqq_4aMQZbMq5izB^!>}a4!Oi> zAb0Czup{emZ|37As;^5d>9Cz%pGZCW3U0p($VI=dg4=z>{WtQw+ (%MJ{>*$R(d5?A)V7fB#D|tTOve*;gW$I2q)Ue}P 4J$<3rl-_;Zn(pUSW6wzvLnO1?=2xA`f^C0+%&=tTsFj^eo4 znQ^bg`xU+<&KbG*H;{|I#FjW~BF1THE*@OiOWSvGM8G9a3fqhS5V^$vgun7WsD4~N zwSJ|xFY(yOU+B4`c%OS_qH5KL#=g~i_mSH;aOBR91ntHD6YM#-NL42% z=t*ne`lFDG{|dQ$-;tM}C0|Mf?K#f>pc0*F@~T9~xPot~{g(K86UWl#820CS2NhJ$ zSxMdW0kbYbp1UrZXI4ks5r1#?it;}C=6L$Q?C;@A;>3{4b3`uV9C@~ b>&00`LF$%FZ(Ok^4_Y^ZH&! z4+q;zy-|M*&v$cI$EoogJui8-em8Q_#X_F3bxV;;eg|^N6G0xEYR(bV!`~EW! aK~$aB=QS}envd-m&9jF_bBXu!{^0dx zcub uoLg0Jt5<`(<$mM$n0C#e zBpo>=p>E0Q_oezk^L`=Ewu|O+KD9A(agrMUlkh& q9Q*j}=_z zH?ZSfXwHv@-qVlQ;XPPmqO6C_*DYo}j68E)G!JsocBDRR_LT(3A#iN^?&f <4o$jC^yvee3p{ O_F#Smr4=nMA$R%D8xx^J$a8K8dQnZY9bUzzZ znETsE{d`?qF>n`$4BY8c0dJ``>lRu!yh!^!Qt&(8V*0 K>BoNo_Ch#r!8os?aRIcxty~jm-t)c;@_Y@ z^)Av2*Ctd$xn2ZcqUVoX>Jb2!^Ix |0s@L=|ar+6gu0t+)RmjQu zw~?p!G2b@Hw>}sv>B|qu8!kp`=#!mVXxV7 z4qWms3HZb#qwVA_HS;7#!g0<-EXOl*tbG5Q>!`No;;+N@;@?AFE&9E_&ugpB1H<%N zdVGdgT7M35s}D)QW&MnNv)*#`K+gMMo#Bak{g!^(#EtV`(u#}!5V`mpk!OaO{WXoc zJx|kLYoyc!egA4)G|yR`B5W_ZM#$^soGy5h`{%2Lq<+*o$*z6}aQD6gmvb=!F8aU} zl h)(}^@J<9&9_1>{;mox{V?fx*2R6Nk=F4Vu{{32x4LA&MJI}oOTPhk zbzNyY?w8-6Cc2*gVF!%Vdj&3jR01w}_Z3|3v-_KIs^a<%Gq|pD`TEt~KXCEe6L9x; z0rzXhmcLhu4$l{;eoZ5dK1$p7pX(aQ#XpJdB`z0v`c3=(`p4Ih8qM_tdvdKEj@x-A znv1`hpuPB|k-K$lJ=byf*YIyVt>?FizuEOIaF;g<+^u_odr}X#wqJo(asO0*s^2g7 zcL8_z30(Z%1l*02iSNewnblC{;CQ)zl;|M<7k@hecjF59()Wzc7)`vPKr>c0(pg{W z@gI|XG~h1347li(p&eJhBk*cy+-o&--J81qUB3Z${Qz9f3kZ0&v;8i#G{$Ko_sz pgmD|DwvAoy^>MgkHzy2H9~AoccxcT#slw9@&0qK0ME2rZtrPQLody zDm&hg|Ngz{H{_B>0NmBT_TS_2H^cp&|6nu^e~Gq}vHDc(x!`lwY(KM3 U!t@-A<8?AZv>}WggdrgP)I_-c(ojRNNQWdw~ci?iKNWk6q9k`osIar10 zSYF32;dLv2r<|XsHFthXXz%7{;A)V)&!8LkOVz-dj@#(@Ve|U1HQ&76Yt5ZrAJ|F7 z#SeBr*EOEXf5Q$s|I7Pb{9vuQ=%|ot&0V}7@a*39dlA0J_rH|K&^+BgDOo=Nmvc$h zQEJs*&aIHgzLNbyM;soweq-5wY^a^DfM*Yn<~6@W+i~})p5Xib zZlM}KT+cr#(KQ9`&ZB|Lxi**0YGp_Lba;6@s#5Q6P4wo8rSneyv8jCj4cm0pe;4v$ zE6n~2xzkfsJM(i-E>gWm= *g9CT|1mF$F*nX>C&HcNC$M|sl9Njt)xLel& z7aaovzPS!KEui47n(*HjnD_Jt`@7Vd%eg#vRjc-Lj*ndY0JAsUP*SgUD@|Q8PWQ9; z4Umhz6LP2L0CwE_= Y5Z?@ssC5* zO*Q-6bm`98;FPW 9dm9qEst@TIVsK0~Fv&=dc zx#;a6C#%ncJnQDM>c!NjJV(Bv-_umRy&u(@JH0aCPX8P@b+vY;mG`l~44@pJ{qPn0 zn~BRJ;B-nfZ|)pzNBV&kjvFcaF5f@ X?yvydSw**E!8e z-5KEO78AE-VoWx-m-sQ{p1h}O0I%hTE~Ms%^!;ysF0J|Ies0Y-uftpOmh;W}=img# zP1W~^SGVPOOumAv%{)`V$D8{{?))~2`!`koR`|TP=jZ6YYrw5e8Ve(|YA@%5$eaIW z{V=gZ`TR>QqV%ukIgYf?9eB%#Xr4PG+D_Qh`YW=}vE4Qc`8n!w9{yzO9s+mzQNZ1K zG4S9&YwUVy$MSb*;k2vRe^%}vsWVHhxzi~E?sTYtySlomMU6D=ef}Ft<~_A>m;}6f zSKB|pT^(NF&DY!S(b!Y?{T#Efoa<7)|3KDJz}@*caHlH;yljgv^*dHqj4%FKya> z>%nD^`pS$q 2`G;KeK+wTH!i5Df{qC<|{>$t7)52z(P z4zK7>0k0GJ3On0%1#ro?BH)sbhCKC@JumYX@c1~9&oP&m$2+<41Kf=V;Gz#k$i>gx zyn>%=J=Y`V`Wt)&zI`shCGUWMOWg sI?n|>FmDsTP-{MS3!FMf z+ey7)`-heeqQ;~0RfqO0&kN-0*8_L)B*0x92=LS_yKbp@Jx@yyNYV#g^?dHli{_&L zK+s-vK`Xet?`lWxpGOvrzH^D*cev*c+&xF&ZhipX@{ygN8yey?;{o K(iv%e~Ka zLe0Lu{s()Xz~??@#}#mQKd0`>c~x)cX^n}8lsd%(Ty*e|yZeXsnGNEPeT3i7EBSkR zlkVrtarXXIYo6Ky&$#%;*6rPWQhFd~z3{rIk6!;bUt;Y8ckw^K-QNYAu079uPt|L2 z>b;!z?{oBXbpCDN&R-4O)sX=n>~HV0YDk=xjp8-OHay?(JSOu4@Ic;o;MMy@+i~B0 zzh9hGjQf8#Z9lBG^B8c6hv#KgtM+c40NlmZgoF7U>UDlst91XQ?O!;1Y*V$R!R3 zxI6Ed$$7i0*hfC ;Q0q*)CV84AMuMvY+^!UtnwdZKSB`<)0yM6=i z`a!+OeZxAj-g^Ew&oejJbq;WsXARu-8}RBqt)G)PKdbv&jTCFv&o^!B-4JqHUj{jK ziMHeV;S{dNka@L+R@LeCq^nmBT=F0Yxa&9I)XDZUeZueW;q2c&M1RM w)l{I8EiVde8XJz2kJ;t|H)4 z?+LkECqVn`m(~v-4CC*`DFggnc#QJp{nb7%;G(z2g~D6652Nj5Pq*)>@%5?ir#E zycS`v*hGn!Yt2P3l%T!D_ab-w5DduE(eXmKV7Tso7v}(6@<0i=>o?$=;~rNmqE0j8 zlr`~+?zvNIF8MgTKX283bDU&r?vJ+T=E220AFgHpRd@4#-L=$w7l4aCDghTgRph}n z)=v5t?*9W8((L7We)DaeDFQBa!H`S+FXX}Aat^|}1esZJS~pO?ziwRlt+^-T1i0h} z5pZ{(^a9_19iJnQUR)kOo8N2T5+?)g-QNYAVs?EycQD_3`3$VQ9%N6Stw&G5rOpv@ z$%8}g{YmDZwT-lLW t8j`ms)etrzPN$FMvEP P2gwDSNcc0z6I{`p@6%5BH+Otc6?^<;aIl!YqGboo-tqU zy+CgDcnP`H@2%k1S^LY*OVFh&6677K@8A6{aM1xK;8M2^`9_KR^0#lKeU8ZIW*c3X zK8xkOXw5};m!Q4q2_siu*nSS~Xr!^D oMRiuMN1%UjshY*0bZ9u{FHT zuSpFy`E)IEUJqRKim|=u5+irxJllrzSw5|y&z?5VSDp)S*U!M+djVW^vwqYue@@V( zBl48GS j&h=McZ-j(H`wMo|e~! zV>9Ocdfxh1fxEmy;O@NxKJi<-Ury(0Xvym}6l<&dXIdwFKfpyVnt)6GQ3aR#RJ`ws zy_;7_;|~lj6hBOBE_sdw?cLu6+`UI5?oUvL_tBqq*W-s4*n9!tF8>I)d+&g^{33pg zMT@AEif4~AI)32=;@@t~CGV2+;##$rJWb@A Ux7zHB_(&Og9i{ulCIwm*T_Z!7!UdX68s_drr_nf0@L z7pOIN^E_~uX9~Po&Ut%Z&$>yU*U-jlegED_d;h>i$D4pVy>Z|zH< Eyl5fi^^;Ydgha9>4UWA-)xvqS!p?ELEp2xlI^9Ano?tr`R z3vk-Su5;2KHB# e&*I(^mz!{i@p%@pp&(uRxYM>@6=>U{0z$d)5ZQS zaLF$w;F6Dwy!lf*4`d(UzBz>7)&AOk%d>X=1TJ}_1YC6Kk*D9can7qaj(I4@q+WWA z9)~UWSo^?pGopF=)o45JeHnFOp2C+JNu9)h2ggwiwev7=(Y+_&?)?Jp-(=QN!M?2L zALD&`?$$)vet4Z($08T~dE`>Z7J0CZeZTfr90SF%y50`jzI!i#yKxTO``z{%aJ8GP z!$aPGW}l&dn(^b#L8vu%=NiC8Cz=29R(4XK+q_YFbTQ?YH>$oSPLDjJV^6>(9~`;l zk0Z}*W&W;Ua{F5P?ewJjfc*`81t**FfIR(}nKzKDTkU#yDr+nq|8;`qa%?4E@_Y%n zJTK%@cc6klW%T@sx(uRpbB$U*T+fqg*28wc)0#`3JGPg+c;srV-7nMk{ElwL`@!S% z_sIQSz} Y>qNJkKgSvJ$UZON)yt!~7qjC8+WUK0p6QaO`IHC}W*%^URN&4p3f$`$ZAZq5x_`SQ zt$%}kM$^qaY2ORvGR~39xT@g$+uu#|x#vobC(M4W=La`G19$T+a3y{r;GyUP`!V(( zE*_{9`!xCTt`vVlYrg8LXkIUR!eA%pFZ0Y!{QW+3K=_H7=hJRpYRxy#Gp)JQ0pVKo zt?aZMX8WiAOFTcs2eKYUzI^{#@s|RR_1Z#vtCvpDJ`lf(`h77iSk;(qGWVbAVb^KE zV_V?4|JZ(m_7X4s`os6thG*VcTHfn59WO2M&&VZS7rE$fAm9AGdvXxfzuTy`HtS?J z?@? 96qZ*9%JHnJ~n%^SpTMmI0! z6ov&fqFLK-tg-t<;2XO|^YDmh?)rJuF?m|`b|ZP8X#3$=cAp4bbZH2 UuW!K``81~ zJl)ys*J5i2lt@iUG+($}-+y?tS+64Zx< 1)0_sweAf(ZU+l-k#U^(LDW&@iSxl zY!~w!t2gp~)bEg>MXbBeSMZ~G-;rk$(e3G~Xdc-1YV`H2Gd3$hJDdFCn6;1G-__Vb z9@=<0 SK2sp|RE-*D&ov}} z0eE_MyB+}U&QFmm>jyZWeSzmRB+}O$tLMYuBfEbA9v(Ee{C6k w4Lz4Xdb)Po{vEL>X)N=Zkd^%*Ub2% z$az=^dU;oEzv1X;UVm{kZysiNx|#hzCsWev$vR 8(uOAM)Uc)sgM}&e83&HlFSBo~++Jit9bSZFGRsU5wuw zxw7#;$T!+N(4T+rS4Xc7D^6;EuUXG5GS3ltaGZJHkx!gp=aaK}|K_tVtnKk;9ez nm!$E0M%a&i7JTJ8 zn7<2oa7{F)tE0KsWefZ};|EhQRirm36obQ9PnR$M5>qb~x!N|meeO2XKf!s~WN^{2 zQccI*^nSehLYwylT>WJ32itGSPRiC1!1loyW2f `u<@A fdF$nEOXwO{PDQ`+c{-P5l-%w|;ra|KpreSifBNbDw(C56E*_ z^IjvT{U6tV7ri ^RRv@+z%Ce#iNn!hpn)G@4qjuQwNqxWB0mL-%tI& zqxsm+x|ILBnhWjco*&(wcC|VlSDo8LH@B3g_W8|>tF@**0dILFx_#q2M&In#E6!`m z9`Hyh?DH>eXW}f=9{I5MjeX=~^P0P4+n1 lC1!%)!y^gI~>fqdd<)bJiy4 z*r|o`*m3@9;F-6h+o!GmKQ;cr`C_Z{*>Cv!z?aM80N!${y&vFotmSE5uh*<#jY|_R z=ShAga9`{IcX<=%U&!^yIEUw^f%<+_owX0# icndQou8>MYpHtEH9=K zRGMF)#YdXIYhg5Zc}&ng_D|dXBhERaRg2ZSl(xh9NP4~^;7+d snhxQxH^-v}k)W6p0`w7pB=Kg3o7iir+8#CwlVO!=`a~wjK+x7b; z`f|wAyF|ASPBivcJ-ILYg?`P`G@cjvlDG)uYBzJA$X$HSg-epup8I&$6^XK)@D2NS zA-8d21U!~7`z$r`v?LwYk!vPhtN$+10YFZ-M7Q^!GV262{P85M`aZ$)kM3v5$44I6 ze0JpNAI*0SdF;Q@oF+v7Zun(1m;8F)=lF$SN *t!k zm!^&=(9`1!)bdk#9Y!e?&7Gbzw0HX34K+MZvQKX1O#OGc^LOA?wtgr97ag|DA9YP( z%agT3kDspB)uL~PJadfEJwq-!S6!M|x2w>x80>SdUXP^)nEpYYv%25NMOOj2=w!Cc z{G~(>Hx<*bx6}KG;1sj3L0&&BnyZQCez3jhcQsDGu*o~GvG&7{cGdPphZA}Dt+9i= zdA#vsAP>*9-*LZKLoFxAX^zPg&mI%aojxSAA2!~$5AI-1`gw7hkkZfH 1=# zyS!lFP7f+Kgy-K^2GI=G>*C83JHY7*dq2RP-Vt!8cQl0kQ66hIgj;F*8!xwZfY*y| z67VX~Ap!36g48J1uvuC|V@yBO#nwJ>7OFDq0pLzor~U*!8=qC6yO-$s$LZn%cRHoO z)4rL<=$8peHDXFJSjc__z9g;>dC=R=KhQp#GUqShb@P(ceOaFNGjW>|7mZxweo}uG=y;Pjk)umd=^>$YbNp--TS_ zyO6v1uJ8E!GLOHdtIspz|2TU-1>CzYn!ETeXz${?PV1MX1#1gxZk3+rGY?ohz&$w^ z171JIv_EWjKCj50l&5;unC2_@l<5cL5|@Qs;*``Ae ZjM>cBlkay=D`-) zX9h&K_xnZj<`?YWJL$y)t>iWPiYEPcwfN?ooq)S|1K^^^68mgGDfnP?ZMZR}zf;vV z-vs$E>wiNodNs&1pPGGr1 97aeH_^AxBzsR@tiSJ~LxOzi-01eApM&jHF}l6z zQDFPrHr8)BqbHwxE{oIe9P?4W{xIKt0`7D?fIIz!`Rw!9v`2w<_(i{8PWKGB%QFQo zdN{!;JZ@8?3$$Z{e&0i@pN3p?U69LrP2J1>$j27as@Zyds3gu1IQ?PgVc?>#5**C? z`uTrN`e&K-vzIXKk=Kuo=H4)K-r*0tzNkK*mZT@2)&1 bV9tA=_Ts%R-)ziFG}Ud9<(>(2YIs{&&YG1n0-?a zjIO1Ne<(G-`---s_A`D( 4!|W@O ziw<)IxAloqceJhZj=QOrrarIVcfXDC=OC}in{k4C<3(njKk7AAN1b0v)_;@M_gQs| z*~cMIU2paa$eZ6Z`^3~Km+{~FN^*~jw|lnyTpG#PLB8tMYQ0{q;BVUd1UuPIc73~k zE8dH ecT9&uW1?EWk0gF+;K6WfA9z;c+kt!AZ=t=7V^@Eh%=#f~^DJer z|6ciB `_a7RQNx2I|6Q5u3bZGm^YE2 ^E9A6SG!HhIJjaUm>!P{e-PloITv4PQMkZ6I zb~fuGTUQ9V+GOk?_qrKBJaVb4l3AWB(ulLT2K<}mIZiNsb>y@rng=@?``AAFqPZXB z-UG%C&6-%G>30`t_a*vw(;K3B_(L>T=R|YrVD1O)ds9t&ReY$(BK`&cAErOE-J*GT zi0wCM?;U9S8903&&AqdY{a5n5-f8A@JvCd$--iD&&lkB@72Q7lp0V$5;Qi$iJ_q@L z&p-JJZC(s=ugTa!E_uqxrT#K Dw0*>T~0N%bafPBbWM0$g{Ry!>D<8Hu)R3 ztyA5q_1`7>y~wlY8vDq@F6_rC&jVm5X8rTQKbMsJp%>Nm-HGE($_>-T4sxmYgk04c z`^a7Wk#H018?#2Y#~O}&xq3subEE7!0r<4jEcYHL`&S#Oo%!y&x&XkZNqqs}DOryJ zcXbES2ghmR!+AQ>_=lbDJ@D$&?fn3E`uQt4e;|82pKJ5kHeXI39{5 4k$ YX0b?_=|UX5U@G--zbH5r+Hsv;Xtu z_DMRz)U|I(Msvwu#`fWVqT5Rzbo$UtlA52dp*F|r`; ?2RTYIt@Z?ziWM7wP!t&Aeyx?~rFNi*DcigXsrsAKo6_-qn?U zB9^3(&jj{0@c`L&cHIKp _v1g1pnrBr(jndT?{3zeYt5? JMZ4>@3^ )J=P0{8n}J&S`bQq?5IuO6q4Jr@f6I33*s!{8#Gk zbCR^SbCJHdQ{QLvXEvS$`QFj(rCtWwkvbIq*L*J7Zhb=a>usJ(&e*TuV~u^}^}V8b zX0n+dx_^9aUHIK8O)FOXSNB7@X!;F#?qkyr$eq4)_1Ji7<%W{~uZ#3PtGV9JGr-f^ z8ox9Fud#9XG_qfT8aWpCy5ke&dBf@C1CM!joddl71an@KJ#WtvwK+L)R=bDF?;&j* z9?eA`9^22g=R3&5ukE-RH7B2bbZ6f8P1kuDzKyFV;0@nLx9@(uz5i^H|NkE@q8|pC zzgP4Rkz0Qn0hf64l`pqzYVO~rsp_<|^g7wMan#5qUK+W?pCfm9UaL4p!@q{LK3NNx zFNyOf;F1@B+~u7?`>K&
{!OvFO+0+2i;1H~Uj3pOx5yj1n)w#F 2zkV{@wX1d4k)qQcb;6{D_l0Su9@~x0do)>a+`y3BnH6`iIyr!gvn049~xy03D zdoNy7?uQCHHlNWyjr)B`$Alm3s>iwHD +*^_0QV$ zi0?{?GneV_h~%MEaGSS+T=Kt=OFq{D$30o6KEANj<;Gi$eQT$J+q@OzlK+KVe)r~0 z+t&G~zE;XTdYrZ|zl&V*zmQ9w8uD^q^QC+`w60;m?QDCLuDe9z|5@IDSMrUleH6vR zw cg h6KTc2e()aKB8Mu2cz-64E z9m!8$x)1A{s1ny6drN 3Ebsf0++m0 zwBy#9hwjSue;VZX9H;MJ-cthZeiyjRGuU2q1885?L#UaRS0`VupReTMBA2{f %;#o7rhs3A6lK6 z>g`$oLETVjnQzW3)pu*ke}_UIejm+6uLj$To=oayzW?gZh34;8>iZWv$mMsDOFtl& zzbk#kjwNcmDc)RYuh;*w&POi$0_1X^$VDH ren{ZctlyG=J6#muqMt(tE=kZn+a~;%O Q5B&$=Vh7vHJda%bDr4F%sPomMCH3TNJ%5twT8_t5 z75pFT^!gCF=)EA9b$IsUrlPmkrjmcy<7WM7?No64yU1nTj$GEgHxA%@dv#l!wl(8Z z{7%T_K9S2l0=f99au+>Z3WMQIvE&4O|KbNjE`BrQ;@3j%)(>a%{&H2UFmXV&p5OZH zVEo1eyk?}0F9I%p0BkS%7}=qnn!@!%npXYoNYnpT_W-%*8z3)_IldHf(VdvoyP>Z6 zs6RCorkL?5It<9=y+AJeO5~y!G;-*uT6*=g(!_g``u;_i1G)H7kp~x<`4GAINodt8 z#j(#!ZOZsBH CuJ6=wY`>p w*@ zt5k6H?Vxf$(B*tydEWjd8ox(T-@535Ah&;4Mf>y(WxsfZonb$k^BOKZSETM7Bl5!` z+P=g&BVT3XmXUj+`vG<&KD<6xj#oM(Pg6N(gD*MfLN4c7$R(Z}xzn%E`mWs<`g4qK zv&8Wda2Ib3-058ace)MDEj6@$O@Ur9=Ul@svGWXYr{@5C>FntCk{>}+b6nryqlEgD z_wjtWb1UHPd FThE_zzJ^@R(JHvjzd)Xry1Km&U~Pk~ zixe}u)1p&B!0V;ofQwEAwijIs3fT7LA0_BS;~#52()K5CX9sxmZ#LclI7$9RcqFfD z9~(gGOMQOi@-Kk9d dx5CED|4 x K(eBO9j& z-04367u^XO!1HpUt~h!A o98E)vlj`i+uu~>KWbMzrpxJ)T>+v?d;o=YRIFy|LNt`y5Eoo^;_VdM%$^++4tT1 zC{8^*j+O6Gwo6Wz19)agbbF`E0qvcR$I+K?9k QHn3n44+s0C#qP2jAQI0l4T( zywdf#I@;4KsoHOJ|A@{8a?#~LE_xTpMIWR2u)cNle7oebxi{+dx#(RW7kv!mqSt}k z=`GNUTwCm +dDYkW&z*h+aHn?x-05imcX}74 z2f3yV?|;Xw(&OLhR{(c97{Hwl25_f$;gxkOxQ^uSJd#B6jpqE?>0