diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,14 @@
 Version change log.
 
+=0.10=
+
+The ParenExpr constructor was removed from the Expression AST
+(WARNING: might break some builds). The pretty printer was rewritten
+to automatically parenthesize sub-expressions based on operator
+precedence. Added a (beta quality) arbitrary instance for all the
+AST's to generate random JavaScript programs (useful for testing).
+
+
 =0.9.1= 
 Increased the upper bound on data-default in dependencies. See
 https://github.com/jswebtools/language-ecmascript/pull/5
diff --git a/language-ecmascript.cabal b/language-ecmascript.cabal
--- a/language-ecmascript.cabal
+++ b/language-ecmascript.cabal
@@ -1,5 +1,5 @@
 Name:           language-ecmascript
-Version:        0.9.1
+Version:        0.10
 Cabal-Version:	>= 1.10
 Copyright:      (c) 2007-2012 Brown University, (c) 2008-2010 Claudiu Saftoiu,
                 (c) 2012 Stevens Institute of Technology
@@ -30,7 +30,7 @@
 Source-repository this
    type: git
    location: git://github.com/jswebtools/language-ecmascript.git
-   tag: 0.9
+   tag: 0.9.1
 
 Library
   Hs-Source-Dirs:
@@ -43,7 +43,8 @@
     containers >= 0.1,
     syb >= 0.1,
     uniplate >= 1.6 && <1.7,
-    data-default >= 0.4 && <0.6
+    data-default >= 0.4 && <0.6,
+    QuickCheck >= 2.4.1.1
   ghc-options:
     -fwarn-incomplete-patterns
   Exposed-Modules:
@@ -53,6 +54,7 @@
     Language.ECMAScript3.PrettyPrint
     Language.ECMAScript3.Syntax
     Language.ECMAScript3.Syntax.Annotations
+    Language.ECMAScript3.Syntax.Arbitrary
     Language.ECMAScript3.Analysis.Environment
     Language.ECMAScript3.Analysis.LabelSets
   Default-Extensions:
@@ -73,7 +75,30 @@
     directory,
     filepath,
     HUnit,
-    data-default >=0.4 && <0.6
+    data-default >=0.4 && <0.6,
+    QuickCheck >= 2.4.1.1
+  Default-Extensions: DeriveDataTypeable, ScopedTypeVariables, DeriveFunctor, DeriveFoldable, DeriveTraversable, FlexibleContexts
+  Default-Language: Haskell2010
+  ghc-options:
+    -fwarn-incomplete-patterns
+
+Test-Suite prettytest
+  Hs-Source-Dirs: src
+  Type: exitcode-stdio-1.0
+  Main-Is: PrettyTest.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.5,
+    QuickCheck >= 2.4.1.1,
+    uniplate >= 1.6 && <1.7
   Default-Extensions: DeriveDataTypeable, ScopedTypeVariables, DeriveFunctor, DeriveFoldable, DeriveTraversable, FlexibleContexts
   Default-Language: Haskell2010
   ghc-options:
diff --git a/src/Language/ECMAScript3/Analysis/Environment.hs b/src/Language/ECMAScript3/Analysis/Environment.hs
--- a/src/Language/ECMAScript3/Analysis/Environment.hs
+++ b/src/Language/ECMAScript3/Analysis/Environment.hs
@@ -72,10 +72,10 @@
   CondExpr _ e1 e2 e3 -> unions [expr e1, expr e2, expr e3]
   AssignExpr _ _ lv e -> unions [lvalue lv, expr e]
   UnaryAssignExpr _ _ lv -> lvalue lv
-  ParenExpr _ e -> expr e
   ListExpr _ es -> unions (map expr es)
   CallExpr _ e es -> unions [expr e, unions $ map expr es]
-  FuncExpr _ _ args s -> nest $ unions [unions $ map decl args, stmt s]
+  FuncExpr _ _ args ss -> nest $ unions [unions $ map decl args
+                                        ,unions $ map stmt ss]
 
 caseClause :: CaseClause SourcePos -> Partial
 caseClause cc = case cc of
@@ -122,8 +122,9 @@
   ReturnStmt _ me -> maybe empty expr me
   WithStmt _ e s -> unions [expr e, stmt s]
   VarDeclStmt _ decls -> unions $ map varDecl decls
-  FunctionStmt _ fnId args s ->
-    unions [decl fnId, nest $ unions [unions $ map decl args, stmt s]]
+  FunctionStmt _ fnId args ss ->
+    unions [decl fnId, nest $ unions [unions $ map decl args,
+                                      unions $ map stmt ss]]
 
 -- |The statically-determinate lexical structure of a JavaScript program.
 data EnvTree = EnvTree (M.Map String SourcePos) [EnvTree]
diff --git a/src/Language/ECMAScript3/Analysis/LabelSets.hs b/src/Language/ECMAScript3/Analysis/LabelSets.hs
--- a/src/Language/ECMAScript3/Analysis/LabelSets.hs
+++ b/src/Language/ECMAScript3/Analysis/LabelSets.hs
@@ -41,7 +41,7 @@
                        -> Statement a
 annotateFuncStmtBodies r w s = case s of
   FunctionStmt a name params body -> 
-    let newbody = descend (annotateStatement r w) body
+    let newbody = map (descend (annotateStatement r w)) body
     in  FunctionStmt a name params newbody
   _ -> s
                        
@@ -52,7 +52,7 @@
                        -> Expression a
 annotateFuncExprBodies r w e = case e of
   FuncExpr a mname params body -> 
-    let newbody = descend (annotateStatement r w) body
+    let newbody = map (descend (annotateStatement r w)) body
     in  FuncExpr a mname params newbody
   _ -> e
 
