packages feed

language-ecmascript 0.14 → 0.15

raw patch · 38 files changed

+2909/−2706 lines, 38 filesdep +Diffdep +data-default-classdep +language-ecmascriptdep −charsetdep −data-defaultdep −sybdep ~QuickCheckdep ~containersPVP ok

version bump matches the API change (PVP)

Dependencies added: Diff, data-default-class, language-ecmascript, test-framework, test-framework-hunit, test-framework-quickcheck2

Dependencies removed: charset, data-default, syb

Dependency ranges changed: QuickCheck, containers

API changes (from Hackage documentation)

- Language.ECMAScript3.Parser: intLen :: (Integral a, Num a1) => a -> a1
- Language.ECMAScript3.Parser: mkDecimal :: Integer -> Integer -> Integer -> Integer -> Double
- Language.ECMAScript3.Parser.State: type ParserState = [String]
- Language.ECMAScript3.Parser.Type: type Parser s a = ParsecT s ParserState Identity a
+ Language.ECMAScript3.Parser: expression :: Stream s Identity Char => Parser s (Expression SourcePos)
+ Language.ECMAScript3.Parser: parseFromFile :: (Error e, MonadIO m, MonadError e m) => String -> m (JavaScript SourcePos)
+ Language.ECMAScript3.Parser: parseFromString :: String -> Either ParseError (JavaScript SourcePos)
+ Language.ECMAScript3.Parser: program :: Stream s Identity Char => Parser s (JavaScript SourcePos)
+ Language.ECMAScript3.Parser: statement :: Stream s Identity Char => Parser s (Statement SourcePos)
+ Language.ECMAScript3.SourceDiff: jsDiff :: JavaScript a -> JavaScript a -> String
+ Language.ECMAScript3.Syntax.Arbitrary: listOfN :: Arbitrary a => Int -> Gen a -> Gen [a]

Files

