a few things:

a few things:

1. fix up the way we're passing arguments in call and new expressions.  there were all sorts of problems,
   including but not limitted to evaluating arguments more than once.
2. llvm.IRBuilder -> irbuilder everywhere.
3. add only_reads_memory to the getprop methods, which allows llvm to remove their calls if the results aren't
   used.

--- lib/compiler.coffee
+++ lib/compiler.coffee
@@ -11,6 +11,7 @@
 { desugar } = require 'echo-desugar'

 llvm = require 'llvm'
+irbuilder = llvm.IRBuilder

 # special key for parent scope when performing lookups
 PARENT_SCOPE_KEY = ":parent:"
@@ -29,13 +30,17 @@
 EjsClosureFuncType = (llvm.FunctionType.get EjsValueType, [EjsClosureEnvType, EjsValueType, llvm.Type.getInt32Ty(), EjsValueType.pointerTo()]).pointerTo()

 BUILTIN_PARAMS = [
-  { type: syntax.Identifier, name: "%env",  llvm_type: EjsClosureEnvType }
-  { type: syntax.Identifier, name: "%this", llvm_type: EjsValueType }
-  { type: syntax.Identifier, name: "%argc", llvm_type: int32Type }
+  { type: syntax.Identifier, name: "%closure", llvm_type: EjsClosureEnvType }
+  { type: syntax.Identifier, name: "%this",    llvm_type: EjsValueType }
+  { type: syntax.Identifier, name: "%argc",    llvm_type: int32Type }
 ]

 takes_builtins = (n) ->
         n.takes_builtins = true
+        n
+
+only_reads_memory = (n) ->
+        n.setOnlyReadsMemory(true)
         n

 class LLVMIRVisitor extends NodeVisitor
@@ -60,8 +65,8 @@
                         regexp_new_utf8:       module.getOrInsertExternalFunction "_ejs_regexp_new_utf8",           EjsValueType, [stringType]
                         truthy:                module.getOrInsertExternalFunction "_ejs_truthy",                    boolType, [EjsValueType]
                         object_setprop:        module.getOrInsertExternalFunction "_ejs_object_setprop",            EjsValueType, [EjsValueType, EjsValueType, EjsValueType]
-                        object_getprop:        module.getOrInsertExternalFunction "_ejs_object_getprop",            EjsValueType, [EjsValueType, EjsValueType]
-                        object_getprop_utf8:   module.getOrInsertExternalFunction "_ejs_object_getprop_utf8",       EjsValueType, [EjsValueType, stringType]
+                        object_getprop:        only_reads_memory module.getOrInsertExternalFunction "_ejs_object_getprop",           EjsValueType, [EjsValueType, EjsValueType]
+                        object_getprop_utf8:   only_reads_memory module.getOrInsertExternalFunction "_ejs_object_getprop_utf8",      EjsValueType, [EjsValueType, stringType]
                         object_setprop_utf8:   module.getOrInsertExternalFunction "_ejs_object_setprop_utf8",       EjsValueType, [EjsValueType, stringType, EjsValueType]
                         prop_iterator_new:     module.getOrInsertExternalFunction "_ejs_property_iterator_new",     EjsPropIteratorType, [EjsValueType]
                         prop_iterator_current: module.getOrInsertExternalFunction "_ejs_property_iterator_current", stringType, [EjsPropIteratorType]
@@ -102,10 +107,10 @@

         loadNullEjsValue: -> llvm.Constant.getNull EjsValueType
         loadUndefinedEjsValue: ->
-                undef = llvm.IRBuilder.createLoad @ejs.undefined, "load_undefined"
+                undef = irbuilder.createLoad @ejs.undefined, "load_undefined"
                 undef.isundefined = true
                 undef
-        loadGlobal: -> llvm.IRBuilder.createLoad @ejs.global, "load_global"
+        loadGlobal: -> irbuilder.createLoad @ejs.global, "load_global"

         pushIIFEInfo: (info) ->
                 @iifeStack.unshift info
@@ -133,14 +138,14 @@
                         if scope.hasOwnProperty ident
                                 return scope[ident]
                         scope = scope[PARENT_SCOPE_KEY]
-                return null
+                null

         createAlloca: (func, type, name) ->
-                saved_insert_point = llvm.IRBuilder.getInsertBlock()
-                llvm.IRBuilder.setInsertPointStartBB func.entry_bb
-                alloca = llvm.IRBuilder.createAlloca type, name
-                llvm.IRBuilder.setInsertPoint saved_insert_point
+                saved_insert_point = irbuilder.getInsertBlock()
+                irbuilder.setInsertPointStartBB func.entry_bb
+                alloca = irbuilder.createAlloca type, name
+                irbuilder.setInsertPoint saved_insert_point
                 alloca

         createAllocas: (func, ids, scope) ->
@@ -148,14 +153,14 @@
                 new_allocas = []

                 # the allocas are always allocated in the function entry_bb so the mem2reg opt pass can regenerate the ssa form for us
-                saved_insert_point = llvm.IRBuilder.getInsertBlock()
-                llvm.IRBuilder.setInsertPointStartBB func.entry_bb
+                saved_insert_point = irbuilder.getInsertBlock()
+                irbuilder.setInsertPointStartBB func.entry_bb

                 j = 0
                 for i in [0...ids.length]
                         name = ids[i].id.name
                         if !scope.hasOwnProperty name
-                                allocas[j] = llvm.IRBuilder.createAlloca EjsValueType, "local_#{name}"
+                                allocas[j] = irbuilder.createAlloca EjsValueType, "local_#{name}"
                                 scope[name] = allocas[j]
                                 new_allocas[j] = true
                         else
@@ -165,14 +170,14 @@

                 # reinstate the IRBuilder to its previous insert point so we can insert the actual initializations
-                llvm.IRBuilder.setInsertPoint saved_insert_point
+                irbuilder.setInsertPoint saved_insert_point

                 { allocas: allocas, new_allocas: new_allocas }

         createPropertyStore: (obj,prop,rhs,computed) ->
                 if computed
                         # we store obj[prop], prop can be any value
-                        llvm.IRBuilder.createCall @ejs.object_setprop, [obj, (@visit prop), rhs], "propstore_computed"
+                        irbuilder.createCall @ejs.object_setprop, [obj, (@visit prop), rhs], "propstore_computed"
                 else
                         # we store obj.prop, prop is an id
                         if prop.type is syntax.Identifier
@@ -182,25 +187,25 @@

                         debug.log "createPropertyStore #{obj}[#{pname}]"

-                        c = llvm.IRBuilder.createGlobalStringPtr pname, "strconst"
-                        llvm.IRBuilder.createCall @ejs.object_setprop_utf8, [obj, c, rhs], "propstore_#{pname}"
+                        c = irbuilder.createGlobalStringPtr pname, "strconst"
+                        irbuilder.createCall @ejs.object_setprop_utf8, [obj, c, rhs], "propstore_#{pname}"

         createPropertyLoad: (obj,prop,computed) ->
                 if computed
                         # we load obj[prop], prop can be any value
                         loadprop = @visit prop
                         pname = "computed"
-                        llvm.IRBuilder.createCall @ejs.object_getprop, [obj, loadprop], "getprop_#{pname}"
+                        irbuilder.createCall @ejs.object_getprop, [obj, loadprop], "getprop_#{pname}"
                 else
                         # we load obj.prop, prop is an id
                         pname = prop.name
-                        c = llvm.IRBuilder.createGlobalStringPtr pname, "strconst"
-                        llvm.IRBuilder.createCall @ejs.object_getprop_utf8, [obj, c], "getprop_#{pname}"
+                        c = irbuilder.createGlobalStringPtr pname, "propname_#{pname}"
+                        irbuilder.createCall @ejs.object_getprop_utf8, [obj, c], "getprop_#{pname}"

         createLoadThis: () ->
                 _this = @findIdentifierInScope "%this", @current_scope
-                return llvm.IRBuilder.createLoad _this, "load_this"
+                return irbuilder.createLoad _this, "load_this"

         visitOrNull: (n) -> (@visit n) || @loadNullEjsValue()
@@ -221,7 +226,7 @@
                 iife_bb = null

                 if n.fromIIFE
-                        insertBlock = llvm.IRBuilder.getInsertBlock()
+                        insertBlock = irbuilder.getInsertBlock()
                         insertFunc = insertBlock.parent

                         iife_rv = @createAlloca @currentFunction, EjsValueType, "%iife_rv"
@@ -233,21 +238,21 @@

                 @popIIFEInfo()
                 if iife_bb
-                        llvm.IRBuilder.createBr iife_bb
-                        llvm.IRBuilder.setInsertPoint iife_bb
-                        rv = llvm.IRBuilder.createLoad iife_rv, "%iife_rv_load"
+                        irbuilder.createBr iife_bb
+                        irbuilder.setInsertPoint iife_bb
+                        rv = irbuilder.createLoad iife_rv, "%iife_rv_load"
                         rv
                 else
                         n

         visitSwitch: (n) ->
-                insertBlock = llvm.IRBuilder.getInsertBlock()
+                insertBlock = irbuilder.getInsertBlock()
                 insertFunc = insertBlock.parent

                 switch_bb = new llvm.BasicBlock "switch", insertFunc

-                llvm.IRBuilder.createBr switch_bb
-                llvm.IRBuilder.setInsertPoint switch_bb
+                irbuilder.createBr switch_bb
+                irbuilder.setInsertPoint switch_bb

                 # find the default: case first
                 defaultCase = null
@@ -278,15 +283,15 @@
                 @breakStack.unshift dest: merge_bb

                 # insert all the code for the tests
-                llvm.IRBuilder.createBr case_checks[0].dest_check
-                llvm.IRBuilder.setInsertPoint case_checks[0].dest_check
+                irbuilder.createBr case_checks[0].dest_check
+                irbuilder.setInsertPoint case_checks[0].dest_check
                 for casenum in [0...case_checks.length-1]
                         test = @visit case_checks[casenum].test
-                        discTest = llvm.IRBuilder.createCall @ejs["binop==="], [discr, test], "test"
-                        disc_truthy = llvm.IRBuilder.createCall @ejs.truthy, [discTest], "disc_truthy"
-                        disc_cmp = llvm.IRBuilder.createICmpEq disc_truthy, (llvm.Constant.getIntegerValue boolType, 0), "disccmpresult"
-                        llvm.IRBuilder.createCondBr disc_cmp, case_checks[casenum+1].dest_check, case_checks[casenum].body
-                        llvm.IRBuilder.setInsertPoint case_checks[casenum+1].dest_check
+                        discTest = irbuilder.createCall @ejs["binop==="], [discr, test], "test"
+                        disc_truthy = irbuilder.createCall @ejs.truthy, [discTest], "disc_truthy"
+                        disc_cmp = irbuilder.createICmpEq disc_truthy, (llvm.Constant.getIntegerValue boolType, 0), "disccmpresult"
+                        irbuilder.createCondBr disc_cmp, case_checks[casenum+1].dest_check, case_checks[casenum].body
+                        irbuilder.setInsertPoint case_checks[casenum+1].dest_check

                 case_bodies = []
@@ -298,12 +303,12 @@
                 case_bodies.push bb:merge_bb

                 for casenum in [0...case_bodies.length-1]
-                        llvm.IRBuilder.setInsertPoint case_bodies[casenum].bb
+                        irbuilder.setInsertPoint case_bodies[casenum].bb
                         for c of case_bodies[casenum].consequent
                                 @visit case_bodies[casenum].consequent[c]
-                        llvm.IRBuilder.createBr case_bodies[casenum+1].bb
-
-                llvm.IRBuilder.setInsertPoint merge_bb
+                        irbuilder.createBr case_bodies[casenum+1].bb
+
+                irbuilder.setInsertPoint merge_bb
                 @breakStack.shift()
                 merge_bb

@@ -317,21 +322,21 @@

         visitBreak: (n) ->
                 if not n.label
-                        llvm.IRBuilder.createBr @breakStack[0].dest
+                        irbuilder.createBr @breakStack[0].dest
                 else
                         el = el for el in @breakStack when el.label is n.label.name
