text:
module Type.Effect.Solve where

import Type.Effect
import Control.Monad.Writer
import qualified  Control.Monad.State as State
--import Control.Monad.Trans
--import Control.Monad (forM, forM_, filterM)

import qualified Data.List as List
import qualified Data.Set as Set

import Reporting.Annotation as A
import Reporting.Warning as Warning

import qualified Data.UnionFind.IO as UF

import qualified Data.Map as Map
import qualified Data.Maybe as Maybe

import qualified Reporting.Region as R
import Debug.Trace (trace)

solve
  :: AnnotConstr
  -> IO ( [(R.Region, Warning.Warning)]
     , Map.Map String (CanonicalAnnot, [Int], [CanonicalConstr]))
solve c = do
  let
      stateComp = runWriterT $ solveSubsetConstraints c
      ioComp = State.runStateT stateComp $ SolverState Map.empty Map.empty
  (((), warnings), finalState) <- ioComp
  finalEnv <- forM (Map.toList $ sSavedEnv finalState) $ \(s, StoredScheme quants constrList annVar) -> do
    ourAnnot <- toCanonicalAnnot (VarAnnot annVar)
    quantData <- forM quants $ \(AnnVar (p, _)) -> UF.descriptor p
    let quantIDs = List.nub $ List.map _uniqueId quantData
    finalConstrs <- forM constrList toCanonicalConstr
    return (s, (ourAnnot, quantIDs, finalConstrs)) --TODO translate constraints
  return (warnings, Map.fromList finalEnv)

toCanonicalConstr :: EmittedConstr -> IO CanonicalConstr
toCanonicalConstr c = case c of
  ESubEffect _ a1 a2 -> CanonSubtype <$> toCanonicalAnnot a1 <*> toCanonicalAnnot a2
  ECanBeMatchedBy _ a1 real -> CanonSubtype <$> toCanonicalAnnot a1 <*> return (CanonLit real)
  EMatchesImplies _ (a1, real) (a2, a3) -> do
    c1 <- toCanonicalAnnot a1
    c2 <- toCanonicalAnnot a2
    c3 <- toCanonicalAnnot a3
    return $ CanonImpl (c1, real) (c2, c3)
  EForallSubEffect _ a1 real a2 ->
    CanonForall <$> toCanonicalAnnot a1 <*> return real <*> toCanonicalAnnot a2
  EPatternEqual _ a1 pat a2 ->
    CanonPatEq <$> toCanonicalAnnot a1 <*> return pat <*> toCanonicalAnnot a2

toCanonicalAnnot :: TypeAnnot -> IO CanonicalAnnot
toCanonicalAnnot = toCanonicalHelper toCanonicalAnnot canonLowerBound

canonLowerBound :: TypeAnnot -> IO CanonicalAnnot
canonLowerBound = toCanonicalHelper canonLowerBound toCanonicalAnnot

emitWarnings x = do
  --forM x $ \_ -> liftIO $ putStrLn $ "Emitting warning"
  tell x

toCanonicalHelper co contra a = case a of
  VarAnnot (AnnVar (pt, _)) -> do
    ourData <- UF.descriptor pt
    case (_annRepr ourData) of
      Nothing -> do
        --putStrLn $ "Making final int for " ++ show v
        return $ CanonVar $ _uniqueId ourData
      Just repr ->
        co repr
  SinglePattern s subs -> do
    canonSubs <- forM subs co
    return $ CanonPatDict $ Set.singleton (s, canonSubs)
  LambdaAnn a b ->
    CanonLambda <$> contra a <*> co b
  TopAnnot ->
    return CanonTop
  ReturnsTop ->
    --TODO find out if has function type?
    return CanonTop

data StoredScheme = StoredScheme [AnnVar] [EmittedConstr] AnnVar | StoredMono AnnVar

--TODO shouldn't this hold schemes, not vars?
type Env = Map.Map String StoredScheme

data SolverState =
  SolverState
  { sEnv :: Env
  , sSavedEnv :: Env
  }

data EmittedConstr =
    ESubEffect R.Region TypeAnnot TypeAnnot
  | ECanBeMatchedBy R.Region TypeAnnot RealAnnot
  | EMatchesImplies R.Region (TypeAnnot, RealAnnot) (TypeAnnot, TypeAnnot)
  | EForallSubEffect R.Region TypeAnnot RealAnnot TypeAnnot
  | EPatternEqual R.Region TypeAnnot PatternLoc TypeAnnot
  deriving (Show)

getEnv :: SolverM' a Env
getEnv =
    State.gets sEnv

modifyEnv :: (Env -> Env) -> SolverM' a ()
modifyEnv f =
    State.modify $ \state -> state { sEnv = f (sEnv state) }

saveLocalEnv :: SolverM' a ()
saveLocalEnv =
  do  currentEnv <- getEnv
      State.modify $ \state -> state { sSavedEnv = currentEnv }

type SolverM' a =  WriterT [a] (State.StateT SolverState IO)

type WorklistM = SolverM' (R.Region, Warning.Warning)

type SolverM = WorklistM

type Point = UF.Point AnnotData

getRepr :: AnnVar -> SolverM' a (Maybe TypeAnnot)
getRepr (AnnVar (pt, _)) =
   liftIO $ _annRepr <$> UF.descriptor pt

setRepr :: AnnVar -> TypeAnnot -> SolverM' a ()
setRepr (AnnVar (pt, _)) repr = liftIO $
  case repr of
    (VarAnnot _) -> error "Should never set repr to another var"
    _ -> do
      annData <- UF.descriptor pt
      UF.setDescriptor pt $ annData {_annRepr = Just repr}

union :: AnnVar -> AnnVar -> SolverM' a ()
union (AnnVar (pt1, _)) (AnnVar (pt2, _)) =
  liftIO $ UF.union pt1 pt2

areSame :: AnnVar -> AnnVar -> SolverM' a Bool
areSame (AnnVar (pt1, _)) (AnnVar (pt2, _)) = liftIO $ UF.equivalent pt1 pt2

applyUnifications :: AnnotConstr -> SolverM [EmittedConstr]
applyUnifications con =
  case con of
    CEqual region r1 r2 -> do
      liftIO $ putStrLn $ "Unifying in cequal" ++ show region
      _ <- unifyAnnots r1 r2
      return []
    CAnd constrs -> do
      andConstraints <- forM constrs applyUnifications
      return $ concat andConstraints
    CLet schemes letConstr -> do
      oldEnv <- getEnv
      --TODO do something with vars in the scheme?
      schemeSolutions <- forM schemes (solveScheme oldEnv)
      let (schemeEmitted, headerList) = unzip schemeSolutions
      let headers =  Map.unions headerList
      modifyEnv $ \env -> Map.union headers env
      letEmitted <- applyUnifications letConstr
      --TODO occurs check?
      modifyEnv $ \_ -> oldEnv
      return $ letEmitted ++ (concat schemeEmitted)
    CInstance r var annot -> do
      env <- getEnv
      emittedFromFresh <-
        case Map.lookup var env of
          Nothing -> error $ "Could not find name " ++ show var ++ " in Effect.Solve\nenv:\n" ++ show (Map.keys env)
          Just (StoredMono storedVar) -> do
            liftIO $ putStrLn $ "CEqual in instance of " ++ show var
            applyUnifications $ CEqual r (VarAnnot storedVar) annot
          Just (StoredScheme quants constr annVar) -> do
            (freshEmitted, newVar) <- makeFreshCopy quants constr annVar
            --Unify the type of the variable use with our newly instantiated type
            liftIO $ putStrLn "Unifying in CInstance"
            unifyAnnots annot (VarAnnot newVar)
            --liftIO $ putStrLn ("Made instance " ++ show annot ++ " of " ++ show var ++ ": " ++ show newVar ++ "\nconstr: " ++ show freshEmitted)
            --Apply our instantiated constraints to that type
            return freshEmitted
      return emittedFromFresh
    CSaveEnv -> do
      saveLocalEnv
      return []
    CTrue -> return []
    CSubEffect r a b ->
      return [ESubEffect r a b]
    CCanBeMatchedBy r a b ->
      return [ECanBeMatchedBy r a b]
    CMatchesImplies r pair1 pair2 ->
      return [EMatchesImplies r pair1 pair2]
    CForallSubEffect r a1 real a2 ->
      return [EForallSubEffect r a1 real a2]
    --Apply basic unifications as soon as we can
    CPatternEqual r a1 (VarLoc) a2 ->
      applyUnifications $ CEqual r a1 a2
    CPatternEqual r a1 pat a2 ->
      return [EPatternEqual r a1 pat a2]

--The constraints that two annotation sets are equal
--We do this at times we can't run unification anymore
makeAnnotsEqual r v1 v2 = do
  constrs1 <- makeSubEffectConstrs r v1 v2
  constrs2 <- makeSubEffectConstrs r v2 v1
  return (constrs1 ++ constrs2 )

--makeWHelper :: EmittedConstr -> SolverM [WConstr]
makeWHelper (ESubEffect r left right ) =
  makeSubEffectConstrs r left right
makeWHelper (ECanBeMatchedBy r a exact) = do
  vinter <- liftIO $ mkVar
  varMatchesAnn <- makeAnnotsEqual r a (VarAnnot vinter)
  return $ (WSubEffectOfLit r vinter exact) : varMatchesAnn
makeWHelper (EMatchesImplies r (a1, real) (a2, a3)) = do
  vinter1 <- liftIO $ mkVar
  vinter2 <- liftIO $ mkVar
  vinter3 <- liftIO $ mkVar
  unifEmitted1 <- makeAnnotsEqual r (VarAnnot vinter1) a1
  unifEmitted2 <- makeAnnotsEqual r (VarAnnot vinter2) a2
  unifEmitted3 <- makeAnnotsEqual r (VarAnnot vinter3) a3
  let unifConstrs = (unifEmitted1 ++ unifEmitted2 ++ unifEmitted3 )
  let implConstr = WSimpleImplies r vinter1 real $ WSubEffect r vinter2 vinter3
  --liftIO $ putStrLn $ "IMPL: made " ++ show (EMatchesImplies r (a1, real) (a2, a3))  ++ " into " ++ show (implConstr : unifConstrs)
  return  $ implConstr : unifConstrs
makeWHelper (EForallSubEffect r a1 real a2) = do
  vinter1 <- liftIO $ mkVar
  vinter2 <- liftIO $ mkVar
  unifEmitted1 <- makeAnnotsEqual r (VarAnnot vinter1) a1
  unifEmitted2 <- makeAnnotsEqual r (VarAnnot vinter2) a2
  let unifConstrs = unifEmitted1 ++ unifEmitted2
      implConstr = WForallImpliesSubOf r vinter1 real vinter2
  return  $ implConstr : unifConstrs
makeWHelper (EPatternEqual r a1 pat a2) = do
  vinter1 <- liftIO $ mkVar
  vinter2 <- liftIO $ mkVar
  unifEmitted1 <- makeAnnotsEqual r (VarAnnot vinter1) a1
  unifEmitted2 <- makeAnnotsEqual r (VarAnnot vinter2) a2
  let unifConstrs = unifEmitted1 ++ unifEmitted2
      implConstr = WPatternEq r vinter1 pat vinter2
  return  $ implConstr : unifConstrs

    --For our other constraints, we defer solving until after unification is done