diff --git a/src/Language/ECMAScript3/Parser.hs b/src/Language/ECMAScript3/Parser.hs
--- a/src/Language/ECMAScript3/Parser.hs
+++ b/src/Language/ECMAScript3/Parser.hs
@@ -1,5 +1,5 @@
--- | Parser for ECMAScript 3.
-
+ -- | Parser for ECMAScript 3.
+{-# LANGUAGE FlexibleContexts #-}
 module Language.ECMAScript3.Parser
   (parse
   , parseScriptFromString
@@ -15,6 +15,9 @@
   , StatementParser
   , ExpressionParser
   , assignExpr
+  -- debugging, remove the next 2 lines
+  , mkDecimal
+  , intLen
   ) where
 
 import Language.ECMAScript3.Lexer hiding (identifier)
@@ -137,7 +140,7 @@
 parseDoWhileStmt = do
   pos <- getPosition
   reserved "do"
-  body <- parseBlockStmt
+  body <- parseStatement
   reserved "while" <?> "while at the end of a do block"
   test <- parseParenExpr <?> "parenthesized test-expression in do loop"
   optional semi
@@ -294,7 +297,8 @@
   name <- try (reserved "function" >> identifier) -- ambiguity with FuncExpr
   args <- parens (identifier `sepBy` comma)
   -- label sets don't cross function boundaries
-  body <- withFreshLabelStack parseBlockStmt <?> "function body in { ... }"
+  BlockStmt _ body <- withFreshLabelStack parseBlockStmt <?> 
+                      "function body in { ... }"
   return (FunctionStmt pos name args body)
 
 parseStatement:: StatementParser
@@ -359,7 +363,7 @@
   name <- optionMaybe identifier
   args <- parens (identifier `sepBy` comma)
   -- labels don't cross function boundaries
-  body <- withFreshLabelStack parseBlockStmt
+  BlockStmt _ body <- withFreshLabelStack parseBlockStmt
   return $ FuncExpr pos name args body
 
 --{{{ parsing strings
@@ -432,12 +436,13 @@
       parseChar = noneOf "/"
   let parseRe = (char '/' >> return "") <|> 
                 (do char '\\'
-                    ch <- anyChar -- TOOD: too lenient
+                    ch <- anyChar -- TODO: too lenient
                     rest <- parseRe
                     return ('\\':ch:rest)) <|> 
                 liftM2 (:) anyChar parseRe
   pos <- getPosition
   char '/'
+  notFollowedBy $ char '/'
   pat <- parseRe --many1 parseChar
   flags <- parseFlags
   spaces -- crucial for Parsec.Token parsers
@@ -467,12 +472,16 @@
   [(hex,"")] <- return $ Numeric.readHex digits
   return (True, hex)
 
--- Creates a decimal value from a whole, fractional and exponent part.
-mkDecimal:: Double -> Double -> Int -> Double
-mkDecimal w f e =  if f >= 1.0
-                   then mkDecimal w (f / 10.0) e
-                   else (w + f) * (10.0 ^^ e)
+-- | Creates a decimal value from a whole, fractional and exponent part.
+mkDecimal :: Integer -> Integer -> Integer -> Integer -> Double
+mkDecimal whole frac fracLen exp = 
+  ((fromInteger whole) + ((fromInteger frac) * (10 ^^ (-fracLen)))) * (10 ^^ exp)
 
+-- mkDecimal:: Double -> Double -> Int -> Double
+-- mkDecimal w f e =  if f >= 1.0
+--                    then mkDecimal w (f / 10.0) e
+--                    else (w + f) * (10.0 ^^ e)
+
 exponentPart = do
   oneOf "eE"
   (char '+' >> decimal) <|> (char '-' >> negate `fmap` decimal) <|> decimal
@@ -486,13 +495,19 @@
       mexp <-  option Nothing (jparser exponentPart)
       if isNothing mfrac && isNothing mexp
         then return (True, fromIntegral whole)
-        else return (False, mkDecimal (fromIntegral whole) 
-                                      (fromIntegral (fromMaybe 0 mfrac))
-                                      (fromIntegral (fromMaybe 0 mexp)))) <|>
+        else let frac = fromIntegral (fromMaybe 0 mfrac)
+             in  return (False, mkDecimal (fromIntegral whole) frac 
+                                          (intLen frac)
+                                          (fromIntegral (fromMaybe 0 mexp))))
+  <|>
   (do frac <- char '.' >> decimal
       exp <- option 0 exponentPart
-      return (False, mkDecimal 0.0 (fromIntegral frac) (fromIntegral exp)))
+      let ifrac = fromIntegral frac
+      return (False, mkDecimal 0 ifrac (intLen frac) (fromIntegral exp)))
 
+intLen i | i `div` 10 < 1 = 1
+intLen i | otherwise = 1 + intLen (i `div` 10)
+
 parseNumLit:: ExpressionParser
 parseNumLit = do
     pos <- getPosition
@@ -528,7 +543,7 @@
 -------------------------------------------------------------------------------
 
 parseParenExpr:: ExpressionParser
-parseParenExpr = withPos ParenExpr (parens parseListExpr)
+parseParenExpr = parens parseListExpr
 
 -- everything above expect functions
 parseExprForNew = parseThisRef <|> parseNullLit <|> parseBoolLit <|> parseStringLit 
@@ -720,7 +735,10 @@
 parseExpression:: ExpressionParser
 parseExpression = assignExpr
 
-parseListExpr = liftM2 ListExpr getPosition (assignExpr `sepBy1` comma)
+parseListExpr = assignExpr `sepBy1` comma >>= \exprs ->
+  case exprs of
+    [expr] -> return expr
+    es     -> liftM2 ListExpr getPosition (return es)
 
 parseScript:: CharParser (JavaScript SourcePos)
 parseScript = do
@@ -728,8 +746,8 @@
   liftM2 Script getPosition (parseStatement `sepBy` whiteSpace)
   
 -- | Parse from a stream; same as 'Text.Parsec.parse'
-parse :: Stream s Identity t =>
-         Parsec s [String] a -- ^ The parser to use
+parse :: Stream s Identity t 
+      => Parsec s [String] a -- ^ The parser to use
       -> SourceName -- ^ Name of the source file
       -> s -- ^ the stream to parse, usually a 'String'
       -> Either ParseError a
diff --git a/src/Language/ECMAScript3/PrettyPrint.hs b/src/Language/ECMAScript3/PrettyPrint.hs
--- a/src/Language/ECMAScript3/PrettyPrint.hs
+++ b/src/Language/ECMAScript3/PrettyPrint.hs
@@ -1,8 +1,6 @@
 -- |Pretty-printing JavaScript.
 module Language.ECMAScript3.PrettyPrint
   ( 
---    stmt
---  , expr
   javaScript
   , renderStatements
   , renderExpression
@@ -10,6 +8,7 @@
 
 import Text.PrettyPrint.HughesPJ
 import Language.ECMAScript3.Syntax
+import Prelude hiding (maybe)
 
 -- | Renders a list of statements as a 'String'
 renderStatements :: [Statement a] -> String
@@ -17,69 +16,76 @@
 
 -- | Renders a list of statements as a 'String'
 renderExpression :: Expression a -> String
-renderExpression = render . expr
+renderExpression = render . (ppExpression True)
 
 -- Displays the statement in { ... }, unless it is a block itself.
 inBlock:: Statement a -> Doc
-inBlock s@(BlockStmt _ _) = stmt s
-inBlock s                 = lbrace $+$ nest 2 (stmt s) $+$ rbrace
+inBlock s@(BlockStmt _ _) = ppStatement s
+inBlock s                 = asBlock [s]
 
--- Displays the expression in ( ... ), unless it is a parenthesized expression
-inParens:: Expression a -> Doc
-inParens e@(ParenExpr _ _) = expr e
-inParens e                 = parens (expr e)
+asBlock :: [Statement a] -> Doc
+asBlock ss = lbrace $+$ nest 2 (stmtList ss) $$ rbrace
 
-pp (Id _ str) = text str
+ppId (Id _ str) = text str
 
 forInit :: ForInit a -> Doc
 forInit t = case t of
   NoInit     -> empty
-  VarInit vs -> text "var" <+> cat (punctuate comma $ map varDecl vs)
-  ExprInit e -> expr e
+  VarInit vs -> text "var" <+> cat (punctuate comma $ map (ppVarDecl False) vs)
+  ExprInit e -> ppExpression False e
 
 forInInit :: ForInInit a -> Doc  
 forInInit t = case t of
-  ForInVar id   -> text "var" <+> pp id
-  ForInLVal lv -> lvalue lv
+  ForInVar id   -> text "var" <+> ppId id
+  ForInLVal lv -> ppLValue lv
 
 caseClause :: CaseClause a -> Doc
 caseClause (CaseClause _ e ss) =
-  text "case" $+$ expr e <+> colon $$ nest 2 (stmtList ss)
+  text "case" $+$ ppExpression True e <+> colon $$ nest 2 (stmtList ss)
 caseClause (CaseDefault _ ss) =
   text "default:" $$ nest 2 (stmtList ss)
 
-varDecl :: VarDecl a -> Doc
-varDecl (VarDecl _ id Nothing) = pp id
-varDecl (VarDecl _ id (Just e)) = pp id <+> equals <+> expr e
+ppVarDecl :: Bool -> VarDecl a -> Doc
+ppVarDecl hasIn vd = case vd of
+  VarDecl _ id Nothing  -> ppId id
+  VarDecl _ id (Just e) -> ppId id <+> equals <+> ppAssignmentExpression hasIn e
 
-stmt :: Statement a -> Doc
-stmt s = case s of
-  BlockStmt _ ss -> lbrace $+$ nest 2 (stmtList ss) $$ rbrace
+ppStatement :: Statement a -> Doc
+ppStatement s = case s of
+  BlockStmt _ ss -> asBlock ss
   EmptyStmt _ -> semi
-  ExprStmt _ e -> expr e <> semi
-  IfSingleStmt _ test cons -> text "if" <+> inParens test $$ stmt cons
-  IfStmt _ test cons alt ->
-    text "if" <+> inParens test $$ stmt cons $$ text "else" <+> stmt alt
+  ExprStmt _ e@(CallExpr _ (FuncExpr {}) _ ) -> 
+    parens (ppExpression True e) <> semi
+  ExprStmt _ e -> ppExpression True e <> semi
+  IfSingleStmt _ test cons -> text "if" <+> 
+                              parens (ppExpression True test) $$ 
+                              ppStatement cons
+  IfStmt _ test cons alt -> text "if" <+> parens (ppExpression True test) $$ 
+                            ppStatement cons $$ text "else" <+> ppStatement alt
   SwitchStmt _ e cases ->
-    text "switch" <+> inParens e $$ 
+    text "switch" <+> parens (ppExpression True e) $$ 
     braces (nest 2 (vcat (map caseClause cases)))
-  WhileStmt _ test body -> text "while" <+> inParens test $$ stmt body
+  WhileStmt _ test body -> text "while" <+> parens (ppExpression True test) $$
+                           ppStatement body
   ReturnStmt _ Nothing -> text "return"
-  ReturnStmt _ (Just e) -> text "return" <+> expr e
+  ReturnStmt _ (Just e) -> text "return" <+> ppExpression True e
   DoWhileStmt _ s e -> 
-    text "do" $$ (stmt s <+> text "while" <+> inParens e <> semi)
+    text "do" $$ 
+    (ppStatement s <+> text "while" <+> parens (ppExpression True e) <> semi)
   BreakStmt _ Nothing ->  text "break" <> semi
-  BreakStmt _ (Just label) -> text "break" <+> pp label <> semi
+  BreakStmt _ (Just label) -> text "break" <+> ppId label <> semi
   ContinueStmt _ Nothing -> text "continue" <> semi
-  ContinueStmt _ (Just label) -> text"continue" <+> pp label <> semi
-  LabelledStmt _ label s -> pp label <> colon $$ stmt s
+  ContinueStmt _ (Just label) -> text"continue" <+> ppId label <> semi
+  LabelledStmt _ label s -> ppId label <> colon $$ ppStatement s
   ForInStmt p init e body -> 
     text "for" <+> 
-    parens (forInInit init <+> text "in" <+> expr e) $+$ stmt body
+    parens (forInInit init <+> text "in" <+> ppExpression True e) $+$ 
+    ppStatement body
   ForStmt _ init incr test body ->
     text "for" <+> 
-    parens (forInit init <> semi <+> mexpr incr <> semi <+> mexpr test) $$ 
-    stmt body
+    parens (forInit init <> semi <+> maybe incr (ppExpression True) <> 
+            semi <+> maybe test (ppExpression True)) $$ 
+    ppStatement body
   TryStmt _ stmt mcatch mfinally ->
     text "try" $$ inBlock stmt $$ ppCatch $$ ppFinally 
     where ppFinally = case mfinally of
@@ -88,22 +94,22 @@
           ppCatch = case mcatch of
             Nothing -> empty
             Just (CatchClause _ id s) -> 
-              text "catch" <+> (parens.pp) id <+> inBlock s
-  ThrowStmt _ e -> text "throw" <+> expr e <> semi
-  WithStmt _ expr s ->  text "with" <+> inParens expr $$ stmt s
+              text "catch" <+> (parens.ppId) id <+> inBlock s
+  ThrowStmt _ e -> text "throw" <+> ppExpression True e <> semi
+  WithStmt _ e s -> text "with" <+> parens (ppExpression True e) $$ ppStatement s
   VarDeclStmt _ decls ->
-    text "var" <+> cat (punctuate comma (map varDecl decls)) <> semi
-  FunctionStmt _ name args s ->
-    text "function" <+> pp name <> 
-    parens (cat $ punctuate comma (map pp args)) $$ 
-    inBlock s
+    text "var" <+> cat (punctuate comma (map (ppVarDecl True) decls)) <> semi
+  FunctionStmt _ name args body ->
+    text "function" <+> ppId name <> 
+    parens (cat $ punctuate comma (map ppId args)) $$ 
+    asBlock body
 
 stmtList :: [Statement a] -> Doc
-stmtList = vcat . map stmt
+stmtList = vcat . map ppStatement
 
 prop :: Prop a -> Doc
 prop p = case p of
-  PropId _ id -> pp id
+  PropId _ id -> ppId id
   PropString _ str -> doubleQuotes (text (jsEscape str))
   PropNum _ n -> text (show n)
 
@@ -173,57 +179,186 @@
     sel '\\' = "\\\\"
     sel x    = [x]
     -- We don't have to do anything about \X, \x and \u escape sequences.
+    
+regexpEscape :: String -> String
+regexpEscape "" = ""
+regexpEscape "\\" = "\\\\"
+regexpEscape ('\\':c:rest) = '\\':c:(regexpEscape rest)
+regexpEscape ('/':rest) = '\\':'/':regexpEscape rest
+regexpEscape (c:rest)   = c:regexpEscape rest
 
-lvalue :: LValue a -> Doc
-lvalue (LVar _ x) = text x
-lvalue (LDot _ e x) = expr e <> text "." <> text x
-lvalue (LBracket _ e1 e2) = expr e1 <> brackets (expr e2)
- 
-expr :: Expression a -> Doc
-expr e = case e of 
-  StringLit _ str ->  doubleQuotes (text (jsEscape str))
-  RegexpLit _ re global ci -> 
-    text "/" <> text re <> text "/" <> g <> i where
-      g = if global then text "g" else empty
-      i = if ci then text "i" else empty
-  NumLit _ n ->  text (show n)
+ppLValue :: LValue a -> Doc
+ppLValue (LVar _ x) = text x
+ppLValue (LDot _ e x) = ppMemberExpression e <> text "." <> text x
+ppLValue (LBracket _ e1 e2) = ppMemberExpression e1 <> 
+                              brackets (ppExpression True e2)
+
+-- 11.1
+ppPrimaryExpression :: Expression a -> Doc
+ppPrimaryExpression e = case e of
+  ThisRef _ -> text "this"
+  VarRef _ id -> ppId id
+  NullLit _ -> text "null"
+  BoolLit _ True -> text "true"
+  BoolLit _ False -> text "false"
+  NumLit  _ n -> text (show n)
   IntLit _ n ->  text (show n)
-  BoolLit _ True ->  text "true"
-  BoolLit _ False ->  text "false"
-  NullLit _ ->  text "null"
-  ArrayLit _ es ->  brackets $ cat $ punctuate comma (map expr es)
+  StringLit _ str -> doubleQuotes (text (jsEscape str))
+  RegexpLit _ reg g ci -> text "/" <> (text (regexpEscape reg)) <> text "/" <>
+                          (if g then text "g" else empty) <> 
+                          (if ci then text "i" else empty)
+  ArrayLit _ es -> 
+    brackets $ cat $ punctuate comma (map (ppAssignmentExpression True) es)
   ObjectLit _ xs ->  
     braces (hsep (punctuate comma (map pp' xs))) where
-      pp' (n,v) =  prop n <> colon <+> expr v
-  ThisRef _ ->  text "this"
-  VarRef _ id ->  pp id
-  DotRef _ e' id -> expr e' <> text "." <> pp id
-  BracketRef _ container key -> expr container <> brackets (expr key)
-  NewExpr _ constr args -> 
-    text "new" <+> expr constr <> 
-    parens (cat $ punctuate comma (map expr args))
-  PrefixExpr _ op e' -> prefixOp op <+> expr e'
-  InfixExpr _ op left right -> expr left <+> infixOp op <+> expr right
-  CondExpr _ test cons alt -> 
-    expr test <+> text "?" <+> expr cons <+> colon <+> expr alt
-  AssignExpr _ op l r ->  lvalue l <+> assignOp op <+> expr r
-  UnaryAssignExpr _ op e' -> case op of
-    PrefixInc -> text "++" <> lvalue e'
-    PrefixDec -> text "--" <> lvalue e'
-    PostfixInc -> lvalue e' <> text "++"
-    PostfixDec -> lvalue e' <> text "--"
-  ParenExpr _ e' ->  parens (expr e')
-  ListExpr _ es ->  cat $ punctuate comma (map expr es)
-  CallExpr _ f args -> 
-    expr f <> parens (cat $ punctuate comma (map expr args))
-  FuncExpr _ name args body -> 
-    text "function" <+> text (maybe "" unId name) <+>
-    parens (cat $ punctuate comma (map pp args)) $$ 
-    inBlock body
+      pp' (n,v) =  prop n <> colon <+> ppAssignmentExpression True v
+  _ -> parens $ ppExpression True e
 
-mexpr :: Maybe (Expression a) -> Doc
-mexpr Nothing = empty
-mexpr (Just e) = expr e
+-- 11.2
+ppMemberExpression :: Expression a -> Doc
+ppMemberExpression e = case e of
+  FuncExpr _ name params body -> 
+    text "function" <+> maybe name ppId <+>
+    parens (cat $ punctuate comma (map ppId params)) $$ 
+    asBlock body
+  DotRef _ obj id -> ppMemberExpression obj <> text "." <> ppId id
+  BracketRef _ obj key -> 
+    ppMemberExpression obj <> brackets (ppExpression True key)  
+  NewExpr _ ctor args -> 
+    text "new" <+> ppMemberExpression ctor <> ppArguments args
+  _ -> ppPrimaryExpression e
+
+ppCallExpression :: Expression a -> Doc
+ppCallExpression e = case e of
+  CallExpr _ f args -> ppCallExpression f <> ppArguments args
+  DotRef _ obj id -> ppCallExpression obj <> text "." <> ppId id
+  BracketRef _ obj key ->ppCallExpression obj <> brackets (ppExpression True key)
+  _ -> ppMemberExpression e  
+    
+ppArguments :: [Expression a] -> Doc
+ppArguments es = 
+  parens $ cat $ punctuate comma (map (ppAssignmentExpression True) es)
+
+ppLHSExpression :: Expression a -> Doc
+ppLHSExpression = ppCallExpression
+
+-- 11.3
+ppPostfixExpression :: Expression a -> Doc
+ppPostfixExpression e = case e of
+  UnaryAssignExpr _ PostfixInc e' -> ppLValue e' <> text "++"
+  UnaryAssignExpr _ PostfixDec e' -> ppLValue e' <> text "--"
+  _ -> ppLHSExpression e
+  
+-- 11.4
+ppUnaryExpression :: Expression a -> Doc
+ppUnaryExpression e = case e of
+  PrefixExpr _ op e' -> prefixOp op <+> ppUnaryExpression e'
+  UnaryAssignExpr _ PrefixInc e' -> text "++" <> ppLValue e'
+  UnaryAssignExpr _ PrefixDec e' -> text "--" <> ppLValue e'
+  _ -> ppPostfixExpression e
+
+-- 11.5
+ppMultiplicativeExpression :: Expression a -> Doc
+ppMultiplicativeExpression e = case e of
+  InfixExpr _ op e1 e2 | op `elem` [OpMul, OpDiv, OpMod] -> 
+    ppMultiplicativeExpression e1 <+> infixOp op <+> ppUnaryExpression e2
+  _ -> ppUnaryExpression e
+  
+-- 11.6
+ppAdditiveExpression :: Expression a -> Doc
+ppAdditiveExpression e = case e of
+  InfixExpr _ op e1 e2 | op `elem` [OpAdd, OpSub] -> 
+    ppAdditiveExpression e1 <+> infixOp op <+> ppMultiplicativeExpression e2
+  _ -> ppMultiplicativeExpression e
+
+-- 11.7
+ppShiftExpression :: Expression a -> Doc
+ppShiftExpression e = case e of
+  InfixExpr _ op e1 e2 | op `elem` [OpLShift, OpSpRShift, OpZfRShift] -> 
+    ppShiftExpression e1 <+> infixOp op <+> ppAdditiveExpression e2  
+  _ -> ppAdditiveExpression e
+
+-- 11.8.  
+-- | @ppRelationalExpression True@ is RelationalExpression,
+-- @ppRelationalExpression False@ is RelationalExpressionNoIn
+ppRelationalExpression :: Bool -> Expression a -> Doc
+ppRelationalExpression hasIn e = 
+  let opsNoIn = [OpLT, OpGT, OpLEq, OpGEq, OpInstanceof]
+      ops     = if hasIn then OpIn:opsNoIn else opsNoIn
+  in case e of    
+    InfixExpr _ op e1 e2 | op `elem` ops -> 
+      ppRelationalExpression hasIn e1 <+> infixOp op <+> ppShiftExpression e2
+    _ -> ppShiftExpression e
+    
+-- 11.9
+ppEqualityExpression :: Bool -> Expression a -> Doc
+ppEqualityExpression hasIn e = case e of
+  InfixExpr _ op e1 e2 | op `elem` [OpEq, OpNEq, OpStrictEq, OpStrictNEq] ->
+    ppEqualityExpression hasIn e1 <+> infixOp op <+> 
+    ppRelationalExpression hasIn e2
+  _ -> ppRelationalExpression hasIn e
+  
+-- 11.10
+ppBitwiseANDExpression :: Bool -> Expression a -> Doc
+ppBitwiseANDExpression hasIn e = case e of
+  InfixExpr _ op@OpBAnd e1 e2 -> ppBitwiseANDExpression hasIn e1 <+> 
+                                 infixOp op <+>
+                                 ppEqualityExpression hasIn e2
+  _ -> ppEqualityExpression hasIn e
+  
+ppBitwiseXORExpression :: Bool -> Expression a -> Doc
+ppBitwiseXORExpression hasIn e = case e of
+  InfixExpr _ op@OpBXor e1 e2 -> ppBitwiseXORExpression hasIn e1 <+>
+                                 infixOp op <+>
+                                 ppBitwiseANDExpression hasIn e2
+  _ -> ppBitwiseANDExpression hasIn e
+  
+ppBitwiseORExpression :: Bool -> Expression a -> Doc
+ppBitwiseORExpression hasIn e = case e of
+  InfixExpr _ op@OpBOr e1 e2 -> ppBitwiseORExpression hasIn e1 <+>
+                                infixOp op <+>
+                                ppBitwiseXORExpression hasIn e2
+  _ -> ppBitwiseXORExpression hasIn e
+
+-- 11.11
+ppLogicalANDExpression :: Bool -> Expression a -> Doc
+ppLogicalANDExpression hasIn e = case e of
+  InfixExpr _ op@OpLAnd e1 e2 -> ppLogicalANDExpression hasIn e1 <+>
+                                 infixOp op <+>
+                                 ppBitwiseORExpression hasIn e2
+  _ -> ppBitwiseORExpression hasIn e                                 
+                                 
+ppLogicalORExpression :: Bool -> Expression a -> Doc
+ppLogicalORExpression hasIn e = case e of
+  InfixExpr _ op@OpLOr e1 e2 -> ppLogicalORExpression hasIn e1 <+>
+                                infixOp op <+>
+                                ppLogicalANDExpression hasIn e2
+  _ -> ppLogicalANDExpression hasIn e
+  
+-- 11.12
+ppConditionalExpression :: Bool -> Expression a -> Doc
+ppConditionalExpression hasIn e = case e of
+  CondExpr _ c et ee -> ppLogicalORExpression hasIn c <+> text "?" <+> 
+                        ppAssignmentExpression hasIn et <+> colon <+>
+                        ppAssignmentExpression hasIn ee
+  _ -> ppLogicalORExpression hasIn e
+
+-- 11.13
+ppAssignmentExpression :: Bool -> Expression a -> Doc
+ppAssignmentExpression hasIn e = case e of
+  AssignExpr _ op l r -> ppLValue l <+> assignOp op <+> 
+                         ppAssignmentExpression hasIn r
+  _ -> ppConditionalExpression hasIn e
+  
+-- 11.14
+ppExpression :: Bool -> Expression a -> Doc
+ppExpression hasIn e = case e of
+  ListExpr _ es -> cat $ punctuate comma (map (ppExpression hasIn) es)
+  _ -> ppAssignmentExpression hasIn e
+
+maybe :: Maybe a -> (a -> Doc) -> Doc
+maybe Nothing  _ = empty
+maybe (Just a) f = f a
 
 -- | Renders a JavaScript program as a document, the show instance of
 -- 'Doc' will pretty-print it automatically
diff --git a/src/Language/ECMAScript3/Syntax.hs b/src/Language/ECMAScript3/Syntax.hs
--- a/src/Language/ECMAScript3/Syntax.hs
+++ b/src/Language/ECMAScript3/Syntax.hs
@@ -1,4 +1,9 @@
--- |ECMAScript 3 syntax. /Spec/ refers to the ECMA-262 specification, 3rd edition.
+-- |ECMAScript 3 syntax. /Spec/ refers to the ECMA-262 specification,
+-- 3rd edition.
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE DeriveTraversable #-}
+{-# LANGUAGE DeriveFoldable #-}
 module Language.ECMAScript3.Syntax (JavaScript(..)
                                    ,unJavaScript
                                    ,Statement(..)
@@ -147,11 +152,10 @@
     -- ^ @e1 ? e2 : e3@, spec 11.12
   | AssignExpr a AssignOp (LValue a) (Expression a)
     -- ^ @e1 \@=e2@, spec 11.13
-  | ParenExpr a (Expression a) -- ^ @(e)@, spec 11.1.6
   | ListExpr a [Expression a] -- ^ @e1, e2@, spec 11.14
   | CallExpr a (Expression a) [Expression a] -- ^ @f(x,y,z)@, spec 11.2.3
   --funcexprs are optionally named
-  | FuncExpr a (Maybe (Id a)) [Id a] (Statement a) 
+  | FuncExpr a (Maybe (Id a)) [Id a] [Statement a]
     -- ^ @function f (x,y,z) {...}@, spec 11.2.5, 13
   deriving (Show,Data,Typeable,Eq,Ord,Functor,Foldable,Traversable)
 
@@ -220,7 +224,7 @@
     -- ^ @with (o) stmt@, spec 12.10
   | VarDeclStmt a [VarDecl a]
     -- ^ @var x, y=42;@, spec 12.2
-  | FunctionStmt a (Id a) {-name-} [Id a] {-args-} (Statement a) {-body-}
+  | FunctionStmt a (Id a) {-name-} [Id a] {-args-} [Statement a] {-body-}
     -- ^ @function f(x, y, z) {...}@, spec 13
   deriving (Show,Data,Typeable,Eq,Ord,Functor,Foldable,Traversable)  
 
diff --git a/src/Language/ECMAScript3/Syntax/Annotations.hs b/src/Language/ECMAScript3/Syntax/Annotations.hs
--- a/src/Language/ECMAScript3/Syntax/Annotations.hs
+++ b/src/Language/ECMAScript3/Syntax/Annotations.hs
@@ -64,7 +64,6 @@
    (InfixExpr a op e1 e2)       -> a
    (CondExpr a g et ef)         -> a
    (AssignExpr a op lv e)       -> a
-   (ParenExpr a e)              -> a
    (ListExpr a es)              -> a
    (CallExpr a fn params)       -> a
    (FuncExpr a mid args s)      -> a
diff --git a/src/Language/ECMAScript3/Syntax/Arbitrary.hs b/src/Language/ECMAScript3/Syntax/Arbitrary.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/ECMAScript3/Syntax/Arbitrary.hs
@@ -0,0 +1,383 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | QuickCheck $Arbitrary$ instances for ECMAScript 3 abstract
+-- syntax.
+
+module Language.ECMAScript3.Syntax.Arbitrary where
+
+import Language.ECMAScript3.Syntax
+import Test.QuickCheck hiding (Prop)
+import Test.QuickCheck.Arbitrary
+import Test.QuickCheck.Property (forAllShrink)
+import Data.Map hiding (map,null,filter,foldr)
+import Data.List (nub,delete)
+import Data.Data
+import Data.Char
+import Data.Generics.Uniplate.Data
+import Data.Generics.Uniplate.Operations
+import Data.Generics.Str
+import Control.Monad
+import Control.Monad.State
+import Data.Maybe (maybeToList)
+
+instance Arbitrary (AssignOp) where
+  arbitrary = 
+    elements [OpAssign, OpAssignAdd, OpAssignSub, OpAssignMul, OpAssignDiv, 
+              OpAssignMod, OpAssignLShift, OpAssignSpRShift, OpAssignZfRShift,
+              OpAssignBAnd, OpAssignBXor, OpAssignBOr]
+
+instance Arbitrary (InfixOp) where
+  arbitrary = 
+    elements [OpLT, OpLEq, OpGT, OpGEq , OpIn , OpInstanceof, OpEq, OpNEq, 
+              OpStrictEq, OpStrictNEq, OpLAnd, OpLOr,
+              OpMul, OpDiv, OpMod , OpSub, OpLShift, OpSpRShift,
+              OpZfRShift, OpBAnd, OpBXor, OpBOr, OpAdd]
+  
+instance Arbitrary (UnaryAssignOp) where
+  arbitrary = 
+    elements [PrefixInc, PrefixDec, PostfixInc, PostfixDec]
+  
+instance Arbitrary (PrefixOp) where
+  arbitrary = 
+    elements [PrefixLNot, PrefixBNot, PrefixPlus, PrefixMinus, 
+              PrefixTypeof, PrefixVoid, PrefixDelete]
+
+
+instance Arbitrary a => Arbitrary (Id a) where
+  arbitrary = liftM2 Id arbitrary identifier
+  shrink (Id a s) = [Id na ns | ns <- shrink s, na <- shrink a]
+
+instance Arbitrary a => Arbitrary (CaseClause a) where
+  arbitrary = oneof [caseclause, casedefault]
+    where caseclause = liftM3 CaseClause arbitrary arbitrary arbitrary
+          casedefault = liftM2 CaseDefault arbitrary arbitrary
+  shrink (CaseClause a expr stmts) = 
+    [CaseClause na ne ns | na <- shrink a, ne <- shrink expr, ns <- shrink stmts]
+  shrink (CaseDefault a stmts) = 
+    [CaseDefault na ns | na <- shrink a, ns <- shrink stmts]
+                         
+instance Arbitrary a => Arbitrary (Prop a) where
+  arbitrary = oneof [liftM2 PropId arbitrary arbitrary,
+                     liftM2 PropString arbitrary nonEmptyString,
+                     liftM2 PropNum arbitrary nonNegative
+                    ]
+  shrink (PropId a id) = [PropId na nid | nid <- shrink id, na <- shrink a] 
+  shrink (PropString a s) = [PropString na ns | ns <- shrink s, na <- shrink a] 
+  shrink (PropNum a i) = [PropNum na ni | ni <- shrink i, na <- shrink a] 
+  
+instance Arbitrary a => Arbitrary (LValue a) where  
+  arbitrary = oneof [liftM2 LVar arbitrary identifier,
+                     liftM3 LDot arbitrary arbitrary identifier,
+                     liftM3 LBracket arbitrary arbitrary arbitrary]
+  shrink (LVar a s) = [LVar na ns | ns <- shrink s, na <- shrink a]
+  shrink (LDot a e s) = [LDot na ne ns | ne <- shrink e, ns <-shrink s, na <-shrink a]
+  shrink (LBracket a e1 e2) = [LBracket na ne1 ne2 | ne1 <- shrink e1, ne2 <-shrink e2, na <- shrink a]
+  
+cshrink :: Arbitrary a => [a] -> [a]
+cshrink = concat . shrink
+
+identifier :: Gen String
+identifier = sized sizedIdent
+    where sizedIdent n = do s <- identStart
+                            rest <- identRest (n-1)
+                            return (s:rest)
+          identStart = arbitrary `suchThat` isIdentStart
+          identRest n | n < 1 = return ""
+          identRest n = do p <- identPart
+                           rest <- identRest (n-1)
+                           return (p:rest)
+          identPart = do arbitrary `suchThat` isIdentPart
+          isIdentStart c = isLetter c || c == '$' || c == '_'
+          isIdentPart c = isIdentStart c || isMark c || isNumber c
+
+-- minimum size generator
+type MSGen a = (Int, Gen a)
+
+sGen :: [MSGen a] -> Gen a
+sGen gens = 
+  sized f 
+  where f n | n >= 0 = oneof $ map snd (filter (\(m, _) -> n >= m) gens)
+        f _          = f 0
+
+recursive :: Gen a -> Gen a
+recursive g = sized (\n -> resize (n-1) g)
+
+rarbitrary :: Arbitrary a => Gen a
+rarbitrary = recursive arbitrary
+
+rrarbitrary :: Arbitrary a => Gen a
+rrarbitrary = recursive $ recursive arbitrary
+
+atLeastOfSize :: Arbitrary a => Int -> Gen a -> Gen a
+atLeastOfSize l gen = sized $ \s -> if s < l then resize l gen else gen
+
+nonEmptyString :: Gen String
+nonEmptyString = sized $ \s -> if s < 1 then stringOfLength 1 else stringOfLength s
+
+regexpBody = nonEmptyString
+
+nonNegative :: (Arbitrary a, Num a) => Gen a
+nonNegative = liftM abs arbitrary
+
+stringOfLength :: Int -> Gen String
+stringOfLength 0 = return ""
+stringOfLength n = do c <- arbitrary
+                      rs <- stringOfLength (n-1)
+                      return (c:rs)
+
+instance Arbitrary a => Arbitrary (Expression a) where
+  arbitrary = 
+    sGen [(0, liftM  ThisRef arbitrary),
+          (0, liftM  NullLit arbitrary),
+          (0, liftM2 StringLit arbitrary arbitrary),
+          (0, liftM2 NumLit arbitrary nonNegative),
+          (0, liftM2 IntLit arbitrary nonNegative),
+          (0, liftM2 BoolLit arbitrary arbitrary),
+          (0, liftM4 RegexpLit arbitrary regexpBody arbitrary arbitrary),
+          (1, liftM2 ArrayLit arbitrary rarbitrary),
+          (1, liftM2 ObjectLit arbitrary rarbitrary),
+          (0, liftM2 VarRef arbitrary arbitrary),
+          (1, liftM3 DotRef arbitrary rarbitrary arbitrary),
+          (2, liftM3 BracketRef arbitrary rarbitrary rarbitrary),
+          (3, liftM3 NewExpr arbitrary rarbitrary rrarbitrary),
+          (1, liftM3 PrefixExpr arbitrary arbitrary rarbitrary),
+          (2, liftM3 UnaryAssignExpr arbitrary arbitrary rarbitrary),
+          (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, liftM3 CallExpr arbitrary rarbitrary rrarbitrary),
+          (1, liftM4 FuncExpr arbitrary arbitrary arbitrary rarbitrary)]
+    
+  shrink (StringLit a s) = [StringLit na ns | na <- shrink a, ns <- shrink s]
+  shrink (RegexpLit a s b1 b2) = [RegexpLit na ns nb1 nb2 | na <- shrink a, nb1 <- shrink b1, nb2 <- shrink b2, ns <- shrink s]
+  shrink (NumLit a d) = [NumLit na nd | na <- shrink a, nd <- shrink d]
+  shrink (IntLit a i) = [IntLit na ni | na <- shrink a, ni <- shrink i]
+  shrink (BoolLit a b) = [BoolLit na nb | na <- shrink a, nb <- shrink b]
+  shrink (NullLit a) = [NullLit na | na <- shrink a]
+  shrink (ArrayLit a xs) = (cshrink xs) ++ xs ++ [ArrayLit na nxs | na <- shrink a, nxs <- shrink xs]
+  shrink (ObjectLit a xs) =  
+    let es = map snd xs in
+    (cshrink es) ++ es ++
+    [ObjectLit na nxs | na <- shrink a, nxs <- shrink xs]
+  shrink (ThisRef a) = [ThisRef na | na <- shrink a]
+  shrink (VarRef a id) = [VarRef na nid | na <- shrink a, nid <- shrink id]
+  shrink (DotRef a e id) = [DotRef na ne nid | na <-shrink a, nid <- shrink id,  ne <- shrink e]
+  shrink (BracketRef a o k) = [BracketRef na no nk | na <- shrink a, no <-shrink o, nk <- shrink k]
+  shrink (NewExpr a c xs) = (shrink c) ++ [c] ++ (cshrink xs) ++ xs ++ [NewExpr na nc nxs | na <- shrink a, nc <- shrink c,  nxs <- shrink xs]
+  shrink (PrefixExpr a op e) = (shrink e) ++ [e] ++ [PrefixExpr na nop ne | na <- shrink a, nop <-shrink op, ne <- shrink e]
+  shrink (UnaryAssignExpr a op v) = [UnaryAssignExpr na nop nv | na <- shrink a, nop <- shrink op, nv <- shrink v]
+  shrink (InfixExpr a op e1 e2) = (shrink e1) ++ [e1] ++ (shrink e2) ++ [e2] ++ [InfixExpr na nop ne1 ne2 | na <- shrink a, nop <- shrink op, ne1 <- shrink e1, ne2 <- shrink e2]
+  shrink (CondExpr a e1 e2 e3) = (shrink e1) ++ [e1] ++ (shrink e2) ++ [e2] ++ (shrink e3) ++ [e3] ++ [CondExpr na ne1 ne2 ne3 | na <- shrink a, ne1 <- shrink e1, ne2 <- shrink e2, ne3 <- shrink e3]
+  shrink (AssignExpr a op v e) = (shrink e) ++ [e] ++ [AssignExpr na nop nv ne | na <- shrink a, nop <- shrink op, nv <- shrink v, ne <-shrink e] 
+  shrink (ListExpr a es) = (cshrink es) ++ es ++ [ListExpr na nes | na <- shrink a, nes <- shrink es]
+  shrink (CallExpr a e es) = (shrink e) ++ [e] ++ (cshrink es) ++ es ++ [CallExpr na ne nes | na <- shrink a, ne <- shrink e, nes <- shrink es]
+  shrink (FuncExpr a mid ids s) = [FuncExpr na nmid nids ns | na <- shrink a, nmid <-  shrink mid, nids <- shrink ids, ns <- shrink s]
+
+instance Arbitrary a => Arbitrary (ForInInit a) where
+  arbitrary = oneof [liftM ForInVar arbitrary,
+                     liftM ForInLVal arbitrary]
+  shrink (ForInVar id) = [ForInVar nid | nid <- shrink id]
+  shrink (ForInLVal id) = [ForInLVal nid | nid <- shrink id]
+  
+instance Arbitrary a => Arbitrary (ForInit a) where  
+  arbitrary = 
+    frequency [
+      (2, return NoInit),
+      (1, liftM VarInit arbitrary),
+      (1, liftM ExprInit arbitrary)]
+  shrink (NoInit) = []
+  shrink (VarInit vds) = [VarInit nvds | nvds <- shrink vds]
+  shrink (ExprInit e) = [ExprInit ne | ne <- shrink e]
+
+instance Arbitrary a => Arbitrary (CatchClause a) where
+  arbitrary = liftM3 CatchClause arbitrary arbitrary arbitrary
+  shrink (CatchClause a id s) = [CatchClause na nid ns | na <- shrink a, nid <- shrink id, ns <- shrink s]
+  
+instance Arbitrary a => Arbitrary (VarDecl a) where
+  arbitrary = liftM3 VarDecl arbitrary arbitrary arbitrary
+  shrink (VarDecl a id me) = [VarDecl na nid nme | na <- shrink a, nid <- shrink id, nme <- shrink me]
+
+instance Arbitrary a => Arbitrary (Statement a) where
+  arbitrary = 
+    sGen [(2, liftM2 BlockStmt arbitrary rrarbitrary),
+          (0, liftM  EmptyStmt arbitrary),
+          (1, liftM2 ExprStmt arbitrary rarbitrary),
+          (3, liftM4 IfStmt arbitrary rarbitrary rarbitrary rarbitrary),
+          (2, liftM3 IfSingleStmt arbitrary rarbitrary rarbitrary),
+          (3, liftM3 SwitchStmt arbitrary rarbitrary rrarbitrary),
+          (2, liftM3 WhileStmt arbitrary rarbitrary rarbitrary),
+          (2, liftM3 DoWhileStmt arbitrary rarbitrary rarbitrary),
+          (0, liftM2 BreakStmt arbitrary arbitrary),
+          (0, liftM2 ContinueStmt arbitrary arbitrary),
+          (1, liftM3 LabelledStmt arbitrary arbitrary rarbitrary),
+          (3, liftM4 ForInStmt arbitrary rarbitrary rarbitrary rarbitrary),
+          (4, liftM5 ForStmt arbitrary rarbitrary rarbitrary rarbitrary rarbitrary),
+          (4, arbtry),
+          (1, liftM2 ThrowStmt arbitrary rarbitrary),
+          (1, liftM2 ReturnStmt arbitrary rarbitrary),
+          (2, liftM3 WithStmt arbitrary rarbitrary rarbitrary),
+          (2, liftM2 VarDeclStmt arbitrary rrarbitrary),
+          (1, liftM4 FunctionStmt arbitrary arbitrary arbitrary rarbitrary)]
+    where arbtry = 
+            do (mCatch, mFinally) <- oneof [liftM2 (,) (return Nothing) (liftM Just rarbitrary),
+                                            liftM2 (,) (liftM Just rarbitrary) (return Nothing),
+                                            liftM2 (,) (liftM Just rarbitrary) (liftM Just rarbitrary)]
+               a <- arbitrary                      
+               body <- rarbitrary
+               return $ TryStmt a body mCatch mFinally
+    
+  shrink (BlockStmt a body) = emptyStmtShrink a ++ 
+                              [BlockStmt as bs | as <- shrink a, bs <- shrink body]
+  shrink (EmptyStmt a) = emptyStmtShrink a
+  shrink (ExprStmt a e) = emptyStmtShrink a ++ 
+                          [ExprStmt as es | as <- shrink a, es <- shrink e]
+  shrink (IfStmt a e th el) = emptyStmtShrink a ++
+                              [IfStmt as es ths els | as <- shrink a, es <- shrink e, ths <- shrink th, els <- shrink el]
+  shrink (IfSingleStmt a e th) = emptyStmtShrink a ++
+                                 [IfSingleStmt as es ths | as <- shrink a, es <- shrink e, ths <- shrink th]
+  shrink (SwitchStmt a e cases) = emptyStmtShrink a ++
+                                  [SwitchStmt as es cs | as <- shrink a, es <-shrink e, cs <- shrink cases] 
+  shrink (WhileStmt a e b) = emptyStmtShrink a ++
+                             [WhileStmt as es bs | as <- shrink a, es <- shrink e, bs <- shrink b]
+  shrink (DoWhileStmt a b e) = emptyStmtShrink a ++  
+                               [DoWhileStmt as bs es | as <- shrink a, es <- shrink e, bs <- shrink b]
+  shrink (BreakStmt a l) = emptyStmtShrink a ++
+                           [BreakStmt as ls | as <- shrink a, ls <- shrink l]
+  shrink (ContinueStmt a l) = emptyStmtShrink a ++
+                              [ContinueStmt as ls | as <- shrink a, ls <- shrink l]
+  shrink (LabelledStmt a l s) = emptyStmtShrink a ++
+                                [LabelledStmt as ls ss | as <- shrink a, ls <- shrink l, ss <- shrink s]
+  shrink (ForInStmt a i o s) = emptyStmtShrink a ++
+                               [ForInStmt as is os ss | as <- shrink a, is <-shrink i, os <-shrink o, ss <- shrink s]
+  shrink (ForStmt a i e1 e2 s) = emptyStmtShrink a ++
+                                 [ForStmt as is e1s e2s ss | as <- shrink a, is <- shrink i, e1s <- shrink e1, e2s <- shrink e2, ss <- shrink s]
+  shrink (TryStmt a b cs mf) = emptyStmtShrink a ++
+                               [TryStmt as bs css mfs | as <- shrink a, bs <- shrink b, css <- shrink cs, mfs <- shrink mf]
+  shrink (ThrowStmt a e) = emptyStmtShrink a ++
+                           [ThrowStmt as es | as <- shrink a, es <- shrink e]
+  shrink (ReturnStmt a e) = emptyStmtShrink a ++
+                            [ReturnStmt as es | as <- shrink a, es <- shrink e]
+  shrink (WithStmt a o s) = emptyStmtShrink a ++
+                            [WithStmt as os ss | as <- shrink a, os <- shrink o, ss <- shrink s]
+  shrink (VarDeclStmt a vds) = emptyStmtShrink a ++
+                               [VarDeclStmt as vdss | as <- shrink a, vdss <- shrink vds]
+  shrink (FunctionStmt a n pars b) = emptyStmtShrink a ++
+                                     [FunctionStmt as ns parss bs | as <- shrink a, ns <- shrink n, parss <- shrink pars, bs <- shrink b]
+    
+emptyStmtShrink a = [EmptyStmt a2 | a2 <- shrink a]    
+
+type LabelSubst   = Map (Id ()) (Id ())
+emptyConstantPool = Data.Map.empty
+
+instance (Data a, Arbitrary a) => Arbitrary (JavaScript a) where
+  arbitrary = do {s <- liftM2 Script arbitrary arbitrary;
+                  if isProgramFixable s then fixLabels s
+                  else arbitrary}
+  shrink (Script a ss) = [Script na nss | na <- shrink a, nss <- shrink ss]
+  
+-- | Fixes labels so that labeled breaks and continues refer to
+-- existing labeled statements, enclosing them; also, reduces the size
+-- of the label set. Assumes that the program has a proper syntactic
+-- structure, i.e. 'isProgramFixable' s = True.
+fixLabels :: (Data a) => JavaScript a -> Gen (JavaScript a)
+fixLabels s = 
+  fixBreakContinueLabels s >>= removeDuplicateLabels
+          
+-- | choose n elements from a list randomly
+rChooseElem :: [a] -> Int -> Gen [a]
+rChooseElem xs n | n > 0 && (not $ null xs) = 
+  if n >= length xs then return xs
+  else (vectorOf n $ choose (0, n-1)) >>=
+       (\subst -> return $ foldr (\n ys -> (xs!!n):ys) [] subst)
+rChooseElem _  _ = return [] 
+
+-- | A predicate that tells us whether a program has a fixable/correct
+-- label-break/continue structure.  The predicate imposes syntactic
+-- restrictions on the break, continue and labeled statements as in
+-- the ECMA spec
+isProgramFixable :: (Data a ) => JavaScript a -> Bool
+isProgramFixable (Script _ stmts) = 
+  Prelude.and $ 
+  Prelude.map 
+             (\stmt -> isBreakContinueFixable stmt False False False) 
+             stmts
+
+-- | Imposes relaxed restrictions on break and continue per ECMAScript
+-- 5 spec (page 92): any continue without a label should be nested
+-- within an iteration stmt, any continue with a label should be
+-- nested in a labeled statement (not necessarily with the same
+-- label); any break statement without a label should be nested in an
+-- iteration or switch stmt, any break statement with a label should
+-- be nested in a labeled statement (not necessarily with the same
+-- label).
+isBreakContinueFixable :: (Data a) => Statement a -> 
+                                      Bool -> 
+                                      Bool -> 
+                                      Bool ->
+                                      Bool
+isBreakContinueFixable stmt inLabeled inIter inSwitch =
+  case stmt of
+    ContinueStmt _ Nothing -> inIter
+    ContinueStmt _ (Just label) -> inLabeled
+    BreakStmt    _ Nothing -> inIter || inSwitch
+    BreakStmt    _ (Just label) -> inLabeled
+    LabelledStmt _ label _ -> 
+      continue stmt True inIter inSwitch
+    _ -> if isIterationStmt stmt then
+             continue stmt inLabeled True inSwitch
+         else if isSwitchStmt stmt then
+                  continue stmt inLabeled inIter True 
+              else True
+  --  _ -> continue stmt inLabeled inIter inSwitch
+  where continue stmt inLabeled inIter inSwitch =
+                   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
+-- spec (page 95): nested labeled statements cannot have duplicating
+-- labels.
+removeDuplicateLabels :: Data a => JavaScript a -> Gen (JavaScript a)
+removeDuplicateLabels (Script x stmts) =
+    return $ Script x (map (\stmt -> (evalState (transformM removeDL stmt) [])) stmts)
+    where
+      removeDL :: Statement a -> State [String] (Statement a)
+      removeDL stmt@(LabelledStmt x lab s) = 
+          do {enclosingLabels <- get;
+              if Prelude.elem (unId lab) enclosingLabels then return s
+              else modify ((:) $ unId lab) >> return stmt}
+      removeDL s = return s        
+      
+-- | Selects a random element of the list
+selectRandomElement :: [a] -> Gen a
+selectRandomElement xs = 
+  let l = length xs in
+  do n <- arbitrary
+     return $ xs !! (n `mod` l - 1)
+-- | Changes labels of break/continue so that they refer to one of the
+-- enclosing labels
+fixBreakContinueLabels :: Data a => JavaScript a -> Gen (JavaScript a)
+fixBreakContinueLabels (Script x stmts) =
+  do stmts2 <- mapM (\stmt -> (evalStateT (fixBCL stmt) [])) stmts
+     return $ Script x stmts2
+    where
+      fixBCL :: Data a => Statement a -> StateT [String] Gen (Statement a)
+      fixBCL stmt@(LabelledStmt _ lab s) =
+        do modify ((:) $ unId lab)
+           descendM fixBCL stmt
+      fixBCL stmt@(BreakStmt x (Just (Id y lab))) =
+          do {labels <- get;
+              if lab `notElem` labels then
+                  do {newLab <- lift $ selectRandomElement labels;
+                      return $ BreakStmt x (Just $ Id y newLab)}
+              else return stmt}
+      fixBCL stmt@(ContinueStmt x (Just (Id y lab))) =
+          do {labels <- get;
+              if lab `notElem` labels then
+                  do {newLab <- lift $ selectRandomElement labels;
+                      return $ ContinueStmt x (Just $ Id y newLab)}
+              else return stmt}
+      fixBCL s = return s
+
+isSwitchStmt :: Statement a    -> Bool
+isSwitchStmt (SwitchStmt _ _ _) = True
+isSwitchStmt _                  = False
diff --git a/src/PrettyTest.hs b/src/PrettyTest.hs
new file mode 100644
--- /dev/null
+++ b/src/PrettyTest.hs
@@ -0,0 +1,30 @@
+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 = 
+  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 $ javaScript js of
+    Left _ -> False
+    Right parsed -> (reannotate (const ()) parsed) == js
diff --git a/src/UnitTest.hs b/src/UnitTest.hs
--- a/src/UnitTest.hs
+++ b/src/UnitTest.hs
@@ -10,6 +10,8 @@
 
 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
diff --git a/tests/parse-pretty/flapjax-fxinternal-22dec2008.js b/tests/parse-pretty/flapjax-fxinternal-22dec2008.js
--- a/tests/parse-pretty/flapjax-fxinternal-22dec2008.js
+++ b/tests/parse-pretty/flapjax-fxinternal-22dec2008.js
@@ -1,8 +1,8 @@
 function flapjaxInit(options) {
   // compress via http://alex.dojotoolkit.org/shrinksafe/
-  // make sure to change final eval call to use exported library renamed 
+  // make sure to change final eval call to use exported library renamed
   // name
-  
+
   var defaultOptions = {
     includeSynonyms: true,
     exportMisc: true,
@@ -12,9 +12,9 @@
     exportWS: true,
     hide: [ ],
     show: [ ],
-    redefine: false,
+    redefine: false
   };
-  
+
   if (options === false) {
     options = { hide: [ ], show: [ ] };
   }
@@ -28,7 +28,7 @@
       options[option] = defaultOptions[option];
     }
   };
-  
+
   // Transform hide and show lists into tables
   var hideArray = options.hide;
   options.hide = { };
@@ -40,26 +40,26 @@
   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, 
+
+
+  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;
@@ -69,15 +69,15 @@
 				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 = { };
 
@@ -86,7 +86,7 @@
   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)) {
@@ -95,7 +95,7 @@
 
     if (typeof(exportName) != 'string') {
       console.log(exportVal);
-      throw 'fxExport: name is ' + exportName;   
+      throw 'fxExport: name is ' + exportName;
     };
 
     exportVal.__flapjaxCategory = exportCategory;
@@ -104,8 +104,8 @@
       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++) {
@@ -113,10 +113,10 @@
       };
     };
   };
-  
+
   //////////////////////////////////////////////////////////////////////////////
   // Miscellaneous functions
-  
+
 	//credit 4umi
 	//slice: Array a * Integer * Integer -> Array a
 	var slice = function (arr, start, stop) {
@@ -128,7 +128,7 @@
 		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') &&
@@ -137,22 +137,22 @@
 
 	//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;} 
+		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++) 
+			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) {
@@ -170,16 +170,16 @@
 			return ret;
 		}
 	};