-                        llvm.IRBuilder.createBr el.dest
+                        irbuilder.createBr el.dest

         visitContinue: (n) ->
                 if not n.label
-                        llvm.IRBuilder.createBr @continueStack[0].dest
+                        irbuilder.createBr @continueStack[0].dest
                 else
                         el = el for el in @continueStack when el.label is n.label.name
-                        llvm.IRBuilder.createBr el.dest
+                        irbuilder.createBr el.dest

         visitFor: (n) ->
-                insertBlock = llvm.IRBuilder.getInsertBlock()
+                insertBlock = irbuilder.getInsertBlock()
                 insertFunc = insertBlock.parent

                 init_bb = new llvm.BasicBlock "for_init", insertFunc
@@ -340,71 +345,71 @@
                 update_bb = new llvm.BasicBlock "for_update", insertFunc
                 merge_bb = new llvm.BasicBlock "for_merge", insertFunc

-                llvm.IRBuilder.createBr init_bb
-
-                llvm.IRBuilder.setInsertPoint init_bb
+                irbuilder.createBr init_bb
+
+                irbuilder.setInsertPoint init_bb
                 @visit n.init
-                llvm.IRBuilder.createBr test_bb
-
-                llvm.IRBuilder.setInsertPoint test_bb
+                irbuilder.createBr test_bb
+
+                irbuilder.setInsertPoint test_bb
                 if n.test
-                        cond_truthy = llvm.IRBuilder.createCall @ejs.truthy, [@visit(n.test)], "cond_truthy"
-                        cmp = llvm.IRBuilder.createICmpEq cond_truthy, (llvm.Constant.getIntegerValue boolType, 0), "cmpresult"
-                        llvm.IRBuilder.createCondBr cmp, merge_bb, body_bb
-                else
-                        llvm.IRBuilder.createBr body_bb
+                        cond_truthy = irbuilder.createCall @ejs.truthy, [@visit(n.test)], "cond_truthy"
+                        cmp = irbuilder.createICmpEq cond_truthy, (llvm.Constant.getIntegerValue boolType, 0), "cmpresult"
+                        irbuilder.createCondBr cmp, merge_bb, body_bb
+                else
+                        irbuilder.createBr body_bb

                 @continueStack.unshift label: n.label, dest: update_bb
                 @breakStack.unshift    label: n.label, dest: merge_bb

-                llvm.IRBuilder.setInsertPoint body_bb
+                irbuilder.setInsertPoint body_bb
                 @visit n.body
-                llvm.IRBuilder.createBr update_bb
-
-                llvm.IRBuilder.setInsertPoint update_bb
+                irbuilder.createBr update_bb
+
+                irbuilder.setInsertPoint update_bb
                 @visit n.update
-                llvm.IRBuilder.createBr test_bb
+                irbuilder.createBr test_bb

                 @continueStack.shift()
                 @breakStack.shift()

-                llvm.IRBuilder.setInsertPoint merge_bb
+                irbuilder.setInsertPoint merge_bb
                 merge_bb

         visitWhile: (n) ->
-                insertBlock = llvm.IRBuilder.getInsertBlock()
+                insertBlock = irbuilder.getInsertBlock()
                 insertFunc = insertBlock.parent

                 while_bb  = new llvm.BasicBlock "while_start", insertFunc
                 body_bb = new llvm.BasicBlock "while_body", insertFunc
                 merge_bb = new llvm.BasicBlock "while_merge", insertFunc

-                llvm.IRBuilder.createBr while_bb
-                llvm.IRBuilder.setInsertPoint while_bb
-
-                cond_truthy = llvm.IRBuilder.createCall @ejs.truthy, [@visit(n.test)], "cond_truthy"
-                cmp = llvm.IRBuilder.createICmpEq cond_truthy, (llvm.Constant.getIntegerValue boolType, 0), "cmpresult"
-
-                llvm.IRBuilder.createCondBr cmp, merge_bb, body_bb
+                irbuilder.createBr while_bb
+                irbuilder.setInsertPoint while_bb
+
+                cond_truthy = irbuilder.createCall @ejs.truthy, [@visit(n.test)], "cond_truthy"
+                cmp = irbuilder.createICmpEq cond_truthy, (llvm.Constant.getIntegerValue boolType, 0), "cmpresult"
+
+                irbuilder.createCondBr cmp, merge_bb, body_bb

                 @continueStack.unshift label: n.label, dest: while_bb
                 @breakStack.unshift    label: n.label, dest: merge_bb

-                llvm.IRBuilder.setInsertPoint body_bb
+                irbuilder.setInsertPoint body_bb
                 @visit n.body
-                llvm.IRBuilder.createBr while_bb
+                irbuilder.createBr while_bb

                 @continueStack.shift()
                 @breakStack.shift()

-                llvm.IRBuilder.setInsertPoint merge_bb
+                irbuilder.setInsertPoint merge_bb
                 merge_bb

         visitForIn: (n) ->
-                insertBlock = llvm.IRBuilder.getInsertBlock()
+                insertBlock = irbuilder.getInsertBlock()
                 insertFunc = insertBlock.parent

-                iterator = llvm.IRBuilder.createCall @ejs.prop_iterator_new, [@visit n.right], "iterator"
+                iterator = irbuilder.createCall @ejs.prop_iterator_new, [@visit n.right], "iterator"

                 # make sure we get an alloca if there's a "var"
                 if n.left[0]?
@@ -417,24 +422,24 @@
                 body_bb   = new llvm.BasicBlock "forin_body",  insertFunc
                 merge_bb  = new llvm.BasicBlock "forin_merge", insertFunc

-                llvm.IRBuilder.createBr forin_bb
-                llvm.IRBuilder.setInsertPoint forin_bb
-
-                current = llvm.IRBuilder.createCall @ejs.prop_iterator_current, [iterator], "iterator_current"
-
-                cmp = llvm.IRBuilder.createICmpEq current, (llvm.Constant.getNull stringType), "cmpresult"
-
-                llvm.IRBuilder.createCondBr cmp, merge_bb, body_bb
-
-                llvm.IRBuilder.setInsertPoint body_bb
-                strcall = llvm.IRBuilder.createCall @ejs.string_new_utf8, [current], "strtmp"
+                irbuilder.createBr forin_bb
+                irbuilder.setInsertPoint forin_bb
+
+                current = irbuilder.createCall @ejs.prop_iterator_current, [iterator], "iterator_current"
+
+                cmp = irbuilder.createICmpEq current, (llvm.Constant.getNull stringType), "cmpresult"
+
+                irbuilder.createCondBr cmp, merge_bb, body_bb
+
+                irbuilder.setInsertPoint body_bb
+                strcall = irbuilder.createCall @ejs.string_new_utf8, [current], "strtmp"
                 @storeValueInDest strcall, lhs
                 @visit n.body
-                llvm.IRBuilder.createCall @ejs.prop_iterator_next, [iterator], ""
-                llvm.IRBuilder.createBr forin_bb
-
-                llvm.IRBuilder.setInsertPoint merge_bb
-                llvm.IRBuilder.createCall @ejs.prop_iterator_free, [iterator], ""
+                irbuilder.createCall @ejs.prop_iterator_next, [iterator], ""
+                irbuilder.createBr forin_bb
+
+                irbuilder.setInsertPoint merge_bb
+                irbuilder.createCall @ejs.prop_iterator_free, [iterator], ""
                 merge_bb

@@ -442,13 +447,13 @@
                 result = @createAlloca @currentFunction, EjsValueType, "%update_result"
                 argument = @visit n.argument
                 c = llvm.ConstantFP.getDouble 1
-                num = llvm.IRBuilder.createCall @ejs.number_new, [c], "numtmp"
+                num = irbuilder.createCall @ejs.number_new, [c], "numtmp"
                 if not n.prefix
                         # postfix updates store the argument before the op
-                        llvm.IRBuilder.createStore argument, result
+                        irbuilder.createStore argument, result

                 # argument = argument $op 1
-                temp = llvm.IRBuilder.createCall @ejs["binop#{if n.operator is '++' then '+' else '-'}"], [argument, num], "update_temp"
+                temp = irbuilder.createCall @ejs["binop#{if n.operator is '++' then '+' else '-'}"], [argument, num], "update_temp"

                 @storeValueInDest temp, n.argument

@@ -456,8 +461,8 @@
                 if n.prefix
                         argument = @visit n.argument
                         # prefix updates store the argument after the op
-                        llvm.IRBuilder.createStore argument, result
-                llvm.IRBuilder.createLoad result, "%update_result_load"
+                        irbuilder.createStore argument, result
+                irbuilder.createLoad result, "%update_result_load"

         visitConditionalExpression: (n) ->
                 @visitIfOrCondExp n, true
@@ -466,13 +471,14 @@
                 @visitIfOrCondExp n, false

         visitIfOrCondExp: (n, load_result) ->
+
                 if load_result
                         cond_val = @createAlloca @currentFunction, EjsValueType, "%cond_val"
-
+
                 # first we convert our conditional EJSValue to a boolean
-                cond_truthy = llvm.IRBuilder.createCall @ejs.truthy, [@visit(n.test)], "cond_truthy"
-
-                insertBlock = llvm.IRBuilder.getInsertBlock()
+                cond_truthy = irbuilder.createCall @ejs.truthy, [@visit(n.test)], "cond_truthy"
+
+                insertBlock = irbuilder.getInsertBlock()
                 insertFunc = insertBlock.parent

                 then_bb  = new llvm.BasicBlock "then", insertFunc
@@ -480,24 +486,24 @@
                 merge_bb = new llvm.BasicBlock "merge", insertFunc

                 # we invert the test here - check if the condition is false/0
-                cmp = llvm.IRBuilder.createICmpEq cond_truthy, (llvm.Constant.getIntegerValue boolType, 0), "cmpresult"
-                llvm.IRBuilder.createCondBr cmp, else_bb, then_bb
-
-                llvm.IRBuilder.setInsertPoint then_bb
+                cmp = irbuilder.createICmpEq cond_truthy, (llvm.Constant.getIntegerValue boolType, 0), "cmpresult"
+                irbuilder.createCondBr cmp, else_bb, then_bb
+
+                irbuilder.setInsertPoint then_bb
                 then_val = @visit n.consequent
                 if load_result
-                        llvm.IRBuilder.createStore then_val, cond_val
-                llvm.IRBuilder.createBr merge_bb
-
-                llvm.IRBuilder.setInsertPoint else_bb
+                        irbuilder.createStore then_val, cond_val
+                irbuilder.createBr merge_bb
+
+                irbuilder.setInsertPoint else_bb
                 else_val = @visit n.alternate
                 if load_result
-                        llvm.IRBuilder.createStore else_val, cond_val
-                llvm.IRBuilder.createBr merge_bb
-
-                llvm.IRBuilder.setInsertPoint merge_bb
+                        irbuilder.createStore else_val, cond_val
+                irbuilder.createBr merge_bb
+
+                irbuilder.setInsertPoint merge_bb
                 if load_result
-                        llvm.IRBuilder.createLoad cond_val, "cond_val_load"
+                        irbuilder.createLoad cond_val, "cond_val_load"
                 else
                         merge_bb

@@ -505,19 +511,18 @@
                 debug.log "visitReturn"
                 if @iifeStack[0].iife_rv?
                         if n.argument?
-                                llvm.IRBuilder.createStore (@visit n.argument), @iifeStack[0].iife_rv
+                                irbuilder.createStore (@visit n.argument), @iifeStack[0].iife_rv
                         else
-                                llvm.IRBuilder.createStore @loadUndefinedEjsValue(), @iifeStack[0].iife_rv
-                        llvm.IRBuilder.createBr @iifeStack[0].iife_dest_bb
+                                irbuilder.createStore @loadUndefinedEjsValue(), @iifeStack[0].iife_rv
+                        irbuilder.createBr @iifeStack[0].iife_dest_bb
                 else
                         if n.argument
-                                llvm.IRBuilder.createRet @visit n.argument
+                                irbuilder.createRet @visit n.argument
                         else
-                                llvm.IRBuilder.createRet @loadUndefinedEjsValue()
+                                irbuilder.createRet @loadUndefinedEjsValue()

         visitVariableDeclaration: (n) ->