makeSubEffectConstrs :: R.Region -> TypeAnnot -> TypeAnnot -> SolverM [WConstr]
makeSubEffectConstrs r aLeft aRight = case (aLeft, aRight) of
    (_, VarAnnot vRight) -> do
      mreprRight <- getRepr vRight
      case mreprRight of
        Just rep1 ->
          makeSubEffectConstrs r aLeft rep1

        Nothing -> do
          case aLeft of
            VarAnnot vLeft -> do
              mreprLeft <- getRepr vLeft
              case mreprLeft of
                Nothing -> do
                  return [WSubEffect r vLeft vRight]

                Just repLeft -> do
                  makeSubEffectConstrs  r repLeft (VarAnnot vRight)

            SinglePattern ctor subPats -> do
                let numArgs = length subPats
                let indices = [0 .. numArgs - 1]
                subVars <- forM subPats $ \_ -> liftIO mkVar
                let varPatTriples = zip3 subPats subVars indices
                --Constrain our new variables to the sub-annotations they're linked to
                --as well as adding a constraint for our overall variable to that var as a sub-pattern
                listsPerTriple <- forM varPatTriples  $ \(subPat, subVar, i) -> do
                  --Constrs: each new argument variable is a contains at least the given pattern
                  subConstrs <- makeSubEffectConstrs  r subPat (VarAnnot subVar)
                  --liftIO $ putStrLn $ "Single pat subs" ++ show (i, subVar, subConstrs)
                  return $ (WPatSubEffectOf r numArgs ctor i subVar vRight) : subConstrs
                --Ensure we have this ctor, even if there are no args
                let ctorConstr = WLitSubEffectOf r (RealAnnot $ Set.singleton(ctor, List.replicate numArgs realBottom)) vRight
                return $ ctorConstr : (concat listsPerTriple)

            LambdaAnn _ _ -> do
              --If there are only subset constraints stating that this variable is a lambda
              --We unify it now to be a lambda
              varg <- liftIO mkVar
              vret <- liftIO mkVar
              let newRepr = (LambdaAnn (VarAnnot varg) (VarAnnot vret))
              setRepr vRight newRepr
              makeSubEffectConstrs r newRepr aLeft

            TopAnnot ->
              return [WLitSubEffectOf r RealTop vRight]
            ReturnsTop -> --If subeffect of var, is not in function position, so is top
              return [WLitSubEffectOf r RealTop vRight]

    (VarAnnot vLeft, _) -> do
            mreprLeft <- getRepr vLeft
            case mreprLeft of
              Just repr -> makeSubEffectConstrs r repr aRight

              Nothing -> case aRight of

                SinglePattern ctor subPats -> do
                    let numArgs = length subPats
                    let indices = [0 .. numArgs - 1]
                    subVars <- forM subPats $ \_ -> liftIO mkVar
                    let varPatTriples = zip3 subPats subVars indices
                    --Constrain our new variables to the sub-annotations they're linked to
                    --as well as adding a constraint for our overall variable to that var as a sub-pattern
                    listsPerTriple <- forM varPatTriples  $ \(subPat, subVar, i) -> do
                      --Ensure that our new variable is a subeffect of the pattern
                      subConstrs <- makeSubEffectConstrs  r (VarAnnot subVar) subPat
                      --Specify that the i'th arg of our left side is a subEffect of our variable
                      return $ (WSubEffectOfPat r numArgs vLeft ctor i subVar) : subConstrs
                    --Ensure we have this ctor, even if there are no args
                    let ctorConstr = WSubEffectOfLit r vLeft (RealAnnot $ Set.singleton (ctor, List.replicate numArgs RealTop))
                    return $ ctorConstr : concat listsPerTriple

                LambdaAnn _ _  -> do
                  --If there are only subset constraints stating that this variable is a lambda
                  --We unify it now to be a lambda
                  varg <- liftIO mkVar
                  vret <- liftIO mkVar
                  let newRepr = (LambdaAnn (VarAnnot varg) (VarAnnot vret))
                  setRepr vLeft newRepr
                  makeSubEffectConstrs r newRepr aRight

                TopAnnot ->
                  return [WSubEffectOfLit r vLeft RealTop]

                ReturnsTop ->
                  return [WSubEffectOfLit r vLeft RealTop]

    (SinglePattern s1 subs1, SinglePattern s2 subs2) -> do
      case (s1 == s2) of
        False
          -> do
               emitWarnings [(r,
                  Warning.MissingCase
                    (RealAnnot $ Set.singleton (s1, [])) (RealAnnot $ Set.singleton (s2, [])) )] --TODO better error
               return []

        True -> do
          subLists <- forM (zip subs1 subs2) $ \(s1, s2) ->
            makeSubEffectConstrs r s1 s2
          return $ concat subLists

    {-
      do
      listPerCtor <- forM d2 $ \(ctor, subPats) ->
        case (Map.lookup ctor d1) of
          Nothing -> return [WWarning r ctor]
          Just leftSubPats -> do
            listPerArg <- forM (zip leftSubPats subPats) $ \(left, right) ->
              makeSubEffectConstrs  r left right
            return $ concat listPerArg
      return $ concat listPerCtor
      -}

    (LambdaAnn a1 a2, LambdaAnn b1 b2) -> do
      --Constrain that the argument variable matches at most our lambda
      --And the return matches at least our lambda
      --Basic covariance and contravariance stuff
      argList <- makeSubEffectConstrs r b1 a1
      retList <- makeSubEffectConstrs r a2 b2
      return $ argList ++ retList

    (TopAnnot, TopAnnot) -> return []

    (x,y) -> error $ "Mismatch in underlying type system\n" ++ show x ++ "\n" ++ show y

      --Make a new variable for each constructor of the pattern

freeVarsInAnnot a =
  case a of
    VarAnnot v -> do
      mrepr <- getRepr v
      case mrepr of
        Nothing -> return [v]
        --Just rep -> ([v] ++) <$> freeVarsInAnnot rep --Can't quantify over if have repr
        Just rep -> freeVarsInAnnot rep --TODO is this right?
    SinglePattern _s subs ->
     concat <$> forM subs freeVarsInAnnot
    LambdaAnn a1 a2 ->
      (++) <$> freeVarsInAnnot a1 <*> freeVarsInAnnot a2
    TopAnnot ->
      return []
    ReturnsTop ->
      return []

freeVarsInConstr :: EmittedConstr -> SolverM [AnnVar]
freeVarsInConstr c = case c of
  ESubEffect _ a1 a2 -> (++) <$> freeVarsInAnnot a1 <*> freeVarsInAnnot a2
  ECanBeMatchedBy _ a1 _ -> freeVarsInAnnot a1
  EMatchesImplies _ (a1, _) (a2, a3) -> concat <$> forM [a1, a2, a3] (freeVarsInAnnot)
  EForallSubEffect _ a1 _ a2 -> (++) <$> freeVarsInAnnot a1 <*> freeVarsInAnnot a2
  EPatternEqual _ a1 _ a2 -> (++) <$> freeVarsInAnnot a1 <*> freeVarsInAnnot a2

freeVarsInEnv :: Env -> SolverM [AnnVar]
freeVarsInEnv env =
  (fmap concat) $ forM (Map.elems env) $ \sch ->
    case sch of
      (StoredScheme quants constrList var) -> do
        freeInTy <- freeVarsInAnnot (VarAnnot var)
        freeInConstr <- concat <$> forM constrList freeVarsInConstr
        filterM (varNotInList quants) (freeInTy ++ freeInConstr)
      StoredMono var -> do
        freeInTy <- freeVarsInAnnot (VarAnnot var)
        filterM (varNotInList []) (freeInTy)

varNotInList :: [AnnVar] -> AnnVar -> SolverM' a Bool
varNotInList vl v = do
  boolList <- forM vl (areSame v)
  return $ not $ List.or boolList

notFreeInEnv env v = do
  freeInEnv <- freeVarsInEnv env
  varNotInList freeInEnv v

removeDuplicates l = removeDuplicatesHelper [] l
  where
    removeDuplicatesHelper :: [AnnVar] -> [AnnVar] -> SolverM [AnnVar]
    removeDuplicatesHelper seenVars [] = return seenVars
    removeDuplicatesHelper seenVars (v:rest) = do
      sameVars <- forM seenVars $ (areSame v)
      let newSeen = case (List.or sameVars) of
            True -> seenVars
            _ -> (v : seenVars)
      removeDuplicatesHelper newSeen rest

solveScheme :: Env -> AnnScheme -> SolverM ([EmittedConstr], Env)
solveScheme oldEnv (Scheme constr hdr) = do
  let oldHeader = Map.toList hdr
  --Solve the relationships between variables before we quantify
  schemeEmitted <- applyUnifications constr
  newSchemeHeaders <- forM oldHeader $ \(nm, (A.A _ ann)) -> do
    newVar <- liftIO mkVar
    annVars <- freeVarsInAnnot ann
    conVars <- concat <$> forM schemeEmitted freeVarsInConstr
    liftIO $ putStrLn $ "Solving scheme " ++ show nm
    liftIO $ putStrLn $ "AnnVars" ++ show annVars ++ "\nconVars " ++ show conVars
    let allVars = annVars ++ conVars
    goodQuants <- filterM (notFreeInEnv oldEnv) allVars
    liftIO $ putStrLn "Unifying in SolveScheme"
    unifyAnnots (VarAnnot newVar) ann
    finalQuants <- removeDuplicates goodQuants
    --liftIO $ putStrLn $ "Unified new scheme var " ++ (show newVar) ++ " with " ++ show ann
    --liftIO $ putStrLn $ "Quantified scheme " ++ (show scheme) ++ "\nnew constr " ++ show constr
    return (schemeEmitted, (nm, StoredScheme finalQuants schemeEmitted  newVar))
  --Now that we have a new header with variables, actually solve the constraint
  --On our scheme
  let (allSchemesEmitted, newHeader) = unzip newSchemeHeaders
  return (concat allSchemesEmitted, Map.fromList newHeader)
solveScheme _ (MonoScheme hdr) = do
  let oldHeader = Map.toList hdr
  newHeader <- forM oldHeader $ \(nm, A.A _ ann) -> do
    newVar <- liftIO mkVar
    liftIO $ putStrLn "Unifying in monoscheme"
    unifyAnnots (VarAnnot newVar) ann
    return (nm, StoredMono newVar)
  --Now that we have a new header with variables, actually solve the constraint
  --On our scheme
  return $ ([], Map.fromList newHeader)

makeFreshCopy :: [AnnVar] -> [EmittedConstr] -> AnnVar -> SolverM ([EmittedConstr], AnnVar)
makeFreshCopy quants inConstrList inVar = do
  let --TODO check if free or not?
    isQuant v = isQuantHelper quants v
    isQuantHelper [] _ = return False
    isQuantHelper (vfree : rest) v = do
      b <- areSame vfree v
      case b of
        True -> return True
        False ->
          isQuantHelper rest v
    copyConHelper c = case c of
      ECanBeMatchedBy r a1 exact -> do
        (subAnn, subPairs) <- copyHelper a1
        return (ECanBeMatchedBy r subAnn exact, subPairs)
      ESubEffect r a1 a2 -> do
        (b1, pairs1) <- copyHelper a1
        (b2, pairs2) <- copyHelper a2
        return (ESubEffect r b1 b2, pairs1 ++ pairs2)
      EMatchesImplies r (a1, real) (a2, a3) -> do
        (sub1, pairs1) <- copyHelper a1
        (sub2, pairs2) <- copyHelper a2
        (sub3, pairs3) <- copyHelper a3
        return (EMatchesImplies r (sub1, real) (sub2, sub3), pairs1 ++ pairs2 ++ pairs3)
      EForallSubEffect r a1 real a2 -> do
        (b1, pairs1) <- copyHelper a1
        (b2, pairs2) <- copyHelper a2
        return (EForallSubEffect r b1 real b2, pairs1 ++ pairs2)
      EPatternEqual r a1 pat a2 -> do
        (b1, pairs1) <- copyHelper a1
        (b2, pairs2) <- copyHelper a2
        return (EPatternEqual r b1 pat b2, pairs1 ++ pairs2)
    --We only need to copy our subtyping constraints
    copyHelper :: TypeAnnot -> SolverM (TypeAnnot, [(AnnVar, AnnVar)])
    copyHelper a = case a of
      VarAnnot v -> do
        mrepr <- getRepr v
        case mrepr of
          --Unified variables get replaced by what they're unified with
          Just rep ->
            copyHelper rep
          Nothing -> do
            vIsFree <- isQuant v
            case vIsFree of
              True -> do
                vnew <- liftIO $ mkVar
                return $ (VarAnnot vnew, [(v, vnew)])

              False ->
                return (VarAnnot v, [])
      SinglePattern s subPats -> do
        (newSubPats, newVarLists) <- unzip <$> forM subPats copyHelper
        return (SinglePattern s newSubPats, concat newVarLists)
      LambdaAnn a1 a2 -> do
        (b1, pairs1) <- copyHelper a1
        (b2, pairs2) <- copyHelper a2
        return (LambdaAnn b1 b2, pairs1 ++ pairs2)
      TopAnnot -> return (TopAnnot, [])
      ReturnsTop -> return (ReturnsTop, [])

    unifyPairs pairList =
      forM_ pairList $ \(old1, new1) -> forM_ pairList $ \(old2, new2) -> do
        sm <- areSame old1 old2
        case sm of
          True -> union new1 new2
          False -> return ()

  (newConstrs, pairList) <- unzip <$> forM inConstrList copyConHelper
  newVar <- liftIO $ mkVar
  (newAnn, varPairs) <- copyHelper (VarAnnot inVar)
  --Unify the var for our new annotation with the annotation itself
  liftIO $ putStrLn "Unifying in UnifyPairs"
  unifyAnnots (VarAnnot newVar) newAnn
  unifyPairs $ varPairs ++ (concat pairList)
  instRepr <- getRepr newVar
  return (newConstrs, newVar)

