add a way to disable specific intrinsic opencode paths, and use it to disable the setSlot intrinsic being opencoded, since it appears to cause crashes with bootstrapping.

--- lib/compiler.coffee
+++ lib/compiler.coffee
@@ -20,8 +20,6 @@
 llvm = require 'llvm'
 ir = llvm.IRBuilder

-opencode_intrinsics = true
-
 BUILTIN_PARAMS = [
   { type: syntax.Identifier, name: "%closure", llvm_type: types.EjsValue } # should be EjsClosureEnv
   { type: syntax.Identifier, name: "%this",    llvm_type: types.EjsValue }
@@ -39,28 +37,37 @@
                         @genRecordId = startGenerator()

                 # build up our runtime method table
-                @ejs_intrinsics =
-                        getLocal:             @handleGetLocal
-                        setLocal:             @handleSetLocal
-                        getGlobal:            @handleGetGlobal
-                        setGlobal:            @handleSetGlobal
-                        slot:                 @handleGetSlot
-                        setSlot:              @handleSetSlot
-                        invokeClosure:        @handleInvokeClosure
-                        makeClosure:          @handleMakeClosure
-                        makeAnonClosure:      @handleMakeAnonClosure
-                        createArgScratchArea: @handleCreateArgScratchArea
-                        makeClosureEnv:       @handleMakeClosureEnv
-                        typeofIsObject:       @handleTypeofIsObject
-                        typeofIsFunction:     @handleTypeofIsFunction
-                        typeofIsString:       @handleTypeofIsString
-                        typeofIsSymbol:       @handleTypeofIsSymbol
-                        typeofIsNumber:       @handleTypeofIsNumber
-                        typeofIsUndefined:    @handleTypeofIsUndefined
-                        typeofIsNull:         @handleTypeofIsNull
-                        typeofIsBoolean:      @handleTypeofIsBoolean
-                        builtinUndefined:     @handleBuiltinUndefined
-
+                @ejs_intrinsics = Object.create null,
+                        getLocal:             { value: @handleGetLocal }
+                        setLocal:             { value: @handleSetLocal }
+                        getGlobal:            { value: @handleGetGlobal }
+                        setGlobal:            { value: @handleSetGlobal }
+                        slot:                 { value: @handleGetSlot }
+                        setSlot:              { value: @handleSetSlot }
+                        invokeClosure:        { value: @handleInvokeClosure }
+                        makeClosure:          { value: @handleMakeClosure }
+                        makeAnonClosure:      { value: @handleMakeAnonClosure }
+                        createArgScratchArea: { value: @handleCreateArgScratchArea }
+                        makeClosureEnv:       { value: @handleMakeClosureEnv }
+                        typeofIsObject:       { value: @handleTypeofIsObject }
+                        typeofIsFunction:     { value: @handleTypeofIsFunction }
+                        typeofIsString:       { value: @handleTypeofIsString }
+                        typeofIsSymbol:       { value: @handleTypeofIsSymbol }
+                        typeofIsNumber:       { value: @handleTypeofIsNumber }
+                        typeofIsUndefined:    { value: @handleTypeofIsUndefined }
+                        typeofIsNull:         { value: @handleTypeofIsNull }
+                        typeofIsBoolean:      { value: @handleTypeofIsBoolean }
+                        builtinUndefined:     { value: @handleBuiltinUndefined }
+
+                # disable setSlot for now
+                @opencode_intrinsics = []
+                @opencode_intrinsics[intrinsic] = true for intrinsic of @ejs_intrinsic
+                @opencode_LoadOne = true
+                @opencode_UnaryNot = true
+                @opencode_NumberNew = true
+
+                @opencode_intrinsics.setSlot = false
+
                 @llvm_intrinsics =
                         gcroot: -> module.getOrInsert "@llvm.gcroot"

@@ -102,7 +109,7 @@
                 rv

         loadBoolEjsValue: (n) ->
-                if opencode_intrinsics and @options.target_pointer_size is 64
+                if @options.target_pointer_size is 64
                         boolval = (consts.int64_lowhi 0xfff98000, if n then 0x00000001 else 0x000000000)
                 else
                         boolval = @createLoad (if n then @ejs_runtime['true'] else @ejs_runtime['false']), "load_bool"
@@ -110,7 +117,7 @@
                 boolval

         loadNullEjsValue: ->
-                if opencode_intrinsics and @options.target_pointer_size is 64
+                if @options.target_pointer_size is 64
                         nullval = (consts.int64_lowhi 0xfffb8000, 0x00000000)
                 else
                         nullval = @createLoad @ejs_runtime['null'], "load_null"
@@ -118,7 +125,7 @@
                 nullval

         loadUndefinedEjsValue: ->
-                if opencode_intrinsics and @options.target_pointer_size is 64
+                if @options.target_pointer_size is 64
                         undef = (consts.int64_lowhi 0xfff90000, 0x00000000)
                 else
                         undef = @createLoad @ejs_runtime.undefined, "load_undefined"
@@ -478,7 +485,7 @@
                 result = @createAlloca @currentFunction, types.EjsValue, "%update_result"
                 argument = @visit n.argument

-                if opencode_intrinsics and @options.target_pointer_size is 64
+                if @opencode_LoadOne and @options.target_pointer_size is 64
                         one = ir.createBitCast (llvm.ConstantFP.getDouble 1), types.EjsValue, "load_one"
                 else
                         one = @createLoad @ejs_runtime['one'], "load_one"
@@ -831,7 +838,7 @@

                 else if n.operator is "!"
                         arg_value =  @visitOrNull n.argument
-                        if opencode_intrinsics and @options.target_pointer_size is 64 and arg_value._ejs_returns_ejsval_bool
+                        if @opencodeUnaryNot and @options.target_pointer_size is 64 and arg_value._ejs_returns_ejsval_bool
                                 cmp = ir.createICmpEq arg_value, (@loadBoolEjsValue true), "cmpresult"
                                 rv = ir.createSelect cmp, (@loadBoolEjsValue false), (@loadBoolEjsValue true), "sel"
                                 rv._ejs_returns_ejsval_bool = true
@@ -957,11 +964,12 @@
                 debug.log -> "          arguments length = #{n.arguments.length}"
                 debug.log -> "          arguments[#{i}] =  #{JSON.stringify n.arguments[i]}" for i in [0...n.arguments.length]

-                intrinsicHandler = @ejs_intrinsics[n.callee.name.slice 1]
+                unescapedName = n.callee.name.slice 1
+                intrinsicHandler = @ejs_intrinsics[unescapedName]
                 if not intrinsicHandler?
                         throw new Error "Internal error: callee should not be null in visitCallExpression (callee = '#{n.callee.name}', arguments = #{n.arguments.length})"

-                intrinsicHandler.call @, n
+                intrinsicHandler.call @, n, @opencode_intrinsics[unescapedName], false

         visitNewExpression: (n) ->
                 if n.callee.type isnt syntax.Identifier or n.callee.name[0] isnt '%'
@@ -970,11 +978,12 @@
                 if n.callee.name isnt "%invokeClosure"
                         throw "new expressions may only have a callee of %invokeClosure, callee = #{n.callee.name}"

-                intrinsicHandler = @ejs_intrinsics[n.callee.name.slice 1]
+                unescapedName = n.callee.name.slice 1
+                intrinsicHandler = @ejs_intrinsics[unescapedName]
                 if not intrinsicHandler
                         throw "Internal error: ctor should not be null"

-                intrinsicHandler.call @, n, true
+                intrinsicHandler.call @, n, @opencode_intrinsics[unescapedName], true

         visitThisExpression: (n) ->
                 debug.log "visitThisExpression"
@@ -1058,7 +1067,7 @@
                 strglobal

         generateEJSValueForString: (id) ->
-                name = "ejsval-string-#{id}"
+                name = "ejsval-#{id}"
                 strglobal = new llvm.GlobalVariable @module, types.EjsValue, name, (consts.int64 0) #llvm.Constant.getAggregateZero types.EjsValue
                 @module.getOrInsertGlobal name, types.EjsValue

@@ -1090,7 +1099,7 @@
                         literalId = @idgen()
                         ucs2_data = @generateUCS2 literalId, str
                         primstring = @generateEJSPrimString literalId, str.length
-                        @module_atoms[literal_key] = @generateEJSValueForString literalId
+                        @module_atoms[literal_key] = @generateEJSValueForString literal_key
                         @addStringLiteralInitialization str, ucs2_data, primstring, @module_atoms[literal_key], str.length

                 strload = @createLoad @module_atoms[literal_key], "literal_load"
@@ -1132,24 +1141,26 @@
                 # number literals
                 if typeof n.value is "number"
                         debug.log -> "literal number: #{n.value}"
-                        literal_key = "num-" + n.value
-                        if @currentFunction.literalAllocas[literal_key]
-                                num_alloca = @currentFunction.literalAllocas[literal_key]
+
+                        if @opencode_NumberNew and @options.target_pointer_size is 64
+                                c = llvm.ConstantFP.getDouble n.value
+                                return ir.createBitCast c, types.EjsValue, "numconst-#{n.value}"
                         else
-                                # only create 1 instance of num literals used in a function, and allocate them in the entry block
-                                @doInsideBBlock @currentFunction.entry_bb, =>
-                                        num_alloca = ir.createAlloca types.EjsValue, "num-alloca-#{n.value}"
-                                        c = llvm.ConstantFP.getDouble n.value
-                                        if opencode_intrinsics and @options.target_pointer_size is 64
-                                                val = ir.createBitCast c, types.EjsValue, "numconst-#{n.value}"
-                                        else
+                                literal_key = "num-" + n.value
+                                if @currentFunction.literalAllocas[literal_key]
+                                        num_alloca = @currentFunction.literalAllocas[literal_key]
+                                else
+                                        # only create 1 instance of num literals used in a function, and allocate them in the entry block
+                                        @doInsideBBlock @currentFunction.entry_bb, =>
+                                                num_alloca = ir.createAlloca types.EjsValue, "num-alloca-#{n.value}"
+                                                c = llvm.ConstantFP.getDouble n.value
                                                 val = @createCall @ejs_runtime.number_new, [c], "numconst-#{n.value}", !@ejs_runtime.number_new.doesNotThrow
-                                        ir.createStore val, num_alloca
-                                        @currentFunction.literalAllocas[literal_key] = num_alloca
-                        numload = @createLoad num_alloca, "%num_alloca"
-                        numload.literal = n
-                        debug.log -> "numload = #{numload}"
-                        return numload
+                                                ir.createStore val, num_alloca
+                                                @currentFunction.literalAllocas[literal_key] = num_alloca
+                                numload = @createLoad num_alloca, "%num_alloca"
+                                numload.literal = n
+                                debug.log -> "numload = #{numload}"
+                                return numload

                 # boolean literals
                 if typeof n.value is "boolean"
@@ -1317,7 +1328,7 @@

                 ir.setInsertPoint merge_block

-        handleGetLocal: (exp) ->
+        handleGetLocal: (exp, opencode) ->
                 source = @findIdentifierInScope exp.arguments[0].name
                 if source?
                         return @createLoad source, "load_#{exp.arguments[0].name}"
@@ -1347,26 +1358,27 @@

                 throw new Error "identifier not found: #{exp.arguments[0].name}"

-        handleSetLocal: (exp) ->
+        handleSetLocal: (exp, opencode) ->
                 dest = @findIdentifierInScope exp.arguments[0].name
                 throw new Error "identifier not found: #{exp.arguments[0].name}" if not dest?
                 new_local_val = @visit exp.arguments[1]
                 ir.createStore new_local_val, dest
                 new_local_val

-        handleGetGlobal: (exp) ->
+        handleGetGlobal: (exp, opencode) ->
                 pname = @getAtom exp.arguments[0].name
                 @createCall @ejs_runtime.global_getprop, [pname], "globalloadprop_#{exp.arguments[0].name}"

-        handleSetGlobal: (exp) ->
+        handleSetGlobal: (exp, opencode) ->
                 pname = @getAtom exp.arguments[0].name
                 value = @visit exp.arguments[1]

                 @createCall @ejs_runtime.global_setprop, [pname, value], "globalpropstore_#{exp.arguments[0].name}"
                 value

+        # this method assumes it's called in an opencoded context
         emitEjsvalTo: (val, type, prefix) ->
-                if opencode_intrinsics and @options.target_pointer_size is 64
+                if @options.target_pointer_size is 64
                         #  %1 = and i64 %val, 140737488355327
                         #  %2 = inttoptr i64 %1 to %struct._EJSObject*
                         payload = ir.createAnd val, (consts.int64_lowhi 0x7fff, 0xffffffff), "#{prefix}_payload"
@@ -1375,8 +1387,9 @@
                         throw new Error "emitEjsvalTo not implemented for this case"

+        # this method assumes it's called in an opencoded context
         emitLoadSpecops: (obj) ->
-                if opencode_intrinsics and @options.target_pointer_size is 64
+                if @options.target_pointer_size is 64
                         # %1 = getelementptr inbounds %struct._EJSObject* %obj, i64 0, i32 1
                         # %specops_load = load %struct.EJSSpecOps** %1, align 8, !tbaa !0
                         specops_slot = ir.createInBoundsGetElementPointer obj, [(consts.int64 0), (consts.int32 1)], "specops_slot"
@@ -1388,31 +1401,34 @@
                 @createCall @ejs_runtime.throw_nativeerror_utf8, [(consts.int32 errorCode), (consts.string ir, errorMessage)], "", true
                 ir.createUnreachable()

+        # this method assumes it's called in an opencoded context
         emitLoadEjsFunctionIsBound: (closure) ->
-                if opencode_intrinsics and @options.target_pointer_size is 64
+                if @options.target_pointer_size is 64
                         bound_slot_gep = ir.createInBoundsGetElementPointer closure, [(consts.int64 1), (consts.int32 2)], "bound_slot_gep"
                         bound_slot = ir.createBitCast bound_slot_gep, types.int32.pointerTo(), "bound_slot"
                         ir.createLoad bound_slot, "bound_load"
                 else
                         throw new Error "emitLoadEjsFunctionIsBound not implemented for this case"

+        # this method assumes it's called in an opencoded context
         emitLoadEjsFunctionClosureFunc: (closure) ->
-                if opencode_intrinsics and @options.target_pointer_size is 64
+                if @options.target_pointer_size is 64
                         func_slot_gep = ir.createInBoundsGetElementPointer closure, [consts.int64 1], "func_slot_gep"
                         func_slot = ir.createBitCast func_slot_gep, types.EjsClosureFunc.pointerTo(), "func_slot"
                         ir.createLoad func_slot, "func_load"
                 else
                         throw new Error "emitLoadEjsFunctionClosureFunc not implemented for this case"

+        # this method assumes it's called in an opencoded context
         emitLoadEjsFunctionClosureEnv: (closure) ->
-                if opencode_intrinsics and @options.target_pointer_size is 64
+                if @options.target_pointer_size is 64
                         env_slot_gep = ir.createInBoundsGetElementPointer closure, [(consts.int64 1),(consts.int32 1)], "env_slot_gep"
                         env_slot = ir.createBitCast env_slot_gep, types.EjsValue.pointerTo(), "env_slot"
                         ir.createLoad env_slot, "env_load"
                 else
                         throw new Error "emitLoadEjsFunctionClosureEnv not implemented for this case"

-        handleInvokeClosure: (exp, ctor_context= false) ->
+        handleInvokeClosure: (exp, opencode, ctor_context) ->
                 insertBlock = ir.getInsertBlock()
                 insertFunc = insertBlock.parent

@@ -1439,7 +1455,7 @@
                 argv = modified_argv
                 call_result = @createAlloca @currentFunction, types.EjsValue, "call_result"

-                if opencode_intrinsics and @options.target_pointer_size is 64
+                if opencode and @options.target_pointer_size is 64
                         candidate_is_object_bb = new llvm.BasicBlock "candidate_is_object_bb", insertFunc
                         check_if_function_is_bound_bb = new llvm.BasicBlock "check_if_function_is_bound_bb", insertFunc
                         object_isnt_function_bb = new llvm.BasicBlock "object_isnt_function_bb", insertFunc
@@ -1506,7 +1522,7 @@
                 # value was an object.  if it was, we return it,
                 # otherwise we return argv[0]

-                if opencode_intrinsics and @options.target_pointer_size is 64
+                if opencode and @options.target_pointer_size is 64
                         cmp = ir.createICmpUGt call_result_load, (consts.int64_lowhi 0xfffbffff, 0xffffffff), "cmpresult"
                 else
                         call_result_is_object = @createCall @ejs_runtime.typeof_is_object, [call_result_load], "call_result_is_object", false
@@ -1514,44 +1530,44 @@
                 return ir.createSelect cmp, call_result_load, argv[1], "sel"

-        handleMakeClosure: (exp, ctor_context= false) ->
+        handleMakeClosure: (exp, opencode) ->
                 argv = @visitArgsForCall @ejs_runtime.make_closure, false, exp.arguments
                 closure_result = @createAlloca @currentFunction, types.EjsValue, "closure_result"
                 calltmp = ir.createCall @ejs_runtime.make_closure, argv, "closure_tmp"
                 store = ir.createStore calltmp, closure_result
                 @createLoad closure_result, "closure_result_load"

-        handleMakeAnonClosure: (exp, ctor_context= false) ->
+        handleMakeAnonClosure: (exp, opencode) ->
                 argv = @visitArgsForCall @ejs_runtime.make_anon_closure, false, exp.arguments
                 closure_result = @createAlloca @currentFunction, types.EjsValue, "closure_result"
                 calltmp = ir.createCall @ejs_runtime.make_anon_closure, argv, "closure_tmp"
                 store = ir.createStore calltmp, closure_result
                 @createLoad closure_result, "closure_result_load"

-        handleCreateArgScratchArea: (exp, ctor_context= false) ->
+        handleCreateArgScratchArea: (exp, opencode) ->
                 argsArrayType = llvm.ArrayType.get types.EjsValue, exp.arguments[0].value
                 @currentFunction.scratch_area = @createAlloca @currentFunction, argsArrayType, "args_scratch_area"

-        handleMakeClosureEnv: (exp, ctor_context= false) ->
+        handleMakeClosureEnv: (exp, opencode) ->
                 size = exp.arguments[0].value
                 ir.createCall @ejs_runtime.make_closure_env, [consts.int32 size], "env_tmp"

-        handleGetSlot: (exp) ->
+        handleGetSlot: (exp, opencode) ->
                 env = @visitOrNull exp.arguments[0]
                 slotnum = exp.arguments[1].value
-                if opencode_intrinsics and @options.target_pointer_size is 64
+                if opencode and @options.target_pointer_size is 64
                         # for 64bit platforms, we can open code this pretty easily
                         #
                         #  %ref = handleSlotRef
                         #  %ret = load i64* %ref, align 8
                         #
-                        slot_ref = @handleSlotRef exp
+                        slot_ref = @handleSlotRef exp, opencode
                         ir.createLoad slot_ref, "slot_ref_load"
                 else
                         ir.createCall @ejs_runtime.get_env_slot_val, [env, (consts.int32 slotnum)], "slot_val_tmp"

-        handleSetSlot: (exp) ->
-                slotref = @handleSlotRef exp
+        handleSetSlot: (exp, opencode) ->
+                slotref = @handleSlotRef exp, opencode
                 if exp.arguments.length is 4
                         new_slot_val = @visit exp.arguments[3]
                         ir.createStore new_slot_val, slotref
@@ -1560,18 +1576,18 @@
                         ir.createStore new_slot_val, slotref
                 new_slot_val

-        handleSlotRef: (exp) ->
+        handleSlotRef: (exp, opencode) ->
                 env = @visitOrNull exp.arguments[0]
                 slotnum = exp.arguments[1].value

-                if opencode_intrinsics and @options.target_pointer_size is 64
+                if opencode and @options.target_pointer_size is 64
                         envp = @emitEjsvalTo env, types.EjsClosureEnv.pointerTo(), "closureenv"
                         ir.createInBoundsGetElementPointer envp, [(consts.int64 0), (consts.int32 2), (consts.int64 slotnum), (consts.int32 0)], "slot_ref"
                 else
                         ir.createCall @ejs_runtime.get_env_slot_ref, [env, (consts.int32 slotnum)], "slot_ref_tmp"

-        handleTypeofIsObject: (exp) ->
-                if opencode_intrinsics and @options.target_pointer_size is 64
+        handleTypeofIsObject: (exp, opencode) ->
+                if opencode and @options.target_pointer_size is 64
                         cmp = ir.createICmpUGt (@visitOrNull exp.arguments[0]), (consts.int64_lowhi 0xfffbffff, 0xffffffff), "cmpresult"
                         rv = ir.createSelect cmp, (@loadBoolEjsValue true), (@loadBoolEjsValue false), "sel"
                         rv._ejs_returns_ejsval_bool = true
@@ -1579,8 +1595,8 @@
                 else
                         @createCall @ejs_runtime.typeof_is_object, [@visitOrNull exp.arguments[0]], "is_object", false

-        handleTypeofIsFunction: (exp) ->
-                if opencode_intrinsics and @options.target_pointer_size is 64
+        handleTypeofIsFunction: (exp, opencode) ->
+                if opencode and @options.target_pointer_size is 64
                         insertBlock = ir.getInsertBlock()
                         insertFunc  = insertBlock.parent

@@ -1617,8 +1633,8 @@
                 else
                         ir.createCall @ejs_runtime.typeof_is_function, [@visitOrNull exp.arguments[0]], "is_function"

-        handleTypeofIsSymbol: (exp) ->
-                if opencode_intrinsics and @options.target_pointer_size is 64
+        handleTypeofIsSymbol: (exp, opencode) ->
+                if opencode and @options.target_pointer_size is 64
                         insertBlock = ir.getInsertBlock()
                         insertFunc  = insertBlock.parent

@@ -1655,8 +1671,8 @@
                 else
                         ir.createCall @ejs_runtime.typeof_is_symbol, [@visitOrNull exp.arguments[0]], "is_symbol"

-        handleTypeofIsString: (exp) ->
-                if opencode_intrinsics and @options.target_pointer_size is 64
+        handleTypeofIsString: (exp, opencode) ->
+                if opencode and @options.target_pointer_size is 64
                         mask = ir.createAnd (@visitOrNull exp.arguments[0]), (consts.int64_lowhi 0xffff8000, 0x00000000), "mask.i"
                         cmp = ir.createICmpEq mask, (consts.int64_lowhi 0xfffa8000, 0x00000000), "cmpresult"
                         t = @loadBoolEjsValue true
@@ -1667,10 +1683,33 @@
                 else
                         @createCall @ejs_runtime.typeof_is_string, [@visitOrNull exp.arguments[0]], "is_string", false

-        handleTypeofIsNumber:    (exp) -> @createCall @ejs_runtime.typeof_is_number,    [@visitOrNull exp.arguments[0]], "is_number", false
-        handleTypeofIsUndefined: (exp) -> @createCall @ejs_runtime.typeof_is_undefined, [@visitOrNull exp.arguments[0]], "is_undefined", false
-        handleTypeofIsNull:      (exp) -> @createCall @ejs_runtime.typeof_is_null,      [@visitOrNull exp.arguments[0]], "is_null", false
-        handleTypeofIsBoolean:   (exp) -> @createCall @ejs_runtime.typeof_is_boolean,   [@visitOrNull exp.arguments[0]], "is_boolean", false
+        handleTypeofIsNumber:    (exp, opencode) ->
+                if opencode and @options.target_pointer_size is 64
+                        cmp = ir.createICmpULt candidate, (consts.int64_lowhi 0xfff80001, 0x00000000), "cmpresult"
+                        rv = ir.createSelect cmp, (@loadBoolEjsValue true), (@loadBoolEjsValue false), "sel"
+                        rv._ejs_returns_ejsval_bool = true
+                        rv
+                else
+                        @createCall @ejs_runtime.typeof_is_number,    [@visitOrNull exp.arguments[0]], "is_number", false
+        handleTypeofIsUndefined: (exp, opencode) ->
+                if opencode and @options.target_pointer_size is 64
+                        cmp = ir.createICmpEq (@visitOrUndefined exp.arguments[0]), (consts.int64_lowhi 0xfff90000, 0x00000000), "cmpresult"
+                        rv = ir.createSelect cmp, (@loadBoolEjsValue true), (@loadBoolEjsValue false), "sel"
+                        rv._ejs_returns_ejsval_bool = true
+                        rv
+                else
+                        @createCall @ejs_runtime.typeof_is_undefined, [@visitOrNull exp.arguments[0]], "is_undefined", false
+
+        handleTypeofIsNull:      (exp) -> console.log "typeof_is_null"; @createCall @ejs_runtime.typeof_is_null,      [@visitOrNull exp.arguments[0]], "is_null", false
+        handleTypeofIsBoolean:   (exp, opencode) ->
+                if opencode and @options.target_pointer_size is 64
+                        mask = ir.createAnd (@visitOrNull exp.arguments[0]), (consts.int64_lowhi 0xffff8000, 0x00000000), "mask.i"
+                        cmp = ir.createICmpEq mask, (consts.int64_lowhi 0xfff98000, 0x00000000), "cmpresult"
+                        rv = ir.createSelect cmp, (@loadBoolEjsValue true), (@loadBoolEjsValue false), "sel"
+                        rv._ejs_returns_ejsval_bool = true
+                        rv
+                else
+                        @createCall @ejs_runtime.typeof_is_boolean,   [@visitOrNull exp.arguments[0]], "is_boolean", false
         handleBuiltinUndefined:  (exp) -> @loadUndefinedEjsValue()

 class AddFunctionsVisitor extends TreeTransformer


add one or all tip show

add one or all tip show

--- app/scripts/helper/validate.coffee
+++ app/scripts/helper/validate.coffee
@@ -45,24 +45,31 @@
   validateFields: ($fields, parent)->
     # TO DO blur tip

-  tipAll: (direct)->
-    $.each @errorFields, (n, i) ->
-      if i.error is 'unvalid'
-        message = i.$el.data("unvalidMessage") || "请正确填写"
-      else
-        message = i.$el.data("emptyMessage") || "请填写此项"
-      parent = i.parent
-      direct = if i.$el.data("direct") then i.$el.data("direct") else if direct then direct else "left"
-      top = if direct is "left" then element.topWithLeft(i.$el, i.parent) else element.topWithUp(i.$el, i.parent)
-      left = if direct is "left" then element.leftWithLeft(i.$el, i.parent) else element.leftWithUp(i.$el, i.parent)
-      new Tip({parent, direct, type: "error", message, top, left, interval: 0}).tip()
+  tipAll: ->
+    $.each @errorFields, (n, i) =>
+      @tipOne("all", i)

-  validateForm: ($form, $fields, method, parent) ->
+  tipOne: (scope, i) ->
+    # console.log @options
+    i = @errorFields[0] if scope is "one" and @errorFields.length isnt 0
+    if i.error is 'unvalid'
+      message = i.$el.data("unvalidMessage") || "请正确填写"
+    else
+      message = i.$el.data("emptyMessage") || "请填写此项"
+    parent = i.parent
+    direct = if i.$el.data("direct") then i.$el.data("direct") else @options.direct
+    top = if direct is "left" then element.topWithLeft(i.$el, i.parent) else element.topWithUp(i.$el, i.parent)
+    left = if direct is "left" then element.leftWithLeft(i.$el, i.parent) else element.leftWithUp(i.$el, i.parent)
+    interval = i.$el.data("interval") || @options.interval
+    new Tip({parent, direct, type: "error", message, top, left, interval}).show()
+
+
+  validateForm: ($form, $fields, parent) ->
     @errorFields = []
     @clearError($form)
-    $.each $fields, (i, el)=>
+    $.each $fields, (i, el) =>
       @validateOne($(el), parent)
-    @tipAll()
+    if @options.scope is "all" then @tipAll() else @tipOne("one")
     if @errorFields.length then @errorFields else false

   clearError: ($form) ->


Fix migration match

Fix migration match

--- app/src/database/migrations.coffee
+++ app/src/database/migrations.coffee
@@ -24,9 +24,9 @@
     Configuration.getInstance(@context).setCurrentApplicationVersion(manifestVersion)

   performMigrations: (fromVersion, toVersion) ->
-    for migration in migrations
-      if (migration.from is fromVersion or migration.from is '*') and (migration.to is toVersion or migration.to is '*')
-        migration.apply(@context)
+    for migration in @_migrations
+      if fromVersion.match(migration.from) and toVersion.match(migration.to)
+        migration.apply @context

 migrations = [
@@ -37,12 +37,11 @@

 migrate_from_1_0_3_x_to_1_4_x = (context) ->
   # Force to save every sync properties on the sync store
-  if (account = Account.findById(0))?
+  if (account = Account.findById(0, context))?
     l "Account", account, account.get('operations')
-    for operation in Operation.all()
+    for operation in Operation.all(context)
       operation.set('account', account).save()
-    account.set('wallet', Wallet.findById(1))
-    account.save()
+    account.set('wallet', Wallet.findById(1, context)).save()
     l "After Account", account, account.get('operations')

   for Model in ledger.database.Model.AllModelClasses()


update fr.coffee v0.6 (#4985)

update fr.coffee v0.6 (#4985)

--- app/locale/fr.coffee
+++ app/locale/fr.coffee
@@ -1373,7 +1373,7 @@
     student_age_range_label: "Tranche d'âge des étudiants"
     student_age_range_younger: "Plus jeune que 6 ans"
     student_age_range_older: "Avoir plus de 18 ans"
-#    student_age_range_to: "to"
+    student_age_range_to: "jusqu'à"
     create_class: "Créer une Classe"
     class_name: "Nom de la classe"
     teacher_account_restricted: "Votre compte est un compte d'enseignant et ne peut pas accéder au contenu des élèves."
@@ -1391,8 +1391,8 @@
     update_account_teachers_can3: "Déverrouillez tous les niveaux de cours pour essayer"
     update_account_teachers_can4: "Accédez aux nouvelles fonctionnalités réservées aux enseignants au fur et à mesure que nous les publions"
     update_account_teachers_warning: "Avertissement : Vous serez retiré de toutes les classes auxquelles vous avez déjà participé et vous ne pourrez pas jouer en tant qu'étudiant."
-#    update_account_remain_teacher: "Remain a Teacher"
-#    update_account_update_teacher: "Update to Teacher"
+    update_account_remain_teacher: "Rester un enseignant"
+    update_account_update_teacher: "Mise à jour à l'enseignant"
     update_account_am_student: "Je suis un étudiant"
     update_account_remove_access: "Supprimer l'accès aux classes que j'ai créées"
     update_account_students_can: "Les comptes étudiant peuvent :"
@@ -1402,8 +1402,8 @@
     update_account_students_can4: "Accédez aux nouvelles fonctionnalités réservées aux étudiants au fur et à mesure que nous les publions"
     update_account_students_warning: "Avertissement : Vous ne pourrez pas gérer les classes que vous avez déjà créées ou en créer de nouvelles."
     unsubscribe_warning: "Avertissement : Vous serez désabonné de votre abonnement mensuel."
-#    update_account_remain_student: "Remain a Student"
-#    update_account_update_student: "Update to Student"
+    update_account_remain_student: "Rester un étudiant"
+    update_account_update_student: "Mise à jour à l'élève"
     need_a_class_code: "Vous aurez besoin d'un code de classe pour la classe à laquelle vous vous inscrivez :"
     update_account_not_sure: "Vous ne savez pas lequel choisir ? Email"
     update_account_confirm_update_student: "Êtes-vous sûr de vouloir mettre à jour votre compte pour une expérience Etudiant ?"
@@ -1422,57 +1422,57 @@
     select_this_hero: "Sélectionnez ce héros"
     current_hero: "Héros actuel :"
     current_hero_female: "Héros actuel :"
-#    web_dev_language_transition: "All classes program in HTML / JavaScript for this course.  Classes that have been using Python will start with extra JavaScript intro levels to ease the transition.  Classes that are already using JavaScript will skip the intro levels."
-#    course_membership_required_to_play: "You'll need to join a course to play this level."
-#    license_required_to_play: "Ask your teacher to assign a license to you so you can continue to play CodeCombat!"
-#    update_old_classroom: "New school year, new levels!"
-#    update_old_classroom_detail: "To make sure you're getting the most up-to-date levels, make sure you create a new class for this semester by clicking Create a New Class on your"
-#    teacher_dashboard: "teacher dashboard"
-#    update_old_classroom_detail_2: "and giving students the new Class Code that appears."
-#    view_assessments: "View Assessments"
-#    view_challenges: "view challenge levels"
-#    challenge: "Challenge:"
-#    challenge_level: "Challenge Level:"
-#    status: "Status:"
-#    assessments: "Assessments"
-#    challenges: "Challenges"
-#    level_name: "Level Name:"
-#    keep_trying: "Keep Trying"
-#    start_challenge: "Start Challenge"
-#    locked: "Locked"
-#    concepts_used: "Concepts Used:"
-#    show_change_log: "Show changes to this course's levels"
-#    hide_change_log: "Hide changes to this course's levels"
-
-#  project_gallery:
-#    no_projects_published: "Be the first to publish a project in this course!"
-#    view_project: "View Project"
-#    edit_project: "Edit Project"
+    web_dev_language_transition: "Tous les programmes de cours en HTML / JavaScript pour ce cours.  Les classes qui ont utilisé Python commenceront avec des niveaux initiaux JavaScript supplémentaires pour faciliter la transition.  Les classes qui utilisent déjà JavaScript sauteront les niveaux initiaux."
+    course_membership_required_to_play: "Vous devrez rejoindre un parcours pour jouer à ce niveau."
+    license_required_to_play: "Demandez à votre professeur de vous attribuer une licence pour que vous puissiez continuer à jouer à CodeCombat !"
+    update_old_classroom: "Nouvelle année scolaire, nouveaux niveaux !"
+    update_old_classroom_detail: "Pour vous assurer d'obtenir les niveaux les plus à jour, assurez-vous de créer une nouvelle classe pour ce semestre en cliquant sur Créer une nouvelle classe dans votre dossier"
+    teacher_dashboard: "tableau de bord de l'enseignant"
+    update_old_classroom_detail_2: "et en donnant aux élèves le nouveau code de classe qui apparaît."
+    view_assessments: "Voir les évaluations"
+    view_challenges: "voir les niveaux de défi"
+    challenge: "Défi:" #challenge
+    challenge_level: "Niveau de défi :"
+    status: "Statut:"
+    assessments: "Évaluations"
+    challenges: "défis"
+    level_name: "Nom du niveau:"
+    keep_trying: "Continuez d'essayer"
+    start_challenge: "Défi de départ"
+    locked: "Verrouillé"
+    concepts_used: "Concepts utilisés:"
+    show_change_log: "Afficher les modifications apportées aux niveaux de ce cours"
+    hide_change_log: "Masquer les modifications apportées aux niveaux de ce cours"
+
+  project_gallery:
+    no_projects_published: "Soyez le premier à publier un projet dans ce cours !"
+    view_project: "Voir le projet"
+    edit_project: "Modifier le projet"

   teacher:
-#    assigning_course: "Assigning course"
-#    back_to_top: "Back to Top"
-#    click_student_code: "Click on any level that the student has started or completed below to view the code they wrote."
+    assigning_course: "Affectation de la formation"
+    back_to_top: "Retour en haut de la page"
+    click_student_code: "Cliquez sur n'importe quel niveau que l'élève a commencé ou complété ci-dessous pour voir le code qu'il a écrit."
 #    code: "__name__'s Code"
-#    complete_solution: "Complete Solution"
-#    course_not_started: "Student has not started this course yet."
-#    no_code_yet: "Student has not written any code for this level yet."
+    complete_solution: "Solution complète"
+    course_not_started: "L'étudiant n'a pas encore commencé ce cours."
+    no_code_yet: "L'étudiant n'a pas encore écrit de code pour ce niveau."
 #    open_ended_level: "Open-Ended Level"
-#    partial_solution: "Partial Solution"
-#    removing_course: "Removing course"
+    partial_solution: "Solution partielle"
+    removing_course: "Suppression d'un cours"
 #    solution_arena_blurb: "Students are encouraged to solve arena levels creatively. The solution provided below meets the requirements of the arena level."
 #    solution_challenge_blurb: "Students are encouraged to solve open-ended challenge levels creatively. One possible solution is displayed below."
 #    solution_project_blurb: "Students are encouraged to build a creative project in this level. Please refer to curriculum guides in the Resource Hub for information on how to evaluate these projects."
 #    students_code_blurb: "A correct solution to each level is provided where appropriate. In some cases, it’s possible for a student to solve a level using different code. Solutions are not shown for levels the student has not started."
-#    course_solution: "Course Solution"
-#    level_overview_solutions: "Level Overview and Solutions"
-#    no_student_assigned: "No students have been assigned this course."
-#    paren_new: "(new)"
+    course_solution: "Solution de cours"
+    level_overview_solutions: "Aperçu des niveaux et solutions"
+    no_student_assigned: "Aucun étudiant n'a été assigné à ce cours."
+    paren_new: "(nouveau)"
 #    student_code: "__name__'s Student Code"
-#    teacher_dashboard: "Teacher Dashboard" # Navbar
+    teacher_dashboard: "Tableau de bord de l'enseignant" # Navbar
     my_classes: "Mes Classes"
-#    courses: "Course Guides"
-#    enrollments: "Student Licenses"
+    courses: "Guides de cours"
+    enrollments: "Licences pour étudiants"
     resources: "Resources"
     help: "Au-Secours !"
     language: "Langue"


respond an image from tiqav.com

respond an image from tiqav.com


Updates clean

Updates clean

--- config/clean.coffee
+++ config/clean.coffee
@@ -1,5 +1,3 @@
 module.exports = (grunt, options) ->
-    return {
-        config : [ 'config' ],
-        tmp: [ '.tmp' ]
-    }+    config : [ 'config' ],
+    tmp: [ '.tmp' ]


Remove workspace selector for keymaps

Remove workspace selector for keymaps

--- keymap.cson
+++ keymap.cson
@@ -83,7 +83,7 @@
   'ctrl-shift-o `': 'expand-region:select-around-back-ticks'
   'ctrl-shift-o t': 'expand-region:select-around-tags'

-'atom-workspace atom-text-editor:not([mini])':
+'atom-text-editor:not([mini])':
   # override snippets:available
   'shift-alt-s': 'find-and-till:select-till'


Remove one more line

Remove one more line

Signed-off-by: Steven Hoffman <f5bcacb8ce1651b7d1e56f2693431f20e085fdeb@valenciamgmt.com>

--- vendor/assets/javascripts/fustrate/components/autocomplete.coffee
+++ vendor/assets/javascripts/fustrate/components/autocomplete.coffee
@@ -63,7 +63,6 @@
         @items.push @createListItem(datum, source)

     @awesomplete.list = @items
-    @awesomplete.evaluate()

   onHighlight: =>
     item = $('+ ul li[aria-selected="true"]', @input)


fixed bad index incrementor in each

fixed bad index incrementor in each

--- script/rerun.coffee
+++ script/rerun.coffee
@@ -28,8 +28,8 @@
 each = (list, final, fun) ->
   index = 0
   next = ->
-    return final() if ++index == list.length
-    fun list[index], next
+    return final() if index == list.length
+    fun list[index++], next
   next()

 # Boot up manager with worker definitions and re-request
@@ -65,7 +65,11 @@
 delete_keys = ->
   if to_delete.length
     chunks = _(to_delete).in_groups_of(10000)
-    each chunks, rerun, (chunk, next) ->
+    wrap_up = ->
+      console.log "Deleted #{to_delete.length/4} keys"
+      rerun()
+    console.log chunks
+    each chunks, wrap_up, (chunk, next) ->
       r.del chunk..., next
   else
     console.log "No keys to delete"


speed control

speed control

--- web/src/cs/views/default.coffee
+++ web/src/cs/views/default.coffee
@@ -14,6 +14,12 @@
 zRange = null
 zDensity = 50 # defines how much z range we want per image
 numLoadedImages = 0
+overImage = true;
+mouse = {x:0.5, y: 0.5}
+mouseOver = (e) ->
+	overImage = true
+mouseOut = () ->
+	overImage = false
 newImageLoaded = (image) ->
 	#console.log 'new image'
 	#console.log image
@@ -53,8 +59,10 @@

 	sp.position.set( xRange(Math.random()), yRange(Math.random()), zRange(Math.random()) )
 	sprites.push(sp)
-
+	#console.log sp
 	scene.add(sp)
+	sp.element.addEventListener('mouseover', mouseOver)
+	sp.element.addEventListener('mouseout', mouseOut)
 	return sp
 initView = (_assets, _scene, _camera) ->
 	assets = _assets
@@ -75,6 +83,7 @@
 	document.addEventListener('mousewheel', (scrollEvent) ->
 		move( scrollEvent.wheelDelta )
 	, false)
+	document.addEventListener('mousemove', mouseMove, false)
 move = (amount) ->
 	_.each(sprites, (sprite) ->
 		sprite.position.z -= amount
@@ -87,8 +96,12 @@

 	)
+mouseMove = (e) ->
+	mouse.x = e.clientX / window.innerWidth
+	mouse.y = e.clientY / window.innerHeight
 update = () ->
-	move(4)
+	amount = (1 - mouse.y ) * 8 + 1
+	move(amount)
 	camera.updateMatrix()
 	TWEEN.update()


Fix doc for coffeescript.

Fix doc for coffeescript.

--- spot.coffee
+++ spot.coffee
@@ -16,8 +16,8 @@
 #   hubot play <song> - Play a particular song. This plays the first most popular result.
 #   hubot volume? - Returns the current volume level.
 #   hubot volume [0-100] - Sets the volume.
-#   hubot volume+ - Bumps the volume 10%.
-#   hubot volume- - Bumps the volume down 10%.
+#   hubot volume+ - Bumps the volume.
+#   hubot volume- - Bumps the volume down.
 #   hubot mute - Sets the volume to 0.
 #   hubot [name here] says turn it down - Sets the volume to 15 and blames [name here].
 #


a couple of basically pointless tests

a couple of basically pointless tests

--- test/breakneck_test.coffee
+++ test/breakneck_test.coffee
@@ -39,6 +39,12 @@
     it 'also provides a convenient dash-separated identifier', ->
       Breakneck.parseName('Foo#bar').identifier.should.eql('Foo-bar')

+    it 'for constructors/namespaces, sets the name to the namespace', ->
+      Breakneck.parseName('Foo').name.should.eql('Foo')
+
+    it 'for constructors/namespaces, sets the identifier to the namespace', ->
+      Breakneck.parseName('Foo').identifier.should.eql('Foo')
+
   describe 'parsePair', ->
     it 'splits a line across the string "//=>"', ->
       Breakneck.parsePair('foo(bar)//=>5').should.eql({


Fix row/col mark test

Fix row/col mark test

--- test/src/tests.coffee
+++ test/src/tests.coffee
@@ -792,7 +792,7 @@
     prompt 10 / 10
   '''

-  key = editor.mark 2, 4, {color: '#F00'}
+  key = editor.mark {row: 2, col: 4}, {color: '#F00'}

   strictEqual editor.markedBlocks[key].model.stringify({}), '10 - 10'
   strictEqual editor.markedBlocks[key].style.color, '#F00'


help now just links url to web help

help now just links url to web help

--- scripts/help.coffee
+++ scripts/help.coffee
@@ -51,25 +51,8 @@
   """

 module.exports = (robot) ->
-  robot.respond /help\s*(.*)?$/i, (msg) ->
-    cmds = robot.helpCommands()
-    filter = msg.match[1]
-
-    if filter
-      cmds = cmds.filter (cmd) ->
-        cmd.match new RegExp(filter, 'i')
-      if cmds.length == 0
-        msg.send "No available commands match #{filter}"
-        return
-
-    prefix = robot.alias or robot.name
-    cmds = cmds.map (cmd) ->
-      cmd = cmd.replace /^hubot/, prefix
-      cmd.replace /hubot/ig, robot.name
-
-    emit = cmds.join "\n"
-
-    robot.send({user: {name: msg.message.user.name}}, emit)
+  robot.respond /help/i, (msg) ->
+    msg.send "#{process.env.HEROKU_URL}/#{robot.name}/help"

   robot.router.get "/#{robot.name}/help", (req, res) ->
     cmds = robot.helpCommands().map (cmd) ->


Utils style fixes.

Utils style fixes.

--- test/testutils.coffee
+++ test/testutils.coffee
@@ -89,18 +89,14 @@

 # fix for node 0.12
 nextTick = (fn, args...) ->
-  process.nextTick ->
-    fn args...
+  process.nextTick -> fn args...

 parallel = (fns, cb) ->
-  promises = _.map fns, (fn) ->
-    Promise.fromCallback fn
-  Promise.all(promises).asCallback(cb)
+  Promise.all(_.map fns, Promise.fromCallback).asCallback(cb)

 series = (fns, cb) ->
-  Promise.each fns, (fn) ->
-    Promise.fromCallback fn
-  .asCallback(cb)
+  Promise.each(fns, Promise.fromCallback).asCallback(cb)
+

 module.exports = {
   ChatService


short nativity io file paths

short nativity io file paths

--- test/mocha/cli.spec.coffee
+++ test/mocha/cli.spec.coffee
@@ -6,9 +6,14 @@
 assertSame = require "../helpers/assert_same"

+# Paths to commands and data files.
+
 precious = "bin/precious.js"
+tis = "test/io/for/nativity.json"
+its = "test/io/out/nativity.json"
 jsontool = "node_modules/jsontool/lib/jsontool.js"
 jsontool0 = "#{jsontool} -o json-0"
+

 describe "$ `precious", ->

@@ -41,10 +46,10 @@

   describe "-`, being piped a stream of spec-conforming json", ->
     it "produces the expected output", ->
-      proVals (proExec "cat test/io/for/nativity.json | #{precious} -")
-            , (proExec "cat test/io/for/nativity.json | #{precious} stream")
-            , (proExec "cat test/io/for/nativity.json | #{precious} s")
-            , (proExec "cat test/io/out/nativity.json")
+      proVals (proExec "cat #{tis} | #{precious} -")
+            , (proExec "cat #{tis} | #{precious} stream")
+            , (proExec "cat #{tis} | #{precious} s")
+            , (proExec "cat #{its}")
             , (results) ->
               assertSame results,
                 parse: true
@@ -55,9 +60,9 @@

   describe "f[ile]`, given path to a spec-conforming json", ->
     it "produces the expected output", ->
-      proVals (proExec "#{precious} f test/io/for/nativity.json")
-            , (proExec "#{precious} file test/io/for/nativity.json")
-            , (proExec "cat test/io/out/nativity.json")
+      proVals (proExec "#{precious} f cat #{tis}")
+            , (proExec "#{precious} file cat #{tis}")
+            , (proExec "cat #{its}")
             , (results) ->
               assertSame results,
                 parse: true
@@ -67,10 +72,10 @@
   # Object
   describe "o[bject]`, given a spec-conforming json string", ->
     it "produces the expected output", ->
-      (proExec "cat test/io/for/nativity.json").then (input) ->
+      (proExec "cat #{tis}").then (input) ->
         proVals (proExec "#{precious} o '#{input}'")
               , (proExec "#{precious} object '#{input}'")
-              , (proExec "cat test/io/out/nativity.json")
+              , (proExec "cat #{its}")
               , (results) ->
                 assertSame results,
                   parse: true
@@ -82,7 +87,7 @@
   describe '{*}` re-run with the extra [0]["re"]', ->
     results = []
     before (done) ->
-      beginning = "#{precious} f test/io/for/nativity.json"
+      beginning = "#{precious} f #{tis}"
       mapExec [
         "#{beginning} | #{jsontool0}"
         "#{beginning} | #{jsontool} 0 | #{jsontool} re | #{jsontool0}


Run test once for each device type in global config

--- test/webserver.coffee
+++ test/webserver.coffee
@@ -3,18 +3,22 @@
 http = require 'http'
 xml2js = require 'xml2js'
 xmlServer = require '../lib/xml-server'
+config = require '../lib/config'
 parser = new xml2js.Parser()

-deviceType = 'MediaServer'
-deviceName = 'Test Device'
-server = xmlServer.createServer deviceType, deviceName
-xmlServer.listen server, (err, httpServer) ->
-    host = httpServer.address
-    port = httpServer.port
-    # test device description
-    http.get host: host, port: port, path: '/device/description', (res) ->
-        assert.equal res.statusCode, 200
-        res.on 'data', (data) ->
-            parser.parseString data, (err, result) ->
-                assert.equal result.device.deviceType, 'urn:schemas-upnp-org:device:' + deviceType + ':1'
-                assert.equal result.device.friendlyName, deviceName
+testWebServer = (deviceType, deviceName, deviceVersion) ->
+    xmlServer.listen xmlServer.createServer(deviceType, deviceName), (err, httpServer) ->
+        assert.ok !err
+        host = httpServer.address
+        port = httpServer.port
+        # test device description
+        http.get host: host, port: port, path: '/device/description', (res) ->
+            assert.equal res.statusCode, 200
+            res.on 'data', (data) ->
+                parser.parseString data, (err, result) ->
+                    assert.ok !err
+                    assert.equal result.device.deviceType, "#{config.schemaPrefix}:device:#{deviceType}:#{deviceVersion}"
+                    assert.equal result.device.friendlyName, deviceName
+
+for deviceType of config.devices
+    testWebServer deviceType, 'Test Device', config.devices[deviceType].version


test/wktreader: add test for empty string and read without input

Both should throw an error.

This commit is related to issue #14.

--- test/wktreader-test.coffee
+++ test/wktreader-test.coffee
@@ -45,6 +45,16 @@
       assert.equal geom.toString(), "POLYGON EMPTY"
       assert.isTrue geom.isEmpty()

+    "should throw an Error on read with empty string": (reader) ->
+      fn = ->
+        reader.read ""
+      assert.throws fn, Error
+
+    "should throw an Error on read without any input": (reader) ->
+      fn = ->
+        reader.read()
+      assert.throws fn, Error
+
   "A WKTReader with non standard GeometryFactory":
     topic: ->
       new WKTReader new GeometryFactory new PrecisionModel "FIXED"


Set user's realname to alias if not set already

--- packages/rocketchat-lib/server/methods/sendMessage.coffee
+++ packages/rocketchat-lib/server/methods/sendMessage.coffee
@@ -6,7 +6,7 @@
 		if not Meteor.userId()
 			throw new Meteor.Error('error-invalid-user', "Invalid user", { method: 'sendMessage' })

-		user = RocketChat.models.Users.findOneById Meteor.userId(), fields: username: 1
+		user = RocketChat.models.Users.findOneById Meteor.userId(), fields: username: 1, name: 1

 		room = Meteor.call 'canAccessRoom', message.rid, user._id

@@ -22,6 +22,8 @@
 			}
 			return false

+		message.alias = message.alias or user.name
+
 		RocketChat.sendMessage user, message, room

 # Limit a user to sending 5 msgs/second


more refactor

more refactor

--- lib/codeglance-view.coffee
+++ lib/codeglance-view.coffee
@@ -18,10 +18,8 @@
     @style.width = "calc(100% - #{getComputedStyle(minimapView).width})"

     nLines = atom.config.get 'minimap-codeglance.numberOfLines'
-    @style.height = nLines * @getLineHeight() + 'px'
-
-  getLineHeight: ->
-    @editor.getLineHeightInPixels()
+    lineHeight = @editor.getLineHeightInPixels()
+    @style.height = nLines * lineHeight + 'px'

   resetGrammar: ->
     @editor.setGrammar switch atom.config.get 'minimap-codeglance.highlightCode'


fix modes in history

fix modes in history

--- lib/console/console.coffee
+++ lib/console/console.coffee
@@ -126,13 +126,17 @@

   modes: -> {}

+  modeByName: (name) ->
+    for char, mode of @modes()
+      return mode if mode.name is name
+
   cursorAtBeginning: (ed) ->
     ed.getCursors().length == 1 and
     ed.getCursors()[0].getBufferPosition().isEqual [0, 0]

   setMode: (cell, mode) ->
     ed = cell.querySelector('atom-text-editor').getModel()
-    if mode?.constructor is String then mode = @modes[mode]
+    if mode?.constructor is String then mode = @modeByName(mode)
     if not mode
       delete ed.inkConsoleMode
       if @view.defaultGrammar then ed.setGrammar @view.defaultGrammar


support going down through previous results

--- lib/console/history.coffee
+++ lib/console/history.coffee
@@ -9,16 +9,21 @@
     @position = @items.length

   push: (x) ->
+    @lastPosition = @position
     @items.push x
     @position = @items.length
     @removeCycles()

   getPrevious: ->
+    delete @lastPosition
     if @position > 0
       @position--
       @items[@position]

   getNext: ->
+    if @lastPosition?
+      @position = @lastPosition
+      delete @lastPosition
     if not @isAtEnd()
       @position++
     @items[@position] or input: ""


use coffeescript's builtin defaults & class vars

--- countUp.coffee
+++ countUp.coffee
@@ -6,41 +6,34 @@
  * @version 0.0.6
 ###
 class countUp
+  useEasing: true
+  startTime: null
+  remaining: null
+  rAF: null
+
   ###*
-   * [constructor description]
-   * @param {[type]} target Id of Html element where counting occurs.
-   * @param {[type]} startVal The value you want to start at.
-   * @param {[type]} endVal The value you want to arrive at.
-   * @param {[type]} decimals Number of decimal places in number, default 0.
-   * @param {[type]} duration Duration in seconds, default 2.
-   * @return {[type]} [description]
+   * @param {String} target Id of Html element where counting occurs.
+   * @param {Number} startVal The value you want to start at.
+   * @param {Number} endVal The value you want to arrive at.
+   * @param {Integer} decimals=0 Number of decimal places in number.
+   * @param {Float} duration=2 Duration in seconds.
   ###
-  constructor: (target, startVal, endVal, decimals, duration) ->
+  constructor: (target, startVal, endVal, decimals=0, duration=2) ->
     lastTime = 0
-    vendors = [
-      'webkit'
-      'moz'
-      'ms'
-    ]
-
-    #toggle easing
-    @useEasing = true
+    vendors = ['webkit', 'moz','ms']

     @doc = document.getElementById target
     startVal = Number startVal
     endVal = Number endVal
     @countDown = if (startVal > endVal) then true else false
-    decimals = Math.max(0, decimals or 0)
+    decimals = Math.max(0, decimals)
     @dec = Math.pow(10, decimals)
-    @duration = duration * 1000 or 2000
-    @startTime = null
-    @remaining = null
+    @duration = duration * 1000
     @frameVal = startVal
-    @rAF = null

     # make sure requestAnimationFrame and cancelAnimationFrame are defined
-    # polyfill for browsers without native support
-    # by Opera engineer Erik Möller
+    # polyfill for browsers without native support by Opera engineer Erik
+    # Möller
     while x < vendors.length and not window.requestAnimationFrame
       window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']
       window.cancelAnimationFrame =
@@ -62,54 +55,52 @@
       window.cancelAnimationFrame = (id) ->
         clearTimeout id

-    # Robert Penner's easeOutExpo
-    @easeOutExpo = (t, b, c, d) ->
-      c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b
+  # format startVal on initialization
+  @doc.innerHTML = @addCommas startVal.toFixed(decimals)

-    @count = (timestamp) ->
-      @startTime = timestamp if @startTime is null
+  # Robert Penner's easeOutExpo
+  easeOutExpo: (t, b, c, d) ->
+    c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b

-      @timestamp = timestamp
+  count: (timestamp) ->
+    @startTime = timestamp if @startTime is null
+    @timestamp = timestamp
+    progress = timestamp - @startTime
+
+    # to ease or not to ease is the question
+    if @useEasing
+      if @countDown
+        i = @easeOutExpo progress, 0, startVal - endVal, @duration
+        @frameVal = startVal - i
+      else
+        @frameVal = @easeOutExpo(progress, startVal, endVal - startVal, @duration)
+    else
+      if @countDown
+        i = (startVal - endVal) * (progress / @duration)
+        @frameVal = startVal - i
+      else
+        @frameVal = startVal + (endVal - startVal) * (progress / @duration)
+
+    # decimal
+    @frameVal = Math.round(@frameVal * @dec) / @dec

-      progress = timestamp - @startTime
-
-      # to ease or not to ease is the question
-      if @useEasing
-        if @countDown
-          i = @easeOutExpo progress, 0, startVal - endVal, @duration
-          @frameVal = startVal - i
-        else
-          @frameVal = @easeOutExpo(progress, startVal, endVal - startVal, @duration)
-      else
-        if @countDown
-          i = (startVal - endVal) * (progress / @duration)
-          @frameVal = startVal - i
-        else
-          @frameVal = startVal + (endVal - startVal) * (progress / @duration)
-
-      # decimal
-      @frameVal = Math.round(@frameVal * @dec) / @dec
+    # don't go past enVal since progress can exceed duration in last grame
+    if @countDown
+      @frameVal = if (@framVal < endVal) then endVal else @frameVal
+    else
+      @frameVal = if (@framVal > endVal) then endVal else @frameVal

-      # don't go past enVal since progress can exceed duration in last grame
-      if @countDown
-        @frameVal = if (@framVal < endVal) then endVal else @frameVal
-      else
-        @frameVal = if (@framVal > endVal) then endVal else @frameVal
+    # formate and print value
+    @doc.innerHTML = @addCommas @frameVal.toFixed(decimals)

-      # formate and print value
-      @doc.innerHTML = @addCommas @frameVal.toFixed(decimals)
+    # weather to continue
+    if progress < @duration
+      @rAF = requestAnimationFrame @count
+    else
+      @callback() if @callback?

-      # weather to continue
-      if progress < @duration
-        @rAF = requestAnimationFrame @count
-      else
-        @callback() if @callback?

-    # format startVal on initialization
-    @doc.innerHTML = @addCommas startVal.toFixed(decimals)
-
-  start: (callback) ->
-    @callback = callback
+  start: (@callback) ->
     # make sure endVal is a number
     requestAnimationFrame @count unless isNaN(endVal) and isNan(startVal) isnt null
     else


Unset tree-view keybindings for copying/pasting files

--- keymap.cson
+++ keymap.cson
@@ -73,6 +73,9 @@
 	"alt-7":          "unset!"
 	"alt-8":          "unset!"
 	"alt-9":          "unset!"
+	"ctrl-c":         "unset!"
+	"ctrl-x":         "unset!"
+	"ctrl-v":         "unset!"
 	"ctrl-1":         "pane:show-item-1"
 	"ctrl-2":         "pane:show-item-2"
 	"ctrl-3":         "pane:show-item-3"
@@ -180,6 +183,9 @@
 	"shift-cmd-c":    "find-and-replace:toggle-case-option"

 "body.platform-darwin .tree-view":
+	"cmd-c":          "unset!"
+	"cmd-x":          "unset!"
+	"cmd-v":          "unset!"
 	"cmd-1":          "pane:show-item-1"
 	"cmd-2":          "pane:show-item-2"
 	"cmd-3":          "pane:show-item-3"


Lock the scroll indicator when scroll past end is enabled

--- lib/minimap-element.coffee
+++ lib/minimap-element.coffee
@@ -255,7 +255,7 @@
     if @scrollIndicator?
       editorHeight = @getTextEditor().getHeight()
       indicatorHeight = editorHeight * (editorHeight / @minimap.getHeight())
-      indicatorScroll = (editorHeight - indicatorHeight) * @minimap.getTextEditorScrollRatio()
+      indicatorScroll = (editorHeight - indicatorHeight) * Math.min(1, @minimap.getTextEditorScrollRatio())
       @scrollIndicator.style.height = indicatorHeight + 'px'
       @transformElement @scrollIndicator, @makeTranslate(0, indicatorScroll)


Possible fix for #24

Possible fix for #24

--- app/annotation/step.cjsx
+++ app/annotation/step.cjsx
@@ -130,6 +130,7 @@
     @props.step.set 1
     @props.subStep.set 0
     @props.currentAnswers.set {}
+    @setState values: []

   finishNote: ->
     console?.log 'send to classification', @props.classification


Only deactivate loaded packages on install

Closes #346

--- lib/package-manager.coffee
+++ lib/package-manager.coffee
@@ -211,8 +211,10 @@
     {name, version, theme} = pack
     activateOnSuccess = not theme and not atom.packages.isPackageDisabled(name)
     activateOnFailure = atom.packages.isPackageActive(name)
-    atom.packages.deactivatePackage(name) if atom.packages.isPackageActive(name)
-    atom.packages.unloadPackage(name) if atom.packages.isPackageLoaded(name)
+
+    if atom.packages.isPackageLoaded(name)
+      atom.packages.deactivatePackage(name) if atom.packages.isPackageActive(name)
+      atom.packages.unloadPackage(name)

     args = ['install', "#{name}@#{version}"]
     exit = (code, stdout, stderr) =>


Fix actions

Fix actions

--- lib/patch/hunk-view.coffee
+++ lib/patch/hunk-view.coffee
@@ -75,8 +75,6 @@
     oldLine = oldStart
     newLine = newStart

-    console.log 'OMGOMGOMGOMGOMGOMGOMGOMG'
-    console.log header
     for line, lineIndex in @hunk.lines
       lineNode              = @createLineNode()
       content               = line.content().split(/[\r\n]/g)[0] # srsly.
@@ -106,7 +104,6 @@

       lineNode.classList.add('staged') if lineOrigin in ['-', '+'] and line.staged

-      console.log line.staged || false, oldLine, newLine, lineIndex, content
       oldLineNumber.textContent = oldLine if line.oldLineno() > 0
       newLineNumber.textContent = newLine if line.newLineno() > 0
       lineNode.dataset.lineIndex = lineIndex
@@ -149,7 +146,6 @@
       context:  headerParts[5]

   processLinesStage: ->
-    action = if @status == 'unstaged' then 'stage' else 'unstage'
     path = @patch.newPathName

     totalChanges = @allChangedLines().length
@@ -177,6 +173,14 @@
     oldCount = newCount = 0

     lines = []
+
+    selectedLineCount = @querySelectorAll(".hunk-line.selected").length
+    stagedLineCount = @querySelectorAll(".hunk-line.selected.staged").length
+
+    action = if stagedLineCount < selectedLineCount - stagedLineCount
+      'stage'
+    else
+      'unstage'

     for line, idx in @hunk.lines
       selected =
@@ -212,7 +216,7 @@
     header = "@@ -#{oldStart},#{oldCount} +#{newStart},#{newCount} @@#{context}\n"
     patch = "#{header}#{lines.join("\n")}\n"

-    promise = if @status == 'unstaged'
+    promise = if action is 'stage'
       @gitIndex.stagePatch(patch, @patch.getRaw())
     else
       @gitIndex.unstagePatch(patch, @patch.getRaw())


Fix to remove `transient-marked` on click

--- lib/transient-emacs.coffee
+++ lib/transient-emacs.coffee
@@ -33,20 +33,17 @@
       'emacs:backward-isearch': => @activate_isearch(false)
       'emacs:backspace': => return @backspace()

-    atom.workspace.getTextEditors().forEach (editor) =>
+    addEditorEventListner = (editor) =>
+      editorView = $(atom.views.getView(editor))
       @event_listeners.push editor.onDidChangeCursorPosition (e)=>
-        @killring.seal() if @is_user_command
+        @killring?.seal() if @is_user_command
         @deactivate_isearch() if @is_user_command
-
+      @event_listeners.push editorView.on 'click',(e)=>
+        editorView.removeClass "transient-marked"
+
+    atom.workspace.getTextEditors().forEach addEditorEventListner
     @add_text_editor_listener = atom.workspace.onDidAddTextEditor (event) =>
-      @event_listeners.push event.textEditor.onDidChangeCursorPosition =>
-        @killring.seal() if @is_user_command
-        @deactivate_isearch() if @is_user_command
-      @event_listeners.push event.textEditor.onWillInsertText (e)=>
-        if @isearch_tile
-          e.cancel()
-          @isearch_word += e.Text
-          @isearch @isearch_word
+      addEditorEventListner(event.textEditor)

     @keymap_listener = atom.keymaps.onDidMatchBinding (e)=>
       if @isearch_tile


:lipstick:

:lipstick:

--- lib/wrap-guide-view.coffee
+++ lib/wrap-guide-view.coffee
@@ -24,15 +24,13 @@
   getGuideColumn: (path) ->
     customColumns = config.get('wrapGuide.columns')
     return @getDefaultColumn() unless _.isArray(customColumns)
-    for customColumn in customColumns
-      continue unless _.isObject(customColumn)
-      pattern = customColumn['pattern']
-      continue unless pattern
-      return parseInt(customColumn['column']) if new RegExp(pattern).test(path)
+    for customColumn in customColumns when _.isObject(customColumn)
+      {pattern, column} = customColumn
+      return parseInt(column) if pattern and new RegExp(pattern).test(path)
     @getDefaultColumn()

   updateGuide: ->
-    column = @getGuideColumn(@editor.getPath(), @defaultColumn)
+    column = @getGuideColumn(@editor.getPath())
     if column > 0
       columnWidth = @editor.charWidth * column
       if columnWidth < @editor.layerMinWidth or columnWidth < @editor.width()


Updated Atom config

Updated Atom config

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -66,6 +66,9 @@
       "seti-ui"
       "seti-monokai"
     ]
+    packagesWithKeymapsDisabled: [
+      "sort-lines"
+    ]
   editor:
     invisibles: {}
     showInvisibles: true


another fix for the 3.x version

another fix for the 3.x version

--- tilde/zephyros.coffee
+++ tilde/zephyros.coffee
@@ -105,17 +105,19 @@
 moveToScreen = (win, screen) ->
   return if screen.null?

-  oldFrame      = win.frame()
+  frame = win.frame()
   oldScreenRect = win.screen().frameWithoutDockOrMenu()
   newScreenRect = screen.frameWithoutDockOrMenu()

   xRatio = newScreenRect.w  / oldScreenRect.w
   yRatio = newScreenRect.h / oldScreenRect.h

-  win.setFrame CGRectMake(Math.round((oldFrame.x - NSMinX(oldScreenRect)) * xRatio) + NSMinX(newScreenRect),
-                          Math.round((oldFrame.y - NSMinY(oldScreenRect)) * yRatio) + NSMinY(newScreenRect),
-                          Math.round(oldframe.w * xRatio),
-                          Math.round(oldframe.h * yRatio))
+  win.setFrame {
+    x: Math.round((frame.x - oldScreenRect.x) * xRatio) + newScreenRect.x
+    y: Math.round((frame.y - oldScreenRect.y) * yRatio) + newScreenRect.y
+    w: Math.round(frame.w * xRatio)
+    h: Math.round(frame.h * yRatio)
+  }

 moveWindow = (fn) ->
   win = api.focusedWindow()


course: due date as a field to assignments -- very minimal

--- salvus/page/editor_course.cjsx
+++ salvus/page/editor_course.cjsx
@@ -24,11 +24,12 @@
 ###
 TODO:

-- [ ] (1:30?) add due date as a field to assignments:
+- [x] (1:30?) (0:23) add due date as a field to assignments:
     - way to edit it (date selector...?)
     - use it to sort assignments
-- [ ] (1:30?) add student metadata (e.g., student_id)
-    - let enter it in the students page
+- [ ] (0:15?) uniformly sort assignments everywhere, efficiently.
+- [ ] (1:30?) add student note field
+    - let enter/edit it in the students page
     - show in the py and csv export
 - [ ] (2:00?) make everything look pretty
         - triangles for show/hide assignment info like for students
@@ -350,6 +351,11 @@
             grades     = syncdb.select_one(where:where).grades ? {}
             grades[student.get('student_id')] = grade
             @_update(set:{grades:grades}, where:where)
+
+        set_due_date: (assignment, due_date) =>
+            assignment = store.get_assignment(assignment)
+            where      = {table:'assignments', assignment_id:assignment.get('assignment_id')}
+            @_update(set:{due_date:due_date}, where:where)

         # Copy the files for the given assignment_id from the given student to the
         # corresponding collection folder.
@@ -629,6 +635,9 @@
         get_grade: (assignment, student) =>
             return @get_assignment(assignment)?.get('grades')?.get(@get_student(student)?.get('student_id'))

+        get_due_date: (assignment) =>
+            return @get_assignment(assignment)?.get('due_date')
+
         get_assignments: => @state.assignments

         get_sorted_assignments: =>
@@ -637,7 +646,8 @@
                 if not assignment.get('deleted')
                     v.push(assignment)
             # TODO: actually worry about sorting by due date (?)
-            v.sort (a,b) -> misc.cmp(a.get('path')?.toLowerCase(), b.get('path')?.toLowerCase())
+            f = (a) -> [a.get('due_date') ? 0, a.get('path')?.toLowerCase()]
+            v.sort (a,b) -> misc.cmp_array(f(a), f(b))
             return v

         get_assignment: (assignment) =>
@@ -1219,16 +1229,48 @@
     getInitialState: ->
         more : false
         confirm_delete : false
+        edit_due : false
+        due_date : undefined
+
+    edit_due_date: ->
+        @setState(edit_due:true, due_date:@props.assignment.get('due_date'))
+
+    save_due_date: (e) ->
+        e?.preventDefault()
+        @props.flux.getActions(@props.name).set_due_date(@props.assignment, @state.due_date)
+        @setState(edit_due:false)
+
+    due_date_keydown: (e) ->
+        if e.keyCode == 27
+            @setState(edit_due:false)
+
+    render_due: ->
+        if @state.edit_due
+            <form onSubmit={@save_due_date}>
+                <Input autoFocus value={@state.due_date} ref='due_date_input'
+                       type='text' placeholder='Due date'
+                       onChange={=>@setState(due_date:@refs.due_date_input.getValue())}
+                       onKeyDown={@due_date_keydown}
+                />
+            </form>
+        else
+            due_date = @props.assignment.get('due_date')
+

+                {"#{due_date}"} <Button onClick={=>@edit_due_date()}>Edit</Button>
+

     render_more_header: ->
         <Row>
             <Col md=1>
                 {@render_close_button()}
             </Col>
-            <Col md=4>
+            <Col md=2>

{@render_path_link()}

             </Col>
-            <Col md=7>
+            <Col md=3>
+                Due: {@render_due()}
+            </Col>
+            <Col md=6>
                 <ButtonToolbar style={float:'right'}>
                     {@render_assign_button()}
                     {@render_collect_button()}
@@ -1319,6 +1361,11 @@
                 <Icon name="trash" /> Delete
             </Button>

+    render_summary_due_date: ->
+        due_date = @props.assignment.get('due_date')
+        if due_date
+            Due: {"#{due_date}"}
+
     render_summary_line: ->
         <Row style={entry_style}>
             <Col md=4>
@@ -1326,6 +1373,9 @@
                     e.preventDefault();@setState(more:true)}>{@props.assignment.get('path')}
                     { (deleted) if @props.assignment.get('deleted')}

+            </Col>
+            <Col md=2>
+                {@render_summary_due_date()}
             </Col>
         </Row>


Social: show troll context for exempt users

--- workers/social/lib/social/models/socialapi/channel.coffee
+++ workers/social/lib/social/models/socialapi/channel.coffee
@@ -218,7 +218,7 @@
   # fetchActivities - fetch activities of a channel
   @fetchActivities = secure (client, options, callback)->
     {connection:{delegate}} = client
-    options.showExempt = delegate.checkFlag "super-admin"
+    options.showExempt = delegate.checkFlag "super-admin" or delegate.isExempt
     options.channelId = options.id
     # just to create social channels
     ensureGroupChannel client, (err, socialApiChannelId)->


Redirect premium tab to pricing

Redirect premium tab to pricing

--- apps/tools/routes.coffee
+++ apps/tools/routes.coffee
@@ -2,9 +2,10 @@
 Authentication = require '../../models/authentication.coffee'

 @tools = (req, res, next) ->
-  res.redirect("/tools/bookmarklet") unless req.params.tab
-  res.redirect("/#log_in") unless req.user
-  res.redirect("/manage") if req.params.tab is 'manage'
+  return res.redirect("/tools/bookmarklet") unless req.params.tab
+  return res.redirect("/log_in") unless req.user
+  return res.redirect("/manage") if req.params.tab is 'manage'
+  return res.redirect("/pricing") if req.params.tab is 'premium'

   tab = res.locals.sd.TAB = req.params.tab
   coupon = res.locals.sd.COUPON = req.query.coupon


Instantiate tooltip for other active users when sourceid changes

--- client/controllers/curatorInbox/curatorUserStatus.coffee
+++ client/controllers/curatorInbox/curatorUserStatus.coffee
@@ -10,6 +10,7 @@
   instance = @
   @autorun ->
     instance.otherActiveUser.get()
+    instance.data.selectedSourceId.get()
     Meteor.defer ->
       $('.curator-viewing-status').tooltip
         container: 'body'


Adds new fields to fulcrum export

Adds new fields to fulcrum export

--- scripts/daily_upload_s3.coffee
+++ scripts/daily_upload_s3.coffee
@@ -24,7 +24,36 @@
 filename = "export_" + moment().format('YYYYMMDDhhmmss') + ".csv"
 dir = 'scripts/tmp/'

-attrs = ['id', 'author_id', 'auction_ids', 'contributing_authors', 'fair_ids', 'featured', 'featured_artist_ids', 'featured_artwork_ids', 'partner_ids', 'primary_featured_artist_ids', 'slugs', 'tags', 'title', 'tier', 'published_at', 'show_ids', 'section_ids', 'thumbnail_image', 'thumbnail_title', 'keywords', 'slug', 'channel_id', 'partner_channel_id']
+attrs = [
+  'id'
+  'author_id'
+  'auction_ids'
+  'contributing_authors'
+  'fair_ids'
+  'featured'
+  'featured_artist_ids'
+  'featured_artwork_ids'
+  'partner_ids'
+  'primary_featured_artist_ids'
+  'slugs'
+  'tags'
+  'title'
+  'tier'
+  'published_at'
+  'show_ids'
+  'thumbnail_image'
+  'thumbnail_title'
+  'keywords'
+  'slug'
+  'channel_id'
+  'partner_channel_id'
+  'vertical'
+  'tracking_tags'
+  'exclude_google_news'
+  'indexable'
+  'is_super_article'
+  'description'
+]
 projections = object attrs, attrs.map -> 1

 db.articles.find({ published: true }, projections).toArray (err, articles) ->
@@ -63,6 +92,12 @@
       stringify a.slug
       a.channel_id
       a.partner_channel_id
+      a.vertical.name
+      stringify a.tracking_tags
+      a.exclude_google_news
+      a.indexable
+      a.is_super_article
+      stringify a.description
     ].join(',')
     csv.push row


StacksV2: InitialView: Support Edit/Create Stack events

--- client/admin/lib/views/stacksv2/initialview.coffee
+++ client/admin/lib/views/stacksv2/initialview.coffee
@@ -16,11 +16,16 @@
     @createStackButton = new kd.ButtonView
       title    : 'Create new Stack'
       cssClass : 'solid compact green action'
-      callback : -> alert 'FIX ME'
+      callback : => @emit 'CreateNewStack'

-    @stackTemplateList = (new StackTemplateListView)
-      .listView.on 'ItemSelected', (stackTemplate) ->
-        console.log 'Selected Template:', stackTemplate
+    @stackTemplateList = new StackTemplateListView
+
+    @stackTemplateList.listView.on 'ItemSelected', (stackTemplate) =>
+      @emit 'EditStack', stackTemplate
+
+
+  reload: ->
+    @stackTemplateList.listController.loadItems()

   pistachio: ->


video: disconnect from video session when collab ends

--- client/ide/lib/videocollaborationcontroller.coffee
+++ client/ide/lib/videocollaborationcontroller.coffee
@@ -22,6 +22,9 @@
         @handleVideoParticipantTalkingStateChanged participant, on
       .on 'ParticipantStoppedTalking', (participant) =>
         @handleVideoParticipantTalkingStateChanged participant, off
+
+    @on 'CollaborationDidCleanup', =>
+      @videoModel.session.disconnect()

   startVideoCollaboration: ->


close tool chooser on Backbone errors - fixes #424

--- client/code/view/tool/list.coffee
+++ client/code/view/tool/list.coffee
@@ -7,6 +7,12 @@

   initialize: ->
     app.tools().on 'fetched', @addTools, @
+
+    Backbone.on 'error', =>
+      # close chooser on errors,
+      # so user can see red alert bar behind
+      @closeChooser()
+
     $(window).on 'keyup', (e) =>
       if e.which == 27
         @closeChooser()


Terminal: fix reconnect to existing session on klient connection closed

--- client/Terminal/webtermview.coffee
+++ client/Terminal/webtermview.coffee
@@ -106,9 +106,11 @@

     kite = @getKite()
     kite.init()
-    kite.webtermConnect(options).then (remote) =>
-
-      return  unless remote?
+    kite.webtermConnect(options).then (_remote) =>
+
+      return  unless _remote?
+
+      remote = _remote

       @setOption "session", remote.session
       @terminal.eventHandler = (data)=>


Viewer: minor whitespace

Viewer: minor whitespace

--- client/Viewer/AppController.coffee
+++ client/Viewer/AppController.coffee
@@ -7,7 +7,6 @@
     openWith     : "forceNew"
     behavior     : "application"
     preCondition :
-
       condition  : (options, cb)->
         {path, vmName} = options
         return cb true  unless path
@@ -15,11 +14,11 @@
         publicPath = path.replace \
           ////home/(.*)/Web/(.*)///, "https://$1.#{KD.config.userSitesDomain}/$2"
         cb publicPath isnt path, {path: publicPath}
-
       failure    : (options, cb)->
         correctPath = \
           "/home/#{KD.nick()}/Web/"
         KD.getSingleton("appManager").notify "File must be under: #{correctPath}"
+

   constructor:(options = {}, data)->

@@ -32,5 +31,5 @@

     super options, data

-  open:(path)->
-    @getView().openPath path
+
+  open:(path)-> @getView().openPath path


Small fix

Small fix

--- client/components/UserBadge.coffee
+++ client/components/UserBadge.coffee
@@ -42,6 +42,7 @@
                 }
             </ButtonGroup>
         </div>
+

 export default class UserBadge extends React.Component
     constructor: (props) ->


disable the “already getting account settings” message issue.

--- salvus/page/account.coffee
+++ salvus/page/account.coffee
@@ -346,6 +346,10 @@
     account_id = mesg.account_id
     account_settings.load_from_server (error) ->
         if error
+            if account_settings.settings?
+                # don't show an error if already loaded settings before successefully; error
+                # is probably just due to trying to reload settings too frequently.
+                return
             alert_message(type:"error", message:error)
         else
             account_settings.set_view()


for file listing, keep trying with exponential backoff

--- salvus/page/project.coffee
+++ salvus/page/project.coffee
@@ -1542,24 +1542,45 @@
             @_file_list_tab_spinner_timer = setTimeout( (() -> spinner.show().spin()), 1000 )

         if @public_access
-            f = salvus_client.public_project_directory_listing
+            g = salvus_client.public_project_directory_listing
         else
-            f = salvus_client.project_directory_listing
+            g = salvus_client.project_directory_listing

         @_requested_path = path

-        f
-            project_id : @project.project_id
-            path       : path
-            time       : @_sort_by_time
-            hidden     : @container.find("a[href=#hide-hidden]").is(":visible")
-            timeout    : 60
-            cb         : (err, listing) =>
+        listing = undefined
+        f = (cb) =>
+            if path != @_requested_path
+                # requested another path after this one, so ignore
+                # this now useless listing
+                cb()
+                return
+            g
+                project_id : @project.project_id
+                path       : path
+                time       : @_sort_by_time
+                hidden     : @container.find("a[href=#hide-hidden]").is(":visible")
+                timeout    : 10
+                cb         : (err, _listing) =>
+                    if err
+                        cb(err)
+                    else
+                        listing = _listing
+                        cb()
+
+        misc.retry_until_success
+            f           : f
+            start_delay : 3000
+            max_delay   : 10000
+            factor      : 1.5
+            max_tries   : 10
+            cb          : (err) =>
                 if path != @_requested_path
                     # requested another path after this one, so ignore
                     # this now useless listing
                     cb?()
                     return
+
                 delete @_requested_path

                 clearTimeout(@_file_list_tab_spinner_timer)


Small form improvements

Small form improvements

Move instructions below label, and default tabindex to 1 (to create our own flow within a form)

--- client/source/helpers/forms.coffee
+++ client/source/helpers/forms.coffee
@@ -12,8 +12,8 @@
     label: null
     help: null
     className: 'form-group'
+  content = tag('p', {className: 'help-block'}, options.help) + content if options.help
   content = createLabel(options.label) + content if options.label
-  content += tag 'p', {className: 'help-block'}, options.help if options.help
   tag 'div', class: options.className, content

 tag = (el, attrs={}, content='', options={}) ->
@@ -38,7 +38,7 @@
     className: settings.className
     id: settings.id
     placeholder: settings.placeholder
-    tabindex: 0
+    tabindex: 1
     type: settings.type
     autocomplete: 'off'

@@ -56,7 +56,7 @@
       name: settings.slugName
       value: settings.slugValue
       placeholder: 'slug'
-      tabindex: '-1'
+      tabindex: 0
     })
     input += slug

@@ -65,11 +65,14 @@
     help: settings.help

 Handlebars.registerHelper 'textarea', (name, value, options) ->
-  settings = options.hash
+
+  settings = _.extend options.hash,
+    tabindex: 1
+    className: 'form-control'

   textarea = tag 'textarea',
     name: name
-    className: settings.className || 'form-control'
+    className: settings.className
     id: "input-#{name}"
     placeholder: settings.placeholder
     tabindex: settings.tabindex
@@ -85,11 +88,13 @@

   settings = _.defaults options.hash,
     className: 'btn btn-primary ladda-button'
+    tabindex: 1

   tag 'button',
     className: settings.className
     'data-style': 'zoom-in'
     type: 'submit'
+    tabindex: settings.tabindex
   , text

 Handlebars.registerHelper 'hidden', (name, value) ->
@@ -122,6 +127,7 @@
     className: 'form-control'
     valueKey: '_id'
     nameKey: 'name'
+    tabIndex: 1

   settings.selected = 'selected' if value


Add some documentation for the autosubmitter class

--- client/suggestion_completer.coffee
+++ client/suggestion_completer.coffee
@@ -2,8 +2,22 @@

 class SuggestionCompleter extends EventEmitter

-  # Emits 'submit' when suggestion is selected
-  # Emits 'arrowdown' and 'arrowup' when the user browse the list with the arrow keys
+  ###
+
+     Give it a qQuery @intputEl (the input(type='text') field)
+     and a @listEl (a UL) to move the suggestion elements into.
+
+     Also, options for
+      @options.suggestionField - name of the suggest-type field in ES.
+      @options.suggestionName, - what to call the response back from ES (key in hash returned as array).
+      @options.indexName - the ES index to query.
+      @options.host and @options.port - map to Elastic Search server.
+
+    Emits 'submit' when suggestion is selected
+    Emits 'arrowdown' and 'arrowup' when the user browse the list with the arrow keys
+    Emits 'enter' and 'tab' when user submits with those keys respectively.
+
+  ###

   constructor: (@inputEl, @listEl, @options={}) ->
     @host = @options.host || 'localhost'
@@ -56,18 +70,14 @@
         else
           @index++
         @select()
-        @emit('arrowdown',
-          @selectedEl
-        )
+        @emit('arrowdown', @selectedEl)
       when 38 # Arrow Up
         if @index < 0
           @index = @suggestionEls.length-1
         else
           @index--
         @select()
-        @emit('arrowup',
-          @selectedEl
-        )
+        @emit('arrowup', @selectedEl)
       when 13, 9 # Enter, tab (submits)
         if keycode == 9
           @emit('tab', @selectedEl)


Added .gsp file extension

Added .gsp file extension

--- src/languages/xml.coffee
+++ src/languages/xml.coffee
@@ -9,14 +9,14 @@
   Supported Grammars
   ###
   grammars: [
-    "SLD", "XML", "XHTML", "XSD", "XSL", "JSP"
+    "SLD", "XML", "XHTML", "XSD", "XSL", "JSP", "GSP"
   ]

   ###
   Supported extensions
   ###
   extensions: [
-    'sld', 'xml', 'xhtml', 'xsd', 'xsl', 'jsp'
+    'sld', 'xml', 'xhtml', 'xsd', 'xsl', 'jsp', 'gsp'
   ]

   defaultBeautifier: "Pretty Diff"


Add multiship info for Raider.

Add multiship info for Raider.

fixes #461

--- coffeescripts/cards-common.coffee
+++ coffeescripts/cards-common.coffee
@@ -532,6 +532,10 @@
                 [ 0, 0, 1, 0, 0, 0 ]
                 [ 0, 0, 1, 0, 0, 0 ]
             ]
+            multisection: [
+                "Raider-class Corvette (Aft)".canonicalize()
+            ]
+            canonical_name: "Raider-class Corvette".canonicalize()
         "Raider-class Corvette (Aft)":
             name: "Raider-class Corvette (Aft)"
             factions: [ "Galactic Empire" ]
@@ -552,6 +556,10 @@
                 [ 0, 0, 1, 0, 0, 0 ]
                 [ 0, 0, 1, 0, 0, 0 ]
             ]
+            multisection: [
+                "Raider-class Corvette (Fore)".canonicalize()
+            ]
+            canonical_name: "Raider-class Corvette".canonicalize()
         "YV-666":
             name: "YV-666"
             factions: [ "Scum and Villainy" ]


One more atom update

One more atom update

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,42 +1,42 @@
-'*':
-  'editor':
-    'fontFamily': 'Menlo'
-    'fontSize': 15
-    'showIndentGuide': true
-    'invisibles': {}
-  'core':
-    'ignoredNames': [
-      '.DS_Store'
-      '.bundle'
-      '.git'
+"*":
+  editor:
+    fontFamily: "Menlo"
+    fontSize: 15
+    showIndentGuide: true
+    invisibles: {}
+  core:
+    ignoredNames: [
+      ".DS_Store"
+      ".bundle"
+      ".git"
     ]
-    'disabledPackages': [
-      'metrics'
-      'vim-mode'
+    disabledPackages: [
+      "metrics"
+      "vim-mode"
     ]
-    'themes': [
-      'spacegray-dark-ui'
-      'base16-ocean-dark-spacegray'
+    themes: [
+      "spacegray-dark-ui"
+      "base16-ocean-dark-spacegray"
     ]
-    'projectHome': '/Users/justas/Projects'
-  'spell-check':
-    'grammars': [
-      'text.plain'
-      'source.gfm'
-      'text.git-commit'
+    projectHome: "/Users/justas/Projects"
+  "spell-check":
+    grammars: [
+      "text.plain"
+      "source.gfm"
+      "text.git-commit"
     ]
-  'welcome':
-    'showOnStartup': false
-  'release-notes':
-    'viewedVersion': '0.95.0'
-  'tree-view':
-    'hideIgnoredNames': true
-  'exception-reporting':
-    'userId': 'a16fb11c-80f5-993c-dac9-27e736ff535e'
-  'linter-rubocop':
-    'rubocopExecutablePath': '/Users/justas/.rbenv/shims/'
-  'linter-scss-lint':
-    'scssLintExecutablePath': '/Users/justas/.rbenv/shims/'
-  'linter': {}
-  'whitespace':
-    'ignoreWhitespaceOnCurrentLine': false
+  welcome:
+    showOnStartup: false
+  "release-notes":
+    viewedVersion: "0.95.0"
+  "tree-view":
+    hideIgnoredNames: true
+  "exception-reporting":
+    userId: "a16fb11c-80f5-993c-dac9-27e736ff535e"
+  "linter-rubocop":
+    rubocopExecutablePath: "/Users/justas/.rbenv/shims/"
+  "linter-scss-lint":
+    scssLintExecutablePath: "/Users/justas/.rbenv/shims/"
+  linter: {}
+  whitespace:
+    ignoreWhitespaceOnCurrentLine: false


Atom settings

Atom settings

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,16 +1,14 @@
 "*":
-  "exception-reporting":
-    userId: "da12a123-0b08-19c5-f3af-964885fa16c4"
-  editor:
-    showIndentGuide: true
-    fontFamily: "Menlo"
-    invisibles: {}
-    fontSize: 15
-    softWrapAtPreferredLineLength: false
-    backUpBeforeSaving: true
-    scrollPastEnd: true
-    preferredLineLength: 100
+  "atom-beautify":
+    _analyticsUserId: "798dbaa8-dc67-4fa3-aa15-738312108e7e"
   core:
+    disabledPackages: [
+      "background-tips"
+      "exception-reporting"
+      "metrics"
+      "jslint"
+    ]
+    hideGitIgnoredFiles: true
     ignoredNames: [
       ".bundle"
       ".git"
@@ -23,29 +21,33 @@
       "atom-dark-ui"
       "solarized-dark-syntax"
     ]
-    hideGitIgnoredFiles: true
-    disabledPackages: [
-      "background-tips"
-      "exception-reporting"
-      "metrics"
-      "jslint"
-    ]
+  editor:
+    backUpBeforeSaving: true
+    fontFamily: "Menlo"
+    invisibles: {}
+    preferredLineLength: 100
+    scrollPastEnd: true
+    showIndentGuide: true
+    softWrapAtPreferredLineLength: false
+  emmet: {}
+  "exception-reporting":
+    userId: "da12a123-0b08-19c5-f3af-964885fa16c4"
+  "git-log": {}
+  linter:
+    showErrorPanel: false
+  minimap:
+    plugins:
+      "highlight-selected": true
+  "release-notes":
+    viewedVersion: "0.89.0"
   "spell-check":
     grammars: [
       "text.plain"
       "source.gfm"
       "text.git-commit"
     ]
+  "status-bar": {}
+  tabs:
+    usePreviewTabs: true
   welcome:
     showOnStartup: false
-  "release-notes":
-    viewedVersion: "0.89.0"
-  tabs:
-    usePreviewTabs: true
-  "status-bar": {}
-  minimap:
-    plugins:
-      "highlight-selected": true
-  linter:
-    showErrorPanel: false
-  "git-log": {}


View: Fixed annotation.

View: Fixed annotation.

getElement method should return Element instead of Node.

--- src/lib/core/View.coffee
+++ src/lib/core/View.coffee
@@ -114,7 +114,7 @@

   ###*
     Returns the DOM element.
-    @return {Node} DOM element of this view.
+    @return {Element} DOM element of this view.
   ###
   getElement: ->
     return @element


Hide user profile when not logged in and navigating to a topic

--- core/app/backbone/controllers/channels_controller.coffee
+++ core/app/backbone/controllers/channels_controller.coffee
@@ -12,6 +12,8 @@
       @showUserProfile currentUser
       window.Channels.setUsernameAndRefreshIfNeeded currentUser.get('username') # TODO: check if this can be removed
       FactlinkApp.Sidebar.showForTopicsAndActivateCorrectItem(topic)
+    else
+      @hideUserProfile()

   showTopicFacts: (slug_title) ->
     FactlinkApp.mainRegion.close()
@@ -41,10 +43,13 @@

   showUserProfile: (user)->
     if user.is_current_user()
-      FactlinkApp.leftTopRegion.close()
+      @hideUserProfile()
     else
       userView = new UserView(model: user)
       FactlinkApp.leftTopRegion.show(userView)
+
+  hideUserProfile: ->
+    FactlinkApp.leftTopRegion.close()

   showChannelFacts: (username, channel_id) ->
     FactlinkApp.mainRegion.close()


Avoid pjaxing images

Avoid pjaxing images

--- scripts/application.coffee
+++ scripts/application.coffee
@@ -12,7 +12,9 @@

   pjax: ->
     $(document)
-      .pjax 'a', '.content', fragment: '.content', timeout: 10000
+      .pjax 'a:not([href*="images"])', '.content',
+        fragment: '.content',
+        timeout: 10000
       .on 'pjax:success', => @modules()

   nprogress: ->


necessary events parameters adjusted. maybe other events are still possibly broken

--- src/loader/loader.coffee
+++ src/loader/loader.coffee
@@ -248,13 +248,13 @@
         @startUpdate()
     onUpToDate: ->
         @log("onUpToDate", arguments)
-    onUpdateFailed: ->
+    onUpdateFailed: (event)->
         @log("onUpdateFailed", arguments)
     onUpdateCompletted: (event) ->
         @log("onUpdateCompletted", arguments)
         return true

-    onModuleBeginDownload: ->
+    onModuleBeginDownload: (module) ->
         @log("onModuleBeginDownload", arguments)
     onModuleDownloaded: ->
         @log("onModuleDownloaded", arguments)
@@ -265,7 +265,7 @@
     onTotalDownloadProgress: ->
         @log("onTotalDownloadProgress", arguments)

-    onEvaluationError: ->
+    onEvaluationError: (error) ->
         @log("onEvaluationError", arguments)
     onApplicationReady: ->
         @log("onApplicationReady", arguments)


Decrease threshold to crop less

Decrease threshold to crop less

--- components/GetBorderlessBox.coffee
+++ components/GetBorderlessBox.coffee
@@ -65,7 +65,7 @@
     ctx = canvas.getContext '2d'
     imageData = ctx.getImageData 0, 0, canvas.width, canvas.height
     data = imageData.data
-    c.params.mean = 2 unless c.params.mean
+    c.params.mean = 0.1 unless c.params.mean
     c.params.max = 10 unless c.params.max
     c.params.avg = 10 unless c.params.avg
     threshold = c.params


Check content-type in launch request

Check content-type in launch request

Signed-off-by: Manson Li <f2a598d7717cc6757bef28b84a9ab02e5efc6048@matchstick.tv>

--- lib/dial/handler/ApplicationControlHandler.coffee
+++ lib/dial/handler/ApplicationControlHandler.coffee
@@ -91,7 +91,7 @@
             Log.d "ApplicationControlHandler receive post:\n#{data}"
             if data
                 contentType = req.headers["content-type"]
-                if "application/json" isnt contentType
+                if not S(contentType).contains("application/json")
                     Log.e "content type must be application/json while posting data"
                     @_onResponse req, res, 400, null, null
                     return
@@ -149,7 +149,7 @@
                 res.end bodyContent
                 SessionManager.getInstance().sessionConnected session
             else
-                Log.e "bad post request: type is #{type}, appInfo is #{appInfo}"
+                Log.e "bad post request: type is #{type}, appInfo is #{JSON.stringify appInfo}"
                 @_onResponse req, res, 400, null, null

     _onLaunch: (appId, appInfo) ->


Set reply-to header of help messages, refs #484

--- server/controllers/help.coffee
+++ server/controllers/help.coffee
@@ -31,6 +31,7 @@

                     data =
                         to: "support@cozycloud.cc"
+                        'reply-to': email
                         subject: "Demande d'assistance depuis un Cozy"
                         content: content

@@ -40,7 +41,7 @@
                             contentType: "application/x-compressed-tar"
                         ]

-                    cozydb.api.sendMailFromUser data, (err) =>
+                    cozydb.api.sendMailFromUser data, (err) ->
                         fs.unlink path
                         return next err if err


greenskeeper exception

greenskeeper exception

--- scripts/github-hook.coffee
+++ scripts/github-hook.coffee
@@ -91,7 +91,10 @@
   formatPushes = (event) ->

     {commits, pusher, repository, compare} = event.data
-    return unless commits?.length > 0
+    return null unless commits?.length > 0
+
+    # damn greenskeeper commits be flooding my channels!
+    return null if commits[0].message.indexOf("chore(package)") != -1

     """
     [#{pusher.name}](https://github.com/#{pusher.name}) pushed #{ordinal(commits.length, 'commit')} to [#{repository.full_name}](https://github.com/#{repository.full_name})


Server: Redirected /activity/p/[0-9]+ to /Activity because they get 404.

--- server/lib/server/index.coffee
+++ server/lib/server/index.coffee
@@ -177,6 +177,9 @@
   username = req.params.username
   res.redirect 302, '/' + username

+app.get "/activity/p/?*", (req, res)->
+  res.redirect 302, '/Activity'
+
 app.get "/sitemap:sitemapName", (req, res)->
   {JSitemap}       = koding.models


Add security notes

Add security notes

--- server/security/queries.coffee
+++ server/security/queries.coffee
@@ -1,9 +1,11 @@
 share.Queries.allow
   insert: share.securityRulesWrapper (userId, query) ->
+    # TODO: don't allow to insert string (always make it "")
     unless userId
       throw new Match.Error("Operation not allowed for unauthorized users")
     true
   update: share.securityRulesWrapper (userId, query, fieldNames, modifier) ->
+    # TODO: don't allow to update string (should always be built)
     unless userId
       throw new Match.Error("Operation not allowed for unauthorized users")
     true


Update plugin spec. (Add arguments to factory)

--- src/core/plugins/nwdrome_plugin_spec.coffee
+++ src/core/plugins/nwdrome_plugin_spec.coffee
@@ -25,7 +25,7 @@
 ##
 # Renderer plugin (& common plugin) structure
 #
-JSdrome.addRendererPlugin ->
+JSdrome.addRendererPlugin (pluginConfig)->
     class RendererPlugin

         # Plugin detail setting to instance or prototype
@@ -79,7 +79,7 @@
 ##
 # Effector plugin structure
 #
-JSdrome.addEffectorPlugin ->
+JSdrome.addEffectorPlugin (pluginConfig)->
     class EffectorPlugin

         # Plugin detail setting to instance or prototype


Fixed an issue with fancy apostrophe

Fixed an issue with fancy apostrophe

--- scripts/personality.coffee
+++ scripts/personality.coffee
@@ -13,7 +13,7 @@
   adorations = ['sweetheart', 'baby', 'honey', 'darlin\'']
   emoticons_happy = [':kissing_heart:', ':grinning:', ':heart_eyes:', ':relieved:', ':stuck_out_tongue_winking_eye:']

-  robot.hear /(who|what)('s| is) bebe/i, (res) ->
+  robot.hear /(who|what)('s|’s| is) bebe/i, (res) ->
     adoration = res.random adorations
     messages = ['your personal slack bot', 'the rocker of your world', 'the spoon to your pudding', 'the destroyer of worlds', 'a fan of the cookie monster']


removed line which is no longer needed

removed line which is no longer needed

--- core/app/backbone/views/auto_completes_view.coffee
+++ core/app/backbone/views/auto_completes_view.coffee
@@ -53,7 +53,6 @@
   moveSelectionDown: ->
     nextKey = if @activeChannelKey()? then this.activeChannelKey() + 1 else 0
     this.setActiveAutoComplete(nextKey, false)
-    e.preventDefault()

   onItemAdded: (view)->
     @list.push(view)