-
                 if n.kind is "var"
                         # vars are hoisted to the containing function's toplevel scope
                         scope = @currentFunction.topScope
@@ -529,10 +534,10 @@
                                         # if the alloca is newly allocated.
                                         if new_allocas[i]
                                                 initializer = @visitOrUndefined n.declarations[i].init
-                                                llvm.IRBuilder.createStore initializer, allocas[i]
+                                                irbuilder.createStore initializer, allocas[i]
                                 else
                                         initializer = @visitOrUndefined n.declarations[i].init
-                                        llvm.IRBuilder.createStore initializer, allocas[i]
+                                        irbuilder.createStore initializer, allocas[i]
                 else if n.kind is "let"
                         # lets are not hoisted to the containing function's toplevel, but instead are bound in the lexical block they inhabit
                         scope = @current_scope;
@@ -544,10 +549,10 @@
                                         # if the alloca is newly allocated.
                                         if new_allocas[i]
                                                 initializer = @visitOrUndefined n.declarations[i].init
-                                                llvm.IRBuilder.createStore initializer, allocas[i]
+                                                irbuilder.createStore initializer, allocas[i]
                                 else
                                         initializer = @visitOrUndefined n.declarations[i].init
-                                        llvm.IRBuilder.createStore initializer, allocas[i]
+                                        irbuilder.createStore initializer, allocas[i]
                 else if n.kind is "const"
                         for i in [0...n.declarations.length]
                                 u = n.declarations[i]
@@ -555,13 +560,21 @@
                                 # XXX bind the initializer to u.name in the current basic block and mark it as constant

         visitMemberExpression: (n) ->
-                @createPropertyLoad (@visit n.object), n.property, n.computed
+                obj_result = @createAlloca @currentFunction, EjsValueType, "result_obj"
+                obj_visit = @visit n.object
+                irbuilder.createStore obj_visit, obj_result
+                obj_load = irbuilder.createLoad obj_result, "obj_load"
+                rv = @createPropertyLoad obj_load, n.property, n.computed
+                load_result = @createAlloca @currentFunction, EjsValueType, "load_result"
+                irbuilder.createStore rv, load_result
+                if not n.result_not_used
+                        irbuilder.createLoad load_result, "rv"

         storeValueInDest: (rhvalue, lhs) ->
                 if lhs.type is syntax.Identifier
                         dest = @findIdentifierInScope lhs.name, @current_scope
                         if dest?
-                                result = llvm.IRBuilder.createStore rhvalue, dest
+                                result = irbuilder.createStore rhvalue, dest
                         else
                                 result = @createPropertyStore @loadGlobal(), lhs, rhvalue, false
                         result
@@ -581,8 +594,8 @@
                         callee = @ejs[builtin]
                         if not callee
                                 throw "Internal error: unhandled binary operator '#{n.operator}'"
-                        rhvalue = llvm.IRBuilder.createCall callee, [(@visit lhs), rhvalue], "result_#{builtin}"
-
+                        rhvalue = irbuilder.createCall callee, [(@visit lhs), rhvalue], "result_#{builtin}"
+
                 @storeValueInDest rhvalue, lhs

                 # we need to visit lhs after the store so that we load the value, but only if it's used
@@ -591,9 +604,9 @@

         visitFunction: (n) ->
                 console.warn "        function #{n.ir_name} at line #{n.loc?.start.line}"
-
+
                 # save off the insert point so we can get back to it after generating this function
-                insertBlock = llvm.IRBuilder.getInsertBlock()
+                insertBlock = irbuilder.getInsertBlock()

                 for param in n.params
                         debug.log param.type
@@ -620,7 +633,7 @@

                 # Create a new basic block to start insertion into.
                 entry_bb = new llvm.BasicBlock "entry", ir_func
-                llvm.IRBuilder.setInsertPoint entry_bb
+                irbuilder.setInsertPoint entry_bb

                 new_scope = {}

@@ -633,19 +646,19 @@

                 # create allocas for the builtin args
                 for i in [0...BUILTIN_PARAMS.length]
-                        alloca = llvm.IRBuilder.createAlloca BUILTIN_PARAMS[i].llvm_type, "local_#{n.params[i].name}"
+                        alloca = irbuilder.createAlloca BUILTIN_PARAMS[i].llvm_type, "local_#{n.params[i].name}"
                         new_scope[n.params[i].name] = alloca
                         allocas.push alloca

                 # create an alloca to store our 'EJSValue** args' parameter, so we can pull the formal parameters out of it
-                args_alloca = llvm.IRBuilder.createAlloca EjsValueType.pointerTo(), "local_%args"
+                args_alloca = irbuilder.createAlloca EjsValueType.pointerTo(), "local_%args"
                 new_scope["%args"] = args_alloca
                 allocas.push args_alloca

                 # now create allocas for the formal parameters
                 for param in n.params[BUILTIN_PARAMS.length..]
                         if param.type is syntax.Identifier
-                                alloca = llvm.IRBuilder.createAlloca EjsValueType, "local_#{param.name}"
+                                alloca = irbuilder.createAlloca EjsValueType, "local_#{param.name}"
                                 new_scope[param.name] = alloca
                                 allocas.push alloca
                         else
@@ -654,49 +667,49 @@
                                 throw "we don't handle destructured args at the moment."

                 debug.log "alloca #{alloca}" for alloca in allocas
-
+
                 # now store the arguments (use .. to include our args array) onto the stack
                 for i in [0..BUILTIN_PARAMS.length]
-                        store = llvm.IRBuilder.createStore ir_args[i], allocas[i]
+                        store = irbuilder.createStore ir_args[i], allocas[i]
                         debug.log "store #{store} *builtin"

                 # initialize all our named parameters to undefined
-                args_load = llvm.IRBuilder.createLoad args_alloca, "args_load"
+                args_load = irbuilder.createLoad args_alloca, "args_load"
                 if n.params.length > BUILTIN_PARAMS.length
                         for i in [BUILTIN_PARAMS.length...n.params.length]
-                                store = llvm.IRBuilder.createStore @loadUndefinedEjsValue(), allocas[i+1]
-
+                                store = irbuilder.createStore @loadUndefinedEjsValue(), allocas[i+1]
+
                 body_bb = new llvm.BasicBlock "body", ir_func
-                llvm.IRBuilder.setInsertPoint body_bb
+                irbuilder.setInsertPoint body_bb

                 insertFunc = body_bb.parent
-
+
                 # now pull the named parameters from our args array for the ones that were passed in.
                 # any arg that isn't specified
                 if n.params.length > BUILTIN_PARAMS.length
-                        load_argc = llvm.IRBuilder.createLoad allocas[2], "argc" # FIXME, magic number alert
-
+                        load_argc = irbuilder.createLoad allocas[2], "argc" # FIXME, magic number alert
+
                         for i in [BUILTIN_PARAMS.length...n.params.length]
                                 then_bb  = new llvm.BasicBlock "arg_then", insertFunc
                                 else_bb  = new llvm.BasicBlock "arg_else", insertFunc
                                 merge_bb = new llvm.BasicBlock "arg_merge", insertFunc

-                                cmp = llvm.IRBuilder.createICmpSGt load_argc, (llvm.Constant.getIntegerValue int32Type, i-BUILTIN_PARAMS.length), "argcmpresult"
-                                llvm.IRBuilder.createCondBr cmp, then_bb, else_bb
-
-                                llvm.IRBuilder.setInsertPoint then_bb
-                                arg_ptr = llvm.IRBuilder.createGetElementPointer args_load, (llvm.Constant.getIntegerValue int32Type, i-BUILTIN_PARAMS.length), "arg#{i-BUILTIN_PARAMS.length}_ptr"
+                                cmp = irbuilder.createICmpSGt load_argc, (llvm.Constant.getIntegerValue int32Type, i-BUILTIN_PARAMS.length), "argcmpresult"
+                                irbuilder.createCondBr cmp, then_bb, else_bb
+
+                                irbuilder.setInsertPoint then_bb
+                                arg_ptr = irbuilder.createGetElementPointer args_load, (llvm.Constant.getIntegerValue int32Type, i-BUILTIN_PARAMS.length), "arg#{i-BUILTIN_PARAMS.length}_ptr"
                                 debug.log "arg_ptr = #{arg_ptr}"
-                                arg = llvm.IRBuilder.createLoad arg_ptr, "arg#{i-BUILTIN_PARAMS.length-1}_load"
-                                store = llvm.IRBuilder.createStore arg, allocas[i+1]
+                                arg = irbuilder.createLoad arg_ptr, "arg#{i-BUILTIN_PARAMS.length-1}_load"
+                                store = irbuilder.createStore arg, allocas[i+1]
                                 debug.log "store #{store}"
-                                llvm.IRBuilder.createBr merge_bb
-
-                                llvm.IRBuilder.setInsertPoint else_bb
-                                llvm.IRBuilder.createBr merge_bb
-
-                                llvm.IRBuilder.setInsertPoint merge_bb
-
+                                irbuilder.createBr merge_bb
+
+                                irbuilder.setInsertPoint else_bb
+                                irbuilder.createBr merge_bb
+
+                                irbuilder.setInsertPoint merge_bb
+
                 # stacks of destinations used by continue and break, of the form [{label:..., dest:...}].
                 #
                 #  when we see an unlabeled "break" or "continue" we insert a branch to the top bb
@@ -704,24 +717,22 @@
                 @continueStack = []
                 @breakStack = []
                 @iifeStack = []
-
+
                 @visitWithScope new_scope, [n.body]

                 # XXX more needed here - this lacks all sorts of control flow stuff.
                 # Finish off the function.
-                llvm.IRBuilder.createRet @loadUndefinedEjsValue()
+                irbuilder.createRet @loadUndefinedEjsValue()

                 # insert an unconditional branch from entry_bb to body here, now that we're
                 # sure we're not going to be inserting allocas into the entry_bb anymore.
-                llvm.IRBuilder.setInsertPoint entry_bb
-                llvm.IRBuilder.createBr body_bb
+                irbuilder.setInsertPoint entry_bb
+                irbuilder.createBr body_bb

                 @currentFunction = null

-                llvm.IRBuilder.setInsertPoint insertBlock
-
-                console.log "ir_func = #{ir_func}"
-
+                irbuilder.setInsertPoint insertBlock
+
                 return ir_func

         visitUnaryExpression: (n) ->
@@ -729,15 +740,14 @@

                 builtin = "unop#{n.operator}"
                 callee = @ejs[builtin]
-
+
                 if n.operator is "delete"
                         if n.argument.type is syntax.MemberExpression
-                                return llvm.IRBuilder.createCall callee, [(@visitOrNull n.argument.object), (@visitOrNull n.argument.property)], "result"
-                        return
+                                return irbuilder.createCall callee, [(@visitOrNull n.argument.object), (@visitOrNull n.argument.property)], "result"
                 else
                         if not callee
                                 throw "Internal error: unary operator '#{n.operator}' not implemented"
-                        return llvm.IRBuilder.createCall callee, [@visitOrNull n.argument], "result"
+                        irbuilder.createCall callee, [@visitOrNull n.argument], "result"

         visitSequenceExpression: (n) ->
@@ -753,149 +763,145 @@
                 if not callee
                         throw "Internal error: unhandled binary operator '#{n.operator}'"
                 # call the add method
-                return llvm.IRBuilder.createCall callee, [(@visit n.left), (@visit n.right)], "result_#{builtin}"
+                return irbuilder.createCall callee, [(@visit n.left), (@visit n.right)], "result_#{builtin}"

         visitLogicalExpression: (n) ->
                 debug.log "operator = '#{n.operator}'"
                 result = @createAlloca @currentFunction, EjsValueType, "result_#{n.operator}"

                 left_visited = @visit n.left
-                cond_truthy = llvm.IRBuilder.createCall @ejs.truthy, [left_visited], "cond_truthy"
-
-                insertBlock = llvm.IRBuilder.getInsertBlock()
+                cond_truthy = irbuilder.createCall @ejs.truthy, [left_visited], "cond_truthy"
+
+                insertBlock = irbuilder.getInsertBlock()
                 insertFunc = insertBlock.parent