unifyAnnots :: TypeAnnot -> TypeAnnot -> SolverM TypeAnnot
unifyAnnots r1 r2 = trace ("Unifying " ++ show (r1, r2)) $
  case (r1, r2) of
    (TopAnnot, TopAnnot) ->
      return TopAnnot

    --Unify two vars: combine their reprs
    (VarAnnot v1, VarAnnot v2) -> do
      mrepr1 <- getRepr v1
      mrepr2 <- getRepr v2
      union v1 v2
      case (mrepr1, mrepr2) of
        (Nothing, Nothing) -> do
          union v1 v2
          return $ VarAnnot v1
        (Just rep, Nothing) -> do
          setRepr v2 rep
          return $ rep
        (Nothing, Just rep) -> do
          setRepr v2 rep
          return $ rep
        (Just rep1, Just rep2) -> do
          newRepr <- unifyAnnots rep1 rep2
          setRepr v1 newRepr
          return newRepr

      --Unify a var with something: unify the var's repr with that thing
    (VarAnnot v, repr2) -> do
          mrepr1 <- getRepr v
          case mrepr1 of
            Nothing -> do
              setRepr v repr2
              return repr2
            Just repr1 -> do
              newRepr <- unifyAnnots repr1 repr2
              setRepr v newRepr
              return newRepr
    --Same as above but flipped
    (repr2, VarAnnot v) -> do
          mrepr1 <- getRepr v
          case mrepr1 of
            Nothing -> do
              setRepr v repr2
              return repr2
            Just repr1 -> do
              newRepr <- unifyAnnots repr1 repr2
              setRepr v newRepr
              return newRepr

    (LambdaAnn a1 a2, LambdaAnn b1 b2) ->
      LambdaAnn <$> unifyAnnots a1 b1 <*> unifyAnnots a2 b2

    --Special cases: we can unify lambda with Top, giving a TopLambda
    --This helps us deal with Native values, or any other places our analysis fails
    (LambdaAnn a1 a2, TopAnnot) -> do
      unifyAnnots a1 TopAnnot
      unifyAnnots a2 TopAnnot
      return $ LambdaAnn TopAnnot TopAnnot
    (TopAnnot, LambdaAnn a1 a2) -> do
        unifyAnnots a1 TopAnnot
        unifyAnnots a2 TopAnnot
        return $ LambdaAnn TopAnnot TopAnnot

    (LambdaAnn a1 a2, ReturnsTop) -> do
      unifyAnnots a2 ReturnsTop
      return $ LambdaAnn a1 ReturnsTop
    (ReturnsTop, LambdaAnn a1 a2) -> do
        unifyAnnots a2 ReturnsTop
        return $ LambdaAnn a1 ReturnsTop
    (ReturnsTop, TopAnnot) ->
      return TopAnnot
    (TopAnnot, ReturnsTop) ->
      return TopAnnot
    --(ReturnsTop, _) -> --TODO is this right?
    --  return TopAnnot
    --(_, ReturnsTop) ->
    --  return TopAnnot

    --TODO singlePattern case?

    _ -> error $ "Invalid unify " ++ show r1 ++ " " ++ show r2

-------------------------
-- Worklist algorithm for solving subset constraints
-------------------------

--Constraints we can actually deal with in our workList algorithm
data WConstr' v =
  WSubEffect R.Region v v
  | WSubEffectOfPat R.Region Int v String Int v --Specific sub-pattern constraints
  | WPatSubEffectOf R.Region Int String Int v v
  | WSubEffectOfLit R.Region v RealAnnot
  | WLitSubEffectOf R.Region RealAnnot v
  | WSimpleImplies R.Region v RealAnnot WConstr
  | WForallImpliesSubOf R.Region v RealAnnot v
  | WPatternEq R.Region v PatternLoc v --Second arg is one we dig into
  deriving (Show)

type WConstr = WConstr' AnnVar

unionAnn :: RealAnnot -> RealAnnot -> RealAnnot
unionAnn RealTop _ = RealTop
unionAnn _ RealTop = RealTop
unionAnn (RealAnnot dict1) (RealAnnot dict2) =
  RealAnnot $  Set.union dict1 dict2

intersectPairs :: (String, [RealAnnot]) -> (String, [RealAnnot]) -> Maybe (String, [RealAnnot])
intersectPairs (s1, args1) (s2, args2) =
  if s1 == s2 then
    let
      argIntersections = zipWith intersectAnn args1 args2
    in
      Just (s1, argIntersections)
  else
      Nothing

intersectAnn :: RealAnnot -> RealAnnot -> RealAnnot
intersectAnn RealTop x = x
intersectAnn x RealTop = x
intersectAnn (RealAnnot dict1) (RealAnnot dict2) =
  --Take the pairwise intersection of all elements then union them
  --TODO do this faster?
  let
    l1 = Set.toList dict1
    l2 = Set.toList dict2
  in
    RealAnnot $ Set.fromList $ Maybe.catMaybes [intersectPairs p1 p2 | p1 <- l1, p2 <- l2 ]

