text:
{-# LANGUAGE FlexibleContexts          #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE ScopedTypeVariables       #-}
{-# LANGUAGE TupleSections             #-}
{-# LANGUAGE PartialTypeSignatures     #-}
{-# LANGUAGE OverloadedStrings         #-}

-- | This module contains the functions that convert /from/ descriptions of
--   symbols, names and types (over freshly parsed /bare/ Strings),
--   /to/ representations connected to GHC 'Var's, 'Name's, and 'Type's.
--   The actual /representations/ of bare and real (refinement) types are all
--   in 'RefType' -- they are different instances of 'RType'.

module Language.Haskell.Liquid.Bare (
  -- * Creating a TargetSpec
  -- $creatingTargetSpecs
    makeTargetSpec

  -- * Loading and Saving lifted specs from/to disk
  , loadLiftedSpec
  , saveLiftedSpec
  ) where

import           Prelude                                    hiding (error)
import           Optics
import           Control.Monad                              (forM)
import           Control.Applicative                        ((<|>))
import qualified Control.Exception                          as Ex
import qualified Data.Binary                                as B
import qualified Data.Maybe                                 as Mb
import qualified Data.List                                  as L
import qualified Data.HashMap.Strict                        as M
import qualified Data.HashSet                               as S
import           Text.PrettyPrint.HughesPJ                  hiding (first, (<>)) -- (text, (<+>))
import           System.FilePath                            (dropExtension)
import           System.Directory                           (doesFileExist)
import           System.Console.CmdArgs.Verbosity           (whenLoud)
import           Language.Fixpoint.Utils.Files              as Files
import           Language.Fixpoint.Misc                     as Misc
import           Language.Fixpoint.Types                    hiding (dcFields, DataDecl, Error, panic)
import qualified Language.Fixpoint.Types                    as F
import qualified Language.Haskell.Liquid.Misc               as Misc -- (nubHashOn)
import qualified Liquid.GHC.Misc           as GM
import qualified Liquid.GHC.API            as Ghc
import           Liquid.GHC.Types          (StableName)
import           Language.Haskell.Liquid.Types
import           Language.Haskell.Liquid.WiredIn
import qualified Language.Haskell.Liquid.Measure            as Ms
import qualified Language.Haskell.Liquid.Bare.Types         as Bare
import qualified Language.Haskell.Liquid.Bare.Resolve       as Bare
import qualified Language.Haskell.Liquid.Bare.DataType      as Bare
import           Language.Haskell.Liquid.Bare.Elaborate
import qualified Language.Haskell.Liquid.Bare.Expand        as Bare
import qualified Language.Haskell.Liquid.Bare.Measure       as Bare
import qualified Language.Haskell.Liquid.Bare.Plugged       as Bare
import qualified Language.Haskell.Liquid.Bare.Axiom         as Bare
import qualified Language.Haskell.Liquid.Bare.ToBare        as Bare
import qualified Language.Haskell.Liquid.Bare.Class         as Bare
import qualified Language.Haskell.Liquid.Bare.Check         as Bare
import qualified Language.Haskell.Liquid.Bare.Laws          as Bare
import qualified Language.Haskell.Liquid.Bare.Typeclass     as Bare
import qualified Language.Haskell.Liquid.Transforms.CoreToLogic as CoreToLogic
import           Control.Arrow                    (second)
import Data.Hashable (Hashable)
import qualified Language.Haskell.Liquid.Bare.Slice as Dg

--------------------------------------------------------------------------------
-- | De/Serializing Spec files
--------------------------------------------------------------------------------

loadLiftedSpec :: Config -> FilePath -> IO (Maybe Ms.BareSpec)
loadLiftedSpec cfg srcF
  | noLiftedImport cfg = putStrLn "No LIFTED Import" >> return Nothing
  | otherwise          = do
      let specF = extFileName BinSpec srcF
      ex  <- doesFileExist specF
      whenLoud $ putStrLn $ "Loading Binary Lifted Spec: " ++ specF ++ " " ++ "for source-file: " ++ show srcF ++ " " ++ show ex
      lSp <- if ex
               then Just <$> B.decodeFile specF
               else {- warnMissingLiftedSpec srcF specF >> -} return Nothing
      Ex.evaluate lSp

-- warnMissingLiftedSpec :: FilePath -> FilePath -> IO ()
-- warnMissingLiftedSpec srcF specF = do
--   incDir <- Misc.getIncludeDir
--   unless (Misc.isIncludeFile incDir srcF)
--     $ Ex.throw (errMissingSpec srcF specF)

saveLiftedSpec :: FilePath -> Ms.BareSpec -> IO ()
saveLiftedSpec srcF lspec = do
  ensurePath specF
  B.encodeFile specF lspec
  -- print (errorP "DIE" "HERE" :: String)
  where
    specF = extFileName BinSpec srcF

{- $creatingTargetSpecs

/Liquid Haskell/ operates on 'TargetSpec's, so this module provides a single function called
'makeTargetSpec' to produce a 'TargetSpec', alongside the 'LiftedSpec'. The former will be used by
functions like 'liquid' or 'liquidOne' to verify our program is correct, the latter will be serialised
to disk so that we can retrieve it later without having to re-check the relevant Haskell file.
-}

-- | 'makeTargetSpec' constructs the 'TargetSpec' and then validates it. Upon success, the 'TargetSpec'
-- and the 'LiftedSpec' are returned. We perform error checking in \"two phases\": during the first phase,
-- we check for errors and warnings in the input 'BareSpec' and the dependencies. During this phase we ideally
-- want to short-circuit in case the validation failure is found in one of the dependencies (to avoid
-- printing potentially endless failures).
-- The second phase involves creating the 'TargetSpec', and returning either the full list of diagnostics
-- (errors and warnings) in case things went wrong, or the final 'TargetSpec' and 'LiftedSpec' together
-- with a list of 'Warning's, which shouldn't abort the compilation (modulo explicit request from the user,
-- to treat warnings and errors).
makeTargetSpec :: Config
               -> LogicMap
               -> TargetSrc
               -> BareSpec
               -> TargetDependencies
               -> Ghc.TcRn (Either Diagnostics ([Warning], TargetSpec, LiftedSpec))
makeTargetSpec cfg lmap targetSrc bareSpec dependencies = do
  let targDiagnostics     = Bare.checkTargetSrc cfg targetSrc
  let depsDiagnostics     = mapM (uncurry Bare.checkBareSpec) legacyDependencies
  let bareSpecDiagnostics = Bare.checkBareSpec (giTargetMod targetSrc) legacyBareSpec
  case targDiagnostics >> depsDiagnostics >> bareSpecDiagnostics of
   Left d | noErrors d -> secondPhase (allWarnings d)
   Left d              -> return $ Left d
   Right ()            -> secondPhase mempty
  where
    secondPhase :: [Warning] -> Ghc.TcRn (Either Diagnostics ([Warning], TargetSpec, LiftedSpec))
    secondPhase phaseOneWarns = do

      -- we should be able to setContext regardless of whether
      -- we use the ghc api. However, ghc will complain
      -- if the filename does not match the module name
      -- when (typeclass cfg) $ do
      --   Ghc.setContext [iimport |(modName, _) <- allSpecs legacyBareSpec,
      --                   let iimport = if isTarget modName
      --                                 then Ghc.IIModule (getModName modName)
      --                                 else Ghc.IIDecl (Ghc.simpleImportDecl (getModName modName))]
      --   void $ Ghc.execStmt
      --     "let {infixr 1 ==>; True ==> False = False; _ ==> _ = True}"
      --     Ghc.execOptions
      --   void $ Ghc.execStmt
      --     "let {infixr 1 <=>; True <=> False = False; _ <=> _ = True}"
      --     Ghc.execOptions
      --   void $ Ghc.execStmt
      --     "let {infix 4 ==; (==) :: a -> a -> Bool; _ == _ = undefined}"
      --     Ghc.execOptions
      --   void $ Ghc.execStmt
      --     "let {infix 4 /=; (/=) :: a -> a -> Bool; _ /= _ = undefined}"
      --     Ghc.execOptions
      --   void $ Ghc.execStmt
      --     "let {infixl 7 /; (/) :: Num a => a -> a -> a; _ / _ = undefined}"
      --     Ghc.execOptions
      --   void $ Ghc.execStmt
      --     "let {len :: [a] -> Int; len _ = undefined}"
      --     Ghc.execOptions

      diagOrSpec <- makeGhcSpec cfg (review targetSrcIso targetSrc) lmap (allSpecs legacyBareSpec)
      return $ do
        (warns, ghcSpec) <- diagOrSpec
        let (targetSpec, liftedSpec) = view targetSpecGetter ghcSpec
        pure (phaseOneWarns <> warns, targetSpec, liftedSpec)

    toLegacyDep :: (Ghc.StableModule, LiftedSpec) -> (ModName, Ms.BareSpec)
    toLegacyDep (sm, ls) = (ModName SrcImport (Ghc.moduleName . Ghc.unStableModule $ sm), unsafeFromLiftedSpec ls)

    toLegacyTarget :: Ms.BareSpec -> (ModName, Ms.BareSpec)
    toLegacyTarget validatedSpec = (giTargetMod targetSrc, validatedSpec)

    legacyDependencies :: [(ModName, Ms.BareSpec)]
    legacyDependencies = map toLegacyDep . M.toList . getDependencies $ dependencies

    allSpecs :: Ms.BareSpec -> [(ModName, Ms.BareSpec)]
    allSpecs validSpec = toLegacyTarget validSpec : legacyDependencies

    legacyBareSpec :: Spec LocBareType F.LocSymbol
    legacyBareSpec = review bareSpecIso bareSpec

-------------------------------------------------------------------------------------
-- | @makeGhcSpec@ invokes @makeGhcSpec0@ to construct the @GhcSpec@ and then
--   validates it using @checkGhcSpec@.
-------------------------------------------------------------------------------------
makeGhcSpec :: Config
            -> GhcSrc
            -> LogicMap
            -> [(ModName, Ms.BareSpec)]
            -> Ghc.TcRn (Either Diagnostics ([Warning], GhcSpec))
-------------------------------------------------------------------------------------
makeGhcSpec cfg src lmap validatedSpecs = do
  (dg0, sp) <- makeGhcSpec0 cfg src lmap validatedSpecs
  let diagnostics = Bare.checkTargetSpec (map snd validatedSpecs)
                                         (view targetSrcIso src)
                                         (ghcSpecEnv sp)
                                         (_giCbs src)
                                         (fst . view targetSpecGetter $ sp)
  pure $ if not (noErrors dg0) then Left dg0 else
           case diagnostics of
             Left dg1
               | noErrors dg1 -> pure (allWarnings dg1, sp)
               | otherwise    -> Left dg1
             Right ()         -> pure (mempty, sp)

ghcSpecEnv :: GhcSpec -> SEnv SortedReft
ghcSpecEnv sp = F.notracepp "RENV" $ fromListSEnv binds
  where
    emb       = gsTcEmbeds (_gsName sp)
    binds     = F.notracepp "binds" $ concat
                 [ [(x,        rSort t) | (x, Loc _ _ t)  <- gsMeas     (_gsData sp)]
                 , [(symbol v, rSort t) | (v, Loc _ _ t)  <- gsCtors    (_gsData sp)]
                 , [(symbol v, vSort v) | v               <- gsReflects (_gsRefl sp)]
                 , [(x,        vSort v) | (x, v)          <- gsFreeSyms (_gsName sp), Ghc.isConLikeId v ]
                 , [(x, RR s mempty)    | (x, s)          <- wiredSortedSyms       ]
                 , [(x, RR s mempty)    | (x, s)          <- _gsImps sp       ]
                 ]
    vSort     = rSort . classRFInfoType (typeclass $ getConfig sp) .
                (ofType :: Ghc.Type -> SpecType) . Ghc.varType
    rSort     = rTypeSortedReft    emb

-------------------------------------------------------------------------------------
-- | @makeGhcSpec0@ slurps up all the relevant information needed to generate
--   constraints for a target module and packages them into a @GhcSpec@
--   See [NOTE] LIFTING-STAGES to see why we split into lSpec0, lSpec1, etc.
--   essentially, to get to the `BareRTEnv` as soon as possible, as thats what
--   lets us use aliases inside data-constructor definitions.
-------------------------------------------------------------------------------------
makeGhcSpec0 :: Config -> GhcSrc ->  LogicMap -> [(ModName, Ms.BareSpec)] ->
                Ghc.TcRn (Diagnostics, GhcSpec)
makeGhcSpec0 cfg src lmap mspecsNoCls = do
  -- build up environments
  tycEnv <- makeTycEnv1 name env (tycEnv0, datacons) coreToLg simplifier
  let tyi      = Bare.tcTyConMap   tycEnv
  let sigEnv   = makeSigEnv  embs tyi (_gsExports src) rtEnv
  let lSpec1   = lSpec0 <> makeLiftedSpec1 cfg src tycEnv lmap mySpec1
  let mySpec   = mySpec2 <> lSpec1
  let specs    = M.insert name mySpec iSpecs2
  let myRTE    = myRTEnv       src env sigEnv rtEnv
  let (dg5, measEnv) = withDiagnostics $ makeMeasEnv      env tycEnv sigEnv       specs
  let (dg4, sig) = withDiagnostics $ makeSpecSig cfg name specs env sigEnv   tycEnv measEnv (_giCbs src)
  elaboratedSig <-
    if allowTC then Bare.makeClassAuxTypes (elaborateSpecType coreToLg simplifier) datacons instMethods
                              >>= elaborateSig sig
               else pure sig
  let qual     = makeSpecQual cfg env tycEnv measEnv rtEnv specs
  let sData    = makeSpecData  src env sigEnv measEnv elaboratedSig specs
  let (dg1, spcVars) = withDiagnostics $ makeSpecVars cfg src mySpec env measEnv
  let (dg2, spcTerm) = withDiagnostics $ makeSpecTerm cfg     mySpec env       name
  let (dg3, refl)    = withDiagnostics $ makeSpecRefl cfg src measEnv specs env name elaboratedSig tycEnv
  let laws     = makeSpecLaws env sigEnv (gsTySigs elaboratedSig ++ gsAsmSigs elaboratedSig) measEnv specs
  let finalLiftedSpec = makeLiftedSpec name src env refl sData elaboratedSig qual myRTE lSpec1
  let diags    = mconcat [dg0, dg1, dg2, dg3, dg4, dg5]

  pure (diags, SP
    { _gsConfig = cfg
    , _gsImps   = makeImports mspecs
    , _gsSig    = addReflSigs env name rtEnv refl elaboratedSig
    , _gsRefl   = refl
    , _gsLaws   = laws
    , _gsData   = sData
    , _gsQual   = qual
    , _gsName   = makeSpecName env     tycEnv measEnv   name
    , _gsVars   = spcVars
    , _gsTerm   = spcTerm

    , _gsLSpec  = finalLiftedSpec
                { impSigs   = makeImports mspecs
                , expSigs   = [ (F.symbol v, F.sr_sort $ Bare.varSortedReft embs v) | v <- gsReflects refl ]
                , dataDecls = Bare.dataDeclSize mySpec $ dataDecls mySpec
                , measures  = Ms.measures mySpec
                  -- We want to export measures in a 'LiftedSpec', especially if they are
                  -- required to check termination of some 'liftedSigs' we export. Due to the fact
                  -- that 'lSpec1' doesn't contain the measures that we compute via 'makeHaskellMeasures',
                  -- we take them from 'mySpec', which has those.
                , asmSigs = Ms.asmSigs finalLiftedSpec ++ Ms.asmSigs mySpec
                  -- Export all the assumptions (not just the ones created out of reflection) in
                  -- a 'LiftedSpec'.
                , imeasures = Ms.imeasures finalLiftedSpec ++ Ms.imeasures mySpec
                  -- Preserve user-defined 'imeasures'.
                , dvariance = Ms.dvariance finalLiftedSpec ++ Ms.dvariance mySpec
                  -- Preserve user-defined 'dvariance'.
                , rinstance = Ms.rinstance finalLiftedSpec ++ Ms.rinstance mySpec
                  -- Preserve rinstances.
                }
    })
  where
    -- typeclass elaboration

    coreToLg ce =
      case CoreToLogic.runToLogic
             embs
             lmap
             dm
             (\x -> todo Nothing ("coreToLogic not working " ++ x))
             (CoreToLogic.coreToLogic allowTC ce) of
        Left msg -> panic Nothing (F.showpp msg)
        Right e -> e
    elaborateSig si auxsig = do
      tySigs <-
        forM (gsTySigs si) $ \(x, t) ->
          if GM.isFromGHCReal x then
            pure (x, t)
          else do t' <- traverse (elaborateSpecType coreToLg simplifier) t
                  pure (x, t')
      -- things like len breaks the code
      -- asmsigs should be elaborated only if they are from the current module
      -- asmSigs <- forM (gsAsmSigs si) $ \(x, t) -> do
      --   t' <- traverse (elaborateSpecType (pure ()) coreToLg) t
      --   pure (x, fst <$> t')
      pure
        si
          { gsTySigs = F.notracepp ("asmSigs" ++ F.showpp (gsAsmSigs si)) tySigs ++ auxsig  }

    simplifier :: Ghc.CoreExpr -> Ghc.TcRn Ghc.CoreExpr
    simplifier = pure -- no simplification
    allowTC  = typeclass cfg
    mySpec2  = Bare.qualifyExpand env name rtEnv l [] mySpec1    where l = F.dummyPos "expand-mySpec2"
    iSpecs2  = Bare.qualifyExpand env name rtEnv l [] iSpecs0    where l = F.dummyPos "expand-iSpecs2"
    rtEnv    = Bare.makeRTEnv env name mySpec1 iSpecs0 lmap
    mspecs   = if allowTC then M.toList $ M.insert name mySpec0 iSpecs0 else mspecsNoCls
    (mySpec0, instMethods)  = if allowTC
                              then Bare.compileClasses src env (name, mySpec0NoCls) (M.toList iSpecs0)
                              else (mySpec0NoCls, [])
    mySpec1  = mySpec0 <> lSpec0
    lSpec0   = makeLiftedSpec0 cfg src embs lmap mySpec0
    embs     = makeEmbeds          src env ((name, mySpec0) : M.toList iSpecs0)
    dm       = Bare.tcDataConMap tycEnv0
    (dg0, datacons, tycEnv0) = makeTycEnv0   cfg name env embs mySpec2 iSpecs2
    -- extract name and specs
    env      = Bare.makeEnv cfg src lmap mspecsNoCls
    (mySpec0NoCls, iSpecs0) = splitSpecs name src mspecsNoCls
    -- check barespecs
    name     = F.notracepp ("ALL-SPECS" ++ zzz) $ _giTargetMod  src
    zzz      = F.showpp (fst <$> mspecs)

splitSpecs :: ModName -> GhcSrc -> [(ModName, Ms.BareSpec)] -> (Ms.BareSpec, Bare.ModSpecs)
splitSpecs name src specs = (mySpec, iSpecm)
  where
    iSpecm             = fmap mconcat . Misc.group $ iSpecs
    iSpecs             = Dg.sliceSpecs src mySpec iSpecs'
    mySpec             = mconcat (snd <$> mySpecs)
    (mySpecs, iSpecs') = L.partition ((name ==) . fst) specs

makeImports :: [(ModName, Ms.BareSpec)] -> [(F.Symbol, F.Sort)]
makeImports specs = concatMap (expSigs . snd) specs'
  where specs' = filter (isSrcImport . fst) specs

makeEmbeds :: GhcSrc -> Bare.Env -> [(ModName, Ms.BareSpec)] -> F.TCEmb Ghc.TyCon
makeEmbeds src env
  = Bare.addClassEmbeds (_gsCls src) (_gsFiTcs src)
  . mconcat
  . map (makeTyConEmbeds env)

makeTyConEmbeds :: Bare.Env -> (ModName, Ms.BareSpec) -> F.TCEmb Ghc.TyCon
makeTyConEmbeds env (name, spec)
  = F.tceFromList [ (tc, t) | (c,t) <- F.tceToList (Ms.embeds spec), tc <- symTc c ]
    where
      symTc = Mb.maybeToList . Bare.maybeResolveSym env name "embed-tycon"

--------------------------------------------------------------------------------
-- | [NOTE]: REFLECT-IMPORTS
--
-- 1. MAKE the full LiftedSpec, which will eventually, contain:
--      makeHaskell{Inlines, Measures, Axioms, Bounds}
-- 2. SAVE the LiftedSpec, which will be reloaded
--
--   This step creates the aliases and inlines etc. It must be done BEFORE
--   we compute the `SpecType` for (all, including the reflected binders),
--   as we need the inlines and aliases to properly `expand` the SpecTypes.
--------------------------------------------------------------------------------
makeLiftedSpec1 :: Config -> GhcSrc -> Bare.TycEnv -> LogicMap -> Ms.BareSpec
                -> Ms.BareSpec
makeLiftedSpec1 config src tycEnv lmap mySpec = mempty
  { Ms.measures  = Bare.makeHaskellMeasures (typeclass config) src tycEnv lmap mySpec }

--------------------------------------------------------------------------------
-- | [NOTE]: LIFTING-STAGES
--
-- We split the lifting up into stage:
-- 0. Where we only lift inlines,
-- 1. Where we lift reflects, measures, and normalized tySigs
--
-- This is because we need the inlines to build the @BareRTEnv@ which then
-- does the alias @expand@ business, that in turn, lets us build the DataConP,
-- i.e. the refined datatypes and their associate selectors, projectors etc,
-- that are needed for subsequent stages of the lifting.
--------------------------------------------------------------------------------
makeLiftedSpec0 :: Config -> GhcSrc -> F.TCEmb Ghc.TyCon -> LogicMap -> Ms.BareSpec
                -> Ms.BareSpec
makeLiftedSpec0 cfg src embs lmap mySpec = mempty
  { Ms.ealiases  = lmapEAlias . snd <$> Bare.makeHaskellInlines (typeclass cfg) src embs lmap mySpec
  , Ms.reflects  = Ms.reflects mySpec
  , Ms.dataDecls = Bare.makeHaskellDataDecls cfg name mySpec tcs
  , Ms.embeds    = Ms.embeds mySpec
  -- We do want 'embeds' to survive and to be present into the final 'LiftedSpec'. The
  -- caveat is to decide which format is more appropriate. We obviously cannot store
  -- them as a 'TCEmb TyCon' as serialising a 'TyCon' would be fairly exponsive. This
  -- needs more thinking.
  , Ms.cmeasures = Ms.cmeasures mySpec
  -- We do want 'cmeasures' to survive and to be present into the final 'LiftedSpec'. The
  -- caveat is to decide which format is more appropriate. This needs more thinking.
  }
  where
    tcs          = uniqNub (_gsTcs src ++ refTcs)
    refTcs       = reflectedTyCons cfg embs cbs  mySpec
    cbs          = _giCbs       src
    name         = _giTargetMod src

uniqNub :: (Ghc.Uniquable a) => [a] -> [a]
uniqNub xs = M.elems $ M.fromList [ (index x, x) | x <- xs ]
  where
    index  = Ghc.getKey . Ghc.getUnique

-- | 'reflectedTyCons' returns the list of `[TyCon]` that must be reflected but
--   which are defined *outside* the current module e.g. in Base or somewhere
--   that we don't have access to the code.

reflectedTyCons :: Config -> TCEmb Ghc.TyCon -> [Ghc.CoreBind] -> Ms.BareSpec -> [Ghc.TyCon]
reflectedTyCons cfg embs cbs spec
  | exactDCFlag cfg = filter (not . isEmbedded embs)
                    $ concatMap varTyCons
                    $ reflectedVars spec cbs ++ measureVars spec cbs
  | otherwise       = []

-- | We cannot reflect embedded tycons (e.g. Bool) as that gives you a sort
--   conflict: e.g. what is the type of is-True? does it take a GHC.Types.Bool
--   or its embedding, a bool?
isEmbedded :: TCEmb Ghc.TyCon -> Ghc.TyCon -> Bool
isEmbedded embs c = F.tceMember c embs

varTyCons :: Ghc.Var -> [Ghc.TyCon]
varTyCons = specTypeCons . ofType . Ghc.varType

specTypeCons           :: SpecType -> [Ghc.TyCon]
specTypeCons         = foldRType tc []
  where
    tc acc t@RApp {} = rtc_tc (rt_tycon t) : acc
    tc acc _         = acc

reflectedVars :: Ms.BareSpec -> [Ghc.CoreBind] -> [Ghc.Var]
reflectedVars spec cbs = fst <$> xDefs
  where
    xDefs              = Mb.mapMaybe (`GM.findVarDef` cbs) reflSyms
    reflSyms           = val <$> S.toList (Ms.reflects spec)

measureVars :: Ms.BareSpec -> [Ghc.CoreBind] -> [Ghc.Var]
measureVars spec cbs = fst <$> xDefs
  where
    xDefs              = Mb.mapMaybe (`GM.findVarDef` cbs) measureSyms
    measureSyms        = val <$> S.toList (Ms.hmeas spec)

------------------------------------------------------------------------------------------
makeSpecVars :: Config -> GhcSrc -> Ms.BareSpec -> Bare.Env -> Bare.MeasEnv
             -> Bare.Lookup GhcSpecVars
------------------------------------------------------------------------------------------
makeSpecVars cfg src mySpec env measEnv = do
  tgtVars     <-   mapM (resolveStringVar  env name)              (checks     cfg)
  igVars      <-  sMapM (Bare.lookupGhcVar env name "gs-ignores") (Ms.ignores mySpec)
  lVars       <-  sMapM (Bare.lookupGhcVar env name "gs-lvars"  ) (Ms.lvars   mySpec)
  return (SpVar tgtVars igVars lVars cMethods)
  where
    name       = _giTargetMod src
    cMethods   = snd3 <$> Bare.meMethods measEnv

sMapM :: (Monad m, Eq b, Hashable b) => (a -> m b) -> S.HashSet a -> m (S.HashSet b)
sMapM f xSet = do
 ys <- mapM f (S.toList xSet)
 return (S.fromList ys)

sForM :: (Monad m, Eq b, Hashable b) =>S.HashSet a -> (a -> m b) -> m (S.HashSet b)
sForM xs f = sMapM f xs

qualifySymbolic :: (F.Symbolic a) => ModName -> a -> F.Symbol
qualifySymbolic name s = GM.qualifySymbol (F.symbol name) (F.symbol s)

resolveStringVar :: Bare.Env -> ModName -> String -> Bare.Lookup Ghc.Var
resolveStringVar env name s = Bare.lookupGhcVar env name "resolve-string-var" lx
  where
    lx                      = dummyLoc (qualifySymbolic name s)

------------------------------------------------------------------------------------------
makeSpecQual :: Config -> Bare.Env -> Bare.TycEnv -> Bare.MeasEnv -> BareRTEnv -> Bare.ModSpecs
             -> GhcSpecQual
------------------------------------------------------------------------------------------
makeSpecQual _cfg env tycEnv measEnv _rtEnv specs = SpQual
  { gsQualifiers = filter okQual quals
  , gsRTAliases  = [] -- makeSpecRTAliases env rtEnv -- TODO-REBARE
  }
  where
    quals        = concatMap (makeQualifiers env tycEnv) (M.toList specs)
    -- mSyms        = F.tracepp "MSYMS" $ M.fromList (Bare.meSyms measEnv ++ Bare.meClassSyms measEnv)
    okQual q     = F.notracepp ("okQual: " ++ F.showpp q)
                   $ all (`S.member` mSyms) (F.syms q)
    mSyms        = F.notracepp "MSYMS" . S.fromList
                   $  (fst <$> wiredSortedSyms)
                   ++ (fst <$> Bare.meSyms measEnv)
                   ++ (fst <$> Bare.meClassSyms measEnv)

makeQualifiers :: Bare.Env -> Bare.TycEnv -> (ModName, Ms.Spec ty bndr) -> [F.Qualifier]
makeQualifiers env tycEnv (modn, spec)
  = fmap        (Bare.qualifyTopDummy env        modn)
  . Mb.mapMaybe (resolveQParams       env tycEnv modn)
  $ Ms.qualifiers spec

-- | @resolveQualParams@ converts the sorts of parameters from, e.g.
--     'Int' ===> 'GHC.Types.Int' or
--     'Ptr' ===> 'GHC.Ptr.Ptr'
--   It would not be required if _all_ qualifiers are scraped from
--   function specs, but we're keeping it around for backwards compatibility.

resolveQParams :: Bare.Env -> Bare.TycEnv -> ModName -> F.Qualifier -> Maybe F.Qualifier
resolveQParams env tycEnv name q = do
     qps   <- mapM goQP (F.qParams q)
     return $ q { F.qParams = qps }
  where
    goQP qp          = do { s <- go (F.qpSort qp) ; return qp { F.qpSort = s } }
    go               :: F.Sort -> Maybe F.Sort
    go (FAbs i s)    = FAbs i <$> go s
    go (FFunc s1 s2) = FFunc  <$> go s1 <*> go s2
    go (FApp  s1 s2) = FApp   <$> go s1 <*> go s2
    go (FTC c)       = qualifyFTycon env tycEnv name c
    go s             = Just s

qualifyFTycon :: Bare.Env -> Bare.TycEnv -> ModName -> F.FTycon -> Maybe F.Sort
qualifyFTycon env tycEnv name c
  | isPrimFTC           = Just (FTC c)
  | otherwise           = tyConSort embs . F.atLoc tcs <$> ty
  where
    ty                  = Bare.maybeResolveSym env name "qualify-FTycon" tcs
    isPrimFTC           = F.val tcs `elem` F.prims
    tcs                 = F.fTyconSymbol c
    embs                = Bare.tcEmbs tycEnv

tyConSort :: F.TCEmb Ghc.TyCon -> F.Located Ghc.TyCon -> F.Sort
tyConSort embs lc = Mb.maybe s0 fst (F.tceLookup c embs)
  where
    c             = F.val lc
    s0            = tyConSortRaw lc

tyConSortRaw :: F.Located Ghc.TyCon -> F.Sort
tyConSortRaw = FTC . F.symbolFTycon . fmap F.symbol

------------------------------------------------------------------------------------------
makeSpecTerm :: Config -> Ms.BareSpec -> Bare.Env -> ModName ->
                Bare.Lookup GhcSpecTerm
------------------------------------------------------------------------------------------
makeSpecTerm cfg mySpec env name = do
  sizes  <- if structuralTerm cfg then pure mempty else makeSize env name mySpec
  lazies <- makeLazy     env name mySpec
  autos  <- makeAutoSize env name mySpec
  decr   <- makeDecrs env name mySpec
  gfail  <- makeFail env name mySpec
  return  $ SpTerm
    { gsLazy       = S.insert dictionaryVar (lazies `mappend` sizes)
    , gsFail       = gfail
    , gsStTerm     = sizes
    , gsAutosize   = autos
    , gsDecr       = decr
    , gsNonStTerm  = mempty
    }

-- formerly, makeHints
makeDecrs :: Bare.Env -> ModName -> Ms.BareSpec -> Bare.Lookup [(Ghc.Var, [Int])]
makeDecrs env name mySpec =
  forM (Ms.decr mySpec) $ \(lx, z) -> do
    v <- Bare.lookupGhcVar env name "decreasing" lx
    return (v, z)

makeRelation :: Bare.Env -> ModName -> Bare.SigEnv ->
  [(LocSymbol, LocSymbol, LocBareType, LocBareType, RelExpr, RelExpr)] -> Bare.Lookup [(Ghc.Var, Ghc.Var, LocSpecType, LocSpecType, RelExpr, RelExpr)]
makeRelation env name sigEnv = mapM go
 where
  go (x, y, tx, ty, a, e) = do
    vx <- Bare.lookupGhcVar env name "Var" x
    vy <- Bare.lookupGhcVar env name "Var" y
    return
        ( vx
        , vy
        , Bare.cookSpecType env sigEnv name (Bare.HsTV vx) tx
        , Bare.cookSpecType env sigEnv name (Bare.HsTV vy) ty
        , a
        , e
        )

makeLazy :: Bare.Env -> ModName -> Ms.BareSpec -> Bare.Lookup (S.HashSet Ghc.Var)
makeLazy env name spec =
  sMapM (Bare.lookupGhcVar env name "Var") (Ms.lazy spec)

makeFail :: Bare.Env -> ModName -> Ms.BareSpec -> Bare.Lookup (S.HashSet (Located Ghc.Var))
makeFail env name spec =
  sForM (Ms.fails spec) $ \x -> do
    vx <- Bare.lookupGhcVar env name "Var" x
    return x { val = vx }

makeRewrite :: Bare.Env -> ModName -> Ms.BareSpec -> Bare.Lookup (S.HashSet (Located Ghc.Var))
makeRewrite env name spec =
  sForM (Ms.rewrites spec) $ \x -> do
    vx <-  Bare.lookupGhcVar env name "Var" x
    return x { val = vx }

makeRewriteWith :: Bare.Env -> ModName -> Ms.BareSpec -> Bare.Lookup (M.HashMap Ghc.Var [Ghc.Var])
makeRewriteWith env name spec = M.fromList <$> makeRewriteWith' env name spec

makeRewriteWith' :: Bare.Env -> ModName -> Spec ty bndr -> Bare.Lookup [(Ghc.Var, [Ghc.Var])]
makeRewriteWith' env name spec =
  forM (M.toList $ Ms.rewriteWith spec) $ \(x, xs) -> do
    xv  <- Bare.lookupGhcVar env name "Var1" x
    xvs <- mapM (Bare.lookupGhcVar env name "Var2") xs
    return (xv, xvs)

makeAutoSize :: Bare.Env -> ModName -> Ms.BareSpec -> Bare.Lookup (S.HashSet Ghc.TyCon)
makeAutoSize env name
  = fmap S.fromList
  . mapM (Bare.lookupGhcTyCon env name "TyCon")
  . S.toList
  . Ms.autosize

makeSize :: Bare.Env -> ModName -> Ms.BareSpec -> Bare.Lookup (S.HashSet Ghc.Var)
makeSize env name
  = fmap S.fromList
  . mapM (Bare.lookupGhcVar env name "Var")
  . Mb.mapMaybe getSizeFuns
  . Ms.dataDecls

getSizeFuns :: DataDecl -> Maybe LocSymbol
getSizeFuns decl
  | Just x       <- tycSFun decl
  , SymSizeFun f <- x
  = Just f
  | otherwise
  = Nothing

------------------------------------------------------------------------------------------
makeSpecLaws :: Bare.Env -> Bare.SigEnv -> [(Ghc.Var,LocSpecType)] -> Bare.MeasEnv -> Bare.ModSpecs
             -> GhcSpecLaws
------------------------------------------------------------------------------------------
makeSpecLaws env sigEnv sigs menv specs = SpLaws
  { gsLawDefs = second (map (\(_,x,y) -> (x,y))) <$> Bare.meCLaws menv
  , gsLawInst = Bare.makeInstanceLaws env sigEnv sigs specs
  }

------------------------------------------------------------------------------------------
makeSpecRefl :: Config -> GhcSrc -> Bare.MeasEnv -> Bare.ModSpecs -> Bare.Env -> ModName -> GhcSpecSig -> Bare.TycEnv
             -> Bare.Lookup GhcSpecRefl
------------------------------------------------------------------------------------------
makeSpecRefl cfg src menv specs env name sig tycEnv = do
  autoInst <- makeAutoInst env name mySpec
  rwr      <- makeRewrite env name mySpec
  rwrWith  <- makeRewriteWith env name mySpec
  wRefls   <- Bare.wiredReflects cfg env name sig
  xtes     <- Bare.makeHaskellAxioms cfg src env tycEnv name lmap sig mySpec
  let myAxioms =
        [ Bare.qualifyTop
            env
            name
            (F.loc lt)
            e {eqName = s, eqRec = S.member s (exprSymbolsSet (eqBody e))}
        | (x, lt, e) <- xtes
        , let s = symbol x
        ]
  let sigVars  = F.notracepp "SIGVARS" $ (fst3 <$> xtes)            -- reflects
                                      ++ (fst  <$> gsAsmSigs sig)   -- assumes
                                      ++ (fst  <$> gsRefSigs sig)
  return SpRefl
    { gsLogicMap   = lmap
    , gsAutoInst   = autoInst
    , gsImpAxioms  = concatMap (Ms.axeqs . snd) (M.toList specs)
    , gsMyAxioms   = F.notracepp "gsMyAxioms" myAxioms
    , gsReflects   = F.notracepp "gsReflects" (lawMethods ++ filter (isReflectVar rflSyms) sigVars ++ wRefls)
    , gsHAxioms    = F.notracepp "gsHAxioms" xtes
    , gsWiredReft  = wRefls
    , gsRewrites   = rwr
    , gsRewritesWith = rwrWith
    }
  where
    lawMethods   = F.notracepp "Law Methods" $ concatMap Ghc.classMethods (fst <$> Bare.meCLaws menv)
    mySpec       = M.lookupDefault mempty name specs
    rflSyms      = S.fromList (getReflects specs)
    lmap         = Bare.reLMap env

isReflectVar :: S.HashSet F.Symbol -> Ghc.Var -> Bool
isReflectVar reflSyms v = S.member vx reflSyms
  where
    vx                  = GM.dropModuleNames (symbol v)

getReflects :: Bare.ModSpecs -> [Symbol]
getReflects  = fmap val . S.toList . S.unions . fmap (names . snd) . M.toList
  where
    names  z = S.unions [ Ms.reflects z, Ms.inlines z, Ms.hmeas z ]

------------------------------------------------------------------------------------------
-- | @updateReflSpecSig@ uses the information about reflected functions to update the
--   "assumed" signatures.
------------------------------------------------------------------------------------------
addReflSigs :: Bare.Env -> ModName -> BareRTEnv -> GhcSpecRefl -> GhcSpecSig -> GhcSpecSig
------------------------------------------------------------------------------------------
addReflSigs env name rtEnv refl sig =
  sig { gsRefSigs = F.notracepp ("gsRefSigs for " ++ F.showpp name) $ map expandReflectedSignature reflSigs
      , gsAsmSigs = F.notracepp ("gsAsmSigs for " ++ F.showpp name) (wreflSigs ++ filter notReflected (gsAsmSigs sig))
      }
  where

    -- See T1738. We need to expand and qualify any reflected signature /here/, after any
    -- relevant binder has been detected and \"promoted\". The problem stems from the fact that any input
    -- 'BareSpec' will have a 'reflects' list of binders to reflect under the form of an opaque 'Var', that
    -- qualifyExpand can't touch when we do a first pass in 'makeGhcSpec0'. However, once we reflected all
    -- the functions, we are left with a pair (Var, LocSpecType). The latter /needs/ to be qualified and
    -- expanded again, for example in case it has expression aliases derived from 'inlines'.
    expandReflectedSignature :: (Ghc.Var, LocSpecType) -> (Ghc.Var, LocSpecType)
    expandReflectedSignature = fmap (Bare.qualifyExpand env name rtEnv (F.dummyPos "expand-refSigs") [])

    (wreflSigs, reflSigs)   = L.partition ((`elem` gsWiredReft refl) . fst)
                                 [ (x, t) | (x, t, _) <- gsHAxioms refl ]
    reflected       = fst <$> (wreflSigs ++ reflSigs)
    notReflected xt = fst xt `notElem` reflected

makeAutoInst :: Bare.Env -> ModName -> Ms.BareSpec ->
                Bare.Lookup (M.HashMap Ghc.Var (Maybe Int))
makeAutoInst env name spec = M.fromList <$> kvs
  where
    kvs = forM (M.toList (Ms.autois spec)) $ \(k, val) -> do
            vk <- Bare.lookupGhcVar env name "Var" k
            return (vk, val)

----------------------------------------------------------------------------------------
makeSpecSig :: Config -> ModName -> Bare.ModSpecs -> Bare.Env -> Bare.SigEnv -> Bare.TycEnv -> Bare.MeasEnv -> [Ghc.CoreBind]
            -> Bare.Lookup GhcSpecSig
----------------------------------------------------------------------------------------
makeSpecSig cfg name specs env sigEnv tycEnv measEnv cbs = do
  mySigs     <- makeTySigs  env sigEnv name mySpec
  aSigs      <- F.notracepp ("makeSpecSig aSigs " ++ F.showpp name) $ makeAsmSigs env sigEnv name specs
  let asmSigs =  Bare.tcSelVars tycEnv
              ++ aSigs
              ++ [ (x,t) | (_, x, t) <- concatMap snd (Bare.meCLaws measEnv) ]
  let tySigs  = strengthenSigs . concat $
                  [ [(v, (0, t)) | (v, t,_) <- mySigs                         ]   -- NOTE: these weights are to priortize
                  , [(v, (1, t)) | (v, t  ) <- makeMthSigs measEnv            ]   -- user defined sigs OVER auto-generated
                  , [(v, (2, t)) | (v, t  ) <- makeInlSigs env rtEnv allSpecs ]   -- during the strengthening, i.e. to KEEP
                  , [(v, (3, t)) | (v, t  ) <- makeMsrSigs env rtEnv allSpecs ]   -- the binders used in USER-defined sigs
                  ]                                                               -- as they appear in termination metrics
  newTys     <-  makeNewTypes env sigEnv allSpecs
  relation   <-  makeRelation env name sigEnv (Ms.relational mySpec)
  asmRel     <-  makeRelation env name sigEnv (Ms.asmRel mySpec)
  return SpSig
    { gsTySigs   = tySigs
    , gsAsmSigs  = asmSigs
    , gsRefSigs  = []
    , gsDicts    = dicts
    -- , gsMethods  = if noclasscheck cfg then [] else Bare.makeMethodTypes dicts (Bare.meClasses  measEnv) cbs
    , gsMethods  = if noclasscheck cfg then [] else Bare.makeMethodTypes (typeclass cfg) dicts (Bare.meClasses  measEnv) cbs
    , gsInSigs   = mempty
    , gsNewTypes = newTys
    , gsTexprs   = [ (v, t, es) | (v, t, Just es) <- mySigs ]
    , gsRelation = relation
    , gsAsmRel   = asmRel
  }
  where
    dicts      = Bare.makeSpecDictionaries env sigEnv specs
    mySpec     = M.lookupDefault mempty name specs
    allSpecs   = M.toList specs
    rtEnv      = Bare.sigRTEnv sigEnv
    -- hmeas      = makeHMeas    env allSpecs

strengthenSigs :: [(Ghc.Var, (Int, LocSpecType))] ->[(Ghc.Var, LocSpecType)]
strengthenSigs sigs = go <$> Misc.groupList sigs
  where
    go (v, ixs)     = (v,) $ L.foldl1' (flip meetLoc) (F.notracepp ("STRENGTHEN-SIGS: " ++ F.showpp v) (prio ixs))
    prio            = fmap snd . Misc.sortOn fst
    meetLoc         :: LocSpecType -> LocSpecType -> LocSpecType
    meetLoc t1 t2   = t1 {val = val t1 `F.meet` val t2}

makeMthSigs :: Bare.MeasEnv -> [(Ghc.Var, LocSpecType)]
makeMthSigs measEnv = [ (v, t) | (_, v, t) <- Bare.meMethods measEnv ]

makeInlSigs :: Bare.Env -> BareRTEnv -> [(ModName, Ms.BareSpec)] -> [(Ghc.Var, LocSpecType)]
makeInlSigs env rtEnv
  = makeLiftedSigs rtEnv (CoreToLogic.inlineSpecType (typeclass (getConfig env)))
  . makeFromSet "hinlines" Ms.inlines env

makeMsrSigs :: Bare.Env -> BareRTEnv -> [(ModName, Ms.BareSpec)] -> [(Ghc.Var, LocSpecType)]
makeMsrSigs env rtEnv
  = makeLiftedSigs rtEnv (CoreToLogic.inlineSpecType (typeclass (getConfig env)))
  . makeFromSet "hmeas" Ms.hmeas env

makeLiftedSigs :: BareRTEnv -> (Ghc.Var -> SpecType) -> [Ghc.Var] -> [(Ghc.Var, LocSpecType)]
makeLiftedSigs rtEnv f xs
  = [(x, lt) | x <- xs
             , let lx = GM.locNamedThing x
             , let lt = expand $ lx {val = f x}
    ]
  where
    expand   = Bare.specExpandType rtEnv

makeFromSet :: String -> (Ms.BareSpec -> S.HashSet LocSymbol) -> Bare.Env -> [(ModName, Ms.BareSpec)]
            -> [Ghc.Var]
makeFromSet msg f env specs = concat [ mk n xs | (n, s) <- specs, let xs = S.toList (f s)]
  where
    mk name                 = Mb.mapMaybe (Bare.maybeResolveSym env name msg)

makeTySigs :: Bare.Env -> Bare.SigEnv -> ModName -> Ms.BareSpec
           -> Bare.Lookup [(Ghc.Var, LocSpecType, Maybe [Located F.Expr])]
makeTySigs env sigEnv name spec = do
  bareSigs   <- bareTySigs env name                spec
  expSigs    <- makeTExpr  env name bareSigs rtEnv spec
  let rawSigs = Bare.resolveLocalBinds env expSigs
  return [ (x, cook x bt, z) | (x, bt, z) <- rawSigs ]
  where
    rtEnv     = Bare.sigRTEnv sigEnv
    cook x bt = Bare.cookSpecType env sigEnv name (Bare.HsTV x) bt

bareTySigs :: Bare.Env -> ModName -> Ms.BareSpec -> Bare.Lookup [(Ghc.Var, LocBareType)]
bareTySigs env name spec = checkDuplicateSigs <$> vts
  where
    vts = forM ( Ms.sigs spec ++ Ms.localSigs spec ) $ \ (x, t) -> do
            v <- F.notracepp "LOOKUP-GHC-VAR" $ Bare.lookupGhcVar env name "rawTySigs" x
            return (v, t)

-- checkDuplicateSigs :: [(Ghc.Var, LocSpecType)] -> [(Ghc.Var, LocSpecType)]
checkDuplicateSigs :: (Symbolic x) => [(x, F.Located t)] -> [(x, F.Located t)]
checkDuplicateSigs xts = case Misc.uniqueByKey symXs  of
  Left (k, ls) -> uError (errDupSpecs (pprint k) (GM.sourcePosSrcSpan <$> ls))
  Right _      -> xts
  where
    symXs = [ (F.symbol x, F.loc t) | (x, t) <- xts ]

makeAsmSigs :: Bare.Env -> Bare.SigEnv -> ModName -> Bare.ModSpecs -> Bare.Lookup [(Ghc.Var, LocSpecType)]
makeAsmSigs env sigEnv myName specs = do
  raSigs <- rawAsmSigs env myName specs
  return [ (x, t) | (name, x, bt) <- raSigs, let t = Bare.cookSpecType env sigEnv name (Bare.LqTV x) bt ]

rawAsmSigs :: Bare.Env -> ModName -> Bare.ModSpecs -> Bare.Lookup [(ModName, Ghc.Var, LocBareType)]
rawAsmSigs env myName specs = do
  aSigs <- allAsmSigs env myName specs
  return [ (m, v, t) | (v, sigs) <- aSigs, let (m, t) = myAsmSig v sigs ]

myAsmSig :: Ghc.Var -> [(Bool, ModName, LocBareType)] -> (ModName, LocBareType)
myAsmSig v sigs = Mb.fromMaybe errImp (Misc.firstMaybes [mbHome, mbImp])
  where
    mbHome      = takeUnique mkErr                  sigsHome
    mbImp       = takeUnique mkErr (Misc.firstGroup sigsImp) -- see [NOTE:Prioritize-Home-Spec]
    sigsHome    = [(m, t)      | (True,  m, t) <- sigs ]
    sigsImp     = F.notracepp ("SIGS-IMP: " ++ F.showpp v)
                  [(d, (m, t)) | (False, m, t) <- sigs, let d = nameDistance vName m]
    mkErr ts    = ErrDupSpecs (Ghc.getSrcSpan v) (F.pprint v) (GM.sourcePosSrcSpan . F.loc . snd <$> ts) :: UserError
    errImp      = impossible Nothing "myAsmSig: cannot happen as sigs is non-null"
    vName       = GM.takeModuleNames (F.symbol v)

makeTExpr :: Bare.Env -> ModName -> [(Ghc.Var, LocBareType)] -> BareRTEnv -> Ms.BareSpec
          -> Bare.Lookup [(Ghc.Var, LocBareType, Maybe [Located F.Expr])]
makeTExpr env name tySigs rtEnv spec = do
  vExprs       <- M.fromList <$> makeVarTExprs env name spec
  let vSigExprs = Misc.hashMapMapWithKey (\v t -> (t, M.lookup v vExprs)) vSigs
  return [ (v, t, qual t <$> es) | (v, (t, es)) <- M.toList vSigExprs ]
  where
    qual t es   = qualifyTermExpr env name rtEnv t <$> es
    vSigs       = M.fromList tySigs

qualifyTermExpr :: Bare.Env -> ModName -> BareRTEnv -> LocBareType -> Located F.Expr
                -> Located F.Expr
qualifyTermExpr env name rtEnv t le
        = F.atLoc le (Bare.qualifyExpand env name rtEnv l bs e)
  where
    l   = F.loc le
    e   = F.val le
    bs  = ty_binds . toRTypeRep . val $ t

makeVarTExprs :: Bare.Env -> ModName -> Ms.BareSpec -> Bare.Lookup [(Ghc.Var, [Located F.Expr])]
makeVarTExprs env name spec =
  forM (Ms.termexprs spec) $ \(x, es) -> do
    vx <- Bare.lookupGhcVar env name "Var" x
    return (vx, es)

----------------------------------------------------------------------------------------
-- [NOTE:Prioritize-Home-Spec] Prioritize spec for THING defined in
-- `Foo.Bar.Baz.Quux.x` over any other specification, IF GHC's
-- fully qualified name for THING is `Foo.Bar.Baz.Quux.x`.
--
-- For example, see tests/names/neg/T1078.hs for example,
-- which assumes a spec for `head` defined in both
--
--   (1) Data/ByteString.spec
--   (2) Data/ByteString/Char8.spec
--
-- We end up resolving the `head` in (1) to the @Var@ `Data.ByteString.Char8.head`
-- even though there is no exact match, just to account for re-exports of "internal"
-- modules and such (see `Resolve.matchMod`). However, we should pick the closer name
-- if its available.
----------------------------------------------------------------------------------------
nameDistance :: F.Symbol -> ModName -> Int
nameDistance vName tName
  | vName == F.symbol tName = 0
  | otherwise               = 1

takeUnique :: Ex.Exception e => ([a] -> e) -> [a] -> Maybe a
takeUnique _ []  = Nothing
takeUnique _ [x] = Just x
takeUnique f xs  = Ex.throw (f xs)

allAsmSigs :: Bare.Env -> ModName -> Bare.ModSpecs ->
              Bare.Lookup [(Ghc.Var, [(Bool, ModName, LocBareType)])]
allAsmSigs env myName specs = do
  let aSigs = [ (name, must, x, t) | (name, spec) <- M.toList specs
                                   , (must, x, t) <- getAsmSigs myName name spec ]
  vSigs    <- forM aSigs $ \(name, must, x, t) -> do
                vMb <- resolveAsmVar env name must x
                return (vMb, (must, name, t))
  return    $ Misc.groupList [ (v, z) | (Just v, z) <- vSigs ]

resolveAsmVar :: Bare.Env -> ModName -> Bool -> LocSymbol -> Bare.Lookup (Maybe Ghc.Var)
resolveAsmVar env name True  lx = Just  <$> Bare.lookupGhcVar env name "resolveAsmVar-True"  lx
resolveAsmVar env name False lx = return $  Bare.maybeResolveSym     env name "resolveAsmVar-False" lx  <|> GM.maybeAuxVar (F.val lx)

getAsmSigs :: ModName -> ModName -> Ms.BareSpec -> [(Bool, LocSymbol, LocBareType)]
getAsmSigs myName name spec
  | myName == name = [ (True,  x,  t) | (x, t) <- Ms.asmSigs spec ] -- MUST    resolve, or error
  | otherwise      = [ (False, x', t) | (x, t) <- Ms.asmSigs spec
                                                  ++ Ms.sigs spec
                                      , let x' = qSym x           ]  -- MAY-NOT resolve
  where
    qSym           = fmap (GM.qualifySymbol ns)
    ns             = F.symbol name

-- TODO-REBARE: grepClassAssumes
_grepClassAssumes :: [RInstance t] -> [(Located F.Symbol, t)]
_grepClassAssumes  = concatMap go
  where
    go    xts              = Mb.mapMaybe goOne (risigs xts)
    goOne (x, RIAssumed t) = Just (fmap (F.symbol . (".$c" ++ ) . F.symbolString) x, t)
    goOne (_, RISig _)     = Nothing

makeSigEnv :: F.TCEmb Ghc.TyCon -> Bare.TyConMap -> S.HashSet StableName -> BareRTEnv -> Bare.SigEnv
makeSigEnv embs tyi exports rtEnv = Bare.SigEnv
  { sigEmbs     = embs
  , sigTyRTyMap = tyi
  , sigExports  = exports
  , sigRTEnv    = rtEnv
  }

makeNewTypes :: Bare.Env -> Bare.SigEnv -> [(ModName, Ms.BareSpec)] ->
                Bare.Lookup [(Ghc.TyCon, LocSpecType)]
makeNewTypes env sigEnv specs = do
  fmap concat $
    forM nameDecls $ uncurry (makeNewType env sigEnv)
  where
    nameDecls = [(name, d) | (name, spec) <- specs, d <- Ms.newtyDecls spec]

makeNewType :: Bare.Env -> Bare.SigEnv -> ModName -> DataDecl ->
               Bare.Lookup [(Ghc.TyCon, LocSpecType)]
makeNewType env sigEnv name d = do
  tcMb <- Bare.lookupGhcDnTyCon env name "makeNewType" tcName
  case tcMb of
    Just tc -> return [(tc, lst)]
    _       -> return []
  where
    tcName                    = tycName d
    lst                       = Bare.cookSpecType env sigEnv name Bare.GenTV bt
    bt                        = getTy tcName (tycSrcPos d) (Mb.fromMaybe [] (tycDCons d))
    getTy _ l [c]
      | [(_, t)] <- dcFields c = Loc l l t
    getTy n l _                = Ex.throw (mkErr n l)
    mkErr n l                  = ErrOther (GM.sourcePosSrcSpan l) ("Bad new type declaration:" <+> F.pprint n) :: UserError

------------------------------------------------------------------------------------------
makeSpecData :: GhcSrc -> Bare.Env -> Bare.SigEnv -> Bare.MeasEnv -> GhcSpecSig -> Bare.ModSpecs
             -> GhcSpecData
------------------------------------------------------------------------------------------
makeSpecData src env sigEnv measEnv sig specs = SpData
  { gsCtors      = F.notracepp "GS-CTORS"
                   [ (x, if allowTC then t else tt)
                       | (x, t) <- Bare.meDataCons measEnv
                       , let tt  = Bare.plugHoles (typeclass $ getConfig env) sigEnv name (Bare.LqTV x) t
                   ]
  , gsMeas       = [ (F.symbol x, uRType <$> t) | (x, t) <- measVars ]
  , gsMeasures   = Bare.qualifyTopDummy env name <$> (ms1 ++ ms2)
  , gsInvariants = Misc.nubHashOn (F.loc . snd) invs
  , gsIaliases   = concatMap (makeIAliases env sigEnv) (M.toList specs)
  , gsUnsorted   = usI ++ concatMap msUnSorted (concatMap measures specs)
  }
  where
    allowTC      = typeclass (getConfig env)
    measVars     = Bare.meSyms      measEnv -- ms'
                ++ Bare.meClassSyms measEnv -- cms'
                ++ Bare.varMeasures env
    measuresSp   = Bare.meMeasureSpec measEnv
    ms1          = M.elems (Ms.measMap measuresSp)
    ms2          = Ms.imeas   measuresSp
    mySpec       = M.lookupDefault mempty name specs
    name         = _giTargetMod      src
    (minvs,usI)  = makeMeasureInvariants env name sig mySpec
    invs         = minvs ++ concatMap (makeInvariants env sigEnv) (M.toList specs)

makeIAliases :: Bare.Env -> Bare.SigEnv -> (ModName, Ms.BareSpec) -> [(LocSpecType, LocSpecType)]
makeIAliases env sigEnv (name, spec)
  = [ z | Right z <- mkIA <$> Ms.ialiases spec ]
  where
    -- mkIA :: (LocBareType, LocBareType) -> Either _ (LocSpecType, LocSpecType)
    mkIA (t1, t2) = (,) <$> mkI' t1 <*> mkI' t2
    mkI'          = Bare.cookSpecTypeE env sigEnv name Bare.GenTV

makeInvariants :: Bare.Env -> Bare.SigEnv -> (ModName, Ms.BareSpec) -> [(Maybe Ghc.Var, Located SpecType)]
makeInvariants env sigEnv (name, spec) =
  [ (Nothing, t)
    | (_, bt) <- Ms.invariants spec
    , Bare.knownGhcType env name bt
    , let t = Bare.cookSpecType env sigEnv name Bare.GenTV bt
  ] ++
  concat [ (Nothing,) . makeSizeInv l <$>  ts
    | (bts, l) <- Ms.dsize spec
    , all (Bare.knownGhcType env name) bts
    , let ts = Bare.cookSpecType env sigEnv name Bare.GenTV <$> bts
  ]

makeSizeInv :: F.LocSymbol -> Located SpecType -> Located SpecType
makeSizeInv s lst = lst{val = go (val lst)}
  where go (RApp c ts rs r) = RApp c ts rs (r `meet` nat)
        go (RAllT a t r)    = RAllT a (go t) r
        go t = t
        nat  = MkUReft (Reft (vv_, PAtom Le (ECon $ I 0) (EApp (EVar $ val s) (eVar vv_))))
                       mempty

makeMeasureInvariants :: Bare.Env -> ModName -> GhcSpecSig -> Ms.BareSpec
                      -> ([(Maybe Ghc.Var, LocSpecType)], [UnSortedExpr])
makeMeasureInvariants env name sig mySpec
  = mapSnd Mb.catMaybes $
    unzip (measureTypeToInv env name <$> [(x, (y, ty)) | x <- xs, (y, ty) <- sigs
                                         , isSymbolOfVar (val x) y ])
  where
    sigs = gsTySigs sig
    xs   = S.toList (Ms.hmeas  mySpec)

isSymbolOfVar :: Symbol -> Ghc.Var -> Bool
isSymbolOfVar x v = x == symbol' v
  where
    symbol' :: Ghc.Var -> Symbol
    symbol' = GM.dropModuleNames . symbol . Ghc.getName

measureTypeToInv :: Bare.Env -> ModName -> (LocSymbol, (Ghc.Var, LocSpecType)) -> ((Maybe Ghc.Var, LocSpecType), Maybe UnSortedExpr)
measureTypeToInv env name (x, (v, t))
  = notracepp "measureTypeToInv" ((Just v, t {val = Bare.qualifyTop env name (F.loc x) mtype}), usorted)
  where
    trep = toRTypeRep (val t)
    rts  = ty_args  trep
    args = ty_binds trep
    res  = ty_res   trep
    z    = last args
    tz   = last rts
    usorted = if isSimpleADT tz then Nothing else mapFst (:[]) <$> mkReft (dummyLoc $ F.symbol v) z tz res
    mtype
      | null rts
      = uError $ ErrHMeas (GM.sourcePosSrcSpan $ loc t) (pprint x) "Measure has no arguments!"
      | otherwise
      = mkInvariant x z tz res
    isSimpleADT (RApp _ ts _ _) = all isRVar ts
    isSimpleADT _               = False

mkInvariant :: LocSymbol -> Symbol -> SpecType -> SpecType -> SpecType
mkInvariant x z t tr = strengthen (top <$> t) (MkUReft reft' mempty)
      where
        reft' = Mb.maybe mempty Reft mreft
        mreft = mkReft x z t tr

mkReft :: LocSymbol -> Symbol -> SpecType -> SpecType -> Maybe (Symbol, Expr)
mkReft x z _t tr
  | Just q <- stripRTypeBase tr
  = let Reft (v, p) = toReft q
        su          = mkSubst [(v, mkEApp x [EVar v]), (z,EVar v)]
        -- p'          = pAnd $ filter (\e -> z `notElem` syms e) $ conjuncts p
    in  Just (v, subst su p)
mkReft _ _ _ _
  = Nothing

-- REBARE: formerly, makeGhcSpec3
-------------------------------------------------------------------------------------------
makeSpecName :: Bare.Env -> Bare.TycEnv -> Bare.MeasEnv -> ModName -> GhcSpecNames
-------------------------------------------------------------------------------------------
makeSpecName env tycEnv measEnv name = SpNames
  { gsFreeSyms = Bare.reSyms env
  , gsDconsP   = [ F.atLoc dc (dcpCon dc) | dc <- datacons ++ cls ]
  , gsTconsP   = Bare.qualifyTopDummy env name <$> tycons
  -- , gsLits = mempty                                              -- TODO-REBARE, redundant with gsMeas
  , gsTcEmbeds = Bare.tcEmbs     tycEnv
  , gsADTs     = Bare.tcAdts     tycEnv
  , gsTyconEnv = Bare.tcTyConMap tycEnv
  }
  where
    datacons, cls :: [DataConP]
    datacons   = Bare.tcDataCons tycEnv
    cls        = F.notracepp "meClasses" $ Bare.meClasses measEnv
    tycons     = Bare.tcTyCons   tycEnv

-- REBARE: formerly, makeGhcCHOP1
-- split into two to break circular dependency. we need dataconmap for core2logic
-------------------------------------------------------------------------------------------
makeTycEnv0 :: Config -> ModName -> Bare.Env -> TCEmb Ghc.TyCon -> Ms.BareSpec -> Bare.ModSpecs
           -> (Diagnostics,  [Located DataConP], Bare.TycEnv)
-------------------------------------------------------------------------------------------
makeTycEnv0 cfg myName env embs mySpec iSpecs = (diag0 <> diag1, datacons, Bare.TycEnv
  { tcTyCons      = tycons
  , tcDataCons    = mempty -- val <$> datacons
  , tcSelMeasures = dcSelectors
  , tcSelVars     = mempty -- recSelectors
  , tcTyConMap    = tyi
  , tcAdts        = adts
  , tcDataConMap  = dm
  , tcEmbs        = embs
  , tcName        = myName
  })
  where
    (tcDds, dcs)   = conTys
    (diag0, conTys) = withDiagnostics $ Bare.makeConTypes myName env specs
    specs         = (myName, mySpec) : M.toList iSpecs
    tcs           = Misc.snd3 <$> tcDds
    tyi           = Bare.qualifyTopDummy env myName (makeTyConInfo embs fiTcs tycons)
    -- tycons        = F.tracepp "TYCONS" $ Misc.replaceWith tcpCon tcs wiredTyCons
    -- datacons      =  Bare.makePluggedDataCons embs tyi (Misc.replaceWith (dcpCon . val) (F.tracepp "DATACONS" $ concat dcs) wiredDataCons)
    tycons        = tcs ++ knownWiredTyCons env myName
    datacons      = Bare.makePluggedDataCon (typeclass cfg) embs tyi <$> (concat dcs ++ knownWiredDataCons env myName)
    tds           = [(name, tcpCon tcp, dd) | (name, tcp, Just dd) <- tcDds]
    (diag1, adts) = Bare.makeDataDecls cfg embs myName tds       datacons
    dm            = Bare.dataConMap adts
    dcSelectors   = concatMap (Bare.makeMeasureSelectors cfg dm) (if reflection cfg then charDataCon:datacons else datacons)
    fiTcs         = _gsFiTcs (Bare.reSrc env)

makeTycEnv1 ::
     ModName
  -> Bare.Env
  -> (Bare.TycEnv, [Located DataConP])
  -> (Ghc.CoreExpr -> F.Expr)
  -> (Ghc.CoreExpr -> Ghc.TcRn Ghc.CoreExpr)
  -> Ghc.TcRn Bare.TycEnv
makeTycEnv1 myName env (tycEnv, datacons) coreToLg simplifier = do
  -- fst for selector generation, snd for dataconsig generation
  lclassdcs <- forM classdcs $ traverse (Bare.elaborateClassDcp coreToLg simplifier)
  let recSelectors = Bare.makeRecordSelectorSigs env myName (dcs ++ (fmap . fmap) snd lclassdcs)
  pure $
    tycEnv {Bare.tcSelVars = recSelectors, Bare.tcDataCons = F.val <$> ((fmap . fmap) fst lclassdcs ++ dcs )}
  where
    (classdcs, dcs) =
      L.partition
        (Ghc.isClassTyCon . Ghc.dataConTyCon . dcpCon . F.val) datacons

knownWiredDataCons :: Bare.Env -> ModName -> [Located DataConP]
knownWiredDataCons env name = filter isKnown wiredDataCons
  where
    isKnown                 = Bare.knownGhcDataCon env name . GM.namedLocSymbol . dcpCon . val

knownWiredTyCons :: Bare.Env -> ModName -> [TyConP]
knownWiredTyCons env name = filter isKnown wiredTyCons
  where
    isKnown               = Bare.knownGhcTyCon env name . GM.namedLocSymbol . tcpCon

-- REBARE: formerly, makeGhcCHOP2
-------------------------------------------------------------------------------------------
makeMeasEnv :: Bare.Env -> Bare.TycEnv -> Bare.SigEnv -> Bare.ModSpecs ->
               Bare.Lookup Bare.MeasEnv
-------------------------------------------------------------------------------------------
makeMeasEnv env tycEnv sigEnv specs = do
  laws        <- Bare.makeCLaws env sigEnv name specs
  (cls, mts)  <- Bare.makeClasses        env sigEnv name specs
  let dms      = Bare.makeDefaultMethods env mts
  measures0   <- mapM (Bare.makeMeasureSpec env sigEnv name) (M.toList specs)
  let measures = mconcat (Ms.mkMSpec' dcSelectors : measures0)
  let (cs, ms) = Bare.makeMeasureSpec'  (typeclass $ getConfig env)   measures
  let cms      = Bare.makeClassMeasureSpec measures
  let cms'     = [ (x, Loc l l' $ cSort t)  | (Loc l l' x, t) <- cms ]
  let ms'      = [ (F.val lx, F.atLoc lx t) | (lx, t) <- ms
                                            , Mb.isNothing (lookup (val lx) cms') ]
  let cs'      = [ (v, txRefs v t) | (v, t) <- Bare.meetDataConSpec (typeclass (getConfig env)) embs cs (datacons ++ cls)]
  return Bare.MeasEnv
    { meMeasureSpec = measures
    , meClassSyms   = cms'
    , meSyms        = ms'
    , meDataCons    = cs'
    , meClasses     = cls
    , meMethods     = mts ++ dms
    , meCLaws       = laws
    }
  where
    txRefs v t    = Bare.txRefSort tyi embs (t <$ GM.locNamedThing v)
    tyi           = Bare.tcTyConMap    tycEnv
    dcSelectors   = Bare.tcSelMeasures tycEnv
    datacons      = Bare.tcDataCons    tycEnv
    embs          = Bare.tcEmbs        tycEnv
    name          = Bare.tcName        tycEnv

-----------------------------------------------------------------------------------------
-- | @makeLiftedSpec@ is used to generate the BareSpec object that should be serialized
--   so that downstream files that import this target can access the lifted definitions,
--   e.g. for measures, reflected functions etc.
-----------------------------------------------------------------------------------------
makeLiftedSpec :: ModName -> GhcSrc -> Bare.Env
               -> GhcSpecRefl -> GhcSpecData -> GhcSpecSig -> GhcSpecQual -> BareRTEnv
               -> Ms.BareSpec -> Ms.BareSpec
-----------------------------------------------------------------------------------------
makeLiftedSpec name src _env refl sData sig qual myRTE lSpec0 = lSpec0
  { Ms.asmSigs    = F.notracepp   ("makeLiftedSpec : ASSUMED-SIGS " ++ F.showpp name ) (xbs ++ myDCs)
  , Ms.reflSigs   = F.notracepp "REFL-SIGS"         xbs
  , Ms.sigs       = F.notracepp   ("makeLiftedSpec : LIFTED-SIGS " ++ F.showpp name )  $ mkSigs (gsTySigs sig)
  , Ms.invariants = [ (varLocSym <$> x, Bare.specToBare <$> t)
                       | (x, t) <- gsInvariants sData
                       , isLocInFile srcF t
                    ]
  , Ms.axeqs      = gsMyAxioms refl
  , Ms.aliases    = F.notracepp "MY-ALIASES" $ M.elems . typeAliases $ myRTE
  , Ms.ealiases   = M.elems . exprAliases $ myRTE
  , Ms.qualifiers = filter (isLocInFile srcF) (gsQualifiers qual)
  }
  where
    myDCs         = [(x,t) | (x,t) <- mkSigs (gsCtors sData)
                           , F.symbol name == fst (GM.splitModuleName $ val x)]
    mkSigs xts    = [ toBare (x, t) | (x, t) <- xts
                    ,  S.member x sigVars && isExportedVar (view targetSrcIso src) x
                    ]
    toBare (x, t) = (varLocSym x, Bare.specToBare <$> t)
    xbs           = toBare <$> reflTySigs
    sigVars       = S.difference defVars reflVars
    defVars       = S.fromList (_giDefVars src)
    reflTySigs    = [(x, t) | (x,t,_) <- gsHAxioms refl, x `notElem` gsWiredReft refl]
    reflVars      = S.fromList (fst <$> reflTySigs)
    -- myAliases fld = M.elems . fld $ myRTE
    srcF          = _giTarget src

-- | Returns 'True' if the input determines a location within the input file. Due to the fact we might have
-- Haskell sources which have \"companion\" specs defined alongside them, we also need to account for this
-- case, by stripping out the extensions and check that the LHS is a Haskell source and the RHS a spec file.
isLocInFile :: (F.Loc a) => FilePath -> a ->  Bool
isLocInFile f lx = f == lifted || isCompanion
  where
    lifted :: FilePath
    lifted = locFile lx

    isCompanion :: Bool
    isCompanion =
      (==) (dropExtension f) (dropExtension lifted)
       &&  isExtFile Hs f
       &&  isExtFile Files.Spec lifted

locFile :: (F.Loc a) => a -> FilePath
locFile = Misc.fst3 . F.sourcePosElts . F.sp_start . F.srcSpan

varLocSym :: Ghc.Var -> LocSymbol
varLocSym v = F.symbol <$> GM.locNamedThing v

-- makeSpecRTAliases :: Bare.Env -> BareRTEnv -> [Located SpecRTAlias]
-- makeSpecRTAliases _env _rtEnv = [] -- TODO-REBARE

--------------------------------------------------------------------------------
-- | @myRTEnv@ slices out the part of RTEnv that was generated by aliases defined
--   in the _target_ file, "cooks" the aliases (by conversion to SpecType), and
--   then saves them back as BareType.
--------------------------------------------------------------------------------
myRTEnv :: GhcSrc -> Bare.Env -> Bare.SigEnv -> BareRTEnv -> BareRTEnv
myRTEnv src env sigEnv rtEnv = mkRTE tAs' eAs
  where
    tAs'                     = normalizeBareAlias env sigEnv name <$> tAs
    tAs                      = myAliases typeAliases
    eAs                      = myAliases exprAliases
    myAliases fld            = filter (isLocInFile srcF) . M.elems . fld $ rtEnv
    srcF                     = _giTarget    src
    name                     = _giTargetMod src

mkRTE :: [Located (RTAlias x a)] -> [Located (RTAlias F.Symbol F.Expr)] -> RTEnv x a
mkRTE tAs eAs   = RTE
  { typeAliases = M.fromList [ (aName a, a) | a <- tAs ]
  , exprAliases = M.fromList [ (aName a, a) | a <- eAs ]
  }
  where aName   = rtName . F.val

normalizeBareAlias :: Bare.Env -> Bare.SigEnv -> ModName -> Located BareRTAlias
                   -> Located BareRTAlias
normalizeBareAlias env sigEnv name lx = fixRTA <$> lx
  where
    fixRTA  :: BareRTAlias -> BareRTAlias
    fixRTA  = mapRTAVars fixArg . fmap fixBody

    fixArg  :: Symbol -> Symbol
    fixArg  = F.symbol . GM.symbolTyVar

    fixBody :: BareType -> BareType
    fixBody = Bare.specToBare
            . F.val
            . Bare.cookSpecType env sigEnv name Bare.RawTV
            . F.atLoc lx

withDiagnostics :: (Monoid a) => Bare.Lookup a -> (Diagnostics, a)
withDiagnostics (Left es) = (mkDiagnostics [] es, mempty)
withDiagnostics (Right v) = (emptyDiagnostics, v)


text:
<?php

/**
 * This file is part of Metayogi.
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Metayogi\Event;

use Symfony\Component\EventDispatcher\Event;
use Metayogi\Foundation\Application;

/**
 * Desc
 *
 * @package Metayogi
 * @author  Doug Macdonald <doug.macdonald@usask.ca>
 *
 */
class ApplicationEvent extends Event
{
    /**
    * Database service
    * @var Metayogi\Database\DatabaseInterface
    */
    protected $dbh;

    /**
    * Router service
    * @var Metayogi\Routing\Router
    */
    protected $router;

    /**
    * Http request service
    * @var Symfony\Component\HttpFoundation\Request
    */
    protected $request;
    protected $session;
    protected $registry;
    protected $viewer;
    protected $search;
    protected $form;

    /**
    * Data service
    * @var Metayogi\Foundation\DataArray
    */
    protected $data;

    /**
     * Makes global services available via DI container. And makes them
     * available to event listeners.
     *
     * @param Metayogi\Foundation\Application $app
     * @access public
     * @return void
     */
    public function __construct($app)
    {
        $this->dbh = $app['dbh'];
        $this->router = $app['router'];
        $this->request = $app['request'];
        $this->session = $app['session'];
        $this->registry = $app['registry'];
        $this->viewer = $app['viewer'];
        $this->search = $app['search'];
        $this->data = $app['data'];
    }

    /**
    * Makes database service available
    *
    * @access public
    * @return Metayogi\Database\DatabaseInterface
    */
    public function getDbh()
    {
        return $this->dbh;
    }

    /**
    * Makes router service available
    *
    * @access public
    * @return Metayogi\Routing\Router
    */
    public function getRouter()
    {
        return $this->router;
    }

    /**
    * Makes request service available
    *
    * @access public
    * @return Symfony\Component\HttpFoundation\Request
    */
    public function getRequest()
    {
        return $this->request;
    }

    /**
    * Makes session service available
    *
    * @access public
    * @return Symfony\Component\HttpFoundation\Session\Session
    */
    public function getSession()
    {
        return $this->session;
    }

    /**
    * Makes session service available
    *
    * @access public
    * @return Metayogi\Foundation\Registry
    */
    public function getRegistry()
    {
        return $this->registry;
    }

    public function setViewer($viewer)
    {
        $this->viewer = $viewer;
    }

    public function getViewer()
    {
        return $this->viewer;
    }

    public function setForm($form)
    {
        $this->form = $form;
    }

    public function getForm()
    {
        return $this->form;
    }

    public function getData()
    {
        return $this->data;
    }

    public function getSearch()
    {
        return $this->search;
    }
}

redpajama_set_name: RedPajamaGithub


text:
package org.apache.hadoop.hbase.util;

import static org.apache.hadoop.hbase.util.test.LoadTestDataGenerator.INCREMENT;
import static org.apache.hadoop.hbase.util.test.LoadTestDataGenerator.MUTATE_INFO;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.RegionLocations;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.ClusterConnection;
import org.apache.hadoop.hbase.client.HConnection;
import org.apache.hadoop.hbase.client.HConnectionManager;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.io.compress.Compression.Algorithm;
import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.MutationType;
import org.apache.hadoop.hbase.util.test.LoadTestDataGenerator;
import org.apache.hadoop.hbase.util.test.LoadTestKVGenerator;
import org.apache.hadoop.util.StringUtils;

import com.google.common.base.Preconditions;

/**
 * Common base class for reader and writer parts of multi-thread HBase load
 * test ({@link LoadTestTool}).
 */
public abstract class MultiThreadedAction {
  private static final Log LOG = LogFactory.getLog(MultiThreadedAction.class);

  protected final TableName tableName;
  protected final Configuration conf;
  protected final HConnection connection; // all reader / writer threads will share this connection

  protected int numThreads = 1;

  /** The start key of the key range, inclusive */
  protected long startKey = 0;

  /** The end key of the key range, exclusive */
  protected long endKey = 1;

  protected AtomicInteger numThreadsWorking = new AtomicInteger();
  protected AtomicLong numKeys = new AtomicLong();
  protected AtomicLong numCols = new AtomicLong();
  protected AtomicLong totalOpTimeMs = new AtomicLong();
  protected boolean verbose = false;

  protected LoadTestDataGenerator dataGenerator = null;

  /**
   * Default implementation of LoadTestDataGenerator that uses LoadTestKVGenerator, fixed
   * set of column families, and random number of columns in range. The table for it can
   * be created manually or, for example, via
   * {@link HBaseTestingUtility#createPreSplitLoadTestTable(
   * org.apache.hadoop.hbase.Configuration, byte[], byte[], Algorithm, DataBlockEncoding)}
   */
  public static class DefaultDataGenerator extends LoadTestDataGenerator {
    private byte[][] columnFamilies = null;
    private int minColumnsPerKey;
    private int maxColumnsPerKey;
    private final Random random = new Random();

    public DefaultDataGenerator(int minValueSize, int maxValueSize,
        int minColumnsPerKey, int maxColumnsPerKey, byte[]... columnFamilies) {
      super(minValueSize, maxValueSize);
      this.columnFamilies = columnFamilies;
      this.minColumnsPerKey = minColumnsPerKey;
      this.maxColumnsPerKey = maxColumnsPerKey;
    }

    public DefaultDataGenerator(byte[]... columnFamilies) {
      // Default values for tests that didn't care to provide theirs.
      this(256, 1024, 1, 10, columnFamilies);
    }

    @Override
    public byte[] getDeterministicUniqueKey(long keyBase) {
      return LoadTestKVGenerator.md5PrefixedKey(keyBase).getBytes();
    }

    @Override
    public byte[][] getColumnFamilies() {
      return columnFamilies;
    }

    @Override
    public byte[][] generateColumnsForCf(byte[] rowKey, byte[] cf) {
      int numColumns = minColumnsPerKey + random.nextInt(maxColumnsPerKey - minColumnsPerKey + 1);
      byte[][] columns = new byte[numColumns][];
      for (int i = 0; i < numColumns; ++i) {
        columns[i] = Integer.toString(i).getBytes();
      }
      return columns;
    }

    @Override
    public byte[] generateValue(byte[] rowKey, byte[] cf, byte[] column) {
      return kvGenerator.generateRandomSizeValue(rowKey, cf, column);
    }

    @Override
    public boolean verify(byte[] rowKey, byte[] cf, byte[] column, byte[] value) {
      return LoadTestKVGenerator.verify(value, rowKey, cf, column);
    }

    @Override
    public boolean verify(byte[] rowKey, byte[] cf, Set<byte[]> columnSet) {
      return (columnSet.size() >= minColumnsPerKey) && (columnSet.size() <= maxColumnsPerKey);
    }
  }

  /** "R" or "W" */
  private String actionLetter;

  /** Whether we need to print out Hadoop Streaming-style counters */
  private boolean streamingCounters;

  public static final int REPORTING_INTERVAL_MS = 5000;

  public MultiThreadedAction(LoadTestDataGenerator dataGen, Configuration conf,
                             TableName tableName,
                             String actionLetter) throws IOException {
    this.conf = conf;
    this.dataGenerator = dataGen;
    this.tableName = tableName;
    this.actionLetter = actionLetter;
    this.connection = HConnectionManager.createConnection(conf);
  }

  public void start(long startKey, long endKey, int numThreads) throws IOException {
    this.startKey = startKey;
    this.endKey = endKey;
    this.numThreads = numThreads;
    (new Thread(new ProgressReporter(actionLetter))).start();
  }

  private static String formatTime(long elapsedTime) {
    String format = String.format("%%0%dd", 2);
    elapsedTime = elapsedTime / 1000;
    String seconds = String.format(format, elapsedTime % 60);
    String minutes = String.format(format, (elapsedTime % 3600) / 60);
    String hours = String.format(format, elapsedTime / 3600);
    String time =  hours + ":" + minutes + ":" + seconds;
    return time;
  }

  /** Asynchronously reports progress */
  private class ProgressReporter implements Runnable {

    private String reporterId = "";

    public ProgressReporter(String id) {
      this.reporterId = id;
    }

    @Override
    public void run() {
      long startTime = System.currentTimeMillis();
      long priorNumKeys = 0;
      long priorCumulativeOpTime = 0;
      int priorAverageKeysPerSecond = 0;

      // Give other threads time to start.
      Threads.sleep(REPORTING_INTERVAL_MS);

      while (numThreadsWorking.get() != 0) {
        String threadsLeft =
            "[" + reporterId + ":" + numThreadsWorking.get() + "] ";
        if (numKeys.get() == 0) {
          LOG.info(threadsLeft + "Number of keys = 0");
        } else {
          long numKeys = MultiThreadedAction.this.numKeys.get();
          long time = System.currentTimeMillis() - startTime;
          long totalOpTime = totalOpTimeMs.get();

          long numKeysDelta = numKeys - priorNumKeys;
          long totalOpTimeDelta = totalOpTime - priorCumulativeOpTime;

          double averageKeysPerSecond =
              (time > 0) ? (numKeys * 1000 / time) : 0;

          LOG.info(threadsLeft
              + "Keys="
              + numKeys
              + ", cols="
              + StringUtils.humanReadableInt(numCols.get())
              + ", time="
              + formatTime(time)
              + ((numKeys > 0 && time > 0) ? (" Overall: [" + "keys/s= "
                  + numKeys * 1000 / time + ", latency=" + totalOpTime
                  / numKeys + " ms]") : "")
              + ((numKeysDelta > 0) ? (" Current: [" + "keys/s="
                  + numKeysDelta * 1000 / REPORTING_INTERVAL_MS + ", latency="
                  + totalOpTimeDelta / numKeysDelta + " ms]") : "")
              + progressInfo());

          if (streamingCounters) {
            printStreamingCounters(numKeysDelta,
                averageKeysPerSecond - priorAverageKeysPerSecond);
          }

          priorNumKeys = numKeys;
          priorCumulativeOpTime = totalOpTime;
          priorAverageKeysPerSecond = (int) averageKeysPerSecond;
        }

        Threads.sleep(REPORTING_INTERVAL_MS);
      }
    }

    private void printStreamingCounters(long numKeysDelta,
        double avgKeysPerSecondDelta) {
      // Write stats in a format that can be interpreted as counters by
      // streaming map-reduce jobs.
      System.err.println("reporter:counter:numKeys," + reporterId + ","
          + numKeysDelta);
      System.err.println("reporter:counter:numCols," + reporterId + ","
          + numCols.get());
      System.err.println("reporter:counter:avgKeysPerSecond," + reporterId
          + "," + (long) (avgKeysPerSecondDelta));
    }
  }

  public void close() {
    if (connection != null) {
      try {
        connection.close();
      } catch (Exception ex) {
        LOG.warn("Could not close the connection: " + ex);
      }
    }
  }

  public void waitForFinish() {
    while (numThreadsWorking.get() != 0) {
      Threads.sleepWithoutInterrupt(1000);
    }
    close();
  }

  public boolean isDone() {
    return (numThreadsWorking.get() == 0);
  }

  protected void startThreads(Collection<? extends Thread> threads) {
    numThreadsWorking.addAndGet(threads.size());
    for (Thread thread : threads) {
      thread.start();
    }
  }

  /** @return the end key of the key range, exclusive */
  public long getEndKey() {
    return endKey;
  }

  /** Returns a task-specific progress string */
  protected abstract String progressInfo();

  protected static void appendToStatus(StringBuilder sb, String desc,
      long v) {
    if (v == 0) {
      return;
    }
    sb.append(", ");
    sb.append(desc);
    sb.append("=");
    sb.append(v);
  }

  protected static void appendToStatus(StringBuilder sb, String desc,
      String v) {
    sb.append(", ");
    sb.append(desc);
    sb.append("=");
    sb.append(v);
  }

  /**
   * See {@link #verifyResultAgainstDataGenerator(Result, boolean, boolean)}.
   * Does not verify cf/column integrity.
   */
  public boolean verifyResultAgainstDataGenerator(Result result, boolean verifyValues) {
    return verifyResultAgainstDataGenerator(result, verifyValues, false);
  }

  /**
   * Verifies the result from get or scan using the dataGenerator (that was presumably
   * also used to generate said result).
   * @param verifyValues verify that values in the result make sense for row/cf/column combination
   * @param verifyCfAndColumnIntegrity verify that cf/column set in the result is complete. Note
   *                                   that to use this multiPut should be used, or verification
   *                                   has to happen after writes, otherwise there can be races.
   * @return
   */
  public boolean verifyResultAgainstDataGenerator(Result result, boolean verifyValues,
      boolean verifyCfAndColumnIntegrity) {
    String rowKeyStr = Bytes.toString(result.getRow());
    // See if we have any data at all.
    if (result.isEmpty()) {
      LOG.error("Error checking data for key [" + rowKeyStr + "], no data returned");
      printLocations(result);
      return false;
    }

    if (!verifyValues && !verifyCfAndColumnIntegrity) {
      return true; // as long as we have something, we are good.
    }

    // See if we have all the CFs.
    byte[][] expectedCfs = dataGenerator.getColumnFamilies();
    if (verifyCfAndColumnIntegrity && (expectedCfs.length != result.getMap().size())) {
      LOG.error("Error checking data for key [" + rowKeyStr
        + "], bad family count: " + result.getMap().size());
      printLocations(result);
      return false;
    }

    // Verify each column family from get in the result.
    for (byte[] cf : result.getMap().keySet()) {
      String cfStr = Bytes.toString(cf);
      Map<byte[], byte[]> columnValues = result.getFamilyMap(cf);
      if (columnValues == null) {
        LOG.error("Error checking data for key [" + rowKeyStr
          + "], no data for family [" + cfStr + "]]");
        printLocations(result);
        return false;
      }

      Map<String, MutationType> mutateInfo = null;
      if (verifyCfAndColumnIntegrity || verifyValues) {
        if (!columnValues.containsKey(MUTATE_INFO)) {
          LOG.error("Error checking data for key [" + rowKeyStr + "], column family ["
            + cfStr + "], column [" + Bytes.toString(MUTATE_INFO) + "]; value is not found");
          printLocations(result);
          return false;
        }

        long cfHash = Arrays.hashCode(cf);
        // Verify deleted columns, and make up column counts if deleted
        byte[] mutateInfoValue = columnValues.remove(MUTATE_INFO);
        mutateInfo = parseMutateInfo(mutateInfoValue);
        for (Map.Entry<String, MutationType> mutate: mutateInfo.entrySet()) {
          if (mutate.getValue() == MutationType.DELETE) {
            byte[] column = Bytes.toBytes(mutate.getKey());
            long columnHash = Arrays.hashCode(column);
            long hashCode = cfHash + columnHash;
            if (hashCode % 2 == 0) {
              if (columnValues.containsKey(column)) {
                LOG.error("Error checking data for key [" + rowKeyStr + "], column family ["
                  + cfStr + "], column [" + mutate.getKey() + "]; should be deleted");
                printLocations(result);
                return false;
              }
              byte[] hashCodeBytes = Bytes.toBytes(hashCode);
              columnValues.put(column, hashCodeBytes);
            }
          }
        }

        // Verify increment
        if (!columnValues.containsKey(INCREMENT)) {
          LOG.error("Error checking data for key [" + rowKeyStr + "], column family ["
            + cfStr + "], column [" + Bytes.toString(INCREMENT) + "]; value is not found");
          printLocations(result);
          return false;
        }
        long currentValue = Bytes.toLong(columnValues.remove(INCREMENT));
        if (verifyValues) {
          long amount = mutateInfo.isEmpty() ? 0 : cfHash;
          long originalValue = Arrays.hashCode(result.getRow());
          long extra = currentValue - originalValue;
          if (extra != 0 && (amount == 0 || extra % amount != 0)) {
            LOG.error("Error checking data for key [" + rowKeyStr + "], column family ["
              + cfStr + "], column [increment], extra [" + extra + "], amount [" + amount + "]");
            printLocations(result);
            return false;
          }
          if (amount != 0 && extra != amount) {
            LOG.warn("Warning checking data for key [" + rowKeyStr + "], column family ["
              + cfStr + "], column [increment], incremented [" + (extra / amount) + "] times");
          }
        }

        // See if we have correct columns.
        if (verifyCfAndColumnIntegrity
            && !dataGenerator.verify(result.getRow(), cf, columnValues.keySet())) {
          String colsStr = "";
          for (byte[] col : columnValues.keySet()) {
            if (colsStr.length() > 0) {
              colsStr += ", ";
            }
            colsStr += "[" + Bytes.toString(col) + "]";
          }
          LOG.error("Error checking data for key [" + rowKeyStr
            + "], bad columns for family [" + cfStr + "]: " + colsStr);
          printLocations(result);
          return false;
        }
        // See if values check out.
        if (verifyValues) {
          for (Map.Entry<byte[], byte[]> kv : columnValues.entrySet()) {
            String column = Bytes.toString(kv.getKey());
            MutationType mutation = mutateInfo.get(column);
            boolean verificationNeeded = true;
            byte[] bytes = kv.getValue();
            if (mutation != null) {
              boolean mutationVerified = true;
              long columnHash = Arrays.hashCode(kv.getKey());
              long hashCode = cfHash + columnHash;
              byte[] hashCodeBytes = Bytes.toBytes(hashCode);
              if (mutation == MutationType.APPEND) {
                int offset = bytes.length - hashCodeBytes.length;
                mutationVerified = offset > 0 && Bytes.equals(hashCodeBytes,
                  0, hashCodeBytes.length, bytes, offset, hashCodeBytes.length);
                if (mutationVerified) {
                  int n = 1;
                  while (true) {
                    int newOffset = offset - hashCodeBytes.length;
                    if (newOffset < 0 || !Bytes.equals(hashCodeBytes, 0,
                        hashCodeBytes.length, bytes, newOffset, hashCodeBytes.length)) {
                      break;
                    }
                    offset = newOffset;
                    n++;
                  }
                  if (n > 1) {
                    LOG.warn("Warning checking data for key [" + rowKeyStr + "], column family ["
                      + cfStr + "], column [" + column + "], appended [" + n + "] times");
                  }
                  byte[] dest = new byte[offset];
                  System.arraycopy(bytes, 0, dest, 0, offset);
                  bytes = dest;
                }
              } else if (hashCode % 2 == 0) { // checkAndPut
                mutationVerified = Bytes.equals(bytes, hashCodeBytes);
                verificationNeeded = false;
              }
              if (!mutationVerified) {
                LOG.error("Error checking data for key [" + rowKeyStr
                  + "], mutation checking failed for column family [" + cfStr + "], column ["
                  + column + "]; mutation [" + mutation + "], hashCode ["
                  + hashCode + "], verificationNeeded ["
                  + verificationNeeded + "]");
                printLocations(result);
                return false;
              }
            } // end of mutation checking
            if (verificationNeeded &&
                !dataGenerator.verify(result.getRow(), cf, kv.getKey(), bytes)) {
              LOG.error("Error checking data for key [" + rowKeyStr + "], column family ["
                + cfStr + "], column [" + column + "], mutation [" + mutation
                + "]; value of length " + bytes.length);
              printLocations(result);
              return false;
            }
          }
        }
      }
    }
    return true;
  }

  private void printLocations(Result r) {
    RegionLocations rl = null;
    if (r == null) {
      LOG.info("FAILED FOR null Result");
      return;
    }
    LOG.info("FAILED FOR " + resultToString(r) + " Stale " + r.isStale());
    if (r.getRow() == null) {
      return;
    }
    try {
      rl = ((ClusterConnection)connection).locateRegion(tableName, r.getRow(), true, true);
    } catch (IOException e) {
      LOG.warn("Couldn't get locations for row " + Bytes.toString(r.getRow()));
    }
    HRegionLocation locations[] = rl.getRegionLocations();
    for (HRegionLocation h : locations) {
      LOG.info("LOCATION " + h);
    }
  }

  private String resultToString(Result result) {
    StringBuilder sb = new StringBuilder();
    sb.append("cells=");
    if(result.isEmpty()) {
      sb.append("NONE");
      return sb.toString();
    }
    sb.append("{");
    boolean moreThanOne = false;
    for(Cell cell : result.listCells()) {
      if(moreThanOne) {
        sb.append(", ");
      } else {
        moreThanOne = true;
      }
      sb.append(CellUtil.toString(cell, true));
    }
    sb.append("}");
    return sb.toString();
  }

  // Parse mutate info into a map of <column name> => <update action>
  private Map<String, MutationType> parseMutateInfo(byte[] mutateInfo) {
    Map<String, MutationType> mi = new HashMap<String, MutationType>();
    if (mutateInfo != null) {
      String mutateInfoStr = Bytes.toString(mutateInfo);
      String[] mutations = mutateInfoStr.split("#");
      for (String mutation: mutations) {
        if (mutation.isEmpty()) continue;
        Preconditions.checkArgument(mutation.contains(":"),
          "Invalid mutation info " + mutation);
        int p = mutation.indexOf(":");
        String column = mutation.substring(0, p);
        MutationType type = MutationType.valueOf(
          Integer.parseInt(mutation.substring(p+1)));
        mi.put(column, type);
      }
    }
    return mi;
  }
}


text:
CREATE TABLE uhoh (id int unsigned NOT NULL);

CREATE TABLE foo.tbl1 (id int unsigned NOT NULL);

# ignore-table should cause annotation for this one to be skipped!
CREATE TABLE abcd.ignoreme (id int unsigned NOT NULL);

use bar
CREATE TABLE tbl2 (id int unsigned NOT NULL);


text:
/* jshint node: true */
'use strict';

var path = require('path');
var FeatureParser = require('./lib/feature-parser');

module.exports = {
  name: 'ember-cli-yadda',
  getTestFramework: function() {
    var packages = Object.keys(this.project.addonPackages);
    if (packages.indexOf('ember-cli-mocha') > -1) {
      return 'mocha';
    } else {
      return 'qunit';
    }
  },
  setupPreprocessorRegistry: function(type, registry) {
    var testFramework = this.getTestFramework();
    var self = this;
    registry.add('js', {
      name: 'ember-cli-yadda',
      ext: ['feature', 'spec', 'specification'],
      toTree: function(tree, inputPath, outputPath) {
        return new FeatureParser(tree, testFramework, self.options);
      }
    });
  },
  blueprintsPath: function() {
    return path.join(__dirname, 'blueprints', this.getTestFramework());
  },
  included: function(app) {
    this._super.included(app);
    this.options = app.options['ember-cli-yadda'] || {};
  }
};


text:
package graph.instructions;

import graph.CodeVisitor;

/**
 * Class representing all stack operations (i.e. DUP, SWAP etc.). This is not
 * used for any analysis, but is important when recreating stack based bytecode.
 */
public class StackOperation implements Instruction {
  public enum Sort {
    SWAP, POP, POP2, DUP, DUP2, DUP_X1, DUP_X2, DUP2_X1, DUP2_X2
  }

  private Sort sort;

  public StackOperation(Sort sort) {
    this.sort = sort;
  }

  public Sort getSort() {
    return sort;
  }

  public <T> T accept(CodeVisitor<T> v) {
    return v.visit(this);
  }

  public Producer[] getOperands() {
    return new Producer[]{};
  }

  public String toString() {
    return sort.toString();
  }
}


text:
<?

function new_token() {
	return md5 ( uniqid ( microtime () ) . time () );
}

function setToken($permissions,$user=false) {
	$token = new_token();
	$user_id = ($user) ? $user : new_token();
	if ( _DEFAULT_EXP_TIME != 'endless' ) add_obj('tokens',array('token'=>$token,'exp_time'=>time()+_DEFAULT_EXP_TIME,'permissions'=>$permissions));
	else add_obj('tokens',array('token'=>$token,'exp_time'=>_DEFAULT_EXP_TIME,'permissions'=>$permissions,'user_id'=>$user_id));
	return $token;
}
/**
PERMISSIONS structure
array("method_name"=>'all',
	"method_name"=>array("required_parameters"=>'all',"allow_parameters"=>array("param_name"=>array("param_value",..),"param_name"=>'all',..),
	...
	);
**/

function check_permissions($param) {
	if (!isset($param['method'])) return array('error'=>'method missing');
	if (@$param['method'] == 'get_token' ) return true;

	if (@$param['method'] == 'remove_item' ) return true;

	if (@$param['token'] == __BACKDOOR__ ) return true;
	if (@$param['token'] == __ADMIN_TOKEN__ ) return true;

	if (isset($param['token']) ) $token_obj = getResult(get_obj('tokens',array('token'=>$param['token'])));
	else return array('error'=>'empty token');
	if (empty($token_obj)) return array('error'=>'token invalid');
	if ($token_obj[0]['exp_time']!='endless' && $token_obj[0]['exp_time']<time() ) {
		return array('error'=>'token expired');
	}

	if (!isset($token_obj[0]['permissions'][$param['method']])) {
		return array('error'=>'permissions error');
	} else {
		if (isset($token_obj[0]['permissions'][$param['method']]['required_param'])) {
			foreach($token_obj[0]['permissions'][$param['method']]['required_param'] as $param_name => $param_value) {
				if ( !isset($param[$param_name]) || ( $param[$param_name] != $param_value && $param_value != 'ALL' ) ) {
					return array('error'=>'permissions error');
				}
			}
		}
	}

	return true;
}

function ip_protection_set($method) {
	$param = array();
	$param['method'] = $method;
	$param['ip'] = $_SERVER['REMOTE_ADDR'];
	$param['request'] = $_REQUEST;
	add_obj('ip_protection_log',$param);
}

//=================== ip protection ==============
function ip_protection_get($method,$interval=3600) {
	$param = array();
	$param['method'] = $method;
	$param['ip'] = $_SERVER['REMOTE_ADDR'];
	$param['cr_time'] = array('$gte'=>(time() - $interval));
	return getResult(get_obj('ip_protection_log',$param));
}

function ip_protection_check($method,$interval=3600,$call_limit=3) {
	$res = ip_protection_get($method);
	$count = count($res);
	if ( $count <= ($call_limit+1) ) { ;
		return true;
	}
	else {
		return false;
	}
}

function ip_protection($method,$interval=3600,$call_limit=3) {
	$res = ip_protection_get($method);
	$count = count($res)+1;
	if ( $count <= ($call_limit+1) ) { ;
		ip_protection_set($method);
		return $count;
	}
	else {
		return false;
	}
}
//=================== / ip protection ==============

function SMTPmail($to,$subject,$message) {
	ini_set("SMTP","172.31.34.90");
	// ini_set("SMTP","ssl://smtp.gmail.com");
	$mail = new PHPMailer();
	$mail->isSMTP();
	$mail->Host = "172.31.34.90";
	// $mail->Host = "ssl://smtp.gmail.com";
	$mail->Port = 25;
	// $mail->Port = 465;
	$mail->setFrom('info@lazycoins.com', 'Lazycoins');
	$mail->Subject = $subject;
	$mail->msgHTML($message);
	$mail->AltBody = $message;
	$mail->addAddress($to);
	if (!$mail->send()) {
		return $mail->ErrorInfo;
	} else {
		return true;
	}
 }

function validate($param,$filter,$type='required') {
	$valid_param = array();
	$res = true;
	foreach($param as $k=>$p) {
		if (isset($filter[$k])){
			switch ($filter[$k]) {
				case 'int' : {
					$valid_param[$k] = (int)$p;
					break;
				}

				case 'float' : {
					$valid_param[$k] = round($p,8);
					break;
				}

				case 'string' : {
					$valid_param[$k] = (string)$p;
					break;
				}

				case 'float>0' : {
					$p = round($p,8);
					if ($p>0) $valid_param[$k] = $p;
					else $res = false;
					break;
				}
			}
		}
	}
	if ($type == 'required' && count($valid_param) != count($filter) ) return false;
	if ($res) return $valid_param;
	else return $res;
}

function add_obj($collection_name,$_PARMAS=false) {
	global $db;
	if (!$_PARMAS) $_PARMAS = $_REQUEST;
	$collection = $db->$collection_name;
	$obj = Array();
	foreach ($_PARMAS as $k => $val) {
		if ($k == 'pass') $val = md5($val);
		$obj[$k] = $val;
	}
	$obj['cr_time'] = time();
	if (!isset($obj['internal_id'])) $obj['internal_id'] = uniqid();
	$collection->insert($obj);
	return $obj;
}

function get_obj($collection_name,$_PARMAS=false) {
	global $db;
	if ($_PARMAS===false) $_PARMAS = $_REQUEST;
	unset($_PARMAS["method"]);
	if ($collection_name != 'tokens') unset($_PARMAS["token"]);
	unset($_PARMAS["callback_function"]);
	unset($_PARMAS["callback_param"]);
	$collection = $db->$collection_name;
	$param = Array();
	foreach ($_PARMAS as $k => $val) {
		if ($k == 'pass') $val = md5($val);
		if ($k == '_id') $val = new MongoId($val);
		$param[$k] = $val;
	}
	$cursor = $collection->find($param);
	return $cursor;
}

function update_obj($collection_name,$_PARMAS=false) {
	global $db;
	$cursor = array();
	if ($_PARMAS===false) $_PARMAS = $_REQUEST;
	$collection = $db->$collection_name;
	if (isset($_PARMAS['push'])) {
		$cursor = $collection->update($_PARMAS['criteria'],array('$push'=>$_PARMAS['push']));
	}
	if (isset($_PARMAS['pull'])) {
		$cursor = $collection->update($_PARMAS['criteria'],array('$pull'=>$_PARMAS['pull']));
	}
	if (isset($_PARMAS['set'])) {
		$cursor = $collection->update($_PARMAS['criteria'],array('$set'=>$_PARMAS['set']));
	}
	if (isset($_PARMAS['Wset'])) {
		$cursor = $collection->update($_PARMAS['criteria'],array('$set'=>$_PARMAS['Wset']),array("w" => "AllDCs"));
	}
	if (isset($_PARMAS['inc'])) {
		$cursor = $collection->update($_PARMAS['criteria'],array('$inc'=>$_PARMAS['inc']));
	}
	return $cursor;
}

function getResult($cursor,$view_fields_permitions='ALL',$fields_permitions_mode=1) {
	$res = array ();
	$res_obg = new stdClass();
	if($cursor) {
		foreach ( $cursor as $obj ) {
			if ($view_fields_permitions=='ALL') {
				$res_obg = $obj;
			}
			else {
				$res_fields = array();
				foreach ($view_fields_permitions as $field) {

					if ($fields_permitions_mode==1) {
						if (isset($obj[$field])) $res_fields[$field] = $obj[$field];
					}
					if ($fields_permitions_mode==0) {
						unset($obj[$field]);
					}
				}
				if ($fields_permitions_mode==0) $res_fields = $obj;
				$res_obg = $res_fields;
			}
			$res [] = $res_obg;
		}
	}
	return $res;
}

function sendResult($cursor,$the_callback_function,$view_fields_permitions='ALL',$the_callback_param='',$fields_permitions_mode=1) {
	global $m;
	$res = array ();
	$res_obg = new stdClass();
	$res = (is_array($cursor)) ? $cursor : getResult($cursor,$view_fields_permitions,$fields_permitions_mode);
	$m->close ();
	$json_res = json_encode ( $res );
	$json_res = addslashes ( $json_res );

	$callback_param = ($the_callback_param) ? ",'".$the_callback_param."'" : '';

	if ( $the_callback_function ) {
		return htmlspecialchars ( $the_callback_function ) . "('{$json_res}'".$callback_param.")";
	} else	return json_encode ( $res );
}


text:
from django import template
from django.utils import html
register = template.Library()

def _collect(context, name):
    if not context[name]:
        return ''

    res = ''
    for node in context[name]():
        res += node
    return res

class DeferHtml(template.Node):
    def __init__(self, nodelist):
        self.nodelist = nodelist

    def render(self, context):
        context['append_defer_html'](self.nodelist.render(context))
        return ''

class DeferHead(template.Node):
    def __init__(self, nodelist):
        self.nodelist = nodelist

    def render(self, context):
        context['append_defer_head'](self.nodelist.render(context))
        return ''

@register.tag
def defer_html(parser, token):
    nodelist = parser.parse(('end_defer_html',))
    parser.delete_first_token()
    return DeferHtml(nodelist)

@register.simple_tag(takes_context=True)
def render_defer_html(context):
    return html.mark_safe(_collect(context, 'get_defer_html'))

@register.tag
def defer_head(parser, token):
    nodelist = parser.parse(('end_defer_head',))
    parser.delete_first_token()
    return DeferHead(nodelist)

@register.simple_tag(takes_context=True)
def render_defer_head(context):
    return ''
#    return html.mark_safe(_collect(context, 'get_defer_head'))


text:
using FansubFileNameParser.Entity.Directory;
using FansubFileNameParser.Utils;
using Sprache;
using System;

namespace FansubFileNameParser.Entity.Parsers
{
    /// <summary>
    /// Contains the Fansub Directory parser
    /// </summary>
    internal static class DirectoryEntityParsers
    {
        #region private fields
        private static readonly Parser<string> Volume = Parse.IgnoreCase("VOLUME").Text();

        private static readonly Parser<string> Vol = Parse.IgnoreCase("VOL").Text();

        private static readonly Parser<string> VolumeToken = Volume.Or(Vol);

        private static readonly Parser<Tuple<int, int>> EpisodeRange =
            from firstNumber in ExtraParsers.Int
            from _ in BaseGrammars.Dash
            from secondNumber in ExtraParsers.Int
            select Tuple.Create(firstNumber, secondNumber);

        private static readonly Parser<int> VolumeNumber =
            from volumeToken in VolumeToken
            from dotAndSpace in Parse.AnyChar.Except(ExtraParsers.Int).Many()
            from number in ExtraParsers.Int
            select number;

        private static readonly Parser<int> DashSeparatorTokenThenVolumeNumber =
            from _1 in BaseGrammars.DashSeparatorToken
            from _2 in VolumeNumber
            select _2;

        private static readonly Parser<Tuple<int, int>> DashSeparatorTokenThenEpisodeRange =
            from _1 in BaseGrammars.DashSeparatorToken
            from _2 in EpisodeRange
            select _2;

        private static readonly Parser<string> SeriesNameDirectory =
            from _1 in ExtraParsers.MainContent.SetResultAsRemainder()
            from seriesName in ExtraParsers.LineUpTo(
                ExtraParsers.Or(
                    EpisodeRange,
                    VolumeNumber,
                    DashSeparatorTokenThenEpisodeRange,
                    DashSeparatorTokenThenVolumeNumber
                )
            )
            select seriesName.Trim();

        private static readonly Parser<IFansubEntity> DirectoryParser =
            from _1 in ExtraParsers.ScanFor(ExtraParsers.FileExtension).Not().ResetInput()
            from metadata in BaseEntityParsers.MediaMetadata.OptionalMaybe().ResetInput()
            from fansubGroup in BaseEntityParsers.FansubGroup.OptionalMaybe().ResetInput()
            from series in SeriesNameDirectory.OptionalMaybe().ResetInput()
            from vol in ExtraParsers.ScanFor(VolumeNumber).OptionalMaybe()
            from range in ExtraParsers.ScanFor(EpisodeRange).OptionalMaybe()
            from _2 in BaseGrammars.Line
            select new FansubDirectoryEntity
            {
                Group = fansubGroup,
                Series = series,
                Metadata = metadata,
                Volume = vol,
                EpisodeRange = range,
            };
        #endregion
        #region public static properties
        /// <summary>
        /// Gets the directory parser
        /// </summary>
        /// <value>
        /// The directory parser
        /// </value>
        public static Parser<IFansubEntity> Directory
        {
            get { return DirectoryParser.Profile("DirectoryParser"); }
        }
        #endregion
    }
}