From d81d9265d9a665a8add104b4f417247b33e325ab Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Sun, 23 Jan 2022 21:58:18 -0500 Subject: [PATCH 01/20] First go --- ghcide/ghcide.cabal | 1 + .../Development/IDE/Plugin/NewCodeAction.hs | 346 ++++++++++++++++++ 2 files changed, 347 insertions(+) create mode 100644 ghcide/src/Development/IDE/Plugin/NewCodeAction.hs diff --git a/ghcide/ghcide.cabal b/ghcide/ghcide.cabal index 57976ef2d4..cf49e338ab 100644 --- a/ghcide/ghcide.cabal +++ b/ghcide/ghcide.cabal @@ -206,6 +206,7 @@ library Development.IDE.Plugin.HLS.GhcIde Development.IDE.Plugin.Test Development.IDE.Plugin.TypeLenses + Development.IDE.Plugin.NewCodeAction other-modules: Development.IDE.Core.FileExists diff --git a/ghcide/src/Development/IDE/Plugin/NewCodeAction.hs b/ghcide/src/Development/IDE/Plugin/NewCodeAction.hs new file mode 100644 index 0000000000..63b1214bc2 --- /dev/null +++ b/ghcide/src/Development/IDE/Plugin/NewCodeAction.hs @@ -0,0 +1,346 @@ +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE OverloadedLabels #-} +{-# LANGUAGE TypeFamilies #-} + +-- | An HLS plugin to provide code lenses for type signatures +module Development.IDE.Plugin.NewCodeAction + ( descriptor, + suggestSignature, + codeActionCommandId, + NewCodeActionTypeSig (..), + NewCodeActionTypeSigs (..), + NewCodeActionTypeSigsResult (..), + ) +where + +import Control.Concurrent.STM.Stats (atomically) +import Control.DeepSeq (rwhnf) +import Control.Monad (mzero) +import Control.Monad.Extra (whenMaybe) +import Control.Monad.IO.Class (MonadIO (liftIO)) +import Data.Aeson.Types (Value (..), toJSON) +import qualified Data.Aeson.Types as A +import qualified Data.HashMap.Strict as Map +import Data.List (find) +import Data.Maybe (catMaybes, isJust) +import qualified Data.Text as T +import Development.IDE (GhcSession (..), + HscEnvEq (hscEnv), + RuleResult, Rules, define, + srcSpanToRange, + unsafePrintSDoc) +import Development.IDE.Core.Compile (TcModuleResult (..)) +import Development.IDE.Core.RuleTypes (GetBindings (GetBindings), + TypeCheck (TypeCheck)) +import Development.IDE.Core.Rules (IdeState, runAction) +import Development.IDE.Core.Service (getDiagnostics) +import Development.IDE.Core.Shake (getHiddenDiagnostics, + ideLogger, logger, use) +import Development.IDE.GHC.Compat +import Development.IDE.GHC.Error +import Development.IDE.GHC.Util (printName) +import Development.IDE.Graph.Classes +import Development.IDE.Spans.LocalBindings (Bindings, getFuzzyScope) +import Development.IDE.Types.Location (Position (Position, _character, _line), + Range (Range, _end, _start), + toNormalizedFilePath', + uriToFilePath') +import qualified Development.IDE.Types.Logger as Logger +import GHC.Generics (Generic) +import Ide.Plugin.Config (Config) +import Ide.Plugin.Properties +import Ide.PluginUtils (mkLspCommand, subRange, + usePropertyLsp) +import Ide.Types (CommandFunction, + CommandId (CommandId), + PluginCommand (PluginCommand), + PluginDescriptor (..), + PluginId, + configCustomConfig, + defaultConfigDescriptor, + defaultPluginDescriptor, + mkCustomConfig, + mkPluginHandler) +import qualified Language.LSP.Server as LSP +import Language.LSP.Types (ApplyWorkspaceEditParams (ApplyWorkspaceEditParams), + CodeAction (..), + CodeActionKind (CodeActionQuickFix), + CodeActionParams (CodeActionParams, _range, _textDocument), + CodeLens (CodeLens), + CodeLensParams (CodeLensParams, _textDocument), + Command, Diagnostic (..), + List (..), ResponseError, + SMethod (..), + TextDocumentIdentifier (TextDocumentIdentifier), + TextEdit (TextEdit), + WorkspaceEdit (WorkspaceEdit), + type (|?) (InR)) +import Language.LSP.Types.Lens (HasCodeActionProvider) +import System.IO +import Text.Regex.TDFA ((=~), (=~~)) + +codeActionCommandId :: T.Text +codeActionCommandId = "typesignature.change" + +descriptor :: PluginId -> PluginDescriptor IdeState +descriptor plId = + (defaultPluginDescriptor plId) + { pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionProvider, + pluginCommands = [PluginCommand (CommandId codeActionCommandId) "change a signature" commandHandler], + pluginRules = rules, + pluginConfigDescriptor = defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties} + } + +properties :: Properties '[ 'PropertyKey "mode" ('TEnum Mode)] +properties = + emptyProperties + & defineEnumProperty + #mode + "Control how type lenses are shown" + [ (Always, "Always displays type lenses of global bindings"), + (Exported, "Only display type lenses of exported global bindings"), + (Diagnostics, "Follows error messages produced by GHC about missing signatures") + ] + Always + +codeActionProvider :: LSP.MonadLsp Config m => IdeState + -> PluginId + -> CodeActionParams + -> m (Either a (List (Command |? CodeAction))) +codeActionProvider ideState pId CodeActionParams {_textDocument = TextDocumentIdentifier uri, _range = currRange} = do + mode <- usePropertyLsp #mode pId properties + fmap (Right . List) $ case uriToFilePath' uri of + Just (toNormalizedFilePath' -> filePath) -> liftIO $ do + env <- fmap hscEnv <$> runAction "codeLens.GhcSession" ideState (use GhcSession filePath) + tmr <- runAction "codeLens.TypeCheck" ideState (use TypeCheck filePath) + bindings <- runAction "codeLens.GetBindings" ideState (use GetBindings filePath) + -- gblSigs <- runAction "codeLens.NewCodeActionTypeSigs" ideState (use NewCodeActionTypeSigs filePath) + + diag <- atomically $ getDiagnostics ideState + hDiag <- atomically $ getHiddenDiagnostics ideState + -- liftIO $ Logger.logError (ideLogger ideState) $ T.pack $ show diag + -- liftIO $ Logger.logError (ideLogger ideState) $ T.pack $ show hDiag + + let toWorkSpaceEdit tedit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing Nothing + matchDiags = filter (\(_, _, d) -> cantMatchType d && currRange `contains` d) (diag <> hDiag) + liftIO $ Logger.logError (ideLogger ideState) $ T.pack $ show matchDiags + hPrint stderr matchDiags + -- generateActionForGlobal sig@NewCodeActionTypeSig {..} = do + -- range <- srcSpanToRange $ gbSrcSpan sig + -- tedit <- gblBindingTypeSigToEdit sig + -- let wedit = toWorkSpaceEdit [tedit] + -- pure $ generateAction pId range (T.pack gbRendered) wedit + -- gblSigs' = maybe [] (\(NewCodeActionTypeSigsResult x) -> x) gblSigs + -- generateActionFromDiags f = + -- sequence + -- [ pure $ generateAction pId _range title edit + -- | (dFile, _, dDiag@Diagnostic {_range = _range}) <- diag ++ hDiag, + -- dFile == filePath, + -- (title, tedit) <- f dDiag, + -- let edit = toWorkSpaceEdit tedit + -- ] + --pure (catMaybes $ generateActionForGlobal <$> gblSigs') + pure [] + -- case mode of + -- Always -> + + -- <> generateActionFromDiags (suggestLocalSignature False env tmr bindings) -- we still need diagnostics for local bindings + -- Exported -> pure $ catMaybes $ generateActionForGlobal <$> filter gbExported gblSigs' + -- Diagnostics -> generateActionFromDiags $ suggestSignature False env gblSigs tmr bindings + -- Nothing -> pure [] + +generateAction :: p1 -> p2 -> T.Text -> WorkspaceEdit -> a |? CodeAction +generateAction _ _ title edit = InR CodeAction { + _title = title, + _kind = Just CodeActionQuickFix, + _diagnostics = Nothing, + _isPreferred = Nothing, + _disabled = Nothing, + _edit = Just edit, + _command = Nothing, + _xdata = Nothing + } + +commandHandler :: CommandFunction IdeState WorkspaceEdit +commandHandler _ideState wedit = do + _ <- LSP.sendRequest SWorkspaceApplyEdit (ApplyWorkspaceEditParams Nothing wedit) (\_ -> pure ()) + return $ Right Null + +test :: Int -> Int +test x = length x + +-------------------------------------------------------------------------------- + +suggestSignature :: Bool -> Maybe HscEnv -> Maybe NewCodeActionTypeSigsResult -> Maybe TcModuleResult -> Maybe Bindings -> Diagnostic -> [(T.Text, [TextEdit])] +suggestSignature isQuickFix env mGblSigs mTmr mBindings diag = + suggestGlobalSignature isQuickFix mGblSigs diag <> suggestLocalSignature isQuickFix env mTmr mBindings diag + +cantMatchType :: Diagnostic -> Bool +cantMatchType Diagnostic {_message} = _message =~ ("Couldn't match expected type" :: T.Text) + +contains :: Range -> Diagnostic -> Bool +contains range Diagnostic {_range} = subRange range _range + +suggestGlobalSignature :: Bool -> Maybe NewCodeActionTypeSigsResult -> Diagnostic -> [(T.Text, [TextEdit])] +suggestGlobalSignature isQuickFix mGblSigs Diagnostic {_message, _range} + | _message + =~ ("Couldn't match expected type" :: T.Text), + Just (NewCodeActionTypeSigsResult sigs) <- mGblSigs, + Just sig <- find (\x -> sameThing (gbSrcSpan x) _range) sigs, + signature <- T.pack $ gbRendered sig, + title <- if isQuickFix then "change signature: " <> signature else signature, + Just action <- gblBindingTypeSigToEdit sig = + [(title, [action])] + | otherwise = [] + +suggestLocalSignature :: Bool -> Maybe HscEnv -> Maybe TcModuleResult -> Maybe Bindings -> Diagnostic -> [(T.Text, [TextEdit])] +suggestLocalSignature isQuickFix mEnv mTmr mBindings Diagnostic {_message, _range = _range@Range {..}} + | Just (_ :: T.Text, _ :: T.Text, _ :: T.Text, [identifier]) <- + (T.unwords . T.words $ _message) + =~~ ("Polymorphic local binding with no type signature: (.*) ::" :: T.Text), + Just bindings <- mBindings, + Just env <- mEnv, + localScope <- getFuzzyScope bindings _start _end, + -- we can't use srcspan to lookup scoped bindings, because the error message reported by GHC includes the entire binding, instead of simply the name + Just (name, ty) <- find (\(x, _) -> printName x == T.unpack identifier) localScope >>= \(name, mTy) -> (name,) <$> mTy, + Just TcModuleResult {tmrTypechecked = TcGblEnv {tcg_rdr_env, tcg_sigs}} <- mTmr, + -- not a top-level thing, to avoid duplication + not $ name `elemNameSet` tcg_sigs, + tyMsg <- printSDocQualifiedUnsafe (mkPrintUnqualifiedDefault env tcg_rdr_env) $ pprSigmaType ty, + signature <- T.pack $ printName name <> " :: " <> tyMsg, + startCharacter <- _character _start, + startOfLine <- Position (_line _start) startCharacter, + beforeLine <- Range startOfLine startOfLine, + title <- if isQuickFix then "add signature: " <> signature else signature, + action <- TextEdit beforeLine $ signature <> "\n" <> T.replicate (fromIntegral startCharacter) " " = + [(title, [action])] + | otherwise = [] + +sameThing :: SrcSpan -> Range -> Bool +sameThing s1 s2 = (_start <$> srcSpanToRange s1) == (_start <$> Just s2) + +gblBindingTypeSigToEdit :: NewCodeActionTypeSig -> Maybe TextEdit +gblBindingTypeSigToEdit NewCodeActionTypeSig {..} + | Just Range {..} <- srcSpanToRange $ getSrcSpan gbName, + startOfLine <- Position (_line _start) 0, + beforeLine <- Range startOfLine startOfLine = + Just $ TextEdit beforeLine $ T.pack gbRendered <> "\n" + | otherwise = Nothing + +data Mode + = -- | always displays type lenses of global bindings, no matter what GHC flags are set + Always + | -- | similar to 'Always', but only displays for exported global bindings + Exported + | -- | follows error messages produced by GHC + Diagnostics + deriving (Eq, Ord, Show, Read, Enum) + +instance A.ToJSON Mode where + toJSON Always = "always" + toJSON Exported = "exported" + toJSON Diagnostics = "diagnostics" + +instance A.FromJSON Mode where + parseJSON = A.withText "Mode" $ \case + "always" -> pure Always + "exported" -> pure Exported + "diagnostics" -> pure Diagnostics + _ -> mzero + +-------------------------------------------------------------------------------- + +showDocRdrEnv :: HscEnv -> GlobalRdrEnv -> SDoc -> String +showDocRdrEnv env rdrEnv = showSDocForUser' env (mkPrintUnqualifiedDefault env rdrEnv) + +data NewCodeActionTypeSigs = NewCodeActionTypeSigs + deriving (Generic, Show, Eq, Ord, Hashable, NFData) + +data NewCodeActionTypeSig = NewCodeActionTypeSig + { gbName :: Name, + gbRendered :: String, + gbExported :: Bool + } + +gbSrcSpan :: NewCodeActionTypeSig -> SrcSpan +gbSrcSpan NewCodeActionTypeSig {gbName} = getSrcSpan gbName + +newtype NewCodeActionTypeSigsResult = NewCodeActionTypeSigsResult [NewCodeActionTypeSig] + +instance Show NewCodeActionTypeSigsResult where + show _ = "" + +instance NFData NewCodeActionTypeSigsResult where + rnf = rwhnf + +type instance RuleResult NewCodeActionTypeSigs = NewCodeActionTypeSigsResult + +rules :: Rules () +rules = do + define $ \NewCodeActionTypeSigs nfp -> do + tmr <- use TypeCheck nfp + -- we need session here for tidying types + hsc <- use GhcSession nfp + result <- liftIO $ gblBindingType (tmrRenamed <$> tmr) (hscEnv <$> hsc) (tmrTypechecked <$> tmr) + pure ([], result) + +gblBindingType :: Maybe RenamedSource -> Maybe HscEnv -> Maybe TcGblEnv -> IO (Maybe NewCodeActionTypeSigsResult) +gblBindingType (Just (rn, _, _, _)) (Just hsc) (Just gblEnv) = do + let exports = availsToNameSet $ tcg_exports gblEnv + -- TODO: check out `getTypeSigNames` + -- sigs = tcg_sigs gblEnv + sigs = maybe emptyNameSet getTypeSigNames $ case hs_valds rn of + ValBinds _ _ s -> Just s + _ -> Nothing + binds = collectHsBindsBinders $ tcg_binds gblEnv + patSyns = tcg_patsyns gblEnv + showDoc = showDocRdrEnv hsc $ tcg_rdr_env gblEnv + hPutStrLn stderr "Renamer stuff" + hPutStrLn stderr $ unsafePrintSDoc $ ppr $ getTypeSigNames <$> (case hs_valds rn of + ValBinds xvb bag gls -> Just gls + XValBindsLR xvbl -> Nothing) + + (_, maybe [] catMaybes -> bindings) <- initTcWithGbl hsc gblEnv (realSrcLocSpan $ mkRealSrcLoc "" 1 1) $ mapM (bindingToSignature sigs exports showDoc) binds + patterns <- catMaybes <$> mapM (patternToSignature sigs exports showDoc) patSyns + pure . Just . NewCodeActionTypeSigsResult $ bindings <> patterns +gblBindingType _ _ _ = pure Nothing + +-- convert a Binding into a Signature +bindingToSignature :: NameSet + -> NameSet + -> (SDoc -> String) + -> Id + -> IOEnv (Env TcGblEnv TcLclEnv) (Maybe NewCodeActionTypeSig) +bindingToSignature sigs exports showDoc id' = do + let name = idName id' + hasSignature name sigs $ do + env <- tcInitTidyEnv + let ty = tidyType env (idType id') + pure $ NewCodeActionTypeSig name (printName name <> " :: " <> showDoc (pprSigmaType ty)) (name `elemNameSet` exports) + +-- convert a Pattern into a Signature +patternToSignature :: Monad m => + NameSet + -> NameSet + -> (SDoc -> String) + -> PatSyn + -> m (Maybe NewCodeActionTypeSig) +patternToSignature sigs exports showDoc pat = do + let name = patSynName pat + hasSignature name sigs $ pure $ NewCodeActionTypeSig name ("pattern " <> printName name <> " :: " <> showDoc (pprPatSynTypeWithoutForalls pat)) (name `elemNameSet` exports) + +-- | Top level bind that HAS a signature +hasSignature :: Monad m => Name -> NameSet -> m a -> m (Maybe a) +hasSignature name sigs = whenMaybe (not $ name `elemNameSet` sigs) + +pprPatSynTypeWithoutForalls :: PatSyn -> SDoc +pprPatSynTypeWithoutForalls p = pprPatSynType pWithoutTypeVariables + where + pWithoutTypeVariables = mkPatSyn name declared_infix ([], req_theta) ([], prov_theta) orig_args' orig_res_ty matcher builder field_labels + (_univ_tvs, req_theta, _ex_tvs, prov_theta, orig_args, orig_res_ty) = patSynSig p + name = patSynName p + declared_infix = patSynIsInfix p + matcher = patSynMatcher p + builder = patSynBuilder p + field_labels = patSynFieldLabels p + orig_args' = map scaledThing orig_args From bffba2a74fe9e196c3baaacb45423167d149c0e7 Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Sat, 29 Jan 2022 11:11:58 -0500 Subject: [PATCH 02/20] Match against specific error message. --- .../src/Development/IDE/Plugin/HLS/GhcIde.hs | 14 +++-- .../Development/IDE/Plugin/NewCodeAction.hs | 61 +++++++++++-------- ghcide/src/Development/IDE/Plugin/error.txt | 6 ++ 3 files changed, 48 insertions(+), 33 deletions(-) create mode 100644 ghcide/src/Development/IDE/Plugin/error.txt diff --git a/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs b/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs index c854330d9c..c05824400e 100644 --- a/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs +++ b/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs @@ -9,15 +9,16 @@ module Development.IDE.Plugin.HLS.GhcIde import Control.Monad.IO.Class import Development.IDE import Development.IDE.LSP.HoverDefinition -import qualified Development.IDE.LSP.Notifications as Notifications +import qualified Development.IDE.LSP.Notifications as Notifications import Development.IDE.LSP.Outline -import qualified Development.IDE.Plugin.CodeAction as CodeAction -import qualified Development.IDE.Plugin.Completions as Completions -import qualified Development.IDE.Plugin.TypeLenses as TypeLenses +import qualified Development.IDE.Plugin.CodeAction as CodeAction +import qualified Development.IDE.Plugin.Completions as Completions +import qualified Development.IDE.Plugin.NewCodeAction as NewCodeAction +import qualified Development.IDE.Plugin.TypeLenses as TypeLenses import Ide.Types -import Language.LSP.Server (LspM) +import Language.LSP.Server (LspM) import Language.LSP.Types -import Text.Regex.TDFA.Text () +import Text.Regex.TDFA.Text () descriptors :: [PluginDescriptor IdeState] descriptors = @@ -28,6 +29,7 @@ descriptors = CodeAction.fillHolePluginDescriptor "ghcide-code-actions-fill-holes", Completions.descriptor "ghcide-completions", TypeLenses.descriptor "ghcide-type-lenses", + NewCodeAction.descriptor "NEW-ACTION", Notifications.descriptor "ghcide-core" ] diff --git a/ghcide/src/Development/IDE/Plugin/NewCodeAction.hs b/ghcide/src/Development/IDE/Plugin/NewCodeAction.hs index 63b1214bc2..eb5fe4872b 100644 --- a/ghcide/src/Development/IDE/Plugin/NewCodeAction.hs +++ b/ghcide/src/Development/IDE/Plugin/NewCodeAction.hs @@ -5,6 +5,7 @@ -- | An HLS plugin to provide code lenses for type signatures module Development.IDE.Plugin.NewCodeAction ( descriptor, + matchExpectedAndActual', suggestSignature, codeActionCommandId, NewCodeActionTypeSig (..), @@ -21,13 +22,14 @@ import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.Aeson.Types (Value (..), toJSON) import qualified Data.Aeson.Types as A import qualified Data.HashMap.Strict as Map +import Data.HashSet (toList) import Data.List (find) -import Data.Maybe (catMaybes, isJust) +import Data.Maybe (catMaybes) +import Data.Text (Text) import qualified Data.Text as T import Development.IDE (GhcSession (..), HscEnvEq (hscEnv), RuleResult, Rules, define, - srcSpanToRange, unsafePrintSDoc) import Development.IDE.Core.Compile (TcModuleResult (..)) import Development.IDE.Core.RuleTypes (GetBindings (GetBindings), @@ -49,8 +51,7 @@ import qualified Development.IDE.Types.Logger as Logger import GHC.Generics (Generic) import Ide.Plugin.Config (Config) import Ide.Plugin.Properties -import Ide.PluginUtils (mkLspCommand, subRange, - usePropertyLsp) +import Ide.PluginUtils (subRange, usePropertyLsp) import Ide.Types (CommandFunction, CommandId (CommandId), PluginCommand (PluginCommand), @@ -66,20 +67,16 @@ import Language.LSP.Types (ApplyWorkspaceEditParams ( CodeAction (..), CodeActionKind (CodeActionQuickFix), CodeActionParams (CodeActionParams, _range, _textDocument), - CodeLens (CodeLens), - CodeLensParams (CodeLensParams, _textDocument), Command, Diagnostic (..), - List (..), ResponseError, - SMethod (..), + List (..), SMethod (..), TextDocumentIdentifier (TextDocumentIdentifier), TextEdit (TextEdit), WorkspaceEdit (WorkspaceEdit), type (|?) (InR)) -import Language.LSP.Types.Lens (HasCodeActionProvider) import System.IO import Text.Regex.TDFA ((=~), (=~~)) -codeActionCommandId :: T.Text +codeActionCommandId :: Text codeActionCommandId = "typesignature.change" descriptor :: PluginId -> PluginDescriptor IdeState @@ -110,6 +107,7 @@ codeActionProvider :: LSP.MonadLsp Config m => IdeState codeActionProvider ideState pId CodeActionParams {_textDocument = TextDocumentIdentifier uri, _range = currRange} = do mode <- usePropertyLsp #mode pId properties fmap (Right . List) $ case uriToFilePath' uri of + Nothing -> pure [] Just (toNormalizedFilePath' -> filePath) -> liftIO $ do env <- fmap hscEnv <$> runAction "codeLens.GhcSession" ideState (use GhcSession filePath) tmr <- runAction "codeLens.TypeCheck" ideState (use TypeCheck filePath) @@ -118,13 +116,15 @@ codeActionProvider ideState pId CodeActionParams {_textDocument = TextDocumentId diag <- atomically $ getDiagnostics ideState hDiag <- atomically $ getHiddenDiagnostics ideState - -- liftIO $ Logger.logError (ideLogger ideState) $ T.pack $ show diag + liftIO $ Logger.logError (ideLogger ideState) $ T.pack $ "Prematched Diags:" <> show diag -- liftIO $ Logger.logError (ideLogger ideState) $ T.pack $ show hDiag let toWorkSpaceEdit tedit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing Nothing - matchDiags = filter (\(_, _, d) -> cantMatchType d && currRange `contains` d) (diag <> hDiag) - liftIO $ Logger.logError (ideLogger ideState) $ T.pack $ show matchDiags - hPrint stderr matchDiags + -- generate a list of diagnostics in current range AND has the expected message + matchedDiags = catMaybes [ matchExpectedAndActual d | (_, _, d) <- diag <> hDiag] + + liftIO $ Logger.logError (ideLogger ideState) $ T.pack $ "Matched Diags:" <> show matchedDiags + -- hPrint stderr matchedDiags -- generateActionForGlobal sig@NewCodeActionTypeSig {..} = do -- range <- srcSpanToRange $ gbSrcSpan sig -- tedit <- gblBindingTypeSigToEdit sig @@ -139,7 +139,7 @@ codeActionProvider ideState pId CodeActionParams {_textDocument = TextDocumentId -- (title, tedit) <- f dDiag, -- let edit = toWorkSpaceEdit tedit -- ] - --pure (catMaybes $ generateActionForGlobal <$> gblSigs') + pure [] -- case mode of -- Always -> @@ -149,7 +149,7 @@ codeActionProvider ideState pId CodeActionParams {_textDocument = TextDocumentId -- Diagnostics -> generateActionFromDiags $ suggestSignature False env gblSigs tmr bindings -- Nothing -> pure [] -generateAction :: p1 -> p2 -> T.Text -> WorkspaceEdit -> a |? CodeAction +generateAction :: p1 -> p2 -> Text -> WorkspaceEdit -> a |? CodeAction generateAction _ _ title edit = InR CodeAction { _title = title, _kind = Just CodeActionQuickFix, @@ -166,25 +166,32 @@ commandHandler _ideState wedit = do _ <- LSP.sendRequest SWorkspaceApplyEdit (ApplyWorkspaceEditParams Nothing wedit) (\_ -> pure ()) return $ Right Null -test :: Int -> Int -test x = length x - -------------------------------------------------------------------------------- +-- test :: Int -> Int +-- test = head . toList -suggestSignature :: Bool -> Maybe HscEnv -> Maybe NewCodeActionTypeSigsResult -> Maybe TcModuleResult -> Maybe Bindings -> Diagnostic -> [(T.Text, [TextEdit])] +suggestSignature :: Bool -> Maybe HscEnv -> Maybe NewCodeActionTypeSigsResult -> Maybe TcModuleResult -> Maybe Bindings -> Diagnostic -> [(Text, [TextEdit])] suggestSignature isQuickFix env mGblSigs mTmr mBindings diag = suggestGlobalSignature isQuickFix mGblSigs diag <> suggestLocalSignature isQuickFix env mTmr mBindings diag -cantMatchType :: Diagnostic -> Bool -cantMatchType Diagnostic {_message} = _message =~ ("Couldn't match expected type" :: T.Text) +matchExpectedAndActual :: Diagnostic -> Maybe (Text, Text, Text) +matchExpectedAndActual Diagnostic{_message}= matchExpectedAndActual' _message + +matchExpectedAndActual' :: Text -> Maybe (Text, Text, Text) +matchExpectedAndActual' message = unwrapMatch $ message =~ ("Expected type: (.+)\n +Actual type: (.+)\n.*\n +In an equation for ‘(.+)’" :: Text) + where + unwrapMatch :: (Text, Text, Text, [Text]) -> Maybe (Text, Text, Text) + unwrapMatch (_, _, _, [exp, act, funcName]) = Just (exp, act, funcName) + unwrapMatch _ = Nothing + contains :: Range -> Diagnostic -> Bool contains range Diagnostic {_range} = subRange range _range -suggestGlobalSignature :: Bool -> Maybe NewCodeActionTypeSigsResult -> Diagnostic -> [(T.Text, [TextEdit])] +suggestGlobalSignature :: Bool -> Maybe NewCodeActionTypeSigsResult -> Diagnostic -> [(Text, [TextEdit])] suggestGlobalSignature isQuickFix mGblSigs Diagnostic {_message, _range} | _message - =~ ("Couldn't match expected type" :: T.Text), + =~ ("Couldn't match expected type" :: Text), Just (NewCodeActionTypeSigsResult sigs) <- mGblSigs, Just sig <- find (\x -> sameThing (gbSrcSpan x) _range) sigs, signature <- T.pack $ gbRendered sig, @@ -193,11 +200,11 @@ suggestGlobalSignature isQuickFix mGblSigs Diagnostic {_message, _range} [(title, [action])] | otherwise = [] -suggestLocalSignature :: Bool -> Maybe HscEnv -> Maybe TcModuleResult -> Maybe Bindings -> Diagnostic -> [(T.Text, [TextEdit])] +suggestLocalSignature :: Bool -> Maybe HscEnv -> Maybe TcModuleResult -> Maybe Bindings -> Diagnostic -> [(Text, [TextEdit])] suggestLocalSignature isQuickFix mEnv mTmr mBindings Diagnostic {_message, _range = _range@Range {..}} - | Just (_ :: T.Text, _ :: T.Text, _ :: T.Text, [identifier]) <- + | Just (_ :: Text, _ :: Text, _ :: Text, [identifier]) <- (T.unwords . T.words $ _message) - =~~ ("Polymorphic local binding with no type signature: (.*) ::" :: T.Text), + =~~ ("Polymorphic local binding with no type signature: (.*) ::" :: Text), Just bindings <- mBindings, Just env <- mEnv, localScope <- getFuzzyScope bindings _start _end, diff --git a/ghcide/src/Development/IDE/Plugin/error.txt b/ghcide/src/Development/IDE/Plugin/error.txt new file mode 100644 index 0000000000..37f0aa4a81 --- /dev/null +++ b/ghcide/src/Development/IDE/Plugin/error.txt @@ -0,0 +1,6 @@ + • Couldn't match type ‘Int’ + with ‘Data.HashSet.Internal.HashSet Int’ + Expected type: Int -> Int + Actual type: Data.HashSet.Internal.HashSet Int -> Int + • In the expression: head . toList + In an equation for ‘test’: test = head . toList From 80a8fa12b6f08c1be49ef5c51ca63c1d8ee7058c Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Sun, 30 Jan 2022 23:59:57 -0500 Subject: [PATCH 03/20] Basic Change Type Signature implementation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implementation only matches a single GHC Error message: ``` • Couldn't match type ‘Int’ with ‘Data.HashSet.Internal.HashSet Int’ Expected type: Int -> Int Actual type: Data.HashSet.Internal.HashSet Int -> Int • In the expression: head . toList In an equation for ‘test’: test = head . toList ``` Specifically on `Expected type: ...`, `Actual type:...` and `In an equation ...`. There are plenty of error messages that match this format but aren't actually valid. --- ghcide/ghcide.cabal | 2 +- .../IDE/Plugin/ChangeTypeAction.hs | 128 +++++++ .../src/Development/IDE/Plugin/HLS/GhcIde.hs | 16 +- .../Development/IDE/Plugin/NewCodeAction.hs | 353 ------------------ hls-plugin-api/src/Ide/PluginUtils.hs | 11 + 5 files changed, 148 insertions(+), 362 deletions(-) create mode 100644 ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs delete mode 100644 ghcide/src/Development/IDE/Plugin/NewCodeAction.hs diff --git a/ghcide/ghcide.cabal b/ghcide/ghcide.cabal index cf75c3a61d..82acbf6db8 100644 --- a/ghcide/ghcide.cabal +++ b/ghcide/ghcide.cabal @@ -205,7 +205,7 @@ library Development.IDE.Plugin.HLS.GhcIde Development.IDE.Plugin.Test Development.IDE.Plugin.TypeLenses - Development.IDE.Plugin.NewCodeAction + Development.IDE.Plugin.ChangeTypeAction other-modules: Development.IDE.Core.FileExists diff --git a/ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs b/ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs new file mode 100644 index 0000000000..4cf7f49717 --- /dev/null +++ b/ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs @@ -0,0 +1,128 @@ +{-# LANGUAGE ConstraintKinds #-} +-- | An HLS plugin to provide code actions to change type signatures +module Development.IDE.Plugin.ChangeTypeAction (descriptor) where + +import Control.Monad.IO.Class (MonadIO (liftIO)) +import Control.Monad.Trans.Except (ExceptT) +import qualified Data.HashMap.Strict as Map +import Data.Maybe (listToMaybe, mapMaybe) +import Data.Text (Text) +import qualified Data.Text as T +import Development.IDE.Core.RuleTypes (GetParsedModule (GetParsedModule)) +import Development.IDE.Core.Service (IdeState, runAction) +import Development.IDE.Core.Shake (use) +import Development.IDE.GHC.Compat +import Development.IDE.GHC.Error (realSrcSpanToRange) +import Ide.PluginUtils (getNormalizedFilePath, + handleMaybeM, response) +import Ide.Types (PluginDescriptor (..), + PluginId, PluginMethodHandler, + defaultPluginDescriptor, + mkPluginHandler) +import Language.LSP.Types (CodeAction (..), + CodeActionContext (CodeActionContext), + CodeActionKind (CodeActionQuickFix), + CodeActionParams (..), Command, + Diagnostic (..), List (..), + Method (TextDocumentCodeAction), + NormalizedFilePath, + SMethod (..), + TextDocumentIdentifier (TextDocumentIdentifier), + TextEdit (TextEdit), Uri, + WorkspaceEdit (WorkspaceEdit), + type (|?) (InR)) +import Text.Regex.TDFA ((=~)) + +descriptor :: PluginId -> PluginDescriptor IdeState +descriptor plId = (defaultPluginDescriptor plId) { pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionHandler } + +codeActionHandler :: PluginMethodHandler IdeState 'TextDocumentCodeAction +codeActionHandler ideState plId CodeActionParams {_textDocument = TextDocumentIdentifier uri, _context = CodeActionContext (List diags) _} = response $ do + nfp <- getNormalizedFilePath plId (TextDocumentIdentifier uri) + decls <- getDecls ideState nfp + let actions = generateActions uri decls diags + pure $ List actions + +getDecls :: MonadIO m => IdeState -> NormalizedFilePath -> ExceptT String m [LHsDecl GhcPs] +getDecls state = handleMaybeM "Error: Could not get Parsed Module" + . liftIO + . fmap (fmap (hsmodDecls . unLoc . pm_parsed_source)) + . runAction "changeSignature.GetParsedModule" state + . use GetParsedModule + +data ChangeSignature = ChangeSignature { expectedType :: Text + , actualType :: Text + , declName :: Text + , declSrcSpan :: Maybe SrcSpan + , diagnostic :: Diagnostic + , uri :: Uri + } + +-- Needed to trackdown OccNames in signatures +type SigName p = (HasOccName (IdP (GhcPass p))) + +-- | Generate CodeActions from a list of Diagnostics +generateActions :: SigName p => Uri -> [LHsDecl (GhcPass p)] -> [Diagnostic] -> [Command |? CodeAction] +generateActions uri = mapMaybe . generateAction uri + +-- | Create a CodeAction from a Diagnostic +generateAction :: SigName p => Uri -> [LHsDecl (GhcPass p)] -> Diagnostic -> Maybe (Command |? CodeAction) +generateAction uri decls diag = diagnosticToChangeSig uri decls diag >>= changeSigToCodeAction + +-- | Convert a diagnostic into a ChangeSignature and add the proper SrcSpan +diagnosticToChangeSig :: SigName p => Uri -> [LHsDecl (GhcPass p)] -> Diagnostic -> Maybe ChangeSignature +diagnosticToChangeSig uri decls diag = addSrcSpan decls <$> matchingDiagnostic uri diag + +-- | If a diagnostic has the proper message create a ChangeSignature from it +matchingDiagnostic :: Uri -> Diagnostic -> Maybe ChangeSignature +matchingDiagnostic uri diag@Diagnostic{_message} = unwrapMatch $ _message =~ ("Expected type: (.+)\n +Actual type: (.+)\n.*\n +In an equation for ‘(.+)’" :: Text) + where + unwrapMatch :: (Text, Text, Text, [Text]) -> Maybe ChangeSignature + unwrapMatch (_, _, _, [exp, act, name]) = Just $ ChangeSignature exp act name Nothing diag uri + unwrapMatch _ = Nothing + +-- | Given a String with the name of a declaration, find that declarations type signature location +-- This is a modified version of functions found in Development.IDE.Plugin.CodeAction +findSigLocOfStringDecl :: SigName p => [LHsDecl (GhcPass p)] -> String -> Maybe SrcSpan +findSigLocOfStringDecl decls declName = + listToMaybe + [ srcSpan + | L srcSpan (SigD _ (TypeSig _ idsSig _)) <- decls, + any ((==) declName . occNameString . occName . unLoc) idsSig + ] + +-- | Update a ChangeSignature to potentially populate `declSrcSpan` +addSrcSpan :: SigName p => [LHsDecl (GhcPass p)] -> ChangeSignature -> ChangeSignature +addSrcSpan _ self@(ChangeSignature _ _ _ (Just _) _ _) = self +addSrcSpan decls chgSig@ChangeSignature{..} = chgSig { declSrcSpan = findSigLocOfStringDecl decls (T.unpack declName) } + +changeSigToCodeAction :: ChangeSignature -> Maybe (Command |? CodeAction) +-- Does not generate a Code action if declSrcSpan is Nothing +changeSigToCodeAction ChangeSignature{..} = declSrcSpan *> Just (InR CodeAction { _title = mkChangeSigTitle declName actualType + , _kind = Just CodeActionQuickFix + , _diagnostics = Just $ List [diagnostic] + , _isPreferred = Nothing + , _disabled = Nothing + -- This CAN but probably never will be Nothing + , _edit = mkChangeSigEdit uri declSrcSpan (mkNewSignature declName actualType) + , _command = Nothing + , _xdata = Nothing + }) +mkChangeSigTitle :: Text -> Text -> Text +mkChangeSigTitle declName actualType = "change signature for ‘" <> declName <> "’ to: " <> actualType + +mkChangeSigEdit :: Uri -> Maybe SrcSpan -> Text -> Maybe WorkspaceEdit +mkChangeSigEdit uri (Just (RealSrcSpan ss _)) replacement = + let txtEdit = TextEdit (realSrcSpanToRange ss) replacement + changes = Just $ Map.singleton uri (List [txtEdit]) + in Just $ WorkspaceEdit changes Nothing Nothing +mkChangeSigEdit _ _ _ = Nothing + +mkNewSignature :: Text -> Text -> Text +mkNewSignature declName actualType = declName <> " :: " <> actualType + +-------------------------------------------------------------------------------- +-- test :: Set.Set Int -> Int +-- test = go +-- where +-- go = head . Set.toList diff --git a/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs b/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs index c05824400e..c7d4e8aaeb 100644 --- a/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs +++ b/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs @@ -9,16 +9,16 @@ module Development.IDE.Plugin.HLS.GhcIde import Control.Monad.IO.Class import Development.IDE import Development.IDE.LSP.HoverDefinition -import qualified Development.IDE.LSP.Notifications as Notifications +import qualified Development.IDE.LSP.Notifications as Notifications import Development.IDE.LSP.Outline -import qualified Development.IDE.Plugin.CodeAction as CodeAction -import qualified Development.IDE.Plugin.Completions as Completions -import qualified Development.IDE.Plugin.NewCodeAction as NewCodeAction -import qualified Development.IDE.Plugin.TypeLenses as TypeLenses +import qualified Development.IDE.Plugin.ChangeTypeAction as ChangeTypeAction +import qualified Development.IDE.Plugin.CodeAction as CodeAction +import qualified Development.IDE.Plugin.Completions as Completions +import qualified Development.IDE.Plugin.TypeLenses as TypeLenses import Ide.Types -import Language.LSP.Server (LspM) +import Language.LSP.Server (LspM) import Language.LSP.Types -import Text.Regex.TDFA.Text () +import Text.Regex.TDFA.Text () descriptors :: [PluginDescriptor IdeState] descriptors = @@ -29,7 +29,7 @@ descriptors = CodeAction.fillHolePluginDescriptor "ghcide-code-actions-fill-holes", Completions.descriptor "ghcide-completions", TypeLenses.descriptor "ghcide-type-lenses", - NewCodeAction.descriptor "NEW-ACTION", + ChangeTypeAction.descriptor "ghcide-change-type", Notifications.descriptor "ghcide-core" ] diff --git a/ghcide/src/Development/IDE/Plugin/NewCodeAction.hs b/ghcide/src/Development/IDE/Plugin/NewCodeAction.hs deleted file mode 100644 index eb5fe4872b..0000000000 --- a/ghcide/src/Development/IDE/Plugin/NewCodeAction.hs +++ /dev/null @@ -1,353 +0,0 @@ -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE OverloadedLabels #-} -{-# LANGUAGE TypeFamilies #-} - --- | An HLS plugin to provide code lenses for type signatures -module Development.IDE.Plugin.NewCodeAction - ( descriptor, - matchExpectedAndActual', - suggestSignature, - codeActionCommandId, - NewCodeActionTypeSig (..), - NewCodeActionTypeSigs (..), - NewCodeActionTypeSigsResult (..), - ) -where - -import Control.Concurrent.STM.Stats (atomically) -import Control.DeepSeq (rwhnf) -import Control.Monad (mzero) -import Control.Monad.Extra (whenMaybe) -import Control.Monad.IO.Class (MonadIO (liftIO)) -import Data.Aeson.Types (Value (..), toJSON) -import qualified Data.Aeson.Types as A -import qualified Data.HashMap.Strict as Map -import Data.HashSet (toList) -import Data.List (find) -import Data.Maybe (catMaybes) -import Data.Text (Text) -import qualified Data.Text as T -import Development.IDE (GhcSession (..), - HscEnvEq (hscEnv), - RuleResult, Rules, define, - unsafePrintSDoc) -import Development.IDE.Core.Compile (TcModuleResult (..)) -import Development.IDE.Core.RuleTypes (GetBindings (GetBindings), - TypeCheck (TypeCheck)) -import Development.IDE.Core.Rules (IdeState, runAction) -import Development.IDE.Core.Service (getDiagnostics) -import Development.IDE.Core.Shake (getHiddenDiagnostics, - ideLogger, logger, use) -import Development.IDE.GHC.Compat -import Development.IDE.GHC.Error -import Development.IDE.GHC.Util (printName) -import Development.IDE.Graph.Classes -import Development.IDE.Spans.LocalBindings (Bindings, getFuzzyScope) -import Development.IDE.Types.Location (Position (Position, _character, _line), - Range (Range, _end, _start), - toNormalizedFilePath', - uriToFilePath') -import qualified Development.IDE.Types.Logger as Logger -import GHC.Generics (Generic) -import Ide.Plugin.Config (Config) -import Ide.Plugin.Properties -import Ide.PluginUtils (subRange, usePropertyLsp) -import Ide.Types (CommandFunction, - CommandId (CommandId), - PluginCommand (PluginCommand), - PluginDescriptor (..), - PluginId, - configCustomConfig, - defaultConfigDescriptor, - defaultPluginDescriptor, - mkCustomConfig, - mkPluginHandler) -import qualified Language.LSP.Server as LSP -import Language.LSP.Types (ApplyWorkspaceEditParams (ApplyWorkspaceEditParams), - CodeAction (..), - CodeActionKind (CodeActionQuickFix), - CodeActionParams (CodeActionParams, _range, _textDocument), - Command, Diagnostic (..), - List (..), SMethod (..), - TextDocumentIdentifier (TextDocumentIdentifier), - TextEdit (TextEdit), - WorkspaceEdit (WorkspaceEdit), - type (|?) (InR)) -import System.IO -import Text.Regex.TDFA ((=~), (=~~)) - -codeActionCommandId :: Text -codeActionCommandId = "typesignature.change" - -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = - (defaultPluginDescriptor plId) - { pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionProvider, - pluginCommands = [PluginCommand (CommandId codeActionCommandId) "change a signature" commandHandler], - pluginRules = rules, - pluginConfigDescriptor = defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties} - } - -properties :: Properties '[ 'PropertyKey "mode" ('TEnum Mode)] -properties = - emptyProperties - & defineEnumProperty - #mode - "Control how type lenses are shown" - [ (Always, "Always displays type lenses of global bindings"), - (Exported, "Only display type lenses of exported global bindings"), - (Diagnostics, "Follows error messages produced by GHC about missing signatures") - ] - Always - -codeActionProvider :: LSP.MonadLsp Config m => IdeState - -> PluginId - -> CodeActionParams - -> m (Either a (List (Command |? CodeAction))) -codeActionProvider ideState pId CodeActionParams {_textDocument = TextDocumentIdentifier uri, _range = currRange} = do - mode <- usePropertyLsp #mode pId properties - fmap (Right . List) $ case uriToFilePath' uri of - Nothing -> pure [] - Just (toNormalizedFilePath' -> filePath) -> liftIO $ do - env <- fmap hscEnv <$> runAction "codeLens.GhcSession" ideState (use GhcSession filePath) - tmr <- runAction "codeLens.TypeCheck" ideState (use TypeCheck filePath) - bindings <- runAction "codeLens.GetBindings" ideState (use GetBindings filePath) - -- gblSigs <- runAction "codeLens.NewCodeActionTypeSigs" ideState (use NewCodeActionTypeSigs filePath) - - diag <- atomically $ getDiagnostics ideState - hDiag <- atomically $ getHiddenDiagnostics ideState - liftIO $ Logger.logError (ideLogger ideState) $ T.pack $ "Prematched Diags:" <> show diag - -- liftIO $ Logger.logError (ideLogger ideState) $ T.pack $ show hDiag - - let toWorkSpaceEdit tedit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing Nothing - -- generate a list of diagnostics in current range AND has the expected message - matchedDiags = catMaybes [ matchExpectedAndActual d | (_, _, d) <- diag <> hDiag] - - liftIO $ Logger.logError (ideLogger ideState) $ T.pack $ "Matched Diags:" <> show matchedDiags - -- hPrint stderr matchedDiags - -- generateActionForGlobal sig@NewCodeActionTypeSig {..} = do - -- range <- srcSpanToRange $ gbSrcSpan sig - -- tedit <- gblBindingTypeSigToEdit sig - -- let wedit = toWorkSpaceEdit [tedit] - -- pure $ generateAction pId range (T.pack gbRendered) wedit - -- gblSigs' = maybe [] (\(NewCodeActionTypeSigsResult x) -> x) gblSigs - -- generateActionFromDiags f = - -- sequence - -- [ pure $ generateAction pId _range title edit - -- | (dFile, _, dDiag@Diagnostic {_range = _range}) <- diag ++ hDiag, - -- dFile == filePath, - -- (title, tedit) <- f dDiag, - -- let edit = toWorkSpaceEdit tedit - -- ] - - pure [] - -- case mode of - -- Always -> - - -- <> generateActionFromDiags (suggestLocalSignature False env tmr bindings) -- we still need diagnostics for local bindings - -- Exported -> pure $ catMaybes $ generateActionForGlobal <$> filter gbExported gblSigs' - -- Diagnostics -> generateActionFromDiags $ suggestSignature False env gblSigs tmr bindings - -- Nothing -> pure [] - -generateAction :: p1 -> p2 -> Text -> WorkspaceEdit -> a |? CodeAction -generateAction _ _ title edit = InR CodeAction { - _title = title, - _kind = Just CodeActionQuickFix, - _diagnostics = Nothing, - _isPreferred = Nothing, - _disabled = Nothing, - _edit = Just edit, - _command = Nothing, - _xdata = Nothing - } - -commandHandler :: CommandFunction IdeState WorkspaceEdit -commandHandler _ideState wedit = do - _ <- LSP.sendRequest SWorkspaceApplyEdit (ApplyWorkspaceEditParams Nothing wedit) (\_ -> pure ()) - return $ Right Null - --------------------------------------------------------------------------------- --- test :: Int -> Int --- test = head . toList - -suggestSignature :: Bool -> Maybe HscEnv -> Maybe NewCodeActionTypeSigsResult -> Maybe TcModuleResult -> Maybe Bindings -> Diagnostic -> [(Text, [TextEdit])] -suggestSignature isQuickFix env mGblSigs mTmr mBindings diag = - suggestGlobalSignature isQuickFix mGblSigs diag <> suggestLocalSignature isQuickFix env mTmr mBindings diag - -matchExpectedAndActual :: Diagnostic -> Maybe (Text, Text, Text) -matchExpectedAndActual Diagnostic{_message}= matchExpectedAndActual' _message - -matchExpectedAndActual' :: Text -> Maybe (Text, Text, Text) -matchExpectedAndActual' message = unwrapMatch $ message =~ ("Expected type: (.+)\n +Actual type: (.+)\n.*\n +In an equation for ‘(.+)’" :: Text) - where - unwrapMatch :: (Text, Text, Text, [Text]) -> Maybe (Text, Text, Text) - unwrapMatch (_, _, _, [exp, act, funcName]) = Just (exp, act, funcName) - unwrapMatch _ = Nothing - - -contains :: Range -> Diagnostic -> Bool -contains range Diagnostic {_range} = subRange range _range - -suggestGlobalSignature :: Bool -> Maybe NewCodeActionTypeSigsResult -> Diagnostic -> [(Text, [TextEdit])] -suggestGlobalSignature isQuickFix mGblSigs Diagnostic {_message, _range} - | _message - =~ ("Couldn't match expected type" :: Text), - Just (NewCodeActionTypeSigsResult sigs) <- mGblSigs, - Just sig <- find (\x -> sameThing (gbSrcSpan x) _range) sigs, - signature <- T.pack $ gbRendered sig, - title <- if isQuickFix then "change signature: " <> signature else signature, - Just action <- gblBindingTypeSigToEdit sig = - [(title, [action])] - | otherwise = [] - -suggestLocalSignature :: Bool -> Maybe HscEnv -> Maybe TcModuleResult -> Maybe Bindings -> Diagnostic -> [(Text, [TextEdit])] -suggestLocalSignature isQuickFix mEnv mTmr mBindings Diagnostic {_message, _range = _range@Range {..}} - | Just (_ :: Text, _ :: Text, _ :: Text, [identifier]) <- - (T.unwords . T.words $ _message) - =~~ ("Polymorphic local binding with no type signature: (.*) ::" :: Text), - Just bindings <- mBindings, - Just env <- mEnv, - localScope <- getFuzzyScope bindings _start _end, - -- we can't use srcspan to lookup scoped bindings, because the error message reported by GHC includes the entire binding, instead of simply the name - Just (name, ty) <- find (\(x, _) -> printName x == T.unpack identifier) localScope >>= \(name, mTy) -> (name,) <$> mTy, - Just TcModuleResult {tmrTypechecked = TcGblEnv {tcg_rdr_env, tcg_sigs}} <- mTmr, - -- not a top-level thing, to avoid duplication - not $ name `elemNameSet` tcg_sigs, - tyMsg <- printSDocQualifiedUnsafe (mkPrintUnqualifiedDefault env tcg_rdr_env) $ pprSigmaType ty, - signature <- T.pack $ printName name <> " :: " <> tyMsg, - startCharacter <- _character _start, - startOfLine <- Position (_line _start) startCharacter, - beforeLine <- Range startOfLine startOfLine, - title <- if isQuickFix then "add signature: " <> signature else signature, - action <- TextEdit beforeLine $ signature <> "\n" <> T.replicate (fromIntegral startCharacter) " " = - [(title, [action])] - | otherwise = [] - -sameThing :: SrcSpan -> Range -> Bool -sameThing s1 s2 = (_start <$> srcSpanToRange s1) == (_start <$> Just s2) - -gblBindingTypeSigToEdit :: NewCodeActionTypeSig -> Maybe TextEdit -gblBindingTypeSigToEdit NewCodeActionTypeSig {..} - | Just Range {..} <- srcSpanToRange $ getSrcSpan gbName, - startOfLine <- Position (_line _start) 0, - beforeLine <- Range startOfLine startOfLine = - Just $ TextEdit beforeLine $ T.pack gbRendered <> "\n" - | otherwise = Nothing - -data Mode - = -- | always displays type lenses of global bindings, no matter what GHC flags are set - Always - | -- | similar to 'Always', but only displays for exported global bindings - Exported - | -- | follows error messages produced by GHC - Diagnostics - deriving (Eq, Ord, Show, Read, Enum) - -instance A.ToJSON Mode where - toJSON Always = "always" - toJSON Exported = "exported" - toJSON Diagnostics = "diagnostics" - -instance A.FromJSON Mode where - parseJSON = A.withText "Mode" $ \case - "always" -> pure Always - "exported" -> pure Exported - "diagnostics" -> pure Diagnostics - _ -> mzero - --------------------------------------------------------------------------------- - -showDocRdrEnv :: HscEnv -> GlobalRdrEnv -> SDoc -> String -showDocRdrEnv env rdrEnv = showSDocForUser' env (mkPrintUnqualifiedDefault env rdrEnv) - -data NewCodeActionTypeSigs = NewCodeActionTypeSigs - deriving (Generic, Show, Eq, Ord, Hashable, NFData) - -data NewCodeActionTypeSig = NewCodeActionTypeSig - { gbName :: Name, - gbRendered :: String, - gbExported :: Bool - } - -gbSrcSpan :: NewCodeActionTypeSig -> SrcSpan -gbSrcSpan NewCodeActionTypeSig {gbName} = getSrcSpan gbName - -newtype NewCodeActionTypeSigsResult = NewCodeActionTypeSigsResult [NewCodeActionTypeSig] - -instance Show NewCodeActionTypeSigsResult where - show _ = "" - -instance NFData NewCodeActionTypeSigsResult where - rnf = rwhnf - -type instance RuleResult NewCodeActionTypeSigs = NewCodeActionTypeSigsResult - -rules :: Rules () -rules = do - define $ \NewCodeActionTypeSigs nfp -> do - tmr <- use TypeCheck nfp - -- we need session here for tidying types - hsc <- use GhcSession nfp - result <- liftIO $ gblBindingType (tmrRenamed <$> tmr) (hscEnv <$> hsc) (tmrTypechecked <$> tmr) - pure ([], result) - -gblBindingType :: Maybe RenamedSource -> Maybe HscEnv -> Maybe TcGblEnv -> IO (Maybe NewCodeActionTypeSigsResult) -gblBindingType (Just (rn, _, _, _)) (Just hsc) (Just gblEnv) = do - let exports = availsToNameSet $ tcg_exports gblEnv - -- TODO: check out `getTypeSigNames` - -- sigs = tcg_sigs gblEnv - sigs = maybe emptyNameSet getTypeSigNames $ case hs_valds rn of - ValBinds _ _ s -> Just s - _ -> Nothing - binds = collectHsBindsBinders $ tcg_binds gblEnv - patSyns = tcg_patsyns gblEnv - showDoc = showDocRdrEnv hsc $ tcg_rdr_env gblEnv - hPutStrLn stderr "Renamer stuff" - hPutStrLn stderr $ unsafePrintSDoc $ ppr $ getTypeSigNames <$> (case hs_valds rn of - ValBinds xvb bag gls -> Just gls - XValBindsLR xvbl -> Nothing) - - (_, maybe [] catMaybes -> bindings) <- initTcWithGbl hsc gblEnv (realSrcLocSpan $ mkRealSrcLoc "" 1 1) $ mapM (bindingToSignature sigs exports showDoc) binds - patterns <- catMaybes <$> mapM (patternToSignature sigs exports showDoc) patSyns - pure . Just . NewCodeActionTypeSigsResult $ bindings <> patterns -gblBindingType _ _ _ = pure Nothing - --- convert a Binding into a Signature -bindingToSignature :: NameSet - -> NameSet - -> (SDoc -> String) - -> Id - -> IOEnv (Env TcGblEnv TcLclEnv) (Maybe NewCodeActionTypeSig) -bindingToSignature sigs exports showDoc id' = do - let name = idName id' - hasSignature name sigs $ do - env <- tcInitTidyEnv - let ty = tidyType env (idType id') - pure $ NewCodeActionTypeSig name (printName name <> " :: " <> showDoc (pprSigmaType ty)) (name `elemNameSet` exports) - --- convert a Pattern into a Signature -patternToSignature :: Monad m => - NameSet - -> NameSet - -> (SDoc -> String) - -> PatSyn - -> m (Maybe NewCodeActionTypeSig) -patternToSignature sigs exports showDoc pat = do - let name = patSynName pat - hasSignature name sigs $ pure $ NewCodeActionTypeSig name ("pattern " <> printName name <> " :: " <> showDoc (pprPatSynTypeWithoutForalls pat)) (name `elemNameSet` exports) - --- | Top level bind that HAS a signature -hasSignature :: Monad m => Name -> NameSet -> m a -> m (Maybe a) -hasSignature name sigs = whenMaybe (not $ name `elemNameSet` sigs) - -pprPatSynTypeWithoutForalls :: PatSyn -> SDoc -pprPatSynTypeWithoutForalls p = pprPatSynType pWithoutTypeVariables - where - pWithoutTypeVariables = mkPatSyn name declared_infix ([], req_theta) ([], prov_theta) orig_args' orig_res_ty matcher builder field_labels - (_univ_tvs, req_theta, _ex_tvs, prov_theta, orig_args, orig_res_ty) = patSynSig p - name = patSynName p - declared_infix = patSynIsInfix p - matcher = patSynMatcher p - builder = patSynBuilder p - field_labels = patSynFieldLabels p - orig_args' = map scaledThing orig_args diff --git a/hls-plugin-api/src/Ide/PluginUtils.hs b/hls-plugin-api/src/Ide/PluginUtils.hs index 5df855f356..474e735b50 100644 --- a/hls-plugin-api/src/Ide/PluginUtils.hs +++ b/hls-plugin-api/src/Ide/PluginUtils.hs @@ -27,6 +27,7 @@ module Ide.PluginUtils subRange, positionInRange, usePropertyLsp, + getNormalizedFilePath, response, handleMaybe, handleMaybeM, @@ -34,6 +35,7 @@ module Ide.PluginUtils where +import Control.Lens ((^.)) import Control.Monad.Extra (maybeM) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Except (ExceptT, runExceptT, throwE) @@ -54,6 +56,7 @@ import Language.LSP.Types hiding SemanticTokensEdit (_start)) import qualified Language.LSP.Types as J import Language.LSP.Types.Capabilities +import Language.LSP.Types.Lens (uri) -- --------------------------------------------------------------------- @@ -243,6 +246,14 @@ allLspCmdIds pid commands = concatMap go commands -- --------------------------------------------------------------------- +getNormalizedFilePath :: Monad m => PluginId -> TextDocumentIdentifier -> ExceptT String m NormalizedFilePath +getNormalizedFilePath (PluginId plId) docId = handleMaybe errMsg + $ uriToNormalizedFilePath + $ toNormalizedUri (docId ^. uri) + where + errMsg = T.unpack $ "Error(" <> plId <> "): converting to NormalizedFilePath" + +-- --------------------------------------------------------------------- handleMaybe :: Monad m => e -> Maybe b -> ExceptT e m b handleMaybe msg = maybe (throwE msg) return From b144e1e8c18a2cdd00490440058f4264fef96533 Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Mon, 31 Jan 2022 00:34:13 -0500 Subject: [PATCH 04/20] GHC 9.2.0 compat change --- ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs b/ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs index 4cf7f49717..bc2daa68b8 100644 --- a/ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs +++ b/ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} -- | An HLS plugin to provide code actions to change type signatures module Development.IDE.Plugin.ChangeTypeAction (descriptor) where @@ -86,7 +87,7 @@ matchingDiagnostic uri diag@Diagnostic{_message} = unwrapMatch $ _message =~ ("E findSigLocOfStringDecl :: SigName p => [LHsDecl (GhcPass p)] -> String -> Maybe SrcSpan findSigLocOfStringDecl decls declName = listToMaybe - [ srcSpan + [ locA srcSpan | L srcSpan (SigD _ (TypeSig _ idsSig _)) <- decls, any ((==) declName . occNameString . occName . unLoc) idsSig ] From 15015ecd89b7233f88eb15c00243d654700b5b40 Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Tue, 1 Feb 2022 19:20:40 -0500 Subject: [PATCH 05/20] Lift expectedError message into a separate binding --- ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs b/ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs index bc2daa68b8..d3b66b9fb9 100644 --- a/ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs +++ b/ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs @@ -76,8 +76,9 @@ diagnosticToChangeSig uri decls diag = addSrcSpan decls <$> matchingDiagnostic u -- | If a diagnostic has the proper message create a ChangeSignature from it matchingDiagnostic :: Uri -> Diagnostic -> Maybe ChangeSignature -matchingDiagnostic uri diag@Diagnostic{_message} = unwrapMatch $ _message =~ ("Expected type: (.+)\n +Actual type: (.+)\n.*\n +In an equation for ‘(.+)’" :: Text) +matchingDiagnostic uri diag@Diagnostic{_message} = unwrapMatch $ _message =~ expectedMessage where + expectedMessage = "Expected type: (.+)\n +Actual type: (.+)\n.*\n +In an equation for ‘(.+)’" :: Text unwrapMatch :: (Text, Text, Text, [Text]) -> Maybe ChangeSignature unwrapMatch (_, _, _, [exp, act, name]) = Just $ ChangeSignature exp act name Nothing diag uri unwrapMatch _ = Nothing From 48e53fe4a3df97dcb0dc67c4f3e1b85b1872c547 Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Mon, 7 Feb 2022 22:22:06 -0500 Subject: [PATCH 06/20] Move ChangeTypeAction into it's own plugin --- cabal-ghc90.project | 1 + cabal-ghc921.project | 1 + cabal.project | 1 + exe/Plugins.hs | 6 + ghcide/ghcide.cabal | 1 - .../src/Development/IDE/Plugin/HLS/GhcIde.hs | 14 +- haskell-language-server.cabal | 11 + .../hls-change-type-signature-plugin/LICENSE | 201 ++++++++++++++++++ .../README.md | 15 ++ .../hls-change-type-signature-plugin.cabal | 59 +++++ .../src/Ide/Plugin/ChangeTypeSignature.hs | 57 ++--- .../tests/Main.hs | 6 + 12 files changed, 337 insertions(+), 36 deletions(-) create mode 100644 plugins/hls-change-type-signature-plugin/LICENSE create mode 100644 plugins/hls-change-type-signature-plugin/README.md create mode 100644 plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal rename ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs => plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs (74%) create mode 100644 plugins/hls-change-type-signature-plugin/tests/Main.hs diff --git a/cabal-ghc90.project b/cabal-ghc90.project index fa4961a8bd..5442bfbc80 100644 --- a/cabal-ghc90.project +++ b/cabal-ghc90.project @@ -27,6 +27,7 @@ packages: ./plugins/hls-call-hierarchy-plugin ./plugins/hls-alternate-number-format-plugin ./plugins/hls-selection-range-plugin + ./plugins/hls-change-type-signature-plugin tests: true diff --git a/cabal-ghc921.project b/cabal-ghc921.project index 308a9e8c8f..f4b153e064 100644 --- a/cabal-ghc921.project +++ b/cabal-ghc921.project @@ -27,6 +27,7 @@ packages: ./plugins/hls-call-hierarchy-plugin ./plugins/hls-alternate-number-format-plugin ./plugins/hls-selection-range-plugin + ./plugins/hls-change-type-signature-plugin with-compiler: ghc-9.2.1 diff --git a/cabal.project b/cabal.project index 34a5106149..48ae9edcf4 100644 --- a/cabal.project +++ b/cabal.project @@ -27,6 +27,7 @@ packages: ./plugins/hls-alternate-number-format-plugin ./plugins/hls-qualify-imported-names-plugin ./plugins/hls-selection-range-plugin + ./plugins/hls-change-type-signature-plugin -- Standard location for temporary packages needed for particular environments -- For example it is used in the project gitlab mirror to help in the MAcOS M1 build script diff --git a/exe/Plugins.hs b/exe/Plugins.hs index 3934b61de8..5fb2013f73 100644 --- a/exe/Plugins.hs +++ b/exe/Plugins.hs @@ -76,6 +76,9 @@ import Ide.Plugin.AlternateNumberFormat as AlternateNumberFormat import Ide.Plugin.SelectionRange as SelectionRange #endif +#if changeTypeSignature +import Ide.Plugin.ChangeTypeSignature as ChangeTypeSignature +#endif -- formatters #if floskell @@ -174,6 +177,9 @@ idePlugins includeExamples = pluginDescToIdePlugins allPlugins #endif #if selectionRange SelectionRange.descriptor "selectionRange" : +#endif +#if changeTypeSignature + ChangeTypeSignature.descriptor "changeTypeSignature" : #endif -- The ghcide descriptors should come last so that the notification handlers -- (which restart the Shake build) run after everything else diff --git a/ghcide/ghcide.cabal b/ghcide/ghcide.cabal index 82acbf6db8..a315037302 100644 --- a/ghcide/ghcide.cabal +++ b/ghcide/ghcide.cabal @@ -205,7 +205,6 @@ library Development.IDE.Plugin.HLS.GhcIde Development.IDE.Plugin.Test Development.IDE.Plugin.TypeLenses - Development.IDE.Plugin.ChangeTypeAction other-modules: Development.IDE.Core.FileExists diff --git a/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs b/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs index c7d4e8aaeb..c854330d9c 100644 --- a/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs +++ b/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs @@ -9,16 +9,15 @@ module Development.IDE.Plugin.HLS.GhcIde import Control.Monad.IO.Class import Development.IDE import Development.IDE.LSP.HoverDefinition -import qualified Development.IDE.LSP.Notifications as Notifications +import qualified Development.IDE.LSP.Notifications as Notifications import Development.IDE.LSP.Outline -import qualified Development.IDE.Plugin.ChangeTypeAction as ChangeTypeAction -import qualified Development.IDE.Plugin.CodeAction as CodeAction -import qualified Development.IDE.Plugin.Completions as Completions -import qualified Development.IDE.Plugin.TypeLenses as TypeLenses +import qualified Development.IDE.Plugin.CodeAction as CodeAction +import qualified Development.IDE.Plugin.Completions as Completions +import qualified Development.IDE.Plugin.TypeLenses as TypeLenses import Ide.Types -import Language.LSP.Server (LspM) +import Language.LSP.Server (LspM) import Language.LSP.Types -import Text.Regex.TDFA.Text () +import Text.Regex.TDFA.Text () descriptors :: [PluginDescriptor IdeState] descriptors = @@ -29,7 +28,6 @@ descriptors = CodeAction.fillHolePluginDescriptor "ghcide-code-actions-fill-holes", Completions.descriptor "ghcide-completions", TypeLenses.descriptor "ghcide-type-lenses", - ChangeTypeAction.descriptor "ghcide-change-type", Notifications.descriptor "ghcide-core" ] diff --git a/haskell-language-server.cabal b/haskell-language-server.cabal index 89d38e953d..ede237777b 100644 --- a/haskell-language-server.cabal +++ b/haskell-language-server.cabal @@ -181,6 +181,11 @@ flag selectionRange default: True manual: True +flag changeTypeSignature + description: Enable changeTypeSignature plugin + default: True + manual: True + -- formatters flag floskell @@ -298,6 +303,11 @@ common selectionRange build-depends: hls-selection-range-plugin ^>=1.0.0.0 cpp-options: -DselectionRange +common changeTypeSignature + if flag(changeTypeSignature) + build-depends: hls-change-type-signature-plugin ^>=1.0.0.0 + cpp-options: -DchangeTypeSignature + -- formatters common floskell @@ -333,6 +343,7 @@ executable haskell-language-server -- plugins , example-plugins , callHierarchy + , changeTypeSignature , class , haddockComments , eval diff --git a/plugins/hls-change-type-signature-plugin/LICENSE b/plugins/hls-change-type-signature-plugin/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/plugins/hls-change-type-signature-plugin/README.md b/plugins/hls-change-type-signature-plugin/README.md new file mode 100644 index 0000000000..e750f3b380 --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/README.md @@ -0,0 +1,15 @@ +# Change Type Signature Plugin + +TODO + +## Setup + +TODO + +## Demo + +TODO + +## Changelog +### 1.0.0.0 +- First Release diff --git a/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal b/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal new file mode 100644 index 0000000000..55ca49862b --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal @@ -0,0 +1,59 @@ +cabal-version: 2.4 +name: hls-change-type-signature-plugin +version: 1.0.0.0 +synopsis: Change a declarations type signature with a Code Action +description: + Please see the README on GitHub at + +license: Apache-2.0 +license-file: LICENSE +author: Nick Suchecki +maintainer: nicksuchecki@gmail.com +category: Development +build-type: Simple +extra-source-files: + LICENSE + README.md + test/testdata/*.hs + test/testdata/*.yaml + +library + exposed-modules: Ide.Plugin.ChangeTypeSignature + hs-source-dirs: src + build-depends: + , base >=4.12 && < 5 + , ghcide ^>=1.6 + , hls-plugin-api ^>=1.3 + , lsp-types + , transformers + , regex-tdfa + , text + , unordered-containers + + default-language: Haskell2010 + default-extensions: + ConstraintKinds + DataKinds + ExplicitNamespaces + FlexibleContexts + NamedFieldPuns + OverloadedStrings + RecordWildCards + TypeOperators + + +test-suite tests + type: exitcode-stdio-1.0 + default-language: Haskell2010 + hs-source-dirs: test + other-modules: Properties.Conversion + main-is: Main.hs + ghc-options: -threaded -rtsopts -with-rtsopts=-N -fno-ignore-asserts + build-depends: + , base >=4.12 && < 5 + , hls-change-type-signature-plugin + , hls-test-utils ^>=1.2 + , lsp + , QuickCheck + , regex-tdfa + , text diff --git a/ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs similarity index 74% rename from ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs rename to plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs index d3b66b9fb9..5e9d4236ee 100644 --- a/ghcide/src/Development/IDE/Plugin/ChangeTypeAction.hs +++ b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs @@ -1,7 +1,5 @@ -{-# LANGUAGE CPP #-} -{-# LANGUAGE ConstraintKinds #-} -- | An HLS plugin to provide code actions to change type signatures -module Development.IDE.Plugin.ChangeTypeAction (descriptor) where +module Ide.Plugin.ChangeTypeSignature (descriptor) where import Control.Monad.IO.Class (MonadIO (liftIO)) import Control.Monad.Trans.Except (ExceptT) @@ -41,7 +39,7 @@ codeActionHandler :: PluginMethodHandler IdeState 'TextDocumentCodeAction codeActionHandler ideState plId CodeActionParams {_textDocument = TextDocumentIdentifier uri, _context = CodeActionContext (List diags) _} = response $ do nfp <- getNormalizedFilePath plId (TextDocumentIdentifier uri) decls <- getDecls ideState nfp - let actions = generateActions uri decls diags + let actions = mapMaybe (generateAction uri decls) diags pure $ List actions getDecls :: MonadIO m => IdeState -> NormalizedFilePath -> ExceptT String m [LHsDecl GhcPs] @@ -51,21 +49,24 @@ getDecls state = handleMaybeM "Error: Could not get Parsed Module" . runAction "changeSignature.GetParsedModule" state . use GetParsedModule +-- | DataType that encodes the necessary information for changing a type signature: +-- `expectedType` - The Expected Type +-- `actualType` - The Actual Type +-- `declName` - The Declaration Name that we are going to change +-- `declSrcSpan` - The Source Span where the signature is located +-- `diagnostic` - The Error Diagnostic we aim to solve +-- `uri` - The URI the declaration is located in data ChangeSignature = ChangeSignature { expectedType :: Text , actualType :: Text , declName :: Text - , declSrcSpan :: Maybe SrcSpan + , declSrcSpan :: Maybe RealSrcSpan , diagnostic :: Diagnostic , uri :: Uri } --- Needed to trackdown OccNames in signatures +-- | Constraint needed to trackdown OccNames in signatures type SigName p = (HasOccName (IdP (GhcPass p))) --- | Generate CodeActions from a list of Diagnostics -generateActions :: SigName p => Uri -> [LHsDecl (GhcPass p)] -> [Diagnostic] -> [Command |? CodeAction] -generateActions uri = mapMaybe . generateAction uri - -- | Create a CodeAction from a Diagnostic generateAction :: SigName p => Uri -> [LHsDecl (GhcPass p)] -> Diagnostic -> Maybe (Command |? CodeAction) generateAction uri decls diag = diagnosticToChangeSig uri decls diag >>= changeSigToCodeAction @@ -85,11 +86,13 @@ matchingDiagnostic uri diag@Diagnostic{_message} = unwrapMatch $ _message =~ exp -- | Given a String with the name of a declaration, find that declarations type signature location -- This is a modified version of functions found in Development.IDE.Plugin.CodeAction -findSigLocOfStringDecl :: SigName p => [LHsDecl (GhcPass p)] -> String -> Maybe SrcSpan +-- This function returns the actual location of the signature rather than the actual signature +-- We also don't have access to `fun_id` or other actual `id` so we must use string compare instead +findSigLocOfStringDecl :: SigName p => [LHsDecl (GhcPass p)] -> String -> Maybe RealSrcSpan findSigLocOfStringDecl decls declName = listToMaybe - [ locA srcSpan - | L srcSpan (SigD _ (TypeSig _ idsSig _)) <- decls, + [ locA rss + | L (RealSrcSpan rss _) (SigD _ (TypeSig _ idsSig _)) <- decls, any ((==) declName . occNameString . occName . unLoc) idsSig ] @@ -100,25 +103,25 @@ addSrcSpan decls chgSig@ChangeSignature{..} = chgSig { declSrcSpan = findSigLocO changeSigToCodeAction :: ChangeSignature -> Maybe (Command |? CodeAction) -- Does not generate a Code action if declSrcSpan is Nothing -changeSigToCodeAction ChangeSignature{..} = declSrcSpan *> Just (InR CodeAction { _title = mkChangeSigTitle declName actualType - , _kind = Just CodeActionQuickFix - , _diagnostics = Just $ List [diagnostic] - , _isPreferred = Nothing - , _disabled = Nothing - -- This CAN but probably never will be Nothing - , _edit = mkChangeSigEdit uri declSrcSpan (mkNewSignature declName actualType) - , _command = Nothing - , _xdata = Nothing - }) +changeSigToCodeAction ChangeSignature{..} = do + realSrcSpan <- declSrcSpan + pure (InR CodeAction { _title = mkChangeSigTitle declName actualType + , _kind = Just CodeActionQuickFix + , _diagnostics = Just $ List [diagnostic] + , _isPreferred = Nothing + , _disabled = Nothing + , _edit = Just $ mkChangeSigEdit uri realSrcSpan (mkNewSignature declName actualType) + , _command = Nothing + , _xdata = Nothing + }) mkChangeSigTitle :: Text -> Text -> Text mkChangeSigTitle declName actualType = "change signature for ‘" <> declName <> "’ to: " <> actualType -mkChangeSigEdit :: Uri -> Maybe SrcSpan -> Text -> Maybe WorkspaceEdit -mkChangeSigEdit uri (Just (RealSrcSpan ss _)) replacement = +mkChangeSigEdit :: Uri -> RealSrcSpan -> Text -> WorkspaceEdit +mkChangeSigEdit uri ss replacement = let txtEdit = TextEdit (realSrcSpanToRange ss) replacement changes = Just $ Map.singleton uri (List [txtEdit]) - in Just $ WorkspaceEdit changes Nothing Nothing -mkChangeSigEdit _ _ _ = Nothing + in WorkspaceEdit changes Nothing Nothing mkNewSignature :: Text -> Text -> Text mkNewSignature declName actualType = declName <> " :: " <> actualType diff --git a/plugins/hls-change-type-signature-plugin/tests/Main.hs b/plugins/hls-change-type-signature-plugin/tests/Main.hs new file mode 100644 index 0000000000..e8a66b0156 --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/tests/Main.hs @@ -0,0 +1,6 @@ +module Main where + +import Test.Hls + +main :: IO () +main = testGroup "Change Type Signature" [] From 61a711f430ea6b3f3eec11c76f35ff8587f09f18 Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Sun, 13 Feb 2022 23:39:43 -0500 Subject: [PATCH 07/20] Add New Error Message parsing. - Add new regex for matching extra errors message types - Revamp original regex to match more. - Add basic test suite. - Begin adding `tidyActualType` semantics to provide slightly prettier TyVars --- .../hls-change-type-signature-plugin.cabal | 7 +- .../src/Ide/Plugin/ChangeTypeSignature.hs | 93 +++++++++++++----- .../test/Main.hs | 98 +++++++++++++++++++ .../TExpectedActualFullSignature.expected.hs | 6 ++ .../testdata/TExpectedActualFullSignature.hs | 6 ++ .../test/testdata/error1.txt | 0 .../test/testdata/error2.txt | 6 ++ .../test/testdata/error3.txt | 10 ++ .../test/testdata/error4.txt | 19 ++++ .../test/testdata/hie.yaml | 7 ++ .../tests/Main.hs | 6 -- 11 files changed, 227 insertions(+), 31 deletions(-) create mode 100644 plugins/hls-change-type-signature-plugin/test/Main.hs create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActualFullSignature.expected.hs create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActualFullSignature.hs rename ghcide/src/Development/IDE/Plugin/error.txt => plugins/hls-change-type-signature-plugin/test/testdata/error1.txt (100%) create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/error2.txt create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/error3.txt create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/error4.txt create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/hie.yaml delete mode 100644 plugins/hls-change-type-signature-plugin/tests/Main.hs diff --git a/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal b/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal index 55ca49862b..6b898bd4c9 100644 --- a/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal +++ b/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal @@ -46,14 +46,19 @@ test-suite tests type: exitcode-stdio-1.0 default-language: Haskell2010 hs-source-dirs: test - other-modules: Properties.Conversion main-is: Main.hs ghc-options: -threaded -rtsopts -with-rtsopts=-N -fno-ignore-asserts build-depends: , base >=4.12 && < 5 + , filepath , hls-change-type-signature-plugin , hls-test-utils ^>=1.2 , lsp , QuickCheck , regex-tdfa , text + default-extensions: + NamedFieldPuns + OverloadedStrings + TypeOperators + ViewPatterns diff --git a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs index 5e9d4236ee..a04ab8d097 100644 --- a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs +++ b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs @@ -1,17 +1,23 @@ -- | An HLS plugin to provide code actions to change type signatures -module Ide.Plugin.ChangeTypeSignature (descriptor) where +module Ide.Plugin.ChangeTypeSignature (descriptor, errorMessageRegexes) where +import Control.Monad (join) import Control.Monad.IO.Class (MonadIO (liftIO)) import Control.Monad.Trans.Except (ExceptT) import qualified Data.HashMap.Strict as Map -import Data.Maybe (listToMaybe, mapMaybe) +import Data.List (find) +import qualified Data.List.NonEmpty as NE +import Data.Maybe (isJust, isNothing, listToMaybe, + mapMaybe) import Data.Text (Text) import qualified Data.Text as T +import Data.Traversable (forM) import Development.IDE.Core.RuleTypes (GetParsedModule (GetParsedModule)) -import Development.IDE.Core.Service (IdeState, runAction) +import Development.IDE.Core.Service (IdeState, ideLogger, runAction) import Development.IDE.Core.Shake (use) import Development.IDE.GHC.Compat import Development.IDE.GHC.Error (realSrcSpanToRange) +import Development.IDE.Types.Logger (logDebug) import Ide.PluginUtils (getNormalizedFilePath, handleMaybeM, response) import Ide.Types (PluginDescriptor (..), @@ -30,7 +36,8 @@ import Language.LSP.Types (CodeAction (..), TextEdit (TextEdit), Uri, WorkspaceEdit (WorkspaceEdit), type (|?) (InR)) -import Text.Regex.TDFA ((=~)) +import Text.Regex.TDFA (AllTextMatches (getAllTextMatches), + (=~)) descriptor :: PluginId -> PluginDescriptor IdeState descriptor plId = (defaultPluginDescriptor plId) { pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionHandler } @@ -40,6 +47,8 @@ codeActionHandler ideState plId CodeActionParams {_textDocument = TextDocumentId nfp <- getNormalizedFilePath plId (TextDocumentIdentifier uri) decls <- getDecls ideState nfp let actions = mapMaybe (generateAction uri decls) diags + liftIO $ logDebug (ideLogger ideState) $ T.pack $ "CTS Diags: " <> show diags + liftIO $ logDebug (ideLogger ideState) $ T.pack $ "CTS Actions: " <> show actions pure $ List actions getDecls :: MonadIO m => IdeState -> NormalizedFilePath -> ExceptT String m [LHsDecl GhcPs] @@ -49,19 +58,25 @@ getDecls state = handleMaybeM "Error: Could not get Parsed Module" . runAction "changeSignature.GetParsedModule" state . use GetParsedModule --- | DataType that encodes the necessary information for changing a type signature: --- `expectedType` - The Expected Type --- `actualType` - The Actual Type --- `declName` - The Declaration Name that we are going to change --- `declSrcSpan` - The Source Span where the signature is located --- `diagnostic` - The Error Diagnostic we aim to solve --- `uri` - The URI the declaration is located in -data ChangeSignature = ChangeSignature { expectedType :: Text - , actualType :: Text - , declName :: Text - , declSrcSpan :: Maybe RealSrcSpan - , diagnostic :: Diagnostic - , uri :: Uri +-- | DataType that encodes the necessary information for changing a type signature +data ChangeSignature = ChangeSignature { + -- | The expected type based on Signature + expectedType :: Text + , + -- | the Actual Type based on definition + actualType :: Text + , + -- | the declaration name to be updated + declName :: Text + , + -- | the location of the declaration signature + declSrcSpan :: Maybe RealSrcSpan + , + -- | the diagnostic to solve + diagnostic :: Diagnostic + , + -- | the URI the declaration is in + uri :: Uri } -- | Constraint needed to trackdown OccNames in signatures @@ -77,13 +92,24 @@ diagnosticToChangeSig uri decls diag = addSrcSpan decls <$> matchingDiagnostic u -- | If a diagnostic has the proper message create a ChangeSignature from it matchingDiagnostic :: Uri -> Diagnostic -> Maybe ChangeSignature -matchingDiagnostic uri diag@Diagnostic{_message} = unwrapMatch $ _message =~ expectedMessage +matchingDiagnostic uri diag@Diagnostic{_message} = case map (unwrapMatch . (=~) _message) errorMessageRegexes of + [] -> Nothing + css -> join $ find isJust css where - expectedMessage = "Expected type: (.+)\n +Actual type: (.+)\n.*\n +In an equation for ‘(.+)’" :: Text unwrapMatch :: (Text, Text, Text, [Text]) -> Maybe ChangeSignature - unwrapMatch (_, _, _, [exp, act, name]) = Just $ ChangeSignature exp act name Nothing diag uri + -- due to using (.|\n) in regex we have to drop the erroneous, but necessary ("." doesn't match newlines), match + unwrapMatch (_, _, _, [exp, act, _, name]) = Just $ ChangeSignature exp act name Nothing diag uri unwrapMatch _ = Nothing +-- | List of regexes that match various Error Messages +errorMessageRegexes :: [Text] +errorMessageRegexes = [ + "Expected type: (" <> typeSigRegex <> ")\n +Actual type: (" <> typeSigRegex <> ")\n(.|\n)+In an equation for ‘(.+)’" + , "Couldn't match expected type ‘(" <> typeSigRegex <> ")’ with actual type ‘(" <> typeSigRegex <> ")’\n(.|\n)+In an equation for ‘(.+)’" + ] + where + typeSigRegex = "[a-zA-Z0-9 ->\\(\\)]+" + -- | Given a String with the name of a declaration, find that declarations type signature location -- This is a modified version of functions found in Development.IDE.Plugin.CodeAction -- This function returns the actual location of the signature rather than the actual signature @@ -114,6 +140,7 @@ changeSigToCodeAction ChangeSignature{..} = do , _command = Nothing , _xdata = Nothing }) + mkChangeSigTitle :: Text -> Text -> Text mkChangeSigTitle declName actualType = "change signature for ‘" <> declName <> "’ to: " <> actualType @@ -124,10 +151,28 @@ mkChangeSigEdit uri ss replacement = in WorkspaceEdit changes Nothing Nothing mkNewSignature :: Text -> Text -> Text -mkNewSignature declName actualType = declName <> " :: " <> actualType +mkNewSignature declName actualType = declName <> " :: " <> tidyActualType actualType + +-- | Cleans up type signatures with oddly-named type variables (t0, m0 ...) +tidyActualType :: Text -> Text +tidyActualType actualType = snd $ replaceAllTyVars $ findAllUniqueTyVars actualType + where + findAllUniqueTyVars at = getAllTextMatches (at =~ ("[a-z0-9]+" :: Text)) :: [Text] + findAllMTyVars at = getAllTextMatches (at =~ ("[m0-9]+" :: Text)) :: [Text] + findAllTTyVars at = getAllTextMatches (at =~ ("[t0-9]+" :: Text)) :: [Text] + findAllFTyVars at = getAllTextMatches (at =~ ("[f0-9]+" :: Text)) :: [Text] + replaceAllTyVars = foldl replaceWithFreshVar (freshVars, actualType) + freshVars = map (T.pack . flip (:) []) ['a'.. 'z'] <> [ a <> b | a <- freshVars, b <- freshVars] + +replaceWithFreshVar :: ([Text], Text) -> Text -> ([Text], Text) +replaceWithFreshVar (replacement:rest, haystack) needle= (rest, T.replace needle replacement haystack) +replaceWithFreshVar _ _ = error "How do I handle this..., the pattern match for infinite list shouldn't fail" -------------------------------------------------------------------------------- --- test :: Set.Set Int -> Int --- test = go +-- test :: Ord a => a -> Int +-- test = go . head . reverse -- where --- go = head . Set.toList +-- go = head . reverse + +test :: a b -> (b -> d e) -> d (a e) +test = forM diff --git a/plugins/hls-change-type-signature-plugin/test/Main.hs b/plugins/hls-change-type-signature-plugin/test/Main.hs new file mode 100644 index 0000000000..a842dd3c44 --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/Main.hs @@ -0,0 +1,98 @@ +module Main where + +import Control.Monad (forM) +import Data.Maybe (mapMaybe) +import Data.Text (Text) +import qualified Data.Text as T +import qualified Data.Text.IO as TIO +import Ide.Plugin.ChangeTypeSignature (errorMessageRegexes) +import qualified Ide.Plugin.ChangeTypeSignature as ChangeTypeSignature +import System.FilePath ((<.>), ()) +import Test.Hls (CodeAction (..), Command, + IdeState, PluginDescriptor, + Position (Position), + Range (Range), Session, + TestTree, + TextDocumentIdentifier, + assertBool, assertFailure, + defaultTestRunner, + executeCodeAction, + getCodeActions, + goldenWithHaskellDoc, liftIO, + testCase, testGroup, + type (|?) (InR), + waitForDiagnostics, + waitForProgressDone) +import Test.Hls.Util (inspectCodeAction) +import Text.Regex.TDFA ((=~)) + +main :: IO () +main = defaultTestRunner test + +changeTypeSignaturePlugin :: PluginDescriptor IdeState +changeTypeSignaturePlugin = ChangeTypeSignature.descriptor "changeTypeSignature" + +test :: TestTree +test = testGroup "changeTypeSignature" [ codeActionTest "TExpectedActualFullSignature" 4 11 , testRegexes ] + +testRegexes :: TestTree +testRegexes = testGroup "Regex Testing" [ + testRegexOne + , testRegexTwo + ] + where + regex1 = errorMessageRegexes !! 0 + regex2 = errorMessageRegexes !! 1 + +testRegexOne :: TestTree +testRegexOne = testGroup "Regex One" [ + regexTest "error1.txt" regex True + , regexTest "error2.txt" regex True + , regexTest "error3.txt" regex False + , regexTest "error4.txt" regex True + ] + where + regex = errorMessageRegexes !! 0 + +testRegexTwo :: TestTree +testRegexTwo = testGroup "Regex Two" [ + regexTest "error1.txt" regex False + , regexTest "error2.txt" regex False + , regexTest "error3.txt" regex True + , regexTest "error4.txt" regex False + ] + where + regex = errorMessageRegexes !! 1 + +testDataDir :: FilePath +testDataDir = "test" "testdata" + +goldenChangeSignature :: FilePath -> (TextDocumentIdentifier -> Session ()) -> TestTree +goldenChangeSignature fp = goldenWithHaskellDoc changeTypeSignaturePlugin (fp <> " (golden)") testDataDir fp "expected" "hs" + +codeActionTest :: FilePath -> Int -> Int -> TestTree +codeActionTest fp line col = goldenChangeSignature fp $ \doc -> do + waitForDiagnostics -- code actions are triggered from Diagnostics + actions <- getCodeActions doc (pointRange line col) + foundAction <- liftIO $ inspectCodeAction actions ["change signature"] + executeCodeAction foundAction + + +regexTest :: FilePath -> Text -> Bool -> TestTree +regexTest fp regex shouldPass = testCase fp $ do + msg <- TIO.readFile (testDataDir fp) + case (msg =~ regex :: (Text, Text, Text, [Text]), shouldPass) of + ((_, _, _, [_, _, _, _]), True) -> pure () + ((_, _, _, [_, _, _, _]), False) -> assertFailure $ "Unexpected match: " <> fp <> " with " <> T.unpack regex + (_, True) -> assertFailure $ "Failed to match: " <> fp <> " with " <> T.unpack regex + (_, False) -> pure () + + +pointRange :: Int -> Int -> Range +pointRange + (subtract 1 -> fromIntegral -> line) + (subtract 1 -> fromIntegral -> col) = + Range (Position line col) (Position line $ col + 1) + +-- fn :: Int -> Int +-- fn = forM diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActualFullSignature.expected.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActualFullSignature.expected.hs new file mode 100644 index 0000000000..4925a2c3bf --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActualFullSignature.expected.hs @@ -0,0 +1,6 @@ +module TExpectedActualFullSignature where + +fullSig :: [Int] -> Int +fullSig = go + where + go = head . reverse diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActualFullSignature.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActualFullSignature.hs new file mode 100644 index 0000000000..ab78d0e97f --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActualFullSignature.hs @@ -0,0 +1,6 @@ +module TExpectedActualFullSignature where + +fullSig :: Int -> Int +fullSig = go + where + go = head . reverse diff --git a/ghcide/src/Development/IDE/Plugin/error.txt b/plugins/hls-change-type-signature-plugin/test/testdata/error1.txt similarity index 100% rename from ghcide/src/Development/IDE/Plugin/error.txt rename to plugins/hls-change-type-signature-plugin/test/testdata/error1.txt diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/error2.txt b/plugins/hls-change-type-signature-plugin/test/testdata/error2.txt new file mode 100644 index 0000000000..497f8350a5 --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/error2.txt @@ -0,0 +1,6 @@ + • Couldn't match type ‘b0 -> t0 a0 -> b0’ with ‘Int’ + Expected type: Int -> Int + Actual type: (b0 -> a0 -> b0) -> b0 -> t0 a0 -> b0 + • Probable cause: ‘foldl’ is applied to too few arguments + In the expression: foldl + In an equation for ‘test’: test = foldl diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/error3.txt b/plugins/hls-change-type-signature-plugin/test/testdata/error3.txt new file mode 100644 index 0000000000..0cbddad7c4 --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/error3.txt @@ -0,0 +1,10 @@ + • Couldn't match expected type ‘Int’ with actual type ‘[Int]’ + • In the expression: map (+ x) [1, 2, 3] + In an equation for ‘test’: + test x + = map (+ x) [1, 2, 3] + where + go = head . reverse + | +152 | test x = map (+ x) [1,2,3] + | ^^^^^^^^^^^^^^^^^ diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/error4.txt b/plugins/hls-change-type-signature-plugin/test/testdata/error4.txt new file mode 100644 index 0000000000..323cf7d4db --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/error4.txt @@ -0,0 +1,19 @@ + • Couldn't match type ‘a’ with ‘[[Int]]’ + ‘a’ is a rigid type variable bound by + the type signature for: + test :: forall a. Ord a => a -> Int + at src/Ide/Plugin/ChangeTypeSignature.hs:154:1-25 + Expected type: a -> Int + Actual type: [[Int]] -> Int + • In the expression: go . head . reverse + In an equation for ‘test’: + test + = go . head . reverse + where + go = head . reverse + • Relevant bindings include + test :: a -> Int + (bound at src/Ide/Plugin/ChangeTypeSignature.hs:155:1) + | +155 | test = go . head . reverse + | ^^^^^^^^^^^^^^^^^^^ diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/hie.yaml b/plugins/hls-change-type-signature-plugin/test/testdata/hie.yaml new file mode 100644 index 0000000000..18a5357ca1 --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/hie.yaml @@ -0,0 +1,7 @@ +cradle: + direct: + arguments: + - -i + - -i. + - TExpectedActualFullSignature + - -Wall diff --git a/plugins/hls-change-type-signature-plugin/tests/Main.hs b/plugins/hls-change-type-signature-plugin/tests/Main.hs deleted file mode 100644 index e8a66b0156..0000000000 --- a/plugins/hls-change-type-signature-plugin/tests/Main.hs +++ /dev/null @@ -1,6 +0,0 @@ -module Main where - -import Test.Hls - -main :: IO () -main = testGroup "Change Type Signature" [] From 6ccd484f8ef17107b39e472fb58f59eaba7641f0 Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Thu, 17 Feb 2022 22:54:40 -0500 Subject: [PATCH 08/20] Added Error Message Validation to ignore bad Messages. - Add Pretty Printing for Types - Added a few test scenarios --- .../src/Ide/Plugin/ChangeTypeSignature.hs | 185 ++++++++++++------ .../test/Main.hs | 40 +++- .../testdata/TErrorGivenPartialSignature.hs | 4 + ...xpected.hs => TExpectedActual.expected.hs} | 2 +- ...ualFullSignature.hs => TExpectedActual.hs} | 2 +- .../test/testdata/TRigidType.expected.hs | 6 + .../test/testdata/TRigidType.hs | 6 + .../test/testdata/hie.yaml | 4 +- 8 files changed, 174 insertions(+), 75 deletions(-) create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TErrorGivenPartialSignature.hs rename plugins/hls-change-type-signature-plugin/test/testdata/{TExpectedActualFullSignature.expected.hs => TExpectedActual.expected.hs} (64%) rename plugins/hls-change-type-signature-plugin/test/testdata/{TExpectedActualFullSignature.hs => TExpectedActual.hs} (63%) create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TRigidType.expected.hs create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TRigidType.hs diff --git a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs index a04ab8d097..2c2f83dd4a 100644 --- a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs +++ b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs @@ -1,11 +1,16 @@ +{-# LANGUAGE LambdaCase #-} +{-# OPTIONS_GHC -Wno-incomplete-patterns #-} -- | An HLS plugin to provide code actions to change type signatures -module Ide.Plugin.ChangeTypeSignature (descriptor, errorMessageRegexes) where +module Ide.Plugin.ChangeTypeSignature (descriptor + -- * For Unit Tests + , errorMessageRegexes + , tidyActualType) where import Control.Monad (join) import Control.Monad.IO.Class (MonadIO (liftIO)) import Control.Monad.Trans.Except (ExceptT) import qualified Data.HashMap.Strict as Map -import Data.List (find) +import Data.List (find, nub) import qualified Data.List.NonEmpty as NE import Data.Maybe (isJust, isNothing, listToMaybe, mapMaybe) @@ -17,6 +22,7 @@ import Development.IDE.Core.Service (IdeState, ideLogger, runAction) import Development.IDE.Core.Shake (use) import Development.IDE.GHC.Compat import Development.IDE.GHC.Error (realSrcSpanToRange) +import Development.IDE.GHC.Util (unsafePrintSDoc) import Development.IDE.Types.Logger (logDebug) import Ide.PluginUtils (getNormalizedFilePath, handleMaybeM, response) @@ -42,13 +48,15 @@ import Text.Regex.TDFA (AllTextMatches (getAllTextMatch descriptor :: PluginId -> PluginDescriptor IdeState descriptor plId = (defaultPluginDescriptor plId) { pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionHandler } -codeActionHandler :: PluginMethodHandler IdeState 'TextDocumentCodeAction +codeActionHandler :: PluginMethodHandler IdeState TextDocumentCodeAction codeActionHandler ideState plId CodeActionParams {_textDocument = TextDocumentIdentifier uri, _context = CodeActionContext (List diags) _} = response $ do nfp <- getNormalizedFilePath plId (TextDocumentIdentifier uri) decls <- getDecls ideState nfp + let sigs = [ sigToText ts | L (RealSrcSpan rss _) (SigD _ ts@(TypeSig _ idsSig _)) <- decls] let actions = mapMaybe (generateAction uri decls) diags liftIO $ logDebug (ideLogger ideState) $ T.pack $ "CTS Diags: " <> show diags liftIO $ logDebug (ideLogger ideState) $ T.pack $ "CTS Actions: " <> show actions + liftIO $ logDebug (ideLogger ideState) $ T.pack $ "CTS Sigs: " <> show sigs pure $ List actions getDecls :: MonadIO m => IdeState -> NormalizedFilePath -> ExceptT String m [LHsDecl GhcPs] @@ -58,19 +66,28 @@ getDecls state = handleMaybeM "Error: Could not get Parsed Module" . runAction "changeSignature.GetParsedModule" state . use GetParsedModule +-- | Text representing a Declaration's Name +type DeclName = Text +-- | The signature provided by GHC Error Message (Expected type) +type ExpectedSig = Text +-- | The signature provided by GHC Error Message (Actual type) +type ActualSig = Text +-- | The signature defined by the user +type DefinedSig = Text + -- | DataType that encodes the necessary information for changing a type signature data ChangeSignature = ChangeSignature { -- | The expected type based on Signature - expectedType :: Text + expectedType :: ExpectedSig , -- | the Actual Type based on definition - actualType :: Text + actualType :: ActualSig , -- | the declaration name to be updated - declName :: Text + declName :: DeclName , -- | the location of the declaration signature - declSrcSpan :: Maybe RealSrcSpan + declSrcSpan :: RealSrcSpan , -- | the diagnostic to solve diagnostic :: Diagnostic @@ -80,66 +97,95 @@ data ChangeSignature = ChangeSignature { } -- | Constraint needed to trackdown OccNames in signatures -type SigName p = (HasOccName (IdP (GhcPass p))) +type SigName = (HasOccName (IdP GhcPs)) + -- | Create a CodeAction from a Diagnostic -generateAction :: SigName p => Uri -> [LHsDecl (GhcPass p)] -> Diagnostic -> Maybe (Command |? CodeAction) -generateAction uri decls diag = diagnosticToChangeSig uri decls diag >>= changeSigToCodeAction +generateAction :: SigName => Uri -> [LHsDecl GhcPs] -> Diagnostic -> Maybe (Command |? CodeAction) +generateAction uri decls diag = changeSigToCodeAction <$> diagnosticToChangeSig uri decls diag -- | Convert a diagnostic into a ChangeSignature and add the proper SrcSpan -diagnosticToChangeSig :: SigName p => Uri -> [LHsDecl (GhcPass p)] -> Diagnostic -> Maybe ChangeSignature -diagnosticToChangeSig uri decls diag = addSrcSpan decls <$> matchingDiagnostic uri diag +diagnosticToChangeSig :: SigName => Uri -> [LHsDecl GhcPs] -> Diagnostic -> Maybe ChangeSignature +diagnosticToChangeSig uri decls diagnostic = do + -- regex match on the GHC Error Message + (expectedType, actualType, declName) <- matchingDiagnostic diagnostic + -- Find the definition and it's location + (declSrcSpan, ghcSig) <- findSigLocOfStringDecl decls (T.unpack declName) + -- Make sure the given "Actual Type" is a full signature + isValidMessage expectedType ghcSig + pure $ ChangeSignature{..} + +-- | Does the GHC Error Message give us a Signature we can use? +-- We only want to change signatures when the "expected signature" given by GHC +-- matches the one given by the user +isValidMessage :: DefinedSig -> ExpectedSig -> Maybe () +isValidMessage defSig expSig = if defSig == expSig then Just () else Nothing -- | If a diagnostic has the proper message create a ChangeSignature from it -matchingDiagnostic :: Uri -> Diagnostic -> Maybe ChangeSignature -matchingDiagnostic uri diag@Diagnostic{_message} = case map (unwrapMatch . (=~) _message) errorMessageRegexes of +matchingDiagnostic :: Diagnostic -> Maybe (ExpectedSig, ActualSig, DeclName) +matchingDiagnostic diag@Diagnostic{_message} = case map (unwrapMatch . (=~) _message) errorMessageRegexes of [] -> Nothing css -> join $ find isJust css where - unwrapMatch :: (Text, Text, Text, [Text]) -> Maybe ChangeSignature + unwrapMatch :: (Text, Text, Text, [Text]) -> Maybe (ExpectedSig, ActualSig, DeclName) -- due to using (.|\n) in regex we have to drop the erroneous, but necessary ("." doesn't match newlines), match - unwrapMatch (_, _, _, [exp, act, _, name]) = Just $ ChangeSignature exp act name Nothing diag uri - unwrapMatch _ = Nothing + unwrapMatch (_, _, _, [exp, act, _, name]) = Just (exp, act, name) + unwrapMatch _ = Nothing -- | List of regexes that match various Error Messages errorMessageRegexes :: [Text] -errorMessageRegexes = [ +errorMessageRegexes = [ -- be sure to add new Error Messages Regexes at the bottom to not fail any existing tests "Expected type: (" <> typeSigRegex <> ")\n +Actual type: (" <> typeSigRegex <> ")\n(.|\n)+In an equation for ‘(.+)’" , "Couldn't match expected type ‘(" <> typeSigRegex <> ")’ with actual type ‘(" <> typeSigRegex <> ")’\n(.|\n)+In an equation for ‘(.+)’" ] where - typeSigRegex = "[a-zA-Z0-9 ->\\(\\)]+" + -- The brackets in position 1 and 2 MUST BE IN THAT ORDER + -- Any other combination of brackets seems to fail + typeSigRegex = "[][a-zA-Z0-9 ->]+" --- | Given a String with the name of a declaration, find that declarations type signature location +-- | Given a String with the name of a declaration, find that declarations and give back +-- the type signature location and the full signature -- This is a modified version of functions found in Development.IDE.Plugin.CodeAction -- This function returns the actual location of the signature rather than the actual signature -- We also don't have access to `fun_id` or other actual `id` so we must use string compare instead -findSigLocOfStringDecl :: SigName p => [LHsDecl (GhcPass p)] -> String -> Maybe RealSrcSpan -findSigLocOfStringDecl decls declName = - listToMaybe - [ locA rss - | L (RealSrcSpan rss _) (SigD _ (TypeSig _ idsSig _)) <- decls, - any ((==) declName . occNameString . occName . unLoc) idsSig - ] +findSigLocOfStringDecl :: SigName => [LHsDecl GhcPs] -> String -> Maybe (RealSrcSpan, DefinedSig) +findSigLocOfStringDecl decls declName = do + -- can we simplify this logic? Just want to make sure ghcSig is a Just value + (rss, Just ghcSig) <- listToMaybe [ (locA rss, sigToText ts) + | L (RealSrcSpan rss _) (SigD _ ts@(TypeSig _ idsSig _)) <- decls, + any ((==) declName . occNameString . occName . unLoc) idsSig + ] + pure (rss, ghcSig) + +-- | Pretty Print the Type Signature (to validate GHC Error Message) +sigToText :: Sig GhcPs -> Maybe Text +sigToText = \case + ts@TypeSig {} -> stripSignature (T.pack $ showSDocUnsafe $ ppr ts) + _ -> Nothing + +stripSignature :: Text -> Maybe Text +-- for whatever reason incoming signatures MAY have new lines after "::" or "=>" +stripSignature sig = case T.filter (/= '\n') sig =~ sigRegex :: (Text, Text, Text, [Text]) of + -- No constraints (Monad m =>) + (_, _, _, [sig']) -> Just $ T.strip sig' + -- Ignore constraints (Monad m =>) + (_, _, _, [_, sig']) -> Just $ T.strip sig' + _ -> Nothing + where + -- we want to test everthing after the constraints (GHC never gives us the constraint in the expected signature) + sigRegex = ".* :: (.*=>)?(.*)" :: Text + --- | Update a ChangeSignature to potentially populate `declSrcSpan` -addSrcSpan :: SigName p => [LHsDecl (GhcPass p)] -> ChangeSignature -> ChangeSignature -addSrcSpan _ self@(ChangeSignature _ _ _ (Just _) _ _) = self -addSrcSpan decls chgSig@ChangeSignature{..} = chgSig { declSrcSpan = findSigLocOfStringDecl decls (T.unpack declName) } - -changeSigToCodeAction :: ChangeSignature -> Maybe (Command |? CodeAction) --- Does not generate a Code action if declSrcSpan is Nothing -changeSigToCodeAction ChangeSignature{..} = do - realSrcSpan <- declSrcSpan - pure (InR CodeAction { _title = mkChangeSigTitle declName actualType - , _kind = Just CodeActionQuickFix - , _diagnostics = Just $ List [diagnostic] - , _isPreferred = Nothing - , _disabled = Nothing - , _edit = Just $ mkChangeSigEdit uri realSrcSpan (mkNewSignature declName actualType) - , _command = Nothing - , _xdata = Nothing - }) +changeSigToCodeAction :: ChangeSignature -> Command |? CodeAction +changeSigToCodeAction ChangeSignature{..} = InR CodeAction { _title = mkChangeSigTitle declName actualType + , _kind = Just CodeActionQuickFix + , _diagnostics = Just $ List [diagnostic] + , _isPreferred = Nothing + , _disabled = Nothing + , _edit = Just $ mkChangeSigEdit uri declSrcSpan (mkNewSignature declName actualType) + , _command = Nothing + , _xdata = Nothing + } mkChangeSigTitle :: Text -> Text -> Text mkChangeSigTitle declName actualType = "change signature for ‘" <> declName <> "’ to: " <> actualType @@ -153,26 +199,39 @@ mkChangeSigEdit uri ss replacement = mkNewSignature :: Text -> Text -> Text mkNewSignature declName actualType = declName <> " :: " <> tidyActualType actualType --- | Cleans up type signatures with oddly-named type variables (t0, m0 ...) +-- | Cleans up type signatures with oddly-named type variables (a0, m0 ...) tidyActualType :: Text -> Text -tidyActualType actualType = snd $ replaceAllTyVars $ findAllUniqueTyVars actualType +tidyActualType actualType = + replaceAllFTyVars + $ replaceAllMTyVars + $ replaceAllTTyVars + $ replaceAllUniqueTyVars uniqueTyVars actualType where - findAllUniqueTyVars at = getAllTextMatches (at =~ ("[a-z0-9]+" :: Text)) :: [Text] - findAllMTyVars at = getAllTextMatches (at =~ ("[m0-9]+" :: Text)) :: [Text] - findAllTTyVars at = getAllTextMatches (at =~ ("[t0-9]+" :: Text)) :: [Text] - findAllFTyVars at = getAllTextMatches (at =~ ("[f0-9]+" :: Text)) :: [Text] - replaceAllTyVars = foldl replaceWithFreshVar (freshVars, actualType) - freshVars = map (T.pack . flip (:) []) ['a'.. 'z'] <> [ a <> b | a <- freshVars, b <- freshVars] + findAllTyVars :: Text -> [Text] + findAllTyVars regex = getAllTextMatches (actualType =~ regex) :: [Text] + uniqueTyVars = nub $ findAllTyVars "[abcdeghijklnopqrsuvwxyz][0-9]" + -- specialize searching on any `f`, `m` or `t` tyVars + fTyVars = findAllTyVars "f[0-9]" + mTyVars = findAllTyVars "m[0-9]" + tTyVars = findAllTyVars "t[0-9]" + -- | From a list of type variables replace all instances with the list of freshVars provided + replaceAllTyVars :: [Text] -> Text -> [Text] -> Text + replaceAllTyVars freshVars sig = snd . foldl replaceWithFreshVar (freshVars, sig) + replaceAllUniqueTyVars replace sig = replaceAllTyVars freshUniqueVars sig replace + replaceAllFTyVars sig = replaceAllTyVars (freshVars "f") sig fTyVars + replaceAllMTyVars sig = replaceAllTyVars (freshVars "m") sig mTyVars + replaceAllTTyVars sig = replaceAllTyVars (freshVars "t") sig tTyVars + + +freshVars :: Text -> [Text] +freshVars var = var : [var <> T.pack (show i) | i <- [0..]] + +freshUniqueVars :: [Text] +freshUniqueVars = map T.singleton validVars <> [ a <> b | a <- freshUniqueVars, b <- freshUniqueVars ] + where + validVars = filter (`notElem` ['f', 'm', 't']) ['a'..'z'] + replaceWithFreshVar :: ([Text], Text) -> Text -> ([Text], Text) -replaceWithFreshVar (replacement:rest, haystack) needle= (rest, T.replace needle replacement haystack) +replaceWithFreshVar (replacement:rest, haystack) needle = (rest, T.replace needle replacement haystack) replaceWithFreshVar _ _ = error "How do I handle this..., the pattern match for infinite list shouldn't fail" - --------------------------------------------------------------------------------- --- test :: Ord a => a -> Int --- test = go . head . reverse --- where --- go = head . reverse - -test :: a b -> (b -> d e) -> d (a e) -test = forM diff --git a/plugins/hls-change-type-signature-plugin/test/Main.hs b/plugins/hls-change-type-signature-plugin/test/Main.hs index a842dd3c44..fdb3ee0e58 100644 --- a/plugins/hls-change-type-signature-plugin/test/Main.hs +++ b/plugins/hls-change-type-signature-plugin/test/Main.hs @@ -1,6 +1,7 @@ module Main where import Control.Monad (forM) +import Data.Either (rights) import Data.Maybe (mapMaybe) import Data.Text (Text) import qualified Data.Text as T @@ -8,21 +9,25 @@ import qualified Data.Text.IO as TIO import Ide.Plugin.ChangeTypeSignature (errorMessageRegexes) import qualified Ide.Plugin.ChangeTypeSignature as ChangeTypeSignature import System.FilePath ((<.>), ()) -import Test.Hls (CodeAction (..), Command, - IdeState, PluginDescriptor, +import Test.Hls (CodeAction (..), + CodeActionKind (CodeActionQuickFix), + Command, IdeState, + PluginDescriptor, Position (Position), Range (Range), Session, - TestTree, + TestName, TestTree, TextDocumentIdentifier, assertBool, assertFailure, defaultTestRunner, executeCodeAction, getCodeActions, goldenWithHaskellDoc, liftIO, - testCase, testGroup, + openDoc, runSessionWithServer, + testCase, testGroup, toEither, type (|?) (InR), waitForDiagnostics, - waitForProgressDone) + waitForProgressDone, (@=?), + (@?=)) import Test.Hls.Util (inspectCodeAction) import Text.Regex.TDFA ((=~)) @@ -33,7 +38,11 @@ changeTypeSignaturePlugin :: PluginDescriptor IdeState changeTypeSignaturePlugin = ChangeTypeSignature.descriptor "changeTypeSignature" test :: TestTree -test = testGroup "changeTypeSignature" [ codeActionTest "TExpectedActualFullSignature" 4 11 , testRegexes ] +test = testGroup "changeTypeSignature" [ + codeActionTest "TExpectedActual" 4 11, + codeActionTest "TRigidType" 4 14, + codeActionProperties "TErrorGivenPartialSignature" [(4, 13)] $ \actions -> liftIO $ length actions @?= 0, + testRegexes ] testRegexes :: TestTree testRegexes = testGroup "Regex Testing" [ @@ -77,6 +86,22 @@ codeActionTest fp line col = goldenChangeSignature fp $ \doc -> do foundAction <- liftIO $ inspectCodeAction actions ["change signature"] executeCodeAction foundAction +codeActionProperties :: TestName -> [(Int, Int)] -> ([CodeAction] -> Session ()) -> TestTree +codeActionProperties fp locs assertions = testCase fp $ do + runSessionWithServer changeTypeSignaturePlugin testDataDir $ do + openDoc (fp <.> ".hs") "haskell" >>= codeActionsFromLocs >>= findChangeTypeActions >>= assertions + where + codeActionsFromLocs doc = concat <$> mapM (getCodeActions doc . uncurry pointRange) locs + +findChangeTypeActions :: [Command |? CodeAction] -> Session [CodeAction] +findChangeTypeActions = pure . filter isChangeTypeAction . rights . map toEither + where + isChangeTypeAction CodeAction{_kind} = case _kind of + Nothing -> False + Just kind -> case kind of + CodeActionQuickFix -> True + _ -> False + regexTest :: FilePath -> Text -> Bool -> TestTree regexTest fp regex shouldPass = testCase fp $ do @@ -93,6 +118,3 @@ pointRange (subtract 1 -> fromIntegral -> line) (subtract 1 -> fromIntegral -> col) = Range (Position line col) (Position line $ col + 1) - --- fn :: Int -> Int --- fn = forM diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TErrorGivenPartialSignature.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TErrorGivenPartialSignature.hs new file mode 100644 index 0000000000..caa595242a --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TErrorGivenPartialSignature.hs @@ -0,0 +1,4 @@ +module ErrorGivenPartialSignature where + +partial :: Int -> Int +partial x = init x diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActualFullSignature.expected.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActual.expected.hs similarity index 64% rename from plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActualFullSignature.expected.hs rename to plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActual.expected.hs index 4925a2c3bf..1d331c00bd 100644 --- a/plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActualFullSignature.expected.hs +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActual.expected.hs @@ -1,4 +1,4 @@ -module TExpectedActualFullSignature where +module TExpectedActual where fullSig :: [Int] -> Int fullSig = go diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActualFullSignature.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActual.hs similarity index 63% rename from plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActualFullSignature.hs rename to plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActual.hs index ab78d0e97f..2a7629c392 100644 --- a/plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActualFullSignature.hs +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TExpectedActual.hs @@ -1,4 +1,4 @@ -module TExpectedActualFullSignature where +module TExpectedActual where fullSig :: Int -> Int fullSig = go diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TRigidType.expected.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TRigidType.expected.hs new file mode 100644 index 0000000000..0158112123 --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TRigidType.expected.hs @@ -0,0 +1,6 @@ +module TRigidType where + +test :: [[Int]] -> Int +test = go . head . reverse + where + go = head . reverse diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TRigidType.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TRigidType.hs new file mode 100644 index 0000000000..d5d7fa4b10 --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TRigidType.hs @@ -0,0 +1,6 @@ +module TRigidType where + +test :: a -> Int +test = go . head . reverse + where + go = head . reverse diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/hie.yaml b/plugins/hls-change-type-signature-plugin/test/testdata/hie.yaml index 18a5357ca1..24b8c29036 100644 --- a/plugins/hls-change-type-signature-plugin/test/testdata/hie.yaml +++ b/plugins/hls-change-type-signature-plugin/test/testdata/hie.yaml @@ -3,5 +3,7 @@ cradle: arguments: - -i - -i. - - TExpectedActualFullSignature + - TExpectedActual + - TRigidType + - TErrorGivenPartialSignature - -Wall From a1db77fc49c9c4021a1753c17980ba46f886d8f2 Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Fri, 18 Feb 2022 13:04:18 -0500 Subject: [PATCH 09/20] Miscellaneous Cleanup. --- .../hls-change-type-signature-plugin/README.md | 11 ++++++----- .../change1.gif | Bin 0 -> 350498 bytes .../change2.gif | Bin 0 -> 175017 bytes .../src/Ide/Plugin/ChangeTypeSignature.hs | 3 --- .../test/Main.hs | 1 + .../test/testdata/TPrettyPrint.expected.hs | 5 +++++ .../test/testdata/TPrettyPrint.hs | 5 +++++ 7 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 plugins/hls-change-type-signature-plugin/change1.gif create mode 100644 plugins/hls-change-type-signature-plugin/change2.gif create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.expected.hs create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.hs diff --git a/plugins/hls-change-type-signature-plugin/README.md b/plugins/hls-change-type-signature-plugin/README.md index e750f3b380..0c93f53296 100644 --- a/plugins/hls-change-type-signature-plugin/README.md +++ b/plugins/hls-change-type-signature-plugin/README.md @@ -1,14 +1,15 @@ # Change Type Signature Plugin -TODO +The change type signature plugin provides a code action to change a user's current type signature to it's actual type signature. +The plugin does not work in all error scenarios. Currently, the plugin uses GHC diagnostic messages to recover the actual type of a function. +If the plugin receives enough information it can correctly change the signature. -## Setup +## Demo -TODO +![Change Type Signature One](change1.gif) -## Demo +![Change Type Signature Two](change2.gif) -TODO ## Changelog ### 1.0.0.0 diff --git a/plugins/hls-change-type-signature-plugin/change1.gif b/plugins/hls-change-type-signature-plugin/change1.gif new file mode 100644 index 0000000000000000000000000000000000000000..de060515450633b4056182b7734a1def2715f0df GIT binary patch literal 350498 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

wY%+VZo2dc=PZ;12u{U&)zM8LStb(gLj@QM~>i< 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%0D7~iT<6eah_S$TC5{AMUukaMzmTS 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

Iti&0YGg4#;tr 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I! zrs{=u5f^v+eP?^og#?*#3t+VMBYmFz1zdh70Lpu1ib0>7r&xEqG<0|EQo0A2)}=T; zhS^RsWjBj;cfU&f$Z3!XY+58jpDbz{iRSyVJ1>d4P};NZi?0l!mTLiP-#IH28@}a7&?srZEM+lm%6W|v5t!`%GiXIn zcUk56V502nML{u#^u3DHXSL8b;_Z&9b6I7t$zkt~1@#|V! z>sDNI`X6tYbtfyz=8UPu%c);qAO!#5X!eIQ|5A~RTS}YBEAdBj?Z6b*=J>YM&Yy!` zo*v`NVyi8$iuVe9>kvQ$b2}NCuQYe!@j>w2H{zV{cy7Tw`j^1EwYBTQa}4rvxMyxJ z4l_w$M=F(PH^QuTZBP6t%4@96Z^mu! zuoaAbG~*Xr!lmZ{ovcr9+S^KD)m!sYr}ud;=g6uU9`S- zqQ|c5;)ePw-e0UfrO*0w?L7v4@3{oKw-jODt#v@}A7zA&L37x3u(JIN%u%nx?M5b^8~g z*jX{SEp{|np|1DRceZytLiUrKYR04$A0GaGK;4tMX3n{a?`q*FA8Hd>2#Dn>X?32i zkov$6!|>}b-n%g!A60mnM6w@TL#ByXiQh)>y)2@XNhwKL9l*Tr1BVy@-IYI}l|4`Y z&sF7mO){Luyh5B!Hb)C5N#m&lXt*uT1KH zVBLFUf(e6GkMr`q(8^!l59^;Xt?ZY}fcqt}>>~NZd!}*tzSX6rdBKiVA%nN#7Us64 zF5Lb*!#iHSLwyP5HMn;_E!IV0?oZvue(Tgb_sv(_)F&M7eQfF8xm4#ZpTFTT z&a1b|m1BVe9{tnjD!;8c(fIn#Cm8R`KrfPaqnvwlxvTh(gk*zHmXAeXmat5jiM>A~ zU*66=S3;iYM<~IM0|GSAmz;sv)|M%uO(V9x5=KZQi-T2((b}%#ojS>GncB_~nKIbH zNS3Y>97ECWyXeoxu4W5&--h_6dl-jb*9ix4TCsCvj%!uVcD6I%c_(zmweRdYoKs#8 zz+#_4sMXQljtnT;aC`hxb{pJJJ53l_9>+#E4&!zZ&M!*o!&zB?Mdi27FD|LcDCGe7 zfb!mUjhNzTZ~s#m_9%d<6mnvDKz zcU^QigG3;x$1zlIL%hcP125gL%So(_?7BZr;tN1QY-&<&z@3RBEHHjPZ(kgzEN>9M# zt63e4k_o(3Fwh2IWk*N*>N;ei^hS+CqY}PSm<1D5Jn&+r+C$Y$y$+pw=tXCvlA3=6 zFITDk7gCqNV>VPpc4h6&RY=?%jxs$Z+qq8&DDX@%@u~BuaNl~2+XxpY zPNlySnqC`R*9>OpU!Y$E850FC-0l~w0(ouA|82^u#-vrb@(yVeATZ{vlLZaT-@UMO zi>O5HHuK!;(3!5Oa+E2(O*=T`yJ5B7@@|d9*s%TzAAdlI3Y@4$spt>eq-)yW4a+-s zY;L^)TFn8xeKx8k)2GI7yZ75MMK7ANo00a4xYq3udLNJne;S=hbwQvQ(#v zVV-$tEap*}D~b@s8wyN_R=GUBTXDxl(!r~KdoomydL>WB?Vo0)==pSclq>b$XMec# zEb5qZa7c_~$}T|4I+O5KLU#@Nx~N;>Q91rfBS`a?j@stR0Jky)-=&{*LyZquM* zsJoDL#<^DXK%&{a!U5TK^qNQzES3tXxpX~@*C6lW2HM-n!5pV?I_g*i z>LsTj&ncCqRp`lrap`$bF9}<};kJ(Nl^*^7WCCC)%Qa3VpRTk7HymKCD()Q6d=Ww# zmGxP9Y|@U&KFXJfl{8qfU{DV$CQxDhR;C4Mh|*B1F`Nfj#ba%RGn(xYOv=}2oc(wo z7%AIv+?3ofoj^yeeVn2$5J5v9MCwz#0WEcm*YQec(mu)Q=Yq10;a-ODH9z}EVKi%# zre;4`50Mlr&U|1K0=p$mlNW%wh6}W#C0uB=QijVmKnxSGGn8uNK|-Yzt~EaNNo9#3 zF{LTc=mSKb4&H8@x8*i7JyHTQWSgs9oLYc=8NeKT=HXxC>uV7kOCeJo^#EcJF2p7+_ah3Hb z5`?W6J2g>#25yQD0iGF8b=ZI?gP-q@_%oqceW56PICJ&L<`uxYa<=Vq;2S<=;W8pP zdHXx&fX`(8pry?xWAQKrxKIMS^{*KDV6J^eWgB6e0Dy0i#muo}h)iQ*MoT^HCpO~& zz=cXfgWxhIZDYVDP%Hfjrpci9SQpnDw*m=~Zlx+bx5PYspF=9p*| z@*QVgp6ZV5DM1>Bw?6W&CgD_ac17>3+=8>_RatN=snd^IdZj?`9jUk|q8}gR53Np* z21wqsFaP!>+IVgt;=~zW$9X+e&Y)c#9bK`Kuo|Z zauvZXYc`)U+nB8C2&6d8Gq!7dDJ`VRn7LGM(lH4Oo{HsviSe#FBr|Yl=Nw6ls_*{l z_0+0t5gCUIQTvSL@pdm(YL*HQ5r_J$4h489w$P@?0@|ZL<6n&=u~@}K-k7hLm3)^VK3mwCUq`2z*%dV{f3lO=#nmcyZ0OxAC}2~6Dmngw|&jeE0?cIJ~D*z zM6)!}#>cWZbjB8>M`)%Y85ie*0VKDOd9>UfCX_3b&Po-maM|6YD_An!BSZh=e5 zigB<(K(t+m;TDOD<2*0$$Ykw`-=uGveD}^2QESygidm;-rSJnY3??5VPPOY5!~gJk z4@Luw*BqMGw*{mU-_B%LmCi@y9>s&9yO^-=Qo@M<$h)Trc3ws2|pk)7CKO)51%4Sdu z-)x|k;1j`vHT>CgG6hCF>sfud{>5%1Z@Rj`=DLhZ4wq|N-f5&ogmv=yK*f17Wp_&nCR@re0T` zJn(+z>ju@(gPJQu{+oM3yb1?;B`x)gLhfU0Go>)z`7Z&)=X39%FnU_KUd`M-gfFc! zj)&-fJ21L_(31(@X!@fBj~24z`Zp*+hF`R?^B1J&w5wZV-k&_LJqGZ8c=l1hXZ;wA zS~y>G-8~26a~HK$s?!%^;Y4Ru!S1dD-)ydzWi%wu_SI}b^DG_@u!*v7!wZ9rjpKmPGrN@;Lkj%aoM^;q87i2W-w9GI#Y{dJnW zqMnSDX@mb0&#JtKm*m0$um*Y{Ul-O@2_V?CO6ELt!vr^qm1(vWp*0gi9^rB|4g)ye zVq%}l&Ql)Zd!()`m-F}Nm^_%$bytzt+&=%|#d#*;c@DT}reDlgYG5fR!i#-sU`}Gi zQ4r0eX=>9=MzOl31!V66MEd6Hh>@vbo)&SMzD#-Md>*;4aCVdo*S<&m2q-<7Hb`e4 z)tn|!t5IAbWrCmJ$-nZSQPq>0@l+xZB{I0hB8vf@kb@q)EhiJn(_(Va#)-H5xA3_C=YsA)E4P6(}zo?k?0#Cno%sckC<0E zO;MRnm}ygNH1spjsKpgHls!wv|7O2wHxug$jmM0~;yxYS z*rud8O^l*tkj0?PVNPWkMFXtl9&DVWA-rgL zh>o+uazkebFRGOm07db1+{Y!&c{=Xd@U=If=^DD@q`~RfQR4oTC10NX^|i#%MoKB? zraDi3c$x_C)muQ|9RV<>(}&jDXz*No`j9KmV$uX%2Hk*uRjWva3T>E+R8a((Nl22n zNn5-6?FC8`2X_Iq`y@mb-nDx~w|_6EgE_BXX3;mwa4H6Xp!xtR=>M}mK<2i0T~eE1 zsZI1%s&9t*iq*E#A%H`;%*U=K!j+_+F|HbIx{z2`ZH}ek#n+1f6ff6nRI;!ZQkAwr z-i25&j`fSpb9*tZ);7IrC@QimMB@#gTqyOPfo~oflw+<{7PE+40Czcr6w8BqGGSi8 z9xu4+lRnK#I#eQbdpu21;zb4x`J^!+HfzIdpPF>vn)W)m@F)W&6ON@R*wtY`x>|3w z&jIjYXj<@$-l5Tr3oG4H)eGq!o>J1|*Euyp5V&M$*r!&?3|gS$C%W9`AA31PvvFfK z4y+9Uch$VAVGiO0tKD$yZ-GojTk*VR8+SF2M(C64qzaOhqyk_f%p!!d3{WPY=^phPl8g;w_&Qfe# zpXLN#y@!q{WNLh;1>5zh#BdNF#erRYyZ9{i1=Mietafyl`rNeI{^=h)rp8xUIT5k_ z;GXT12O;6$r_cBt;h6sNDwdT~O!ztB-hXyd#@-_KJ$ zF{A(TNmQBhx|&d(g_3piE--VJs>}=QB#k-BxpOLomJ6|RQ*>6-V!=YEQzDQGtTndQ z^A9!9gaV@FD6{j=I-%r5{k4Cv&v3mLA5H9pi{1sZ$UB`g_Xz!;s z?lrKDKV*`&qfeCsgRSXtp=)AU)IXO`5(*HZuoKEKlw7hSR;+N|dEZ-*(7#)6#i@g) z8)49JCR#ovZo78Wz;1Y#i`l=YsL{BC(eY(b=A*70MhPDG4|ttuh(;gPjw{WmSa>#Z z_>)l1_`Y@4p+Y1CzK)&N{JiH=l=;GV^PS50J7f-YLrfYmgx!0ZS=N?wW@A>q%A7VK zC%+U~0?3VqkV?f#TL?K1yT?z(=jYqx5B--1yOKlyus+9otJ{$~pU00M?dD|U=3g8y z$hzV2C_{~9m9UUr8ngcq|mJg!!}AgnM6GjIse7@j82ZF8AxaocwF z?1!t)xvG@~zZgw-k=Jaw55{w=;)Q*xc_bZS`!8V`ej8c!3|KC_I-UvAwgEH~=$Ejf zJEu`qm}h(L(A8S|Anh)dQLZ5GxxdgdNa#qdr3BSz1=Vh+R_wNOrk2-!yPB0lKt)gF z`vsjlXHlz2E#0<^JXj0KQ(eLs&d671%X*skGS2xWWK>aG4*0fIEw?Ia=CpvXkj+7?U1=kchC8iZxd|~pB|&n zF!ujs{*T?`toEPX4@o^6`FN zT^%~u6R_cR<}MMR@CcKijW6<*HTih$cS@r`iYv1B*R`8}f8Q*#2q^aYQHgD_Gg|#R z8${x}-@Jn>iN9UobS;0L(9dB!LW<2C1}u{XOi~~G!AszI5@{!}V%0=MEB2Cw@R;c# z@pSX>=8db6%JV#tZSVhR-)~-9Vgmqe)92DWm?R1#JIqyS3O8QiBKn4|Jy`Qmwz9_G zD8}BdPa0`<=yd$^0M3@TUGjJ4DU?q4p5P$FY~D}iMDcx0SaL)B=JRt`N2dPVpPp*-jke0|J1I6jbL;6D(5QCgbY zkE#@J*fSHIqjQp=tUZ6=@%q1YR}#lsC&rI-cW#&(E4zMcWjf&0JDX7pHD|W%=`6>l z(;Cj_j~~3E(bqF2tZoz=q#{8(}x{-(Ht~N|3@dr4*+Q<+B3Ce|0xir?qapB;1%Ovv{fY??sC3 zD}KU^(Ti8C@>gz79jk84x<$=yK6`%iiQ2ViUl%;9MrpS1dhzo5v)O|u&abn3ZMpO9 zyP!8}FW!DyehX?gdi;Bn=k#pv*|)n-yq0ZOvu-q0-6&7{H`n~)`Qe@KLNwo-op`;n z<9*iI+U+;yhyG1nI+1_##saMTZG}_K^_}l-|NHPX{exCd!<)oJY#_KlOaJz4=A; z_wzv8PitN*I^O*1eRAr7Mu+vy^=>O)cdUHVqka!R`F-Eb?*~`DN3Z))=7{47}a>-5QAWjB9St^BH9w_Ja6x%uXD`^s|Xy5E;h{yw?u$Mu!p zee3=Vo&0m>=AZj3e;%&;J9hH#vzvdXR{kDf>)J^nQO_M?XI3|5eizk+x$XrB@x*+{ znt`p=foG<{)rh%L8HSOMGx3kjG^@Rp2d8`KHnCh#6m?rG*`B^LyuiR~kLil|O(yY- z1xQ2d-p1U|w>-A|$5uk?&tm3K9kVU=Z6X+{AE#AYv<%7dnfwcfo#8Gy_yaLh5z#tX z^e3~ry-k!mIp|HE(5Ut!kQ5(R?GkTK+lz1RuUE4v?Fw1r4ypfRm&bx>$kD17N#bFJ&4%oYtb`Dd(+77w5kQU- zR#@kdssCs_qq>>?-88apxBMK50LKFw@0i`w+xTcDg=v>N@;X+Qt26(znSDmn*PO9> z%$s>YhLTR)gL5|506MvCzFq^#VU-wHq_$NXQvmqK_PfNXZ{D^-J6IJ-XOT|P=zvyU z?qa!&Tb8T_sK%H(yQgpN95~>W#uJ-0GDFU|h<9+9n9TV8bU5=Kdxq(j3f1|Ecoz`F ze1hke#P=FmVMRVx&zKmY?VNyeX87nJn%c{}rPtJrtU$`+S$ouq$$ie)9sbV4Xx-)n zOoa~F`UOHWQ>2dm>6Z$qZi)nMYw0bTVF+t0Jt#qw(+`o_hddcO4Ls19nl>?_#<^pL zQZp@WTd82qSuQYoJ#C9=-z_z|_AkC%aW_xO#KvjEz42SeZYgX5`qPkvx?(y_hxwYG z3FX;9r=bGQxblF}leV9rO#qIlg}o7s7pW0KjE>FU zz#a0X(}k%9TV%#;7xYH)Fj>u%+lPIU2)Q5V__j~c=*L+mgn>3PN7PgSHXJyAV;Y8* z{a+X!aEXJgG@U8oEF^+WCk?A1jx4#=E!F0juxt2bI zsd(^ug%Z|4zmoV^vXMqT^mX*mpn?{^molu2w;tqCJ#}^rVbB(fd^qws9A4J&S9BeS zj}7hLEo0LB(u_(J@!;PMltJ1D@hq5TShz`&adJGY}msUnoqPU7EU?EfRX-I`|ENlKidG20jMyeFRX-u}&qe1#M)*E8bRX2?!h^GCa7GY61n3fcf1Hm9D$v*dE`}Pq z_P{hFNcSVIRIHif!L_peLU2TbBLs)FravM`Yb>9<#w?c=F9g ziK!ApjJ{H<%l1O)5F^?*GRpC=u}+k+oGiXVJFNhULs^w|6MycCAoRoZz}Z)j6{8_q{|ZYclYcyLLQtj zY*eZQAl-wLt?uPkx9(w7W-CbL;Gsey!xkM;x545kB!! zGPd2o!ZK_B+op7ordVdEDo2$_Ry`%O&OLO-3e$Z}AC#S0S%h47d;!b;aS+D|c_F<5 zSnEBcXK=i;A7TdF)@RJZ?H8c8E*l}4A8;K7LZ3B@RFcH+X7=t%QD#~uQ?L)ME_Km& z=cqVF5&JU==1;UQ%R77JBn)EU1hg=9y$TJ&aZ)fo-x2IP*)6W|d5Xr-TWJql;PJz> z(I+Vfm`g22IM40AI6!PY{h_Xf2BX%ooxxpw11~IT!&NQ z*nqWzO$+?ZC)$o;zl_xT0}(ouEyCQH-)P--{6R~-axPp~X1k-J;o7~t)EqnMdHUkQ zmaWU+++SCbsuACymlxph2ki7R93n9$XHyTSg6Dq0l(O-hWSd-4l?n?hXN{P&=@c>s&BGt@7OLLtpY z;tV7_?8Y$`7%)oe@-xf{Txoik@t;3@W(eG&v&jGQgeGsFwq`)5r0S=?1}i@Ea8?B!x~bcx(EdqkgDfnwGN_MbNr`MVkuY zCtUTnh#*5?#m#FLq0a+PFCNm3RQH zfWM7iI&3EfJ*#=>2yJqe+eYnB#9s=wn1(E?g*P!GaMKLYCH1uNpo33h>0L2N0_3?{ zNFxFK$wjY2C0bO$+DJD1lo(O87!k=0xHGnT?QO*y&OjI$txtnq8yM4p&~q-B7V{M_ z3c#KL(40p}Doo7TC)=toBb>!Ps;Mq}wg5X^upV4<|2|9(0-y~b{g+VuTlNRVP;IR} zUW~MQLe(C&_V|W0j5js5fe>QwxC`d{S}A+ zoVtiS$u(!XAj5cuUbop+X5jHxn9PDxI$uy_XLj2nva7biG=#P-94PLR#q48VcoU`i zcDk04@@8{AYBi|EkRz~s+P*7nS!)SM7<(=n+?4~z3k-A_MF#8by?-PnYCB&ofLj-` zf)|l<&f8Xtir`CBV~J%oO>-X?bjZ@$ypQr$x#*r-oLaxkg+?}6zp@=$tsQ7fS=Aib zL5Eg7^WDC$a8sx9zF&m^*I-IFnxJzAwiLhDmTYv@R9E6{li;gG28+#0DAR>|ZA<7} z&AiKe2ZW*)2mCfpW;Ib{U1ys?q}C8}8xvE{Fj9#wp#x{sh6{BU;~~C5*V=M`r_uGg z@X*_`Rc<~S(o%TeA=>&1&uLX1OyQ2|gW}DhNg{BQ2w^EmNp>xyiU5oV?iU~Myoi!G zQ=rzVh1zra()y}xit%a>HH@lripgj>LE^oi@|{_fnX89t1FGIWlb4$=TbFqj;6ahH z!IaRqhylBBhQc;0>IgZfVg`REMakZaqU{KTFd>l z*4eeTEw%O|wT|<(>#%h!<2sihc{3W!BfD;WOWlT%I`8?qP1yR)#`Rmg>izcDZ_BO^ zY^mQqQom!qeiybO#JFL%S3`JtoojZ(zLtgqBMk@V8xCO`qm3I6do>=}-*_~;F`=dL z*hu5?`Np|B@|;c$x9Za`2PyS;f}{CLOzS3Qff2nAdRL>tG*B+aD)8s!%(o=HQwGQ8 zVD`Xiy^v;ze?&(Lv*W=Qe#xgyG_4M4g7>Yo0Q|@P*4ky%a}H@9s6IWf zd9S7Q7Pa;ArB=_)t@jFQ>qnq-6Y_H7#P?!Sjo@@J3#ew}lh05V>PQ6wgD);Mt%(te z^cr1ii%KU}cEj~koquXmhU{AYvun<-p~*PKY(9Wy=bfF0)pe8M$NV8P@BxDm$UToc zuuTS>tzlh&vtS=WP4En2yTGts9x21WCVmEa@*Pe*SaV`0jn)}A4Vp{fTR4RGEV*Sj z;(f`<)S&ZkCMrJ$bt$y2_>?UvZqKO=(6O9`6)y%=dci>-4QYPmZlca}Y9hy`L0O zFGO|e)i_CEra~A^r-RPUJM=Vg7QjftD@_@YG7tOLD|A+^!v<*4WcbMlz_^E<$^fnh zK+LGEoPMyaTA6Vp<6HB$11k=*p;IGZ6Py>D z?HTLN1zC>GnT**$OFgilr5l9Y6Epx`ZI5g>ys``cW@O0VVgFb+OlD)B-$n|T_9<3F z&xBYio@LYtbvldeBz<%osp9hSiH+ly!)fq@|a4QJqowR%*p00J56WJp;U4uH?oP!uxM#l+25KnvSTC|&T0MdCFc{;x53O^6*?Tp>(wP^%kvP4STb zT9KbP9e+5aDwAQ$6lj=-osbghIfM~1!d0L6iAK7_f!&J5d|D*-EXbC=$T%tHrHo~| zi0&E_ot0s}#aJz}j#2^qIg|8uBdLUY=K>SwM5ELT@pu7zf`OS}T;42IqH<9U3xwm6 z%iMw^*MY0;-8YYjAV)m>Yb5@qln^3Tkl{JM3vpBtSxej%B89I+Qg|HvmI}3NoI4jd z9aC&elEy>%zu?;E=od^9z*E7p)&$5U zHwo5JM&D+mG6!x(72vvQl=nDHEgmxF;xCbrVF2N;m*)}(4RJBBcC+;6jz3tP4^+8P z0nUPp|4)LLrJ*$!;rnO^&LX}UKtx3gOQdkrak&-&F^-AI0@mtej8E1v-!dxIC5cQA}s1J;w1;=!NA<+J^WofrfBB3%ti$*Js(|! z*-8lK$)~*-q-e2~QUS6^0@?pPu|=}a?AqK9ChxhM!-hGe~l!SLpS;t{uu=8VS z_r}sAujkI4Klvv~>&5h1d|~t9|6T|XAzxY#0mPui9vH>;wE$6NN$lYPO!8AYIqx6MfC)F=Doule4_!2Yh;?`- zD`{BYX~yv1g0|0$)_Se4T#}4>{Sf=A)0+(EU>^ZGR31(YJUv2t+D!(v$+MUt%nQlM z%S6P}W$kjE9=huu$y1i1 znGe%?RgSZ9Lk!|BDd8+Ka>*MS>-yr@F(lk~EeTT@A?Pr?60d!P?dws-YFh;?Q_A~7ydL_YU7?!Cp8`TrDCa8OwE zk_V)`{p11_00ca|9tXQ7^vBRYf+G+1LX3HZ8%(qx{!O1U4f`R_$Fa?lrl!86ntm)5 zy?za#M+8!BDfTnrQQw0vir0rW0zZcst5VzEp9+!AaI|zR{*J9%)$sD0V#suQ`gcCQ zHRaFr`}`Tb^D%GF86B7_SEEBYlf&BVJj)ZW2!dB}2=W)~%Bl$724##K!B>zHI}Ohy z^G>BjJJYtB8OkMAC2NbldrfJsr*zlL&Lw%08$@enrC4~%#dU`Io{}hVV~s~f5qj_} z_yb+g^O?}YZlkHsoDCfsH0EeK;}hI7vQR+a`efP?N|n@L+^m_s%?$;ky_*+Eq%A>2 zLKkmoygJq`vpwNUI)_vDBIpM5Um;pHE}FjaO%hD*3{BfPOhX47`=7^N3?2HIeXlN; zfhJ`sTRX8}mFoIRIpKY3fgP#4^DAxiFrL9gb-I&8lpbXH{`{_iQ-4I$vM97`$HmyG zNn7-r2UQ+tZulPf@_y{n_6HMFzmG0X59J%|S~<}RST0BTE&1;Eo!Mf&_$ORSJ6ng~ z%uj1i3i%enCxppxQpC^n(;CG*qz+^?(q9{Mi@kacL^d)wW!ypwsW0*68S!_RHfIUw zZIpt%gABPW-i~b6K#tCz?Rr&?O%b!iMq$i;G`EY>f34kBrpR!t^L&*`2rt}Iss0}n zdUj7qfKHV^J0K)4ZfimRDc`V&_8zi2!}**un+CQg00XZXfQsx}`R@rBNWa}8FU*U% zmj#x^`*eaGWSh+m2$E~eMNQ94Pn~qdjTf_dUjDy*d*F!$gIVi$iM(;@p5q_79&3kt zdur#o`s&I>*dVWBzKuj(n{P@vV)7!e{{6?RL3{J=IqW?4?c3AEQ{+$Rkc)CknB5>v zsW&tQ5I@_SLs06awH&v~+*4hDIpd>1>OY~GEd4&Q_iFohbmTdN^m$vC_Y?cQ?Rm-* z@z?EZGGqW@|Dcd}dRKyuKL6nJJYmS&|9KMVf91s|$g1RdYUk<8vT!a>dFmr0ecR5A zwKuj&4;1MAus`u=$9PbM6|3?8I0;~oUp+7Qd z+zJ4q)jdW3tMQaukn~BB9y{xrmbD=<#Xau^FFN&3Mk=#q))Z9L8(^+0>W%;P$SC8~ znyQ7Z;OyLOMZe8Th7XT4@nPFys94vl_1HYQ7MkAG+7>)iS9(5v+I4Q88WU7 zgA!*nJeu!CwBgiXF`AQnEXn>)LpCWORnGl1=dqld8)P|p2Wz6v%F(oo9YvS93Jcvy zm(a<8=8!0vNx4+a4=b&z6gfw=p!y*ztGtq09XL7 zt73vh5Oh{F0|N}(`q#sDxJNfLsdb`kt+wcuLJZL$iFKD^lSy+9tkf5$pE1Z>bT#}{ z#Z3;qB$RPDE(JIPn%lgX=ST!WK_o^P;QT@Hs*sY5q6&oi6-`20m~oLr+v7Ct7pJXj z;=HWXf1df7f2_$99id<$yby&pES|~eyqXY5pV$m*F?Q^d=S0pY-K>+=yr3L->jRV{; zR=PN!=OGOBC_nIGp+R{Ft_PJl`yc!^7O=P762L7^6U_f}<%hutrSmY{F2E&&)Y_J8 z2qr1O5HztT9|rT^xE5LH8MAT$iv@~lIhq?~fsgqvoiAwOC2kC8Tq*fHpfzN}>hA@9 z=E)uvd(_){*U?%psCW)?YrVvAUVfXIvsyyFrcgBW8ZrY0Ez)RZJfjk3w5`Ea8|E#W z-IBBWV3(Mm?Tu{P7-^%tR{^I(P0Y@YkhW&^Ud0wy&kTOKkr zBT_fXZu#FIk5x3o{!>3?V}5KwaNM?Cs3=>6!o6JDc$^)@9H?edo9zF{3BpFV_EOr@`Y&W+=OjPkzloeSm zoW)n!xiDG(A54F3ht(&Ag#B?|GAKF&(X^82T!EKbNl>L%vPT?ZX+Ob&D!y zD~(1rr?ay`0-Q0Vqi9G7o-Hi7{M8=~brMg^M$s-;c<9FYLlFuLNIM|SN?nLNJ{YnI zh)}c*1_4qVq`Gkivgs9O#63=~Tqe7LKRI`*+{~?{t$Wlzk8Xg1X9{FR>Q!@%EBSUZ zNXK!G^Utq*r0cKQq8bI4EG!3md=R$nYSQd~pP!9{?|YSXe9qmBtVed2K@w{4DWvqp zTo0RSzbP&P<4N9ZxUfKwigL^?rF?`d?cjGqcv-bP5>| zr22K$s%?(oVX4)p5+os*=hDY&6VVk3T{An^ebY58Xpv~pFi|BAt!i)h>A@1H-Wb7z z5?MK`X~k_uDK3_?578IjEOqb*rkXl}`+RY`W`?H=wV0e8pDUv*pi|fy7=(GG3z=P7 zw40Jv=NDNB*NeZk++vWbA!4GSGRUIbEN{xPR@3&F9^i1z7r7GLUuYl(aa=a<`Ki9m zuOw-X@A=4}chUg2(hNgRh^(J3)W%DhjwKi#^fi>qmaQw_dWhfuM2BdvvjOXi)q7xd z2y1pd#Zrx%lIZCSL`iO|#2yG_RZc^uGM(0qRzC9am$QMT2S5}RMU8x=P^On+Nl8mq zFodbrhl9A!GpHlI(<(7KKzP0hc-)x}x;3HbtGUo#X@Bm^mQTmM-F=HzAE>zG;_7&7 z5tN(L)?fn84%+;>D(^h``ON!X$41~(huWiPT1z--8ovACJY4n(m9La6TrhLXQUpTA zl?lW+=qPSxA{lRNUn2xoKY>72Z%fMoo&_%JBWEPsn&TJG~}HH<~zt3Aju z(pTY-=64C205G9@(%VK#QsjwJ9V>fWU(@O6HCONLRzE6o(UAoNI&-_JN4c(!vC)l* z!1i%l&YVsbK=hYT0NU9om#?k)p#qlDvLXCRpS?i&@ZrnSSWTPr+_b0^5dV$cDEBow z$8i!wUeCO3w7^B}54z|#Dsh8WZzg_CC>6hZbld2$L}EkBmW|{rTVE~^d`y|wXWpdr z|KOm&ljGp5AYJ1Ln;1Na2DDaqM;bpYX2@6>Lq47$Y=p86^gOE0e_*8@&NhnkW_^~`jtAWVojFqsEenkd=^oe~gz1JXg05VR~Md>0U-QnA&I#3JD2PL=4*WRNc*rs)zl z6hWDbgikUd4teX&dA5=X1^YWC?a6OGy8BV zfEMQc)r0)wP-`zkUAuE`d#(aye8wj5TRi9kApXT4yfqB@i1MI<>;^-)oiJZZD8urB zS3Sv9r8$RV^PRZ162t7SSD?SU%0-n^IB`BPFk54VYqc;A{!GiYlf4{WP17yQF%`k= z1le->$d?k-jz#cFX^xX9r%kS)2W|0yjL{0)+rrBk?k=E;Pg`FVbR}nntuHAbkKeu} z3pNezPatd3po713)D?BnVz5+#I>5vIVWW7v$&spOFlHxiz0%1|^_F)fA4;&Cz63-9 zm>2*vBgOmB&ZL)-c~?s^FuI4E$!E%RsuIWni>Twe|D&_95$Pm!$|g>PQHjG{=bcEi z(s0{~E)1|YtK?Eb*3lZmXGv0_)az%P=Z zUL=lky-he#cdu6MNvJ3vuFAe$B3&tqIP;}MTTuC`xw2HZ!s#=Z>0dfmcJ_0E$BTrL zFA3*CTv{;CQgJ0Uzsh%6_sV1%e1A$~$gTo&e*2)|>h6@sdj6022$ z$Z~eosuR_k%hfcyb80-*SMwvGV&t7+y#%eqt~1RRZfdDy zwSasns_As~4s1Pnxz@Z~h!z2IO2wQSot1s$t%;V9EU+V^3?(JhJrN5Df$ zGV&+!gAgA>K8K<-Qtg@?<(xi!X@HwCFI?0)=>_?EkLR zn2)a9f3Bol*se{o$aU zHXQ8b`f7|P9Tx%BQbMRa^tcF05~si8V$Y`|ZZj_z@$esjW2;0^fF$)D)7(U&nR^C0 zDGzK z_?`2;zxQ=*FvBVK#Qr&MB9g>p5zmOhO-~4^r$Dk8Jh+zmSiUwc{Kz}$=0IqN8U&L9 zs$D?O&akV zow%$5 z6la)uxtAH9h5XIN9KpdAobKH&*zJJo3kdOE3$3aEUUP6J9Ap6--3}1G!Bzrk^5&~xMTFN<S3l9P`1BZoa2-?$Y*N2Y~UIU*iOaaAPD z6Bb=bA#^Nx$+HR9+nyb0AWOoZWQ5p3PkWze3cZXi$YEmScaAF-y_1W zSD^pvzhadm0eXi5KMcWZ zZeIV?Fx;SWgJ^TZT^+V;4!)AS<7dMS6A_|Oq6}>jO6#BLi49xD$S;Gyw2a>{KO#A_ zi(qAbIzYEvPbRM6z#TXAlj(gd(Yhm2)sb#+P>c%&V&eTH%N6(J*{XnC?}`HdPH7A! z4;nV$m4?YBa@a7S8tDKZBp*y`UH{^k?$iSttmh?V<4Z*wjRo+_f|ry_wyv0~HvVb* zV6hfd=8$;D5v2%lodZHKhuPIO>Os28pFzhBA^SW9>ggGJmX-qFcLZy^d&m>pvHsXt()BD(w?{->DmnT?(BEDE7VFuF6kd{SPv zoyu8@u>)Y6EtFkp82R+rJr?~!%g9dz(!Bfjk=2A4GFUDmd=(SEvK(WC9luoB+d$Q# z6z04_HAI9P6Q3%?BOCFLo32GF6aLpEWX;V&V|Jf$zI2_-rCCoD2D|>n{>f@N`|M`;+g_yLAQZGC#A=V8u@|cD-2j#eNt;L`c>OvVbYC0^IllVoHq5lcQfi?E8OL zUt1oz&8x_r&UPlja<*d9UZuy-GZXB>mi*UsVfls~!;=;kktLFwg%W)I|G702qzJ!` z(%GHv`he;XJ2*)kIVODyJ;UX}UpnkQ3zMS%0_$S?3(cVft&LBhvi=y!lh=mv<4Snz z0icjftd}4UvsX0@sKh9!Wdg~_F3!S^Rs7jiSDjyxI^b(}KMVM@&g;J786Mk|f=Xf! zPo|uH<8^Z8nz-(-ARkiv_<7ResMsc9(BiuT#L{C<0JO zmC(DhES&DuJ~cc{#kaTc!1fxyOhNpJ*BRpFMF1_<#{MwJ8(+T-BTXkuu`fvKdjOfM z96!b)2dJ_?y&I4Gi>i<-K`3{IMSYLREQ(ImSVBi=avf zk5hX&_^Mh2)0YQh#G6iw5f0gyOO6|qI?JF%%nkr;qj-%g7;hoK&gZ;&B$2D19ZdU- z@b!1@fp+w!p{b_{b+l^%>)rtiuU8Drq)80%2Bt7+e`*kdf?7i z9q|h6b25U^*Ylj@wN->CE=Hfdch6?iI_7E^w=z?2n2CG|Y3mA=2C(JMF6)OPg3(q}EmXwm6&Z$tQ<5gz(b zr;boLJ}^(Gm@%gBI@`IXr(~TsgBfr7Y{?@l16N3k?8}^+_+$h`VTLB3m?fEGNI?CH zqTz{*$dhYMdm}|_W~0u;U)zl|i24xSm3p_)uOVvVqf=|{B_SbzOEd}5x%0h=0pF{Z zzgCbA9mwEc+qG*(zGN_SCYa<(1DigW^_LwZYuhSGV$wf(O=&A9CW^p1DMqi~-p7nA(C>W1;vefn8 zyhhk^qUJirse3!&?CZ!u9LuJo{m@A}{OQdtbEx^UnSg7kEo-&Uy|F!?n9> zf|l%;j`FY|+gZXmI)Ii4}l_gGEx0@-V6~E=LjlDQS^ixC!b9KKnuJbld zOJ00EF|1K6upeAf+M$l1FtUel+fTWNhuA!Gv=4QA+j=h4V|3^HKD|CUSD-Rwp2c;Z zXgY3`Is?HL<(-x0S*6L3n~Dv+N#EuMT_0Ut9qQlL<+wU*CDJJ}{8q%~)5K6OLf`p2 zht(kh{k}R>yW%`+G(7ipSES@?fA`w;dyvl2iNzKdqLZuqoMTcCq+W>GaJ0xdHskoQ z3$a;e2b|Y!y!iUUy4)K`m$*$gEiT4wzUSu>zvW@-#rUl+id+)5y*+j@VaMkIm-V}T zZhYvbou94+yj^(mUZCMityo{AlcxI^^Qqpq__VQ2QLzA&B-cb6yy;1<`aD6uqSiC3 z9C8eDla_!_OROrXtJnGIeZ7+@7Ubk_`+f>pM(Rha-H8QMl?;$mZyK;vF3BqGUr)yI z{r4e6^y3q-#o`(tMoenm&AD^takak`NnQF(nO?~52Qk_k>YRg%Hbj5nzU#a_m;$cY z?fEU^+D}vzU^Wr{R+}0$&IYe9r6W_XX?jdmZjXCVqnY9_TIO_1J?^Rd-6(PPFlNPE z1slN72K19N>%Hv!928v*tQq3(V!_evv(`Sl|x7T8Q;DWBib`^uG z;TACUp2=gZH3dUu`MVc7ii+tXfAram; zvCA-KM&P>8%GZ!qYO$haDxmyoS|b@rC_!6>erFn%jBb_o$*}1FKHL=qv*iJX{n|mi z3motO>qQlB0zd)DTHb7#&MOMqO4&410@|Fy>#&=c4D=Fs!b9dJlbJp+-*=Sh*pw-waGn}nTzlU~>oN7L$_nzgac^J6zt~QMpD6(GV zBE7@Jg+@Bozz1phCt*|uNmmV`i&>W8;(4HK@#(_-2eg)z?x<#k=xsQv17pC zy%1rS=XTB3rEt0^$=PDxZVjymlYGN`Mx{x*7`2aibJ6pvh}WPk)m-tN9_e_mQZ($oq?vzDM zufVN2LIIW&JB5x^nI<(=;N%|+#iTXWRZEX8J@(cqHDoh{%bFE4ci(YJZIncGU1$B9u<8Vt1JGIJ7Jc?kTf13Y+=kfNAgzk9*| zzWFFwsDqQ_Rj{+lbmwB3hzJg9f6z?8V56(C+|8z8cvNZd{c_pSwPM?TFp7@9T$4aK(P z{RFQWGD#%^ZKvE-F1hMsRK=Nv!6=$LCScbrFhyQhPnR1j#Qcw65dPbZ;2PI`jQ34~ z>XnSWms!78)uMV%(!AytS>Z^Rzlmk2-k0#VtZy#1lZ-cU$Mt|;r}7$qg(mzkJ*t&1 zHre6IMgM&b|7Q^gAKv7h@G04-WCc8Zv|RIX#y(+%pam#G+<87l!hXm>Wqb^Lh% zM>_kuhH`10nb$Prva1JCe7WspP0SuR`J8`Q*ST|03iN@6QNqf{AYG)`d1El zAJ)gW#`_H9?>O`qKfPyjx=;8`k0Xai+OKVhU-BPj$J1|)@0`9ro3nQRJ7&Ls>)>AM zmqhogA_-7%dhcW(HE8FXTZp;KKd*f`dUj%pl3Vx+d3`MS=G8ZTFMi$BFrGhqZ~xna z38$c~MYviW&$FKzf8$OpKL39Gv)8l4l{+K8lzr#F(45Y?p@mEzm|uJFnl#|v4#nr| zzYkmO{;}-XsWX%BmmKS&N7(|!+7%^#27Z>+PlQeP&JOV2)C_uTu3VMW#qm`O?AJ3M0DlIgB2ka;kGqM_IQPaYe3J z+G{=Ce+(R|Q(q#-y_nND5(A8Gqpy#Ftr79CN-rXv>(S1|Y2xr0K`2g3-?qpfvr^+1 z=qhC#Z_?e%z%7G{Or%`yW0kZeMK+>_)9sj85zo}{I*MlaMO=PPEIWIPd-j_sXAT6| zLK^_sI(bNa2Dz93@vJrXqL{pVr5GM_sOeUjg#;BWS3S*ChIWUsss|66>7DKIX>K~G zNiL2mB)#DHUY;X44+$B}gX<1*U4}rz_JetHBo6X9O9xP70hP%J8*R6(KX{|8<{TiP zk8|UcHmnaSD5bEf1VOJ9_#4kR)T8EEY6vPTRAe+ zhY)cRuKEYjhIXV0liSe)+d6qtT~xHX-R(TRY8kWGP7Yq=HoVm3#m~U4NHr@xkDo0$ zbmGLJv#gsvf&G59W=&rMw$Gu|;&7X0g;Z&8$U#9a+q=uYfsgRBs4vFA_P??b+R6_t zig^B#^np5sAdW8PsspxH{7%z>l3Hd0!dBzf&6iB3Wp-7DYF~N3juIo{qwkOc6f-!m zJ@%@CO@v`p7ISe)DgS6CbVOEO)7N}s^3imKlYQawZNJA5B4_;L?)=_>AWdjB_; z@7g(Ni833W5oSVg59N%q#OM0L7SOQ%q8G+D{w_;dJca;gvm{J;YH@#}H{7Fck2*VlTg81Yx`sq9fa?aUPMfb>; zj*fbNNxyUlth_gM#E5!)((U&B>{Y{)Bcz4EhucI=`vSK#1@58=2+H;sfZkLN(CDZJ zDdNHv{`(B2Lk(`^iq-eDZHhqI_vj)3es19fcq|tsZY*G<(pZO$#YOQVWJ?~fP%gdI)Eu(<|Qh0JYdJPr60}^y7c-cMjH`^L# zzU)KoVkzY-Xqb3K4=-B|*QP_kGeRQ~#A1sVSCAY0R2vT8MrJIWwS=%$0KY&4x1|ZU zO0c1HF=#_pFKWU~Fw~9|uPD*?bVUi3ij;H+e;1`haQR_@B z=Y*l@B4d&Bc0j3%GyhMG@#IzU4smfl24V((Gs zs4e&N>j9U&aQsRAD}lwdlA4s1v9%StX?$c>;eE0c^h=G@o*ScljQk!hG;%GSV8Sx8 zienXE&JNZN_OWEo1B?o-#i-M8Z3P%#U!1v`6)T5_4G9A{Jg-7@Y@uM~kZ^aI9_=J* z1H|`dqB9hgV^~ip7sFY1B;jp-RgA3lXd#A(I2sR~`gO z{N(7)vyf4O5&#0YFxUx{W?A|B8_4M;m5;ZP@)oI&v+@1~RuwsLvi&sN1w`MbsLj>2I zyp0Ovip%Cs^5Q5mJf_ePCF%5$J}M*?o%pYfB#H5o#tg4|d~9Q^)sUHo2u{YBtz`pf zk#Mn)-r_L>=A{drAU+On@Wj!4*(7X1CEkf96pfYLtay5>h-dn`XoZAtILXf*hg0A4 zX>xQRlZ#SH-KbD7#x$)SW9DtTFlHY5we@*L@wC@-jiFG(c4X?zvlrL+ULs*82a262 z^56)R);l!WF`WJU28_2+BCw5yZV&UuNPygHd1Ozq5;thda`fN;kb3-B1s?&SI<#6n z$KY;so>s}h=XS+8^yP@_Y}z>Aku$Uj%T+E92%2s!PK_%yhsJWypS{XzVQB(Kse%$x zC&Bh^gw?{K4SC2@e8iS?toA68{|kzbw)bB^StS73k1fk$f%r21B5DRH+xC>khUw?^ z&FI^?os2z8v!Y75T7{(nN+}$GqD*q}fUgy&=s+wt4iGLT@pI?e*F>1Q74R}Izs%px zyO#vJUc~bcvMN2vGw3qw_?caT5E3 zbnZOcrO@zgbcedM%SUWEem^xK&Bkiz_=X?Uk%dEu_BRegZt*P3eUwF_W1 zB=#Cq0>4wskS$)qyUTUSYW;3AvwsyglT-Av9>x*Fji?nhwZd)b#Rcumy*5|wPE&6@ z)*sM19B?^hSpm=0i(q)_w<~g7>u~Qd4^{zRJd4We9D!Z11XBL-E64hu*+F*ta08kpo-NoSLNVI! z%AGA^wPU)h(Qze|82gP$Z(^z1$QBv{@LlcjkQK94Ne5kLvLvx3o$n8I zR^IKcMM4o+SeM?+yI%n_{JWF=<4vAbiOM{hKf+1pg7VWdz2i3*{V# zU!emf)7EXaYZst1WA9OD0OcyoAqnj0sP=rJ?+7*f{gR)RjYs2WBOictI7-!g*n(w9W1dJKewK%LQNwp&H;hdJ@o%?$NJ%kV(0{=& z9f?-HO@IkMfQ(DgnP_M-VEh~waj%22?ADzhoOr_w=JK<;<~F5 zK+B$)qx6^jzw&I_4-8r;?b?ifa5;)4gl2!ttZFfK)$d-?T^#8g9Lli{uI3$HLNafI zTKW+E#fW=@SlIZfNoLkF+v-P7gdkr0yU^-Ok+~sd2^YmzK^+u*A}N$vFs?y0h#+M? zJZZtUX>9dhBlO(ys{fux><%DB;}*ns-?9#8Sd=$~02dv86RLNeM-zA#H=SV4Xx&pc zIL>nAzHCLa!VI6au5nWuzm{fD9}s>yf37Rh$dgv5l?T|*P212nZ z%qua!@Yd?^yFUBZB$GI$D=rqMpb5s1n4vQNXe)bd1&y&;F@i*^S7GTB8p_Uj zN<;;mKL7SGJW4g)2ebS9a$*hMs6Wh}Q=3<{WDyTEg_-LC5R`Yvt++m=g4OBg{PtNm ze3fd?fzX|KMv-BLfl2dLVy?>X4IDCU0#bi}^;@OabH}7U6@7N1YRmKV&R$sK&hbj; zk3+sH4vyPff)M5%op>!*0niIeN&iOhdf(pVgIG)6x2of$L=58FJAA@CMwm@9`*XY~ zBmwim`!<0J%)NJc(7I-(JUIQ_h^N53y22>LmUHvee0p+eMmyIGO^D7uS4=P$i5b{; z6Y8MuP)Bmra<%9`mF`ux5`@FvldH=}>f*5xkFU{XeMXP&Y}cm^2_z>mNI`QI#k>Sy zIzR7^4aQYlQi46^TU&|=Cal{7%NOV6E#6p47eBhG=uy{`60=hp0qnSNj zpMb~5aJI92R3o`VRpWW>7#D43mVM&dd|}^G9}O4V94)uPq`S8hX2@n3)BM++?%n;Q zUeePG!7!k3=eJPzDqoT}+)H^v;3&47Ko@Uc`RrL)keatjvX$p8f|M282BJ>8_$!18T0M*T3K0_aRFJSx>KijeRpI?#jNg3TkqTmzTv&1rt zj(87@fb*rXvUvHjUd*Dk=pHXrXQvoWnCOB~5(Vsa%Nlqnjimj7jh?*%{n4G_V;sd? zQa|Ibsf3SR$|gIph0Jy&4<-2w3$0fy=F??AenDKq1l_W>nqO-t=4Orp;4bnFwZl~z z`1BW8GcgFiEJEVRY~osok4fjCH4KLOC%lhrN?{<#^{aH9XZWRFG~OFCu)DtSIzF@m zZlr5=`j9K#e4n$xBh3sS;)xp29uf{Yu3^kHm-S$(~3j2O3= zF+<#?s#k)Ef`;s-rTcYlA?ph@9zw$u%7evGe)gHWxo?=!Fs~JiV{iKjt)uP%-x3 z`F1b2%i0x#8pli>+hZLMd8kc~$2$*L1#@}f-CQ$I8#~Pqzn*&tEtPWj(u}6c$r6`& zt_IwpwaN4=SC|guByjxPBVLQV1`50dd?qA|RJ6wl60oQP!zr>i-p>toJC(4gK6zv6 z`z(a(U?Y~fUi+zh@isH0!j`$5e9_(Rz3Gr*994hj{eM|}oNCg)%!0l}rql3e`U4 z{5JizkTXvCn#HbOZW~wn>f8=zVM$`2PTJDdg3J1i%*fI5HxvzgletrnZ*!72Irfs0jF-MsFc%6vIx-59jJOKvUY}p& z5x<^*yE5r9a;`BT?nCPGKNNjsq93suZsinq~?(M3Q7qWD;|hK+}N zBC#C@DrpE__IpX+*#^7M+s3av|8f1|Pw7Y1)SYz1=obRG039{W=1XA8LU63C$D@Ob zPuB}nTJkUs)F!`-9=>)c^tod5)tAPL3rF`J(BGg2DKmfGx;Ad!YF0IvqtGY{rSl32XB zJ1s^E*I##!&|B6`H4~zp-5-yi`O$sb;N3|OIx@UzZ_h0m_HV|3`UOhq;bK!G!2--q znxNB3{6cswy4hWP>&L+I>t8BwEF0V3=%G&I>7Ahls4kl8!6IlrI#7d%Qj*FZ)y0^DIU+<8D@-n|;k(iL@kBAbZ)yW0+vFIrMHf()k#Up+NJNksUe3uw^#^hMcW0XxpeUoBWCp)H- zOt?-aUT@rDeX#Aw{qpWfl4%U-pKhDpqfX>vG|`!Y{q(TtKSc?so3AznflZpGQ`Nt; z_P90aT#w$)Xwv@oP&eYSu6C1dCPka~Q0KxFe*0vZ-jv>vfSn8N8HH|q|PuAB}52ci;C8a%TYNIq)#b}%5G)Ma>%yuW~ zpiGMbO)YszMtP<-XV{h}>n-%7m;88SQ&6zb}Pf! z+}pC%d#SmPbF0q^b6@{f-%xYEs8+uObN{qf|D0DV-?s$pHfIW3naY*Gy4Ju(^PslY zpfl#d7g~d_n}=+l`kgODM(e|#hNJP~){TH!NZoXdFM=}`_AiFjYqBPTj+U?gDIy`T z;pmwZu_j<($WRiIVF>SMiGuJ424TNbR*aRH<*z-qpH7Bg)JYkZY9X$clA`&BGg4L% zLj5Wo;mLq|A5xio9hND@dvaq{g5c($O}6q}WoX#;i$kOqEJmzw|3~JL*}(pOPxiUa zW9xcTS2#oPkY3c^V?HEh|Kl%c5z>nkLntWC>MD1w+d37pHx=s5;_-BJM`0m==>mwe z?YDVknG-Q&LhjXaWRUKRJDbvBPZ{LDAf61sfnK$GHUFn6YIC4PAw~a93l1!fklydq`>vtBkcS|y)TM{623Ek^IEtp8AkxkF71x!L<_&d@9e*{dyFd+9DFr`}x zdex*>TN{JRLlHewvO-gDf&%ajDc6egCWpw>B{Bos^j*6kbruf?7}-BMPGTeAwW$Un zGED%cqaY#FsN{0snK`vdy`BGn`osE-&efyIKYFcG7((M=b#d>O8ZfL&W>MR#>go$> zGSoyM^(t8XhMw%M7dRw4-2C!48B#Co)ufVA9W>2UWvJ{K6>60g#K;W2Uw6pD+He-z zvlj>ftgmtpYJwJq?+q3Jpirt#=JouRs!@0`!*6ypDiI9~jkrar0S$(Z<5}hRZW(^+ zd}iXe1T-)QOtYmZARC5&5wE`Wl_Mo-8NMM_RGN2;L$5)JBG%B*8h~wGrB!4OnABU4 zv!%avt+PXUSj~G)y>GgL)`FT@{pz5KfDT4;V+wjzqZ!$u-p6A>8wh6im$9SPg8G*W zs)b>w4C)=rXnTMp>LqDPZ}!4$Iv60C$5Y>D5Ymfzx2{c!TwXG&67Q=^B_C6Ts3UV=_vv&Y%&MM# z5~b4Tz&QBav|^4yzRDnncwbn7fVVUH{TH({dPdPq>G?)1iF6|UAN`FAV4Tmxn%^>7 z^U>J#ok<|@;Zu6n1sO@HfN!Ajcvgil3&?xE zIrY^)n^z|lXc5CePX9C})eM0>lMKA6=~eBptTKg}hH%wIy(VJm$DmBBzYLrRGHCs* zPV=^sN=Fl5da5!Lk+<@~8N|WFZCor>X7MVAK9H_3(J?lG+F&HIq-7~ zQppDJcRm=*Ni)?KSF0&bpK}FFZD%zPTi{5uq>g1|njKXFqR-3ZK{nP448+cT-~G?n zsQ`M^^e=y9nyMDuf?gc}G!fSVe|!Td2&0qk|{+;sKdS`bk%>9ItSS-c=>lO_Sa& zRoXUjTX`hAjh1P454J7S`U^{7Q^o?fqQg0TTI&WKM^9d9EO|5Y8 z<8+w~js~eIKB^Ie9(yx{p{fRR3&&X9 z5GVo7N=nCf(^c|Mk-8b=9{S6FrPQ!~qgzjnj0ORQNay-od*~fai7ej1_kLRD4pFa; z7{EHxUEuFv5NH+$%YOeQ(&)Xa=wz&>)MApm?@Up|awkG~_KrkNknFupzs4NxZHK-; z5DTup>G%xOv5ND?wW!nNx0;>^j07Xm=ei6!U{tGa{aV;d9+Wh4C~^0X=ZDK8}_nlpV_OtKsRsWNk2x>F|?%beGlIZ^j?xmw76t;k;Ymi8qF z0At_W{@rsVUnf!0`H$Q%-7rD%NE%!LW;g@duDxo$Z_qjKjC7?iGC=MC+arp(&H&u@ zTj)rq5}gTp!e=MKeAlxC z@3KE1No3_A#f58fop;|mI#SZ@1(AL=t+Z@i@es;BRl&O(H z^?3+|fSDF5KjiImwR_3zUjDPeW&e5KTF9zUc4tavqAZZr_7X+E(2sAK{{^+9x2C%E z@A}5DdKESv3cB30$CBs5mvry^NuPVr>VH4S>;BTsKKEVMY}wX@1k;@ekn57ofQ`s| z-udi&0*~9fom2l^eLE!0QMPg*mA}>{IJ){DStOrss{!hQo9%+TF%nn*)noAw>6Sas znLG)+XxfG*Uub^+;P>?Lgo|^@XFun{7wKO@7#3s?0K*~sx~ZDA-!FKdvA$PlLW=XC zX1W}4=4T%K$s+{&uIXfu+b@0GeNm0f6XdM%*$O2T_o}HXe#cpDb-LicY-?Dsw37JY z($=v2;QqjSPhp3p7)R;96PGo1EB}gR-Mw$0FJ(~Ko5*)IqC0*X?x9b1fz`h~aIR1; z-<5pPonp|nC%INSHbRP%!qTCQZ8C1zz6=yked4mtPH4lq3=L8bCZ@2ybKr*f^I~&q z(@==P9hz7r6E9w-v&db={-YTOo1M=yZE(j?WvUwQG&=wlRnFpeE|yKV!2GAp+6>o} zX%S^Qv@eKws@-nw9c}C_uj1V*hAhs@RK0@=J9eizbpF<_XYK&EO1b^Eugjtku8C1}Q zcEss#ZqvD^tq7dlhPyitwoD1Z?BsORUE+9-_2Tb)9Qyk6d{cR;? zOZO>#*PEvV0aZTITZyLA6rh3VzkHla@%O3SwjNm*Tr){2HLzhB# zqgh9u(*W;G3=F*^{F)ksA>kTe3mpA$s4t;)hkuA-v!-T)zAZvT@$=;i=}HxDJ?C8o zk?6eXZK!-UvW|3#tD(^F?Q2+>vrR(w@kek#zbLprO?J-8#>#i!zj5{#(upN2C5*@x zKHzdPgtL-44HpJQ+QRSQSEp_M_4CWyhc}My*|WF^s*-w8LG>wo!q;&HpYWlt;unfq%SG9OP>!-A)IwLQTo+ak{QTu`XY8f z!+)$t+<&0)#662*PnA>EYRrZ3e*FMdM!)$!gzVO7U=9jWYc~fa7@dyM>r1<{N8oCn zJ$D&)qy4A(`WN#>LBM(2eT=1@<>I?G4T9Cd4IO`#Gi?wF=5xMUs4KmR z?i4+>g)%6&(44HFg5&!eQc#?|tMdAYHgQ`^vaiaU`cu4oHIlYy604| zQ!v>yd*;-G#1H32Lk(O{Y~Ft;{^|1(yGYZ0@eLb)O<%b3@X+5Uu^(@M#JD*bcG=Up zKDDs8F9UkHPruxxRK-E9h=fB=IEmkG`es|*R z^WU?b_Y(em)YA$2x>_x_qDaGV_tQU%p=6VbNYlC7=+0*q3clJ-IavJl(!CcO^fLcF zFPd8|vHojMK>qiq%E&Sie99E-%%`Ji^)y=ie~AV^Sm=B62N;T>T!d|*38c>w6m;-S znrCWPVMt|3@+B)1M+40D`#U7qAu~?$(8IKzqicYd-u_qaVWTd8O}0{%Ep?4;YVa>&;Pgu5$odlg zpV#OT?|De|5Dl57Ivu54S8_X4&DXlRHy5yZwM!^q-pHV>O`$FNdpvGZbz_oN=DRWQ zio{+Gb+P)Ai7I%lxXQa{RLRp2*eEtIZ+Ib)U6cGr`9nU;`>YkaMScW9;ZT8=RP&|8 z6d=)sTjk01KP3HQpXwTrN?1r@j|R3*QehU+mGd=&uF^&+)!$!paHJoP@1X2+;3XPY zvm);pe`(j4?AMspwe)(`gfwK0*Y%t~$VwxPtk9k^e!U=bf97|45u=%V`3|0;hb1GT z873Foc{)K&#e$u8(JRU?}Z|gux*a#i^fQlI{!l;mhPWlGG%UM}sMl|%Q+*#tKJ2oPf|9^CqH!KqHRH+R6nxFrWfs&z=0 z-Qf1w&rmA;XV@T}RcvTVg2l?4TdWtTb+z4yjaQR(hN7Dg1x+fcJADiapkpRixTr%X zr;N;B6?_|KB`9$bpX%EL7Lsmyyb8w|2-x6(!kZqSX7QB2gS9UT1Kf?P zMMm3UhCkRvM|al>Hp=<^^Ag0CR0hrjb4+uXO;9xR`hLs-cs10FbE42-*l!O0__vLtmGk?xP~{?X|Z|RNW%cLz^z`EZxGkRL@rE z?aU@nU#g)o-5d8`zh*j-O?`SOdV6kzbIvOi92+swBv}}3aozOo@b>e~=)(E{BTcjM zL$6^v-e0KZQXEWcQCU(=B*Pt}dKwCKy@3OBuf09ztg2c$MWL~$x*W+BadL(3h|-FT znBrQsGE~@w{x)LPx%!x1tlx!GHe-os8^>vaDH*hW+@zv>DK<=G^VYu z%yE35)WOxu4&HR!&f#ZvG!Ly`5E@m|N|PgFvS{}MjM9@h8Gp%Wfa6!w>rmw?240Yv zede*Oui_A{UZB#o=4%g6^Gvcd84@@EtD8hsJA)i2{oPRZ++_2$uZeo&F~+(<4&yJ-dn(nVV^>Cc{h7S`e)w10&~Vvw-;W-S&i%x#dB zFCjs4r}Z2OAnM%gFRIc_!+J%t$M``krdtv3=;Bb zh;fIeG>fkQ`D!9x%hne#Y`;kn#-WvU0)o?KKc^%)ELPOJ+kox=E)Zdl?mz#VT(X5C z65`@IAjHeFXnj`{Z$9uuw6A1P-7vf=#e7OPU%DLQ%Fv4yn>{7|b4YoQm{P5`d-?$B zqx*WqoyR=<37szuY|9~;hZXI7xloh)tGx2DAs)e*StcL(*m(D22no5kMl?R=?>aMO z{QTZs$n5h6I~UhnePcg32h>eE{hLJ8LA`#ESD|s0A<`Cc4F^2i0t2-rLXPQUS|Yfe zqE#<8#3X{XQoRXTZ_TN+l-zfBUe6gP6^9}%XUM#MMS#9GNm<`?Z!%glVW zk1EB0(xdrG7M?qS)^6J;6VGL(!Xwh`PHEcYjzJ? zWjXJERwt;+5W__^GPDG21e>eV#ik6}vHscB4(FzR zI@GA?Oy7y^+_%##%UF)>U8Xg_h54m))dL3W?X~}WnH@Z)bH7rD+XWV@>)_E*^F9bs z@FidAvcH76nWVX%WMh>?P#@6AX9VYb%ss@9n>vU>&Hk!7{#j&Kl>5iv#hnrODn{>;X zhO|vJj--%YR5^tKR`KEA%KYB3M&F5-B1S@v?%s#c+-HA3!Z-7am025gN3~9ox?z#O z&Z*_qwgJF|xXJjWre)$#=oD&>-j=<@*qre}Nne{i3ATbdyCIdrD%5qZRskIgt@>JM zhU-z>{OLmJ&{iRhkj0D&F(zY@MKcD&IQiC)oy`LT+6AA>-vln}%~rD2n% zhcUhyT2mBz+Ta#9gu{IJY03DBFK($o$Kf^h(yUZoBeGe$;5ku^7u zS#Vbee)zDcJB>X2>3npAW&YQ&ph#jX*{{X7t5T+YY`Ob64di0J-JkqahnsN2cSH+p zXyabvF&U8qnExXijDflrW^Dy9T!+l~Dnlho9CMywP|Jc zERynCn0BMKNlja-tDi{u$p&FyP3;uH*(uPGt=!t_wWS1_OEt*13>;JuL7;A?rHREp z<^IQX^phzg)SW;Y-y{}9GwJpdGCgvscC$248zAO|Xw8(R^WMqIZmFw;8C@r{F5qZ_ zX+k4o^(pfEs5Ve4HO^}SooCg4;PjrB_78E-yuYviz;^xdP^F&j>)}N7*nGf>tasYY zM~qb)UuC=xvV?h4l8y*sPj88|;9tP@i3zPtK+fo{3h# zYP1pc1IrFe(b~;QfnN8kbYEFi>GKT(|4w736V*Nl9PTRik|PjLZt|nDlNRH9GY>G& z{y3@pUbX+cgQ&JJo1n^)HjpH4t}Eai`~ee4`Nn=!CbUak2fdX3z5Vvy0_n;M3(LS) za0N5>HMP5~Zdb3+vN9;`nYQLnP51BzJ(A_r&7nB6JV(w}hAT9(gX!RD5Q5@9ku)$*Z5+6S32G_{4V zlbKetO^?TW#W0?yCv7;8n)y&?op$OutF0LsyJMVtYFoiNu~9ljb?Cw0^XYA6!aaL$ zk7K&UnhU~ox@s?3CFkPBy0x$xsp_yaQ@Er$@Bi*wP?G?yKUN37!i%*sHWuQxc2bKj`4M#n*RoU56~B6_{#&Rz9ZjuyISgD9;eUyy{HPaj)q0nz_gk&|#jSrsxiMc@ zM$8~W4AEb{-X;ob&W9Q$)A}E-&NLpX_J90m_IjFBV+4@ zU7Ji5dT9k36ferlUY|b_$SBz8`Q8fY{sI}w6*HsmD^cpWv<+o62qDyh=vp2MzcjMF z{GvSbop_!dEB)10{ik9#icCz{$OA2?9|y^($z@S*u7yL6YeKEN9&Kjqh!LO%Youzy z%=+?*o0FGj%i|4T!W$isF^(wq{#v0)N@ge;g!Na2;psr^B=ukJ=fh$E;73z>H7uUW zg|;ULD84R(EY}{3Pc#D*iL8Ff}W^ zvIBkykft=rwhBxW(j_0$i0%YCTk4%SvO&-Tsk^EQ&Dvj9K9;QJvA?QA6=~p0s@8Ei zGqlEKea46@L@I$Mf@euAxYoM`g&XQs|NATM{m)D9=X9@iK}v2DnF8giFl0Tip_qlM z4kK;V@}vft*f;<}R#ieX(ehn2zF3LSkG1}#a#}R(cfdxS1Ha3Zt_R60G?^fZoir7i zK$Cf}uRvtp4eY|SuV?4F1|MPIhN7P^n9_|@{DWC(YeNKkR%!6O-5xY*XAgFBRyqO1 zuBeK~tXxfqxdyF=NK^48s!H2w*vT5!7a_hYWCTL6b`@`~F?VC2x4tmC;vR}8 zDge1l*)2ih0IceVdaO+p9K7YO1|WnCh32S>$0(OG5kQiw$1of7iP${=?<}tfTlE729Jr(bY zf@PN!0C)_+D_XK@EFYfy11ZR~8PNusKZKU3Ovo&T0D?@v?1LHwC8jJx7!d>#Mf@9d%f>LhK}s(yNp ze1OZIg9|ANRb4${7&~N(lw`v@Lh<14YC+Ru!KG9@3q;lOFjv);9U+jR(Ulu|GQAXn z|88v_Lm@;J3#ZAH9D``nxP5@Q;*=YYqOc_*L;qsjIwep5Y1m$leTReSOCyFuWkSFT zS5T~smfpuJbKp%6sfuS;+z)1QKg^Q9dr04%#dY(f;1C0B?Y(2ccQiT3sG3~e+&7P& z^)WGGgEjae4$*bSj&e--VvOCVX5<;(l{>u38r!j1)~eFGvg?00rI1B=O(a>~L_b4N z(FM72U5?TuH=F<&0~J51DuvK~iqiJ}%$i4Gq$)sJjHdjlOAhS`Gp$g5T$--HAobD| zK?qQxI=NAIRVkYbWK03IGqU2U@W3XsoBJR7(v4YVkY}L};}a~|QS9`w`!p{g`42jQ zcI)KV&DC}3K1Qb@UWEDG8iN4onCA=s2Dhof2QOPgw)4c1Sm3gajp|p&4-#9T zT2LPONMczs02GE=?e%h%{10n-W8!wivkIF$)0-t4kWHpon;*InXh2KP#he4J&EYxy2S3Do|0Lmey9IIc2L98_kCB&s zvYsQXzrz^f1-`e4FN3Zfu8mqxy6Dl3pk2sXJtHLiF+NN#w+6++&&S< z+Vw(xAVp*u({9V!I=~Y5at+Ir4vh+f$$t{`oCVHpn}zCZ3Sh3H{Jknmwq@{O-j2uU z@O)({b56eLOm=vI<(I+m3$}mJ5o~*+TYcIk5hg1~?*J)_qg1z{IsTAsd7Bv2>~xs?6Lh9K1AJI~z*qvh-`|JZ-gV~4Ba zOM5h$0%(@(In&02T8W5G7;TMJN3$~eeJVW1xdRp`=E!xpcC^5KC6AyTe_@wt$oKKc zhD5b%fnvsSOqJCL)r;4;f933VT(4pmdq#9RkZyku6!-PPZD)GQHtxU5M2;}lloO3( zePeI8ePVBQ1!xbpW)T|-JpRdqQ$}`MhOxgdBerRG*w=L|*{c!F9R*7wPkM*LU6~O2 zv9gu&i%u1)`Ub~%GKq{^=QNZbL^mp@VIv!TEH-Wt%{`w=aISAAmBZYZd|mOXQReow zip~#XZ6dd?6e4vzgFgq#7OI`=4a*eTV_tBJoV+AIk~N9H)EMce7pb#7M8!+E6Jw*A z{5*~E!0z7O07@NQ-$fATV*ZEkaKSoAKw%o5{{#ZcGw2!`sr9bI1+(bv>(vU2`C=bk zPTp{MVH0`fe5T3XB|cSrWrGRI&y>{ewrco9rDKlY_r;N9>cAnhP{IC^fzJK?pxBwk z`mHOb#j@+?&B6v_hb^@X8@gQNjSY_CPM;g+5jq;{utcOw1U_T{$e`K<9yopBWYcDLWw6V)5|#30jCsQBJSv=y^#Ja9U${Xayc~Tq_jMTF(9VM zYQ66TZH&J@+ZUVm`8Rqz2$H$=c8KyP$_dM(lkAN_$Y>l=Tz3&Gc7u9oFgZ(;In2u@*=$wauF{=hFV22?w zq>u_7;Ibsr8y;!9`{*kR;0Ch5xnxclLZu9DR4ag=ybPdzgdb=HD9p_*P3{?0J`dvs zf`xsmaOJ=kUy}AXhg7YG%)2tQa|@}Xy|YQrwUJN}o5wg+6t)|k@urOswM`nTxCLX1CSLJ1m{lyI}A##~XLmC8J3tWiWi}RG-j&2N(~v78mA6cSik3 z=4B-g&O$>P2TaFdy!5o=4YP?<3yrSKa26A@jPJ6X)?t?vM&&PdXt02wZm;i|#g9Y* z%2=mo%H;T=vZd+I*;Ke;i7H;{7h1M}Mr`&POKy|Q@%V8_CiK->T_QmX^2VURl0w6Q zjDEV@s*_f>;WiD%734d#-8l+}a9SPI0Wc1gzjj{pfaV>-KTJ0}2Z*E|nL83`mEYd{ zqxc{S6nn3ltx3zFye!ht%sTwy0*jOQr<1rB=43fqGYgfEC^G2C?djOm3Q~w$)Q=EM zw_y!$zZ_m7Ur@zrciwIpD?JGDjK^u;pu&x|fGp)QDm-pX4gbO8iq|fm^SYEU+_tz_ z!&V+M^i3{sX<{1gS+iTR@o+>Y+MfI?X=bD42mDe>hPkLwHeJ?HS?QrpRMIK21uh*ja}SM z2DJYflo0&DxxEO0Jk&cn_uEU$=jxkrT=QhBjbmmXPLyxEM^)NY)oRn@Samw0+1{@J@0 z45)s|GN`xMw^?$=+l%<~foLFo%kpuYToAu|muh>DQF8!-Imx{)!U`(I(m!xRt_NyN z`or_Pa+HjDM}35Yt!1kPiGk@)J0G*r{jg6AT(Gr@s9hd4+DLc$2=`g*Dne%L^jf|S zp^tPuOftAG76Lk4ICvCp$%p6=tfqEPcQKZJhxRwZ2~tL8=w0Jq4jcjDa-+0^puS~a zm20HNgZ)ovKtrE_mM=sBulvw4c6Ix2I40}fRpq_^q-HkzXzXf71_A~u#;Nm)U)u-l zh->V;)CG;59Z$WLV-?=sHnnP!ld@~w=~f?(OAhvS$r<&z7+mBLT9kf_q@GTC)2ZDU z%`2NS{NU%kP1o{k+vt_8f*M$ZgSdHPht#jvivRK$=*WqK3DYAWlGTRa&wMcX!mF7) z2$~N1?2@Wfma!Z{d``S|`r^UpADti5zNUVC_->21$-{-ZyeoWxGUa3tacD=qgVw|A zeZ}1Yu4_duIPUnKpZ6jjYnx0J&ZC|ruko^wlk5zhxe5o@@K@c~{G6_%N!<(I?6una zf07NJq`Y~p{0*Vj`H80T`|a-t4NVI-$uEymJ{xe*^9BtEtG1)G_>Hrj-aiA+DM?RW zqe>rnIJD@nm9}r+>7_}T|Gr|z;)NTwKR$RrTT#D|_7#2F{ZQuDVsY zFD}Fp_96}|60;0ald@{DD^$`DcZUi+nFtZXu7-+CG$K&e9v=KOhiLrz)T?^po+X$( z7x$fyJ!&jpEzYeOauW<5uMHn7bP%OzMp>STDofEndU+1 zZ!TMD*RvCj&8DZGv^xu8v(!(2kj4ts!7qt83o7Cp88diI>7^PZkWGyE085J3e`|nt z6c9onzT*^>BNaEom)e^RI0bo-PI%6R z;f?eAlJhA-yI%~V1v{tf9{dFbWlKGuAb?Bf6w15d-Zthc{>Z&7ldgU(McXy66s6X- zBz?dAocI zbcCssoE3zg1K0HLftmAx2nw--PuO2mDiAF@6D=~jT%ut=3lQd1ToBu1AA8poDYH2? z#-nr(AV9wo?h=Vvn)+SrA%M%0BR-BC&sFxZD6M8f&(INjEhuwc$TNNLXh)BW%W&Mi z-Q3OM8-vLcqQBAjGs`ld_TltM)x6aYi6RKxk2n%^HCJV>bazMj4v54hl*2m1y(tV# z6hRPwhQ7A9NvHz&%0^2(P-T3CE z`4TS=MXzxPZRD8buE;e$;e6bwuNi1b4AdiT3-qD}XL6PGSH+b8C~?*KR+Frnfz(AV z%$NN?sG&ETpjgN$6RT8i1R=X>x7{!9K3u7uTx?Qa^5Avt{bjII8WR1ASWHQ?6}??_ zm3KK5Z%_(CVguw*l)`FHLFp)lP$7U96s91Uy*#cBl?dCqBj07)>b6&O+cK zx+$AD!$<20AihGpVti>PQ2TB*MLeeV&T_3rVEUbjVojM6t?Z^<@{nO^-NKbTs|VsX zQ=Be;%Uv5{Dqw>P_M#nZ3sJIKOJ8hUIb6u2qStwDCz`6iwOsp2I`xTtsy|4rHFPP?i-*bW>M%l4-1_nMADH%yh0$aiumBNX1PR{sYfIk zv3Pas?jZ`o>*GJ$V{U0&YN~hu;$-W3aw>H$Rkq3|Z|aJVhNt4>+u+l{8459U4PnXU z9*|4A4rI{<2~cswfdtaFC1rE*^TG2X_$SpBs?Y*f>wl&Q`MdcM1ym8aP17 zS`pxV$fa!@V(3-eX*uXI20p@ECRok>GrVN(k7|Kwn&>N>fPmV$pq<+3DI@$0Vz%%?I-B1uO!!_L6R!&Q= zl75mAFY7m`G+BN*!w}}k)gTHP4wjVly!^#q*FFR#n>Tk2>opfbx<8z%6hP9y{A!Vs zJ>7MwdoiY4tqiP7dDMeR6=ZdX&nEmRj0=ppw?n(c-c4FWgRL=zWK+l+8cs)^RUVG- zsgjYQ4xgms)p`BR140W%AxOlhM-)~bo`qa=(E857CxNh&lAfE`vo<4rCU^}6YuWW_ zh`hs@9l0u3YW=L@pt(PMjwouR4);5>J`R|Bd{zW8iXF_#AI!;Dl^1BUYX>jjpZeE| zYT{UHK~iD<)1%B1wb$B}d*a7%LrMd&mui#>r7&X;0fvC^heNywZdDfN$Tf8i-NeV9 zEZP>%mNlIwwyI-m-3-;aevwsmSJ{r30YH&T{FhNwGd%q7r{Nd)e_vMJJ9ZoBr$m2c z*f`GpPkEOdU^&Wj`*+r;g^V~sMjl>}mH-HoeG2m-&p*78xU)y^xm40NI!wra#uS5` z1dn_c;P)D2Ku_V?#igH}BrOVIdF4;D@#HSJg9Q$z&aLI<1=-z<=UPgKuTX2J)!mMa2+ zAHDy;ZTLefX^s-5EatbuxNw)J(E#9$dutBg0ZOP^%K)aWScHi&-C$rM5@E0CTFs!m zw_qYz>}Dfn`W0ZU_MemnZ*=dhg2-8SK|kuzI^ioD*~llZ2u&DWh!;FuiH=OiQK?-u z$YnBOS9qi0%iW!~AF|1be}AJ6)WfutbPe`yUm+s{;_V7}_`-R@b7A#dgl|)l-R0wb ziG)*@K_1E}FemV8j|4mpgopA8?Ub#N`q!y=K5lZad12?XtV%fCqxN=%gRj5AfqT)lh7g%6ALAd@?pf5w|e|bN9Iwl4Ez#mp#xO$ z?+ntk8u05a*2bXmVTJQh4C;V5=V0Ny)y#ayLvcK%)Xxoyt@m|iR!x6~h-`=aE(%8<6z~$YQ#iVKG!`gSN5%-4oYx;2E%GZY^+jDWelKM1)Z@G+oe~Fk*U2 zPQQ7z*o4q;=Bn!U0shl9Jkl)BR%bjP;9gxx2+3_WnE1m#BzoQ^5IkS6c zQZM#PHWkPgjF06IrCzkXxn3yUwBw7lE_bKK?uoR;6G(jqfSoqrzu72(zXV<$Mal?K z!znf=S5=t#XEd_=@0PE>`=T~$YoK@gp)fPE=>wXMNDb70H#GDUbMYd{&@MGkh-Cn2AC@J!kS%H^->-Y@Gg`% zASCQn?X}>*O8%nlY0$GE-kNbV&q8?lIS@m4*XBT4_yjGO`17Ovskf#9^2bwhN%L_y zkmhqqQRmgx4|*uE*LJaFF?jOx4wr6dxFZn3+5K1D^=-Gz0>j;cCRy-0=q-_~0c?R3 zG?YhUVI-uDv)QU$86-K~kU)NoV}`iSKMNBt=UqgtoCO;DMi$&kbbKVyCi=J>GW15T zLUAp`!VPL>seKLCCy_9oaDxN+hb+O`XCE8EQ=Pf16-sy0;nh^PC?|h0c?N*KZ3>2T zW?fy+3$vY`vPUx(99h{Wf(=)<t*T_NpU?=4D z-3!h?OW-FyGSsl9w`^M;ypSsa5g>%bqJnH`2is0(o9Nm zQQDhGZj=NV^4%4>ap(*1?UWuSMcfsfmpwJI3PUN~Oc|(7JU8UpS->e-qY#X#ee%a* zCU3#WLiKA&zq^}!^Yim{ItGC!F+}c+RACKd3z;N@?34~9L+Uitv#I{l zUK6w|k|m#(g;1La%i8~J-Q-oIjgS|xFTM-Gi#VPpg;K00_@ja`2c@R=Dag*I2d2f% z!GO;F7dc{qfGP`TD=@Vttt{TNv$oshWrgjFqGpIWvrlBYIV@@)I33UM6gh;+ul)DV z=Zj9u5l5xrF=>KV(;41W03sdIHlBknYJ}`p&ea*nWVvX%!o+v93j)tbU2U}9g<2!} zg{DcT&@deFF1a=BJo%*%j){SU|8cINDv)RP}nhvzOi zE1#MwznU+VSdp4YKYZ)Y%B!9C->m*ydGc>caY>eFk+b2VUDgSnZIp`N{9Oe){xlL+^xLzg0Fjui4H2 z+y-L&-U;PL>>hS_GuzhRY_6Q7;s5!^ujPf!C$YkCBWJ1rxE2<{o^R`u!uJTViytzWSyxIFNf~kIo zmMz(U2J}J=RfERVq;F>T>8ID{Db3EwkPh}6REy=uD27YfjW}lxI~On(YMWZjoz1IR zxyikCGH*9sZ1xnY?f;~%@D%OjsI``p<{R;!?BrmPwRll+eT1fsI2lm=2}fW70NDQj zG<3g#|4&1=A?Tv?WZ@yyDp$i=Uar(5^Ix~2;XQfEa?ZTDM!zO!7t3>1=mbq?z{dSz z#a*X{XO-s1+=rj8&+@9Ns(i z_FE+e-iB_^zIEuPb9USu948$ydJ4h5xFe8xWctg5>it{qo`A3eQteVV88?%D%iG>4 zix2C{f%snb>}XwlR;Er$dQ=H}SyyT&C zSkup^0CUyvVA1!na#`I-<%)1M$qy9~&C7?f_xdz_s7~Fp9C=0LpIhSWn=IE%Wob1p z)$(pXjXLCE>)v?rgqHSlL)oF`<*QXmE6dk%#CiQXbVq7B6)hY8OjaHs+oRLsw&qrR z<)gS6Bo*ymX<~`Lyoq zs)E{K)U;&-4a+kY|4M_G?b?ID}(0aOs)v0tBRUyF@}IW?+Z(Df?A z1CUa{lh0f2_4$1Ly0%05u>1J0i}q3n{*3kCfO}p?9>Y*uyL4Ujzm4UKQ!%@mOYl5s z1l!?)`4o^3kcS5A3e3Lc-|p_x;6Mw^HhN)CiI#jm&St|?0tF?GZK++bUeI8|ELx)Y zJefiMdMiobKm20;M*ipg$u`H^8F0=-ILRVR1Ne9TJGzL5PW??t7B}l19YQI0LJFiU z66djyRO{y#jKmGNxzBhdFL#dfP&@x5ODK+JOMc5P`Y1l_>VV!B=HSz9I1>m(@3J_i z(A_3zw@2^zu~d@*Ke;jMV$){;W?8ZaX@exY!4?Sl9mOGACH+t6s`-gQrZe;8aJOIqstiQu;V0fTz%^irkhDN{Tc=>Nl836#)a` znvsq^wO2Ha>w&h45}CAL=HeoRCo(GEj=BmU^42hMdOPpu;AXdbP*EnX9d0vISfH)w z3DX9g^#|9^9b1B+cx>dpzlcn?R0pglZ&LOy3atJwAGnn5BJEDW#dp>zFK9!^bA`mc zu3dR7tN8(Vw>uMlP^sedfF;%xexyD_hQ?DLu+}o5)YmEZ$MOh+w;wqCLr?M=tq{Mr z+J54OgUUJJwdM!67bTe-Oj2Nmax8y~3;}3LKX}ttGor!-0FyPR9MlG+vyZVHD|wr!CE z`2e7&pIDxgsL0GVdDbna8q^vvo)D&?P2E`)e=g?6LDaTEN0a10J+ z{<}s_T;P55KO)6c?wyy$m^;(<23?m+b&z6?XX0ErG{wYuX+&IxE!rdFXgd_EH=%ni zhBf}`K@tVnj+8VA1a@sL&6BBv&L-&Fs7L@0F7tYoV+u_r194LC1fPw&vtWS+b!iW@ z2MB|FTf1QgDf1-;>>{5S`H4vuDYBY3<4B&4_GHZ^Cy`1Usnt14JOHq4gP4GCeFnL< zv8RhneY=xPzLRgDubNm>pxgUG3QteB_E$x_H44OcDlk-1sTtu*_R(Hp`p1kz8Z91u z@42)A_-aBBWEKb^W@qh?=D?!|=Z_$qsF;NK3nx><$o~|`2N|*w-WqH8f!3>pAZ5r0ECgKFw9xai4F4pLkBr)LWOB(cc z{Rg>pbW~=JtRw_&%`5edmk&eT8G7N$krHuG$5bYOo={EbeJJA~WwSh|ubxQ)siXe0 z#!Zt~_4gI?UgdWt1{hq1C=SWPZy3d+58A}|7{PZ@b&F209Tl}yV@4*t{7wQAE6^@i z$L*~{t-(g@_}7uH^jvmP{pHU|9??5ylt+#)>{mcGJe<-hN@BeE_bawb!De?l|3u?a zN?KOs8;=V56PX#6AN*;n>3_t!lpcTmB-?30e)l6r_W3IH<@;HYxVhIZboF>%r;F~^ zRPsQ;jKZt*KZ}aF?ME%~DrGyf7tN2A^gI1?{M*DsN13eehrbuE*E(R|QLZHO#UhV_ zS?^~cSxKG8BQ~0kJ^e7Y?^llY-{a*Uwce`lOzt)-*mk}0Kl^A)$%Y3T*9=n1blgro zj8t^G_HOXMPsuMzYE~RitlqWx3X=XrQqsQ7Zyt6@l8a{yzQ`@MjT2&u_a8X&;XPn|MW+-Gqhr8k`RWLRmSnR+cTUu0`$E_2W$?)l6U5d zOB&UH#1fn$jWVx^2Yn--c~S!cbf(P2>Ft|mRNkkp^GM4z!hzwgg$&F2pOkC>LsIivV1?xKnY^7MXnr6Xs^^&Ohno(81k5x`71^$V1Q! zl4+*P%5=XCBnt@kVAkv^YEGC+k}y1@ZQ#x!Wg0MN#URyGT)>uW=Ft=BI)m^6Do(~V z&52GbWE;+8WlNYCM2|vq&E<}^>w}xA)1#P+ODzAzv>yN_4M5M6Z4rZ#)9cbLrczF< zF!y>uOjLo`CM5&FEJ2t}-|lMzP)jPgu+&)eYwmy(&y!J> zNRh=39(NDx!-I#+n=sT(Bf?FijF388d>q0A(NB+92Qi6vibfcu4Gy8c$gs{CssOW0 zr@|(MXfG~s><~#*&=RHVzELpV#t4x<%#&dfSZA{R6(Qz5wz{Xp8}L1lf&tVaHPn&? zI$F)m%MRw=K_O_9p~K-Ay0E~5hj)?=@ua|u94sy#k3p)IF7rt16!az(GesdyQP6a% zy+ah~ITyQ3CC#wy^d^gTJ}tJzlvoN;A3?Jra$sg1#0bDSy~q1-k(!gl7KX#yYw#aJ z^JP9vhifIu;r=Ny^yT6zBtqBo*@psFD-|~XzxKXHC3xWn}p8@;@P zqC#S#sMW!Wq)r@*xoHbtpw(CF2yRqa5&}28+lAKai-1T{H5G(fDK;fVV?5*b$lTF~ za*(&oL;l2J`GX7=8!D1%wqUPE(V;KsSNCo4>1h;HB)5*3hwrDN&r@CTj8=9WI*SX{ z4BBaE>|o;9>Mk@-?jcZz)jrWT>miDrZ+xmrFBqE3em zQG)Gz9d0B#x=H%@V-fPKDpCHJ&c@795sr6p2ZPA&Kk;roPL4QbADs^1#xK=Mq3rAK4N`(nJ~Tv>7VP0W z=?EeaJhqD-l)#70ZSgR+l+bh8**D+2b_(Es0!Y``&d~V#Emp{^k8t|cb{Xve8DByN z#jE*FUdt#dRtlvFQbk$U=@CGaL!3KOxtR^a-g)$kjG1o54pKZR8!;UmyzG(3Z$BWz zHGn;E#6aca|LT$93%VMUFe)cUi30V}2$rFD7P4KGg^+8>?A`VF>0r`5h5ZN)vaW&Y zTkKXj=63T4Vx58!`M$2lkwmgno&mk`F7Y`Z!Rj?Q@DXlZ@u*1;+Twt+jB^M8@vr#A zNjiRC939h^*8=xwt%q7h-xrXPmcnji1HRq`coY{F+rC?s@A?90UFTz4M)K)GgqXSc z-z^#Uy1UQ@4cnNIQv;g=A$PYEGf?h0y ze-siC$H^*e;Gsx$2kszG4gI0w0Y7@Xq|4={&hR%xfk=31HE`k$uJuIEt4&(GLE2_3 zc8!BiV_%y1b%D_3mj)oTrLWbk$Fw*MG%2FiuR}EHq!vCz74&$}i&>^a83v>iaZgVl zA^fvF^Pxh`7r3_|eP;`mG?EYfQI<}y+7)e-W-||zivSs1>^QgU99yrI1$g^5s$h1^ zTKk;g6W!>D`)#K8{}4Mua#a|QP(S_E*Ui6DNk7P*R7KPm1?wLr-oMAZ@moLn%Dn9& zOCJx!C(se0bc7rId6@tT4qpnJrrqc%)fguinh?`PIO;0*>vuZ|-{|gs_fL8N;1N3d z1hjQ~a4ec&`wfz%hgjxXp3mzn+>1TPA)TNDTYg!vz4Ru>Q&8G@k8k)i!Iewo2OvPa zAwUecqs+;o1(UD;c6&RA&EAf(1fH1KU<@>UjS(z2Sc+;y$C3 zogWXgp{e+{acKJa{(XTSiCpHn&9dF>%avbqZ9y2~?afPtA_HtBsT5ecXk9tP7 zosF-imGk?uT|t_uGXtb^42YhTi+#!A2<@VA1474K3HENEmowBu>f!WUt;Ri|73{B~ z5G!yGPx1VHWd}a|EDhFoRB0Gs93^L5zkfEhJx7nA5i=OJKzOzPO15xs*f&IYDZ)O{ z|Kxx8;zfu9n;@q1q8`Na%n|A*U|0GqYx1AB)drLcd@dXvUd;=%rAl`nCO^6lXc!RY z0qQ&(aa4pB(+5ff&$6P>5?q4*-?^B`Vayf-`(B@~17x)TU6~+kb=P(o9@@-2O$4eG zt8y;r#jZT;zDb8byY|J}K3xCk6r#6xvl1aH9(OQG8s5H62$^s73#vW?ZHk;c;o3E(Tg8XkQMUeOHcH9_LRPWgJ6EfMi?0slf2(4{rMojCB**Dc%IZ z^HJGGgoN082M7pXGVv3(l~o5Z1M%;8O&2MMDj|YJ#jW#nr(VO}0eBXGp@GXT={_KYcs2t~#)={H1lhdvLS!0aGn|UtjVK!8 z2TloZEYgWY`X@ordpkaCii1CY78b`Lm9go8@?BaJX)!#~0|Ba;zkz4Kr*@FT4}9-L zVE%6HTmRYT_kfCKd^9p+;NO85m>+7?c9vJXyiTSoS(sTFTwIGIjSEw8JoJuvf<<#5 zP_x}BH=)H9EQ1ylh}>>u_GHey;85*bXgOy1q`=vN>^MtCb_! z!=moI1ShZFxt5Qy2#_~cWJbQIHq#$mdbED;E)2YS=JBff4|t~TiH(x+_>s5|v%Pr= zq!jgIjQ!Bc&O__G+#x~+`OYbfZ{rd~89y_1Fjh>NgDNGjG z9_Si2CanpE$&Tb%mPGcZGfAso0|I8m9bCU!^~zcTZoW0v^mubV%xsD@jI$M@rx!b`XTXfCL-OV%jxn2=bLjBcwt}eBi2?7d>yB9YAVpG+U3BSlfR6%(iOPv>Pq&GRHK-R z@W;O{92Q}*G)w>fXL+>kwg2l_CH^6+FV8k&-~}d%<)~tbPV4nnEiR+C!oc8BzWaqm zXY2UBC->y;)NM&tRwtDd&c{EyaIs=(TR}9+(j)!quLSr+vdd++B>L#bzT4I}Ohd(x za7BIpz(+~bVV5p{pB{b1f$y7{bd^%R_<7CK`&Id{=P;S>aM?gGV{>X*Zrk1W&m6J^ zFzG;HSC;2a)Pd2u%80P6FSHkL65!;CGg(U614?g^A#_b4%WG(;Ln#%aS{^7uI z{&71MbXVF=t5L*uzRi*<2Z9%Ee9guNA>m(`nyc??U9{~$&aJKVS1=W%idk1cA)mEB z<`t&Pc$d^Ye&*Qq8Fb`Q7a^uO!`$t_CN;39=@CE64t|iFY3_)9ACYD4sD>(b?a{=Z z&-P{=lx#5X>opO}vb=q8KB25v|Io{Ge(-SFKJ$K+9SoVOS=8aBmjus67Q~sKHRI?C zivxI=Gb3u^HgQ>a!OL^|KGn*^yE@xTkFc}+-axrrlzn1`B8$ROtP(;l)3YFpY-a-B zG2Jf0p-62we5~L-6aNQBRKZ3{z;p)P)kaEhu_CwMT7b+i*vo69yTtE>VYEdA{a$J_pzo)~bT@doax?tv$jz6SBS1)mfft;>#?X!5XDzGF&x5-Qa}C z>`2O7!cFQBj4=Nb&e=1*`vSiC>UBq#%Ho~lm|_OCis4jm9}#>u1>KFZ;`lp8TKZPJ zl8pcK$pf9bFI)OD6pNt4VzJ!3Xete617@1cK#2KQ$1wW}`>mr?k#mz{%>jKe{wH_& z7)4VMGjV+~JXMsEXbO2*&?|FeHCsuNBDtE)65mmQxEACLJ895w=@=$;^ZWR%v%9x> z{dcg690`@%qkSED(Gh#dk%>WwG*mlVK`>?HMC>dCM5-}>z~sBlAmV706V9o{)Dcbv z&)NPH4_)fHUF8B#UYbfL>p&X@(4jk38`!yNBLpjH#*F-UG&qy2^he@y+T)a9mjh;yU z6+d?@%IjD{U>A8m^GcM~Y{Dt?QyK-8IrDjQ;@3B`gAcA|jh=gq9*{j$zy*LCFX6yO z2K3C`xO11=`(#cA_E@BrFEX~41pj^G_U#D0%sPq>AD2ogbqP&aic)-|ij#ZBnCgSs zlQS;+)u`A2yNVye?Q|UW+N*Bh(g&2@Jw%nK?rBaeCy7{dE%pJ(($0I0MieP1?^p)XXVGLP1TxrpWnOp zeo>Sv6jq*X$%zoFq!!=v=#X0Lef&$m=3ir`>!KqB z8?qzDcQVBKZriQ5D?SG*CkD@azZE?dyEDn~&E%`^_uO_b#i#_o?W+k z1l4BEg;oD}JxP9hW8r?MOW?7s?cKowUkT0kYezqYy*8eG^Y=vl;i%YjtN7XaSKqp% zsz2o&3yzTrnCnNJ8Q;0~Yr1+zZNK58UhsNIDdnBO) z9{ZgtIQ-ReV*H<#8+DZ|LpJTrqOEA{Z@-)zI4$zToqYV`?boxYR8c2Xa<|NkFv}%% zPU=Z=zuC;{g)3I7U#+_$pAEkdcYMH6KlM|_EA+W>b!&c@YuodO6-O(sgmys)fn&v7 z0X=lRVtxCmsn;{#?+>JXIq~H5%#W>^A0l`8^SjvOCvZRELGT zm$4)Ui|f`{W?=Q!O?QYpkV(&W@N*RzI5`*&+={}h;yKual$cUkI0m;ve4jXtcE~6i#I+n$w2)pdOWl*kGAVbWf?m z+@qMX8X0>UA*HM0kD~ez+cS-+0I>|N=E`$M+hcIz*9@9r&9_>-YZ0nbN3wnqa53XG0s8Mmif ziL_PiR2Z3wbCvoJHuU>;K2Y+ca4HAM>%wW)zx z^uwxs;vAN$_G2QMiPVO=mqGV%U9tw<=-Qbk>`Q1Nh-CaL(lAJeNuI4rG z_#6oU&e;xhA=Ij~oLvu9V!#{)pu6_4du)%Mg@h?R15Sl2n?p<)83Z((xgeg9_*72^ zYRiE;)2S}PjP)2$gTvZ@52Q@z#4R*m$4M%N`vv4dpOY2Xuv=Sr^kuz zSPZ5eX1*OE!%cSw5Ps%8%3^>X6+!1@+VMdJG|PkXOmdT|*~l`H6?tKS6i=w1EHvd8 zJO1-0<)zc zB(lZ!ih*hrgc=(pQXHfa@U4^O{iMrq8CM^~AG#?o15w42XDIv_vw<@J=S|oy;V2HQ zmMizBQ{j~1Vx%j?x&2>}DNZjr-LxI96GtVJLDMC;D!SBo)rYkq<>kaW7Yo=mFtxZ$ z_us|HK&T@XE@}c4k6@__eRKl*^qyk9DG2i_NAr4?2X*j!DsuNH@m-rRd1|^UHC+b{ zm*~wG)Biuh-n*-*=KaInsU!hH2)!o|dhZbtlF*AZ5zz-VR3j>)A|j&h6d?3SQAE_x zq=<+Lh>AQ3O{57@L<9|ph=>Y`JXksT{?0mopBJ##%FdeEGjq@Vxvm{)7@RvDelNk} z@ye(!ZD2u>(?%Z)eLW?@B6sUQa?8QCM0lBYu<6 z2T*tW>F3g(L=7V1vahQ)g{6!G3v57H6Of`DB*ljt(II!#gY@2UHd7wMAI>`!Q>8;h z#-_UgRb>{@fGN!bE=R%4ikW1g6q2w*yH`%@Dkmi;P+asf31t~i`h#cL+5(tCRft{K zmFEMG(>K^AVW9IQi~0`cj(T}#p6R-G%zYfRGz0=BS+w9D8#*LlX^bSRZn_$l@92Fy@m|7^d#`r1ft6CUsu0*d<-v3fLXPIGL3*F zpGj$C%Eb{HM_{ z_oQsl4UlLYod3n9FnTVJj84n-o70)rm!XH+@LC9tEFHuXQVk8H+@i;%hYfW>Kkpij zIYmQS`GpGq>TT)qTi-?7=*-6ECpJ3r0+gG0%7hRBC;s@C=?qz2j%+d1j!^`sbMT(b z_0D}|<9L}Qm{rXs8P71KR{R~4RC;!}ZD^`2NlX;0G@n#>vlnRadO^XxRz$k*+A_KCFpDGroEV|r zWT*yjQZ~Sydp1&Z_42<`z8fyg;)ERHcOwepm7Rdz6#mjukBLR3nokU>8UXfSXNUYg zY2|Ty^5}9sWLa8Ht0({7kNKx3{!VFi# z1^P%&0pCgC9}r%NWi2~e71(1*ux z$ZH`{5N$ECPd+6|l{f9c47gnJD?b9%@^^#08{Cn5AgU|--~#)l0*EH0j+rdf{EyOb zQ-#iiat|sN=ONuY2QDuJG%pC_Ja5{C(^jR8Zzw|J*%v>*>G$LTZt$ZfBfw+M+32Tq z#I(sOAVJ~i1ATDr%b3!`cCFXvT|iv`q3zk;Ck?ry0AaRA{QW-d)4Iph7L)<{HeW+h z4L3k6eec^+$gE4Bcro**nh^%B3*kaZH`RHSIIwI3=X3xQvV*q8jV)tQn3ag*|3OS#DV}os2{FFEe7L)vM z^h7sIncyem;rOq)N8|4(B=s_i684_KIA z1MXD%XuYHAieL-T&+Thi-EcTD2^CCc;V8@tjyosDT+ALE93U4czQzRs@V@dWD>_W^ z@We$^IcI;iKET$bK;qs(Nur6M2@uu3xYPZ45DsF?VLMt584WM>#~+`TDVMrLc zKH&JO(W|!EkTrLIlm{Gu1q(*ijX=lj7@X&+ZA~F$?qQSF5&cQf&eLCYWk)~~yZzY3 zd(mud6vxo>sb3N-v}{GJb^{CmV-e?^q8yqxycxgw6we!Vu3?_qwRhq#Q(^Lrl^5t! zJOt+^1#Pg?y#UzwpbihPZ5&nXx@NaA>`Z|ueD85?eJ{fUl<6>Uo=Z@xxG4EnZ-sGm z4R%`FJu>)t-aFWqHMlbwlDX*~+zQjtI~Az^of6M+{Lm@ZGP&DXXkBH>QvA^jwmcWK zPh#^fEbHPE>SS8UV2E1DIAZ zaJSj~U(%e1mnICAnbMaMPc2;86siX;Zx~Or$A@R(4z_~+mfO=ZkFRRD= z^#hPpr^!Ca-|0-ZC7iYcxX$oNdRf;Z3JqWsv_s=(Su|-?MchU_wF?bLIg#54tFs3CBN#RcP`1tzcXzjaDf zV=C;5>g3=6F7)yqgf|U_vCAfz?AD%rRw+X~caF=Sdn!-Ta)4`mU5**LPEko~C9Td2F5G?DNPw!jp64zvcqN(5JhVH8 zJTfeTAAdLZq`>^Ph49Xf0N@vi2?|_*<-tq0KU{J8`}^mA-=3JB{B(HSP@)L@qmm?I zUXZqZbp(a=;In1D$;4EJJxRngmDpBdx<>K_kxR@ZYiH<|Bxz?F*0pM9nLgam&bI6$ z>*P3g6JWVpmRfc4w*B1D;ZZSLNEh5xPm}V!j2@5*wmbYF6$W~5(Jk7!r#3QYckBb* zOM8=l=oW8=XKvBE99?o+ujF9e1HCIp9{$iPJ=V8H|LV!9)B4wJlI=TCP8*`#KDrx? zY=3Ej=zW^W3Oy)Yip-Z(Mf`Ptj&=I2cj3D9@fIf50i_$LRXiM`>ii$srRMng!#a5m z_FHUaB`*$Ls?O48oHTBDu=LRQ_T#xJitMMh$Y+LuA0AQ+nwKfG+tOgT43W6uVA?$X zc@M^d=y}NW{>;xQK;?sL_|5yH&sVaod{Y9@9HMSto4sb*dd zx>5`_yD8Kweo%uleroL3!%g=xmG>`db6Z?5XW#9!k`2h{-``IX%$-bn zZ58{r>_CPbsoy4Hgl5aie*5znVO?2@7~rD%T^^rWwe4wG-V5s@AZN&3LRVJOglw0x ziWzC#J6*P@<1H;&q?aMLd_=t2nd8f*V#)I4GoN-GS&^Cp$b0;aZQ*}6E~;`?aM(@# zRxAjAvVw1FS$_^XG2UuSHU3W!#YrBc+CC7Zw%A>|n@ad!$DD)}Z}u)i%p!fe(PRI! z@mj?ipt2_v107q*JsCWx8IGF?3<9#l7_fayNvhBl0yeofQepldf$k#J_FR$+YU(GT zGe*rz^3;X`1cZfmS?=jpsKmEXFMNy8zI``M0&0=kPr8daXuwl19(M2T0a+KsLYFl{ zIw2(9?J7?Y|KVZIoN^5gkqnc2-RQn$4wR2<f>1^q2$~usk^-NFrmcINsPUAg%tJUQz#T-y1pjExQ2csqkfRQ>0Ad>36G~K-uKKi z^RCK$BJe>e^Wn&^+2_ol{aOJdp4WZL_TBmiwSP*8*0zbzOcmRkm6g@PMB0b&!7t&t zfs!_pvub7q6!YhS>2mxCbw5w;DUJX-lLII|1X0qv2;>ysO}_USs=b$rIUC@i zlZay?Rw(MI`ob3F@SJUh5d6hn^#4epO z+86=*_#zFiDeACZ$02s{*q9SzPfs9q3mol+&x&!xHe8T>e43_>7tkDhe^hr>hT}ul zo@$=~B+k&wZSuelmp#NB)g(b}Kv5lPsWm4~YLkU}9nfufTC5=45TNf44m6!!Cx&iOc?;SsC7Y$|YwAaJ0G= zOH#m6s{LmM^+q2vPL5%u*Loc&k^r$lxhhVFDY364*G0-4i|vhpc?r-_zX6G+P`7XH z0;#~RlLpw(FyiwYls9+mlpYK#epr%CpW=K~*;(xBm`Q~nOSoutSuDYp$BQ8PG0A5a zJC5E97`V(IEwV=M$3k~`#FI=qH|;)sJ{3LJzh3M9C_m={uo0gpZYGs7dtI-Xu;RGG z7ly$LQ?1n-1;|)H>A?!+(3bl=FG9ube^a3j;{~to{HQ!A_=FCsgk%_4m#OzYhFaB! z=bW0>mOQk3#yYh&ue?2%0VuO<#T~=f`Q{h&PNaz;6}fQiX}j5vRBYP_mWcT%|4cno zf?I+^)a`I`M>gUYWVe;`=&%70W|}F?C0gi6IfUjI6_zQYJsgsCZm{JTH)qR50Za!;|L*et!NoXZAnw8RH45n1AQ0%?_+iFslEC<&<{8oo8;J^?>#VJl|nI z3ICQ)hIe_dX7UdiS3lac^7nl7Zm&(bqU=CB7IWYd$9xkV87g&;rIq2D;c5%^N zGKBEa*FYx`C|;qtrxfftv(@01;~H&!YTxchN8XuQf0J0B`BGmw9sfx(up#l!6*1od zZZavv##PD5c!DaM-@+IkS*+&~qo>yYIg-C$5^&~rKIOBIn^!KU-9gNpxY2qbeh2>@ zd|6w;w+2Zp$ymDa;L7=D@zEAra590d0wY4>{k>lY_YK}}c-+E=4@Q*%<0^iaXkmkUk@0xS3)=f|$ zNBm4QN4aRZQnh}g(emJE zW2dBYk;6PodCkw5A*pzB8pz`mUG+J9PlU@r)#u*j}VT%nB8>(_&~ zx+T&?sQfJRA3aT>sI@Kok4(?f28y0YO_6(rVV{`xZEUh9RNe+e+OQnRzLtwDNiOJW z@_bv8%YGuDR_Wp(fSM!`B{DQ#8tz>y0&RLb9cyTk8`r0f?4CpuAn*>yUYNx+WDB2p zivY^4}{n2q&-{C)w7n%vgCqYth9jDhFEYV%_Aj z)du#`1XSg*#Sa>?4F)iJ44DP_vvV0OU91s=B9F-<^NEe~#M z3zS+;MK)G!T@t9yX)6D8y}3K}^$PC|FtpZtx$c&mm06^99dgBRzu#DR>LO7S<92%h zzH%$8DG9t~Q`%Oa8e)Rz6hrFmyffy)8|X4V>A}TbKdcyTeh@jLNWu)+oQev=CPiUQD?e@6prsE}k*( z4t4X;D{Eef{)W)#PM|lNL`QywN0@a5_yNj~rBECENX5;V$m9J7BElHnzRH^HZ7VQ~ zWkJ0N6TOsKw=(?f>;j`?A^c%X1im{WLhtri%+Wc$5Xz0CQ}dQV{fAVmqvvA$4fe*f zfW}^!sVB9ItdC=`)s?dju@(ZJ$9UMiiI0`)S#*;LfZ%^qv@P|HeO+is0x&j^(=CD& z#)0I8vg3;Hf^Ni=gjou_r)B^T{zZKdiHCK;|~GGS6^FmCWxZPSUPa_ zvpy&7UH76JO3;M?FcCj9TLfMEybVtHN$tm{gMJHHGw)B`l}u)7yF(3*O;n$4U(8ml z(foNJ(cR!koqkfxKxSh9x2HAS@bb$y zJqNFOA1r-Xo02S9(r3skKX`d!@#@^c)V~K$C`Mg0I}oQ=&8w>|{`>yYQmtPv7%)}K zU;l7zia|B16KvF0PU+Qj7*u2~<@g!Zv>0A;s*4Lc=wjpljgZOxSsR&Xv|sgVOJnTO zRPX{(Dg*no|#e8!&;8E_VocH`KD>#G|IQ$ znyia^OG6kpy$$j%GMK7|3aw&p_0>K|Gfq0LfBW-h&CTPa`manJ`hr7Sz_|^k$vlPo zlhfij+_Ie6Qb^M`kh!L6WTeu$wT+EaxR7NE>eoQ)L>@SdWY?67X{EHk`r(d_-pl1n zZ4O2rM(N;$al?>nHX;ZI7s_yfCmU$(=Z9fkyXu!Iegg07@Vr0j9`y-*Cn!)aX-u7? z$B^a`_y*ek7VD z48OxZiK(-5_te}iF;r0{$>n_uj8Zj>X~zAF?}oZYn!$zsA6)aBX)^|Jqp{nzHEbjK z!7tA{o&FB~y5{+|#}nB4Ie_vRr9Ok@gUDg1$qHafhRKyq*sKYpgFB75(@F-fWqms= zr}2z&7ZM4gY16Tv2j~qCVaT#}KTPogssjoN^QEv3jyo=PypU20bsXM1qZpl&1B61H zn`ju2x=k#|w%8QdkYRX7W=DnqBYL|vK{g=8FYi{j%(qU{X^QMvCy~@ukn>h_fr4MA zErfXcFQ>wIorYmxL{u>C2h)}Vk+T6Xix!YKceq{3&I2$zz2HT?eTFG8jg{S9si1Mv zF3Dl2VPResLbO_wj!Y7G*}BbI!Zo=UUFF5Y2eYeaq?tC$6D^rQh+6s2~{G z#d0#jfiDcgnRa=?WjB~ulYW2FKTG_t%9Q}j;)2pqy?D|kB!%Swz~l(C`=&vacc~JT z5$qz6Xh}6Vh1J}DFRd%o=ux%wJObhxX}l=F#P6d4P-_MilfZUt>*P1P(8f8XPd7dK zc7A=jmo|=)v~H=-`4MZ@`^_)--jtM_YUq?s(glT@!WI$KLLR_<6F(DqCa~u)D%H%V zShXe?)2g`FQ6<0xTzk&mR>Rg3Hs09)zntf$4R@0WPrIrb6yjp+w%>egHM! z!I3lOpeJBk*RIGU1B4V884+k7&++5#=_4u($0i{9iP?jr>WiKjB-rytEH;-dYEG$+8*hT@` zWD)MjPUcYH9J_nJAyzBmO+r^;4s&OkUG#V{(grXi&-vvGU|TG?NnZuXS|2QOcA1DbMWBzPR6w^XM<9V!J5L53|UW4zcpnaSUQN=wfXGk-g7C)(g}a zh4PbB!(Q+ZC%VJh)i^1(BP3_$j6$KQH4y1Fu z9M#4o^I*q!mntlFni3$Ii=7lp&^p*fl|eOJ+=S>?0ak4=(qVIdJ_S;FM6m{GUQL0) zE0oeh)Pt!C!>0ZO&?M?Jf5jKGW~w&{M0Bm$+-uG1Z1vgNazzaV6&ZJ7eY9*S1__;5 zhCqBhYKnU4NM<{CDbLm?;O6FJ#&> z*j50{lsm053Ys+D`_|x&c4T{(QI1tKTd%Fk{w-Q-VO#Z5UBhmty#=3q?t+q+JL?*7 zppSzmBq+&6r_EcY@S!8gAutJ0R2O1ad~vMK+ppMWQPM3n$Wq(gjv@KK&?o6gEmzQ85Ho7u{FVE$2d7beKY-_MmIKlJN5c*mFQ_WI($pk{m( zPXy_If=B`8RNF=}9}Rr;=v?&`Y9KW-e$xzkd!2iRbfz@5K~iO>A{lS~$S*GYciKDG zlknw0y~pQ#ZTy#e(gxecKYFO#xy&Vq-;*WV{ypx)@A14pS9YB}uI-7U8$COEGN5!R zwX&Yu`sZq#VV{xN%TBMSCF!F|snZAMf%BfPZ&p9jOP_hO4d^_3OEMTg4@aSOcdTk3VT~>+I(<2SIP$okit4Vdy-f1k>R zlq|@~36-*4zTY>ZfH*RbPG!R(fJHGc+=YXYp*fO|(Ot46bukGWytyupq~sp?E%{Mi z1^R(Ef*<5Z`&=>)k0AY6(Q$)#uU+nBcItpQV#tHcVOiI~a`bsjfSh^%$OY(mq=t84 z?9OUw7qGW^X_K8^j_R#H^Ca*3HZN5JD+4R6bVer0rjnQD)%BF8YST!U#p~o8`O@?C zW^*UImx+(scKo?zq+5@*v6a+=z{toa1vx>S2bWJAcy^td?*8(d_V#`;YFyRBPcnDZ z(`&x&J2Td+%6B_0XWJ{Ij@QL1f2T`qiBP!h^D$%jZjUEdzE5e74b#msa1W}g`EIEO zohTzNh4L>Xe>YEc3WFfoiNNHBnuJ6eqr3b;lau@dC^ZPXjN4q~%y+v*ER} zPBaAEta*=9=zs9;N@Cno8XFe_R$WcZd|KZ4!SjcEZa1pSh%=ju=R$OrYAdXcTCDbz z9G@EofXE4=B)BJpY}D|e;lyf#e89^aMFycFFN)0AR)ia%xL8$mto_Fg83SA^=bE5R zR@<02H=3>c^PKgd6<~O4?70v1(HFx%%W@2EWTip3ib2B_(d9jTxF`jT5|5y?m$MSC zk9Lm*AzQfw?MrdPy#zR9+TcL8o&AyTNIHY`O8h1Y_dKN+L8}b2T5xO6ZI4kofOm6;|$J<4x3Unb)4xYUazE zmFE6IUOfJ#ge5Yh=vXO_4$kiRm;M8hMs;y}U5LkLgIcpIf7XB>obd-x+aj(dZDRq0{HNC{63l z2=*kW>@^8hBdSJ;VgnuL|NNm4^ABb9U(v;tv)gg-A)}WMa+@iZm9|i8o zdmCf>3nF#O&h@%9337gUS_Vzej7S(d*L&}E5MQxNIrA=e>nLc}Ld#OxCv*6DDB|T> zAXm|(PS2C8X6Z54{ea0o>puMC7p9Y$upO;5@!+{5N=c=Y*pNl+E&nl~&yx@6(7cIb z$q}p!0WywNT}nV3Eo!>PE+y3c8ay;+=ymq5~+fd->fbu8G1sdeu1Nr2Qjei;G)FFX7M(+rwwNU~QMZdyuE3&#re z3yhI_d#D`ufw#Dc{8YPkF{%tz?)Dn0eK2V|T0UtHu$nf^aRL--`5r4YtloL?u zi+s1Akp+8kcE(Z;c=5tRY%o!7>kG+_HQ;JZdpy{GdHrO&PP z`3tdj`A7{{MVg3-SY|2t5d`uN!}Ah+du;&&F$J;=qc2ZE&wEN(sjm{@@qD%ahI>di zMlwH+H7I^t0&Q9@w5()kD2zv{dORQHWk%&CX1icD2+Y4FHmJ&c*UM6n ztkB+wi<|)%Fd=l?sV0&**4wGJe^_|(#tx0RYn2e`MK(GCyjQS+u!vIey$%=(P2``T z=3AdQngl8rY_Zb&t-E|4GQIgwCg4KoPR^hN>Lm`k!?NY)b`;u`(tACARA{ipOE6xZzaiHFew#^+knDGiiLd6Q7(EyQ z1NltNXUc#IIj?Zvix;v;JHhtEuLb7s?Ce52-3^yklD2%4+tbE=WUr>;quL0^?`(ht z*nRUDDvhzd{nAJxLknyL{Sm{&5kU+;Tu;MLfjSp)x?UADRT z@$y}-pK?1g;LARX_wI&mZhjlRx&Hn3FCDERKKQIH#Oh{I+ee=ZF*}+M>wf zrpD9I8sDF{W`EZsN=^#*A!)GqUMBim(@EyQpuy<$MWr((!ALDP|Gm31UQM+8_gG9g zj|3J1GWNtAQEY@qafGJOGNx_sRk8HBO&|Kam#x+XG?UvV8FY_sfMwQvp zA@tJ2_khThJJEuVfygJaLDR>FnQ#3>s?sFs1#*QaT$_LCt9tBm6zPE7f;oJQe9g`0Sp<)_l$H_+cYJ z#ZS7Z>>*PEmS`L zBF$!A^zVZ6X2H{z1E&_R{oSDhLU;r>jf;;A#Tx1_Aq!7T;{xCs3XaiGqHud78gW;9 zwWUlQ84k^zRpf)f245Y|g!zW6mdp_jcdOihps(@O!l>{N0J4*a5i4~<1hC%`>JRDA zWTNNhIq}z$smgAhL_kUtsjY$NxPEuB6lkst3yRQQZd0O$&H3$rrsGHJ zEnM2Do{9B(%UH~9eS|VWlf>MV($1cm69NP^u|aP+uE<-YOoCv>SYn>Jvnu~yAB8|D zQ;nb_f=L>&;p%rOJyKZ#xLKFGEO`MFTTD>u10gGXHO~A+v3kavuW7fkoIvT(W2!V! zBnCX-Q}eOwUBQZ+GsW(tjmDeGVv`OC+dd~8QIx`H?D|`<%wA7s(TZT@&I{M3Q6SG6^DdP(C{3Zb$a^xdyIu(V$w!*QY2D zR!PVW# z2f5l1gndY1%?Wmeh)r_G(#)u;e7?z9k%Kk`y17nKSzzLxM~RE>QVwOBr9@K))(nF3!NSfanr{!{`dF07TmqEJ=V=$iR~aHk7^XoS`BM#LC`Efsa>cd>9XwyNxn}gb%yBG;Bj8N$*mqI**r`dV=E04 zP%ReQYR9|_Ds5yFw!iax1H9e9S3!CS8kGdIwlZ1hSEF-t*!r^7IzXZ|2pcaL6g%5! z0K&1%|1m`WqXm&c`4(jUJ5Hb$4Ec~xP!nTTx&~FIgqpFlKGCxqe=j&w0m=348lVll z_?arSMlpc`Jf**RU8eR^0Ntomdfl|j5u9g)Yn>pX;suydB4%>cPf|zJ@CCnJ8@d9z zLKp8BKl`zHuKCDh)1D7;5S-{0hi`HO5jjUQpEo=^9Rtx897~*oYSV8n);OMYru`$7U3_fw}H|~P+oWW5dCZRB)`4;xpP{P4_h`4n(#Oye_V=Po$y}M8PS^0RQY-nKO*rAGqwHHYe^4jZwaubiB zO-C1oOHvG@rd<)aRD}*cCRgO(+i$x@s65FeD);9@FQRBZd+)xQ6sRpzH8(-3 z6h8{0UMAmXYG6G0oCfUeo%MNtKh1P*Yb>BhvIrToI2r%nT+E;$yj+$S4xXtVN!&G~ z`GV*K=ynRwAtJb0dj4=8agw0E^4Xw-tago@d13vaQ<77^39*o_7F;IPPEfMxH&z5P zq_yGu2-2$I+K1kI9^&6UOwNOdV1>9ZaeWxETuba%BQ@P;OiGv$9%e(0)!Y-mCH z!~S1|+c_UtyXXr~ys9x%j@!V~0QDviO#<;Pb{YiY<9xcB70Jbf*%Jru{PN}0N<==) z6M|sL2N0E-!Zpd^`fc}f#~`VeH`;zulADDQ^-CJ_e8n-U#%3jWv(B?XW_;+? z%Xleqca2*abUMO|KuOAW6Uh`4F~vX!Ab{aOnb+YO#c4;gD`JYnHTuF;ozO9NyM)DE zUUU9=l1g^Bs?Wp`C29mN-g0TqK{A&Ys0_5t5A)yqB8#)Jjha9VhOBCMT&%i8l{=0!nr0s?)N%9zW^q~-Qd3wAMF-5{)jktbUdhY(INe{{ zq#MRgCFd!Lu*GE>rQ$X0bMiC|Frz{ZZHgN@9eO?<$*pZP-NnBboNdTLnh`bXnOc3q zmPWjm+*E9Nqt=sh6*wq!(SsaMBs%TBzq{nu)U0?~;fK+1?j$$T(=6gu>@@v!Jq*{y zq#Yl-?{QjBeMjMCf}6GldDB*u(OX?8ZxQ|E!~@y6&aEl@OVyC!61#>c#`yAw{buIR z`OOWxTZ#zxDIjpM9IFfn&h(P{-lyYwX<5dPhnH)w+^3<`KGaD0Tjb*&2r>;Wysdj=>>DI_R)HEge2=&}0*EzmPSa4G4|h)f2>K8@0P z62#(31qUE(*$_ zOv9wdLBKbz;LD^?j+p^1#&(D%h=S@vO+TvH2mCN~x>I`E_{KxoBzpA{A7Vp?6;u6t zMlIt16JC5>Sx7HF#+Tio%J(f-2E|t0HA56a6v_osi5+rLR2(Py=2gLot#s+i-ea4p zBF;Ji!xbfZMKo^i7FD;LlhwsEq(i#MNkNp1sqny?R2iG^?alZ*u~m?EFn?UAQcibR zr>HMNly3+tb<|Xvglc4}x^EzqBGepX$~#a8s1ztp*lgqMI#uTTS*VHihoy=B0i*nn z%LCA}_pj47s9~jIm0a7bMpwA3i|fVy*%dzmZRp&SFyIEsH zmu#Q?KLM=>MGrr8`%8wBKyISUw@+K@a8R`;S`&N?Wyvo@bbh!I+v;I*0k6=Y&d)YwawQyDS_a1$LPRwnc}{A}R{`QKBXxvF zy43U_f9sjQQVvavBbAUtCaHBzOXFvBOsMOh_ijC~=lR|CoUQji&$RtI7bPsezcQ|> z8m27lc#^9Tn*KixUGmXu|5Saciu+^Ty*&Ns%;smMtx4%~Pp&xUIsG}Yw7lA)6uR%R z@IU_B{(tkFofFm_zdgTyUF+;MNX>pGQWK?oeq5tV3&5CpZVt1@OvUiY^-32H35<9A zfWsHDRE#3Y`8wpVnmr5gmvjY6WtOw1PcWZJ06`24HfF52{t^I_4s6< zn@(>qvlA-WwAksV%7}-=yM}6~qmK0a*nj?LpUOO?X(8iK!_to*74`V_rH_8BsQ?2M zUU{?^ixSP|;C5_N{on^}4IEOAi49=c7njCw(&~&kMm~pUmU-pK+bR`)TW35Y^l#tm zz|24LcwKks@%nL(_t%AbwUv=rvpd*r(9wJ8Sk&5aZ^hAz1*sG$MYX&#HW^m3X@v*ddNcGEOt7j%*?I#`9Z?^ws5sV1qs5_Pb z3f36k2~gDTG!>SkKqOHBW;(vE(MDV$BuRbsb8)oh%E1GmcgJyGAL{qt$0S+j+1wtq zYfoGnxQ=4=1eicj#=fSbo=+Y$Hg7$>0zqwqM`V)|$QQ~1trv?_$m2yQLUxBWF|q&R z=29H>=>5Ud@7qSM*qtFsJ?iko6QnlXMxdWeExX6I9D!Q5k?+V&5asw?jvp91yyXY> zVjUOkUj3|l-=p=cB(Kw>HPRm>6u8XP=nT6zKclsEpt1g?-56sVKJ~cj*+w5rzt-5T z0eP>X-DunzwfqRE_(D!M@9hX$&DER}K(S%v;A~ z^NMt^I~$puh5S64I83(i6{%k`40n%m!3S6r%u!k%di&~NJq-#@AJ-Eo_u(8#8*IBh zJOKivs!dtA8@37I7hJ`iZ=vZ9KP?obD*=U9A_-%0>T9dIj_>P6S9e8v_GH(M-Kv5P z`=(H-iqlWrtxYOas&t@=n_+@8+Oa@xJ;PgPg((LwXQC4LFteYYa3_jU4%cXl z$s{vNoLvw#5~RQ5+(M^Y+N`~g=XYN4I?%Y1?Sx`VoGbPqX@i>Q1CJM0j*UZ=!^=)F zT(;+#R2lC__jlHJ<(vQBZ*nxFKg@0+`r)$f;Ks@88!N{zb#grGS;2NXX#c|a$Q$O@ ze<&;Wy)Pb;@+bX))yx_mjW)V@V__IM7>~V?G&qg1_|<$nY9YJyRn*Hi*9Q-VWn~V` zOz*avgk`dsHvQFSs^4X+wB%k$0Pv7=)rC^;0 zC^Sw&B*QL9YAh2VkK>W5KLOC)LU>E2d4KSc2gA=gf*VeB8(&R!2yU-yIiK{{&`A;x zl_xMU_uOb$&C0G=dW6v#T)KRGBQk!N$)F!nw*ON%HVl=olIwo|vP5#~N<-ppU4+SD z7s0LNYruWg&CpaU7M&etzz#jXatnLoq;|8O&DH)jy`T@?zVjW;Nw?1$J6FH*zcSU_ z4wF3`E_r5BF?h((nvMjTAlXw~k&KwiBsaV@tt+Uhsp8#XuieIP9?|TR`m>DBb=K}L z`nrpNq64yB0Z8q_GD)$7NEh}uSZHv89Dm}B~pI`nM$=&7ZpI2<1 ze-CUKH#AQEGfH#imFICQ&pFo4TF&EA4K~1kbjj{!<--!k80!WD!B&6I$!ji1FFG*( z-bv3$pC^AoZq)>ZVvBQLoH|4TWk9o^4-e6+R4555x>r_J(Pf1ar+<}c=E@ri*}f`W zI@_AIRNWf|)fg~2d#(_lD{S}NpFCFCo+JN(cw;9aV5};x`KI$Xh~oH&1ldz`^JvbY zr|QHPZR=qa;Qx;%ZY19d`s!?L;BbLPI=VWjz=8Tzw#>C+XRcmtW_~#TIDtpd$ zr95C(6jmX&1)Tg@?lFK(O9?I-!Rw~#7bPF3>ax9M6t>Wm`FAVbvU%+-$3AZUy-==5 zWQGMC{2-kHT;3DW;YtP5CoY*Ao&o{LgMT+S0i=Nl6o(}VbV(8cE<@WO@Q}nc$bgKo zFAakw)1kgtW1PUlGT<=NSHTxW@3x8L02I{LaT*kj4m&O>?{r51CAC(9>DGbEjV`cv z&FN2U7zx8KC~!i#q`Z+I(MQE8+rrCo_iu=gydSrb2EE}4O_eZ$Qm$LmP^*!cAsmf` zIx4uk&-7EX<#t5_Ab@4Up&S#cjdsZ{FhQizBA=reYrvNbqseUhzzNJp8UQC|F-KG0 zs#*v{!{G*RDHqVz;ftUc>dlvh78C1P1FrBeyuae9%uSbPj`M|ptHZY%?Np>;!dq|1 zjf7-U{#~+oPrLRw8>F(SKb4g4|s~{1-qwCGE5WZ!x#OnQZs4T%+9_A1A(@HoT z=q9J{8t+1QxhUs>e%916Pcd)!y?v`$ff(;i%D$PZ*p3mT-&66wGibPNS755N&6h*# zFB#Rh?8;P2MeArN8bobjr3BiW-i|3Bk|pCd1H7u=I^AUhabpE@nLvH{Ko(+cZa`(c zp4Evi4Ze2~sft_8F*2|4@p3#iED3a7J-0#?In}S&EogL~@M*TbnDayGiccWcOgmV5 zD7jrxls2Nmp}5#JQ0{cB#^1j6`|E)Hm*3&&HQGA~SqplqQz~#_yFF*Q%(r@^nw_E1 zto)kQQh(@HrI~I7W;_5nzAUo?!GWBGeiP9J8@NvtnC7>QiVpkrc@C z>2*=SEwg19@!7iDzNAy6%5j_D-`Sd@Ibv?Jhb5{J9!>C7x2F9cw>hy1=4KQ$qE$?l zIWxRn!hzgjHXojs?CXL^3Xs?~e<3SVco<^10kvAD=7o`|grI~p$Bko>aDb@vl^(2> zxRQRjtwN()83xIuU{5c);OR69VXU{uz#<&RCq!{hpS9pJRM4W`0Z+jp_-$ZCZ0U? z?b^mbwbOr3H=mvR`RzI&y$G(m1pEc~{NIL)R0KO9)xgFAt}8{;F&fU?vsRvcx`v|a z5SSLbM$q~$>9)-wkR7pBY4DigA^CMA-%h@qsN3taX|+SpI#y{oSnK!S?x2ggYkbV! z+U@6KdBqNeH8v+d_+9E7OI}~Q5s*_CT!9&@71P8+kJN?S|Jhj`qi~aM%LqNXXZ#MW z=q6+Pp~r2p6D?^c3F;aj-Di?Rny0=uAj)qBE7iRyxp=aHo_h12{-s@Qs_Ts^pBVd# zrgmL-4{l)Xtq+v-dD)kr;0*3H3IDz{DeN1oztUYF?cp=kxu`(XQ5LRFdjoc*EO*kR z3^Y4F%W~6%0CmC~f~gYFS}AmASuzB>?(%pVADqwW4Wgs*Vd^NPX9LJ_P_TxP!3zP} zo;R#)8)0vd$P;lcV^DGJ;qXYJl&bQ868(aeVof3f8BRfm1*We#)f{;$2jVlC$Wh9T z2hgWxS%sIU-X63S|8{v(UN~E!(N2B_q*2ksX$gEHqQ{^cO9Lj5(?(&xATAHq?{N-? z(j+tqjOGS~SMM;cT|P=J%WD3=Xa+zo$!RND7)RzgS`h7wFT z&ViF1y0TJ)_A-QqNvm)b(cy@i-LIpg0<_=sIR6J0$z0ob(${8{as>nZGsNE1T4SW! zpddZW*@TLe=mipk2orPo8q2Q6cY)rGS+x|!oMEbkoa!DL8bhXH4^kof zz>jw^Xv^qsmiokP8%lzEgJvzPPu?%jq%pFl`-QO!Z8rBTb2 z#j*b7mJn#vUJV62yWZYfN14UOG5J7Z=;@OL1{;Ss#)=UxOEF`P<4*f`+-8-{ja99t zCT+i!D(QBjeC>7>s5KGw#|l9KY2RD8b%)4{^T@Vy<;as+vooQoc~%T(^2?<*!Sf$7 z;EpRT&}ii@Er%exXp6f6CoU9vE^cu2TURUV-kpe$*k{Y*S=mX$Bb|aNt<@p zdZ5A^E-T?E@M#+sRlGHn2w6t;H5=J_ z(^D;d^45;rJ$I8nbG4W70}EO&c(8zRt>=lkCi8SzUwR5k!iUHsD9G4)&JKn3G&_wq z1)OcJUxTI}y=)Q29g?zK9fkL>Ek{Vg!dGOF3#4nfBb zkaiGFKS)rn0^N6eGk-JAsJ9H+5qeU;73?}gc8Tap6G5et^RD*oDISW8*iLAI{ z$+O^sei;b`F2&SU+{ta#VD6Cv}(kD-4-< ziN+Teaz7obq-3B29BHdZFA0m?MMqxGufoo+EdPa_r+of}oh#*z*4GyZCV-QC+#w1= zX*;)D7iZ;L>MGvtD6lu;gH1DwC+N72YFsA;QNg0(n57Pz;20J>hr8#52r9B#3$2lP z-vPfOlD&XWeJeys`!2>z_y-{$n{Rz%`H1`kJPpv_i9ETgJJV%bL_i)Anaf0&68C(% z4Csp>>+vvTUiQhWM!$rp_;KVgE6sp~>BhsxiC8x;$UO#fhuwjT3%YkzQoir`4Lk$7 zO+?%dsw16jkwvz*e^{_K+D2m;(=9QcS)srVwxhek@#JXpZ8M~!W(mWS( zSAy9!51-73TodXzN>OM5Y)4KKn4QHH?tckLSyiCn8|;e!7A!Hn7IR>nZ#lPYGWDiX z)lp^_A4|6a*V1vDh(UUQ%oC}COLkb*o&|>9tQ0x%cB%GEaJTp3I+#f+h5_B@NGG}^ z-4W1xuweSI=CrODa3SI zjJ+lX?C`QJ%v}!~_W#@fegq)1X5c;-bg^{sTXAjsquur*OBmCoM4;OkZ7QwCj+LQD zgeTW$rKheCfg5Bjom><8SXruW`&`xC^$MvxqjPGBypUJ6P7pz*yG)A`b9^2gV#h=paAp_0j)i2vPtwG0WB6*MN5n2 z7mW%s-wAPHc7*FMQGX9zcJ_`-X=psauwSUN$1zjbe&8lLR(eJ?Zha9Uw28qNCD{=o z)E#vs@DF@wm_W7>NfI+NEzs>>)WF)3^p_{>5ADw!MCIrMZJS1d{)&e05WsCI4G(KN zwE)Zihk{H+WeV6Utb-RSmkh@!~ksdCI{uiecHDcu~tAc-3(6 z)JhuI2(61?3j@A@J{ZH^kZr#D)?hdOD?(EivPav9l2cn#C^@xTEOYm8P}MvuneI@iM)-t0*+ZT};R9k*wWJhFGFuzO?p- zyRC=B*j(a`(3#5TXx+2AF!#r%H`{Ddnc#yjKm_TyS%@Q6vpg?!(ywEsF7(+@+@QpA zvHe-sHb+ZcXuXk+yX7~2zOs?J&^I^39GH4~_yKo}?t!-#4nOJF zBG;dJtbB@vN!%6d6wO$6V1urn{U6lsnw** zo!3Vb(V=}vNS86IH0H7Y#fylPrtdcBiC#6~ zZx&UUJ#kM?KZG*3f;+IrLglMK&;>z1(@bZjc6jEK1u!h1pS;@JR%hQLqz|awfdKcmJ}&B>gtm7 zR*C2p3OGM+)reNu2*&Y{cs;7##{b8NPM&n(OQ5i$2(x5sDQ_+{qSK%aZa;6luSOpv zmy`biqM5}f{s%;}w%Seq9}w;G#)Z0l-3yoJq7i5$dYdp&OA16gzH*WR(eLgHHwhjU z7{^P2XuC3Z5**m~7_mzXS8$byU9j1q3~~`*&91?vMs(oO6#3L4H|E@k@P!=!|H(qC zfRE_5>^?ps+r^N7b_ejHOo1)`__i)TEc~g~oQ)KRzV#;OHxB)rPls1%II6(L;q6`z z@OzzvK%1fLcRJR%9VjHHK3@^%1xlKY9LQt-EzvZY=OWop3)uCw&~dyEop&fCUG{j9 zuI!^q7gLizoVP-P<&4G=B)l;}M0Opx)rp5C3EI`ZgvrR@l z_Frv6(4nX9?(^3Lor;y^_Gs+|aKM|pCSO4KkgJj#xMw2S;zy)IP#;d{RvBrrS7KS{-WT5Sm3(3!*xrB`Q;y;^gtqycq>jVq@Rai$e?dxjBNk@ijN=uVCh;W`c*|; zr3f%b(iX0oqm@=<^3{Y}mjt-al#{&8a-R=C)PxI+445$)J15k_zBW4?-0+=_`*sl> zxjbob^5eU$*@Ygm#btWsL!{iM`yTj(CA=($`PwMX@oued`gdJ`Wun91va`m)dEL_3 zfc5q@j&Xn7Y##}LOepIxU9ZPFhL(Qcewf?X4jN;O_nugHZNUE>HsAngz+?v1*AUQK zYdJoteCM*iS@kW|n5CguN4t!G2Ll1;?%@l`xZK%Fy4m-^oF#Ct@>JRPq-Na%QA_wV zlZ=(`RV)1$&n`hamM)$3tlZ^zbQc~HvosaE4f3MWbmr$fO~$1)_?{L2*9yxzLa=Yg zx|UI8=`SkB6}u1Gz}7!*SUwolJ-`0f;o!f9F8eD3=x)jMs7%|%Poe?YKMS_~$Z}&8 zT>5_TlBF6x830iv6b=llNWPH498bG zZcwv71V95vQKF-o5K43T=UIW8-*A?9P=$%sVdda&mo2tv--HtC*DIeljhkxOVu&HU zfS{FJR}M5EIv5N&qS^6DS8yZ7`y;nid3rBW)SrzuW#V(IQZv84zOR`i7Cp_yzff)1 zDrBhJ0Z{C~X796F4R8YRi^I~^PCW1fn4hrA+{QTg3-aem^F5uvG}Qb>K>qblZaE5} z^`aV?%f-Dgd1$Z8%cVarxgqY%6w{U`A@{F9UptBWQESzN{ea!rr~cgV1Nd800SDI8 zhKObBb!4%9gqs@K!6kk8+zS3JUD@ROo|x=_v;nP>NVyTCpyc5JLd?(4mZYZ3t*wT2 z0f|GL9))(Zznb-|*72HagNMwD_38tTCWg|z42Gb)*V%q`Zd*rq`Tpw_$Lo_{16QmT zKd-DSmwOhx?witdwpP}1Nm3-n}TWtD*W$TV_*tC1kgAH4E?MzlY;D z1#Nov?V*e8m#N!KH;souk)xhhH;3GBd9ZQsu7g(}GIlKj*CT7GIz0W3RwxQoCceO@ zh|cxr%cwEEPAgY6XjZ$)^HvoD>q-Ka`;DHLZOZ*YLG#E+pCu?18m~r_f({E zR=6qYZ=|`z$Ll@uv;jsnBrWCRm(5!@pLd94-u8O%jJWN2$%pbCDNY~Kp6ygf5T$#) zcs_2CZ-@rdRN)2S09Ee=+r@myb%KQoyCkjf&?|zW3gE6qJuux12_8CeU0iZ-@X5~O z4^KRKe@bSXe45%kTDkv_u>@M=Fvzr7Y^Y&vInSnXwHU3hG?`%S>Mx_3 z{CKU1f%=YD;>>i_50jqzwv0``=xO_t`Yz|xo=+_&e>{6^{A82bO>3WC^^HA%H%?P+ zUPm*qNBF8l6NT_});$Lm#huGM@wH6mBcpIn9vC$rqyBc_f+-_v7pKAGSy$)<*IjY= zm38J5TFq16%b)BaLZ@$g*jTYK#!rJFP4zOy8-iuaO|1OD_Qfr%7%?W^|GZ_<3=nkoQ_AjAB7 z_(yJQijfEaZ17VIPobN~)?Sa{y?1xq_u+m)@HqbX%#yyFR+6ut|Jfscu|2j9qw8`e zYjj^s4V`-Aw;^|IvrbUDx7P>DKo#)Ik>NPs$ov4`!;4i~7cP(ZJIV!>XsByZA9|ZP zp6BJNR=8sBYrVva6n=&egiDODnbJY*gyh^yynvVPyQB$~bzVwu5i92=)j7%^0x1wV+HW+a0G%q-ML4@p61dRo#ye`}MJRo|fHcacDu3GkGLb*oQoq{4dnP-VP8T#lx?7_#g zditZjuV4C=btstMq824Yu4>|w=j{f!2kz+#sal%6;08;gXFG;gwB9aj)=LUL-W7Tt z{D!-en-o}mJqO2M19qzzZP!cun@H*JIM2zO6+X+80vIpGH3k+^F^N5^pwjk)^G zFC8DY`4Otq2X|~8d>iCT6Q*Rrk{LHg9&YII6Xtrp55=lkQFgYKWdKtdnXxv_C_U^P^4ytr{Ceao+lSZgW$#R{bK3Hjb^$Wk`W~#y1UK;Y!D=E9 zdLe(}o#TbBsN*1#QcU1LqZDW^#{{ne%_^Q3-fY>G_7Bi}5)PUHD~UANK#2&LS_PUV zQlJ_3%o6~Gi?^^nGWtS|0c{EhCH+35lS3fy#_ZlwY6gHH@whORac2kei<^jZesX$3 zmVO?w2j|`Gv(er5Iynxhd23e00FfUpo!WyHz35TU3QG5!Dzg~b z$M&a3*~dQG@+me84<)ihgv1Nmk3E%`?Qn23+uM4`U;GD7;~JbT7|;up$j@fZU>jk; zFC$O^9j~Ui-JZJNfP!>d%(#E_majVAGF#`DWJG2?N`0A}uWj@a=Tn~Gb%K=;LqCBs>^#oHc|$1Tv}!9Zf0Z35~=*#^a8a5tQ&w=?zTyGLOwD*6MoLsuUxeef3^%D)OGg5k1cSOmCuQJIG72oHQS>p z;X$gG1!Q>#7#LP?@)rzfSFw02ILf<+^%?!n4}aM=5_ORNK7HCopSew^Dxp~7j@B60*%75g>q!~=7Dto79rGX9dwvG_fP|W zDEJJo%EbOC1{`gd?!e(9DAN`7%iQs&9 zptJTCnANHQU^3WPrB}u(86a$sO1~NO1a>_GDP@HFt}gJD=gLJoM!O%p`1licfC%1N ze2vbkiX6*anL&RWNJko3^4{&GK(R(({qvLpUTN+dfzhDaPfd`lHDx(Oa*=?SUh%!} zg@2uN{eI(8x))weVQc+WYGNQvQwSnx)bn0Bf#8%~deCILJ6Hw8l^3$H>Ii5-NZx+5 zBgg2swJaukFF=-lTgxkFy39=fwU)ES0cREKRcpE2Fb=(HEywKm&sxSKkeytr>3`O; zxV@F(6bis1mLb?qHl>qy-Jh)-!to2|5`;I0G5&$gV&9=uM-aFQ+g@nbN_J5(EoAEqITs@H~RdL z^)lk%F9k#h{5${p4erUtn_*I zG{^K^hc$z}QayN7J?}bCJJ`D8kUOI8%x`g--lf_J)Hs1Pj3|IqT*hDfEiOxmBc7Z9 zG@vf}*=xtcgRF>L^fDkFNU9;A>KUzF`#qWNu5=X+B9C>@1AL{T^&k&KsJ|xti%1~b zBpl?L2oXnGudJB|z5Ej(%(Gv6Ea#+~<{3l(Lzh{G>-7e)2=-xP zw^ej`9*vzIQth;iXddkz@Kl-}<(2w!mH}|NjYj7MotKcf=9@gd-{P{+@UIw_`uwHA zr+&NzmK~8x{}UKbXLIVW2McU3(YawN>~M_x8WCuvr!bJd4ASV7>M^!!hS}IB+%YsxRYj|5J3-lUX|9Ifcc1p6lL_{}YoeOI~V@Y{s> zjxy)T4~6-+o19}wU59&V%OGBVGDL05(dxPWtkYDwC}h5gEro!o6W!hqfGr0gZs|AG z1VOo-!Cb^x=fH#QrT}T4ry4#k{HaV)DcW%g%mr?{Er68P*~^KiGC6LxDqsu%QwuAg zBytyb%Yr(gPNLEDEe{FvVLh>VvVwp(J;Xrh7%y*wlFF6Y3Kqo&^!MY|vlC-cl^iz} z3$_Y}qH<|81aco@*I^2Cg0fZ|T0pjn5A9m6b(pbMz2!WS)LSn3%kmw@Mpn|}rtfV! z&$~|wUFDXiFDVS#E+csq=6#bIWUA6rQU_WUm&>iyrmsQ8!+82=NBT|K@LPq`QoLqr zC6((%X5V@b)wTC-d8{P+nd%|pav!w+IqdGr3sy?7e`S!0R#%-~BDrPmtk!`gO+gQje}LI^X`1(>x+-Zjk^)(3L` z0hqJqzuobm z+5TI127-SJ%+LatJSn2AV3ycm3iABLRm+>7@p!Hs&PKOffObL`{ed$E*>2%%ybplm z^^l|nGjrf$!BN}#UN;I`yYQ-;%9_(TAX@>CM#^@|V;SrKpE+vhwtRiZXvdlXUsogR zparh{@b*l1X-6ZNXB!`jgL*IIdp9Knhq-%{vk41s{{xt*W3&3?cx16RAeL11Z`}yYPULT)c!3{`0TD#qkHS27-wyL(5q$EpBLLm7I_J_c{Tw_w#yJO z17hYQBB{vUI&!U(1iaTAvHBBG;J$d|L;*Kz$2F*&cL3xnNF2=` z-pyIq$z!C<^x@=4#>+q4KBV1rBXWEU5s&7duQ8k^Z_DF4u%E_Q;8*4m`)?$JKYbln z-}hxS>&v2ml6D;2d_3d&0HNw(K*FmQ|=MXcGM_Spbz9MVJx)E)pDR zl7bo%uI|Ik)U;VHcOSm^}&At@1<^C@vd+bb5(W*RIiw~c_C&8mvrZX!&9JTk| zY`nJpg5nYY`av4|dFX!%3IHRm{!6YNS`1q-N#0XB7wL`6`X4_=-u?*5+FNoh&8KmI&CzVFg& zCE>kNk((){muM*Wb7#W-`h<)DyT2y9k7*xLPYC)+iuj&&vh*GDLfppMN#z6Lhk}){ zVw3TG`S&sqs?QA3^)CXD-jR{Y80P%2k!(=S90WvE(EgYORbv z!Ve7uWn?qh_nS_X4;`FKkUuy9vz~u(^9vsI4m-3)@xAb<qGTAN4R|jkozx8V#{}Q=MnDW68`z?OvJX51_AZGuGvDLmT?C-qGYVCgxy1?NsB+ab!`Y ziTo{iP)oRf7QJNdNGDap#o)e-*{uS>&fGrDKX=F9t8CoZzVk!GmDqf&(jqnfQsr6) zT{W=cGj$4AVUD z;+>fDhlbA(zrKP7937?MLDEUq^5=F#-~KIkT81cuSwU-syJxa|@xk|hz2eIl15%aW*0^r>4Bm*%lnu@epQzoe=?aT<>I*{|b09JlB0l|F!z| zXvNFr`ho9lOEcyU8ikOCforh=8fNy=Ed=5}f;BAG%4Op{w%l>x&K~`@wQLzP;llad zencsyB1umy1%5NuSWUfr`J$b`e~h&mETqx~{H<5!-aG<;;3g;huvRl~PM6$7IhnP} zZO8Y)lqF1Xow+X)vqr*Jq(QKY=k7Q?4hO>^l*te{QfH2X4&NmA5D)g`lVq)i^{!IZ zv=n~5V|S2}dVK3};%5+msQ-M|@z*1HuTZe`@`rpavHzswHyu{4{o-&ts!6&Pd+*S% z3=%Y4n_P`^`RpSH0&0Pf0>`hN9PXtRbN$wJN6aItxxjfn_#2b)bbp+|V~MQ{3NRDp z*e&u&!zlBs9^j(%&rbN_KWJE$Ll0}KARP>I!5pO{;T(|> zA@_Zx$ZLe4)%G4Jt$^OB4H-h#7tRi(JwWx+&LRqdBNlWaHr}0JQaXxxES7^gxJ8vwtfR}OCsr$OHg*~6`GpO0)X2y>`ox3s6SJI61vZ!M1!#)tn`wjD!w{~k4n#< z$We%_JD1`^!kCGx<@N9&8Am(^d+vBkx$w;E%V5;`KS@N$cE{hUH3L7RHp8}Kxuegh zB0%`{MP?K~wWj$gXOX@|qz5aa|H-&k5240FKNtASSyioZu2?-b-=j!7F4%V^p!1I0 zmU$T+A0Z1}C;mIugn94EUDEOfK|6!%PXAThYIatQ`erlcPjQ2 zcsqsG5MbnOafyZ55k9MVb+|8V8hZWi8%U&FzC4h_z&eswq6}J5o0%0a3d)MOo1OJR z$lwQDjf@&im9-M(>&z!I;{HD-S#5GmK_K60)Q7-^=8p}7FkA?1+oiBvI>h3Q|uz|g9t|Y)wWTu zuQD<=rkX3AYdUq$xK;Kx{a#%1pnq+;TETdU2LDuF^Qh-W+S<1w~D z#ewk`>(Gxg6#m=RtFC`r5}!mL`wzRO&w!9*QiMYOoZk8b-)G3T;j?dRuQ>t)x4hZ< zt$s;sPMr3Wsf%@e=I_g^Kh4@w%RxRM^4|G5on7Kk!1wGU5$VcO?3(C=&zDE!EMPi* zUen8bw(BsO2G%{$kK3^a>}+!l6*~aHuQ7AbK2~ZY3-!$pYTFEk6fLywkZ@-%`s_)k z;w&@Vl?UyW5FR3A9IuI3YrBWKb3o_O*YRqa1LZAmLcvH=4459t!Lal6~;tu$mCfC z*J-f5pKAPv#x%^c5AwRh>vOCobu!G6yS|#GhS4w}H9iZh@t6=MMZJ|1`4BbH3~~p) z8gqhd0EkD%SR+u(qj`6QpJI181(xgk3~CiyP!yS`LvI1lDjhEhj1V;CUw87)dI(`p z*_PukPA6Q;S~%*ppdsz6{}Ir!qsV5cM$ukOX^Ygsc2u$={1Uo|6;;uXbpNcgaws{n zh6wV>BcW)C52m%V6iaI&U%C#g-^p(Ne&f@#BUe7Zv!9a;x@631&hViMY67-begE1) zaklh8vZ3`^zxs9$Kz(Jr1Q#x5NAbX-pC(xF>#4;;^6VZp%7_cGxEVDicUHgJ@ZC)%083YK_u z5`DUesBqSbTA~9~v4n*;IlE5s0CTJ`KtMzpD8-&*;g3{r*#e7}vB>$&Q?nj@ z81VENYa#0DZ>ZMasvBrcA*|}tphytgc9=?t*4>p&`A3|d*2sqoDAFhc+F955uCDpi zO!1~-*=8Wpa|Bl_Fh|LSSBQ|!B6On{d2glJ-_=$Yq|?^O)8yOp3mcM`!-c?+wa-0l zvW6@8gS*OQj+JNoC6m?`k&MqHcLmhg7S#BjtFdm2*%3Rtw{zCPi)4pd$+zqAiV~3= zK9Y#%c=M4Y=hHc^eYb3G4#uA*?z0qsPQC3ZRiw~ivPtzjLAH)1^|r&NO_3Q zd&=emP;?>i1T)Z@E={)aaPuq_l?G|0qZ{bE54}eH5Pf29h)s{PmbEti}tn2to=c#(ye4JUZ5kQ@3|6p8Cb0aBB7l_`*T6@YG{$mtl}h z16Q9&NeJNFGjdwM3 z3K?vhvULzWw&NoEW`?`*a)2?#6H&%8OWbC@Ksi(mm>l3LP{7}OEI#Ofo=+fY=jpdw zZq+w_obwx>-=wRGN(9VBU|BI|E&ic%fV=EdicK@^@Ih*gX0M(Gcg`c&McPS~P)S0T zW;Ca=nF3|8J~E8{=SaIL-glm-$tpqL79QEAGGI&ycDBz|T#$0xfXXC9#~OeHaMu!7 zdgb-X5zVZ>Z}g9KC!U<1q}ILr*OB&s1!o#K&xFan2NypNS}O;=Vh=b}^uau`;ZXdq z<^L$@JX4Pjqjg=ed_mIX^>dBqlW&jA?)n098{;nZ1|brGn&W+TVzxF21e6~)4G3Aq zr7su68b7TzJ1&y}Kp!!R8sG@$fU@lr%Sp~nA}Wx&)r0+RNIJq&^w4_{c0n%}2&XzH zu3IIh=eIfv*jt!}i4@c-F-`GY$6=j4uiq6&N0C{>DrP!&;{)c8{i{qX1o+ZNu?vO# zEy<*}qG3yFXHv>=(p>)Y+UmD;DQ$_H1kEFRS3d5jot*Be#v)Wf^lhu^G%F(X|I}&j zw(KW3vi#3N;T9JhGUJ z|8SzdKDnp9K+a%ew`W1tMbHHFC~EeGlE>%+h||K!`}` zAPR|fvJ}I9s~BOLmdn9Lxcq{OFx`g5v|8R2Yy`Xhy!xpZa$qDpe0o0BD4d> zZ*X9>QjnS_4pyy{Sxm+aoBZQZlP`*(?~iJGQnc0#X%iu`^DJ`FBNa-NmVB`Pb_zrS zo+BWUg`+o6F$e)=)uYa6f{V#88nAE1GUhnvAQzQ7lZR!;fDs-sT;9XnV)PFcNt7@IQd96v428meUT1K~=s=N-i~6{w;{xHKdR zA&Y5;?-Q}ZocBG(3CBfi1MsMHE1Z-2m}_Ou*mfr)t_Iz(>g`%wsE=~o%K3P!20Xxu z@S*agGIeb3R(ywZ?ViAYWa?jw+d1wDQkfcBypeY#;`q8w%-$#`-H;0=wyrjzXDz{I z30h8k`Fi{l%E(_D8#EIaDATWDLaaK3vj3vttQi2dHvAi49n4DbHWR^xNBdo?fAI|U zws2l=fnjSv>F9OPMCPGmqC;<43Q6BnmGv)@J$OETn>~Q3b^B!XYuwX$ym5~!9C*D@%(!0=_}8B1=jE&G(fLuHcTS*Cgem8`s6{SQ)2E;3v>ga66M zhlucfP)%DNUTOB&7$YDrBj50%EWUMg!<9VBCUs%Smx*ZtcmR_3Eid;vFwS zbT4P;IS2#%Sc4{=w97wdeJ4xR_?tF^uM5%4xYJn{&79z;*+1e64?}~JB8Ov)Lr+Kb z?W}jGrPsX*hGLVs@n42Qe4_Rp@VlSmpb}c{jWDP8Mpt=2>j6TdyQw|sP}MWb z%gCa3r`u$hHNH4{$Z=L;S4`dN;;KJyLrR zj-5(ehhkz6OYXQQU$6f&g(v8bq-n#D29#&{Y7E->$?6aJK8`+8QQzQ z9)PF;+J+fi`$xp7B7ZnbDtQsb?-Ue3J4fP>glg$FX5`yJB#6d3ow3PBdYI0N87fkv zGv7<7P*0CpfgU1kEZj>0%O8{k_TdtAIy=`E>fjJ}E zAVVl3G(D74XpJNoZs;ygjTtJ|@jl^vDlKmGq-8=+;mNgI`6EP2CdFcWI#R@JCZesB zFXDXl@ndPirz)3<$~TRkUsD7x*f4YS^9@VO9S?nBMh&@MpGZa;+%*HRLbl?e@AFr# zdk3O$orZyCk&%l=n`ANNQ@2%YwrJvYm|L(V2ej1W+|>_Yolfk2sQ$;}%nO=(`W9F> zW&9GoP76l*(7=sluucaD*Of==tH4v+u@3LW{jyYPc8s9;Zp@>gfDU)c`q-;~Wg?K? zVg^L)UsuC6TJbPKgYo%8{5jq6Jlo#*xeYiw*hZr`Q>A<$&GKd!Iv7FfMF9|k~%PI0lza2;(aVD}HI*HM6S?pCcF5g~kxAlIpI z%gPg)Y|Z-;Ni&6^-|UZCiz&)AiTSNHmRpa-A8%eXuFbx_><%`vB#l(~ z-+tv!ar*RHfqa!xdJz4J)Q?|Lr}mj`_qDWgq5&X6 zNBIT3c12#}=IhN7^=z%4?RqFGQ~aXmm#AQ|wf)BDTStuKNjpJ`@#6CW&Ap<}4=hzY z87CvF>uWIAkUO7#9?~h+u*!w6ALhdLz8FM;&(GhgN@u<)s!?U!4pcNm(K!|A{8T+1 zsQvsatrUY(=M`H$nmo1k2NE1D$Jg!CC8-tlj$0JHJ$1fvFKV0!9sjVhJwe04k*MPq z+@m`1*0RabWQWyMX0G<3_a%CbnUjV0-pl;Ldu#3L5mTGn=VB{bWz^>Tp_<(>g*hqD zbzBckM#Itkb=hqq0#t>q@x44(AEW1h4CHeZyC>n76&lP_YYnv-W!_fx`sbtrZ0RJk zMybzU&enhzp*AY@x8$xP0Q*f~ovwk|OI69Y_dP(ZTFnscW?&b9e{oP(sG@ZU*aC>O z(MjZ@kVrvp5qmUdfJ0SCloYIkQe=L;Bzz9%7sgr7s@~5yRVD0IOBbqPxx1Zl<~*fO z8QNvGlPrB`o`t5*tTss1hl;ae{I;4uvk|&1%=5ez&R^Cfh_fcO=#&n-av>H%+j*?C za&gX3xt*nexKEOXc5nxP+hch!=a|SigtP&@z&du~%H@~lZj-01PA9r|4ZK{#Rt<>S zJ8)9TTDg)OG8Sb~dg{&`{jfq!Np=O=N*sx?LT|Wa@!4wEqOO6hf2?pvn!M%n^j8k| zAKC9XArIT#R_IWJyyve|TJf^%wWB)eUWUnTBT2w(H<05g*OoZ*+NTL6NTb;enOfJ6iJmPUbb*9ub9cqRaCaSe^Q| zn)(Ql9G{R=n8=fv%9!`H8B`H)(yOOKeW@!LXdoQ)?aWV&1|Juz&*iiSE0*Fo(0QXHBj=0f3itu2Vv)ngE1kdt2wn!k7P47@Y z^#-K)Tb|k`V9Pg(wVwOi2bX^Go=0LKgM&w@h4w@?$yl-^|q)An<(;-;BHA;Y-@GkSn_l) z-u1YRuUc4E>enl+dn^qJBEW}Vje8P;0hz4d+$!d4U+tt4-lpbNrsY7To8hRo<(p}k zXz)z`PZX@h(zmEugY%OH7%=Mq zZ}VFvFoR&Jr%dsn8PHHtzzBKG2m)CUAKi-fSH>7oT|^jZTY{Be%E(bl2eb$pUV!0? zd1#dm$|%%Ocfi)RZSAo*+N93dJ8Aa2Rs;pBa1{etoq8CW%t669y|$gH-j|*}UO#*K z6;BV)4!^8%I!$j{qs50A%m=4Yz`hxuS!X(0N)qmEo-@7O2knTGJp>)rN>jmY&2Zk6 z^^^eb<#;*~U$N_?0Vxg@WKs5+W4SdtF?63y*WbdUyN~p)kfqsB3o#mLG<^U5Jwh+O zjk;^mdT@qj_|w-{#7+qBgKwh`X{9glL~ElKvcsc72Db+_1YUVnxrPL?Ct@=fvMpV- z_hP@g7sZ}UH13$OMeyIzOE#`fRQGCE(8Zy9b8<#iL7S(uY-111Dw*fs(CDI{vyUZ0 zn}Az=yV8-{DQxowC@r|2UG6UlLEPIj+W?v`a0&zbGxQ16s02~VQmSIvF zb#6fhNEdJyODl~}Jam42WMt~%*jL0tape5N&g$2~>YT!qdH&p)yIfvBsJRR%mkT^TbalncIVN%BZs9*SwYKqkyxHPN9+Ot60)g0f{DQ>iN{v9j%cb zr4uLt|EoGv4grEs_EOcEI)fLXPSh-D;DPAm**?tITVP=79YLX5&l#90<0Cg&RB5@t z>Z+|zYys|wPtXNGBAWDy3sR?i!{g&SVXLt7aLc)Q>`+p%_gfvgEI`&E3T{zMY8zX% zomXjRR=$*W*7BncV;3rZ)6P|xEftsa>^Y!?WVO>Gw6uq{n5Xnp02K+ecIHA2qU88Q z1oMSD?JlKI3iUQ z|FNCbMtDO84mACc!!SMs5-zFchUV0#8P(w0tqB zVC5^J+vLz!EJW}gzg`;S@=jXsMcLLKzdTNzPGK6%5zTB%gRhh$4v!_hP87hWs%3z4 zuADmf*DnUD6RPO(T$BENG>N&%EU$0g%6}f5eT?LqXKEe$+A(^qF~njZI(tS;0{5!8 z<{%8txl-CKqt@D*Bd(RdIOkDX>f^2122quX`V{-sj=g(ry|IVPs6|I=sZ!s=y+-z@ z+8z3tuPW9$)~&64`^Lc=3)mr@F6?$X6;iFst+M)5y0ysZ_FCKgw=2mlj$zGHw!6IW zqV{DHkl+EZJvmB$kv(ti%A;@r8;RlSz>!~I{#dBu!c9sl9~BkVt;n(DScV0&k$0|}v5 zA)$sIkX{pdHy|P+YA8}fG$<;d;7$k-dO)OFLKP7e5fOVRD)xvC6fqPP5HTn!daJzg zKIebNc%Si%@qEsQWbEu@ueIi!*RP%c$sdXSRKfNPQuLBFP-GP9-E4#vLUX~ia&!3^T-^;h@hL+7Z#=!nVI!i?7j`+W#a}9$WZB*sX5D&qK z)oJd})^>;SQ4AQ+Ma3KtI6YSI^y+S;8@K7TOI+uG*rm$7K-ldxS2sZ1|F7#TJ`^xuk^)80J;T#bjr#|oDQ3_MIN?WzdKiyF`;y<=?oe%svRRaLjS{u|v zItm^PjDRLxLj}n+yC*RDWkYOF^ozX@<7`kPQsekeb?led52ubF&~t)zIiK@H`PlD6qiL+sphCmV06V##q4#6 zKag4@gbhrzlKU5U*3p6U2{7MWwdW0*t$krJts8x3Ognw>+dCpzUn13-ZtsGmev0jr z{ttMz0)ZZydOw7mk=wlD-~rEs)C_1+-+)o?Kn<&CbQ`2uI03Kw^aHG#{h#pMZ~3qA z3|os{Fx8CFjBG$TQ@8zBcqS{x9`B-yXDW#uXuwA3Us3?`1mQpM4-E z^6C04xm;a7GrMxMeo5#Ls8Zn*qceHKYB3Pv=e9mwE!_4RJ~o8AKkx#DB!ok;=&Lw0JJ8I6C1P`BqUR z<8dhF`1_!2wgb{TClL7hxfW{xQ*{zOn zoXAmFR+|Ybx#P~j_E?OYvFOwd$~*Y7H~EM9+iMv*X^W`5V2}By`MPx`iQL9ldR1>w zn5zvk*%lK!p6E8~OZNYnekxQ@LO>6$?@0jkKbmnEtIN8CrRBGkzHuYh`zLg zFR31{?(kvKJWt`6MH#yS0YUG^y5>E4aD%M!RA!f9)|Yyxq9G3IEYd zXdgOq!YWkJ4-qLkW4Y5i3S)UWk&H^s@h2CS%)H>l!z!p4`_Cw5gL;qDqYU!HsjC&B z_X!)~4Y@q!e!lN+(!tbgBX`=a&`A%kq-{eCs;zX3tV>*8qFW7pDK}icf0s{2Q#ZZ5 zw8=T)u=|Dcb@!9JPNq43O?v9nlXWHQ^-7}ijVG^9ukH@r4(MJu`0VJ~(QD2&7Y>QA z<5Rz18N!{7wjD)`H(OaWetsSKIGp!$mB^@RT-&u-*fXJjeJo#LLgARxrsN6iR+tz7 zT=VhlJ!DP&13NAxctmf@nVQ1~d~d}ftfguS3U8kI>VLx8Eg^f%&G^03p7GVkEcazk z+G$DiS%gMG@rhmJcXOcc#I!CSW-gF5XE(Uh1nQD|RbP>J_uZ&n=p`-3lazO1Ved^g zkK1WYE&hK0Ncnx%F}hIAp9&#*yC8z#oF{R3C3tg=h0au{fbfwo) z76D;QX?SbBnNv^QTl}r8te-j@{&2 zu$OEN-2JY?6a*e-+#vxulyC@fqL{YoWrId%P`$BRn`1`3)|N4|<1P=b&pU0I-;n&} z#l_{X1@tP$D$Ob_q9ml(*N3C`^^VTzLkJ|JPj#C3>Q3V)YaLtvGeBSi(K~#;vJd1&e|4x49pfA1UX*Fd~CvmG?jp!3uc72LM6{ zbT~cM84>~j$~a>@%x_V(9B53X>)6Ag4^4BIxjl{B#wi&40r?%+3T z-%^n=+kLpO%VThRn?s0nmg6hqnFkYBsx7WPOPl{X|LV#?*_8`PUwz;ETrDw0Zz{MZ z*L_C=1QgbF_hVJ$62|@t&@gFN4q-)Pe$$@Bh8|z9w3Kym!vWiIZfvRJt&5Wp7c&ld zU2_p~2p}MRz)vBFQc)BJs_tuv+5hSU&kgK+4XQ%9eXhG37aPk zHI&%is+`0rXafYA{7^?zur_QP4>W!y9`Hx#jim-UeM*nTVo9cq`%cF;8*@+*2fid( zZV(o<7pAn_-FE8C^|~gEX%t`NC2cJLr5%qjgkBQVybt4QpIVNROB1qWWh)4M=u5`Z z6QH#HP(S`|E8uy?v^iv@jBMK{mAp<=8nENiyY_c|7tcj625P&DMYo;HJ(&xqT%H&0 zy#8}R;}uxk7W>HQrD?PI4U~209Qa}c=l2=kMMQg;-yMMlv@gRyp?o;iSqGLU6OQ}}F7d!$asj%b+BK^w zO{KPi#EA**`@Vgi9^+{5ugiZ{&USvDK)_^(Y}LC|j#XMTJ&2WKi7>P!NL-*dLiay} zMZzCBSx9qU)Ssyb)<^81uRr(XzmRgqzmPKJ^6&-O16myoIInjw)p@p7`G;F_Ou@w+ zLvUuGYSiN$+(EtY;*hNbHfB48vsuwENQDH$dU)#SZ%Zx0CJS)gtOAWe2KKg)pmd3Q z%X%feICLr9$1z;4d3AegX`1s0T1Nmz{{YbL?M>P%Z5DE27#_#8nIv1_iyx+x7jK{5 zMyIluX6~0)c1*9Y>j#KWoABlL)gGE+{pm5Gl1|+6=k5jmKAWNN%P>~AJCBp`loWw_ zT#6cN?chqZP1J^#E^7j~Iwjr#huJz3fZoAQ;~XU14?y2`|akL96wE6 znP5qO1g}9Ra)hNB5&>x6Eyv(%V$@GWp76Tpi%2%@ll$uHEniAQn>9DB5TyE%=EI)S zp)&wlgOR6S!w_x@(?vxJk${w>CEJpZ`O1a+noB*^Fc7I`wRu_IT12J*Fw9~bT*{p% z9o0-kKI7eX629QBQcXL47Y4)qJ%oySrnQS4Pk%J$2G)QIuX&yhKtnMKplR=c=wY}* zne~bHh><}shu}q68IJ*u&g3X)Hk)=ED?nlv_uVZjx%w|$BQnbpgyfji30ukMGOLv?CD~;)c7PCDCa4v1B7|T!%yLf-H$aw zxN#V|K!1OFlbk6}H|^8@9u$$fK~5;J&{*OVrsdpmi2xA6EKjrW8SIU%=+1cXn`?xbSlQBUUFeLteyW3HOp<%qNmO8LuT`T8=_m(#6Z3wCdaoxu2 z%a-YAsK%lsEM!A!{$mv*j{UXt&!3BoolH>QmWhp9@P+~be;148~&jK$PH%U?dcd358iyZsK?4~pGq}0AV0V%|cOcWt92~8X=c3Uh& zMHx-=Je8B;AX(*_>54$xJJY4X-W!MoYyE#rQ^WnSTPu9_&c3Z?M?~SkDP-^u4NZRwHgzBgr*b^0*3l4AVv)hwm_yOZdGYwpWc5*bwHuD|7)LZ>+ zV`ccZ*_N2lkrTB_J6@8TEAk@At<6>2=1vx2GwWKBeM57lr_Zc7o~%22If-AuJENvs zki)*)a{5w#;aumSa`ODSLTurD*L~X$^XG-$CLg<>h9`f#FcN?2W6#*$4<9dz@=O+b zr>l||F3q%_TDUx4dWwe8E$(y=&XE(`GNOA@Gy#li>OECy&&~lnWFv(1To3S`VeK(X zECE86LnU(TNno@bWqv)}s299bR`dYK$2$^?*cj<=Js$m8U-$N7spg%KtW%UJ{l>~R z@e7qsUlv^Y^KbwGuHPG){}8++vl;-&Au{T=tE*B6fFtt_sKtk`&M?&ZRB0<)%qmq_ zLmC`OLv)wp)s0lw-o=xC>4!Mh%u9PKg;|uB=sQ9yM+B=osOQcy_N{$TjWXg*Neva0 zGtu^$OD=H)=3r-x)Oe-*h0WYoivyxRX7nCHs&wVImukO|Lw1of;yoiMOJLBM zdq7d-?Lwbg-%G9BczyCiO!ccJ=U>7nrPdstOs2bLuzQhAi?sJQ`vh4%iGN<)z&0(J z5j$^*iddVAKX?)J8uOiRyp0VpWZpNUQ(Sp{mkzAWSHQH~$liiu01lBP)+S+&)^~fN z%jF5q;@7Rl;{-PR_ZM{PvP`NVaS$OpY@MappZ%)V8#ee_O&28?3Hh4n zHJ2@En7K4>r)0U@x{@-|tYl4xh^F`^dT6~QAQTBq?DXh>+9_YO%T*GWvFk~_C=PV_ zSg_bhIu=6wEt+xC^4tJHNaresysXcV*tt*m< z$-Ng6T+;dghr$aICf$Saqr4O=iZ0p?pjREC0h>qR^8_^?x@ z>rRnf+KA(s)TDW8ot_YoV?4%-;u`>O-Yu8q2^kI1a3m;fApuOdcO1Nq3VE9&Qi}}c zAl!#GB#A3-Z?MC zkb>0q5tIQYLpe)J0qKl37j5)ikr{Frv19r^< z4py^CF0?J5tccdeMeDuZlE1+*j@K5 z1;jTYS~f=#dsvfNqWc}q#JJ;6o8+4i@@3+wF|t)$wk?B{@1ht=yq&{QljMG^8GJkCEA8*)6(v&)O%UQrfWNoiSbkp+?be43A_TA9!sIg(OUgyB$Yp&$CgMo7D>5j-33J0 z5L0C@h;AEAww12Kun9)J9!>_ElB_F5YP1!tUBv5;(GHapeLaUeEisR|ncZxda{eF* ze~$f+t+cf>*In_C)TSIQp7tq1Ki-j5>{SP-UFEW^o1-1nod@I}7k5q)^tLJ+1i@8Q zX}HSAQ|q`>Xq@y-dq9jD`baHGWm^7z`LO@SA}Cc$Kr1n+(59sbA3q(MDJgW?heA_- z!lYrQeQpE`ht(eXp4EO>niB=+q8*2>D9^lgW5uNr%+1h>amr^chCC$8LrI~Qw^?y! z$vvsmNBImId3iPITWq?A?Pganv@&P%pbkv6Cly2PM!~KKkc#F^gqlAin@)ya=FFiU ze#=8f`*@e7tl0geg-SV!B35joLV!)5qY$_mmc9K1{2yTB;aqC%vy2Hu!P6_7~nRMumy0ir{eeIfX^*0c8YQ33fvqrA)e!{#S78!0xWED{$+oC zHVY5{F=5q2=AOMCVnes(Nwi4d4ia)x2^i*9*$-m;>qCaxJm88z_9kREVN)W(f789) zdYAXFQbcEP|FwTRvqT~;FP(z}fWq?$$~6k8^HQJrGFgJPpDy|X6yz%*n$Fl1Tm?(@ z088574~91UKJj1smjo4c-TpuO7b+S#gndrk8flFh*hiP}zgN;MQBzV&{4%n@o)8Wk z;CVQ}qVWU|9bfR&3LR&fh>_9-0HF&;kPwdwQaR5{6~X>T06QC|3mNorOz9)YTU(rk zgM$`#(5O9mFV}$&YYsk>2ZI>@D!^jhpI>2GRNMc51(+vMfa}xu(1}4GNy*!5L(&8Y zM;*5*B8EZC5fE{as|hA5C;^#}dYgN1C?s2@fSnGGjKqdb8c6!JwCU-gJp5^49)jf7 zLPY(fqmcj;o0j{D>Q;2p65c1Jr1LKYEQqQmWQK{>A-c+yS!QI?JcqIP_7I6K-vQ$F@{_GWRLM@%m zpvzv=sZ9-&Wdqo8F??ybSeaXyvJd%M8GAC;dwPQe2R^1iCFD0B*J_iY%+mH`9QDtv zd{JR(ao!sIyR?B3sX(iEfBXsLX%e{09w*gAXR1a|`GCC}YEu;$6_m^_asCk^z8(!U z5D6(K(B)WQeC11wNnGvL1eyuGV6`K8U{U5Ok)TCS&o{(<%e9pp2at@TxKun_j6C5l z-IcJ{hhYyer5$=tjsk(Y{*s@!*IFSyjrrFL-tLzmKdK?|f?cGtu?726zGGY|78d7^ znsoh3215xFGT36Z#jKHp3@&Yt!zgs(4qgUWbx3S2&?<~Qe;5QkvoD8X>^m*wfW5^6 zr==JKAjjVOC0YB1bBRa$}u1N6Dk`U_}>B1e>UC$2+; zFzf`?0tmHfurGxu@Uf%AC0-uW(qR@rmSe|7z&EKDxSZ@@AHc1a?iJQVuhiunCE{K9 z$VJI?H}&-Mx^oi4tyZF4i|ZrXVHPI?ny4`K{h)V---`;*Yzi)>7ychRxZVH>Kym)h z8KVkig#(#vzZy4*9n5V1YX?(O9D2}qiAC3_cB+O18A{>yi^Y!AlXO1fl}N_20e_QV z0%rrQJUoXexhdj67UL2>c1|Sq&rclp9YUU$ut5ydrUP-JN-F=te;nb0E4>|~(&OTU zyL3E2z`PPl?P4b86vzw_P_7UNx6~vOL0GHoMJA{RF?xyEBUGPYI=H6@n+0HF1PFYL z1QV8wrsE}!Ryt9(d}DMl@AP~vQgP+yF`-B%ON<<%;N&*$t9C$6@TIdvYVcI}kQjF` z9vezm;!vf(P*9FdFc&dSK*jI~h&JZ-#dF(N{IA|J$peH3U#i7Q4FFfkQv_Of(r>p;07IytB3;T={2_5=`E(0}oMm|VG{Rb9aI===W$}Wl9 zf31Xqmzc6S&bU|s@bg7!S$gfa{=i8wPKpM2QSqOJxl)qoMa7|aX${Ly{`$hej}!7S zoBsO3d;~z*a+3-K(1SN|0WTtsYl^QX!}yFfsWK-d%5Z@Nrv;-Pv2JPttFaTy;6!cJd?d;FavCDNBYVe$}zP5`e~lE z4xUb5VGaPp;K^z@?|6X|4Kf)O9)94kAw0-OgJhkTqn?D#PF=}qf- z;1epIY3%m;3keZ|H#jZ*>{*UNg|Eo;;r(ZKmiV$2#7A3{kN_RGczJV)k}O+vNO{@# zQK-R@DFdY6@j2jUFonu-z$uA@eXKDlc6ii2i)+G!m#NcYJ8ko_(sb^bXG zfsBfiD?0Q!Zj!jWgh(LqWhSMgP7T3teHbRm@m>1xS?8P`Zvzh9K$j4D!} z?>?$?H->n{g;X3wy!l`><1`7bPcrTT4`&gzR)nw}pxn?=M+uaD_% z{A?5i8k2VrtTs;tvnOSTZAt)ivIw)B28PS)z=shL0?cy)3WqSI&P^rhygg`Twza~* z^o;XeBD$=9%I`Dcwh;e`7jq6r4rc?~g++%5YRcnNboaOG{}3^^9)5}$hlqriC-u=2 zZ*8^S@31oRDSCh4&qUY)uZx*Cxx$xn7QM`p*Oi{ceqcOM19c^Z=s5z)>CgL|Y_p8d zCL!{moER4RG`n`;{bsGRrkz%<^moi)A_f9Nttm$1b4FUQ)j7i#vtTNnpgna4WjVu| zH0f&8vpe(V^1}~;g?IhO^sY60aOI~tiDr*U61^F)W>@`!w2!Tur^Z1;E#APP;E6k% z=dE`byl`2VJf_#V%J4?%Liz9ncJ3l9xA z@?!WFaarT1bzQUI8-sY)PY3Ykxs9{pV3RAuwOzvtM;nc9bS(y?d;F%t{Y3iOnclHudGyjt{Y!8KKuFD=MVY^7xf+)Ufs2LF6B%7FT>TY^O?sM z?H4{>@A?vE^+mDlb7$AljpvR2Ssc^)v&g0`c(6Z>S{d(ZoX5hxY_|Bic7=-al)bZ? zDr0Rg!$7#pxPdgdL=XG?M}PAc)kq6H1&ik+?%!%FzFVv;W^ehHc@BsW`>?Eib1Pf$ z#yGSzpeII;(tY1QoXd1uW~F}Lc;oxJ@vjH84Iu61xUwIdvji=nhU3k(uE;POMaO z$^fX(M2z*?7jJK@{CZ;sG{C&hY+L1yp*NnTvtv*273oc9gISxN@DpcX_g*?N7rSIK zz71jF=;3#dm0SU?*i*=QpN{s*S-%v=8`3Gx5H-Wjb0^MN>U(45H;+} z5%T)$Pg#hjXA*_Ft4>%v*ZN2%7;o0ouXbiD8i7!r)2-(PY@IA@;g~_HE5IUeTd^m9wUp{*zxi<@BZQDCZ9DM)C|vGSwT~%Fti@e zT=K|exwKFtpz_pPq7<5(d{n2qoG*PY2kA$o4V-8X~x~uEc3MT(@(OtVj~ZTX&hp{VwbOO^`KRN z1V+Jmo0vr1@ijg*-4(d{k>_e7%d<P&4Y0Ury*9}1ZTH$WZb+N35Fh;uVQbfT*{oZ) ze(ME^yPazjz9B*15~a4|rp@|I``%tyzvUp(HX=GVtM5kDLV9$>*6OW28xoG^+D0aw zXz7VeK6}%4V@htzg^fFJAnl@3Z|h%-+WpAOZquF@TVJ$(9^=?;&UoLl&sWyC4O^P- z)XP9>&LQm?EVP0BEu@Y;sh54YkP6q7OqoR&7={;aIcRjtKDH#kTXD;gIEH7DlC%9f zq-|+L0~rS{x}#&u5F6quwxkGHeztUz)`!XwBDQq+-2H^3HW3hXOhpp>rx5NA0m@bJ zCudK1U>a5cS1Rl#UO5fVN;uA%u0DZOocRH^Cxd=?gI!exb9#CalAMUpyn@8Db~C`X zEAqVh9jyT)lVDE*C=WY!ZwG)0?I8jfV{e8!OM!?Ih^3eI7UTr9jWm$+G}TKC5CnoF z8@o~cHxr&2Y=5EqMcxIL{Eh{xK{416SD_F;Fm%XnbG(tUKNXvs9yV-GJB=lugMWEj zFU#WC5^7_(+T??NMBC+>X*6qrItf4OjvZ83qsr3F6K+-SHy%j{#g>r>R6X>KO~WE7 z&(3dgxcjp@aQ#T8o221O(Pmk2ACu1pVoob2Q31384ROi_+;!N)Q#U*O5_QIW#XwR!#t$lcToV)=b_zAVL^y!nb zYpCvMbpZr4PU0q4Yd-R3^br1E*j~P}1v{iTgoe-v|K43gfMnK}+(xAgIrqBdFnc4gZA;@=Io(BgI zh_`tT1#)83=&CEwyF5l9?T;Sp+KPQ{Vw?`3%VW!JCk~(p(YXOUHu}QG0;wtn!b-Bm zSd-3r%~57QO{%E+93?;>>4uE(Z}&JyDZvGz0t+U2zdnDEu>1@rXU)e{)__LGA{>0# zjf%;b7=$y?iED5l!=;1z-$d}mEbC_7J$kxaw3LNNtdB^9E2Rlgo=m>{_&h=rGE}et z06ANGn8pY-hdK>NT7M`0i3>%z(%EwBcXPBAdn-_SEcxxdO)rA!Y%0W-FA?!jVu~|8 zPzODk%pm*IauK!+KA(wD3fEyd$(&U*?{wFvvZP*@%T%=iNV7kDmIh){{z_n|l|t56j0qsh za{~imax4ZyZJ8>izzK%y5vX#$Gz2zHv^O8gK>@t}Yr*|U&b61DMS>O9ap&>HmX?N@lo#2Q`g!W|`mSYL1U{X$C`AhOVT zI0Aec=3{NSX6vdUj3=)jpBg(TXJwMRatQ%z03e&5XxB9|W%4?!`hqunUQ@@LkSNLh z1Rf=qdjGV3r>40hOp;(tX{`2EV^rMk!*r9hTEGaX#myg~qNA@EMp zGE`nZ^YURNOEHYvFKhLxz^w8nn;HPyVMkeqBAb_w>4NexMBsrsumg!1Ot7S4jXMSB zb*W~Cmk(g$gAW_Nh(juVLmWa185j?8A4-qsYs-vA=?FC8oB+;f++O)j@g0)NN3MR< zMElmNL^-kGrN&AyS#QTW*h=SRj~&rh4=@HB_S}Jg?Rs%d5~Ycj0t(IOcuo=n_UfmT zca@Bj@y8$rA$D>IOPrL}WlqbO^M`ar)GJzCfxIRRGGpw4W2v5Cq99Q2tlr6&n+h;P z)I8|}0#KRQjzd)k{3>PM@&axWbO^VvIe<*KtPRZC^n=?{_Nw*9w4+ePn~V#)Ef6u%F!T?KQe&bO(P0XtQ#oskYWVy7M1ysn+aHz|z&Z~@iL z2Py2}8rc10MGnAOWzTb~VOKNGKj^<=r~|vI;RbXX{YTstC~zg>?(`@@BJKi2Ti^?g zSV@h$qEH>-!ffi4YOqayWuPyHE7!2y#DIJaL}fx6OwL|~LZfa7sm7+J7pkm6GhUY z4tHSawP4K8#*$5Z+nk&KMR)mH>WP;Tl=Fnn3sFrcW!os1gw#%^MBIg;=xoV+o7ySG zes_d(jl1kNtY{KmssLe$x$I2ZHxR-BP*)91xyIu{EWkX%emzU`6e@@+e5$BDw{x&9 zM8H$*B1&xno&PC%l=lih#C-2i_mK*Lu8k*?4g@Z%1uhzO7_ z`RpP)e=3_mwUtXBc%yqI=L%=@6*D;DI8q47|Hs{J>*dwK>MJd+h`D<|Kqs9*r?ntI z_WIS#9?UXy&IDKu2k2=XFHiaquwI1B9@MlaKyc6}UP2}U$618|R+vD4RT-IX=V)v@ z$^L)t?#f1rF{BR88|Vz#@SMQg+f)^o4Ppn~S3C6-Z+G=1Xx?*RMaruKebYmGzb&JTSGlspgzkdn$$M-N%&Q;`<@h*0{C8q-!Xk&ECn#H zI?~(;BR+3D*vKT?)3pVtL`Y)Gu6U`laTpE>u#?a(ZXd898T1B#u?+ZZalb=(XAUE3}lPR}tW8d3>t z&^=cd15-@&M0m8l`yshTfGZg`0V3`#yIC=Eu3`^4Pw@T({)gUWX-|QA%jYmpp{pjI zp1sszW2D^7s-uoR{%!2IC1qh8*g4V;K~|ozjU4ROW1E@ zzyxzsj9@4KQZS{LJ|fSzxckD*eS$Qgy=nK>>*;5&W>w<(x`C=v-IZUx2sG zyba63B<5WE30EYWs{hQfY{vQJ{xx_fNq-IA!-=4GGsz8b!-YyA0N{zSwJTXm!tkD+ z%u#pGbz;IMC~M{PLwssV-m`|QhFTFD3+~skB$hGr_lBS%*(HM-At2Mv!xoDAHc zUQ1{NBrT{{5I>K@1PQ*RS#s@m*>XE%oSNodJUD6!vjyUF5D;ojfiLeAmR@mj10qm$W7wDZhforU5 z{GqN;CG-Btjea0F#&tFCV<3jPW7Ij|m|dwKrZm^5ALm?h?lOJLM1;yKOrk+9;&ht|4m zAROeBN3G>OE4u%}rQZT3ry9M<>vT|`2g|Jj(vJXFu**4qs$&l8q~z%=LlIlI?at^& zYzqdK`8(&rl@WC$OxBm!+(8H!5@S0Gqi{P~h+H)FCx)DKS>!#*npuYRfao_>U9`-OO@}Er#h2 z*Z|i!Wz_VVGZi7qalY^3EX}8je^hurj9q&t?!vW0sykxo-dh6~Cj44sqIPW6aea$@ zUK5rVO|^~7IQKTRbUL#1Eo3xpWghPptmJp*f&cZ9z;SHC^S4n|@w)ME>xA#N9~)1) zKJB{rF7Zt1rr@dgV{u1%Lz8>rqi!)Ac8rJbjo-Z^F7u4y#?h(+&);Xgd!PO7{Xx_W zq&&kin90_v+~t~Zi4wmj>HT(dUha-+Zq>|6LF-Im&rH#+nd0X&CGQe1FOLVKW_il9 zJBfm+%(PYU%6-|+lyqNW{9D9*d@tnchZS~>_5xa>BCoEu(jl#5N z3L@DRg=q!qRg7z~K*|LMpxcJtg%LkFR)k{Y?2SNLE`ys0h-*CsU+X@;+>8a=5M$3% z5NC6$dO!A3r1Cluh62I#<{kBkh`0#xWf8Ebl{0jbW!;wV&Sl>(#d6y6KkY4$hw?-{ z9~z=rgB!70-xm+_Vc%Ih7YWE9B$PZ{EF1+?0YoY_hb)9?0u#yy7Z+ba31lWfEXYjE zT~QbBL_NY17u7T=W7Rw;R)jRf=(I0Bm`O*cbRx*)^OO>&=$) zjMKN(0*JU?7!H!hjv&LC;D(WWhnSu@` zvb}5a-5CI0{DpH98AUgju~<4>1I4x>tvhpe3R18$xoK@V3e?=xnKHFxfW&BitR@Lg zLXx41HEUp7hjP_~s7S7)Sc%9y3^$sA?@8pWV#;d~@?9*pwMQe8M{=wnL;zhnG!eZ{ z1oLgn-xfeI?Bi@BfZ7b$_vD;()tt5&RG{yXQ^#OhWb`Iqf_ZwL3m05ZL>sGqtG2JH z+kxG+vfBy`?%_%HVys=gxsfls(?n(D@)GMBMD%g&O6Dh+eJ47wx77y%k0&9M+F-K0 zEK`1#A-7`Zo4g&W2putM9e;PN$X}ZY?vKSh5U-{RQAVO&0H2k@%cC$@v-?0S7aH91 z>sA7`ReARajT=r(t$u|4d>NfB<|gllGXacQpff=B1wt;Fs$2VRya^0lb<}g8?pGpt z{wr6LF^orcX7-pcV^l8nY&ad!Yh>3-o*VBbXiX4oT#5G z-I-1^su9)blSu%DNni8SQ%-9=>>p|j#-6oyA2o23p_yo>!iJizD5Td zJd`csUnoQt$=&yKAbm(Rh*>Ga7e6(rWEt~rsqB6$B_|O??49JESpQ<(I&XYvQb|`w za?~%e0fS7r8E1Uttp#6acb$(=X6HHVLlI#DT|=ErIG|^a#sgh_xR_l|MHtzHCl&Ul z|BMiUNW;4b>KJ8NJbC+&#m+y@KbPiS98wXyAHS9vd#fT#Av{0)MQbZ<1NUAnyxgxD zW_~FhD)-jhV~e#4Ek;0o@=Lq!`tKM#gbX~A;RzWzuujmVhN(IeMuC-UpDGPS#6EDk z7-#uxZ577nu>4Qo<|oE4Srm><8bxli?$C6nJ59}Ds&M}lby2uUkH?6Tbx41Lclp%) z<)P8)g;o-vMG=gYtjM;kMFS+o#0^nj_#vBuuBv(WqwWi60haSJeSxZu93tEJZsly9 z{I;$QtL)S4Y4STRm%ohwDYuRYXobYF4TKI8V2 z?U#*Dod*97QgpArQzi;3FVPGo?R{b`B}c{`f=^29Xwg=kX1q;9n!mE?rDmm_*CwW4 z=gXAz2Iy`IQ^4YGi~Bvn)?Un%W#g|OTVu=2?lzSbE+Dvew!bzIh_}Rmj7hMw;$zQS zNewi+Gik(rv{vtx#F!TI=X#jFU{AHW+N|3x(VE9}O7zAfhJ&O{IAWT?T`uK$a%!4) z8?9Dr%%ExIhEnC0lThNoi`&)_yJvT6513eF-A##aKSh&vv3~4zNQow?s7o4HMHxic z>Z|sBqcm(1aQ2;3SX5?|xbuhSF%F0s2D_U(1;k2rcXD3ZXM%vAO z_1y9>wkw$W!4uHG%+t-YyR7)c2BX7l3``DFOU+Es1{gtids7yY`j70hHNqU8j2bRl zbIa-MqN0Y2%hzWcEjD+*dB%a%=Q?!qR4;df0{M^D{T{k$D36`qug)Ro=y!sUCJt>1j>@ZcJs~u*e@`>D$j5}qXGup1 zl!nDD+2GEb=Gm4Ts&?VO%+TUmDVK`s6Ja^IaSE zKH(VHoPT(FTI+ay7$->O?T|L%PF{*HK){hOi<<}b~i zL%Tue;6FRorwsoyU^_!9o7cN|<4=ll+R>4*pD(Lp5NFIY26l@+HeS3eqr81z(lDem zl%pJ4qm5AqfRrIp=fb*AIrmN-gMTVdUs>a_29rre>iyyuJl0RGrVBYr7x_*r*DOm< zsxUstC-lMc&Ou7^vF}=|(>;|tU#bfM(lP_7YW{ZkOy;EAKdOCiQ!Scg=A)J(-XRPl zXu28)Hg)C+?wx&LS@*>Gj`8v82V*vtoGs4rIZ&fkC9Qo4JIZ06!pzyA4S>DIL$#-<1=>Vr2GT6dvM5<*sA z8GWc#CiBvG+x+CuQGcX$duPhWl#LoNX<$W$A+mRA+0g1-Wh7+D#HtBQ_rTtu>@*vk z6!xu7$!yW=!}Pya6nE4k3*Oo6?|$%+wORvqpe^+9Q#n+U^aI(hA=;(ev9*Q7r&cX9 zo(UyAKYww%Rgp20ZzW@1b!oI^r z?bho{LZs%`eJuP;*^Dcs(_0RTi9TZJh30&~ zC$G$h#evv|UWbE3UX#*Om;kvFEbvav7tAMqXZ>NC|9pICv!P@DLje?w+CS7_HrI&& zEBOENM|Zgi7;7dv^!iY#ExGnH8FrbynVVo!{?u-S=_-0sO$h zalCnt*Yoi-f{~+Akbergv*CJv>}^fSdfBeuE)|{q?)g5IjXM7F{k-C1HUq(f7zhAE zbExFlotsk>{4xL^P^k7`801}88z_-$W)8($k+~UMOy#5{@lAXl zEXj3HZnfX=6%eRw6Z0y~vnjn$qt~eC(9Fs~=)Y92XF4*E^?jMK#m82TNQSZj*<6Bl ztlEt(z9TYO=VeaO@83vOU&xr+SWt zSEUt8JUhVZL3%l03+Acrre->ez$lbyFi;^|yz2YX|o);QM{5t7j zes*SFyxw(c9UF?K|gu z5sh>ke01JZ8zH?*?=_`n^oKF@7ld7uP>E$gB=I@Ml^f-352H37_yw8>7~=8rE|Yb^ zARr=DpGZ>&TJg=rPBDCzQiVLG2x7PhkxAel4t)EE-d)Zmn9I}J({z6bk!JOGSQ42s zc(_U3^0*xmbvPYhl-_J~+{mrzJh)2;@Ma(#inzcoojsKvC^@&=Y;NGacWBYZtd>O{ zTPW@_gwn4>22{fUP#LgQ4tr>2){kcg=!bDJJ!H!!*8iZpTukfcm;_=5`)TCA=q|u_ z{TJP3E>^M-Y}HFmim3mfyG*52u3`q%LTZq;)Ne=tRTleIn>nVQwhCcn-9@r&gAm=d zC1fHoQY3P4ubp2A#*7q>(X<&5qPye-0>hw3<(RIzYaM_E0IezDLgnM!6u9JYN?F0B z^6NU6N|q9Y5k0~y%PHIckGpG5BAX}g?16$u0F)h|GI?mHhQ}uk3H>~Ihuyp|@}ccF z^08P_hF^Vm)>O!Ejyri3Y|8d}6Oyv;M51L2bNdYs2`Ytvl`|K4f)Q405>bqh4Pd6x;M^}0*L9UfRh^_;| zFYtX&$}QH1#PZ8SXCvYXjPZTig%;$g?_3)VHJ~o})aYwh-fK8F|FB@`MZNzeA;6nh zB{2+pJ^oajGzv)sl%%IURb63;7aonlKtC4s6ii|AwfKXBFw#fgd_WN-ePJTU3YI6o za}{J%GJrHMJFdcDv)JKEH&RyNsiFe-y$SBP*!)3P;gj^@qx))x&zQ~ApA3Uf`EWE5 zc5_etKb8!uVprrIs2DdNIxOAl`y%yUk9Uz9E#~-jLpoXYQ~b{-Z|-jHXMTS&{awCo z=74vOEJU~E(8sGwmyhR@Wi1vD0M8ct)Wh z=T+rZqt%Kf7RTrUc%o7I+6%jbeyR>L;=Z-^6%QXORKqnJl~1gmJwXqt*s%UwL#lXZ zt?+QBymee*E$YPS=kh->TQ|l|yf;?J_E%Ull3T&}eReO$8!S!tds>YwGJSLZ&|5HdJX~3iha$ zeLjHDYfpCY_qnQjFy4&xy+?@sLg)y^ciD90H{!YD#LKUa7uVTJv9H$KZ_uGZ1&q*?MCDWzOV6e*aSDqYlXm}qO+NqHuueFd8yH3Bi0o4xj!pW`;3=u$yOV*g3UDF>((Br59l(^cKjyvudq)+38ZKPmu-KeCfjhb4^my}tMZEXLXW0u=x4r>wzasT zj$s2tJ|rai?WB{ z+ZNW7x$!Q+o4w?LWYzZTBfNpVp?-;fhoGC^%Vt3TntOMR{Z7t2Q|oV6WW*KNkDNHe zY&$bi{UiHE*5rV&vMBQg1fe%u6_lox-9E$IQ70@b`r;aKi|UrKcehInDK-9OC;LsO zVzez32WsR&|B8q`2mc<}9Sp&CxzID5>PF5ATP^=?$ds8odW2!rV{DlC{P5FQTUwg6 zlugb@7#{Y`zdt24Ik$8w)h=)B&9eB?q8*0OWqpo>jDMcOA_Rn@up@IQpyP@ z?Yoa0oNr&Rq>P5h?N6_`;y8Lr*jy2F#gKt{z}PMYdrZ(tmEwu1a*_6AA;~rp>VX`prp(osV_- z7AV-Syq(MgG3OHJ+;+J_cZWx#xHopSL$zZ7bXeK0FR}>_+HA>1b|7G1HDW&~<#_Xl zn~v|6GLkCUIbLd2^^2|AH$3P&ygQ(9`$O9uBRy{wA0FFP;{DJLca|%5IHOQ%lT%1M z?w$J7M_TSM+IOL`#MJ=M8SXHUIDUjz?CNuz9RDOf6=@g^QQBpEq+TY(LU#G2SB0X# zSa!1d!rS!mSDx{3OoxmYlZ5EBUbnvcMRpHFq~sEn_)kmQ>FeN}YpLA(Yw^53%eCMr z1G>OXUhJd@PJ>%`2xV$0Iw{MPEuuW;=(B49-ZBp(SDrqHSvY2A#vkdu(GA}6 zyC82K@Va06o76H<-EV8huF zC-uMZOihP0dMn%RDS}}%=DJF>iJQz_b9jzr@!Cv^v{%IBxFb@7P!!JgA;Vz9f)M<% z7aYwj5_*CF4|+P2zU6fEI6rwqVI@uFL=(>$>cDMtls9yvU4r?(2yc{8>Cm&ku*Hi3 zRoWU&nl0P&a^C_{Nn>hI#q0O*y=rT@1A(#$1L1Z^CYRLeYheNq;La~jX)C)$paMW& zspXJS^%JDS%BLz-Wjyv+thaLzB~66us?yz|j3QgvMfND|Wzz$nG+B>A~w$80p|5j(XKj7@tt>l}89tAuH%G zmAucA0t*ZkAajZq^wyvP7Dxc{BiT)P43|;kl;lG?%3X7X9xYgK+s1n>WafT_S;bvt z!{^1dQEZLsoeYu^hH7Z^dhM}qLS?o04Ib@qu|~ZoJO8b`Ivg>ZKewK*M66LU^Fo*? zlE?De<#e3Q9q>AGBnxpd_st_DbkryoRd6KGCtxo6h`jbW34lFQPG*yU{3s#QAw^%L zsg;_@aceI;-Nv(*ML0L5zsLIUz@JWK9Jq3@Jxl`6eX{{&2=~}h4{q4(nk8AjoN1nMG$I85&!( zP+YN_A|Qs&$(EIJ1xkt1QdJx#_Gf_NE6M)FzFX%)$ZB+n)tBZlHI`~{?HN&lzp6%O zzshf-mIi;5Yicl)ytOGvVrM)=wVXDbAQhNpD0H`l;ZAXitqP%n<9HB1K_HQj9Udy8BuA|EqGPh0ogKd3#~k3GUqrFAj4Sn2wihL!S0zIV;p{@_==wA;=!3E9Vsai z!Iwr+Q>5=rPfG!nnvfb9d1=e&x-*>*SZ|j8a4!LPOYRxSQv<3{6eIsBaNwgtw8v%>dMM|9z%&(JUXYjL;EGln z3rpX1#JDR?S0^hRZX|=P%YBx{KJ+v`{aQ4^)P%68{CY7NPHJTw%Ko>1EP+w200gR}PjJynzg}scub7Nl zadR|qmC2k6vHj&FilVe0kpOOul;e7@Zebn3Zn9;bNPXWI9B2~t4c;Mxl|n!&SH|r#GOwV{W$V4<@8o)00JnZM*KqyF~1=H?RW?v z62q%i9wz+N+;->Kna?jRczeV;@9a^)cO|@*RF$+1dwrZKIsbAQagEe5yAvQz8vpFr z7(B)*PfALAC8{k(l{p&`v?auXgNwUsTpd*$iZE0Dt8>KGt!O;YYJsZ~&%J*qs_Jv% z!cD~Y`#V&=T--Zounp;SEB#Pp^;Z9RM~S$5{#7e|q7F}fhi`-Y9w;i^IIX#Jb$-+; z`NCCXDfCtb5=0K0H)$$RSlb!KK6kH8 zZ_{(jyVQeAeUvn``!sNG4uxlG>I8`tz0JhraO+l(8g{7o_w z6m@@@gC>h6OM3BP6<4){)^4yP;m20R-&+AB@kfKi^}AX5014eemLBDcM3JTMqIB0z zXxQ-K6Kvem3{Z*NaReB7x)r{u{uYWzch?IJ9_2{4t170XX%Y?m8^Cz_k{q#DaWcTB z65vLqVDf}55dp(yd=Yc_A8WVZW4jIQzt(QR^aO~H29O0bMX%5p12R&9kFaVEJ{yM0 zpXrZwAW%T*D6--LQ?mQPstm25TS8BP4gLUD+I#VAZrT5FyCh_by5=8lH{j5Ne(@?m zui*YMy^Pr9tRHH`ynn4-3Y%dCfE#?}ryxssQZnyVEDKN`4N%BP1&i1!OSG)j^HQJg z{o_fLeN&Sbk{*0q71=~+vp$dDk}!AKN?9D6W`{rGuBZXZ!{!gTyZJ}lCB!K?{GYhn zaH*mu?@Sp1!sUz90g?*=ch&e%B1d8FTGHxPr+XafBV4E*T>d}k?o9eqJSG$Fd1!Nx6cu&ccPxVytM*c=ILtH>bvByt2_BxlPd3Ly+j;@ej_j(mgYasl>r@?P zgRnNvnVxEzH)v(c+GVrcMmi`f2f-jSG0%fxt|TQDPLLIVU4HZ}%1*(LBdeMr3?)b| zOCXyvId!dPUYvt%el0-TaG^gDXQrd1y$CQoTeeODO(n1Itj+jsLcHUA?SNK#gRnsz z56bfYL+>uQvJMIGDGk@wI9LUiYF&-_&sFgk^Ev^-^E3`9(3jlLLKvwkH#4`4GGSf> z%4HLgjw?CSi^~7HyAO0=QJ}1XjlswYEt{hZ*@v%Wt1f;1ovQ)o<29-;HT|J?$r!=) zil0%K!SjdtnV1tgVQ$V)I$5E>&^QJ$Sv{(Qe_O@#DE7Ieu@?{1px6;jAtP##Kl(0P zW{!gk)s{JT`9xHcxNwtm`}$myhW>`u_HAos1rupNd-d^m)z-9Yt33HS(0lV=fp@mH z)o!Wi1&R)l{84mL)0VG)(L<>|57Wh0lyQYrs~Xz#p+K)<1mUw_FSNUG`_VPY!7sjE z0W^SyYG!WTUjzMGaJj`LED9!D$+5wIk?L+xPjVx)7M*D~%XfBPvkW($+7Hq#t@&MVApWF>D_BwCH0K6NQ#~Nd(Bn2-H zqfhEQCT1z37*ns-b)22v+MJQ{R@G#ixI(*%N;|m8;3|&N$`F*-+hJ%wNjG$i?Y|5! zKoEIgm+t3;N-g-W#LKYOS+}okMBWAE>PVtlpqK&yeU~FM5vhU*#Ah>+DFoR$GGXe! z67SDERW7ZxhAoju*ldOwJyVCbgVNb;DsJQoHxXE@*{-UOR^Ra&C2VB{CQ{?Ncy2JX z4796WTFB_H`i<|T?Nj~_#ygW9)gi$nVDw-KMWA#ISG4qD%U*CiKY{ymgHaQ$%Fzhn ztAz8*A-%D}UE~_@D_3!vtW<&o64;{mXMA5k-YKcYlmn*n4D27CmrO7j1*Ilc+&E#| zXd-uKRC>r5FFtB6M+LU932-H!ay;EMMY9~p-rCAPfNct-Gj{{9_c{_SXZec-Pd!iS zPw3s3JMwfRn`8A^)w7WJ^cjIDvLi(7DT(1~MLT;-jd4Er?3pZmS`Me><5N2V6fgel z_l_Aa$QzA7%J=0LKb}GD*zo8aEsc1!f{*H9R|yoxBQ3XWn-ZNf0%1y;gz{Vd!}SKv z#d@5y>l#Z$uFugPvI1J>QMs1v&{q^#`pL0*pWO7JmYMjVrI6Z1-mHI^s;KK$*_w%O zKgQA?dS_hCeQQ*^!x@xD$SqFQWE6I$?P|&X^(n)CEc<@+xxYKrqPL3eejwjY1CBn; z8k9MA!aIADl|w#0OS`=A!`wW(GyU|Z8P=19$+G#3PK|}gvWei$?EYNz`s*LZGfqz} z5-l?0I&;3oYdx5HJ*ifx`ziaJPl2}YTfI|xBHs(|sLiFYY&YVI!@uTT$z3oxRpRoz zXs`S^kJ{WX@#o6>U*|%LejU$rbjwVF?%tYgA=RZt`JTP`YfmQgs@M8Pd8BXY=gze9 z<%&4@`PT0jVgf+{NqJdSd65J`+dy&yl&5Ea&*!9$hCUw~DBaN7{S~?$6t7%=ZrBPa zpj0t)v`6lsQOQEaEBxTE0|r#`OmATE^brM&RX-;avO`~ zkG!&j9Uw9j_WjVSE7rI#ewqDy;oQe%m=iDg5BXalU3>FXZA^leoAihVS58J0j4D`j zt{}KaX`Zix{nphtV!*wGiN59mr4JO10l7(zayJabnQ-mul<+@QWy^Q(hutT5FPc6$+0CI4 zRPdZ98PgEfl1@uBPsaoAYQF!t9qqM!z z?IjwpVgm_eSs|JxnvFJ4yb*Ko7lrS6^-2pFroZbSyz@b^qHP*;!>}@@Y|rQO(aFFe zE#m@cQv*KHN*B9*`Hrcr~D|&WFs7{X@MBePEzRVJp9X?myO# zlzNDC2T&90VoPMH?4J)xTlho_E7|9jSCDBdU;YOP70;DeP{peO57&F%3pz`@m#nX= z>&OUaYrZSD_tt!~8aH%%XxsHD^V3V8V@c9yCf0MtGryNXq33naJihU8;_=2~)AGmm z{v%ee9~u8DaoqLfW=_!?wc7o^o}8a}5^&~eoDrnura?vW)0nFF$NA!)fP%PPQ#Zvv z_|VFHxafsPP+J;;N>Q1!Z3K z3pa4cSb}jCDE5PWkW%t;eivs9g>K?b=M#{04fthHvI9aNIVr~T1a$rZ-~Hn6&ir{@ zO`mQD^&-o&xQHmSywFqoO|y#OTi#Tju~2dEshaM)1AlQ8QAXa&49K;oN$#S&?YjBa z-`bv-h8kdtX0S!O2@l;N;@RL!PT;eeEQ~}`)`;GLw!JB*`OpU1_?Qx-P_tJ>%drTjcMms2TT``w&FN>`>M^+9rdD&+DasR+OM2%<)2^K*^Y2wj}M@a3+6WBUO;d(ZfUwAK(Se@vjddwXzI30vb6 z0Jv!FUfs62En;krezkDN?lq*{Is3oYhHSS*y+z? zkx3>Ye}DD({^{iAw>N4|pCol<2(SWfL!H$g&*2ZV$A5Q3AO&@SBL@4j29}tcKP(~G zY}H>fG+8AMa)E=C*ANwa7RNqPY=r~P+yg(j2~Si-1^HePaPQW?e+Q|-8W{2gfan@o z3J64)njcszzRjw;ppRF*n|R}7@I)KYO`(p|kX@o2wNFN%Tbhx4Dclz*v&uB7A1yXG z*qykEHf?xNZg%uVPo`<(Se4c3A3xD%P1K8a&4!VlTYU?HqTB2A+XLZ7e%oz$YW2_| zL`X@QPqUX{nvB0MMyU{%O3qJ+G!s1|vZLiySM-M$ch2p&HeG_wUB9$H;+5<%5-AHIserr*_6Dy>XJy9fE6kyiz{H^TsY9)!&E*GqGcK(mM-KasscJof)u)ItOaMU$PAzg%j%O?S9KkO!;DmlXSpJj9x6_jlfg0z9srV3r4rBh!} z5K@!6Bg|_Y!a(6(aUNQ}XmZ~#!Q*|&-LWqZutDhv$?aX!W_^7jrf1P1Wr4XP9#9lT zmWh}MXOp9Q+K7E2VrIlji5^4Vg80PiMqi{XC9Y2#EN}|rq^an=J(FcL8djUDhvA;d zH(6rVWgN;1Z>VVa8rE2Cvhz~ygJ&aNHm`6Zbdn`c3q#pUxsEy*6y9?^&4KEle^H>{{C@O8^+z{ z(zI%F`Q1#ds_u@DFFW_QfVSb)gygEpUiqrqohxsLx9ZJ2mRB`AaU!an;&!Jy=H*{c z4GqC)c`&dsTp6BMexpbf&$%Zk@Jvv*HyT5t_2yY9=+U3LWgIN;o875aeU3L+gWeRpwN1}WY)B4 zBSHk4W}#y2VU8`-rO4)rp8GQUUmUjyP`a`#1l5H&?y$Swu_O(uF7{H~&iuI;>F|u{xsD*t|MwaBF$>K5@w4 z%LB7#5nmpfzia+7X7z3Pq{rY{spuQFp`KgEzf8NV{jJ!0dVE|7es@`~JGkT6`qTkO{f@`J7sR&PA3Nvybx&CT$Mq+1L&v_o@^RU`dh6AZ zXM3t|$UHo@_WYl2<>)tFCm*)Il_UQXKNt5-qth^+1>uvqonR% z8}B}U`mz4u#O{B7|MM4s+}Qr0Cznxg%l?Po$Q?L!mAMf_fJskn{Q=ThDVBsAGL5~W zmqn86uZW@E@8}!fbtP%#HVvbQx{V)`NL{v7z2g_(Cp&sAO|od_y~*QV{1P^$^JKup z=Goz$n2x-(kI4adwr31{6KhSf^PIsm<1f_i$xm^L2o&V$*c(niIw!NtxvPY_*KA15 zHjSP|j)&RJ(c3bWJGmG-m20Awm!Vz6{w0HDN>&0)91jrpVPD#ohC3&x5vcTTu@@d| zOwV+6Q@gfkBTuvu(MQcn_GS!Wy|77ow0@iygCqv)6WK{1|Cp8?baN2+mJHM(%N8kC z-K(ko;S8u&8#9V*2bDd@g&PsDG;vck1s)fIB0PZ0(cnoi5Q5^e!nBT7JdvV+8vuqn z#e}Q33X3+s`0p589`F_NP8>CiQg zBfCD27$Ps5ru}uY(qpD^Y@11RHmyp@OMwbG6iZT5SR@m4j58&vx>u{?lW!{3Fr}yv zDGpa(Z-UMu?qT3#DVIsV6{fIxY_W{8KI~ccM0ywikKp%foE1!25@w)sZ4>wnK6-C7 zMBJD^rJW9lUv^J%iI;;wu=&tT;o|E}vfHt%4bi(fnj%^h#mC9haj^`OTRPfClf);?qW^_0NLyTX8A&xAMs;sZ7o_haFiO9jpxYev@RJNMb z!Nm{zC@xQw^`x?V>cye4;gFLSUQieIz?N!8intjA?6eHEr6`aVfg}il6BIxLyR*fN%k;3dmn>g>HuhUSJaX5OtO~eH>eii5j3|SC9@o zS`)rf&sukOY_}*AFb*OAExdFzVW?rlJNuORbY|>M5153P7I<0o(R-7VptuYLI;`tz z17SRv*MO>N5QFF}(k9?V8_0fm>2Q3MD{!0yC$s`-md(tOekowfZ{ho$*$7)_ zP~m~JFrgIl;;b1&&F2Pk3(f1*+*hzrp6N}EC*PImGXAeBQvG|`Pd!j`dy^`d!S6*+ zanrljSrA+!)vtv)63` zULoWZrE=LUk_J8fc1a)Hs|lt<9e?WECoj!r4{kA|CzJea9_bD@;`Q3naEm`62semc z8ey@jUrh|oZxg;tgt}$ZP^EI3klAP^+LMKAA`NcgDHeSC(`9<&gk;0vxBoW40^!KT-e~@p0B@S!~q>%TTCFw?(ExcFNt22UWH;n65bj1I*rl z%G)F{&z$rZlR(1ND9-hWItK1(E(zZvNZIaZgK=I+P~52s!`o%Ud_T9M&TjdM3uA+v zMzUlC0e46hf~#vy-Yp-Q((KaPA@Tg0HYM`e*mNHgN`$??M$3E9WL$-)hEJ>0Oa0QudP@}1b{)6A-2#MuzRt7 zq3}8qoFahwK0_a5!%BI6gGG?ITcDH>hZO8{)bh1sz>EoiRS59Q6JYXV^xc709*(vqfIh7- zZ$_lH&oO%j@)RUuMi%xy9(?!wFYIOift?&lzuxw%2`yTY_w}iGvaEkyGHcT9( zg-jJA4EQdCp&1#3zyy@vZ#d3%b32$JfU9$ZP3a&d7G|EeSG*SxwrhCs5Q?oJ;0-Zr z4SU;2uUN#Ykr2UjP#DUSAwiim==YS+o?HF^_86N8!(l;01}tG}F9HQsV+1J*KuG{2 zWLOh(a+`B0-DT{~Ol zl?pJxQUMfrj;Q29n3LxsxF{5Zh2jHG?l~r5QJovOvK@JQSfPJ$Azmi%`FX4_5~a=s zG&e~Y4+2DkpU`>>R3+suJD`gNa7(@+!W`NH2YS6TpyNgFJ82{oZVL%$PKB1)L-vm# zpM@rT4uz)>As$@BfpQ?53en}d7@&bUZJde#5!~v(g>bHp8CuWxyU>8RLWJB6jXlJG zwmwUj12DT8Q0?dGQ}b})2T$N7yi{blz11ZvK zEGmckNC6Uger5Bl(I+q`2AD`nE~3MB<|R+XBv*IklH$!12UfDKm8J|*S z&Imf=1C-L?+ZmCzB&gL7>O!Z#3Rj`zdvO*0$c0RlaVw;|u5iH9+X7LPww}~z5w`F( zE`wIc)eJin8f!wr<~xQvDpf@#8zu@Gpk6j)uAnR>8N-C=czq5 zX$bjR2aqITh8-^MMguD5Py<@+))9cS6Mnp2&r2_{7Jud5tqc#L-bF1dfB-N)!oQ+G zd}g0YI_eWVTICxvULN-vjZ@(R83Ne;62J%5+&7BoA8Vc3TEB}gXm(nY7nTShT{00KLrdE@8XPwS`VVjOeP$2KPTr`Z(u!R5!(L1M9^K5~sl`X@D3580dms z2|XxE%xC$c9r@AB6v)NRr|CuufKFNN(<4o?>tWh?u0zowFuvp4(zK%%T2EQN$tH=2 z0#`KSpa&h?bZT^9V9xUB`g$P=6c!PV+E2@OD6eFF1N$L~nLZgeFvT4Qa9+M;6e2cn zV~^xGAjYevY=0?e}I2I0K+W6eez=JdC7;glayQcBz%SW z(BqH?8(=i%(N_2#;Nrpp7~c`*i*&yqc|PPDVn68!g8)00fpNq_bn=3>VTQH0tNZ%CMt;djZ5Q24r&xP9fA=UIFVXs?>|ZDV(L{v~x&w?S-k1A&nW;&1TF0Y; zn7yswF)BT770DJLs_-}sATxprV-n%kPthlcnvO>gNaBp)G&t=@-WCFQ&!N}T3zGK@ zxsA{_*>rVxD@5DZ5KTvaE&=RaF-duvXkyg!Sm8?^qNvnU<}t$Z8&ZcF{b?PkiD|_H z&VKXlB)I9nu9YXnesELjgi|n1;JbH)8M|s-# z2xmb`(!voVMHxh>I*E=K2B5Lv2>~LrvD1ZgM|CLD@*R3V9W)~x@0>NfCma zEt!z^G-OrlfF|isnI<>i0DFI@Vep{Kt);(U3_!LObWk)>_>k3Q9)iz%fH-_hmhIjj z<^E*t=#)~s!fj9u_G`4? z@^aHIcK2NMc+~@pKXCW*a$8spGvLSduYqq<-1mRLPH&3fBGU&W1V|Vc;Ul0s(h|;V z`H!@_E-9pHuY>b*<0^*OxydArD%YjaNs}{KR!YQ}c@%fF`PPecO_X2G?Czi%>uHE@ zHUV^Lh2aIrLg2B80;nf|dC+}}yZc4FgL+nx#OM87`&QTrc+y_e!$J%C9z66Bn;mBO z(gK?^TVlIS_!d2N=GfF39b9)fj^Ki;P=ib?pbKgDN50|;cj1b@V!u4#P_7V1Qrx;9 z+sza};6skUf$pP}zVY2Ito;fJSo-+29_m+ZCK?tG*F^{nBR={wugifrCiP0z1*UNW^f z613I3etNY^`d*Or*E4T6s^0v#^XBL4H@|lvv-GrIzAsS_dcrg^7lp&ySiFu?%?Lyq1HUyNRjcA z*UuE$(4BPL$Rx6i=v{J8;u~Ldi#0x}Rcw_l{!PkwbO5sT_^ixtoG?}KnI_RleeSA^ zxk)d2h(vrPpYSn9u-{BQ{*sB;v-))infq-0Wt@mI}Ncg zEM^dZC%NSQprX9{-WSnDsI9XKs^E12%8iP<0*ES}#GM92ukM$G(J(^${ElIP~yGnP-ZD24lQ<2WvdA^O!wQi;19B=AE~q2W}CR4hD61vlp-G4ctk z35Yd`3!>{m1AbBT=4F^p(nrj#j~uo{4eb;pAiRJN<6j4f0BV+j*vE#NQ(wqlTq*1V zA7MWOt$(faFx%Ll#C{w0r$9~jVDWU(9>J0q9uoT!`GF%=0>HJK1Qi7$oit6zwfBNU)Ui#8xWw~F^3mk6L&^QuK&2o_%CiMs;YFGv!r z^!bD+^k-oCCtu8lrn!ZSS|UlT5YRXPr~^dn+2UXL7<1aXcs}eU_0#-u^v!V0#cJ0p z1Tk%jco|!)&>G=>9f;tIt&zl8M91D=pN{076JGf5lYmV#(9<-rc`P#KuxQ#Ni8ZQ7 z%jQk^8!CK<5stwS75don>cUD5j2l5DZMQhP95S_K`Q_h`lix)fNk50Fh--&Zn62{w z4#Fj&hg2+Z##B{8i-|d z-LZ|mk$id7w%p_T2)U`Xw;;AM!>qzP14I_<*zo)6LDK)I5mfUTA49X)yVA*O9PjR( z+SHtrHi1W>ss;!(5)o2jq+^{peCCpB>UBTUp7Fqm^UqkCQFSQyXJL*haH|2QsM#RL z3~YAuM_uTMyN&xt&lQH}XOuW|t8UO`tpTKnGGz0`fTDV*VgrKo$>Kt9ZKV-TrPJ!A zLo_UB-2D?iWs;)P00@S!E;FRW%hx3H%T(?QNB!rM3f){^hax3uzIHb}5yQ4zx zqH~Jd6;!zAv>#dJcf1e5s`cy}%zURH=*^Una^}lD@Hs$H)TINNX~*i&$#7Uz9sx2H zT)T%Ou{}N{uK*AZ-FmSXbsgkG|HW~gfNh^?M3hiXFhfYfseQnXQF&X=(*tS*srHaSyd*ldt?nFin8#<~ zj2Nk<2Ba)rL7g0(t+KBU7PTo&vnB+f)XIGx*NX#}w9=$00`{$F@$j~4b0xN(Gv1sm z96}EBO@+%i&>W=TF;VPp8xsJyoq%aGDfKg#WOtj#|6rtrUM|z94$QzdQr1lJ9Y&c6 z>z=Cl-1oKTwx9d%p?y;v5=BUhq8~pXeeKsc)Y%YjP?zE9N*Sd@{)^*!Yl9n|@2V5- z#oww|y~zV9pldk-BcMm#0}0KKfl@!K&g)mMNmangMXv3+QtH7bJ{~GZ5$E@m!wL}v zu*F~-4vEoruOjX^(}qn7YT1uIQxokpo|4v@mRofA2&`PmOD;n{)UPW}NhdHtry0|uXprr4DS|v|2O$npwL#L?8*0IxLN1#$pOC5*qZymBasi01Ql*ej)x6rDc zW1nJgZ}hz$5MHLmnQ87Q@Nof5a0igtLspt1rsK_(dv*jU`6d@Uxjy$!A7I0gFxM_k zk@E96GtSk}hw^1rr?{&R%f3)Xv~RxVS;+97kqhOoU4$1vha&_>zz;b z&YK!Tw9*ATa~pgKRTY=PMfPDWOE~# zhU{a_LB1Phx*L#2DN%{TM$h|KX)QqU?n*PzrF8PM2cxyeU%$;9&Z`@EMw11wh=rqsXI2Hxq=r;0W zmy2;gxSB{H_F!zK(;4EImi}FKk=Y`JUntajlqwy2eUkva{avG#8362B%3*`U7A`(& zB(Wu*RJj56IWL2H3OHm`Yf=Y3S9NXZ`x zV*n?lFaRVahK8^OSjk$^oHsuS^CdgIu9rM%4z)je;7PYvNA8+~h)~6_auli2)N)7fzfvYTsj~-Iil2eJe}Xw94DQSJ;|1muH8v;@eke?$g4PQmmF|vUMnz zghzBolh_R97_(aCk6{Qr*a~dR>sNVCw?{^@{*S^4u-3K6t`|eq2uIvgyXJ>O9%gVg z*Nic}gdpX$PUNm(T(W*R;m(IApw~#MQ#p1FEwwsuX1-VARD34W8d~`U0Q_d~&wLw1 zRrR;^1c<*}gi7EukoeWRNah|@slcLk=Vq!1OBG5t0Xl7DA|-8rR)%0BYkHP zcUL&=j*^#Zd3;aN^u+{rXWFg}F#F-FMG1v`$F!}xj<}b;m{dAW!p)IIbg{?uNxU?r zvcw|}>1^a5px4h|U4qRo-xS#oavmXq=)#fR>%j8(sNJ-Kr{VWi-7mRnrTt6#@cA6%HO@A&5OK#UQ8 zYvAh7wEDk~W_{XZtqwrs%R;%~1t-cFh5Uc+`t`{F7PN^Ey#Cd4tM8cEN*dDdEfCk4 zW^wkj{duLinS~9m=H1EM`-}$c-$JfDPjKEt2_~|;tJYHdOTty9w?B-o3`+n0QdxRo zaeeIj5OU19uuy4SCkYLaVe9Sxo?7Cx`@_ioVfpGCQvukQJ3>9T6`rLs796+!I0=wq zWH#W7*ZjB;pR)BcfBh;xquh(SEDo=F=ejHg#}FP*YQ zea@PPSaGtHd7D*&xX@H|nn~oM2pDYbj3&qb;e^Pn+8Em?G`|$ej#vjlkOS>11H%u}}_^ zA^tZP(+xIu-iP}O&c$*;R1-sz4F{$W$ELs@+U>3{Z78a=%#pvb!xC4zx1Y6T!ceK< za><|CNS9xNTeu?DGa`StT3yF$+b|$CmvqH+KmsA%izJKfWJn4>A_BrZNn2==Pg9XDB!&hr&54&5OHI=O6vaBB zo5$jjLg1}y1O14NJRyK84Wn`wGtU1%wB2V^Q)|>O`juWN3896agkD6NbTFYAiVzSH z5j7wppi~hN5LXgP=%FbhVn9$tL_|e&BZeZ<1w=PkLq|nKKxHe+&3n!`;0IK zk&%pKWvyq;XU^XrU};VulJJ=>q-;$~hz8lExr0mN!mlb6o%d1G!6DW~@b|5M96tF$HuI+9B zFx#I_60piwtNeO_QOES)d&pA^MALq!&FW0#@254%ojPp}TDI2OC)#Izca=Y-`ONW)7VHVB&W^x!$1$w)#~mem+-ee={I{m&bXX;=vF3#rIuwb6y@Sa z05iSxXg;U5>K;BO-7OpvKtkN~xiqZ{37a5FtN^dMS4@&L;R2W@q#(EsaiFM~LpJEh zs?F|3OwtIoG|-)zQ_!6!Lv=mK1T{&xrjecQ5FBL%rZT~D8))5|qB*1t8_q?!uJqBn z+U`(Th!KF!KrxwYVs5SeL&#Q~0KN|j;7AD17c5pVv~LN#x!&K9(|%>9zcIygKF4#( z(IHyd{pyU>d`_n2#tx+oEhx3oZ-gZ~p{n^)?~ryj|hO^IhdeBRE{ocBeS@R}uzxGFJ2cq$|i$bbT_sXWE+CbIZNlh3|S z3A6wF_2mrZs^A4>wE+O529?Y}*`Uipvq4-;T5};Gz@a};kS3j|DTS{46*yd9;SqQI z=2C+v?yTKXg(qd(*rTrDrHa0G_kX_R%720Hia6QFN~}v_W-bS*oMhpYSCF1%c@l3~ zx~(KFX8Wdw$CmVC(c~e!ehs4GT?Boa4twl^P(eHBqFjaS)*$FmE(dyxq0ejnzQ&T? zaPCRge6{4IFOV=O+%5e_MP?hsm+E6*St?9c z!~qs2F(Xfe=`#Jwf5Ae85EXt)z5>VKh@Z-&yeJPkP&93>4$+HsjVK=R;Uf+T(l5o2 zzYPOpN79iz4H|X)4h$T#9U8B21^k_xVs{S@5~TCYA`aB!07!X`%{$)=BcKPV1E~$! zy9G9@`bwy)L&oCmAfM7apX#@2iMuae+Pm-mUUj=Mt(PyOHXlNqIm%qf-!V`XkD~hn zw%knXvg|Wq8JYkmcMOzGguUQFZFCR{{w&(-XQ`XJ9_@$4jKFm19O<&`#Ig*n6{s(d zt!#~u*w`Pqp{0aidDLa-QQ6x@S}gFWI1>EO9q8Gx^wjZ8$1tFz0l9sI?K8qbv0Ul& zr)5+YRHws$SHy}0-mdm(WO4NBpdT8B0*ca&#&cg?s+Ad`c{H&ud>-93sn@*Yz`Z;d z-qU_fkI6uZcf5akivB#VmEK=^a6f@!-CNvtx+&8>3}h^3sE8JYRAd07Z0k%6@>C*f z|9Cc9z%lheJr8!50kxA?kn);nuex%x@ofe?yHoshBamp>gp6b$nS8`oT}wqCqJGNh zkuK|)Ktg5(ENBq%r&fzS@EYWF~v+|%_Q1@CqnUCt)S$J*hK;r zF6uACqh+816(9?-0X#8sJ+TLc+r7jD^JW3umq^B()q1(0tg++4IuFY?zv! zz_{&qSL$#QsJybdKL*0Ww@U zTMQV7drzWd6eQ(*0<<-UmCGcBZ3{r>vGS0L}!SgbJ zJ9`TwanWw29%1lz+kQ*Ypx`Gx8Ni8%id!L++5Z~=nkUD8ERSgp9QkyyvS_crbXy%H zS1(Oxg>`YUa9F+tb%P62Zi_(J!9t&Y-A*a zRjQOj{1Y1mlm8+~>Csednd;}$ljU31y?aP28CgxpuhQa2nw(SlnE?|!sxlTIctU(9 zGW@tuxiFl3HZM<#YNC)Cy^&!LvIi;@SDGKsYb~vs-zQrlb#)NO_zGdS(oOJbds}%3 z9tbay_`%3|J9*i-?tl#mO6g6HqH==XevP~u{oC9@86>ZcO1%~I`PH$Cv(v7Ch=1fb zQLX7L(3Lj&rF{O&CxOEJ>-^=7{1sxsDpMyNJpNGY>)DqeE|C+zh}>QmB{=U#V2HKE zh_&*-emqJ)fVL(V7X`z4#vn_KW+tcM(MGafp`KD}z`%Qzg^N!%g-|akE)o@K2^o{b z8_QKi=#V;sEx#l>L$+i9WZ+_HyyX!!URneoudT$kX@Ug7?3xoWzp7LZbd>&{l10Q} z=9l|lzb`(UujW+)Z@qlHtTn1!q1fc(wS_y?J6Mlz-+R#bkLSYd1M=7TD-0x^BokK_ zgYQK!1(3hvD~6f1oAX*`QsTRq$m6}pvs@T2W+>v-hrN5bEm3;;S^H>50p8&4gjQ5s zE1v7U&*sCI^COD*EB9_=ln!}A6<-RqI^k}(2k#;y>#JrLx(J0Mx^a}Jk z#`fL6S(<6v!_ZsGF+-d}WXzXWM#)o>M(P(^*KS2%eqp{n47_m%vi=|nY|YS!gW)tb zc4+XSq2-N;4QMo76c8A)5)as zZ=lX)pRr84!b3!Eu#I96G+vhsHKQz^eQ0?jzyT%YQa@Mifhl^iK) zz?S~^Yxj@;WWd1NKVIh*zhH^9-kNraxL~7WT>L}7ECVh$_~`WJ#$<6fAZWABjGe>2 zUcD_05u?PsOv;f67?{CcSJN^usz2Bf`Aow-ptR7TS3Svrcn6ZByhD>MseHa4Ph7dAgd{eDK+jy zVv)G5Pxd1;m>c_PswL(xasYtKM!Gd}eUOw~8O5T{k5QKyh6<=F$y=K3@r0yb z7td&whu80yIrpbj;hM*hj5D*bRxjg8O2EjJ0y-;Chg5cSOeXBIUdP68)XoX?byo?4 z(P5ik_r@TXHCyBtymKj;6&H4%!fIDpknd~Vs4Y*5NWJ<eb(!R>xfj4u{)7eP6%<-<&3zf%8u2se9o$$J%r(aiJm-KsE z>r{e%eaf3(3lT}|Y2O!6-N8gWRANckRrD_O#K zur(d}d8=);L0$WE{lh1(vy6MU&7`ajX-WUNcFpu@py`X-?neTKDxVOd z+kD1V4&;UWd*H6c{qf-2`t$dcpZ}|R+50p`<9A~ysjrFfz`T5wa^KyB+ z^=Id8Oz~6eZ8LdzS>$~Ip*Jl^!_Cb9#hK4LMX9BZsx`?EraI2$Bz@}B-%4505#KpP zG;aU_Xz^X6+n$PHV6xrO!Mf4;xJ9EGj3sco1F<;6Z1a?IBAs#ilOF?-+|q9<;7H1+ zG;ROo2Ru|bD}D^3W>;!rX;;>GA(D?{OlFoi6xvmlKZiqQIkh#VHXf z$-!!)Sx6#8GFit_Z1c4%CSJJN#_O*_RT(ol5E49PcD;?Ay2`5(-uYRy3f z_R67{fB2b}ilfQ^2uX-2aTEnnLEWf&DiuvMQKM(h>5;2SHqtP_!=F zP}+4vU49$YdvlqYs}kX;7{{H}&{yaoHaC|xnn^>60A|Z)yaQuTrfNoPTZe_ca87oQ}QCF2YWdh?U2m-oNrJN-Mb*~j7E{i%Dhs%(J$`OfuTqa_~ z*IA}_G+Q>2YCW^q2~Ud6xt<2dinfeY#=KFG7?SEODpX;f%te-f%8eTkg4Uh%55Tli zoPedG1#yFtf|VIY1c;%xq+<+Ue#dO>c9yOOK%z=)F1kntv=)<79C04R!AdkWD{&lx zR!wK458rrkdDT~2vlbnTjfIbGLfh(;n_tt$C|97&H}X9Xgd z8HL^pdo+T8xiN5Y86d)%|5@XIOpqmaxGaI{ybJZeOpu_x9?C_J#;+;fxRh4sXmw^4 zd7RF|z>Sdl6@vXuSWx^Im6M%R|K{CtN%?x~GvAZ_s#hJVNKi%>*M|p3-yo{F302}(z>1XoxF3PRJdbr#$g50O9yVk!=d}HJm~_~G5=1~ zVa7An_!T(Xl-9ZRT_-J(RckG~*7DS_kqEIQNu05DYCS?}jCD54802-`u*uRh8OU}T ze%L~od>o-BindCc(=gtn!h*f{7gQz9C_QMJh-x0_viE<>_Y%5ANZ+6F6o11U}vbceN4t-KiRpFy0m zj;w4MKxH@?*c?Up9otB&QyE3(_S3q0tH3d5nosP)j}zZ?mDfyeeLZ^>BMM3YB<{u# zN6ncdCP4t|69hx4sk(J(P2cdYyNC{{MkSVYs~5lAeayE@EI=n+b5a7WSF* zzafzFD#+c^hLqm&|MiNdd-P)o0fK1Ge8^0$%xm&N` zazxY)0I1bxSOB7p=0hR~MDH^BMP&Iq*FB0MIWrcoU!-37*E_TD-f=)-jEo>9U6sN; z@7*_bwv}@azPrWFP z?q9d(9nhum*fl(TOz~^ju5Iyr4--M-r?X9Nc;6GJiigJly!>M-dmoEpsje&(LZyTs z<`VGbV)0Z~z9G+*f`9nsiy-;^78S1ESu*^eAOl+Q1ZN4^WC0jm2KGPT&wq4?%WfE1 z*tP-wj0drE&r!~4f4%?*-}P+R9{#!x&W;15K^Qh%a4+w}%a?hRvH{<3k;MMyE_}=@ z7|(fI;xs*(h9VYpmSv{-yJpuoMLm|69=}8jb8_|167NCblCa|JEwG5&olZr+s&yg} zIm8V>%7cv#9U9BczBhY7ER`%~;yNnhCOMonOp-E<&&Nv+z2WDL5r_BHIr@_vo21HX zX@}R}k%`OX?|D-LVY!|%j3;j|tJO1A-(SLJ^e~L+&BWXRzL=Uzu$ml2^L^>YKQtNNq62hlUn8*=J=hx+Oy%0w}p{|QWs2E0<97fI}S zrs0+Q&Ov5e$-;VM4-F6eqK5AfpmPNqxgJ&GjGk|Bi{LGFl%Bf1UV*ClkTwM%*1^an zdsD*zVpx|=9Y=E!1!b^J1AX1_H8e_%=Xmzg`g<+ej?=YR2821O%NfxjNs}I)QPW1JSob>g^08=KMe{-0PPH z`hEO5C5(=)tC64-Gj^<&~UZ84?2W)Sa zKvX5QsN*aHJ-Beu?KsRXrRzwTKz<2t;^AnjgBeU0;6c&d0t?PyD_?_YECP}m9p->6 zV?SHcOdwHqXuEgz&!zc~uF`HisNO8wd=RG1``~0K$UHdLrjtpF;Am1iO3rrK^wPG~ zajfYqN%ZjU7@B#VLl4a}*}9{RdXV;C*%frfo`ABGSpqd9M;Rkp8dY=^?yzZaw2N18 zB?H=tFw+J{D-TDaF-RD9RN?N6Igz2vJQ~(s_W&>Nv!AwoPV|8)+g2S zc)BC837nbI@(iQmjJCQo=pCwNdo{uxwUz)`o}+P!;6l1WT);j!*db4cXbn1ka2BAL z4m+A^k04OLb45-RhytWc1Z*(4t9TpWMXfOiGDm+x>H#uH`LlsYrhzUYLyoq$-@LDR2wLrDTe1I;!@ z2P%Zzju$8~o$f10H{3|OBq|-Z>f|o#-4GI(ltuoRv~pKZeLCm+iD6Pxz@BNR>!FYm zmGi|j{G{Y0Gk2)Yckv}JEQ1CRu@p3qDroufavm{A0xLZE@uKpBD__p8+X z{T98=1mepW4@fL9Yv{zLQK9P&r%4dKvJmZR6lPrCmv?E8tn?m9={oB^=v#>CJ&x&m z2UN2({1DrmTwyQM8LgZVqq3wzBHTW|RNkutP%m?q;Szxk*8Z@aB`{2bpgwZ1Tx&?` zmkSYQ9AKq`o91FD?2Hb)c|P06X5zYrWk+<|(Lm@fY?;1~=B1!CfW(FE6TI!v)85xO zP#JzJ_UN95aKMnxDcZbgw)?>SmwCJ6zr+nMa?PmMq9Xb~l_lC4z;+x^6sCiemsyHE zE#!SFM&NTdeJ}K&G^VysE6RJLK9m(ua3AgPHp7(8k&R`Ww1V~fFATl*Pu;&I@p&XTJkC&CKBa5cRbZNU6P*H(5;@-|^4lwq_h&?<`QEB-U~5AJcz;gYYgbhF z%@&2dK~ro~V&9WWs9hv>hh+5O@JnGw>&H*kr|hV!>&SK%VV|wrGT*xx)^W_^IVvl< zUR)|_{pNJz_Edhu%%KT7-q)HA?TCSzj8o?mJiG0ji(S7MX(E3@w;8UBjsAM6L2{H? z1U_qhVRbJr+0VXsZ3sw5Y2W*N-`;Vha_Hmh&n9-9nr7JB71vBN=d$qe4mN`e zK_JasG@85)fj7?}%8t*~faZK?!K*IaM1?_?0J-M;3i*|94#g=)sF;Ds6M(6$(|u!c zcMTJ1VnJ3thbW|~uW)p7Uu*q@C_1qUfkG3$gG?FZzcXwDv_pkSy|n)kR0Az&kPef9 zaGfDixz9b{Ml@pY7>T93`JrxW$if^9_$Dam+=MIG1zS70{XBSo0i2IIJO>4p3$h7GC>p#7FI9q+-M&CTZ70 zWmmt3Hr0hhzDZ)hmRJ^T982(JN$fEzoovl3X|$6^E#|J9mpE9Rh`902`A|it?s0)! zN|#+CN2Wm_C15Kj5DpoF+6`U!J1)e)d$zz{>vf1%NKa^dkI_#vh71FIOFHFEN2jPc zq%28v9tLOoL1xw&uz_xwRUq>Q5W8O}!$TSE@IFpXQ|>J~K@VSIB5k>8MpG`=c5%l0 zK6f5|HJgpT2YSy8XzncKD3hgq%no|X_r9l3OSwrHQVD3?52k%7Z)YzlG*iNM2KQ|Yj)pvVSaV7y`$3BS z)bZ=p^3&5q`_rQ#!O5oT-S?(bP>FB4oiJ+_?{nQ#UMT7)4rxBx9er2)4L^7yW_r>? zU7pZtj&03YE77BS5VVuO+?g$~m6gcV*RT!5fUO8K*u z!JlQQU$HhT$J{_;k3%=dhNJI2bo2ij9Y)0%y>4GRlXv31jb+idFzPaqV|~xjg3jh= z{)*k+VePMNmqvt!?Yc`T?Rj*j-`pUE4;T-?{RQINBaxgr>i5KGNpF+NIHZKi#<0r5?dCPxxBE z_A%XLH%n``kR8DKmO!TdWOD6^$}?2RI@^#6k+M9bbv--tw2i=K_o;KO?|2~WW=Z3| zZf7&itG8_$-bA3w08_@(vbo6?l|9xW@iHk7o@^xx&TS5kCmeghY@Mg>EBk%$KI^(x zvc$)^poCrbX(n@NJ*cJ5On=M+Stpmvkx%B&=RcQtG;ZM(QPeY4|W}YYUpRk%Ku{N@t#T{+MF;6ha^ot_e@a>x-#U z&W@=)=AW!i*rFH~3Dm+I#R65(22|1d!nlNOVFWqoOeK)Itm_=rxNv+`r}+v@-wD9H zg#grS3;(Uopr(UwM)Q$O)>)rj2_1IP+gn4fKj?k&xJ=$IXR=zKorP`!?*I2kBu~vU z&O=F4x6Z1~==JZ^&`UgXp&M!h&3?jh z46~wwcuO8rv}P5@!oe6)R~imySYlaN?Z`#yhmN-v9@$l(M$3?~DhhEe*7p8iIIc^& zl+7W7I`7ck>4wsV_gsyf&@5G3|F@XY>ftJsaa4EWouhlMdsVrVT9-!by=i$`&+Zp~ z>+{$xiM-SySECcJYRrydHIqvt5Bx72_n)|%es_-l^IqjZX4@z;I#l?$|9wOu@U?D_7(X|s<+gT65%b*T9#!ql#3R}Xup4EcXQ z_U1wC!mGyzR!_WVxo^qYS0u*HXsRz-k|`UpStXZ6IPT>~3reS#m+IOtC!hZMVK>EJ z5DXWS^Gpd_vVxVGN3K4)@tVcwnk9eo#Z1zmDd)DfAa5lgMz7CYS4mp>DCz~(!?NJM z%t;nvU)*R=rl$++*T@ z!`37;$(h|^LwERl#s(L-@jk;=`pKsC5S*=1ha9^<3>i8;iX?8Mu<<*Qtw6mtjw3fs>oe)1;Z|zQ3XDtNm?2tKb2~G2+%2^(=vc1f z11{;k829Ln-!>3fZFo@sZk5nOe)7!qlMg0?k5N9|xoQgr$tU5L=F!TFTc2H2H_Ik) z&DN}c-1|;FjQIE8tSySgA=1a839ICDPyd}hdphopI2mYyfQPbKo!%^ZnV(Jp`IUUg z6PN1!&8MP6FHGco8J{@z-tv9CF*7qlh>SFPNY2pAf9O2NRYMFkn;coTyvARXJ@4V=j>mI11@GN-f48a_Hfo(Cklr?)8Cdx24bR4}FcssXVB%>uFoBa$-szOq_dc zVEV%BYrv0}#w`cd-`J>MUT7f5H*A00nPhdl{=k;^r_F8 z?8r5N?2{V@GaHfnwTFXt($^IiqFgo0CafzH3#DS33rSuL zjw(Sb;QuL@YV)RK?<`)yd$1H-0gk=XH*L!>n%Z0|l<;UO8*z3@DZ#Q+BVP)sZALW|x&sQEeuAa0HhM|l`as2wfjrPoMGHQa&k8dq0vwcJ9g+~egtQ1SAuqB?3A4XYw# z!Umh*(u@9i5#3a=N4*Y^d{MHP5g+}X%R!1OxbKhZiNJ_<)+4-gV^e5KRKUUZ6UfHT zLgjT63vI=n3KGnMQSlz?Xdg77c%n;n(}-s`E9~4KReUMtjv~Z^l@&#=Rt6a^Fpyth zy`EMU@06iG*u|DGH$}`^K1K1J*_e>4I8WZf%p(N`>(J2zI9Z^X?VYb@bd~s&B(%=F zm?JX=mGkC}#Q6ya{o;ir4Z6TI0D_QkVxnv;g;eiypQp;tNzgDyt3fGPNVg+#;~%D1 zOkqxCTa`*ZkFDZH=HSD|p$6&zWo!L^5Zfv#Yf`aWmEz0NKOT+3q9x2&D9WE1!K2fpAWhqW4U&#B7)0S}#8zHCB53xUlDtvz`vRCw>3u^xnJAa{^9!+_d|Z zcmDnxgImr15$7l5Zr{JZZT9$)UAB|q{Vk8bXhrR`u@L_E!@^FA2G7!07S_Ltx#_+f zr92LwwclrL6yLv4;oy)Hv8Ev}s_4fE1h^ESO=}cH)(AL~o;BJ^t&Zx6G5;1-TtFGD z(BZZMwsaFe-R~oSq3qgv_qowelVF52{r6IlHs~leb&!v>rKSHZ>UOThJ8~QVl*3B(26BR6a4+pc6ugB%UK)U(lgZ)&X04<75sA$p33rB z>Ok4WcBr{|W9duB(&$2`L9!H#mt2i2=0DXC4YXsHt7PiJoJMv~*%vObtG;4n2XJXHckV+OEpIW;R^|EVh3BYc-cO%<*6MaE@NJ$RV%zacqxSS) zs)~hdLR~d3SI1esx`~G-w#&HLcQk0W0@X@(i(*W>Y1!K>rFf`p@Py+ww?de53MkHA z=+4;(1O?C`_}Y#A(EJXpS{XomCF%lx-GQN)1*@imwJy**`LI5971#@O#wT)?!br6e zqpaB+Y|l)jPq&3nKyj9_dvKeqE8c>1+fZjs{J{V5S6M>>p#qwQ4XE0TVWQhr|8?6%$B9FJ6^H2O)TTxn^DXU%phTP?W=pX9&5r5PXf`=UXIFhbG&} zL}~@$;z`h6CZQdVx1^ywW^u|iYz-4v8MWRmDqgW<)A-sBo?`cos24?zBnhN^tHhW1 zQgS4W8x0r1l#m>O)+4YYmlOiv7-V_teCf0skg{wPmn2?bATkGKwWiQeW2hpCwhkh! z^KptnJ(Wh->rL2)0_kq>zlbWAz%Pg=RM{V5D1QJ_LR#|Z9>;^Tib2RYsw_H)RwR&a z2T{NH(y71?02JS1<)eYB8)keNFJoCHGTclE)e0gg(!?!k8%?0X8Gzv1Au2 z^BEpTQl+rQ`lsaVL3pA8u(uOtq@mgjU>H+KGm^Ythph{!@aRjALw&J5=2ztxXuY76 zE`Vt^O)Ch&Kma2d zSRYK2_N5_{1jn4>MBk~H7GJ&sSz)x&CgO4@qSS4vZk{AlQ>bG@q&Iz)zcHmc?xJ?B zN_$yAY^YKx!d@P`t$wEAZEAytQFpkf5b8iew2{5UXQ{t+#I{;V`4vp<|2kCP2dS)g z;EhTk&xO!j9~eMW8LN`3XCeYaUSn&V9_LX+hA<$?z#ZtT2Htiv?XyWsY^cQUM!5)x zEPT84+j+$TcM6>}+et+Y6UN*?0vJ6LK^B)2>PhG3TTjjRlVH5#+b5T9TwCpKxQC4) zNobKJ%3erXk|ll(6Ve1Gzd;}ubhC((^(7-y#s_`@R{#)RDR2u9nh7LhMKf28Qi!E( zLk^zeWlXDU_uRZ`-g|_|c7wfsc|&GY!o^0Jm3Z=c37n^|q{PDGL2=6tlp=GzpV`yK zmkH)0v{*j3d~voo+>(r6tmrIWH8W@?zGY1{rJb_UKuf81pscBIwCt6JJ-7tE9cHR+ zUgIE~ikW9ACyYm~OTUikP|%2^C&*vCf@+Nw$N?fM~;Q*@c=)iyu6q#3wvx2v5I%1hB zw?2gr><)G&?KL;k$LyxOUK6Y1OTX=r-~LkRwiM(%U#~nNCHrg(x-&?G%Z&h7d#vdVi^XawNO~%lPr| zY&>L--Jr=6=2MN*ms{}yXi~M;CNQkS7A-MH0Wj)ILQi0bY&#WBXAZ@X;N2}JI3!bN z&|;T|*I~)P{W}OU%sdA3&3J9P(EKTjLd+;Op!9+QCS-DvVb2EY#TN50hYdU&@G97BG>Xv(EX6 zKUa`Q@v|Ij^M+Y=;FM3>b-nbqxM#Vzpbsa>R8)yq^Y@;JzL*I9W`E4DMd&OOZP#8( zD6U#Ofe@RUh$A3moT}1IMf*;vIc`&B_!n{y&;ooh#9}QL4qv@6>pjH zLD1wIhyZj-p*w9S9*`Pm;gJf`4tS9dq$J*P`1W@B@=?i8RkD=c(xCn4Yo#Q&lv!v$ z-h8F#s?fkmxg+;Wh#C`mDCJAMIF9QEX`aQXdoc*VAp^DD=-wv7Gb9OrOGM{4^!t^M zZMiE=e8X5FTn-fXC68G{mpTE=BO|QeZJ9bD{Ly~A8Gx8zh$T`h6uM0iK{o35zoulP zHbLwO(-?QXz4qvwF8*BGXq5`2T2m1)%k3&J7&3Q&*Y6h}+;2k%AW(>Oz!V`zTI?pE zkQ|KB>5xpLif=N{$2M)0OI4)z@G}`f6Fh(m;1u`!IZ5R!jnqZZJ}>FCEv=KD&2k~1+ZjiMORImc}ueR z1}s|TXT%=htDES`zY=LP+^Lm>8I&QU>83NOk0vj{&4GDe)?#3ix&|l#$F&nR_7$!~ zCf%2bQIaKX)0P+Y-m&DcDF}~?6bkd8SromLCQ|hd1 z`|R$&v)=Y|dsFB3x6d8?I~Qa>e>8PIynR0M?|iKN!l~4SGwlm!|1Pj9XXPogoc6`M zzl(+TA4^j|iWq>)e?L~KE@aw&y3zjW*56Ne>_6X6{roU>;d=Y$4*R92sY`wBOGA~P zpZr~Vnfhh2{mZ+*U;6C7>}!X+36PZ*IYsN%Vr3`(_uKX#t`@8XmHPT8*? z6^Pd7M8`wFwm_^5q*QwvL-a`Vfph})Bh*2@N9ly7j$VB1l z6cg={3e|!9bZv(xfdtXLmJZ_{FJ_9OUe%c{E_+_5V^M-bIHALWo?1X%)iowsGsdz| z;tG1cW*S`!yYe&szj53pQE_8efuCDeiSbmCysGJmxADxhaUNz5hAndh0O=??3Y0VpFND;GBy`Rr<_$_1)HV8>eQ_mJO8dNq>I

yGvn^eJi5pYx0fN-PhMt76Jea0-*K8bNB?GO1fx@+GAsFiN-R zzZ)B&Q`qNi7W4hG_|lgS4!iO)H#l3bu{StJjP;6v)fE14z(&G-I)mYVXEe@s7=>$wc;M;up~>$kb?HSey5JnME=}7}oQ5gbGblIhPA{+N z%suD9dmo>&T5eEMkL%A4rJW}Cnhmc2S!O9_#22gloXfL zi6GSAtCW1@4_Z2g6w3;GG_>G)rI9;hsC@)~f6QlONLEZyZYp82iHfN9=#)V zsj-ao^^#M^t(<+PwMu-??-X~ga)$0O;ebYOg)W-KgMvi|gp3ZnCd)O6Q%!e0-?dK* zjLo9fF?Q&E)$MsSMx+5G5SuE%1!$W*0%_ea;79V062dA9a>`1?I$a%*# zxT!{RU&!K))ds%f#CgXMxA-@!1M-k6CtcGfeK_lo6D!Jt9(vZ1bk68zWz5$oI9Yav zviF;sY2u>;IF1CZOX?5O#AhH{`Fl}J!U`CG-}uqwy({`9=^fmRk321@c%UN-qrOw} z%xuwB|K?p$i7G!LZV!_P;+h(?EZK7&ciz3T`T1(=e6!R| z96EeQPMdYO=Hr+|RIxEfOj6Xrn3Q)H^(^_@q1C68+Iyzo(^;Jfj#ZXXzfihn_aM_c0 z#T*=i5|;O{r+S||3|Oh$k*R*v&PAb9VqW=Gj-*jZlwGwW(wfWEbkuVG!ROf{lcIy# z1Pqp-PxK2~H1s7?j;nWGbix+$N;C{uGKW{(aP+%I3L=>~zDq)48OT(4%aYIor_V73 z4pTgeglj8Q{?QMVh8daTMwF|HuPq{MF@p&H@xG7`=x3HL%OI8}uTF%BUQa>m`9swm zSlFF405XK{giGbsHuUk~?oQUC!whCtNVe*6TzN`BOEd zCk{x9K(O;Z>2;XNx0uL|k5TG293{^K1FqB}Z0}NsHl&8#R04`uZa`QqfUQ;k$;x$G zDHVkl2nMK!o3HG~5EyKQ6cQOj7d+PBdu6Vy?ZoQ3ifj3@-JX(=ING8p<%{ztlD~Uv z^I~oUKtu+vw_nM=+2@EAAQ$oCsfbcQJdg*w@b?;j=gCE!2D3=5w>L$sL-)TEOc;2+ zMptPYi$2p#=ho1W7J!cD8Qv543BX8?p}cwRH7^q^5$EcJ+daX)YRaCgH2tq66zIj@ z4R*N{38br|pGrHwhTkeGcd&Un=AM~#>UPSP;~u@A_FV*I3`qkoC9ny_GH;pabJ&I> zYX9sLI3zTe+-f-5r8hYck#M)-OT#mh&yyqB3HNILV8YyUUXRx&+=oB_@_%py761T) zQ&3&eLkIw%;Q#~<|NrHQ|6#MUfa9X~_}^^yit3YOH12(}HXPaU|7NoTe0vKjJJKa~ z{BJfp=Xfir<}`!sn5q3gZ1x_~g&lxBWpktX+Vd+^{YKZs0?mQbT5$q#5t}{4F*q%! z>C+`*v$g*F#`zx7qZIR*I4p2$S?UR=C)_$|rg6aQZp;jJ_NNZR^6YnTy;|O<@o+=t zl4kWi$*Mwk@xz-3mwXEzTbHz`bhG`r!98WHF$rJG+qxOXCOOw8GY^}RA|^wxKI`gP z{8y_GGV)2cFWc-{CzdsIK%?>@^2>er!+Q_DWt|(F8=oxv@MdNN^9g2z1Fu!9)Y=ye zAKXK$-uB?+mc`#N{O~T|{o||G57{MCX0ARTg$jFdtRQaL=<_SRg&WVvQk_^J&4__g z2oZL$RY4&H>|p@_3x|cX)8vBDQyIz$i&L4T44rAN#`&=6ES+n0)7b_si_B88M^ajA?L&AgFodKBcK3ReMHZDk%YI~69J>j%qouwsAru*Ffuk9_@fqSye5Go zBMc45AkB4Y+phx*&#HaB<_tNU6}hwcAG0y%9fcz?;@dqm@P#^vA4E4}g^T4_;3a;` z#MwOFk_J-CuHQbCxh3vACBcx^AR@uDjV)!#m=3@;UZc<ZUsC}L(*-f=lC;=7(v6EBOz$Kf^Dye(bXWnQco4GcL^=NUNVkGN zkB^9HQ1%|c6>s7&a)$nQpNj2FJK3(Z_8W?&YyVk$>VT67={9L2eIMVxIcPHMwU+FN zKkz{~ypze1c;;jY#L!Td!VwT@k1qed({5eJ)u!>A2fAUtcr)7S$W-Q2s)R(+`7X8(CE+f1X-iglre>cyLBiJN(y+>2;*2Z0 zWS<6A2luq9qw*<<2?xSb7)MBXHo+Z+&&*olNR` z&Z>;c+6YmK<)sc2kp?}lYZLE!n!jQIXI&og1b?Xdcr<|ddKcYodwxk*Qu}nPBa*p` zP$@AhN9WQNLp2amwu=fM0VEJ11;vK&wFax{9ljb+LW+<94Wj)8n?dwa7{>&2VMLXH z|Gy`YS|Aco1&IIWUr%omQujO(*9-K=!=b<|QPIG{CCvdZ=}s4I#Phi}`nCq$bZ8n1 zuc49DyMpsX79x%NOZr9})6e}8CW5Xp*Pf@FZyoG=c(>~LMJz{B;83CsUfn6CcUIu5 z?N#TELY@_ry6<86--V*FQ!FT&*-k-_u7-?@0S21`Ofu}C+$LVk-eazyId(QE2+nfy`%yTwxcgv4>LK|J!_jPtJ=v9LGP-L)9d_)sGqp zr>+zzS+L*6{JecSddF<`chJ=9!hv!%K%|!6-i6;)$>zV_A$YC=5BXFz%7Rx7gEdPP1n=5^pv0IEYrR?=I{0lu++=AQ)*QXgvNx55 zNIvsWG{Erx{^7!aOhD!T{&4&b&i}*SdpX`-NlqMYzN@4Me;pL6%QU+%~IC#*I57-Rk> zoJGoIu)a_)hJVLrcenoUD+e;ZO9FZEJSSHUYy|%@6VaiubmRepz)^epP0`VZ>Yicc zyVrrNT$x)4zJwc>#$Y;j)S{Ghty{oYbQ3hM;Kq)$YT$oM z*vnbni#{^jOs(c^k+un)3yu9JOdIwyBG`AIDxo*-*Sri|eV6}r2dx~`e{nT%&T;HLa^G)SX(Wb&YxlF=?*s>6|+u7edij8-UoMS(jbn#ye z`n=jX|ID@c?wciy*XShTBVY-@nIaDz*Zh)ek8k;Or#%r1`Dsm(Q-J-zRd&a&wQgeK zIDeCDHC{c>MG9zbDZBwQ)dNKA`=K>k>bYtH296*$zEWL)Q_f$&CW;G1HA8_O=Js)6 zOJPlsa*uPAE2DtH;@c%J&6Xo8BuzFz=tVGLNdW9ab0n1a6TF86{gM~@0EUzx*=Q2r zB^(CtX6t)g;ACq{c5YuQb6KGL2J(*KGE^5z5C1^NCJQ-8EhE=Zn_VVMSd5; z1Of88paHk|7U!6cA?h56{Ztrkt&~JP^+Z3Wv557D-59MgRQ(aeQnhFU!9Y1xjtWdbdu17m)X?gbwc| zoMprq?Hs8ABNHV8OkrdVGVYwZ@j26vheYWIW!BIB;CIm=sDg*6RNhZ{d^Fv)rIKXH zEU0D4%?4f9kv*z}F6>^I12ztcWiz|b;V^n&;0DF5YG}!PH$;x8E&g8U;9@}FHomLR z-5^~3mv>cd0JIdP!Z?5~K=)lqTReQmFq9E7-|-2Q8^Dic7o1&njV()PaI%3$7)uPt z!;3oj90U5QhxkI?a8#c1X{R_9&zXBa;_?GvcW_*dHG{|=aAnY3wIiHKx3ULmjI@8x z7gAmCZmeXD?zZ5g`bVR7(p|9u?Eenee;y^#0}#U8ffKueeNmiDwVu8cC~Oi!?R<0g z0C5P%t%X?$+dq8d(E$!HSkHz(jKm`sZEe*pn ztR+!4oqE)#?&77Um$(%&S80@HP5AQ46+se9O{{+(3W+M(i0NRoU<7H?uL+%ha}xP<3D8Mdw`pyECIA)ZJ5l zfNzgB+&p(Gcfb0^X$5l*022w{(p@t`z7K3eG07>w8CU^hIy$DFUc|;5J#!d^b&SJ_ zG}A&${wSdSlgC&=*8vp3@%N7bjK%B!%3}x-L0w9fK?s{dF%3ofxRZpYKsnnI$FFpR zZ&EBWN<~Q@ZNgqaUPOsoi|rG?BFr8rct>a(@4W|P)ZDqJBqu$_K#bU@tWpGD>m(@w z^lptfwyIBJ?9S{#{$@UO1-c>tI7et$1thU3RGL#rI{GvB}f( zSS&UPw+bUts#RJiQzNau0L=jQ#N|%%nBO1%qT_7Nd;m>7M<&})l~*?z+B+*bh63y?yKvKGOLGPg&%q84vDWD(VLUx1U4uR;e$fH*5Q(8mW}|a^~6TDMv}8>bs^Ym>3`nB8xQ~b!*{>| zsr;Crtl$GlA7q!JDI+b8&b&K0x1Uoax$2Q7bKJ zFfjrC{Qk`sd`7%_{XWl6!#OX2lTk=o#>jwfIIAr{qOvh4De-{BXTHTCXG$o?8vdCa z=qMIC4eu6oj;#A=F8~-UcOTFD@lRS-HAJ8^q%y50OiFOtN-fY zfy;IZ>_(z=vmj%5j6&Zj@KtpyE91p4W17a=6K5G&9XyH*P$ej&m@1MQ9EtKMqXJmj zN*DkkvhtK>D9STQTzWLrIyeACOr%Bu03D5x)46B{2Y&tTgcJvIoQlQb1S6HDQ(q)n z3oZht5w0h30s~yobc!JTD;lo24>4que|(#XMpJIuiqdB6=79eWROsQ1;Ymwj&hqxg z3q+bFcLt2rihwI)|ECxHk2UzDcJu+){_P&>|I=iCa?nZ`h(229a+w`3J~?Pr>2muf zJxA0&gOtxYq4ckVRw9EJ=&@;Vqt}Zj&6I;yEN?_QI8Lo6 z<(oPW>8~rW&7mYU@{D30)6<%Tx}(Q}b5CAP5U%LG-*{`5`Mwyvv_B1bo#33g`e^$S})KAj^{D)s2kx3g`J(0X4-%sPMB-UU`c$K!p< zCFghEO>#`z22_~uZ>%hYD-W&-1E1ebj6Axh!*mGDE61_}ykGEWPo!r|Bpve&eJrvl zN*^u_AbZe!J_H<$Hw=h`F~!U>!2w%%5gJ8^D@qXh|71OVb3MvPo(vfn|CgO43Na53zpB`J)IkU`IrkLN31fIW_GT}$9i zXdh7ne?sfpeRfOy$O%Y%VMNFgQT3$dWoxR0bJ5rhbgzvgfcZ1L+tbI|g_7fq0O}WP z*9Q_xyVRgeU+H&_yc>u19j3p48=Lh~PXn_cEZowvJBby1xS+?F63Psf8Yu7SX`no_ zC1@l402RY}5g_ViK5>}+tn*)CsdlrT6wqc6MArlJI8~91mi^tJx))PK#l9JRd^_X1R?u@p5Hu}f#Z|QSc&o7&qE2u!&^a9?s=G4k zU!kw#XypKs+PvaTPnCRDv}eQXfyD(iYaa>}!M=C{wlPxFegWPRh6YjIokM%|X6ZK9 z>;DsRn*eSCcmB`5_hh{K`-mKzM8qWgbwtj(us@M<^_+L;i?DGzCFVqY8_B~D6wICm zay31+h&^@o-Qw+2WtIhKwvE^I6R~KhOnT#NL$OB`9Bu&3mlE#Fr{npBvRbLhd>ULD zOn_VKp4Y-@msrxbEeqt?a5n+P^b4~3Up>Eht&+K+xq?m8aJzksep|*x$pafXD`Uq54en zC+^oL>~lX5GBT>C57-);4xy#tzZ<*t(OiXwui4F<;=i~%jMWokYJnclth52*cs|=V z^+`*ulPiR9<-tfw`1O1k)?xP{dQn~9$HPJ*B{TEUUx;a}=cr@>yLeSm7)b{e4H)SJ zM~%PLE00&mfGd8Dv%&D8cgJWYY#lGq>YWcM(fe33lb)e^83 z6sR$a;!so$c2P(g{(qvhOrStO>)-V~v?Ze(g8i>qJ@%xdJ-18oAx7L(p@xOe*k18^&0bN(pIoA1)brN*820*>0$!#kIWfsJ)F|USl=P09tahZ z#Hy030EHvV^>arllexY6xeBn=2F_Ls(2~m)!68K)^1TdPWNBrJhfX>$s&-4ho>Jwy z1P3Z}IUs=1VmP$BrGc)V0FaH%_VBS)Q3g?f$2O5VnfE%B>2B}auF0~cxK4!7tvJE4 zb-2EDy7#}vs?Aj_Ld#F;sw-z7GQf!eZ0XB9lz(rNp#AAhabz@EImi#NMsUWznW;>A z__l+vvJezX;M{8lYncrT87Fz%*zJMws@KlM>W(I>O;T^Kr08a1%k(Lwu zDO1>4jg1!XNX$ibpG1R{K#_Eli_JcG3$H*CdTXiHsr$T@Rv*pv2M##k{|x?@fG=P`09$OF)BlR{LK(}2x=BFdQmY2l(LohOLb9eDDMj4JB0}Lmd>;IRp=%X z@~1}cYl(a6^X_PI5x0)QcYT|?D8*GjgTPPl3j3u?gSxF!>?zHsTPGRA^}eid{8^wf zf0Z2JQMo@!jec?Ahhz5-0lhK+pa)ixKqR@%W{3q7z#vY>(t#+%AzY$xln-oCOban3 zoTG-v&=@&kn`BuTb+zEiuejLtB?N7bKnJ1-UzYLG& zjuJu2Nvr3K%c8&mgOoFp1TJrix-$~yjL`4lb`+X2Wv0Eo^e#$VOt~8^;-fmIysuq? zx#HB=n#O2`V8t2eS+-2rzu%VNd+0f=&RmqxR&uFW^miFs5CJiLQTLx#e?_r6*MFsa zDC)Xh=84tyXN~ena9Uxp4j_>OKr)|-X!_28&Prm+k(|VkrfOsa6(aRRs~?r7KO>g7 z41IOi(Vt1cSevkrz^cc!`+Ld^FU^4u)M0V(o}Mm{!_T)3WDs%xB-%mj=%vZQH4{YwB&fb^dK*0!-$- z+uS$Cly)tf49=$Wrp{V+fU&W1DNh>n^>?|bOZ}v{Gmn5gi;L$5*WSxf0k+?oCbi5F zQ4X&`NW~mCPFz@C^vFf|Q3QQ!HEXJ<1H2i+o1#7$OM8Y^P3a8$P28|j51r}Eawtr|2d-m|LDm7fR4PR5OPA4_Wy5E zPXD6C-zcwkXc9*TlvdbOIXgLp1@9>4uMMYXW>w#2HCz(8Agl|Z+H& z%1rg(8I-XeU=o5Nm{F04C`U^Bpw6#JrjT-yls&oxH;s*Myh)h@NdLDQKx-3@eoZ2LJ-&S&s?5cUhyYfwf-w539Bv7KXyKu?>Q~qqwnQh6ZNdG^lYYOfxV?T z=f{!MDxs_^-yS7#5cRr3c^e=My!6TkyEp(uOOZnzwSQSLB=Bth`7}dsq<4i^v%st2 zynzv3WaB5L3A#$|;{SWT&*x)@NC6%$0qrEW8Y29;6^nc#AbsRi=#BUMkP zsEYe2Oz==EUL2P-hKm?OfDh@k{K?Ac0~XBp1CS1XcR2tOOylLBfwDvtf_QY9l4!(r z6-4_o|F_QagmL+|NqHr9vqd9M(hQ|2$SU6)_jNF4DugM4KbJN^BlY_e__dGlliiTG z43u`b%X)WDS44nrk#?(6VJrogA!TYbiFH3bruLZgYb-kppkdma+)Wb0#b^rPr5h*) ze}op)wgN!rcEtj?iL6nkRpF z)fHr1uz!wSR3C0Uo$@$lbH|d!`}4fXv$btlcM7CTAwx*vo90=@V7{A|ZB$m20~bz|JA_6AUE0soUe%`UqJ@Q$nN^IG1V#p`Og6 zP+77nEBQ)p67GM5uB(YdrQW7+80kSS^&>e=Vpkz>oMOr`xt%HMh(6@_^s*w;Y0q;$y^>qJQ8k8r~+DFE8!i-#tHdY5;Dr9d*Kuo^sJSZAHYPYsrm0 z=&yIxQ{?D56;n|_5*+JWwVnAud}nbYO0fXm9HS0SQy`pqh5}*F#2&4htBCez7YcK8 z-ZEzk*)IkF7GB#_^!7d+Om8C9N=pTlj5Bhc4Uk|n0QcjmX@L$HWi{@k`IEN84r?wr zu;BD6=|435bRxGhhF4rt%2B`933!-;_1HsZq?p zkrHxThlVcQR;qZZD;gfagNSC}!#IeTK3+zBgTZQ-T&~KiPV{G+O_!Qh{>@zj1o&-E zS{<`G42~~B^U~Z#&&Yn22gkMZD|Nh$MgXidH|@f(yJIJ$+52}5R!X}@6bNtVFVgH; z055GyxUlgW1q6#{&)3*}+s-Cojqs!ckH=+ceuk7a&3y< z&f6^(7O!|#I)O)rLFo2}pcEPP#+eV6I*8X#Y>wY_T79d933}~A&Xu~S?pnRbu+J7; zNT3sBB|1HOnH!DF&1ctz%hVGVbWe~g4CEaJxjLo_eS<9xWbVPSe*A%^Is*{y`-RBX zqvhHT$dL0uAVE;qd?;w1Z*%+>6 z%}!P9zp<_-jfxSaPyD}$WOO6;>Ey0BoZOaYeiMK({!G-3VZc$s409!(P~o_b2>e1N<#(?+3}4VAju^8Lc&C8slZ@RhZP;(VjooQKKzoi+m4 z+ko|~9lp+u={lAh3^!BQ0iy``F`ZtY`Qe^^O2Cge zkv;?48G# zJUt68BU)alLF{Y3iKm?V1yAWy4plNGdssi!Bmk2D|BCy5Ga)*)P zI_N|S3NoIz+{?~tGncAj^vAm!e5E9VL8cxc^n;N%HAs+Axx_~>p*Unu^BvPcZ}>Nw z@|vft*EYAGu|!B;d%~1Ld#z>l=EBvs52l0H+IJc+FBSZb=eY#uqa4Tp3jNDL`dRb7 zC}pr88APi|G!aw}1OVM|zTu^SSQc$zt8gs<-ILGqT+RBQ3C@P%pCVu+=)^zWiJZnr zDhkrj>0&*&i@@GFV$jt$rjTeSlPd)(ruZl7L>16j@;6jGbfOB7vOfCtX3U{0hn+{M zPbtl-rh!P#Ej#IzGOeM%IOGI5tPg0Hd)ULTq1p`Q3oO{F6J{RLAzNM;fgu7Kc;{ zF6n0EW7V)-`b)%Rr0;QX_BuOTH;jT1?nZM2{$@(KD}5s3Vx=JT*Ea>HV96?$lX%6$ zAQ%?;3v?plTBgR+iXia?+A9H=ePoQFj)6*2^v${aB^8AI=Gw`4b0;z-;sf}{J z8oNmgJL_im$8=y4s+c+LSZcGnxropWVRXP&QC&G-5-XPE_chMmf`3W`Aum$3)i|oU zxz#joD81c0b^h}9li7<^+fNsRDgH^0k=|+fkafBCDG*8l?6ztzTXXCN7hiSN2}2pW8|!nNuYZ#$bnwiZ%KiFFD374$YWe z14qAZO!9&b)7TW8dDX_Ko{Fojh;$}fGeg$%}ie;s>P^c!dA7y9qy43V31ExxEf zzs_x3OQYuI^ymT!Cyisiy--ePINcf-$$+$qbeYxTdlJ{ffFwe%H{3kUd|3;k1G$$Y4F@^lKaq zA7zJop+1)P*m#2BZW0be=Mb&=u8{sb9ONVE;z^qW>ypaq^Vu^4NqBS{cpNN&6&m3@ zGfQ-ma9uuCAFO1aHMJs2k4;Sm#~+7^@t^XFR2!$3EkVbHtuNc~y8wc(K}CLfV2W^s zO12yob8Rsa#2{fL{T&wPt&gJ-RgaM>QZUw9CxYn84b^jTc6(2?^D|V+q%7?QBe6`can$VfXy$1$h(WV3iIog+v?&Y<5Co5* z>`4GyKUNoFGoI`}h@vSagCGZllnc+5pc_7AT1%2+0Wk;)PoS#ubEoj)8 zaU6qjS=gK2Zg5H(LLzB`|GUErE%OQ-Ke2~<26%Cb3LAH+mXU*<&qSe{iCQd=3?gxe}VMsjQuqcB}D zTU=DFUdh}b`=Zvh*ULbeXdriUf>D69z>|$T4c%X6wFP?3mY$MBy=L*Aa=_EI;w8LWp>eUum%WbN(_vhpa<0^%rgr*5?PM+Olhp*OHhbZ@ zBV~_B`fMy*Orp+XEEezO1V)@K7i7^keFD|iW3@s80>f$UD%s3bf*$Tr^8wd;^h=Dk z>*#spGHAkU%zb0ZND!Wc1f#&5rEuSD;6~^CA?-8h)#y+rp++hKMj%}!GD@ia8sUE z>C>T7EZHwe*B15oS_nOih24x1p~48Vas$JAToMM2i%`J!w=Hz)Y|A;!FrNy#Co^`6^_}_O{NYq=r$ooj0;Q3g?*}i1i z{(<_ysWU!R2DKaPWwrCx7WO4LGK6`(X55h9r>!`DNBjA&@;bMsYWW{cikoe34tL&m zy32?v*Ury%wgWW!6h8>i<3S*CjQSB@?{{f`l$AexdHKv+{@A0sc z1LBQvC3o+<196u1PwIeh(mHl3WP>-sYmi>M+(hG(#}GH?Ol6ULTFVLl_jvk9C*q_ zES(svVX!x*DI_&LoSO~Aj|QLsn28u=>>HID8^ymHYGe#pa)PWRqAfV1&l>|y>d|(g z(T3U4X9uGljH8|4F>awTKE4zhCdPX<+N&ixz&P6WM}S(~sgObIUOn$nD(r2Ea8|WY z&ob4AdX)F_ZnT8B`eudRJHUG#KXX0P!X!82-7^^nf(Ji;5v;!+_aY=-b`l>1zgc7x zr=c1j))HJ5d@uDtgQpB1sUCM`FrNQ~V%BF*`= z!8xholIybLO81god*g1EajhClFCB2H&$#MNq~KSQe{ixNsV6;ECfwOeh2AEVcoE>O z1ikDOxm4rT)C+&sBPr z08i7DWagKQn)l5#>drK(xIZ#@ztT9fWHQ*8D{)vYYr>nL%9T}eF&yok1uxH1{&ZjR zw!a-sV!uO**KJp)R+VewnNJ@CTT0$Xb0vvzdB+?)I6IVjC;tAQwUD%f`>quaZgV}z z7*hB1yN9L8fX=B!+`iKlo9MUtpw0dP+1I;-E1M`09&$Sgw;pRBpVSfO4a_Dm4&{V9 z$#IAS*?y)PuX*)h8~VPYL~-PY&G)s zD{=;Mf{)fzj~pNBa1!rQ#D9mm?UIic;g4d^5xp-xqRUMsI{K8ra_E> zYifrQCv%8g{t4@n51SunG9n5;`W2CH=eDUA48`Y4$7glvWgDK)XA^(4mQOrULo@Ny?V_cMlII7-Tr4H^l11eXCB?;rVVKI#&}4FJg8bub zn@Qqh^~ZW9L9U2LX@`m7KhobE|F&x)e?^fc4T z;;_nL_4HKJQXNE*$x>0~M)@{pRk;(7(R?}IPzGPFa+yih+t#Wl!vfDX5-G1JB{&sX zwiPvP6nB{>y}ModoV$A8q4JL;me~5pC-+{?$plx;Yt4+-`FoY|M9#3Hw1Y>e zH&w$wOO}Q!row7T@o|Dub=z&3vz5gXl{x)wDW5lZdvoi?=WpO8TzRER`r6XKW<>#9 z<)sc~Oo-a!u=Fn*+3&fFb$#pQ6Y%q`^_S+8lr~amr5ji-tFql`I5%7)G!mpWUt6+L zdXVst*{N}esh;Dw!bRe8y`omhJ=1br1yRtf>6vGfxqr1aqV&yh(cAK-7DSF9<)KCC zW@1?5ctx!#PlHHXX;l0@mC!oX`5R|`1-T5ToFBPi~P!TMAwWv z4{y_^VznN~CbR=i*^R&29yzzqhqk|P^1qeXT$0tU}=h~@}s(TL;M}8&es+V#MKUvJ_nC5;WMEkf|>$!x}^G{U?CT34N z6BU;$@(@z0dkdrfxj8!Mp7)efy2oB7k^Rc^$U9G*E;YygdTwAo zl-Hg1fUa+6xaZWRX6=VHqsGJO;q{=yp26IqB^qsVV%~YpM`d&)I7p+uM*9oeuG-5_ z9v&6EpNl(w*m-$tJk6$E$t_9Z$`=&AD-TdjSU$Cbv`9`jJ+Lg z-!vcV(HcJvAFUZ3%}5&ez%=(%Hx`9Ao6Qf^thUoyOyqbD7s@2?o4y`AP{#ba_j$38 z^y4u@&MTDb@NM(Tz2jdQ#k`ZOn*%CWC$*9%0gcHs7A=XqQ@NT``foD~PuFPPp8RPR z`mUq3&AH#`s%x0i#Km@Igv`isV#+K3>98vkf;8>Hqf`8J8CdbAHM+6WZ~J3;XKuKV zj1#Bfo5Kf*WB&ASGOJ6QWhNL$v|4$`&Ky19lj-Ey?sU6Kdc4)37&^|CT++og8~L(X zsiVuXvwI`x5+n&T(X5p!!*}_M!z>_v+%biEK^B%h~MkXSb4H@#GEE zRWB|aRXsjEw;Hzi{&;JW-Sxrx{A|l&$%w_wAD;0kzIkc0sU`aHhV6NbwlbQhr{QW3 z`e?%c2HdC~9+J&lprS-kT`{WeX~-MLcV%CgL>i#wywY`1gN!s6u-@7iQjbdui` z>yDnYc$U1l$O4|^V_4>@UgG&Pc+O&Z^!8Fx^)eqry4;`TNXeDEyeqrgL(h`um0yXg zUYp@{tr_ZE37A|Nsp&)3%B8H7JbSm=D(7t{`Kohg z^IZGpAMLHlz0LY}IV;IqgJoO(;UgV8TXyu@PhLIxQTcI-e|d&~8?m#n-nlL9wOR7; z?XsKL2e%g!p*v%8)x58EwBK#BxqjN+Y5n@DD%b7vxronuwV#{PcmDio0l8NJk18Q` zp+^i`RQGn5ht(Qh?Jl})g)!9Z(|u_w*j<@ls0!a=KNg_9cZ%cIO4QZtKmQ6Oe))L3Q+%0WZ)xJ|#;+Y!#&V^)ameqlTB%Q&$GTd1_xa!NY547n zr|z4|?^;|>7e3xMVELy0dpB6`o8r}PLHKV^r5c<*3p8-AadS_{(wA|#x46}9uhh1= zaqR50Hzxl1MnCq+|8w(z>yLL_iqZyp#`?Syh}HP0TF zq#njbtQYD$o~`ef+q@4W%zkG{3N?px%dt`wSILk|3*Uz0mkOuzOw{VIRo^TG9N zhbF~idef7e5WIz zTs9?oF`_ED+KyiZ4erZe0`g{Wcp0Qixr-^sO|HJoq`$l~S~0nHHd8Ko)rE#>-KN0M zRrSK{eX-X$%vB6`{qH}1U8LWtWbspR#kldp%K|={;Oc%N&vfN|t}I!L7`ON5s~65~ zVp>A#-hEsDA@Ba!(Rp=x!K&V+0!#mlo{nwXXZSuQ^2t%C;>y6aPcyEqw=a41Bq%1j z$(-LmR}^dgf^Um+WpyU*SoqRFK2L~QY^%FvblbBKi-h_&VmszHgZt{V@145N*V=q` zu)oak!Pb<-wwQe&L{n9!+8vAb5)}@z@-rj8)uk)GQ9C+mZ?fmcGzmI<; zSAGY~N3_6<+LsleppNSp7|Vyx7#i^{d9iJYBw9WCWc+m!z4+x_Jtlgd27ML{?a%sb z7IecsY_#EuhFq6Q8Vq?<=)M@%27YKT61WFdGDh8EZ8R26)mJhRz3$v-BK{~!X_zfO zv(Z$#u20E~!Fr|9Ouh?x%3Se-trlRcfZ6I$!T9rMC-sA^L1_qEAK5HE8H#uxrTspr@{(Yo#0x zw>SIM+#NqpKXbol^6`f|4)&CStuPuoSmRkPws`75!2j8Wu>@!-Ix1lbyYv<~?ZauT zfQJDT-0t8<-J^yGIz}-Ubuv{YE9B1w<8p%MQ_u|OHS_f)%s>(&f077A(qV{T)&TqF zG(?U@DIYfg!16^)v`pCWXwGUB{E=Lc8yvU)(IQIY>brfUikL3Wn*OH#5|fA?hleXb z)+9!k32-?_@r{fN_TBUEEgB@e)_vRJ!Soch6nTC23GXpD%dZDW<@S2i6ZwSd%Q+Ff zl)gdf$$nTL{({_}9^o$*EczD%BTONrB(6-2f*6qSE#2-4rk)gfkKii{1)z@Emk*zr zBT4ulbnyTF#Vmhmt_}bUoL3!*rEEUXa4Q5XN5P|zAfyQ7GCeIb6AR*K7d9inE}+EE zd(cf{Wf4|LP;RmAp=Oq{ZxoR@S8T!pcyZ@}P#=t$`Ho9QDX=$Sl@A0OA9xPes>x_m zIE~K^T@{A+apCk%!>et;1S3jKY;S5#aydcD7kt#*YwiZYvT7WTZk$M$un z^wWbYR8exw(w0{UeeU^*!fWA4>W#}oK7!5{x72Ux56B^d|CF6uU4Jco_6_f$y?)~K zxrOJyFL9IJuopxS?#kZs*YUPL{=)9J+=qv;r#OdpLYJw9csu}KoZ>2NoI*(*!#{q8 z4Zuth9sXyflK{suKq<0Ab!3ztP-qM~Ak{DH#-g<8a4LRKcp?gxK=Q?s;Oqi=k$r<- z3r!O_Py1w>oWjRGpyRuE03%YI=J?OszS}p}upH$!bO#S`>$)7Wp%-~PWY<~B5QR>m zyVpNKL>!vhP!ok!R)8CISZm~Tv@`QX6BkD_wd#e28`Cjtp&UCl%)V=0a|>!a>77to zc>~NYEpW;5a|%`cL4B>JDU`pl>@^iI6mhKRHpnQR`aIJ>+%{NzdxWd3Fw0e{$QX4! zGVb-Pg7?5$`SIiPzhA(xC8uxNez)WdLerkr$+{@k@}lTcH0dt*_cKE>xl{J(nbSy} zDCN%AKMqP6=fDc_?2vDg9U+Xs>AsTB`E{u}OIp7m6O&_br6`ptv>04)+(g`}`2kEX zn!rrMK>d%cJ4ec58TY?dpZ?3eShz(7tqS#`=xEO5trry;aJbb+13l}byZ`!;AvVGzDVok-q2xVxN*G?@o`Rz! zZAwqeY6A-URO!;T;(UCYUq#~?T#jXj?jx%Od_K>!WvrB5F<|zSH-Xgmd+^D4G)p#3 z`o5E`mUkudwQXkQiH7gf*hF3`5Xo;P)C?`1`m%g4b68Nh1Zv%>$A9YXWbYjLZL=wZ z5I$od?i0qXK7jdB*^~aU(8?i@0xvcl{ZsBv;YV5ewM3CW^l0Ptktq^s3&>sDNT4T7 zusnZssvI`LrZc)eR64@a7WkZck^~~lh?@~)HI0vB&Fy-WH7?kmH$QfO+&BNedny$Z z@B4K`K9H^`UJM^7sCV{tCpn%DvVUq270;<$D9gH`=oziX85L=9YI;A_(t&ed(1G&G zt06*>^FucTqD?AJRSyLsF|G=Q7`Us*Tz{G%>I067Upog!;0H)P8G^n6AN3hj{H)*} zVKo0unBzTLJ{fN7&>628sZHxP*xY!x;9zmIz_RX?Wy1iW&;_IYj>a z-n>-vXfTGFDR^I^p`Q}m+C!YXsirS7kvdO-UHJvzvbY`CxV7;@IQSCRIr*qwV*!B4iK_+-2a|Xuv2GB?@^SyGlJ+zj$7YPc+iPbTfrR zl%5d-#R^l8aF{J8__ahaVvQXO8Nv%i#z!K!yK6f>s@$*%@&lpnz`pI?S25`ZvV)P; z95T9&3?IB?B=g33Vu$%dsm|K?G=K2*_cde8kIBvM8<%`NkG(GZv6^?vdLVIA-l`)U zhoG|9kp3p3+VKS(bsNd0|9#=YSAmSz+!$qLMshb6_Wd(tyuPR~2Kfc^5l6)ph18{{ zJO+UR_J`j5H?_k5Wuu4(VEy+$hC>7TX)$;Ri&TfrE)7;3+3CV0VO@mga1;4M;ewsI zlA&yFR}QWN2wO?&qg(3ZLO_yz!Ie=}(!61!y1W-CL;68+`mv43Z3wo&7}uCNgaJ1X z=>x&QX#0JuAw{iOW^sT}3&Zfcg0fP@Ozkk)K)lZI;syn_WEBQExXRfo# zeeBP7KY%c!E+TC?S74ZD_w4;xmyWmS73C>Q9eU3%ZhBAXo@L!T5qa3VEP~JiW}|9W z+z8nNGDYMuJIO;oSNPsl!D96<5s{OEngoTS?1Z$B@(Zet(Y>1F&g$+W&`_Q2x(-tBO^o@^!F>xwyFG7`taiLr?P?=%KS%6m-4SDFQ}}nsD3=Z zQCT~1jMyXsCCErBBt2#GmOqpT0{DGUTlIbHm$w=Q#r|(3`V1HwSFi>0L?y631 z-|>Ce7ehkNt8;6Y_t};0fA@_7E?;`b`H6WDwo_LodPaUYZBsD{l~*-WI~z0M5PrM6 z%`nAV$G=YvF|V0Z&22@XRG0RO!h2|b&WuOVTAh=zeP5y3{VA3l!4!uz5k^Id>H{vah;ipz@ zTC<*aSZtk`w}{aKvt+m*s{47Hcyp(u#hqDad$@7{RIA*Bh9b9EggV57P9fj*kYPkEk=G+s0cc{!&sd052PUXf%8h=1mnwV7D)x&L z34YrH^mFdIt3in_-RHG>u9OQ!1moqNawF^=}&_SKt%nOorDP$9*wi*@flRkA^38+34rVw*j(&X`120;sw2wwUDGLsyRo?|$oNj}7I3`C?3OM%` zIaVqZpfZluna@{OU);1A4o`=PkijMvFW$hlnX7bvb@K?dMYDt|LM7{a zIjqoXZDE4hA0HM9-I=zPn#DlWW-DOR@r?qb-xxHGNX+S#F#hAdiN@gdZbSjM9be|T z6qk~Gv-czo#zl{kJH~i=U8`s{(h`F^#f`PC@U_%WlD|0v^!z_(gnqiu6daTPA)b%RM1RA0)bM5HuwJ$J$S)m2-V99j31826K3V(Ewr((gZ3 zYI(HhD}o)!z9xFR5Mo*bEHqS85-X!fe-=AE%>{dSv_6J6cIn6hhLGI)jYr)W2K zxDl0AESWmv47lvZF10*wAp&3G1bsEDWom|lNdWkL)6PzE4Gv+1?Y&bse(`0IIpkd? zz}10@wh>r@w*K*`hy93AK0+fjJTPdBCR_Sy&o}>zrt|)%`i=Ye=Pc(q$2j)p*pfZ6 za}Ec`-ZOMEN~J<&(;4XcNGjucdRb&x+dTD>Voy4zr+R9%ELPMX`$%(^gR8_Ks%IDJ*z=;IThfoK;Jx((@p zD-U9id&iN^sQUlF<8Pdh{zj^#vxjrpni_>H+S*@iSMyzcN7-qJR(4rOfo7X6apYp8R=M#PIL28Wnsa)FuzE;|sZLIfY zw`X0?Uh|o;Lq0c757KqxmA3@E)wy0Y5}D$1{xG zx1+CzANFEfsJh_^Xb80(P#c1z{~)fkL(YW3P0==Qwn6g)U|6l5db=Yb9lA9FGnoy2 zBoz5iEI>XAY{=HT9-dINevWm`ZPx~-RBnw?foh~d+JqxL9zxxrMpQ2Rs+Qy}U9rmg7-(IBQCA2m`` zf}&_{0rg?LrPk>NM{dV~L+8P+YBnutF|xz}IV?EW6Zgp4U~1Op0*ypnJ6t?s^mffB zQ4RL19ef09sw;{k70ILX)fm|$W&T2^^Db|I#m2zZ@fU?e zpkYkNlgqC4qET~~@MvL(bZ2qz_pIYguRwpAHYQRW&UI(Li0~0MMmQ334`e(7sfU*R z-Mc<{AdMr6qgY@=39woRjQr5k2-(xOTjOKrhK!nwGS8wx>jd+aT1b99sL8L$81J*`TXeQIOOg)8 za^ct&2V`24v)DvD73>F`X@Z1)D7zXx=oN4ewlrW;wQ6p)LH&~uoB7@Zww`D+3&k-G z3i-j39N5?(tU=jAzQa}`s`xZV@5#?_eZ1{EIKXLx4Xs{?%>*a0;e_r8iEG!V=d3^Z zrm5czb9s3fH)sMxL2mClUBB$!a0x=l_7+zzMZM0~<3Mn9@bQdDxz3;?zsk!-Al?kF zv$spk+>R>fTzOmK?h%#vexT}+5EyVf>UFtBLk)sMLv>k)lkY{llCH{n!ScngpY?KX z{Z%P@)kt_hAmM8_5OCTkx*q;l?YgY7l^H8g-xc}Ib@Sr7{})MngCmYL^s z*PZ_k_;FT&y%2a%1!f4uHsDi?eUB^9T#Pxmsy0V8tc@ixJ6Hb_?G?FI^q%?}>^KI5 z#iW!|FYqD5dMQrcw)z#}x5Z4r5+9C{jLX$um^|?J+xrQ-I~GbR2dCIxPr^Vu#BG(! zqkqhiQN)5T^`#Trj!|r|j-+EjyqR!^@z%>z=L}=L0FB32!SVHwn;p(43{FNogj}=% zZ|s*f*~Yu_<^=p*1C1GzbuQIDt#z&Ogj}G*bb&C1`m(qBt>OCTA3-!Ug+Si|j=!zN zPh7PWKULNB2s~L|!MoPhE8)1b0ouwT3thJVqt>df@7gPDOAI(FSgR*Vzw~|`RJn)y zA^za~IC%C{^nmq)Rugww(nYLV7C>_rk8=(B-J$A+l_x&@`3a_^QyseQg2-qPI(EyN z!-YxLlNth_O~k(sg$O~TG!dmI)xq`awTH~wR~yV!K3=+Il%nKlpmDpTG|uca!>jXR zv?NhP4Xs^k4fS9JeuZW{c@cRe!M1nho)N7IKr425c;aanoH}AXh~lZ9N0c~Rx%=xE zSa&m-yBS%7DanvK`Gi8BpXUte9cUj*BMI}%*3bYn2y+%BOHVY3f+k_OM$5SHZf6Ew zo6g%ZRq5c@hhZKJkfZohQw}5+o%A{4Ttfzg5Do2#J#%v>ihdI0i?P@gO}g_QTz|dl z0f$8lPPM@; zXyhqK;u6)&gIP3p5+YijpShEZKGG+ENaWKnIMoHI550V2t)ljJpJwdQSSCz%vXGKy zh88xy z{GH#RSG5ppx`kjKNmGY#*RJ~c)qfbG zfyIC8@HAl+_IhBmKk2um5e3|=4bpw&un=ij?8{Im*@tkKhp-QwTp)LCobor(vL_Dd*8^9sm2dIy=b*qGkxL+Y4s16 znPFq`dz`+Ip+JOb3eo80&q|@mkQYK8$JaqCB?lD)o{8*I!TmZfL!GK)xg+|VP}W7G zFevbO-Kk{blG^rlEx^m=8kZ)zAM^L9_UNsm3=e3&oncxkp~LRO8#sy%CY-xyfySxQ zLF;&LrMVC-#WTXrS9?aLpPw?3M8A+eh+uShw%n}-84%yKx%<_@!WRsAySN(G4p)7` zIjlPgTDYIDyDr?MHxz2Lu{pKn;FvQPa#GR}PmBK5XjboIx--PknLnH%V>e@i_HgqW zt8-9Q@iVw{=P>EfxShu{5s2Jx7Xh|!w2WcGkmqP)=9oxX;vOsuF=19}^ms2t*3D_; zufEN!)yNY1i$Y*Y+nueI#Z84+UfkW!R!g#2?_02?-hHr!>kD+W;?nTa;gL`WtuJPF zJ4;cqNr2+rqXSy{gIWXqS^zQrbHCnHN{Jc-5WpDqUrs#hVAuoJ`0vf)SIW}on2_vE z{MwS%tme{6ivD&?q83zpb{oApK!V#E2)J0(yr6A{fKF_Hgj1KFSp@C=H6je^u_{6Q ze0C45k339YdGY0)^wEH;P>pCvW^>ltEvvV>Pqg5vi|>}SzIUf80IR(UfeI{;7?Bl` z#x~mmDOGiDK12&1?E$E!eb6=jf$+~^I*4EI`39cBZZp3QIiIQ`Zz^e9HdK0!PzJKvU(tprM#`@0~2o7sn@bB8IXYce~auwDKdjbV4i|FUV>i4>HZ|boj0SA?gtA*!iN?cfo^N zw+pnJw%`w@OrJwOODleEKmTzj#y*a50Npzp%YsUr-~3%;oEZDrP;C<`WT-Brs{uL1 z<>??E3KDR0y}zZUY27+6tG(X*kzdhtB^9K(>UgB2OliVY7PBRP5wCvnQ(4%G(r1(U zN5&w&FMq&*3^56SXc&?fSD$cr-f{T$Ip}w5B3hi^E3kUHDe{Uoa|Ti3wkELu4I}qm z!ScJP=i<*+SS<}A@!*>P3z5(CP?Fo$+qc{{IKKTA42VH>j**b+S2(gP#1%J4_4#f5 z@g3VMJ8}>}o5tpg2Jy*jy8_5WEUKN!Z3+O#mJnX=5a;Ufb=V&z7}!zHVLQ%`IySPL z`DI@a6bJC!#KP*>JZT3#r8?YR{M=S7z~&(NMt`bLLORTcHUK;wQ8L`g+*4Q>35)7L z!%!?BfS;$1iRX3y8OQHKxb^G$(_g~dVfs68vJUqZ8uu|^dp8BfU~&T(uJ$Mk6dG|8 zJyc2L-g@{SfPqyqe|+#kUSW-P(02bTzyTO|og4BPiTk1)_zD}L9|dh7a-*2QBNiNk zLD$nEzOLNV!T(D44=nn0WcL-=BQ`Yq7;^rR{kb~O#JfMwFZ_3N{~t$gAL9D07Yxw{ zAbS@`-&(hyw*$cPz2|&N^jZL5oGcaMmoyCofDdK-P=}mqZh;#2+x)WT|0kjov=}=Z zU2SzBT7Wxx*FQXTsM6)Ik3s)hw6m%Vp!KI^4R1~LzVERU(H=s+UZxQXpvj~B&!*r1is&{se7*#9%7fZRUxP@C-2o42<78Hetg0h%8f@!0-=rpb z{tqr4S*EUvnAK4M)d;Af&UVv_zh8v`ic>MLsSfoKq)5wusY6hJ2O9xNBMprANMG_JYO6+Ihfn~vm|cuZ_9O9nv)a`J zOxx9LudTM4))Zk}794Or!#oAbCLHMLd-jqogKz=U4aj~u?rrUDq@a{rI(p6O42WC% zX0}yBz`vW#p01WK!vhgrMua5H053zl?O6cyF~_ue;%IUNv&dtR-B+l6DS}jNn`~Tj zHQ;6z9Uib7wIUGcQWTReaG6Es=8x(-F)JZqAE zHD%s|J8EP{KY>u1XYHsnBnTSa&n*-4_;#VGph;c1mU??BQg-HjiC3mvhH*%?YVg!- z`__MbxysNpjcK-51x|@*b_Irr1UT4Ri

au~A+*hcZN*^h|NN((O!>Of;cwzF04n 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

Fha>tID#LyB%2_da>-&M#8#eMOO3GOD!K^ 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%0A~%OleTe7c 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


nDMmypc=XxjqVTAo6+0HK;#gxDIQwYUv? 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
n+aiixnj;E*c}&!50C@ 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

u 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 I{wwGI16`E_M*si- literal 0 HcmV?d00001 diff --git a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs index 2c2f83dd4a..fb238d124f 100644 --- a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs +++ b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs @@ -54,9 +54,6 @@ codeActionHandler ideState plId CodeActionParams {_textDocument = TextDocumentId decls <- getDecls ideState nfp let sigs = [ sigToText ts | L (RealSrcSpan rss _) (SigD _ ts@(TypeSig _ idsSig _)) <- decls] let actions = mapMaybe (generateAction uri decls) diags - liftIO $ logDebug (ideLogger ideState) $ T.pack $ "CTS Diags: " <> show diags - liftIO $ logDebug (ideLogger ideState) $ T.pack $ "CTS Actions: " <> show actions - liftIO $ logDebug (ideLogger ideState) $ T.pack $ "CTS Sigs: " <> show sigs pure $ List actions getDecls :: MonadIO m => IdeState -> NormalizedFilePath -> ExceptT String m [LHsDecl GhcPs] diff --git a/plugins/hls-change-type-signature-plugin/test/Main.hs b/plugins/hls-change-type-signature-plugin/test/Main.hs index fdb3ee0e58..92fd5d6630 100644 --- a/plugins/hls-change-type-signature-plugin/test/Main.hs +++ b/plugins/hls-change-type-signature-plugin/test/Main.hs @@ -41,6 +41,7 @@ test :: TestTree test = testGroup "changeTypeSignature" [ codeActionTest "TExpectedActual" 4 11, codeActionTest "TRigidType" 4 14, + codeActionTest "TPrettyPrint" 5 13, codeActionProperties "TErrorGivenPartialSignature" [(4, 13)] $ \actions -> liftIO $ length actions @?= 0, testRegexes ] diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.expected.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.expected.hs new file mode 100644 index 0000000000..b80076a380 --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.expected.hs @@ -0,0 +1,5 @@ +module TPrettyPrint where +import Control.Monad (forM) + +pretty :: t a -> (a -> m b) -> m (t b) +pretty = forM \ No newline at end of file diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.hs new file mode 100644 index 0000000000..27a6ec971c --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.hs @@ -0,0 +1,5 @@ +module TPrettyPrint where +import Control.Monad (forM) + +pretty :: Int -> Int +pretty = forM \ No newline at end of file From 481db1b78df347f0099a11581693d6bb66bc11d6 Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Sat, 19 Feb 2022 00:41:56 -0500 Subject: [PATCH 10/20] Update Tide Type Signature logic. - Be able to tidy signatures with operators in it - Use T.words instead of regex matching to split tyVars --- .../src/Ide/Plugin/ChangeTypeSignature.hs | 100 ++++++++++-------- .../test/Main.hs | 29 +++-- .../test/testdata/TPrettyPrint.expected.hs | 5 - .../test/testdata/TPrettyPrint.hs | 5 - 4 files changed, 80 insertions(+), 59 deletions(-) delete mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.expected.hs delete mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.hs diff --git a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs index fb238d124f..aca154ce52 100644 --- a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs +++ b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs @@ -1,14 +1,15 @@ {-# LANGUAGE LambdaCase #-} -{-# OPTIONS_GHC -Wno-incomplete-patterns #-} -- | An HLS plugin to provide code actions to change type signatures module Ide.Plugin.ChangeTypeSignature (descriptor -- * For Unit Tests , errorMessageRegexes - , tidyActualType) where + , tidyTypeSignature) where import Control.Monad (join) import Control.Monad.IO.Class (MonadIO (liftIO)) import Control.Monad.Trans.Except (ExceptT) +import Data.Char (isAlpha, isAlphaNum, isNumber, + isPunctuation) import qualified Data.HashMap.Strict as Map import Data.List (find, nub) import qualified Data.List.NonEmpty as NE @@ -88,9 +89,6 @@ data ChangeSignature = ChangeSignature { , -- | the diagnostic to solve diagnostic :: Diagnostic - , - -- | the URI the declaration is in - uri :: Uri } -- | Constraint needed to trackdown OccNames in signatures @@ -99,13 +97,14 @@ type SigName = (HasOccName (IdP GhcPs)) -- | Create a CodeAction from a Diagnostic generateAction :: SigName => Uri -> [LHsDecl GhcPs] -> Diagnostic -> Maybe (Command |? CodeAction) -generateAction uri decls diag = changeSigToCodeAction <$> diagnosticToChangeSig uri decls diag +generateAction uri decls diag = changeSigToCodeAction uri <$> diagnosticToChangeSig decls diag -- | Convert a diagnostic into a ChangeSignature and add the proper SrcSpan -diagnosticToChangeSig :: SigName => Uri -> [LHsDecl GhcPs] -> Diagnostic -> Maybe ChangeSignature -diagnosticToChangeSig uri decls diagnostic = do +diagnosticToChangeSig :: SigName => [LHsDecl GhcPs] -> Diagnostic -> Maybe ChangeSignature +diagnosticToChangeSig decls diagnostic = do -- regex match on the GHC Error Message - (expectedType, actualType, declName) <- matchingDiagnostic diagnostic + (expectedType, actualType', declName) <- matchingDiagnostic diagnostic + let actualType = tidyTypeSignature actualType' -- Find the definition and it's location (declSrcSpan, ghcSig) <- findSigLocOfStringDecl decls (T.unpack declName) -- Make sure the given "Actual Type" is a full signature @@ -173,16 +172,16 @@ stripSignature sig = case T.filter (/= '\n') sig =~ sigRegex :: (Text, Text, Tex sigRegex = ".* :: (.*=>)?(.*)" :: Text -changeSigToCodeAction :: ChangeSignature -> Command |? CodeAction -changeSigToCodeAction ChangeSignature{..} = InR CodeAction { _title = mkChangeSigTitle declName actualType - , _kind = Just CodeActionQuickFix - , _diagnostics = Just $ List [diagnostic] - , _isPreferred = Nothing - , _disabled = Nothing - , _edit = Just $ mkChangeSigEdit uri declSrcSpan (mkNewSignature declName actualType) - , _command = Nothing - , _xdata = Nothing - } +changeSigToCodeAction :: Uri -> ChangeSignature -> Command |? CodeAction +changeSigToCodeAction uri ChangeSignature{..} = InR CodeAction { _title = mkChangeSigTitle declName actualType + , _kind = Just CodeActionQuickFix + , _diagnostics = Just $ List [diagnostic] + , _isPreferred = Nothing + , _disabled = Nothing + , _edit = Just $ mkChangeSigEdit uri declSrcSpan (mkNewSignature declName actualType) + , _command = Nothing + , _xdata = Nothing + } mkChangeSigTitle :: Text -> Text -> Text mkChangeSigTitle declName actualType = "change signature for ‘" <> declName <> "’ to: " <> actualType @@ -194,41 +193,56 @@ mkChangeSigEdit uri ss replacement = in WorkspaceEdit changes Nothing Nothing mkNewSignature :: Text -> Text -> Text -mkNewSignature declName actualType = declName <> " :: " <> tidyActualType actualType +mkNewSignature declName actualType = declName <> " :: " <> actualType -- | Cleans up type signatures with oddly-named type variables (a0, m0 ...) -tidyActualType :: Text -> Text -tidyActualType actualType = +tidyTypeSignature :: Text -> Text +tidyTypeSignature actualType = replaceAllFTyVars $ replaceAllMTyVars $ replaceAllTTyVars - $ replaceAllUniqueTyVars uniqueTyVars actualType + $ replaceAllUniqueTyVars actualType where - findAllTyVars :: Text -> [Text] - findAllTyVars regex = getAllTextMatches (actualType =~ regex) :: [Text] - uniqueTyVars = nub $ findAllTyVars "[abcdeghijklnopqrsuvwxyz][0-9]" - -- specialize searching on any `f`, `m` or `t` tyVars - fTyVars = findAllTyVars "f[0-9]" - mTyVars = findAllTyVars "m[0-9]" - tTyVars = findAllTyVars "t[0-9]" - -- | From a list of type variables replace all instances with the list of freshVars provided + -- split on whitespace and remove any non-alphaNum chars + words' = filter (not . T.null) $ map (T.filter isAlphaNum) $ T.words actualType + -- words' = T.words actualType + -- find the tyVars which are just alphaChars (a, b, thing ...) + tidyTyVars = nub $ filter (T.all isAlpha) words' + -- find tyVars with numbers (a0, b1, c5 ...) + untidyTyVars = nub $ filter (T.any isNumber) words' + + freshTcVars' = freshTcVars tidyTyVars + (fTyVars, mTyVars, tTyVars, uniqueTyVars) = untidyTyVarsToGroup untidyTyVars + + -- From a list of type variables replace all instances with the list of freshVars provided replaceAllTyVars :: [Text] -> Text -> [Text] -> Text - replaceAllTyVars freshVars sig = snd . foldl replaceWithFreshVar (freshVars, sig) - replaceAllUniqueTyVars replace sig = replaceAllTyVars freshUniqueVars sig replace - replaceAllFTyVars sig = replaceAllTyVars (freshVars "f") sig fTyVars - replaceAllMTyVars sig = replaceAllTyVars (freshVars "m") sig mTyVars - replaceAllTTyVars sig = replaceAllTyVars (freshVars "t") sig tTyVars + replaceAllTyVars freshVars sig untidy = snd $ foldl replaceWithFreshVar (freshVars, sig) untidy + + -- we must reverse the untidy vars as they are "backwards" when lookint at type sig from Left to Right + replaceAllUniqueTyVars sig = replaceAllTyVars (filter (`notElem` tidyTyVars) freshUniqueVars) sig (reverse uniqueTyVars) + replaceAllFTyVars sig = replaceAllTyVars (freshTcVars' "f") sig (reverse fTyVars) + replaceAllMTyVars sig = replaceAllTyVars (freshTcVars' "m") sig (reverse mTyVars) + replaceAllTTyVars sig = replaceAllTyVars (freshTcVars' "t") sig (reverse tTyVars) +replaceWithFreshVar :: ([Text], Text) -> Text -> ([Text], Text) +replaceWithFreshVar (replacement:rest, haystack) needle = (rest, T.replace needle replacement haystack) +replaceWithFreshVar _ _ = error "How do I handle this..., the pattern match for infinite list shouldn't fail" -freshVars :: Text -> [Text] -freshVars var = var : [var <> T.pack (show i) | i <- [0..]] +freshTcVars :: [Text] -> Text -> [Text] +freshTcVars used var = filter (`notElem` used) $ var : [var <> T.pack (show i) | i <- [0 .. ]] -freshUniqueVars :: [Text] +freshUniqueVars :: [Text] freshUniqueVars = map T.singleton validVars <> [ a <> b | a <- freshUniqueVars, b <- freshUniqueVars ] where validVars = filter (`notElem` ['f', 'm', 't']) ['a'..'z'] - -replaceWithFreshVar :: ([Text], Text) -> Text -> ([Text], Text) -replaceWithFreshVar (replacement:rest, haystack) needle = (rest, T.replace needle replacement haystack) -replaceWithFreshVar _ _ = error "How do I handle this..., the pattern match for infinite list shouldn't fail" +-- | divvy up UntidyTyVars into their tyVar category +untidyTyVarsToGroup :: [Text] -> ([Text], [Text], [Text], [Text]) +untidyTyVarsToGroup untidy = foldl dispatchVar ([], [], [], []) untidy + where + dispatchVar acc@(fVars, mVars, tVars, uVars) var = case T.uncons var of + Just ('f', rest) -> (var:fVars, mVars, tVars, uVars) + Just ('m', rest) -> (fVars, var:mVars, tVars, uVars) + Just ('t', rest) -> (fVars, mVars, var:tVars, uVars) + Just _ -> (fVars, mVars, tVars, var:uVars) + _ -> acc diff --git a/plugins/hls-change-type-signature-plugin/test/Main.hs b/plugins/hls-change-type-signature-plugin/test/Main.hs index 92fd5d6630..0c64e7be7b 100644 --- a/plugins/hls-change-type-signature-plugin/test/Main.hs +++ b/plugins/hls-change-type-signature-plugin/test/Main.hs @@ -6,7 +6,8 @@ import Data.Maybe (mapMaybe) import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.IO as TIO -import Ide.Plugin.ChangeTypeSignature (errorMessageRegexes) +import Ide.Plugin.ChangeTypeSignature (errorMessageRegexes, + tidyTypeSignature) import qualified Ide.Plugin.ChangeTypeSignature as ChangeTypeSignature import System.FilePath ((<.>), ()) import Test.Hls (CodeAction (..), @@ -39,11 +40,12 @@ changeTypeSignaturePlugin = ChangeTypeSignature.descriptor "changeTypeSignature" test :: TestTree test = testGroup "changeTypeSignature" [ - codeActionTest "TExpectedActual" 4 11, - codeActionTest "TRigidType" 4 14, - codeActionTest "TPrettyPrint" 5 13, - codeActionProperties "TErrorGivenPartialSignature" [(4, 13)] $ \actions -> liftIO $ length actions @?= 0, - testRegexes ] + codeActionTest "TExpectedActual" 4 11 + , codeActionTest "TRigidType" 4 14 + , codeActionProperties "TErrorGivenPartialSignature" [(4, 13)] $ \actions -> liftIO $ length actions @?= 0 + , testRegexes + , testTidyType + ] testRegexes :: TestTree testRegexes = testGroup "Regex Testing" [ @@ -54,6 +56,18 @@ testRegexes = testGroup "Regex Testing" [ regex1 = errorMessageRegexes !! 0 regex2 = errorMessageRegexes !! 1 +testTidyType :: TestTree +testTidyType = testGroup "Tidy Type Signature" [ + tidyTypeSignatureTest "a -> a -> a" "a -> a -> a" + , tidyTypeSignatureTest "Int -> Double -> String" "Int -> Double -> String" + , tidyTypeSignatureTest "t1 a -> t2 c0 -> g7" "t a -> t0 b -> c" + , tidyTypeSignatureTest "t0 d -> t c" "t0 d -> t c" + , tidyTypeSignatureTest "a0 -> a1 -> a2" "a -> b -> c" + , tidyTypeSignatureTest "(a -> c1) -> c1" "(a -> b) -> b" + , tidyTypeSignatureTest "[a1] -> [b1] -> z" "[a] -> [b] -> z" + , tidyTypeSignatureTest "t0 a0 -> (a0 -> m0 b0) -> m0 (t0 b0)" "t a -> (a -> m b) -> m (t b)" + ] + testRegexOne :: TestTree testRegexOne = testGroup "Regex One" [ regexTest "error1.txt" regex True @@ -113,9 +127,12 @@ regexTest fp regex shouldPass = testCase fp $ do (_, True) -> assertFailure $ "Failed to match: " <> fp <> " with " <> T.unpack regex (_, False) -> pure () +tidyTypeSignatureTest :: Text -> Text -> TestTree +tidyTypeSignatureTest toTidy expected = testCase (T.unpack toTidy) $ tidyTypeSignature toTidy @?= expected pointRange :: Int -> Int -> Range pointRange (subtract 1 -> fromIntegral -> line) (subtract 1 -> fromIntegral -> col) = Range (Position line col) (Position line $ col + 1) + diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.expected.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.expected.hs deleted file mode 100644 index b80076a380..0000000000 --- a/plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.expected.hs +++ /dev/null @@ -1,5 +0,0 @@ -module TPrettyPrint where -import Control.Monad (forM) - -pretty :: t a -> (a -> m b) -> m (t b) -pretty = forM \ No newline at end of file diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.hs deleted file mode 100644 index 27a6ec971c..0000000000 --- a/plugins/hls-change-type-signature-plugin/test/testdata/TPrettyPrint.hs +++ /dev/null @@ -1,5 +0,0 @@ -module TPrettyPrint where -import Control.Monad (forM) - -pretty :: Int -> Int -pretty = forM \ No newline at end of file From d3101d489524c29240e02aed3a7568215a3f756e Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Sat, 19 Feb 2022 00:44:58 -0500 Subject: [PATCH 11/20] Remove locA (defaults to id in 8.10) to satisfy 9.0+ --- .../src/Ide/Plugin/ChangeTypeSignature.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs index aca154ce52..f5c7c6047e 100644 --- a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs +++ b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs @@ -147,7 +147,7 @@ errorMessageRegexes = [ -- be sure to add new Error Messages Regexes at the bott findSigLocOfStringDecl :: SigName => [LHsDecl GhcPs] -> String -> Maybe (RealSrcSpan, DefinedSig) findSigLocOfStringDecl decls declName = do -- can we simplify this logic? Just want to make sure ghcSig is a Just value - (rss, Just ghcSig) <- listToMaybe [ (locA rss, sigToText ts) + (rss, Just ghcSig) <- listToMaybe [ (rss, sigToText ts) | L (RealSrcSpan rss _) (SigD _ ts@(TypeSig _ idsSig _)) <- decls, any ((==) declName . occNameString . occName . unLoc) idsSig ] From c640a2961347812a865a993cc9901f0415361a35 Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Sat, 19 Feb 2022 01:19:15 -0500 Subject: [PATCH 12/20] Touch up 9.2.1 --- .../src/Ide/Plugin/ChangeTypeSignature.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs index f5c7c6047e..57133b9f4b 100644 --- a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs +++ b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs @@ -53,7 +53,6 @@ codeActionHandler :: PluginMethodHandler IdeState TextDocumentCodeAction codeActionHandler ideState plId CodeActionParams {_textDocument = TextDocumentIdentifier uri, _context = CodeActionContext (List diags) _} = response $ do nfp <- getNormalizedFilePath plId (TextDocumentIdentifier uri) decls <- getDecls ideState nfp - let sigs = [ sigToText ts | L (RealSrcSpan rss _) (SigD _ ts@(TypeSig _ idsSig _)) <- decls] let actions = mapMaybe (generateAction uri decls) diags pure $ List actions @@ -147,8 +146,8 @@ errorMessageRegexes = [ -- be sure to add new Error Messages Regexes at the bott findSigLocOfStringDecl :: SigName => [LHsDecl GhcPs] -> String -> Maybe (RealSrcSpan, DefinedSig) findSigLocOfStringDecl decls declName = do -- can we simplify this logic? Just want to make sure ghcSig is a Just value - (rss, Just ghcSig) <- listToMaybe [ (rss, sigToText ts) - | L (RealSrcSpan rss _) (SigD _ ts@(TypeSig _ idsSig _)) <- decls, + (RealSrcSpan rss _, Just ghcSig) <- listToMaybe [ (locA ss, sigToText ts) + | L ss (SigD _ ts@(TypeSig _ idsSig _)) <- decls, any ((==) declName . occNameString . occName . unLoc) idsSig ] pure (rss, ghcSig) From 4c482a81c129a715a21dd38a791d87422a3495cc Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Sun, 20 Feb 2022 16:32:51 -0500 Subject: [PATCH 13/20] Clean up review notes --- docs/features.md | 18 ++- hls-plugin-api/src/Ide/PluginUtils.hs | 5 +- .../src/Ide/Plugin/ChangeTypeSignature.hs | 113 ++++-------------- .../test/Main.hs | 26 +--- 4 files changed, 48 insertions(+), 114 deletions(-) diff --git a/docs/features.md b/docs/features.md index 2939daee00..52542bee92 100644 --- a/docs/features.md +++ b/docs/features.md @@ -18,7 +18,7 @@ Many of these are standard LSP features, but a lot of special features are provi | [Highlight references](#highlight-references) | `textDocument/documentHighlight` | | [Code actions](#code-actions) | `textDocument/codeAction` | | [Code lenses](#code-lenses) | `textDocument/codeLens` | -| [Selection range](#selection-range) | `textDocument/selectionRange` | +| [Selection range](#selection-range) | `textDocument/selectionRange` | The individual sections below also identify which [HLS plugin](./what-is-hls.md#hls-plugins) is responsible for providing the given functionality, which is useful if you want to raise an issue report or contribute! Additionally, not all plugins are supported on all versions of GHC, see the [GHC version support page](supported-versions.md) for details. @@ -237,6 +237,22 @@ Provides a variety of code actions for interactive code development, see PluginId -> TextDocumentIdentifier -> ExceptT String m NormalizedFilePath getNormalizedFilePath (PluginId plId) docId = handleMaybe errMsg $ uriToNormalizedFilePath - $ toNormalizedUri (docId ^. uri) + $ toNormalizedUri uri' where - errMsg = T.unpack $ "Error(" <> plId <> "): converting to NormalizedFilePath" + errMsg = T.unpack $ "Error(" <> plId <> "): converting " <> getUri uri' <> " to NormalizedFilePath" + uri' = docId ^. uri -- --------------------------------------------------------------------- handleMaybe :: Monad m => e -> Maybe b -> ExceptT e m b diff --git a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs index 57133b9f4b..067f57bad4 100644 --- a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs +++ b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs @@ -1,15 +1,17 @@ -{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE ViewPatterns #-} -- | An HLS plugin to provide code actions to change type signatures module Ide.Plugin.ChangeTypeSignature (descriptor -- * For Unit Tests , errorMessageRegexes - , tidyTypeSignature) where + ) where -import Control.Monad (join) +import Control.Monad (forM, guard, join) import Control.Monad.IO.Class (MonadIO (liftIO)) import Control.Monad.Trans.Except (ExceptT) import Data.Char (isAlpha, isAlphaNum, isNumber, isPunctuation) +import Data.Foldable (asum) import qualified Data.HashMap.Strict as Map import Data.List (find, nub) import qualified Data.List.NonEmpty as NE @@ -17,13 +19,12 @@ import Data.Maybe (isJust, isNothing, listToMaybe, mapMaybe) import Data.Text (Text) import qualified Data.Text as T -import Data.Traversable (forM) import Development.IDE.Core.RuleTypes (GetParsedModule (GetParsedModule)) import Development.IDE.Core.Service (IdeState, ideLogger, runAction) import Development.IDE.Core.Shake (use) import Development.IDE.GHC.Compat import Development.IDE.GHC.Error (realSrcSpanToRange) -import Development.IDE.GHC.Util (unsafePrintSDoc) +import Development.IDE.GHC.Util (prettyPrint, unsafePrintSDoc) import Development.IDE.Types.Logger (logDebug) import Ide.PluginUtils (getNormalizedFilePath, handleMaybeM, response) @@ -75,19 +76,15 @@ type DefinedSig = Text -- | DataType that encodes the necessary information for changing a type signature data ChangeSignature = ChangeSignature { -- | The expected type based on Signature - expectedType :: ExpectedSig - , + expectedType :: ExpectedSig -- | the Actual Type based on definition - actualType :: ActualSig - , + , actualType :: ActualSig -- | the declaration name to be updated - declName :: DeclName - , + , declName :: DeclName -- | the location of the declaration signature - declSrcSpan :: RealSrcSpan - , + , declSrcSpan :: RealSrcSpan -- | the diagnostic to solve - diagnostic :: Diagnostic + , diagnostic :: Diagnostic } -- | Constraint needed to trackdown OccNames in signatures @@ -102,25 +99,22 @@ generateAction uri decls diag = changeSigToCodeAction uri <$> diagnosticToChange diagnosticToChangeSig :: SigName => [LHsDecl GhcPs] -> Diagnostic -> Maybe ChangeSignature diagnosticToChangeSig decls diagnostic = do -- regex match on the GHC Error Message - (expectedType, actualType', declName) <- matchingDiagnostic diagnostic - let actualType = tidyTypeSignature actualType' + (expectedType, actualType, declName) <- matchingDiagnostic diagnostic -- Find the definition and it's location (declSrcSpan, ghcSig) <- findSigLocOfStringDecl decls (T.unpack declName) -- Make sure the given "Actual Type" is a full signature - isValidMessage expectedType ghcSig + guard (isValidMessage expectedType ghcSig) pure $ ChangeSignature{..} -- | Does the GHC Error Message give us a Signature we can use? -- We only want to change signatures when the "expected signature" given by GHC -- matches the one given by the user -isValidMessage :: DefinedSig -> ExpectedSig -> Maybe () -isValidMessage defSig expSig = if defSig == expSig then Just () else Nothing +isValidMessage :: DefinedSig -> ExpectedSig -> Bool +isValidMessage = (==) -- | If a diagnostic has the proper message create a ChangeSignature from it matchingDiagnostic :: Diagnostic -> Maybe (ExpectedSig, ActualSig, DeclName) -matchingDiagnostic diag@Diagnostic{_message} = case map (unwrapMatch . (=~) _message) errorMessageRegexes of - [] -> Nothing - css -> join $ find isJust css +matchingDiagnostic diag@Diagnostic{_message} = asum $ map (unwrapMatch . (=~) _message) errorMessageRegexes where unwrapMatch :: (Text, Text, Text, [Text]) -> Maybe (ExpectedSig, ActualSig, DeclName) -- due to using (.|\n) in regex we have to drop the erroneous, but necessary ("." doesn't match newlines), match @@ -130,13 +124,9 @@ matchingDiagnostic diag@Diagnostic{_message} = case map (unwrapMatch . (=~) _mes -- | List of regexes that match various Error Messages errorMessageRegexes :: [Text] errorMessageRegexes = [ -- be sure to add new Error Messages Regexes at the bottom to not fail any existing tests - "Expected type: (" <> typeSigRegex <> ")\n +Actual type: (" <> typeSigRegex <> ")\n(.|\n)+In an equation for ‘(.+)’" - , "Couldn't match expected type ‘(" <> typeSigRegex <> ")’ with actual type ‘(" <> typeSigRegex <> ")’\n(.|\n)+In an equation for ‘(.+)’" + "Expected type: (.+)\n +Actual type: (.+)\n(.|\n)+In an equation for ‘(.+)’" + , "Couldn't match expected type ‘(.+)’ with actual type ‘(.+)’\n(.|\n)+In an equation for ‘(.+)’" ] - where - -- The brackets in position 1 and 2 MUST BE IN THAT ORDER - -- Any other combination of brackets seems to fail - typeSigRegex = "[][a-zA-Z0-9 ->]+" -- | Given a String with the name of a declaration, find that declarations and give back -- the type signature location and the full signature @@ -144,18 +134,15 @@ errorMessageRegexes = [ -- be sure to add new Error Messages Regexes at the bott -- This function returns the actual location of the signature rather than the actual signature -- We also don't have access to `fun_id` or other actual `id` so we must use string compare instead findSigLocOfStringDecl :: SigName => [LHsDecl GhcPs] -> String -> Maybe (RealSrcSpan, DefinedSig) -findSigLocOfStringDecl decls declName = do - -- can we simplify this logic? Just want to make sure ghcSig is a Just value - (RealSrcSpan rss _, Just ghcSig) <- listToMaybe [ (locA ss, sigToText ts) - | L ss (SigD _ ts@(TypeSig _ idsSig _)) <- decls, - any ((==) declName . occNameString . occName . unLoc) idsSig - ] - pure (rss, ghcSig) +findSigLocOfStringDecl decls declName = sequence =<< listToMaybe [ (rss, sigToText ts) + | L (locA -> (RealSrcSpan rss _)) (SigD _ ts@(TypeSig _ idsSig _)) <- decls, + any ((==) declName . occNameString . occName . unLoc) idsSig + ] -- | Pretty Print the Type Signature (to validate GHC Error Message) sigToText :: Sig GhcPs -> Maybe Text sigToText = \case - ts@TypeSig {} -> stripSignature (T.pack $ showSDocUnsafe $ ppr ts) + ts@TypeSig {} -> stripSignature $ T.pack $ prettyPrint ts _ -> Nothing stripSignature :: Text -> Maybe Text @@ -183,7 +170,7 @@ changeSigToCodeAction uri ChangeSignature{..} = InR CodeAction { _title = } mkChangeSigTitle :: Text -> Text -> Text -mkChangeSigTitle declName actualType = "change signature for ‘" <> declName <> "’ to: " <> actualType +mkChangeSigTitle declName actualType = "Change signature for ‘" <> declName <> "’ to: " <> actualType mkChangeSigEdit :: Uri -> RealSrcSpan -> Text -> WorkspaceEdit mkChangeSigEdit uri ss replacement = @@ -193,55 +180,3 @@ mkChangeSigEdit uri ss replacement = mkNewSignature :: Text -> Text -> Text mkNewSignature declName actualType = declName <> " :: " <> actualType - --- | Cleans up type signatures with oddly-named type variables (a0, m0 ...) -tidyTypeSignature :: Text -> Text -tidyTypeSignature actualType = - replaceAllFTyVars - $ replaceAllMTyVars - $ replaceAllTTyVars - $ replaceAllUniqueTyVars actualType - where - -- split on whitespace and remove any non-alphaNum chars - words' = filter (not . T.null) $ map (T.filter isAlphaNum) $ T.words actualType - -- words' = T.words actualType - -- find the tyVars which are just alphaChars (a, b, thing ...) - tidyTyVars = nub $ filter (T.all isAlpha) words' - -- find tyVars with numbers (a0, b1, c5 ...) - untidyTyVars = nub $ filter (T.any isNumber) words' - - freshTcVars' = freshTcVars tidyTyVars - (fTyVars, mTyVars, tTyVars, uniqueTyVars) = untidyTyVarsToGroup untidyTyVars - - -- From a list of type variables replace all instances with the list of freshVars provided - replaceAllTyVars :: [Text] -> Text -> [Text] -> Text - replaceAllTyVars freshVars sig untidy = snd $ foldl replaceWithFreshVar (freshVars, sig) untidy - - -- we must reverse the untidy vars as they are "backwards" when lookint at type sig from Left to Right - replaceAllUniqueTyVars sig = replaceAllTyVars (filter (`notElem` tidyTyVars) freshUniqueVars) sig (reverse uniqueTyVars) - replaceAllFTyVars sig = replaceAllTyVars (freshTcVars' "f") sig (reverse fTyVars) - replaceAllMTyVars sig = replaceAllTyVars (freshTcVars' "m") sig (reverse mTyVars) - replaceAllTTyVars sig = replaceAllTyVars (freshTcVars' "t") sig (reverse tTyVars) - -replaceWithFreshVar :: ([Text], Text) -> Text -> ([Text], Text) -replaceWithFreshVar (replacement:rest, haystack) needle = (rest, T.replace needle replacement haystack) -replaceWithFreshVar _ _ = error "How do I handle this..., the pattern match for infinite list shouldn't fail" - -freshTcVars :: [Text] -> Text -> [Text] -freshTcVars used var = filter (`notElem` used) $ var : [var <> T.pack (show i) | i <- [0 .. ]] - -freshUniqueVars :: [Text] -freshUniqueVars = map T.singleton validVars <> [ a <> b | a <- freshUniqueVars, b <- freshUniqueVars ] - where - validVars = filter (`notElem` ['f', 'm', 't']) ['a'..'z'] - --- | divvy up UntidyTyVars into their tyVar category -untidyTyVarsToGroup :: [Text] -> ([Text], [Text], [Text], [Text]) -untidyTyVarsToGroup untidy = foldl dispatchVar ([], [], [], []) untidy - where - dispatchVar acc@(fVars, mVars, tVars, uVars) var = case T.uncons var of - Just ('f', rest) -> (var:fVars, mVars, tVars, uVars) - Just ('m', rest) -> (fVars, var:mVars, tVars, uVars) - Just ('t', rest) -> (fVars, mVars, var:tVars, uVars) - Just _ -> (fVars, mVars, tVars, var:uVars) - _ -> acc diff --git a/plugins/hls-change-type-signature-plugin/test/Main.hs b/plugins/hls-change-type-signature-plugin/test/Main.hs index 0c64e7be7b..88151995aa 100644 --- a/plugins/hls-change-type-signature-plugin/test/Main.hs +++ b/plugins/hls-change-type-signature-plugin/test/Main.hs @@ -6,8 +6,7 @@ import Data.Maybe (mapMaybe) import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.IO as TIO -import Ide.Plugin.ChangeTypeSignature (errorMessageRegexes, - tidyTypeSignature) +import Ide.Plugin.ChangeTypeSignature (errorMessageRegexes) import qualified Ide.Plugin.ChangeTypeSignature as ChangeTypeSignature import System.FilePath ((<.>), ()) import Test.Hls (CodeAction (..), @@ -44,7 +43,6 @@ test = testGroup "changeTypeSignature" [ , codeActionTest "TRigidType" 4 14 , codeActionProperties "TErrorGivenPartialSignature" [(4, 13)] $ \actions -> liftIO $ length actions @?= 0 , testRegexes - , testTidyType ] testRegexes :: TestTree @@ -56,18 +54,6 @@ testRegexes = testGroup "Regex Testing" [ regex1 = errorMessageRegexes !! 0 regex2 = errorMessageRegexes !! 1 -testTidyType :: TestTree -testTidyType = testGroup "Tidy Type Signature" [ - tidyTypeSignatureTest "a -> a -> a" "a -> a -> a" - , tidyTypeSignatureTest "Int -> Double -> String" "Int -> Double -> String" - , tidyTypeSignatureTest "t1 a -> t2 c0 -> g7" "t a -> t0 b -> c" - , tidyTypeSignatureTest "t0 d -> t c" "t0 d -> t c" - , tidyTypeSignatureTest "a0 -> a1 -> a2" "a -> b -> c" - , tidyTypeSignatureTest "(a -> c1) -> c1" "(a -> b) -> b" - , tidyTypeSignatureTest "[a1] -> [b1] -> z" "[a] -> [b] -> z" - , tidyTypeSignatureTest "t0 a0 -> (a0 -> m0 b0) -> m0 (t0 b0)" "t a -> (a -> m b) -> m (t b)" - ] - testRegexOne :: TestTree testRegexOne = testGroup "Regex One" [ regexTest "error1.txt" regex True @@ -98,7 +84,7 @@ codeActionTest :: FilePath -> Int -> Int -> TestTree codeActionTest fp line col = goldenChangeSignature fp $ \doc -> do waitForDiagnostics -- code actions are triggered from Diagnostics actions <- getCodeActions doc (pointRange line col) - foundAction <- liftIO $ inspectCodeAction actions ["change signature"] + foundAction <- liftIO $ inspectCodeAction actions ["Change signature"] executeCodeAction foundAction codeActionProperties :: TestName -> [(Int, Int)] -> ([CodeAction] -> Session ()) -> TestTree @@ -114,8 +100,8 @@ findChangeTypeActions = pure . filter isChangeTypeAction . rights . map toEither isChangeTypeAction CodeAction{_kind} = case _kind of Nothing -> False Just kind -> case kind of - CodeActionQuickFix -> True - _ -> False + "quickfix.changeSignature" -> True + _ -> False regexTest :: FilePath -> Text -> Bool -> TestTree @@ -127,12 +113,8 @@ regexTest fp regex shouldPass = testCase fp $ do (_, True) -> assertFailure $ "Failed to match: " <> fp <> " with " <> T.unpack regex (_, False) -> pure () -tidyTypeSignatureTest :: Text -> Text -> TestTree -tidyTypeSignatureTest toTidy expected = testCase (T.unpack toTidy) $ tidyTypeSignature toTidy @?= expected - pointRange :: Int -> Int -> Range pointRange (subtract 1 -> fromIntegral -> line) (subtract 1 -> fromIntegral -> col) = Range (Position line col) (Position line $ col + 1) - From 7d7febcc0678a655502780c336ba722bbe536287 Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Sun, 20 Feb 2022 16:45:03 -0500 Subject: [PATCH 14/20] Update stack.yamls --- stack-8.10.6.yaml | 1 + stack-8.10.7.yaml | 1 + stack-8.6.5.yaml | 1 + stack-8.8.4.yaml | 1 + stack-9.0.1.yaml | 1 + stack-9.0.2.yaml | 1 + stack-9.2.1.yaml | 3 ++- stack.yaml | 1 + 8 files changed, 9 insertions(+), 1 deletion(-) diff --git a/stack-8.10.6.yaml b/stack-8.10.6.yaml index 321f143bcd..aea8d642a7 100644 --- a/stack-8.10.6.yaml +++ b/stack-8.10.6.yaml @@ -31,6 +31,7 @@ packages: - ./plugins/hls-ormolu-plugin - ./plugins/hls-alternate-number-format-plugin - ./plugins/hls-selection-range-plugin + - ./plugins/hls-change-type-signature-plugin ghc-options: "$everything": -haddock diff --git a/stack-8.10.7.yaml b/stack-8.10.7.yaml index f373a37ea5..ac68693305 100644 --- a/stack-8.10.7.yaml +++ b/stack-8.10.7.yaml @@ -32,6 +32,7 @@ packages: - ./plugins/hls-ormolu-plugin - ./plugins/hls-alternate-number-format-plugin - ./plugins/hls-selection-range-plugin + - ./plugins/hls-change-type-signature-plugin ghc-options: "$everything": -haddock diff --git a/stack-8.6.5.yaml b/stack-8.6.5.yaml index 121998bfc6..fa41b1f0a8 100644 --- a/stack-8.6.5.yaml +++ b/stack-8.6.5.yaml @@ -29,6 +29,7 @@ packages: - ./plugins/hls-ormolu-plugin - ./plugins/hls-alternate-number-format-plugin - ./plugins/hls-selection-range-plugin + - ./plugins/hls-change-type-signature-plugin ghc-options: "$everything": -haddock diff --git a/stack-8.8.4.yaml b/stack-8.8.4.yaml index ce00d47573..d2ccd76c49 100644 --- a/stack-8.8.4.yaml +++ b/stack-8.8.4.yaml @@ -29,6 +29,7 @@ packages: - ./plugins/hls-ormolu-plugin - ./plugins/hls-alternate-number-format-plugin - ./plugins/hls-selection-range-plugin + - ./plugins/hls-change-type-signature-plugin ghc-options: "$everything": -haddock diff --git a/stack-9.0.1.yaml b/stack-9.0.1.yaml index 2f75afbaee..d10110d8ca 100644 --- a/stack-9.0.1.yaml +++ b/stack-9.0.1.yaml @@ -29,6 +29,7 @@ packages: - ./plugins/hls-ormolu-plugin - ./plugins/hls-alternate-number-format-plugin - ./plugins/hls-selection-range-plugin +- ./plugins/hls-change-type-signature-plugin extra-deps: - aeson-2.0.3.0 diff --git a/stack-9.0.2.yaml b/stack-9.0.2.yaml index df94686560..28a57e760a 100644 --- a/stack-9.0.2.yaml +++ b/stack-9.0.2.yaml @@ -29,6 +29,7 @@ packages: - ./plugins/hls-ormolu-plugin - ./plugins/hls-alternate-number-format-plugin - ./plugins/hls-selection-range-plugin +- ./plugins/hls-change-type-signature-plugin extra-deps: - aeson-2.0.3.0 diff --git a/stack-9.2.1.yaml b/stack-9.2.1.yaml index 8bcf7b4b3d..add654dae7 100644 --- a/stack-9.2.1.yaml +++ b/stack-9.2.1.yaml @@ -28,8 +28,9 @@ packages: - ./plugins/hls-pragmas-plugin - ./plugins/hls-module-name-plugin - ./plugins/hls-ormolu-plugin -# - ./plugins/hls-alternate-number-format-plugin +- ./plugins/hls-alternate-number-format-plugin - ./plugins/hls-selection-range-plugin +- ./plugins/hls-change-type-signature-range-plugin extra-deps: - aeson-2.0.3.0 diff --git a/stack.yaml b/stack.yaml index f373a37ea5..ac68693305 100644 --- a/stack.yaml +++ b/stack.yaml @@ -32,6 +32,7 @@ packages: - ./plugins/hls-ormolu-plugin - ./plugins/hls-alternate-number-format-plugin - ./plugins/hls-selection-range-plugin + - ./plugins/hls-change-type-signature-plugin ghc-options: "$everything": -haddock From ab9646a548b48c0dd01cedcc7dcfe1db21bc9548 Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Sun, 20 Feb 2022 16:49:05 -0500 Subject: [PATCH 15/20] Fix copy-paste error --- stack-9.2.1.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stack-9.2.1.yaml b/stack-9.2.1.yaml index add654dae7..76487c77d9 100644 --- a/stack-9.2.1.yaml +++ b/stack-9.2.1.yaml @@ -30,7 +30,7 @@ packages: - ./plugins/hls-ormolu-plugin - ./plugins/hls-alternate-number-format-plugin - ./plugins/hls-selection-range-plugin -- ./plugins/hls-change-type-signature-range-plugin +- ./plugins/hls-change-type-signature-plugin extra-deps: - aeson-2.0.3.0 From 2e8c95b87b98ecb62998414e9f0bd63a53f9004f Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Wed, 23 Feb 2022 08:21:07 -0500 Subject: [PATCH 16/20] Fix Local Signature resolution --- docs/features.md | 4 + .../hls-change-type-signature-plugin.cabal | 5 +- .../src/Ide/Plugin/ChangeTypeSignature.hs | 143 ++++++++++-------- .../test/Main.hs | 12 +- .../test/testdata/TLocalBinding.expected.hs | 6 + .../test/testdata/TLocalBinding.hs | 6 + .../testdata/TLocalBindingShadow1.expected.hs | 9 ++ .../test/testdata/TLocalBindingShadow1.hs | 9 ++ .../testdata/TLocalBindingShadow2.expected.hs | 9 ++ .../test/testdata/TLocalBindingShadow2.hs | 9 ++ .../test/testdata/error5.txt | 15 ++ .../test/testdata/hie.yaml | 3 + 12 files changed, 164 insertions(+), 66 deletions(-) create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TLocalBinding.expected.hs create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TLocalBinding.hs create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow1.expected.hs create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow1.hs create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow2.expected.hs create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow2.hs create mode 100644 plugins/hls-change-type-signature-plugin/test/testdata/error5.txt diff --git a/docs/features.md b/docs/features.md index 52542bee92..dfb0b6b516 100644 --- a/docs/features.md +++ b/docs/features.md @@ -247,6 +247,10 @@ Change/Update a type signature to match implementation. Status: Until GHC 9.4, the implementation is ad-hoc and relies on GHC error messages to create a new signature. Not all GHC error messages are supported. +Known Limitations: +- Not all GHC error messages are supported +- Top-level and Function-local bindings with the same names can cause issues, such as incorrect signature changes or no code actions available. + ![Change Type Signature Demo](../plugins/hls-change-type-signature-plugin/change1.gif) ![Change Type Signature Demo](../plugins/hls-change-type-signature-plugin/change2.gif) diff --git a/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal b/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal index 6b898bd4c9..bd3fe7e5d1 100644 --- a/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal +++ b/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal @@ -25,9 +25,10 @@ library , ghcide ^>=1.6 , hls-plugin-api ^>=1.3 , lsp-types - , transformers - , regex-tdfa + , regex-tdfa + , syb , text + , transformers , unordered-containers default-language: Haskell2010 diff --git a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs index 067f57bad4..1f1e800d3d 100644 --- a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs +++ b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs @@ -6,55 +6,68 @@ module Ide.Plugin.ChangeTypeSignature (descriptor , errorMessageRegexes ) where -import Control.Monad (forM, guard, join) -import Control.Monad.IO.Class (MonadIO (liftIO)) -import Control.Monad.Trans.Except (ExceptT) -import Data.Char (isAlpha, isAlphaNum, isNumber, - isPunctuation) -import Data.Foldable (asum) -import qualified Data.HashMap.Strict as Map -import Data.List (find, nub) -import qualified Data.List.NonEmpty as NE -import Data.Maybe (isJust, isNothing, listToMaybe, - mapMaybe) -import Data.Text (Text) -import qualified Data.Text as T -import Development.IDE.Core.RuleTypes (GetParsedModule (GetParsedModule)) -import Development.IDE.Core.Service (IdeState, ideLogger, runAction) -import Development.IDE.Core.Shake (use) +import Control.Monad (forM, guard, join) +import Control.Monad.IO.Class (MonadIO (liftIO)) +import Control.Monad.Trans.Except (ExceptT) +import Data.Char (isAlpha, isAlphaNum, + isNumber, isPunctuation) +import Data.Foldable (asum, traverse_) +import qualified Data.HashMap.Strict as Map +import Data.List (find, nub) +import qualified Data.List.NonEmpty as NE +import Data.Maybe (isJust, isNothing, + listToMaybe, mapMaybe) +import Data.Text (Text) +import qualified Data.Text as T +import Development.IDE.Core.RuleTypes (GetBindings (GetBindings), + GetParsedModule (GetParsedModule)) +import Development.IDE.Core.Service (IdeState, ideLogger, + runAction) +import Development.IDE.Core.Shake (use) import Development.IDE.GHC.Compat -import Development.IDE.GHC.Error (realSrcSpanToRange) -import Development.IDE.GHC.Util (prettyPrint, unsafePrintSDoc) -import Development.IDE.Types.Logger (logDebug) -import Ide.PluginUtils (getNormalizedFilePath, - handleMaybeM, response) -import Ide.Types (PluginDescriptor (..), - PluginId, PluginMethodHandler, - defaultPluginDescriptor, - mkPluginHandler) -import Language.LSP.Types (CodeAction (..), - CodeActionContext (CodeActionContext), - CodeActionKind (CodeActionQuickFix), - CodeActionParams (..), Command, - Diagnostic (..), List (..), - Method (TextDocumentCodeAction), - NormalizedFilePath, - SMethod (..), - TextDocumentIdentifier (TextDocumentIdentifier), - TextEdit (TextEdit), Uri, - WorkspaceEdit (WorkspaceEdit), - type (|?) (InR)) -import Text.Regex.TDFA (AllTextMatches (getAllTextMatches), - (=~)) +import Development.IDE.GHC.Error (realSrcSpanToRange) +import Development.IDE.GHC.Util (prettyPrint, + unsafePrintSDoc) +import Development.IDE.Spans.LocalBindings (Bindings, getFuzzyScope) +import Development.IDE.Types.Location (Range (Range)) +import Development.IDE.Types.Logger (logDebug, logInfo) +import Generics.SYB (extQ, mkQ, something, + somewhere) +import Ide.PluginUtils (getNormalizedFilePath, + handleMaybeM, response) +import Ide.Types (PluginDescriptor (..), + PluginId, + PluginMethodHandler, + defaultPluginDescriptor, + mkPluginHandler) +import Language.LSP.Types (CodeAction (..), + CodeActionContext (CodeActionContext), + CodeActionKind (CodeActionQuickFix, CodeActionUnknown), + CodeActionParams (..), + Command, Diagnostic (..), + List (..), + Method (TextDocumentCodeAction), + NormalizedFilePath, + SMethod (..), + TextDocumentIdentifier (TextDocumentIdentifier), + TextEdit (TextEdit), Uri, + WorkspaceEdit (WorkspaceEdit), + type (|?) (InR)) +import Text.Regex.TDFA (AllTextMatches (getAllTextMatches), + (=~)) descriptor :: PluginId -> PluginDescriptor IdeState descriptor plId = (defaultPluginDescriptor plId) { pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionHandler } codeActionHandler :: PluginMethodHandler IdeState TextDocumentCodeAction -codeActionHandler ideState plId CodeActionParams {_textDocument = TextDocumentIdentifier uri, _context = CodeActionContext (List diags) _} = response $ do +codeActionHandler ideState plId CodeActionParams {_textDocument = TextDocumentIdentifier uri, _context = CodeActionContext (List diags) _, _range} = response $ do nfp <- getNormalizedFilePath plId (TextDocumentIdentifier uri) + -- for changing top-level bindings signatures decls <- getDecls ideState nfp + let actions = mapMaybe (generateAction uri decls) diags + + -- liftIO $ logInfo (ideLogger ideState) $ T.pack $ show binds pure $ List actions getDecls :: MonadIO m => IdeState -> NormalizedFilePath -> ExceptT String m [LHsDecl GhcPs] @@ -90,7 +103,6 @@ data ChangeSignature = ChangeSignature { -- | Constraint needed to trackdown OccNames in signatures type SigName = (HasOccName (IdP GhcPs)) - -- | Create a CodeAction from a Diagnostic generateAction :: SigName => Uri -> [LHsDecl GhcPs] -> Diagnostic -> Maybe (Command |? CodeAction) generateAction uri decls diag = changeSigToCodeAction uri <$> diagnosticToChangeSig decls diag @@ -101,16 +113,9 @@ diagnosticToChangeSig decls diagnostic = do -- regex match on the GHC Error Message (expectedType, actualType, declName) <- matchingDiagnostic diagnostic -- Find the definition and it's location - (declSrcSpan, ghcSig) <- findSigLocOfStringDecl decls (T.unpack declName) - -- Make sure the given "Actual Type" is a full signature - guard (isValidMessage expectedType ghcSig) + declSrcSpan <- findSigLocOfStringDecl decls expectedType (T.unpack declName) pure $ ChangeSignature{..} --- | Does the GHC Error Message give us a Signature we can use? --- We only want to change signatures when the "expected signature" given by GHC --- matches the one given by the user -isValidMessage :: DefinedSig -> ExpectedSig -> Bool -isValidMessage = (==) -- | If a diagnostic has the proper message create a ChangeSignature from it matchingDiagnostic :: Diagnostic -> Maybe (ExpectedSig, ActualSig, DeclName) @@ -128,16 +133,34 @@ errorMessageRegexes = [ -- be sure to add new Error Messages Regexes at the bott , "Couldn't match expected type ‘(.+)’ with actual type ‘(.+)’\n(.|\n)+In an equation for ‘(.+)’" ] --- | Given a String with the name of a declaration, find that declarations and give back --- the type signature location and the full signature --- This is a modified version of functions found in Development.IDE.Plugin.CodeAction --- This function returns the actual location of the signature rather than the actual signature --- We also don't have access to `fun_id` or other actual `id` so we must use string compare instead -findSigLocOfStringDecl :: SigName => [LHsDecl GhcPs] -> String -> Maybe (RealSrcSpan, DefinedSig) -findSigLocOfStringDecl decls declName = sequence =<< listToMaybe [ (rss, sigToText ts) - | L (locA -> (RealSrcSpan rss _)) (SigD _ ts@(TypeSig _ idsSig _)) <- decls, - any ((==) declName . occNameString . occName . unLoc) idsSig - ] +-- | Given a String with the name of a declaration, GHC's "Expected Type", find the declaration that matches +-- both the name given and the Expected Type, and return the type signature location +findSigLocOfStringDecl :: SigName => [LHsDecl GhcPs] -> ExpectedSig -> String -> Maybe RealSrcSpan +findSigLocOfStringDecl decls expectedType declName = something (const Nothing `extQ` findSig `extQ` findLocalSig) decls + where + -- search for Top Level Signatures + findSig :: GenLocated SrcSpan (HsDecl GhcPs) -> Maybe RealSrcSpan + findSig = \case + L (locA -> (RealSrcSpan rss _)) (SigD _ sig) -> case sig of + ts@(TypeSig _ idsSig _) -> isMatch ts idsSig >> pure rss + _ -> Nothing + _ -> Nothing + + -- search for Local Signatures + findLocalSig :: GenLocated SrcSpan (Sig GhcPs) -> Maybe RealSrcSpan + findLocalSig = \case + (L (locA -> (RealSrcSpan rss _)) ts@(TypeSig _ idsSig _)) -> isMatch ts idsSig >> pure rss + _ -> Nothing + + -- Does the declName match? and does the expected signature match? + isMatch ts idsSig = do + ghcSig <- sigToText ts + guard (any compareId idsSig && expectedType == ghcSig) + + -- Given an IdP check to see if it matches the declName + compareId (L _ id') = declName == occNameString (occName id') + + -- | Pretty Print the Type Signature (to validate GHC Error Message) sigToText :: Sig GhcPs -> Maybe Text @@ -160,7 +183,7 @@ stripSignature sig = case T.filter (/= '\n') sig =~ sigRegex :: (Text, Text, Tex changeSigToCodeAction :: Uri -> ChangeSignature -> Command |? CodeAction changeSigToCodeAction uri ChangeSignature{..} = InR CodeAction { _title = mkChangeSigTitle declName actualType - , _kind = Just CodeActionQuickFix + , _kind = Just (CodeActionUnknown "quickfix.changeSignature") , _diagnostics = Just $ List [diagnostic] , _isPreferred = Nothing , _disabled = Nothing diff --git a/plugins/hls-change-type-signature-plugin/test/Main.hs b/plugins/hls-change-type-signature-plugin/test/Main.hs index 88151995aa..dddd5d3b24 100644 --- a/plugins/hls-change-type-signature-plugin/test/Main.hs +++ b/plugins/hls-change-type-signature-plugin/test/Main.hs @@ -1,6 +1,5 @@ module Main where -import Control.Monad (forM) import Data.Either (rights) import Data.Maybe (mapMaybe) import Data.Text (Text) @@ -28,7 +27,6 @@ import Test.Hls (CodeAction (..), waitForDiagnostics, waitForProgressDone, (@=?), (@?=)) -import Test.Hls.Util (inspectCodeAction) import Text.Regex.TDFA ((=~)) main :: IO () @@ -41,6 +39,9 @@ test :: TestTree test = testGroup "changeTypeSignature" [ codeActionTest "TExpectedActual" 4 11 , codeActionTest "TRigidType" 4 14 + , codeActionTest "TLocalBinding" 6 21 + , codeActionTest "TLocalBindingShadow1" 10 7 + , codeActionTest "TLocalBindingShadow2" 6 21 , codeActionProperties "TErrorGivenPartialSignature" [(4, 13)] $ \actions -> liftIO $ length actions @?= 0 , testRegexes ] @@ -60,6 +61,7 @@ testRegexOne = testGroup "Regex One" [ , regexTest "error2.txt" regex True , regexTest "error3.txt" regex False , regexTest "error4.txt" regex True + , regexTest "error5.txt" regex True ] where regex = errorMessageRegexes !! 0 @@ -70,6 +72,7 @@ testRegexTwo = testGroup "Regex Two" [ , regexTest "error2.txt" regex False , regexTest "error3.txt" regex True , regexTest "error4.txt" regex False + , regexTest "error5.txt" regex False ] where regex = errorMessageRegexes !! 1 @@ -84,8 +87,9 @@ codeActionTest :: FilePath -> Int -> Int -> TestTree codeActionTest fp line col = goldenChangeSignature fp $ \doc -> do waitForDiagnostics -- code actions are triggered from Diagnostics actions <- getCodeActions doc (pointRange line col) - foundAction <- liftIO $ inspectCodeAction actions ["Change signature"] - executeCodeAction foundAction + foundActions <- findChangeTypeActions actions + liftIO $ length foundActions @?= 1 + executeCodeAction (head foundActions) codeActionProperties :: TestName -> [(Int, Int)] -> ([CodeAction] -> Session ()) -> TestTree codeActionProperties fp locs assertions = testCase fp $ do diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBinding.expected.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBinding.expected.hs new file mode 100644 index 0000000000..4e15704726 --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBinding.expected.hs @@ -0,0 +1,6 @@ +module TLocalBinding where + +local :: Int -> Int +local x = let test :: [Int] -> Int + test = head . reverse + in x + 1 diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBinding.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBinding.hs new file mode 100644 index 0000000000..3937213237 --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBinding.hs @@ -0,0 +1,6 @@ +module TLocalBinding where + +local :: Int -> Int +local x = let test :: Int -> Int + test = head . reverse + in x + 1 diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow1.expected.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow1.expected.hs new file mode 100644 index 0000000000..b8a5243f18 --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow1.expected.hs @@ -0,0 +1,9 @@ +module TLocalBindingShadow1 where + +local :: Int -> Int +local x = let test :: Int -> Int + test = (+2) + in test x + +test :: [Double] -> Double +test = head . reverse diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow1.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow1.hs new file mode 100644 index 0000000000..80a2cce85e --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow1.hs @@ -0,0 +1,9 @@ +module TLocalBindingShadow1 where + +local :: Int -> Int +local x = let test :: Int -> Int + test = (+2) + in test x + +test :: Int -> Double +test = head . reverse diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow2.expected.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow2.expected.hs new file mode 100644 index 0000000000..749ebc56b1 --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow2.expected.hs @@ -0,0 +1,9 @@ +module TLocalBindingShadow2 where + +local :: Int -> Int +local x = let test :: [Int] -> Int + test = head . reverse + in test x + +test :: String -> String +test = reverse diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow2.hs b/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow2.hs new file mode 100644 index 0000000000..c274a462bc --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/TLocalBindingShadow2.hs @@ -0,0 +1,9 @@ +module TLocalBindingShadow2 where + +local :: Int -> Int +local x = let test :: Int -> Int + test = head . reverse + in test x + +test :: String -> String +test = reverse diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/error5.txt b/plugins/hls-change-type-signature-plugin/test/testdata/error5.txt new file mode 100644 index 0000000000..a7a5d9a20b --- /dev/null +++ b/plugins/hls-change-type-signature-plugin/test/testdata/error5.txt @@ -0,0 +1,15 @@ + • Couldn't match type ‘(a0 -> m0 b0) -> m0 (t0 b0)’ with ‘Int’ + Expected type: Int -> Int + Actual type: t0 a0 -> (a0 -> m0 b0) -> m0 (t0 b0) + • Probable cause: ‘forM’ is applied to too few arguments + In the expression: forM + In an equation for ‘test’: test = forM + In an equation for ‘implicit’: + implicit + = return OpTEmpty + where + test :: Int -> Int + test = forM + | +82 | test = forM + | ^^^^ diff --git a/plugins/hls-change-type-signature-plugin/test/testdata/hie.yaml b/plugins/hls-change-type-signature-plugin/test/testdata/hie.yaml index 24b8c29036..8af53b6833 100644 --- a/plugins/hls-change-type-signature-plugin/test/testdata/hie.yaml +++ b/plugins/hls-change-type-signature-plugin/test/testdata/hie.yaml @@ -6,4 +6,7 @@ cradle: - TExpectedActual - TRigidType - TErrorGivenPartialSignature + - TLocalBinding + - TLocalBindingShadow1 + - TLocalBindingShadow2 - -Wall From 30750a755ef52a20ae1087f115659299a90df996 Mon Sep 17 00:00:00 2001 From: "J. S" Date: Sun, 20 Feb 2022 16:50:28 -0500 Subject: [PATCH 17/20] Improve logging (#2558) * convert to contravariant logging style part 1, uses additional hardcoded log file to see it side by side with original logging * convert Session to contravariant logging style * convert Plugin/HLS and FireStore to contravariant logging style * convert Rules (and most of the universe) to contravariant logging style * fix tests, allow old style logging and contravariant logging to write to same log file * fix import inside wrong CPP * add CPP for LogTactic constructor * remove redundant import * fix ghcide tests * remove unused import * fix plugin tests * LSP_TEST_STDERR should apply to contra logger as well * fix tactic plugin test * use CPP for Log datatype plugin constructors, remove unused imports * add a few Pretty instances, add prettyprinter to haskell-language-sever and hls-plugin-api dependencies * add Pretty Log instances for Session, FileStore, Notifications * add remaining Pretty Log instances * add logToPriorities * fix slight interleaving issue with hslogger and logger both logging, have default logger be mutex stderr or file handle, use stderr if failing to open log file * forgot to add .cabal files with hslogger dep * dont use UnliftIO file IO helpers because they are too new * remove log helper comments, use Doc instead of Text as final console/file logger input, renaming, export Log constructors * remove accidentally added useless file, removed prettyprinter dep from hls-plugin-api because stack ghc8.6.5 doesnt have it? * use deprecated prettyprint modules import for the sake of circleci ghc-8.6.5 * use dummy stderr logger for plugin cli commands, use priorityToHsLoggerPriority function instead of manual mapping * remove old plugin detritus that somehow got committed * fix prettyprinter imports for 8.6.5 * try enforcing prettyprinter bounds? * enforcing bound makes no sense * maybe changing stack yamls does trick * filter out warnings when their diags are empty to more closely match original * add ability to select wanted logging columns, match prev ghcide exe logging behaviour * dont log anything when diags are empty in some defineEarlyCutoff versions * use non-deprecated prettyprinter imports * fix ghcide test module * change logWith to accept priority at call site, remove all logToPriority functions, add cmapWithPrio that contramaps through WithPriority * remove useless hiding import list, add comments to default recorder makers * make cradleToOptsAndLibDir take concrete cradle to remove existential type var in Log constructor * Types.Logger now re-exports prettyprinter, remove unused dependencies on prettyprinter and hslogger * existential type var to remove boilerplate in Plugins.hs, remove a few Show instances * add SourceLoc logging column, inline logToDoc functions, add comment explaining hslogger setup existence * qualify a name to match original source * fix -WError --- exe/Main.hs | 51 +++- exe/Plugins.hs | 82 +++--- ghcide/exe/Main.hs | 73 +++-- .../session-loader/Development/IDE/Session.hs | 253 ++++++++++++------ ghcide/src/Development/IDE/Core/FileExists.hs | 42 ++- ghcide/src/Development/IDE/Core/FileStore.hs | 77 ++++-- ghcide/src/Development/IDE/Core/OfInterest.hs | 29 +- ghcide/src/Development/IDE/Core/Rules.hs | 242 +++++++++-------- ghcide/src/Development/IDE/Core/Service.hs | 37 ++- ghcide/src/Development/IDE/Core/Shake.hs | 141 +++++++--- ghcide/src/Development/IDE/GHC/ExactPrint.hs | 18 +- .../src/Development/IDE/LSP/LanguageServer.hs | 60 +++-- .../src/Development/IDE/LSP/Notifications.hs | 31 ++- ghcide/src/Development/IDE/Main.hs | 172 +++++++----- ghcide/src/Development/IDE/Main/HeapStats.hs | 50 +++- .../src/Development/IDE/Plugin/Completions.hs | 31 ++- ghcide/src/Development/IDE/Plugin/HLS.hs | 25 +- .../src/Development/IDE/Plugin/HLS/GhcIde.hs | 23 +- .../src/Development/IDE/Plugin/TypeLenses.hs | 25 +- ghcide/src/Development/IDE/Types/Logger.hs | 248 ++++++++++++++++- ghcide/test/exe/HieDbRetry.hs | 43 +-- ghcide/test/exe/Main.hs | 46 +++- haskell-language-server.cabal | 1 + hls-plugin-api/src/Ide/Types.hs | 1 + hls-test-utils/src/Test/Hls.hs | 91 +++++-- plugins/default/src/Ide/Plugin/Example.hs | 21 +- plugins/default/src/Ide/Plugin/Example2.hs | 23 +- .../src/Ide/Plugin/AlternateNumberFormat.hs | 19 +- .../test/Main.hs | 2 +- .../hls-eval-plugin/src/Ide/Plugin/Eval.hs | 35 ++- .../src/Ide/Plugin/Eval/Rules.hs | 28 +- plugins/hls-eval-plugin/test/Main.hs | 2 +- .../src/Ide/Plugin/ExplicitImports.hs | 29 +- .../hls-explicit-imports-plugin/test/Main.hs | 2 +- .../hls-hlint-plugin/src/Ide/Plugin/Hlint.hs | 27 +- plugins/hls-hlint-plugin/test/Main.hs | 2 +- .../src/Ide/Plugin/RefineImports.hs | 21 +- .../hls-refine-imports-plugin/test/Main.hs | 2 +- .../src/Ide/Plugin/Tactic.hs | 2 +- .../src/Wingman/LanguageServer.hs | 20 +- .../hls-tactics-plugin/src/Wingman/Plugin.hs | 17 +- plugins/hls-tactics-plugin/test/Utils.hs | 2 +- src/Ide/Arguments.hs | 1 + src/Ide/Main.hs | 68 +++-- stack-8.6.5.yaml | 1 + stack-8.8.4.yaml | 1 + 46 files changed, 1572 insertions(+), 645 deletions(-) diff --git a/exe/Main.hs b/exe/Main.hs index e5ba2cb6a7..d3f8af8d00 100644 --- a/exe/Main.hs +++ b/exe/Main.hs @@ -1,21 +1,50 @@ -- Copyright (c) 2019 The DAML Authors. All rights reserved. -- SPDX-License-Identifier: Apache-2.0 +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} module Main(main) where -import Ide.Arguments (Arguments (..), GhcideArguments (..), - getArguments) -import Ide.Main (defaultMain) -import Plugins +import Data.Function ((&)) +import Development.IDE.Types.Logger (Priority (Debug, Info), + WithPriority (WithPriority, priority), + cfilter, cmapWithPrio, + makeDefaultStderrRecorder, + withDefaultRecorder) +import Ide.Arguments (Arguments (..), + GhcideArguments (..), + getArguments) +import Ide.Main (defaultMain) +import qualified Ide.Main as IdeMain +import qualified Plugins +import Prettyprinter (Pretty (pretty)) + +data Log + = LogIdeMain IdeMain.Log + | LogPlugins Plugins.Log + +instance Pretty Log where + pretty log = case log of + LogIdeMain ideMainLog -> pretty ideMainLog + LogPlugins pluginsLog -> pretty pluginsLog main :: IO () main = do - args <- getArguments "haskell-language-server" (idePlugins False) + -- plugin cli commands use stderr logger for now unless we change the args + -- parser to get logging arguments first or do more complicated things + pluginCliRecorder <- cmapWithPrio pretty <$> makeDefaultStderrRecorder Nothing Info + args <- getArguments "haskell-language-server" (Plugins.idePlugins (cmapWithPrio LogPlugins pluginCliRecorder) False) + + let (minPriority, logFilePath, includeExamplePlugins) = + case args of + Ghcide GhcideArguments{ argsTesting, argsDebugOn, argsLogFile, argsExamplePlugin } -> + let minPriority = if argsDebugOn || argsTesting then Debug else Info + in (minPriority, argsLogFile, argsExamplePlugin) + _ -> (Info, Nothing, False) - let withExamples = - case args of - Ghcide GhcideArguments{..} -> argsExamplePlugin - _ -> False + withDefaultRecorder logFilePath Nothing minPriority $ \textWithPriorityRecorder -> do + let recorder = + textWithPriorityRecorder + & cfilter (\WithPriority{ priority } -> priority >= minPriority) + & cmapWithPrio pretty - defaultMain args (idePlugins withExamples) + defaultMain (cmapWithPrio LogIdeMain recorder) args (Plugins.idePlugins (cmapWithPrio LogPlugins recorder) includeExamplePlugins) diff --git a/exe/Plugins.hs b/exe/Plugins.hs index 5fb2013f73..05ccc8fb20 100644 --- a/exe/Plugins.hs +++ b/exe/Plugins.hs @@ -1,75 +1,78 @@ -{-# LANGUAGE CPP #-} -{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE CPP #-} +{-# LANGUAGE ExistentialQuantification #-} +{-# LANGUAGE OverloadedStrings #-} module Plugins where +import Development.IDE.Types.Logger (Pretty (pretty), Recorder, + WithPriority, cmapWithPrio) import Ide.PluginUtils (pluginDescToIdePlugins) import Ide.Types (IdePlugins) -- fixed plugins import Development.IDE (IdeState) -import Development.IDE.Plugin.HLS.GhcIde as GhcIde -import Ide.Plugin.Example as Example -import Ide.Plugin.Example2 as Example2 +import qualified Development.IDE.Plugin.HLS.GhcIde as GhcIde +import qualified Ide.Plugin.Example as Example +import qualified Ide.Plugin.Example2 as Example2 -- haskell-language-server optional plugins #if qualifyImportedNames -import Ide.Plugin.QualifyImportedNames as QualifyImportedNames +import qualified Ide.Plugin.QualifyImportedNames as QualifyImportedNames #endif #if callHierarchy -import Ide.Plugin.CallHierarchy as CallHierarchy +import qualified Ide.Plugin.CallHierarchy as CallHierarchy #endif #if class -import Ide.Plugin.Class as Class +import qualified Ide.Plugin.Class as Class #endif #if haddockComments -import Ide.Plugin.HaddockComments as HaddockComments +import qualified Ide.Plugin.HaddockComments as HaddockComments #endif #if eval -import Ide.Plugin.Eval as Eval +import qualified Ide.Plugin.Eval as Eval #endif #if importLens -import Ide.Plugin.ExplicitImports as ExplicitImports +import qualified Ide.Plugin.ExplicitImports as ExplicitImports #endif #if refineImports -import Ide.Plugin.RefineImports as RefineImports +import qualified Ide.Plugin.RefineImports as RefineImports #endif #if rename -import Ide.Plugin.Rename as Rename +import qualified Ide.Plugin.Rename as Rename #endif #if retrie -import Ide.Plugin.Retrie as Retrie +import qualified Ide.Plugin.Retrie as Retrie #endif #if tactic -import Ide.Plugin.Tactic as Tactic +import qualified Ide.Plugin.Tactic as Tactic #endif #if hlint -import Ide.Plugin.Hlint as Hlint +import qualified Ide.Plugin.Hlint as Hlint #endif #if moduleName -import Ide.Plugin.ModuleName as ModuleName +import qualified Ide.Plugin.ModuleName as ModuleName #endif #if pragmas -import Ide.Plugin.Pragmas as Pragmas +import qualified Ide.Plugin.Pragmas as Pragmas #endif #if splice -import Ide.Plugin.Splice as Splice +import qualified Ide.Plugin.Splice as Splice #endif #if alternateNumberFormat -import Ide.Plugin.AlternateNumberFormat as AlternateNumberFormat +import qualified Ide.Plugin.AlternateNumberFormat as AlternateNumberFormat #endif #if selectionRange @@ -82,25 +85,30 @@ import Ide.Plugin.ChangeTypeSignature as ChangeTypeSignature -- formatters #if floskell -import Ide.Plugin.Floskell as Floskell +import qualified Ide.Plugin.Floskell as Floskell #endif #if fourmolu -import Ide.Plugin.Fourmolu as Fourmolu +import qualified Ide.Plugin.Fourmolu as Fourmolu #endif #if ormolu -import Ide.Plugin.Ormolu as Ormolu +import qualified Ide.Plugin.Ormolu as Ormolu #endif #if stylishHaskell -import Ide.Plugin.StylishHaskell as StylishHaskell +import qualified Ide.Plugin.StylishHaskell as StylishHaskell #endif #if brittany -import Ide.Plugin.Brittany as Brittany +import qualified Ide.Plugin.Brittany as Brittany #endif +data Log = forall a. (Pretty a) => Log a + +instance Pretty Log where + pretty (Log a) = pretty a + -- --------------------------------------------------------------------- -- | The plugins configured for use in this instance of the language @@ -108,9 +116,11 @@ import Ide.Plugin.Brittany as Brittany -- These can be freely added or removed to tailor the available -- features of the server. -idePlugins :: Bool -> IdePlugins IdeState -idePlugins includeExamples = pluginDescToIdePlugins allPlugins +idePlugins :: Recorder (WithPriority Log) -> Bool -> IdePlugins IdeState +idePlugins recorder includeExamples = pluginDescToIdePlugins allPlugins where + pluginRecorder :: forall log. (Pretty log) => Recorder (WithPriority log) + pluginRecorder = cmapWithPrio Log recorder allPlugins = if includeExamples then basePlugins ++ examplePlugins else basePlugins @@ -125,7 +135,7 @@ idePlugins includeExamples = pluginDescToIdePlugins allPlugins Fourmolu.descriptor "fourmolu" : #endif #if tactic - Tactic.descriptor "tactics" : + Tactic.descriptor pluginRecorder "tactics" : #endif #if ormolu Ormolu.descriptor "ormolu" : @@ -152,28 +162,28 @@ idePlugins includeExamples = pluginDescToIdePlugins allPlugins HaddockComments.descriptor "haddockComments" : #endif #if eval - Eval.descriptor "eval" : + Eval.descriptor pluginRecorder "eval" : #endif #if importLens - ExplicitImports.descriptor "importLens" : + ExplicitImports.descriptor pluginRecorder "importLens" : #endif #if qualifyImportedNames QualifyImportedNames.descriptor "qualifyImportedNames" : #endif #if refineImports - RefineImports.descriptor "refineImports" : + RefineImports.descriptor pluginRecorder "refineImports" : #endif #if moduleName ModuleName.descriptor "moduleName" : #endif #if hlint - Hlint.descriptor "hlint" : + Hlint.descriptor pluginRecorder "hlint" : #endif #if splice Splice.descriptor "splice" : #endif #if alternateNumberFormat - AlternateNumberFormat.descriptor "alternateNumberFormat" : + AlternateNumberFormat.descriptor pluginRecorder "alternateNumberFormat" : #endif #if selectionRange SelectionRange.descriptor "selectionRange" : @@ -183,8 +193,8 @@ idePlugins includeExamples = pluginDescToIdePlugins allPlugins #endif -- The ghcide descriptors should come last so that the notification handlers -- (which restart the Shake build) run after everything else - GhcIde.descriptors + GhcIde.descriptors pluginRecorder examplePlugins = - [Example.descriptor "eg" - ,Example2.descriptor "eg2" + [Example.descriptor pluginRecorder "eg" + ,Example2.descriptor pluginRecorder "eg2" ] diff --git a/ghcide/exe/Main.hs b/ghcide/exe/Main.hs index c743231255..178052da71 100644 --- a/ghcide/exe/Main.hs +++ b/ghcide/exe/Main.hs @@ -9,17 +9,28 @@ import Arguments (Arguments (..), getArguments) import Control.Monad.Extra (unless) import Data.Default (def) +import Data.Function ((&)) import Data.Version (showVersion) import Development.GitRev (gitHash) -import Development.IDE (Priority (Debug, Info), - action) +import Development.IDE (action) import Development.IDE.Core.OfInterest (kick) import Development.IDE.Core.Rules (mainRule) +import qualified Development.IDE.Core.Rules as Rules import Development.IDE.Core.Tracing (withTelemetryLogger) import Development.IDE.Graph (ShakeOptions (shakeThreads)) -import qualified Development.IDE.Main as Main +import qualified Development.IDE.Main as IDEMain import qualified Development.IDE.Plugin.HLS.GhcIde as GhcIde +import Development.IDE.Types.Logger (Logger (Logger), + LoggingColumn (DataColumn, PriorityColumn), + Pretty (pretty), + Priority (Debug, Info), + Recorder (Recorder), + WithPriority (WithPriority, priority), + cfilter, cmapWithPrio, + makeDefaultStderrRecorder) +import qualified Development.IDE.Types.Logger as Logger import Development.IDE.Types.Options +import GHC.Stack (emptyCallStack) import Ide.Plugin.Config (Config (checkParents, checkProject)) import Ide.PluginUtils (pluginDescToIdePlugins) import Paths_ghcide (version) @@ -29,6 +40,17 @@ import System.Exit (exitSuccess) import System.IO (hPutStrLn, stderr) import System.Info (compilerVersion) +data Log + = LogIDEMain IDEMain.Log + | LogRules Rules.Log + | LogGhcIde GhcIde.Log + +instance Pretty Log where + pretty = \case + LogIDEMain log -> pretty log + LogRules log -> pretty log + LogGhcIde log -> pretty log + ghcideVersion :: IO String ghcideVersion = do path <- getExecutablePath @@ -42,7 +64,12 @@ ghcideVersion = do main :: IO () main = withTelemetryLogger $ \telemetryLogger -> do - let hlsPlugins = pluginDescToIdePlugins GhcIde.descriptors + -- stderr recorder just for plugin cli commands + pluginCliRecorder <- + cmapWithPrio pretty + <$> makeDefaultStderrRecorder (Just [PriorityColumn, DataColumn]) Info + + let hlsPlugins = pluginDescToIdePlugins (GhcIde.descriptors (cmapWithPrio LogGhcIde pluginCliRecorder)) -- WARNING: If you write to stdout before runLanguageServer -- then the language server will not work Arguments{..} <- getArguments hlsPlugins @@ -55,26 +82,42 @@ main = withTelemetryLogger $ \telemetryLogger -> do Nothing -> IO.getCurrentDirectory Just root -> IO.setCurrentDirectory root >> IO.getCurrentDirectory - let logPriority = if argsVerbose then Debug else Info - arguments = if argsTesting then Main.testing else Main.defaultArguments logPriority + let minPriority = if argsVerbose then Debug else Info + + docWithPriorityRecorder <- makeDefaultStderrRecorder (Just [PriorityColumn, DataColumn]) minPriority + + let docWithFilteredPriorityRecorder@Recorder{ logger_ } = + docWithPriorityRecorder + & cfilter (\WithPriority{ priority } -> priority >= minPriority) + + -- exists so old-style logging works. intended to be phased out + let logger = Logger $ \p m -> logger_ (WithPriority p emptyCallStack (pretty m)) + + let recorder = docWithFilteredPriorityRecorder + & cmapWithPrio pretty + + let arguments = + if argsTesting + then IDEMain.testing (cmapWithPrio LogIDEMain recorder) logger + else IDEMain.defaultArguments (cmapWithPrio LogIDEMain recorder) logger - Main.defaultMain arguments - { Main.argsProjectRoot = Just argsCwd - , Main.argCommand = argsCommand - ,Main.argsLogger = Main.argsLogger arguments <> pure telemetryLogger + IDEMain.defaultMain (cmapWithPrio LogIDEMain recorder) arguments + { IDEMain.argsProjectRoot = Just argsCwd + , IDEMain.argCommand = argsCommand + , IDEMain.argsLogger = IDEMain.argsLogger arguments <> pure telemetryLogger - ,Main.argsRules = do + , IDEMain.argsRules = do -- install the main and ghcide-plugin rules - mainRule def + mainRule (cmapWithPrio LogRules recorder) def -- install the kick action, which triggers a typecheck on every -- Shake database restart, i.e. on every user edit. unless argsDisableKick $ action kick - ,Main.argsThreads = case argsThreads of 0 -> Nothing ; i -> Just (fromIntegral i) + , IDEMain.argsThreads = case argsThreads of 0 -> Nothing ; i -> Just (fromIntegral i) - ,Main.argsIdeOptions = \config sessionLoader -> - let defOptions = Main.argsIdeOptions arguments config sessionLoader + , IDEMain.argsIdeOptions = \config sessionLoader -> + let defOptions = IDEMain.argsIdeOptions arguments config sessionLoader in defOptions { optShakeProfiling = argsShakeProfiling , optOTMemoryProfiling = IdeOTMemoryProfiling argsOTMemoryProfiling diff --git a/ghcide/session-loader/Development/IDE/Session.hs b/ghcide/session-loader/Development/IDE/Session.hs index 19d9ed4aaa..07d4595652 100644 --- a/ghcide/session-loader/Development/IDE/Session.hs +++ b/ghcide/session-loader/Development/IDE/Session.hs @@ -1,5 +1,6 @@ -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE ExistentialQuantification #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeFamilies #-} {-| The logic for setting up a ghcide session by tapping into hie-bios. @@ -14,6 +15,7 @@ module Development.IDE.Session ,runWithDb ,retryOnSqliteBusy ,retryOnException + ,Log(..) ) where -- Unfortunately, we cannot use loadSession with ghc-lib since hie-bios uses @@ -27,7 +29,7 @@ import Control.Monad import Control.Monad.Extra import Control.Monad.IO.Class import qualified Crypto.Hash.SHA1 as H -import Data.Aeson +import Data.Aeson hiding (Error) import Data.Bifunctor import qualified Data.ByteString.Base16 as B16 import qualified Data.ByteString.Char8 as B @@ -44,11 +46,12 @@ import qualified Data.Text as T import Data.Time.Clock import Data.Version import Development.IDE.Core.RuleTypes -import Development.IDE.Core.Shake hiding (withHieDb) +import Development.IDE.Core.Shake hiding (Log, Priority, + withHieDb) import qualified Development.IDE.GHC.Compat as Compat import Development.IDE.GHC.Compat.Core hiding (Target, TargetFile, TargetModule, - Var) + Var, Warning) import qualified Development.IDE.GHC.Compat.Core as GHC import Development.IDE.GHC.Compat.Env hiding (Logger) import Development.IDE.GHC.Compat.Units (UnitId) @@ -60,7 +63,11 @@ import Development.IDE.Types.Exports import Development.IDE.Types.HscEnvEq (HscEnvEq, newHscEnvEq, newHscEnvEqPreserveImportPaths) import Development.IDE.Types.Location -import Development.IDE.Types.Logger +import Development.IDE.Types.Logger (Pretty (pretty), + Priority (Debug, Error, Info, Warning), + Recorder, WithPriority, + logWith, nest, vcat, + viaShow, (<+>)) import Development.IDE.Types.Options import GHC.Check import qualified HIE.Bios as HieBios @@ -72,7 +79,6 @@ import Language.LSP.Types import System.Directory import qualified System.Directory.Extra as IO import System.FilePath -import System.IO import System.Info import Control.Applicative (Alternative ((<|>))) @@ -82,6 +88,8 @@ import Control.Concurrent.STM.Stats (atomically, modifyTVar', readTVar, writeTVar) import Control.Concurrent.STM.TQueue import Data.Foldable (for_) +import Data.HashMap.Strict (HashMap) +import Data.HashSet (HashSet) import qualified Data.HashSet as Set import Database.SQLite.Simple import Development.IDE.Core.Tracing (withTrace) @@ -92,6 +100,94 @@ import HieDb.Utils import System.Random (RandomGen) import qualified System.Random as Random +data Log + = LogSettingInitialDynFlags + | LogGetInitialGhcLibDirDefaultCradleFail !CradleError !FilePath !(Maybe FilePath) !(Cradle Void) + | LogGetInitialGhcLibDirDefaultCradleNone + | LogHieDbRetry !Int !Int !Int !SomeException + | LogHieDbRetriesExhausted !Int !Int !Int !SomeException + | LogHieDbWriterThreadSQLiteError !SQLError + | LogHieDbWriterThreadException !SomeException + | LogInterfaceFilesCacheDir !FilePath + | LogKnownFilesUpdated !(HashMap Target (HashSet NormalizedFilePath)) + | LogMakingNewHscEnv ![UnitId] + | LogDLLLoadError !String + | LogCradlePath !FilePath + | LogCradleNotFound !FilePath + | LogSessionLoadingResult !(Either [CradleError] (ComponentOptions, FilePath)) + | LogCradle !(Cradle Void) + | LogNoneCradleFound FilePath + | LogNewComponentCache !(([FileDiagnostic], Maybe HscEnvEq), DependencyInfo) +deriving instance Show Log + +instance Pretty Log where + pretty = \case + LogNoneCradleFound path -> + "None cradle found for" <+> pretty path <+> ", ignoring the file" + LogSettingInitialDynFlags -> + "Setting initial dynflags..." + LogGetInitialGhcLibDirDefaultCradleFail cradleError rootDirPath hieYamlPath cradle -> + nest 2 $ + vcat + [ "Couldn't load cradle for ghc libdir." + , "Cradle error:" <+> viaShow cradleError + , "Root dir path:" <+> pretty rootDirPath + , "hie.yaml path:" <+> pretty hieYamlPath + , "Cradle:" <+> viaShow cradle ] + LogGetInitialGhcLibDirDefaultCradleNone -> + "Couldn't load cradle. Cradle not found." + LogHieDbRetry delay maxDelay maxRetryCount e -> + nest 2 $ + vcat + [ "Retrying hiedb action..." + , "delay:" <+> pretty delay + , "maximum delay:" <+> pretty maxDelay + , "retries remaining:" <+> pretty maxRetryCount + , "SQLite error:" <+> pretty (displayException e) ] + LogHieDbRetriesExhausted baseDelay maxDelay maxRetryCount e -> + nest 2 $ + vcat + [ "Retries exhausted for hiedb action." + , "base delay:" <+> pretty baseDelay + , "maximum delay:" <+> pretty maxDelay + , "retries remaining:" <+> pretty maxRetryCount + , "Exception:" <+> pretty (displayException e) ] + LogHieDbWriterThreadSQLiteError e -> + nest 2 $ + vcat + [ "HieDb writer thread SQLite error:" + , pretty (displayException e) ] + LogHieDbWriterThreadException e -> + nest 2 $ + vcat + [ "HieDb writer thread exception:" + , pretty (displayException e) ] + LogInterfaceFilesCacheDir path -> + "Interface files cache directory:" <+> pretty path + LogKnownFilesUpdated targetToPathsMap -> + nest 2 $ + vcat + [ "Known files updated:" + , viaShow $ (HM.map . Set.map) fromNormalizedFilePath targetToPathsMap + ] + LogMakingNewHscEnv inPlaceUnitIds -> + "Making new HscEnv. In-place unit ids:" <+> pretty (map show inPlaceUnitIds) + LogDLLLoadError errorString -> + "Error dynamically loading libm.so.6:" <+> pretty errorString + LogCradlePath path -> + "Cradle path:" <+> pretty path + LogCradleNotFound path -> + vcat + [ "No [cradle](https://github.com/mpickering/hie-bios#hie-bios) found for" <+> pretty path <> "." + , "Proceeding with [implicit cradle](https://hackage.haskell.org/package/implicit-hie)." + , "You should ignore this message, unless you see a 'Multi Cradle: No prefixes matched' error." ] + LogSessionLoadingResult e -> + "Session loading result:" <+> viaShow e + LogCradle cradle -> + "Cradle:" <+> viaShow cradle + LogNewComponentCache componentCache -> + "New component cache HscEnvEq:" <+> viaShow componentCache + -- | Bump this version number when making changes to the format of the data stored in hiedb hiedbDataVersion :: String hiedbDataVersion = "1" @@ -110,7 +206,7 @@ data SessionLoadingOptions = SessionLoadingOptions -- or 'Nothing' to respect the cradle setting , getCacheDirs :: String -> [String] -> IO CacheDirs -- | Return the GHC lib dir to use for the 'unsafeGlobalDynFlags' - , getInitialGhcLibDir :: Logger -> FilePath -> IO (Maybe LibDir) + , getInitialGhcLibDir :: Recorder (WithPriority Log) -> FilePath -> IO (Maybe LibDir) , fakeUid :: UnitId -- ^ unit id used to tag the internal component built by ghcide -- To reuse external interface files the unit ids must match, @@ -119,7 +215,7 @@ data SessionLoadingOptions = SessionLoadingOptions } instance Default SessionLoadingOptions where - def = SessionLoadingOptions + def = SessionLoadingOptions {findCradle = HieBios.findCradle ,loadCradle = loadWithImplicitCradle ,getCacheDirs = getCacheDirsDefault @@ -148,26 +244,27 @@ loadWithImplicitCradle mHieYaml rootDir = do Just yaml -> HieBios.loadCradle yaml Nothing -> loadImplicitHieCradle $ addTrailingPathSeparator rootDir -getInitialGhcLibDirDefault :: Logger -> FilePath -> IO (Maybe LibDir) -getInitialGhcLibDirDefault logger rootDir = do +getInitialGhcLibDirDefault :: Recorder (WithPriority Log) -> FilePath -> IO (Maybe LibDir) +getInitialGhcLibDirDefault recorder rootDir = do + let log = logWith recorder hieYaml <- findCradle def rootDir cradle <- loadCradle def hieYaml rootDir - logDebug logger $ T.pack $ "setInitialDynFlags cradle: " ++ show cradle libDirRes <- getRuntimeGhcLibDir cradle case libDirRes of CradleSuccess libdir -> pure $ Just $ LibDir libdir CradleFail err -> do - hPutStrLn stderr $ "Couldn't load cradle for libdir: " ++ show (err,rootDir,hieYaml,cradle) + log Warning $ LogGetInitialGhcLibDirDefaultCradleFail err rootDir hieYaml cradle pure Nothing CradleNone -> do - hPutStrLn stderr "Couldn't load cradle (CradleNone)" + log Warning LogGetInitialGhcLibDirDefaultCradleNone pure Nothing -- | Sets `unsafeGlobalDynFlags` on using the hie-bios cradle and returns the GHC libdir -setInitialDynFlags :: Logger -> FilePath -> SessionLoadingOptions -> IO (Maybe LibDir) -setInitialDynFlags logger rootDir SessionLoadingOptions{..} = do - libdir <- getInitialGhcLibDir logger rootDir +setInitialDynFlags :: Recorder (WithPriority Log) -> FilePath -> SessionLoadingOptions -> IO (Maybe LibDir) +setInitialDynFlags recorder rootDir SessionLoadingOptions{..} = do + libdir <- getInitialGhcLibDir recorder rootDir dynFlags <- mapM dynFlagsForPrinting libdir + logWith recorder Debug LogSettingInitialDynFlags mapM_ setUnsafeGlobalDynFlags dynFlags pure libdir @@ -180,14 +277,14 @@ setInitialDynFlags logger rootDir SessionLoadingOptions{..} = do retryOnException :: (MonadIO m, MonadCatch m, RandomGen g, Exception e) => (e -> Maybe e) -- ^ only retry on exception if this predicate returns Just - -> Logger + -> Recorder (WithPriority Log) -> Int -- ^ maximum backoff delay in microseconds -> Int -- ^ base backoff delay in microseconds -> Int -- ^ maximum number of times to retry -> g -- ^ random number generator -> m a -- ^ action that may throw exception -> m a -retryOnException exceptionPred logger maxDelay !baseDelay !maxRetryCount rng action = do +retryOnException exceptionPred recorder maxDelay !baseDelay !maxRetryCount rng action = do result <- tryJust exceptionPred action case result of Left e @@ -197,30 +294,18 @@ retryOnException exceptionPred logger maxDelay !baseDelay !maxRetryCount rng act let (delay, newRng) = Random.randomR (0, newBaseDelay) rng let newMaxRetryCount = maxRetryCount - 1 liftIO $ do - logWarning logger $ "Retrying - " <> makeLogMsgComponentsText (Right delay) newMaxRetryCount e + log Warning $ LogHieDbRetry delay maxDelay newMaxRetryCount (toException e) threadDelay delay - retryOnException exceptionPred logger maxDelay newBaseDelay newMaxRetryCount newRng action + retryOnException exceptionPred recorder maxDelay newBaseDelay newMaxRetryCount newRng action | otherwise -> do liftIO $ do - logWarning logger $ "Retries exhausted - " <> makeLogMsgComponentsText (Left baseDelay) maxRetryCount e + log Warning $ LogHieDbRetriesExhausted baseDelay maxDelay maxRetryCount (toException e) throwIO e Right b -> pure b where - -- e.g. delay: 1010102, maximumDelay: 12010, maxRetryCount: 9, exception: SQLError { ... } - makeLogMsgComponentsText delay newMaxRetryCount e = - let - logMsgComponents = - [ either - (("base delay: " <>) . T.pack . show) - (("delay: " <>) . T.pack . show) - delay - , "maximumDelay: " <> T.pack (show maxDelay) - , "maxRetryCount: " <> T.pack (show newMaxRetryCount) - , "exception: " <> T.pack (show e)] - in - T.intercalate ", " logMsgComponents + log = logWith recorder -- | in microseconds oneSecond :: Int @@ -235,30 +320,30 @@ maxRetryCount :: Int maxRetryCount = 10 retryOnSqliteBusy :: (MonadIO m, MonadCatch m, RandomGen g) - => Logger -> g -> m a -> m a -retryOnSqliteBusy logger rng action = + => Recorder (WithPriority Log) -> g -> m a -> m a +retryOnSqliteBusy recorder rng action = let isErrorBusy e | SQLError{ sqlError = ErrorBusy } <- e = Just e | otherwise = Nothing in - retryOnException isErrorBusy logger oneSecond oneMillisecond maxRetryCount rng action + retryOnException isErrorBusy recorder oneSecond oneMillisecond maxRetryCount rng action -makeWithHieDbRetryable :: RandomGen g => Logger -> g -> HieDb -> WithHieDb -makeWithHieDbRetryable logger rng hieDb f = - retryOnSqliteBusy logger rng (f hieDb) +makeWithHieDbRetryable :: RandomGen g => Recorder (WithPriority Log) -> g -> HieDb -> WithHieDb +makeWithHieDbRetryable recorder rng hieDb f = + retryOnSqliteBusy recorder rng (f hieDb) -- | Wraps `withHieDb` to provide a database connection for reading, and a `HieWriterChan` for -- writing. Actions are picked off one by one from the `HieWriterChan` and executed in serial -- by a worker thread using a dedicated database connection. -- This is done in order to serialize writes to the database, or else SQLite becomes unhappy -runWithDb :: Logger -> FilePath -> (WithHieDb -> IndexQueue -> IO ()) -> IO () -runWithDb logger fp k = do +runWithDb :: Recorder (WithPriority Log) -> FilePath -> (WithHieDb -> IndexQueue -> IO ()) -> IO () +runWithDb recorder fp k = do -- use non-deterministic seed because maybe multiple HLS start at same time -- and send bursts of requests rng <- Random.newStdGen -- Delete the database if it has an incompatible schema version retryOnSqliteBusy - logger + recorder rng (withHieDb fp (const $ pure ()) `Safe.catch` \IncompatibleSchemaVersion{} -> removeFile fp) @@ -267,14 +352,16 @@ runWithDb logger fp k = do -- e.g. `withWriteDbRetrable initConn` without type signature will -- instantiate tyvar `a` to `()` let withWriteDbRetryable :: WithHieDb - withWriteDbRetryable = makeWithHieDbRetryable logger rng writedb + withWriteDbRetryable = makeWithHieDbRetryable recorder rng writedb withWriteDbRetryable initConn chan <- newTQueueIO withAsync (writerThread withWriteDbRetryable chan) $ \_ -> do - withHieDb fp (\readDb -> k (makeWithHieDbRetryable logger rng readDb) chan) + withHieDb fp (\readDb -> k (makeWithHieDbRetryable recorder rng readDb) chan) where + log = logWith recorder + writerThread :: WithHieDb -> IndexQueue -> IO () writerThread withHieDbRetryable chan = do -- Clear the index of any files that might have been deleted since the last run @@ -282,11 +369,12 @@ runWithDb logger fp k = do _ <- withHieDbRetryable garbageCollectTypeNames forever $ do k <- atomically $ readTQueue chan + -- TODO: probably should let exceptions be caught/logged/handled by top level handler k withHieDbRetryable `Safe.catch` \e@SQLError{} -> do - logDebug logger $ T.pack $ "SQLite error in worker, ignoring: " ++ show e + log Error $ LogHieDbWriterThreadSQLiteError e `Safe.catchAny` \e -> do - logDebug logger $ T.pack $ "Uncaught error in database worker, ignoring: " ++ show e + log Error $ LogHieDbWriterThreadException e getHieDbLoc :: FilePath -> IO FilePath @@ -310,11 +398,11 @@ getHieDbLoc dir = do -- This is the key function which implements multi-component support. All -- components mapping to the same hie.yaml file are mapped to the same -- HscEnv which is updated as new components are discovered. -loadSession :: FilePath -> IO (Action IdeGhcSession) -loadSession = loadSessionWithOptions def +loadSession :: Recorder (WithPriority Log) -> FilePath -> IO (Action IdeGhcSession) +loadSession recorder = loadSessionWithOptions recorder def -loadSessionWithOptions :: SessionLoadingOptions -> FilePath -> IO (Action IdeGhcSession) -loadSessionWithOptions SessionLoadingOptions{..} dir = do +loadSessionWithOptions :: Recorder (WithPriority Log) -> SessionLoadingOptions -> FilePath -> IO (Action IdeGhcSession) +loadSessionWithOptions recorder SessionLoadingOptions{..} dir = do -- Mapping from hie.yaml file to HscEnv, one per hie.yaml file hscEnvs <- newVar Map.empty :: IO (Var HieMap) -- Mapping from a Filepath to HscEnv @@ -340,7 +428,7 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do runningCradle <- newVar dummyAs :: IO (Var (Async (IdeResult HscEnvEq,[FilePath]))) return $ do - extras@ShakeExtras{logger, restartShakeSession, ideNc, knownTargetsVar, lspEnv + extras@ShakeExtras{restartShakeSession, ideNc, knownTargetsVar, lspEnv } <- getShakeExtras let invalidateShakeCache :: IO () invalidateShakeCache = do @@ -371,8 +459,7 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do logDirtyKeys <- recordDirtyKeys extras GetKnownTargets [emptyFilePath] return (logDirtyKeys >> pure hasUpdate) for_ hasUpdate $ \x -> - logDebug logger $ "Known files updated: " <> - T.pack(show $ (HM.map . Set.map) fromNormalizedFilePath x) + logWith recorder Debug $ LogKnownFilesUpdated x -- Create a new HscEnv from a hieYaml root and a set of options -- If the hieYaml file already has an HscEnv, the new component is @@ -412,7 +499,7 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do let hscComponents = sort $ map show uids cacheDirOpts = hscComponents ++ componentOptions opts cacheDirs <- liftIO $ getCacheDirs prefix cacheDirOpts - processed_df <- setCacheDirs logger cacheDirs df2 + processed_df <- setCacheDirs recorder cacheDirs df2 -- The final component information, mostly the same but the DynFlags don't -- contain any packages which are also loaded -- into the same component. @@ -427,7 +514,7 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do -- scratch again (for now) -- It's important to keep the same NameCache though for reasons -- that I do not fully understand - logInfo logger (T.pack ("Making new HscEnv" ++ show inplace)) + log Info $ LogMakingNewHscEnv inplace hscEnv <- emptyHscEnv ideNc libDir newHscEnv <- -- Add the options for the current component to the HscEnv @@ -463,9 +550,9 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do initObjLinker hscEnv res <- loadDLL hscEnv "libm.so.6" case res of - Nothing -> pure () - Just err -> logDebug logger $ T.pack $ - "Error dynamically loading libm.so.6:\n" <> err + Nothing -> pure () + Just err -> log Error $ LogDLLLoadError err + -- Make a map from unit-id to DynFlags, this is used when trying to -- resolve imports. (especially PackageImports) @@ -476,7 +563,7 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do -- New HscEnv for the component in question, returns the new HscEnvEq and -- a mapping from FilePath to the newly created HscEnvEq. - let new_cache = newComponentCache logger optExtensions hieYaml _cfp hscEnv uids + let new_cache = newComponentCache recorder optExtensions hieYaml _cfp hscEnv uids (cs, res) <- new_cache new -- Modified cache targets for everything else in the hie.yaml file -- which now uses the same EPS and so on @@ -513,10 +600,10 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do let consultCradle :: Maybe FilePath -> FilePath -> IO (IdeResult HscEnvEq, [FilePath]) consultCradle hieYaml cfp = do lfp <- flip makeRelative cfp <$> getCurrentDirectory - logInfo logger $ T.pack ("Consulting the cradle for " <> show lfp) + log Info $ LogCradlePath lfp when (isNothing hieYaml) $ - logWarning logger $ implicitCradleWarning lfp + log Warning $ LogCradleNotFound lfp cradle <- loadCradle hieYaml dir lfp <- flip makeRelative cfp <$> getCurrentDirectory @@ -530,12 +617,11 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do eopts <- mRunLspTCallback lspEnv (withIndefiniteProgress progMsg NotCancellable) $ withTrace "Load cradle" $ \addTag -> do addTag "file" lfp - res <- cradleToOptsAndLibDir logger cradle cfp + res <- cradleToOptsAndLibDir recorder cradle cfp addTag "result" (show res) return res - - logDebug logger $ T.pack ("Session loading result: " <> show eopts) + log Debug $ LogSessionLoadingResult eopts case eopts of -- The cradle gave us some options so get to work turning them -- into and HscEnv. @@ -598,18 +684,19 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do as <- async $ getOptions file return (as, wait as) pure opts + where + log = logWith recorder -- | Run the specific cradle on a specific FilePath via hie-bios. -- This then builds dependencies or whatever based on the cradle, gets the -- GHC options/dynflags needed for the session and the GHC library directory - -cradleToOptsAndLibDir :: Show a => Logger -> Cradle a -> FilePath +cradleToOptsAndLibDir :: Recorder (WithPriority Log) -> Cradle Void -> FilePath -> IO (Either [CradleError] (ComponentOptions, FilePath)) -cradleToOptsAndLibDir logger cradle file = do - let noneCradleFoundMessage :: FilePath -> T.Text - noneCradleFoundMessage f = T.pack $ "none cradle found for " <> f <> ", ignoring the file" +cradleToOptsAndLibDir recorder cradle file = do + -- let noneCradleFoundMessage :: FilePath -> T.Text + -- noneCradleFoundMessage f = T.pack $ "none cradle found for " <> f <> ", ignoring the file" -- Start off by getting the session options - logDebug logger $ T.pack $ "Output from setting up the cradle " <> show cradle + logWith recorder Debug $ LogCradle cradle cradleRes <- HieBios.getCompilerOptions file cradle case cradleRes of CradleSuccess r -> do @@ -620,12 +707,12 @@ cradleToOptsAndLibDir logger cradle file = do CradleSuccess libDir -> pure (Right (r, libDir)) CradleFail err -> return (Left [err]) CradleNone -> do - logInfo logger $ noneCradleFoundMessage file + logWith recorder Info $ LogNoneCradleFound file return (Left []) CradleFail err -> return (Left [err]) CradleNone -> do - logInfo logger $ noneCradleFoundMessage file + logWith recorder Info $ LogNoneCradleFound file return (Left []) emptyHscEnv :: IORef NameCache -> FilePath -> IO HscEnv @@ -672,7 +759,7 @@ setNameCache nc hsc = hsc { hsc_NC = nc } -- | Create a mapping from FilePaths to HscEnvEqs newComponentCache - :: Logger + :: Recorder (WithPriority Log) -> [String] -- File extensions to consider -> Maybe FilePath -- Path to cradle -> NormalizedFilePath -- Path to file that caused the creation of this component @@ -680,7 +767,7 @@ newComponentCache -> [(UnitId, DynFlags)] -> ComponentInfo -> IO ( [TargetDetails], (IdeResult HscEnvEq, DependencyInfo)) -newComponentCache logger exts cradlePath cfp hsc_env uids ci = do +newComponentCache recorder exts cradlePath cfp hsc_env uids ci = do let df = componentDynFlags ci let hscEnv' = hscSetFlags df hsc_env { hsc_IC = (hsc_IC hsc_env) { ic_dflags = df } } @@ -690,7 +777,7 @@ newComponentCache logger exts cradlePath cfp hsc_env uids ci = do let targetEnv = ([], Just henv) targetDepends = componentDependencyInfo ci res = (targetEnv, targetDepends) - logDebug logger ("New Component Cache HscEnvEq: " <> T.pack (show res)) + logWith recorder Debug $ LogNewComponentCache res let mk t = fromTargetId (importPaths df) exts (targetId t) targetEnv targetDepends ctargets <- concatMapM mk (componentTargets ci) @@ -758,9 +845,9 @@ should be filtered out, such that we dont have to re-compile everything. -- | Set the cache-directory based on the ComponentOptions and a list of -- internal packages. -- For the exact reason, see Note [Avoiding bad interface files]. -setCacheDirs :: MonadIO m => Logger -> CacheDirs -> DynFlags -> m DynFlags -setCacheDirs logger CacheDirs{..} dflags = do - liftIO $ logInfo logger $ "Using interface files cache dir: " <> T.pack (fromMaybe cacheDir hiCacheDir) +setCacheDirs :: MonadIO m => Recorder (WithPriority Log) -> CacheDirs -> DynFlags -> m DynFlags +setCacheDirs recorder CacheDirs{..} dflags = do + logWith recorder Info $ LogInterfaceFilesCacheDir (fromMaybe cacheDir hiCacheDir) pure $ dflags & maybe id setHiDir hiCacheDir & maybe id setHieDir hieCacheDir @@ -933,12 +1020,6 @@ getCacheDirsDefault prefix opts = do cacheDir :: String cacheDir = "ghcide" -implicitCradleWarning :: FilePath -> T.Text -implicitCradleWarning fp = - "No [cradle](https://github.com/mpickering/hie-bios#hie-bios) found for " - <> T.pack fp <> - ".\n Proceeding with [implicit cradle](https://hackage.haskell.org/package/implicit-hie).\n"<> - "You should ignore this message, unless you see a 'Multi Cradle: No prefixes matched' error." ---------------------------------------------------------------------------------------------------- data PackageSetupException diff --git a/ghcide/src/Development/IDE/Core/FileExists.hs b/ghcide/src/Development/IDE/Core/FileExists.hs index 15cddd821e..d30f8047f2 100644 --- a/ghcide/src/Development/IDE/Core/FileExists.hs +++ b/ghcide/src/Development/IDE/Core/FileExists.hs @@ -7,6 +7,7 @@ module Development.IDE.Core.FileExists , getFileExists , watchedGlobs , GetFileExists(..) + , Log(..) ) where @@ -18,12 +19,17 @@ import Control.Monad.IO.Class import qualified Data.ByteString as BS import Data.List (partition) import Data.Maybe -import Development.IDE.Core.FileStore +import Development.IDE.Core.FileStore hiding (Log, LogShake) +import qualified Development.IDE.Core.FileStore as FileStore import Development.IDE.Core.IdeConfiguration import Development.IDE.Core.RuleTypes -import Development.IDE.Core.Shake +import Development.IDE.Core.Shake hiding (Log) +import qualified Development.IDE.Core.Shake as Shake import Development.IDE.Graph import Development.IDE.Types.Location +import Development.IDE.Types.Logger (Pretty (pretty), + Recorder, WithPriority, + cmapWithPrio) import Development.IDE.Types.Options import qualified Focus import Ide.Plugin.Config (Config) @@ -82,6 +88,16 @@ newtype FileExistsMapVar = FileExistsMapVar FileExistsMap instance IsIdeGlobal FileExistsMapVar +data Log + = LogFileStore FileStore.Log + | LogShake Shake.Log + deriving Show + +instance Pretty Log where + pretty = \case + LogFileStore log -> pretty log + LogShake log -> pretty log + -- | Grab the current global value of 'FileExistsMap' without acquiring a dependency getFileExistsMapUntracked :: Action FileExistsMap getFileExistsMapUntracked = do @@ -157,8 +173,8 @@ allExtensions opts = [extIncBoot | ext <- optExtensions opts, extIncBoot <- [ext -- | Installs the 'getFileExists' rules. -- Provides a fast implementation if client supports dynamic watched files. -- Creates a global state as a side effect in that case. -fileExistsRules :: Maybe (LanguageContextEnv Config) -> VFSHandle -> Rules () -fileExistsRules lspEnv vfs = do +fileExistsRules :: Recorder (WithPriority Log) -> Maybe (LanguageContextEnv Config) -> VFSHandle -> Rules () +fileExistsRules recorder lspEnv vfs = do supportsWatchedFiles <- case lspEnv of Nothing -> pure False Just lspEnv' -> liftIO $ runLspT lspEnv' isWatchSupported @@ -179,15 +195,15 @@ fileExistsRules lspEnv vfs = do else const $ pure False if supportsWatchedFiles - then fileExistsRulesFast isWatched vfs - else fileExistsRulesSlow vfs + then fileExistsRulesFast recorder isWatched vfs + else fileExistsRulesSlow recorder vfs - fileStoreRules vfs isWatched + fileStoreRules (cmapWithPrio LogFileStore recorder) vfs isWatched -- Requires an lsp client that provides WatchedFiles notifications, but assumes that this has already been checked. -fileExistsRulesFast :: (NormalizedFilePath -> Action Bool) -> VFSHandle -> Rules () -fileExistsRulesFast isWatched vfs = - defineEarlyCutoff $ RuleNoDiagnostics $ \GetFileExists file -> do +fileExistsRulesFast :: Recorder (WithPriority Log) -> (NormalizedFilePath -> Action Bool) -> VFSHandle -> Rules () +fileExistsRulesFast recorder isWatched vfs = + defineEarlyCutoff (cmapWithPrio LogShake recorder) $ RuleNoDiagnostics $ \GetFileExists file -> do isWF <- isWatched file if isWF then fileExistsFast vfs file @@ -225,9 +241,9 @@ fileExistsFast vfs file = do summarizeExists :: Bool -> Maybe BS.ByteString summarizeExists x = Just $ if x then BS.singleton 1 else BS.empty -fileExistsRulesSlow :: VFSHandle -> Rules () -fileExistsRulesSlow vfs = - defineEarlyCutoff $ RuleNoDiagnostics $ \GetFileExists file -> fileExistsSlow vfs file +fileExistsRulesSlow :: Recorder (WithPriority Log) -> VFSHandle -> Rules () +fileExistsRulesSlow recorder vfs = + defineEarlyCutoff (cmapWithPrio LogShake recorder) $ RuleNoDiagnostics $ \GetFileExists file -> fileExistsSlow vfs file fileExistsSlow :: VFSHandle -> NormalizedFilePath -> Action (Maybe BS.ByteString, Maybe Bool) fileExistsSlow vfs file = do diff --git a/ghcide/src/Development/IDE/Core/FileStore.hs b/ghcide/src/Development/IDE/Core/FileStore.hs index f6f93d3c02..81a2fea695 100644 --- a/ghcide/src/Development/IDE/Core/FileStore.hs +++ b/ghcide/src/Development/IDE/Core/FileStore.hs @@ -21,7 +21,8 @@ module Development.IDE.Core.FileStore( getFileContentsImpl, getModTime, isWatchSupported, - registerFileWatches + registerFileWatches, + Log(..) ) where import Control.Concurrent.STM.Stats (STM, atomically, @@ -40,7 +41,7 @@ import qualified Data.Text as T import Data.Time import Data.Time.Clock.POSIX import Development.IDE.Core.RuleTypes -import Development.IDE.Core.Shake +import Development.IDE.Core.Shake hiding (Log) import Development.IDE.GHC.Orphans () import Development.IDE.Graph import Development.IDE.Import.DependencyInformation @@ -67,6 +68,14 @@ import qualified Data.HashSet as HSet import Data.List (foldl') import qualified Data.Text as Text import Development.IDE.Core.IdeConfiguration (isWorkspaceFile) +import qualified Development.IDE.Core.Shake as Shake +import Development.IDE.Types.Logger (Pretty (pretty), + Priority (Info), + Recorder, + WithPriority, + cmapWithPrio, + logWith, viaShow, + (<+>)) import Language.LSP.Server hiding (getVirtualFile) import qualified Language.LSP.Server as LSP @@ -80,6 +89,23 @@ import qualified Language.LSP.Types.Capabilities as LSP import Language.LSP.VFS import System.FilePath +data Log + = LogCouldNotIdentifyReverseDeps !NormalizedFilePath + | LogTypeCheckingReverseDeps !NormalizedFilePath !(Maybe [NormalizedFilePath]) + | LogShake Shake.Log + deriving Show + +instance Pretty Log where + pretty = \case + LogCouldNotIdentifyReverseDeps path -> + "Could not identify reverse dependencies for" <+> viaShow path + (LogTypeCheckingReverseDeps path reverseDepPaths) -> + "Typechecking reverse dependecies for" + <+> viaShow path + <> ":" + <+> pretty (fmap (fmap show) reverseDepPaths) + LogShake log -> pretty log + makeVFSHandle :: IO VFSHandle makeVFSHandle = do vfsVar <- newVar (1, Map.empty) @@ -101,8 +127,8 @@ makeLSPVFSHandle lspEnv = VFSHandle , setVirtualFileContents = Nothing } -addWatchedFileRule :: (NormalizedFilePath -> Action Bool) -> Rules () -addWatchedFileRule isWatched = defineNoDiagnostics $ \AddWatchedFile f -> do +addWatchedFileRule :: Recorder (WithPriority Log) -> (NormalizedFilePath -> Action Bool) -> Rules () +addWatchedFileRule recorder isWatched = defineNoDiagnostics (cmapWithPrio LogShake recorder) $ \AddWatchedFile f -> do isAlreadyWatched <- isWatched f isWp <- isWorkspaceFile f if isAlreadyWatched then pure (Just True) else @@ -114,8 +140,8 @@ addWatchedFileRule isWatched = defineNoDiagnostics $ \AddWatchedFile f -> do Nothing -> pure $ Just False -getModificationTimeRule :: VFSHandle -> Rules () -getModificationTimeRule vfs = defineEarlyCutoff $ Rule $ \(GetModificationTime_ missingFileDiags) file -> +getModificationTimeRule :: Recorder (WithPriority Log) -> VFSHandle -> Rules () +getModificationTimeRule recorder vfs = defineEarlyCutoff (cmapWithPrio LogShake recorder) $ Rule $ \(GetModificationTime_ missingFileDiags) file -> getModificationTimeImpl vfs missingFileDiags file getModificationTimeImpl :: VFSHandle @@ -201,8 +227,8 @@ modificationTime :: FileVersion -> Maybe UTCTime modificationTime VFSVersion{} = Nothing modificationTime (ModificationTime posix) = Just $ posixSecondsToUTCTime posix -getFileContentsRule :: VFSHandle -> Rules () -getFileContentsRule vfs = define $ \GetFileContents file -> getFileContentsImpl vfs file +getFileContentsRule :: Recorder (WithPriority Log) -> VFSHandle -> Rules () +getFileContentsRule recorder vfs = define (cmapWithPrio LogShake recorder) $ \GetFileContents file -> getFileContentsImpl vfs file getFileContentsImpl :: VFSHandle @@ -240,20 +266,21 @@ getFileContents f = do pure $ posixSecondsToUTCTime posix return (modTime, txt) -fileStoreRules :: VFSHandle -> (NormalizedFilePath -> Action Bool) -> Rules () -fileStoreRules vfs isWatched = do +fileStoreRules :: Recorder (WithPriority Log) -> VFSHandle -> (NormalizedFilePath -> Action Bool) -> Rules () +fileStoreRules recorder vfs isWatched = do addIdeGlobal vfs - getModificationTimeRule vfs - getFileContentsRule vfs - addWatchedFileRule isWatched + getModificationTimeRule recorder vfs + getFileContentsRule recorder vfs + addWatchedFileRule recorder isWatched -- | Note that some buffer for a specific file has been modified but not -- with what changes. -setFileModified :: IdeState +setFileModified :: Recorder (WithPriority Log) + -> IdeState -> Bool -- ^ Was the file saved? -> NormalizedFilePath -> IO () -setFileModified state saved nfp = do +setFileModified recorder state saved nfp = do ideOptions <- getIdeOptionsIO $ shakeExtras state doCheckParents <- optCheckParents ideOptions let checkParents = case doCheckParents of @@ -266,22 +293,20 @@ setFileModified state saved nfp = do join $ atomically $ recordDirtyKeys (shakeExtras state) GetModificationTime [nfp] restartShakeSession (shakeExtras state) (fromNormalizedFilePath nfp ++ " (modified)") [] when checkParents $ - typecheckParents state nfp + typecheckParents recorder state nfp -typecheckParents :: IdeState -> NormalizedFilePath -> IO () -typecheckParents state nfp = void $ shakeEnqueue (shakeExtras state) parents - where parents = mkDelayedAction "ParentTC" L.Debug (typecheckParentsAction nfp) +typecheckParents :: Recorder (WithPriority Log) -> IdeState -> NormalizedFilePath -> IO () +typecheckParents recorder state nfp = void $ shakeEnqueue (shakeExtras state) parents + where parents = mkDelayedAction "ParentTC" L.Debug (typecheckParentsAction recorder nfp) -typecheckParentsAction :: NormalizedFilePath -> Action () -typecheckParentsAction nfp = do +typecheckParentsAction :: Recorder (WithPriority Log) -> NormalizedFilePath -> Action () +typecheckParentsAction recorder nfp = do revs <- transitiveReverseDependencies nfp <$> useNoFile_ GetModuleGraph - logger <- logger <$> getShakeExtras - let log = L.logInfo logger . T.pack + let log = logWith recorder case revs of - Nothing -> liftIO $ log $ "Could not identify reverse dependencies for " ++ show nfp + Nothing -> log Info $ LogCouldNotIdentifyReverseDeps nfp Just rs -> do - liftIO $ (log $ "Typechecking reverse dependencies for " ++ show nfp ++ ": " ++ show revs) - `catch` \(e :: SomeException) -> log (show e) + log Info $ LogTypeCheckingReverseDeps nfp revs void $ uses GetModIface rs -- | Note that some keys have been modified and restart the session diff --git a/ghcide/src/Development/IDE/Core/OfInterest.hs b/ghcide/src/Development/IDE/Core/OfInterest.hs index 8f31856098..3d50287c3b 100644 --- a/ghcide/src/Development/IDE/Core/OfInterest.hs +++ b/ghcide/src/Development/IDE/Core/OfInterest.hs @@ -14,8 +14,10 @@ module Development.IDE.Core.OfInterest( deleteFileOfInterest, setFilesOfInterest, kick, FileOfInterestStatus(..), - OfInterestVar(..) - ,scheduleGarbageCollection) where + OfInterestVar(..), + scheduleGarbageCollection, + Log(..) + ) where import Control.Concurrent.Strict import Control.Monad @@ -32,24 +34,37 @@ import qualified Data.ByteString as BS import Data.Maybe (catMaybes) import Development.IDE.Core.ProgressReporting import Development.IDE.Core.RuleTypes -import Development.IDE.Core.Shake +import Development.IDE.Core.Shake hiding (Log) +import qualified Development.IDE.Core.Shake as Shake import Development.IDE.Plugin.Completions.Types import Development.IDE.Types.Exports import Development.IDE.Types.Location -import Development.IDE.Types.Logger +import Development.IDE.Types.Logger (Pretty (pretty), + Recorder, + WithPriority, + cmapWithPrio, + logDebug) import Development.IDE.Types.Options (IdeTesting (..)) import qualified Language.LSP.Server as LSP import qualified Language.LSP.Types as LSP +data Log = LogShake Shake.Log + deriving Show + +instance Pretty Log where + pretty = \case + LogShake log -> pretty log + newtype OfInterestVar = OfInterestVar (Var (HashMap NormalizedFilePath FileOfInterestStatus)) + instance IsIdeGlobal OfInterestVar -- | The rule that initialises the files of interest state. -ofInterestRules :: Rules () -ofInterestRules = do +ofInterestRules :: Recorder (WithPriority Log) -> Rules () +ofInterestRules recorder = do addIdeGlobal . OfInterestVar =<< liftIO (newVar HashMap.empty) addIdeGlobal . GarbageCollectVar =<< liftIO (newVar False) - defineEarlyCutoff $ RuleNoDiagnostics $ \IsFileOfInterest f -> do + defineEarlyCutoff (cmapWithPrio LogShake recorder) $ RuleNoDiagnostics $ \IsFileOfInterest f -> do alwaysRerun filesOfInterest <- getFilesOfInterestUntracked let foi = maybe NotFOI IsFOI $ f `HashMap.lookup` filesOfInterest diff --git a/ghcide/src/Development/IDE/Core/Rules.hs b/ghcide/src/Development/IDE/Core/Rules.hs index ba4bec4e50..5e8b33a28c 100644 --- a/ghcide/src/Development/IDE/Core/Rules.hs +++ b/ghcide/src/Development/IDE/Core/Rules.hs @@ -57,6 +57,7 @@ module Development.IDE.Core.Rules( getParsedModuleDefinition, typeCheckRuleDefinition, GhcSessionDepsConfig(..), + Log(..), DisplayTHWarning(..), ) where @@ -96,25 +97,27 @@ import qualified Data.Text.Encoding as T import Data.Time (UTCTime (..)) import Data.Tuple.Extra import Development.IDE.Core.Compile -import Development.IDE.Core.FileExists +import Development.IDE.Core.FileExists hiding (LogShake, Log) import Development.IDE.Core.FileStore (getFileContents, modificationTime, resetInterfaceStore) import Development.IDE.Core.IdeConfiguration -import Development.IDE.Core.OfInterest +import Development.IDE.Core.OfInterest hiding (LogShake, Log) import Development.IDE.Core.PositionMapping import Development.IDE.Core.RuleTypes -import Development.IDE.Core.Service -import Development.IDE.Core.Shake +import Development.IDE.Core.Service hiding (LogShake, Log) +import Development.IDE.Core.Shake hiding (Log) +import Development.IDE.GHC.Compat.Env import Development.IDE.GHC.Compat hiding - (parseModule, + (vcat, nest, parseModule, TargetId(..), loadInterface, - Var) -import qualified Development.IDE.GHC.Compat as Compat + Var, + (<+>)) +import qualified Development.IDE.GHC.Compat as Compat hiding (vcat, nest) import qualified Development.IDE.GHC.Compat.Util as Util import Development.IDE.GHC.Error -import Development.IDE.GHC.ExactPrint +import Development.IDE.GHC.ExactPrint hiding (LogShake, Log) import Development.IDE.GHC.Util hiding (modifyDynFlags) import Development.IDE.Graph @@ -127,7 +130,6 @@ import Development.IDE.Spans.LocalBindings import Development.IDE.Types.Diagnostics as Diag import Development.IDE.Types.HscEnvEq import Development.IDE.Types.Location -import qualified Development.IDE.Types.Logger as L import Development.IDE.Types.Options import GHC.Generics (Generic) import qualified GHC.LanguageExtensions as LangExt @@ -150,6 +152,35 @@ import Control.Concurrent.STM.Stats (atomically) import Language.LSP.Server (LspT) import System.Info.Extra (isWindows) import HIE.Bios.Ghc.Gap (hostIsDynamic) +import Development.IDE.Types.Logger (Recorder, logWith, cmapWithPrio, WithPriority, Pretty (pretty), (<+>), nest, vcat) +import qualified Development.IDE.Core.Shake as Shake +import qualified Development.IDE.GHC.ExactPrint as ExactPrint hiding (LogShake) +import qualified Development.IDE.Types.Logger as Logger + +data Log + = LogShake Shake.Log + | LogReindexingHieFile !NormalizedFilePath + | LogLoadingHieFile !NormalizedFilePath + | LogLoadingHieFileFail !FilePath !SomeException + | LogLoadingHieFileSuccess !FilePath + | LogExactPrint ExactPrint.Log + deriving Show + +instance Pretty Log where + pretty = \case + LogShake log -> pretty log + LogReindexingHieFile path -> + "Re-indexing hie file for" <+> pretty (fromNormalizedFilePath path) + LogLoadingHieFile path -> + "LOADING HIE FILE FOR" <+> pretty (fromNormalizedFilePath path) + LogLoadingHieFileFail path e -> + nest 2 $ + vcat + [ "FAILED LOADING HIE FILE FOR" <+> pretty path + , pretty (displayException e) ] + LogLoadingHieFileSuccess path -> + "SUCCEEDED LOADING HIE FILE FOR" <+> pretty path + LogExactPrint log -> pretty log templateHaskellInstructions :: T.Text templateHaskellInstructions = "https://haskell-language-server.readthedocs.io/en/latest/troubleshooting.html#static-binaries" @@ -207,10 +238,10 @@ priorityFilesOfInterest = Priority (-2) -- See https://github.com/haskell/ghcide/pull/350#discussion_r370878197 -- and https://github.com/mpickering/ghcide/pull/22#issuecomment-625070490 -- GHC wiki about: https://gitlab.haskell.org/ghc/ghc/-/wikis/api-annotations -getParsedModuleRule :: Rules () -getParsedModuleRule = +getParsedModuleRule :: Recorder (WithPriority Log) -> Rules () +getParsedModuleRule recorder = -- this rule does not have early cutoff since all its dependencies already have it - define $ \GetParsedModule file -> do + define (cmapWithPrio LogShake recorder) $ \GetParsedModule file -> do ModSummaryResult{msrModSummary = ms'} <- use_ GetModSummary file sess <- use_ GhcSession file let hsc = hscEnv sess @@ -280,11 +311,11 @@ mergeParseErrorsHaddock normal haddock = normal ++ -- | This rule provides a ParsedModule preserving all annotations, -- including keywords, punctuation and comments. -- So it is suitable for use cases where you need a perfect edit. -getParsedModuleWithCommentsRule :: Rules () -getParsedModuleWithCommentsRule = +getParsedModuleWithCommentsRule :: Recorder (WithPriority Log) -> Rules () +getParsedModuleWithCommentsRule recorder = -- The parse diagnostics are owned by the GetParsedModule rule -- For this reason, this rule does not produce any diagnostics - defineNoDiagnostics $ \GetParsedModuleWithComments file -> do + defineNoDiagnostics (cmapWithPrio LogShake recorder) $ \GetParsedModuleWithComments file -> do ModSummaryResult{msrModSummary = ms} <- use_ GetModSummary file sess <- use_ GhcSession file opt <- getIdeOptions @@ -315,9 +346,9 @@ getParsedModuleDefinition packageState opt file ms = do Nothing -> pure (diag, Nothing) Just modu -> pure (diag, Just modu) -getLocatedImportsRule :: Rules () -getLocatedImportsRule = - define $ \GetLocatedImports file -> do +getLocatedImportsRule :: Recorder (WithPriority Log) -> Rules () +getLocatedImportsRule recorder = + define (cmapWithPrio LogShake recorder) $ \GetLocatedImports file -> do ModSummaryResult{msrModSummary = ms} <- use_ GetModSummaryWithoutTimestamps file targets <- useNoFile_ GetKnownTargets let targetsMap = HM.mapWithKey const targets @@ -474,15 +505,15 @@ rawDependencyInformation fs = do dropBootSuffix :: FilePath -> FilePath dropBootSuffix hs_src = reverse . drop (length @[] "-boot") . reverse $ hs_src -getDependencyInformationRule :: Rules () -getDependencyInformationRule = - define $ \GetDependencyInformation file -> do +getDependencyInformationRule :: Recorder (WithPriority Log) -> Rules () +getDependencyInformationRule recorder = + define (cmapWithPrio LogShake recorder) $ \GetDependencyInformation file -> do rawDepInfo <- rawDependencyInformation [file] pure ([], Just $ processDependencyInformation rawDepInfo) -reportImportCyclesRule :: Rules () -reportImportCyclesRule = - define $ \ReportImportCycles file -> fmap (\errs -> if null errs then ([], Just ()) else (errs, Nothing)) $ do +reportImportCyclesRule :: Recorder (WithPriority Log) -> Rules () +reportImportCyclesRule recorder = + define (cmapWithPrio LogShake recorder) $ \ReportImportCycles file -> fmap (\errs -> if null errs then ([], Just ()) else (errs, Nothing)) $ do DependencyInformation{..} <- use_ GetDependencyInformation file let fileId = pathToId depPathIdMap file case IntMap.lookup (getFilePathId fileId) depErrorNodes of @@ -514,16 +545,16 @@ reportImportCyclesRule = pure (moduleNameString . moduleName . ms_mod $ ms) showCycle mods = T.intercalate ", " (map T.pack mods) -getHieAstsRule :: Rules () -getHieAstsRule = - define $ \GetHieAst f -> do +getHieAstsRule :: Recorder (WithPriority Log) -> Rules () +getHieAstsRule recorder = + define (cmapWithPrio LogShake recorder) $ \GetHieAst f -> do tmr <- use_ TypeCheck f hsc <- hscEnv <$> use_ GhcSessionDeps f getHieAstRuleDefinition f hsc tmr -persistentHieFileRule :: Rules () -persistentHieFileRule = addPersistentRule GetHieAst $ \file -> runMaybeT $ do - res <- readHieFileForSrcFromDisk file +persistentHieFileRule :: Recorder (WithPriority Log) -> Rules () +persistentHieFileRule recorder = addPersistentRule GetHieAst $ \file -> runMaybeT $ do + res <- readHieFileForSrcFromDisk recorder file vfs <- asks vfs (currentSource,ver) <- liftIO $ do mvf <- getVirtualFile vfs $ filePathToUri' file @@ -557,8 +588,8 @@ getHieAstRuleDefinition f hsc tmr = do typemap = AtPoint.computeTypeReferences . Compat.getAsts <$> masts pure (diags <> diagsWrite, HAR (ms_mod $ tmrModSummary tmr) <$> masts <*> refmap <*> typemap <*> pure HieFresh) -getImportMapRule :: Rules () -getImportMapRule = define $ \GetImportMap f -> do +getImportMapRule :: Recorder (WithPriority Log) -> Rules () +getImportMapRule recorder = define (cmapWithPrio LogShake recorder) $ \GetImportMap f -> do im <- use GetLocatedImports f let mkImports fileImports = M.fromList $ mapMaybe (\(m, mfp) -> (unLoc m,) . artifactFilePath <$> mfp) fileImports pure ([], ImportMap . mkImports <$> im) @@ -567,17 +598,17 @@ getImportMapRule = define $ \GetImportMap f -> do persistentImportMapRule :: Rules () persistentImportMapRule = addPersistentRule GetImportMap $ \_ -> pure $ Just (ImportMap mempty, idDelta, Nothing) -getBindingsRule :: Rules () -getBindingsRule = - define $ \GetBindings f -> do +getBindingsRule :: Recorder (WithPriority Log) -> Rules () +getBindingsRule recorder = + define (cmapWithPrio LogShake recorder) $ \GetBindings f -> do HAR{hieKind=kind, refMap=rm} <- use_ GetHieAst f case kind of HieFresh -> pure ([], Just $ bindings rm) HieFromDisk _ -> pure ([], Nothing) -getDocMapRule :: Rules () -getDocMapRule = - define $ \GetDocMap file -> do +getDocMapRule :: Recorder (WithPriority Log) -> Rules () +getDocMapRule recorder = + define (cmapWithPrio LogShake recorder) $ \GetDocMap file -> do -- Stale data for the scenario where a broken module has previously typechecked -- but we never generated a DocMap for it (tmrTypechecked -> tc, _) <- useWithStale_ TypeCheck file @@ -591,40 +622,39 @@ getDocMapRule = persistentDocMapRule :: Rules () persistentDocMapRule = addPersistentRule GetDocMap $ \_ -> pure $ Just (DKMap mempty mempty, idDelta, Nothing) -readHieFileForSrcFromDisk :: NormalizedFilePath -> MaybeT IdeAction Compat.HieFile -readHieFileForSrcFromDisk file = do +readHieFileForSrcFromDisk :: Recorder (WithPriority Log) -> NormalizedFilePath -> MaybeT IdeAction Compat.HieFile +readHieFileForSrcFromDisk recorder file = do ShakeExtras{withHieDb} <- ask - log <- asks $ L.logDebug . logger row <- MaybeT $ liftIO $ withHieDb (\hieDb -> HieDb.lookupHieFileFromSource hieDb $ fromNormalizedFilePath file) let hie_loc = HieDb.hieModuleHieFile row - liftIO $ log $ "LOADING HIE FILE :" <> T.pack (show file) - exceptToMaybeT $ readHieFileFromDisk hie_loc + logWith recorder Logger.Debug $ LogLoadingHieFile file + exceptToMaybeT $ readHieFileFromDisk recorder hie_loc -readHieFileFromDisk :: FilePath -> ExceptT SomeException IdeAction Compat.HieFile -readHieFileFromDisk hie_loc = do +readHieFileFromDisk :: Recorder (WithPriority Log) -> FilePath -> ExceptT SomeException IdeAction Compat.HieFile +readHieFileFromDisk recorder hie_loc = do nc <- asks ideNc - log <- asks $ L.logDebug . logger res <- liftIO $ tryAny $ loadHieFile (mkUpdater nc) hie_loc - liftIO . log $ either (const $ "FAILED LOADING HIE FILE FOR:" <> T.pack (show hie_loc)) - (const $ "SUCCEEDED LOADING HIE FILE FOR:" <> T.pack (show hie_loc)) - res + let log = logWith recorder + case res of + Left e -> log Logger.Debug $ LogLoadingHieFileFail hie_loc e + Right _ -> log Logger.Debug $ LogLoadingHieFileSuccess hie_loc except res -- | Typechecks a module. -typeCheckRule :: Rules () -typeCheckRule = define $ \TypeCheck file -> do +typeCheckRule :: Recorder (WithPriority Log) -> Rules () +typeCheckRule recorder = define (cmapWithPrio LogShake recorder) $ \TypeCheck file -> do pm <- use_ GetParsedModule file hsc <- hscEnv <$> use_ GhcSessionDeps file typeCheckRuleDefinition hsc pm -knownFilesRule :: Rules () -knownFilesRule = defineEarlyCutOffNoFile $ \GetKnownTargets -> do +knownFilesRule :: Recorder (WithPriority Log) -> Rules () +knownFilesRule recorder = defineEarlyCutOffNoFile (cmapWithPrio LogShake recorder) $ \GetKnownTargets -> do alwaysRerun fs <- knownTargets pure (LBS.toStrict $ B.encode $ hash fs, unhashed fs) -getModuleGraphRule :: Rules () -getModuleGraphRule = defineNoFile $ \GetModuleGraph -> do +getModuleGraphRule :: Recorder (WithPriority Log) -> Rules () +getModuleGraphRule recorder = defineNoFile (cmapWithPrio LogShake recorder) $ \GetModuleGraph -> do fs <- toKnownFiles <$> useNoFile_ GetKnownTargets rawDepInfo <- rawDependencyInformation (HashSet.toList fs) pure $ processDependencyInformation rawDepInfo @@ -663,11 +693,11 @@ currentLinkables = do where go (mod, time) = LM time mod [] -loadGhcSession :: GhcSessionDepsConfig -> Rules () -loadGhcSession ghcSessionDepsConfig = do +loadGhcSession :: Recorder (WithPriority Log) -> GhcSessionDepsConfig -> Rules () +loadGhcSession recorder ghcSessionDepsConfig = do -- This function should always be rerun because it tracks changes -- to the version of the collection of HscEnv's. - defineEarlyCutOffNoFile $ \GhcSessionIO -> do + defineEarlyCutOffNoFile (cmapWithPrio LogShake recorder) $ \GhcSessionIO -> do alwaysRerun opts <- getIdeOptions res <- optGhcSession opts @@ -675,7 +705,7 @@ loadGhcSession ghcSessionDepsConfig = do let fingerprint = LBS.toStrict $ B.encode $ hash (sessionVersion res) return (fingerprint, res) - defineEarlyCutoff $ Rule $ \GhcSession file -> do + defineEarlyCutoff (cmapWithPrio LogShake recorder) $ Rule $ \GhcSession file -> do IdeGhcSession{loadSessionFun} <- useNoFile_ GhcSessionIO (val,deps) <- liftIO $ loadSessionFun $ fromNormalizedFilePath file @@ -700,7 +730,7 @@ loadGhcSession ghcSessionDepsConfig = do Nothing -> LBS.toStrict $ B.encode (hash (snd val)) return (Just cutoffHash, val) - defineNoDiagnostics $ \(GhcSessionDeps_ fullModSummary) file -> do + defineNoDiagnostics (cmapWithPrio LogShake recorder) $ \(GhcSessionDeps_ fullModSummary) file -> do env <- use_ GhcSession file ghcSessionDepsDefinition fullModSummary ghcSessionDepsConfig env file @@ -738,8 +768,8 @@ ghcSessionDepsDefinition fullModSummary GhcSessionDepsConfig{..} env file = do -- | Load a iface from disk, or generate it if there isn't one or it is out of date -- This rule also ensures that the `.hie` and `.o` (if needed) files are written out. -getModIfaceFromDiskRule :: Rules () -getModIfaceFromDiskRule = defineEarlyCutoff $ Rule $ \GetModIfaceFromDisk f -> do +getModIfaceFromDiskRule :: Recorder (WithPriority Log) -> Rules () +getModIfaceFromDiskRule recorder = defineEarlyCutoff (cmapWithPrio LogShake recorder) $ Rule $ \GetModIfaceFromDisk f -> do ms <- msrModSummary <$> use_ GetModSummary f mb_session <- use GhcSessionDeps f case mb_session of @@ -762,10 +792,10 @@ getModIfaceFromDiskRule = defineEarlyCutoff $ Rule $ \GetModIfaceFromDisk f -> d -- `.hie` file. There should be an up2date `.hie` file on -- disk since we are careful to write out the `.hie` file before writing the -- `.hi` file -getModIfaceFromDiskAndIndexRule :: Rules () -getModIfaceFromDiskAndIndexRule = +getModIfaceFromDiskAndIndexRule :: Recorder (WithPriority Log) -> Rules () +getModIfaceFromDiskAndIndexRule recorder = -- doesn't need early cutoff since all its dependencies already have it - defineNoDiagnostics $ \GetModIfaceFromDiskAndIndex f -> do + defineNoDiagnostics (cmapWithPrio LogShake recorder) $ \GetModIfaceFromDiskAndIndex f -> do x <- use_ GetModIfaceFromDisk f se@ShakeExtras{withHieDb} <- getShakeExtras @@ -787,19 +817,19 @@ getModIfaceFromDiskAndIndexRule = -- Not in db, must re-index _ -> do ehf <- liftIO $ runIdeAction "GetModIfaceFromDiskAndIndex" se $ runExceptT $ - readHieFileFromDisk hie_loc + readHieFileFromDisk recorder hie_loc case ehf of -- Uh oh, we failed to read the file for some reason, need to regenerate it Left err -> fail $ "failed to read .hie file " ++ show hie_loc ++ ": " ++ displayException err -- can just re-index the file we read from disk Right hf -> liftIO $ do - L.logDebug (logger se) $ "Re-indexing hie file for" <> T.pack (fromNormalizedFilePath f) + logWith recorder Logger.Debug $ LogReindexingHieFile f indexHieFile se ms f hash hf return (Just x) -isHiFileStableRule :: Rules () -isHiFileStableRule = defineEarlyCutoff $ RuleNoDiagnostics $ \IsHiFileStable f -> do +isHiFileStableRule :: Recorder (WithPriority Log) -> Rules () +isHiFileStableRule recorder = defineEarlyCutoff (cmapWithPrio LogShake recorder) $ RuleNoDiagnostics $ \IsHiFileStable f -> do ms <- msrModSummary <$> use_ GetModSummaryWithoutTimestamps f let hiFile = toNormalizedFilePath' $ Compat.ml_hi_file $ ms_location ms @@ -837,14 +867,14 @@ displayTHWarning newtype DisplayTHWarning = DisplayTHWarning (IO ()) instance IsIdeGlobal DisplayTHWarning -getModSummaryRule :: Rules () -getModSummaryRule = do +getModSummaryRule :: Recorder (WithPriority Log) -> Rules () +getModSummaryRule recorder = do menv <- lspEnv <$> getShakeExtrasRules forM_ menv $ \env -> do displayItOnce <- liftIO $ once $ LSP.runLspT env displayTHWarning addIdeGlobal (DisplayTHWarning displayItOnce) - defineEarlyCutoff $ Rule $ \GetModSummary f -> do + defineEarlyCutoff (cmapWithPrio LogShake recorder) $ Rule $ \GetModSummary f -> do session' <- hscEnv <$> use_ GhcSession f modify_dflags <- getModifyDynFlags dynFlagsModifyGlobal let session = hscSetFlags (modify_dflags $ hsc_dflags session') session' @@ -865,7 +895,7 @@ getModSummaryRule = do return ( Just (fingerprintToBS fingerPrint) , ([], Just res)) Left diags -> return (Nothing, (diags, Nothing)) - defineEarlyCutoff $ RuleNoDiagnostics $ \GetModSummaryWithoutTimestamps f -> do + defineEarlyCutoff (cmapWithPrio LogShake recorder) $ RuleNoDiagnostics $ \GetModSummaryWithoutTimestamps f -> do ms <- use GetModSummary f case ms of Just res@ModSummaryResult{..} -> do @@ -884,12 +914,12 @@ generateCore runSimplifier file = do setPriority priorityGenerateCore liftIO $ compileModule runSimplifier packageState (tmrModSummary tm) (tmrTypechecked tm) -generateCoreRule :: Rules () -generateCoreRule = - define $ \GenerateCore -> generateCore (RunSimplifier True) +generateCoreRule :: Recorder (WithPriority Log) -> Rules () +generateCoreRule recorder = + define (cmapWithPrio LogShake recorder) $ \GenerateCore -> generateCore (RunSimplifier True) -getModIfaceRule :: Rules () -getModIfaceRule = defineEarlyCutoff $ Rule $ \GetModIface f -> do +getModIfaceRule :: Recorder (WithPriority Log) -> Rules () +getModIfaceRule recorder = defineEarlyCutoff (cmapWithPrio LogShake recorder) $ Rule $ \GetModIface f -> do fileOfInterest <- use_ IsFileOfInterest f res@(_,(_,mhmi)) <- case fileOfInterest of IsFOI status -> do @@ -992,8 +1022,8 @@ compileToObjCodeIfNeeded hsc (Just linkableType) getGuts tmr = do (diags', !res) <- liftIO $ mkHiFileResultCompile hsc tmr guts linkableType pure (diags++diags', res) -getClientSettingsRule :: Rules () -getClientSettingsRule = defineEarlyCutOffNoFile $ \GetClientSettings -> do +getClientSettingsRule :: Recorder (WithPriority Log) -> Rules () +getClientSettingsRule recorder = defineEarlyCutOffNoFile (cmapWithPrio LogShake recorder) $ \GetClientSettings -> do alwaysRerun settings <- clientSettings <$> getIdeConfiguration return (LBS.toStrict $ B.encode $ hash settings, settings) @@ -1103,28 +1133,28 @@ data RulesConfig = RulesConfig instance Default RulesConfig where def = RulesConfig True True -- | A rule that wires per-file rules together -mainRule :: RulesConfig -> Rules () -mainRule RulesConfig{..} = do +mainRule :: Recorder (WithPriority Log) -> RulesConfig -> Rules () +mainRule recorder RulesConfig{..} = do linkables <- liftIO $ newVar emptyModuleEnv addIdeGlobal $ CompiledLinkables linkables - getParsedModuleRule - getParsedModuleWithCommentsRule - getLocatedImportsRule - getDependencyInformationRule - reportImportCyclesRule - typeCheckRule - getDocMapRule - loadGhcSession def{checkForImportCycles} - getModIfaceFromDiskRule - getModIfaceFromDiskAndIndexRule - getModIfaceRule - getModSummaryRule - isHiFileStableRule - getModuleGraphRule - knownFilesRule - getClientSettingsRule - getHieAstsRule - getBindingsRule + getParsedModuleRule recorder + getParsedModuleWithCommentsRule recorder + getLocatedImportsRule recorder + getDependencyInformationRule recorder + reportImportCyclesRule recorder + typeCheckRule recorder + getDocMapRule recorder + loadGhcSession recorder def{checkForImportCycles} + getModIfaceFromDiskRule recorder + getModIfaceFromDiskAndIndexRule recorder + getModIfaceRule recorder + getModSummaryRule recorder + isHiFileStableRule recorder + getModuleGraphRule recorder + knownFilesRule recorder + getClientSettingsRule recorder + getHieAstsRule recorder + getBindingsRule recorder -- This rule uses a custom newness check that relies on the encoding -- produced by 'encodeLinkable'. This works as follows: -- * -> @@ -1132,13 +1162,13 @@ mainRule RulesConfig{..} = do -- * Object/BCO -> NoLinkable : the prev linkable can be ignored, signal "no change" -- * otherwise : the prev linkable cannot be reused, signal "value has changed" if enableTemplateHaskell - then defineEarlyCutoff $ RuleWithCustomNewnessCheck (<=) $ \NeedsCompilation file -> + then defineEarlyCutoff (cmapWithPrio LogShake recorder) $ RuleWithCustomNewnessCheck (<=) $ \NeedsCompilation file -> needsCompilationRule file - else defineNoDiagnostics $ \NeedsCompilation _ -> return $ Just Nothing - generateCoreRule - getImportMapRule - getAnnotatedParsedSourceRule - persistentHieFileRule + else defineNoDiagnostics (cmapWithPrio LogShake recorder) $ \NeedsCompilation _ -> return $ Just Nothing + generateCoreRule recorder + getImportMapRule recorder + getAnnotatedParsedSourceRule (cmapWithPrio LogExactPrint recorder) + persistentHieFileRule recorder persistentDocMapRule persistentImportMapRule diff --git a/ghcide/src/Development/IDE/Core/Service.hs b/ghcide/src/Development/IDE/Core/Service.hs index e5eae280e2..d190a0d6cf 100644 --- a/ghcide/src/Development/IDE/Core/Service.hs +++ b/ghcide/src/Development/IDE/Core/Service.hs @@ -15,30 +15,52 @@ module Development.IDE.Core.Service( getDiagnostics, ideLogger, updatePositionMapping, + Log(..), ) where import Control.Applicative ((<|>)) import Development.IDE.Core.Debouncer import Development.IDE.Core.FileExists (fileExistsRules) -import Development.IDE.Core.OfInterest +import Development.IDE.Core.OfInterest hiding (Log, LogShake) import Development.IDE.Graph -import Development.IDE.Types.Logger as Logger +import Development.IDE.Types.Logger as Logger (Logger, + Pretty (pretty), + Priority (Debug), + Recorder, + WithPriority, + cmapWithPrio) import Development.IDE.Types.Options (IdeOptions (..)) import Ide.Plugin.Config import qualified Language.LSP.Server as LSP import qualified Language.LSP.Types as LSP import Control.Monad -import Development.IDE.Core.Shake +import qualified Development.IDE.Core.FileExists as FileExists +import qualified Development.IDE.Core.OfInterest as OfInterest +import Development.IDE.Core.Shake hiding (Log) +import qualified Development.IDE.Core.Shake as Shake import Development.IDE.Types.Shake (WithHieDb) import System.Environment (lookupEnv) +data Log + = LogShake Shake.Log + | LogOfInterest OfInterest.Log + | LogFileExists FileExists.Log + deriving Show + +instance Pretty Log where + pretty = \case + LogShake log -> pretty log + LogOfInterest log -> pretty log + LogFileExists log -> pretty log + ------------------------------------------------------------ -- Exposed API -- | Initialise the Compiler Service. -initialise :: Config +initialise :: Recorder (WithPriority Log) + -> Config -> Rules () -> Maybe (LSP.LanguageContextEnv Config) -> Logger @@ -48,12 +70,13 @@ initialise :: Config -> WithHieDb -> IndexQueue -> IO IdeState -initialise defaultConfig mainRule lspEnv logger debouncer options vfs withHieDb hiedbChan = do +initialise recorder defaultConfig mainRule lspEnv logger debouncer options vfs withHieDb hiedbChan = do shakeProfiling <- do let fromConf = optShakeProfiling options fromEnv <- lookupEnv "GHCIDE_BUILD_PROFILING" return $ fromConf <|> fromEnv shakeOpen + (cmapWithPrio LogShake recorder) lspEnv defaultConfig logger @@ -67,8 +90,8 @@ initialise defaultConfig mainRule lspEnv logger debouncer options vfs withHieDb (optShakeOptions options) $ do addIdeGlobal $ GlobalIdeOptions options - ofInterestRules - fileExistsRules lspEnv vfs + ofInterestRules (cmapWithPrio LogOfInterest recorder) + fileExistsRules (cmapWithPrio LogFileExists recorder) lspEnv vfs mainRule -- | Shutdown the Compiler Service. diff --git a/ghcide/src/Development/IDE/Core/Shake.hs b/ghcide/src/Development/IDE/Core/Shake.hs index da727cadd2..fec940731a 100644 --- a/ghcide/src/Development/IDE/Core/Shake.hs +++ b/ghcide/src/Development/IDE/Core/Shake.hs @@ -77,6 +77,7 @@ module Development.IDE.Core.Shake( addPersistentRule, garbageCollectDirtyKeys, garbageCollectDirtyKeysOlderThan, + Log(..) ) where import Control.Concurrent.Async @@ -158,7 +159,6 @@ import Data.Foldable (for_, toList) import Data.HashSet (HashSet) import qualified Data.HashSet as HSet import Data.String (fromString) -import Data.Text (pack) import Debug.Trace.Flags (userTracingEnabled) import qualified Development.IDE.Types.Exports as ExportsMap import qualified Focus @@ -169,6 +169,47 @@ import Ide.Types (PluginId) import qualified "list-t" ListT import qualified StmContainers.Map as STM +data Log + = LogCreateHieDbExportsMapStart + | LogCreateHieDbExportsMapFinish !Int + | LogBuildSessionRestart !String ![DelayedActionInternal] !(HashSet Key) !Seconds !(Maybe FilePath) + | LogDelayedAction !(DelayedAction ()) !Seconds + | LogBuildSessionFinish !(Maybe SomeException) + | LogDiagsDiffButNoLspEnv ![FileDiagnostic] + | LogDefineEarlyCutoffRuleNoDiagHasDiag !FileDiagnostic + | LogDefineEarlyCutoffRuleCustomNewnessHasDiag !FileDiagnostic + deriving Show + +instance Pretty Log where + pretty = \case + LogCreateHieDbExportsMapStart -> + "Initializing exports map from hiedb" + LogCreateHieDbExportsMapFinish exportsMapSize -> + "Done initializing exports map from hiedb. Size:" <+> pretty exportsMapSize + LogBuildSessionRestart reason actionQueue keyBackLog abortDuration shakeProfilePath -> + vcat + [ "Restarting build session due to" <+> pretty reason + , "Action Queue:" <+> pretty (map actionName actionQueue) + , "Keys:" <+> pretty (map show $ HSet.toList keyBackLog) + , "Aborting previous build session took" <+> pretty (showDuration abortDuration) <+> pretty shakeProfilePath ] + LogDelayedAction delayedAction duration -> + hsep + [ "Finished:" <+> pretty (actionName delayedAction) + , "Took:" <+> pretty (showDuration duration) ] + LogBuildSessionFinish e -> + vcat + [ "Finished build session" + , pretty (fmap displayException e) ] + LogDiagsDiffButNoLspEnv fileDiagnostics -> + "updateFileDiagnostics published different from new diagnostics - file diagnostics:" + <+> pretty (showDiagnosticsColored fileDiagnostics) + LogDefineEarlyCutoffRuleNoDiagHasDiag fileDiagnostic -> + "defineEarlyCutoff RuleNoDiagnostics - file diagnostic:" + <+> pretty (showDiagnosticsColored [fileDiagnostic]) + LogDefineEarlyCutoffRuleCustomNewnessHasDiag fileDiagnostic -> + "defineEarlyCutoff RuleWithCustomNewnessCheck - file diagnostic:" + <+> pretty (showDiagnosticsColored [fileDiagnostic]) + -- | We need to serialize writes to the database, so we send any function that -- needs to write to the database over the channel, where it will be picked up by -- a worker thread. @@ -494,7 +535,8 @@ seqValue val = case val of Failed _ -> val -- | Open a 'IdeState', should be shut using 'shakeShut'. -shakeOpen :: Maybe (LSP.LanguageContextEnv Config) +shakeOpen :: Recorder (WithPriority Log) + -> Maybe (LSP.LanguageContextEnv Config) -> Config -> Logger -> Debouncer NormalizedUri @@ -507,8 +549,10 @@ shakeOpen :: Maybe (LSP.LanguageContextEnv Config) -> ShakeOptions -> Rules () -> IO IdeState -shakeOpen lspEnv defaultConfig logger debouncer +shakeOpen recorder lspEnv defaultConfig logger debouncer shakeProfileDir (IdeReportProgress reportProgress) ideTesting@(IdeTesting testing) withHieDb indexQueue vfs opts rules = mdo + let log :: Logger.Priority -> Log -> IO () + log = logWith recorder us <- mkSplitUniqSupply 'r' ideNc <- newIORef (initNameCache us knownKeyNames) @@ -520,7 +564,7 @@ shakeOpen lspEnv defaultConfig logger debouncer publishedDiagnostics <- STM.newIO positionMapping <- STM.newIO knownTargetsVar <- newTVarIO $ hashed HMap.empty - let restartShakeSession = shakeRestart ideState + let restartShakeSession = shakeRestart recorder ideState persistentKeys <- newTVarIO HMap.empty indexPending <- newTVarIO HMap.empty indexCompleted <- newTVarIO 0 @@ -528,11 +572,12 @@ shakeOpen lspEnv defaultConfig logger debouncer let hiedbWriter = HieDbWriter{..} exportsMap <- newTVarIO mempty -- lazily initialize the exports map with the contents of the hiedb + -- TODO: exceptions can be swallowed here? _ <- async $ do - logDebug logger "Initializing exports map from hiedb" + log Debug LogCreateHieDbExportsMapStart em <- createExportsMapHieDb withHieDb atomically $ modifyTVar' exportsMap (<> em) - logDebug logger $ "Done initializing exports map from hiedb (" <> pack(show (ExportsMap.size em)) <> ")" + log Debug $ LogCreateHieDbExportsMapFinish (ExportsMap.size em) progress <- do let (before, after) = if testing then (0,0.1) else (0.1,0.1) @@ -584,9 +629,9 @@ startTelemetry db extras@ShakeExtras{..} -- | Must be called in the 'Initialized' handler and only once -shakeSessionInit :: IdeState -> IO () -shakeSessionInit ide@IdeState{..} = do - initSession <- newSession shakeExtras shakeDb [] "shakeSessionInit" +shakeSessionInit :: Recorder (WithPriority Log) -> IdeState -> IO () +shakeSessionInit recorder ide@IdeState{..} = do + initSession <- newSession recorder shakeExtras shakeDb [] "shakeSessionInit" putMVar shakeSession initSession logDebug (ideLogger ide) "Shake session initialized" @@ -626,31 +671,35 @@ delayedAction a = do -- | Restart the current 'ShakeSession' with the given system actions. -- Any actions running in the current session will be aborted, -- but actions added via 'shakeEnqueue' will be requeued. -shakeRestart :: IdeState -> String -> [DelayedAction ()] -> IO () -shakeRestart IdeState{..} reason acts = +shakeRestart :: Recorder (WithPriority Log) -> IdeState -> String -> [DelayedAction ()] -> IO () +shakeRestart recorder IdeState{..} reason acts = withMVar' shakeSession (\runner -> do + let log = logWith recorder (stopTime,()) <- duration (cancelShakeSession runner) res <- shakeDatabaseProfile shakeDb backlog <- readTVarIO $ dirtyKeys shakeExtras queue <- atomicallyNamed "actionQueue - peek" $ peekInProgress $ actionQueue shakeExtras + + log Debug $ LogBuildSessionRestart reason queue backlog stopTime res + let profile = case res of Just fp -> ", profile saved at " <> fp _ -> "" + -- TODO: should replace with logging using a logger that sends lsp message let msg = T.pack $ "Restarting build session " ++ reason' ++ queueMsg ++ keysMsg ++ abortMsg reason' = "due to " ++ reason queueMsg = " with queue " ++ show (map actionName queue) keysMsg = " for keys " ++ show (HSet.toList backlog) ++ " " abortMsg = "(aborting the previous one took " ++ showDuration stopTime ++ profile ++ ")" - logDebug (logger shakeExtras) msg notifyTestingLogMessage shakeExtras msg ) -- It is crucial to be masked here, otherwise we can get killed -- between spawning the new thread and updating shakeSession. -- See https://github.com/haskell/ghcide/issues/79 (\() -> do - (,()) <$> newSession shakeExtras shakeDb acts reason) + (,()) <$> newSession recorder shakeExtras shakeDb acts reason) notifyTestingLogMessage :: ShakeExtras -> T.Text -> IO () notifyTestingLogMessage extras msg = do @@ -684,12 +733,13 @@ shakeEnqueue ShakeExtras{actionQueue, logger} act = do -- | Set up a new 'ShakeSession' with a set of initial actions -- Will crash if there is an existing 'ShakeSession' running. newSession - :: ShakeExtras + :: Recorder (WithPriority Log) + -> ShakeExtras -> ShakeDatabase -> [DelayedActionInternal] -> String -> IO ShakeSession -newSession extras@ShakeExtras{..} shakeDb acts reason = do +newSession recorder extras@ShakeExtras{..} shakeDb acts reason = do IdeOptions{optRunSubset} <- getIdeOptionsIO extras reenqueued <- atomicallyNamed "actionQueue - peek" $ peekInProgress actionQueue allPendingKeys <- @@ -709,10 +759,7 @@ newSession extras@ShakeExtras{..} shakeDb acts reason = do getAction d liftIO $ atomicallyNamed "actionQueue - done" $ doneQueue d actionQueue runTime <- liftIO start - let msg = T.pack $ "finish: " ++ actionName d - ++ " (took " ++ showDuration runTime ++ ")" - liftIO $ do - logPriority logger (actionPriority d) msg + logWith recorder (actionPriority d) $ LogDelayedAction d runTime -- The inferred type signature doesn't work in ghc >= 9.0.1 workRun :: (forall b. IO b -> IO b) -> IO (IO ()) @@ -728,7 +775,11 @@ newSession extras@ShakeExtras{..} shakeDb acts reason = do Right _ -> "completed" let msg = T.pack $ "Finishing build session(" ++ res' ++ ")" return $ do - logDebug logger msg + let exception = + case res of + Left e -> Just e + _ -> Nothing + logWith recorder Debug $ LogBuildSessionFinish exception notifyTestingLogMessage extras msg -- Do the work in a background thread @@ -736,6 +787,7 @@ newSession extras@ShakeExtras{..} shakeDb acts reason = do -- run the wrap up in a separate thread since it contains interruptible -- commands (and we are not using uninterruptible mask) + -- TODO: can possibly swallow exceptions? _ <- async $ join $ wait workThread -- Cancelling is required to flush the Shake database when either @@ -843,13 +895,13 @@ preservedKeys checkParents = HSet.fromList $ -- | Define a new Rule without early cutoff define :: IdeRule k v - => (k -> NormalizedFilePath -> Action (IdeResult v)) -> Rules () -define op = defineEarlyCutoff $ Rule $ \k v -> (Nothing,) <$> op k v + => Recorder (WithPriority Log) -> (k -> NormalizedFilePath -> Action (IdeResult v)) -> Rules () +define recorder op = defineEarlyCutoff recorder $ Rule $ \k v -> (Nothing,) <$> op k v defineNoDiagnostics :: IdeRule k v - => (k -> NormalizedFilePath -> Action (Maybe v)) -> Rules () -defineNoDiagnostics op = defineEarlyCutoff $ RuleNoDiagnostics $ \k v -> (Nothing,) <$> op k v + => Recorder (WithPriority Log) -> (k -> NormalizedFilePath -> Action (Maybe v)) -> Rules () +defineNoDiagnostics recorder op = defineEarlyCutoff recorder $ RuleNoDiagnostics $ \k v -> (Nothing,) <$> op k v -- | Request a Rule result if available use :: IdeRule k v @@ -971,37 +1023,36 @@ data RuleBody k v -- | Define a new Rule with early cutoff defineEarlyCutoff :: IdeRule k v - => RuleBody k v + => Recorder (WithPriority Log) + -> RuleBody k v -> Rules () -defineEarlyCutoff (Rule op) = addRule $ \(Q (key, file)) (old :: Maybe BS.ByteString) mode -> otTracedAction key file mode traceA $ \traceDiagnostics -> do +defineEarlyCutoff recorder (Rule op) = addRule $ \(Q (key, file)) (old :: Maybe BS.ByteString) mode -> otTracedAction key file mode traceA $ \traceDiagnostics -> do extras <- getShakeExtras let diagnostics diags = do traceDiagnostics diags - updateFileDiagnostics file (Key key) extras . map (\(_,y,z) -> (y,z)) $ diags + updateFileDiagnostics recorder file (Key key) extras . map (\(_,y,z) -> (y,z)) $ diags defineEarlyCutoff' diagnostics (==) key file old mode $ op key file -defineEarlyCutoff (RuleNoDiagnostics op) = addRule $ \(Q (key, file)) (old :: Maybe BS.ByteString) mode -> otTracedAction key file mode traceA $ \traceDiagnostics -> do - ShakeExtras{logger} <- getShakeExtras +defineEarlyCutoff recorder (RuleNoDiagnostics op) = addRule $ \(Q (key, file)) (old :: Maybe BS.ByteString) mode -> otTracedAction key file mode traceA $ \traceDiagnostics -> do let diagnostics diags = do traceDiagnostics diags - mapM_ (\d -> liftIO $ logWarning logger $ showDiagnosticsColored [d]) diags + mapM_ (logWith recorder Warning . LogDefineEarlyCutoffRuleNoDiagHasDiag) diags defineEarlyCutoff' diagnostics (==) key file old mode $ second (mempty,) <$> op key file -defineEarlyCutoff RuleWithCustomNewnessCheck{..} = +defineEarlyCutoff recorder RuleWithCustomNewnessCheck{..} = addRule $ \(Q (key, file)) (old :: Maybe BS.ByteString) mode -> otTracedAction key file mode traceA $ \ traceDiagnostics -> do - ShakeExtras{logger} <- getShakeExtras let diagnostics diags = do - mapM_ (\d -> liftIO $ logWarning logger $ showDiagnosticsColored [d]) diags traceDiagnostics diags + mapM_ (logWith recorder Warning . LogDefineEarlyCutoffRuleCustomNewnessHasDiag) diags defineEarlyCutoff' diagnostics newnessCheck key file old mode $ second (mempty,) <$> build key file -defineNoFile :: IdeRule k v => (k -> Action v) -> Rules () -defineNoFile f = defineNoDiagnostics $ \k file -> do +defineNoFile :: IdeRule k v => Recorder (WithPriority Log) -> (k -> Action v) -> Rules () +defineNoFile recorder f = defineNoDiagnostics recorder $ \k file -> do if file == emptyFilePath then do res <- f k; return (Just res) else fail $ "Rule " ++ show k ++ " should always be called with the empty string for a file" -defineEarlyCutOffNoFile :: IdeRule k v => (k -> Action (BS.ByteString, v)) -> Rules () -defineEarlyCutOffNoFile f = defineEarlyCutoff $ RuleNoDiagnostics $ \k file -> do +defineEarlyCutOffNoFile :: IdeRule k v => Recorder (WithPriority Log) -> (k -> Action (BS.ByteString, v)) -> Rules () +defineEarlyCutOffNoFile recorder f = defineEarlyCutoff recorder $ RuleNoDiagnostics $ \k file -> do if file == emptyFilePath then do (hash, res) <- f k; return (Just hash, Just res) else fail $ "Rule " ++ show k ++ " should always be called with the empty string for a file" @@ -1107,9 +1158,10 @@ data OnDiskRule = OnDiskRule -- the internals of this module that we do not want to expose. defineOnDisk :: (Shake.ShakeValue k, RuleResult k ~ ()) - => (k -> NormalizedFilePath -> OnDiskRule) + => Recorder (WithPriority Log) + -> (k -> NormalizedFilePath -> OnDiskRule) -> Rules () -defineOnDisk act = addRule $ +defineOnDisk recorder act = addRule $ \(QDisk key file) (mbOld :: Maybe BS.ByteString) mode -> do extras <- getShakeExtras let OnDiskRule{..} = act key file @@ -1121,7 +1173,7 @@ defineOnDisk act = addRule $ case mbOld of Nothing -> do (diags, mbHash) <- runAct - updateFileDiagnostics file (Key key) extras $ map (\(_,y,z) -> (y,z)) diags + updateFileDiagnostics recorder file (Key key) extras $ map (\(_,y,z) -> (y,z)) diags pure $ RunResult ChangedRecomputeDiff (fromMaybe "" mbHash) (isJust mbHash) Just old -> do current <- validateHash <$> (actionCatch getHash $ \(_ :: SomeException) -> pure "") @@ -1132,7 +1184,7 @@ defineOnDisk act = addRule $ pure $ RunResult ChangedNothing (fromMaybe "" current) (isJust current) else do (diags, mbHash) <- runAct - updateFileDiagnostics file (Key key) extras $ map (\(_,y,z) -> (y,z)) diags + updateFileDiagnostics recorder file (Key key) extras $ map (\(_,y,z) -> (y,z)) diags let change | mbHash == Just old = ChangedRecomputeSame | otherwise = ChangedRecomputeDiff @@ -1149,12 +1201,13 @@ needOnDisks k files = do liftIO $ unless (and successfulls) $ throwIO $ BadDependency (show k) updateFileDiagnostics :: MonadIO m - => NormalizedFilePath + => Recorder (WithPriority Log) + -> NormalizedFilePath -> Key -> ShakeExtras -> [(ShowDiagnostic,Diagnostic)] -- ^ current results -> m () -updateFileDiagnostics fp k ShakeExtras{logger, diagnostics, hiddenDiagnostics, publishedDiagnostics, state, debouncer, lspEnv} current = liftIO $ do +updateFileDiagnostics recorder fp k ShakeExtras{diagnostics, hiddenDiagnostics, publishedDiagnostics, state, debouncer, lspEnv} current = liftIO $ do modTime <- (currentValue . fst =<<) <$> atomicallyNamed "diagnostics - read" (getValues state GetModificationTime fp) let (currentShown, currentHidden) = partition ((== ShowDiag) . fst) current uri = filePathToUri' fp @@ -1174,7 +1227,7 @@ updateFileDiagnostics fp k ShakeExtras{logger, diagnostics, hiddenDiagnostics, p lastPublish <- atomicallyNamed "diagnostics - publish" $ STM.focus (Focus.lookupWithDefault [] <* Focus.insert newDiags) uri publishedDiagnostics let action = when (lastPublish /= newDiags) $ case lspEnv of Nothing -> -- Print an LSP event. - logInfo logger $ showDiagnosticsColored $ map (fp,ShowDiag,) newDiags + logWith recorder Info $ LogDiagsDiffButNoLspEnv (map (fp, ShowDiag,) newDiags) Just env -> LSP.runLspT env $ LSP.sendNotification LSP.STextDocumentPublishDiagnostics $ LSP.PublishDiagnosticsParams (fromNormalizedUri uri) (fmap fromIntegral ver) (List newDiags) diff --git a/ghcide/src/Development/IDE/GHC/ExactPrint.hs b/ghcide/src/Development/IDE/GHC/ExactPrint.hs index 1c258ddd78..a2257250b4 100644 --- a/ghcide/src/Development/IDE/GHC/ExactPrint.hs +++ b/ghcide/src/Development/IDE/GHC/ExactPrint.hs @@ -43,6 +43,7 @@ module Development.IDE.GHC.ExactPrint ASTElement (..), ExceptStringT (..), TransformT, + Log(..), ) where @@ -66,13 +67,18 @@ import qualified Data.Text as T import Data.Traversable (for) import Development.IDE.Core.RuleTypes import Development.IDE.Core.Service (runAction) -import Development.IDE.Core.Shake +import Development.IDE.Core.Shake hiding (Log) +import qualified Development.IDE.Core.Shake as Shake import Development.IDE.GHC.Compat hiding (parseImport, parsePattern, parseType) import Development.IDE.Graph (RuleResult, Rules) import Development.IDE.Graph.Classes import Development.IDE.Types.Location +import Development.IDE.Types.Logger (Pretty (pretty), + Recorder, + WithPriority, + cmapWithPrio) import qualified GHC.Generics as GHC import Generics.SYB import Generics.SYB.GHC @@ -100,6 +106,12 @@ import GHC.Parser.Annotation (AnnContext (..), ------------------------------------------------------------------------------ +data Log = LogShake Shake.Log deriving Show + +instance Pretty Log where + pretty = \case + LogShake shakeLog -> pretty shakeLog + data GetAnnotatedParsedSource = GetAnnotatedParsedSource deriving (Eq, Show, Typeable, GHC.Generic) @@ -108,8 +120,8 @@ instance NFData GetAnnotatedParsedSource type instance RuleResult GetAnnotatedParsedSource = Annotated ParsedSource -- | Get the latest version of the annotated parse source with comments. -getAnnotatedParsedSourceRule :: Rules () -getAnnotatedParsedSourceRule = define $ \GetAnnotatedParsedSource nfp -> do +getAnnotatedParsedSourceRule :: Recorder (WithPriority Log) -> Rules () +getAnnotatedParsedSourceRule recorder = define (cmapWithPrio LogShake recorder) $ \GetAnnotatedParsedSource nfp -> do pm <- use GetParsedModuleWithComments nfp return ([], fmap annotateParsedSource pm) diff --git a/ghcide/src/Development/IDE/LSP/LanguageServer.hs b/ghcide/src/Development/IDE/LSP/LanguageServer.hs index f3e4f4d9e8..9f16788c3b 100644 --- a/ghcide/src/Development/IDE/LSP/LanguageServer.hs +++ b/ghcide/src/Development/IDE/LSP/LanguageServer.hs @@ -10,6 +10,7 @@ -- This version removes the daml: handling module Development.IDE.LSP.LanguageServer ( runLanguageServer + , Log(..) ) where import Control.Concurrent.STM @@ -31,17 +32,46 @@ import UnliftIO.Concurrent import UnliftIO.Directory import UnliftIO.Exception -import Development.IDE.Core.FileStore +import Development.IDE.Core.FileStore hiding (Log) import Development.IDE.Core.IdeConfiguration -import Development.IDE.Core.Shake +import Development.IDE.Core.Shake hiding (Log) import Development.IDE.Core.Tracing import Development.IDE.LSP.HoverDefinition import Development.IDE.Types.Logger import Control.Monad.IO.Unlift (MonadUnliftIO) +import qualified Development.IDE.Session as Session +import qualified Development.IDE.Types.Logger as Logger import Development.IDE.Types.Shake (WithHieDb) import System.IO.Unsafe (unsafeInterleaveIO) +data Log + = LogRegisteringIdeConfig !IdeConfiguration + | LogReactorThreadException !SomeException + | LogReactorMessageActionException !SomeException + | LogReactorThreadStopped + | LogCancelledRequest !SomeLspId + | LogSession Session.Log + deriving Show + +instance Pretty Log where + pretty = \case + LogRegisteringIdeConfig ideConfig -> + "Registering IDE configuration:" <+> viaShow ideConfig + LogReactorThreadException e -> + vcat + [ "ReactorThreadException" + , pretty $ displayException e ] + LogReactorMessageActionException e -> + vcat + [ "ReactorMessageActionException" + , pretty $ displayException e ] + LogReactorThreadStopped -> + "Reactor thread stopped" + LogCancelledRequest requestId -> + "Cancelled request" <+> viaShow requestId + LogSession log -> pretty log + issueTrackerUrl :: T.Text issueTrackerUrl = "https://github.com/haskell/haskell-language-server/issues" @@ -50,7 +80,8 @@ newtype WithHieDbShield = WithHieDbShield WithHieDb runLanguageServer :: forall config. (Show config) - => LSP.Options + => Recorder (WithPriority Log) + -> LSP.Options -> Handle -- input -> Handle -- output -> (FilePath -> IO FilePath) -- ^ Map root paths to the location of the hiedb for the project @@ -59,7 +90,7 @@ runLanguageServer -> LSP.Handlers (ServerM config) -> (LSP.LanguageContextEnv config -> VFSHandle -> Maybe FilePath -> WithHieDb -> IndexQueue -> IO IdeState) -> IO () -runLanguageServer options inH outH getHieDbLoc defaultConfig onConfigurationChange userHandlers getIdeState = do +runLanguageServer recorder options inH outH getHieDbLoc defaultConfig onConfigurationChange userHandlers getIdeState = do -- This MVar becomes full when the server thread exits or we receive exit message from client. -- LSP server will be canceled when it's full. @@ -128,6 +159,9 @@ runLanguageServer options inH outH getHieDbLoc defaultConfig onConfigurationChan serverDefinition where + log :: Logger.Priority -> Log -> IO () + log = logWith recorder + handleInit :: MVar () -> IO () -> (SomeLspId -> IO ()) -> (SomeLspId -> IO ()) -> Chan ReactorMessage -> LSP.LanguageContextEnv config -> RequestMessage Initialize -> IO (Either err (LSP.LanguageContextEnv config, IdeState)) @@ -145,12 +179,12 @@ runLanguageServer options inH outH getHieDbLoc defaultConfig onConfigurationChan ide <- getIdeState env (makeLSPVFSHandle env) root withHieDb hieChan let initConfig = parseConfiguration params - logInfo (ideLogger ide) $ T.pack $ "Registering ide configuration: " <> show initConfig + + log Info $ LogRegisteringIdeConfig initConfig registerIdeConfiguration (shakeExtras ide) initConfig let handleServerException (Left e) = do - logError logger $ - T.pack $ "Fatal error in server thread: " <> show e + log Error $ LogReactorThreadException e sendErrorMessage e exitClientMsg handleServerException (Right _) = pure () @@ -163,13 +197,9 @@ runLanguageServer options inH outH getHieDbLoc defaultConfig onConfigurationChan ] exceptionInHandler e = do - logError logger $ T.pack $ - "Unexpected exception, please report!\n" ++ - "Exception: " ++ show e + log Error $ LogReactorMessageActionException e sendErrorMessage e - logger = ideLogger ide - checkCancelled _id act k = flip finally (clearReqId _id) $ catch (do @@ -180,14 +210,14 @@ runLanguageServer options inH outH getHieDbLoc defaultConfig onConfigurationChan cancelOrRes <- race (waitForCancel _id) act case cancelOrRes of Left () -> do - logDebug (ideLogger ide) $ T.pack $ "Cancelled request " <> show _id + log Debug $ LogCancelledRequest _id k $ ResponseError RequestCancelled "" Nothing Right res -> pure res ) $ \(e :: SomeException) -> do exceptionInHandler e k $ ResponseError InternalError (T.pack $ show e) Nothing _ <- flip forkFinally handleServerException $ do - untilMVar lifetime $ runWithDb logger dbLoc $ \withHieDb hieChan -> do + untilMVar lifetime $ runWithDb (cmapWithPrio LogSession recorder) dbLoc $ \withHieDb hieChan -> do putMVar dbMVar (WithHieDbShield withHieDb,hieChan) forever $ do msg <- readChan clientMsgChan @@ -196,7 +226,7 @@ runLanguageServer options inH outH getHieDbLoc defaultConfig onConfigurationChan case msg of ReactorNotification act -> handle exceptionInHandler act ReactorRequest _id act k -> void $ async $ checkCancelled _id act k - logInfo logger "Reactor thread stopped" + log Info LogReactorThreadStopped pure $ Right (env,ide) diff --git a/ghcide/src/Development/IDE/LSP/Notifications.hs b/ghcide/src/Development/IDE/LSP/Notifications.hs index 49dab15015..6b25942ba2 100644 --- a/ghcide/src/Development/IDE/LSP/Notifications.hs +++ b/ghcide/src/Development/IDE/LSP/Notifications.hs @@ -9,6 +9,7 @@ module Development.IDE.LSP.Notifications ( whenUriFile , descriptor + , Log(..) ) where import Language.LSP.Types @@ -26,21 +27,33 @@ import Development.IDE.Core.FileStore (registerFileWatches, resetFileStore, setFileModified, setSomethingModified) +import qualified Development.IDE.Core.FileStore as FileStore import Development.IDE.Core.IdeConfiguration -import Development.IDE.Core.OfInterest +import Development.IDE.Core.OfInterest hiding (Log, LogShake) import Development.IDE.Core.RuleTypes (GetClientSettings (..)) -import Development.IDE.Core.Service -import Development.IDE.Core.Shake +import Development.IDE.Core.Service hiding (Log, LogShake) +import Development.IDE.Core.Shake hiding (Log, Priority) +import qualified Development.IDE.Core.Shake as Shake import Development.IDE.Types.Location import Development.IDE.Types.Logger import Development.IDE.Types.Shake (toKey) import Ide.Types +data Log + = LogShake Shake.Log + | LogFileStore FileStore.Log + deriving Show + +instance Pretty Log where + pretty = \case + LogShake log -> pretty log + LogFileStore log -> pretty log + whenUriFile :: Uri -> (NormalizedFilePath -> IO ()) -> IO () whenUriFile uri act = whenJust (LSP.uriToFilePath uri) $ act . toNormalizedFilePath' -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = (defaultPluginDescriptor plId) { pluginNotificationHandlers = mconcat +descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState +descriptor recorder plId = (defaultPluginDescriptor plId) { pluginNotificationHandlers = mconcat [ mkPluginNotificationHandler LSP.STextDocumentDidOpen $ \ide _ (DidOpenTextDocumentParams TextDocumentItem{_uri,_version}) -> liftIO $ do atomically $ updatePositionMapping ide (VersionedTextDocumentIdentifier _uri (Just _version)) (List []) @@ -48,7 +61,7 @@ descriptor plId = (defaultPluginDescriptor plId) { pluginNotificationHandlers = -- We don't know if the file actually exists, or if the contents match those on disk -- For example, vscode restores previously unsaved contents on open addFileOfInterest ide file Modified{firstOpen=True} - setFileModified ide False file + setFileModified (cmapWithPrio LogFileStore recorder) ide False file logDebug (ideLogger ide) $ "Opened text document: " <> getUri _uri , mkPluginNotificationHandler LSP.STextDocumentDidChange $ @@ -56,14 +69,14 @@ descriptor plId = (defaultPluginDescriptor plId) { pluginNotificationHandlers = atomically $ updatePositionMapping ide identifier changes whenUriFile _uri $ \file -> do addFileOfInterest ide file Modified{firstOpen=False} - setFileModified ide False file + setFileModified (cmapWithPrio LogFileStore recorder) ide False file logDebug (ideLogger ide) $ "Modified text document: " <> getUri _uri , mkPluginNotificationHandler LSP.STextDocumentDidSave $ \ide _ (DidSaveTextDocumentParams TextDocumentIdentifier{_uri} _) -> liftIO $ do whenUriFile _uri $ \file -> do addFileOfInterest ide file OnDisk - setFileModified ide True file + setFileModified (cmapWithPrio LogFileStore recorder) ide True file logDebug (ideLogger ide) $ "Saved text document: " <> getUri _uri , mkPluginNotificationHandler LSP.STextDocumentDidClose $ @@ -112,7 +125,7 @@ descriptor plId = (defaultPluginDescriptor plId) { pluginNotificationHandlers = , mkPluginNotificationHandler LSP.SInitialized $ \ide _ _ -> do --------- Initialize Shake session -------------------------------------------------------------------- - liftIO $ shakeSessionInit ide + liftIO $ shakeSessionInit (cmapWithPrio LogShake recorder) ide --------- Set up file watchers ------------------------------------------------------------------------ opts <- liftIO $ getIdeOptionsIO $ shakeExtras ide diff --git a/ghcide/src/Development/IDE/Main.hs b/ghcide/src/Development/IDE/Main.hs index 1554ec185b..936a7f80e3 100644 --- a/ghcide/src/Development/IDE/Main.hs +++ b/ghcide/src/Development/IDE/Main.hs @@ -8,13 +8,14 @@ module Development.IDE.Main ,isLSP ,commandP ,defaultMain -,testing) where -import Control.Concurrent.Extra (newLock, withLock, - withNumCapabilities) +,testing +,Log(..) +) where +import Control.Concurrent.Extra (withNumCapabilities) import Control.Concurrent.STM.Stats (atomically, dumpSTMStats) -import Control.Exception.Safe (Exception (displayException), - catchAny) +import Control.Exception.Safe (SomeException, catchAny, + displayException) import Control.Monad.Extra (concatMapM, unless, when) import qualified Data.Aeson.Encode.Pretty as A @@ -26,7 +27,6 @@ import Data.List.Extra (intercalate, isPrefixOf, nub, nubOrd, partition) import Data.Maybe (catMaybes, isJust) import qualified Data.Text as T -import qualified Data.Text.IO as T import Data.Text.Lazy.Encoding (decodeUtf8) import qualified Data.Text.Lazy.IO as LT import Data.Typeable (typeOf) @@ -50,17 +50,23 @@ import Development.IDE.Core.RuleTypes (GenerateCore (GenerateCo TypeCheck (TypeCheck)) import Development.IDE.Core.Rules (GhcSessionIO (GhcSessionIO), mainRule) +import qualified Development.IDE.Core.Rules as Rules import Development.IDE.Core.Service (initialise, runAction) +import qualified Development.IDE.Core.Service as Service import Development.IDE.Core.Shake (IdeState (shakeExtras), ShakeExtras (state), shakeSessionInit, uses) +import qualified Development.IDE.Core.Shake as Shake import Development.IDE.Core.Tracing (measureMemory) import Development.IDE.Graph (action) import Development.IDE.LSP.LanguageServer (runLanguageServer) +import qualified Development.IDE.LSP.LanguageServer as LanguageServer import Development.IDE.Main.HeapStats (withHeapStats) +import qualified Development.IDE.Main.HeapStats as HeapStats import Development.IDE.Plugin (Plugin (pluginHandlers, pluginModifyDynflags, pluginRules)) import Development.IDE.Plugin.HLS (asGhcIdePlugin) -import qualified Development.IDE.Plugin.HLS.GhcIde as Ghcide +import qualified Development.IDE.Plugin.HLS as PluginHLS +import qualified Development.IDE.Plugin.HLS.GhcIde as GhcIde import qualified Development.IDE.Plugin.Test as Test import Development.IDE.Session (SessionLoadingOptions, getHieDbLoc, @@ -68,11 +74,14 @@ import Development.IDE.Session (SessionLoadingOptions, retryOnSqliteBusy, runWithDb, setInitialDynFlags) +import qualified Development.IDE.Session as Session import Development.IDE.Types.Location (NormalizedUri, toNormalizedFilePath') -import Development.IDE.Types.Logger (Logger (Logger), - Priority (Info), - logDebug, logInfo) +import Development.IDE.Types.Logger (Logger, Pretty (pretty), + Priority (Info, Warning), + Recorder, WithPriority, + cmapWithPrio, logWith, + vsep, (<+>)) import Development.IDE.Types.Options (IdeGhcSession, IdeOptions (optCheckParents, optCheckProject, optReportProgress, optRunSubset), IdeTesting (IdeTesting), @@ -118,10 +127,49 @@ import System.IO (BufferMode (LineBufferin hSetEncoding, stderr, stdin, stdout, utf8) import System.Random (newStdGen) -import System.Time.Extra (offsetTime, +import System.Time.Extra (Seconds, offsetTime, showDuration) import Text.Printf (printf) +data Log + = LogHeapStats !HeapStats.Log + | LogLspStart + | LogLspStartDuration !Seconds + | LogShouldRunSubset !Bool + | LogOnlyPartialGhc9Support + | LogSetInitialDynFlagsException !SomeException + | LogService Service.Log + | LogShake Shake.Log + | LogGhcIde GhcIde.Log + | LogLanguageServer LanguageServer.Log + | LogSession Session.Log + | LogPluginHLS PluginHLS.Log + | LogRules Rules.Log + deriving Show + +instance Pretty Log where + pretty = \case + LogHeapStats log -> pretty log + LogLspStart -> + vsep + [ "Staring LSP server..." + , "If you are seeing this in a terminal, you probably should have run WITHOUT the --lsp option!"] + LogLspStartDuration duration -> + "Started LSP server in" <+> pretty (showDuration duration) + LogShouldRunSubset shouldRunSubset -> + "shouldRunSubset:" <+> pretty shouldRunSubset + LogOnlyPartialGhc9Support -> + "Currently, HLS supports GHC 9 only partially. See [issue #297](https://github.com/haskell/haskell-language-server/issues/297) for more detail." + LogSetInitialDynFlagsException e -> + "setInitialDynFlags:" <+> pretty (displayException e) + LogService log -> pretty log + LogShake log -> pretty log + LogGhcIde log -> pretty log + LogLanguageServer log -> pretty log + LogSession log -> pretty log + LogPluginHLS log -> pretty log + LogRules log -> pretty log + data Command = Check [FilePath] -- ^ Typecheck some paths and print diagnostics. Exit code is the number of failures | Db {hieOptions :: HieDb.Options, hieCommand :: HieDb.Command} @@ -132,7 +180,6 @@ data Command | Custom {ideCommand :: IdeCommand IdeState} -- ^ User defined deriving Show - -- TODO move these to hiedb deriving instance Show HieDb.Command deriving instance Show HieDb.Options @@ -187,18 +234,16 @@ data Arguments = Arguments , argsThreads :: Maybe Natural } -instance Default Arguments where - def = defaultArguments Info -defaultArguments :: Priority -> Arguments -defaultArguments priority = Arguments +defaultArguments :: Recorder (WithPriority Log) -> Logger -> Arguments +defaultArguments recorder logger = Arguments { argsProjectRoot = Nothing , argsOTMemoryProfiling = False , argCommand = LSP - , argsLogger = stderrLogger priority - , argsRules = mainRule def >> action kick + , argsLogger = pure logger + , argsRules = mainRule (cmapWithPrio LogRules recorder) def >> action kick , argsGhcidePlugin = mempty - , argsHlsPlugins = pluginDescToIdePlugins Ghcide.descriptors + , argsHlsPlugins = pluginDescToIdePlugins (GhcIde.descriptors (cmapWithPrio LogGhcIde recorder)) , argsSessionLoadingOptions = def , argsIdeOptions = \config ghcSession -> (defaultIdeOptions ghcSession) { optCheckProject = pure $ checkProject config @@ -226,35 +271,39 @@ defaultArguments priority = Arguments return newStdout } -testing :: Arguments -testing = (defaultArguments Debug) { - argsHlsPlugins = pluginDescToIdePlugins $ - idePluginsToPluginDesc (argsHlsPlugins def) - ++ [Test.blockCommandDescriptor "block-command", Test.plugin], - argsIdeOptions = \config sessionLoader -> - let defOptions = argsIdeOptions def config sessionLoader - in defOptions { - optTesting = IdeTesting True - } -} - --- | Cheap stderr logger that relies on LineBuffering -stderrLogger :: Priority -> IO Logger -stderrLogger logLevel = do - lock <- newLock - return $ Logger $ \p m -> when (p >= logLevel) $ withLock lock $ - T.hPutStrLn stderr $ "[" <> T.pack (show p) <> "] " <> m -defaultMain :: Arguments -> IO () -defaultMain Arguments{..} = flip withHeapStats fun =<< argsLogger +testing :: Recorder (WithPriority Log) -> Logger -> Arguments +testing recorder logger = + let + arguments@Arguments{ argsHlsPlugins, argsIdeOptions } = defaultArguments recorder logger + hlsPlugins = pluginDescToIdePlugins $ + idePluginsToPluginDesc argsHlsPlugins + ++ [Test.blockCommandDescriptor "block-command", Test.plugin] + ideOptions = \config sessionLoader -> + let + defOptions = argsIdeOptions config sessionLoader + in + defOptions{ optTesting = IdeTesting True } + in + arguments + { argsHlsPlugins = hlsPlugins + , argsIdeOptions = ideOptions + } + + +defaultMain :: Recorder (WithPriority Log) -> Arguments -> IO () +defaultMain recorder Arguments{..} = withHeapStats (cmapWithPrio LogHeapStats recorder) fun where + log :: Priority -> Log -> IO () + log = logWith recorder + fun = do setLocaleEncoding utf8 pid <- T.pack . show <$> getProcessID logger <- argsLogger hSetBuffering stderr LineBuffering - let hlsPlugin = asGhcIdePlugin argsHlsPlugins + let hlsPlugin = asGhcIdePlugin (cmapWithPrio LogPluginHLS recorder) argsHlsPlugins hlsCommands = allLspCmdIds' pid argsHlsPlugins plugins = hlsPlugin <> argsGhcidePlugin options = argsLspOptions { LSP.executeCommandCommands = LSP.executeCommandCommands argsLspOptions <> Just hlsCommands } @@ -274,29 +323,29 @@ defaultMain Arguments{..} = flip withHeapStats fun =<< argsLogger LT.putStrLn $ decodeUtf8 $ A.encodePretty $ pluginsToDefaultConfig argsHlsPlugins LSP -> withNumCapabilities (maybe (numProcessors `div` 2) fromIntegral argsThreads) $ do t <- offsetTime - logInfo logger "Starting LSP server..." - logInfo logger "If you are seeing this in a terminal, you probably should have run WITHOUT the --lsp option!" - runLanguageServer options inH outH argsGetHieDbLoc argsDefaultHlsConfig argsOnConfigChange (pluginHandlers plugins) $ \env vfs rootPath withHieDb hieChan -> do + log Info LogLspStart + + runLanguageServer (cmapWithPrio LogLanguageServer recorder) options inH outH argsGetHieDbLoc argsDefaultHlsConfig argsOnConfigChange (pluginHandlers plugins) $ \env vfs rootPath withHieDb hieChan -> do traverse_ IO.setCurrentDirectory rootPath t <- t - logInfo logger $ T.pack $ "Started LSP server in " ++ showDuration t + log Info $ LogLspStartDuration t dir <- maybe IO.getCurrentDirectory return rootPath -- We want to set the global DynFlags right now, so that we can use -- `unsafeGlobalDynFlags` even before the project is configured _mlibdir <- - setInitialDynFlags logger dir argsSessionLoadingOptions - `catchAny` (\e -> (logDebug logger $ T.pack $ "setInitialDynFlags: " ++ displayException e) >> pure Nothing) - + setInitialDynFlags (cmapWithPrio LogSession recorder) dir argsSessionLoadingOptions + -- TODO: should probably catch/log/rethrow at top level instead + `catchAny` (\e -> log Debug (LogSetInitialDynFlagsException e) >> pure Nothing) - sessionLoader <- loadSessionWithOptions argsSessionLoadingOptions dir + sessionLoader <- loadSessionWithOptions (cmapWithPrio LogSession recorder) argsSessionLoadingOptions dir config <- LSP.runLspT env LSP.getConfig let def_options = argsIdeOptions config sessionLoader -- disable runSubset if the client doesn't support watched files runSubset <- (optRunSubset def_options &&) <$> LSP.runLspT env isWatchSupported - logDebug logger $ T.pack $ "runSubset: " <> show runSubset + log Debug $ LogShouldRunSubset runSubset let options = def_options { optReportProgress = clientSupportsProgress caps @@ -306,10 +355,9 @@ defaultMain Arguments{..} = flip withHeapStats fun =<< argsLogger caps = LSP.resClientCapabilities env -- FIXME: Remove this after GHC 9 gets fully supported when (ghcVersion == GHC90) $ - hPutStrLn stderr $ - "Currently, HLS supports GHC 9 only partially. " - <> "See [issue #297](https://github.com/haskell/haskell-language-server/issues/297) for more detail." + log Warning LogOnlyPartialGhc9Support initialise + (cmapWithPrio LogService recorder) argsDefaultHlsConfig rules (Just env) @@ -323,7 +371,7 @@ defaultMain Arguments{..} = flip withHeapStats fun =<< argsLogger Check argFiles -> do dir <- maybe IO.getCurrentDirectory return argsProjectRoot dbLoc <- getHieDbLoc dir - runWithDb logger dbLoc $ \hiedb hieChan -> do + runWithDb (cmapWithPrio LogSession recorder) dbLoc $ \hiedb hieChan -> do -- GHC produces messages with UTF8 in them, so make sure the terminal doesn't error hSetEncoding stdout utf8 hSetEncoding stderr utf8 @@ -345,15 +393,15 @@ defaultMain Arguments{..} = flip withHeapStats fun =<< argsLogger when (n > 0) $ putStrLn $ " (" ++ intercalate ", " (catMaybes ucradles) ++ ")" putStrLn "\nStep 3/4: Initializing the IDE" vfs <- makeVFSHandle - sessionLoader <- loadSessionWithOptions argsSessionLoadingOptions dir + sessionLoader <- loadSessionWithOptions (cmapWithPrio LogSession recorder) argsSessionLoadingOptions dir let def_options = argsIdeOptions argsDefaultHlsConfig sessionLoader options = def_options { optCheckParents = pure NeverCheck , optCheckProject = pure False , optModifyDynFlags = optModifyDynFlags def_options <> pluginModifyDynflags plugins } - ide <- initialise argsDefaultHlsConfig rules Nothing logger debouncer options vfs hiedb hieChan - shakeSessionInit ide + ide <- initialise (cmapWithPrio LogService recorder) argsDefaultHlsConfig rules Nothing logger debouncer options vfs hiedb hieChan + shakeSessionInit (cmapWithPrio LogShake recorder) ide registerIdeConfiguration (shakeExtras ide) $ IdeConfiguration mempty (hashed Nothing) putStrLn "\nStep 4/4: Type checking the files" @@ -388,26 +436,26 @@ defaultMain Arguments{..} = flip withHeapStats fun =<< argsLogger root <- maybe IO.getCurrentDirectory return argsProjectRoot dbLoc <- getHieDbLoc root hPutStrLn stderr $ "Using hiedb at: " ++ dbLoc - mlibdir <- setInitialDynFlags logger root def + mlibdir <- setInitialDynFlags (cmapWithPrio LogSession recorder) root def rng <- newStdGen case mlibdir of Nothing -> exitWith $ ExitFailure 1 - Just libdir -> retryOnSqliteBusy logger rng (HieDb.runCommand libdir opts{HieDb.database = dbLoc} cmd) + Just libdir -> retryOnSqliteBusy (cmapWithPrio LogSession recorder) rng (HieDb.runCommand libdir opts{HieDb.database = dbLoc} cmd) Custom (IdeCommand c) -> do root <- maybe IO.getCurrentDirectory return argsProjectRoot dbLoc <- getHieDbLoc root - runWithDb logger dbLoc $ \hiedb hieChan -> do + runWithDb (cmapWithPrio LogSession recorder) dbLoc $ \hiedb hieChan -> do vfs <- makeVFSHandle - sessionLoader <- loadSessionWithOptions argsSessionLoadingOptions "." + sessionLoader <- loadSessionWithOptions (cmapWithPrio LogSession recorder) argsSessionLoadingOptions "." let def_options = argsIdeOptions argsDefaultHlsConfig sessionLoader options = def_options { optCheckParents = pure NeverCheck , optCheckProject = pure False , optModifyDynFlags = optModifyDynFlags def_options <> pluginModifyDynflags plugins } - ide <- initialise argsDefaultHlsConfig rules Nothing logger debouncer options vfs hiedb hieChan - shakeSessionInit ide + ide <- initialise (cmapWithPrio LogService recorder) argsDefaultHlsConfig rules Nothing logger debouncer options vfs hiedb hieChan + shakeSessionInit (cmapWithPrio LogShake recorder) ide registerIdeConfiguration (shakeExtras ide) $ IdeConfiguration mempty (hashed Nothing) c ide diff --git a/ghcide/src/Development/IDE/Main/HeapStats.hs b/ghcide/src/Development/IDE/Main/HeapStats.hs index de17eef1df..c998630f6a 100644 --- a/ghcide/src/Development/IDE/Main/HeapStats.hs +++ b/ghcide/src/Development/IDE/Main/HeapStats.hs @@ -1,22 +1,48 @@ {-# LANGUAGE NumericUnderscores #-} -- | Logging utilities for reporting heap statistics -module Development.IDE.Main.HeapStats ( withHeapStats ) where +module Development.IDE.Main.HeapStats ( withHeapStats, Log(..)) where import Control.Concurrent import Control.Concurrent.Async import Control.Monad -import qualified Data.Text as T import Data.Word -import Development.IDE.Types.Logger (Logger, logInfo) +import Development.IDE.Types.Logger (Pretty (pretty), Priority (Info), + Recorder, WithPriority, hsep, + logWith, (<+>)) import GHC.Stats import Text.Printf (printf) +data Log + = LogHeapStatsPeriod !Int + | LogHeapStatsDisabled + | LogHeapStats !Word64 !Word64 + deriving Show + +instance Pretty Log where + pretty log = case log of + LogHeapStatsPeriod period -> + "Logging heap statistics every" <+> pretty (toFormattedSeconds period) + LogHeapStatsDisabled -> + "Heap statistics are not enabled (RTS option -T is needed)" + LogHeapStats liveBytes heapSize -> + hsep + [ "Live bytes:" + , pretty (toFormattedMegabytes liveBytes) + , "Heap size:" + , pretty (toFormattedMegabytes heapSize) ] + where + toFormattedSeconds :: Int -> String + toFormattedSeconds s = printf "%.2fs" (fromIntegral @Int @Double s / 1e6) + + toFormattedMegabytes :: Word64 -> String + toFormattedMegabytes b = printf "%.2fMB" (fromIntegral @Word64 @Double b / 1e6) + -- | Interval at which to report the latest heap statistics. heapStatsInterval :: Int heapStatsInterval = 60_000_000 -- 60s -- | Report the live bytes and heap size at the last major collection. -logHeapStats :: Logger -> IO () +logHeapStats :: Recorder (WithPriority Log) -> IO () logHeapStats l = do stats <- getRTSStats -- live_bytes is the total amount of live memory in a program @@ -25,14 +51,10 @@ logHeapStats l = do -- heap_size is the total amount of memory the RTS is using -- this corresponds closer to OS memory usage heap_size = gcdetails_mem_in_use_bytes (gc stats) - format :: Word64 -> T.Text - format m = T.pack (printf "%.2fMB" (fromIntegral @Word64 @Double m / 1e6)) - message = "Live bytes: " <> format live_bytes <> " " <> - "Heap size: " <> format heap_size - logInfo l message + logWith l Info $ LogHeapStats live_bytes heap_size -- | An action which logs heap statistics at the 'heapStatsInterval' -heapStatsThread :: Logger -> IO r +heapStatsThread :: Recorder (WithPriority Log) -> IO r heapStatsThread l = forever $ do threadDelay heapStatsInterval logHeapStats l @@ -40,14 +62,14 @@ heapStatsThread l = forever $ do -- | A helper function which lauches the 'heapStatsThread' and kills it -- appropiately when the inner action finishes. It also checks to see -- if `-T` is enabled. -withHeapStats :: Logger -> IO r -> IO r +withHeapStats :: Recorder (WithPriority Log) -> IO r -> IO r withHeapStats l k = do enabled <- getRTSStatsEnabled if enabled then do - logInfo l ("Logging heap statistics every " - <> T.pack (printf "%.2fs" (fromIntegral @Int @Double heapStatsInterval / 1e6))) + logWith l Info $ LogHeapStatsPeriod heapStatsInterval withAsync (heapStatsThread l) (const k) else do - logInfo l "Heap statistics are not enabled (RTS option -T is needed)" + logWith l Info LogHeapStatsDisabled k + diff --git a/ghcide/src/Development/IDE/Plugin/Completions.hs b/ghcide/src/Development/IDE/Plugin/Completions.hs index 8e0292cdc6..edc656ada0 100644 --- a/ghcide/src/Development/IDE/Plugin/Completions.hs +++ b/ghcide/src/Development/IDE/Plugin/Completions.hs @@ -4,6 +4,7 @@ module Development.IDE.Plugin.Completions ( descriptor + , Log(..) ) where import Control.Concurrent.Async (concurrently) @@ -19,8 +20,10 @@ import Data.Maybe import qualified Data.Text as T import Development.IDE.Core.PositionMapping import Development.IDE.Core.RuleTypes -import Development.IDE.Core.Service -import Development.IDE.Core.Shake +import Development.IDE.Core.Service hiding (Log, + LogShake) +import Development.IDE.Core.Shake hiding (Log) +import qualified Development.IDE.Core.Shake as Shake import Development.IDE.GHC.Compat import Development.IDE.GHC.Error (rangeToSrcSpan) import Development.IDE.GHC.ExactPrint (GetAnnotatedParsedSource (GetAnnotatedParsedSource)) @@ -36,6 +39,10 @@ import Development.IDE.Types.HscEnvEq (HscEnvEq (envPack hscEnv) import qualified Development.IDE.Types.KnownTargets as KT import Development.IDE.Types.Location +import Development.IDE.Types.Logger (Pretty (pretty), + Recorder, + WithPriority, + cmapWithPrio) import GHC.Exts (fromList, toList) import Ide.Plugin.Config (Config) import Ide.Types @@ -44,17 +51,23 @@ import Language.LSP.Types import qualified Language.LSP.VFS as VFS import Text.Fuzzy.Parallel (Scored (..)) -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = (defaultPluginDescriptor plId) - { pluginRules = produceCompletions +data Log = LogShake Shake.Log deriving Show + +instance Pretty Log where + pretty = \case + LogShake log -> pretty log + +descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState +descriptor recorder plId = (defaultPluginDescriptor plId) + { pluginRules = produceCompletions recorder , pluginHandlers = mkPluginHandler STextDocumentCompletion getCompletionsLSP , pluginCommands = [extendImportCommand] , pluginConfigDescriptor = defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties} } -produceCompletions :: Rules () -produceCompletions = do - define $ \LocalCompletions file -> do +produceCompletions :: Recorder (WithPriority Log) -> Rules () +produceCompletions recorder = do + define (cmapWithPrio LogShake recorder) $ \LocalCompletions file -> do let uri = fromNormalizedUri $ normalizedFilePathToUri file pm <- useWithStale GetParsedModule file case pm of @@ -62,7 +75,7 @@ produceCompletions = do let cdata = localCompletionsForParsedModule uri pm return ([], Just cdata) _ -> return ([], Nothing) - define $ \NonLocalCompletions file -> do + define (cmapWithPrio LogShake recorder) $ \NonLocalCompletions file -> do -- For non local completions we avoid depending on the parsed module, -- synthetizing a fake module with an empty body from the buffer -- in the ModSummary, which preserves all the imports diff --git a/ghcide/src/Development/IDE/Plugin/HLS.hs b/ghcide/src/Development/IDE/Plugin/HLS.hs index 842b69b530..a7c64a024f 100644 --- a/ghcide/src/Development/IDE/Plugin/HLS.hs +++ b/ghcide/src/Development/IDE/Plugin/HLS.hs @@ -6,11 +6,11 @@ module Development.IDE.Plugin.HLS ( asGhcIdePlugin + , Log(..) ) where import Control.Exception (SomeException) import Control.Monad -import Control.Monad.IO.Class import qualified Data.Aeson as J import Data.Bifunctor import Data.Dependent.Map (DMap) @@ -22,7 +22,7 @@ import Data.List.NonEmpty (NonEmpty, nonEmpty, toList) import qualified Data.Map as Map import Data.String import qualified Data.Text as T -import Development.IDE.Core.Shake +import Development.IDE.Core.Shake hiding (Log) import Development.IDE.Core.Tracing import Development.IDE.Graph (Rules) import Development.IDE.LSP.Server @@ -43,13 +43,22 @@ import UnliftIO.Exception (catchAny) -- --------------------------------------------------------------------- -- +data Log + = LogNoEnabledPlugins + deriving Show + +instance Pretty Log where + pretty = \case + LogNoEnabledPlugins -> + "extensibleNotificationPlugins no enabled plugins" + -- | Map a set of plugins to the underlying ghcide engine. -asGhcIdePlugin :: IdePlugins IdeState -> Plugin Config -asGhcIdePlugin (IdePlugins ls) = +asGhcIdePlugin :: Recorder (WithPriority Log) -> IdePlugins IdeState -> Plugin Config +asGhcIdePlugin recorder (IdePlugins ls) = mkPlugin rulesPlugins HLS.pluginRules <> mkPlugin executeCommandPlugins HLS.pluginCommands <> mkPlugin extensiblePlugins HLS.pluginHandlers <> - mkPlugin extensibleNotificationPlugins HLS.pluginNotificationHandlers <> + mkPlugin (extensibleNotificationPlugins recorder) HLS.pluginNotificationHandlers <> mkPlugin dynFlagsPlugins HLS.pluginModifyDynflags where @@ -171,8 +180,8 @@ extensiblePlugins xs = mempty { P.pluginHandlers = handlers } pure $ Right $ combineResponses m config caps params xs -- --------------------------------------------------------------------- -extensibleNotificationPlugins :: [(PluginId, PluginNotificationHandlers IdeState)] -> Plugin Config -extensibleNotificationPlugins xs = mempty { P.pluginHandlers = handlers } +extensibleNotificationPlugins :: Recorder (WithPriority Log) -> [(PluginId, PluginNotificationHandlers IdeState)] -> Plugin Config +extensibleNotificationPlugins recorder xs = mempty { P.pluginHandlers = handlers } where IdeNotificationHandlers handlers' = foldMap bakePluginId xs bakePluginId :: (PluginId, PluginNotificationHandlers IdeState) -> IdeNotificationHandlers @@ -186,7 +195,7 @@ extensibleNotificationPlugins xs = mempty { P.pluginHandlers = handlers } let fs = filter (\(pid,_) -> plcGlobalOn $ configForPlugin config pid) fs' case nonEmpty fs of Nothing -> do - liftIO $ logInfo (ideLogger ide) "extensibleNotificationPlugins no enabled plugins" + logWith recorder Info LogNoEnabledPlugins pure () Just fs -> do -- We run the notifications in order, so the core ghcide provider diff --git a/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs b/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs index c854330d9c..c1393b1f4b 100644 --- a/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs +++ b/ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs @@ -5,6 +5,7 @@ module Development.IDE.Plugin.HLS.GhcIde ( descriptors + , Log(..) ) where import Control.Monad.IO.Class import Development.IDE @@ -19,16 +20,28 @@ import Language.LSP.Server (LspM) import Language.LSP.Types import Text.Regex.TDFA.Text () -descriptors :: [PluginDescriptor IdeState] -descriptors = +data Log + = LogNotifications Notifications.Log + | LogCompletions Completions.Log + | LogTypeLenses TypeLenses.Log + deriving Show + +instance Pretty Log where + pretty = \case + LogNotifications log -> pretty log + LogCompletions log -> pretty log + LogTypeLenses log -> pretty log + +descriptors :: Recorder (WithPriority Log) -> [PluginDescriptor IdeState] +descriptors recorder = [ descriptor "ghcide-hover-and-symbols", CodeAction.iePluginDescriptor "ghcide-code-actions-imports-exports", CodeAction.typeSigsPluginDescriptor "ghcide-code-actions-type-signatures", CodeAction.bindingsPluginDescriptor "ghcide-code-actions-bindings", CodeAction.fillHolePluginDescriptor "ghcide-code-actions-fill-holes", - Completions.descriptor "ghcide-completions", - TypeLenses.descriptor "ghcide-type-lenses", - Notifications.descriptor "ghcide-core" + Completions.descriptor (cmapWithPrio LogCompletions recorder) "ghcide-completions", + TypeLenses.descriptor (cmapWithPrio LogTypeLenses recorder) "ghcide-type-lenses", + Notifications.descriptor (cmapWithPrio LogNotifications recorder) "ghcide-core" ] -- --------------------------------------------------------------------- diff --git a/ghcide/src/Development/IDE/Plugin/TypeLenses.hs b/ghcide/src/Development/IDE/Plugin/TypeLenses.hs index 4f7084badb..ecfdd35449 100644 --- a/ghcide/src/Development/IDE/Plugin/TypeLenses.hs +++ b/ghcide/src/Development/IDE/Plugin/TypeLenses.hs @@ -10,7 +10,8 @@ module Development.IDE.Plugin.TypeLenses ( GlobalBindingTypeSig (..), GetGlobalBindingTypeSigs (..), GlobalBindingTypeSigsResult (..), -) where + Log(..) + ) where import Control.Concurrent.STM.Stats (atomically) import Control.DeepSeq (rwhnf) @@ -33,6 +34,7 @@ import Development.IDE.Core.RuleTypes (GetBindings (GetBindings), import Development.IDE.Core.Rules (IdeState, runAction) import Development.IDE.Core.Service (getDiagnostics) import Development.IDE.Core.Shake (getHiddenDiagnostics, use) +import qualified Development.IDE.Core.Shake as Shake import Development.IDE.GHC.Compat import Development.IDE.GHC.Util (printName) import Development.IDE.Graph.Classes @@ -41,6 +43,9 @@ import Development.IDE.Types.Location (Position (Position, _chara Range (Range, _end, _start), toNormalizedFilePath', uriToFilePath') +import Development.IDE.Types.Logger (Pretty (pretty), Recorder, + WithPriority, + cmapWithPrio) import GHC.Generics (Generic) import Ide.Plugin.Config (Config) import Ide.Plugin.Properties @@ -68,15 +73,21 @@ import Language.LSP.Types (ApplyWorkspaceEditParams ( WorkspaceEdit (WorkspaceEdit)) import Text.Regex.TDFA ((=~), (=~~)) +data Log = LogShake Shake.Log deriving Show + +instance Pretty Log where + pretty = \case + LogShake log -> pretty log + typeLensCommandId :: T.Text typeLensCommandId = "typesignature.add" -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = +descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState +descriptor recorder plId = (defaultPluginDescriptor plId) { pluginHandlers = mkPluginHandler STextDocumentCodeLens codeLensProvider , pluginCommands = [PluginCommand (CommandId typeLensCommandId) "adds a signature" commandHandler] - , pluginRules = rules + , pluginRules = rules recorder , pluginConfigDescriptor = defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties} } @@ -239,9 +250,9 @@ instance NFData GlobalBindingTypeSigsResult where type instance RuleResult GetGlobalBindingTypeSigs = GlobalBindingTypeSigsResult -rules :: Rules () -rules = do - define $ \GetGlobalBindingTypeSigs nfp -> do +rules :: Recorder (WithPriority Log) -> Rules () +rules recorder = do + define (cmapWithPrio LogShake recorder) $ \GetGlobalBindingTypeSigs nfp -> do tmr <- use TypeCheck nfp -- we need session here for tidying types hsc <- use GhcSession nfp diff --git a/ghcide/src/Development/IDE/Types/Logger.hs b/ghcide/src/Development/IDE/Types/Logger.hs index c40ef36e54..9f696210e2 100644 --- a/ghcide/src/Development/IDE/Types/Logger.hs +++ b/ghcide/src/Development/IDE/Types/Logger.hs @@ -8,12 +8,50 @@ module Development.IDE.Types.Logger ( Priority(..) , Logger(..) + , Recorder(..) , logError, logWarning, logInfo, logDebug, logTelemetry , noLogging + , WithPriority(..) + , logWith + , cmap + , cmapIO + , cfilter + , withDefaultRecorder + , makeDefaultStderrRecorder + , priorityToHsLoggerPriority + , LoggingColumn(..) + , cmapWithPrio + , module PrettyPrinterModule ) where -import qualified Data.Text as T - +import Control.Concurrent (myThreadId) +import Control.Concurrent.Extra (Lock, newLock, withLock) +import Control.Exception (IOException) +import Control.Monad (forM_, when, (>=>)) +import Control.Monad.IO.Class (MonadIO (liftIO)) +import Data.Functor.Contravariant (Contravariant (contramap)) +import Data.Maybe (fromMaybe) +import Data.Text (Text) +import qualified Data.Text as T +import qualified Data.Text as Text +import qualified Data.Text.IO as Text +import Data.Time (defaultTimeLocale, formatTime, + getCurrentTime) +import GHC.Stack (CallStack, HasCallStack, + SrcLoc (SrcLoc, srcLocModule, srcLocStartCol, srcLocStartLine), + callStack, getCallStack, + withFrozenCallStack) +import Prettyprinter as PrettyPrinterModule +import Prettyprinter.Render.Text (renderStrict) +import System.IO (Handle, IOMode (AppendMode), + hClose, hFlush, hSetEncoding, + openFile, stderr, utf8) +import qualified System.Log.Formatter as HSL +import qualified System.Log.Handler as HSL +import qualified System.Log.Handler.Simple as HSL +import qualified System.Log.Logger as HsLogger +import UnliftIO (MonadUnliftIO, displayException, + finally, try) data Priority -- Don't change the ordering of this type or you will mess up the Ord @@ -27,7 +65,6 @@ data Priority | Error -- ^ Such log messages must never occur in expected usage. deriving (Eq, Show, Ord, Enum, Bounded) - -- | Note that this is logging actions _of the program_, not of the user. -- You shouldn't call warning/error if the user has caused an error, only -- if our code has gone wrong and is itself erroneous (e.g. we threw an exception). @@ -57,3 +94,208 @@ logTelemetry x = logPriority x Telemetry noLogging :: Logger noLogging = Logger $ \_ _ -> return () + +data WithPriority a = WithPriority { priority :: Priority, callStack_ :: CallStack, payload :: a } deriving Functor + +-- | Note that this is logging actions _of the program_, not of the user. +-- You shouldn't call warning/error if the user has caused an error, only +-- if our code has gone wrong and is itself erroneous (e.g. we threw an exception). +data Recorder msg = Recorder + { logger_ :: forall m. (MonadIO m) => msg -> m () } + +logWith :: (HasCallStack, MonadIO m) => Recorder (WithPriority msg) -> Priority -> msg -> m () +logWith recorder priority msg = withFrozenCallStack $ logger_ recorder (WithPriority priority callStack msg) + +instance Semigroup (Recorder msg) where + (<>) Recorder{ logger_ = logger_1 } Recorder{ logger_ = logger_2 } = + Recorder + { logger_ = \msg -> logger_1 msg >> logger_2 msg } + +instance Monoid (Recorder msg) where + mempty = + Recorder + { logger_ = \_ -> pure () } + +instance Contravariant Recorder where + contramap f Recorder{ logger_ } = + Recorder + { logger_ = logger_ . f } + +cmap :: (a -> b) -> Recorder b -> Recorder a +cmap = contramap + +cmapWithPrio :: (a -> b) -> Recorder (WithPriority b) -> Recorder (WithPriority a) +cmapWithPrio f = cmap (fmap f) + +cmapIO :: (a -> IO b) -> Recorder b -> Recorder a +cmapIO f Recorder{ logger_ } = + Recorder + { logger_ = (liftIO . f) >=> logger_ } + +cfilter :: (a -> Bool) -> Recorder a -> Recorder a +cfilter p Recorder{ logger_ } = + Recorder + { logger_ = \msg -> when (p msg) (logger_ msg) } + +textHandleRecorder :: Handle -> Recorder Text +textHandleRecorder handle = + Recorder + { logger_ = \text -> liftIO $ Text.hPutStrLn handle text *> hFlush handle } + +-- | Priority is actually for hslogger compatibility +makeDefaultStderrRecorder :: MonadIO m => Maybe [LoggingColumn] -> Priority -> m (Recorder (WithPriority (Doc a))) +makeDefaultStderrRecorder columns minPriority = do + lock <- liftIO newLock + makeDefaultHandleRecorder columns minPriority lock stderr + +-- | If no path given then use stderr, otherwise use file. +-- Kinda complicated because we also need to setup `hslogger` for +-- `hie-bios` log compatibility reasons. If `hie-bios` can be set to use our +-- logger instead or if `hie-bios` doesn't use `hslogger` then `hslogger` can +-- be removed completely. See `setupHsLogger` comment. +withDefaultRecorder + :: MonadUnliftIO m + => Maybe FilePath + -- ^ Log file path. `Nothing` uses stderr + -> Maybe [LoggingColumn] + -- ^ logging columns to display. `Nothing` uses `defaultLoggingColumns` + -> Priority + -- ^ min priority for hslogger compatibility + -> (Recorder (WithPriority (Doc d)) -> m a) + -- ^ action given a recorder + -> m a +withDefaultRecorder path columns minPriority action = do + lock <- liftIO newLock + let makeHandleRecorder = makeDefaultHandleRecorder columns minPriority lock + case path of + Nothing -> do + recorder <- makeHandleRecorder stderr + let message = "No log file specified; using stderr." + logWith recorder Info message + action recorder + Just path -> do + fileHandle :: Either IOException Handle <- liftIO $ try (openFile path AppendMode) + case fileHandle of + Left e -> do + recorder <- makeHandleRecorder stderr + let exceptionMessage = pretty $ displayException e + let message = vcat [exceptionMessage, "Couldn't open log file" <+> pretty path <> "; falling back to stderr."] + logWith recorder Warning message + action recorder + Right fileHandle -> finally (makeHandleRecorder fileHandle >>= action) (liftIO $ hClose fileHandle) + +makeDefaultHandleRecorder + :: MonadIO m + => Maybe [LoggingColumn] + -- ^ built-in logging columns to display. Nothing uses the default + -> Priority + -- ^ min priority for hslogger compatibility + -> Lock + -- ^ lock to take when outputting to handle + -> Handle + -- ^ handle to output to + -> m (Recorder (WithPriority (Doc a))) +makeDefaultHandleRecorder columns minPriority lock handle = do + let Recorder{ logger_ } = textHandleRecorder handle + let threadSafeRecorder = Recorder { logger_ = \msg -> liftIO $ withLock lock (logger_ msg) } + let loggingColumns = fromMaybe defaultLoggingColumns columns + let textWithPriorityRecorder = cmapIO (textWithPriorityToText loggingColumns) threadSafeRecorder + -- see `setupHsLogger` comment + liftIO $ setupHsLogger lock handle ["hls", "hie-bios"] (priorityToHsLoggerPriority minPriority) + pure (cmap docToText textWithPriorityRecorder) + where + docToText = fmap (renderStrict . layoutPretty defaultLayoutOptions) + +priorityToHsLoggerPriority :: Priority -> HsLogger.Priority +priorityToHsLoggerPriority = \case + Telemetry -> HsLogger.INFO + Debug -> HsLogger.DEBUG + Info -> HsLogger.INFO + Warning -> HsLogger.WARNING + Error -> HsLogger.ERROR + +-- | The purpose of setting up `hslogger` at all is that `hie-bios` uses +-- `hslogger` to output compilation logs. The easiest way to merge these logs +-- with our log output is to setup an `hslogger` that uses the same handle +-- and same lock as our loggers. That way the output from our loggers and +-- `hie-bios` don't interleave strangely. +-- It may be possible to have `hie-bios` use our logger by decorating the +-- `Cradle.cradleOptsProg.runCradle` we get in the Cradle from +-- `HieBios.findCradle`, but I remember trying that and something not good +-- happened. I'd have to try it again to remember if that was a real issue. +-- Once that is figured out or `hie-bios` doesn't use `hslogger`, then all +-- references to `hslogger` can be removed entirely. +setupHsLogger :: Lock -> Handle -> [String] -> HsLogger.Priority -> IO () +setupHsLogger lock handle extraLogNames level = do + hSetEncoding handle utf8 + + logH <- HSL.streamHandler handle level + + let logHandle = logH + { HSL.writeFunc = \a s -> withLock lock $ HSL.writeFunc logH a s } + logFormatter = HSL.tfLogFormatter logDateFormat logFormat + logHandler = HSL.setFormatter logHandle logFormatter + + HsLogger.updateGlobalLogger HsLogger.rootLoggerName $ HsLogger.setHandlers ([] :: [HSL.GenericHandler Handle]) + HsLogger.updateGlobalLogger "haskell-lsp" $ HsLogger.setHandlers [logHandler] + HsLogger.updateGlobalLogger "haskell-lsp" $ HsLogger.setLevel level + + -- Also route the additional log names to the same log + forM_ extraLogNames $ \logName -> do + HsLogger.updateGlobalLogger logName $ HsLogger.setHandlers [logHandler] + HsLogger.updateGlobalLogger logName $ HsLogger.setLevel level + where + logFormat = "$time [$tid] $prio $loggername:\t$msg" + logDateFormat = "%Y-%m-%d %H:%M:%S%Q" + +data LoggingColumn + = TimeColumn + | ThreadIdColumn + | PriorityColumn + | DataColumn + | SourceLocColumn + +defaultLoggingColumns :: [LoggingColumn] +defaultLoggingColumns = [TimeColumn, PriorityColumn, DataColumn] + +textWithPriorityToText :: [LoggingColumn] -> WithPriority Text -> IO Text +textWithPriorityToText columns WithPriority{ priority, callStack_, payload } = do + textColumns <- mapM loggingColumnToText columns + pure $ Text.intercalate " | " textColumns + where + showAsText :: Show a => a -> Text + showAsText = Text.pack . show + + utcTimeToText utcTime = Text.pack $ formatTime defaultTimeLocale "%Y-%m-%dT%H:%M:%S%6QZ" utcTime + + priorityToText :: Priority -> Text + priorityToText = showAsText + + threadIdToText = showAsText + + callStackToSrcLoc :: CallStack -> Maybe SrcLoc + callStackToSrcLoc callStack = + case getCallStack callStack of + (_, srcLoc) : _ -> Just srcLoc + _ -> Nothing + + srcLocToText = \case + Nothing -> "" + Just SrcLoc{ srcLocModule, srcLocStartLine, srcLocStartCol } -> + Text.pack srcLocModule <> "#" <> showAsText srcLocStartLine <> ":" <> showAsText srcLocStartCol + + loggingColumnToText :: LoggingColumn -> IO Text + loggingColumnToText = \case + TimeColumn -> do + utcTime <- getCurrentTime + pure (utcTimeToText utcTime) + SourceLocColumn -> pure $ (srcLocToText . callStackToSrcLoc) callStack_ + ThreadIdColumn -> do + threadId <- myThreadId + pure (threadIdToText threadId) + PriorityColumn -> pure (priorityToText priority) + DataColumn -> pure payload + + + + diff --git a/ghcide/test/exe/HieDbRetry.hs b/ghcide/test/exe/HieDbRetry.hs index f3a29cea39..c51c8bbebc 100644 --- a/ghcide/test/exe/HieDbRetry.hs +++ b/ghcide/test/exe/HieDbRetry.hs @@ -5,25 +5,34 @@ import Control.Concurrent.Extra (Var, modifyVar, newVar, readVar, withVar) import Control.Exception (ErrorCall (ErrorCall), evaluate, throwIO, tryJust) -import Data.Text (Text) +import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.Tuple.Extra (dupe) import qualified Database.SQLite.Simple as SQLite import Development.IDE.Session (retryOnException, retryOnSqliteBusy) -import Development.IDE.Types.Logger (Logger (Logger), Priority, - noLogging) +import qualified Development.IDE.Session as Session +import Development.IDE.Types.Logger (Recorder (Recorder, logger_), + WithPriority (WithPriority, payload), + cmapWithPrio) import qualified System.Random as Random import Test.Tasty (TestTree, testGroup) import Test.Tasty.HUnit (assertFailure, testCase, (@?=)) -makeLogger :: Var [(Priority, Text)] -> Logger -makeLogger msgsVar = Logger $ \priority msg -> modifyVar msgsVar (\msgs -> pure ((priority, msg) : msgs, ())) +data Log + = LogSession Session.Log + deriving Show + +makeLogger :: Var [Log] -> Recorder (WithPriority Log) +makeLogger msgsVar = + Recorder { + logger_ = \WithPriority{ payload = msg } -> liftIO $ modifyVar msgsVar (\msgs -> pure (msg : msgs, ())) + } rng :: Random.StdGen rng = Random.mkStdGen 0 -retryOnSqliteBusyForTest :: Logger -> Int -> IO a -> IO a -retryOnSqliteBusyForTest logger maxRetryCount = retryOnException isErrorBusy logger 1 1 maxRetryCount rng +retryOnSqliteBusyForTest :: Recorder (WithPriority Log) -> Int -> IO a -> IO a +retryOnSqliteBusyForTest recorder maxRetryCount = retryOnException isErrorBusy (cmapWithPrio LogSession recorder) 1 1 maxRetryCount rng isErrorBusy :: SQLite.SQLError -> Maybe SQLite.SQLError isErrorBusy e @@ -60,7 +69,7 @@ tests = testGroup "RetryHieDb" let expected = 1 :: Int let maxRetryCount = 0 - actual <- retryOnSqliteBusyForTest noLogging maxRetryCount (pure expected) + actual <- retryOnSqliteBusyForTest mempty maxRetryCount (pure expected) actual @?= expected @@ -69,7 +78,7 @@ tests = testGroup "RetryHieDb" let maxRetryCount = 3 let incrementThenThrow = modifyVar countVar (\count -> pure (dupe (count + 1))) >> throwIO errorBusy - _ <- tryJust isErrorBusy (retryOnSqliteBusyForTest noLogging maxRetryCount incrementThenThrow) + _ <- tryJust isErrorBusy (retryOnSqliteBusyForTest mempty maxRetryCount incrementThenThrow) withVar countVar $ \count -> count @?= maxRetryCount + 1 @@ -86,7 +95,7 @@ tests = testGroup "RetryHieDb" modifyVar countVar (\count -> pure (dupe (count + 1))) - _ <- tryJust isErrorCall (retryOnSqliteBusyForTest noLogging maxRetryCount throwThenIncrement) + _ <- tryJust isErrorCall (retryOnSqliteBusyForTest mempty maxRetryCount throwThenIncrement) withVar countVar $ \count -> count @?= 0 @@ -101,27 +110,29 @@ tests = testGroup "RetryHieDb" else modifyVar countVar (\count -> pure (dupe (count + 1))) - _ <- retryOnSqliteBusy noLogging rng incrementThenThrowThenIncrement + _ <- retryOnSqliteBusy mempty rng incrementThenThrowThenIncrement withVar countVar $ \count -> count @?= 2 , testCase "retryOnException exponentially backs off" $ do - logMsgsVar <- newVar ([] :: [(Priority, Text)]) + logMsgsVar <- newVar ([] :: [Log]) let maxDelay = 100 let baseDelay = 1 let maxRetryCount = 6 let logger = makeLogger logMsgsVar - result <- tryJust isErrorBusy (retryOnException isErrorBusy logger maxDelay baseDelay maxRetryCount rng (throwIO errorBusy)) + result <- tryJust isErrorBusy (retryOnException isErrorBusy (cmapWithPrio LogSession logger) maxDelay baseDelay maxRetryCount rng (throwIO errorBusy)) case result of Left _ -> do withVar logMsgsVar $ \logMsgs -> - if | ((_, lastLogMsg) : _) <- logMsgs -> - -- uses log messages to indirectly check backoff... - lastLogMsg @?= "Retries exhausted - base delay: 64, maximumDelay: 100, maxRetryCount: 0, exception: SQLite3 returned ErrorBusy while attempting to perform : " + -- uses log messages to check backoff... + if | (LogSession (Session.LogHieDbRetriesExhausted baseDelay maximumDelay maxRetryCount _) : _) <- logMsgs -> do + baseDelay @?= 64 + maximumDelay @?= 100 + maxRetryCount @?= 0 | otherwise -> assertFailure "Expected more than 0 log messages" Right _ -> assertFailure "Expected ErrorBusy exception" ] diff --git a/ghcide/test/exe/Main.hs b/ghcide/test/exe/Main.hs index 6f4481f9e5..286c5e98d0 100644 --- a/ghcide/test/exe/Main.hs +++ b/ghcide/test/exe/Main.hs @@ -107,7 +107,6 @@ import qualified Development.IDE.Plugin.HLS.GhcIde as Ghcide import Development.IDE.Plugin.Test (TestRequest (BlockSeconds), WaitForIdeRuleResult (..), blockCommandId) -import qualified HieDbRetry import Ide.PluginUtils (pluginDescToIdePlugins) import Ide.Types import qualified Language.LSP.Types as LSP @@ -121,8 +120,21 @@ import Test.Tasty.Ingredients.Rerun import Test.Tasty.QuickCheck import Text.Printf (printf) import Text.Regex.TDFA ((=~)) +import qualified HieDbRetry +import Development.IDE.Types.Logger (WithPriority(WithPriority, priority), Priority (Debug), cmapWithPrio, Recorder (Recorder, logger_), makeDefaultStderrRecorder, cfilter, LoggingColumn (PriorityColumn, DataColumn), Logger (Logger), Pretty (pretty)) +import Data.Function ((&)) +import GHC.Stack (emptyCallStack) import qualified FuzzySearch +data Log + = LogGhcIde Ghcide.Log + | LogIDEMain IDE.Log + +instance Pretty Log where + pretty = \case + LogGhcIde log -> pretty log + LogIDEMain log -> pretty log + -- | Wait for the next progress begin step waitForProgressBegin :: Session () waitForProgressBegin = skipManyTill anyMessage $ satisfyMaybe $ \case @@ -151,6 +163,18 @@ waitForAllProgressDone = loop main :: IO () main = do + docWithPriorityRecorder <- makeDefaultStderrRecorder (Just [PriorityColumn, DataColumn]) Debug + + let docWithFilteredPriorityRecorder@Recorder{ logger_ } = + docWithPriorityRecorder + & cfilter (\WithPriority{ priority } -> priority >= Debug) + + -- exists so old-style logging works. intended to be phased out + let logger = Logger $ \p m -> logger_ (WithPriority p emptyCallStack (pretty m)) + + let recorder = docWithFilteredPriorityRecorder + & cmapWithPrio pretty + -- We mess with env vars so run single-threaded. defaultMainWithRerun $ testGroup "ghcide" [ testSession "open close" $ do @@ -174,7 +198,7 @@ main = do , thTests , symlinkTests , safeTests - , unitTests + , unitTests recorder logger , haddockTests , positionMappingTests , watchedFilesTests @@ -6174,8 +6198,8 @@ findCodeActions' op errMsg doc range expectedTitles = do findCodeAction :: TextDocumentIdentifier -> Range -> T.Text -> Session CodeAction findCodeAction doc range t = head <$> findCodeActions doc range [t] -unitTests :: TestTree -unitTests = do +unitTests :: Recorder (WithPriority Log) -> Logger -> TestTree +unitTests recorder logger = do testGroup "Unit" [ testCase "empty file path does NOT work with the empty String literal" $ uriToFilePath' (fromNormalizedUri $ filePathToUri' "") @?= Just "." @@ -6215,9 +6239,9 @@ unitTests = do ] } | i <- [(1::Int)..20] - ] ++ Ghcide.descriptors + ] ++ Ghcide.descriptors (cmapWithPrio LogGhcIde recorder) - testIde IDE.testing{IDE.argsHlsPlugins = plugins} $ do + testIde recorder (IDE.testing (cmapWithPrio LogIDEMain recorder) logger){IDE.argsHlsPlugins = plugins} $ do _ <- createDoc "haskell" "A.hs" "module A where" waitForProgressDone actualOrder <- liftIO $ readIORef orderRef @@ -6316,16 +6340,14 @@ findResolution_us delay_us = withTempFile $ \f -> withTempFile $ \f' -> do if t /= t' then return delay_us else findResolution_us (delay_us * 10) -testIde :: IDE.Arguments -> Session a -> IO a -testIde = testIde' "." - -testIde' :: FilePath -> IDE.Arguments -> Session a -> IO a -testIde' projDir arguments session = do +testIde :: Recorder (WithPriority Log) -> IDE.Arguments -> Session () -> IO () +testIde recorder arguments session = do config <- getConfigFromEnv cwd <- getCurrentDirectory (hInRead, hInWrite) <- createPipe (hOutRead, hOutWrite) <- createPipe - let server = IDE.defaultMain arguments + let projDir = "." + let server = IDE.defaultMain (cmapWithPrio LogIDEMain recorder) arguments { IDE.argsHandleIn = pure hInRead , IDE.argsHandleOut = pure hOutWrite } diff --git a/haskell-language-server.cabal b/haskell-language-server.cabal index 84277c86bf..2ee0036ad8 100644 --- a/haskell-language-server.cabal +++ b/haskell-language-server.cabal @@ -39,6 +39,7 @@ common common-deps , extra , filepath , text + , prettyprinter -- Default warnings in HLS common warnings diff --git a/hls-plugin-api/src/Ide/Types.hs b/hls-plugin-api/src/Ide/Types.hs index 0fb06387d4..b4faf554ec 100644 --- a/hls-plugin-api/src/Ide/Types.hs +++ b/hls-plugin-api/src/Ide/Types.hs @@ -396,6 +396,7 @@ type CommandFunction ideState a newtype PluginId = PluginId T.Text deriving (Show, Read, Eq, Ord) + instance IsString PluginId where fromString = PluginId . T.pack diff --git a/hls-test-utils/src/Test/Hls.hs b/hls-test-utils/src/Test/Hls.hs index b6d25909a8..02ece9efb4 100644 --- a/hls-test-utils/src/Test/Hls.hs +++ b/hls-test-utils/src/Test/Hls.hs @@ -1,9 +1,9 @@ -{-# LANGUAGE GADTs #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE PolyKinds #-} -{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE DisambiguateRecordFields #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PolyKinds #-} module Test.Hls ( module Test.Tasty.HUnit, module Test.Tasty, @@ -51,14 +51,24 @@ import Data.Maybe (fromMaybe) import qualified Data.Text as T import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy.Encoding as TL -import Development.IDE (IdeState, noLogging) +import Development.IDE (IdeState) import Development.IDE.Graph (ShakeOptions (shakeThreads)) -import Development.IDE.Main +import Development.IDE.Main hiding (Log) import qualified Development.IDE.Main as Ghcide +import qualified Development.IDE.Main as IDEMain import Development.IDE.Plugin.Test (TestRequest (GetBuildKeysBuilt, WaitForIdeRule, WaitForShakeQueue), WaitForIdeRuleResult (ideResultSuccess)) +import qualified Development.IDE.Plugin.Test as Test +import Development.IDE.Types.Logger (Logger (Logger), + Pretty (pretty), + Priority (Debug), + Recorder (Recorder, logger_), + WithPriority (WithPriority, priority), + cfilter, cmapWithPrio, + makeDefaultStderrRecorder) import Development.IDE.Types.Options import GHC.IO.Handle +import GHC.Stack (emptyCallStack) import Ide.Plugin.Config (Config, formattingProvider) import Ide.PluginUtils (idePluginsToPluginDesc, pluginDescToIdePlugins) @@ -69,6 +79,7 @@ import Language.LSP.Types hiding SemanticTokenRelative (length), SemanticTokensEdit (_start)) import Language.LSP.Types.Capabilities (ClientCapabilities) +import Prelude hiding (log) import System.Directory (getCurrentDirectory, setCurrentDirectory) import System.Environment (lookupEnv) @@ -83,6 +94,12 @@ import Test.Tasty.Golden import Test.Tasty.HUnit import Test.Tasty.Ingredients.Rerun +newtype Log = LogIDEMain IDEMain.Log + +instance Pretty Log where + pretty = \case + LogIDEMain log -> pretty log + -- | Run 'defaultMainWithRerun', limiting each single test case running at most 10 minutes defaultTestRunner :: TestTree -> IO () defaultTestRunner = defaultMainWithRerun . adjustOption (const $ mkTimeout 600000000) @@ -152,6 +169,7 @@ keepCurrentDirectory = bracket getCurrentDirectory setCurrentDirectory . const lock :: Lock lock = unsafePerformIO newLock + -- | Host a server, and run a test session on it -- Note: cwd will be shifted into @root@ in @Session a@ runSessionWithServer' :: @@ -165,31 +183,50 @@ runSessionWithServer' :: FilePath -> Session a -> IO a -runSessionWithServer' plugin conf sconf caps root s = withLock lock $ keepCurrentDirectory $ do +runSessionWithServer' plugins conf sconf caps root s = withLock lock $ keepCurrentDirectory $ do (inR, inW) <- createPipe (outR, outW) <- createPipe - let logger = do - logStdErr <- fromMaybe "0" <$> lookupEnv "LSP_TEST_LOG_STDERR" - if logStdErr == "0" - then return noLogging - else argsLogger testing + + docWithPriorityRecorder <- makeDefaultStderrRecorder Nothing Debug + + logStdErr <- fromMaybe "0" <$> lookupEnv "LSP_TEST_LOG_STDERR" + + let + docWithFilteredPriorityRecorder@Recorder{ logger_ } = + if logStdErr == "0" then mempty + else cfilter (\WithPriority{ priority } -> priority >= Debug) docWithPriorityRecorder + + -- exists until old logging style is phased out + logger = Logger $ \p m -> logger_ (WithPriority p emptyCallStack (pretty m)) + + recorder = cmapWithPrio pretty docWithFilteredPriorityRecorder + + arguments@Arguments{ argsHlsPlugins, argsIdeOptions, argsLogger } = defaultArguments (cmapWithPrio LogIDEMain recorder) logger + + hlsPlugins = + idePluginsToPluginDesc argsHlsPlugins + ++ [Test.blockCommandDescriptor "block-command", Test.plugin] + ++ plugins + ideOptions = \config ghcSession -> + let defIdeOptions@IdeOptions{ optShakeOptions } = argsIdeOptions config ghcSession + in defIdeOptions + { optTesting = IdeTesting True + , optCheckProject = pure False + , optShakeOptions = optShakeOptions{ shakeThreads = 2 } + } server <- async $ Ghcide.defaultMain - testing - { argsHandleIn = pure inR, - argsHandleOut = pure outW, - argsDefaultHlsConfig = conf, - argsLogger = logger, - argsIdeOptions = \config sessionLoader -> - let ideOptions = (argsIdeOptions def config sessionLoader) - {optTesting = IdeTesting True - ,optCheckProject = pure False - } - in ideOptions {optShakeOptions = (optShakeOptions ideOptions) {shakeThreads = 2}}, - argsHlsPlugins = pluginDescToIdePlugins $ plugin ++ idePluginsToPluginDesc (argsHlsPlugins testing) - } + (cmapWithPrio LogIDEMain recorder) + arguments + { argsHandleIn = pure inR + , argsHandleOut = pure outW + , argsDefaultHlsConfig = conf + , argsLogger = argsLogger + , argsIdeOptions = ideOptions + , argsHlsPlugins = pluginDescToIdePlugins hlsPlugins } + x <- runSessionWithHandles inW outR sconf caps root s hClose inW timeout 3 (wait server) >>= \case diff --git a/plugins/default/src/Ide/Plugin/Example.hs b/plugins/default/src/Ide/Plugin/Example.hs index 9511b00b06..0416cbe8d1 100644 --- a/plugins/default/src/Ide/Plugin/Example.hs +++ b/plugins/default/src/Ide/Plugin/Example.hs @@ -3,6 +3,7 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TupleSections #-} @@ -12,6 +13,7 @@ module Ide.Plugin.Example ( descriptor + , Log(..) ) where import Control.Concurrent.STM @@ -27,6 +29,7 @@ import Data.Typeable import Development.IDE as D import Development.IDE.Core.Shake (getDiagnostics, getHiddenDiagnostics) +import qualified Development.IDE.Core.Shake as Shake import Development.IDE.GHC.Compat import GHC.Generics import Ide.PluginUtils @@ -38,9 +41,15 @@ import Text.Regex.TDFA.Text () -- --------------------------------------------------------------------- -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = (defaultPluginDescriptor plId) - { pluginRules = exampleRules +newtype Log = LogShake Shake.Log deriving Show + +instance Pretty Log where + pretty = \case + LogShake log -> pretty log + +descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState +descriptor recorder plId = (defaultPluginDescriptor plId) + { pluginRules = exampleRules recorder , pluginCommands = [PluginCommand "codelens.todo" "example adding" addTodoCmd] , pluginHandlers = mkPluginHandler STextDocumentCodeAction codeAction <> mkPluginHandler STextDocumentCodeLens codeLens @@ -74,9 +83,9 @@ instance NFData Example type instance RuleResult Example = () -exampleRules :: Rules () -exampleRules = do - define $ \Example file -> do +exampleRules :: Recorder (WithPriority Log) -> Rules () +exampleRules recorder = do + define (cmapWithPrio LogShake recorder) $ \Example file -> do _pm <- getParsedModule file let diag = mkDiag file "example" DsError (Range (Position 0 0) (Position 1 0)) "example diagnostic, hello world" return ([diag], Just ()) diff --git a/plugins/default/src/Ide/Plugin/Example2.hs b/plugins/default/src/Ide/Plugin/Example2.hs index 4b95e4242b..6595ce58a6 100644 --- a/plugins/default/src/Ide/Plugin/Example2.hs +++ b/plugins/default/src/Ide/Plugin/Example2.hs @@ -3,6 +3,7 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TupleSections #-} @@ -12,6 +13,7 @@ module Ide.Plugin.Example2 ( descriptor + , Log(..) ) where import Control.Concurrent.STM @@ -25,7 +27,8 @@ import Data.Hashable import qualified Data.Text as T import Data.Typeable import Development.IDE as D -import Development.IDE.Core.Shake +import Development.IDE.Core.Shake hiding (Log) +import qualified Development.IDE.Core.Shake as Shake import GHC.Generics import Ide.PluginUtils import Ide.Types @@ -35,9 +38,15 @@ import Text.Regex.TDFA.Text () -- --------------------------------------------------------------------- -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = (defaultPluginDescriptor plId) - { pluginRules = exampleRules +newtype Log = LogShake Shake.Log deriving Show + +instance Pretty Log where + pretty = \case + LogShake log -> pretty log + +descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState +descriptor recorder plId = (defaultPluginDescriptor plId) + { pluginRules = exampleRules recorder , pluginCommands = [PluginCommand "codelens.todo" "example adding" addTodoCmd] , pluginHandlers = mkPluginHandler STextDocumentCodeAction codeAction <> mkPluginHandler STextDocumentCodeLens codeLens @@ -66,9 +75,9 @@ instance NFData Example2 type instance RuleResult Example2 = () -exampleRules :: Rules () -exampleRules = do - define $ \Example2 file -> do +exampleRules :: Recorder (WithPriority Log) -> Rules () +exampleRules recorder = do + define (cmapWithPrio LogShake recorder) $ \Example2 file -> do _pm <- getParsedModule file let diag = mkDiag file "example2" DsError (Range (Position 0 0) (Position 1 0)) "example2 diagnostic, hello world" return ([diag], Just ()) diff --git a/plugins/hls-alternate-number-format-plugin/src/Ide/Plugin/AlternateNumberFormat.hs b/plugins/hls-alternate-number-format-plugin/src/Ide/Plugin/AlternateNumberFormat.hs index 53056164e2..e1c4d064dc 100644 --- a/plugins/hls-alternate-number-format-plugin/src/Ide/Plugin/AlternateNumberFormat.hs +++ b/plugins/hls-alternate-number-format-plugin/src/Ide/Plugin/AlternateNumberFormat.hs @@ -2,7 +2,7 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} -module Ide.Plugin.AlternateNumberFormat (descriptor) where +module Ide.Plugin.AlternateNumberFormat (descriptor, Log(..)) where import Control.Lens ((^.)) import Control.Monad.Except (ExceptT, MonadIO, liftIO) @@ -14,6 +14,7 @@ import Development.IDE (GetParsedModule (GetParsedModu define, ideLogger, realSrcSpanToRange, runAction, use) +import qualified Development.IDE.Core.Shake as Shake import Development.IDE.GHC.Compat hiding (getSrcSpan) import Development.IDE.GHC.Compat.Util (toList) import Development.IDE.Graph.Classes (Hashable, NFData) @@ -29,10 +30,16 @@ import Ide.Types import Language.LSP.Types import Language.LSP.Types.Lens (uri) -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = (defaultPluginDescriptor plId) +newtype Log = LogShake Shake.Log deriving Show + +instance Pretty Log where + pretty = \case + LogShake log -> pretty log + +descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState +descriptor recorder plId = (defaultPluginDescriptor plId) { pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionHandler - , pluginRules = collectLiteralsRule + , pluginRules = collectLiteralsRule recorder } data CollectLiterals = CollectLiterals @@ -53,8 +60,8 @@ instance Show CollectLiteralsResult where instance NFData CollectLiteralsResult -collectLiteralsRule :: Rules () -collectLiteralsRule = define $ \CollectLiterals nfp -> do +collectLiteralsRule :: Recorder (WithPriority Log) -> Rules () +collectLiteralsRule recorder = define (cmapWithPrio LogShake recorder) $ \CollectLiterals nfp -> do pm <- use GetParsedModule nfp -- get the current extensions active and transform them into FormatTypes let fmts = getFormatTypes <$> pm diff --git a/plugins/hls-alternate-number-format-plugin/test/Main.hs b/plugins/hls-alternate-number-format-plugin/test/Main.hs index cda83db6b7..f37ec9e4f0 100644 --- a/plugins/hls-alternate-number-format-plugin/test/Main.hs +++ b/plugins/hls-alternate-number-format-plugin/test/Main.hs @@ -21,7 +21,7 @@ main :: IO () main = defaultTestRunner test alternateNumberFormatPlugin :: PluginDescriptor IdeState -alternateNumberFormatPlugin = AlternateNumberFormat.descriptor "alternateNumberFormat" +alternateNumberFormatPlugin = AlternateNumberFormat.descriptor mempty "alternateNumberFormat" -- NOTE: For whatever reason, this plugin does not play nice with creating Code Actions on time. diff --git a/plugins/hls-eval-plugin/src/Ide/Plugin/Eval.hs b/plugins/hls-eval-plugin/src/Ide/Plugin/Eval.hs index c223f522f1..c00022fd13 100644 --- a/plugins/hls-eval-plugin/src/Ide/Plugin/Eval.hs +++ b/plugins/hls-eval-plugin/src/Ide/Plugin/Eval.hs @@ -1,32 +1,43 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -Wwarn #-} +{-# LANGUAGE LambdaCase #-} {- | Eval Plugin entry point. -} module Ide.Plugin.Eval ( descriptor, -) where + Log(..) + ) where -import Development.IDE (IdeState) -import qualified Ide.Plugin.Eval.CodeLens as CL +import Development.IDE (IdeState) +import Development.IDE.Types.Logger (Pretty (pretty), Recorder, + WithPriority, cmapWithPrio) +import qualified Ide.Plugin.Eval.CodeLens as CL import Ide.Plugin.Eval.Config -import Ide.Plugin.Eval.Rules (rules) -import Ide.Types (ConfigDescriptor (..), - PluginDescriptor (..), PluginId, - defaultConfigDescriptor, - defaultPluginDescriptor, - mkCustomConfig, mkPluginHandler) +import Ide.Plugin.Eval.Rules (rules) +import qualified Ide.Plugin.Eval.Rules as EvalRules +import Ide.Types (ConfigDescriptor (..), + PluginDescriptor (..), PluginId, + defaultConfigDescriptor, + defaultPluginDescriptor, + mkCustomConfig, mkPluginHandler) import Language.LSP.Types +newtype Log = LogEvalRules EvalRules.Log deriving Show + +instance Pretty Log where + pretty = \case + LogEvalRules log -> pretty log + -- |Plugin descriptor -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = +descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState +descriptor recorder plId = (defaultPluginDescriptor plId) { pluginHandlers = mkPluginHandler STextDocumentCodeLens CL.codeLens , pluginCommands = [CL.evalCommand plId] - , pluginRules = rules + , pluginRules = rules (cmapWithPrio LogEvalRules recorder) , pluginConfigDescriptor = defaultConfigDescriptor { configCustomConfig = mkCustomConfig properties } diff --git a/plugins/hls-eval-plugin/src/Ide/Plugin/Eval/Rules.hs b/plugins/hls-eval-plugin/src/Ide/Plugin/Eval/Rules.hs index b23adc7b21..1a9c94c98b 100644 --- a/plugins/hls-eval-plugin/src/Ide/Plugin/Eval/Rules.hs +++ b/plugins/hls-eval-plugin/src/Ide/Plugin/Eval/Rules.hs @@ -2,9 +2,10 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RecordWildCards #-} + -- To avoid warning "Pattern match has inaccessible right hand side" {-# OPTIONS_GHC -Wno-overlapping-patterns #-} -module Ide.Plugin.Eval.Rules (GetEvalComments(..), rules,queueForEvaluation) where +module Ide.Plugin.Eval.Rules (GetEvalComments(..), rules,queueForEvaluation, Log) where import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.HashSet (HashSet) @@ -32,20 +33,29 @@ import Development.IDE.Core.Shake (IsIdeGlobal, addIdeGlobal, getIdeGlobalAction, getIdeGlobalState) +import qualified Development.IDE.Core.Shake as Shake import Development.IDE.GHC.Compat import qualified Development.IDE.GHC.Compat as SrcLoc import qualified Development.IDE.GHC.Compat.Util as FastString import Development.IDE.Graph (alwaysRerun) +import Development.IDE.Types.Logger (Pretty (pretty), + Recorder, WithPriority, + cmapWithPrio) #if MIN_VERSION_ghc(9,2,0) import GHC.Parser.Annotation #endif import Ide.Plugin.Eval.Types +newtype Log = LogShake Shake.Log deriving Show + +instance Pretty Log where + pretty = \case + LogShake shakeLog -> pretty shakeLog -rules :: Rules () -rules = do - evalParsedModuleRule - redefinedNeedsCompilation +rules :: Recorder (WithPriority Log) -> Rules () +rules recorder = do + evalParsedModuleRule recorder + redefinedNeedsCompilation recorder addIdeGlobal . EvaluatingVar =<< liftIO(newIORef mempty) newtype EvaluatingVar = EvaluatingVar (IORef (HashSet NormalizedFilePath)) @@ -91,8 +101,8 @@ pattern RealSrcSpanAlready :: SrcLoc.RealSrcSpan -> SrcSpan pattern RealSrcSpanAlready x = SrcLoc.RealSrcSpan x Nothing #endif -evalParsedModuleRule :: Rules () -evalParsedModuleRule = defineEarlyCutoff $ RuleNoDiagnostics $ \GetEvalComments nfp -> do +evalParsedModuleRule :: Recorder (WithPriority Log) -> Rules () +evalParsedModuleRule recorder = defineEarlyCutoff (cmapWithPrio LogShake recorder) $ RuleNoDiagnostics $ \GetEvalComments nfp -> do (pm, posMap) <- useWithStale_ GetParsedModuleWithComments nfp let comments = foldMap (\case L (RealSrcSpanAlready real) bdy @@ -123,8 +133,8 @@ evalParsedModuleRule = defineEarlyCutoff $ RuleNoDiagnostics $ \GetEvalComments -- This will ensure that the modules are loaded with linkables -- and the interactive session won't try to compile them on the fly, -- leading to much better performance of the evaluate code lens -redefinedNeedsCompilation :: Rules () -redefinedNeedsCompilation = defineEarlyCutoff $ RuleWithCustomNewnessCheck (<=) $ \NeedsCompilation f -> do +redefinedNeedsCompilation :: Recorder (WithPriority Log) -> Rules () +redefinedNeedsCompilation recorder = defineEarlyCutoff (cmapWithPrio LogShake recorder) $ RuleWithCustomNewnessCheck (<=) $ \NeedsCompilation f -> do alwaysRerun EvaluatingVar var <- getIdeGlobalAction diff --git a/plugins/hls-eval-plugin/test/Main.hs b/plugins/hls-eval-plugin/test/Main.hs index 36c0feb951..2830815fe7 100644 --- a/plugins/hls-eval-plugin/test/Main.hs +++ b/plugins/hls-eval-plugin/test/Main.hs @@ -30,7 +30,7 @@ main :: IO () main = defaultTestRunner tests evalPlugin :: PluginDescriptor IdeState -evalPlugin = Eval.descriptor "eval" +evalPlugin = Eval.descriptor mempty "eval" tests :: TestTree tests = diff --git a/plugins/hls-explicit-imports-plugin/src/Ide/Plugin/ExplicitImports.hs b/plugins/hls-explicit-imports-plugin/src/Ide/Plugin/ExplicitImports.hs index 7a14519904..6f42430748 100644 --- a/plugins/hls-explicit-imports-plugin/src/Ide/Plugin/ExplicitImports.hs +++ b/plugins/hls-explicit-imports-plugin/src/Ide/Plugin/ExplicitImports.hs @@ -2,6 +2,7 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} @@ -13,6 +14,7 @@ module Ide.Plugin.ExplicitImports , descriptorForModules , extractMinimalImports , within + , Log(..) ) where import Control.DeepSeq @@ -29,8 +31,10 @@ import qualified Data.Text as T import Development.IDE hiding (pluginHandlers, pluginRules) import Development.IDE.Core.PositionMapping +import qualified Development.IDE.Core.Shake as Shake import Development.IDE.GHC.Compat import Development.IDE.Graph.Classes +import Development.IDE.Types.Logger as Logger (Pretty (pretty)) import GHC.Generics (Generic) import Ide.PluginUtils (mkLspCommand) import Ide.Types @@ -40,24 +44,33 @@ import Language.LSP.Types importCommandId :: CommandId importCommandId = "ImportLensCommand" +newtype Log + = LogShake Shake.Log + deriving Show + +instance Pretty Log where + pretty = \case + LogShake log -> pretty log + -- | The "main" function of a plugin -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor = +descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState +descriptor recorder = -- (almost) no one wants to see an explicit import list for Prelude - descriptorForModules (/= moduleName pRELUDE) + descriptorForModules recorder (/= moduleName pRELUDE) descriptorForModules - :: (ModuleName -> Bool) + :: Recorder (WithPriority Log) + -> (ModuleName -> Bool) -- ^ Predicate to select modules that will be annotated -> PluginId -> PluginDescriptor IdeState -descriptorForModules pred plId = +descriptorForModules recorder pred plId = (defaultPluginDescriptor plId) { -- This plugin provides a command handler pluginCommands = [importLensCommand], -- This plugin defines a new rule - pluginRules = minimalImportsRule, + pluginRules = minimalImportsRule recorder, pluginHandlers = mconcat [ -- This plugin provides code lenses mkPluginHandler STextDocumentCodeLens $ lensProvider pred @@ -185,8 +198,8 @@ exportedModuleStrings ParsedModule{pm_parsed_source = L _ HsModule{..}} = map prettyPrint exports exportedModuleStrings _ = [] -minimalImportsRule :: Rules () -minimalImportsRule = define $ \MinimalImports nfp -> do +minimalImportsRule :: Recorder (WithPriority Log) -> Rules () +minimalImportsRule recorder = define (cmapWithPrio LogShake recorder) $ \MinimalImports nfp -> do -- Get the typechecking artifacts from the module tmr <- use TypeCheck nfp -- We also need a GHC session with all the dependencies diff --git a/plugins/hls-explicit-imports-plugin/test/Main.hs b/plugins/hls-explicit-imports-plugin/test/Main.hs index 3bf8b57fec..1395fac5e8 100644 --- a/plugins/hls-explicit-imports-plugin/test/Main.hs +++ b/plugins/hls-explicit-imports-plugin/test/Main.hs @@ -16,7 +16,7 @@ import System.FilePath ((<.>), ()) import Test.Hls explicitImportsPlugin :: PluginDescriptor IdeState -explicitImportsPlugin = ExplicitImports.descriptor "explicitImports" +explicitImportsPlugin = ExplicitImports.descriptor mempty "explicitImports" main :: IO () diff --git a/plugins/hls-hlint-plugin/src/Ide/Plugin/Hlint.hs b/plugins/hls-hlint-plugin/src/Ide/Plugin/Hlint.hs index 3f4ca1b510..a5ba0b9c2e 100644 --- a/plugins/hls-hlint-plugin/src/Ide/Plugin/Hlint.hs +++ b/plugins/hls-hlint-plugin/src/Ide/Plugin/Hlint.hs @@ -13,6 +13,7 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -Wno-orphans #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RecordWildCards #-} @@ -26,6 +27,7 @@ module Ide.Plugin.Hlint ( descriptor + , Log(..) ) where import Control.Arrow ((&&&)) import Control.Concurrent.STM @@ -109,6 +111,7 @@ import Language.LSP.Types hiding import qualified Language.LSP.Types as LSP import qualified Language.LSP.Types.Lens as LSP +import qualified Development.IDE.Core.Shake as Shake import Development.IDE.Spans.Pragmas (LineSplitTextEdits (LineSplitTextEdits), NextPragmaInfo (NextPragmaInfo), getNextPragmaInfo, @@ -122,6 +125,14 @@ import System.Environment (setEnv, import Text.Regex.TDFA.Text () -- --------------------------------------------------------------------- +newtype Log + = LogShake Shake.Log + deriving Show + +instance Pretty Log where + pretty = \case + LogShake log -> pretty log + #ifdef HLINT_ON_GHC_LIB -- Reimplementing this, since the one in Development.IDE.GHC.Compat isn't for ghc-lib pattern RealSrcSpan :: GHC.RealSrcSpan -> Maybe BufSpan -> GHC.SrcSpan @@ -133,9 +144,9 @@ pattern RealSrcSpan x y <- ((,Nothing) -> (GHC.RealSrcSpan x, y)) {-# COMPLETE RealSrcSpan, UnhelpfulSpan #-} #endif -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = (defaultPluginDescriptor plId) - { pluginRules = rules plId +descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState +descriptor recorder plId = (defaultPluginDescriptor plId) + { pluginRules = rules recorder plId , pluginCommands = [ PluginCommand "applyOne" "Apply a single hint" applyOneCmd , PluginCommand "applyAll" "Apply all hints to the file" applyAllCmd @@ -163,15 +174,15 @@ type instance RuleResult GetHlintDiagnostics = () -- | - `getIdeas` -> `getFileContents` if the hls ghc does not match the hlint default ghc -- | - The client settings have changed, to honour the `hlintOn` setting, via `getClientConfigAction` -- | - The hlint specific settings have changed, via `getHlintSettingsRule` -rules :: PluginId -> Rules () -rules plugin = do - define $ \GetHlintDiagnostics file -> do +rules :: Recorder (WithPriority Log) -> PluginId -> Rules () +rules recorder plugin = do + define (cmapWithPrio LogShake recorder) $ \GetHlintDiagnostics file -> do config <- getClientConfigAction def let hlintOn = pluginEnabledConfig plcDiagnosticsOn plugin config ideas <- if hlintOn then getIdeas file else return (Right []) return (diagnostics file ideas, Just ()) - defineNoFile $ \GetHlintSettings -> do + defineNoFile (cmapWithPrio LogShake recorder) $ \GetHlintSettings -> do (Config flags) <- getHlintConfig plugin liftIO $ argsSettings flags @@ -519,7 +530,7 @@ applyHint ide nfp mhint = liftIO $ logm $ "applyHint:apply=" ++ show commands let fp = fromNormalizedFilePath nfp (_, mbOldContent) <- liftIO $ runAction' $ getFileContents nfp - oldContent <- maybe (liftIO $ fmap T.decodeUtf8 $ BS.readFile fp) return mbOldContent + oldContent <- maybe (liftIO $ fmap T.decodeUtf8 (BS.readFile fp)) return mbOldContent modsum <- liftIO $ runAction' $ use_ GetModSummary nfp let dflags = ms_hspp_opts $ msrModSummary modsum -- Setting a environment variable with the libdir used by ghc-exactprint. diff --git a/plugins/hls-hlint-plugin/test/Main.hs b/plugins/hls-hlint-plugin/test/Main.hs index 65242266c2..b0fa0987ae 100644 --- a/plugins/hls-hlint-plugin/test/Main.hs +++ b/plugins/hls-hlint-plugin/test/Main.hs @@ -25,7 +25,7 @@ main :: IO () main = defaultTestRunner tests hlintPlugin :: PluginDescriptor IdeState -hlintPlugin = HLint.descriptor "hlint" +hlintPlugin = HLint.descriptor mempty "hlint" tests :: TestTree tests = testGroup "hlint" [ diff --git a/plugins/hls-refine-imports-plugin/src/Ide/Plugin/RefineImports.hs b/plugins/hls-refine-imports-plugin/src/Ide/Plugin/RefineImports.hs index 6e505377cc..2519ce1366 100644 --- a/plugins/hls-refine-imports-plugin/src/Ide/Plugin/RefineImports.hs +++ b/plugins/hls-refine-imports-plugin/src/Ide/Plugin/RefineImports.hs @@ -2,12 +2,13 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE DuplicateRecordFields #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeFamilies #-} -module Ide.Plugin.RefineImports (descriptor) where +module Ide.Plugin.RefineImports (descriptor, Log(..)) where import Control.Arrow (Arrow (second)) import Control.DeepSeq (rwhnf) @@ -37,7 +38,9 @@ import Development.IDE.GHC.Compat RealSrcSpan(..), getLoc, ieName, noLoc, tcg_exports, unLoc) -} +import qualified Development.IDE.Core.Shake as Shake import Development.IDE.Graph.Classes +import qualified Development.IDE.Types.Logger as Logger import GHC.Generics (Generic) import Ide.Plugin.ExplicitImports (extractMinimalImports, within) @@ -46,11 +49,17 @@ import Ide.Types import Language.LSP.Server import Language.LSP.Types +newtype Log = LogShake Shake.Log deriving Show + +instance Pretty Log where + pretty = \case + LogShake log -> pretty log + -- | plugin declaration -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId = (defaultPluginDescriptor plId) +descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState +descriptor recorder plId = (defaultPluginDescriptor plId) { pluginCommands = [refineImportCommand] - , pluginRules = refineImportsRule + , pluginRules = refineImportsRule recorder , pluginHandlers = mconcat [ -- This plugin provides code lenses mkPluginHandler STextDocumentCodeLens lensProvider @@ -163,8 +172,8 @@ newtype RefineImportsResult = RefineImportsResult instance Show RefineImportsResult where show _ = "" instance NFData RefineImportsResult where rnf = rwhnf -refineImportsRule :: Rules () -refineImportsRule = define $ \RefineImports nfp -> do +refineImportsRule :: Recorder (WithPriority Log) -> Rules () +refineImportsRule recorder = define (cmapWithPrio LogShake recorder) $ \RefineImports nfp -> do -- Get the typechecking artifacts from the module tmr <- use TypeCheck nfp -- We also need a GHC session with all the dependencies diff --git a/plugins/hls-refine-imports-plugin/test/Main.hs b/plugins/hls-refine-imports-plugin/test/Main.hs index 18b021b29d..bbd1ad6958 100644 --- a/plugins/hls-refine-imports-plugin/test/Main.hs +++ b/plugins/hls-refine-imports-plugin/test/Main.hs @@ -24,7 +24,7 @@ main = defaultTestRunner $ ] refineImportsPlugin :: PluginDescriptor IdeState -refineImportsPlugin = RefineImports.descriptor "refineImports" +refineImportsPlugin = RefineImports.descriptor mempty "refineImports" -- code action tests diff --git a/plugins/hls-tactics-plugin/src/Ide/Plugin/Tactic.hs b/plugins/hls-tactics-plugin/src/Ide/Plugin/Tactic.hs index de93d03ed0..cf326ee653 100644 --- a/plugins/hls-tactics-plugin/src/Ide/Plugin/Tactic.hs +++ b/plugins/hls-tactics-plugin/src/Ide/Plugin/Tactic.hs @@ -1,5 +1,5 @@ -- | A plugin that uses tactics to synthesize code -module Ide.Plugin.Tactic (descriptor) where +module Ide.Plugin.Tactic (descriptor, Log(..)) where import Wingman.Plugin diff --git a/plugins/hls-tactics-plugin/src/Wingman/LanguageServer.hs b/plugins/hls-tactics-plugin/src/Wingman/LanguageServer.hs index 104de36d50..ed896a99eb 100644 --- a/plugins/hls-tactics-plugin/src/Wingman/LanguageServer.hs +++ b/plugins/hls-tactics-plugin/src/Wingman/LanguageServer.hs @@ -36,7 +36,7 @@ import Development.IDE.Core.UseStale import Development.IDE.GHC.Compat hiding (empty) import qualified Development.IDE.GHC.Compat.Util as FastString import Development.IDE.GHC.Error (realSrcSpanToRange) -import Development.IDE.GHC.ExactPrint +import Development.IDE.GHC.ExactPrint hiding (LogShake, Log) import Development.IDE.Graph (Action, RuleResult, Rules, action) import Development.IDE.Graph.Classes (Hashable, NFData) import Development.IDE.Spans.LocalBindings (Bindings, getDefiningBindings) @@ -63,8 +63,18 @@ import Wingman.Judgements.Theta import Wingman.Range import Wingman.StaticPlugin (pattern WingmanMetaprogram, pattern MetaprogramSyntax) import Wingman.Types +import Development.IDE.Types.Logger (Recorder, cmapWithPrio, WithPriority, Pretty (pretty)) +import qualified Development.IDE.Core.Shake as Shake +newtype Log + = LogShake Shake.Log + deriving Show + +instance Pretty Log where + pretty = \case + LogShake shakeLog -> pretty shakeLog + tacticDesc :: T.Text -> T.Text tacticDesc name = "fill the hole using the " <> name <> " tactic" @@ -550,9 +560,9 @@ instance NFData GetMetaprograms type instance RuleResult GetMetaprograms = [(Tracked 'Current RealSrcSpan, T.Text)] -wingmanRules :: PluginId -> Rules () -wingmanRules plId = do - define $ \WriteDiagnostics nfp -> +wingmanRules :: Recorder (WithPriority Log) -> PluginId -> Rules () +wingmanRules recorder plId = do + define (cmapWithPrio LogShake recorder) $ \WriteDiagnostics nfp -> usePropertyAction #hole_severity plId properties >>= \case Nothing -> pure (mempty, Just ()) Just severity -> @@ -585,7 +595,7 @@ wingmanRules plId = do , Just () ) - defineNoDiagnostics $ \GetMetaprograms nfp -> do + defineNoDiagnostics (cmapWithPrio LogShake recorder) $ \GetMetaprograms nfp -> do TrackedStale tcg tcg_map <- fmap tmrTypechecked <$> useWithStale_ TypeCheck nfp let scrutinees = traverse (metaprogramQ . tcg_binds) tcg return $ Just $ flip mapMaybe scrutinees $ \aged@(unTrack -> (ss, program)) -> do diff --git a/plugins/hls-tactics-plugin/src/Wingman/Plugin.hs b/plugins/hls-tactics-plugin/src/Wingman/Plugin.hs index d01bdbbc92..6473a725d5 100644 --- a/plugins/hls-tactics-plugin/src/Wingman/Plugin.hs +++ b/plugins/hls-tactics-plugin/src/Wingman/Plugin.hs @@ -9,20 +9,29 @@ import Prelude hiding (span) import Wingman.AbstractLSP import Wingman.AbstractLSP.TacticActions (makeTacticInteraction) import Wingman.EmptyCase -import Wingman.LanguageServer +import Wingman.LanguageServer hiding (Log) +import qualified Wingman.LanguageServer as WingmanLanguageServer import Wingman.LanguageServer.Metaprogram (hoverProvider) import Wingman.StaticPlugin +import Development.IDE.Types.Logger (Recorder, cmapWithPrio, WithPriority, Pretty (pretty)) +newtype Log + = LogWingmanLanguageServer WingmanLanguageServer.Log + deriving Show -descriptor :: PluginId -> PluginDescriptor IdeState -descriptor plId +instance Pretty Log where + pretty = \case + LogWingmanLanguageServer log -> pretty log + +descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState +descriptor recorder plId = installInteractions ( emptyCaseInteraction : fmap makeTacticInteraction [minBound .. maxBound] ) $ (defaultPluginDescriptor plId) { pluginHandlers = mkPluginHandler STextDocumentHover hoverProvider - , pluginRules = wingmanRules plId + , pluginRules = wingmanRules (cmapWithPrio LogWingmanLanguageServer recorder) plId , pluginConfigDescriptor = defaultConfigDescriptor { configCustomConfig = mkCustomConfig properties diff --git a/plugins/hls-tactics-plugin/test/Utils.hs b/plugins/hls-tactics-plugin/test/Utils.hs index 08ecb83c2e..9f124efdb6 100644 --- a/plugins/hls-tactics-plugin/test/Utils.hs +++ b/plugins/hls-tactics-plugin/test/Utils.hs @@ -35,7 +35,7 @@ import Wingman.Types plugin :: PluginDescriptor IdeState -plugin = Tactic.descriptor "tactics" +plugin = Tactic.descriptor mempty "tactics" ------------------------------------------------------------------------------ -- | Get a range at the given line and column corresponding to having nothing diff --git a/src/Ide/Arguments.hs b/src/Ide/Arguments.hs index b94463b841..eb87bee30c 100644 --- a/src/Ide/Arguments.hs +++ b/src/Ide/Arguments.hs @@ -151,3 +151,4 @@ haskellLanguageServerVersion = do <> " (GHC: " <> VERSION_ghc <> ") (PATH: " <> path <> ")" <> gitHashSection + diff --git a/src/Ide/Main.hs b/src/Ide/Main.hs index 3925c985a7..73acc2a922 100644 --- a/src/Ide/Main.hs +++ b/src/Ide/Main.hs @@ -5,26 +5,29 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} -module Ide.Main(defaultMain, runLspMode) where +module Ide.Main(defaultMain, runLspMode, Log(..)) where import Control.Monad.Extra import qualified Data.Aeson.Encode.Pretty as A import qualified Data.ByteString.Lazy.Char8 as LBS +import Data.Coerce (coerce) import Data.Default import Data.List (sort) +import Data.Text (Text) import qualified Data.Text as T -import Development.IDE.Core.Rules +import Development.IDE.Core.Rules hiding (Log, logToPriority) import Development.IDE.Core.Tracing (withTelemetryLogger) import Development.IDE.Graph (ShakeOptions (shakeThreads)) import Development.IDE.Main (isLSP) -import qualified Development.IDE.Main as Main +import qualified Development.IDE.Main as IDEMain import qualified Development.IDE.Session as Session import Development.IDE.Types.Logger as G import qualified Development.IDE.Types.Options as Ghcide +import qualified HIE.Bios.Environment as HieBios import HIE.Bios.Types -import qualified HIE.Bios.Environment as HieBios import Ide.Arguments import Ide.Logger import Ide.Plugin.ConfigUtils (pluginsToDefaultConfig, @@ -32,15 +35,31 @@ import Ide.Plugin.ConfigUtils (pluginsToDefaultConfig, import Ide.Types (IdePlugins, PluginId (PluginId), ipMap) import Ide.Version -import qualified Language.LSP.Server as LSP import System.Directory import qualified System.Directory.Extra as IO import System.FilePath -import System.IO -import qualified System.Log.Logger as L -defaultMain :: Arguments -> IdePlugins IdeState -> IO () -defaultMain args idePlugins = do +data Log + = LogVersion !String + | LogDirectory !FilePath + | LogLspStart !GhcideArguments ![PluginId] + | LogIDEMain IDEMain.Log + deriving Show + +instance Pretty Log where + pretty log = case log of + LogVersion version -> pretty version + LogDirectory path -> "Directory:" <+> pretty path + LogLspStart ghcideArgs pluginIds -> + nest 2 $ + vsep + [ "Starting (haskell-language-server) LSP server..." + , viaShow ghcideArgs + , "PluginIds:" <+> pretty (coerce @_ @[Text] pluginIds) ] + LogIDEMain iDEMainLog -> pretty iDEMainLog + +defaultMain :: Recorder (WithPriority Log) -> Arguments -> IdePlugins IdeState -> IO () +defaultMain recorder args idePlugins = do -- WARNING: If you write to stdout before runLanguageServer -- then the language server will not work @@ -72,8 +91,8 @@ defaultMain args idePlugins = do Ghcide ghcideArgs -> do {- see WARNING above -} - hPutStrLn stderr hlsVer - runLspMode ghcideArgs idePlugins + logWith recorder Info $ LogVersion hlsVer + runLspMode recorder ghcideArgs idePlugins VSCodeExtensionSchemaMode -> do LBS.putStrLn $ A.encodePretty $ pluginsToVSCodeExtensionSchema idePlugins @@ -101,25 +120,22 @@ hlsLogger = G.Logger $ \pri txt -> -- --------------------------------------------------------------------- -runLspMode :: GhcideArguments -> IdePlugins IdeState -> IO () -runLspMode ghcideArgs@GhcideArguments{..} idePlugins = withTelemetryLogger $ \telemetryLogger -> do +runLspMode :: Recorder (WithPriority Log) -> GhcideArguments -> IdePlugins IdeState -> IO () +runLspMode recorder ghcideArgs@GhcideArguments{..} idePlugins = withTelemetryLogger $ \telemetryLogger -> do + let log = logWith recorder whenJust argsCwd IO.setCurrentDirectory dir <- IO.getCurrentDirectory - LSP.setupLogger argsLogFile ["hls", "hie-bios"] - $ if argsDebugOn then L.DEBUG else L.INFO + log Info $ LogDirectory dir when (isLSP argsCommand) $ do - hPutStrLn stderr "Starting (haskell-language-server)LSP server..." - hPutStrLn stderr $ " with arguments: " <> show ghcideArgs - hPutStrLn stderr $ " with plugins: " <> show (map fst $ ipMap idePlugins) - hPutStrLn stderr $ " in directory: " <> dir - - Main.defaultMain def - { Main.argCommand = argsCommand - , Main.argsHlsPlugins = idePlugins - , Main.argsLogger = pure hlsLogger <> pure telemetryLogger - , Main.argsThreads = if argsThreads == 0 then Nothing else Just $ fromIntegral argsThreads - , Main.argsIdeOptions = \_config sessionLoader -> + log Info $ LogLspStart ghcideArgs (map fst $ ipMap idePlugins) + + IDEMain.defaultMain (cmapWithPrio LogIDEMain recorder) (IDEMain.defaultArguments (cmapWithPrio LogIDEMain recorder) hlsLogger) + { IDEMain.argCommand = argsCommand + , IDEMain.argsHlsPlugins = idePlugins + , IDEMain.argsLogger = pure hlsLogger <> pure telemetryLogger + , IDEMain.argsThreads = if argsThreads == 0 then Nothing else Just $ fromIntegral argsThreads + , IDEMain.argsIdeOptions = \_config sessionLoader -> let defOptions = Ghcide.defaultIdeOptions sessionLoader in defOptions { Ghcide.optShakeProfiling = argsShakeProfiling diff --git a/stack-8.6.5.yaml b/stack-8.6.5.yaml index fa41b1f0a8..cc7df70d98 100644 --- a/stack-8.6.5.yaml +++ b/stack-8.6.5.yaml @@ -80,6 +80,7 @@ extra-deps: - optparse-applicative-0.15.1.0 - ormolu-0.1.4.1 - parser-combinators-1.2.1 + - prettyprinter-1.7.1 - primitive-0.7.1.0 - refinery-0.4.0.0 - regex-base-0.94.0.0 diff --git a/stack-8.8.4.yaml b/stack-8.8.4.yaml index d2ccd76c49..a7578c04a6 100644 --- a/stack-8.8.4.yaml +++ b/stack-8.8.4.yaml @@ -65,6 +65,7 @@ extra-deps: - monad-dijkstra-0.1.1.2 - opentelemetry-0.6.1 - opentelemetry-extra-0.6.1 + - prettyprinter-1.7.1 - refinery-0.4.0.0 - retrie-1.1.0.0 - semigroups-0.18.5 From 2b9f18978775881cd44699184090a847b6f6c027 Mon Sep 17 00:00:00 2001 From: Michael Peyton Jones Date: Mon, 21 Feb 2022 04:04:39 +0000 Subject: [PATCH 18/20] Delete the Telemetry log level (#2727) It's a bit non-standard, and moreover it's entirely dead. --- ghcide/src/Development/IDE/Types/Logger.hs | 10 ++-------- src/Ide/Main.hs | 1 - 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/ghcide/src/Development/IDE/Types/Logger.hs b/ghcide/src/Development/IDE/Types/Logger.hs index 9f696210e2..da0912861d 100644 --- a/ghcide/src/Development/IDE/Types/Logger.hs +++ b/ghcide/src/Development/IDE/Types/Logger.hs @@ -9,7 +9,7 @@ module Development.IDE.Types.Logger ( Priority(..) , Logger(..) , Recorder(..) - , logError, logWarning, logInfo, logDebug, logTelemetry + , logError, logWarning, logInfo, logDebug , noLogging , WithPriority(..) , logWith @@ -56,8 +56,7 @@ import UnliftIO (MonadUnliftIO, displayException, data Priority -- Don't change the ordering of this type or you will mess up the Ord -- instance - = Telemetry -- ^ Events that are useful for gathering user metrics. - | Debug -- ^ Verbose debug logging. + = Debug -- ^ Verbose debug logging. | Info -- ^ Useful information in case an error has to be understood. | Warning -- ^ These error messages should not occur in a expected usage, and @@ -88,10 +87,6 @@ logInfo x = logPriority x Info logDebug :: Logger -> T.Text -> IO () logDebug x = logPriority x Debug -logTelemetry :: Logger -> T.Text -> IO () -logTelemetry x = logPriority x Telemetry - - noLogging :: Logger noLogging = Logger $ \_ _ -> return () @@ -208,7 +203,6 @@ makeDefaultHandleRecorder columns minPriority lock handle = do priorityToHsLoggerPriority :: Priority -> HsLogger.Priority priorityToHsLoggerPriority = \case - Telemetry -> HsLogger.INFO Debug -> HsLogger.DEBUG Info -> HsLogger.INFO Warning -> HsLogger.WARNING diff --git a/src/Ide/Main.hs b/src/Ide/Main.hs index 73acc2a922..b50d4f0ce0 100644 --- a/src/Ide/Main.hs +++ b/src/Ide/Main.hs @@ -112,7 +112,6 @@ defaultMain recorder args idePlugins = do hlsLogger :: G.Logger hlsLogger = G.Logger $ \pri txt -> case pri of - G.Telemetry -> logm (T.unpack txt) G.Debug -> debugm (T.unpack txt) G.Info -> logm (T.unpack txt) G.Warning -> warningm (T.unpack txt) From 0590ed89b07d8979d647782b3cb2008b7ef9af6f Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Wed, 23 Feb 2022 08:51:03 -0500 Subject: [PATCH 19/20] Wall and 9.2 fix --- .../hls-change-type-signature-plugin.cabal | 3 +- .../src/Ide/Plugin/ChangeTypeSignature.hs | 82 ++++++------------- .../test/Main.hs | 1 - 3 files changed, 29 insertions(+), 57 deletions(-) diff --git a/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal b/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal index bd3fe7e5d1..64bc9b8a4a 100644 --- a/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal +++ b/plugins/hls-change-type-signature-plugin/hls-change-type-signature-plugin.cabal @@ -31,6 +31,7 @@ library , transformers , unordered-containers + ghc-options: -Wall default-language: Haskell2010 default-extensions: ConstraintKinds @@ -48,7 +49,7 @@ test-suite tests default-language: Haskell2010 hs-source-dirs: test main-is: Main.hs - ghc-options: -threaded -rtsopts -with-rtsopts=-N -fno-ignore-asserts + ghc-options: -threaded -rtsopts -with-rtsopts=-N -fno-ignore-asserts -Wall build-depends: , base >=4.12 && < 5 , filepath diff --git a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs index 1f1e800d3d..52fcd1d5ab 100644 --- a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs +++ b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs @@ -6,60 +6,34 @@ module Ide.Plugin.ChangeTypeSignature (descriptor , errorMessageRegexes ) where -import Control.Monad (forM, guard, join) -import Control.Monad.IO.Class (MonadIO (liftIO)) -import Control.Monad.Trans.Except (ExceptT) -import Data.Char (isAlpha, isAlphaNum, - isNumber, isPunctuation) -import Data.Foldable (asum, traverse_) -import qualified Data.HashMap.Strict as Map -import Data.List (find, nub) -import qualified Data.List.NonEmpty as NE -import Data.Maybe (isJust, isNothing, - listToMaybe, mapMaybe) -import Data.Text (Text) -import qualified Data.Text as T -import Development.IDE.Core.RuleTypes (GetBindings (GetBindings), - GetParsedModule (GetParsedModule)) -import Development.IDE.Core.Service (IdeState, ideLogger, - runAction) -import Development.IDE.Core.Shake (use) +import Control.Monad (guard) +import Control.Monad.IO.Class (MonadIO (liftIO)) +import Control.Monad.Trans.Except (ExceptT) +import Data.Foldable (asum) +import qualified Data.HashMap.Strict as Map +import Data.Maybe (mapMaybe) +import Data.Text (Text) +import qualified Data.Text as T +import Development.IDE (realSrcSpanToRange) +import Development.IDE.Core.RuleTypes (GetParsedModule (GetParsedModule)) +import Development.IDE.Core.Service (IdeState, runAction) +import Development.IDE.Core.Shake (use) import Development.IDE.GHC.Compat -import Development.IDE.GHC.Error (realSrcSpanToRange) -import Development.IDE.GHC.Util (prettyPrint, - unsafePrintSDoc) -import Development.IDE.Spans.LocalBindings (Bindings, getFuzzyScope) -import Development.IDE.Types.Location (Range (Range)) -import Development.IDE.Types.Logger (logDebug, logInfo) -import Generics.SYB (extQ, mkQ, something, - somewhere) -import Ide.PluginUtils (getNormalizedFilePath, - handleMaybeM, response) -import Ide.Types (PluginDescriptor (..), - PluginId, - PluginMethodHandler, - defaultPluginDescriptor, - mkPluginHandler) -import Language.LSP.Types (CodeAction (..), - CodeActionContext (CodeActionContext), - CodeActionKind (CodeActionQuickFix, CodeActionUnknown), - CodeActionParams (..), - Command, Diagnostic (..), - List (..), - Method (TextDocumentCodeAction), - NormalizedFilePath, - SMethod (..), - TextDocumentIdentifier (TextDocumentIdentifier), - TextEdit (TextEdit), Uri, - WorkspaceEdit (WorkspaceEdit), - type (|?) (InR)) -import Text.Regex.TDFA (AllTextMatches (getAllTextMatches), - (=~)) +import Development.IDE.GHC.Util (prettyPrint) +import Generics.SYB (extQ, something) +import Ide.PluginUtils (getNormalizedFilePath, + handleMaybeM, response) +import Ide.Types (PluginDescriptor (..), + PluginId, PluginMethodHandler, + defaultPluginDescriptor, + mkPluginHandler) +import Language.LSP.Types +import Text.Regex.TDFA ((=~)) descriptor :: PluginId -> PluginDescriptor IdeState descriptor plId = (defaultPluginDescriptor plId) { pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionHandler } -codeActionHandler :: PluginMethodHandler IdeState TextDocumentCodeAction +codeActionHandler :: PluginMethodHandler IdeState 'TextDocumentCodeAction codeActionHandler ideState plId CodeActionParams {_textDocument = TextDocumentIdentifier uri, _context = CodeActionContext (List diags) _, _range} = response $ do nfp <- getNormalizedFilePath plId (TextDocumentIdentifier uri) -- for changing top-level bindings signatures @@ -83,8 +57,6 @@ type DeclName = Text type ExpectedSig = Text -- | The signature provided by GHC Error Message (Actual type) type ActualSig = Text --- | The signature defined by the user -type DefinedSig = Text -- | DataType that encodes the necessary information for changing a type signature data ChangeSignature = ChangeSignature { @@ -119,11 +91,11 @@ diagnosticToChangeSig decls diagnostic = do -- | If a diagnostic has the proper message create a ChangeSignature from it matchingDiagnostic :: Diagnostic -> Maybe (ExpectedSig, ActualSig, DeclName) -matchingDiagnostic diag@Diagnostic{_message} = asum $ map (unwrapMatch . (=~) _message) errorMessageRegexes +matchingDiagnostic Diagnostic{_message} = asum $ map (unwrapMatch . (=~) _message) errorMessageRegexes where unwrapMatch :: (Text, Text, Text, [Text]) -> Maybe (ExpectedSig, ActualSig, DeclName) -- due to using (.|\n) in regex we have to drop the erroneous, but necessary ("." doesn't match newlines), match - unwrapMatch (_, _, _, [exp, act, _, name]) = Just (exp, act, name) + unwrapMatch (_, _, _, [expect, actual, _, name]) = Just (expect, actual, name) unwrapMatch _ = Nothing -- | List of regexes that match various Error Messages @@ -139,7 +111,7 @@ findSigLocOfStringDecl :: SigName => [LHsDecl GhcPs] -> ExpectedSig -> String -> findSigLocOfStringDecl decls expectedType declName = something (const Nothing `extQ` findSig `extQ` findLocalSig) decls where -- search for Top Level Signatures - findSig :: GenLocated SrcSpan (HsDecl GhcPs) -> Maybe RealSrcSpan + findSig :: LHsDecl GhcPs -> Maybe RealSrcSpan findSig = \case L (locA -> (RealSrcSpan rss _)) (SigD _ sig) -> case sig of ts@(TypeSig _ idsSig _) -> isMatch ts idsSig >> pure rss @@ -147,7 +119,7 @@ findSigLocOfStringDecl decls expectedType declName = something (const Nothing `e _ -> Nothing -- search for Local Signatures - findLocalSig :: GenLocated SrcSpan (Sig GhcPs) -> Maybe RealSrcSpan + findLocalSig :: LSig GhcPs -> Maybe RealSrcSpan findLocalSig = \case (L (locA -> (RealSrcSpan rss _)) ts@(TypeSig _ idsSig _)) -> isMatch ts idsSig >> pure rss _ -> Nothing diff --git a/plugins/hls-change-type-signature-plugin/test/Main.hs b/plugins/hls-change-type-signature-plugin/test/Main.hs index dddd5d3b24..2cfb7b35c4 100644 --- a/plugins/hls-change-type-signature-plugin/test/Main.hs +++ b/plugins/hls-change-type-signature-plugin/test/Main.hs @@ -1,7 +1,6 @@ module Main where import Data.Either (rights) -import Data.Maybe (mapMaybe) import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.IO as TIO From b166dbf02bf0e9fd91647c5482d26abaa172a3a9 Mon Sep 17 00:00:00 2001 From: Nick Suchecki Date: Wed, 23 Feb 2022 20:14:48 -0500 Subject: [PATCH 20/20] Remove unneeded comments/code --- .../src/Ide/Plugin/ChangeTypeSignature.hs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs index 52fcd1d5ab..ff86652710 100644 --- a/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs +++ b/plugins/hls-change-type-signature-plugin/src/Ide/Plugin/ChangeTypeSignature.hs @@ -34,14 +34,10 @@ descriptor :: PluginId -> PluginDescriptor IdeState descriptor plId = (defaultPluginDescriptor plId) { pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionHandler } codeActionHandler :: PluginMethodHandler IdeState 'TextDocumentCodeAction -codeActionHandler ideState plId CodeActionParams {_textDocument = TextDocumentIdentifier uri, _context = CodeActionContext (List diags) _, _range} = response $ do +codeActionHandler ideState plId CodeActionParams {_textDocument = TextDocumentIdentifier uri, _context = CodeActionContext (List diags) _} = response $ do nfp <- getNormalizedFilePath plId (TextDocumentIdentifier uri) - -- for changing top-level bindings signatures decls <- getDecls ideState nfp - let actions = mapMaybe (generateAction uri decls) diags - - -- liftIO $ logInfo (ideLogger ideState) $ T.pack $ show binds pure $ List actions getDecls :: MonadIO m => IdeState -> NormalizedFilePath -> ExceptT String m [LHsDecl GhcPs]