--Return a waring if the single pattern (S, p1 ... pn) is not matched by (S', p1' ... pn')
elemMismatches :: R.Region -> (String, [RealAnnot]) -> (String, [RealAnnot]) -> [(R.Region, Warning.Warning)]
elemMismatches region pr1@(s1,args1) pr2@(s2, args2) =
  if (s1 == s2) then
    concat $ zipWith (mismatches region) args1 args2
  else
    [(region, Warning.MissingCase (RealAnnot $ Set.singleton pr1) (RealAnnot $ Set.singleton pr2))]

--Return a warning for every element in a1 that is not matched by any element of a2
mismatches :: R.Region -> RealAnnot -> RealAnnot -> [(R.Region, Warning.Warning)]
mismatches _ _ RealTop = []
mismatches r RealTop x = [(r, Warning.MissingCase RealTop x)]
mismatches region (RealAnnot subs1) (RealAnnot subs2) =
  let
    --forSet s f = Set.map f s
    for = flip List.map
    ctors1 = Set.map fst subs1
    ctors2 = Set.map fst subs2
    ctorFails = Set.toList $ Set.difference ctors1 ctors2
    ctorsCanMatch = RealAnnot $ Set.map (\(ctor, _) -> (ctor, [])) subs2
    ctorWarnings = for ctorFails $ \ctor -> (region, Warning.MissingCase (RealAnnot $ Set.singleton (ctor, [])) ctorsCanMatch)
    failsForAllSubs =
      for (Set.toList subs1) $ \sub1 ->
        let
          failsForSub1 = for (Set.toList subs2) $ \sub2 ->
            elemMismatches region sub1 sub2
        in
          --Check if there were any elements in subs2 that matched subs1
          if (List.any List.null failsForSub1) then
            []
          else
            [(region, Warning.MissingCase (RealAnnot $ Set.singleton sub1) (RealAnnot subs2))]
            --concat failsForSub1
  in --trace ("Mismatches for " ++ show (RealAnnot subs1, RealAnnot subs2) ++ ":\n  " ++ show (length ctorWarnings, length failsForAllSubs) ) $
    ctorWarnings ++ concat failsForAllSubs
{-
  concatMap (\(s, subPatsToMatch) ->
      case Map.lookup s d1 of
        Nothing -> [(r, Warning.MissingCase s)] --TODO better error messages
        --TODO assert same size lists?
        Just subPats -> concat $ zipWith (canMatchAll r) subPats subPatsToMatch
      )  (Map.toList d2)
-}

minMatchingPat = findMatchingPat intersectAnn RealTop
maxMatchingPat = findMatchingPat unionAnn realBottom

findMatchingPat combine neutral pat annot = case (pat, annot) of
  (VarLoc, x) -> x
  (_, RealTop) -> RealTop
  (PatternLoc ctor argNum subPat, RealAnnot annSet) ->
    Set.foldr combine neutral $ (flip Set.map) annSet $ \(annCtor, argList) ->
      if (annCtor == ctor) then
        findMatchingPat combine neutral subPat (argList List.!! argNum )
      else
        realBottom

getAnnData :: AnnVar -> SolverM' a (AnnotData)
getAnnData (AnnVar (pt, _)) = do
   ret <- liftIO $ UF.descriptor pt
   --liftIO $ putStrLn $ "Data for " ++ show v ++ " (LB, UB) " ++ show (_lb ret, _ub ret)
   return ret

canMatchAll :: RealAnnot -> RealAnnot -> Bool
canMatchAll r1 r2 = case mismatches (error "matchall region") r2 r1 of
  [] -> True
  _ -> False

--Return true if this union makes a change, false otherwise
unionUB :: R.Region -> AnnVar -> RealAnnot -> WorklistM Bool
unionUB r (AnnVar (pt, _)) ann = do
  annData <- liftIO $ UF.descriptor pt
  let newUB = _ub annData `unionAnn` ann
  liftIO $ UF.setDescriptor pt $ annData {_ub = newUB}
  --Check if we changed the set at all
  --TODO faster shortcut method
  return $ not $ (_ub annData) `canMatchAll` newUB

  --TODO emit warning

intersectLB :: R.Region -> AnnVar -> RealAnnot -> WorklistM Bool
intersectLB r (AnnVar (pt, vn)) ann =  do
  --liftIO $ putStrLn $ "Setting LB of " ++ show vn ++ " to" ++ show ann
  annData <- liftIO $ UF.descriptor pt
  let newLB = _lb annData `intersectAnn` ann
  liftIO $ UF.setDescriptor pt $ annData {_lb = newLB}
  return $ not $ newLB `canMatchAll` (_lb annData)

data VarPosition = Sub | Super
  deriving (Show)

--All constraints where some type is a supertype of the given var
constraintEdges :: WConstr -> [(AnnVar, VarPosition)]
constraintEdges c = case c of
  WSubEffect _ v1 v2 -> [(v1, Sub), (v2, Super)]
  WSubEffectOfPat _ _ v1 _ _ v2 -> [(v1, Sub), (v2, Super)]
  WPatSubEffectOf _ _ _ _ v1 v2 -> [(v1, Super), (v2, Sub)]
  WLitSubEffectOf _ _ v2 -> [(v2, Super)]
  WSubEffectOfLit _ v1 _ -> [(v1, Sub)]
  --TODO which one is it?
  WSimpleImplies _ v1 _ subConstr ->
    --TODO this is way too conservative
    [(v, s) | s <- [Super, Sub], v <- v1:(allVars subConstr) ]
    --[(v1, Sub), (v1, Super)] ++ constraintEdges subConstr
  WForallImpliesSubOf _ v1 _ v2 ->
    --TODO this is way too conservative
    [(v, s) | s <- [Super, Sub], v <- [v1,v2] ]
  WPatternEq _ v1 _ v2 ->
    --TODO this is way too conservative
    [(v, s) | s <- [Super, Sub], v <- [v1,v2] ]

allVars  c = case c of
  WSubEffect _ v1 v2 -> [v1, v2]
  WSubEffectOfPat _ _ v1 _ _ v2 -> [v1, v2]
  WPatSubEffectOf _ _ _ _ v1 v2 -> [v1, v2]
  WLitSubEffectOf _ _ v2 -> [v2]
  WSubEffectOfLit _ v1 _ -> [v1]
  WSimpleImplies _ v1 _ subConstr -> [v1] ++ allVars subConstr
  WForallImpliesSubOf _ v1 _ v2 -> [v1, v2]
  WPatternEq _ v1 _ v2 -> [v1, v2]

addConstraintEdge :: Int -> (AnnVar, VarPosition) -> WorklistM ()
addConstraintEdge i (AnnVar (pt, _), Sub) = liftIO $ do
  desc <- UF.descriptor pt
  UF.setDescriptor pt $ desc {_superOf = i : (_superOf desc)}
addConstraintEdge i (AnnVar (pt, _), Super) = liftIO $ do
  desc <- UF.descriptor pt
  UF.setDescriptor pt $ desc {_subOf = i : (_subOf desc)}

solveSubsetConstraints :: AnnotConstr -> WorklistM ()
solveSubsetConstraints inCon = do
  emittedConstrs <- applyUnifications inCon
  wConstraints <-  concat <$> forM emittedConstrs makeWHelper

  let constrPairs = zip [1..] wConstraints
  forM constrPairs $ \(i, c) -> forM (constraintEdges c) $ \v ->
    addConstraintEdge i v
  --TODO avoid list ops here?
  workList (Map.fromList constrPairs) wConstraints
  --One last check: once we've solved our constraints, check the constraint
  --That all possible values (upperBound) are covered by least possible matches
  --(lower bound)
  --TODO notation backwards
  finalLowerBoundsCheck wConstraints
  --liftIO $ putStrLn $ "WConstraints: " ++ show wConstraints

--TODO lower bounds for pat and lit cases?

finalLowerBoundsCheck :: [WConstr] -> WorklistM ()
finalLowerBoundsCheck constrList = forM_ constrList $ \c -> do
  --liftIO $ putStrLn $ "\nFinal bounds check on " ++ show c
  case c of
      WSubEffect r v1 v2 -> do
        data1 <- getAnnData v1
        data2 <- getAnnData v2
        emitWarnings $ mismatches r (_ub data1) (_lb data1)
        emitWarnings $ mismatches r (_ub data2) (_lb data2)
      WSubEffectOfPat r _ v1 _ _ v2 -> do
        data1 <- getAnnData v1
        data2 <- getAnnData v2
        emitWarnings $ mismatches r (_ub data1) (_lb data1)
        emitWarnings $ mismatches r (_ub data2) (_lb data2)
      WPatSubEffectOf r _ _ _ v1 v2 -> do
        data1 <- getAnnData v1
        data2 <- getAnnData v2
        emitWarnings $ mismatches r (_ub data1) (_lb data1)
        emitWarnings $ mismatches r (_ub data2) (_lb data2)
      WLitSubEffectOf r _ v2 -> do
        data2 <- getAnnData v2
        emitWarnings $ mismatches r (_ub data2) (_lb data2)
      WSubEffectOfLit r v1 _ -> do
        data1 <- getAnnData v1
        emitWarnings $ mismatches r (_ub data1) (_lb data1)
      WSimpleImplies r v real subCon -> do
        data1 <- getAnnData v
        emitWarnings $ mismatches r (_ub data1) (_lb data1)
        --liftIO $ putStrLn "Checking imp RHS"
        finalLowerBoundsCheck [subCon]
        --liftIO $ putStrLn "Done imp RHS"
      WForallImpliesSubOf r v1 _ v2 -> do
        data1 <- getAnnData v1
        data2 <- getAnnData v2
        emitWarnings $ mismatches r (_ub data1) (_lb data1)
        emitWarnings $ mismatches r (_ub data2) (_lb data2)
      WPatternEq r v1 _ v2 -> do
        data1 <- getAnnData v1
        data2 <- getAnnData v2
        emitWarnings $ mismatches r (_ub data1) (_lb data1)
        emitWarnings $ mismatches r (_ub data2) (_lb data2)

workList :: (Map.Map Int WConstr) -> [WConstr] -> WorklistM ()
workList _ [] = return () --When we're finished
workList allConstrs (c:rest) = case c of
  WSubEffect r v1 v2 -> do
    data1 <- getAnnData v1
    data2 <- getAnnData v2
    changed1 <- unionUB r v2 (_ub data1)
    changed2 <- intersectLB r v1 (_lb data2)

    let needsUpdate1 =
          case changed1 of
            False -> []
            True -> List.map (allConstrs Map.! ) $ _superOf data2

    let needsUpdate2 =
          case changed2 of
            False -> []
            True -> List.map (allConstrs Map.! ) $ _subOf data1
    workList allConstrs (needsUpdate1 ++ needsUpdate2 ++ rest)

  WSubEffectOfLit r v1 realAnn -> do
    changed <- intersectLB r v1 realAnn
    ourData <- getAnnData v1
    let needsUpdate =
          case changed of
            False -> []
            True -> List.map (allConstrs Map.! ) $ _superOf ourData
    workList allConstrs (needsUpdate ++ rest)

  WLitSubEffectOf r realAnn v1 -> do
    changed <- unionUB r v1 realAnn
    ourData <- getAnnData v1
    let needsUpdate =
          case changed of
            False -> []
            True -> List.map (allConstrs Map.! ) $ _subOf ourData
    workList allConstrs (needsUpdate ++ rest)

  WPatSubEffectOf r numArgs ctor argNum argVar wholeVal -> do
    argData <- getAnnData argVar
    wholeData <- getAnnData wholeVal
    let nBottoms =
          (List.replicate argNum realBottom) ++ [_ub argData] ++ (List.replicate (numArgs - argNum - 1) realBottom)
    changedWhole <- unionUB r wholeVal $ RealAnnot $ Set.singleton (ctor, nBottoms)
    {-
    let lbPartOfWhole =
          case _lb wholeData of
            RealTop -> RealTop
            RealAnnot pats ->
              RealAnnot $ Set.filter ((== ctor) . fst) pats

    changedPart <- intersectLB r argVar lbPartOfWhole
    -} --TODO need to constrain part?

    {-let needsUpdate1 =
          case changedPart of
            False -> []
            True -> List.map (allConstrs Map.! ) $ _superOf argData-}

    let needsUpdate2 =
          case changedWhole of
            False -> []
            True -> List.map (allConstrs Map.! ) $ _subOf wholeData
    workList allConstrs (needsUpdate2 ++ {-needsUpdate1 ++-} rest)

  WSubEffectOfPat r numArgs wholeVal ctor argNum argVar -> do
    argData <- getAnnData argVar
    wholeData <- getAnnData wholeVal
    let nBottoms =
          (List.replicate argNum RealTop) ++ [_lb argData] ++ (List.replicate (numArgs - argNum - 1) RealTop)
    changedWhole <- intersectLB r wholeVal $ RealAnnot $ Set.singleton (ctor, nBottoms)
    {-let wholeMatchingCtor =
          case _ub wholeData of
            RealTop -> RealTop
            RealAnnot pats ->
              RealAnnot $ Set.filter ((== ctor) . fst) pats

    changedPart <- unionUB r argVar wholeMatchingCtor-}

    {-let needsUpdate1 =
          case changedPart of
            False -> []
            True -> List.map (allConstrs Map.! ) $ _subOf argData-}

    let needsUpdate2 =
          case changedWhole of
            False -> []
            True -> List.map (allConstrs Map.! ) $ _superOf wholeData
    workList allConstrs ({-needsUpdate1 ++-} needsUpdate2 ++ rest)

  WSimpleImplies _ v real subConstr -> do
    ourUB <- _ub <$> getAnnData v
    --Check if our implication condition is true, and if it is solve the sub-constraint
    let condsToAdd =
          case ourUB `canMatchAll` real of
            True -> [subConstr]
            False -> []
    --liftIO $ putStrLn $ "Impl " ++ show c ++ " did match? " ++ show (ourUB, real, ourUB `canMatchAll` real)
    workList allConstrs (condsToAdd ++ rest)

  WForallImpliesSubOf r v1 real v2 -> do
    ourUB <- _ub <$> getAnnData v1
    let partMatching = intersectAnn ourUB real
        condsToAdd = [WLitSubEffectOf r partMatching v2]

    workList allConstrs (condsToAdd ++ rest)

  WPatternEq r vpart pat vwhole -> do
    wholeData <- getAnnData vwhole
    partData <- getAnnData vpart
    let newPartUB = maxMatchingPat pat (_ub wholeData)
        newPartLB = minMatchingPat pat (_lb wholeData)
    changed1 <- unionUB r vpart newPartUB
    changed2 <- intersectLB r vpart newPartLB
    let needsUpdate1 =
          case changed1 of
            False -> []
            True -> List.map (allConstrs Map.! ) $ _superOf partData

    let needsUpdate2 =
          case changed2 of
            False -> []
            True -> List.map (allConstrs Map.! ) $ _subOf partData
    workList allConstrs (needsUpdate1 ++ needsUpdate2 ++ rest)


text:
struct resolve_undo_info {
	unsigned int mode[3];
	unsigned char sha1[3][20];
};

extern void record_resolve_undo(struct index_state *, struct cache_entry *);
extern void resolve_undo_write(struct strbuf *, struct string_list *);
extern struct string_list *resolve_undo_read(const char *, unsigned long);
extern void resolve_undo_clear_index(struct index_state *);
extern int unmerge_index_entry_at(struct index_state *, int);
extern void unmerge_index(struct index_state *, const char **);
extern void unmerge_marked_index(struct index_state *);

#endif

redpajama_set_name: RedPajamaGithub


text:
<?xml version="1.0" encoding="UTF-8"?>

<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
    <section name="DotdigitalDashboardSection">
        <element name="lockStatus" type="text" selector=".ddg-dashboard-container" />
    </section>
</sections>


text:
/* global describe, it, expect, before */
/* jshint camelcase: false, expr: true */

var chai = require('chai')
  , code = require('../../lib/grant/code');

describe('grant.code', function() {

  describe('module', function() {
    var mod = code(function(){});

    it('should be named code', function() {
      expect(mod.name).to.equal('code');
    });

    it('should expose request and response functions', function() {
      expect(mod.request).to.be.a('function');
      expect(mod.response).to.be.a('function');
    });
  });

  it('should throw if constructed without a issue callback', function() {
    expect(function() {
      code();
    }).to.throw(TypeError, 'oauth2orize.code grant requires an issue callback');
  });

  describe('request parsing', function() {
    function issue(){}

    describe('request', function() {
      var err, out;

      before(function(done) {
        chai.oauth2orize.grant(code(issue))
          .req(function(req) {
            req.query = {};
            req.query.client_id = 'c123';
            req.query.redirect_uri = 'http://example.com/auth/callback';
            req.query.state = 'f1o1o1';
          })
          .parse(function(e, o) {
            err = e;
            out = o;
            done();
          })
          .authorize();
      });

      it('should not error', function() {
        expect(err).to.be.null;
      });

      it('should parse request', function() {
        expect(out.clientID).to.equal('c123');
        expect(out.redirectURI).to.equal('http://example.com/auth/callback');
        expect(out.scope).to.be.undefined;
        expect(out.state).to.equal('f1o1o1');
      });
    });

    describe('request with scope', function() {
      var err, out;

      before(function(done) {
        chai.oauth2orize.grant(code(issue))
          .req(function(req) {
            req.query = {};
            req.query.client_id = 'c123';
            req.query.redirect_uri = 'http://example.com/auth/callback';
            req.query.scope = 'read';
            req.query.state = 'f1o1o1';
          })
          .parse(function(e, o) {
            err = e;
            out = o;
            done();
          })
          .authorize();
      });

      it('should not error', function() {
        expect(err).to.be.null;
      });

      it('should parse request', function() {
        expect(out.clientID).to.equal('c123');
        expect(out.redirectURI).to.equal('http://example.com/auth/callback');
        expect(out.scope).to.be.an('array');
        expect(out.scope).to.have.length(1);
        expect(out.scope[0]).to.equal('read');
        expect(out.state).to.equal('f1o1o1');
      });
    });

    describe('request with list of scopes', function() {
      var err, out;

      before(function(done) {
        chai.oauth2orize.grant(code(issue))
          .req(function(req) {
            req.query = {};
            req.query.client_id = 'c123';
            req.query.redirect_uri = 'http://example.com/auth/callback';
            req.query.scope = 'read write';
            req.query.state = 'f1o1o1';
          })
          .parse(function(e, o) {
            err = e;
            out = o;
            done();
          })
          .authorize();
      });

      it('should not error', function() {
        expect(err).to.be.null;
      });

      it('should parse request', function() {
        expect(out.clientID).to.equal('c123');
        expect(out.redirectURI).to.equal('http://example.com/auth/callback');
        expect(out.scope).to.be.an('array');
        expect(out.scope).to.have.length(2);
        expect(out.scope[0]).to.equal('read');
        expect(out.scope[1]).to.equal('write');
        expect(out.state).to.equal('f1o1o1');
      });
    });

    describe('request with list of scopes using scope separator option', function() {
      var err, out;

      before(function(done) {
        chai.oauth2orize.grant(code({ scopeSeparator: ',' }, issue))
          .req(function(req) {
            req.query = {};
            req.query.client_id = 'c123';
            req.query.redirect_uri = 'http://example.com/auth/callback';
            req.query.scope = 'read,write';
            req.query.state = 'f1o1o1';
          })
          .parse(function(e, o) {
            err = e;
            out = o;
            done();
          })
          .authorize();
      });

      it('should not error', function() {
        expect(err).to.be.null;
      });

      it('should parse request', function() {
        expect(out.clientID).to.equal('c123');
        expect(out.redirectURI).to.equal('http://example.com/auth/callback');
        expect(out.scope).to.be.an('array');
        expect(out.scope).to.have.length(2);
        expect(out.scope[0]).to.equal('read');
        expect(out.scope[1]).to.equal('write');
        expect(out.state).to.equal('f1o1o1');
      });
    });

    describe('request with list of scopes separated by space using multiple scope separator option', function() {
      var err, out;

      before(function(done) {
        chai.oauth2orize.grant(code({ scopeSeparator: [' ', ','] }, issue))
          .req(function(req) {
            req.query = {};
            req.query.client_id = 'c123';
            req.query.redirect_uri = 'http://example.com/auth/callback';
            req.query.scope = 'read write';
            req.query.state = 'f1o1o1';
          })
          .parse(function(e, o) {
            err = e;
            out = o;
            done();
          })
          .authorize();
      });

      it('should not error', function() {
        expect(err).to.be.null;
      });

      it('should parse request', function() {
        expect(out.clientID).to.equal('c123');
        expect(out.redirectURI).to.equal('http://example.com/auth/callback');
        expect(out.scope).to.be.an('array');
        expect(out.scope).to.have.length(2);
        expect(out.scope[0]).to.equal('read');
        expect(out.scope[1]).to.equal('write');
        expect(out.state).to.equal('f1o1o1');
      });
    });

    describe('request with list of scopes separated by comma using multiple scope separator option', function() {
      var err, out;

      before(function(done) {
        chai.oauth2orize.grant(code({ scopeSeparator: [' ', ','] }, issue))
          .req(function(req) {
            req.query = {};
            req.query.client_id = 'c123';
            req.query.redirect_uri = 'http://example.com/auth/callback';
            req.query.scope = 'read,write';
            req.query.state = 'f1o1o1';
          })
          .parse(function(e, o) {
            err = e;
            out = o;
            done();
          })
          .authorize();
      });

      it('should not error', function() {
        expect(err).to.be.null;
      });

      it('should parse request', function() {
        expect(out.clientID).to.equal('c123');
        expect(out.redirectURI).to.equal('http://example.com/auth/callback');
        expect(out.scope).to.be.an('array');
        expect(out.scope).to.have.length(2);
        expect(out.scope[0]).to.equal('read');
        expect(out.scope[1]).to.equal('write');
        expect(out.state).to.equal('f1o1o1');
      });
    });

    describe('request with missing client_id parameter', function() {
      var err, out;

      before(function(done) {
        chai.oauth2orize.grant(code(issue))
          .req(function(req) {
            req.query = {};
            req.query.redirect_uri = 'http://example.com/auth/callback';
            req.query.state = 'f1o1o1';
          })
          .parse(function(e, o) {
            err = e;
            out = o;
            done();
          })
          .authorize();
      });

      it('should error', function() {
        expect(err).to.be.an.instanceOf(Error);
        expect(err.constructor.name).to.equal('AuthorizationError');
        expect(err.message).to.equal('Missing required parameter: client_id');
        expect(err.code).to.equal('invalid_request');
      });
    });
  });

  describe('decision handling', function() {
    function issue(client, redirectURI, user, scope, done) {
      if (client.id == 'c123' && redirectURI == 'http://example.com/auth/callback' && user.id == 'u123') {
        return done(null, 'xyz');
      } else if (client.id == 'cUNAUTHZ') {
        return done(null, false);
      } else if (client.id == 'cTHROW') {
        throw new Error('something was thrown');
      }
      return done(new Error('something went wrong'));
    }

    describe('transaction', function() {
      var response;

      before(function(done) {
        chai.oauth2orize.grant(code(issue))
          .txn(function(txn) {
            txn.client = { id: 'c123', name: 'Example' };
            txn.redirectURI = 'http://www.example.com/auth/callback';
            txn.req = {
              redirectURI: 'http://example.com/auth/callback'
            };
            txn.user = { id: 'u123', name: 'Bob' };
            txn.res = { allow: true };
          })
          .end(function(res) {
            response = res;
            done();
          })
          .decide();
      });

      it('should respond', function() {
        expect(response.statusCode).to.equal(302);
        expect(response.getHeader('Location')).to.equal('http://www.example.com/auth/callback?code=xyz');
      });
    });

    describe('transaction with request state', function() {
      var response;

      before(function(done) {
        chai.oauth2orize.grant(code(issue))
          .txn(function(txn) {
            txn.client = { id: 'c123', name: 'Example' };
            txn.redirectURI = 'http://www.example.com/auth/callback';
            txn.req = {
              redirectURI: 'http://example.com/auth/callback',
              state: 'f1o1o1'
            };
            txn.user = { id: 'u123', name: 'Bob' };
            txn.res = { allow: true };
          })
          .end(function(res) {
            response = res;
            done();
          })
          .decide();
      });

      it('should respond', function() {
        expect(response.statusCode).to.equal(302);
        expect(response.getHeader('Location')).to.equal('http://www.example.com/auth/callback?code=xyz&state=f1o1o1');
      });
    });

    describe('disallowed transaction', function() {
      var response;

      before(function(done) {
        chai.oauth2orize.grant(code(issue))
          .txn(function(txn) {
            txn.client = { id: 'c123', name: 'Example' };
            txn.redirectURI = 'http://www.example.com/auth/callback';
            txn.req = {
              redirectURI: 'http://example.com/auth/callback'
            };
            txn.user = { id: 'u123', name: 'Bob' };
            txn.res = { allow: false };
          })
          .end(function(res) {
            response = res;
            done();
          })
          .decide();
      });

      it('should respond', function() {
        expect(response.statusCode).to.equal(302);
        expect(response.getHeader('Location')).to.equal('http://www.example.com/auth/callback?error=access_denied');
      });
    });

    describe('disallowed transaction with request state', function() {
      var response;

      before(function(done) {
        chai.oauth2orize.grant(code(issue))
          .txn(function(txn) {
            txn.client = { id: 'c123', name: 'Example' };
            txn.redirectURI = 'http://www.example.com/auth/callback';
            txn.req = {
              redirectURI: 'http://example.com/auth/callback',
              state: 'f2o2o2'
            };
            txn.user = { id: 'u123', name: 'Bob' };
            txn.res = { allow: false };
          })
          .end(function(res) {
            response = res;
            done();
          })
          .decide();
      });

      it('should respond', function() {
        expect(response.statusCode).to.equal(302);
        expect(response.getHeader('Location')).to.equal('http://www.example.com/auth/callback?error=access_denied&state=f2o2o2');
      });
    });

    describe('unauthorized client', function() {
      var err;

      before(function(done) {
        chai.oauth2orize.grant(code(issue))
          .txn(function(txn) {
            txn.client = { id: 'cUNAUTHZ', name: 'Example' };
            txn.redirectURI = 'http://www.example.com/auth/callback';
            txn.req = {
              redirectURI: 'http://example.com/auth/callback'
            };
            txn.user = { id: 'u123', name: 'Bob' };
            txn.res = { allow: true };
          })
          .next(function(e) {
            err = e;
            done();
          })
          .decide();
      });

      it('should error', function() {
        expect(err).to.be.an.instanceOf(Error);
        expect(err.constructor.name).to.equal('AuthorizationError');
        expect(err.message).to.equal('Request denied by authorization server');
        expect(err.code).to.equal('access_denied');
        expect(err.status).to.equal(403);
      });
    });

    describe('encountering an error while issuing code', function() {
      var err;

      before(function(done) {
        chai.oauth2orize.grant(code(issue))
          .txn(function(txn) {
            txn.client = { id: 'cERROR', name: 'Example' };
            txn.redirectURI = 'http://www.example.com/auth/callback';
            txn.req = {
              redirectURI: 'http://example.com/auth/callback'
            };
            txn.user = { id: 'u123', name: 'Bob' };
            txn.res = { allow: true };
          })
          .next(function(e) {
            err = e;
            done();
          })
          .decide();
      });

      it('should error', function() {
        expect(err).to.be.an.instanceOf(Error);
        expect(err.message).to.equal('something went wrong');
      });
    });

    describe('throwing an error while issuing code', function() {
      var err;

      before(function(done) {
        chai.oauth2orize.grant(code(issue))
          .txn(function(txn) {
            txn.client = { id: 'cTHROW', name: 'Example' };
            txn.redirectURI = 'http://www.example.com/auth/callback';
            txn.req = {
              redirectURI: 'http://example.com/auth/callback'
            };
            txn.user = { id: 'u123', name: 'Bob' };
            txn.res = { allow: true };
          })
          .next(function(e) {
            err = e;
            done();
          })
          .decide();
      });

      it('should error', function() {
        expect(err).to.be.an.instanceOf(Error);
        expect(err.message).to.equal('something was thrown');
      });
    });

    describe('transaction without redirect URL', function() {
      var err;

      before(function(done) {
        chai.oauth2orize.grant(code(issue))
          .txn(function(txn) {
            txn.client = { id: 'c123', name: 'Example' };
            txn.req = {
              redirectURI: 'http://example.com/auth/callback'
            };
            txn.user = { id: 'u123', name: 'Bob' };
            txn.res = { allow: true };
          })
          .next(function(e) {
            err = e;
            done();
          })
          .decide();
      });

      it('should error', function() {
        expect(err).to.be.an.instanceOf(Error);
        expect(err.message).to.equal('Unable to issue redirect for OAuth 2.0 transaction');
      });
    });
  });

  describe('decision handling with user response', function() {
    function issue(client, redirectURI, user, scope, ares, done) {
      if (client.id == 'c123' && redirectURI == 'http://example.com/auth/callback' && user.id == 'u123' && ares.scope == 'foo') {
        return done(null, 'xyz');
      }
      return done(new Error('something went wrong'));
    }

    describe('transaction with response scope', function() {
      var response;

      before(function(done) {
        chai.oauth2orize.grant(code(issue))
          .txn(function(txn) {
            txn.client = { id: 'c123', name: 'Example' };
            txn.redirectURI = 'http://www.example.com/auth/callback';
            txn.req = {
              redirectURI: 'http://example.com/auth/callback'
            };
            txn.user = { id: 'u123', name: 'Bob' };
            txn.res = { allow: true, scope: 'foo' };
          })
          .end(function(res) {
            response = res;
            done();
          })
          .decide();
      });

      it('should respond', function() {
        expect(response.statusCode).to.equal(302);
        expect(response.getHeader('Location')).to.equal('http://www.example.com/auth/callback?code=xyz');
      });
    });
  });

});


text:
Titanium.include('/helpers/utils.js');

var win = Titanium.UI.currentWindow;

win.setBackgroundColor('red');

win.layout = 'vertical';

var tableView;
var dataRows = [];
var jsonData = JSON.parse(Ti.App.Properties.getString("data"));

// create a var to track the active row
var currentRow = null;
var currentRowIndex = null;

// create the rest of the rows

for(var c = 0; c < jsonData.length; c++) {

	var row = Ti.UI.createTableViewRow();
	row.selectedBackgroundColor = '#ebebeb';
	row.height = 100;
	row.className = 'datarow';
	row.clickName = 'row';

	var photo = Ti.UI.createImageView({
		image : jsonData[c].photo,
		top : 5,
		left : 10,
		width : 50,
		height : 50,
		clickName : 'photo'
	});
	row.add(photo);

	var user = Ti.UI.createLabel({
		color : '#576996',
		font : {
			fontSize : 16,
			fontWeight : 'bold',
			fontFamily : 'Arial'
		},
		left : 70,
		top : 2,
		height : 30,
		width : 200,
		text : 'N°' + jsonData[c].id_mission
	});

	row.filter = user.text;
	row.add(user);

	var fontSize = 16;
	if(Titanium.Platform.name == 'android') {
		fontSize = 14;
	}
	var comment = Ti.UI.createLabel({
		color : '#222',
		font : {
			fontSize : fontSize,
			fontWeight : 'normal',
			fontFamily : 'Arial'
		},
		left : 70,
		top : 21,
		height : 50,
		width : 200,
		clickName : 'comment',
		text : 'Got some fresh fruit, conducted some business, took a nap'
	});
	row.add(comment);

	var calendar = Ti.UI.createView({
		backgroundImage : '../images/custom_tableview/eventsButton.png',
		bottom : 2,
		left : 70,
		width : 32,
		clickName : 'calendar',
		height : 32
	});
	row.add(calendar);

	var button = Ti.UI.createView({
		backgroundImage : '../images/custom_tableview/commentButton.png',
		top : 35,
		right : 5,
		width : 36,
		clickName : 'button',
		height : 34
	});
	row.add(button);

	var date = Ti.UI.createLabel({
		color : '#999',
		font : {
			fontSize : 13,
			fontWeight : 'normal',
			fontFamily : 'Arial'
		},
		left : 105,
		bottom : 5,
		height : 20,
		width : 100,
		clickName : 'date',
		text : 'posted on 3/11'
	});
	row.add(date);

	dataRows.push(row);
}

//
// create table view (
//
var header = Ti.UI.createView({
	width : deviceWidth,
	height : deviceHeight * 0.1,
	backgroundColor : '#ebebeb',

	layout : 'horizontal'
});

win.add(header);
var imgHeight = (deviceHeight * 0.1) - 10;
var image = Ti.UI.createView({
	backgroundImage : '../images/logo.png',
	top : 5,
	left : 10,
	height : imgHeight,
	width : imgHeight * 1.6

});
header.add(image);
var nomDiag = Ti.UI.createLabel({
	text : 'Liste Missions',
	top : 5,
	left : 40,
	height : imgHeight,
	width : 'auto',
	color : 'black',
	font : {
		fontSize : '18dp',
	},

});
header.add(nomDiag);

var body = Ti.UI.createView({
	width : deviceWidth,
	height : deviceHeight - 60,
	backgroundColor : 'red',

});
win.add(body);
tableView = Titanium.UI.createTableView({
	data : dataRows,

	backgroundColor : 'white'
});
body.add(tableView);

tableView.addEventListener('click', function(e) {
	Ti.API.info('table view row clicked - source ' + e.source);
	// use rowNum property on object to get row number
	var rowNum = e.index;
});


text:
<?php $this->beginContent('application.modules_core.activity.views.activityLayoutMail', array('activity' => $activity, 'showSpace' => true)); ?>

<?php echo Yii::t('CommentModule.views_activities_CommentCreated', "%displayName% wrote a new comment ", array(
    '%displayName%' => ''. CHtml::encode($user->displayName) .''
));
?>

<?php $text = ActivityModule::formatOutput($target->message); ?>
"<?php echo $text; ?>"

<?php $this->endContent(); ?>


text:
cd "test-classes/tests" || exit
(
  found_nonempty=''
  for file in cypress.json ; do
    if [[ -s "$file" ]] ; then
      found_nonempty=1
    fi
  done
  if [ "$found_nonempty" ] ; then
    echo "Running identity apps cypress integration tests..."
    cypress cache clear
    sleep 25
    npm run cy:headless
  else
    echo "Failed to find the $file file."
    exit 1
  fi
)


text:
				<button type="button" class="close" data-dismiss="modal"aria-label="Close">
					×
				</button>

Choose a table relation with {{tableName}}

Choose a Parent table relation with {{tableName}}

Choose custom filters for {{collectionName}}.

				Join to Table :
				Join to Parent Table :
				Define Self filter with :

				  <button class="btn btn-default dropdown-toggle" ng-disabled="isEditorMode"  id="dLabel" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
				    {{ joinTableName || "Select"}}

				  </button>

{{tableEntry}}

				    |
				Join Type :

				  <button class="btn btn-default dropdown-toggle dropdown-label"  id="dLabel" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
				    {{ joinType || "Select Joint Type"}}

				  </button>

INNER

LEFT_OUTER

RIGHT_OUTER

FULL_OUTER

Loading.... Please Wait !!

							<button class="btn btn-info dropdown-toggle"  id="dSqlOperationOpratorLabel" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
							    {{filter.logicalOperator || "Select"}}

						  </button>

AND

OR

					  <button aria-label="Close" class="close" ng-click="removeFilter(filter)" ng-hide="isFirstTableRelationFilter()" type="button">
							×
						</button>

							 Column type {{getLHSColumnType()}} is not allowed in comparison !!

							Operator

								<button class="btn btn-default dropdown-toggle"  id="dSqlOperationLabel" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
								    {{filter.sqlOperation || "Select"}}

								  </button>

EQ

NE

GT

GTE

LT

LTE

IN

NIN

ISNULL

ISNOTNULL

<button type="button" class="btn btn-primary" id="AddFilterToRelationBtn" ng-click="addNewFilter()">ADD Filter</button>

					<button type="button" class="btn btn-primary" id="DBMigratorTableRelationPopupCancelButton" data-dismiss="modal" ng-click="DiscardRelation()">Cancel</button>
					<button type="button" class="btn btn-primary" id="DBMigratorTableRelationPopupOkButton" ng-click="ValidateAndAddRelation()">OK</button>


text:
ACCEPTED

#### According to
Index Fungorum

#### Published in
Nova Hedwigia 13: 184 (1967)

#### Original name
Phyllosticta arborea Cejp

### Remarks
null


text:
<?php

namespace MPWAR\Controllers;

use MPWAR\AppKernel;
use MPWAR\Request\Request;

abstract class BaseController
{
    protected $request;
    protected $app;
    protected $strings;

    public function __construct(Request $req, AppKernel $app, array $strings)
    {
        $this->request = $req;
        $this->app = $app;
        $this->strings = $strings;
    }
}


text:
import { diag } from '@opentelemetry/api';
import { Detector, Resource } from '@opentelemetry/resources';
import {
  CloudProviderValues,
  CloudPlatformValues,
  SemanticResourceAttributes,
} from '@opentelemetry/semantic-conventions';
import * as http from 'http';
import * as util from 'util';
import * as fs from 'fs';
import * as os from 'os';
import { getEnv } from '@opentelemetry/core';

const HTTP_TIMEOUT_IN_MS = 1000;

interface AwsLogOptions {
  readonly 'awslogs-region'?: string;
  readonly 'awslogs-group'?: string;
  readonly 'awslogs-stream'?: string;
}

/**
 * The AwsEcsDetector can be used to detect if a process is running in AWS
 * ECS and return a {@link Resource} populated with data about the ECS
 * plugins of AWS X-Ray. Returns an empty Resource if detection fails.
 */
export class AwsEcsDetector implements Detector {
  static readonly CONTAINER_ID_LENGTH = 64;
  static readonly DEFAULT_CGROUP_PATH = '/proc/self/cgroup';

  private static readFileAsync = util.promisify(fs.readFile);

  async detect(): Promise<Resource> {
    const env = getEnv();
    if (!env.ECS_CONTAINER_METADATA_URI_V4 && !env.ECS_CONTAINER_METADATA_URI) {
      diag.debug('AwsEcsDetector failed: Process is not on ECS');
      return Resource.empty();
    }

    let resource = new Resource({
      [SemanticResourceAttributes.CLOUD_PROVIDER]: CloudProviderValues.AWS,
      [SemanticResourceAttributes.CLOUD_PLATFORM]: CloudPlatformValues.AWS_ECS,
    }).merge(await AwsEcsDetector._getContainerIdAndHostnameResource());

    const metadataUrl = getEnv().ECS_CONTAINER_METADATA_URI_V4;
    if (metadataUrl) {
      const [containerMetadata, taskMetadata] = await Promise.all([
        AwsEcsDetector._getUrlAsJson(metadataUrl),
        AwsEcsDetector._getUrlAsJson(`${metadataUrl}/task`),
      ]);

      const metadatav4Resource = await AwsEcsDetector._getMetadataV4Resource(
        containerMetadata,
        taskMetadata
      );
      const logsResource = await AwsEcsDetector._getLogResource(
        containerMetadata
      );

      resource = resource.merge(metadatav4Resource).merge(logsResource);
    }

    return resource;
  }

  /**
   * Read container ID from cgroup file
   * In ECS, even if we fail to find target file
   * or target file does not contain container ID
   * we do not throw an error but throw warning message
   * and then return null string
   */
  private static async _getContainerIdAndHostnameResource(): Promise<Resource> {
    const hostName = os.hostname();

    let containerId = '';
    try {
      const rawData = await AwsEcsDetector.readFileAsync(
        AwsEcsDetector.DEFAULT_CGROUP_PATH,
        'utf8'
      );
      const splitData = rawData.trim().split('\n');
      for (const str of splitData) {
        if (str.length > AwsEcsDetector.CONTAINER_ID_LENGTH) {
          containerId = str.substring(
            str.length - AwsEcsDetector.CONTAINER_ID_LENGTH
          );
          break;
        }
      }
    } catch (e) {
      diag.warn('AwsEcsDetector failed to read container ID', e);
    }

    if (hostName || containerId) {
      return new Resource({
        [SemanticResourceAttributes.CONTAINER_NAME]: hostName || '',
        [SemanticResourceAttributes.CONTAINER_ID]: containerId || '',
      });
    }

    return Resource.empty();
  }

  private static async _getMetadataV4Resource(
    containerMetadata: any,
    taskMetadata: any
  ): Promise<Resource> {
    const launchType: string = taskMetadata['LaunchType'];
    const taskArn: string = taskMetadata['TaskARN'];

    const baseArn: string = taskArn.substring(0, taskArn.lastIndexOf(':'));
    const cluster: string = taskMetadata['Cluster'];

    const clusterArn = cluster.startsWith('arn:')
      ? cluster
      : `${baseArn}:cluster/${cluster}`;

    const containerArn: string = containerMetadata['ContainerARN'];

    // https://github.com/open-telemetry/opentelemetry-specification/blob/main/semantic_conventions/resource/cloud_provider/aws/ecs.yaml
    return new Resource({
      [SemanticResourceAttributes.AWS_ECS_CONTAINER_ARN]: containerArn,
      [SemanticResourceAttributes.AWS_ECS_CLUSTER_ARN]: clusterArn,
      [SemanticResourceAttributes.AWS_ECS_LAUNCHTYPE]:
        launchType?.toLowerCase(),
      [SemanticResourceAttributes.AWS_ECS_TASK_ARN]: taskArn,
      [SemanticResourceAttributes.AWS_ECS_TASK_FAMILY]: taskMetadata['Family'],
      [SemanticResourceAttributes.AWS_ECS_TASK_REVISION]:
        taskMetadata['Revision'],
    });
  }

  private static async _getLogResource(
    containerMetadata: any
  ): Promise<Resource> {
    if (
      containerMetadata['LogDriver'] !== 'awslogs' ||
      !containerMetadata['LogOptions']
    ) {
      return Resource.EMPTY;
    }

    const containerArn = containerMetadata['ContainerARN']!;
    const logOptions = containerMetadata['LogOptions'] as AwsLogOptions;

    const logsRegion =
      logOptions['awslogs-region'] ||
      AwsEcsDetector._getRegionFromArn(containerArn);

    const awsAccount = AwsEcsDetector._getAccountFromArn(containerArn);

    const logsGroupName = logOptions['awslogs-group']!;
    const logsGroupArn = `arn:aws:logs:${logsRegion}:${awsAccount}:log-group:${logsGroupName}`;
    const logsStreamName = logOptions['awslogs-stream']!;
    const logsStreamArn = `arn:aws:logs:${logsRegion}:${awsAccount}:log-group:${logsGroupName}:log-stream:${logsStreamName}`;

    return new Resource({
      [SemanticResourceAttributes.AWS_LOG_GROUP_NAMES]: [logsGroupName],
      [SemanticResourceAttributes.AWS_LOG_GROUP_ARNS]: [logsGroupArn],
      [SemanticResourceAttributes.AWS_LOG_STREAM_NAMES]: [logsStreamName],
      [SemanticResourceAttributes.AWS_LOG_STREAM_ARNS]: [logsStreamArn],
    });
  }

  private static _getAccountFromArn(containerArn: string): string {
    const match = /arn:aws:ecs:[^:]+:([^:]+):.*/.exec(containerArn);
    return match![1];
  }

  private static _getRegionFromArn(containerArn: string): string {
    const match = /arn:aws:ecs:([^:]+):.*/.exec(containerArn);
    return match![1];
  }

  private static _getUrlAsJson(url: string): Promise<any> {
    return new Promise<string>((resolve, reject) => {
      const request = http.get(url, (response: http.IncomingMessage) => {
        if (response.statusCode && response.statusCode >= 400) {
          reject(
            new Error(
              `Request to '${url}' failed with status ${response.statusCode}`
            )
          );
        }
        /*
         * Concatenate the response out of chunks:
         * https://nodejs.org/api/stream.html#stream_event_data
         */
        let responseBody = '';
        response.on(
          'data',
          (chunk: Buffer) => (responseBody += chunk.toString())
        );
        // All the data has been read, resolve the Promise
        response.on('end', () => resolve(responseBody));
        /*
         * https://nodejs.org/api/http.html#httprequesturl-options-callback, see the
         * 'In the case of a premature connection close after the response is received'
         * case
         */
        request.on('error', reject);
      });

      // Set an aggressive timeout to prevent lock-ups
      request.setTimeout(HTTP_TIMEOUT_IN_MS, () => {
        request.destroy();
      });
      // Connection error, disconnection, etc.
      request.on('error', reject);
      request.end();
    }).then(responseBodyRaw => JSON.parse(responseBodyRaw));
  }
}

export const awsEcsDetector = new AwsEcsDetector();


text:
package gov.hhs.fha.nhinc.messaging.client;

import gov.hhs.fha.nhinc.common.nhinccommon.AssertionType;
import gov.hhs.fha.nhinc.messaging.service.BaseServiceEndpoint;
import gov.hhs.fha.nhinc.messaging.service.ServiceEndpoint;
import gov.hhs.fha.nhinc.messaging.service.decorator.MTOMServiceEndpointDecorator;
import gov.hhs.fha.nhinc.messaging.service.decorator.cxf.WsAddressingServiceEndpointDecorator;
import gov.hhs.fha.nhinc.messaging.service.port.CachingCXFSecuredServicePortBuilder;
import gov.hhs.fha.nhinc.messaging.service.port.ServicePortDescriptor;

/**
 * @author akong
 *
 */
public class CONNECTTestClient<T> implements CONNECTClient<T> {

    protected ServiceEndpoint<T> serviceEndpoint = null;

    /**
     * Constructor for a client used solely for unit tests. This class will only do the base configuration for the
     * endpoint, but it will expose the service endpoint for test classes to use. This class will also use the caching
     * mechanism that will single instance the port.
     *
     * @param portDescriptor
     */
    public CONNECTTestClient(ServicePortDescriptor<T> portDescriptor) {
        serviceEndpoint = new BaseServiceEndpoint<T>(new CachingCXFSecuredServicePortBuilder<T>(portDescriptor).createPort());
    }

    public ServiceEndpoint<T> getServiceEndpoint() {
        return serviceEndpoint;
    }

    /* (non-Javadoc)
     * @see gov.hhs.fha.nhinc.messaging.client.CONNECTClient#getPort()
     */
    @Override
    public T getPort() {
        return serviceEndpoint.getPort();
    }

    /* (non-Javadoc)
     * @see gov.hhs.fha.nhinc.messaging.client.CONNECTClient#invokePort(java.lang.Class, java.lang.String, java.lang.Object)
     */
    @Override
    public Object invokePort(Class<T> portClass, String methodName, Object ... operationInput) throws Exception {
        return null;
    }

    /* (non-Javadoc)
     * @see gov.hhs.fha.nhinc.messaging.client.CONNECTClient#supportMtom()
     */
    @Override
    public void enableMtom() {
        serviceEndpoint = new MTOMServiceEndpointDecorator<T>(serviceEndpoint);
    }

    /* (non-Javadoc)
     * @see gov.hhs.fha.nhinc.messaging.client.CONNECTClient#enableWSA(gov.hhs.fha.nhinc.common.nhinccommon.AssertionType, java.lang.String, java.lang.String)
     */
    @Override
    public void enableWSA(AssertionType assertion, String wsAddressingTo, String wsAddressingActionId) {
        serviceEndpoint = new WsAddressingServiceEndpointDecorator<T>(serviceEndpoint, wsAddressingTo, wsAddressingActionId, assertion);
    }
}


text:
layout: page
title: Hero Financial Show
date: 2016-05-24
author: Cheryl Holland
tags: weekly links, java
status: published
summary: Pellentesque sed augue vestibulum, mollis arcu ac, dignissim.
banner: images/banner/meeting-01.jpg
booking:
  startDate: 01/09/2017
  endDate: 01/14/2017
  ctyhocn: DENUSHX
  groupCode: HFS
published: true
---
Pellentesque sodales, ex lobortis suscipit dapibus, est velit pulvinar tellus, a aliquam dui justo non sem. Pellentesque et tellus sed leo mollis hendrerit sit amet vitae magna. Mauris sit amet placerat neque, in dapibus sem. Vivamus vestibulum ultricies augue, dignissim dignissim lectus ultrices id. Maecenas euismod mi mauris, nec dignissim lectus vestibulum sit amet. Mauris dapibus quis est eget consectetur. Morbi pellentesque fermentum turpis id auctor. Aliquam tincidunt risus sit amet neque ornare, sed porta libero feugiat.

1 In ullamcorper elit ut enim sagittis, non ornare tortor efficitur
1 Donec facilisis libero ac posuere interdum
1 Phasellus eget purus et libero finibus rutrum
1 Aenean id ex eget enim convallis tempor.

Curabitur pellentesque varius dapibus. Pellentesque eu sollicitudin neque. Cras vehicula faucibus est non fringilla. Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse tincidunt leo eget dignissim vestibulum. Maecenas aliquet tellus ac justo tincidunt, at aliquam tellus viverra. Aenean eu leo mauris. Sed a metus sem. Nullam ut sem eget sapien sollicitudin venenatis. Maecenas cursus velit et ex scelerisque, at sollicitudin erat feugiat.
Nulla et metus mauris. Nam nec urna et eros vestibulum sagittis id non mi. Vivamus a varius massa. Ut eget porttitor sem, vel venenatis libero. Proin tempus suscipit egestas. Quisque tempus non purus ut placerat. Aenean lacinia, magna id sodales scelerisque, dolor felis luctus nisl, sit amet vehicula odio magna vitae urna. Nullam vel odio ante. Fusce vitae mi eu lacus lacinia mollis at a odio. Etiam iaculis tincidunt lectus nec dictum. Mauris iaculis libero et metus sodales, blandit tincidunt lorem accumsan. Praesent blandit, risus eget venenatis sollicitudin, enim arcu condimentum ante, placerat consequat nibh velit vitae metus.


text:
var NavigationController;
NavigationController = (function() {
  function NavigationController() {
    this.windowStack = [];
  }
  NavigationController.prototype.open = function(windowToOpen) {
    var containerWindow, that;
    this.windowStack.push(windowToOpen);
    that = this;
    windowToOpen.addEventListener('close', function() {
      return that.windowStack.pop();
    });
    windowToOpen.navBarHidden = windowToOpen.navBarHidden || false;
    if (this.windowStack.length === 1) {
      if (App.isAndroid) {
        windowToOpen.exitOnClose = true;
        return windowToOpen.open();
      } else {
        this.navGroup = Ti.UI.iPhone.createNavigationGroup({
          window: windowToOpen
        });
        containerWindow = Ti.UI.createWindow();
        containerWindow.add(this.navGroup);
        return containerWindow.open();
      }
    } else {
      if (App.isAndroid) {
        return windowToOpen.open();
      } else {
        return this.navGroup.open(windowToOpen);
      }
    }
  };
  NavigationController.prototype.home = function() {
    var win, windows, _i, _len;
    windows = this.windowStack.concat([]).slice(1);
    for (_i = 0, _len = windows.length; _i < _len; _i++) {
      win = windows[_i];
      if (this.navGroup) {
        this.navGroup.close(win);
      } else {
        win.close();
      }
    }
    return this.windowStack = [this.windowStack[0]];
  };
  return NavigationController;
})();
exports.NavigationController = NavigationController;


text:
@implementation NSString (PxUIKit)

- (CGFloat)heightForWidth:(CGFloat)width config:(PxFontConfig)config {
    CGSize size = CGSizeMake(width, INT_MAX);
    CGFloat height;
    CGFloat multiLineHeight;
    NSMutableDictionary *fontAttributes = [NSMutableDictionary dictionary];
    NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
    NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];

    if (config.font) {
        fontAttributes[NSFontAttributeName] = config.font;
    }

    if (config.lineBreakMode) {
        paragraph.lineBreakMode = config.lineBreakMode;

        fontAttributes[NSParagraphStyleAttributeName] = paragraph;
    }

    if (config.adjustsFontSizeToFitWidth) {
        context.minimumScaleFactor = config.minimumScaleFactor;
    }

    height = [self boundingRectWithSize:size options:0 attributes:fontAttributes context:context].size.height;

    if (config.numberOfLines != 1) {
        if (
            paragraph.lineBreakMode == NSLineBreakByTruncatingHead ||
            paragraph.lineBreakMode == NSLineBreakByTruncatingMiddle ||
            paragraph.lineBreakMode == NSLineBreakByTruncatingTail
            ) {
            paragraph.lineBreakMode = NSLineBreakByWordWrapping;
        }

        multiLineHeight = [self boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:fontAttributes context:context].size.height;

        if (config.numberOfLines == 0) {
            height = multiLineHeight;
        } else {
            height *= config.numberOfLines;
        }

        height = MIN(height, multiLineHeight);
    }

    return height;
}