-	  
+
 	//filter: (a -> Boolean) * Array a -> Array a
 	var filter = function (predFn, arr) {
 		var res = [];
-		for (var i = 0; i < arr.length; i++) { 
+		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 */) {
@@ -195,7 +195,7 @@
 		else {
 			var acc = init;
 			for (var i = 0; i < lists[0].length; i++) {
-				var args = map( function (lst) { return lst[i];}, 
+				var args = map( function (lst) { return lst[i];},
 		          lists);
 				args.push(acc);
 				acc = fn.apply({}, args);
@@ -203,7 +203,7 @@
 			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 */) {
@@ -218,22 +218,22 @@
 		else {
 			var acc = init;
 			for (var i = lists[0].length - 1; i > -1; i--) {
-				var args = map( function (lst) { return lst[i];}, 
+				var args = map( function (lst) { return lst[i];},
 		          lists);
 				args.push(acc);
 				acc = fn.apply({}, args);
 			}
-			return acc;     
+			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');
@@ -241,10 +241,10 @@
   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;
@@ -266,8 +266,8 @@
 				ctx.val[kvpos] = kv;
 			}
     };
-    this.isEmpty = function () { 
-      return ctx.val.length === 0; 
+    this.isEmpty = function () {
+      return ctx.val.length === 0;
     };
     this.pop = function () {
 			if(ctx.val.length == 1) {
@@ -296,13 +296,13 @@
 			return ret;
 		};
   };
-  
+
   var lastRank = 0;
   var stamp = 1;
   var nextStamp = function () { return ++stamp; };
-  
-  //propagatePulse: Pulse * Array Node -> 
-  //Send the pulse to each node 
+
+  //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});
@@ -314,36 +314,36 @@
 		},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;
@@ -355,7 +355,7 @@
 			}
 		}
   };
-  
+
   //removeListenerNode: Node * Node -> Boolean
   //remove flow from node to dependent
   //note: does not remove flow as counting for rank nor updates parent ranks
@@ -363,7 +363,7 @@
   {
     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) {
@@ -371,23 +371,23 @@
         foundSending = true;
       }
     }
-    
+
     return foundSending;
   };