-
+
                 left_bb  = new llvm.BasicBlock "cond_left", insertFunc
                 right_bb  = new llvm.BasicBlock "cond_right", insertFunc
                 merge_bb = new llvm.BasicBlock "cond_merge", insertFunc

                 # we invert the test here - check if the condition is false/0
-                cmp = llvm.IRBuilder.createICmpEq cond_truthy, (llvm.Constant.getIntegerValue boolType, 0), "cmpresult"
-                llvm.IRBuilder.createCondBr cmp, right_bb, left_bb
-
-                llvm.IRBuilder.setInsertPoint left_bb
+                cmp = irbuilder.createICmpEq cond_truthy, (llvm.Constant.getIntegerValue boolType, 0), "cmpresult"
+                irbuilder.createCondBr cmp, right_bb, left_bb
+
+                irbuilder.setInsertPoint left_bb
                 # inside the else branch, left was truthy
                 if n.operator is "||"
                         # for || we short circuit out here
-                        llvm.IRBuilder.createStore left_visited, result
+                        irbuilder.createStore left_visited, result
                 else if n.operator is "&&"
                         # for && we evaluate the second and store it
-                        llvm.IRBuilder.createStore (@visit n.right), result
+                        irbuilder.createStore (@visit n.right), result
                 else
                         throw "Internal error 99.1"
-                llvm.IRBuilder.createBr merge_bb
-
-                llvm.IRBuilder.setInsertPoint right_bb
+                irbuilder.createBr merge_bb
+
+                irbuilder.setInsertPoint right_bb
                 # inside the then branch, left was falsy
                 if n.operator is "||"
                         # for || we evaluate the second and store it
-                        llvm.IRBuilder.createStore (@visit n.right), result
+                        irbuilder.createStore (@visit n.right), result
                 else if n.operator is "&&"
                         # for && we short circuit out here
-                        llvm.IRBuilder.createStore left_visited, result
+                        irbuilder.createStore left_visited, result
                 else
                         throw "Internal error 99.1"
-                llvm.IRBuilder.createBr merge_bb
-
-                llvm.IRBuilder.setInsertPoint merge_bb
-                rv = llvm.IRBuilder.createLoad result, "result_#{n.operator}_load"
-
-                llvm.IRBuilder.setInsertPoint merge_bb
+                irbuilder.createBr merge_bb
+
+                irbuilder.setInsertPoint merge_bb
+                rv = irbuilder.createLoad result, "result_#{n.operator}_load"
+
+                irbuilder.setInsertPoint merge_bb

                 rv

-        visitArgs: (callee, args) ->
+        visitArgsForCall: (callee, pullThisFromArg0, args) ->
                 argv = []
-
-                debug.log "args!!!!!!!!!!!!!!!!!!! #{args.length} of them"

                 args_offset = 0
                 if callee.takes_builtins
-                        argv.push @visitOrNull args[0]                                      # % env
-                        argv.push null                                                      # %this
-                        argv.push llvm.Constant.getIntegerValue int32Type, args.length-1    # argc. subtract 1 for our use of args[0] above
-                        args_offset = 1 # we used args[0] already, so skip it in the loop below
-
-                debug.log "args_offset = #{args_offset}"
+                        args_offset = 1
+                        if pullThisFromArg0 and args[0].type is syntax.MemberExpression
+                                thisArg = @visit args[0].object
+                                closure = @createPropertyLoad thisArg, args[0].property, args[0].computed
+                        else
+                                thisArg = @loadUndefinedEjsValue()
+                                closure = @visit args[0]
+
+                        argv.push closure                                                   # %closure
+                        argv.push thisArg                                                   # %this
+                        argv.push llvm.Constant.getIntegerValue int32Type, args.length-1    # %argc. -1 because we pulled out the first arg to send as the closure
+
                 if args.length > args_offset
                         argv.push @visitOrNull args[i] for i in [args_offset...args.length]

                 argv
-
+
+        visitArgsForConstruct: (callee, args) ->
+                argv = []
+
+                ctor = @visit args[0]
+
+                proto = @createPropertyLoad ctor, { name: "prototype" }, false
+
+                thisArg = irbuilder.createCall @ejs.object_new, [proto], "objtmp"
+
+                argv.push ctor                                                      # %closure
+                argv.push thisArg                                                   # %this
+                argv.push llvm.Constant.getIntegerValue int32Type, args.length-1    # %argc. -1 because we pulled out the first arg to send as the closure
+
+                if args.length > 1
+                        argv.push @visitOrNull args[i] for i in [1...args.length]
+
+                argv
+
         visitCallExpression: (n) ->
                 debug.log "visitCall #{JSON.stringify n}"
                 debug.log "          arguments length = #{n.arguments.length}"
                 debug.log "          arguments[#{i}] =  #{JSON.stringify n.arguments[i]}" for i in [0...n.arguments.length]
-
-                args = n.arguments
-
-                obj = @loadUndefinedEjsValue()
-
-                if n.callee.type is syntax.Identifier and n.callee.name[0] == '%'
-                        debug.log "builtin"
-                        callee = @builtins[n.callee.name.slice(1)]
-                        if callee.length # replace with a better Array test
-                                callee = callee[n.arguments.length]
-                        if n.callee.name is "%invokeClosure"
-                                # hack to pull out the proper "this" if the closure is a member expression
-                                closure = args[0]
-                                if closure.type is syntax.MemberExpression
-                                        obj = @visit closure.object
-                else if n.callee.type is syntax.MemberExpression
-                        debug.log "creating property load!"
-                        obj = @visit n.callee.object
-                        callee = @createPropertyLoad obj, n.callee.property, n.callee.computed
-                else
-                        callee = @visit n.callee
-
+
+                obj_load = @loadUndefinedEjsValue()
+                args_offset = 0
+
+                if n.callee.type isnt syntax.Identifier or n.callee.name[0] isnt '%'
+                        throw "invalid call to #{JSON.stringify n.callee}"
+
+                callee = @builtins[n.callee.name.slice(1)]
+                if Array.isArray callee
+                        callee = callee[n.arguments.length]
                 if not callee
-                        console.warn "visitCall #{JSON.stringify n}"
                         throw "Internal error: callee should not be null in visitCallExpression"

-                # At this point we assume callee is a function object
-                argv = @visitArgs callee, args
-
-                if callee.takes_builtins
-                        argv[1] = obj
-
-                debug.log "done visiting args"
+                pullThisFromArg0 = n.callee.name is "%invokeClosure"
+
+                argv = @visitArgsForCall callee, pullThisFromArg0, n.arguments

                 # we're dealing with a function here
                 # if callee.argSize isnt args.length
                 # this isn't invalid in JS.  if argSize > args.length, the args are undefined.
                 # if argSize < args.length, the args are still passed

-                llvm.IRBuilder.createCall callee, argv, if callee.returnType and callee.returnType.isVoid() then "" else "calltmp"
+                call_result = @createAlloca @currentFunction, EjsValueType, "call_result"
+                calltmp = irbuilder.createCall callee, argv, if callee.returnType and callee.returnType.isVoid() then "" else "calltmp"
+                store = irbuilder.createStore calltmp, call_result
+                irbuilder.createLoad call_result, "call_result_load"
+

         visitNewExpression: (n) ->
-                args = n.arguments
-
-                if n.callee.type is syntax.Identifier and n.callee.name[0] == '%'
-                        ctor = @builtins[n.callee.name.slice(1)]
-                        if ctor.length  # replace with a better Array test
-                                ctor = ctor[n.arguments.length]
-                else if n.callee.type is syntax.MemberExpression
-                        debug.log "creating property load!"
-                        ctor = @createPropertyLoad (@visit n.callee.object), n.callee.property, n.callee.computed
-                else
-                        ctor = @visit n.callee
-
-                if not ctor
+                if n.callee.type isnt syntax.Identifier or n.callee.name[0] isnt '%'
+                        throw "invalid ctor #{JSON.stringify n.callee}"
+
+                callee = @builtins[n.callee.name.slice(1)]
+                if Array.isArray callee
+                        callee = callee[n.arguments.length]
+                if not callee
                         throw "Internal error: ctor should not be null"
-
-
-                # ctor isn't the constructor here, by virtue of closure conversion.
-
-                argv = @visitArgs ctor, args
-
-                proto = @createPropertyLoad argv[0], { name: "prototype" }, false
-
-                obj = llvm.IRBuilder.createCall @ejs.object_new, [proto], "objtmp"
-                if ctor.takes_builtins
-                        argv[1] = obj
-
-                llvm.IRBuilder.createCall ctor, argv, "newtmp"
-                obj
+
+
+                argv = @visitArgsForConstruct callee, n.arguments
+
+                irbuilder.createCall callee, argv, "newtmp"
+
+                argv[1]

         visitPropertyAccess: (n) ->
                 debug.log "property access: #{nc[1].value}" #NC-USAGE
@@ -910,7 +916,7 @@
                 val = n.name
                 source = @findIdentifierInScope val, @current_scope
                 if source?
-                        rv = llvm.IRBuilder.createLoad source, "load_#{val}"
+                        rv = irbuilder.createLoad source, "load_#{val}"
                         return rv

                 # special handling of the arguments object here, so we
@@ -918,21 +924,20 @@
                 # actually going to use it.
                 if val is "arguments"
                         arguments_alloca = @createAlloca @currentFunction, EjsValueType, "local_arguments_object"
-                        saved_insert_point = llvm.IRBuilder.getInsertBlock()
-                        llvm.IRBuilder.setInsertPoint @currentFunction.entry_bb
-
-                        load_argc = llvm.IRBuilder.createLoad @currentFunction.topScope["%argc"], "argc_load"
-                        load_args = llvm.IRBuilder.createLoad @currentFunction.topScope["%args"], "args_load"
-
-                        arguments_object = llvm.IRBuilder.createCall @ejs.arguments_new, [load_argc, load_args], "argstmp"
-                        llvm.IRBuilder.createStore arguments_object, arguments_alloca
+                        saved_insert_point = irbuilder.getInsertBlock()
+                        irbuilder.setInsertPoint @currentFunction.entry_bb
+
+                        load_argc = irbuilder.createLoad @currentFunction.topScope["%argc"], "argc_load"
+                        load_args = irbuilder.createLoad @currentFunction.topScope["%args"], "args_load"
+
+                        arguments_object = irbuilder.createCall @ejs.arguments_new, [load_argc, load_args], "argstmp"
+                        irbuilder.createStore arguments_object, arguments_alloca
                         @currentFunction.topScope["arguments"] = arguments_alloca

-                        llvm.IRBuilder.setInsertPoint saved_insert_point
-                        rv = llvm.IRBuilder.createLoad arguments_alloca, "load_arguments"
+                        irbuilder.setInsertPoint saved_insert_point
+                        rv = irbuilder.createLoad arguments_alloca, "load_arguments"
                         return rv
-
-
+
                 rv = null
                 debug.log "calling getFunction for #{val}"
                 rv = @module.getFunction val
@@ -945,15 +950,15 @@
                 rv

         visitObjectExpression: (n) ->
-                obj = llvm.IRBuilder.createCall @ejs.object_new, [@loadNullEjsValue()], "objtmp"
+                obj = irbuilder.createCall @ejs.object_new, [@loadNullEjsValue()], "objtmp"
                 for property in n.properties
                         val = @visit property.value
                         key = property.key
                         @createPropertyStore obj, key, val, false
-                return obj
+                obj

         visitArrayExpression: (n) ->
-                obj = llvm.IRBuilder.createCall @ejs.array_new, [(llvm.Constant.getIntegerValue int32Type, n.elements.length)], "arrtmp"
+                obj = irbuilder.createCall @ejs.array_new, [(llvm.Constant.getIntegerValue int32Type, n.elements.length)], "arrtmp"
                 i = 0;
                 for el in n.elements
                         val = @visit el
@@ -972,30 +977,29 @@
                         return @loadNullEjsValue() # this isn't properly typed...  dunno what to do about this here
                 else if typeof n.raw is "string" and (n.raw[0] is '"' or n.raw[0] is "'")
                         debug.log "literal string: #{n.value}"