@end


text:
import Backburner from 'backburner';
import lolex from 'lolex';

// used to ensure tests for fake timers can reliably use native setTimeout
const SET_TIMEOUT = setTimeout;
let fakeClock;

function escapeCurrentMicrotaskQueue() {
  return new Promise((resolve) => {
    // this ensures that we have been to the end of the current
    // events microtask queue
    setTimeout(resolve, 0);
  });
}

QUnit.module('tests/autorun', {
  afterEach() {
    if (fakeClock) {
      fakeClock.uninstall();
    }
  }
});

QUnit.test('autorun', function(assert) {
  let done = assert.async();
  let bb = new Backburner(['zomg']);
  let step = 0;

  assert.ok(!bb.currentInstance, 'The DeferredActionQueues object is lazily instaniated');
  assert.equal(step++, 0);

  bb.schedule('zomg', null, () => {
    assert.equal(step++, 2);
    setTimeout(() => {
      assert.ok(!bb.hasTimers(), 'The all timers are cleared');
      done();
    });
  });

  assert.ok(bb.currentInstance, 'The DeferredActionQueues object exists');
  assert.equal(step++, 1);
});

QUnit.test('autorun (joins next run if not yet flushed)', function(assert) {
  let bb = new Backburner(['zomg']);
  let order = -1;

  let tasks = {
    one: { count: 0, order: -1 },
    two: { count: 0, order: -1 }
  };

  bb.schedule('zomg', null, () => {
    tasks.one.count++;
    tasks.one.order = ++order;
  });

  assert.deepEqual(tasks, {
    one: { count: 0, order: -1 },
    two: { count: 0, order: -1 }
  });

  bb.run(() => {
    bb.schedule('zomg', null, () => {
      tasks.two.count++;
      tasks.two.order = ++order;
    });

    assert.deepEqual(tasks, {
      one: { count: 0, order: -1 },
      two: { count: 0, order: -1 }
    });
  });

  assert.deepEqual(tasks, {
    one: { count: 1, order: 0 },
    two: { count: 1, order: 1 }
  });
});