-  
-  // An internal_e is a node that simply propagates all pulses it receives.  It's used internally by various 
+
+  // 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) {
@@ -401,7 +401,7 @@
     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) {
@@ -428,10 +428,10 @@
     });
   };
   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 = [];
@@ -445,32 +445,32 @@
           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'; 
+    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);} : 
+      [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) {
@@ -479,16 +479,16 @@
     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
@@ -497,12 +497,12 @@
      */
     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) { 
+      if (prev_e) {
         removeListener(prev_e,out_e);
       }
       prev_e = k(pulse.value);
@@ -514,7 +514,7 @@
       }
     });
     in_e.name = "bind in_e";
-    
+
     return out_e;
   };
 
@@ -526,7 +526,7 @@
     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);
@@ -534,18 +534,18 @@
   };
   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) {
@@ -553,10 +553,10 @@
     });
   };
   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;
@@ -565,11 +565,11 @@
       if (!done) { done = true; send(pulse); }
     });
   };
-  fxMethodSynonyms(EventStream,'once_e','once')
-  
+  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) {
@@ -580,10 +580,10 @@
     });
   };
   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(
@@ -594,31 +594,31 @@
       });
   };
   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); }
@@ -626,43 +626,43 @@
       { 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; 
+    return acc;
   };
   fxExport(core,cond_e,'cond_e');
