From 6bf9a6188f4ca3c53327a41c5ce40d8ff57fb9e0 Mon Sep 17 00:00:00 2001 From: Oleh Stolyar Date: Wed, 9 Aug 2023 17:44:20 +0100 Subject: [PATCH] Fixes, nixpkgs upgrade, formatting --- .envrc | 2 + README.md | 8 +- backend/app/Main.hs | 2 +- backend/grafanix.cabal | 2 +- backend/src/Config.hs | 6 +- backend/src/Nix.hs | 146 +++++++++++++------------- backend/src/Parser.hs | 114 +++++++++++---------- backend/src/Types.hs | 135 +++++++++++++------------ backend/test/Spec.hs | 3 + default.nix | 122 +++++++++++----------- frontend/default.nix | 50 ++++----- frontend/elm-srcs.nix | 118 ++++++++++----------- frontend/elm.json | 2 +- frontend/registry.dat | Bin 0 -> 131736 bytes frontend/scripts/build.sh | 2 +- frontend/versions.dat | Bin 104983 -> 0 bytes nix/grafanix-backend.nix | 17 ++-- nix/grafanix-release.nix | 8 +- nix/grafanix.nix | 2 +- nix/sources.json | 60 +++-------- nix/sources.nix | 208 ++++++++++++++++++++++++-------------- shell.nix | 2 +- treefmt.toml | 12 +++ 23 files changed, 538 insertions(+), 483 deletions(-) create mode 100644 .envrc create mode 100644 frontend/registry.dat delete mode 100644 frontend/versions.dat create mode 100644 treefmt.toml diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..c9293c0 --- /dev/null +++ b/.envrc @@ -0,0 +1,2 @@ +use nix + diff --git a/README.md b/README.md index 126d2e8..cb988c9 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ After starting Grafanix, open `localhost:3000` in your browser. I suggest using VSCode with the following plugins: -- Haskell IDE Engine +- ghcide - HTML CSS Support - Elm Support @@ -52,3 +52,9 @@ cd frontend ./scripts/watch.sh # Rebuild on every change ``` + +### Formatting + +```bash +treefmt +``` \ No newline at end of file diff --git a/backend/app/Main.hs b/backend/app/Main.hs index ae6974d..717a637 100644 --- a/backend/app/Main.hs +++ b/backend/app/Main.hs @@ -1,6 +1,6 @@ module Main where -import Control.Error (Script, runExceptT) +import Control.Error (Script) import System.Environment (getExecutablePath) import System.FilePath ((), takeDirectory) import Protolude hiding (get) diff --git a/backend/grafanix.cabal b/backend/grafanix.cabal index c23c472..856b387 100644 --- a/backend/grafanix.cabal +++ b/backend/grafanix.cabal @@ -22,7 +22,7 @@ library grafanix-internal , containers , errors , hashable - , lrucaching + , lrucache , optparse-applicative , protolude , text diff --git a/backend/src/Config.hs b/backend/src/Config.hs index 7d2c529..1ea0788 100644 --- a/backend/src/Config.hs +++ b/backend/src/Config.hs @@ -1,6 +1,6 @@ module Config (Config(..), StaticAssetLocation(..), devConfig, readConfig) where -import Data.String (IsString, fromString) +import Data.String (fromString) import Options.Applicative import Protolude hiding (option) @@ -13,8 +13,8 @@ instance IsString StaticAssetLocation where data Config = Config { nixpkgsPath :: Text , staticPath :: StaticAssetLocation - , duCacheSize :: Int - , whyCacheSize :: Int + , duCacheSize :: Integer + , whyCacheSize :: Integer , port :: Int } deriving (Show) diff --git a/backend/src/Nix.hs b/backend/src/Nix.hs index a106dc8..99fd831 100644 --- a/backend/src/Nix.hs +++ b/backend/src/Nix.hs @@ -1,96 +1,88 @@ module Nix - ( drvPath - , pkgPath - , depGraph + ( drvPath, + pkgPath, + depGraph, ) where -import Control.Error ( Script - , scriptIO - ) -import Data.Attoparsec.Text ( Parser - , parseOnly - ) -import qualified Data.ByteString.Lazy.Char8 as ByteString.Lazy -import qualified Data.ByteString.Lazy.Builder as ByteString.Builder -import Data.Hashable ( Hashable ) -import Data.IORef ( atomicModifyIORef ) -import Data.LruCache ( insert - , lookup - ) -import Data.LruCache.IO ( LruHandle(..) ) -import Data.Map ( Map ) -import qualified Data.Map as Map -import Data.Vector ( Vector ) -import qualified Data.Vector as Vector -import qualified Data.Text as Text -import System.Process.Typed -import Protolude - -import Config +import Config +import Control.Error + ( Script, + scriptIO, + ) +import Data.Attoparsec.Text + ( Parser, + parseOnly, + ) +import qualified Data.ByteString.Lazy as L +import qualified Data.ByteString.Char8 as C +import Data.Cache.LRU.IO (AtomicLRU, insert, lookup) +import qualified Data.Map as Map +import qualified Data.Text as Text +import Data.Vector (Vector) +import qualified Data.Vector as Vector import qualified Parser -import Types +import Protolude +import System.Process.Typed +import Types -decolor :: ByteString.Lazy.ByteString -> ByteString.Lazy.ByteString -decolor = ByteString.Builder.toLazyByteString . go mempty - where - go - :: ByteString.Builder.Builder - -> ByteString.Lazy.ByteString - -> ByteString.Builder.Builder - go acc "" = acc - go acc string = - let esc = '\x1b' - colorSequenceStart = "\x1b[" - (text, colored) = ByteString.Lazy.span (/= esc) string - -- Attempt to strip a color sequence - rest = case ByteString.Lazy.stripPrefix colorSequenceStart colored of - Just x -> - -- All color sequences look like this: ESC[#(;#)m - ByteString.Lazy.drop 1 . ByteString.Lazy.dropWhile (/= 'm') $ x - Nothing -> - -- Just skip ESC otherwise - ByteString.Lazy.dropWhile (== esc) colored - in go (acc <> ByteString.Builder.lazyByteString text) rest +decolor :: ByteString -> ByteString +decolor = go mempty + where + go acc "" = acc + go acc string = + let esc = '\x1b' + colorSequenceStart = "\x1b[" + (text, colored) = C.span (/= esc) string + -- Attempt to strip a color sequence + rest = case C.stripPrefix colorSequenceStart colored of + Just x -> + -- All color sequences look like this: ESC[#(;#)m + C.drop 1 . C.dropWhile (/= 'm') $ x + Nothing -> + -- Just skip ESC otherwise + C.dropWhile (== esc) colored + in go (acc <> text) rest run :: Text -> [Text] -> Script Text run cmd args = do putText cmdline let procConfig = - setStdin closed $ setStdout byteStringOutput $ setStderr closed $ proc - (toS cmd) - (map toS args) + setStdin closed $ + setStdout byteStringOutput $ + setStderr closed $ + proc + (toS cmd) + (map toS args) (exitCode, out, err) <- readProcess procConfig if exitCode == ExitSuccess - then return . toS $ decolor out + then return . decodeUtf8 . decolor . L.toStrict $ out else - let message = "Command '" <> cmdline <> "' failed with:\n" <> toS err - in throwError message - where cmdline = cmd <> " " <> Text.unwords args + let message = "Command '" <> cmdline <> "' failed with:\n" <> (decodeUtf8 . L.toStrict $ err) + in throwError message + where + cmdline = cmd <> " " <> Text.unwords args -cached - :: (Hashable k, Ord k) => LruHandle k v -> (k -> Script v) -> k -> Script v -cached (LruHandle ref) script k = do - cachedValue <- scriptIO $ atomicModifyIORef ref $ \cache -> - case lookup k cache of - Nothing -> (cache, Nothing) - Just (v, cache') -> (cache', Just v) +cached :: + (Hashable k, Ord k) => AtomicLRU k v -> (k -> Script v) -> k -> Script v +cached cache script k = do + cachedValue <- scriptIO $ lookup k cache case cachedValue of - Just v -> return v + Just v -> return v Nothing -> do v <- script k - scriptIO $ atomicModifyIORef ref $ \cache -> (insert k v cache, ()) + scriptIO $ insert k v cache return v parse :: Parser a -> Text -> Script a parse parser text = case parseOnly parser text of - Right a -> return a - Left err -> throwError . toS $ err + Right a -> return a + Left err -> throwError . toS $ err drvPath :: Text -> App Text drvPath pkgExpr = do nixpkgs <- asks (nixpkgsPath . config) - out <- lift $ run "nix-instantiate" ["--expr", "with import " <> nixpkgs <> " {}; " <> pkgExpr] + out <- lift $ run "nix-instantiate" ["--expr", "with import " <> nixpkgs <> " {}; " <> pkgExpr] lift $ parse Parser.nixPath out pkgPath :: Text -> App Text @@ -111,14 +103,14 @@ whyDepends (src, dest) = do info :: Text -> App Info info path = do - sizeCache <- asks sizeCache + sizeCache <- asks sizeCache (size, closureSize) <- lift $ cached sizeCache sizeAndClosureSize path - (sha , name ) <- lift $ parse Parser.hashAndName path + (sha, name) <- lift $ parse Parser.hashAndName path return Info {..} depGraph :: Text -> App (DepGraph, Map Int Info, Map (Int, Int) (Vector Why)) depGraph path = do - out <- lift $ run "nix-store" ["--query", "--graph", path] + out <- lift $ run "nix-store" ["--query", "--graph", path] graph <- lift $ parse Parser.depGraph out let DepGraph {..} = graph infoVector <- mapM info nodes @@ -128,11 +120,11 @@ depGraph path = do whyVector <- mapM getWhy textEdges let whyMap = vectorToMap $ Vector.zip edges whyVector return (graph, infoMap, whyMap) - where - vectorToMap :: Ord a => Vector (a, b) -> Map a b - vectorToMap = Map.fromList . Vector.toList + where + vectorToMap :: Ord a => Vector (a, b) -> Map a b + vectorToMap = Map.fromList . Vector.toList - getWhy :: (Text, Text) -> App (Vector Why) - getWhy (src, dest) = do - whyCache <- asks whyCache - lift $ cached whyCache whyDepends (src, dest) + getWhy :: (Text, Text) -> App (Vector Why) + getWhy (src, dest) = do + whyCache <- asks whyCache + lift $ cached whyCache whyDepends (src, dest) diff --git a/backend/src/Parser.hs b/backend/src/Parser.hs index b872840..64c2c7c 100644 --- a/backend/src/Parser.hs +++ b/backend/src/Parser.hs @@ -1,24 +1,26 @@ module Parser where -import Control.Monad ( fail ) -import Data.Attoparsec.Text -import Data.Char -import Data.Maybe -import qualified Data.Map.Strict as Map -import Data.Vector (Vector) -import qualified Data.Vector as Vector -import qualified Data.Text as Text -import Protolude hiding ( hash - , takeWhile - , try - ) -import Types - +import Control.Monad (fail) +import Data.Attoparsec.Text +import Data.Char +import qualified Data.Map.Strict as Map +import Data.Maybe +import qualified Data.Text as Text +import Data.Vector (Vector) +import qualified Data.Vector as Vector +import Protolude hiding + ( from, + hash, + takeWhile, + to, + try, + ) +import Types parseEither :: Parser a -> Text -> Either Text a parseEither parser text = case parseOnly parser text of - Right a -> Right a - Left err -> Left $ toS err + Right a -> Right a + Left err -> Left $ toS err restOfLine :: Parser () restOfLine = takeTill isEndOfLine *> endOfLine @@ -31,10 +33,10 @@ legalNixFileNameChar = inClass "a-zA-Z0-9+.?=_-" hashAndName :: Parser (Text, Text) hashAndName = do - _ <- string "/nix/store/" + _ <- "/nix/store/" <|> "" hash <- takeWhile legalNixHashChar when (Text.length hash /= 32) $ fail "failed to parse hash" - _ <- char '-' + _ <- char '-' name <- takeWhile legalNixFileNameChar return (hash, name) @@ -49,22 +51,21 @@ quoted p = char '"' *> p <* char '"' -- Parse the output of `nix-store --query --graph`, depGraph :: Parser DepGraph depGraph = do - _ <- string "digraph G {" *> restOfLine + _ <- string "digraph G {" *> restOfLine edgesOrNodes <- many (dotEdge <|> dotNode) - _ <- string "}" - let - (n, e) = - Vector.partition (isNothing . snd) . Vector.fromList $ edgesOrNodes - nodes = Vector.map fst n + _ <- string "}" + let (n, e) = + Vector.partition (isNothing . snd) . Vector.fromList $ edgesOrNodes + nodes = Vector.map fst n - addOne (numSoFar, acc) name = (numSoFar + 1, Map.insert name numSoFar acc) - (_, index) = Vector.foldl addOne (0, Map.empty) nodes + addOne (numSoFar, acc) name = (numSoFar + 1, Map.insert name numSoFar acc) + (_, index) = Vector.foldl addOne (0, Map.empty) nodes - mkEdge (source, Just target) = - Just (index Map.! source, index Map.! target) - mkEdge _ = Nothing - edges = Vector.map fromJust . Vector.filter isJust . Vector.map mkEdge $ e - return $ DepGraph { .. } + mkEdge (source, Just target) = + Just (index Map.! source, index Map.! target) + mkEdge _ = Nothing + edges = Vector.map fromJust . Vector.filter isJust . Vector.map mkEdge $ e + return $ DepGraph {..} dotNode :: Parser (Text, Maybe Text) dotNode = do @@ -73,10 +74,10 @@ dotNode = do dotEdge :: Parser (Text, Maybe Text) dotEdge = do - to <- quoted nixPath - _ <- string " -> " + to <- quoted nixPath + _ <- string " -> " from <- quoted nixPath - _ <- restOfLine + _ <- restOfLine return (from, Just to) -- Given the output of `nix why-depends --all $from $to`, @@ -87,29 +88,30 @@ dotEdge = do whyDepends :: Parser (Vector Why) whyDepends = do _ <- nixPath *> string "\n" - whys <- choice - [ why `manyTill` arrow - , return [] - ] + whys <- + choice + [ why `manyTill` arrow, + return [] + ] return $ Vector.fromList whys - where - -- `filepath:…reason…` => Why - why :: Parser Why - why = do - skipWhile isIndent - file <- takeTill (== ':') <* takeTill (== '…') <* char '…' - reason <- takeTill (== '…') - restOfLine - return Why { .. } - - isIndent :: Char -> Bool - isIndent c = c == ' ' || c == '║' || c == '╠' || c == '╚' || c == '═' - - arrow :: Parser () - arrow = do - skipWhile isIndent - _ <- string "=> " - restOfLine + where + -- `filepath:…reason…` => Why + why :: Parser Why + why = do + skipWhile isIndent + file <- takeTill (== ':') <* takeTill (== '…') <* char '…' + reason <- takeTill (== '…') + restOfLine + return Why {..} + + isIndent :: Char -> Bool + isIndent c = c == ' ' || c == '║' || c == '╠' || c == '╚' || c == '═' + + arrow :: Parser () + arrow = do + skipWhile isIndent + _ <- string "=> " + restOfLine -- Given the output of `nix path-info --size --closure-size $path`, -- get size and closure size diff --git a/backend/src/Types.hs b/backend/src/Types.hs index d6d34c9..8e1c942 100644 --- a/backend/src/Types.hs +++ b/backend/src/Types.hs @@ -1,34 +1,34 @@ module Types - ( App - , Env(..) - , Info(..) - , Why(..) - , DepGraph(..) - , emptyGraph - , depsToJson - , makeEnv - , runApp + ( App, + Env (..), + Info (..), + Why (..), + DepGraph (..), + emptyGraph, + depsToJson, + makeEnv, + runApp, ) where -import Control.Error ( Script ) -import Data.Aeson ( ToJSON - , Value - , object - , toJSON - ) -import Data.Maybe -import qualified Data.Map as Map -import Data.Map ( Map ) -import Data.LruCache.IO ( LruHandle - , newLruHandle - ) -import Data.Vector ( Vector ) -import qualified Data.Vector as Vector -import GHC.Generics -import Protolude - -import Config +import Config +import Control.Error (Script) +import Data.Aeson + ( ToJSON, + Value, + object, + toJSON, + ) +import Data.Cache.LRU.IO + ( AtomicLRU, + newAtomicLRU, + ) +import qualified Data.Map as Map +import Data.Maybe +import Data.Vector (Vector) +import qualified Data.Vector as Vector +import GHC.Generics +import Protolude type App = ReaderT Env Script @@ -39,64 +39,69 @@ runApp = flip runReaderT -- Since we are only interested in /nix/store and the store is immutable, -- it is safe to cache information about store paths. data Env = Env - { config :: Config + { config :: Config, -- Cache storing sizes and closure sizes. - , sizeCache :: LruHandle Text (Int, Int) + sizeCache :: AtomicLRU Text (Int, Int), -- Cache storing reasons why there is a dependency between two store paths (src, dest). - , whyCache :: LruHandle (Text, Text) (Vector Why) + whyCache :: AtomicLRU (Text, Text) (Vector Why) } makeEnv :: Config -> IO Env makeEnv config = do - sizeCache <- newLruHandle (fromIntegral . duCacheSize $ config) - whyCache <- newLruHandle (fromIntegral . whyCacheSize $ config) - return Env { .. } + sizeCache <- newAtomicLRU (Just . duCacheSize $ config) + whyCache <- newAtomicLRU (Just . whyCacheSize $ config) + return Env {..} -- A node in a dependency tree data Info = Info - { name :: Text - , sha :: Text - , size :: Int - , closureSize :: Int - } deriving (Eq, Show) + { name :: Text, + sha :: Text, + size :: Int, + closureSize :: Int + } + deriving (Eq, Show) -- A reason why a node depends on its parent data Why = Why - { file :: Text - , reason :: Text - } deriving (Eq, Show, Generic) + { file :: Text, + reason :: Text + } + deriving (Eq, Show, Generic) instance ToJSON Why data DepGraph = DepGraph - { nodes :: Vector Text - , edges :: Vector (Int, Int) - } deriving (Show) + { nodes :: Vector Text, + edges :: Vector (Int, Int) + } + deriving (Show) emptyGraph :: DepGraph -emptyGraph = DepGraph { nodes = Vector.empty, edges = Vector.empty } +emptyGraph = DepGraph {nodes = Vector.empty, edges = Vector.empty} depsToJson :: DepGraph -> Map Int Info -> Map (Int, Int) (Vector Why) -> Value depsToJson graph infos whys = object - [ ("nodes", toJSON . Vector.imapMaybe mkNode $ nodes graph) - , ("links", toJSON . Vector.mapMaybe mkLink $ edges graph) + [ ("nodes", toJSON . Vector.imapMaybe mkNode $ nodes graph), + ("links", toJSON . Vector.mapMaybe mkLink $ edges graph) ] - where - mkNode :: Int -> Text -> Maybe Value - mkNode n _ = do - Info {..} <- infos Map.!? n - return $ object - [ ("name" , toJSON name) - , ("size" , toJSON size) - , ("sha" , toJSON sha) - , ("closureSize", toJSON closureSize) - ] - mkLink :: (Int, Int) -> Maybe Value - mkLink (sourceIndex, targetIndex) = do - why <- whys Map.!? (sourceIndex, targetIndex) - return $ object - [ ("source", toJSON sourceIndex) - , ("target", toJSON targetIndex) - , ("why" , toJSON why) - ] + where + mkNode :: Int -> Text -> Maybe Value + mkNode n _ = do + Info {..} <- infos Map.!? n + return $ + object + [ ("name", toJSON name), + ("size", toJSON size), + ("sha", toJSON sha), + ("closureSize", toJSON closureSize) + ] + mkLink :: (Int, Int) -> Maybe Value + mkLink (sourceIndex, targetIndex) = do + why <- whys Map.!? (sourceIndex, targetIndex) + return $ + object + [ ("source", toJSON sourceIndex), + ("target", toJSON targetIndex), + ("why", toJSON why) + ] diff --git a/backend/test/Spec.hs b/backend/test/Spec.hs index 5959beb..120f08a 100644 --- a/backend/test/Spec.hs +++ b/backend/test/Spec.hs @@ -22,6 +22,9 @@ main = do it "works on glibc" $ nixPath `shouldSucceedOn` ("/nix/store/2kcrj1ksd2a14bm5sky182fv2xwfhfap-glibc-2.26-131" :: Text) + it "works without /nix/store" $ + nixPath `shouldSucceedOn` + ("2kcrj1ksd2a14bm5sky182fv2xwfhfap-glibc-2.26-131" :: Text) it "fails on illegal characters" $ nixPath `shouldFailOn` ("/nix/store/2kcrj\"ksd2a14bm5sky182fv2xwfhfap-glibc-2.26-131" :: Text) diff --git a/default.nix b/default.nix index 7a63f32..0273393 100644 --- a/default.nix +++ b/default.nix @@ -1,69 +1,77 @@ {}: let sources = import ./nix/sources.nix; - pkgs = import sources.nixpkgs {}; - static = - import (sources.static-haskell-nix + "/survey") { - integer-simple = true; - }; - haskellCompiler = "ghc864"; + pkgs = import sources.nixpkgs { }; + + haskellCompiler = "ghc927"; + haskellPackages = pkgs.haskell.packages.${haskellCompiler}; + + static = import (sources.static-haskell-nix + "/survey") { + + compiler = haskellCompiler; + integer-simple = false; + }; staticHaskellPackages = static.haskellPackagesWithLibsReadyForStaticLinking; - niv = (import sources.niv { inherit pkgs; }).niv; - hie = (import sources.all-hies {}).versions."${haskellCompiler}"; - websocat = (import sources.unstable {}).websocat; - d3 = sources.d3; + d3 = builtins.fetchurl { + url = "https://d3js.org/d3.v5.min.js"; + sha256 = "0g5529s28dm27sqp5zzff1ipva1fyipdswl51c7h3ps7715r5gjx"; + }; - bootstrap = sources.bootstrap; + bootstrap = builtins.fetchurl { + url = "https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"; + sha256 = "0dldiln2s3z8iqc5ccjid2i5gh9527naas064bwly8x9lrfrxcb0"; + }; in - rec { - backend = pkgs.haskellPackages.callPackage ./nix/grafanix-backend.nix {}; - backend-static = staticHaskellPackages.callPackage ./nix/grafanix-backend.nix { - static = true; - zlib = static.pkgs.zlib; +rec { + backend = haskellPackages.callPackage ./nix/grafanix-backend.nix { + static = false; + }; + backend-static = staticHaskellPackages.callPackage ./nix/grafanix-backend.nix { + static = true; + ncurses = static.pkgs.ncurses.override { + enableStatic = true; }; + zlib = static.pkgs.zlib; + }; - frontend = pkgs.callPackage ./frontend {}; + frontend = pkgs.callPackage ./frontend/default.nix { }; - grafanix = pkgs.callPackage ./nix/grafanix.nix { - inherit bootstrap d3; - inherit backend frontend; - }; - grafanix-static = pkgs.callPackage ./nix/grafanix.nix { - inherit bootstrap d3; - inherit frontend; - backend = backend-static; - }; + grafanix = pkgs.callPackage ./nix/grafanix.nix { + inherit bootstrap d3; + inherit backend frontend; + }; + grafanix-static = pkgs.callPackage ./nix/grafanix.nix { + inherit bootstrap d3; + inherit frontend; + backend = backend-static; + }; - grafanix-release = pkgs.callPackage ./nix/grafanix-release.nix { - grafanix = grafanix-static; - }; + grafanix-release = pkgs.callPackage ./nix/grafanix-release.nix { + grafanix = grafanix-static; + }; - shell = ( - pkgs.haskell.lib.addBuildTools - backend - ( - [ - hie - pkgs.haskellPackages.cabal2nix - pkgs.haskellPackages.cabal-install - pkgs.haskellPackages.hoogle - pkgs.haskellPackages.ghcid - pkgs.haskellPackages.stack - niv - websocat - ] ++ - frontend.buildInputs - ) - ).env.overrideAttrs ( - old: { - shellHook = '' - ( - cd ${builtins.toString ./static} - ln -snf ${bootstrap} bootstrap.css - ln -snf ${d3} d3.js - ) - ''; - } - ); - } + shell = ( + pkgs.haskell.lib.addBuildTools + backend + ( + [ + haskellPackages.cabal2nix + haskellPackages.cabal-install + haskellPackages.ghcide + haskellPackages.ormolu + pkgs.elm2nix + pkgs.inotify-tools + pkgs.niv + pkgs.treefmt + ] ++ frontend.buildInputs + ) + ).env.overrideAttrs ( + old: { + shellHook = '' + ln -snfv ${bootstrap} ${builtins.toString ./.}/static/bootstrap.css + ln -snfv ${d3} ${builtins.toString ./.}/static/d3.js + ''; + } + ); +} diff --git a/frontend/default.nix b/frontend/default.nix index f12469e..eba9da3 100644 --- a/frontend/default.nix +++ b/frontend/default.nix @@ -5,34 +5,34 @@ , nodePackages }: let - versionsDat = ./versions.dat; srcs = ./elm-srcs.nix; in - stdenvNoCC.mkDerivation { - name = "grafanix"; +stdenvNoCC.mkDerivation { + name = "grafanix"; - src = lib.sourceByRegex ./. [ - "src(.*elm)?" - "elm.json" - "build.sh" - ]; + src = lib.sourceByRegex ./. [ + "src(.*elm)?" + "elm.json" + "build.sh" + ]; - buildInputs = [ - elmPackages.elm - nodePackages.uglify-js - ] ++ lib.optionals lib.inNixShell [ - elm2nix - elmPackages.elm-format - ]; + buildInputs = [ + elmPackages.elm + nodePackages.uglify-js + ] ++ lib.optionals lib.inNixShell [ + elm2nix + elmPackages.elm-format + ]; - buildPhase = elmPackages.fetchElmDeps { - elmPackages = import srcs; - inherit versionsDat; - }; + buildPhase = elmPackages.fetchElmDeps { + elmPackages = import srcs; + elmVersion = "0.19.1"; + registryDat = ./registry.dat; + }; - installPhase = '' - mkdir -p $out - ${scripts/build.sh} src/Main.elm - cp elm.min.js $out/main.js - ''; - } + installPhase = '' + mkdir -p $out + ${scripts/build.sh} src/Main.elm + cp elm.min.js $out/main.js + ''; +} diff --git a/frontend/elm-srcs.nix b/frontend/elm-srcs.nix index 77cee3e..26173d5 100644 --- a/frontend/elm-srcs.nix +++ b/frontend/elm-srcs.nix @@ -1,62 +1,62 @@ { - "rundis/elm-bootstrap" = { - sha256 = "0jn864353vbq6q73gmycbcncm26a9v0mkb6ba75ab611sq7pc5kb"; - version = "5.1.0"; - }; - - "elm/browser" = { - sha256 = "1zlmx672glg7fdgkvh5jm47y85pv7pdfr5mkhg6x7ar6k000vyka"; - version = "1.0.1"; - }; - - "elm/core" = { - sha256 = "1l0qdbczw91kzz8sx5d5zwz9x662bspy7p21dsr3f2rigxiix2as"; - version = "1.0.2"; - }; - - "elm/http" = { - sha256 = "008bs76mnp48b4dw8qwjj4fyvzbxvlrl4xpa2qh1gg2kfwyw56v1"; - version = "2.0.0"; - }; - - "elm/bytes" = { - sha256 = "02ywbf52akvxclpxwj9n04jydajcbsbcbsnjs53yjc5lwck3abwj"; - version = "1.0.8"; - }; - - "elm/file" = { - sha256 = "1rljcb41dl97myidyjih2yliyzddkr2m7n74x7gg46rcw4jl0ny8"; - version = "1.0.5"; - }; - - "elm/json" = { - sha256 = "0kjwrz195z84kwywaxhhlnpl3p251qlbm5iz6byd6jky2crmyqyh"; - version = "1.1.3"; - }; - - "elm/html" = { - sha256 = "1n3gpzmpqqdsldys4ipgyl1zacn0kbpc3g4v3hdpiyfjlgh8bf3k"; - version = "1.0.0"; - }; - - "avh4/elm-color" = { - sha256 = "0n16wnvp87x9az3m5qjrl6smsg7051m719xn5d244painx8xmpzq"; - version = "1.0.0"; - }; - - "elm/url" = { - sha256 = "0av8x5syid40sgpl5vd7pry2rq0q4pga28b4yykn9gd9v12rs3l4"; - version = "1.0.0"; - }; - - "elm/time" = { - sha256 = "0vch7i86vn0x8b850w1p69vplll1bnbkp8s383z7pinyg94cm2z1"; - version = "1.0.0"; - }; - - "elm/virtual-dom" = { - sha256 = "0q1v5gi4g336bzz1lgwpn5b1639lrn63d8y6k6pimcyismp2i1yg"; - version = "1.0.2"; - }; + "rundis/elm-bootstrap" = { + sha256 = "0jn864353vbq6q73gmycbcncm26a9v0mkb6ba75ab611sq7pc5kb"; + version = "5.1.0"; + }; + + "elm/browser" = { + sha256 = "1zlmx672glg7fdgkvh5jm47y85pv7pdfr5mkhg6x7ar6k000vyka"; + version = "1.0.1"; + }; + + "elm/core" = { + sha256 = "1l0qdbczw91kzz8sx5d5zwz9x662bspy7p21dsr3f2rigxiix2as"; + version = "1.0.2"; + }; + + "elm/http" = { + sha256 = "008bs76mnp48b4dw8qwjj4fyvzbxvlrl4xpa2qh1gg2kfwyw56v1"; + version = "2.0.0"; + }; + + "elm/bytes" = { + sha256 = "02ywbf52akvxclpxwj9n04jydajcbsbcbsnjs53yjc5lwck3abwj"; + version = "1.0.8"; + }; + + "elm/file" = { + sha256 = "1rljcb41dl97myidyjih2yliyzddkr2m7n74x7gg46rcw4jl0ny8"; + version = "1.0.5"; + }; + + "elm/json" = { + sha256 = "0kjwrz195z84kwywaxhhlnpl3p251qlbm5iz6byd6jky2crmyqyh"; + version = "1.1.3"; + }; + + "elm/html" = { + sha256 = "1n3gpzmpqqdsldys4ipgyl1zacn0kbpc3g4v3hdpiyfjlgh8bf3k"; + version = "1.0.0"; + }; + + "avh4/elm-color" = { + sha256 = "0n16wnvp87x9az3m5qjrl6smsg7051m719xn5d244painx8xmpzq"; + version = "1.0.0"; + }; + + "elm/url" = { + sha256 = "0av8x5syid40sgpl5vd7pry2rq0q4pga28b4yykn9gd9v12rs3l4"; + version = "1.0.0"; + }; + + "elm/time" = { + sha256 = "0vch7i86vn0x8b850w1p69vplll1bnbkp8s383z7pinyg94cm2z1"; + version = "1.0.0"; + }; + + "elm/virtual-dom" = { + sha256 = "0q1v5gi4g336bzz1lgwpn5b1639lrn63d8y6k6pimcyismp2i1yg"; + version = "1.0.2"; + }; } diff --git a/frontend/elm.json b/frontend/elm.json index 8115c6d..e2fe09a 100644 --- a/frontend/elm.json +++ b/frontend/elm.json @@ -3,7 +3,7 @@ "source-directories": [ "src" ], - "elm-version": "0.19.0", + "elm-version": "0.19.1", "dependencies": { "direct": { "elm/browser": "1.0.1", diff --git a/frontend/registry.dat b/frontend/registry.dat new file mode 100644 index 0000000000000000000000000000000000000000..b2944276581e506d79d3e1c902e5412561bfc3fd GIT binary patch literal 131736 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
YxSRH{im(| z)2#m_>)&Mk>vsRT)xXaAS6TnE)xXU8h~ojg9tGsEZkoj1KiRu;0uDf zl3?Jh_p_|`pR(RRwR-=Q^*+yfpJlyITfI-S-X~e_<5utEtoKp7_ff0&QPz8r^`2+F z4_mztv)%`--UnIlS=M`+^`2zCo2+-8^{!gItE_jK^~SByEPSu+<%sct(U@i}W*65;YaE z)9tpq-InGgh5$e1Q8(Geb#`%;U0h}tTlBI@iRSl40 z86aw<1Jxr2RB{**DeKvb!6s0@`Qy#56lr~ejuR!O&sAd5UPY%y(t;K$gS>2kJoprG zD7JBFT7x(}qLNrJC-7@eWN$E^sso_?fkU?|~L#4c?K3-w=( zLtXC=kK`4&(CV}4mVrEul+rfnbvF9zYEI53ww*%R9V((KRDM9=bxiH)U*YJuY5s}> z;XSVKka!&Mxzu!I78U{wxrAtamOe^Oyf zlQI{m$7cYP3(oNL1sh(%mG+j`%5JvDf2vJi<3oo+W|4 zE27oT2$OX<{5892wJK+_Ble|xqiYhbrT*#@k;eC>Te!*}(Hs1+uw_27MQn?KmH8&h zddczH3C`Llh7|^{?|>5>&_!qFfr!f|Jck|gh6cp~-@6G9gf~4%v=?KzA;gaEu-t>H zG=>k4(4a?dllzc7Yxa2$t<%8cbahaO2(NT^ku zY$KcuCDys!m*kB$k#HE_N&ZhwnCSG486w7`aI+?NK?i@!u}>1&tvg{E#?zvfj}Smi zwRHNpb07F^W(5IGtrLr?!jFlWbh{7n_hg~e^7ND>CJh6AmK8GLF)+Ae3A1+J|D#O1 zrF^@kth>|ypxytVr92!49=Nyh?UZS^lyA5D{Z_)gjde??gUi|xj!MLPV5$vXns}gv zr*%4n2Rr=#4Ugrh|_Off@X*;JkkS=kM%@Q36~NzTe*L=5NLBRthJ;K>qOk_kUG&OcjAh zC!VQM$*yi%c|aE_yjJ{=p2dopT?t&)|656h82O zp@n0LxzS@+yjupKRM@-)9-Wak0>LvN<%(t@G*v7$+9mzq$*MU5WgfkMEr0m-^>>4% zOugLv_)lT0e)V~~^?5t{ymj$;tMhrQ{duePc`N%oYki(&pJmynS@uc0^+`MXq?LV= zwLZx*Q9;l-vX*EMSxdA55&v7F0hpMdwV!4!k?xV@vzCbGK>$bSMlNn68Y36CUFehu z#Tq>ogI^o7)CK{GMJdivt_fH$u}%P`Ac#hHhh<#8UJ_3)rBsO2bw}t|qGq_(O|3<- zx8p_(Ojxx<#L^EX7eYlpd>rW+Uvk==W{JD*yakkHp=j(;>s*&ZRIFA9y9nYHDppMh zO*_-g(E#N+3*O=a&_IJgfYmOi^f+y0ra7{CQa5G)HU3u)^IA#@Nu)nWF-aY=?wWWw z7kntuRY}zhl6Kt^(4p%>l}^LA)+x*j0)@j#hzckZ_aK%7C;1jh{~B+gBh=(G-^Lik z634Ae(!dkp3H{F?@$KxhcJ?Wxyq$fF`3Msb_8e?D?d$`rG}vUYz+h2X&^W99`bbLL?n_qTCd8V4YBk;0+x%^zYgz5JiVrGcTumApS04qtO0yU z3^~LD_XkPWA`jUYrIZHz4FVCf7b30M4*oFNt%k}xdi}UU*MCh-DYap5$=ZilS$ag` zQ^^KDy#8$^>8BPrA@L91DD5{Rl&Ijuyhh+#>4`eenqD?-B~1GM=l)`q^EH~Q;{n8FG@+Qc!nLt#UC1$ zm(%%*r93cVETh4nDk6{Rim6U0D`WXg=kkaA@lU9zaKp`Fh)i9qC0fr8Ac%y@*L`W$Vksnjklyap31GOG+SBo;%}ZbHq4-RK!F=x8S)_q>B?SoPetuLk#v@ zeE$&vys#Bls&lRTzZ?z-1Cb-Jb4dDDWkIV+rQyL%0P`(H5mmjq&MpCN*$Jn6q1{UU zn%E=4mvpQ2=RJ;@v?JYAtaFn4I`&0_t{5fBf*k{s+ zggn-gE^9Elg&GzKU7BLg!BHG`5b~Gyr+3xE%GuUW=jp$pE##};yxkJ2pgvU4;i zw=6RJ>v$yyh~P>_wDV!ADTL*w26q5Lr%1x@5o(S2l6jMDNzphEmE$k{eWN z@@sO^!RUV+AM8oi9!TaNd0bXTDZjgm%t?nl#8!@TsQqMHj=FSUY|ac8aa@)h~ZJ z5)-A1);q7J3~~qBh)#|0aG$*J{2cy`$A02 z;)Af7u)1_{T;P&Ot$OOa5!1V>S#r6+!SsH`r96R4t|r7kL1T1a0Ns$Z2_!PRqSVPI zf5c@tCvei_95n>h?8}h~*Ws1Wi5Mq7&iX~J1CEv5d!+C)iI<`dJ;LLL7G?!n-K+@> z$fv}i5avlSm-)t%;dq+zw+J&57#k4j-F1Si$GlH9FKBF}>k%<&Lr|!1q>^URvto(j zxK>P!*xn_1H{7h4(bSamreQyjW)(>VM_8<;D(b{diw zFh1R(tJ+i|T?3(<1ROgwSnuzSvEtMa4CU=k(XoCaV;%3dELJtWTLyW&%ipXj!#?G7 zC!B0V2FmepCuy5?b>p0}6k$IKYDo-1oxlx6CAAMR10nzm=M(lh&dGt=AE;1M?93Rs z%`JX)uO_q;VRb-*FA>#D#?5hi!+pjSH*Vo_}RIwgpbH}5|rb<4>a;IR5lJ_k5He4g2yO?$U!^#;*ILIcbjUO z5NX+(evT4D4M%0gl1VD4wD;M}I8kD}rOQOq{5bU!Icn)~x|=VKlXoiOQMRC=13FVh zoYWX-Ny^(TXWPcTKS6{PR{5_cMT8sf$U!e(B70diay^oX7L*|Iz;7Woph(~aC0!FG z1b37;LI#yAm$2snLPuR4mkrg(wKoLZZ+z)&k@!L%^0!`oM^xrYdqE_x{Z4it+#WlFx8E zd#ME6vj<{0?^63=54N$bwi?XrocAhdFU2WP&r2KtO7)W57V4ewepIIJe%2*wh6FI? zKs^N-NLH-)O33GQzfzRaOvq*ql6{GNvc|(g0>(i+NhgrAwa)@?4EbY&r?COr_a^3rP3@8_w|S?W!-^Ask#decS=MNl zTV0$zihYDUxh-{lH4e*`BcV4+*_5?@N=yvD08N&;1D^-1s{$(|4dsAu-yi3)r0Pex?bOG9GGlNCJ!i#XcQl zbGJ7g_FEK#j!k&LOJEnqU z<&m)lrAUATCH19Kf8L0m$~CVU_=hAwhX$CP%o$&sU#-QYB~Pkz|`QwR#)<>v_8t4jS23KZNY}R_tl? zqO-)~I<2O}-@EpoUQqH~;_Zp0$C3s~JeP~)L{EYXf{vV87$UW345?H`1RhkDfq2*h7%7X=!wYFM%7GT$!Xlc#sDL;yX>mBP;UQ;WXAmH`$qBOf!YRm-HDJ; zsgr_c`D5fVc%zIRru%-9(tDpW;3SfHpCMimD6X1Okp%lj)) zi-nEK8w|L`{8`p)wtazFEX%>1lyxEF(OgKbiJ1#SjIZ(O8Y&E>EFQk}>b_e@da@sc zc@6Q9Nqp7X-Xf_uZmmcWkxKqXE#MtpnEF+h^$VmB-y@m-9nz3*o)ONY>G_f8LSb#6oUaA9ajZ+L4gSmfXJrwvYYb; z(ouhOPo5=nv>%lqTa9BmEbhHKEX-wwL_yq^v1wF2d~doCF_ZWvkn)IXsc)7+>E$s_ zPd!^?8{ah}7=#M>ssc+%MZJSMx?^1iq!=phNtY>&mt1m6>w99L$~Ta9@(CCnr&Pm) zWNwJ0JV}7Dh5QSTqX>D1p9ZIUH!p69vP*Hse$;I!C>T2@hjOyuP~H=olZ*+LONr6V zoXYtp`=L9gmNM_450rt}FFOdkL1&hv;)ga4FK9u>-D!@!ejXxsjVMKuZgW)JR(q|Y zv?Uk|_Y8AwV1aYxB74_)taYcNj)K%HtoUiw_F7jj#jJgi#dCw|fw0r&j`t+5xeV=U zO>uAy4~1a;r1!$+>RhOCYK5jo+t?sslxDC2>&p6 zAEttcGu1Pk{dg{WOXP`7{&tLAMvU!9g_yJ477Av2on3chggS&8OYxaI#lTPmxfzNW zLIT`Gl7>p;(1)ccBVKqUZZq#k*@NrL?BlT|jg7}pl~>e?n6@~At0yj?rf)9kKnesI`>tVZ~*-3IGeL2oI>g=%_s z(A!dqa{4Wx~ITV9g0O3+xG++h0MQX*5j{rD`vusu9vms6) zA>7Dgm#>ZlL#RpZ*+AY6gzlKFPz`oJ5{jcGppqRJ0(K~0efjc>&xB4bkL*15BXjl0 z^OsaQ=6Pg49M(~XS2DfWSUCpo*x0*pmTSz7avzg4Wgz5{(1|Q`NRdjO^@A<+B(=Mi z_#J<{l=>iI*%yCK=rnCT-p+3)E^MH_gRz&sq*F13KU}4nDv3!8TaKSiXD=@gd&r0e zv9}9?J-2aNFe9CGB2lqW1Hk~7&Y~nn_r$TB*xxW@&HePaBZ~&boC_ZNQ*pfwrs9i% zlbGP(-fWOPx35{8GQcaQlD6i<{~SCb)s$1&RgdPw5=2jOw*yoFQxu{YKngb5W2b>x zCFkaQwTI*y;8NX^#2_w0_&mI(RW-Z!@J@R;X=F0c>BEw~)2LZbBm@6AZOF(TP6?Bx zxo}S<$uxW(M29NZi&`Zp|D)=B;R&UMkdo$GJ|0wsM%A7s7^M&1k$!GVl*dbX0f4KW(;Bt*t6T&l7d4>=P~ zns#8yAoj!P2Oc{+s0_@GDhqJ3vtvtX2R4JWWdW_QlBjvo<2C|4KWr; z*&Fa2?hgo^+eXDZmv*l>;iFAFMhZfvK)NOK672%3C|2-1RZ&tv<7E;^P|c@7-y(Ui zrfr>BrQUsro4jDCVds7-%Ini1bS`S^@XSQmxqV~SC@17B)TyuJ%$UYV(Etj`EEbU< zUdMDqRTlJVMMt~kjZFKVX$7cEBVLGuPG0G9GzK?u-Tk1$q`m8wd7mb=0^Ik%Yt4Z7 z6%4Ra0am4}C55`O&Q;cSRl2N}7V@YS&kAqZA|YT9N+)R*<#_>3{03D8j(WD8^5wRy0q5XO4lUv(u{|pef>g`%Rc${d%c#wg1vHN0D_M2J3aM z0~--v=3jjMbE$e}-%q)L(>du;ItSrf45N@q&6)}~D2m2uGhIp}L52(E#}-4zKc+NF z$Ry*}oIZgHVyCuS%O-l0NIJL*Se91Ii%iKg0OyS%X;Ymyhb5k8gnM1;8ATy&qUacK z+=auzApK&Q_PMm8CdJfA$8JImC4Xh85^`-N_TsfoDtsU|;PN8@TV9^_RXv2Hgb-E} zUe4ghe-h2`%*ay6oUOQ)M;Y|{&)2Q)b?f4~)wyo9uUjphj}a3sIsyT)DkF+!n1JG& zERd13qFj`xjDVb(l^(ueT)|skU;jLk?4cgMwo};xRNzmjBwL=Ii{3r$K;BD>SA~3{ zlpRYuT8H_YSr0H0YIsE8LQ(}W4T-S*cf(jCCsbm=hjsf+h<%QdqD)MXt@fv_)~78B>a?V$j#Sg} zrF5har&iOE+M4ZVO`TTjnH13U6*H|wW~+14YTvY4H&*@;F2!x;}T;*z9{x8HNI{_6QSsVwVFD=Mq( zE;aB=;quGI?3FHQOvxPWIPL?aL~dXm zSQR6&o>Q9J&Hd_pF+C?Z7#)<&z1C3)alu?hgsl!Mfihb4JZd)4V>6(^VtJTP2YdC% z&Ju&7o7^QJSV}SbQq2r&EAKT)Ch%^81*&?8ooXpFQ9)GCb{H>{x|r^c@6_w#gb^jJ zPQ&yVA%G+Gw-YQsTV93BGyz9F5WA7UsNdHjpD=4_Y=Pi2N_rGG;!68dvhI1XqKm~# zK2`vYm`rdnH?v6YU%L0#?D23}(ybrrn--G~2gFAZ!5NxQbCemG?dCd;g2s z?C$!_OzDsETS6t=WSMo)<>e3n(?gJ#!{Y6PVz7pDW()$+v4zcfXSL9F%h_yta{QM- z;hV})bc%Z;wGW&bMpUx$B8sZR%JGxze4AOdAR?wwEusdhh?vuTBa*)cq$-pE@rtXK zkx}BKTOxa3gH>v5rh<4v4zFu~+Ns`X7cKK7$P^!IjXSL^P480pS?fIqz6Xm4XEcSkHL{57S1ycEl7(zrM)xKlHWJtx@7#4N2Mni zNfisoY0^+TKfdhOZY5EM-~6JB?dR3Yh#|86=FhL{Xx67S@gxuCn6jtVQB7SnCV!$) zG2nXcwsy@VsxMZ~B8s_QIm;}(IvS}WyNBvQFQ;4yuRCYi&s4{vmNsRuDP^6eE{V1j zlewkH8qaZ9cI&x7X|WC(uj82A)o|nLrErzp?AhifZ*YLR!R7~`-nZM~kH@X9l-+K1 z#;ta&lP>qhG(=tu(HGZTsw3rLy{af%U}B)0gd4<^aj9jsoA9)A{j?m6-YOW`x}dC? z`(9`vN_)UJjEzyr_K9G#7PJde>Nm+7zZ9$OY7J-H6mqHW?Es77Z7T1^U(MG;QWYkC zAG_t};kGsc>m|L#6-7{1;^{-W6WYz_;W!#?R1}gneuZpln4mf@h-DL(;8_4A;Y240 zc5Lki&~JvsUV|G)HupeuPnsb1`V@ z@`(&a8w9qAA(1~CSz~EK-PE6Q#MXe{@TM1Z2Y*;46&sUd8Za3$J|;^g_%8i&Pti17 z8DZkOuMTqW9w5b~WA>)K2=Dgwk@u7Zaht+geZ(0nHigkPjmJ=0Ng-=={dHyUiag#l(lrHKuxp2z*H6xYHR8=SESLH-Pq>D zzxdu|0(~MjB~SW-d!O^rf$R54w{;=qoaH^e#6Kuh3yyD6M>uu6iOX^;sSoVEJn1gl zR9+v7UF7k)J6>dZN)ZIuWZA7jkwN36|y@$bxOPvTKb-YM~I6^Bc+>BZ!_C1q?TN=}${s%f=2< zKxHdLST-H%u`6ZKhw8vf*M6wPIuN#1N5oo&+!g(W1U-iZFt|G_cMt;+O68;?7Q?F| zbBt3Ms)xyh3x5<*ag1;`0nS)dT)IUqM=i0opCc)*bYIAHkRsgx8WH98t3K}!s?F+g zLOon=;Dopbc_Ys642`)n=;QarUL6T#q7>9DlMn+EL`V}Y%6UGtAS2bJeOEH50f~v8 zhzG?f^1>;WBSr4s3ujJ#Fyp7eRJ^mW6|4RY4OGEEHy|>{+8l=1Us%4zS^J%0qOBUx zrTEJkT*Ib4lnP_ArqQh2&5jxxX*!p_@~tdU?6&rC@de$2oN&I874vLLZV9aNn#lD8 zJ))TYNw0GuQIwrFJ`ev)OT#6{4fjG*q&6Qi4)f5;du(WN*VXN$2q*dFMC?;X9KNKu zu7kUqnvAakj$SSsJA`oXUJWF=5uqlinKahPYvV8$uL`;EW3}?~a7`z^85Ddhyt!wB zv*}HOLg;xS{=ohd&fh>Qovo&`>uhP_1{<+wzI|XI5z~`7YZoewY8M?JxxnjFOjROq zd0@z1)Cte&Ady&22SJ%6_BKpe@us#ldI5A8k%V$;N&4^Hk_-^*1T^0-sR5@QT7^M7 zDX+5N6^|z+L{@KCdQ2)^xZ=A)3iHJEa(0iL4z(xg%4q~aq-A$fE7K`LXu`L}T+^J{E1A&Vih#Z9n)6Trz(aSX)Jse)F zCubZ)Y3sqdSYf?=_>vd`x7a80;#V}!n3`!iW}*^H*Fp|yg|~yCTe1{4&Fc{QjMI+5 zm(FjY8I$4S$Zc~gjG%)v4<=vEsD4baK7PD>qZnnVeL{+q6zvK4 z5yhMV(4vG?V-!nRySzL_@k!sKbT}3(#-lvyzMI=s!i1zxP|LOTkW3&2)N4TOuL7Qh zLl<3d?E$KLL~&G7Ib!_~`2!JiSlVL}J6Dzk3!G$b7xQo{#Ud5NF_|;V63ODtTqRw7 zde{TkqR@u39dCKAAMaK}s^U;XSp*diNeW#&DC>1s{m2Gw&9IA$YwD-WIT?2LW_ziA z;?;`fu?)NJ?$MFFfogw>LbwFo`acnCOY4HTEqSQ5<-LPgRh(;(5`Jb0;RQ9GL*wN$ z&rc##ceiCUgNor_V6#6WUY+YF_Z&wPk&i?a9@)zJaVHIwpGxGRPkohgKLrQnnZ~n! zP=sFiw@EvVT}QSo@>j23Dpi*ND@iX9|5Vrm+3(>T&-No)nr*mhKy`@joLV+k%E&Au zC%m3Ak84T|-67eb!kXc6c_hQjZ?>;^<;g&!fzsDKW@}nU@jtv^+{Dv9!->A8q5;Y< zIE!guV@?`(yc{l2$2-F46-|6toX5NRUd`bWm|@p@MLMlUgZb5UMc5*Su+%A!08`gB zLVLZE+MXh`N6Ocq?9~|9+j75LV5++`z1qKK@26gy8`U;9s`wYV9wd5<#jy&9^=J=) z_0%hZ>$SYC(nOD>Gu;(SRu>nAePcEEA+{Qy@z-7O!O@7M2c>+PJZZv$KWx2%vdpqr z5i85X5^@{Vf{w)~tz@HShepWiNjt6v+k~(QYj3D$`+i1R(TR{q`J9;aj z-lmY9JuSZsJzHT&1W|A8B6$?)HUn>yRcI8F)do!;Fz|aG1(tMTx@Afc2+2;9an6IA zK;)BmB(&5oS`gK^pj^gu2%T3*_;JNh_H*BM!U5%DkwR0TK0m5Z1ZtA;lnnl=-h}Oc?XF{lvqd?+Ew=&wctItGEUrO${_CX z4Hr8-JPf&qio$RH=opImP_JZ`-{kx}gA`p|w$YIN~V$*ok< z;LXZ_9&(3Zg#uJD4>)L{b`|DAwgLv;ih5ZatTleO;%36#9*QOWQc+!rEAcDT%)wjZ zc4+_~QJhjT?lxI|z2Vi9`7IS}P~$iAt*f+1+%%6)QgF0ZE3OG^_B>?R$lNXFGvyUo zPg1r^ikjT@0T4pwr5;fVM$_kYra@3fL(fW zn!e^ca*TSpJA!3j{PNXHl^9rLI4-zHf;X3QB8Aip&g*R|w@zo=lNEq!yHxKMj* z(c(h0_Km%`m}%s5cZPuStRuXccq!5RSSP~wvJX1EcAP!!WKTNTO((nVWLG?Q-^tJmd6tBDZ4_0U@aIbO zw0O)4(TpG{TuAtY*jmJ$VAAC(jCkZ+j1TX%y+@YcnXe!9a+K@aNc-xvLSR%<+oJ39 zE-OVu(v^bkW-7>@&mlLD2Ws9dMDD}bc(#*ok7NDT=4UQ)j+-zllYt7lM63+=;XE{pg-4iQ~1){I;O(fmov;P5vxogFUpK*gAhp zB*HsME~rJ;cp%eFA9w{eJZk5zm*B>(dXrnIhWNTq5Y~=UfmAZq!qVq*%c8o{dvu%#?AruKyI|k2l)8zgm>FFl4~kkC+5z&uxiuMhMMOg4MA1ZNUYXsTf zK`4Vqp(YePJ(2Yho63ZHQLmxVguPNvn3faAXdQY^g0L>rsHYuF@V zi}I?7-|)yt(~+MlDZovru?yNl)ByczM%}d0rEjEV;`{*h{Tg95D8vj(_ECUnPW%G} zl8R@js#J}>!}}1Kfqz@ed^pYxE*LT{z|LEAL};s`k9(~x4&>NmpKMu)^)LZF4J4x% z|9PMn0KUPRKxua#@D{s{K0%*A4hS!NB!{O^K6kq+Dblr}xR2d2k86=d@!${KP4y$= zyGQDZ;b^Q?7zc=pwtD>X<(EpJk#S7GuEikw$z}<-&LV(|#z+LH--D#QyoifVhDuti zT%ti$V%7AM7vq)_1hNZec5h6H_bjjy)}QCrpY;a0D%DMP+AHSwcxv>75M&f4yV!uDx>J2(R`^lrLL;E26`*06E7t}Rg1BF z+_13@OnJ7IZd01oh!k~Dx@=c~)y=?feB3_=tJ0GT4(9CN`ss@iiv=4beb$VP(Fa;6$f4XHl5v5D^$R#S7`-aYX9gW~R3loNI zzZDO(v6f_x2YH4zxv43JX%mqh<7iLov5rB*s%y4q4^dA?#V%cBGmh5{tVgYF-Lgc_Fg-{HNbge>$eT5%{)Ai&3SB;UZ#%-qdKdV^ir? zTKEX5Iw!ouK`Djb8kxe*#Q_ju7<2K@FVkMU2YPR}V*tcsnNuQANlQ)}Bv)R+M83p4H zc*=YWci2jTh$*|z_k`fiD)!R#4fkbC&2MC_-yJ833&WR;}wuvRm z(K6Z2dS@e5zHBbx2(FU|McE_IU9oSap?jyjJ>eY@%oL%#Wg^c;G_FrTtuk6;J`&TK zW3>+6P+I!oDb6STcDLWY=(jt~yu{QxDO;o~YVL#HEf?PwZh<6688JCss!l{{y~Rf~ zaj8CS{eO{3`n$~l?>!k6StXj97y0s@~ecdK3|*+2grNF5_ z<-QSP!rtYo)#$AgN9xml5`@O!UGh%s^K81_ypMV+6d)jE@Chmxs{@ZBx(9PwcFlo$ zS9C^hBNy@vB|FpGFkT10@+Ok;9$bq4_?8_cwP^h2fSY3Wgu$KNAF5~&k*U`}N_5-z z*`SBJuRZ9taQdM-4>~QZ{Dbzzpxr?X#HJrB`Un%$SlR{|v7_<&Ut^`*Gx>%0l`;$67sG-%U1vcPZ_C)-q?wGuYmfrH9(4Ob|L+n-+(#X6D2QO6OEYf$C zjxmBde|x>F8P@)+||pT?_oLmTRbN_3|7OKkU+ zT%3l_-f6>|1#dAqo0b*u)w`o(hvB4-jjBaV#!c(SUsVct*Tb1ykddy{&D$m|y>vt^ z2%Wf#8m2N%Yce*4kpQKSQpAhX?1Z1m<#W^IkI-&_d45{qynEjYg_y^FYpbWs0Fv{2 z8j@dkPnlLR3v$fv1Fzl14->eNm;r1U`;x+{2+{B9PV}!hjVSJfenuKJUkPJ*PZy~c z7FF(HP33lH<0wSvJgqkEXVHY|S*7Xv;Hof@$9v$M=PHS4Evh<@{d)|M`>T01J8HRm zGpG8ElWmVsPWO$1TurQwa8I52Fa#~6s*BDH#}frD_Ql0)N;Ne|c3?SN)_3u8To`HH+~9%1DfbV5ArkwQFP#e8<8c<_QX zx$i$qwND9C(cByaQk?C?{WnW}CdK+Bp2D&_k@AWMLQ3U83cS}fX+`$-_V9>pc)yI?HBMFj)-TrbR`WqEjzYQB z4nNr+w~~&V^wldilK-UlR;&WaPkrfNUlgtn7^BSvqdcCnGk|J9mDoIcO07_hz(3ju zb2}HE6jDu83{g(Y{P{;0VH42v*h}Kt|Ag($&-#f?1b$9jggm<(@tMmX@R^;mL0%ZV zmPW&FfoNloHHTXeS$U(01iRW=eG`Xmatzk_Q|nwEZ0`l4E;(ThRz#(aOum~-lcnUG z@`gkAnj%|LOQ^a%NG)1Diuq}>JI+)y(zvF3v1 zkZ`QN;d4MLCyQN6y{+|4aUg0ErWk#gnWB#SQMG@`Su-Par2i@|rjR<)j}*c>$b%G7 zwutg{+T|WTAxS_@54eL-Y3#ToSDBk?m&LD5rkVB>GbQ5c9IffIQFoY2^(-}N8{Z!O zPIFG7KRHN(uP*a_c+9OXkLHdIiBih1BD1tfsB$usxZiEu{yhEbPw_fodSUrnh! zUu~{jChVSBr4P=_GMPWruG&1uQ7cKIh)n*W0TFThFkS#>S03_}B?Z>WcQ{%nqm2t* zd{~!@BQ8H>x^5GT*k`<~qe5Qg*zrQVMUH3$xh%sz={o^Y+gJIv>62_i*dyVfiC={L zjcMKSbh6YtovX!FhcXR`OW?i_xECCm+uJs^5qW|LW*v+i*b`DqOT1!f{~D+X5)#!f zju8m^PDo4`r9K;VWSh(AE#-(Qj8AmBn-5&IW-~}fQOw{_cz>ImI#g@dhA_XA06#(N zLyk{HS)$8A3-givalZ#v6BJ#^Iuk75_#&7d?2=ct7Mil+ryCE}b*FGH2qJlEjV-MA zr*~4*z+CK=?@?4yF%X~3K+iBK^@xJ()^G2l!5M-*%VczSaox<6Zzk>Gp86Pp>m+Q5 z;+$$><$-cu?&r&svR?9&4?nE0O=+p?VPdInbqseiQatc*n&K4Cpq|{|NFxE1un5F(pa|C&QoFZoKzyfVBegbLMUR00_wK_5|Y%F&?RfbUXj8d zD5T=&m7aPW)hpVZm)l(bK!fR4XCz{fRog2AfrOJmLRDN;K94mi9x9}sLER-9SLwS` zW`%6wdr>n;19!AHt7QdFx(P#-4a_c*!VI-Km1GeAG~AWO5*|22$pQO`C5+_hWYd7+ zDax>JGivIf-*Rdna?G`m3^|TI-XV&6?)4J52Vfp~mpLbBQQn{mU$=ORoNl|PFX%CY z*&U)x0@JyDS(1bzQ3}5JyM*5Bch3C^c)#3N-~9aLt8=_hx*JIV8~Opr81FztpZ@Ka z?<6AhS|oekBsWK@Qou6M2zpUbNkun&-yH6KIwBcaR-2?7~-DrD+9PvLM|5lWz3> zO3PcFB zgPPgok;-_*+#rKn;yFcoRdULm;kXk+lIt%(>3-t8MUp2jnP}JIARXCfsSS=~3~uLB z$?~d{2a19r_#_7q=}=84x^xe0Yr3e;#=p27kh^~_YB(F*QoT+%wocBp6<^~g5-Ci- zIx}ZF%0{=43f#m*YbaK_2O(8_s$(UI{Sp#D7IXE)Bx0#nGQq0Sv`hAHsW<;7zoinz zeo4u3feELI!GM=3dAwsw-IJpT=vU~-^5BusNMTRmYXUYjil2hSh(vEZFW(F_>D}^d z($R`(A9vV+py6e-$=h3okbXP9ta~fP?8obBw_TPyS;&WB*#9DVLcF4$7LR9jRxsYZ z)sPrnu!&*G6fIh_RxGL^REUoWRgf+9ns}M)ibQ@%)gy`rr0kH)9AV(MIZ-WvcWP2$*?#9X z;A7Y)and~hu_Yu7#T%uS7>Uin%ZkWXNpYL>nX914i71f_I-+plnu>oSkIHfAC+@5F zAk(E74t4bTJ}FanilR>gpj;{umd`K%hhG<5gC9R|wP1byt_i|=#1@&Gf<1Mam%GJO z9$%B{;sFscLewt76)*f?s>9hr5yW?Tc1>0_6p(pIqMTv}i8==y$y9drdm%_I(~N-1 z`nA*uiTiuf{U=`sVDue2e6YvZF%98OX*f}O*dymNm+I}_7bSzy_aN3O=)2uJ2WygS zfmKX`OpzE-(>%QFivv@sShXAOQ0!47%ANSeZ4N#W-%Phff)*i#X|I<|lm~Mj3wg6w zaTzny>@I|!BnV2D+nmQIW|jcJ%kUH+fQU%|J*Sg)+Pyu#DJ`#215DT=5;#+4JG>&7dbw(`(csFyf8PoFvef zFMmP#H|KK+lYp+o-+RVolOOy1NOJ1Iu-WNlYNLrug?~8~)?a98DAP#J<^eB?Me)Vg zuhdZJ?4vkvw#eCHw~lg|-YCC1w@f7&KOi-XmAI4&_F4S3PuB z2hy%IkpHI!RB_(o#v1R%)_YTVM>7a4Pc%8WI-rtC1%%Y37qDNiJCgBA&z$9b3VrI9)w(YRU3gH%U#E};Fxf2+pa`PrUvnyW!z|818I|>Q zH~er~5Q)Nj7h?EVPk@QQQCRe&B-AbRj|RkJa2(3c-X^#we!YvM+rFRiJVdwG>h`iO zmBXp%;U3)ZF>>+kgJ4@$&5t9fMV|%P6{;F{I*hE$NJb_grC=EM{nzeAr+d-vUbK>N zF}Ip2JGeZ=j;@qe#p=t9ry5$+-JpgciYhUOF{uf9D`KM1E5X60L=)z7aVY1HQl!g1 zHo%gij9v@V0(4QSy5}r~6P~ncx=F7{cOhx;z!OH~vGuH=X*^nYKQ4hP_81v3!5p3| zH9@GtWrFh!fl5Rye;iDwC)w+F)s@_&5TX#H{)Rr_+*}f@H(CNli*k!mkC(U>=_A$+ zSzF~XT_I8eMwOY~-Gs~fU11L#gkrB40g0-UP(**HuwUx^J6Rcbkn0}4;bP5` zdnI*+w7*btt!{)|RHP6c*IIN_pT4?km&V(=6^V?)5H{O96^Ds3r5Ly>XiQya-C}EKd#|Fr;r;uY+lgBQSfv+y8R*ti4Ex7 zw)XKft@CfbGC)*?$9l;=`5lYaooV~jM34=%PyVJq?~D8Q-g!#fkXJ~(IrF(F692ez zZ^oV=R)p4l3<>vsNT}Jdod4qM{yU6D>LBq);SlO-`EteOTD-&(x?G<>-OFWuS8en$ z`)MUo4KaPmqgd382@*h!`wWp(Z{HQvGu3``eXthh0ESDtCwqx|z9;Re6tq(`=+0ro^Vim*vqS^3D;(PRrY6ahtzW znO{rBh`E@e&?&!2;PjqJ0SOq(>GR(SpnBZ|@C(gp!g(t(5HalbGP2-i$=ASJWwR)a zLM0h1Z};XQ6-DEZIw?3OdIeE{P00uQJCzcv#R}7_qBP1kuZf)ZLk=h#J-_9t6}^)A zd@^k)m;wO1SlsD>`^RJafoJT%t^|)5Qvu8lT|Zlpjg+~Hpb+9T^#1A=>9qEBs#611 zX}g#;{dH+?uAGy;P%RQ}m{(To>4m>@R$MFkJADH|L8+jy7z6W)SQ6nVmzwE9Xf&2JBML{v_`DVQ8RHA{sew}&@u@c7n>}ji&19x=0?@= zy%K5>a}X=t(9~YE(p`+noyu z1Cl@>6S|FR=@^2$O4j9pA@){d!LTt*4H7glLsQ8 zd3HtoAG1=i-@7m052g}HXr>65((kAIgb@pc6PknlwAi#u5)1q($mxO}kAFVu)>~|+ zO2Zz4;~Me+)ScLAx1R7puOgO79~aB@{!UNC)mW!u1uJK0%vxM*k8d>&s*TJ<1nG7a z+?|E3KE*zc=GD7hr8_S^UXK>RQvt+^T1$6h5iIAFj)vu&0otwRv#ptzux=)`uBj}i z!o0}Z@n(&dN7OX2z#Ef?IkJaB1ne6thxcNCEeyp}L^c;?!(LPeQSk-CV^Ao4dlZcX zFB`#k0(ObxpZC#F0TJ2tI=z}hvo-YY#3-D?Dh2yec0!CEe*Za4RwtrK@CV6GJ2bBi zruat(8em*MjvAaHj^rCSZNx9`{k{5#oQ|*kNmY?ii}zbP#4@<2TTb6?v1xO2O$UF^ zw3Vs)0la?Xw!5*N|17sOfYwtSE!ezDf}4EYz}aP~g*tSFnt`H03O1PUcSCTdwr_fv zp-C+)t414ZjZ{_(jWj(gtnFlkn#9AgyAM4hp!!K0MH_4qlUFY(?h`qce^d>8m0SpK zLJ>qdK~u#D@!V8vVvuWbOSQ%5SZMKE@%H}IRw<3cW{vDcyaW#-;`<19@Wc#L8$)F| z$@bs3{Ywwob(?351|dh5#EwS7zrWCp6I0aEz6?8%BSks4&)=(>-O366wHYP7fG5Oc z@{TrQfa~SGiM!BP*1uKFA%=UMNG3xJAP^ejuE#=&Pg5=;fFtI-9q`EgcVCii1DeFE zmc@3ufO?L4xX0O5tpcn|)m5vBBRgP=99`^AMO%dCsE#&o+B4^3$X9zFlgC?oXOTKS ze(c0gA-7HjInz*Yol6RpLT5?AGBvd5g&mR>gHl*kFZ;N-NMeA~`yG;g`vk>35>NL; z*$h?8)-YBvzn%ws8r`@Pg7(#HYH!27}O@D^erWLO+~Op|6v9srfR>cUod8dNyVM zV!wnxE)w=UtQ$yevTlHJxqed>@^)vjzsd?Qp+FBL;;jiG=r4yi z`w0?!aE19rr~%K3e@QzfT2@xiN%8d)X8^=Rh4PU+D0n25x$n7u_zBx_My=UlTAV+T2V&tGX zc15$X7%ng>cF+(GwB!uRg2_@OWG;%|@awf?H7>N9HaM>zn* z^AIGXcULLxfDrF3)Y4o}l27g@O0)2zA|H}FWew}}IY6jXMewUcEm%aEpSoy{Tnk}^ zLTTwfG}0?{sI<6gSjI)U`|42#oEj0T%@F&8K!%KnvcY3$k0fjF zZsr9t0)!2fMiiT5dA)LvZ)l;t@r(+UuU&6f^0=hCBZ|ICZ~ug-H@#;=FMaiYjA3|)DRt_lesnKYmZ_HwUvI{Qs*_-(6tuqe? zehlB_NG?29X0Mgub{9|4f^&$oBJ~-1n>xN_0BKq5p@tS5#dZ=#To3TSQV^8Y93lNt zF~&_Kc7El3sy|&TGOPEcHUbSvni4(km>fpju(CMA9V}lrn`#D3_MCCbmLh--GkolI z4fo&Vn>QM)a(6z1@I*obBS35vb0%ovY#RR|cg{YpqFp_A?zILwXGK2lm#2D>ztmtg zsCEBkTt50(&9G8~)}HrGpH>azsd|l7jGmvU%-2*7m)C?P^cMQ9N*gq{YTQgQ?=$mY zOW*{3v#(!$(P$O8;;80(cQiJ3!co!5I$!S2JGNt(D=#H*KNF^UD*DhD2{*-4g0nEN zp`Mb>D&f}}sQkTQ2fiX&1&y4ENk<$>oi5VZX30_cQ1Uv`lsECUiYHgy|}2yMs&NKi*BdW?X-n$@F<^C^1aEFtreP}CK$zh zJ#D5(R0dUM>Znei529ox$-5$2oJi=?8SV-D! zN>NHJv38p`rKF-57}BN^hT2Sc53Hr7636WhH+d*UyQuot>9srEbAAQ1$K;x%3(|9N z26M^spdtXuxjYVFAJiq~NXb^Hv>RG#*$Qeziq^L({=dfFtT(bG%kRAI^qpjExmDEG zRjrYL7KT7XZk72Yprv`xKm!cWkf4`&aMGQm)7SDPxP1Ego&T}zUUz2Ktx9BMxLvzu z$BvzSd9w706Vx=rMu1FjTeDe91n}qWD@9C_3S6VPc}^)ZVNRtD{sVO*^4rp15r;IL2&aFGSGx6XxT|^1O&$j$yXLF78~9{9F!wKg%l!69-*xWO?V??VSrtE zw&g%2BvTEzUHv7D{15HwpW4-*+tr`i)gRl{AKKOL+ttT*^}BZUUAy|WU47H8zHV1v zwW|;9>V3O<*Cs9&6JB-M#(7mi_bKK=Q6LOgzy&E7($(MuM@ug^YX-{Weg_$tC4OO< zF~h@^2kW3~tBG60my&JOE@}YMVMXPhNxI|JUt6s|w_1N{wf@*@{h`(ReXI4c)%snl z^<5t=5}X>$26lXtmD&ftEJLKk_~(0Ry=R_!y}` zeaN|ngk@$PUMbQ$);9kcra2luC$%b(w%#GG7V`g+D=jw#`BvC^;O=o0&Xi@t^N zgtl8Aq(2bQbWe-9byOSk!Ba; z0ptG7tzZeP&LK=B2&3KOH?st(7?ei_S5x3E*DD|gN!r90Js9K~N==4%cv)n7hM-Ft z&pm~lj%~1Epa71wg~&|#!4YRpZd5WaI$yYS3A}dc!c@}U31-Y-a7j`OKS;xItdtdn zZMs&T5933tdQWdQ(k{ul{Kw0#hBfHSLRkh30BM0~smb{du3sS)@5@v>|Lv%LVw^Wj+B>WsiJGo2X7I3}_s8?>i*EK|f8)Kv zywGL&{n5h`Nt}LL`zf(|>%&I5&k;m?YWT3+jK9FB=iO`Ix5*qLn^5u?ea>7v5?B$V z?Q))+Os`Fn&{L#i&@OqL`}pupSfbt9iT_cf3xxR#25JYCa@Uy5Shb zfxkw8inh9NpIv@+yw{XELt;xOb(oH@^xsSeq=!hI9`TiFF&HYz_uJucnc7_W z8bi&Tl=;@VChPkZt(EARA^{IP#8IQB$!>5Y?>in*v~s04L`W=I+!z8{LPSpr<`#x+ zQ(MF77GD#j?X_%fZ2EuS+1f~19IpsWLn&Iu8&(*F?Cg%ljr>A;^zCCu)lRP@+ec3V;bmk=C4p0|Llq?L2Nh*P@geC2pCvd5XohM9mwjIfY* zv{WVcqsUA3o9y;zf!Q$GZQll;7sDzY*5Lht{kt~9$*<^q zVGV1e8S$QF9)A2K?bjV1MSCVn`k2bZ1OZecK(D;5f^3H+=Jc>qI;X4Ys@X@p(lhlg z>t!Kx3QeSeY$$T_@2l4DtLo#K=~W+F)yJy(T~&QoRo}L%Z!2rV`E{!br5re6qzNuNamaMdrVl5| zR$0oy5VycoOjOvqQiF=4z>woDf2A}mYl=rlR&@@X7DaF<|6TGA;e*bo&-Ehg<2K^4 zNeP@`c+mcYtmddekW46x8O~pG$<&NaTig!V;^M2B$Ht+OA(rbhf;RpnT&MKM6B1u~ z;*Ua6=)xTV9cg+H#rNQJF0DsGq-79b!7*2nB(IY?dYoS0Mgz6-Y4PjUC&UUhY;>E zH=#JPK$~qHLsW45^877-`8tg(QL2dW+tQ@JCoZLLo!y9>#)oMrG}QKqnPeXs7T=30g& zBR9HmWbdX|B-j#+WN{=|@Z2qx{rcxkzdnS#&bre~LJ{DlBrlj`_$+qjKRa%ndxO#e$D`z{l z>+4TbvCc#PXlD~l9XOf}H!};uUf|Fp-U~7iCt$lUxI_&45185S4$l|(laZ*bKwlYp zV;^S7`T@v`8M)v~`e0s@Q8NwWJ`h#VBYkJPZ+JTU56phpEuuO>L6N2@V(>um04o!F zu@8wwS8R!D(P8BmW=u}CDa*5}p^HsI$JP(D#WO!`O+*Yci3vu8ss#a;KoT7ztNB)0v02KzGIy? zL$%n15`{^CGtp6`59r8{YLzH-Y_Uk=-bwN$#5&dzjFbx=&j}QePa1_5nUf9-1JZQo zJ{{zEGtKa<+4If~sxu0uF0XeT3s}q*MlMVU3spx82{su6wZ-y%Ar(f~=+G)aT@KSh z+oxR3$P1%!ffJn4sAupk-xkNv+pe!zphF}bfeM$yM>55Ds8~9xEKHO`m2CTB7U6mF2W_f*0>~mtD|1ZmFZ9lM%yfcnoOz9jdk`fvy%B<`pFPMv7;HcY~f}` zAk&lHp;XzDv9JK~=;6!c%L48&U44^lG@6Sg)GRB;UOs$T&+e$6Z-oXu&fdcH>*TLK z$a&hB^ot{S*9VF@Es3?vUSG`p4O>5v1LX=t&?!j`rY?^4lkUSKmFfDTXJ*)n7Dn6* zM_vSD9;I;EFek!5Z7!E4y!a!@C*h#q<9;O~ryeVJssK``7iIZSeOBUAg* zbN-MAdrKvS+7=_a4^NAyCy578@jE!!Zgyv7=8G|-ho>j%H81eqqC&5}tQTM4w807# z;eZO9nOyOPDB=x<7RfOu1K81@O?W62G?SUrHznP8DMreIg}u?4s3cV!Z4$QAi;l@w zUxAf{#}7-o$#1N8@hKQrU-zao7wC*XeW$hqVSO~{(dZyN|0U3yUN!7i!w#t+IL_V; z+i!>MH^cVjuzfLXpAXxkVS6}i4~Fgju-&5@-mu-lvumE=b_+*a3~cqDgifxaE?{Pf zMk5um5e!vkpXgY%=^TIw4=7Fk|4x^%0svx`UKiEV3{IH@it#$pn6w(9Q69M%%#KKn z@r0^M(|tZaU}W^#7_Skr*RW2s$?QdugkT|!i9N+dcgw?XhN%?GmUc#pT|{}*_Ot5Z ztfGD}IyfssSq8tzG(IxCW*{dBm%Q(2?`A{}kbLOs94c2`Q)+*`k3}cxIxnvA+U{5(+%v zUlEk)O!OQG^aoKR_{8dZZ))gM*8QPmw)9df`BkOHBy5PE`9D8(WxQ#AxPU&l$j zf=OnIaZ5Gu4$VQOr9sHT(%xH(xfUhmk+QMXpqiEdk1|y@u{5x2fTNM1GRt0y=yDpN z309hIXwQz+q&`+z8vf75jGQoZKeoHSYj?kEcfW0SziD^BZg;_=tp__VmjuTyQDA53}N0Yx77&5}29f&|(V5^O> zTj^piv-x8{={-DKc%5!;SyCi|1qlQ+6)8QjiowInlbKuYa7gbrK0no_!~7Q35sxDB z-SasT-58oZn|UcEHDk3lv}L5%fKmL-)N}23tMP_%00gMx5Gj3hX;@TWW9U1~E<9hy z+O^Rl?}qrAAW@Ro+67^LGEZqXE0RvuS0*k4UJA!wSKLSBd~#i>VKzGzpBWb>*jt65 z*|iJEY!NIDs~$xM9q3u;4v|jw{6z^ayGN?C<vBB_Q zR4=XffdPaUFrwq?TA^5^MVZW=FrgY*K_PQyPPev>nEw?UBh@%ZL3st+$8$li$@t!^GL2uXpqH z%}k$tt>c2t!oX)!S~Ly%XWF6tv>jV!f>2sPQBnLafo0J@zy72#GGv=71bmNV3}(~F z(m-g*WELlnVr93lrliI3??Q_1=H_H0&5Jqq_VI)DVOn|f8oTu*14SA!Di}*c3%C8( z-WL#VCPjte5h7$vO>xy4<=1iY=xs@5ZbGL@UBt~S|J77EaJ0$eYD*E7gn{kwkcH>* z51r}{XBK<-hnBo%-Rk$9>i1{vJ|i*@4_fu{vif*YeLSx|j;fEt>f@mGaZr8iS08)r zkGd$JR#7!rH){@caRu(y_KHIOZ|D)-}oCSuM11OWXGNV`EhX zHYUc^K*E@HW(cMyklp&qayl;<8U}tB$R6%;)^&E)Icr5!_ zgF<+ye7ni;bN6$hP&D*{53!*?M@08!Ew+kaw~A{ zMi|QXp0BDTfb^CMDCD;!$6eKnK85d#u@xf$Vj(Gtv6Y~7{SSH1h04qth#bZwhv4t2 zNM)X!lc9KAf}WML${eHS!Md0qCNBqbT=Es|14<34B-~auVnR{~N-<8P2Q8&R>5A7w z^tTn%bT$Q!kh$56gzL-?K@1?c>+mHz7cd7%5jNEGYiIbS;qtEqCu>oe#s6`MVo)W|?8@%X>4AT6b88&P{Z|IRM*&799LXxDX$JKBz{h5! z8;x=D(Nxb$dcKb}2Q2`wX<8ky5RCZaoi4QeSXbW95u}Kxki^6^T1H)EEMH+|B_Ki4 zb9{mK(nu*sKC;mfF^K$thl@!H=YA*fTpw5vL3B>TAeLbj7_bUuq*;2(7F*1u`|dNO z0@Bv8&Yzy;g_vR9fo7<1&MICO#Dc9Ro`q=Fk=)NLK{lPNe2sjrl{EkqK?R0W>vIrA zjjYlSZRE4{xD+t#PJ}x1=_IR55H;%b(Z+1n&n7p>bBUx%Af71FIc_e1l><27o&NMm zf5%u5=tYjo7RG1)#wtrpb{$@hc=0+OajBTZv@0i@JOH#h~93)W}Z zXPfc!djH;xESB!3{J<-azs_`+l>on=$1@RTZ}Xv!8i{??f&$ZU=~<9c?pm-3ff?n6Nn+Q;T1wo)PFP8dzuG)JcR6G%?0Q4S#4)l0@YbWB-FS@aL zrh?1*P#VKqiHNJ&B$G*_`a(&_r?CedZXTI3CJ>KqI$r=33L``G*y_3qc0t2nnW>geecSQ!)F#KchOG zf|a?b5unBt>xa#HBFuweJq5HePyIX|7kkug$P6mJCN-hX_2W+>Qz(L}pml{6XS=^S z(#^uxKZY;~O0PMs4T%>PC>>$gSn#*`6~c)rDd(IrZkx?tFu8$oyaIn+?y@?!guAC_ zxUjs?)x*!91!^K{yy%~OK7Q9xFpqR`hL#4n!g9mbH05AH7UP~`H2UIBX}l~wJORBf z7I(yFTW1}T#Cucfpv@5V(laD^cS(@h_E`jk`e?Ip{pZ#0*{m?WE2_nfi-tEcsNkZnu_li$t#Zf9VapSZn!4J&;j)cLbaB7G0=oK(I_S@R`c!E_?YEq z>SCG`$Ks&sFV^IouDw^08ZTR1I`Jv>!->Nrrde-B%OA~CqTsQBB%o%_H&TfG|NOWA z@!$XTTz@>!q-hOWM>uFP@!X2h{zpb{7IB~ONBc~K2}^=~ysUL;f`mGrOdxuBc4PQy zpBgPG$GjgWqC%Jv9A1xc?UScYhPU~v^juncvz7d(X8sd9y@YsEUzlJZvZBO#qe0*B6fZ)n;h#NQg#vhn;jo`+QX_1EDWv@s8 zrl&E#FjyquH9arRDhbEyRr$V|$sdcU14sp!bQoK5!J#5P*lx8R77hBRbtBr5Ttzd@ zAAb7Tl_hDf+&mhdJt1U3E#lG*N9-sL6fr#9X+03!D-7w>-EIVx#8JA*(eU+eRXU#c*C*b9akFNcoO& zt@#teM=Qo)@mA?cb4p93N#PDRVEFYrxdYWgFq}#9Mn}U_@CI|{ujK^i1q8J6=6o#t zpW}C`pZ~e4{(4sZwO#$S)%t6z`fFAFrK;e%q_*) zS1rZax2$U-2EG($??yd0*uhWC-{~84dwZFnQNz0gC!LfDJBaF0HzZyofb3hvZIIfZ z%97#XNHvG;Vj$p!cm-L1grnt6$?y`+m_;7#I;-T^9ux3S=78DprPWG2gjQJaW-91n z1{r_8J#Wc$86c57ZaU{&oFb;daGy-Sa)VotQqre_kV5y$G=0I2(=ZdStyC{Yb1Xg5 zt*@xYgCHnlj%E1L!07g{63hMvGWyfZB64yQlb^;M#!QeCk4<{%jo;f^f;_6k8Ww>@ zYF98GC~!){zb}RZ(>a`0)(^{GdxBpXNe*3&udv&pNuqH?>Rhwnq$&T8V#=j8-(-pa z871#rp-~h@x8&I^34JCO4qnG`%Wn7^Gag=z31C1H-Y%ikiPKzQlozj;%D^>%!)e5 z+0m+zLr*v&l^M0mh@uCII9)9L4wlDerk2c6^L7+kPohqep0Fzmbh4t_|J{O z<8c~S9W4&?DNO|T*Ux|PQ&+^jbV+B@MrfhASD$~4?*XmiHAzJZXb2{Y7+J-(vOE!p zZ`_FMSwf3qDp^Z%Yy=cLJm;d^{<3YA9~$PMVis}JMxDIkXT<^s0bGv5&Dz3cUZEDn zi>^!n3L75LHc0tVKPiS28XAKbkwBbNiicuGlwvohB>pGK< zuV=EH1^C8elKK%BHds7imZ2KnpP>JS|3_qrMOgH3eA|$tw|JhQZHpOV4K^S9D`4s@ zo>wa!A2fw7B(%P{$sodxUb0!6S}$l~I1xE4uT9*eB09}OG?IgQ#-OA;Ji!U)+zIVu zxV*xC3zP6FjL|S!-`Vohr@v3Y{!Jm(!T? zX%p2c(oEzxG~>%P>g(nxqn%m2ph=mBm_!?aSyP4Ub}WLLeM_)7PUg}Vq!`ei!UR0fn z>WtD#A>8e(eSX%$?oGvb&Rxy(qbxUGZyxkFRd(t;1|S2)$;aQtrVg@1=V|;~)xc{0 zuhzG>CyaUNHysrAQd4yE40evg<#>(b5R;K4H_W(Jx+`9o%nI{3iM|{IBPJoRWDtCL6MLFHSwkA6niW^0CV@lOmen`x7do)lLo#O{9;&@!fzR` zIVj@G4!iGvP>{@owny}tOC7voGY*JMc$Lx$DJrj|&xW31CSispx2Tk$HR{OZsz@_W zgi5F#-W4sPfaY?HE3xd4lc$&308rSY6as|vJZf?m-G*_a zlm)h$VCl)j-=mxG8>YP*Om^Ioau}$yzn_gQf9U=lx1UHrOPxd*-k2#qo^wXDH2N~R zJWFM^Vh=ul{{DxbPQ^PmCbwwj-NEX>e){Rt-!9guWzkDg?8`<0a;mpj6q5+j zasoe1k8Rur>>fn&V7N#EtGoCyS#ASu)X)doeR%~`0#A3iQD$pMQh2h584|MJ6126*$X@)C_ zQWVc~Ey7)0SEPB-`Z-STHa5oYh^On|8bf4`I|?Uxw!C(ahvI$<#Sd*J+R~szP+G0p zhUh14lbaX6$x6qW%i+;Ae)!{>gda?UsyaW>eR2wrTgVYD>G731=ce-rJ( zUPRwc)9W2^GU!f7U!&!O-0Is~q(D*0oP%W|Y}^OCDFzBHeIN$1G(EZu_z?h83>RND z)+xn7;1877CaHf% zdlv4djpvYns>s~Jf=Y_d7k6Ld}o=@y$5`*qW4`g%l2t8+mCRI7+e2~=uV zl74yI50~8-_=`DZ?`+I@W#KF2v_0)H8VCY{NaIcErZgrsHC+#uxmW%0#TVcB*YE;b z85ioBM1aR+qgp^3dmy#fm<0X3EXpF}+-7~bnEJgarVUUc` zez~Dml*-K<4uqx)(n!tBFLb2Qx^cPOBgCVM8z#<_u~D1r0;LAeCAtkhOU(wqwE_ii z_>e!}gosEto>C6dMe3TV^T>4XE=?`B_6ebh$#II@a$zo>5%$`e(bR~HuR2A)7xdT8 z-cG$Xy~uZHg?1%k69rrN0B6~_YqfWEO?M_{5!YnZDqfF&=q;y@_p?2vhXapFz(S{3 zQtx9T0VG|7h(#>oIC$1y@VgFRVu6kXm2UuUjO8ucXtVp*P`XA?e169if(P(o!AHW` z0?zKOgvB)}zAFi@bo;tTC_O{051Q`NZNkIZ`@b zIZ7w_>4UJZSiGUYNAqc+VZPniOual^I|BP?+C_*JJYQ1#g}`_ds>ru>r31`H*@px`9o(TubUBXX5b-?-LvukMFIJ- z87ic(-Q80}EWXO=@eT5>ZpQcbCkuW6cd=W+irrfR>B?)jd#dVk-sus@2PtPyTIlVjcDFkE_ zn1hkQyq?4jB{*h#vXm#qTzqFW`&S|YzcCULZi+?kscOs)^JDmIcA%zL{6<>P2C5QReUK!mnZ4JO0JWrRaZlPj7>vOwM48E3DpM7vtg7f2Z4<0V)$Rq!jAoi5s! zB4y2@OZvJX$x)XVApNMT)bPW`ZD3wyW#yiQHc6fTjcalf9dZ!xtu#HBP< ztQ#t#o@S{hofRnVJANnMi;ydp5>2?%U(S)>Z+4@co0g_EYK4gwM7o`NFgDO2Gy(lB zRmdm|8l{PWSkUL6e);@a=xP9;W{LzeGJ5LBLp*gDdhWRfA*>`W!jQkeB<_Em*I^gYt?Cr;kq*3rZ2&<_*uka zrfN7eqgi_|ne3GM4p}k^kY}$5QAnk-a5i&r9cTuV)89jLF=>bdLwI~x+hsHtYepzw z!#^B_vtmXOFIQL%+~WohJ3TUFk|l_gdQUnN5fnTlH&c3)q9$H#<|P9vX4Vaq^OjLQ zceW|9r)UZ;MVO;xr(!+{ZK~Jd^`>Ji47L4aT0WI#6L>wKjGBE7@B&krMh9fW_6cke zxTDB+xx{_3L>i#S?rit=NIEG|c(C+V=+7dP*!l1ixTQ1BoMXj6?hG>6ub8fUQU{Eo`U`Zj*$zuBKJonkAk3SnGrr!k)>n>q+wanB0 z$~c`wU{Y`kkSpygP=;bs!N43*j~F@39$J2SxP(=x8q0g@9!WBR#ib!8t#8o>U4;TbI&`?julV=2D*r(QR^`D>_KW;-W*(iqX*cob9!!_!DbT&}(5}25=>y7VEi2fZdMlcU-8)jqa89jAf=SZ?uoQTu zUW~biqmF&WFm|qjzUwC)q)7k-!gz4zk!<_U2U{^^F4zy>f9jc${iokhOOD=ne}igk z1}+mosDfaJn4Y82Ju4hqbIcwM(XtiR90FK(z%M-K(06W;#Q1thN>rPUrZYv0)uq!g z(~=P~RynW+@$>@pW{K2B#$VyF0})5U#pqE&@ZZL_Vs**RDw9qeD9=k6eX*Ki_YRF- zh5foswCpL74~s5q$b$YGEZNGLA~pshuJ^{*Hwd*`@{!NjL!~Y78v%_XLZQfV`wPFw#RnNM8SmT*AJHZ+xt*;KUAF$ z)!B!t{h?BD4Bbz1K5*we9dM(^q{(;W)W5glQ$x3xBUcm(#4Cpq3mp{{Sde~pK1Q`&dfz*1z06c-OCLApxtPKx8_eE zNnjBpsw1?G63l4%I3^c)cQ2l3;!^RMOMWLb#Jr^_4Ihlv8x1fb=;pL4 zf5i&$zs0T6Ei+}sAJW8S1P-`)+Il`%&DVrTjXn8a;pOptW;v(C@cql3c|&4{MZ)-_ zND%QkpnN%4LYvKoO_<$=6;aTtBl*J;xYHj;jLWe#?E;d~ZmDZ`>+KZ4tPT-5O=Bf9E2kysD!`CNeCL zne$ceu6Ea}^|w2+cw)Msa`+qhg3T8OdI8P@$qA50zl0{7EGFkSCG5z*c&Q1@=WhIq zyA);tdfCv?r>f}m@cGB6hTY5)1&T+~UmaGf{dy^^y`~I4vaM0-xGJWNLqyCFW_I#^ zWGF(+8p%9o=eY$}}yBbSCkVt&jR@+;H zOZT%8Re;tM3qos)T!3{&WUe7fctdIz#7d=Tp?>+;GVcmQ2Qk|+QxHHJcz+o4CXVs_ z=L>-}Qcw$nTAZKR>{12J5a#Jx3K-IEM5FqzZ*xfw5&V4iDz912u1j>jzTZ-iX$9lF zJ13llc9YUX^EC?6LEoYyAd(_Q%Q38fTZWMK)+>mjXAx54F>H>Rv`Fby&=Pmz`nEba+_rlCxX$pWYn!nBdvV_ zLc0aNCy%SvDy^+hjtmM!6B9^*SsVz$Io&Ab+!VGo(c5R4VpO9Q(8W|;-J)P{Mnhc>c5Eah!|dF;o8hXOOctLzH(&q~;+D_y)JZla

Re* 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 b_RZbtX=leS&a^0>PMU?vH6$F$YyAHK;*Pue literal 0 HcmV?d00001 diff --git a/frontend/scripts/build.sh b/frontend/scripts/build.sh index 7e308aa..720b7a0 100755 --- a/frontend/scripts/build.sh +++ b/frontend/scripts/build.sh @@ -6,7 +6,7 @@ min="elm.min.js" elm make --optimize --output=$js $@ -uglifyjs $js --compress 'pure_funcs="F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9",pure_getters,keep_fargs=false,unsafe_comps,unsafe' | uglifyjs --mangle --output=$min +uglifyjs $js --compress 'pure_funcs="F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9",pure_getters,keep_fargs=false,unsafe_comps,unsafe' | uglifyjs --mangle --output $min echo "Compiled size: $(cat $js | wc -c) bytes ($js)" echo "Minified size: $(cat $min | wc -c) bytes ($min)" diff --git a/frontend/versions.dat b/frontend/versions.dat deleted file mode 100644 index d4dbe3a62e6788bfb5bfd707541876dce5801a45..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104983 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
8tPb$fIjrpZ>qJ zz=>8mT@`DwB5DtpS3++BNkjWVUKpP&eVxC1iph|Sb{_eNu#iKeK*S3JxYmg4`Jn9} zE0HLmDMFNdK-z`wdFA$Sg4<4M^oQI!@xiFB9LJJfWrM)1>0Si0hKdK}PCxZSqQt0P z?O4#)Q!g>~Uw##1h=%7r+z^CphJ|-q31R7Z%f!lvTAPelOcc*vn zjEINXormRq91!?It85&OdtnplJaqANLSNtD9zsnp47GR3aiqlZ8qUD})gvGF2iKIub(W_!NZ^#HwB)d;wn$B`o!7jGxZc zB)huCPv`0;ySmM;o@H0hRbP;>V;6Ibfa5;Gj=TMS&qW?1q_scl^he$PIO~r){Ylop zrn?Lzs{^&TJHX(bt3jtf=nN!AqL&Rw+7Qe(;8%k|Z!na&*ukhX7-xe?Hb4*8oxx2u zxW!Lr@GKiV&jv5D!OLv$Q8xG(Kb^rR+2E7T;L~%PeZAe6G`9vn?Ei546>uBYNf;0$ zpaU}%9lk?l2obv-*w4nD&LrzxXPq1Tm{=ziK#th$=0%o&yN87ax8t-E5l`oN;X04S zI}H!;&cYtvgVcxP6DSQdGco?#t$#21obVpR>>;{llYd_?5I+tj(B?}z2=ykY3o?Qu zg}S8Sza!k^DowY5-QEmVU7uRr)4~TYEaj^@+~%dyA07~|EHUp;|d}JA~>H6-9;wjsxe%j;u$1U z`AG0Zx7(K}q3*ET9d*0oZg(O#mqEvZkrJCBkO(pNq!X7|basjXI=#`~au_KPL!-Zw z$hm0wS>bmt+J#mCam*$m*^T3^gHaSamD2@mK9vm~4fDz0kVdgAVYoW{TT$(oWe#sa zJV&_=iPn_j`6YO2;-)ZZpT=H!dive)ZzbX`y_JM=igIR&E}ic76$~e)NTwLp{~Od@ zLx1rzO+A;fp<*c@X-?b+?!wR)&rYsObjuPDnw*?#-0?r#t7uCT0FD70P%zX*EeHR* z{KxmNf6&24E7^o{Yq1%hJA4I>dJ3in)NTjZCK(J2b#Q{Fcv>KC;@@sI?up9<kL1ji|B@*!QcPwH?zv5ofmK^9~|LBFdbwPZIy2F&ENC&-CuDO2yZw07ZK}SC9-6Q zua_-%cM4P1&-1@mGX!M)IESegxN9R11dn%ia?z$t{tkMw{oNjowTE7@H}Td6AYs=( z0|0>(f1C#&(hZOfma#_!*LWu@v7vUfO~?`aO6%fnX_m8eUbSIH>*|hN%jW4;AC}(i z|2aXNfD%nE8fNtR4^MBu+;7aV{M<<(lr$s1Nd$5II^UH0f8=Xehjk{Sd_RM^&hKE@ zwlKNj>-@BS=RsUFzd8G($oFWZ8pthLi6{$B7+6}={P}AdA|+p`+`!eKlXI*?!1kv& znk9m~dA&lQlH`OT@<72-gaLv^cl73Uxj>NkUyIE!-iw|NaMULN;~4(BPyJb`b@)MsvJ=UGB@%;Wfkn+jgh5>_E)4r>ObxH9Qj`ko_4l z^TbLkD!|lp1(gTlLrS334J-b-W`>GdR+>CbCsUgNC%Y&RB%puiod*iLPp!3!*_8OL z=D^00NoZ+eVHdR?9O+ykm|sJ{jC87Xx;bwN(e-|sT5r9(?HirxhYkNc4P>#w8xmM; zoZ;q#IMe;tI+nV+&&{iG(SEV8lKsqXRja2yW`=n5;c=Q*kqpwa3l z$+xeOzNz0(G2d0R*tviun+9&8&3^Qc*T1hM;#q-sI;pKRWq+*z#r6%7o@~=D15kto zMKe_)kmJb2Q=66g3d|i5w$YXW#kmH;VGzarN*C4?4r>6;v&VFYSj9+>x^++oVpd0dm3;FQdVO;A|b>|=VvX2L7qF1CNO1Y#FQ;+ zPA_aK7Jhk+EyhH<`JAyV*nOJgIyqG`IPF?oJRdes3~s`G+$0?iFhpGL>*XOOIMuVi zi$k6@Jo$^=b{ITFsJjxCDve5<*8&zz73W*%F-FD~aL zVp>G4*{#YsELKnjb)zDv=l_5@@bEn*1FJ2(_O_LhwpYf&tzcz>A!i_onhV5OGWCMO zhxVx?$=xaa?o2178oW=*9MbD_29^TM4pH0)Pn45CPQ_}c<9$#M6wUxD8Rkc%LLN(B z+`x9hP%b+&iD$-P>LyI#$d}jt?6CwcJx-yaATX!ps@(iz1@-0dpG6sxlZ2GtmEI9Y zIgMslAzdz;nc;FebXymK#?nPHW4qinx$D_KN(jBHr{78}tT&rbfZOCxGh`(05KoFI z74MOcQ10b_KAI>ZKQny;ZC;*TN%*8XaSXtDs-O3=k*q^sqsI z-wGEl%Djn|Klm?1g_LuJAVXau;8=f85p?ihpj=C1XOtqoT1>^frOj2wlQq$oAcw7g zg5sV)^J3C6hK;RG`w+q$4mr8tDLARzDnG2I!ftd7h4fphU#F0ys@3cs1R=6fP}(pQ zZH426TRl*hHt9VsD9+fiDvA=VBlA!q`6D^K_(Zrg*f*AITvs1gVuH6_8mT297I1z> zIrL2=?0u!b_hGs57KHae&R{uv_1$+0IicMw&Y=hg>8`yt9OWrsd#HlsH;Mq1&Kgl{ z{&W%GcZ%%fob5Q5dXXxp&S{Sni#v>df@WY|8BpF$l4U`g2SwUb+}>?T%@NvxS6+Z59SI zSaO|(mS$fm%i;yq`nq0#FRiC=MnhHQ&^kBS5I3lPaf?jDZT+)DRpbVJ&9hd5^+x}hzFFeiP;Z~Qd+xNU=1 zxxfkCmmzDu4b4Dz8|F>yzzJE5uswKl&d%kUbGa*vwa;*??c&oze!n(>&WWQjO>dml z1Yvlm;{(F}j6SAvIx8jV0#g#!g#5Xe?n5lk6qiB4jTzE)g*A#+C)<+9c{y!Ul0w+L&<~-N zn$_p>l;HVu25(rqEw2D1E?>c%Xz0M(zCFRDS0P|X_DORM zX?t>`^=V~D6)iSx=#KiZwHiyo;l`sj48cks5cXh-2fK&3Wh>*EIlGaY*)V^YmCL1V z9;J}t?hXfSUs>Fdm{36SggRnG=NHx0)jHuGP#8&^p^7hIg#bhCH7{@Q62kryRLB&G zNBKjw+o8mUj!L~;+=p_BP_xJO`ZAQ;@M@Xt2sxv6+lMOUeM!UwQLZH95YZ35(oa|g zc6?pzd|48PJuRyWnH1C09+{0R_&ub8l6D^fjsW-;)!6LpxdG=KZS}@nJ%cU*5xKW6 z^bdan=trpiCISg=ud;pK6hz1CJR9TfVDnl^92@S0gi~re*=>V?NvXD^mjO!ZL6!a{ zy>MWHNrF})@;lP*BY3m0OF;Ck+%*TkXGU zrGYT~BQ;)^L%k{vvzzU!2cOYSED&*}tk0EAutbCO=k|$U)-b5LMKqM{@n~DGA2S|cEuROQa z@D_`Z1UI%go90F;QkmMoGmLt?KX|^!1A!)dCQz%^S_sUUmN@2~I4 z{(tEu_EzhWDu>uyUe%PpV%+j*SB65B2t0@oZe7|lG4=_n7x0jKPDcBUD%?^!X#ijoW&y&Yv7NA2UNdSH|E-Zp&E}I1LYlbsGnQc!#x6VAkpfVFW@^v zY}V8#aO(GhIq_B5E}jmSEyAm^EGn_MX!GbYQ|#BTNBMTODNo)9ax1dF&|9fYX2@%> zGTn#@4yEaGWh7*@*e2Jxo^|W?PBld-d1RllB&fqr=5J=dkQ5R9v)^9?kKh_e)POf& zk=0gk%fTFVu-WoT*`Z{Ue0Ks7+`>(*9lA6#$tHb-o0<|%thqflfveqfnlfrxg%1v|`*+46Xh%yS6Agee{P2vit3jL@mTO_2Bv!A2)fP&g2=Tw6~x z;eL*qr*@CoG_5~;t|_lPjBJnzB9u{*0U*ItoIGVIod|}i9)HwdoD_@jAlNM-Iv~Ga z|B#+V0>k_6*b}O4fCno`I>#^u=%)3Ea`!qk3G~2@YbvHiCjl{RgXUoxJVicTs+ssHNQ85cyLP0bQlCh#o24n?q zf@Z`|GFK|K&@`=-*txSIE;AK(19MggZM|?TS8|j(=7naHfLz)*n!^Bg?8V854lzoS zNa#qE#O3!vaM}`tDxSv(AU*8~!j@0yEfhr}O39IjinwAOau-kT4y_odLxvc77>Pn` zI22FPQ=Qlld>VF#nf}V%p8w<}55psmd1!xp+WLg>>tm7Q9>lesiPlqp__W74>kv&v$m zxdT``uOH@TgdKk(Z`-SNd`;XLx$tIgft{?sS?>-+Zk*cBXsBHl+BU zDH(rELzj1PCr-FC`o&`sQn5-msXNIB}X>EF&{C6VNer6HabZ?15#$WCKu zXp?F`1mX#)#^QuxWwrsb!|vJxEJWzUV>(8I`Yz&@K;nvlrmJ}=2QJY75TGTk#k&^% zf20zh?UM%yH4pAJ-CAOb-9nj}`<(6J%yuM*6Wkm`GBB-V{j%>4=bf1`C?UPsuZ(nY zoC6*bf!;L_31G1&b@szbN(I|WI95KVn&pqFK>|iKsB2g+P+%b@X>AhMiy7)_O5IBs zcIGRD%;-KnN99XYQd%IaL~NC&P)FM_oaGM>h@e&g&Qju*<1+CwqL2dl7yt0nN3!R_ z*5-t%3KarF8He-=PSE@)P7hCIZ)gw&&yKQ{X{g|73+eGvvkYzHj--ME;zAM=6sxUKbLGH{$SmKZ{aNy?-?0N;=tOg=jkqvQBx&p-8&rZs2dVa zqwy7DsaoW?Mmq^x15t>g*LAY#WJWWwmj|BXqz|o{s1SjM$tF5k&i$zlO~gZH#@VQy z8H#e{CUrT(6yFulk&@Gf0=-4Jo^8!P$!Wuuv!S)k$ym-h7d&)rw`z=PF-b=sBTmRY zhQn0**yf?|INU&|CxBmwS=YOyNON5(-gF+(`e^n7bX>t(<(oLf~})%wgBA2 zh>73>GhdKMiN2qjeA|Gr)WfO73nYnwWr1XXb7eor@JWh!&l44I^u$eqPd~<)2;FNy zJjf(>%JA63T+hn25Q$>xQ<_}u1_^~w?OReTbU=gm6r%;+p$`J%z01!K)ocFV_C)Z* z5i-9I|Dbj>E02!|0EC(zoZanXr@#~*K+rwyOo#+)gp$_6;U=gAA{Zj%TIRxCpYNYg z=xCaI9{vFq-$A3{fO;^rqCW zWoAxkE+MoceiHUnZ-0(%cMF)Ko6tqUy=FS04?!f}ZcsI;upTLVoMw7?QUv5QX$rvm zQj*AI94}a|!V!xbh$ePmVr)!lS%;(G5GD)Bs?vqLchg7_StK49B9&nk@TI#Jm+d6P$-eEH|#e{Pu@2}T8VZ#CVN3j}9H&lH5K?@{DDT5!{uv3hqx zM2~TpB*0Z!zDGZF>pm?L@v zZOeyH0b+K@@J-@A6f6C0_QX%_lOfjGwS`VurnEuquu|(n=VEWZ zVLHHH7mbQZx#>JZ9p|irO7qV;__zD)5;x<06$Ea`ex|1D9!(%0u+X)4R``V9ufABVkhtVm?*^jvLL@T&}lM*ns}Nld_Mr zvCI1vuax$My)>l0o#CNQsJ+|jke|%KI9MY#U}3G(uCaqBBo8fdW_Y*5Mi+*-Ft?(x4J?M0B6-GT~?=u+M;U3DE$ZhE0r*jL$%d+SA z>ENgHywiQ&>AlD@1Yy0*GH}C>vJ67bN1e{cS@v<(`6SCem7mV1S@+XU_OlE>9fXko zJj;H8CnWLH$v)5U(?N}a&pY_H`+2ALdFSf$PXF`H;EOE#BI|sSb-&1ZUu0KbcyV_; zs~%_hYEc;@ruMOd(V#?vK~*5_MCZ=mcPga$P?7>ZLEs15DS41LJcZ zwyjU@U@$4PWmnhP)}-8G8u@2CN6}sfd^VG(2I0JiZXcq;NG%w}CP7i!RKXn`*Y8FE zU#^Z`bQ~Rozyv21@!TKN)og#VAT}Dol_!(b#HtLyq7xX-kY9K3W~Dw%#a>#G0Rl}J zVHG+4XH(`n8U`iB9+fP)lH1w4a)XR75WryF8Am}UkF2QnRWuiX+&k2&&W!$wRR%ch~k3*YJn#P zY|GfoYCfOo$W6LEM~z7+8No?TBexW6M@%&z?vlfN}rm{h>}TMoBI0_+PO@#6j`G$j0-| z#F~J6;T5H;a4lS_0jfs#oggBLfoKTMIi*3WQd|p9^P;d-RI@Lgg_Cz zn>$$)Z|yuiu3_2rwp0c+m^_hb8c5dwCC=SJe?;n)nHAFj3gUTWI;{`R9!TRt50@rO zRs<)!6xGnhUuy1b^zuMsVn1&;X2@C4@PM;8x3N?i=xf2MeP*St8LOq%07R7_FZXHe zn(KoG*2q|XX&K}tE=oT+A<=oBH|~*H#|2-3dB@o z#xYT^5FX$j?Pl+-T_NLT=gZ5cbZCe$izpA|3K*H|G--v9bHz@}={hXoUK=5hBqOZhR_+7;>MCa)| zxj@sGlLe-;9YYwaw&E2F3j_w*g=<})#t_8MO)LHx7_`)Rxu2itZ`O{9xpe0w*Djcg zFsulUp1@t~BEEYK>VWc%QFp&gU$RrTcGf3cJY$U_9wbo;=Gw5{( zz22Y)c4(jG4EVyW_{3b&XbJN&3R{b7$c`+!_)Tyw05&p~KT0+*c{g0Hu32bN>=B9* zwo?}7Noccc+LDOpC|2*1cO-~hm+}FdOB&n=hN7_MHdc)8l9Hy;Mp8qNpXOY+Om@X2 zqG%p0VI7eUM$|)!!QzCB$T@*@MAC|9^HS+DlWNu|0t!;rG<&jj=DKkaJvlC%Y&R>IaPGKj)Jjg5wKc3$&a4Dg4Xm{5VVufet zkbBZ{uZQ#dO_WhbR$-}j+CfAG#`6ajUHZzRB*-MBcy*|^&>*~hyqj}>ubsI8;IWK! zzVtwcc*jj%p-}*}8=wTJoxiRcTaTmERy81wQozZ&FT9ek+wQ;un-|>Xr`E-2Q>>@6 z;_++!vj_@+br-vKt9>H8yUgAOs-WY!ymp7^b~7HdU+T7XH9&9FP{Wvf?LPvv{eT`& z84`DTbILb#X1EK0TuAIkdPZ$jNv?Uc2Kl;c>x5Lu#h1 zEF?d+1q{%`-aA)lLck+Ql1t*P4$6kzo;%51$HII?yty}qKNVxk9<_F0g)Za{UUHNC_QbIPIpAf3$-;N>~anT6ryQ!jh zdX#b+qDL%!>^eimXZ3^G;B(LuSYNRB`pwU0`3$%!!Y6E4h!2|X)+g+x{y9CmNdvr* zGmsP!`51G=eh6owDvSSeB9XgC?ocHgS?chLRTO4WI0d>st$RE_A;KVkH?rAIL`6L=)Lu5dKjt%l><>_HWRM?#$ zBCUKa#S{a{|8!5=!AT4cJ9eoJgMG;FmnS{iWQ3`l9zt{;XP@|`&mlCPQkO~;KIxu& z6ep0@syE0X`O(Elul0^O5$t%{8<`G!o4R5)I^V`#UIX&3Jgk0#(jozJ*4q~sPh7rUN5KnLY+jc~8$@zE(54H|#$7K9nzixxvAh1~UN^KItP%xrXuPKy6xPoY| z3T}IMw0uT&qgv=IHrMH3HqS+lh)ey2IOlGAB9li;2P+BfuaV?gY!9nr;rZ#grs*SE zatHiL>)@dDZ{UIOA!*!IM5-UF+38N(M7;xNkzl$*&P!nq9r6ZAAN1ADQZ&a1kHsp~ zxgctgOu~B=D$DAw`T05N3R9MRIQMyu+Odnf>g^NM@a(|`B_@Uh9w9i2DCFhSWiV@j43gn5JZ>=cU2XH>ax>TnFLZ#6idzBy zLZIno!>erA&xQj!dl6`0dsG{Y>^FYpO(yF1*i#YRu?Z3rA+ktJh<-zY)TrX-Pedpn z^qB{+%wXE10KVG%|#%$073rw!@iJOi#iaG0txU5XZDM_Uaa<~H|6%L@4U#y z0|>FHdh`9#wA-5nLTG3ZMcH@#&Iy<6a$2DxpH#_qxqSN9goFf2-`0^+G?SMa&CHZ4 z^q3WT3iMPi2tRGTj_bzMU!XO`f9r$=$b=U2ef1bI;0xlTB^GajsFN-W^~bK8wn3ly zK@sKdL2Cij_<$4CeoC4 zL=e2?JBa6awjr*5N5*a>TgUu#QGrz)k;k}%K!QN`)x)}a&_9k2Tjc47SEHf{P8L;# zFg^KK8#{(9<_(PM*-Qv=ibYpBUzWvF*uesEAbTUCT=DXR;B|ys#l_#E@khvG#H{_^ z@%Hj$w97!ClsVCnXA7%AbM6coZ**bGlUx^S!DqTqy$EVIbA;>$i8$zx!sZ37s6gzI z{!06#gn)y>=MOBKt$#_6cbI~OT;$VMUUNpKxRj2xQ7^)BdpG&psU%Y%{-MoRH-NNo zpIdia+v<4SrT8SHU~T$ILFh?fU7PF5f9#!biI+sQ6KUxqIGlx0vH#_t`?6^ zW&v`V+rFeMtgU(NMJiR+EoN}(fu9(dI3}Sx$-_DcZw#ms0}?}=-j&>R871J>_2S*> z0S~&%vm8454Xk&P0fLe$a5|PM4tiIaX6)}h2GO09Y5=eA3?5d6j(aBPvWe1V2V7VU@ zJ>1dCqNp)ANzX}WGBNL}#~|*LZY+(Gr^1*@gGc1-+GrYZqM6NYsK!|T30R3V;du8!$FIb!G zz=w_Ehk?i`Jk5YaSmuW{lwcitBJwSgIND>G>aF`{qQHB>;eeRZ>M@jn8)M>)m;t4TUHHsb~ZJ+HR$u?_m z(~oPewKwS@;Y25N_BgNF`FFH{UZ}#d9d40rt-uPpr!O`=378KMwHJlRwyt-aB3bUlcLT>ca3N9`miPnijE@+{lEREw9L~~ds1f5wT zwF7DGcS7wZ?lr9*uYx4_fUE{e&v%6MI@>$P@3qXFx) z>DHt>=2=NAaJvH05@#T;hu9+7?cf>HVYfHzUJbkbp#(zn(>e;NK$_iQlXRrk<8muF zCrQyKK7s}ox5Dzvx?qFBA)SjMM8sE}IdWv=9@SBj%v~Y@;a$qt%L2|$1qioVsEwSH zaf{ZDxQa&56OWnG@q2J#9<44D*$BZozmnGBsRlUylH89E+s3-(+}tO)OdJ`vDyFm& zDDT(PIvv+x&>>B!Xp<=L6e$dwFllx&jEf8X41GIFDnYVzBI}v7j>Q{-JhP?A3Ze`A z_qyoECN)`n0#2)(1W#D3o!y2rIMu9?ra~ur75Zdsi;9(@XY0~lcr|6ZmsDY6j8S}7 zDxh83ry+Fv$dbk@>JB)l=;v0{xSqrigLbqQln~WKK`Nw}H|^t>W;3qe+V?RJl;du> zrPLtZU8i)R2S>dv6gh9*+)3lMTCsAW8^Lpv*yWK8;xqCvmit`j{(Z4@t)T6`Q{j$b zlUf0<&&DJMgeEpaR=PCz^VN4rPk8Q^;BQ(ek&r@vI+uX^tUaeKK48%|Edh{1yfK)U z6N7!Nb>9Zb6LrR$-@i-^n2h_8a-r0S;`Tx83YV!m-}H=o=XSgY##P=4 zN`i?<6g3<#bLj2p4`$&^8<);xTz?u*8JklR(l*#qldAcukpjcTas+w@(=I7|P@Hz>SKoGXP9xmuXvzLxg z@3U9a5ZUFKw%5&KBeqbvu>92fk4uv_=ub;yZxV=(s@`m5)!B8-_v~6^WRsRQQ}|~^ zsEo3Kk=F=C>VrC+Y!Q61tQ*bsVw^v91hE!KojQ~#ClOSu%kz&+28NG9nCw$u#DsCT zl`z~7T1ktkKrOqT4C=D%zH7JjfycgJgEn|CZVcQ*i>=e7f`33HFV1J7EhsF)+TEtJ zy1yZ&%9ONQyhM9q!NSP1k?wQ@Cbb`#9%QsPnME|xOZ832gO#Y<8Zx*d6y|b{)oC4J z*wq~Gw`-^GX*#?^)a~(=m0(Gi@w~w61;`*rX|gxs{LwCN@l?nWUIlo^LNa*cOwIt) zXz-Lr*0=QP+{lxaIC_aVvMu&sRE1eusGJYvGa9t6LTg|z(E?&4v zf(au+zxI4ie3NwwHRzu?XcjYog$U(w;y&7VZ+iz4h357s>EQgaymSL2DPx1zOQU(8 z2f2o%x-1THvUZB4wW-}W^b*^fkCGvVd71lM!zn@mLa z(a_3vpG->I0rUZn^hj|YW1X}^yMXvuCHVwv^fW;f3(NB)5XlSGRYE7I1KhJ>;xvcPjiiGu7FF4)PKKXoKY z?GHXp$EqK#vmmY2{-()WG(2k07SdS|Lk)@<0@}I8G3YtqD$!iyM@EI8xkYM^gi*{tBOY;0!L0;nkgyJI0SZjWnae<>}Y}Z z+FOK=(JsaioL@~nSHq-OUL+_8Y6-Yuj~Dp-n;TI=jRV-d3@h)*Z|p5{&jhZW1(*KW-nf@Lq0=8fAr{Isy};v z0biLQB<`@B%S@ zKUlk%9>Jju9+Dm<`bVeoVs@GVf0ifYEkj86&ihL+csRviVx9I9$R_~=k0&77tUcJV zF}+{3!6BaALSinB87&QCei+QB$#`<9uw8lc*cuak4&AN9gD?^TEpebtkZV|E9>sPz zozL~Jl#uch)VAcc$!JlNJLLQ!pE%UF<2{;Hu+Ymz3J*#+uTG@hf=>$T&`$$~B%ArnNJ2c|Er#i@v}trkgF6IJ&W(?8 znEKmVjjNHuI4MCMYGb@eupZahcsvk=QA$mr0*3niRTu>)fo2RRt~jPm7)nPbvP{RgXjXKz!#|f02rOyMrx$$ zHbq--ewg}$9APo7Fcdso_)7a5C9P28e+->>$zmTkL0)o8{xVE?->P`Hk$2*Q+KYbp zfs>+g*cxTqy7ZUsfQ5ugkXksM2GaGG%bCuB2oP7$j}Bct}*D70z{!qNDN+F#?QpyUb*#pqw9*a0?HDWIc#4AgNc)pF$-P1cbdl6rr) z;*5dC7NuMQMQoeH5YHbYN7YWo3BB->K_Uuo%LpKlR^)kGYgPl~B}}Av?#;R8#8w7> zFHjlMQ;mx-ynYmZeliNK_AfU#5fn(nd=WHISN*ijHX+Or3Xhg0+$W$X3QKH%gK%p7 zUCOa}iU}i=?u?l4)QSfit}BR1$}EO4?4Z_kaVeP+-w^ zyZl;i08<>GoY#1S)OSRm2!PrSQi)DJ380SrkcGIxrI?j8mnwG7OEfQ{Nr_Fl!r1Dq1>vM zewsY5Vd&?f8?anFk_aI!7{Q1ZGgzL=#ji~Y9=?Od87wJ{&Tm&=uAdO*{3Q}nS0>ar z$%C0nI{&Eun^pc$ZN=M#avAz(VQh$uu*Egp%MrP^4S`T~_bv*q=9qaLwnW1>udl;e zM+eWrlfoa6T8~m#a8zkC5?;^9U}iyCm1?<$W~>c(bPOhd3rxQw-7wKnzZ;=E-Qo@p z9_sH-&RR@ow&rvsY!dQ0D%5m=yG%iNSK$L~1OMJhI-{K|~1D0z{2v1yk?S z6xkuc_z*!|t@1~k5DyKHe@n#%JG69H`m18TH|O_rhI1Tf1C5+%p*oV&5S$p`{8cXd z&ygiiBkuxAYQKB>l#E8UdO$He-J`~pOIlx(k0hpb`YS{}BDJP$B9kKTg~PPlb52us zKa}#;A=!@J?Hpflt@#^dp?U9i8&=oAc?=?9AwVEDH3ZN=(Q2SP_GW>-#^SG09uw67 zVFQ~RYVb5`_SW<^y#x@%UwO?)%3mW~$F71e)t3Tbi=X~tW^m6AQBz)0=M^@>tuZQf zKZxPN>^meziBRDBx8)CEYizPWda%+uvoK>~noDNp&;abE1JcWsu*ljkt zQ8CDVy_kD<0f&g}+)2DYpgafFDNI(UWrf!l4|#6i2qjooOYEP16FJ75z$Iy~qASa9 zPVDoW)W@@?UQVFSfQnTxS%WG@y@iRGzh7CoD`evd@eO<(c!wTB*t^npfSrCVyCNEc zb{a6x&m?ODc4sW%Y)P(5iWO~uL_U4Q)8xj8-Z|+}y5Xm-hyO$N)p~%}B2Gzgv0y$- zt#KRL`eTt4-ydWaNG(Vivu%3+l6Z@K2f-KlL8G_v!v=1)O`FG89;)f9FTeisYu&GK zXsxG480d04zLKjj?_VJOS}>(U(1bq(j|ad4robPxM)GdSLNtylSmx1Qdum%FIXD5` z!3L2bTIdz#Wpso>iO`%x9_Az|66siD$l$n6A+YFLYU`X0J!~{rausQ|W@dEvnl?s% zsm~3{)wL#^rAN{j-ub*&c4x!&sqg7WYH7>Y2fTL#1N?(w^(7k~bwn~lo%#80i254t z89zQwGQuuEC-pNdH?t?WkoDIWq{gUowgG<;4PL)b*Iom98LaZtEs7WWI>HS+9D(A` zQE=7lh=T(1w*T$D&HIdMji!XH)la?WkvOHJheYf+ybSI^>yZ6jS@?LW=uQ~*%NhW& zWnbe|u*x#4(Ok5R)Xvfj3UUkWnR3DRefP}wo6`u5Y zMjs(05f`nfjiPNBln~?J7@4GMkY@FsZA(5WloSxc&C*|~^kC}kNpBGEAkR-GepTKU>?UU@IWIaFqd5)Wk68G^FvFRvmaOdzDTzn=-Q*sM;}*&4CzD&9a8RKTXb8AS7c;rf;m>0s z0PTg_Bz6(QA|8z0?(F6sVxTwzr7E_95c_3_3PCG4RQ)60`kkG0vIM-(9OT^%3taqka_PDm$a-TD11e5MX8=%cG9KcgY3u zcAFHlu#?++#O7=ZL*EYxu?}(ua0AXptA#GM_xz3kqQ=>?=}0P+wMEkA{eg2GOL}yp%3OQDw}!=&^dk(%NMlb9&x50GVMFpYcKs|?-WHXKYOccoJqgKQlr7wT9h3waWO3x^8E z2X8thdZCalQXOOC4^UKlXax|PTi^~s%k?mD@<5p|ZI-+n&zPeWvBc46tF}WM-KUVZ zQWR0BmlV;neN9Qi@Lqy$52huM&qavU-vA-mf<>oKSJBvq*WO<<|*h~>LTS2+brV%re%+W*2KA7sk&e9c7 zdn@@0+jJ#Q*Xw|WJf1tGU_3+^{o&Q4*%S9q0WWPAZ4Y4E;#l*xS_1f6kq$%IY+wAO zeFvpQ$y`k1Qb=wQJ%5Pr4?$GtrFnVf92z|KFjPR1_nY}_GltVoItnpH69~W+war=l zWOI3PJmE^R0bu}K7`O*lc(lX_?GQQ&=&mV6=?3@j!E)_#@>F1W2Y+5n;e@I=!#%N1 zfD{jXZQpb{NmIvB;Z!>s(nd?2+;5gsJbsH<0o?~U?W)r*4l0hC5ALh{!Hb{lIVp~n za9YesvItDGsy}Ix_QeIAeRXOAwe+q;DE`)zLubGcCoyCyl()9&N0SB6YKzLdwdd98 zQ*v)HIE5y}1gE>$gy&U|=weV;A9Edic)$m&7KU7xtRa-ueVRRSxlt!d?OYF{+k51C zA*(=mB;KdSzF0o61fazHtI`a5aQ29J-gwgf$x|32tB8t?noofZ zMIqlZ_XM6OQ|+QWuV~iXrldJ_qPPl%(p$ezZnMu$w@>v%|9o+zA&e#Bm~OUxd5@bZ z`!BEPAPRqLuPM`82Irp|1x$jGy~O+k`{|6*9?y0|DNVwbLR1kFnsE-)t-*_=JF)j* zt>~H<#uPxwwnEh)Jh|*1B;i13hv8Nt{KAWZ(RQ2#;&Fj8g_pe>Eaoh%vsoiiodo5- zv9IlQM|4}=1?y{fBIzKA_^>k4W}7L*RNJH$UZ&W&EtT8uKDADqNFjo$ynAnS+5{zc zHm!iem7qaCh|z{5at?OS8O=bQ2ffSgNjGBwMKOR*r4ZC?j3>k*Zp5#AzpmB8%m zzB}PcNESbBvxM>0yHp}+$0&uMr~Bac!eoY;seb1t48}WF2S4>_nWK9=&zryV0jAtL zJW{2-U1;f+h2#_X77%AF@k9!w<$5qBpowbG^sixoKpCuB3K07lk0FFEU>ovp!Cmdj zwP8{;foEuk@K%@#AUpZztSI>dMI>`ToaJ8H7QDjt=$x+aE1)M>7s@^AR}?@cknk94 zX{4;D1&G7BSgI5PWA8c9;Ds2x;)UJJ2&@8(1u(10H2?^CO9cZgjqM~2%~#(i-Vu(L2zcR zrd{J^@$ITZQ>%h2Ns29@3}|8w(hKG=5wu$etam|7u%{KZjmpa&6e}0Kzg5K>Y? z+uj@@EIxs4^-3e%oO4?B^Sv|7txAafXGy3=tS^T;n`0B1|5G8y6~31NDJAQlV`mxp@G9K zz!NH%v1`hp?2=_IPz*?w_thja#;%MSeZ%aDLloIK`N{p8#hW#VnvcWzG~@?MsJdn) z>Pn*xyuE)@l}l7#lB`|39!}{C(KCYUfzh;rID(#^{5$WqR(}aw!8p<;JbxsZ8CJ=6 z3xdhCwFeR<6mbF9^XWE?vHSOr$ZEB77K2~xJG}_!0qIQu!ee~*kBF+-!>^#zVhlxlxwzCsMdOdH<^EAPaZIIY zWaJw}A^LKfNzxXLd()iS4gFZC3?PCXw8rui0cQC&-{SecHR?8M#^&TQvcrWS9I7Tz~B#sNyU_M z@zmB15#4yc43;Y!_W}@kJTkpqIZ@AoD5B6oEFzMnzUX8zFhVi+9s$)5Y#LQClmQkC zmD|Dpk~`==1IaciXV#x^1X!MJx*^#|Kxrhy#gePbnV^(VYd54they;Nus^$V^Ly=w z&-xEyllxR8p5I~TDlJ6sNZP@ z%ifBorQa(R0JMH;a5paI=CNEL8_t^e3A^J;+!LdRazBrrBPHE;0u^44(;no|{6>j% z7Ck1eP3rwT7j5`VX|7m~A3WeeJa2#JDG5TGqg~ePwpqtX+dIB2?Wd5b65Bj)wC!^% zFwI0Lln6>-$kqPbJLniLCrH@{qJjJ%tqPB)+u2<|tnsWJ{3&H&SkA7Ifq4Yt>e$gW z8v+0?hvoVgUQMU)!1jpJq{XBDMQ}MB_0_{>W{wIsK!wCC|3oNJBi`EK!?t(~Ze|X% zznlN+yKlcu-59#bkpBHXZK0PKt-3+Y%sDdifjVA{Z;S?IhSet05 zuhrHY>D7GUHyV4Qj7K^XR|aD4e5Q3cowmN3b{BgXBjy&_z+t$Tsnm1eg^;$cDd1qA zY!lu(RKaNoS!7a}>qdlQdLt!n1l8rES1N$ckc3BF5ky8;L~VG|y4e_V$rTV>TxxhQ zb<*ujy4^{)H|btYy8TIaFzIEJUT4zlPI|owT3&S~{cJMGCc|tpk_T3A@PpR~y4g(+ zKb@Pa?53aH46>VHb~DOu#@WpzySdJ8v+SAtbe`jtmaOw4%UZb@tg!_StRrd6s?N!B6M&ZuWUE z`}`{Vyq|rMWnXl%FS^+mz3hvt?4K0nu)G#TL?sEa07BKatMgBKD%7j}O>r&(DfbVf z0&Mq=1xl?g$tM6Kj0I6wLi#Ej;Duwy;&cveGZ?1vh7FR?1~X{{@rD<6b;=SeBWZ_H z(wc&vpq8;)c@7CKgnkAOaeJ~t z5R~;|dfG*13oedQNGllc-hBVG^Y8j7M@XDo=}^2>sF6O`9yzTu%iy$xYQy|;tRS)| z%oz?T_aZ zJ-aGi!Cb>t>s$BgViq?y7ZvD|Z_OI7}u=abw~F zlJmt=uKkQR)v_o=VbCuwO3eenBcfTG@`^y2V@8_IOV>(LqTdZ3p7O)V3?wNYOHCOd7To+QCmWUXInhAqtAXz$1?2o_dU?KV$A?6Fo#Xh)$pJ>y&oxx0cWbzrw?4&P9fJ&& z)mGq#GM2~&P()(!X#)KdHoK^BEJ;c|5I8_up)sh1c0F1n z#_x!#y|`r8?VcJ1MjDQ?v!K!S%qb;AQ8e1U?~i?(%S=kg9r#b;LT!h z59H%vnrpDUcM_>^-uey*yjNG* z`iAfrA)?jBV1%)w-6op|A>;ej&ogovkqnrDo;;C+4s98f zCP(*0Z(trO^j>GeYwz+GRPdxrsiYwM1kY?W6RO+|cFeZDqvtF})tFawfktaA=5RQe zDR|&(8C!+<@F%J`^Zc%}x2=-~xfS97oS@ILZQUa1^4MHAB+vX3D zt{=*R5GZ{-UZrSvV$cK~k*95eV-7Z7e)*G6B_YL=GHa3~2v4<6EZUZ|y<-bIv!>O_ zTe#s@l1rn#Azx*Iu=c`@0=GK7A(cczAo5G%;EMx4?8F zQj`J`ljYc@fT_-~Z8$ug1yWyyKy#sAtxDT?lUGmtBfnM{PinKS&vP zq9J1naqj<~Q=rR#hsB)6W9i8^jL70u5qq@w5N-CN}0TgYsehz4Q zl!fmjkxDo4g#_UsM}kr95pyIPcjw_+o`H8_q<9ESl4}S6cpeZ|-t82QRl`l*4G|yq zySYvzTBy8z1^^#h=DaW{8Nx~OUj>qTFO=O$WB%@H2fh{tJCNW5(9+W!HI2MPr;`nL z1Dkv}oV+PYMJ*EmZDZq&!9l`fbUJ+XwNA=~SRmGbxldAbME_v62cWpqpg{u2jr8x$ zo=_kMRT&T?H$NTlSaO@u<5p~ENY2A4hVXJud$TaVNVK;yhBQA|;Tqm5zW*My*|5y8 zF$BEFL$$`WX^nw*?SP`@KEqug0V50%|K&b6G9(mW@fj@iJ92CIT<`Jn3!WwNUKgqe zp0@z+gCOByRjhF%3~g*kPulvM`LDnHMxl7|=dcl=>h;tYMC04F zz%$@BtN}1k(MOCBOu=_zkXRS#DHoflJ%QTA1LR0?6jbA9vVrYs0j1`bzt(Rw_Kuak zrnQ4Naz%3I7?kg4ffNHgG~?Z-yi_5&Lm0TWjnHkfse^Hk7|A$Ab)|rF4FxE^W6f^J z9GO-#eaw$@BZ|aaLI%aY3CyXJbo%-0)FYoArA22UbTJ5LcfzSO2$nh7O_$6hIVYn_ z-t{LJ!=ra|Vv(j%pPBkV{N-{sZ@6#~#NO+7di`#%-|O|Sdi}nkCtMMY?f+M=cz`;U zxS3GGr()!q9?G{zL@4Mg(~H>bXCVD}WKAz$v-LBlrRe+bb}c?~TjYp^tjC_~fiYhe zb|nfKPE@KtB1)l0!TrMSy_8YJ^^0+K$U5+D9(`fgZN9VkdPU7Sc%ZI{Ux(?z{_bG= ziZ!+eHUSg9$hc6~cp7Rg1n;Lq7R=dq?z@Ep6rLgYc=XfXAYOZ+zmSsp)6g#)_dygE z`y}A*DnM{ZW2uwUV{(`6T6p6Ctj9=+4iv_fM5X@fGNpC6WHh$}MJ3!@|E}!9on{*h zl^!AW`p1YsBz==}!so$4B(bV)Z-&Oi5CT#&Jp{zL!VD?b-E- zuxTU_P`?Qgh+L=$#&hiiV>QM$XjgB`>MPswe4oa+PYWX3mwn8G8&41uabDd}E3Gu0Qgd(yCyBuYjT z9c~^VC-@SOlSU9u)OL)VE1bdl&QOX5Ek%EMxfA{lNM{Z6EV{sa^#f)fLz0j7|X%?`e+I2M(+ww3{{ zT8JkYy1XVZMK3U2IDT>z$w8oHh;UN(vD+X=fkeJze4gvsGZz0arwzl4;fvm z3An-*+FC8!VRY}jhEbdJKoQIzUvqVl@GQIQqex{-!=YbZbAZ2L!HoeOhANon*1;mE(pKJZr^6VT+PK8p89!@Hm)wLDM+MN2sMIHB~q-3 zVAv7&8E^J)VBP_G>K7!9ASF`jLchWa?9*s&l-!Ft4az^-AOUl+_9UCUIC^-8^YKDe zy|vS5Pz!>O%mr!vG89)XLD!GaX}n<|g_&$X{thch5w>*B3{0VA-6OGB#Nqt#tQC>7 zu+jDQ;jqjDie=04|VvzB#eE1}cq z3s4}b`WZ>ZU=+j2^>?Bdvc!=F8u=j_`#wN&+H3z}8E=S3t~jNFtbwFGu!fs$aoSh< z%3eGyjYV`U>9;{nrGOhTr)Mx3@j+fB>IIU?$>+0q8vmJMc{?OeK{AyjhybYb%`bHd zVF5HV@Z0t-Xk5T4q863H27j-dpgT3O1jz~LXNYxdP*+WV1^GkugFHgHNb6w)kn%E2 zCJKV23Qp~ts<(D_wJkkGdLddMocxjtN$peH$iX_4XaRaImNB^g*QxJ0Lh8}>p@L7* z2h5P7(c7%uMQyKInwkuQ?O<%sJ$Jb)E# zUA^^3N*g5!3P%)4?-3B@xJPu5u9;hn2%7>fq&%eConK!B>m3-sno3=3{NtDI6OV9a zz;Ll$2(CNP%`4@+y)N!Tr;|>O_m&t6Vbq%ld2c=E96}6#_05-G*%`{7r%yXZYaea# z^5hyOA#FVtIl7FB1Jw0*y;h#W)H^_$zjk2cIS__G+3HYzM4x@Vuo>g3ktga71$qvH zk?bD+&QHCU>!wFpDT^a3e(s6&v);=XC1+u33nD`Z(9#YlX`h+HjZ?nxI7LwM6YA`y zqR@j1Bl#Hli9AG%92>}m*1K+npbY4k(nd_96`n#K!cgO^RKZ&Tw2R&fID$+c7bPcM zA%eCxe`d`S`O_3G9*~d~KPnkQYz{->MR)=?Kz|0Gaa5WIfe6rCJVBBbV582Bdli)jf6rojp;&rg+erA+rdtJx3=fHyJWui9n$!l#lS{WTnnf zFxv^;k!xb|4V694_!{qt0+rzj_Mz6ixA`7#xCR3KFX#XV5&FP?JEMUQMu0%hgeQ0T zK(0Y3`jXfrxlNKwm-R3WA0La|_nueXyOz1Q9Z1QpnRd@ZaRqo-7K}Wpgy5!+Ek6%R zx<}oCj*}?8G{VD{iIU#KdL-|r1^@V;W!q%aQwjx)ab9l`u@OAZR3uPl91A^;SMY#e zb&(r()$d#lva4b6EbA6xBaw(0XC(F{e;<;?xWjx~sql$JL`z5Pi4PiY8$!goMxLSM z9CmIqq!e~QO>evS>D>0R+pFxhkDtzMzkA#7-S)3;`~BPg;I=<}COL- zIL%65^OOV~>w}0k^{+TY!}oX9qjxS6#}Gk@H`$}REnLGPwr;{;S3#7pz-%4^tir(_ zuWW|5nII_ucY|>o+FvxC0ph+Mye2km7Rts%^piGq{sajsPNTF{M0XdY71D(wBZTjv z<#f_PP^JRq5wJZ&gres04>QNMX_{oNg#3x>5%oSJ*DMP0_L>I`& zGUqleK+n z;9;%ti`~=PQu0_e3&!9m&Jh{iwo2rMEEXP6$?o+8GMWO;$9xVGJP?5EBbBhNLF<<3 zA8(+e;9&w-u23~tziUxGS#cl+r8J^+_n+D`Q*YP!zOp}u48VJ(BGnp)KOFy?* z_PczJ^y0_-G1o6gs5g(NAUsKnuC%`+t$-wFWVLamM%a3{;~onx&4EPjp_tEeb55L* zm0Bl4A`E+LVySOX$qIzx5$cfZR_^Se8n@tPcY1h0QW0?0N3L+d`pfVU zwen(`oQIsXeul6LLs7G_+N0|da{Y*OGmE~VXoD9KkZ(B!%@R9@_6rP`gVxVr_YUmC z_y;wmZH~+!7c&@J)~U`y90Ouf8w_(D?%wTQefOQko=%_uRrA;#9?i19pFT`yI{46$ zO=G6#no+{z5}*w!D6*otadvO*>$v-8C^0ex2A{;S>}hibyDN_u za+>!!9-n}$;x(rKAxgY(0xEvUJ#;Ca$1)E8h!%JQQ##(uMIp7^R~{V6@0-f2<-|%Z zQ&;zFU#zwjb`~0Gc-xc{K9oyww&ckp&2m&i+W0{P4J54nbWyF180vAiMhQ2r#CTuG zT=875%|@0ixeSTTGg_m@?ChbOn0K4x*OlP0ZqoC>C|f*x_a-+)ri3*+Zv}mUIDg6i z2bNdDhYdlvE9KX(zWFA${YJAp2S}cdI(v1{be^LLL+F%v%u$%f zkV8qk;}SZZku*Yz$3lN+K$zAfbg1BTdOO<&5)JSU+OK^5LK3Oe@}(U|(;e^2cllk8 z#{=|lv;#M_CF90xBN5nS|FAzL z&qH$)K@IBJ{*4V7?$=YKa2UaL;)wX6edJo$ce}aBGEJe#0n2TqufA^_u8MCsAw&jm z&HLaxRny!lJJg~fo_md9Pl)X?s}QeLLuo0e@QyoODa3;kc3u2OPb%_29rib& zHfJJ>2#m--K`z!xaVYZ4I4_bD{!C59c0wjapAfh7Q|lL*GUXa-WC&aJQlyA7v@QW2 zhv^ICLeF>7TYHZ;Qi}6{;I=tvhc*egfC;sO4Pi7yoTfnpV&im(b|457a+4*76Gfs6 zZS-NVR{)J6Jkmgdw~qGkaT^VA>{N6c|S5FTzW zYQ=%i+3?Y|9q+5xB{taq?WUz@VM^w2_IUevf4s-z>pqj2R7;%MND+WfJksIb4@)}1 zJn&M=1ACWC+d<3NDC1E*RQs)&cF81=pM^xklSe(3%vuiO8eKd>hQ!NSh9G2AK93Q2 z5JIn_t!e?}O*$cweVPEtnlZ9|t}vj9bL8BGFBg`o*7PUDwFfes4s&n4Lx~zP0?3X0 zG-%u{Tu@>|h0zFtxz2zT735sParCS7SX!ZYrqq;X3t1p?_7ynMSRF;ESviqkF$m6) zwmDINmEHwmv|l+i?3)rvk_j8JtqXEm>tZTt^Q$ELEL~%Nk0>-7i8v$1W<+y)G-zxl zwjYo7?QCn~_1g=2deN%Zx`h^UQ2!oU05CXB@K;uFQDb|WnpfHhyG&cJp zrbGL?gGEQ`YuXfXVs0Yt+&q(z%j-Vl{qe3?FM=cG7MsV{C#i#Jt7sb=0R1^$i8Gxq zJ=8{9XD|2i`2TYAlU){eE>V8KE;mcs>r<-{8L_u2JA1OT6t&xpI~_F(4N=g#e;ci!RqR>YfCE-6*z~kQb!<~lE*=jGR_~yjlA(Ed=Vv|j70i* zz=u#r*xrY2;0u?N4w9C>mM4dbnVnnbbL8RY^QWm?Rv~8EPR`b?=N#Y*v9%E-9Z#;F z+hCJDTGn*&DX7K{ID=VIPw&!(4UuV6i~J88Fo4|+LYA(|G4EO&HQ6HWYs3orv|IbF zc*+rdiMqe~1#wplCkV&`*6sHdBzlw>FuW1dlHU>v`P~9UjevMgYS!KbH6gqx z6yAnv(20pm7%zKN-f6>gfTtKw`-W&ug$oO9!cmgt>j>2JbViKSsO|MaDTkom%?4z6v?HA2GP;cGjh8(6krfl2&k?3$#)rg-?q3^2|^ zRG?Up;Y-r5Z$}c$B0}Yz$x%_uA+jG=hoj--HFqV!g0wMW2ZJX`kZiNCXOGnsDu*o0 z3OFaY3hqRoF<0=>0TyWF(KTtTW7R0@o`!8lgZB`)tlL208^yxKmM@Re*q%hKuMhL; zc!U9G=`DNCAOL1mFLOwne?*bxArw@2clowZXnl?KmQIO+!r{bvWn}RGYwXH;8##{f zP$D@)>ezJ-#K`rOR|59h0XEOcV*&&SkjDU|NQu-zYI#Vaeto|Bx~lq^;jRh6@RC#A zJ>7M6ofH^3$2W91u`K1nS=}FD!C2L4Nb0&CuLw>u`(+yuV;oZ$xTZm^(0_$g!Gwc~ ztg|<`bgvU%Ys=lJR1m3-5W?DY1TJ>7ovrq~+JS(Kn|3iLK9=t{m-m>OYfC=H@h4^X$!`=2Mmoa`uyn`Q^C`S$aVpA?J~HU&TKlDFl<+z`gX z*`(q0fRdTQTf&h)z$BhrA!E*m0+Rs;vy5P7$gU65l*0vTha+@xdoYD7p^9d={CWG+ z)6YikT=g^BXc^*&zLesDz6{`CGk$O*DW@saoO~J-6a;1}_~_Fq2hx>p5kh_j} zOBfDu2eGA6qrt3p%}!oR=G?58@I)GSCyHb&J2^ZuL97B8<{n?x5!R`y_IN?##$61# zi8t}8PtIzH1TEGXR3x|dSlo|TNC}mubu+-7!>WS930oh_QV6$}{@`a)wPb+)9qeqO zYi$o7f;JEqEVKx*?Vk7ioGvMP&}2eduj*jrnW5I?#48sk``nP%ua{TH9B*T{88?Q0aI&u|1HH;KY{$G2QU}BTDl=LbmR_%P+60_bPHjIJ2@H?WI;u22lOOM%mIQTCpH^c#qHcrKF$4<6sRIf z8UW%#q0uHtY~9IxGIF#X%S7n!e-ip3upUM@36{T+a!~_mHH3&BDHk=W&c@Z*g#-Yd zUG~nds;wLKi0wQ3E;AN&PJfOf>-xi=eg7j15b+`*N$TrK9X)8GfP1<8X@3wd zq!L3@uXib-iHuH^71<|$^Yf)=Y5YcCnfAc2Yx3?wP8wub3Mlqn3P#(`_xdOW95pi} z^^F;>IRDPqboRy0JEx@lDK^G~sXz0yRt6LXl3ZMKPKBAY*r_Y~0(IuYfq8$j8z6wfPY30KCBrB@Wf@{DI5sBrB z^|e?SWTNcA5{xMU8Y!=nutmzGgpcTJm0;X#T&AK;K<-73RK?vdUn3$raMexb?82vV z!Vy3+ZAArk#xOmw7^kp#y_@RdDfMJyvQ3d$9ToM-@$LZ4g8mHsrjxCAEw~MO$~1~Y z1WMw+*d=~0cZV(XMcI@`Gv|=%X9r~7>qF?fQtIDf2#EkC6@~7r5=7n`0B@snig*jp z)UbzG{Qj^v7<$F>uBpjCIvk=27IlHqOPBbF1d|*gaDn;C%aYWQk0sDX>fe}+N(4-e zKtV)1rGPn0?OLg+kZZzq+10wBhzU%IN*au`2=WU3)6nQ@jgaJpEAZSJAfTNkp~whz zQ?3bx)^o@##5GyJ{jfOP;DQ88#snb&Zr8EVN z@q*8G^M~dw@d-BeR}5na4n|np2Kx}VPt1!eIF6yLBbuzez8WPE5nf<4$NFY2X64NT z{>C_%tG#prk=pVIb2PhU5xki1F{aoq-XCm}&r#u7*J1QQeZ|Bmgi8)E#B?!&EZN)Q zxnP{c9T~<5!Iu}a%L}IHj0FgJcxHS!Jv#qAc2NLsXzW`6iDMXjbMUFBn9klsz>QUv!Tdh)hPY8_e!bCF5{kN zKtvfR1}U}6f;p|s=$M>={W=s(W~>Ih^lKDc>oC4$AcHgvP&5flg9!xv4EMU;s?JMw z88-^N7_0NM8Sa<=+1wiHU%`?oMr+ahJ&I6JG^)>6DBA_T2jA2aijeBuLZFNS=z5=P zK#25vfWiVW1>q6S9#QM@KGu6QoetL`l7>FpJpyGh^v~NwT}>i(sJHl`=tvD}OiNj3 zd*RV^l}FhrS*BQ{q%Pzsk#SI1P7KyauggiawUpI%17djP&J&|hpCT{S2eA3Vk4`+! zU63Z`z$c>wLKr|*zB3h)&NzGFI7AUS@DuY98u$SZ9-?NJP#%m3zP?V<8BR-#sEI4D zrIwVdrMS>?981Oz>B2w^rd*I^0;fg244-lov~hYrrt$r%*vJUo5Z4e)Oxr=UT%-jR zg?f?(+uGu0znIc=sDt|~h#f63@Y4Q0LElk*JS%$|L=KP;h$ot|Px>7oQHAPZb1MOY zN8o^h6D7pm4oj->7kS@64EoT8K%)#Es{9#AQgn8thH2z!0QXn-6wyc@e#ai|mx#66 zA!}b}3+|U?T%(*+2XR6`F8Ah^BFZp{VtUivXabv=LGU&o!ch$?Ta3Jfp|SOK^#FAb z4Wz*Rp5Xd0=p3iVI^E25g%ND-C`=GzCrCpAjP@&3uv%~2M$Dtx2ZHLM+ME&5H97K!!bbc>+N)p2Q zty_5xO-#B)-0<<6fHiAVxC3RlKxKKSBHL?7#9$i2yTL*e3^TOKgsSJZllfTv1**^K zPs(aVv^qhTQ%k(In|WJ!Ts)23P$b2yC!6P_PGTtzB~T%-&9IDOjLTrCmFz2T%al_< z0ZDj+t^Qu8I0xx>mN{0em^OGaQBVEA#Ntr*8{r8s#`c&w zj)t{ym$!F|m2o->j60m#VU~L!a?-qlb$+`zBF%b*gfkuLqcG!{gox#-!|{wN)Gpb^ zzdg}8cvsS3 zXrf4Zyd@k;6mQ`Ij1@gHaRxrFpG(Yli;$CPlIa!bT&>RfT#g$u8$!RMFI>2tB%s>v zD)j`?2~qa-qEI_@oI{E;n#V-f_2d{ux0%TD4g;9!H#t0l`IJ~9B5)#=sWT4{N zgA%AicMypTXH2a`n6S>45Prhq%Qq!IHaTclMY3`58Z0gN zu0R34jrKD8?eTrRig~7Vq3VxunNUN}Oy&@~Lh-$jeWg!!;IIn*w6Ej{9A~!q*YxjZ zmuR4ara1zw?P)>O0uj%`b|=N+7R(6Odq{xT$SpfTMS_&GwnpH=NOT)|L)yXET3vj% zp!#=@{xnrI7XzLF>~b<9dHcs|1l&grXzE$SHm-6@_8=UwH+8is|@m)(JVgDd~q8<(pkaOni=K_%!A~nNx%ml?pFaKSk_w@GP|J2{OI25r$79=za z7-NedSRkG4TM5cr&pk9fxgAU0G0%76l{Hbnbc7myT%_TcZHv)9^Lu35Z6xp!LzF>b z;Q$r-8qioGtc23qz;uSO#2+(x$JD{(Z86~*)>hjJFdn z^G#co^f3$JnL3zIrJP)<$z33o57V)UV>+iOr`VsQNT<cMgVz)`kc9Toby=D+` zkE~Ms$k3Ok5${RR8q{FLDx?;PSYOr9}05F4)BYGvJ)?Uj9RbbNHl#5T6j6 zi9oB}(whV(wk8UYP|#F1)l7S_r^^UcRcWI=A4u3R}_cqjc1+b00?#T|-(89I+eB4w8%3q}x)j}o5ZUAUW$gR)t#Xe=Yy zGO@rNjjOOdKsd)_uzW*42o(BgGuIMCq{ERXE!Nl(80z%997Rq55+5HIZ@vfINiq%{ z<^L)9^q9D{qfM&U91_pD!^_v?PY9`so|s6Vdy7ghhV z>R;in*T1g%AFBSxs{dWp|CJcgf&`GFZx97&wu=DJel;B6uQwc=4F~7LL4P=`hBf|r z!=@UJs^K_FjQYH)`&B)tYGivme?#Pd$O!L&(e<0&paE#FZhB4A8#TRg)4OPTmu0^A z;H(*(H(2;!Ai3i;{(4P~^znYvRDf)nvu0E^W8s|oX%N@8e_43Z3?8+(9`}=I08S8d z43%+zzk#pK>^rx7>-~H=MKtE#890?L(iybKLL2F# zi{@2o4aAzSeW~-H@19TAyrOX@>Hu4)EDU9_Buf5h{}t^ub&yVHqKTNn+jRS48%0Zk zg}yQJSBFTpHv^!o5IyGElSF9>qlgaFZ!#Kam`=q-K|mlv+mE@9e2ry;n)#v|{q zP=;bH68HxG1LHf%G|k)UalL_$K;N-1v1a=JT4zf3lFDdsWr^jVvE4wZw0404jl}Br zFrDO`P}M|)hEOv{)*New#~+sX(@}m=zW&8=j^v&70tabG3&Y&q;;pDFS5EY_-@RK? zP!`uk4cB*+3x;8J4%D4Y=g`)X0T7w8(hgNzU12pmrsD*Y31SL-Daj`1kCN-Nr}mqB zf7_>+jZT#YPqTQ83rK3DBDYmm`3WGs?CBpbPRW!Ohr}rN zy(nloDB}3MVA)D>#W_z*K9ePac$Uz(P^aWTc!TT5+At`A&tH_RlDq`P4*d1kF0?B=6HTI65}K*`6tTM$<&6?sbvJ^JW@+srr<9T)+(i5ye2D zVrs%~7nJ0Q+e+ycO9mAQ8HG;)Og16;8KvzFV78s^e(D~AhYrVp-9^8#Nga*Ol1)0b zPVy!;^%2e9@aXhZVNubZc=}1w>0y71Y@SwHU&g+Qo%>yK)966UcoPh_KNVuMVU+!4 QJ4dF*&J3Ue;pJ8S4}Tc8mjD0& diff --git a/nix/grafanix-backend.nix b/nix/grafanix-backend.nix index 8844bf1..b5a3832 100644 --- a/nix/grafanix-backend.nix +++ b/nix/grafanix-backend.nix @@ -1,5 +1,5 @@ { mkDerivation -, stdenv +, lib , aeson , attoparsec @@ -11,7 +11,7 @@ , hashable , hspec , hspec-attoparsec -, lrucaching +, lrucache , optparse-applicative , protolude , scotty @@ -22,12 +22,13 @@ , wai-middleware-static , static ? false -, zlib +, ncurses ? null +, zlib ? null }: mkDerivation { pname = "grafanix-backend"; version = "0.1.0.0"; - src = stdenv.lib.sourceByRegex ../backend [ + src = lib.sourceByRegex ../backend [ "app" "app/.*\.hs" "src" @@ -43,9 +44,9 @@ mkDerivation { enableSharedLibraries = false; enableSharedExecutables = false; configureFlags = - stdenv.lib.optionals static [ + lib.optionals static [ "--ghc-option=-optl=-static" - "--extra-lib-dirs=${zlib.static}/lib" + "--extra-lib-dirs=${zlib.static}/lib:${ncurses}/lib" ]; executableHaskellDepends = [ @@ -57,7 +58,7 @@ mkDerivation { errors filepath hashable - lrucaching + lrucache optparse-applicative protolude scotty @@ -68,5 +69,5 @@ mkDerivation { wai-middleware-static ]; testHaskellDepends = [ base hspec hspec-attoparsec ]; - license = stdenv.lib.licenses.mit; + license = lib.licenses.mit; } diff --git a/nix/grafanix-release.nix b/nix/grafanix-release.nix index b408e42..3ec5415 100644 --- a/nix/grafanix-release.nix +++ b/nix/grafanix-release.nix @@ -5,7 +5,7 @@ let version = grafanix.version; in - runCommand "grafanix-${version}.zip" {} '' - cd ${grafanix} - ${zip}/bin/zip -9 -r $out * - '' \ No newline at end of file +runCommand "grafanix-${version}.zip" { } '' + cd ${grafanix} + ${zip}/bin/zip -9 -r $out * +'' diff --git a/nix/grafanix.nix b/nix/grafanix.nix index baa285c..61085fb 100644 --- a/nix/grafanix.nix +++ b/nix/grafanix.nix @@ -7,7 +7,7 @@ }: stdenvNoCC.mkDerivation { name = "grafanix"; - version = "0.2"; + version = "0.3"; src = lib.sourceByRegex ../static [ "drawGraph.js" diff --git a/nix/sources.json b/nix/sources.json index d180d33..b525526 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -1,51 +1,26 @@ { - "all-hies": { - "branch": "master", - "description": "Cached Haskell IDE Engine Nix builds for all GHC versions", - "homepage": "", - "owner": "Infinisil", - "repo": "all-hies", - "rev": "b06fdd252c71404ace1eea5e09b562bcf7f834f7", - "sha256": "1gzipcmhm6xbfjdjx3i4057vysmvrm6xykx9aplj3wcwmk3bhmdy", - "type": "tarball", - "url": "https://github.com/Infinisil/all-hies/archive/b06fdd252c71404ace1eea5e09b562bcf7f834f7.tar.gz", - "url_template": "https://github.com///archive/.tar.gz" - }, - "bootstrap": { - "sha256": "0dldiln2s3z8iqc5ccjid2i5gh9527naas064bwly8x9lrfrxcb0", - "type": "file", - "url": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css", - "url_template": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap//css/bootstrap.min.css", - "version": "4.3.1" - }, - "d3": { - "sha256": "0mjblqriz0k8v9034sra5pz10ql3x8ysaril24if6w2pq0i2ci4v", - "type": "file", - "url": "https://cdnjs.cloudflare.com/ajax/libs/d3/5.15.0/d3.min.js", - "url_template": "https://cdnjs.cloudflare.com/ajax/libs/d3//d3.min.js", - "version": "5.15.0" - }, "niv": { "branch": "master", "description": "Easy dependency management for Nix projects", "homepage": "https://github.com/nmattia/niv", "owner": "nmattia", "repo": "niv", - "rev": "2ecfd86b631714b457e56d70dd83fa60435baeb6", - "sha256": "01j6727cws8blg1npp54b4w6xa0gpgyzhyws2vqgp8clnlnmqqhi", + "rev": "914aba08a26cb10538b84d00d6cfb01c9776d80c", + "sha256": "0gx316gc7prjay5b0cr13x4zc2pdbiwxkfkpjvrlb2rml80lm4pm", "type": "tarball", - "url": "https://github.com/nmattia/niv/archive/2ecfd86b631714b457e56d70dd83fa60435baeb6.tar.gz", + "url": "https://github.com/nmattia/niv/archive/914aba08a26cb10538b84d00d6cfb01c9776d80c.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, "nixpkgs": { - "branch": "nixos-19.03", + "branch": "23.05", "description": "Nixpkgs/NixOS branches that track the Nixpkgs/NixOS channels", + "homepage": "https://github.com/NixOS/nixpkgs", "owner": "NixOS", - "repo": "nixpkgs-channels", - "rev": "7bb74e653654dbf9206e751574b5132b15f46bb5", - "sha256": "1dbdy4f58yqz4l67n032184rx7ci94hx3wl52c8h2bg06awkzq87", + "repo": "nixpkgs", + "rev": "4ecab3273592f27479a583fb6d975d4aba3486fe", + "sha256": "10wn0l08j9lgqcw8177nh2ljrnxdrpri7bp0g7nvrsn9rkawvlbf", "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs-channels/archive/7bb74e653654dbf9206e751574b5132b15f46bb5.tar.gz", + "url": "https://github.com/NixOS/nixpkgs/archive/4ecab3273592f27479a583fb6d975d4aba3486fe.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, "static-haskell-nix": { @@ -54,21 +29,10 @@ "homepage": "", "owner": "nh2", "repo": "static-haskell-nix", - "rev": "b06f8979bfaa27dc4ce76cbeaa393e0c28b5baef", - "sha256": "17f4if6rx7xhsfz1n9i151n7zxf82p08nmyml24fb1axi9j6ya38", - "type": "tarball", - "url": "https://github.com/nh2/static-haskell-nix/archive/b06f8979bfaa27dc4ce76cbeaa393e0c28b5baef.tar.gz", - "url_template": "https://github.com///archive/.tar.gz" - }, - "unstable": { - "branch": "nixos-unstable", - "description": "Nixpkgs/NixOS branches that track the Nixpkgs/NixOS channels", - "owner": "NixOS", - "repo": "nixpkgs-channels", - "rev": "beff2f8d75ef2c65017fb25e251337c6bb2e950d", - "sha256": "1av1m2mibv9dgfrjv9r8n3ih9dyb0wi594s5xb4c135v121jpzs3", + "rev": "88f1e2d57e3f4cd6d980eb3d8f99d5e60040ad54", + "sha256": "1hf1470r9axjzjjnl9k21drvwx7wfcalpj3k578yb3qz5j1lh5nk", "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs-channels/archive/beff2f8d75ef2c65017fb25e251337c6bb2e950d.tar.gz", + "url": "https://github.com/nh2/static-haskell-nix/archive/88f1e2d57e3f4cd6d980eb3d8f99d5e60040ad54.tar.gz", "url_template": "https://github.com///archive/.tar.gz" } } diff --git a/nix/sources.nix b/nix/sources.nix index 6e2bf23..fe3dadf 100644 --- a/nix/sources.nix +++ b/nix/sources.nix @@ -6,83 +6,124 @@ let # The fetchers. fetch_ fetches specs of type . # - fetch_file = pkgs: spec: + fetch_file = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in if spec.builtin or true then - builtins_fetchurl { inherit (spec) url sha256; } + builtins_fetchurl { inherit (spec) url sha256; name = name'; } else - pkgs.fetchurl { inherit (spec) url sha256; }; + pkgs.fetchurl { inherit (spec) url sha256; name = name'; }; - fetch_tarball = pkgs: spec: + fetch_tarball = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in if spec.builtin or true then - builtins_fetchTarball { inherit (spec) url sha256; } + builtins_fetchTarball { name = name'; inherit (spec) url sha256; } else - pkgs.fetchzip { inherit (spec) url sha256; }; - - fetch_git = spec: - builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; }; + pkgs.fetchzip { name = name'; inherit (spec) url sha256; }; - fetch_builtin-tarball = spec: - builtins.trace - '' - WARNING: - The niv type "builtin-tarball" will soon be deprecated. You should - instead use `builtin = true`. + fetch_git = name: spec: + let + ref = + spec.ref or ( + if spec ? branch then "refs/heads/${spec.branch}" else + if spec ? tag then "refs/tags/${spec.tag}" else + abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!" + ); + submodules = spec.submodules or false; + submoduleArg = + let + nixSupportsSubmodules = builtins.compareVersions builtins.nixVersion "2.4" >= 0; + emptyArgWithWarning = + if submodules + then + builtins.trace + ( + "The niv input \"${name}\" uses submodules " + + "but your nix's (${builtins.nixVersion}) builtins.fetchGit " + + "does not support them" + ) + { } + else { }; + in + if nixSupportsSubmodules + then { inherit submodules; } + else emptyArgWithWarning; + in + builtins.fetchGit + ({ url = spec.repo; inherit (spec) rev; inherit ref; } // submoduleArg); - $ niv modify -a type=tarball -a builtin=true - '' - builtins_fetchTarball { inherit (spec) url sha256; }; + fetch_local = spec: spec.path; - fetch_builtin-url = spec: - builtins.trace - '' - WARNING: - The niv type "builtin-url" will soon be deprecated. You should - instead use `builtin = true`. + fetch_builtin-tarball = name: throw + ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=tarball -a builtin=true''; - $ niv modify -a type=file -a builtin=true - '' - (builtins_fetchurl { inherit (spec) url sha256; }); + fetch_builtin-url = name: throw + ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=file -a builtin=true''; # # Various helpers # - # The set of packages used when specs are fetched using non-builtins. - mkPkgs = sources: - if hasNixpkgsPath - then - if hasThisAsNixpkgsPath - then import (builtins_fetchTarball { inherit (mkNixpkgs sources) url sha256; }) {} - else import {} - else - import (builtins_fetchTarball { inherit (mkNixpkgs sources) url sha256; }) {}; + # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695 + sanitizeName = name: + ( + concatMapStrings (s: if builtins.isList s then "-" else s) + ( + builtins.split "[^[:alnum:]+._?=-]+" + ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name) + ) + ); - mkNixpkgs = sources: + # The set of packages used when specs are fetched using non-builtins. + mkPkgs = sources: system: + let + sourcesNixpkgs = + import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; }; + hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; + hasThisAsNixpkgsPath = == ./.; + in if builtins.hasAttr "nixpkgs" sources - then sources.nixpkgs - else abort - '' - Please specify either (through -I or NIX_PATH=nixpkgs=...) or - add a package called "nixpkgs" to your sources.json. - ''; - - hasNixpkgsPath = (builtins.tryEval ).success; - hasThisAsNixpkgsPath = - (builtins.tryEval ).success && == ./.; + then sourcesNixpkgs + else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then + import { } + else + abort + '' + Please specify either (through -I or NIX_PATH=nixpkgs=...) or + add a package called "nixpkgs" to your sources.json. + ''; # The actual fetching function. fetch = pkgs: name: spec: if ! builtins.hasAttr "type" spec then abort "ERROR: niv spec ${name} does not have a 'type' attribute" - else if spec.type == "file" then fetch_file pkgs spec - else if spec.type == "tarball" then fetch_tarball pkgs spec - else if spec.type == "git" then fetch_git spec - else if spec.type == "builtin-tarball" then fetch_builtin-tarball spec - else if spec.type == "builtin-url" then fetch_builtin-url spec + else if spec.type == "file" then fetch_file pkgs name spec + else if spec.type == "tarball" then fetch_tarball pkgs name spec + else if spec.type == "git" then fetch_git name spec + else if spec.type == "local" then fetch_local spec + else if spec.type == "builtin-tarball" then fetch_builtin-tarball name + else if spec.type == "builtin-url" then fetch_builtin-url name else abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; + # If the environment variable NIV_OVERRIDE_${name} is set, then use + # the path directly as opposed to the fetched source. + replace = name: drv: + let + saneName = stringAsChars (c: if (builtins.match "[a-zA-Z0-9]" c) == null then "_" else c) name; + ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; + in + if ersatz == "" then drv else + # this turns the string into an actual Nix path (for both absolute and + # relative paths) + if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}"; + # Ports of functions for older nix versions # a Nix version of mapAttrs if the built-in doesn't exist @@ -91,42 +132,60 @@ let listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) ); + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 + range = first: last: if first > last then [ ] else builtins.genList (n: first + n) (last - first + 1); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 + stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 + stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); + concatMapStrings = f: list: concatStrings (map f list); + concatStrings = builtins.concatStringsSep ""; + + # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331 + optionalAttrs = cond: as: if cond then as else { }; + # fetchTarball version that is compatible between all the versions of Nix - builtins_fetchTarball = { url, sha256 }@attrs: + builtins_fetchTarball = { url, name ? null, sha256 }@attrs: let inherit (builtins) lessThan nixVersion fetchTarball; in - if lessThan nixVersion "1.12" then - fetchTarball { inherit url; } - else - fetchTarball attrs; + if lessThan nixVersion "1.12" then + fetchTarball ({ inherit url; } // (optionalAttrs (name != null) { inherit name; })) + else + fetchTarball attrs; # fetchurl version that is compatible between all the versions of Nix - builtins_fetchurl = { url, sha256 }@attrs: + builtins_fetchurl = { url, name ? null, sha256 }@attrs: let inherit (builtins) lessThan nixVersion fetchurl; in - if lessThan nixVersion "1.12" then - fetchurl { inherit url; } - else - fetchurl attrs; + if lessThan nixVersion "1.12" then + fetchurl ({ inherit url; } // (optionalAttrs (name != null) { inherit name; })) + else + fetchurl attrs; # Create the final "sources" from the config mkSources = config: - mapAttrs ( - name: spec: - if builtins.hasAttr "outPath" spec - then abort - "The values in sources.json should not have an 'outPath' attribute" - else - spec // { outPath = fetch config.pkgs name spec; } - ) config.sources; + mapAttrs + ( + name: spec: + if builtins.hasAttr "outPath" spec + then + abort + "The values in sources.json should not have an 'outPath' attribute" + else + spec // { outPath = replace name (fetch config.pkgs name spec); } + ) + config.sources; # The "config" used by the fetchers mkConfig = - { sourcesFile ? ./sources.json - , sources ? builtins.fromJSON (builtins.readFile sourcesFile) - , pkgs ? mkPkgs sources + { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null + , sources ? if sourcesFile == null then { } else builtins.fromJSON (builtins.readFile sourcesFile) + , system ? builtins.currentSystem + , pkgs ? mkPkgs sources system }: rec { # The sources, i.e. the attribute set of spec name to spec inherit sources; @@ -134,5 +193,6 @@ let # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers inherit pkgs; }; + in -mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); } +mkSources (mkConfig { }) // { __functor = _: settings: mkSources (mkConfig settings); } diff --git a/shell.nix b/shell.nix index 0d9af5e..fbd4670 100644 --- a/shell.nix +++ b/shell.nix @@ -1 +1 @@ -(import ./. {}).shell +(import ./default.nix { }).shell diff --git a/treefmt.toml b/treefmt.toml new file mode 100644 index 0000000..d6772c8 --- /dev/null +++ b/treefmt.toml @@ -0,0 +1,12 @@ +[formatter.elm] +command = "elm-format" +options = ["--yes"] +includes = ["*.elm"] + +[formatter.haskell] +command = "ormolu" +includes = ["*.hs"] + +[formatter.nix] +command = "nixpkgs-fmt" +includes = ["*.nix"]