QUnit.test('autorun completes before items scheduled by later (via microtasks)', function(assert) {
  let done = assert.async();
  let bb = new Backburner(['first', 'second']);
  let order = new Array();

  // this later will be scheduled into the `first` queue when
  // its timer is up
  bb.later(() => {
    order.push('second - later');
  }, 0);

  // scheduling this into the second queue so that we can confirm this _still_
  // runs first (due to autorun resolving before scheduled timer)
  bb.schedule('second', null, () => {
    order.push('first - scheduled');
  });

  setTimeout(() => {
    assert.deepEqual(order, ['first - scheduled', 'second - later']);
    done();
  }, 20);
});

QUnit.test('can be canceled (private API)', function(assert) {
  assert.expect(0);

  let done = assert.async();
  let bb = new Backburner(['zomg']);

  bb.schedule('zomg', null, () => {
    assert.notOk(true, 'should not flush');
  });

  bb['_cancelAutorun']();

  setTimeout(done, 10);
});

QUnit.test('autorun interleaved with microtasks do not get dropped [GH#332]', function(assert) {
  let done = assert.async();
  let actual: string[] = [];
  let bb = new Backburner(['actions', 'render']);

  bb.schedule('render', function() {
    actual.push('first');
    bb.schedule('actions', () => {
      actual.push('action1');
    });

    Promise.resolve().then(() => {
      actual.push('second');
      bb.schedule('actions', () => {
        actual.push('action2');
      });

      return Promise.resolve().then(() => {
        actual.push('third');

        bb.schedule('actions', () => {
          actual.push('action3');
        });
      });
    });
  });

  setTimeout(function() {
    assert.deepEqual(actual, ['first', 'action1', 'second', 'action2', 'third', 'action3']);

    done();
  });
});