-  
+
   var and_e = function (/* . nodes */) {
     var nodes = slice(arguments, 0);
-    
-    var acc = (nodes.length > 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],
+        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); 
+    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],
@@ -672,72 +672,72 @@
     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);}, 
+      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 = 
+      var link =
       {
-        from: event, 
+        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 = 
+      var switcherE =
       createNode(
         [changes(time)],
         function (s, p) {
-          removeListener(link.from, link.towards); 
+          removeListener(link.from, link.towards);
           link =
           {
-            from: event, 
+            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 = [];
@@ -746,26 +746,26 @@
     for (var i = 0; i < valsOrNodes.length; i++) {
       if (valsOrNodes[i] instanceof EventStream) {
         nodes.push(valsOrNodes[i]);
-        selectors.push( 
+        selectors.push(
           (function(ii) {
-              return function(realArgs) { 
+              return function(realArgs) {
                 return realArgs[ii];
               };
           })(selectI));
         selectI++;
       } else {
-        selectors.push( 
-          (function(aa) { 
+        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)) {
@@ -773,7 +773,7 @@
         function () {
           var args = arguments;
           return fn.apply(
-            context, 
+            context,
             map(function (s) {return s(args);}, nofnodes));
         });
     } else if (nodes.length === 1) {
@@ -781,9 +781,9 @@
         function (v) {
           var args = arguments;
           return v.apply(
-            context, 
+            context,
             map(function (s) {return s(args);}, nofnodes));
-        });                
+        });
     } else if (fn instanceof Function) {
       return createTimeSyncNode(nodes).lift_e(
         function (arr) {
@@ -795,13 +795,13 @@
       return createTimeSyncNode(nodes).lift_e(
         function (arr) {
           return arr[0].apply(
-            this, 
+            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],
@@ -809,7 +809,7 @@
         p.value = valueNow(valueB);
         s(p);
       }
-      ); 
+      );
   };
   fxMethodSynonyms(EventStream,'snapshot_e','snapshot','takeSnapshot');
 
@@ -821,7 +821,7 @@
   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;
@@ -854,7 +854,7 @@
       }());
 		return out;
   };
-  
+
   //calm_e: Event a * [Behaviour] Number -> Event a
   EventStream.prototype.calm_e = function(time) {
     if (time instanceof Behaviour) {
@@ -865,26 +865,26 @@
           var towards = null;
           return function (s, p) {
             if (towards !== null) { clearTimeout(towards); }
-            towards = setTimeout( function () { towards = null; sendEvent(out,p.value) }, valueNow(time));
+             towards = setTimeout( function () { towards = null; sendEvent(out,p.value);}, valueNow(time));
           };
         }());
 			return out;
     } else {
-      return calmStatic_e(this,time);       
+      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 = 
+        var intervalFn =
         time instanceof Behaviour?
         function () { return valueNow(time); }
         : function () { return time; };
@@ -899,12 +899,12 @@
       }());
   };
   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);
   };