CHANGELOG view
@@ -1,5 +1,15 @@ Version change log. +=0.15=+Bug fixes in the pretty-printer, the parser and the QuickCheck arbitrary+instance for the AST. Refactored tests to use test-framework. Reorganized+the interface for the parser to make it consistent; see deprecation+warnings for details. Added Language.ECMAScript3.SourceDiff -- a simple+source-based differ for ECMAScript programs, which is now used for+visualizing test failures. Revised package dependencies. Factored the+analyses out in a separate package: language-ecmascript-analysis;+Language.ECMAScript3.Analysis.* are now deprecated.+ =0.14= Refactoring of the pretty-printing module: added class Pretty with a more comprehensive coverage of AST datatypes and better documentation. Removed
language-ecmascript.cabal view
@@ -1,5 +1,5 @@ Name:           language-ecmascript-Version:        0.14+Version:        0.15 Cabal-Version:	>= 1.10 Copyright:      (c) 2007-2012 Brown University, (c) 2008-2010 Claudiu Saftoiu,                 (c) 2012-2013 Stevens Institute of Technology@@ -11,15 +11,17 @@ Homepage:       http://github.com/jswebtools/language-ecmascript Bug-reports:    http://github.com/jswebtools/language-ecmascript/issues Stability:      experimental-Tested-with:    GHC==7.4.1, GHC==7.6.3-Extra-Source-Files: tests/parse-pretty/*.js, CHANGELOG+Tested-with:    GHC==7.6.3+Extra-Source-Files: test/parse-pretty/*.js, test/diff/left/*.js, test/diff/right/*.js, test/diff/expects/*.diff, CHANGELOG Category:       Language Build-Type:     Simple-Synopsis:       JavaScript analysis tools+Synopsis:       JavaScript parser and pretty-printer library Description:-  Some tools for working with ECMAScript 3 (popularly known as JavaScript). -  Includes a parser, pretty-printer, and basic building blocks for more-  sophisticated tools.+  Tools for working with ECMAScript 3 (popularly known as JavaScript).+  Includes a parser, pretty-printer, a simple quasi-quoter and tools+  for working with source tree annotations and an arbitrary+  instance. Analyses have migrated to package+  'language-ecmascript-analysis'.  Source-repository head    type: git@@ -28,7 +30,7 @@ Source-repository this    type: git    location: git://github.com/jswebtools/language-ecmascript.git-   tag: 0.14+   tag: 0.15  Library   Hs-Source-Dirs:@@ -39,12 +41,11 @@     parsec < 3.2.0,     pretty >= 0.1,     containers >= 0.1,-    syb >= 0.1,     uniplate >= 1.6 && <1.7,-    data-default >= 0.4 && <0.6,+    data-default-class >= 0.0.1 && < 0.1,     QuickCheck >= 2.5,     template-haskell,-    charset >= 0.3.2.1+    Diff == 0.3.*   ghc-options:     -fwarn-incomplete-patterns   Exposed-Modules:@@ -58,51 +59,38 @@     Language.ECMAScript3.Syntax.QuasiQuote     Language.ECMAScript3.Analysis.Environment     Language.ECMAScript3.Analysis.LabelSets+    Language.ECMAScript3.SourceDiff+  Other-Modules:     Language.ECMAScript3.Parser.Type     Language.ECMAScript3.Parser.State   Default-Extensions:     DeriveDataTypeable, ScopedTypeVariables, DeriveFunctor, DeriveFoldable, DeriveTraversable, FlexibleContexts   Default-Language: Haskell2010 -Test-Suite unittest-  Hs-Source-Dirs: src-  Type: exitcode-stdio-1.0-  Main-Is: UnitTest.hs-  Build-Depends:-    base >= 4 && < 5,-    mtl >= 1.1.0.1,-    parsec < 3.2.0,-    pretty >= 0.1,-    containers >= 0.1,-    syb >= 0.1,-    directory,-    filepath,-    HUnit,-    data-default >=0.4 && <0.6,-    QuickCheck >= 2.5,-    charset >= 0.3.2.1-  Default-Extensions: DeriveDataTypeable, ScopedTypeVariables, DeriveFunctor, DeriveFoldable, DeriveTraversable, FlexibleContexts-  Default-Language: Haskell2010-  ghc-options:-    -fwarn-incomplete-patterns--Test-Suite prettytest-  Hs-Source-Dirs: src+Test-Suite test+  Hs-Source-Dirs: test   Type: exitcode-stdio-1.0-  Main-Is: PrettyTest.hs+  Main-Is: TestMain.hs+  Other-Modules:+    Test.Diff+    Test.Unit+    Test.Pretty   Build-Depends:     base >= 4 && < 5,     mtl >= 1.1.0.1,     parsec < 3.2.0,     pretty >= 0.1,-    containers >= 0.1,-    syb >= 0.1,+    containers >= 0.1 && < 0.6,     directory,     filepath,     HUnit,-    data-default >=0.4 && <0.6,-    QuickCheck >= 2.5,-    uniplate >= 1.6 && <1.7+    QuickCheck >= 2.5 && < 2.6,+    data-default-class >= 0.0.1 && < 0.1,+    test-framework >= 0.8 && < 0.9,+    test-framework-hunit >= 0.3.0 && < 0.4,+    test-framework-quickcheck2 >= 0.3.0.1 && < 0.4,+    Diff == 0.3.*,+    language-ecmascript   Default-Extensions: DeriveDataTypeable, ScopedTypeVariables, DeriveFunctor, DeriveFoldable, DeriveTraversable, FlexibleContexts   Default-Language: Haskell2010   ghc-options:
src/Language/ECMAScript3/Analysis/Environment.hs view
@@ -1,6 +1,8 @@ -- | A lexical environment analysis of ECMAScript programs  module Language.ECMAScript3.Analysis.Environment+       {-# DEPRECATED "Use 'Language.ECMAScript.Analysis.LexicalEnvironment'\+                      \ from package 'language-ecmascript-analysis'" #-}   ( env   , localVars   , EnvTree (..)
src/Language/ECMAScript3/Analysis/LabelSets.hs view
@@ -3,8 +3,11 @@ -- section 12.12. The result of this analysis are useful for building -- control-flow graphs. -module Language.ECMAScript3.Analysis.LabelSets (annotateLabelSets -                                               ,Label(..)) where+module Language.ECMAScript3.Analysis.LabelSets+       {-# DEPRECATED "Use 'Language.ECMAScript3.Analysis.LabelSet'\+                      \ from package 'language-ecmascript-analysis'" #-}+       (annotateLabelSets +       ,Label(..)) where  import Language.ECMAScript3.Syntax import Language.ECMAScript3.Syntax.Annotations
src/Language/ECMAScript3/Parser.hs view
@@ -2,6 +2,13 @@ {-# LANGUAGE FlexibleContexts #-} module Language.ECMAScript3.Parser   (parse+  , Parser  +  , expression+  , statement+  , program+  , parseFromString+  , parseFromFile+  -- old and deprecated      , parseScriptFromString   , parseJavaScriptFromFile   , parseScript@@ -15,11 +22,7 @@   , StatementParser   , ExpressionParser   , assignExpr-  -- debugging, remove the next 2 lines-  , mkDecimal-  , intLen   , parseObjectLit  -  , Parser     ) where  import Language.ECMAScript3.Lexer hiding (identifier)@@ -28,7 +31,7 @@ import Language.ECMAScript3.Parser.Type import Language.ECMAScript3.Syntax import Language.ECMAScript3.Syntax.Annotations-import Data.Default+import Data.Default.Class import Text.Parsec hiding (parse) import Text.Parsec.Expr import Control.Monad(liftM,liftM2)@@ -37,7 +40,25 @@ import Data.Char import Control.Monad.Identity import Data.Maybe (isJust, isNothing, fromMaybe)+import Control.Monad.Error.Class +{-# DEPRECATED ParsedStatement, ParsedExpression, StatementParser,+               ExpressionParser+    "These type aliases will be hidden in the next version" #-}++{-# DEPRECATED parseSimpleExpr', parseBlockStmt, parseObjectLit+   "These parsers will be hidden in the next version" #-}++{-# DEPRECATED assignExpr, parseExpression "Use 'expression' instead" #-}++{-# DEPRECATED parseStatement "Use 'statement' instead" #-}++{-# DEPRECATED parseScript "Use 'program' instead" #-}++{-# DEPRECATED parseScriptFromString, parseString "Use 'parseFromString' instead" #-}++{-# DEPRECATED parseJavaScriptFromFile "Use 'parseFromFile' instead" #-}+ -- We parameterize the parse tree over source-locations. type ParsedStatement = Statement SourcePos type ParsedExpression = Expression SourcePos@@ -46,7 +67,6 @@ type StatementParser s = Parser s ParsedStatement type ExpressionParser s = Parser s ParsedExpression - initialParserState :: ParserState initialParserState = [] @@ -303,7 +323,7 @@                       "function body in { ... }"   return (FunctionStmt pos name args body) -parseStatement:: Stream s Identity Char => StatementParser s+parseStatement :: Stream s Identity Char => StatementParser s parseStatement = parseIfStmt <|> parseSwitchStmt <|> parseWhileStmt    <|> parseDoWhileStmt <|> parseContinueStmt <|> parseBreakStmt    <|> parseBlockStmt <|> parseEmptyStmt <|> parseForInStmt <|> parseForStmt@@ -312,6 +332,10 @@   -- labelled, expression and the error message always go last, in this order   <|> parseLabelledStmt <|> parseExpressionStmt <?> "statement" +-- | The parser that parses a single ECMAScript statement+statement :: Stream s Identity Char => Parser s (Statement SourcePos)+statement = parseStatement+ --}}}  --{{{ Expressions@@ -473,7 +497,7 @@ --{{{ Parsing numbers.  From pg. 17-18 of ECMA-262. hexLit :: Stream s Identity Char => Parser s (Bool, Double) hexLit = do-  try (string "0x")+  try (char '0' >> oneOf "xX")   digits <- many1 (oneOf "0123456789abcdefABCDEF")   [(hex,"")] <- return $ Numeric.readHex digits   return (True, hex)@@ -735,6 +759,10 @@ parseExpression:: Stream s Identity Char => ExpressionParser s parseExpression = assignExpr +-- | A parser that parses ECMAScript expressions+expression :: Stream s Identity Char => Parser s (Expression SourcePos)+expression = assignExpr+ parseListExpr :: Stream s Identity Char => ExpressionParser s parseListExpr = assignExpr `sepBy1` comma >>= \exprs ->   case exprs of@@ -745,14 +773,39 @@ parseScript = do   whiteSpace   liftM2 Script getPosition (parseStatement `sepBy` whiteSpace)++-- | A parser that parses an ECMAScript program.+program :: Stream s Identity Char => Parser s (JavaScript SourcePos)+program = parseScript   --- | Parse from a stream; same as 'Text.Parsec.parse'+-- | Parse from a stream given a parser, same as 'Text.Parsec.parse'+-- in Parsec. We can use this to parse expressions or statements alone,+-- not just whole programs. parse :: Stream s Identity Char       => Parser s a -- ^ The parser to use       -> SourceName -- ^ Name of the source file       -> s -- ^ the stream to parse, usually a 'String'       -> Either ParseError a parse p = runParser p initialParserState++-- | A convenience function that takes a 'String' and tries to parse+-- it as an ECMAScript program:+--+-- > parseFromString = parse program ""+parseFromString :: String -- ^ JavaScript source to parse+                  -> Either ParseError (JavaScript SourcePos)+parseFromString = parse program ""++-- | A convenience function that takes a filename and tries to parse+-- the file contents an ECMAScript program, it fails with an error+-- message if it can't.+parseFromFile :: (Error e, MonadIO m, MonadError e m) => String -- ^ file name+                -> m (JavaScript SourcePos)+parseFromFile fname =+  liftIO (readFile fname) >>= \source ->+  case parse program fname source of+    Left err -> throwError $ strMsg $ show err+    Right js -> return js  -- | Read a JavaScript program from file an parse it into a list of -- statements
src/Language/ECMAScript3/Parser/Type.hs view
@@ -4,4 +4,6 @@ import Text.Parsec import Control.Monad.Identity +-- | The parser type, parametrised by the stream type @s@ and the+-- return value @a@ type Parser s a = ParsecT s ParserState Identity a
src/Language/ECMAScript3/PrettyPrint.hs view
@@ -228,13 +228,22 @@     sel '\\' = "\\\\"     sel x    = [x]     -- We don't have to do anything about \X, \x and \u escape sequences.-    ++-- | Escapes a regular expression so that it can be parsed correctly afterwards regexpEscape :: String -> String-regexpEscape "" = ""-regexpEscape "\\" = "\\\\"-regexpEscape ('\\':c:rest) = '\\':c:(regexpEscape rest)-regexpEscape ('/':rest) = '\\':'/':regexpEscape rest-regexpEscape (c:rest)   = c:regexpEscape rest+regexpEscape = regexpEscapeChar True+  where regexpEscapeChar :: Bool -- ^ First char?+                         -> String -> String+        regexpEscapeChar first s = +          case (s, first) of+            ("", True) -> "(?:)"+            ("", False)-> ""+            -- see spec 7.8.5, RegularExpressionFirstChar+            ("\\", _) -> "\\\\"+            ('\\':c:rest, _) -> '\\':c:(regexpEscapeChar False rest)+            ('/':rest, _) -> '\\':'/':regexpEscapeChar False rest+            ('*':rest, True) -> ('\\':'*':regexpEscapeChar False rest)+            (c:rest, _)   -> c:regexpEscapeChar False rest  -- 11.1 ppPrimaryExpression :: Expression a -> Doc
+ src/Language/ECMAScript3/SourceDiff.hs view
@@ -0,0 +1,24 @@+-- | Simple textual diffing of JavaScript programs for inspecting test+-- failures+module Language.ECMAScript3.SourceDiff where++import Data.Algorithm.Diff+--import Data.Algorithm.DiffOutput+import Language.ECMAScript3.Syntax+import Language.ECMAScript3.PrettyPrint+import Data.List (intersperse)+++jsDiff :: JavaScript a -> JavaScript a -> String+jsDiff js1 js2 = +  -- let plines = lines . show . prettyPrint+  -- in  ppDiff $ getGroupedDiff (plines js1) (plines js2)+  let plines = lines . show . prettyPrint+      diff = getGroupedDiff (plines js1) (plines js2)+      formatDiff :: Diff [String] -> String+      formatDiff d = let (prefix, strs) = case d of+                           First ss  -> ('-', ss)+                           Second ss -> ('+', ss)+                           Both ss _ -> (' ', ss)+                     in concat $ intersperse "\n" $  map (prefix:) strs+  in  concat $ intersperse "\n" $ map formatDiff diff
src/Language/ECMAScript3/Syntax.hs view
@@ -26,10 +26,11 @@                                    ) where  import Text.Parsec.Pos(initialPos,SourcePos) -- used by data JavaScript-import Data.Generics(Data,Typeable)+import Data.Data (Data)+import Data.Typeable (Typeable) import Data.Foldable (Foldable) import Data.Traversable (Traversable)-import Data.Default+import Data.Default.Class  data JavaScript a   -- |A script in \<script\> ... \</script\> tags.
src/Language/ECMAScript3/Syntax/Arbitrary.hs view
@@ -110,6 +110,12 @@ atLeastOfSize :: Arbitrary a => Int -> Gen a -> Gen a atLeastOfSize l gen = sized $ \s -> if s < l then resize l gen else gen +listOfN :: Arbitrary a => Int -> Gen a -> Gen [a]+listOfN l gen = sized $ \n ->+  let l' = l `max` 0+  in do k <- choose (l', l' `max` n)+        vectorOf k gen+ nonEmptyString :: Gen String nonEmptyString = sized $ \s -> if s < 1 then stringOfLength 1 else stringOfLength s @@ -144,7 +150,7 @@           (2, liftM4 InfixExpr arbitrary arbitrary rarbitrary rarbitrary),           (3, liftM4 CondExpr arbitrary rarbitrary rarbitrary rarbitrary),           (3, liftM4 AssignExpr arbitrary rarbitrary rarbitrary rarbitrary),-          (3, liftM2 ListExpr arbitrary (recursive (atLeastOfSize 2 arbitrary))),+          (3, liftM2 ListExpr arbitrary (recursive (listOfN 2 arbitrary))),           (3, liftM3 CallExpr arbitrary rarbitrary rrarbitrary),           (1, liftM4 FuncExpr arbitrary arbitrary arbitrary rarbitrary)]     @@ -216,7 +222,7 @@           (1, liftM2 ThrowStmt arbitrary rarbitrary),           (1, liftM2 ReturnStmt arbitrary rarbitrary),           (2, liftM3 WithStmt arbitrary rarbitrary rarbitrary),-          (2, liftM2 VarDeclStmt arbitrary rrarbitrary),+          (2, liftM2 VarDeclStmt arbitrary (listOf1 rrarbitrary)),           (1, liftM4 FunctionStmt arbitrary arbitrary arbitrary rarbitrary)]     where arbtry =              do (mCatch, mFinally) <- oneof [liftM2 (,) (return Nothing) (liftM Just rarbitrary),@@ -330,7 +336,7 @@               else True   --  _ -> continue stmt inLabeled inIter inSwitch   where continue stmt inLabeled inIter inSwitch =-                   and $ map (\s -> isBreakContinueFixable s inLabeled inIter inSwitch) (children stmt)+          and $ map (\s -> isBreakContinueFixable s inLabeled inIter inSwitch) (children stmt)                     -- | Removes duplicate labels from nested labeled statements in order -- to impose restrictions on labeled statements as per ECMAScript 5
src/Language/ECMAScript3/Syntax/QuasiQuote.hs view
@@ -23,13 +23,13 @@ js = QuasiQuoter {quoteExp = quoteJS}  quoteJSExpr :: String -> TH.ExpQ-quoteJSExpr = quoteCommon parseExpression+quoteJSExpr = quoteCommon expression  quoteJSStmt :: String -> TH.ExpQ-quoteJSStmt = quoteCommon parseStatement+quoteJSStmt = quoteCommon statement  quoteJS :: String -> TH.ExpQ-quoteJS = quoteCommon parseScript+quoteJS = quoteCommon program  quoteCommon :: Data a => Parser String a -> String -> TH.ExpQ quoteCommon p s = do loc <- TH.location
− src/PrettyTest.hs
@@ -1,29 +0,0 @@-module Main where--import Language.ECMAScript3.Parser-import Language.ECMAScript3.PrettyPrint-import Language.ECMAScript3.Syntax-import Language.ECMAScript3.Syntax.Arbitrary()-import Language.ECMAScript3.Syntax.Annotations-import Test.QuickCheck-import System.Exit--main :: IO ()-main = -  let qcArgs = Args {maxSuccess = 50-                    ,maxDiscardRatio = 10-                    ,maxSize = 10-                    ,replay = Nothing-                    ,chatty = True}-  in quickCheckWithResult qcArgs prettyParseEquivalence >>= \res ->-  case res of-    Success {} -> putStrLn "All tests passes"-    GaveUp {} -> putStrLn "Gave up"-    Failure {} -> putStrLn "Test failed" >> exitFailure-    NoExpectedFailure {} -> putStrLn "Unexpected failure" >> exitFailure-        -prettyParseEquivalence :: JavaScript () -> Bool-prettyParseEquivalence js = -  case parseScriptFromString "" $ show $ prettyPrint js of-    Left _ -> False-    Right parsed -> (reannotate (const ()) parsed) == js
− src/UnitTest.hs
@@ -1,33 +0,0 @@-module Main where--import Test.HUnit-import System.Exit-import System.Directory-import qualified System.FilePath as FilePath-import Language.ECMAScript3.Parser-import Language.ECMAScript3.PrettyPrint-import Language.ECMAScript3.Syntax--testDir = "tests/parse-pretty"----- | tests the parser with pre-defined test-cases-parsePrettyTest filename = TestLabel filename $ TestCase $ do-  js <- parseJavaScriptFromFile filename-  let str = renderStatements js-  case parseScriptFromString "" str of-    Left err -> assertFailure (show err)-    Right (Script _ js') -> do-      let str' = renderStatements js'-      assertBool "pretty-printed code should re-parse" (str == str')--main = do-  allFiles <- getDirectoryContents testDir-  let files =  map (testDir `FilePath.combine`) $ -        filter (\x -> FilePath.takeExtension x == ".js") allFiles-  let parsePretty = TestLabel "parser - printer composition" -        (TestList (map parsePrettyTest files))-  results <- runTestTT parsePretty-  if errors results > 0 || failures results > 0 -    then exitFailure-    else putStrLn "All tests passed."
+ test/Test/Diff.hs view
@@ -0,0 +1,58 @@+module Test.Diff where++import Test.HUnit hiding (Test)+import Test.Framework+import Test.Framework.Providers.HUnit+import System.Exit+import System.Directory+import qualified System.FilePath as FP+import Language.ECMAScript3.Parser+import Language.ECMAScript3.PrettyPrint+import Language.ECMAScript3.Syntax+import Language.ECMAScript3.Syntax.Annotations+import Language.ECMAScript3.SourceDiff+import Control.Monad++tests_diff :: Test+tests_diff =+  buildTest $+  do allLefts  <- getDirectoryContents leftDir+     allRights <- getDirectoryContents rightDir+     allDiffs  <- getDirectoryContents expectsDir+     let validLefts  = getValidJS allLefts+     let validRights = getValidJS allRights+     let validDiffs  = getValidDiffs allDiffs+     return $ testGroup "Source Diff tests" $+       map genTest $ filter ((`elem` (map FP.dropExtension validDiffs)) .+                             FP.dropExtension)+                   $ filter (`elem` validRights) validLefts+       where getValidJS = filter $ \x -> FP.takeExtension x == ".js"+             getValidDiffs = filter $ \x -> FP.takeExtension x == ".diff"++leftDir = "test/diff/left"+rightDir = "test/diff/right"+expectsDir = "test/diff/expects"++genTest :: FilePath -> Test+genTest testFileName = testCase testFileName $+                       diffTest (leftDir `FP.combine` testFileName)+                                (rightDir `FP.combine` testFileName)+                                (expectsDir `FP.combine`+                                 ((FP.dropExtension testFileName)+                                  `FP.addExtension` "diff"))++diffTest :: FilePath -> FilePath -> FilePath -> Assertion+diffTest leftFile rightFile diffFile =+  do left  <- readFile leftFile+     right <- readFile rightFile+     expect<- readFile diffFile+     let x = do ljs <- parseFromString left+                rjs <- parseFromString right+                return (removeAnnotations ljs, removeAnnotations rjs)+     case x of+       Left err -> assertFailure $ "Parsing error: " ++ (show err)+       Right (ljs, rjs) ->+         let diff = jsDiff ljs rjs+             msg = "Failed to match diff output to an expected one. Expected:\n"+                   ++ expect ++ "\nSaw:\n" ++ diff+         in unless (diff == expect) (assertFailure msg)
+ test/Test/Pretty.hs view
@@ -0,0 +1,43 @@+module Test.Pretty where++import Test.Framework+import Test.Framework.Providers.QuickCheck2+import Language.ECMAScript3.Parser+import Language.ECMAScript3.PrettyPrint+import Language.ECMAScript3.Syntax+import Language.ECMAScript3.Syntax.Arbitrary()+import Language.ECMAScript3.Syntax.Annotations+--import System.Exit+import Language.ECMAScript3.SourceDiff+import Test.QuickCheck++tests_pretty :: Test+tests_pretty = testProperty "Parse is the inverse of pretty" prettyParseEquivalence++-- main :: IO ()+-- main = +--   let qcArgs = Args {maxSuccess = 50+--                     ,maxDiscardRatio = 10+--                     ,maxSize = 10+--                     ,replay = Nothing+--                     ,chatty = False}+--   in quickCheckWithResult qcArgs prettyParseEquivalence >>= \res ->+--   case res of+--     Success {} -> putStrLn "All tests passes"+--     GaveUp {} -> putStrLn "Gave up"+--     Failure {} -> putStrLn "Test failed" >> exitFailure+--     NoExpectedFailure {} -> putStrLn "Unexpected failure" >> exitFailure++prettyParseEquivalence :: JavaScript () -> Property+prettyParseEquivalence orig =+  let pp = show $ prettyPrint orig+  in case parseFromString pp of+    Left e -> +      let err = "Can't parse pretty-printed code. The error was: " ++ (show e) +++                "\nThe pretty-printed code in question:\n" ++ pp+      in whenFail (putStrLn err) False+    Right parsed ->+      let eq = (removeAnnotations parsed) == orig+          msg ="The parse of the pretty-printed AST didn't match the original\n"+               ++"Diff:\n" ++ jsDiff orig (reannotate (const ()) parsed)+      in whenFail (putStrLn msg) eq
+ test/Test/Unit.hs view
@@ -0,0 +1,49 @@+module Test.Unit where++import Test.Framework+import Test.Framework.Providers.HUnit+import Test.HUnit hiding (Test)+import System.Exit+import System.Directory+import qualified System.FilePath as FilePath+import Language.ECMAScript3.Parser+import Language.ECMAScript3.PrettyPrint+import Language.ECMAScript3.Syntax+import Language.ECMAScript3.Syntax.Annotations+import Language.ECMAScript3.SourceDiff+import Control.Monad+++tests_unit :: Test+tests_unit =+  buildTest $+  do allFiles <- getDirectoryContents testDir+     let validFiles = filter (\x -> FilePath.takeExtension x == ".js") allFiles+     return $ testGroup "Parser Unit tests" $  map genTest validFiles+++genTest :: FilePath -> Test+genTest file = testCase file $ parsePrettyTest (testDir `FilePath.combine` file) ++testDir = "test/parse-pretty"++-- | tests the parser with pre-defined test-cases+parsePrettyTest :: FilePath -> Assertion+parsePrettyTest filename =+  readFile filename >>= \src ->+  case parseFromString src of+    Left err -> assertFailure $ "Can't parse a test-case: " ++ filename+    Right js -> let str = show $ prettyPrint js+                in  case parseFromString str of+                  Left err ->+                    let msg = "Can't parse pretty-printed code. The error was: "+                              ++ (show err)+                              ++ "\nThe pretty-printed code in question:\n" ++ str+                    in assertFailure msg+                  Right js' -> do+                    let str' = show $ prettyPrint js'+                    unless (str == str') $ do+                      let msg = "The parse of the pretty-printed AST didn't match the original\n"+                                ++ "Diff:\n" ++ jsDiff js js'+                      assertFailure msg+
+ test/TestMain.hs view
@@ -0,0 +1,12 @@+-- | main entry point for tests+module Main where++import Test.Framework+import Test.Unit+import Test.Pretty+import Test.Diff+          +-- entry point for the test-suite+main = defaultMain tests++tests = [tests_diff, tests_pretty, tests_unit]
+ test/diff/expects/t1.diff view
@@ -0,0 +1,2 @@+ x = 1;+-y = 2;
+ test/diff/left/t1.js view
@@ -0,0 +1,2 @@+x = 1;+y = 2;
+ test/diff/right/t1.js view
@@ -0,0 +1,1 @@+x = 1;
+ test/parse-pretty/add.js view
@@ -0,0 +1,1 @@+1+2;;;;
+ test/parse-pretty/do-while.js view
@@ -0,0 +1,3 @@+do {+  x = y;+} while (element);
+ test/parse-pretty/flapjax-fxinternal-22dec2008.js view
@@ -0,0 +1,2552 @@+function flapjaxInit(options) {+  // compress via http://alex.dojotoolkit.org/shrinksafe/+  // make sure to change final eval call to use exported library renamed+  // name++  var defaultOptions = {+    includeSynonyms: true,+    exportMisc: true,+    exportCore: true,+    exportDOM: true,+    exportDOMMisc: true,+    exportWS: true,+    hide: [ ],+    show: [ ],+    redefine: false+  };++  if (options === false) {+    options = { hide: [ ], show: [ ] };+  }+  else if (options === true || !options) {+    options = { };+  }++  // Fill in any missing options using the defaults.+  for (var option in defaultOptions) {+    if (options[option] === undefined) {+      options[option] = defaultOptions[option];+    }+  };++  // Transform hide and show lists into tables+  var hideArray = options.hide;+  options.hide = { };+  for (var i = 0; i < hideArray.length; i++) {+    options.hide[hideArray[i]] = true;+  }+  var showArray = options.show;+  options.show = { };+  for (var i = 0; i < showArray.length; i++) {+    options.show[showArray[i]] = true;+  }++  var warn = function(s) {+    /*if (console && console.warn) {+      console.warn(s);+    }*/+  };+++  var flapjax = {+    version: 4,+    base: {}, //pulses+    combinators: {}, // combinators yielding nodes+	  behaviours: {},+    dom: {} // dom convenience methods and combinators+  };++  var d = flapjax.dom;++	flapjax.pub = {util:flapjax};++	var annotate = function(fn,names,protoArg,protoObjs,protoNames) {+		for(var i=0; i<names.length;i++) {+			flapjax.pub[names[i]] = fn;+		}+		if(protoArg != undefined) {+			var pf = function() {+				var args = slice(arguments,0);+				args.splice(protoArg,0,this);+				return fn.apply(this,args);+			};+			for(var i=0; i<protoObjs.length; i++) {+				for(var j=0; j<protoNames.length;j++) {+					protoObjs[i][protoNames[j]] = pf;+				}+			}+		}+	};++  var exports = { };+  var synonyms = { };++  var misc = { }; /* Used as a symbol */+  var core = { }; /* Used as a symbol */+  var dom = { }; /* Used as a symbol */+  var domMisc = { }; /* Used as a symbol */+  var ws = { }; /* Used as a symbol */++  var fxExport = function(exportCategory,exportVal,+                          exportName /* , synonyms */) {+    if (!(exportCategory instanceof Object)) {+      throw 'fxExport: category is ' + exportCategory;+    };++    if (typeof(exportName) != 'string') {+      console.log(exportVal);+      throw 'fxExport: name is ' + exportName;+    };++    exportVal.__flapjaxCategory = exportCategory;+    exports[exportName] = exportVal;+    for (var i = 3; i < arguments.length; i++) {+      exports[arguments[i]] = exportVal;+      synonyms[arguments[i]] = true;+    }+  };++  var fxMethodSynonyms = function(obj,method) {+    if (options.includeSynonyms === true) {+      for (var i = 2; i < arguments.length; i++) {+        obj.prototype[arguments[i]] = obj.prototype[method];+      };+    };+  };++  //////////////////////////////////////////////////////////////////////////////+  // Miscellaneous functions++	//credit 4umi+	//slice: Array a * Integer * Integer -> Array a+	var slice = function (arr, start, stop) {+		var i, len = arr.length, r = [];+		if( !stop ) { stop = len; }+		if( stop < 0 ) { stop = len + stop; }+		if( start < 0 ) { start = len - start; }+		if( stop < start ) { i = start; start = stop; stop = i; }+		for( i = 0; i < stop - start; i++ ) { r[i] = arr[start+i]; }+		return r;+	}++	var isEqual = function (a,b) {+		return (a == b) ||+			( (((typeof(a) == 'number') && isNaN(a)) || a == 'NaN') &&+			  (((typeof(b) == 'number') && isNaN(b)) || b == 'NaN') );+	};++	//member: a * Array b -> Boolean+	var member = function(elt, lst) {+		for (var i = 0; i < lst.length; i++) {+			if (isEqual(lst[i], elt)) {return true;}+		}+		return false;+	};++	var zip = function(arrays) {+		if (arrays.length == 0) return [];+		var ret = [];+		for(var i=0; i<arrays[0].length;i++) {+			ret.push([]);+			for(var j=0; j<arrays.length;j++)+				ret[i].push(arrays[j][i]);+		}+		return ret;+	};++	//map: (a * ... -> z) * [a] * ... -> [z]+	var map = function (fn) {+		var arrays = slice(arguments, 1);+		if (arrays.length === 0) { return []; }+		else if (arrays.length === 1) {+			var ret = [];+			for(var i=0; i<arrays[0].length; i++) {ret.push(fn(arrays[0][i]));}+			return ret;+		}+		else {+			var ret = zip(arrays);+			var o = new Object();+			for(var i=0; i<ret.length; i++) {ret[i] = fn.apply(o,ret[i]);}+			return ret;+		}+	};++	//filter: (a -> Boolean) * Array a -> Array a+	var filter = function (predFn, arr) {+		var res = [];+		for (var i = 0; i < arr.length; i++) {+			if (predFn(arr[i])) { res.push(arr[i]); }+		}+		return res;+	};++  //fold: (a * .... * accum -> accum) * accum * [a] * ... -> accum+  //fold over list(s), left to right+  var fold = function(fn, init /* arrays */) {+		var lists = slice(arguments, 2);+		if (lists.length === 0) { return init; }+		else if(lists.length === 1) {+			var acc = init;+			for(var i = 0; i < lists[0].length; i++) {+				acc = fn(lists[0][i],acc);+			}+			return acc;+		}+		else {+			var acc = init;+			for (var i = 0; i < lists[0].length; i++) {+				var args = map( function (lst) { return lst[i];},+		          lists);+				args.push(acc);+				acc = fn.apply({}, args);+			}+			return acc;+		}+  };++  //foldR: (a * .... * accum -> accum) * accum * [a] * ... -> accum+	//fold over list(s), right to left, fold more memory efficient (left to right)+	var foldR = function (fn, init /* arrays */) {+    var lists = slice(arguments, 2);+		if (lists.length === 0) { return init; }+		else if(lists.length === 1) {+			var acc = init;+			for(var i=lists[0].length - 1; i > -1; i--)+				acc = fn(lists[0][i],acc);+			return acc;+		}+		else {+			var acc = init;+			for (var i = lists[0].length - 1; i > -1; i--) {+				var args = map( function (lst) { return lst[i];},+		          lists);+				args.push(acc);+				acc = fn.apply({}, args);+			}+			return acc;+		}+	};++  var pushAll = function(destArray,srcArray) {+    for (var i = 0; i < srcArray.length; i++) {+      destArray.push(srcArray[i]);+    }+    return destArray;+  };++  fxExport(misc,slice,'slice');+  fxExport(misc,member,'member');+  fxExport(misc,map,'map');+  fxExport(misc,map,'forEach');+  fxExport(misc,filter,'filter');+  fxExport(misc,fold,'fold');+  fxExport(misc,foldR,'foldR');++  //////////////////////////////////////////////////////////////////////////////+  // Flapjax core++  //Pulse: Stamp * Path * Obj+  var Pulse = function (stamp, value) {+    this.stamp = stamp;+    this.value = value;+  };+++  //Probably can optimize as we expect increasing insert runs etc+  var PQ = function () {+    var ctx = this;+    ctx.val = [];+    this.insert = function (kv) {+			ctx.val.push(kv);+			var kvpos = ctx.val.length-1;+			while(kvpos > 0 && kv.k < ctx.val[Math.floor((kvpos-1)/2)].k) {+				var oldpos = kvpos;+				kvpos = Math.floor((kvpos-1)/2);+				ctx.val[oldpos] = ctx.val[kvpos];+				ctx.val[kvpos] = kv;+			}+    };+    this.isEmpty = function () {+      return ctx.val.length === 0;+    };+    this.pop = function () {+			if(ctx.val.length == 1) {+				return ctx.val.pop();+			}+			var ret = ctx.val.shift();+			ctx.val.unshift(ctx.val.pop());+			var kvpos = 0;+			var kv = ctx.val[0];+			while(1) {+				var leftChild = (kvpos*2+1 < ctx.val.length ? ctx.val[kvpos*2+1].k : kv.k+1);+				var rightChild = (kvpos*2+2 < ctx.val.length ? ctx.val[kvpos*2+2].k : kv.k+1);+				if(leftChild > kv.k && rightChild > kv.k)+					break;+				else if(leftChild < rightChild) {+					ctx.val[kvpos] = ctx.val[kvpos*2+1];+					ctx.val[kvpos*2+1] = kv;+					kvpos = kvpos*2+1;+				}+				else {+					ctx.val[kvpos] = ctx.val[kvpos*2+2];+					ctx.val[kvpos*2+2] = kv;+					kvpos = kvpos*2+2;+				}+			}+			return ret;+		};+  };++  var lastRank = 0;+  var stamp = 1;+  var nextStamp = function () { return ++stamp; };++  //propagatePulse: Pulse * Array Node ->+  //Send the pulse to each node+  var propagatePulse = function (pulse, node) {+    var queue = new PQ(); //topological queue for current timestep+	queue.insert({k:node.rank,n:node,v:pulse});+	while(!(queue.isEmpty())) {+		var qv = queue.pop();+		qv.n.updater(function(nextPulse) {+			for(var i=0; i<qv.n.sendsTo.length;i++)+				queue.insert({k:qv.n.sendsTo[i].rank,n:qv.n.sendsTo[i],v:nextPulse});+		},new Pulse(qv.v.stamp,qv.v.value));+	}+  };++  //Event: Array Node b * ( (Pulse a -> Void) * Pulse b -> Void)+  var EventStream = function (nodes,updater) {+    this.updater = updater;++    this.sendsTo = []; //forward link++    for (var i = 0; i < nodes.length; i++) {+      nodes[i].sendsTo.push(this);+    }++    this.rank = ++lastRank;+  };+	EventStream.prototype = new Object();++  fxExport(core,EventStream,'EventStream');+++  //createNode: Array Node a * ( (Pulse b ->) * (Pulse a) -> Void) -> Node b+  var createNode = function (nodes, updater) {+		return new EventStream(nodes,updater);+	};++  //attachListenerNode: Node * Node -> Voids+  //flow from node to dependent+  //note: does not add flow as counting for rank nor updates parent ranks+  var attachListener = function (node, dependent) {+    if (!(node instanceof EventStream)) { throw 'attachListenenerNode: expects event as first arg';} //SAFETY+    if (!(dependent instanceof EventStream)) { throw 'attachListenenerNode: expects event as second arg';} //SAFETY++    node.sendsTo.push(dependent);+		if(node.rank > dependent.rank) {+			var lowest = lastRank+1;+			var q = [dependent];+			while(q.length) {+				var cur = q.splice(0,1)[0];+				cur.rank = ++lastRank;+				q = q.concat(cur.sendsTo);+			}+		}+  };++  //removeListenerNode: Node * Node -> Boolean+  //remove flow from node to dependent+  //note: does not remove flow as counting for rank nor updates parent ranks+  var removeListener = function (node, dependent)+  {+    if (!(node instanceof EventStream)) { throw 'removeListenerNode: expects event as first arg';} //SAFETY+    if (!(dependent instanceof EventStream)) { throw 'removeListenenerNode: expects event as second arg';} //SAFETY++    var foundSending = false;+    for (var i = 0; i < node.sendsTo.length && !foundSending; i++) {+      if (node.sendsTo[i] == dependent) {+        node.sendsTo.splice(i, 1);+        foundSending = true;+      }+    }++    return foundSending;+  };++  // An internal_e is a node that simply propagates all pulses it receives.  It's used internally by various+  // combinators.+  var internal_e = function(dependsOn) {+    return createNode(dependsOn || [ ],function(send,pulse) { send(pulse); });+  }++  var zero_e = function() {+    return createNode([],function(send,pulse) {+        throw ('zero_e : received a value; zero_e should not receive a value; the value was ' + pulse.value);+    });+  };+  fxExport(core,zero_e,'zero_e');++  var one_e = function(val) {+    var sent = false;+    var evt = createNode([],function(send,pulse) {+      if (sent) {+        throw ('one_e : received an extra value');+      }+      sent = true;+      send(pulse);+    });+    window.setTimeout(function() { sendEvent(evt,val); },0);+    return evt;+  };+  fxExport(core,one_e,'one_e');++  // a.k.a. mplus; merge_e(e1,e2) == merge_e(e2,e1)+  var merge_e = function() {+    if (arguments.length == 0) {+      return zero_e();+    }+    else {+      var deps = slice(arguments,0);+      return internal_e(deps);+    }+  };+  fxExport(core,merge_e,'merge_e');++  EventStream.prototype.merge_e = function() {+    var deps = slice(arguments,0);+    deps.push(this);+    return internal_e(deps);+  };+  fxMethodSynonyms(EventStream,'merge_e','merge');++  EventStream.prototype.constant_e = function(constantValue) {+    return createNode([this],function(send,pulse) {+      pulse.value = constantValue;+      send(pulse);+    });+  };+  fxMethodSynonyms(EventStream,'constant_e','constant','replaceValue_e','replaceValue');++  var constant_e = function(e) { return e.constant_e(); };+  fxExport(core,constant_e,'constant_e','replaceValue_e');++	var createTimeSyncNode = function(nodes) {+		var nqs = map(function(n) {+				var qpulse = [];+				return {q:qpulse,v:createNode([n],function(s,p) {qpulse.push(p.value); s(p);},nodes)};+    },nodes);+		return createNode(+      map(function(n) {return n.v;},nqs), function(s,p) {+        var allfull = fold(function(n,acc) {return n.q.length && acc;},true,nqs);+        if(allfull) {+          p.value = map(function(n) {return n.q.shift();},nqs);+          s(p);+      }});+	};++	//This is up here so we can add things to its prototype that are in flapjax.combinators+  var Behaviour = function (event, init, updater) {+    if (!(event instanceof EventStream)) {+      throw 'Behaviour: expected event as second arg';+    }++    var behave = this;+    this.last = init;++    //sendEvent to this might impact other nodes that depend on this event+    //sendBehaviour defaults to this one+    this.underlyingRaw = event;++    //unexposed, sendEvent to this will only impact dependents of this behaviour+    this.underlying =+    createNode(+      [event],+	  (updater ?+	   function (s, p) {behave.last = updater(p.value); p.value = behave.last; s(p);} :+	   function (s, p) {behave.last = p.value;  s(p);}));+  };+	Behaviour.prototype = new Object();+  fxExport(core,Behaviour,'Behaviour');+  fxExport(core,Behaviour,'Behavior');++  var receiver_e = function() {+    var evt = internal_e();+    evt.sendEvent = function(value) {+      propagatePulse(new Pulse(nextStamp(), value),evt);+    };+    return evt;+  };+  fxExport(core,receiver_e,'receiver_e');++  //note that this creates a new timestamp and new event queue+  var sendEvent = function (node, value) {+    if (!(node instanceof EventStream)) { throw 'sendEvent: expected Event as first arg'; } //SAFETY++    propagatePulse(new Pulse(nextStamp(), value),node);+  };+  fxExport(core,sendEvent,'sendEvent');+  synonyms['sendEvent'] = true; // Hack: sendEvent simply should not be exported; calling it a synonym deprecates it.++  // bind_e :: EventStream a * (a -> EventStream b) -> EventStream b+  EventStream.prototype.bind_e = function(k) {+    /* m.sendsTo result_e+     * result_e.sendsTo prev_e+     * prev_e.sendsTo return_e+     */+    var m = this;+    var prev_e = false;++    var out_e = createNode([],function(send,pulse) { send(pulse); });+    out_e.name = "bind out_e";++    var in_e = createNode([m], function (send,pulse) {+      if (prev_e) {+        removeListener(prev_e,out_e);+      }+      prev_e = k(pulse.value);+      if (prev_e instanceof EventStream) {+        attachListener(prev_e,out_e);+      }+      else {+        throw "bind_e : expected EventStream";+      }+    });+    in_e.name = "bind in_e";++    return out_e;+  };++  /* Could be written as:+   *+   * e.bind_e(function(v) { return one_e(f(v)); })+   */+  EventStream.prototype.lift_e = function(f) {+    if (!(f instanceof Function)) {+      throw ('lift_e : expected a function as the first argument; received ' + f);+    };++    return createNode([this],function(send,pulse) {+      pulse.value = f(pulse.value);+      send(pulse);+    });+  };+  fxMethodSynonyms(EventStream,'lift_e',+    'transform_e','map_e','apply_e','lift','transform','map','apply');++  EventStream.prototype.not_e = function() { return this.lift_e(function(v) { return !v; }); };+  fxMethodSynonyms(EventStream,'not_e','not');++  var not_e = function(e) { return e.not_e(); };+  fxExport(core,not_e,'not_e','not');++  EventStream.prototype.filter_e = function(pred) {+    if (!(pred instanceof Function)) {+      throw ('filter_e : expected predicate; received ' + pred);+    };++    // Can be a bind_e+    return createNode([this],+      function(send,pulse) {+        if (pred(pulse.value)) { send(pulse); }+    });+  };+  fxMethodSynonyms(EventStream,'filter_e','filter');++  var filter_e = function(e,p) { return e.filter_e(p); };+  fxExport(core,filter_e,'filter_e');++  // Fires just once.+  EventStream.prototype.once_e = function() {+    var done = false;+    // Alternately: this.collect_e(0,\n v -> (n+1,v)).filter_e(\(n,v) -> n == 1).lift_e(fst)+    return createNode([this],function(send,pulse) {+      if (!done) { done = true; send(pulse); }+    });+  };+  fxMethodSynonyms(EventStream,'once_e','once');++  var once_e = function(e) { return e.once_e(); };+  fxExport(core,once_e,'once_e');++  EventStream.prototype.skipFirst_e = function() {+    var skipped = false;+    return createNode([this],function(send,pulse) {+      if (skipped)+        { send(pulse); }+      else+        { skipped = true; }+    });+  };+  fxMethodSynonyms(EventStream,'skipFirst_e','skipFirst');++  var skipFirst_e = function(e) { return e.skipFirst_e(); };+  fxExport(core,skipFirst_e,'skipFirst_e');++  EventStream.prototype.collect_e = function(init,fold) {+    var acc = init;+    return this.lift_e(+      function (n) {+        var next = fold(n, acc);+        acc = next;+        return next;+      });+  };+  fxMethodSynonyms(EventStream,'collect_e','collect','transformWithMemory');++  var collect_e = function(e,i,f) { return e.collect_e(i,f); };+  fxExport(core,collect_e,'collect_e');++  // a.k.a. join+  EventStream.prototype.switch_e = function() {+    return this.bind_e(function(v) { return v; });+  };+  fxMethodSynonyms(EventStream,'switch_e','forwardLatest');++  var switch_e = function(e) { return e.switch_e(); };+  fxExport(core,switch_e,'switch_e');++  EventStream.prototype.if_e = function(thenE,elseE) {+    var testStamp = -1;+    var testValue = false;++    createNode([this],function(_,pulse) { testStamp = pulse.stamp; testValue = pulse.value; });++    return merge_e(+      createNode([thenE],function(send,pulse) { if (testValue && (testStamp == pulse.stamp)) { send(pulse); } }),+      createNode([elseE],function(send,pulse) { if (!testValue && (testStamp == pulse.stamp)) { send(pulse); } }));+  };+  fxMethodSynonyms(EventStream,'if_e','choose_e','choose');++  var if_e = function(test,thenE,elseE) {+    if (test instanceof EventStream)+      { return test.if_e(thenE,elseE); }+    else+      { return test ? thenE : elseE; }+  };+  fxExport(core,if_e,'if_e','choose_e');++  var cond_e = function (/*. predValArrays */) {+    var predValArrays = slice(arguments, 0);+    var acc = zero_e();+    for (var i = predValArrays.length - 1; i > -1; i--) {+      acc = if_e(predValArrays[i][0],predValArrays[i][1], acc);+    }+    return acc;+  };+  fxExport(core,cond_e,'cond_e');++  var and_e = function (/* . nodes */) {+    var nodes = slice(arguments, 0);++    var acc = (nodes.length > 0)?+    nodes[nodes.length - 1] : one_e(true);++    for (var i = nodes.length - 2; i > -1; i--) {+      acc = if_e(+        nodes[i],+        acc,+        nodes[i].constant_e(false));+    }+    return acc;+  };+  fxExport(core,and_e,'and_e');++  EventStream.prototype.and_e = function( /* others */ ) {+    var deps = [this].concat(slice(arguments,0));+    return and_e.apply(this,deps);+  };+  fxMethodSynonyms(EventStream,'and_e','and');++  var or_e = function () {+    var nodes = slice(arguments, 0);+    var acc = (nodes.length > 2)?+    nodes[nodes.length - 1] : one_e(false);+    for (var i = nodes.length - 2; i > -1; i--) {+      acc = if_e(+        nodes[i],+        nodes[i],+        acc);+    }+    return acc;+  };+  fxExport(core,or_e,'or_e');++  EventStream.prototype.or_e = function(/*others*/) {+    var deps = [this].concat(slice(arguments,0));+    return or_e.apply(this,deps);+  };+  fxMethodSynonyms(EventStream,'or_e','or');++  var delayStatic_e = function (event, time) {++    var resE = internal_e();++    createNode(+      [event],+      function (s, p) {+        setTimeout(+          function () { sendEvent(resE, p.value);},+      time ); });++    return resE;+  };++  //delay_e: Event a * [Behaviour] Number ->  Event a+  EventStream.prototype.delay_e = function (time) {+    var event = this;++    if (time instanceof Behaviour) {++      var receiverEE = internal_e();+      var link =+      {+        from: event,+        towards: delayStatic_e(event, valueNow(time))+      };++			//TODO: Change semantics such that we are always guaranteed to get an event going out?+      var switcherE =+      createNode(+        [changes(time)],+        function (s, p) {+          removeListener(link.from, link.towards);+          link =+          {+            from: event,+            towards: delayStatic_e(event, p.value)+          };+          sendEvent(receiverEE, link.towards);+        });++      var resE = receiverEE.switch_e();++      sendEvent(switcherE, valueNow(time));+      return resE;++        } else { return delayStatic_e(event, time); }+  };+  fxMethodSynonyms(EventStream,'delay_e','delay');++  var delay_e = function(sourceE,interval) {+    return sourceE.delay_e(interval);+  };+  fxExport(core,delay_e,'delay_e');++  //lift_e: ([Event] (. Array a -> b)) . Array [Event] a -> [Event] b+  var lift_e = function (fn /*, [node0 | val0], ...*/) {+    //      if (!(fn instanceof Function)) { throw 'lift_e: expected fn as second arg'; } //SAFETY++    var valsOrNodes = slice(arguments, 0);+    //selectors[i]() returns either the node or real val, optimize real vals+    var selectors = [];+    var selectI = 0;+    var nodes = [];+    for (var i = 0; i < valsOrNodes.length; i++) {+      if (valsOrNodes[i] instanceof EventStream) {+        nodes.push(valsOrNodes[i]);+        selectors.push(+          (function(ii) {+              return function(realArgs) {+                return realArgs[ii];+              };+          })(selectI));+        selectI++;+      } else {+        selectors.push(+          (function(aa) {+              return function () {+                return aa;+              };+          })(valsOrNodes[i]));+      }+    }++    var context = this;+		var nofnodes = slice(selectors,1);++    if (nodes.length === 0) {+      return one_e(fn.apply(context, valsOrNodes));+    } else if ((nodes.length === 1) && (fn instanceof Function)) {+      return nodes[0].lift_e(+        function () {+          var args = arguments;+          return fn.apply(+            context,+            map(function (s) {return s(args);}, nofnodes));+        });+    } else if (nodes.length === 1) {+      return fn.lift_e(+        function (v) {+          var args = arguments;+          return v.apply(+            context,+            map(function (s) {return s(args);}, nofnodes));+        });+    } else if (fn instanceof Function) {+      return createTimeSyncNode(nodes).lift_e(+        function (arr) {+          return fn.apply(+            this,+            map(function (s) { return s(arr); }, nofnodes));+        });+    } else if (fn instanceof EventStream) {+      return createTimeSyncNode(nodes).lift_e(+        function (arr) {+          return arr[0].apply(+            this,+            map(function (s) {return s(arr); }, nofnodes));+        });+        } else {throw 'unknown lift_e case';}+  };+  fxExport(core,lift_e,'lift_e','transform_e','map_e','apply_e');++  EventStream.prototype.snapshot_e = function (valueB) {+    return createNode(+      [this],+      function (s, p) {+        p.value = valueNow(valueB);+        s(p);+      }+      );+  };+  fxMethodSynonyms(EventStream,'snapshot_e','snapshot','takeSnapshot');++  var snapshot_e = function(triggerE,valueB) {+    return triggerE.snapshot_e(valueB);+  };+  fxExport(core,snapshot_e,'snapshot_e');++  EventStream.prototype.filterRepeats_e = function(optStart) {+    var hadFirst = optStart === undefined ? false : true;+    var prev = optStart;++    return this.filter_e(function (v) {+      if (!hadFirst || !(isEqual(prev,v))) {+        hadFirst = true;+        prev = v;+        return true;+      }+      else {+        return false;+      }+    });+  };+  fxMethodSynonyms(EventStream,'filterRepeats_e','filterRepeats');++  var filterRepeats_e = function(sourceE,optStart) {+    return sourceE.filterRepeats_e(optStart);+  };+  fxExport(core,filterRepeats_e,'filterRepeats_e','filterRepeats');++  //credit Pete Hopkins+  var calmStatic_e = function (triggerE, time) {+		var out = internal_e();+    createNode(+      [triggerE],+      function() {+        var towards = null;+        return function (s, p) {+          if (towards !== null) { clearTimeout(towards); }+          towards = setTimeout( function () { towards = null; sendEvent(out,p.value) }, time );+        };+      }());+		return out;+  };++  //calm_e: Event a * [Behaviour] Number -> Event a+  EventStream.prototype.calm_e = function(time) {+    if (time instanceof Behaviour) {+			var out = internal_e();+      createNode(+        [this],+        function() {+          var towards = null;+          return function (s, p) {+            if (towards !== null) { clearTimeout(towards); }+             towards = setTimeout( function () { towards = null; sendEvent(out,p.value);}, valueNow(time));+          };+        }());+			return out;+    } else {+      return calmStatic_e(this,time);+    }+  };+  fxMethodSynonyms(EventStream,'calm_e','calm');++  var calm_e = function(sourceE,interval) {+    return sourceE.calm_e(interval);+  };+  fxExport(core,calm_e,'calm_e');++  EventStream.prototype.blind_e = function (time) {+    return createNode(+      [this],+      function () {+        var intervalFn =+        time instanceof Behaviour?+        function () { return valueNow(time); }+        : function () { return time; };+        var lastSent = (new Date()).getTime() - intervalFn() - 1;+        return function (s, p) {+          var curTime = (new Date()).getTime();+          if (curTime - lastSent > intervalFn()) {+            lastSent = curTime;+            s(p);+          }+        };+      }());+  };+  fxMethodSynonyms(EventStream,'blind_e','blind');++  var blind_e = function(sourceE,interval) {+    return sourceE.blind_e(interval);+  };+  fxExport(core,blind_e,'blind_e');++  EventStream.prototype.hold = function(init) {+    return new Behaviour(this,init);+  };+  fxMethodSynonyms(EventStream,'hold','startsWith','toBehavior');++  var hold = function(e,init) {+    if (!(e instanceof EventStream)) {+      throw 'hold: expected EventStream; received ' + e;+    }+    return e.hold(init);+  };+  fxExport(core,hold,'hold');++  Behaviour.prototype.valueNow = function() {+    return this.last;+  };+  var valueNow = function(behavior) { return behavior.valueNow(); };+  fxExport(core,valueNow,'valueNow');++  Behaviour.prototype.changes = function() {+    return this.underlying;+  };+  fxMethodSynonyms(Behaviour,'changes','toEvent');++   var changes = function (behave) { return behave.changes(); };+  fxExport(core,changes,'changes');++  Behaviour.prototype.switch_b = function() {+    var behaviourCreatorsB = this;+    var init = valueNow(behaviourCreatorsB);++    var prevSourceE = null;++    var receiverE = new internal_e();++		//XXX could result in out-of-order propagation! Fix!+    var makerE =+    createNode(+      [changes(behaviourCreatorsB)],+      function (_, p) {+        if (!(p.value instanceof Behaviour)) { throw 'switch_b: expected Behaviour as value of Behaviour of first argument'; } //SAFETY+        if (prevSourceE != null) {+          removeListener(prevSourceE, receiverE);+        }++        prevSourceE = changes(p.value);+        attachListener(prevSourceE, receiverE);++        sendEvent(receiverE, valueNow(p.value));+      });++    if (init instanceof Behaviour) {+      sendEvent(makerE, init);+    }++    return hold(+      receiverE,+      init instanceof Behaviour? valueNow(init) : init);+  };+  fxMethodSynonyms(Behaviour,'switch_b','forwardLatest');++  var switch_b = function (b) { return b.switch_b(); };+  fxExport(core,switch_b,'switch_b');++  //TODO test, signature+  var timer_b = function(interval) {+    return hold(timer_e(interval), (new Date()).getTime());+  };+  fxExport(dom,timer_b,'timer_b','asTimer_b');++  //TODO test, signature+  var delayStatic_b = function (triggerB, time, init) {+    return hold(delayStatic_e(changes(triggerB), time), init);+  };++  //TODO test, signature+  Behaviour.prototype.delay_b = function (time, init) {+    var triggerB = this;+    if (time instanceof Behaviour) {+      return hold(+        delay_e(+          changes(triggerB),+          time),+        arguments.length > 3 ? init : valueNow(triggerB));+    } else {+      return delayStatic_b(+        triggerB,+        time,+        arguments.length > 3 ? init : valueNow(triggerB));+    }+  };+  fxMethodSynonyms(Behaviour,'delay_b','delay');++  var delay_b = function(srcB, timeB, init) {+    return srcB.delay_b(timeB,init);+  };+  fxExport(core,delay_b,'delay_b');++  //artificially send a pulse to underlying event node of a behaviour+  //note: in use, might want to use a receiver node as a proxy or an identity map+  Behaviour.prototype.sendBehaviour = function(val) {+    sendEvent(this.underlyingRaw,val);+  };+  Behaviour.prototype.sendBehavior = Behaviour.prototype.sendBehaviour;++  var sendBehaviour = function (b,v) { b.sendBehaviour(v); };+  fxExport(core,sendBehaviour,'sendBehaviour');+  fxExport(core,sendBehaviour,'sendBehavior');++  Behaviour.prototype.if_b = function(trueB,falseB) {+    var testB = this;+    //TODO auto conversion for behaviour funcs+    if (!(trueB instanceof Behaviour)) { trueB = constant_b(trueB); }+    if (!(falseB instanceof Behaviour)) { falseB = constant_b(falseB); }+    return lift_b(function(te,t,f) { return te ? t : f; },testB,trueB,falseB);+  };+  fxMethodSynonyms(Behaviour,'if_b','choose_b','choose');++  var if_b = function(test,cons,altr) {+    if (!(test instanceof Behaviour)) { test = constant_b(test); };++    return test.if_b(cons,altr);+  };+  fxExport(core,if_b,'if_b','choose_b');+++  //cond_b: . [Behaviour boolean, Behaviour a] -> Behaviour a+  var cond_b = function (/* . pairs */ ) {+    var pairs = slice(arguments, 0);+	return lift_b.apply({},[function() {+			for(var i=0;i<pairs.length;i++) {+				if(arguments[i]) return arguments[pairs.length+i];+			}+			return undefined;+		}].concat(map(function(pair) {return pair[0];},pairs).concat(map(function(pair) {return pair[1];},pairs))));+  };+  fxExport(core,cond_b,'cond_b');++  //TODO optionally append to objects+  //createConstantB: a -> Behaviour a+  var constant_b = function (val) {+    return new Behaviour(internal_e(), val);+  };+  fxExport(core,constant_b,'constant_b','receiver_b');++	var lift_b = function (fn /* . behaves */) {+    var args = slice(arguments, 1);++    //dependencies+    var constituentsE =+      map(changes,+      filter(function (v) { return v instanceof Behaviour; },+        arguments));++    //calculate new vals+    var getCur = function (v) {+      return v instanceof Behaviour ? v.last : v;+    };++    var ctx = this;+    var getRes = function () {+      return getCur(fn).apply(ctx, map(getCur, args));+    };++    if(constituentsE.length == 1) {+      return new Behaviour(constituentsE[0],getRes(),getRes);+    }++    //gen/send vals @ appropriate time+    var prevStamp = -1;+    var mid = createNode(constituentsE, function (s, p) {+        if (p.stamp != prevStamp) {+          prevStamp = p.stamp;+          s(p);+    }});+    return new Behaviour(mid,getRes(),getRes);+  };+  fxExport(core,lift_b,'lift_b','transform_b','apply_b');++  Behaviour.prototype.lift_b = function(/* args */) {+    var args= slice(arguments,0).concat([this]);+    return lift_b.apply(this,args);+  };+  fxMethodSynonyms(Behaviour,'lift_b','transform_b','apply_b','transform',+    'lift');++  var and_b = function (/* . behaves */) {+	return lift_b.apply({},[function() {+			for(var i=0; i<arguments.length; i++) {if(!arguments[i]) return false;}+			return true;+	}].concat(slice(arguments,0)));+  };+  fxExport(core, and_b, 'and_b');++  Behaviour.prototype.and_b = function() {+    return and_b([this].concat(arguments));+  };+  fxMethodSynonyms(Behaviour,'and_b','and');++  var or_b = function (/* . behaves */ ) {+	return lift_b.apply({},[function() {+			for(var i=0; i<arguments.length; i++) {if(arguments[i]) return true;}+			return false;+	}].concat(slice(arguments,0)));+  };+  fxExport(core,or_b,'or_b');++  Behaviour.prototype.or_b = function () {+    return or_b([this].concat(arguments));+  };+  fxMethodSynonyms(Behaviour, 'or_b', 'or');++  Behaviour.prototype.not_b = function() {+    return this.lift_b(function(v) { return !v; });+  };+  fxMethodSynonyms(Behaviour,'not_b','not');++  var not_b = function(b) { return b.not_b(); };+  fxExport(core,not_b,'not_b');++  Behaviour.prototype.blind_b = function (intervalB) {+    return changes(this).blind_e(intervalB).hold(this.valueNow());+  };+  fxMethodSynonyms(Behaviour,'blind_b','blind');++  var blind_b = function(srcB,intervalB) {+    return srcB.blind_b(intervalB);+  };+  fxExport(core,blind_b,'blind_b');++  Behaviour.prototype.calm_b = function (intervalB) {+    return this.changes().calm_e(intervalB).hold(this.valueNow());+  };+  fxMethodSynonyms(Behaviour,'calm_b','calm');++  var calm_b = function (srcB,intervalB) {+    return srcB.calm_b(intervalB);+  };+  fxExport(core,calm_b,'calm_b');++  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+  // DOM Utilities++	//credit Scott Andrew+	//usage: addEvent(myDomObj, "mouseover", event->void )+	//warning: do not use 'this' as meaning depends on browser (myDomObj vs window)+	//addEvent: Dom * String DomEventEnum * (DomEvent -> a) -> Void+	var addEvent = function (obj, evType, fn) {+		//TODO encode mouseleave evt, formalize new evt interface++		if (obj.addEventListener) {+      obj.addEventListener(evType, fn, false); //TODO true fails on Opera+      return true;+		} else if (obj.attachEvent) {+      //some reason original had code bloat here+      return obj.attachEvent("on"+evType, fn);+		} else {+      return false;+		}+	};+  fxExport(domMisc,addEvent,'addEvent');++  // The Flapjax library does not use this function+	//credit Dustin Diaz+	//note: node/tag optional+	//getElementsByClass: Regexp CSSSelector * Dom * String DomNodeEnum -> Array Dom+	var getElementsByClass = function (searchClass, node, tag) {+		var classElements = [];+		if ( (node === null) || (node === undefined) ) { node = document; }+		if ( (tag === null) || (tag === undefined) ) { tag = '*'; }+		var els = node.getElementsByTagName(tag);+		var elsLen = els.length;+		var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");+		for (var i = 0, j = 0; i < elsLen; i++) {+      if ( pattern.test(els[i].className) ) {+        classElements.push(els[i]);+      }+		}+		return classElements;+	};+  fxExport(domMisc,getElementsByClass,'getElementsByClass','$$');++	//assumes IDs already preserved+	//swapDom: (Dom a U String) [* (Dom b U String)] -> Dom a+	var swapDom = function(replaceMe, withMe) {+		if ((replaceMe === null) || (replaceMe === undefined)) { throw ('swapDom: expected dom node or id, received: ' + replaceMe); } //SAFETY++		var replaceMeD = getObj(replaceMe);+		if (!(replaceMeD.nodeType > 0)) { throw ('swapDom expected a Dom node as first arg, received ' + replaceMeD); } //SAFETY++		if (withMe) {+      var withMeD = getObj(withMe);+      if (!(withMeD.nodeType > 0)) { throw 'swapDom: can only swap with a DOM object'; } //SAFETY+      try {+        if(withMeD != replaceMeD) replaceMeD.parentNode.replaceChild(withMeD, replaceMeD);+      } catch (e) {+        throw('swapDom error in replace call: withMeD: ' + withMeD + ', replaceMe Parent: ' + replaceMeD + ', ' + e + ', parent: ' + replaceMeD.parentNode);+      }+		} else {+      replaceMeD.parentNode.removeChild(replaceMeD); //TODO isolate child and set innerHTML to "" to avoid psuedo-leaks?+		}+		return replaceMeD;+	};+  fxExport(domMisc,swapDom,'swapDom');++	//getObj: String U Dom -> Dom+	//throws+	//  'getObj: expects a Dom obj or Dom id as first arg'+	//  'getObj: flapjax: cannot access object'+	//  'getObj: no obj to get+	//also known as '$'+	//TODO Maybe alternative?+	var getObj = function (name) {+		if (typeof(name) == 'object') { return name; }+		else if ((typeof(name) == 'null') || (typeof(name) == 'undefined')) {+      throw 'getObj: expects a Dom obj or Dom id as first arg';+		} else {++      var res =+			document.getElementById ? document.getElementById(name) :+			document.all ? document.all[name] :+			document.layers ? document.layers[name] :+			(function(){ throw 'getObj: flapjax: cannot access object';})();+      if ((res === null) || (res === undefined)) {+        throw ('getObj: no obj to get: ' + name);+      }+      return res;+		}+	};+  fxExport(domMisc,getObj,'getObj');+  fxExport(domMisc,getObj,'$');++  //helper to reduce obj look ups+  //getDynObj: domNode . Array (id) -> domObj+  //obj * [] ->  obj+  //obj * ['position'] ->  obj+  //obj * ['style', 'color'] ->  obj.style+  var getMostDom = function (domObj, indices) {+    var acc = getObj(domObj);+    if ( (indices === null) || (indices === undefined) || (indices.length < 1)) {+      return acc;+    } else {+      for (var i = 0; i < indices.length - 1; i++) {+        acc = acc[indices[i]];+      }+      return acc;+    }+  };++  var getDomVal = function (domObj, indices) {+    var val = getMostDom(domObj, indices);+    if (indices && indices.length > 0) {+      val = val[indices[indices.length - 1]];+    }+    return val;+  };++  //TODO: manual timer management stinks.+  // TODO: Name turn off or somethin+  var ___timerID = 0;+  var __getTimerId = function () { return ++___timerID; };+  var timerDisablers = [];++  var disableTimerNode = function (node) { timerDisablers[node.__timerId](); };++  var disableTimer = function (v) {+    if (v instanceof Behaviour) {+      disableTimerNode(v.underlyingRaw);+    } else if (v instanceof EventStream) {+      disableTimerNode(v);+    }+  };+  fxExport(dom,disableTimer,'disableTimer');++  var createTimerNodeStatic = function (interval) {+    var node = internal_e();+    node.__timerId = __getTimerId();+    var fn = function () { sendEvent(node, (new Date()).getTime());};+    var timer = setInterval(fn, interval);+    timerDisablers[node.__timerId] = function () {clearInterval(timer); };+    return node;+  };++  var timer_e = function (interval) {+    if (interval instanceof Behaviour) {+      var receiverE = internal_e();++      //the return+      var res = receiverE.switch_e();++      //keep track of previous timer to disable it+      var prevE = createTimerNodeStatic(valueNow(interval));++      //init+      sendEvent(receiverE, prevE);++      //interval changes: collect old timer+      createNode(+        [changes(interval)],+        function (_, p) {+          disableTimerNode(prevE);+          prevE = createTimerNodeStatic(p.value);+          sendEvent(receiverE, prevE);+        });++      res.__timerId = __getTimerId();+      timerDisablers[res.__timerId] = function () {+        disableTimerNode[prevE]();+        return;+      };++      return res;+    } else {+      return createTimerNodeStatic(interval);+    }+  };+  fxExport(dom,timer_e,'timer_e','asTimer_e');++	d.TagB = function(tagName,args) {+		this.resE = internal_e();+		this.currentTag = document.createElement(tagName);+		this.extractParameters(args);+		this.insertChildrenNodes();+		this.styleHooks = [];+		this.styleChangedE = internal_e();+		var ctx = this;+    this.styleChangedE.lift_e(function(_) {+				var oldTag = ctx.currentTag;+				ctx.currentTag = document.createElement(tagName);+        while (oldTag.firstChild) {+          ctx.currentTag.appendChild(oldTag.removeChild(oldTag.firstChild));+				}+				while(ctx.styleHooks.length) removeListener(ctx.styleHooks.pop(),ctx.styleChangedE);+        ctx.enstyle(ctx.currentTag,ctx.attribs);+        sendEvent(ctx.resE, ctx.currentTag);+		});+		this.enstyle(this.currentTag,this.attribs);+    this.resB = hold(this.resE, this.currentTag);+	};+	d.TagB.prototype = {+    // Array [[Behaviour] Object *] [[Behaviour] Array] [Behaviour] Dom U String U undefined+    //   --> {attribs: Array [Behaviour] Object, arrs: Array [Behaviour] Array [Behaviour] Dom }+    // split an arguments array into:+    //   1. arrs: (coalesced, and possibly time varying) arrays of dom objects+    //   2. attribs: attribute objects+		extractParameters: function(args) {+			this.arrs = [];+			var attribs = [];++			var curarr = [];+			this.arrs.push(curarr);+			for (var i = 0; i < args.length; i++) {+				if (args[i] instanceof Behaviour) {+					var vn = valueNow(args[i]);+					if (vn instanceof Array) {+						this.arrs.push(args[i]);+						curarr = [];+						this.arrs.push(curarr);+					} else {+						if ( ((typeof(vn) == 'object') && (vn.nodeType == 1)) ||+              (typeof(vn) == 'string') || (vn == undefined)) {+            curarr.push(args[i]);+              } else if (typeof(vn) == 'object') {+                attribs.push(args[i]);+              }+              else { throw ('createParameterizedTagB: unknown behaviour argument argument ' + i); } //SAFETY+					}+				} else {+					if (args[i] instanceof Array) {+						var arr = args[i];+						for (var j = 0; j < arr.length; j++) { curarr.push(arr[j]); }+					} else {+						var vn = args[i];+						if ( ((typeof(vn) == 'object') && (vn.nodeType == 1)) ||+              (typeof(vn) == 'string') || (vn == undefined)) {+						curarr.push(args[i]);+              } else if (typeof(vn) == 'object') {+                attribs.push(args[i]);+              }+					}+				}+			};+			if(attribs.length > 1) throw ('createParameterizedTagB ' + tagName + ': more than one attribute (' + attribs.length + ')');+			this.attribs = attribs.length > 0 ? attribs[0] : {};+		},+		insertChildrenNodes: function() {+			var ctx = this;++			function quickNode(e) {+        if ((typeof(e) == 'object') && (e.nodeType))+					return e;+        else if ( e == undefined )+					return document.createTextNode('');+        else+          return document.createTextNode(e);+      }++			function unBehaviourize(arr) {+				return map(function(n) {return (n instanceof Behaviour) ? valueNow(n) : n;},arr)+			}++			var lnodes = map(function() {return [];},this.arrs);+			var arrLastVals = map(unBehaviourize,unBehaviourize(this.arrs));++			var arrChangesE = internal_e();+			var nodeChangesE = internal_e();++			function attachNodes(i,arr) {+				for(var j=0;j<arr.length;j++) {+					var cnode = arr[j];+					if(cnode instanceof Behaviour) {+						var newnode = (function(jj) {+                return changes(cnode).lift_e(function(n) {return {index:i,jdex:jj,val:n};});+						})(j);+						lnodes[i].push(newnode);+						attachListener(newnode,nodeChangesE);+						cnode = valueNow(cnode);+					}+				}+			}++			var childChangesE = merge_e(+				// Behaviour arrays change+				arrChangesE.lift_e(function(ai) {+            var i = ai.index;+            var newarr = ai.val;+            while(lnodes[i].length) {+              var ln = lnodes[i].pop();+              removeListener(ln,nodeChangesE);+            }+            var newvals = map(function(n) {return quickNode(n);},unBehaviourize(newarr));+            for(var j=0;j<arrLastVals[i].length;j++)+				try {+					ctx.currentTag.removeChild(arrLastVals[i][j]);+				}+				catch(e) {}+            if(newvals.length) {+              var nextNode = null;+              for(ii = i+1; ii < arrLastVals.length && !(arrLastVals[ii].length) ; ii++);+              if(ii < arrLastVals.length) nextNode = arrLastVals[ii][0];+              for(var j=0; j<newvals.length; j++) ctx.currentTag.insertBefore(newvals[j],nextNode);+            }+            arrLastVals[i] = newvals;+            attachNodes(i,newarr);+            return ctx.currentTag;+				}),+				// Behaviour nodes change+				nodeChangesE.lift_e(function(ni) {+            var i = ni.index;+            var j = ni.jdex;+            var newnode = quickNode(ni.val);+            swapDom(arrLastVals[i][j],newnode);+            arrLastVals[i][j] = newnode;+            return ctx.currentTag;+				}));+			childChangesE.lift_e(function(cc) {sendEvent(ctx.resE,cc);});++			for(var i=0; i<this.arrs.length;i++) {+				for(var j=0; j<arrLastVals[i].length; j++) {+					arrLastVals[i][j] = quickNode(arrLastVals[i][j]);+					this.currentTag.appendChild(arrLastVals[i][j]);+				}+				if(this.arrs[i] instanceof Behaviour) {+					attachNodes(i,valueNow(this.arrs[i]));+					var newnode = (function(ii) {return changes(ctx.arrs[ii]).lift_e(function(na) {return {index:ii,val:na};});})(i);+					attachListener(newnode,arrChangesE);+				}+				else {+					attachNodes(i,this.arrs[i]);+				}+			}+		},+		enstyle: function(obj,vals) {+			//build & record hook if dynamic collection+			if (vals instanceof Behaviour) {+				if (!(typeof(valueNow(vals)) == 'object')) { throw 'enstyle: expected object literal as behaviour value'; } //SAFETY+				this.styleHooks.push(changes(vals));+				attachListener(changes(vals),this.styleChangedE);+			}+			var valsV = vals instanceof Behaviour ? valueNow(vals) : vals;+			if (typeof(valsV) == 'object') {+				for (var i in valsV) {+					if (!(Object.prototype) || !(Object.prototype[i])) {+						this.enstyleProperty(obj,valsV, i);+					}+				}+			}+			else { throw 'enstyle: expected object literals'; } //SAFETY+		},+    enstyleProperty: function (obj, vals, i) {+      if (vals[i] instanceof Behaviour) {+        if (typeof(valueNow(vals[i])) == 'object') {+          this.enstyle(obj[i], vals[i]);+        }+				else {+          obj[i] = valueNow(vals[i]);+					changes(vals[i]).lift_e(function(v) {obj[i] = v;});+				}+			}+			else {+        if (typeof(vals[i]) == 'object') {+          this.enstyle(obj[i], vals[i]);+        } else {+          obj[i] = vals[i];+        }+      }+    }+	};++	d.createParameterizedTagB = function(tagName) {+		return new d.TagB(tagName,slice(arguments,1)).resB;+	};++  d.enstyleStaticProperty = function (obj, props, index) {+    if (typeof(props[index]) == 'object') {+      for (var i in props[index]) {+        if (!(Object.prototype) || !(Object.prototype[i])) {+          d.enstyleStaticProperty(obj[index], props[index], i);+        }+      }+    } else {+      obj[index] = props[index];+			if (index == 'checked')	obj['defaultChecked'] = props[index]; /* TODO: this should maybe be elsewhere? */+			if (index == 'selected') obj['defaultSelected'] = props[index]; /* TODO: this should maybe be elsewhere? */+    }+  };++  d.staticTagMaker = function (tagName) {++    return function () {++      var tagD = document.createElement(tagName);+      if (!(tagD.nodeType > 0)) { throw (tagName + ': invalid tag name'); } //SAFETY++      //partition input++      //          if (arguments[1] === null || arguments[1] === undefined) { arguments[1] = {}; }+      var attribs = [];+      for (var i = 0; i < arguments.length; i++) {+        if (arguments[i] instanceof Array) {+          for (var j = 0; j < arguments[i].length; j++) {+            if (arguments[i][j]) {+              tagD.appendChild(+                (typeof(arguments[i][j]) == 'object' &&+                  arguments[i][j].nodeType > 0)?+                arguments[i][j] :+                document.createTextNode(arguments[i][j]));+            }+          }+        } else if (!arguments[i]) {+          //ignore+        } else if ((typeof(arguments[i]) == 'object') &&+          (arguments[i].nodeType > 0)) {+        tagD.appendChild(arguments[i]);+          } else if (typeof(arguments[i]) == 'object') {+            attribs.push(arguments[i]);+          } else {+            tagD.appendChild(document.createTextNode(arguments[i]));+          }+      }++      if (attribs.length == 1) {+        for (var k in attribs[0]) {+          if (!(Object.prototype) || !(Object.prototype[k])) {+            d.enstyleStaticProperty(tagD, attribs[0], k);+          }+        }+      } else if (attribs.length >  0) {+        throw 'static enstyle: expected object literals'; //SAFETY+      } /* else {+      alert('no attribs on: ' + tagName);+      } */+++      return tagD;+    };+  };++++  var generatedTags =+  [ "a", "b", "blockquote", "br", "button", "canvas", "div", "fieldset",+  "form", "font", "h1", "h2", "h3", "h4", "hr", "img", "iframe", "input",+  "label", "legend", "li", "ol", "optgroup", "option",+  "p", "pre", "select", "span", "strong", "table", "tbody",+  "td", "textarea", "tfoot", "th", "thead", "tr", "tt", "ul" ];++  map(+    function (tagName) {++      var upper = tagName.toUpperCase();++      //d.<TAG>B+      d[upper + 'B'] = function () {+        return d.createParameterizedTagB.apply(this, [tagName].concat(slice(arguments,0)));+      };+			annotate(d[upper+'B'],[upper+'B']);++      //d.<TAG>+      d[upper] = d.staticTagMaker(tagName);  //faster, simple+      /*              function () {+      // 8/16/06 - leo - arguments bug+      // more forgiving: allows reactive children (just doesn't propagate them)+      var args = [b.maybeEmpty].concat(slice(arguments, 0));+      return valueNow(d[upper + 'B'].apply(this, args));+      }; */+			annotate(d[upper],[upper]);+    },+    generatedTags);++  //TEXTB: Behaviour a -> Behaviour Dom TextNode+  d.TEXTB = function (strB) {+    //      if (!(strB instanceof Behaviour || typeof(strB) == 'string')) { throw 'TEXTB: expected Behaviour as second arg'; } //SAFETY+    if (!(strB instanceof Behaviour)) { strB = constant_b(strB); }++    return hold(+      changes(strB).lift_e(+        function (txt) { return document.createTextNode(txt); }),+      document.createTextNode(valueNow(strB)));+  };+	annotate(d.TEXTB,['TEXTB']);++  var TEXT = function (str) {+    return document.createTextNode(str);+  };+  fxExport(dom,TEXT,'TEXT');++  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+  // Reactive DOM++  //tagRec: Array (EventName a) *+  //      ( .Array (Event a) * Array (Event a) -> Behaviour Dom) -> Behaviour Dom+  var tagRec = function (eventNames, maker) {+    if (!(eventNames instanceof Array)) { throw 'tagRec: expected array of event names as first arg'; } //SAFETY+    if (!(maker instanceof Function)) { throw 'tagRec: expected function as second arg'; } //SAFETY++    var numEvents = eventNames.length;+    var internals = [ ];+    var switches = [ ];+    for (var i = 0; i < numEvents; i++) {+      internals[i] = internal_e();+      switches[i] = internals[i].switch_e();+    };++    var domB = maker.apply(this,switches);++    var prevValue;++    var interceptE = createNode([domB.changes()],function (_,p) {+      if (isEqual(p.value,prevValue)) { return; }++      prevValue = p.value;+      for (var i = 0; i < numEvents; i++) {+        sendEvent(internals[i],extractEvent_e(prevValue,eventNames[i]));+      };+    });++    sendEvent(interceptE,domB.valueNow());++    return domB;+  };+  fxExport(dom,tagRec,'tagRec','nodeWithOwnEvents');++  //extractEventStatic_e: Dom * String -> Event+  var extractEventStatic_e = function (domObj, eventName) {+    if (!eventName) { throw 'extractEvent_e : no event name specified'; }+    if (!domObj) { throw 'extractEvent_e : no DOM element specified'; }++    domObj = getObj(domObj);++    var primEventE = internal_e();+    addEvent(domObj,eventName,function(evt) {+       sendEvent(primEventE, evt || window.event);+       // Important for IE; false would prevent things like a checkbox actually+       // checking.+       return true;+    });++    return primEventE;+  };++  //extractEvent_e: [Behaviour] Dom * String -> Event+  var extractEvent_e = function (domB, eventName) {+    if (!(domB instanceof Behaviour)) {+      return extractEventStatic_e(domB,eventName);+    }+    else {+      var domE = domB.changes();++      var eventEE = domE.lift_e(function(dom) {+        return extractEventStatic_e(dom,eventName);+      });++      var resultE = eventEE.switch_e();++      sendEvent(domE,domB.valueNow());++      return resultE;+    };+  };+  fxExport(dom,extractEvent_e,'extractEvent_e','$EVT');++  //extractEvents_e:+  //      [Behaviour] Dom+  //      . Array String+  //      -> Event+  // ex: extractEvents_e(m, 'body', 'mouseover', 'mouseout')+  d.extractEvents_e = function (domObj /* . eventNames */) {+    var eventNames = slice(arguments, 1);++    var events = map(+      function (eventName) {+        return extractEvent_e(domObj, eventName);+      },+      eventNames.length === 0 ? [] : eventNames);++    return merge_e.apply(this, events);+  };+  annotate(d.extractEvents_e,['extractEvents_e'],0,[Behaviour.prototype],['extractEvents_e']);++  //value of dom form object during trigger+  d.extractValueOnEvent_e = function (triggerE, domObj) {+    if (!(triggerE instanceof EventStream)) { throw 'extractValueOnEvent_e: expected Event as first arg'; } //SAFETY++    return changes(d.extractValueOnEvent_b.apply(this, arguments));++  };+  annotate(d.extractValueOnEvent_e,['extractValueOnEvent_e']);++  //extractDomFieldOnEvent_e: Event * Dom U String . Array String -> Event a+  d.extractDomFieldOnEvent_e = function (triggerE, domObj /* . indices */) {+    if (!(triggerE instanceof EventStream)) { throw 'extractDomFieldOnEvent_e: expected Event as first arg'; } //SAFETY+    var indices = slice(arguments, 2);+    var res =+    triggerE.lift_e(+      function () { return getDomVal(domObj, indices); });+    return res;+  };++  d.extractValue_e = function (domObj) {+    return changes(d.extractValue_b.apply(this, arguments));+  };+  annotate(d.extractValue_e,['extractValue_e','$E']);++  //extractValueOnEvent_b: Event * DOM -> Behaviour+  // value of a dom form object, polled during trigger+  d.extractValueOnEvent_b = function (triggerE, domObj) {+    return d.extractValueStatic_b(domObj, triggerE);+  };+  annotate(d.extractValueOnEvent_b,['extractValueOnEvent_b']);++  //extractValueStatic_b: DOM [ * Event ] -> Behaviour a+  //If no trigger for extraction is specified, guess one+  d.extractValueStatic_b = function (domObj, triggerE) {++    var objD;+    try {+      objD = getObj(domObj);+	    //This is for IE+	    if(typeof(domObj) == 'string' && objD.id != domObj) {+	    	throw 'Make a radio group';+	    }+    } catch (e) {+      objD = {type: 'radio-group', name: domObj};+    }++    var getter; // get value at any current point in time+++    switch (objD.type)  {++      //TODO: checkbox.value instead of status?+    case 'checkbox':++      return hold(+        filterRepeats_e(+          d.extractDomFieldOnEvent_e(+            triggerE ? triggerE :+            d.extractEvents_e(+              objD,+              'click', 'keyup', 'change'),+            objD,+            'checked'),objD.checked),+        objD.checked);++      case 'select-one':++        getter = function (_) {+          return objD.selectedIndex > -1 ?+          (objD.options[objD.selectedIndex].value ?+            objD.options[objD.selectedIndex].value :+            objD.options[objD.selectedIndex].innerText)+			    : undefined;+        };++        return hold(+          filterRepeats_e(+              (triggerE ? triggerE :+              d.extractEvents_e(+                objD,+                'click', 'keyup', 'change')).lift_e(getter)),getter(),+          getter());++        case 'select-multiple':+          //TODO ryan's cfilter adapted for equality check++          getter = function (_) {+            var res = [];+            for (var i = 0; i < objD.options.length; i++) {+              if (objD.options[i].selected) {+                res.push(objD.options[i].value ? objD.options[i].value : objD.options[i].innerText);+              }+            }+            return res;+          };+++          return hold(+              (triggerE ? triggerE :+              d.extractEvents_e(+                objD,+                'click', 'keyup', 'change')).lift_e(getter),+            getter());++          case 'text':+          case 'textarea':+          case 'hidden':+          case 'password':++            return hold(+              filterRepeats_e(+                d.extractDomFieldOnEvent_e(+                  triggerE ? triggerE :+                  d.extractEvents_e(+                    objD,+                    'click', 'keyup', 'change'),+                  objD,+                  'value'),objD.value),+              objD.value);++            case 'button': //same as above, but don't filter repeats++              return hold(+                d.extractDomFieldOnEvent_e(+                  triggerE ? triggerE :+                  d.extractEvents_e(+                    objD,+                    'click', 'keyup', 'change'),+                  objD,+                  'value'),+                objD.value);+++              case 'radio':+              case 'radio-group':++                //TODO returns value of selected button, but if none specified,+                //      returns 'on', which is ambiguous. could return index,+                //      but that is probably more annoying++                var radiosAD = filter(+                  function (elt) {+                    return (elt.type == 'radio') &&+                    (elt.getAttribute('name') == objD.name);+                  },+                  document.getElementsByTagName('input'));++                getter =+                objD.type == 'radio' ?++                function (_) {+                  return objD.checked;+                } :++                function (_) {+                  for (var i = 0; i < radiosAD.length; i++) {+                    if (radiosAD[i].checked) {+                      return radiosAD[i].value;+                    }+                  }+                  return undefined; //TODO throw exn?+                };++                var actualTriggerE = triggerE ? triggerE :+                merge_e.apply(+                  this,+                  map(+                    function (radio) {+                      return d.extractEvents_e(+                        radio,+                    'click', 'keyup', 'change'); },+                      radiosAD));++                return hold(+                  filterRepeats_e(+                      actualTriggerE.lift_e(getter),getter()),+                  getter());++                default:++                  throw ('extractValueStatic_b: unknown value type "' + objD.type + '"');+    }+  };++  d.extractValue_b = function (domObj) {+    if (domObj instanceof Behaviour) {+      return lift_b(function (dom) { return d.extractValueStatic_b(dom); },+                    domObj)+             .switch_b();+    } else {+      return d.extractValueStatic_b(domObj);+    }+  };+	annotate(d.extractValue_b,['extractValue_b','$B'],0,[Behaviour.prototype],['extractValue_b','$B']);++  //into[index] = deepValueNow(from) via descending from object and mutating each field+  d.deepStaticUpdate = function (into, from, index) {+    var fV = (from instanceof Behaviour)? valueNow(from) : from;+    if (typeof(fV) == 'object') {+      for (var i in fV) {+        if (!(Object.prototype) || !(Object.prototype[i])) {+          d.deepStaticUpdate(index? into[index] : into, fV[i], i);+        }+      }+    } else {+      var old = into[index];+      into[index] = fV;+    }+  };++  //note: no object may be time varying, just the fields+  //into[index] = from+  //only updates on changes+  d.deepDynamicUpdate = function (into, from, index) {+    var fV = (from instanceof Behaviour)? valueNow(from) : from;+    if (typeof(fV) == 'object') {+      if (from instanceof Behaviour) {+        throw 'deepDynamicUpdate: dynamic collections not supported';+      }+      for (var i in fV) {+        if (!(Object.prototype) || !(Object.prototype[i])) {+          d.deepDynamicUpdate(index? into[index] : into, fV[i], i);+        }+      }+    } else {+      if (from instanceof Behaviour) {+        createNode(+          [changes(from)],+          function (s, p) {+            if (index) {+              var old = into[index];+              into[index] = p.value;+            }+            else { into = p.value; } //TODO notify topE?+          });+      }+    }+  };+++  d.insertValue = function (val, domObj /* . indices */) {+    var indices = slice(arguments, 2);+    var parent = getMostDom(domObj, indices);+    d.deepStaticUpdate(parent, val, indices ? indices[indices.length - 1] : undefined);+  };+  annotate(d.insertValue,['insertValue']);++  //TODO convenience method (default to firstChild nodeValue)+  d.insertValueE = function (triggerE, domObj /* . indices */) {+    if (!(triggerE instanceof EventStream)) { throw 'insertValueE: expected Event as first arg'; } //SAFETY++    var indices = slice(arguments, 2);+    var parent = getMostDom(domObj, indices);++      triggerE.lift_e(function (v) {+        d.deepStaticUpdate(parent, v, indices? indices[indices.length - 1] : undefined);+      });+  };+  annotate(d.insertValueE,['insertValueE'],0,[EventStream.prototype],['insertValueE']);++  //insertValueB: Behaviour * domeNode . Array (id) -> void+  //TODO notify adapter of initial state change?+  d.insertValueB = function (triggerB, domObj /* . indices */) {++    var indices = slice(arguments, 2);+    var parent = getMostDom(domObj, indices);+++    //NOW+    d.deepStaticUpdate(parent, triggerB, indices ? indices[indices.length - 1] : undefined);++    //LATER+    d.deepDynamicUpdate(parent, triggerB, indices? indices[indices.length -1] : undefined);++  };+  annotate(d.insertValueB,['insertValueB'],0,[Behaviour.prototype],['insertValueB']);++  //TODO copy dom event call backs of original to new? i don't thinks so+  //  complication though: registration of call backs should be scoped+  d.insertDomE = function (triggerE, domObj) {++    if (!(triggerE instanceof EventStream)) { throw 'insertDomE: expected Event as first arg'; } //SAFETY++    var objD = getObj(domObj);++    var res = triggerE.lift_e(+      function (newObj) {+        //TODO safer check+        if (!((typeof(newObj) == 'object') && (newObj.nodeType == 1))) {+          newObj = d.SPAN({}, newObj);+        }+        swapDom(objD, newObj);+        objD = newObj;+        return newObj; // newObj;+      });++    return res;+  };+  annotate(d.insertDomE,['insertDomE'],0,[EventStream.prototype],['insertDomE']);++  //insertDom: dom+  //          * dom+  //          [* (null | undefined | 'over' | 'before' | 'after' | 'leftMost' | 'rightMost' | 'beginning' | 'end']+  //          -> void+  // TODO: for consistency, switch replaceWithD, hookD argument order+  d.insertDom = function (hookD, replaceWithD, optPosition) {+    switch (optPosition)+    {+    case undefined:+    case null:+    case 'over':+      swapDom(hookD,replaceWithD);+      break;+    case 'before':+      hookD.parentNode.insertBefore(replaceWithD, hookD);+      break;+    case 'after':+      if (hookD.nextSibling) {+        hookD.parentNode.insertBefore(replaceWithD, hookD.nextSibling);+      } else {+        hookD.parentNode.appendChild(replaceWithD);+      }+      break;+    case 'leftMost':+      if (hookD.parentNode.firstChild) {+        hookD.parentNode.insertBefore(+          replaceWithD,+          hookD.parentNode.firstChild);+                } else { hookD.parentNode.appendChild(replaceWithD); }+                break;+              case 'rightMost':+                hookD.parentNode.appendChild(replaceWithD);+                break;+              case 'beginning':+                if (hookD.firstChild) {+                  hookD.insertBefore(+                    replaceWithD,+                    hookD.firstChild);+                } else { hookD.appendChild(replaceWithD); }+                break;+              case 'end':+                hookD.appendChild(replaceWithD);+                break;+              default:+                throw ('domInsert: unknown position: ' + optPosition);+    }+  };++  //insertDom: dom+  //          * dom U String domID+  //          [* (null | undefined | 'over' | 'before' | 'after' | 'leftMost' | 'rightMost' | 'beginning' | 'end']+  //          -> void+  d.insertDomClean = function (replaceWithD, hook, optPosition) {+    //TODO span of textnode instead of textnode?+    d.insertDom(+	    getObj(hook),+	    ((typeof(replaceWithD) == 'object') && (replaceWithD.nodeType > 0)) ? replaceWithD :+      document.createTextNode(replaceWithD),+	    optPosition);+  };+  annotate(d.insertDomClean,['insertDom']);++  //TODO test+  //insertDomB:+  //      [Behaviour] String U Dom+  //      [* ( id U null U undefined )+  //          [* ('before' U 'after' U 'leftMost' U 'rightMost' U 'over' U 'beginning' U 'end')]]+  //      -> Behaviour a+  //if optID not specified, id must be set in init val of trigger+  //if position is not specified, default to 'over'+  //performs initial swap onload+  d.insertDomB = function (initTriggerB, optID, optPosition) {++    if (!(initTriggerB instanceof Behaviour)) {+      initTriggerB = constant_b(initTriggerB);+    }++    var triggerB =+    lift_b(+      function (d) {+        if ((typeof(d) == 'object') && (d.nodeType >  0)) {+          return d;+        } else {+          var res = document.createElement('span'); //TODO createText instead+          res.appendChild(document.createTextNode(d));+          return res;+        }+      },+      initTriggerB);++    var initD = valueNow(triggerB);+    if (!((typeof(initD) == 'object') && (initD.nodeType == 1))) { throw ('insertDomB: initial value conversion failed: ' + initD); } //SAFETY++    d.insertDom(+      optID === null || optID === undefined ? getObj(initD.getAttribute('id')) : getObj(optID),+      initD,+      optPosition);++    var resB = hold(+      d.insertDomE(+        changes(triggerB),+        initD),+      initD);++    return resB;+  };+  annotate(d.insertDomB,['insertDomB'],0,[Behaviour.prototype],['insertDomB']);+++  d.extractId_b = function (id, start)+  {+    return hold(+      createNode( start instanceof Behaviour? [changes(start)] :+        [],+        function (s, p) {+          p.value = getObj(id);+          s(p);+        }),+      getObj(id));+  };+  annotate(d.insertDomB,['extractId_b'],1,[Behaviour.prototype],['extractId_b']);++  var mouse_e = function(elem) {+    return extractEvent_e(elem,'mousemove')+    .lift_e(function(evt) {+        if (evt.pageX | evt.pageY) {+          return { left: evt.pageX, top: evt.pageY };+        }+        else if (evt.clientX || evt.clientY) {+          return { left : evt.clientX + document.body.scrollLeft,+                   top: evt.clientY + document.body.scrollTop };+        }+        else {+          return { left: 0, top: 0 };+        }+    });+  };++  var mouse_b = function(elem) {+    return mouse_e(elem).hold({ left: 0, top: 0 });+  }+  fxExport(dom,mouse_b,'mouse_b');++  var mouseLeft_b = function(elem) {+    return lift_b(function(v) { return v.left; },mouse_b(elem));+  };+  fxExport(dom,mouseLeft_b,'mouseLeft_b');++  var mouseTop_b = function(elem) {+    return mouse_b(elem).lift_b(function(v) { return v.top; });+  };++  fxExport(dom,mouseTop_b,'mouseTop_b');++  var clicks_e = function(elem) {+    return extractEvent_e(elem,'click');+  };+  fxExport(dom,clicks_e,'clicks_e');++  //////////////////////////////////////////////////////////////////////////////+  // Combinators for web services+++	//credit Matt White+	var getURLParam = function (param) {+    var lparam = param.toLowerCase();+    var aReturn = [];+    var strHref = window.location.href;+    var endstr = (strHref.indexOf('#') > -1) ? strHref.indexOf('#') : strHref.length;+    if ( strHref.indexOf("?") > -1 ) {+      var strQueryString = strHref.substring(strHref.indexOf("?")+1,endstr);+      map(function(qp) {+          var eq = qp.indexOf('=');+          var qname = qp.substr(0,eq+1).toLowerCase();+          if(qname == lparam+"=") aReturn.push(decodeURIComponent(qp.substr(eq+1)));+      },strQueryString.split("&"));+    }+    if (aReturn.length == 0) return undefined;+    else if(aReturn.length == 1) return aReturn[0];+    else return aReturn;+	};+  fxExport(domMisc,getURLParam,'getURLParam','$URL');++	//credit Quirksmode+	//readCookie: String -> String U Undefined+	var readCookie = function (name) {+    var nameEQ = name + "=";+    var ca = document.cookie.split(';');+    for (var i=0; i < ca.length; i++) {+      var co = ca[i];+      while (co.charAt(0) == ' ') { co = co.substring(1, co.length); }+      if (co.indexOf(nameEQ) === 0) {+        return co.substring(nameEQ.length, co.length);+      }+    }+    return undefined;+	};+  fxExport(domMisc,readCookie,'readCookie');++  //========== dynamic scripts ==========+  var scriptCounter = 0;+  var deleteScript = function (scriptID) {+    var scriptD = getObj(scriptID);+    scriptD.parentNode.removeChild(scriptD); //TODO isolate child and set innerHTML to "" to avoid psuedo-leaks?+  };++  // optional fn/param that gets polled until parm is defined+  var runScript = function (url, fn, param) {+    var script = document.createElement("script");+    script.src = url;+    var scriptID = 'scriptFnRPC' + scriptCounter++;+    script.setAttribute('id', scriptID);+    document.getElementsByTagName("head").item(0).appendChild(script);+    var timer = {};+    var check =+    function () {+      eval("try { if (" + param + "!== undefined) {var stat = " + param + ";}} catch (e) {}");+      if (stat !== undefined) {+        eval(param + " = undefined;");+        clearInterval(timer.timer);+        clearInterval(timer.timeout);+        if (fn instanceof Function) {+          fn(stat);+        }+        deleteScript(scriptID);+      }+    };+    timer.timer = setInterval(check, 3500);+    timer.timeout =+    setTimeout(+      function () {+        try { clearInterval(timer.timer); }+        catch (e) {}+      },+      5000); //TODO make parameter?+  };++  // Node {url, globalArg} -> Node a+  //load script @ url and poll until param is set, then pass it along+  var evalForeignScriptVal_e = function(urlArg_e) {+    var result = receiver_e();+    urlArg_e.lift_e(function(urlArg) {+        runScript(urlArg.url,+          function(val) { result.sendEvent(val); },+          urlArg.globalArg);+    });++    return result;+  };+  fxExport(ws,evalForeignScriptVal_e,'evalForeignScriptVal_e');++  var ajaxRequest = function(method,url,body,async,useFlash,callback) {+    var xhr;+    if (useFlash) {+      xhr = new FlashXMLHttpRequest();+      xhr.onload = function() { callback(xhr); };+    }+    else if (window.XMLHttpRequest && !(window.ActiveXObject)) {+      xhr = new window.XMLHttpRequest();+      xhr.onload = function() { callback(xhr); };+    }+    else if (window.ActiveXObject) {+      try { xhr = new ActiveXObject("Msxml2.XMLHTTP"); }+      catch(e) { xhr = new ActiveXObject("Microsoft.XMLHTTP"); }++      xhr.onreadystatechange = function() {+        if (xhr.readyState == 4) { callback(xhr); }+      };+    };++    xhr.open(method,url,async);++    if (method == 'POST') {+      xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');+    }++    xhr.send(body);+    return xhr;+  };++  var encodeREST = function(obj) {+    var str = "";+    for (var field in obj) {+      if (typeof(obj[field]) !== 'function') { // skips functions in the object+        if (str != '') { str += '&'; }+        str += field + '=' + encodeURIComponent(obj[field]);+      }+    }+    return str;+  };++  // From json.org+  var parseJSON = function(str) {+    try {+        return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(+                str.replace(/"(\\.|[^"\\])*"/g, ''))) &&+            eval('(' + str + ')');+    } catch (e) {+        throw 'cannot parse JSON string: ' + e;+    }+  };++  var toJSONString = (function() {+    var m = {+            '\b': '\\b',+            '\t': '\\t',+            '\n': '\\n',+            '\f': '\\f',+            '\r': '\\r',+            '"' : '\\"',+            '\\': '\\\\'+        };+    var s = {+      array: function (x) {+        var a = ['['], b, f, i, l = x.length, v;+        for (i = 0; i < l; i += 1) {+          v = x[i];+          f = s[typeof v];+          if (f) {+            v = f(v);+            if (typeof v == 'string') {+              if (b) {+                a[a.length] = ',';+              }+              a[a.length] = v;+              b = true;+            }+          }+        }+        a[a.length] = ']';+        return a.join('');+      },+      'boolean': function (x) {+        return String(x);+      },+      'null': function (x) {+        return "null";+      },+      number: function (x) {+        return isFinite(x) ? String(x) : 'null';+      },+      object: function (x) {+        if (x) {+          if (x instanceof Array) {+            return s.array(x);+          }+          var a = ['{'], b, f, i, v;+          for (i in x) {+            v = x[i];+            f = s[typeof v];+            if (f) {+              v = f(v);+              if (typeof v == 'string') {+                if (b) {+                  a[a.length] = ',';+                }+                a.push(s.string(i), ':', v);+                b = true;+              }+            }+          }+          a[a.length] = '}';+          return a.join('');+        }+        return 'null';+      },+      string: function (x) {+        if (/["\\\x00-\x1f]/.test(x)) {+          x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {+              var c = m[b];+              if (c) {+                return c;+              }+              c = b.charCodeAt();+              return '\\u00' ++              Math.floor(c / 16).toString(16) ++              (c % 16).toString(16);+          });+        }+        return '"' + x + '"';+      }+    };+    return function(val) {+      var f = s[typeof val];+      if (f) { return f(val); }+      else { throw 'parseJSON: unknown object type: ' + (typeof val); }+    };+  })();++  var serverRequest_e = function(useFlash,requestE) {+    var response_e = receiver_e();++    requestE.lift_e(function (obj) {+        var body = '';+        var method = 'GET';+        var url = obj.url;++        var reqType = obj.request ? obj.request : (obj.fields ? 'post' : 'get');+        if (obj.request == 'get') {+          url += "?" + encodeREST(obj.fields);+          body = '';+          method = 'GET';+        } else if (obj.request == 'post') {+          body = toJSONString(obj.fields);+          method = 'POST';+        } else if (obj.request == 'rawPost') {+          body = obj.body;+          method = 'POST';+        }+        else if (obj.request == 'rest') {+          body = encodeREST(obj.fields);+          method = 'POST';+        }+        else {+          raise ("Invalid request type: " + obj.request);+        }++        var async = obj.async;++        var xhr;++        // Branch on the response type to determine how to parse it+        if (obj.response == 'json') {+          xhr = ajaxRequest(method,url,body,async,useFlash,+            function(xhr) {+              response_e.sendEvent(parseJSON(xhr.responseText));+            });+        }+        else if (obj.response == 'xml') {+          ajaxRequest(method,url,body,async,useFlash,+            function(xhr) {+              response_e.sendEvent(xhr.responseXML);+            });+        }+        else if (obj.response == 'plain' || !obj.response) {+          ajaxRequest(method,url,body,async,useFlash,+            function(xhr) {+              response_e.sendEvent(xhr.responseText);+          });+        }+        else {+          raise('Unknown response format: ' + obj.response);+        }+    });++    return response_e;+  };++  var getWebServiceObject_e = function(requestE) {+    return serverRequest_e(false,requestE);+  };+  fxExport(ws,getWebServiceObject_e,'getWebServiceObject_e');++  var getForeignWebServiceObject_e = function(requestE) {+    return serverRequest_e(true,requestE);+  };+  fxExport(ws,getForeignWebServiceObject_e,'getForeignWebServiceObject_e');++  var cumulativeOffset = function(element) {+    var valueT = 0, valueL = 0;+    do {+      valueT += element.offsetTop  || 0;+      valueL += element.offsetLeft || 0;+      element = element.offsetParent;+    } while (element);+    return { left: valueL, top: valueT };+ };+fxExport(domMisc,cumulativeOffset,'cumulativeOffset');++  ///////// OPTIONALLY EXPORT PUBLIC FUNCTIONS TO GLOBAL NAMESPACE+  if (!options.hideAll) {+    for (var zz in flapjax.pub) {+      if (!options[zz]) {+        window[zz] = flapjax.pub[zz]; // use eval instead so as to achieve Flash compatibility+      }+    }+  }++  for (var id in exports) {+    if (window[id]) {+      if (options.redefine === false) {+        warn('window.' + id + ' is already defined; Flapjax will not ' ++             'redefine it.');+      }+      else {+        warn('Flapjax is redefining window.' + id + '.');+      }+    }++    if (window[id] && options.redefine === false) {+      // Don't redefine id+    }+    else if (options.show && options.hide && options.show[id] === true &&+        options.hide[id] === true) {+      throw('flapjaxInit: invalid options: ' + id + " specified as 'show' and 'hide'");+    }+    else if (options.show && options.show[id]) {+      window[id] = exports[id];+    }+    else if (options.hide && options.hide[id]) {+      // do nothing -- don't export+    }+    // Default behavior--check if it is a synonym first ...+    else if (!synonyms[id] || options.includeSynonyms) {+      // ... then export if its of the right category+      if (options.exportMisc && exports[id].__flapjaxCategory === misc) {+        window[id] = exports[id];+      }+      else if (options.exportDOMMisc && exports[id].__flapjaxCategory === domMisc) {+        window[id] = exports[id];+      }+      else if (options.exportDOM && exports[id].__flapjaxCategory === dom) {+        window[id] = exports[id];+      }+      else if (options.exportCore && exports[id].__flapjaxCategory === core) {+        window[id] = exports[id];+      }+      else if (options.exportWS && exports[id].__flapjaxCategory === ws) {+        window[id] = exports[id];+      }+    }+  }++  return exports;+}
+ test/parse-pretty/neg.js view
@@ -0,0 +1,2 @@+var foo = -x;+var bar = +y;
+ test/parse-pretty/numbers.js view
@@ -0,0 +1,2 @@+var x = 23;+var y = 23.0;
+ test/parse-pretty/object-lit-1.js view
@@ -0,0 +1,4 @@+var x = {  // avoid ambiguity with BlockStmt+  foo : 23, +  bar : 50 +}
+ test/parse-pretty/object-lit-2.js view
@@ -0,0 +1,4 @@+var x = {  // avoid ambiguity with BlockStmt+  foo : 23, +  bar : 50, +} 
+ test/parse-pretty/prefix-chain.js view
@@ -0,0 +1,4 @@+var w = typeof typeof 34;+var x = ! -- x; // derived from jQuery+var y = ! !x; // derived from Prototype+var z = !! -- x;
+ test/parse-pretty/strings.js view
@@ -0,0 +1,6 @@+var x = '\b';+var z = {+  '\b': '\\b' // lhs is a PropString, not a StringLit, but must be printed+              //  as a StringLit+};+var w = "\\s";
− tests/parse-pretty/add.js
@@ -1,1 +0,0 @@-1+2;;;;
− tests/parse-pretty/do-while.js
@@ -1,3 +0,0 @@-do {-  x = y;-} while (element);
− tests/parse-pretty/flapjax-fxinternal-22dec2008.js
@@ -1,2552 +0,0 @@-function flapjaxInit(options) {-  // compress via http://alex.dojotoolkit.org/shrinksafe/-  // make sure to change final eval call to use exported library renamed-  // name--  var defaultOptions = {-    includeSynonyms: true,-    exportMisc: true,-    exportCore: true,-    exportDOM: true,-    exportDOMMisc: true,-    exportWS: true,-    hide: [ ],-    show: [ ],-    redefine: false-  };--  if (options === false) {-    options = { hide: [ ], show: [ ] };-  }-  else if (options === true || !options) {-    options = { };-  }--  // Fill in any missing options using the defaults.-  for (var option in defaultOptions) {-    if (options[option] === undefined) {-      options[option] = defaultOptions[option];-    }-  };--  // Transform hide and show lists into tables-  var hideArray = options.hide;-  options.hide = { };-  for (var i = 0; i < hideArray.length; i++) {-    options.hide[hideArray[i]] = true;-  }-  var showArray = options.show;-  options.show = { };-  for (var i = 0; i < showArray.length; i++) {-    options.show[showArray[i]] = true;-  }--  var warn = function(s) {-    /*if (console && console.warn) {-      console.warn(s);-    }*/-  };---  var flapjax = {-    version: 4,-    base: {}, //pulses-    combinators: {}, // combinators yielding nodes-	  behaviours: {},-    dom: {} // dom convenience methods and combinators-  };--  var d = flapjax.dom;--	flapjax.pub = {util:flapjax};--	var annotate = function(fn,names,protoArg,protoObjs,protoNames) {-		for(var i=0; i<names.length;i++) {-			flapjax.pub[names[i]] = fn;-		}-		if(protoArg != undefined) {-			var pf = function() {-				var args = slice(arguments,0);-				args.splice(protoArg,0,this);-				return fn.apply(this,args);-			};-			for(var i=0; i<protoObjs.length; i++) {-				for(var j=0; j<protoNames.length;j++) {-					protoObjs[i][protoNames[j]] = pf;-				}-			}-		}-	};--  var exports = { };-  var synonyms = { };--  var misc = { }; /* Used as a symbol */-  var core = { }; /* Used as a symbol */-  var dom = { }; /* Used as a symbol */-  var domMisc = { }; /* Used as a symbol */-  var ws = { }; /* Used as a symbol */--  var fxExport = function(exportCategory,exportVal,-                          exportName /* , synonyms */) {-    if (!(exportCategory instanceof Object)) {-      throw 'fxExport: category is ' + exportCategory;-    };--    if (typeof(exportName) != 'string') {-      console.log(exportVal);-      throw 'fxExport: name is ' + exportName;-    };--    exportVal.__flapjaxCategory = exportCategory;-    exports[exportName] = exportVal;-    for (var i = 3; i < arguments.length; i++) {-      exports[arguments[i]] = exportVal;-      synonyms[arguments[i]] = true;-    }-  };--  var fxMethodSynonyms = function(obj,method) {-    if (options.includeSynonyms === true) {-      for (var i = 2; i < arguments.length; i++) {-        obj.prototype[arguments[i]] = obj.prototype[method];-      };-    };-  };--  //////////////////////////////////////////////////////////////////////////////-  // Miscellaneous functions--	//credit 4umi-	//slice: Array a * Integer * Integer -> Array a-	var slice = function (arr, start, stop) {-		var i, len = arr.length, r = [];-		if( !stop ) { stop = len; }-		if( stop < 0 ) { stop = len + stop; }-		if( start < 0 ) { start = len - start; }-		if( stop < start ) { i = start; start = stop; stop = i; }-		for( i = 0; i < stop - start; i++ ) { r[i] = arr[start+i]; }-		return r;-	}--	var isEqual = function (a,b) {-		return (a == b) ||-			( (((typeof(a) == 'number') && isNaN(a)) || a == 'NaN') &&-			  (((typeof(b) == 'number') && isNaN(b)) || b == 'NaN') );-	};--	//member: a * Array b -> Boolean-	var member = function(elt, lst) {-		for (var i = 0; i < lst.length; i++) {-			if (isEqual(lst[i], elt)) {return true;}-		}-		return false;-	};--	var zip = function(arrays) {-		if (arrays.length == 0) return [];-		var ret = [];-		for(var i=0; i<arrays[0].length;i++) {-			ret.push([]);-			for(var j=0; j<arrays.length;j++)-				ret[i].push(arrays[j][i]);-		}-		return ret;-	};--	//map: (a * ... -> z) * [a] * ... -> [z]-	var map = function (fn) {-		var arrays = slice(arguments, 1);-		if (arrays.length === 0) { return []; }-		else if (arrays.length === 1) {-			var ret = [];-			for(var i=0; i<arrays[0].length; i++) {ret.push(fn(arrays[0][i]));}-			return ret;-		}-		else {-			var ret = zip(arrays);-			var o = new Object();-			for(var i=0; i<ret.length; i++) {ret[i] = fn.apply(o,ret[i]);}-			return ret;-		}-	};--	//filter: (a -> Boolean) * Array a -> Array a-	var filter = function (predFn, arr) {-		var res = [];-		for (var i = 0; i < arr.length; i++) {-			if (predFn(arr[i])) { res.push(arr[i]); }-		}-		return res;-	};--  //fold: (a * .... * accum -> accum) * accum * [a] * ... -> accum-  //fold over list(s), left to right-  var fold = function(fn, init /* arrays */) {-		var lists = slice(arguments, 2);-		if (lists.length === 0) { return init; }-		else if(lists.length === 1) {-			var acc = init;-			for(var i = 0; i < lists[0].length; i++) {-				acc = fn(lists[0][i],acc);-			}-			return acc;-		}-		else {-			var acc = init;-			for (var i = 0; i < lists[0].length; i++) {-				var args = map( function (lst) { return lst[i];},-		          lists);-				args.push(acc);-				acc = fn.apply({}, args);-			}-			return acc;-		}-  };--  //foldR: (a * .... * accum -> accum) * accum * [a] * ... -> accum-	//fold over list(s), right to left, fold more memory efficient (left to right)-	var foldR = function (fn, init /* arrays */) {-    var lists = slice(arguments, 2);-		if (lists.length === 0) { return init; }-		else if(lists.length === 1) {-			var acc = init;-			for(var i=lists[0].length - 1; i > -1; i--)-				acc = fn(lists[0][i],acc);-			return acc;-		}-		else {-			var acc = init;-			for (var i = lists[0].length - 1; i > -1; i--) {-				var args = map( function (lst) { return lst[i];},-		          lists);-				args.push(acc);-				acc = fn.apply({}, args);-			}-			return acc;-		}-	};--  var pushAll = function(destArray,srcArray) {-    for (var i = 0; i < srcArray.length; i++) {-      destArray.push(srcArray[i]);-    }-    return destArray;-  };--  fxExport(misc,slice,'slice');-  fxExport(misc,member,'member');-  fxExport(misc,map,'map');-  fxExport(misc,map,'forEach');-  fxExport(misc,filter,'filter');-  fxExport(misc,fold,'fold');-  fxExport(misc,foldR,'foldR');--  //////////////////////////////////////////////////////////////////////////////-  // Flapjax core--  //Pulse: Stamp * Path * Obj-  var Pulse = function (stamp, value) {-    this.stamp = stamp;-    this.value = value;-  };---  //Probably can optimize as we expect increasing insert runs etc-  var PQ = function () {-    var ctx = this;-    ctx.val = [];-    this.insert = function (kv) {-			ctx.val.push(kv);-			var kvpos = ctx.val.length-1;-			while(kvpos > 0 && kv.k < ctx.val[Math.floor((kvpos-1)/2)].k) {-				var oldpos = kvpos;-				kvpos = Math.floor((kvpos-1)/2);-				ctx.val[oldpos] = ctx.val[kvpos];-				ctx.val[kvpos] = kv;-			}-    };-    this.isEmpty = function () {-      return ctx.val.length === 0;-    };-    this.pop = function () {-			if(ctx.val.length == 1) {-				return ctx.val.pop();-			}-			var ret = ctx.val.shift();-			ctx.val.unshift(ctx.val.pop());-			var kvpos = 0;-			var kv = ctx.val[0];-			while(1) {-				var leftChild = (kvpos*2+1 < ctx.val.length ? ctx.val[kvpos*2+1].k : kv.k+1);-				var rightChild = (kvpos*2+2 < ctx.val.length ? ctx.val[kvpos*2+2].k : kv.k+1);-				if(leftChild > kv.k && rightChild > kv.k)-					break;-				else if(leftChild < rightChild) {-					ctx.val[kvpos] = ctx.val[kvpos*2+1];-					ctx.val[kvpos*2+1] = kv;-					kvpos = kvpos*2+1;-				}-				else {-					ctx.val[kvpos] = ctx.val[kvpos*2+2];-					ctx.val[kvpos*2+2] = kv;-					kvpos = kvpos*2+2;-				}-			}-			return ret;-		};-  };--  var lastRank = 0;-  var stamp = 1;-  var nextStamp = function () { return ++stamp; };--  //propagatePulse: Pulse * Array Node ->-  //Send the pulse to each node-  var propagatePulse = function (pulse, node) {-    var queue = new PQ(); //topological queue for current timestep-	queue.insert({k:node.rank,n:node,v:pulse});-	while(!(queue.isEmpty())) {-		var qv = queue.pop();-		qv.n.updater(function(nextPulse) {-			for(var i=0; i<qv.n.sendsTo.length;i++)-				queue.insert({k:qv.n.sendsTo[i].rank,n:qv.n.sendsTo[i],v:nextPulse});-		},new Pulse(qv.v.stamp,qv.v.value));-	}-  };--  //Event: Array Node b * ( (Pulse a -> Void) * Pulse b -> Void)-  var EventStream = function (nodes,updater) {-    this.updater = updater;--    this.sendsTo = []; //forward link--    for (var i = 0; i < nodes.length; i++) {-      nodes[i].sendsTo.push(this);-    }--    this.rank = ++lastRank;-  };-	EventStream.prototype = new Object();--  fxExport(core,EventStream,'EventStream');---  //createNode: Array Node a * ( (Pulse b ->) * (Pulse a) -> Void) -> Node b-  var createNode = function (nodes, updater) {-		return new EventStream(nodes,updater);-	};--  //attachListenerNode: Node * Node -> Voids-  //flow from node to dependent-  //note: does not add flow as counting for rank nor updates parent ranks-  var attachListener = function (node, dependent) {-    if (!(node instanceof EventStream)) { throw 'attachListenenerNode: expects event as first arg';} //SAFETY-    if (!(dependent instanceof EventStream)) { throw 'attachListenenerNode: expects event as second arg';} //SAFETY--    node.sendsTo.push(dependent);-		if(node.rank > dependent.rank) {-			var lowest = lastRank+1;-			var q = [dependent];-			while(q.length) {-				var cur = q.splice(0,1)[0];-				cur.rank = ++lastRank;-				q = q.concat(cur.sendsTo);-			}-		}-  };--  //removeListenerNode: Node * Node -> Boolean-  //remove flow from node to dependent-  //note: does not remove flow as counting for rank nor updates parent ranks-  var removeListener = function (node, dependent)-  {-    if (!(node instanceof EventStream)) { throw 'removeListenerNode: expects event as first arg';} //SAFETY-    if (!(dependent instanceof EventStream)) { throw 'removeListenenerNode: expects event as second arg';} //SAFETY--    var foundSending = false;-    for (var i = 0; i < node.sendsTo.length && !foundSending; i++) {-      if (node.sendsTo[i] == dependent) {-        node.sendsTo.splice(i, 1);-        foundSending = true;-      }-    }--    return foundSending;-  };--  // An internal_e is a node that simply propagates all pulses it receives.  It's used internally by various-  // combinators.-  var internal_e = function(dependsOn) {-    return createNode(dependsOn || [ ],function(send,pulse) { send(pulse); });-  }--  var zero_e = function() {-    return createNode([],function(send,pulse) {-        throw ('zero_e : received a value; zero_e should not receive a value; the value was ' + pulse.value);-    });-  };-  fxExport(core,zero_e,'zero_e');--  var one_e = function(val) {-    var sent = false;-    var evt = createNode([],function(send,pulse) {-      if (sent) {-        throw ('one_e : received an extra value');-      }-      sent = true;-      send(pulse);-    });-    window.setTimeout(function() { sendEvent(evt,val); },0);-    return evt;-  };-  fxExport(core,one_e,'one_e');--  // a.k.a. mplus; merge_e(e1,e2) == merge_e(e2,e1)-  var merge_e = function() {-    if (arguments.length == 0) {-      return zero_e();-    }-    else {-      var deps = slice(arguments,0);-      return internal_e(deps);-    }-  };-  fxExport(core,merge_e,'merge_e');--  EventStream.prototype.merge_e = function() {-    var deps = slice(arguments,0);-    deps.push(this);-    return internal_e(deps);-  };-  fxMethodSynonyms(EventStream,'merge_e','merge');--  EventStream.prototype.constant_e = function(constantValue) {-    return createNode([this],function(send,pulse) {-      pulse.value = constantValue;-      send(pulse);-    });-  };-  fxMethodSynonyms(EventStream,'constant_e','constant','replaceValue_e','replaceValue');--  var constant_e = function(e) { return e.constant_e(); };-  fxExport(core,constant_e,'constant_e','replaceValue_e');--	var createTimeSyncNode = function(nodes) {-		var nqs = map(function(n) {-				var qpulse = [];-				return {q:qpulse,v:createNode([n],function(s,p) {qpulse.push(p.value); s(p);},nodes)};-    },nodes);-		return createNode(-      map(function(n) {return n.v;},nqs), function(s,p) {-        var allfull = fold(function(n,acc) {return n.q.length && acc;},true,nqs);-        if(allfull) {-          p.value = map(function(n) {return n.q.shift();},nqs);-          s(p);-      }});-	};--	//This is up here so we can add things to its prototype that are in flapjax.combinators-  var Behaviour = function (event, init, updater) {-    if (!(event instanceof EventStream)) {-      throw 'Behaviour: expected event as second arg';-    }--    var behave = this;-    this.last = init;--    //sendEvent to this might impact other nodes that depend on this event-    //sendBehaviour defaults to this one-    this.underlyingRaw = event;--    //unexposed, sendEvent to this will only impact dependents of this behaviour-    this.underlying =-    createNode(-      [event],-	  (updater ?-	   function (s, p) {behave.last = updater(p.value); p.value = behave.last; s(p);} :-	   function (s, p) {behave.last = p.value;  s(p);}));-  };-	Behaviour.prototype = new Object();-  fxExport(core,Behaviour,'Behaviour');-  fxExport(core,Behaviour,'Behavior');--  var receiver_e = function() {-    var evt = internal_e();-    evt.sendEvent = function(value) {-      propagatePulse(new Pulse(nextStamp(), value),evt);-    };-    return evt;-  };-  fxExport(core,receiver_e,'receiver_e');--  //note that this creates a new timestamp and new event queue-  var sendEvent = function (node, value) {-    if (!(node instanceof EventStream)) { throw 'sendEvent: expected Event as first arg'; } //SAFETY--    propagatePulse(new Pulse(nextStamp(), value),node);-  };-  fxExport(core,sendEvent,'sendEvent');-  synonyms['sendEvent'] = true; // Hack: sendEvent simply should not be exported; calling it a synonym deprecates it.--  // bind_e :: EventStream a * (a -> EventStream b) -> EventStream b-  EventStream.prototype.bind_e = function(k) {-    /* m.sendsTo result_e-     * result_e.sendsTo prev_e-     * prev_e.sendsTo return_e-     */-    var m = this;-    var prev_e = false;--    var out_e = createNode([],function(send,pulse) { send(pulse); });-    out_e.name = "bind out_e";--    var in_e = createNode([m], function (send,pulse) {-      if (prev_e) {-        removeListener(prev_e,out_e);-      }-      prev_e = k(pulse.value);-      if (prev_e instanceof EventStream) {-        attachListener(prev_e,out_e);-      }-      else {-        throw "bind_e : expected EventStream";-      }-    });-    in_e.name = "bind in_e";--    return out_e;-  };--  /* Could be written as:-   *-   * e.bind_e(function(v) { return one_e(f(v)); })-   */-  EventStream.prototype.lift_e = function(f) {-    if (!(f instanceof Function)) {-      throw ('lift_e : expected a function as the first argument; received ' + f);-    };--    return createNode([this],function(send,pulse) {-      pulse.value = f(pulse.value);-      send(pulse);-    });-  };-  fxMethodSynonyms(EventStream,'lift_e',-    'transform_e','map_e','apply_e','lift','transform','map','apply');--  EventStream.prototype.not_e = function() { return this.lift_e(function(v) { return !v; }); };-  fxMethodSynonyms(EventStream,'not_e','not');--  var not_e = function(e) { return e.not_e(); };-  fxExport(core,not_e,'not_e','not');--  EventStream.prototype.filter_e = function(pred) {-    if (!(pred instanceof Function)) {-      throw ('filter_e : expected predicate; received ' + pred);-    };--    // Can be a bind_e-    return createNode([this],-      function(send,pulse) {-        if (pred(pulse.value)) { send(pulse); }-    });-  };-  fxMethodSynonyms(EventStream,'filter_e','filter');--  var filter_e = function(e,p) { return e.filter_e(p); };-  fxExport(core,filter_e,'filter_e');--  // Fires just once.-  EventStream.prototype.once_e = function() {-    var done = false;-    // Alternately: this.collect_e(0,\n v -> (n+1,v)).filter_e(\(n,v) -> n == 1).lift_e(fst)-    return createNode([this],function(send,pulse) {-      if (!done) { done = true; send(pulse); }-    });-  };-  fxMethodSynonyms(EventStream,'once_e','once');--  var once_e = function(e) { return e.once_e(); };-  fxExport(core,once_e,'once_e');--  EventStream.prototype.skipFirst_e = function() {-    var skipped = false;-    return createNode([this],function(send,pulse) {-      if (skipped)-        { send(pulse); }-      else-        { skipped = true; }-    });-  };-  fxMethodSynonyms(EventStream,'skipFirst_e','skipFirst');--  var skipFirst_e = function(e) { return e.skipFirst_e(); };-  fxExport(core,skipFirst_e,'skipFirst_e');--  EventStream.prototype.collect_e = function(init,fold) {-    var acc = init;-    return this.lift_e(-      function (n) {-        var next = fold(n, acc);-        acc = next;-        return next;-      });-  };-  fxMethodSynonyms(EventStream,'collect_e','collect','transformWithMemory');--  var collect_e = function(e,i,f) { return e.collect_e(i,f); };-  fxExport(core,collect_e,'collect_e');--  // a.k.a. join-  EventStream.prototype.switch_e = function() {-    return this.bind_e(function(v) { return v; });-  };-  fxMethodSynonyms(EventStream,'switch_e','forwardLatest');--  var switch_e = function(e) { return e.switch_e(); };-  fxExport(core,switch_e,'switch_e');--  EventStream.prototype.if_e = function(thenE,elseE) {-    var testStamp = -1;-    var testValue = false;--    createNode([this],function(_,pulse) { testStamp = pulse.stamp; testValue = pulse.value; });--    return merge_e(-      createNode([thenE],function(send,pulse) { if (testValue && (testStamp == pulse.stamp)) { send(pulse); } }),-      createNode([elseE],function(send,pulse) { if (!testValue && (testStamp == pulse.stamp)) { send(pulse); } }));-  };-  fxMethodSynonyms(EventStream,'if_e','choose_e','choose');--  var if_e = function(test,thenE,elseE) {-    if (test instanceof EventStream)-      { return test.if_e(thenE,elseE); }-    else-      { return test ? thenE : elseE; }-  };-  fxExport(core,if_e,'if_e','choose_e');--  var cond_e = function (/*. predValArrays */) {-    var predValArrays = slice(arguments, 0);-    var acc = zero_e();-    for (var i = predValArrays.length - 1; i > -1; i--) {-      acc = if_e(predValArrays[i][0],predValArrays[i][1], acc);-    }-    return acc;-  };-  fxExport(core,cond_e,'cond_e');--  var and_e = function (/* . nodes */) {-    var nodes = slice(arguments, 0);--    var acc = (nodes.length > 0)?-    nodes[nodes.length - 1] : one_e(true);--    for (var i = nodes.length - 2; i > -1; i--) {-      acc = if_e(-        nodes[i],-        acc,-        nodes[i].constant_e(false));-    }-    return acc;-  };-  fxExport(core,and_e,'and_e');--  EventStream.prototype.and_e = function( /* others */ ) {-    var deps = [this].concat(slice(arguments,0));-    return and_e.apply(this,deps);-  };-  fxMethodSynonyms(EventStream,'and_e','and');--  var or_e = function () {-    var nodes = slice(arguments, 0);-    var acc = (nodes.length > 2)?-    nodes[nodes.length - 1] : one_e(false);-    for (var i = nodes.length - 2; i > -1; i--) {-      acc = if_e(-        nodes[i],-        nodes[i],-        acc);-    }-    return acc;-  };-  fxExport(core,or_e,'or_e');--  EventStream.prototype.or_e = function(/*others*/) {-    var deps = [this].concat(slice(arguments,0));-    return or_e.apply(this,deps);-  };-  fxMethodSynonyms(EventStream,'or_e','or');--  var delayStatic_e = function (event, time) {--    var resE = internal_e();--    createNode(-      [event],-      function (s, p) {-        setTimeout(-          function () { sendEvent(resE, p.value);},-      time ); });--    return resE;-  };--  //delay_e: Event a * [Behaviour] Number ->  Event a-  EventStream.prototype.delay_e = function (time) {-    var event = this;--    if (time instanceof Behaviour) {--      var receiverEE = internal_e();-      var link =-      {-        from: event,-        towards: delayStatic_e(event, valueNow(time))-      };--			//TODO: Change semantics such that we are always guaranteed to get an event going out?-      var switcherE =-      createNode(-        [changes(time)],-        function (s, p) {-          removeListener(link.from, link.towards);-          link =-          {-            from: event,-            towards: delayStatic_e(event, p.value)-          };-          sendEvent(receiverEE, link.towards);-        });--      var resE = receiverEE.switch_e();--      sendEvent(switcherE, valueNow(time));-      return resE;--        } else { return delayStatic_e(event, time); }-  };-  fxMethodSynonyms(EventStream,'delay_e','delay');--  var delay_e = function(sourceE,interval) {-    return sourceE.delay_e(interval);-  };-  fxExport(core,delay_e,'delay_e');--  //lift_e: ([Event] (. Array a -> b)) . Array [Event] a -> [Event] b-  var lift_e = function (fn /*, [node0 | val0], ...*/) {-    //      if (!(fn instanceof Function)) { throw 'lift_e: expected fn as second arg'; } //SAFETY--    var valsOrNodes = slice(arguments, 0);-    //selectors[i]() returns either the node or real val, optimize real vals-    var selectors = [];-    var selectI = 0;-    var nodes = [];-    for (var i = 0; i < valsOrNodes.length; i++) {-      if (valsOrNodes[i] instanceof EventStream) {-        nodes.push(valsOrNodes[i]);-        selectors.push(-          (function(ii) {-              return function(realArgs) {-                return realArgs[ii];-              };-          })(selectI));-        selectI++;-      } else {-        selectors.push(-          (function(aa) {-              return function () {-                return aa;-              };-          })(valsOrNodes[i]));-      }-    }--    var context = this;-		var nofnodes = slice(selectors,1);--    if (nodes.length === 0) {-      return one_e(fn.apply(context, valsOrNodes));-    } else if ((nodes.length === 1) && (fn instanceof Function)) {-      return nodes[0].lift_e(-        function () {-          var args = arguments;-          return fn.apply(-            context,-            map(function (s) {return s(args);}, nofnodes));-        });-    } else if (nodes.length === 1) {-      return fn.lift_e(-        function (v) {-          var args = arguments;-          return v.apply(-            context,-            map(function (s) {return s(args);}, nofnodes));-        });-    } else if (fn instanceof Function) {-      return createTimeSyncNode(nodes).lift_e(-        function (arr) {-          return fn.apply(-            this,-            map(function (s) { return s(arr); }, nofnodes));-        });-    } else if (fn instanceof EventStream) {-      return createTimeSyncNode(nodes).lift_e(-        function (arr) {-          return arr[0].apply(-            this,-            map(function (s) {return s(arr); }, nofnodes));-        });-        } else {throw 'unknown lift_e case';}-  };-  fxExport(core,lift_e,'lift_e','transform_e','map_e','apply_e');--  EventStream.prototype.snapshot_e = function (valueB) {-    return createNode(-      [this],-      function (s, p) {-        p.value = valueNow(valueB);-        s(p);-      }-      );-  };-  fxMethodSynonyms(EventStream,'snapshot_e','snapshot','takeSnapshot');--  var snapshot_e = function(triggerE,valueB) {-    return triggerE.snapshot_e(valueB);-  };-  fxExport(core,snapshot_e,'snapshot_e');--  EventStream.prototype.filterRepeats_e = function(optStart) {-    var hadFirst = optStart === undefined ? false : true;-    var prev = optStart;--    return this.filter_e(function (v) {-      if (!hadFirst || !(isEqual(prev,v))) {-        hadFirst = true;-        prev = v;-        return true;-      }-      else {-        return false;-      }-    });-  };-  fxMethodSynonyms(EventStream,'filterRepeats_e','filterRepeats');--  var filterRepeats_e = function(sourceE,optStart) {-    return sourceE.filterRepeats_e(optStart);-  };-  fxExport(core,filterRepeats_e,'filterRepeats_e','filterRepeats');--  //credit Pete Hopkins-  var calmStatic_e = function (triggerE, time) {-		var out = internal_e();-    createNode(-      [triggerE],-      function() {-        var towards = null;-        return function (s, p) {-          if (towards !== null) { clearTimeout(towards); }-          towards = setTimeout( function () { towards = null; sendEvent(out,p.value) }, time );-        };-      }());-		return out;-  };--  //calm_e: Event a * [Behaviour] Number -> Event a-  EventStream.prototype.calm_e = function(time) {-    if (time instanceof Behaviour) {-			var out = internal_e();-      createNode(-        [this],-        function() {-          var towards = null;-          return function (s, p) {-            if (towards !== null) { clearTimeout(towards); }-             towards = setTimeout( function () { towards = null; sendEvent(out,p.value);}, valueNow(time));-          };-        }());-			return out;-    } else {-      return calmStatic_e(this,time);-    }-  };-  fxMethodSynonyms(EventStream,'calm_e','calm');--  var calm_e = function(sourceE,interval) {-    return sourceE.calm_e(interval);-  };-  fxExport(core,calm_e,'calm_e');--  EventStream.prototype.blind_e = function (time) {-    return createNode(-      [this],-      function () {-        var intervalFn =-        time instanceof Behaviour?-        function () { return valueNow(time); }-        : function () { return time; };-        var lastSent = (new Date()).getTime() - intervalFn() - 1;-        return function (s, p) {-          var curTime = (new Date()).getTime();-          if (curTime - lastSent > intervalFn()) {-            lastSent = curTime;-            s(p);-          }-        };-      }());-  };-  fxMethodSynonyms(EventStream,'blind_e','blind');--  var blind_e = function(sourceE,interval) {-    return sourceE.blind_e(interval);-  };-  fxExport(core,blind_e,'blind_e');--  EventStream.prototype.hold = function(init) {-    return new Behaviour(this,init);-  };-  fxMethodSynonyms(EventStream,'hold','startsWith','toBehavior');--  var hold = function(e,init) {-    if (!(e instanceof EventStream)) {-      throw 'hold: expected EventStream; received ' + e;-    }-    return e.hold(init);-  };-  fxExport(core,hold,'hold');--  Behaviour.prototype.valueNow = function() {-    return this.last;-  };-  var valueNow = function(behavior) { return behavior.valueNow(); };-  fxExport(core,valueNow,'valueNow');--  Behaviour.prototype.changes = function() {-    return this.underlying;-  };-  fxMethodSynonyms(Behaviour,'changes','toEvent');--   var changes = function (behave) { return behave.changes(); };-  fxExport(core,changes,'changes');--  Behaviour.prototype.switch_b = function() {-    var behaviourCreatorsB = this;-    var init = valueNow(behaviourCreatorsB);--    var prevSourceE = null;--    var receiverE = new internal_e();--		//XXX could result in out-of-order propagation! Fix!-    var makerE =-    createNode(-      [changes(behaviourCreatorsB)],-      function (_, p) {-        if (!(p.value instanceof Behaviour)) { throw 'switch_b: expected Behaviour as value of Behaviour of first argument'; } //SAFETY-        if (prevSourceE != null) {-          removeListener(prevSourceE, receiverE);-        }--        prevSourceE = changes(p.value);-        attachListener(prevSourceE, receiverE);--        sendEvent(receiverE, valueNow(p.value));-      });--    if (init instanceof Behaviour) {-      sendEvent(makerE, init);-    }--    return hold(-      receiverE,-      init instanceof Behaviour? valueNow(init) : init);-  };-  fxMethodSynonyms(Behaviour,'switch_b','forwardLatest');--  var switch_b = function (b) { return b.switch_b(); };-  fxExport(core,switch_b,'switch_b');--  //TODO test, signature-  var timer_b = function(interval) {-    return hold(timer_e(interval), (new Date()).getTime());-  };-  fxExport(dom,timer_b,'timer_b','asTimer_b');--  //TODO test, signature-  var delayStatic_b = function (triggerB, time, init) {-    return hold(delayStatic_e(changes(triggerB), time), init);-  };--  //TODO test, signature-  Behaviour.prototype.delay_b = function (time, init) {-    var triggerB = this;-    if (time instanceof Behaviour) {-      return hold(-        delay_e(-          changes(triggerB),-          time),-        arguments.length > 3 ? init : valueNow(triggerB));-    } else {-      return delayStatic_b(-        triggerB,-        time,-        arguments.length > 3 ? init : valueNow(triggerB));-    }-  };-  fxMethodSynonyms(Behaviour,'delay_b','delay');--  var delay_b = function(srcB, timeB, init) {-    return srcB.delay_b(timeB,init);-  };-  fxExport(core,delay_b,'delay_b');--  //artificially send a pulse to underlying event node of a behaviour-  //note: in use, might want to use a receiver node as a proxy or an identity map-  Behaviour.prototype.sendBehaviour = function(val) {-    sendEvent(this.underlyingRaw,val);-  };-  Behaviour.prototype.sendBehavior = Behaviour.prototype.sendBehaviour;--  var sendBehaviour = function (b,v) { b.sendBehaviour(v); };-  fxExport(core,sendBehaviour,'sendBehaviour');-  fxExport(core,sendBehaviour,'sendBehavior');--  Behaviour.prototype.if_b = function(trueB,falseB) {-    var testB = this;-    //TODO auto conversion for behaviour funcs-    if (!(trueB instanceof Behaviour)) { trueB = constant_b(trueB); }-    if (!(falseB instanceof Behaviour)) { falseB = constant_b(falseB); }-    return lift_b(function(te,t,f) { return te ? t : f; },testB,trueB,falseB);-  };-  fxMethodSynonyms(Behaviour,'if_b','choose_b','choose');--  var if_b = function(test,cons,altr) {-    if (!(test instanceof Behaviour)) { test = constant_b(test); };--    return test.if_b(cons,altr);-  };-  fxExport(core,if_b,'if_b','choose_b');---  //cond_b: . [Behaviour boolean, Behaviour a] -> Behaviour a-  var cond_b = function (/* . pairs */ ) {-    var pairs = slice(arguments, 0);-	return lift_b.apply({},[function() {-			for(var i=0;i<pairs.length;i++) {-				if(arguments[i]) return arguments[pairs.length+i];-			}-			return undefined;-		}].concat(map(function(pair) {return pair[0];},pairs).concat(map(function(pair) {return pair[1];},pairs))));-  };-  fxExport(core,cond_b,'cond_b');--  //TODO optionally append to objects-  //createConstantB: a -> Behaviour a-  var constant_b = function (val) {-    return new Behaviour(internal_e(), val);-  };-  fxExport(core,constant_b,'constant_b','receiver_b');--	var lift_b = function (fn /* . behaves */) {-    var args = slice(arguments, 1);--    //dependencies-    var constituentsE =-      map(changes,-      filter(function (v) { return v instanceof Behaviour; },-        arguments));--    //calculate new vals-    var getCur = function (v) {-      return v instanceof Behaviour ? v.last : v;-    };--    var ctx = this;-    var getRes = function () {-      return getCur(fn).apply(ctx, map(getCur, args));-    };--    if(constituentsE.length == 1) {-      return new Behaviour(constituentsE[0],getRes(),getRes);-    }--    //gen/send vals @ appropriate time-    var prevStamp = -1;-    var mid = createNode(constituentsE, function (s, p) {-        if (p.stamp != prevStamp) {-          prevStamp = p.stamp;-          s(p);-    }});-    return new Behaviour(mid,getRes(),getRes);-  };-  fxExport(core,lift_b,'lift_b','transform_b','apply_b');--  Behaviour.prototype.lift_b = function(/* args */) {-    var args= slice(arguments,0).concat([this]);-    return lift_b.apply(this,args);-  };-  fxMethodSynonyms(Behaviour,'lift_b','transform_b','apply_b','transform',-    'lift');--  var and_b = function (/* . behaves */) {-	return lift_b.apply({},[function() {-			for(var i=0; i<arguments.length; i++) {if(!arguments[i]) return false;}-			return true;-	}].concat(slice(arguments,0)));-  };-  fxExport(core, and_b, 'and_b');--  Behaviour.prototype.and_b = function() {-    return and_b([this].concat(arguments));-  };-  fxMethodSynonyms(Behaviour,'and_b','and');--  var or_b = function (/* . behaves */ ) {-	return lift_b.apply({},[function() {-			for(var i=0; i<arguments.length; i++) {if(arguments[i]) return true;}-			return false;-	}].concat(slice(arguments,0)));-  };-  fxExport(core,or_b,'or_b');--  Behaviour.prototype.or_b = function () {-    return or_b([this].concat(arguments));-  };-  fxMethodSynonyms(Behaviour, 'or_b', 'or');--  Behaviour.prototype.not_b = function() {-    return this.lift_b(function(v) { return !v; });-  };-  fxMethodSynonyms(Behaviour,'not_b','not');--  var not_b = function(b) { return b.not_b(); };-  fxExport(core,not_b,'not_b');--  Behaviour.prototype.blind_b = function (intervalB) {-    return changes(this).blind_e(intervalB).hold(this.valueNow());-  };-  fxMethodSynonyms(Behaviour,'blind_b','blind');--  var blind_b = function(srcB,intervalB) {-    return srcB.blind_b(intervalB);-  };-  fxExport(core,blind_b,'blind_b');--  Behaviour.prototype.calm_b = function (intervalB) {-    return this.changes().calm_e(intervalB).hold(this.valueNow());-  };-  fxMethodSynonyms(Behaviour,'calm_b','calm');--  var calm_b = function (srcB,intervalB) {-    return srcB.calm_b(intervalB);-  };-  fxExport(core,calm_b,'calm_b');--  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////-  // DOM Utilities--	//credit Scott Andrew-	//usage: addEvent(myDomObj, "mouseover", event->void )-	//warning: do not use 'this' as meaning depends on browser (myDomObj vs window)-	//addEvent: Dom * String DomEventEnum * (DomEvent -> a) -> Void-	var addEvent = function (obj, evType, fn) {-		//TODO encode mouseleave evt, formalize new evt interface--		if (obj.addEventListener) {-      obj.addEventListener(evType, fn, false); //TODO true fails on Opera-      return true;-		} else if (obj.attachEvent) {-      //some reason original had code bloat here-      return obj.attachEvent("on"+evType, fn);-		} else {-      return false;-		}-	};-  fxExport(domMisc,addEvent,'addEvent');--  // The Flapjax library does not use this function-	//credit Dustin Diaz-	//note: node/tag optional-	//getElementsByClass: Regexp CSSSelector * Dom * String DomNodeEnum -> Array Dom-	var getElementsByClass = function (searchClass, node, tag) {-		var classElements = [];-		if ( (node === null) || (node === undefined) ) { node = document; }-		if ( (tag === null) || (tag === undefined) ) { tag = '*'; }-		var els = node.getElementsByTagName(tag);-		var elsLen = els.length;-		var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");-		for (var i = 0, j = 0; i < elsLen; i++) {-      if ( pattern.test(els[i].className) ) {-        classElements.push(els[i]);-      }-		}-		return classElements;-	};-  fxExport(domMisc,getElementsByClass,'getElementsByClass','$$');--	//assumes IDs already preserved-	//swapDom: (Dom a U String) [* (Dom b U String)] -> Dom a-	var swapDom = function(replaceMe, withMe) {-		if ((replaceMe === null) || (replaceMe === undefined)) { throw ('swapDom: expected dom node or id, received: ' + replaceMe); } //SAFETY--		var replaceMeD = getObj(replaceMe);-		if (!(replaceMeD.nodeType > 0)) { throw ('swapDom expected a Dom node as first arg, received ' + replaceMeD); } //SAFETY--		if (withMe) {-      var withMeD = getObj(withMe);-      if (!(withMeD.nodeType > 0)) { throw 'swapDom: can only swap with a DOM object'; } //SAFETY-      try {-        if(withMeD != replaceMeD) replaceMeD.parentNode.replaceChild(withMeD, replaceMeD);-      } catch (e) {-        throw('swapDom error in replace call: withMeD: ' + withMeD + ', replaceMe Parent: ' + replaceMeD + ', ' + e + ', parent: ' + replaceMeD.parentNode);-      }-		} else {-      replaceMeD.parentNode.removeChild(replaceMeD); //TODO isolate child and set innerHTML to "" to avoid psuedo-leaks?-		}-		return replaceMeD;-	};-  fxExport(domMisc,swapDom,'swapDom');--	//getObj: String U Dom -> Dom-	//throws-	//  'getObj: expects a Dom obj or Dom id as first arg'-	//  'getObj: flapjax: cannot access object'-	//  'getObj: no obj to get-	//also known as '$'-	//TODO Maybe alternative?-	var getObj = function (name) {-		if (typeof(name) == 'object') { return name; }-		else if ((typeof(name) == 'null') || (typeof(name) == 'undefined')) {-      throw 'getObj: expects a Dom obj or Dom id as first arg';-		} else {--      var res =-			document.getElementById ? document.getElementById(name) :-			document.all ? document.all[name] :-			document.layers ? document.layers[name] :-			(function(){ throw 'getObj: flapjax: cannot access object';})();-      if ((res === null) || (res === undefined)) {-        throw ('getObj: no obj to get: ' + name);-      }-      return res;-		}-	};-  fxExport(domMisc,getObj,'getObj');-  fxExport(domMisc,getObj,'$');--  //helper to reduce obj look ups-  //getDynObj: domNode . Array (id) -> domObj-  //obj * [] ->  obj-  //obj * ['position'] ->  obj-  //obj * ['style', 'color'] ->  obj.style-  var getMostDom = function (domObj, indices) {-    var acc = getObj(domObj);-    if ( (indices === null) || (indices === undefined) || (indices.length < 1)) {-      return acc;-    } else {-      for (var i = 0; i < indices.length - 1; i++) {-        acc = acc[indices[i]];-      }-      return acc;-    }-  };--  var getDomVal = function (domObj, indices) {-    var val = getMostDom(domObj, indices);-    if (indices && indices.length > 0) {-      val = val[indices[indices.length - 1]];-    }-    return val;-  };--  //TODO: manual timer management stinks.-  // TODO: Name turn off or somethin-  var ___timerID = 0;-  var __getTimerId = function () { return ++___timerID; };-  var timerDisablers = [];--  var disableTimerNode = function (node) { timerDisablers[node.__timerId](); };--  var disableTimer = function (v) {-    if (v instanceof Behaviour) {-      disableTimerNode(v.underlyingRaw);-    } else if (v instanceof EventStream) {-      disableTimerNode(v);-    }-  };-  fxExport(dom,disableTimer,'disableTimer');--  var createTimerNodeStatic = function (interval) {-    var node = internal_e();-    node.__timerId = __getTimerId();-    var fn = function () { sendEvent(node, (new Date()).getTime());};-    var timer = setInterval(fn, interval);-    timerDisablers[node.__timerId] = function () {clearInterval(timer); };-    return node;-  };--  var timer_e = function (interval) {-    if (interval instanceof Behaviour) {-      var receiverE = internal_e();--      //the return-      var res = receiverE.switch_e();--      //keep track of previous timer to disable it-      var prevE = createTimerNodeStatic(valueNow(interval));--      //init-      sendEvent(receiverE, prevE);--      //interval changes: collect old timer-      createNode(-        [changes(interval)],-        function (_, p) {-          disableTimerNode(prevE);-          prevE = createTimerNodeStatic(p.value);-          sendEvent(receiverE, prevE);-        });--      res.__timerId = __getTimerId();-      timerDisablers[res.__timerId] = function () {-        disableTimerNode[prevE]();-        return;-      };--      return res;-    } else {-      return createTimerNodeStatic(interval);-    }-  };-  fxExport(dom,timer_e,'timer_e','asTimer_e');--	d.TagB = function(tagName,args) {-		this.resE = internal_e();-		this.currentTag = document.createElement(tagName);-		this.extractParameters(args);-		this.insertChildrenNodes();-		this.styleHooks = [];-		this.styleChangedE = internal_e();-		var ctx = this;-    this.styleChangedE.lift_e(function(_) {-				var oldTag = ctx.currentTag;-				ctx.currentTag = document.createElement(tagName);-        while (oldTag.firstChild) {-          ctx.currentTag.appendChild(oldTag.removeChild(oldTag.firstChild));-				}-				while(ctx.styleHooks.length) removeListener(ctx.styleHooks.pop(),ctx.styleChangedE);-        ctx.enstyle(ctx.currentTag,ctx.attribs);-        sendEvent(ctx.resE, ctx.currentTag);-		});-		this.enstyle(this.currentTag,this.attribs);-    this.resB = hold(this.resE, this.currentTag);-	};-	d.TagB.prototype = {-    // Array [[Behaviour] Object *] [[Behaviour] Array] [Behaviour] Dom U String U undefined-    //   --> {attribs: Array [Behaviour] Object, arrs: Array [Behaviour] Array [Behaviour] Dom }-    // split an arguments array into:-    //   1. arrs: (coalesced, and possibly time varying) arrays of dom objects-    //   2. attribs: attribute objects-		extractParameters: function(args) {-			this.arrs = [];-			var attribs = [];--			var curarr = [];-			this.arrs.push(curarr);-			for (var i = 0; i < args.length; i++) {-				if (args[i] instanceof Behaviour) {-					var vn = valueNow(args[i]);-					if (vn instanceof Array) {-						this.arrs.push(args[i]);-						curarr = [];-						this.arrs.push(curarr);-					} else {-						if ( ((typeof(vn) == 'object') && (vn.nodeType == 1)) ||-              (typeof(vn) == 'string') || (vn == undefined)) {-            curarr.push(args[i]);-              } else if (typeof(vn) == 'object') {-                attribs.push(args[i]);-              }-              else { throw ('createParameterizedTagB: unknown behaviour argument argument ' + i); } //SAFETY-					}-				} else {-					if (args[i] instanceof Array) {-						var arr = args[i];-						for (var j = 0; j < arr.length; j++) { curarr.push(arr[j]); }-					} else {-						var vn = args[i];-						if ( ((typeof(vn) == 'object') && (vn.nodeType == 1)) ||-              (typeof(vn) == 'string') || (vn == undefined)) {-						curarr.push(args[i]);-              } else if (typeof(vn) == 'object') {-                attribs.push(args[i]);-              }-					}-				}-			};-			if(attribs.length > 1) throw ('createParameterizedTagB ' + tagName + ': more than one attribute (' + attribs.length + ')');-			this.attribs = attribs.length > 0 ? attribs[0] : {};-		},-		insertChildrenNodes: function() {-			var ctx = this;--			function quickNode(e) {-        if ((typeof(e) == 'object') && (e.nodeType))-					return e;-        else if ( e == undefined )-					return document.createTextNode('');-        else-          return document.createTextNode(e);-      }--			function unBehaviourize(arr) {-				return map(function(n) {return (n instanceof Behaviour) ? valueNow(n) : n;},arr)-			}--			var lnodes = map(function() {return [];},this.arrs);-			var arrLastVals = map(unBehaviourize,unBehaviourize(this.arrs));--			var arrChangesE = internal_e();-			var nodeChangesE = internal_e();--			function attachNodes(i,arr) {-				for(var j=0;j<arr.length;j++) {-					var cnode = arr[j];-					if(cnode instanceof Behaviour) {-						var newnode = (function(jj) {-                return changes(cnode).lift_e(function(n) {return {index:i,jdex:jj,val:n};});-						})(j);-						lnodes[i].push(newnode);-						attachListener(newnode,nodeChangesE);-						cnode = valueNow(cnode);-					}-				}-			}--			var childChangesE = merge_e(-				// Behaviour arrays change-				arrChangesE.lift_e(function(ai) {-            var i = ai.index;-            var newarr = ai.val;-            while(lnodes[i].length) {-              var ln = lnodes[i].pop();-              removeListener(ln,nodeChangesE);-            }-            var newvals = map(function(n) {return quickNode(n);},unBehaviourize(newarr));-            for(var j=0;j<arrLastVals[i].length;j++)-				try {-					ctx.currentTag.removeChild(arrLastVals[i][j]);-				}-				catch(e) {}-            if(newvals.length) {-              var nextNode = null;-              for(ii = i+1; ii < arrLastVals.length && !(arrLastVals[ii].length) ; ii++);-              if(ii < arrLastVals.length) nextNode = arrLastVals[ii][0];-              for(var j=0; j<newvals.length; j++) ctx.currentTag.insertBefore(newvals[j],nextNode);-            }-            arrLastVals[i] = newvals;-            attachNodes(i,newarr);-            return ctx.currentTag;-				}),-				// Behaviour nodes change-				nodeChangesE.lift_e(function(ni) {-            var i = ni.index;-            var j = ni.jdex;-            var newnode = quickNode(ni.val);-            swapDom(arrLastVals[i][j],newnode);-            arrLastVals[i][j] = newnode;-            return ctx.currentTag;-				}));-			childChangesE.lift_e(function(cc) {sendEvent(ctx.resE,cc);});--			for(var i=0; i<this.arrs.length;i++) {-				for(var j=0; j<arrLastVals[i].length; j++) {-					arrLastVals[i][j] = quickNode(arrLastVals[i][j]);-					this.currentTag.appendChild(arrLastVals[i][j]);-				}-				if(this.arrs[i] instanceof Behaviour) {-					attachNodes(i,valueNow(this.arrs[i]));-					var newnode = (function(ii) {return changes(ctx.arrs[ii]).lift_e(function(na) {return {index:ii,val:na};});})(i);-					attachListener(newnode,arrChangesE);-				}-				else {-					attachNodes(i,this.arrs[i]);-				}-			}-		},-		enstyle: function(obj,vals) {-			//build & record hook if dynamic collection-			if (vals instanceof Behaviour) {-				if (!(typeof(valueNow(vals)) == 'object')) { throw 'enstyle: expected object literal as behaviour value'; } //SAFETY-				this.styleHooks.push(changes(vals));-				attachListener(changes(vals),this.styleChangedE);-			}-			var valsV = vals instanceof Behaviour ? valueNow(vals) : vals;-			if (typeof(valsV) == 'object') {-				for (var i in valsV) {-					if (!(Object.prototype) || !(Object.prototype[i])) {-						this.enstyleProperty(obj,valsV, i);-					}-				}-			}-			else { throw 'enstyle: expected object literals'; } //SAFETY-		},-    enstyleProperty: function (obj, vals, i) {-      if (vals[i] instanceof Behaviour) {-        if (typeof(valueNow(vals[i])) == 'object') {-          this.enstyle(obj[i], vals[i]);-        }-				else {-          obj[i] = valueNow(vals[i]);-					changes(vals[i]).lift_e(function(v) {obj[i] = v;});-				}-			}-			else {-        if (typeof(vals[i]) == 'object') {-          this.enstyle(obj[i], vals[i]);-        } else {-          obj[i] = vals[i];-        }-      }-    }-	};--	d.createParameterizedTagB = function(tagName) {-		return new d.TagB(tagName,slice(arguments,1)).resB;-	};--  d.enstyleStaticProperty = function (obj, props, index) {-    if (typeof(props[index]) == 'object') {-      for (var i in props[index]) {-        if (!(Object.prototype) || !(Object.prototype[i])) {-          d.enstyleStaticProperty(obj[index], props[index], i);-        }-      }-    } else {-      obj[index] = props[index];-			if (index == 'checked')	obj['defaultChecked'] = props[index]; /* TODO: this should maybe be elsewhere? */-			if (index == 'selected') obj['defaultSelected'] = props[index]; /* TODO: this should maybe be elsewhere? */-    }-  };--  d.staticTagMaker = function (tagName) {--    return function () {--      var tagD = document.createElement(tagName);-      if (!(tagD.nodeType > 0)) { throw (tagName + ': invalid tag name'); } //SAFETY--      //partition input--      //          if (arguments[1] === null || arguments[1] === undefined) { arguments[1] = {}; }-      var attribs = [];-      for (var i = 0; i < arguments.length; i++) {-        if (arguments[i] instanceof Array) {-          for (var j = 0; j < arguments[i].length; j++) {-            if (arguments[i][j]) {-              tagD.appendChild(-                (typeof(arguments[i][j]) == 'object' &&-                  arguments[i][j].nodeType > 0)?-                arguments[i][j] :-                document.createTextNode(arguments[i][j]));-            }-          }-        } else if (!arguments[i]) {-          //ignore-        } else if ((typeof(arguments[i]) == 'object') &&-          (arguments[i].nodeType > 0)) {-        tagD.appendChild(arguments[i]);-          } else if (typeof(arguments[i]) == 'object') {-            attribs.push(arguments[i]);-          } else {-            tagD.appendChild(document.createTextNode(arguments[i]));-          }-      }--      if (attribs.length == 1) {-        for (var k in attribs[0]) {-          if (!(Object.prototype) || !(Object.prototype[k])) {-            d.enstyleStaticProperty(tagD, attribs[0], k);-          }-        }-      } else if (attribs.length >  0) {-        throw 'static enstyle: expected object literals'; //SAFETY-      } /* else {-      alert('no attribs on: ' + tagName);-      } */---      return tagD;-    };-  };----  var generatedTags =-  [ "a", "b", "blockquote", "br", "button", "canvas", "div", "fieldset",-  "form", "font", "h1", "h2", "h3", "h4", "hr", "img", "iframe", "input",-  "label", "legend", "li", "ol", "optgroup", "option",-  "p", "pre", "select", "span", "strong", "table", "tbody",-  "td", "textarea", "tfoot", "th", "thead", "tr", "tt", "ul" ];--  map(-    function (tagName) {--      var upper = tagName.toUpperCase();--      //d.<TAG>B-      d[upper + 'B'] = function () {-        return d.createParameterizedTagB.apply(this, [tagName].concat(slice(arguments,0)));-      };-			annotate(d[upper+'B'],[upper+'B']);--      //d.<TAG>-      d[upper] = d.staticTagMaker(tagName);  //faster, simple-      /*              function () {-      // 8/16/06 - leo - arguments bug-      // more forgiving: allows reactive children (just doesn't propagate them)-      var args = [b.maybeEmpty].concat(slice(arguments, 0));-      return valueNow(d[upper + 'B'].apply(this, args));-      }; */-			annotate(d[upper],[upper]);-    },-    generatedTags);--  //TEXTB: Behaviour a -> Behaviour Dom TextNode-  d.TEXTB = function (strB) {-    //      if (!(strB instanceof Behaviour || typeof(strB) == 'string')) { throw 'TEXTB: expected Behaviour as second arg'; } //SAFETY-    if (!(strB instanceof Behaviour)) { strB = constant_b(strB); }--    return hold(-      changes(strB).lift_e(-        function (txt) { return document.createTextNode(txt); }),-      document.createTextNode(valueNow(strB)));-  };-	annotate(d.TEXTB,['TEXTB']);--  var TEXT = function (str) {-    return document.createTextNode(str);-  };-  fxExport(dom,TEXT,'TEXT');--  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////-  // Reactive DOM--  //tagRec: Array (EventName a) *-  //      ( .Array (Event a) * Array (Event a) -> Behaviour Dom) -> Behaviour Dom-  var tagRec = function (eventNames, maker) {-    if (!(eventNames instanceof Array)) { throw 'tagRec: expected array of event names as first arg'; } //SAFETY-    if (!(maker instanceof Function)) { throw 'tagRec: expected function as second arg'; } //SAFETY--    var numEvents = eventNames.length;-    var internals = [ ];-    var switches = [ ];-    for (var i = 0; i < numEvents; i++) {-      internals[i] = internal_e();-      switches[i] = internals[i].switch_e();-    };--    var domB = maker.apply(this,switches);--    var prevValue;--    var interceptE = createNode([domB.changes()],function (_,p) {-      if (isEqual(p.value,prevValue)) { return; }--      prevValue = p.value;-      for (var i = 0; i < numEvents; i++) {-        sendEvent(internals[i],extractEvent_e(prevValue,eventNames[i]));-      };-    });--    sendEvent(interceptE,domB.valueNow());--    return domB;-  };-  fxExport(dom,tagRec,'tagRec','nodeWithOwnEvents');--  //extractEventStatic_e: Dom * String -> Event-  var extractEventStatic_e = function (domObj, eventName) {-    if (!eventName) { throw 'extractEvent_e : no event name specified'; }-    if (!domObj) { throw 'extractEvent_e : no DOM element specified'; }--    domObj = getObj(domObj);--    var primEventE = internal_e();-    addEvent(domObj,eventName,function(evt) {-       sendEvent(primEventE, evt || window.event);-       // Important for IE; false would prevent things like a checkbox actually-       // checking.-       return true;-    });--    return primEventE;-  };--  //extractEvent_e: [Behaviour] Dom * String -> Event-  var extractEvent_e = function (domB, eventName) {-    if (!(domB instanceof Behaviour)) {-      return extractEventStatic_e(domB,eventName);-    }-    else {-      var domE = domB.changes();--      var eventEE = domE.lift_e(function(dom) {-        return extractEventStatic_e(dom,eventName);-      });--      var resultE = eventEE.switch_e();--      sendEvent(domE,domB.valueNow());--      return resultE;-    };-  };-  fxExport(dom,extractEvent_e,'extractEvent_e','$EVT');--  //extractEvents_e:-  //      [Behaviour] Dom-  //      . Array String-  //      -> Event-  // ex: extractEvents_e(m, 'body', 'mouseover', 'mouseout')-  d.extractEvents_e = function (domObj /* . eventNames */) {-    var eventNames = slice(arguments, 1);--    var events = map(-      function (eventName) {-        return extractEvent_e(domObj, eventName);-      },-      eventNames.length === 0 ? [] : eventNames);--    return merge_e.apply(this, events);-  };-  annotate(d.extractEvents_e,['extractEvents_e'],0,[Behaviour.prototype],['extractEvents_e']);--  //value of dom form object during trigger-  d.extractValueOnEvent_e = function (triggerE, domObj) {-    if (!(triggerE instanceof EventStream)) { throw 'extractValueOnEvent_e: expected Event as first arg'; } //SAFETY--    return changes(d.extractValueOnEvent_b.apply(this, arguments));--  };-  annotate(d.extractValueOnEvent_e,['extractValueOnEvent_e']);--  //extractDomFieldOnEvent_e: Event * Dom U String . Array String -> Event a-  d.extractDomFieldOnEvent_e = function (triggerE, domObj /* . indices */) {-    if (!(triggerE instanceof EventStream)) { throw 'extractDomFieldOnEvent_e: expected Event as first arg'; } //SAFETY-    var indices = slice(arguments, 2);-    var res =-    triggerE.lift_e(-      function () { return getDomVal(domObj, indices); });-    return res;-  };--  d.extractValue_e = function (domObj) {-    return changes(d.extractValue_b.apply(this, arguments));-  };-  annotate(d.extractValue_e,['extractValue_e','$E']);--  //extractValueOnEvent_b: Event * DOM -> Behaviour-  // value of a dom form object, polled during trigger-  d.extractValueOnEvent_b = function (triggerE, domObj) {-    return d.extractValueStatic_b(domObj, triggerE);-  };-  annotate(d.extractValueOnEvent_b,['extractValueOnEvent_b']);--  //extractValueStatic_b: DOM [ * Event ] -> Behaviour a-  //If no trigger for extraction is specified, guess one-  d.extractValueStatic_b = function (domObj, triggerE) {--    var objD;-    try {-      objD = getObj(domObj);-	    //This is for IE-	    if(typeof(domObj) == 'string' && objD.id != domObj) {-	    	throw 'Make a radio group';-	    }-    } catch (e) {-      objD = {type: 'radio-group', name: domObj};-    }--    var getter; // get value at any current point in time---    switch (objD.type)  {--      //TODO: checkbox.value instead of status?-    case 'checkbox':--      return hold(-        filterRepeats_e(-          d.extractDomFieldOnEvent_e(-            triggerE ? triggerE :-            d.extractEvents_e(-              objD,-              'click', 'keyup', 'change'),-            objD,-            'checked'),objD.checked),-        objD.checked);--      case 'select-one':--        getter = function (_) {-          return objD.selectedIndex > -1 ?-          (objD.options[objD.selectedIndex].value ?-            objD.options[objD.selectedIndex].value :-            objD.options[objD.selectedIndex].innerText)-			    : undefined;-        };--        return hold(-          filterRepeats_e(-              (triggerE ? triggerE :-              d.extractEvents_e(-                objD,-                'click', 'keyup', 'change')).lift_e(getter)),getter(),-          getter());--        case 'select-multiple':-          //TODO ryan's cfilter adapted for equality check--          getter = function (_) {-            var res = [];-            for (var i = 0; i < objD.options.length; i++) {-              if (objD.options[i].selected) {-                res.push(objD.options[i].value ? objD.options[i].value : objD.options[i].innerText);-              }-            }-            return res;-          };---          return hold(-              (triggerE ? triggerE :-              d.extractEvents_e(-                objD,-                'click', 'keyup', 'change')).lift_e(getter),-            getter());--          case 'text':-          case 'textarea':-          case 'hidden':-          case 'password':--            return hold(-              filterRepeats_e(-                d.extractDomFieldOnEvent_e(-                  triggerE ? triggerE :-                  d.extractEvents_e(-                    objD,-                    'click', 'keyup', 'change'),-                  objD,-                  'value'),objD.value),-              objD.value);--            case 'button': //same as above, but don't filter repeats--              return hold(-                d.extractDomFieldOnEvent_e(-                  triggerE ? triggerE :-                  d.extractEvents_e(-                    objD,-                    'click', 'keyup', 'change'),-                  objD,-                  'value'),-                objD.value);---              case 'radio':-              case 'radio-group':--                //TODO returns value of selected button, but if none specified,-                //      returns 'on', which is ambiguous. could return index,-                //      but that is probably more annoying--                var radiosAD = filter(-                  function (elt) {-                    return (elt.type == 'radio') &&-                    (elt.getAttribute('name') == objD.name);-                  },-                  document.getElementsByTagName('input'));--                getter =-                objD.type == 'radio' ?--                function (_) {-                  return objD.checked;-                } :--                function (_) {-                  for (var i = 0; i < radiosAD.length; i++) {-                    if (radiosAD[i].checked) {-                      return radiosAD[i].value;-                    }-                  }-                  return undefined; //TODO throw exn?-                };--                var actualTriggerE = triggerE ? triggerE :-                merge_e.apply(-                  this,-                  map(-                    function (radio) {-                      return d.extractEvents_e(-                        radio,-                    'click', 'keyup', 'change'); },-                      radiosAD));--                return hold(-                  filterRepeats_e(-                      actualTriggerE.lift_e(getter),getter()),-                  getter());--                default:--                  throw ('extractValueStatic_b: unknown value type "' + objD.type + '"');-    }-  };--  d.extractValue_b = function (domObj) {-    if (domObj instanceof Behaviour) {-      return lift_b(function (dom) { return d.extractValueStatic_b(dom); },-                    domObj)-             .switch_b();-    } else {-      return d.extractValueStatic_b(domObj);-    }-  };-	annotate(d.extractValue_b,['extractValue_b','$B'],0,[Behaviour.prototype],['extractValue_b','$B']);--  //into[index] = deepValueNow(from) via descending from object and mutating each field-  d.deepStaticUpdate = function (into, from, index) {-    var fV = (from instanceof Behaviour)? valueNow(from) : from;-    if (typeof(fV) == 'object') {-      for (var i in fV) {-        if (!(Object.prototype) || !(Object.prototype[i])) {-          d.deepStaticUpdate(index? into[index] : into, fV[i], i);-        }-      }-    } else {-      var old = into[index];-      into[index] = fV;-    }-  };--  //note: no object may be time varying, just the fields-  //into[index] = from-  //only updates on changes-  d.deepDynamicUpdate = function (into, from, index) {-    var fV = (from instanceof Behaviour)? valueNow(from) : from;-    if (typeof(fV) == 'object') {-      if (from instanceof Behaviour) {-        throw 'deepDynamicUpdate: dynamic collections not supported';-      }-      for (var i in fV) {-        if (!(Object.prototype) || !(Object.prototype[i])) {-          d.deepDynamicUpdate(index? into[index] : into, fV[i], i);-        }-      }-    } else {-      if (from instanceof Behaviour) {-        createNode(-          [changes(from)],-          function (s, p) {-            if (index) {-              var old = into[index];-              into[index] = p.value;-            }-            else { into = p.value; } //TODO notify topE?-          });-      }-    }-  };---  d.insertValue = function (val, domObj /* . indices */) {-    var indices = slice(arguments, 2);-    var parent = getMostDom(domObj, indices);-    d.deepStaticUpdate(parent, val, indices ? indices[indices.length - 1] : undefined);-  };-  annotate(d.insertValue,['insertValue']);--  //TODO convenience method (default to firstChild nodeValue)-  d.insertValueE = function (triggerE, domObj /* . indices */) {-    if (!(triggerE instanceof EventStream)) { throw 'insertValueE: expected Event as first arg'; } //SAFETY--    var indices = slice(arguments, 2);-    var parent = getMostDom(domObj, indices);--      triggerE.lift_e(function (v) {-        d.deepStaticUpdate(parent, v, indices? indices[indices.length - 1] : undefined);-      });-  };-  annotate(d.insertValueE,['insertValueE'],0,[EventStream.prototype],['insertValueE']);--  //insertValueB: Behaviour * domeNode . Array (id) -> void-  //TODO notify adapter of initial state change?-  d.insertValueB = function (triggerB, domObj /* . indices */) {--    var indices = slice(arguments, 2);-    var parent = getMostDom(domObj, indices);---    //NOW-    d.deepStaticUpdate(parent, triggerB, indices ? indices[indices.length - 1] : undefined);--    //LATER-    d.deepDynamicUpdate(parent, triggerB, indices? indices[indices.length -1] : undefined);--  };-  annotate(d.insertValueB,['insertValueB'],0,[Behaviour.prototype],['insertValueB']);--  //TODO copy dom event call backs of original to new? i don't thinks so-  //  complication though: registration of call backs should be scoped-  d.insertDomE = function (triggerE, domObj) {--    if (!(triggerE instanceof EventStream)) { throw 'insertDomE: expected Event as first arg'; } //SAFETY--    var objD = getObj(domObj);--    var res = triggerE.lift_e(-      function (newObj) {-        //TODO safer check-        if (!((typeof(newObj) == 'object') && (newObj.nodeType == 1))) {-          newObj = d.SPAN({}, newObj);-        }-        swapDom(objD, newObj);-        objD = newObj;-        return newObj; // newObj;-      });--    return res;-  };-  annotate(d.insertDomE,['insertDomE'],0,[EventStream.prototype],['insertDomE']);--  //insertDom: dom-  //          * dom-  //          [* (null | undefined | 'over' | 'before' | 'after' | 'leftMost' | 'rightMost' | 'beginning' | 'end']-  //          -> void-  // TODO: for consistency, switch replaceWithD, hookD argument order-  d.insertDom = function (hookD, replaceWithD, optPosition) {-    switch (optPosition)-    {-    case undefined:-    case null:-    case 'over':-      swapDom(hookD,replaceWithD);-      break;-    case 'before':-      hookD.parentNode.insertBefore(replaceWithD, hookD);-      break;-    case 'after':-      if (hookD.nextSibling) {-        hookD.parentNode.insertBefore(replaceWithD, hookD.nextSibling);-      } else {-        hookD.parentNode.appendChild(replaceWithD);-      }-      break;-    case 'leftMost':-      if (hookD.parentNode.firstChild) {-        hookD.parentNode.insertBefore(-          replaceWithD,-          hookD.parentNode.firstChild);-                } else { hookD.parentNode.appendChild(replaceWithD); }-                break;-              case 'rightMost':-                hookD.parentNode.appendChild(replaceWithD);-                break;-              case 'beginning':-                if (hookD.firstChild) {-                  hookD.insertBefore(-                    replaceWithD,-                    hookD.firstChild);-                } else { hookD.appendChild(replaceWithD); }-                break;-              case 'end':-                hookD.appendChild(replaceWithD);-                break;-              default:-                throw ('domInsert: unknown position: ' + optPosition);-    }-  };--  //insertDom: dom-  //          * dom U String domID-  //          [* (null | undefined | 'over' | 'before' | 'after' | 'leftMost' | 'rightMost' | 'beginning' | 'end']-  //          -> void-  d.insertDomClean = function (replaceWithD, hook, optPosition) {-    //TODO span of textnode instead of textnode?-    d.insertDom(-	    getObj(hook),-	    ((typeof(replaceWithD) == 'object') && (replaceWithD.nodeType > 0)) ? replaceWithD :-      document.createTextNode(replaceWithD),-	    optPosition);-  };-  annotate(d.insertDomClean,['insertDom']);--  //TODO test-  //insertDomB:-  //      [Behaviour] String U Dom-  //      [* ( id U null U undefined )-  //          [* ('before' U 'after' U 'leftMost' U 'rightMost' U 'over' U 'beginning' U 'end')]]-  //      -> Behaviour a-  //if optID not specified, id must be set in init val of trigger-  //if position is not specified, default to 'over'-  //performs initial swap onload-  d.insertDomB = function (initTriggerB, optID, optPosition) {--    if (!(initTriggerB instanceof Behaviour)) {-      initTriggerB = constant_b(initTriggerB);-    }--    var triggerB =-    lift_b(-      function (d) {-        if ((typeof(d) == 'object') && (d.nodeType >  0)) {-          return d;-        } else {-          var res = document.createElement('span'); //TODO createText instead-          res.appendChild(document.createTextNode(d));-          return res;-        }-      },-      initTriggerB);--    var initD = valueNow(triggerB);-    if (!((typeof(initD) == 'object') && (initD.nodeType == 1))) { throw ('insertDomB: initial value conversion failed: ' + initD); } //SAFETY--    d.insertDom(-      optID === null || optID === undefined ? getObj(initD.getAttribute('id')) : getObj(optID),-      initD,-      optPosition);--    var resB = hold(-      d.insertDomE(-        changes(triggerB),-        initD),-      initD);--    return resB;-  };-  annotate(d.insertDomB,['insertDomB'],0,[Behaviour.prototype],['insertDomB']);---  d.extractId_b = function (id, start)-  {-    return hold(-      createNode( start instanceof Behaviour? [changes(start)] :-        [],-        function (s, p) {-          p.value = getObj(id);-          s(p);-        }),-      getObj(id));-  };-  annotate(d.insertDomB,['extractId_b'],1,[Behaviour.prototype],['extractId_b']);--  var mouse_e = function(elem) {-    return extractEvent_e(elem,'mousemove')-    .lift_e(function(evt) {-        if (evt.pageX | evt.pageY) {-          return { left: evt.pageX, top: evt.pageY };-        }-        else if (evt.clientX || evt.clientY) {-          return { left : evt.clientX + document.body.scrollLeft,-                   top: evt.clientY + document.body.scrollTop };-        }-        else {-          return { left: 0, top: 0 };-        }-    });-  };--  var mouse_b = function(elem) {-    return mouse_e(elem).hold({ left: 0, top: 0 });-  }-  fxExport(dom,mouse_b,'mouse_b');--  var mouseLeft_b = function(elem) {-    return lift_b(function(v) { return v.left; },mouse_b(elem));-  };-  fxExport(dom,mouseLeft_b,'mouseLeft_b');--  var mouseTop_b = function(elem) {-    return mouse_b(elem).lift_b(function(v) { return v.top; });-  };--  fxExport(dom,mouseTop_b,'mouseTop_b');--  var clicks_e = function(elem) {-    return extractEvent_e(elem,'click');-  };-  fxExport(dom,clicks_e,'clicks_e');--  //////////////////////////////////////////////////////////////////////////////-  // Combinators for web services---	//credit Matt White-	var getURLParam = function (param) {-    var lparam = param.toLowerCase();-    var aReturn = [];-    var strHref = window.location.href;-    var endstr = (strHref.indexOf('#') > -1) ? strHref.indexOf('#') : strHref.length;-    if ( strHref.indexOf("?") > -1 ) {-      var strQueryString = strHref.substring(strHref.indexOf("?")+1,endstr);-      map(function(qp) {-          var eq = qp.indexOf('=');-          var qname = qp.substr(0,eq+1).toLowerCase();-          if(qname == lparam+"=") aReturn.push(decodeURIComponent(qp.substr(eq+1)));-      },strQueryString.split("&"));-    }-    if (aReturn.length == 0) return undefined;-    else if(aReturn.length == 1) return aReturn[0];-    else return aReturn;-	};-  fxExport(domMisc,getURLParam,'getURLParam','$URL');--	//credit Quirksmode-	//readCookie: String -> String U Undefined-	var readCookie = function (name) {-    var nameEQ = name + "=";-    var ca = document.cookie.split(';');-    for (var i=0; i < ca.length; i++) {-      var co = ca[i];-      while (co.charAt(0) == ' ') { co = co.substring(1, co.length); }-      if (co.indexOf(nameEQ) === 0) {-        return co.substring(nameEQ.length, co.length);-      }-    }-    return undefined;-	};-  fxExport(domMisc,readCookie,'readCookie');--  //========== dynamic scripts ==========-  var scriptCounter = 0;-  var deleteScript = function (scriptID) {-    var scriptD = getObj(scriptID);-    scriptD.parentNode.removeChild(scriptD); //TODO isolate child and set innerHTML to "" to avoid psuedo-leaks?-  };--  // optional fn/param that gets polled until parm is defined-  var runScript = function (url, fn, param) {-    var script = document.createElement("script");-    script.src = url;-    var scriptID = 'scriptFnRPC' + scriptCounter++;-    script.setAttribute('id', scriptID);-    document.getElementsByTagName("head").item(0).appendChild(script);-    var timer = {};-    var check =-    function () {-      eval("try { if (" + param + "!== undefined) {var stat = " + param + ";}} catch (e) {}");-      if (stat !== undefined) {-        eval(param + " = undefined;");-        clearInterval(timer.timer);-        clearInterval(timer.timeout);-        if (fn instanceof Function) {-          fn(stat);-        }-        deleteScript(scriptID);-      }-    };-    timer.timer = setInterval(check, 3500);-    timer.timeout =-    setTimeout(-      function () {-        try { clearInterval(timer.timer); }-        catch (e) {}-      },-      5000); //TODO make parameter?-  };--  // Node {url, globalArg} -> Node a-  //load script @ url and poll until param is set, then pass it along-  var evalForeignScriptVal_e = function(urlArg_e) {-    var result = receiver_e();-    urlArg_e.lift_e(function(urlArg) {-        runScript(urlArg.url,-          function(val) { result.sendEvent(val); },-          urlArg.globalArg);-    });--    return result;-  };-  fxExport(ws,evalForeignScriptVal_e,'evalForeignScriptVal_e');--  var ajaxRequest = function(method,url,body,async,useFlash,callback) {-    var xhr;-    if (useFlash) {-      xhr = new FlashXMLHttpRequest();-      xhr.onload = function() { callback(xhr); };-    }-    else if (window.XMLHttpRequest && !(window.ActiveXObject)) {-      xhr = new window.XMLHttpRequest();-      xhr.onload = function() { callback(xhr); };-    }-    else if (window.ActiveXObject) {-      try { xhr = new ActiveXObject("Msxml2.XMLHTTP"); }-      catch(e) { xhr = new ActiveXObject("Microsoft.XMLHTTP"); }--      xhr.onreadystatechange = function() {-        if (xhr.readyState == 4) { callback(xhr); }-      };-    };--    xhr.open(method,url,async);--    if (method == 'POST') {-      xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');-    }--    xhr.send(body);-    return xhr;-  };--  var encodeREST = function(obj) {-    var str = "";-    for (var field in obj) {-      if (typeof(obj[field]) !== 'function') { // skips functions in the object-        if (str != '') { str += '&'; }-        str += field + '=' + encodeURIComponent(obj[field]);-      }-    }-    return str;-  };--  // From json.org-  var parseJSON = function(str) {-    try {-        return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(-                str.replace(/"(\\.|[^"\\])*"/g, ''))) &&-            eval('(' + str + ')');-    } catch (e) {-        throw 'cannot parse JSON string: ' + e;-    }-  };--  var toJSONString = (function() {-    var m = {-            '\b': '\\b',-            '\t': '\\t',-            '\n': '\\n',-            '\f': '\\f',-            '\r': '\\r',-            '"' : '\\"',-            '\\': '\\\\'-        };-    var s = {-      array: function (x) {-        var a = ['['], b, f, i, l = x.length, v;-        for (i = 0; i < l; i += 1) {-          v = x[i];-          f = s[typeof v];-          if (f) {-            v = f(v);-            if (typeof v == 'string') {-              if (b) {-                a[a.length] = ',';-              }-              a[a.length] = v;-              b = true;-            }-          }-        }-        a[a.length] = ']';-        return a.join('');-      },-      'boolean': function (x) {-        return String(x);-      },-      'null': function (x) {-        return "null";-      },-      number: function (x) {-        return isFinite(x) ? String(x) : 'null';-      },-      object: function (x) {-        if (x) {-          if (x instanceof Array) {-            return s.array(x);-          }-          var a = ['{'], b, f, i, v;-          for (i in x) {-            v = x[i];-            f = s[typeof v];-            if (f) {-              v = f(v);-              if (typeof v == 'string') {-                if (b) {-                  a[a.length] = ',';-                }-                a.push(s.string(i), ':', v);-                b = true;-              }-            }-          }-          a[a.length] = '}';-          return a.join('');-        }-        return 'null';-      },-      string: function (x) {-        if (/["\\\x00-\x1f]/.test(x)) {-          x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {-              var c = m[b];-              if (c) {-                return c;-              }-              c = b.charCodeAt();-              return '\\u00' +-              Math.floor(c / 16).toString(16) +-              (c % 16).toString(16);-          });-        }-        return '"' + x + '"';-      }-    };-    return function(val) {-      var f = s[typeof val];-      if (f) { return f(val); }-      else { throw 'parseJSON: unknown object type: ' + (typeof val); }-    };-  })();--  var serverRequest_e = function(useFlash,requestE) {-    var response_e = receiver_e();--    requestE.lift_e(function (obj) {-        var body = '';-        var method = 'GET';-        var url = obj.url;--        var reqType = obj.request ? obj.request : (obj.fields ? 'post' : 'get');-        if (obj.request == 'get') {-          url += "?" + encodeREST(obj.fields);-          body = '';-          method = 'GET';-        } else if (obj.request == 'post') {-          body = toJSONString(obj.fields);-          method = 'POST';-        } else if (obj.request == 'rawPost') {-          body = obj.body;-          method = 'POST';-        }-        else if (obj.request == 'rest') {-          body = encodeREST(obj.fields);-          method = 'POST';-        }-        else {-          raise ("Invalid request type: " + obj.request);-        }--        var async = obj.async;--        var xhr;--        // Branch on the response type to determine how to parse it-        if (obj.response == 'json') {-          xhr = ajaxRequest(method,url,body,async,useFlash,-            function(xhr) {-              response_e.sendEvent(parseJSON(xhr.responseText));-            });-        }-        else if (obj.response == 'xml') {-          ajaxRequest(method,url,body,async,useFlash,-            function(xhr) {-              response_e.sendEvent(xhr.responseXML);-            });-        }-        else if (obj.response == 'plain' || !obj.response) {-          ajaxRequest(method,url,body,async,useFlash,-            function(xhr) {-              response_e.sendEvent(xhr.responseText);-          });-        }-        else {-          raise('Unknown response format: ' + obj.response);-        }-    });--    return response_e;-  };--  var getWebServiceObject_e = function(requestE) {-    return serverRequest_e(false,requestE);-  };-  fxExport(ws,getWebServiceObject_e,'getWebServiceObject_e');--  var getForeignWebServiceObject_e = function(requestE) {-    return serverRequest_e(true,requestE);-  };-  fxExport(ws,getForeignWebServiceObject_e,'getForeignWebServiceObject_e');--  var cumulativeOffset = function(element) {-    var valueT = 0, valueL = 0;-    do {-      valueT += element.offsetTop  || 0;-      valueL += element.offsetLeft || 0;-      element = element.offsetParent;-    } while (element);-    return { left: valueL, top: valueT };- };-fxExport(domMisc,cumulativeOffset,'cumulativeOffset');--  ///////// OPTIONALLY EXPORT PUBLIC FUNCTIONS TO GLOBAL NAMESPACE-  if (!options.hideAll) {-    for (var zz in flapjax.pub) {-      if (!options[zz]) {-        window[zz] = flapjax.pub[zz]; // use eval instead so as to achieve Flash compatibility-      }-    }-  }--  for (var id in exports) {-    if (window[id]) {-      if (options.redefine === false) {-        warn('window.' + id + ' is already defined; Flapjax will not ' +-             'redefine it.');-      }-      else {-        warn('Flapjax is redefining window.' + id + '.');-      }-    }--    if (window[id] && options.redefine === false) {-      // Don't redefine id-    }-    else if (options.show && options.hide && options.show[id] === true &&-        options.hide[id] === true) {-      throw('flapjaxInit: invalid options: ' + id + " specified as 'show' and 'hide'");-    }-    else if (options.show && options.show[id]) {-      window[id] = exports[id];-    }-    else if (options.hide && options.hide[id]) {-      // do nothing -- don't export-    }-    // Default behavior--check if it is a synonym first ...-    else if (!synonyms[id] || options.includeSynonyms) {-      // ... then export if its of the right category-      if (options.exportMisc && exports[id].__flapjaxCategory === misc) {-        window[id] = exports[id];-      }-      else if (options.exportDOMMisc && exports[id].__flapjaxCategory === domMisc) {-        window[id] = exports[id];-      }-      else if (options.exportDOM && exports[id].__flapjaxCategory === dom) {-        window[id] = exports[id];-      }-      else if (options.exportCore && exports[id].__flapjaxCategory === core) {-        window[id] = exports[id];-      }-      else if (options.exportWS && exports[id].__flapjaxCategory === ws) {-        window[id] = exports[id];-      }-    }-  }--  return exports;-}
− tests/parse-pretty/neg.js
@@ -1,2 +0,0 @@-var foo = -x;-var bar = +y;
− tests/parse-pretty/numbers.js
@@ -1,2 +0,0 @@-var x = 23;-var y = 23.0;
− tests/parse-pretty/object-lit-1.js
@@ -1,4 +0,0 @@-var x = {  // avoid ambiguity with BlockStmt-  foo : 23, -  bar : 50 -}
− tests/parse-pretty/object-lit-2.js
@@ -1,4 +0,0 @@-var x = {  // avoid ambiguity with BlockStmt-  foo : 23, -  bar : 50, -} 
− tests/parse-pretty/prefix-chain.js
@@ -1,4 +0,0 @@-var w = typeof typeof 34;-var x = ! -- x; // derived from jQuery-var y = ! !x; // derived from Prototype-var z = !! -- x;
− tests/parse-pretty/strings.js
@@ -1,6 +0,0 @@-var x = '\b';-var z = {-  '\b': '\\b' // lhs is a PropString, not a StringLit, but must be printed-              //  as a StringLit-};-var w = "\\s";