QUnit.test('autorun functions even when using fake timers', function(assert) {
  let done = assert.async();
  let bb = new Backburner(['zomg']);
  let step = 0;

  assert.ok(!bb.currentInstance, 'The DeferredActionQueues object is lazily instaniated');
  assert.equal(step++, 0);

  fakeClock = lolex.install();
  bb.schedule('zomg', null, () => {
    assert.equal(step++, 2);
    SET_TIMEOUT(() => {
      assert.ok(!bb.hasTimers(), 'The all timers are cleared');
      done();
    });
  });

  assert.ok(bb.currentInstance, 'The DeferredActionQueues object exists');
  assert.equal(step++, 1);
});

QUnit.test('customizing flushing per queue via flush', function(assert) {
  assert.step('start');

  let deferredFlush;

  let bb = new Backburner(
    [
      'zomg',
      'render',
      'afterRender'
    ],
    {
      flush(queueName, flush) {
        if (queueName === 'render') {
          deferredFlush = flush;
        } else {
          flush();
        }
      }
    }
  );

  bb.schedule('zomg', null, () => {
    assert.step('running zomg');
  });

  bb.schedule('render', null, () => {
    assert.step('running render');
  });

  bb.schedule('afterRender', null, () => {
    assert.step('running afterRender');
  });

  return escapeCurrentMicrotaskQueue()
    .then(() => {
      deferredFlush();
    })
    .then(escapeCurrentMicrotaskQueue)
    .then(() => {
      assert.verifySteps([
        'start',
        'running zomg',
        'running render',
        'running afterRender',
      ]);
    });
});

QUnit.test('customized flushing - precedence is rechecked upon each flush', function(assert) {
  assert.step('start');

  let deferredFlush;

  let bb = new Backburner(
    [
      'zomg',
      'render',
      'afterRender'
    ],
    {
      flush(queueName, flush) {
        if (deferredFlush === undefined && queueName === 'render') {
          deferredFlush = flush;
        } else {
          flush();
        }
      }
    }
  );

  bb.schedule('zomg', null, () => {
    assert.step('running zomg');
  });

  bb.schedule('render', null, () => {
    assert.step('running render');
  });

  bb.schedule('afterRender', null, () => {
    assert.step('running afterRender');
  });

  return escapeCurrentMicrotaskQueue()
    .then(() => {
      bb.schedule('zomg', null, () => {
        assert.step('running zomg 2');
      });

      deferredFlush();
    })
    .then(escapeCurrentMicrotaskQueue)
    .then(() => {
      assert.verifySteps([
        'start',
        'running zomg',
        'running zomg 2',
        'running render',
        'running afterRender',
      ]);
    });
});