@@ -914,10 +914,10 @@
     if (!(e instanceof EventStream)) {
       throw 'hold: expected EventStream; received ' + e;
     }
-    return e.hold(init); 
+    return e.hold(init);
   };
   fxExport(core,hold,'hold');
-  
+
   Behaviour.prototype.valueNow = function() {
     return this.last;
   };
@@ -928,20 +928,20 @@
     return this.underlying;
   };
   fxMethodSynonyms(Behaviour,'changes','toEvent');
-  
-  var changes = function (behave) { return behave.changes(); }
+
+   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 = 
+    var makerE =
     createNode(
       [changes(behaviourCreatorsB)],
       function (_, p) {
@@ -949,67 +949,67 @@
         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), 
+          changes(triggerB),
           time),
         arguments.length > 3 ? init : valueNow(triggerB));
     } else {
       return delayStatic_b(
-        triggerB, 
+        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); 
+
+  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');
@@ -1022,15 +1022,15 @@
     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);
@@ -1042,14 +1042,14 @@
 		}].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);
 
@@ -1058,21 +1058,21 @@
       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) {
@@ -1083,14 +1083,14 @@
     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;}
@@ -1098,12 +1098,12 @@
 	}].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;}
@@ -1111,64 +1111,64 @@
 	}].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) { 
+
+  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); 
+      return obj.attachEvent("on"+evType, fn);
 		} else {
-      return false; 
+      return false;
 		}
 	};
   fxExport(domMisc,addEvent,'addEvent');
 