-                        c = llvm.IRBuilder.createGlobalStringPtr n.value, "strconst"
-                        strcall = llvm.IRBuilder.createCall @ejs.string_new_utf8, [c], "strtmp"
+                        c = irbuilder.createGlobalStringPtr n.value, "strconst"
+                        strcall = irbuilder.createCall @ejs.string_new_utf8, [c], "strtmp"
                         debug.log "strcall = #{strcall}"
                         return strcall
                 else if typeof n.raw is "string" and n.raw[0] is '/'
                         debug.log "literal regexp: #{n.raw}"
-                        c = llvm.IRBuilder.createGlobalStringPtr n.raw, "strconst"
-                        regexpcall = llvm.IRBuilder.createCall @ejs.regexp_new_utf8, [c], "regexptmp"
+                        c = irbuilder.createGlobalStringPtr n.raw, "strconst"
+                        regexpcall = irbuilder.createCall @ejs.regexp_new_utf8, [c], "regexptmp"
                         debug.log "regexpcall = #{strcall}"
                         return regexpcall
                 else if typeof n.value is "number"
                         debug.log "literal number: #{n.value}"
                         c = llvm.ConstantFP.getDouble n.value
-                        return llvm.IRBuilder.createCall @ejs.number_new, [c], "numtmp"
+                        return irbuilder.createCall @ejs.number_new, [c], "numtmp"
                 else if typeof n.value is "boolean"
                         debug.log "literal boolean: #{n.value}"
                         c = llvm.Constant.getIntegerValue boolType, (if n.value then 1 else 0)
-                        return llvm.IRBuilder.createCall @ejs.boolean_new, [c], "booltmp"
-                console.warn "n.raw[0] = #{n.raw[0]}"
+                        return irbuilder.createCall @ejs.boolean_new, [c], "booltmp"
                 throw "Internal error: unrecognized literal of type #{typeof n.value}"

         visitThrow: (n) ->
                 arg = @visit n.argument
-                return llvm.IRBuilder.createCall @ejs.throw, [arg], ""
+                return irbuilder.createCall @ejs.throw, [arg], ""

 class AddFunctionsVisitor extends NodeVisitor
         constructor: (@module) ->
@@ -1029,9 +1033,20 @@

 insert_toplevel_func = (tree, filename) ->
         sanitize = (filename) ->
-                filename = filename.replace /\.js$/, ""
-                filename = filename.replace /[.,-\/\\]/g, "_" # this is insanely inadequate
-                filename
+                if __ejs?
+                        filename = filename.replace ".js", ""
+                        if c_callable
+                                filename = filename.replace ".", "_"
+                                filename = filename.replace ",", "_"
+                                filename = filename.replace "-", "_"
+                                filename = filename.replace "/", "_"
+                                filename = filename.replace "\\", "_"
+                                filename
+                        filename
+                else
+                        filename = filename.replace /\.js$/, ""
+                        filename = filename.replace /[.,-\/\\]/g, "_" # this is insanely inadequate
+                        filename

         toplevel =
                 type: syntax.FunctionDeclaration,
@@ -1087,6 +1102,9 @@

         #tree = desugar tree
         #debug.log -> escodegen.generate tree
+
+        debug.log "before closure conversion"
+        debug.log -> escodegen.generate tree

         tree = closure_conversion.convert tree


Fix time units in standalone graph opening

--- src/code/models/codap-connect.coffee
+++ src/code/models/codap-connect.coffee
@@ -146,11 +146,12 @@
       }

   createGraph: (yAttributeName)->
+    timeUnit = TimeUnits.toString SimulationStore.store.settings.stepUnits, true
     @codapPhone.call
       action: 'createComponent'
       args: {
         type: 'DG.GraphView',
-        xAttributeName: 'time',
+        xAttributeName: timeUnit,
         yAttributeName: yAttributeName,
         size: { width: 242, height: 221 },
         position: 'bottom'


Interpolate points between two quickly-drawn points

When the mouse moves quickly across the drawing canvas, we only see a small
subset of the events. With a simple technique of recording the x, y location
of the events and plotting them on the graph, we are left with lots of missing
points.

A previous method for addressing this seemed to be to set all the points
from x-4 to x+4 to the same value. However, (1) this caused a weird "plateau"
effect of a flat area of the graph, and (2) we still got holes most of the
time when dragging across the canvas, resulting in a tooth-shaped line.

Now we check the time between the last-drawn point and this one, and if it
is <100ms, we interpolate all the points linearly between them. This seems
to work much better.

Also the way we set data is simplified, from knowing that our data is ordered.

[#156226989]

--- src/code/views/svg-graph-view.coffee
+++ src/code/views/svg-graph-view.coffee
@@ -200,14 +200,37 @@
       evt.preventDefault()
       scaledCoords = @pointToScaledCoords(evt)

-      if scaledCoords.x >= 0 && scaledCoords.x <= 100 && scaledCoords.y >= 0 && scaledCoords.y <= 100
-        newData = _.map @state.currentData, (d) ->
-          x = d[0]
-          y = d[1]
-          if x > scaledCoords.x - 4 && x < scaledCoords.x + 4
-            y = scaledCoords.y
-          [x, y]
-        @updatePointData @props.formula, newData
+      x = Math.round scaledCoords.x
+      y = scaledCoords.y
+
+      return if x < 0 || x > 100 || y < 0 || y > 100
+
+      # our data is ordered in the format [[0, y], [1, y], [2, y], ...]
+      # so we can set a new x, y simply using data[x] = [x, y]
+
+      newData = _.clone @state.currentData
+
+      currentTime = Date.now()
+      if @_lastPoint && @_lastPoint.x != x && currentTime - @_lastPoint.time < 100
+        # if our last point was < 100ms ago, this is probably the mouse moving across the canvas,
+        # so interpolate all the points between that point and this point
+        minX = Math.min x, @_lastPoint.x
+        maxX = Math.max x, @_lastPoint.x
+        minY = if x < @_lastPoint.x then y else @_lastPoint.y
+        maxY = if x < @_lastPoint.x then @_lastPoint.y else y
+        steps = maxX - minX
+        yStep = (maxY - minY) / steps
+        for i in [0..steps]
+          interpolatedX = minX + i
+          interpolatedY = minY + (yStep * i)
+          newData[interpolatedX] = [interpolatedX, interpolatedY]
+      else
+        # otherwise, just set this point
+        newData[x] = [x, y]
+
+      @updatePointData @props.formula, newData
+
+      @_lastPoint = {x: x, y: y, time: currentTime}

   endDrawCurve: (evt) ->
     if @drawing
@@ -216,6 +239,7 @@
       @drawing = false
       #update relation with custom data
       @updateRelationCustomData(@state.currentData)
+    delete @_lastPoint

   pointToScaledCoords: (evt) ->
     rect = this.refs.graphBody?.getBoundingClientRect()


artik5.coffee: Set initial versioning and change to 1
the partition holding config.json

Signed-off-by: Florin Sarbu <3a837a37a2ac9072a088641ec330e0e5d5b86f4e@resin.io>

--- artik5.coffee
+++ artik5.coffee
@@ -14,6 +14,7 @@
 ]

 module.exports =
+	version: 1
 	slug: 'artik5'
 	aliases: [ 'artik5' ]
 	name: 'Samsung Artik 5'
@@ -51,8 +52,7 @@
 	configuration:
 		config:
 			partition:
-				primary: 4
-				logical: 1
+				primary: 1
 			path: '/config.json'

 	initialization: commonImg.initialization


Only format Atom if Prettier is a project dependency

--- atom/config.cson
+++ atom/config.cson
@@ -79,6 +79,7 @@
   "prettier-atom":
     formatOnSaveOptions:
       enabled: true
+      isDisabledIfNotInPackageJson: true
     useEslint: true
   "ruby-test":
     rspecAllCommand: "source ~/.zshrc && spring rspec --tty"


Update to latest Atom configuration

Update to latest Atom configuration

--- atom/config.cson
+++ atom/config.cson
@@ -4,6 +4,9 @@
   "advanced-open-file":
     createFileInstantly: true
   "asciidoc-preview": {}
+  "atom-beautify":
+    _analyticsUserId: "628f791d-dc9a-4907-89ef-e27445244039"
+    js_indent_with_tabs: true
   "atom-color-highlight":
     hideMarkersInComments: true
     hideMarkersInStrings: true
@@ -21,12 +24,22 @@
   "autocomplete-erlang":
     elixirPath: "/usr/local/bin/elixir"
   "autocomplete-plus":
+    confirmCompletion: "tab"
     defaultProvider: "Fuzzy"
     scopeBlacklist: [
       ".string"
     ]
   core:
     audioBeep: false
+    customFileTypes:
+      "text.xml.plist": [
+        "plist"
+      ]
+    disabledPackages: [
+      "spell-check-test"
+      "autocomplete-elixir"
+      "autocomplete-erlang"
+    ]
     followSymlinks: true
     ignoredNames: [
       ".git"
@@ -45,7 +58,8 @@
     ]
   editor:
     backUpBeforeSaving: true
-    fontFamily: "Source Code Pro"
+    fontFamily: "Input Mono Narrow"
+    fontSize: 16
     invisibles:
       cr: "↩"
       eol: " "
@@ -58,7 +72,6 @@
     highlightAuthor: "lee-dohm"
   "exception-reporting":
     userId: "ee24cf00-f793-9081-be2a-2cdae5536b7f"
-  "find-and-replace": {}
   "fuzzy-finder":
     preserveLastSearch: true
   linter:
@@ -75,6 +88,8 @@
   metrics:
     userId: "51eeb6113c1ae801c9aade9b6d679aa5189ced25"
   minimap:
+    charHeight: 4
+    charWidth: 2
     plugins:
       "find-and-replace": true
     v4Preview: true
@@ -84,8 +99,10 @@
   "package-generator":
     createInDevMode: true
   pigments:
+    ignoredScopes: [
+      "\\.elixir"
+    ]
     markerType: "dot"
-  "spell-check": {}
   "status-bar":
     cursorPositionFormat: "L:%L C:%C"
   tabs:
@@ -114,21 +131,8 @@
 ".c.source":
   editor:
     tabLength: 4
-".css.scss.source":
-  editor:
-    preferredLineLength: 100
-".erb.html.text":
-  editor:
-    preferredLineLength: 100
-".erlang.html.text.yaws":
-  editor:
-    preferredLineLength: 100
-".erlang.source":
-  editor:
-    preferredLineLength: 100
 ".gfm.source":
   editor:
-    preferredLineLength: 100
     showInvisibles: false
     softWrap: true
     tabLength: 4
@@ -137,54 +141,15 @@
 ".git-commit.text":
   editor:
     preferredLineLength: 72
-".git-config.source":
-  editor:
-    preferredLineLength: 100
-".git-rebase.text":
-  editor:
-    preferredLineLength: 100
 ".haml.text":
   "wrap-guide":
     enabled: false
-".html.ruby.text":
-  editor:
-    preferredLineLength: 100
 ".java.source":
   editor:
     tabLength: 4
-".js.rails.source source.jquery.js":
-  editor:
-    preferredLineLength: 100
-".js.regexp.replacement.source":
-  editor:
-    preferredLineLength: 100
-".js.regexp.source":
-  editor:
-    preferredLineLength: 100
-".js.source":
-  editor:
-    preferredLineLength: 100
 ".json.source":
   "wrap-guide":
     enabled: false
-".plain.text":
-  editor:
-    preferredLineLength: 80
 ".python.source":
   editor:
     tabLength: 4
-".rails.rjs.ruby.source":
-  editor:
-    preferredLineLength: 100
-".rails.ruby.source":
-  editor:
-    preferredLineLength: 100
-".ruby.source":
-  editor:
-    preferredLineLength: 100
-".ruby.source.sql":
-  editor:
-    preferredLineLength: 100
-".sass.source":
-  editor:
-    preferredLineLength: 100


chore(atom/config.cson): backup atom/config.cson

--- atom/config.cson
+++ atom/config.cson
@@ -24,7 +24,6 @@
     fonts: {}
     tabs:
       compactTabs: true
-      tintedTabBar: true
     treeView:
       compactList: true
     ui:
@@ -33,12 +32,14 @@
   "atom-pair": {}
   "color-picker": {}
   core:
+    autoHideMenuBar: true
     disabledPackages: [
       "vim-mode"
       "vim-surround"
       "vim-mode-plus-ex-mode"
       "welcome"
       "markdown-format"
+      "terminal-plus"
     ]
     packagesWithKeymapsDisabled: []
     telemetryConsent: "limited"
@@ -61,6 +62,7 @@
   "exception-reporting":
     userId: "5f1fd872-de33-9d23-b5da-da0fbe791e6c"
   "file-icons": {}
+  "git-plus": {}
   jumpy:
     fontSize: 1
   "markdown-preview":
@@ -87,6 +89,8 @@
     markerType: "native-dot"
   "regex-railroad-diagram": {}
   script: {}
+  "terminal-plus":
+    core: {}
   "todo-show": {}
   "tree-view":
     alwaysOpenExisting: true
@@ -96,7 +100,6 @@
     wrapLeftRightMotion: true
   "vim-mode-plus":
     clearHighlightSearchOnResetNormalMode: true
-    clearMultipleCursorsOnEscapeInsertMode: true
     highlightSearch: true
     ignoreCaseForSearch: true
     ignoreCaseForSearchCurrentWord: true


Switch to Inconsolata for Atom font

Switch to Inconsolata for Atom font

--- atom/config.cson
+++ atom/config.cson
@@ -24,7 +24,7 @@
       "one-light-syntax"
     ]
   editor:
-    fontFamily: "Hack"
+    fontFamily: "Inconsolata"
     fontSize: 20
     invisibles: {}
     tabType: "soft"


Adjusted settings

Adjusted settings

--- atom/config.cson
+++ atom/config.cson
@@ -31,7 +31,7 @@
   "exception-reporting":
     userId: "f1e0477d-2841-2599-08d1-fa26e2c03351"
   "file-icons":
-    coloured: false
+    coloured: true
     forceShow: true
     onChanges: true
   "flex-tool-bar": {}
@@ -62,6 +62,6 @@
     iconSize: "16px"
     position: "Right"
   "tree-view":
-    hideIgnoredNames: true
+    hideIgnoredNames: false
   welcome:
     showOnStartup: false


Change output parameter from outDir to outFile

related to b3a102460b79da753c8d4b41829aa9564896a114

--- lib/grammars.coffee
+++ lib/grammars.coffee
@@ -829,8 +829,8 @@
         code = context.getCode(true)
         tmpFile = GrammarUtils.createTempFileWithCode(code, ".ts")
         jsFile = tmpFile.replace /\.ts$/, ".js"
-        args = ['-c', "tsc --outDir '#{jsFile}' '#{tmpFile}' && node '#{jsFile}'"]
-        return args
-    "File Based":
-      command: "bash"
-      args: (context) -> ['-c', "tsc '#{context.filepath}' --outDir /tmp/js.out && node /tmp/js.out"]
+        args = ['-c', "tsc --outFile '#{jsFile}' '#{tmpFile}' && node '#{jsFile}'"]
+        return args
+    "File Based":
+      command: "bash"
+      args: (context) -> ['-c', "tsc '#{context.filepath}' --outFile /tmp/js.out && node /tmp/js.out"]


updating leave confirmation to use tutor dialog

--- src/components/task-plan/footer.cjsx
+++ src/components/task-plan/footer.cjsx
@@ -2,6 +2,7 @@
 BS = require 'react-bootstrap'
 {TaskPlanStore, TaskPlanActions} = require '../../flux/task-plan'
 AsyncButton = require '../buttons/async-button'
+TutorDialog = require '../tutor-dialog'

 PlanFooter = React.createClass
   displayName: 'PlanFooter'
@@ -33,11 +34,15 @@
   onCancel: ->
     {id, courseId} = @props

-    if TaskPlanStore.isChanged(id) and confirm('Are you sure you want to cancel?')
+    if not TaskPlanStore.isChanged(id)
       @reset()
-    else if not TaskPlanStore.isChanged(id)
-      @reset()
-
+    else
+      TutorDialog.show(
+        title: 'Unsaved Changes'
+        body: 'Are you sure you want to cancel?'
+      ).then( =>
+        @reset()
+      )

   reset: ->
     {id, courseId} = @props


refactor matcher

refactor matcher

--- lib/matchers.coffee
+++ lib/matchers.coffee
@@ -3,11 +3,11 @@
 module.exports =
   isA: (type) ->
     __matches: (actual) ->
-      if _.isNumber(actual)
-        new Number(actual) instanceof type
-      else if _.isString(actual)
-        new String(actual) instanceof type
-      else if _.isBoolean(actual)
-        new Boolean(actual) instanceof type
+      if type == Number
+        _.isNumber(actual)
+      else if type == String
+        _.isString(actual)
+      else if type == Boolean
+        _.isBoolean(actual)
       else
         actual instanceof type


notification for forked

notification for forked

--- lib/notifier.coffee
+++ lib/notifier.coffee
@@ -57,7 +57,7 @@
                 notif.onclick = ->
                   notif.close()

-              if rawData.message.type == 'forked'
+              if rawData.message.type == 'lesson_forked'
                 notif = new Notification rawData.title,
                   body: rawData.message.value == 'true' ? 'Lesson forked successfully' : 'Lesson forked failed'


Guard against null window load time

Guard against null window load time

--- lib/reporter.coffee
+++ lib/reporter.coffee
@@ -15,7 +15,7 @@
           version: atom.getVersion()
           cpus: os.cpus()?.length ? 0
           memory: os.totalmem() ? 0
-          window_load_time: atom.getWindowLoadTime()
+          window_load_time: atom.getWindowLoadTime() ? 0
         context:
           packages: @getPackageData()
           themes: @getThemeData()


Open temporary tab if file is modified

Open temporary tab if file is modified

--- lib/tab-view.coffee
+++ lib/tab-view.coffee
@@ -164,6 +164,9 @@

   updateModifiedStatus: ->
     if @item.isModified?()
+      if atom.config.get('tabs.temporaryTabs')
+        @open = true
+        @itemTitle.classList.remove('temp')
       @classList.add('modified') unless @isModified
       @isModified = true
     else


Fix incorrect check for item pendingness

Signed-off-by: Katrina Uychaco <ef0b2ab5bd1ac851826b76acd653f3c4825374fb@github.com>

--- lib/tab-view.coffee
+++ lib/tab-view.coffee
@@ -26,7 +26,7 @@
     @updateModifiedStatus()
     @setupTooltip()

-    if @pane.getPendingItem() is @item
+    if @isItemPending()
       @itemTitle.classList.add('temp')
       @classList.add('pending-tab')


removed rain fake

removed rain fake

--- lib/uweather.coffee
+++ lib/uweather.coffee
@@ -39,7 +39,7 @@

     for entry, i in data.hourly_forecast
       if i < 13
