content: module ExampleDemo (Environ,initial,getNext, provideExample, testThis,mkFuncWithArg,searchGoodTree,isMeta)
    where
  
  import PGF
  --import System.IO
  import Data.List
  --import Control.Monad
  import qualified Data.Map as Map
  --import qualified Data.IntMap as IntMap
  import qualified Data.Set as Set
  import Data.Maybe
  --import System.Environment (getArgs)
  import System.Random (RandomGen) --newStdGen
  
  
  type MyType = CId                                -- name of the categories from the program
  type ConcType = CId                              -- categories from the resource grammar, that we parse on
  type MyFunc = CId                                -- functions that we need to implement
  --type FuncWithArg = ((MyFunc, MyType), Expr)    -- function with arguments  
  type InterInstr = [String]                       -- lincats that were generated but not written to the file
  
  
  
  data FuncWithArg = FuncWithArg 
                        {getName :: MyFunc,        -- name of the function to generate
                         getType :: MyType,        -- return type of the function
                         getTypeArgs :: [MyType]  -- types of arguments 
                         }
         deriving (Show,Eq,Ord)
  
  -- we assume that it's for English for the moment
  
  
  type TypeMap = Map.Map MyType ConcType           -- mapping found from a file
  
  type ConcMap = Map.Map MyFunc Expr               -- concrete expression after parsing
  
  data Environ = Env {getTypeMap :: TypeMap,                  -- mapping between a category in the grammar and a concrete type from RGL
                      getConcMap :: ConcMap,                  -- concrete expression after parsing          
                      getSigs :: Map.Map MyType [FuncWithArg], -- functions for which we have the concrete syntax already with args 
                      getAll :: [FuncWithArg]           -- all the functions with arguments  
                      }
  
  
  getNext :: Environ -> Environ -> ([MyFunc],[MyFunc])
  getNext env example_env = 
    let sgs = getSigs env
        allfuncs  = getAll env
        names = Set.fromList $ map getName $ concat $ Map.elems sgs
        exampleable = filter (\x -> (isJust $ getNameExpr x env) 
                                 &&
                                 (not $ Set.member x names) -- maybe drop this if you want to also rewrite from examples...
                              ) $ map getName allfuncs
        testeable = filter (\x -> (isJust $ getNameExpr x env ) 
                                && 
                                 (Set.member x names)
                            ) $ map getName allfuncs    
  
       in (exampleable,testeable)
  
  
  provideExample :: RandomGen gen => gen -> Environ -> MyFunc -> PGF -> PGF -> Language -> Maybe (Expr,String)
  provideExample gen env myfunc parsePGF pgfFile lang = 
        fmap giveExample $ getNameExpr myfunc env
   where 
     giveExample e_ = 
       let newexpr = head $ generateRandomFromDepth gen pgfFile e_ (Just 5) -- change here with the new random generator
           ty = getType $ head $ filter (\x -> getName x == myfunc) $ getAll env
           embeddedExpr = maybe "" (\x -> ", as in: " ++ q (linearize pgfFile lang x)) (embedInStart (getAll env) (Map.fromList [(ty,e_)]))
           lexpr = linearize pgfFile lang newexpr  
           q s = sq++s++sq
           sq = "\""
         in (newexpr,q lexpr ++ embeddedExpr)
  -- question, you need the IO monad for the random generator, how to do otherwise ??
  -- question can you make the expression bold/italic - somehow distinguishable from the rest ?
  
  
  
  testThis :: Environ -> MyFunc -> PGF -> Language -> Maybe String  
  testThis env myfunc parsePGF lang = 
      fmap (linearize parsePGF lang . mapToResource env . llin env) $
      getNameExpr myfunc env  
  
  
  -- we assume that even the functions linearized by the user will still be in getSigs along with their linearization 
  
  
  -- fill in the blancs of an expression that we want to linearize for testing purposes
  ---------------------------------------------------------------------------
  
  llin :: Environ -> Expr -> Expr 
  llin env expr = 
       let 
           (id,args) = fromJust $ unApp expr
         --cexpr = fromJust $ Map.lookup id (getConcMap env)
       in 
           if any isMeta args 
                then let 
                         sigs = concat $ Map.elems $ getSigs env
                         tys = findExprWhich sigs id
                      in  replaceConcArg 1 tys expr env 
             else mkApp id $ map (llin env) args
  
  
  -- argument of the meta variable to replace, list of arguments left, expression to replace, environment, current replace expression 
  replaceConcArg :: Int -> [MyType] -> Expr -> Environ -> Expr
  replaceConcArg i [] expr env = expr
  replaceConcArg i (t:ts) expr env =      -- TO DO : insert randomness here !!
     let ss = fromJust $ Map.lookup t $ getSigs env 
         args = filter (null . getTypeArgs) ss 
         finArg = if null args then let l = last ss in llin env (mkApp (getName l) [mkMeta j | j <- [1..(length $ getTypeArgs l)]]) 
                     else mkApp (getName $ last args) [] 
      in   
                       let newe = replaceOne i finArg expr
                                 in replaceConcArg (i+1) ts newe env       
                     
  -- replace a certain metavariable with a certain expression in another expression - return updated expression
  replaceOne :: Int -> Expr -> Expr -> Expr                               
  replaceOne i erep expr = 
        if isMeta expr && ((fromJust $ unMeta expr) == i) 
                 then erep
          else if isMeta expr then expr
                else let (id,args) = fromJust $ unApp expr
                         in  
                          mkApp id $ map (replaceOne i erep) args
  
  
  findExprWhich :: [FuncWithArg] -> MyFunc -> [MyType]
  findExprWhich lst f = getTypeArgs $ head $ filter (\x -> getName x == f) lst 
  
  
  mapToResource :: Environ -> Expr -> Expr 
  mapToResource env expr = 
        let (id,args) =  maybe (error $ "tried to unwrap " ++ showExpr [] expr) (\x -> x) (unApp expr)
            cmap      = getConcMap env
            cexp      = maybe (error $ "didn't find " ++ showCId id ++ " in  "++ show cmap) (\x -> x)  (Map.lookup id cmap)
          in 
          if null args then cexp
               else let newargs = map (mapToResource env) args
                     in replaceAllArgs cexp 1 newargs
        where 
        replaceAllArgs expr i []     = expr 
        replaceAllArgs expr i (x:xs) = replaceAllArgs (replaceOne i x expr) (i+1) xs 
     
           
  
  -----------------------------------------------
  
  -- embed expression in another one from the start category
  
  embedInStart :: [FuncWithArg] -> Map.Map MyType Expr -> Maybe Expr 
  embedInStart fss cs =
    let currset = Map.toList cs 
        nextset = Map.fromList $ concat [ if elem myt (getTypeArgs farg) 
                       then connectWithArg (myt,exp) farg else [] 
                          | (myt,exp) <- currset, farg <- fss]
        nextmap = Map.union cs nextset
        maybeExpr = Map.lookup startCateg nextset
       in if isNothing maybeExpr then 
                 if Map.size nextmap == Map.size cs then Nothing --error $ "could't build " ++ show startCateg ++ "with " ++ show fss 
                    else embedInStart fss nextmap
         else return $ fromJust maybeExpr
     where 
        connectWithArg (myt,exp) farg = 
               let ind = head $ elemIndices myt (getTypeArgs farg)
                in [(getType farg, mkApp (getName farg) $ [mkMeta i | i <- [1..ind]] ++ [exp] ++ [mkMeta i | i <- [(ind + 1)..((length $ getTypeArgs farg) - 1)]])]
                 
  
  
  
  
  -----------------------------------------------
  {-
  updateConcMap :: Environ -> MyFunc -> Expr -> Environ
  updateConcMap env myf expr = 
       Env (getTypeMap env) (Map.insert myf expr (getConcMap env)) (getSigs env) (getAll env)
  
   
  updateInterInstr :: Environ -> MyType -> FuncWithArg -> Environ
  updateInterInstr env myt myf  = 
    let  ii = getSigs env
         newInterInstr = 
           maybe (Map.insert myt [myf] ii) (\x -> Map.insert myt (myf:x) ii) $ Map.lookup myt ii
        in Env (getTypeMap env) (getConcMap env) newInterInstr (getAll env)
  
  
  putSignatures :: Environ -> [FuncWithArg] -> Environ
  putSignatures env fss = 
       Env (getTypeMap env) (getConcMap env) (mkSigs fss) (getAll env)
        
        
  updateEnv :: Environ -> FuncWithArg -> MyType -> Expr -> Environ 
  updateEnv env myf myt expr =  
    let  ii = getSigs env
         nn = getName myf
         newInterInstr = 
           maybe (Map.insert myt [myf] ii) (\x -> Map.insert myt (myf:x) ii) $ Map.lookup myt ii
        in Env (getTypeMap env) (Map.insert nn expr (getConcMap env)) newInterInstr (getAll env)
  -}
  
  mkSigs :: [FuncWithArg] -> Map.Map MyType [FuncWithArg]
  mkSigs fss = Map.fromListWith (++) $ zip (map getType fss) (map (\x -> [x]) fss)
  
  
  
  {------------------------------------
  lang :: String 
  lang = "Eng"
  
  
  parseLang :: Language
  parseLang = fromJust $ readLanguage "ParseEng"
  
  
  parsePGFfile :: String
  parsePGFfile = "ParseEngAbs.pgf"
  ------------------------------------}
  
  
  
  
                   
  searchGoodTree :: Environ -> Expr -> [Expr] -> IO (Maybe (Expr,Expr))
  searchGoodTree env expr [] = return Nothing
  searchGoodTree env expr (e:es) = 
       do val <- debugReplaceArgs expr e env
          maybe (searchGoodTree env expr es) (\x -> return $ Just (x,e)) val 
  
  
  
  getNameExpr :: MyFunc -> Environ -> Maybe Expr
  getNameExpr myfunc env = 
      let allfunc = filter (\x -> getName x == myfunc) $ getAll env
              in 
          if null allfunc then Nothing
              else getExpr (head allfunc) env
  
  -- find an expression to generate where we have all the other elements available
  getExpr :: FuncWithArg -> Environ -> Maybe Expr 
  getExpr farg env =  
    let tys = getTypeArgs farg
        ctx = getSigs env 
        lst = getConcTypes ctx tys 1
      in if (all isJust lst) then  Just $ mkApp (getName farg) (map fromJust lst)
              else  Nothing    
       where getConcTypes context [] i = []
             getConcTypes context (ty:types) i =  
                  let pos = Map.lookup ty context
                     in 
                      if isNothing pos  || (null $ fromJust pos) then [Nothing]                                                
                            else  
                               let mm = last $ fromJust pos
                                   mmargs = getTypeArgs mm
                                   newi = i + length mmargs - 1  
                                   lst = getConcTypes (Map.insert ty (init $ (fromJust pos)) context) types (newi+1)
                                    in                      
                                    if (all isJust lst) then                     -- i..newi
                                           (Just $ mkApp (getName mm) [mkMeta j | j <- [1..(length mmargs)]]) : lst 
                                         else  [Nothing]
        
  
  
  
  
  -- only covers simple expressions with meta variables, not the rest...
  isGeneralizationOf :: Expr -> Expr -> Bool
  isGeneralizationOf genExpr testExpr = 
    if isMeta genExpr then True
     else if isMeta testExpr then False
      else let genUnwrap = unApp genExpr 
               testUnwrap = unApp testExpr
         in if isNothing genUnwrap || isNothing testUnwrap then False -- see if you can generalize here
             else let (gencid, genargs) = fromJust genUnwrap 
                      (testcid, testargs) = fromJust testUnwrap
                  in 
                     (gencid == testcid) && (length genargs == length testargs)       
                         && (and [isGeneralizationOf g t | (g,t) <- (zip genargs testargs)])
  
  {-do lst <- getConcTypes context types (i+1)
       return $ mkMeta i : lst -} 
  
  debugReplaceArgs :: Expr -> Expr -> Environ -> IO (Maybe Expr)
  debugReplaceArgs aexpr cexpr env = 
    if isNothing $ unApp aexpr then return Nothing
         else if any isNothing $ map unApp $ snd $ fromJust $ unApp aexpr then return Nothing
       else
         let args = map (fst.fromJust.unApp) $ snd $ fromJust $ unApp aexpr
             concExprs = map (\x -> fromJust $ Map.lookup x $ getConcMap env) args
           in startReplace 1 cexpr concExprs
          where 
            startReplace i cex []        = return $ Just cex
            startReplace i cex (a:as)    = do val <- debugReplaceConc cex i a
                                              maybe ( --do putStrLn $ "didn't find "++ showExpr [] a ++ " in " ++showExpr [] cexpr
                                                         return Nothing) 
                                                    (\x -> --do putStrLn $ "found it, the current expression is "++ showExpr [] x
                                                              startReplace (i+1) x as) 
                                                       val 
                        
  debugReplaceConc :: Expr -> Int -> Expr -> IO (Maybe Expr)
  debugReplaceConc expr i e = 
         let (newe,isThere) = searchArg expr 
            in if isThere then return $ Just newe else return $ Nothing 
       where   
        searchArg e_  =  
              if isGeneralizationOf e e_ then (mkMeta i, True)
                else maybe (e_,False) (\(cid,args) -> let repargs = map searchArg args
                                           in (mkApp cid (map  fst repargs), or $ map snd repargs)) $ unApp e_  
   
  
  {-
  -- replaceArgs : Original expression to parse (from abstract syntax) -> Concrete expression (parsed) 
  replaceArgs :: Expr -> Expr -> Environ -> Maybe Expr
  replaceArgs aexpr cexpr env =
    if isNothing $ unApp aexpr then error $ "could't unwrap this "++ show aexpr 
        else if any isNothing $ map unApp $ snd $ fromJust $ unApp aexpr then error $ "couldn't unwrap more this : "++ show aexpr
    else 
     let  args = map (fst.fromJust.unApp) $ snd $ fromJust $ unApp aexpr
          concExprs = map (\x -> fromJust $ Map.lookup x $ getConcMap env) args
            in startReplace 1 cexpr concExprs
      where 
        startReplace i cex []       = return cex 
        startReplace i cex (a:as)   = maybe Nothing (\x -> startReplace (i+1) x as) $ replaceConc cex i a
  
  
  
  replaceConc :: Expr -> Int -> Expr -> Maybe Expr
  replaceConc expr i e = 
         let (newe,isThere) = searchArg expr 
            in if isThere then return newe else Nothing 
       where   
        searchArg e_  =  
              if isGeneralizationOf e e_ then (mkMeta i, True)
                else maybe (e_,False) (\(cid,args) -> let repargs = map searchArg args
                                           in (mkApp cid (map  fst repargs), or $ map snd repargs)) $ unApp e_  
  
  
  
  writeResults :: Environ -> String -> IO ()
  writeResults env fileName = 
     let cmap = getConcMap env
         lincats = unlines $ map (\(x,y) -> "lincat " ++ showCId x ++ " = " ++ showCId y ++ " ; " ) $ Map.toList $ getTypeMap env 
         sigs = unlines $ map 
                    (\x -> let n = getName x 
                               no = length $ getTypeArgs x
                               oargs = unwords $ ("lin " ++ showCId n) : ["o"++show i | i <- [1..no]]     
                           in (oargs ++ " = " ++ (simpleReplace $ showExpr [] $ fromJust $ Map.lookup n cmap) ++ " ; ")) $ concat $ Map.elems $ getSigs env
      in 
            writeFile fileName ("\n" ++ lincats ++ "\n\n" ++  sigs)  
           
  
  simpleReplace :: String -> String 
  simpleReplace [] = []
  simpleReplace ('?':xs) = 'o' : simpleReplace xs
  simpleReplace (x:xs) = x : simpleReplace xs
  -}
  
  isMeta :: Expr -> Bool
  isMeta = isJust.unMeta 
  
  -- works with utf-8 characters also, as it seems
  
  
  mkFuncWithArg ::  ((CId,CId),[CId]) -> FuncWithArg
  mkFuncWithArg ((c1,c2),cids) = FuncWithArg c1 c2 cids
  
  
  ---------------------------------------------------------------------------------
  
  initial :: TypeMap -> ConcMap -> [FuncWithArg] -> [FuncWithArg] -> Environ
  initial tm cm fss allfs = Env tm cm (mkSigs fss) allfs
  {-
  testInit :: [FuncWithArg] -> Environ
  testInit allfs = initial lTypes Map.empty [] allfs
  
  lTypes = Map.fromList [(mkCId "Comment", mkCId "S"),(mkCId "Item", mkCId "NP"), (mkCId "Kind", mkCId "CN"), (mkCId "Quality", mkCId "AP")]
  -}
  startCateg = mkCId "Comment"
  -- question about either to give the startcat or not ...
  
  
  
  
  
  ----------------------------------------------------------------------------------------------------------
  {-
  main = 
   do args <- getArgs
      case args of 
        [pgfFile] -> 
           do pgf <- readPGF pgfFile
              parsePGF <- readPGF parsePGFfile
              fsWithArg <- forExample pgf
              let funcsWithArg = map (map mkFuncWithArg) fsWithArg
              let morpho = buildMorpho parsePGF parseLang
              let fss = concat funcsWithArg
              let fileName = takeWhile (/='.') pgfFile ++ lang ++ ".gf"
              env <- start parsePGF pgf morpho (testInit fss) fss
              putStrLn $ "Should I write the results to a file ? yes/no"
              ans <-getLine 
              if ans == "yes" then do writeResults env fileName
                                      putStrLn $ "Wrote file " ++ fileName
               else return ()  
        _ ->  fail "usage : Testing <path-to-pgf> "
  
  
    
  start :: PGF -> PGF -> Morpho -> Environ -> [FuncWithArg] -> IO Environ
  start parsePGF pgfFile morpho env lst = 
    do putStrLn "Do you want examples from another language ? (no/concrete syntax name otherwise)"
       ans1 <- getLine
       putStrLn "Do you want testing mode ? (yes/no)"
       ans2 <- getLine
       case (ans1,ans2) of
         ("no","no")    -> do putStrLn "no extra language, just the abstract syntax tree"
                              interact env lst False Nothing 
         (_,"no")       -> interact env lst False (readLanguage ans1)
         ("no","yes")   -> do putStrLn "no extra language, just the abstract syntax tree"
                              interact env lst True Nothing
         (_,"yes")    -> interact env lst True (readLanguage ans1)
         ("no",_)       -> do putStrLn "no extra language, just the abstract syntax tree"
                              putStrLn $ "I assume you don't want the testing mode ... " 
                              interact env lst False Nothing
         (_,_)          -> do putStrLn $ "I assume you don't want the testing mode ... " 
                              interact env lst False (readLanguage ans1)             
    where 
  
     interact environ [] func _ = return environ
     interact environ (farg:fargs) boo otherLang = 
               do 
                  maybeEnv <- basicInter farg otherLang environ boo
                  if isNothing maybeEnv then return environ
                   else interact (fromJust maybeEnv) fargs boo otherLang                
  
     basicInter farg js environ False = 
         let e_ = getExpr farg environ in 
          if isNothing e_ then return $ Just environ
               else parseAndBuild farg js environ (getType farg) e_ Nothing 
     basicInter farg js environ True = 
          let (e_,e_test) = get2Expr farg environ in 
           if isNothing e_ then return $ Just environ 
            else if isNothing e_test then do putStrLn $ "not enough arguments "++ (showCId $ getName farg)
                                             parseAndBuild farg js environ (getType farg) e_ Nothing  
                      else parseAndBuild farg js environ (getType farg) e_ e_test
  
  -- . head . generateRandomFrom gen2 pgfFile
     parseAndBuild farg js environ ty e_ e_test =
             do let expr = fromJust e_
                gen1 <- newStdGen
                gen2 <- newStdGen
                let newexpr = head $ generateRandomFrom gen1 pgfFile expr
                let embeddedExpr = maybe "***" (showExpr [] ) (embedInStart (getAll environ) (Map.fromList [(ty,expr)])) 
                let lexpr = if isNothing js then "" else "\n-- " ++ linearize pgfFile (fromJust js) newexpr ++ " --" 
                putStrLn $ "Give an example for " ++ (showExpr [] expr)    
                                 ++ lexpr ++ "and now"
                                 ++ "\n\nas in " ++ embeddedExpr ++ "\n\n"
                --
                ex <- getLine 
                if (ex == ":q") then return Nothing  
                      else 
                        let ctype = fromJust $ Map.lookup (getType farg) (getTypeMap environ) in
                           do env' <- decypher farg ex expr environ (fromJust $ readType $ showCId ctype) e_test
                              return (Just env')
         
     decypher farg ex expr environ ty e_test =  
       --do putStrLn $ "We need to parse " ++ ex ++ " as " ++ show ctype
          let pTrees = parse parsePGF (fromJust $ readLanguage "ParseEng") ty ex  in 
               pickTree farg expr environ ex e_test pTrees 
               
   --  putStrLn $ "And now for testing, \n is this also correct yes/no \n ## " ++  (linearize parsePGF parseLang $ mapToResource newenv $ llin newenv e_test) ++ " ##"
                                                 
     -- select the right tree among the options given by the parser 
     pickTree farg expr environ ex e_test [] =  
                  let miswords = morphoMissing morpho (words ex) 
                     in 
                  if null miswords then do putStrLn $ "all words known, but some syntactic construction is not covered by the grammar..."
                                           return environ
                      else do putStrLn $ "the following words are unknown, please add them to the lexicon: " ++ show miswords
                              return environ
     pickTree farg expr environ ex e_test [tree] = 
                  do val <- searchGoodTree environ expr [tree]  -- maybe order here after the probabilities for better precision
                     maybe (do putStrLn $ "none of the trees is consistent with the rest of the grammar, please check arguments "
                               return environ) 
                           (\(x,newtree) -> let newenv = updateEnv environ farg (getType farg) x in
                                                do putStrLn $ "the result is "++showExpr [] x
                                                   newtestenv <- testTest newenv e_test -- question ? should it belong there - there is just one possibility of a tree... 
                                                   return newenv) val
     pickTree farg expr environ ex e_test parseTrees = 
                  do putStrLn $ "There is more than one possibility, do you want to choose the right tree yourself ? yes/no "
                     putStr "  >"
                     ans <- getLine
                     if ans == "yes" then do pTree <- chooseRightTree parseTrees
                                             processTree farg environ expr pTree e_test
                       else processTree farg environ expr parseTrees e_test
  
     -- introduce testing function, if it doesn't work, then reparse, take that tree
     testTree envv e_test = return envv -- TO DO - add testing here
     
     testTest envv Nothing = return envv
     testTest envv (Just exxpr) = testTree envv exxpr   
   
  
     -- allows the user to pick his own tree
     chooseRightTree trees = return trees -- TO DO - add something clever here     
     
     -- selects the tree from where one can abstract over the original arguments 
     processTree farg environ expr lsTrees e_test =
       let trmes = if length lsTrees == 1 then "the tree is not consistent " else "none of the trees is consistent " in
       do val <- searchGoodTree environ expr lsTrees
          maybe (do putStrLn $ trmes ++ "with the rest of the grammar, please check arguments! "
                    return environ) 
                           (\(x,newtree) -> let newenv = updateEnv environ farg (getType farg) x in
                                                do putStrLn $ "the result is "++showExpr [] x
                                                   newtestenv <- testTest newenv e_test 
                                                   return newenv) val
  
  
  
  -------------------------------
  
  get2Expr :: FuncWithArg -> Environ -> (Maybe Expr, Maybe Expr)
  get2Expr farg env =
    let tys = getTypeArgs farg
        ctx = getSigs env
        (lst1,lst2) = getConcTypes2 ctx tys 1
        arg1 = if (all isJust lst1) then Just $ mkApp (getName farg) (map fromJust lst1) else Nothing
        arg2 = if (all isJust lst2) then Just $ mkApp (getName farg) (map fromJust lst2) else Nothing
     in if arg1 == arg2 then (arg1, Nothing)
           else (arg1,arg2)
    where 
             getConcTypes2 context [] i = ([],[])
             getConcTypes2 context (ty:types) i =  
                  let pos = Map.lookup ty context
                     in 
                      if isNothing pos  || (null $ fromJust pos) then ([Nothing],[Nothing])                                                
                            else  
                               let (mm,tt) = (last $ fromJust pos, head $ fromJust pos)
                                   mmargs = getTypeArgs mm
                                   newi = i + length mmargs - 1  
                                   (lst1,lst2) = getConcTypes2 (Map.insert ty (init (fromJust pos)) context) types (newi+1)
                                   ttargs = getTypeArgs tt
                                   newtti = i + length ttargs - 1
                                   fstArg = if (all isJust lst1) then               -- i..newi  
                                               (Just $ mkApp (getName mm) [mkMeta j | j <- [1..(length mmargs)]]) : lst1 
                                              else [Nothing]
                                   sndArg = if (all isJust lst2) then 
                                               (Just $ mkApp (getName tt) [mkMeta j | j <- [1..(length ttargs)]]) : lst2
                                              else [Nothing]
                                in 
                                  (fstArg,sndArg)   
  
  
  -}
   