-  // The Flapjax library does not use this function  
-	//credit Dustin Diaz 
+  // 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) {
@@ -1186,22 +1186,22 @@
 		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);                    
+        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?
@@ -1209,9 +1209,9 @@
 		return replaceMeD;
 	};
   fxExport(domMisc,swapDom,'swapDom');
-  
+
 	//getObj: String U Dom -> Dom
-	//throws 
+	//throws
 	//  'getObj: expects a Dom obj or Dom id as first arg'
 	//  'getObj: flapjax: cannot access object'
 	//  'getObj: no obj to get
@@ -1222,21 +1222,21 @@
 		else if ((typeof(name) == 'null') || (typeof(name) == 'undefined')) {
       throw 'getObj: expects a Dom obj or Dom id as first arg';
 		} else {
-      
-      var res = 
+
+      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); 
+      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
@@ -1251,9 +1251,9 @@
         acc = acc[indices[i]];
       }
       return acc;
-    }       
+    }
   };
-  
+
   var getDomVal = function (domObj, indices) {
     var val = getMostDom(domObj, indices);
     if (indices && indices.length > 0) {
@@ -1261,24 +1261,24 @@
     }
     return val;
   };
-  
+
   //TODO: manual timer management stinks.
   // TODO: Name turn off or somethin
   var ___timerID = 0;
-  var __getTimerId = function () { return ++___timerID; };    
+  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); 
+    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();
@@ -1287,35 +1287,35 @@
     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); 
+          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);
@@ -1348,18 +1348,18 @@
     // 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 
+    //   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) {	        
+					if (vn instanceof Array) {
 						this.arrs.push(args[i]);
 						curarr = [];
 						this.arrs.push(curarr);
@@ -1392,26 +1392,26 @@
 		},
 		insertChildrenNodes: function() {
 			var ctx = this;
-      
-			function quickNode(e) { 
+
+			function quickNode(e) {
         if ((typeof(e) == 'object') && (e.nodeType))
-					return e; 
+					return e;
         else if ( e == undefined )
-					return document.createTextNode(''); 
-        else 
-          return document.createTextNode(e); 
+					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];
@@ -1425,7 +1425,7 @@
 					}
 				}
 			}
-      
+
 			var childChangesE = merge_e(
 				// Behaviour arrays change
 				arrChangesE.lift_e(function(ai) {
@@ -1461,7 +1461,7 @@
             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]);
@@ -1491,7 +1491,7 @@
 						this.enstyleProperty(obj,valsV, i);
 					}
 				}