-        weather.rain.probability.push(Math.min(99, parseInt(entry.pop, 10)*10))
+        weather.rain.probability.push(Math.min(99, parseInt(entry.pop, 10)))
         weather.rain.hour.push(if i%6 is 0 then entry.FCTTIME.hour else "")

     weather.probabilityMax = Math.floor weather.rain.probability.reduce((prev, current) ->


Bugfix for initial prop onChange

Bugfix for initial prop onChange

--- components.coffee
+++ components.coffee
@@ -244,6 +244,9 @@

     reactSpec.getInitialState = ->
+        J.assert not Tracker.active, "Can't initialize a component
+            in a reactive computation: #{@toString()}"
+
         @_componentId = J._nextComponentId
         J._nextComponentId += 1
         J._componentById[@_componentId] = @
@@ -458,8 +461,9 @@
         # Call all the onChange handlers synchronously because they might initialize
         # the state during a cascading React render thread.
         for lazyPropName, lazyPropAutoVar of @_lazyProps
-            propVar = @_props[lazyPropName]
-            lazyPropAutoVar.onChange? undefined, propVar._value, true
+            lazyPropValue = lazyPropAutoVar.get()
+            if _.isFunction lazyPropAutoVar.onChange
+                lazyPropAutoVar.onChange undefined, lazyPropValue, true
         for reactiveName, reactiveAutoVar of @reactives
             reactiveSpec = reactiveSpecByName[reactiveName]
             if reactiveSpec.early


Add EOF error

Add EOF error

--- lisp.coffee
+++ lisp.coffee
@@ -52,7 +52,11 @@
   expects: (pattern, throwing = false) ->
     valid = @code[@pos] && (pattern instanceof RegExp and pattern.test @code[@pos]) || pattern == @code[@pos...@pos + pattern.length]
     if !valid && throwing
-      throw "unexpected \"#{@code[@pos]}\", expects \"#{pattern}\""
+      current = if @pos < @code.length
+          @code[@pos]
+        else
+          'EOF'
+      throw "unexpected \"#{current}\", expects \"#{pattern}\""

     return valid


Move this package to the top of the projects list

--- user/projects.cson
+++ user/projects.cson
@@ -1,15 +1,15 @@
 [
+	{
+		title: "@Atom Theme"
+		paths: [
+			"/Users/johngardner/Labs/Atom-PhoenixTheme"
+		]
+		devMode: true
+	}
 	{
 		title: "Snippets"
 		paths: [
 			"/Users/johngardner/Labs/Snippets"
-		]
-		devMode: true
-	}
-	{
-		title: "@Atom Theme"
-		paths: [
-			"/Users/johngardner/Labs/Atom-PhoenixTheme"
 		]
 		devMode: true
 	}


update test timeout

update test timeout

Signed-off-by: Joshua Rubin <5af9dd6785dff068189d7fd731f38e1d0699263c@zvelo.com>

--- test/src/base/hashmash_test.coffee
+++ test/src/base/hashmash_test.coffee
@@ -122,7 +122,7 @@

       describe "success", ->
         it "should validate", (done) ->
-          @timeout(20000)
+          @timeout(30000)

           hc = new HashMash parts.bits
           hc.generate(parts.resource)


Update language to match default

Update language to match default

`en_US` != `en`

It may be better to reject this fix and change english.coffee, but I'm unsure if you want to use 2-char or 4-char codes.

Cheers

--- client/entry.coffee
+++ client/entry.coffee
@@ -8,7 +8,7 @@
   config: (appConfig) ->
     @settings = _.extend(@settings, appConfig)

-    i18n.setDefaultLanguage "en_US"
+    i18n.setDefaultLanguage "en"
     if appConfig.language
       i18n.setLanguage appConfig.language


Tooltip on pause animation button fix.

Tooltip on pause animation button fix.

--- client/index.coffee
+++ client/index.coffee
@@ -58,7 +58,6 @@

 Template.backgroundPause.events
   'click button': (event, template) ->
-    $(template.find 'button').tooltip('destroy')
     Session.set('backgroundPaused', not Session.get 'backgroundPaused')
     return # Make sure CoffeeScript does not return anything


some todo notes

some todo notes

--- client/index.coffee
+++ client/index.coffee
@@ -4,7 +4,16 @@
 React = require('react')
 R = React.DOM

+# TODO
+# - wire up websocket to vert.x
+# - consume David's event stream
+# - use Rx to throttle it and do rollups
+# - chart it
+
+# see
+# http://neugierig.org/software/blog/2014/02/react-jsx-coffeescript.html
+# for notes on using React directly in coffeescript rather than via jsx
 component = R.h1 null,
   pkg.name
-  " brought to you by Tavis and David!"
+  " a work in progress brought to you by Tavis and David!"
 React.renderComponent(component, document.body);


update task-panel.cjsx

update task-panel.cjsx

--- views/components/main/parts/task-panel.cjsx
+++ views/components/main/parts/task-panel.cjsx
@@ -132,7 +132,7 @@
           if getCurrentDay() < questRecord.day
             for id, q of questRecord
               delete questRecord[id] if questGoals[id].type is 3
-          if getCurrentMonth() > questRecord.month
+          if getCurrentMonth() isnt questRecord.month
             for id, q of questRecord
               delete questRecord[id] if questGoals[id].type is 6
         else


Synchronize the fancy toggle its related form on load

Because some browsers restore previous state on reload.

--- resources/assets/coffee/_classes/form-toggle.coffee
+++ resources/assets/coffee/_classes/form-toggle.coffee
@@ -18,12 +18,24 @@

 class @FormToggle
   constructor: ->
-    $(document).on 'change', '.js-form-toggle--input', @togglePollForm
+    addEventListener 'turbolinks:load', @sync
+    $(document).on 'change', '.js-form-toggle--input', @onChange

-  togglePollForm: (e) =>
-    show = e.currentTarget.checked
-    id = e.currentTarget.dataset.formToggleId
+  onChange: (e) =>
+    @toggle e.currentTarget
+
+
+  sync: =>
+    inputs = document.getElementsByClassName('js-form-toggle--input')
+
+    @toggle(input) for input in inputs
+
+
+  toggle: (input) ->
+    id = input.dataset.formToggleId
+    show = input.checked
+
     $form = $(".js-form-toggle--form[data-form-toggle-id='#{id}']")

     direction = if show then 'Down' else 'Up'


[fix] Ensure saveAs is in scope so downloading works

--- public/js/baobab.controller.thread.coffee
+++ public/js/baobab.controller.thread.coffee
@@ -1,5 +1,5 @@

-define ["angular", "underscore", "error"], (angular, _, error) ->
+define ["angular", "underscore", "error", "FileSaver"], (angular, _, error, saveAs) ->
   angular.module("baobab.controller.thread", [])
   .controller('ThreadCtrl', ['$scope', '$namespaces', '$threads', '$modal', '$routeParams', '$location', '$scrollState',
     ($scope, $namespaces, $threads, $modal, $routeParams, $location, $scrollState) ->


[feature] Switch to full-page composer if there is only one draft in a thread

--- public/js/baobab.controller.thread.coffee
+++ public/js/baobab.controller.thread.coffee
@@ -98,6 +98,10 @@

       @draftClicked = (msg) =>
+        if (@messages.length == 0 && @drafts.length == 1)
+          $location.path("/mail/compose/" + msg.id)
+          return
+
         @draft = msg
         $scope.$broadcast("compose-set-draft", msg)


`util/routes`: rewritten date & time helpers

--- util/routes.coffee
+++ util/routes.coffee
@@ -61,17 +61,33 @@

 	return [
 		[
-			('0' + start.getHours()).slice -2
-			('0' + start.getMinutes()).slice -2
-		].join ':'
-		'–'
-		[
-			('0' + stop.getHours()).slice -2
-			('0' + stop.getMinutes()).slice -2
-		].join ':'
-		chalk.yellow new Duration(stop - start).toString()
+			renderTime first.when
+			renderTime last.when
+		].join chalk.gray '-'
+		renderDuration first.when, last.when
 		types
 	].join ' '
+
+
+
+
+
+renderDate = (timestamp) ->
+	return chalk.cyan moment.unix(timestamp).format 'MMM D'
+
+renderTime = (timestamp) ->
+	return chalk.cyan moment.unix(timestamp).format 'HH:mm'
+
+renderDuration = (start, stop) ->
+	if stop? then m = moment.duration stop - start
+	else m = moment.duration start
+	result = []
+	if m.hours() >= 1 then result.push m.hours() + 'h'
+	if m.minutes() >= 1 then result.push m.minutes() + 'm'
+	if m.seconds() >= 1 then result.push m.seconds() + 's'
+	return chalk.yellow result.join ' '
+	# todo: pad numbers with ' '
+	# todo: ' ' between digits


Update tests to use `v2` instead of `ewa`

Change-type: patch

--- tests/integration/auth.spec.coffee
+++ tests/integration/auth.spec.coffee
@@ -69,7 +69,7 @@
 				.then (userId) ->
 					return resin.request.send
 						method: 'DELETE'
-						url: "/ewa/user(#{userId})"
+						url: "/v2/user(#{userId})"
 						baseUrl: sdkOpts.apiUrl
 					.then(resin.auth.logout)
 				.catch(message: 'Request error: Unauthorized', ->)


fix: Ignore linter package instalation

fix: Ignore linter package instalation

--- configs/atom.cson
+++ configs/atom.cson
@@ -1,6 +1,10 @@
 "*":
   "atom-beautify":
     general: {}
+  "atom-package-deps":
+    ignored: [
+      "linter-package-json-validator"
+    ]
   core:
     telemetryConsent: "limited"
   editor:


Add context menu items to open related files

--- menus/titanium.cson
+++ menus/titanium.cson
@@ -1,22 +1,28 @@
-# See https://atom.io/docs/latest/hacking-atom-package-word-count#menus for more details
 'context-menu':
   'atom-text-editor': [
     {
-      'label': 'Toggle titanium'
-      'command': 'titanium:toggle'
+      'label': 'Alloy'
+      'submenu': [
+        {
+          'label': 'Open view'
+          'command': 'titanium:openView'
+        }
+        {
+          'label': 'Open style'
+          'command': 'titanium:openStyle'
+        }
+        {
+          'label': 'Open controller'
+          'command': 'titanium:openController'
+        }
+        {
+          'label': 'Open related'
+          'command': 'titanium:openAllRelatedFiles'
+        }
+        {
+          'label': 'Clode related'
+          'command': 'titanium:closeAllRelatedPanes'
+        }
+      ]
     }
   ]
-'menu': [
-  {
-    'label': 'Packages'
-    'submenu': [
-      'label': 'titanium'
-      'submenu': [
-        {
-          'label': 'Toggle'
-          'command': 'titanium:toggle'
-        }
-      ]
-    ]
-  }
-]


unused

unused

--- resources/assets/lib/store-centili.coffee
+++ resources/assets/lib/store-centili.coffee
@@ -30,7 +30,6 @@

   observer = new MutationObserver (mutations) ->
     mutations.forEach (mutation) ->
-      $nodes = $(mutation.addedNodes)
       hasFrame = false
       hasContent = false
       for node in mutation.addedNodes


add acceptance test for ordering of project structure changes

--- services/document-updater/test/acceptance/coffee/ApplyingUpdatesToProjectStructureTests.coffee
+++ services/document-updater/test/acceptance/coffee/ApplyingUpdatesToProjectStructureTests.coffee
@@ -104,6 +104,73 @@
 					update.version.should.equal "#{@version}.0"

 					done()
+
+	describe "renaming multiple documents and files", ->
+		before ->
+			@docUpdate0 =
+				id: DocUpdaterClient.randomId()
+				pathname: '/doc-path0'
+				newPathname: '/new-doc-path0'
+			@docUpdate1 =
+				id: DocUpdaterClient.randomId()
+				pathname: '/doc-path1'
+				newPathname: '/new-doc-path1'
+			@docUpdates = [ @docUpdate0, @docUpdate1 ]
+			@fileUpdate0 =
+				id: DocUpdaterClient.randomId()
+				pathname: '/file-path0'
+				newPathname: '/new-file-path0'
+			@fileUpdate1 =
+				id: DocUpdaterClient.randomId()
+				pathname: '/file-path1'
+				newPathname: '/new-file-path1'
+			@fileUpdates = [ @fileUpdate0, @fileUpdate1 ]
+
+		describe "when the documents are not loaded", ->
+			before (done) ->
+				@project_id = DocUpdaterClient.randomId()
+				DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, @fileUpdates, @version, (error) ->
+					throw error if error?
+					setTimeout done, 200
+
+			it "should push the applied doc renames to the project history api", (done) ->
+				rclient_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
+					throw error if error?
+
+					update = JSON.parse(updates[0])
+					update.doc.should.equal @docUpdate0.id
+					update.pathname.should.equal '/doc-path0'
+					update.new_pathname.should.equal '/new-doc-path0'
+					update.meta.user_id.should.equal @user_id
+					update.meta.ts.should.be.a('string')
+					update.version.should.equal "#{@version}.0"
+
+					update = JSON.parse(updates[1])
+					update.doc.should.equal @docUpdate1.id
+					update.pathname.should.equal '/doc-path1'
+					update.new_pathname.should.equal '/new-doc-path1'
+					update.meta.user_id.should.equal @user_id
+					update.meta.ts.should.be.a('string')
+					update.version.should.equal "#{@version}.1"
+
+					update = JSON.parse(updates[2])
+					update.file.should.equal @fileUpdate0.id
+					update.pathname.should.equal '/file-path0'
+					update.new_pathname.should.equal '/new-file-path0'
+					update.meta.user_id.should.equal @user_id
+					update.meta.ts.should.be.a('string')
+					update.version.should.equal "#{@version}.2"
+
+					update = JSON.parse(updates[3])
+					update.file.should.equal @fileUpdate1.id
+					update.pathname.should.equal '/file-path1'
+					update.new_pathname.should.equal '/new-file-path1'
+					update.meta.user_id.should.equal @user_id
+					update.meta.ts.should.be.a('string')
+					update.version.should.equal "#{@version}.3"
+
+					done()
+

 	describe "adding a file", ->
 		before (done) ->


fix shopping spec

fix shopping spec

--- spec/javascripts/lib/core/shopping_cart_spec.coffee
+++ spec/javascripts/lib/core/shopping_cart_spec.coffee
@@ -4,10 +4,6 @@

     it 'is defined', ->
       expect(ShoppingCart).toBeDefined()
-
-    it 'has a version', ->
-      expect(ShoppingCart.version).toBeDefined()
-

     describe 'Empty basket', ->


Ignore whitespace in comparison operator

--- grammars/perl.cson
+++ grammars/perl.cson
@@ -741,7 +741,7 @@
     'name': 'keyword.operator.logical.perl'
   }
   {
-    'match': '(<=>| =>|->)'
+    'match': '(<=>|=>|->)'
     'name': 'keyword.operator.comparison.perl'
   }
   {


fix path to bumble docs - get's flattened by npm

--- gruntConfig.coffee
+++ gruntConfig.coffee
@@ -11,7 +11,7 @@
 _ = require('lodash')

-BUMBLE_DOCS_SCRIPTS = './node_modules/bumble-build/node_modules/bumble-docs/bin/'
+BUMBLE_DOCS_SCRIPTS = './node_modules/bumble-docs/bin/'
 bumbleScriptCommand = (scriptFile, args="")->
   return "coffee #{Path.join(BUMBLE_DOCS_SCRIPTS, scriptFile)} #{args}"


basic voxel stacking

basic voxel stacking

--- src/client/rooms/controllers/room-controller.coffee
+++ src/client/rooms/controllers/room-controller.coffee
@@ -36,7 +36,10 @@

             placeTile = (i, y, z, type) ->
                 tile = Crafty.e "2D, DOM, #{type}, Mouse"
-                            .attr 'z',i+1 * y+1
+                            .attr 'gridX', i
+                            .attr 'gridY', y
+                            .attr 'gridZ', z
+                            .attr 'z',i+1 * y+1 # graphical layering ordering
                             .areaMap 74,10,138,42,138,106,74,138,10,106,10,42
                             .bind "MouseUp", (e) ->
                                 # destroy on right click
@@ -58,16 +61,25 @@
                                     this.sprite 1,0,1,1
                                     return

-                    iso.place i,y,0,tile
+                    iso.place i,y,z,tile
                     return tile

             iso = Crafty.isometric.size 128
-            z = 0
+            z = 0 # z dimension
             for x in [20...0]
                 for y in [0...20]
                     which = Crafty.math.randomInt 0,10
-                    type = if which > 5 then "grass" else "stone"
-                    placeTile(x, y, z, type)
+                    # type = if which > 5 then "grass" else "stone"
+                    type = 'stone'
+                    tile = placeTile(x, y, z, type)
+                    tile.bind "MouseUp", (e) ->
+                        if e.mouseButton == Crafty.mouseButtons.LEFT
+                            $log.debug this.gridX
+                            $log.debug this.gridY
+                            $log.debug this.gridZ
+                            $log.debug 'YO'
+                            placeTile(this.gridX, this.gridY, this.gridZ + 2, 'grass')
+                        return

             # these are dom events (not crafty.js ones) so don't capitalize them
             Crafty.addEvent this, Crafty.stage.elem, "mousedown", (e) ->


remove debug logging

remove debug logging

--- newebe/client/app/views/app_view.coffee
+++ newebe/client/app/views/app_view.coffee
@@ -116,7 +116,6 @@
         else @checkUserState showView

     changeSubView: (subView, callback) =>
-        console.log $(window).width()
         if $(window).width() < 760
             @$('#navigation ul').slideUp()
         @changeMenuState subView


Create a new Bunchball object to handle api communication w/ bunchball. Remove a bunch of code in gamification that the new object replaces. First steps to eliminating gon by adding data attributes to the body tags of appropriate pages. Create namespaces for decorators and libraries in the window.ttm family. Update student dashboard decorator to use bunchball lib object.

--- javascripts/lib.coffee
+++ javascripts/lib.coffee
@@ -2,7 +2,8 @@
 #= require underscore-min

 window.ttm ||= {}
-window.decorators ||= {}
+window.ttm.decorators ||= {}
+window.ttm.lib ||= {}

 ttm.ClassMixer = (klass)->
   klass.build = ->


Autocomplete snippets now are pipe operator aware

--- lib/elixir-autocomplete-provider.coffee
+++ lib/elixir-autocomplete-provider.coffee
@@ -37,7 +37,9 @@
       unless (activatedManually || 'autocomplete-active' in editorElement.classList)
         return

-    prefix = getPrefix(editor, bufferPosition)
+    textBeforeCursor = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition])
+    prefix = getPrefix(textBeforeCursor)
+    pipeBefore = !!textBeforeCursor.match(///\|>\s*#{prefix}$///)

     return if !activatedManually && prefix == ""

@@ -71,17 +73,16 @@
           name = fields[0]
           if lastModuleHint && (lastModuleHint not in [name, ":#{name}"]) && modules_to_add.length > 0
             fields[0] = modules_to_add.join('.') + '.' + name
-          createSuggestion(serverSuggestion, fields, prefix)
+          createSuggestion(serverSuggestion, fields, prefix, pipeBefore)

         suggestions = sortSuggestions(suggestions)
         resolve(suggestions)

-  getPrefix = (editor, bufferPosition) ->
-    line = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition])
+  getPrefix = (textBeforeCursor) ->
     regex = /[\w0-9\._!\?\:@]+$/