QUnit.test('customizing flushing per queue via flush - with forced run', function(assert) {
  assert.step('start');

  let deferredFlush;

  let bb = new Backburner(
    [
      'zomg',
      'render',
      'afterRender'
    ],
    {
      flush(queueName, flush) {
        if (queueName === 'render') {
          deferredFlush = flush;
        } else {
          flush();
        }
      }
    }
  );

  bb.schedule('zomg', null, () => {
    assert.step('running zomg');
  });

  bb.schedule('render', null, () => {
    assert.step('running render');
  });

  bb.schedule('afterRender', null, () => {
    assert.step('running afterRender');
  });

  return escapeCurrentMicrotaskQueue()
    .then(() => {
      bb.run(() => {});

      assert.verifySteps([
        'start',
        'running zomg',
        'running render',
        'running afterRender',
      ]);
    });
});


text:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;

namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.RequestOrdering
{
    public partial class RequestOrderingTests : AbstractLanguageServerProtocolTests
    {
        protected override TestComposition Composition => base.Composition
            .AddParts(typeof(MutatingRequestHandler))
            .AddParts(typeof(NonMutatingRequestHandler))
            .AddParts(typeof(FailingRequestHandler))
            .AddParts(typeof(FailingMutatingRequestHandler))
            .AddParts(typeof(NonLSPSolutionRequestHandler))
            .AddParts(typeof(LongRunningNonMutatingRequestHandler));

        [Fact]
        public async Task MutatingRequestsDontOverlap()
        {
            var requests = new[] {
                new TestRequest(MutatingRequestHandler.MethodName),
                new TestRequest(MutatingRequestHandler.MethodName),
                new TestRequest(MutatingRequestHandler.MethodName),
            };

            await using var testLspServer = await CreateTestLspServerAsync("class C { }");
            var responses = await TestAsync(testLspServer, requests);

            // Every request should have started at or after the one before it
            Assert.True(responses[1].StartTime >= responses[0].EndTime);
            Assert.True(responses[2].StartTime >= responses[1].EndTime);
        }

        [Fact]
        public async Task NonMutatingRequestsOverlap()
        {
            var requests = new[] {
                new TestRequest(NonMutatingRequestHandler.MethodName),
                new TestRequest(NonMutatingRequestHandler.MethodName),
                new TestRequest(NonMutatingRequestHandler.MethodName),
            };

            await using var testLspServer = await CreateTestLspServerAsync("class C { }");
            var responses = await TestAsync(testLspServer, requests);

            // Every request should have started immediately, without waiting
            Assert.True(responses[1].StartTime < responses[0].EndTime);
            Assert.True(responses[2].StartTime < responses[1].EndTime);
        }

        [Fact]
        public async Task NonMutatingWaitsForMutating()
        {
            var requests = new[] {
                new TestRequest(MutatingRequestHandler.MethodName),
                new TestRequest(NonMutatingRequestHandler.MethodName),
                new TestRequest(NonMutatingRequestHandler.MethodName),
            };

            await using var testLspServer = await CreateTestLspServerAsync("class C { }");
            var responses = await TestAsync(testLspServer, requests);

            // The non mutating tasks should have waited for the first task to finish
            Assert.True(responses[1].StartTime >= responses[0].EndTime);
            Assert.True(responses[2].StartTime >= responses[0].EndTime);
            // The non mutating requests shouldn't have waited for each other
            Assert.True(responses[1].StartTime < responses[2].EndTime);
            Assert.True(responses[2].StartTime < responses[1].EndTime);
        }

        [Fact]
        public async Task MutatingDoesntWaitForNonMutating()
        {
            var requests = new[] {
                new TestRequest(NonMutatingRequestHandler.MethodName),
                new TestRequest(NonMutatingRequestHandler.MethodName),
                new TestRequest(MutatingRequestHandler.MethodName),
            };

            await using var testLspServer = await CreateTestLspServerAsync("class C { }");
            var responses = await TestAsync(testLspServer, requests);

            // All tasks should start without waiting for any to finish
            Assert.True(responses[1].StartTime < responses[0].EndTime);
            Assert.True(responses[2].StartTime < responses[0].EndTime);
            Assert.True(responses[1].StartTime < responses[2].EndTime);
            Assert.True(responses[2].StartTime < responses[1].EndTime);
        }

        [Fact]
        public async Task ThrowingTaskDoesntBringDownQueue()
        {
            var requests = new[] {
                new TestRequest(FailingRequestHandler.MethodName),
                new TestRequest(NonMutatingRequestHandler.MethodName),
                new TestRequest(MutatingRequestHandler.MethodName),
                new TestRequest(NonMutatingRequestHandler.MethodName),
            };

            await using var testLspServer = await CreateTestLspServerAsync("class C { }");
            var waitables = StartTestRun(testLspServer, requests);

            // first task should fail
            await Assert.ThrowsAsync<StreamJsonRpc.RemoteInvocationException>(() => waitables[0]);

            // remaining tasks should have executed normally
            var responses = await Task.WhenAll(waitables.Skip(1));

            Assert.Empty(responses.Where(r => r == null));
            Assert.Empty(responses.Where(r => r!.StartTime == default));
            Assert.All(responses, r => Assert.True(r!.EndTime > r!.StartTime));
        }

        [Fact]
        public async Task LongRunningSynchronousNonMutatingTaskDoesNotBlockQueue()
        {
            var requests = new[] {
                new TestRequest(LongRunningNonMutatingRequestHandler.MethodName),
                new TestRequest(MutatingRequestHandler.MethodName),
                new TestRequest(NonMutatingRequestHandler.MethodName),
            };

            await using var testLspServer = await CreateTestLspServerAsync("class C { }");

            // Cancel all requests if the request queue is blocked for 1 minute. This will result in a failed test run.
            using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1));
            var waitables = StartTestRun(testLspServer, requests, cts.Token);

            // Non-long running tasks should run and complete. If there's a test-failure for a "cancellation"
            // at this point it means our long running task blocked the queue and prevented completion.
            var responses = await Task.WhenAll(waitables.Skip(1));
            Assert.Empty(responses.Where(r => r == null));
            Assert.Empty(responses.Where(r => r!.StartTime == default));
            Assert.All(responses, r => Assert.True(r!.EndTime > r!.StartTime));

            // Our long-running waitable should still be running until cancelled.
            var longRunningWaitable = waitables[0];
            Assert.False(longRunningWaitable.IsCompleted);
        }

        [Fact]
        public async Task FailingMutableTaskShutsDownQueue()
        {
            // NOTE: A failing task shuts down the queue not due to an exception escaping out of the handler
            //       but because the solution state would be invalid. This doesn't test the queues exception
            //       resiliancy.

            var requests = new[] {
                new TestRequest(FailingMutatingRequestHandler.MethodName),
                new TestRequest(NonMutatingRequestHandler.MethodName),
                new TestRequest(MutatingRequestHandler.MethodName),
                new TestRequest(NonMutatingRequestHandler.MethodName),
            };

            await using var testLspServer = await CreateTestLspServerAsync("class C { }");
            var waitables = StartTestRun(testLspServer, requests);

            // first task should fail
            await Assert.ThrowsAsync<StreamJsonRpc.RemoteInvocationException>(() => waitables[0]);

            // The failed request returns to the client before the shutdown completes.
            // Wait for the queue to finish handling the failed request and shutdown.
            await testLspServer.GetQueueAccessor()!.Value.WaitForProcessingToStopAsync().ConfigureAwait(false);

            // remaining tasks should be canceled
            var areAllItemsCancelled = await testLspServer.GetQueueAccessor()!.Value.AreAllItemsCancelledUnsafeAsync();
            Assert.True(areAllItemsCancelled);
        }

        [Fact]
        public async Task NonMutatingRequestsOperateOnTheSameSolutionAfterMutation()
        {
            await using var testLspServer = await CreateTestLspServerAsync("class C { {|caret:|} }");

            var expectedSolution = testLspServer.GetCurrentSolution();

            // solution should be the same because no mutations have happened
            var solution = await GetLSPSolution(testLspServer, NonMutatingRequestHandler.MethodName);
            Assert.Equal(expectedSolution, solution);

            // Open a document, to get a forked solution
            await ExecuteDidOpen(testLspServer, testLspServer.GetLocations("caret").First().Uri);

            // solution should be different because there has been a mutation
            solution = await GetLSPSolution(testLspServer, NonMutatingRequestHandler.MethodName);
            Assert.NotEqual(expectedSolution, solution);

            expectedSolution = solution;

            // solution should be the same because no mutations have happened
            solution = await GetLSPSolution(testLspServer, NonMutatingRequestHandler.MethodName);
            Assert.Equal(expectedSolution, solution);

            // Apply some random change to the workspace that the LSP server doesn't "see"
            testLspServer.TestWorkspace.SetCurrentSolution(s => s.WithProjectName(s.Projects.First().Id, "NewName"), WorkspaceChangeKind.ProjectChanged);

            expectedSolution = testLspServer.GetCurrentSolution();

            // solution should be different because there has been a workspace change
            solution = await GetLSPSolution(testLspServer, NonMutatingRequestHandler.MethodName);
            Assert.NotEqual(expectedSolution, solution);

            expectedSolution = solution;

            // solution should be the same because no mutations have happened
            solution = await GetLSPSolution(testLspServer, NonMutatingRequestHandler.MethodName);
            Assert.Equal(expectedSolution, solution);
        }

        [Fact]
        public async Task HandlerThatSkipsBuildingLSPSolutionGetsWorkspaceSolution()
        {
            await using var testLspServer = await CreateTestLspServerAsync("class C { {|caret:|} }");

            var solution = await GetLSPSolution(testLspServer, NonLSPSolutionRequestHandler.MethodName);
            Assert.Null(solution);

            // Open a document, to create a change that LSP handlers wouldn normally see
            await ExecuteDidOpen(testLspServer, testLspServer.GetLocations("caret").First().Uri);

            // solution shouldn't have changed
            solution = await GetLSPSolution(testLspServer, NonLSPSolutionRequestHandler.MethodName);
            Assert.Null(solution);
        }

        private static async Task ExecuteDidOpen(TestLspServer testLspServer, Uri documentUri)
        {
            var didOpenParams = new LSP.DidOpenTextDocumentParams
            {
                TextDocument = new LSP.TextDocumentItem
                {
                    Uri = documentUri,
                    Text = "// hi there"
                }
            };
            await testLspServer.ExecuteRequestAsync<LSP.DidOpenTextDocumentParams, object>(Methods.TextDocumentDidOpenName, didOpenParams, CancellationToken.None);
        }

        private static async Task<Solution?> GetLSPSolution(TestLspServer testLspServer, string methodName)
        {
            var request = new TestRequest(methodName);
            var response = await testLspServer.ExecuteRequestAsync<TestRequest, TestResponse>(request.MethodName, request, CancellationToken.None);
            Contract.ThrowIfNull(response);
            if (response.ContextHasSolution)
            {
                var (_, solution) = await testLspServer.GetManager().GetLspSolutionInfoAsync(CancellationToken.None).ConfigureAwait(false);
                Contract.ThrowIfNull(solution);
                return solution;
            }

            return null;
        }

        private static async Task<TestResponse[]> TestAsync(TestLspServer testLspServer, TestRequest[] requests)
        {
            var waitables = StartTestRun(testLspServer, requests);

            var responses = await Task.WhenAll(waitables);

            // Sanity checks to ensure test handlers aren't doing something wacky, making future checks invalid
            Assert.Empty(responses.Where(r => r == null));
            Assert.Empty(responses.Where(r => r!.StartTime == default));
            Assert.All(responses, r => Assert.True(r!.EndTime > r!.StartTime));

            return responses!;
        }

        private static List<Task<TestResponse?>> StartTestRun(TestLspServer testLspServer, TestRequest[] requests, CancellationToken cancellationToken = default)
        {
            var waitables = new List<Task<TestResponse?>>();
            foreach (var request in requests)
                waitables.Add(testLspServer.ExecuteRequestAsync<TestRequest, TestResponse>(request.MethodName, request, cancellationToken));

            return waitables;
        }
    }
}


text:
  Asnières-sur-Nouère est
      une ville située dans le département de Charente en Poitou-Charentes. Elle comptait 1 083 habitants en 2008.

À coté de Asnières-sur-Nouère sont situées les communes de
Saint-Saturnin située à 5 km, 1 291 habitants,
Vindelle à 5 km, 938 habitants,
Douzat située à 3 km, 321 habitants,
Échallat située à 6 km, 439 habitants,
Saint-Amant-de-Nouère localisée à 5 km, 380 habitants,
Linars localisée à 6 km, 2 071 habitants,
 entre autres. De plus, Asnières-sur-Nouère est située à seulement onze km de Angoulême.

À Asnières-sur-Nouère, le prix moyen à l'achat d'un appartement se situe à 1 794 € du m² en vente. La valeur moyenne d'une maison à l'achat se situe à 1 542 € du m². À la location la valeur moyenne se situe à 3,89 € du m² par mois.

Le nombre d'habitations, à Asnières-sur-Nouère, était réparti en 2011 en douze appartements et 517 maisons soit
 un marché relativement équilibré.

La commune compte quelques  équipements sportifs, elle dispose, entre autres, de un terrain de tennis et un terrain de sport.