-			} 
+			}
 			else { throw 'enstyle: expected object literals'; } //SAFETY
 		},
     enstyleProperty: function (obj, vals, i) {
@@ -1513,11 +1513,11 @@
       }
     }
 	};
-  
+
 	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]) {
@@ -1531,16 +1531,16 @@
 			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++) {
@@ -1556,91 +1556,91 @@
           }
         } else if (!arguments[i]) {
           //ignore
-        } else if ((typeof(arguments[i]) == 'object') && 
+        } 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]));                    
+            tagD.appendChild(document.createTextNode(arguments[i]));
           }
       }
-      
-      if (attribs.length == 1) { 
+
+      if (attribs.length == 1) {
         for (var k in attribs[0]) {
           if (!(Object.prototype) || !(Object.prototype[k])) {
-            d.enstyleStaticProperty(tagD, attribs[0], k);   
+            d.enstyleStaticProperty(tagD, attribs[0], k);
           }
         }
-      } else if (attribs.length >  0) { 
+      } 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", 
+
+
+
+  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) { 
-      
+    function (tagName) {
+
       var upper = tagName.toUpperCase();
-      
+
       //d.<TAG>B
-      d[upper + 'B'] = function () { 
+      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)); 
+      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    
+
+  //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) * 
+
+  //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 = [ ];
@@ -1648,33 +1648,33 @@
       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);
@@ -1682,7 +1682,7 @@
        // checking.
        return true;
     });
-    
+
     return primEventE;
   };
 
@@ -1693,47 +1693,47 @@
     }
     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  
+
+  //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); 
+        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
@@ -1743,23 +1743,23 @@
       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);
@@ -1770,36 +1770,36 @@
     } 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': 
-      
+    case 'checkbox':
+
       return hold(
         filterRepeats_e(
           d.extractDomFieldOnEvent_e(
-            triggerE ? triggerE : 
+            triggerE ? triggerE :
             d.extractEvents_e(
-              objD, 
+              objD,
               'click', 'keyup', 'change'),
             objD,
             'checked'),objD.checked),
         objD.checked);
-      
+
       case 'select-one':
-        
-        getter = function (_) {                         
-          return objD.selectedIndex > -1 ? 
+
+        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 :
@@ -1807,10 +1807,10 @@
                 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++) {
@@ -1820,95 +1820,95 @@
             }
             return res;
           };
-          
-          
+
+
           return hold(
-              (triggerE ? triggerE : 
+              (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, 
+                    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, 
+                    objD,
                     'click', 'keyup', 'change'),
                   objD,
                   'value'),
                 objD.value);
-              
-              
-              case 'radio': 
+
+
+              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) { 
+                  function (elt) {
                     return (elt.type == 'radio') &&
-                    (elt.getAttribute('name') == objD.name); 
+                    (elt.getAttribute('name') == objD.name);
                   },
                   document.getElementsByTagName('input'));
-                
-                getter = 
+
+                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 radiosAD[i].value;
                     }
                   }
-                  return undefined; //TODO throw exn? 
+                  return undefined; //TODO throw exn?
                 };
-                
+
                 var actualTriggerE = triggerE ? triggerE :
                 merge_e.apply(
                   this,
                   map(
-                    function (radio) { 
+                    function (radio) {
                       return d.extractEvents_e(
-                        radio, 
+                        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); },
@@ -1919,7 +1919,7 @@
     }
   };
 	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;
@@ -1934,7 +1934,7 @@
       into[index] = fV;
     }
   };
-  
+
   //note: no object may be time varying, just the fields
   //into[index] = from
   //only updates on changes
@@ -1954,7 +1954,7 @@
         createNode(
           [changes(from)],
           function (s, p) {
-            if (index) { 
+            if (index) {
               var old = into[index];
               into[index] = p.value;
             }
@@ -1963,70 +1963,70 @@
       }
     }
   };
-  
-	
+
+
   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);    	
+    d.deepStaticUpdate(parent, val, indices ? indices[indices.length - 1] : undefined);
   };
   annotate(d.insertValue,['insertValue']);
-  
-  //TODO convenience method (default to firstChild nodeValue) 
+
+  //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 */) { 
-    
+  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))) { 
+        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 
+
+  //insertDom: dom
+  //          * dom
   //          [* (null | undefined | 'over' | 'before' | 'after' | 'leftMost' | 'rightMost' | 'beginning' | 'end']
   //          -> void
   // TODO: for consistency, switch replaceWithD, hookD argument order
@@ -2038,7 +2038,7 @@
     case 'over':
       swapDom(hookD,replaceWithD);
       break;
-    case 'before':  
+    case 'before':
       hookD.parentNode.insertBefore(replaceWithD, hookD);
       break;
     case 'after':
@@ -2049,9 +2049,9 @@
       }
       break;
     case 'leftMost':
-      if (hookD.parentNode.firstChild) { 
+      if (hookD.parentNode.firstChild) {
         hookD.parentNode.insertBefore(
-          replaceWithD, 
+          replaceWithD,
           hookD.parentNode.firstChild);
                 } else { hookD.parentNode.appendChild(replaceWithD); }
                 break;
@@ -2059,9 +2059,9 @@
                 hookD.parentNode.appendChild(replaceWithD);
                 break;
               case 'beginning':
-                if (hookD.firstChild) { 
+                if (hookD.firstChild) {
                   hookD.insertBefore(
-                    replaceWithD, 
+                    replaceWithD,
                     hookD.firstChild);
                 } else { hookD.appendChild(replaceWithD); }
                 break;
@@ -2072,39 +2072,39 @@
                 throw ('domInsert: unknown position: ' + optPosition);
     }
   };
-  
-  //insertDom: dom 
-  //          * dom U String domID 
+
+  //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), 
+	    getObj(hook),
 	    ((typeof(replaceWithD) == 'object') && (replaceWithD.nodeType > 0)) ? replaceWithD :
-      document.createTextNode(replaceWithD),	    
-	    optPosition);     	    
+      document.createTextNode(replaceWithD),
+	    optPosition);
   };
   annotate(d.insertDomClean,['insertDom']);
-  
+
   //TODO test
-  //insertDomB: 
-  //      [Behaviour] String U Dom 
-  //      [* ( id U null U undefined ) 
+  //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    
+  //performs initial swap onload
   d.insertDomB = function (initTriggerB, optID, optPosition) {
-    
-    if (!(initTriggerB instanceof Behaviour)) { 
+
+    if (!(initTriggerB instanceof Behaviour)) {
       initTriggerB = constant_b(initTriggerB);
     }
-    
-    var triggerB = 
+
+    var triggerB =
     lift_b(
-      function (d) { 
+      function (d) {
         if ((typeof(d) == 'object') && (d.nodeType >  0)) {
           return d;
         } else {
@@ -2114,26 +2114,26 @@
         }
       },
       initTriggerB);
-    
+
     var initD = valueNow(triggerB);
-    if (!((typeof(initD) == 'object') && (initD.nodeType == 1))) { throw ('insertDomB: initial value conversion failed: ' + initD); } //SAFETY	
-    
+    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, 
+      optID === null || optID === undefined ? getObj(initD.getAttribute('id')) : getObj(optID),
+      initD,
       optPosition);
-    
+
     var resB = hold(
       d.insertDomE(
         changes(triggerB),
-        initD), 
+        initD),
       initD);
-    
+
     return resB;
   };
   annotate(d.insertDomB,['insertDomB'],0,[Behaviour.prototype],['insertDomB']);
-  
-  
+
+
   d.extractId_b = function (id, start)
   {
     return hold(
@@ -2146,7 +2146,7 @@
       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) {
@@ -2162,32 +2162,32 @@
         }
     });
   };
-  
+
   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();
@@ -2207,7 +2207,7 @@
     else return aReturn;
 	};
   fxExport(domMisc,getURLParam,'getURLParam','$URL');
-  
+
 	//credit Quirksmode
 	//readCookie: String -> String U Undefined
 	var readCookie = function (name) {
@@ -2216,21 +2216,21 @@
     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) { 
+      if (co.indexOf(nameEQ) === 0) {
         return co.substring(nameEQ.length, co.length);
       }
     }
-    return undefined;       
+    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");
@@ -2239,7 +2239,7 @@
     script.setAttribute('id', scriptID);
     document.getElementsByTagName("head").item(0).appendChild(script);
     var timer = {};
-    var check = 
+    var check =
     function () {
       eval("try { if (" + param + "!== undefined) {var stat = " + param + ";}} catch (e) {}");
       if (stat !== undefined) {
@@ -2247,35 +2247,35 @@
         clearInterval(timer.timer);
         clearInterval(timer.timeout);
         if (fn instanceof Function) {
-          fn(stat); 
+          fn(stat);
         }
         deleteScript(scriptID);
       }
     };
     timer.timer = setInterval(check, 3500);
-    timer.timeout = 
-    setTimeout( 
-      function () { 
+    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); }, 
+          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) {
@@ -2289,18 +2289,18 @@
     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;
   };
@@ -2413,22 +2413,22 @@
       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); 
+          body = toJSONString(obj.fields);
           method = 'POST';
         } else if (obj.request == 'rawPost') {
           body = obj.body;
@@ -2441,16 +2441,16 @@
         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)); 
+              response_e.sendEvent(parseJSON(xhr.responseText));
             });
         }
         else if (obj.response == 'xml') {
@@ -2469,15 +2469,15 @@
           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);
   };
@@ -2502,7 +2502,7 @@
       }
     }
   }
-  
+
   for (var id in exports) {
     if (window[id]) {
       if (options.redefine === false) {
@@ -2517,9 +2517,9 @@
     if (window[id] && options.redefine === false) {
       // Don't redefine id
     }
-    else if (options.show && options.hide && options.show[id] === true && 
+    else if (options.show && options.hide && options.show[id] === true &&
         options.hide[id] === true) {
-      throw('flapjaxInit: invalid options: ' + id + " specified as 'show' and 'hide'"); 
+      throw('flapjaxInit: invalid options: ' + id + " specified as 'show' and 'hide'");
     }
     else if (options.show && options.show[id]) {
       window[id] = exports[id];
@@ -2547,6 +2547,6 @@
       }
     }
   }
-  
+
   return exports;
 }