-    line.match(regex)?[0] or ''
-
-  createSuggestion = (serverSuggestion, fields, prefix) ->
+    textBeforeCursor.match(regex)?[0] or ''
+
+  createSuggestion = (serverSuggestion, fields, prefix, pipeBefore) ->
     if fields[1] == 'module'
       [name, kind, subtype, desc] = fields
     else
@@ -95,15 +96,15 @@
       when 'var'
         createSuggestionForVariable(name)
       when 'private_function'
-        createSuggestionForFunction(serverSuggestion, name, kind, signature, "", desc, spec, prefix)
+        createSuggestionForFunction(serverSuggestion, name, kind, signature, "", desc, spec, prefix, pipeBefore)
       when 'public_function'
-        createSuggestionForFunction(serverSuggestion, name, kind, signature, "", desc, spec, prefix)
+        createSuggestionForFunction(serverSuggestion, name, kind, signature, "", desc, spec, prefix, pipeBefore)
       when 'function'
-        createSuggestionForFunction(serverSuggestion, name, kind, signature, mod, desc, spec, prefix)
+        createSuggestionForFunction(serverSuggestion, name, kind, signature, mod, desc, spec, prefix, pipeBefore)
       when 'public_macro'
-        createSuggestionForFunction(serverSuggestion, name, kind, signature, "", desc, spec, prefix)
+        createSuggestionForFunction(serverSuggestion, name, kind, signature, "", desc, spec, prefix, pipeBefore)
       when 'macro'
-        createSuggestionForFunction(serverSuggestion, name, kind, signature, mod, desc, spec, prefix)
+        createSuggestionForFunction(serverSuggestion, name, kind, signature, mod, desc, spec, prefix, pipeBefore)
       when 'module'
         createSuggestionForModule(serverSuggestion, name, desc, prefix, subtype)
       else
@@ -138,7 +139,7 @@
       rightLabel: 'variable'
     }

-  createSuggestionForFunction = (serverSuggestion, name, kind, signature, mod, desc, spec, prefix) ->
+  createSuggestionForFunction = (serverSuggestion, name, kind, signature, mod, desc, spec, prefix, pipeBefore) ->
     args = signature.split(',')
     [func, arity] = name.split('/')
     [moduleParts..., postfix] = prefix.split('.')
@@ -155,10 +156,13 @@
       params  = [1..arity].map (i) -> "${#{i}:arg#{i}}"
       displayText = "#{func}/#{arity}"

-    if arity != '0'
-      snippet = "#{func}(#{params.join(', ')})"
-
-    snippet = snippet.replace(/^:/, '') + " $0"
+    snippet_params = params
+    snippet_params = snippet_params[1...] if snippet_params.length > 0 && pipeBefore
+
+    if snippet_params.length > 0
+      snippet = "#{func}(#{snippet_params.join(', ')})"
+
+    snippet = snippet.replace(/^:/, '') + "$0"

     [type, iconHTML, rightLabel] =
       switch kind


Remove unnecessary fat arrow

Remove unnecessary fat arrow

--- lib/models/environment-variables.coffee
+++ lib/models/environment-variables.coffee
@@ -9,7 +9,7 @@
 				application: applicationId
 			orderby: 'name asc'

-	.then (environmentVariables) =>
+	.then (environmentVariables) ->
 		if not environmentVariables?
 			return Promise.reject(new Error('Not found'))
 		return environmentVariables


nprogress.js tooltip in tree

nprogress.js tooltip in tree

--- main/static/src/script/site/tree.coffee
+++ main/static/src/script/site/tree.coffee
@@ -54,6 +54,7 @@

   'lib': 'The server side (Python) libraries. If you want to add more Python libraries that are not included in the default installation, just put them here.'
   'bootstrap': 'The Bootstrap sources that includes all the *.less and *.js files.'
+  'nprogress.js': 'A nanoscopic progress bar. Featuring realistic trickle animations to convince your users that something is happening!
 Read More '

   'templates': 'The Jinja2 templates.'
   'base.html': 'The base template that most of the pages are inheriting from.'


Fixed #337 refreshing grid for non empty initial filter value

--- wzk/ui/grid/FilterWatcher.coffee
+++ wzk/ui/grid/FilterWatcher.coffee
@@ -58,11 +58,10 @@
   handleLoad: (e) =>
     if @initialCheck
       @query.each (k, v) =>
-        if @fields[k]?
+        if v[0]?
           @fields[k].setValue v[0]
-    else
-      for k, field of @fields
-        @filter field
+    for k, field of @fields
+      @filter field
     @initialCheck = false

   ###*


Small optimizations

Small optimizations

* Avoid to access the db twice for same document
* Change for loop into while

--- server/controllers/sharing.coffee
+++ server/controllers/sharing.coffee
@@ -283,9 +283,9 @@
         return next err if err?

         # Get the answering target
-        for t in doc.targets
-            if t.recipientUrl is answer.recipientUrl
-                target = t
+        i = 0
+        while t = doc.targets[i++]
+            if t.recipientUrl is answer.recipientUrl then target = t

         unless target?
             err = new Error "#{answer.recipientUrl} not found for this sharing"
@@ -323,32 +323,36 @@
         db.merge doc._id, doc, (err, result) ->
             return next err if err?

-            # Retrieve all the docIDs
-            docIDs = (rule.id for rule in doc.rules)
-
             # Params structure for the replication
-            replicate =
-                target    : target
-                id        : doc._id
-                docIDs    : docIDs
-                continuous: doc.continuous
-
-            req.replicate = replicate
+            share =
+                target : target
+                doc    : doc
+
+            req.share = share
             next()

 # Replicate documents to the target url

 # Params must contain:
-#   id         -> the Sharing id, used as a login
+#   doc        -> the Sharing document
 #   target     -> contains the url and the token of the target
-#   docIDs     -> the docIDs to replicate
-#   continuous -> [optionnal] if the sharing is synchronous or not
 module.exports.replicate = (req, res, next) ->
-    replicate = req.replicate
+    share = req.share

     # Replicate only if the target has accepted, i.e. gave a token
-    if replicate.target.token?
+    if share.target.token?
+        doc = share.doc
+        target = share.target
+
+        # Retrieve all the docIDs
+        docIDs = (rule.id for rule in doc.rules)
+        replicate =
+            id          : doc._id
+            target      : target
+            docIDs      : docIDs
+            continuous  : doc.continuous
+
         Sharing.replicateDocs replicate, (err, repID) ->
             if err?
                 next err
@@ -358,23 +362,18 @@
                 err.status = 500
                 next err
             else
-                log.info "Data sent to #{replicate.target.recipientUrl}"
+                log.info "Data sent to #{target.recipientUrl}"

                 # Update the target with the repID if the sharing is continuous
                 if replicate.continuous
-                    db.get replicate.id, (err, doc) ->
+
+                    i = doc.targets.indexOf target
+                    doc.targets[i].repID = repID
+
+                    db.merge doc._id, doc, (err, result) ->
                         return next err if err?

-                        # Find the target in the db and update it
-                        targetUrl = replicate.target.recipientUrl
-                        for target, i in doc.targets
-                            if target.recipientUrl is targetUrl
-                                target.repID = repID
-
-                        db.merge replicate.id, doc, (err, result) ->
-                            return next err if err?
-
-                            res.status(200).send success: true
+                        res.status(200).send success: true
                 else
                     res.status(200).send success: true


Added tests for offline mock

Added tests for offline mock

--- spec/ApiClient-spec.coffee
+++ spec/ApiClient-spec.coffee
@@ -109,7 +109,52 @@
       expect(status.value.info).toBe('I didn\'t recognize that core name or ID')

-  # TODO: Test offline
+describe 'Tests for mocked ApiClient library with devices which should be offline', ->
+  client = null
+  promise = null
+
+  beforeEach ->
+    ApiClient = require './mocks/ApiClient-offline'
+
+    client = new ApiClient settings.apiUrl
+
+  it 'lists devices', ->
+    promise = client.listDevices()
+
+    waitsFor ->
+      (promise != null) && (promise.inspect().state != 'pending')
+
+    runs ->
+      expect(promise).not.toBe(null)
+      status = promise.inspect()
+      expect(status.state).toBe('fulfilled')
+      expect(status.value).not.toBe(null)
+      # There should be 2 devices, one connected and one not
+      expect(status.value.length).toBe(2)
+      expect(status.value[0].connected).toBe(false)
+      expect(status.value[1].connected).toBe(false)
+
+  it 'gets device attributes', ->
+    promise = client.getAttributes('51ff6e065067545724680187')
+
+    waitsFor ->
+      (promise != null) && (promise.inspect().state != 'pending')
+
+    runs ->
+      expect(promise).not.toBe(null)
+      status = promise.inspect()
+      expect(status.state).toBe('fulfilled')
+      expect(status.value).not.toBe(null)
+
+      expect(status.value.id).toBe('51ff6e065067545724680187')
+      expect(status.value.name).toBe('Online Core')
+      expect(status.value.connected).toBe(false)
+
+      expect(typeof status.value.variables).toBe('object')
+      expect(Object.keys(status.value.variables).length).toBe(0)
+      expect(status.value.functions instanceof Array).toBe(true)
+      expect(status.value.functions.length).toBe(0)
+

 xdescribe 'testing setTimeout', ->
   done = false


Add option to disable status bar icon

Add option to disable status bar icon

--- lib/git-plus.coffee
+++ lib/git-plus.coffee
@@ -93,6 +93,9 @@
       description: '(Experimental) Show diffs in commit pane?'
       type: 'boolean'
       default: false
+    enableStatusBarIcon:
+      type: 'boolean'
+      default: true

   subscriptions: null

@@ -168,7 +171,8 @@

   consumeStatusBar: (statusBar) ->
     @setupBranchesMenuToggle statusBar
-    @setupOutputViewToggle statusBar
+    if atom.config.get 'git-plus.enableStatusBarIcon'
+      @setupOutputViewToggle statusBar

   setupOutputViewToggle: (statusBar) ->
     div = document.createElement 'div'