remove old closure conversion passes

remove old closure conversion passes

--- lib/closure-conversion.coffee
+++ lib/closure-conversion.coffee
@@ -330,97 +330,6 @@

                 b.expressionStatement(b.callExpression(b.memberExpression(b.identifier("Object"), b.identifier("defineProperties")), [target, propdescs_literal]))

-#
-# each element in env is an object of the form:
-#   { exp: ...     // the AST node corresponding to this environment.  will be a function or a BlockStatement. (right now just functions)
-#     id:  ...     // the number/id of this environment
-#     decls: ..    // a set of the variable names that are declared in this environment
-#     closed: ...  // a set of the variable names that are used from this environment (i.e. the ones that need to move to the environment)
-#     parent: ...  // the parent environment object
-#   }
-#
-LocateEnv = class LocateEnv extends TransformPass
-        constructor: ->
-                super
-                @envs = new Stack
-                @env_id = 0
-
-        visitFunction: (n) ->
-                current_env = @envs.top if @envs.depth > 0
-                new_env = { exp: n, id: @env_id, decls: (if n.ejs_decls? then n.ejs_decls else new Set), closed: new Set, parent: current_env }
-                @env_id += 1
-                n.ejs_env = new_env
-                @envs.push new_env
-                # don't visit the parameters for the same reason we don't visit the id's of variable declarators below:
-                # we don't want a function to look like:  function foo (%env_1.x) { }
-                # instead of                              function foo (x) { }
-                n.body = @visit n.body
-                @envs.pop()
-                n
-
-        visitBlock: (n) ->
-                return super(n) if n.no_ejs_env
-
-                current_env = @envs.top if @envs.depth > 0
-                new_env = { exp: n, id: @env_id, decls: (if n.ejs_decls? then n.ejs_decls else new Set), closed: new Set, parent: current_env }
-                @env_id += 1
-                n.ejs_env = new_env
-                @envs.push new_env
-                super(n)
-                @envs.pop()
-                n
-
-        visitVariableDeclarator: (n) ->
-                # don't visit the id, as that will cause us to mark it ejs_substitute = true, and we'll end up with things like:
-                #   var %env_1.x = blah
-                # instead of what we want:
-                #   var x = blah
-                n.init = @visit n.init
-                n
-
-        visitProperty: (n) ->
-                if n.key.type is ComputedPropertyKey
-                        n.key = @visit n.key
-                n.value = @visit n.value
-                n
-
-        visitIdentifier: (n) ->
-                # find the environment in the env-stack that includes this variable's decl.  add it to the env's .closed set.
-                current_env = @envs.top
-                env = current_env
-
-                # if the current environment declares that identifier, nothing to do.
-                return n if env.decls.has n.name
-
-                closed_over = false
-                # look up our environment stack for the decl for it.
-                env = env.parent
-                intervening_function = false
-                while env?
-                        if env.decls?.has n.name
-                                closed_over = intervening_function
-                                env = null
-                        else
-                                if env.exp.type isnt BlockStatement # if it's a function
-                                        intervening_function = true
-                                env = env.parent
-
-
-                # if we found it higher on the function stack, we need to walk back up the stack forcing environments along the way, and make
-                # sure the frame that declares it knows that something down the stack closes over it.
-                if closed_over
-                        env = current_env.parent
-                        while env?
-                                if env.decls?.has n.name
-                                        env.closed.add n.name
-                                        env = null
-                                else
-                                        env.nested_requires_env = true
-                                        env = env.parent
-
-                        n.ejs_substitute = true
-                n
-
 # this should move to echo-desugar.coffee

 class HoistFuncDecls extends TransformPass
@@ -751,478 +660,7 @@
                         n.body.body.unshift m.prepend
                 n

-
-# this class really doesn't behave like a normal TreeVisitor, as it modifies the tree in-place.
-# XXX reformulate this as a TreeVisitor subclass.
-class ComputeFree extends TransformPass
-        constructor: ->
-                super
-                @call_free = @free.bind @
-                @setUnion = Set.union
-
-        visit: (n) ->
-                @free n
-                n
-
-        decl_names: (arr) ->
-                result = []
-                for n in arr
-                        if n.declarations?
-                                result = result.concat (decl.id.name for decl in n.declarations)
-                        else if n.id?
-                                result.push n.id.name
-                new Set result
-
-        id_names: (arr) ->
-                new Set arr.map ((id) -> id.name)
-
-        collect_decls: (body) ->
-                statement for statement in body when statement.type is VariableDeclaration or statement.type is FunctionDeclaration
-
-        free_blocklike: (exp,body) ->
-                if body?
-                        decls = @decl_names @collect_decls body
-                        uses = @setUnion.apply null, body.map @call_free
-                else
-                        decls = []
-                        uses = new Set()
-                exp.ejs_decls = decls
-                exp.ejs_free_vars = uses.subtract decls
-                exp.ejs_free_vars
-
-        get_decls = (exp) -> if not exp? then null else exp.ejs_decls
-
-        # TODO: move this into the @visit method
-        free: (exp) ->
-                return new Set if not exp?
-
-                # define the properties we'll be filling in below, so that we can make them non-enumerable
-                Object.defineProperty exp, "ejs_decls",     { value: undefined, writable: true, configurable: true }
-                Object.defineProperty exp, "ejs_free_vars", { value: undefined, writable: true, configurable: true }
-
-                switch exp.type
-                        when Program
-                                decls = @decl_names @collect_decls exp.body
-                                uses = @setUnion.apply null, exp.body.map @call_free
-                                exp.ejs_decls = decls
-                                exp.ejs_free_vars = uses.subtract decls
-                        when FunctionDeclaration
-                                # this should only happen for the toplevel function we create to wrap the source file
-                                param_names = @id_names exp.params
-                                param_names.add exp.rest.name if exp.rest?
-                                exp.ejs_free_vars = @free(exp.body).subtract param_names
-                                exp.ejs_decls = exp.body.ejs_decls.union param_names
-                        when FunctionExpression
-                                param_names = @id_names exp.params
-                                param_names.add exp.rest.name if exp.rest?
-                                exp.ejs_free_vars = @free(exp.body).subtract param_names
-                                exp.ejs_decls = param_names.union exp.body.ejs_decls
-                        when ArrowFunctionExpression
-                                param_names = @id_names exp.params
-                                param_names.add exp.rest.name if exp.rest?
-                                exp.ejs_free_vars = @free(exp.body).subtract param_names
-                                exp.ejs_decls = param_names.union exp.body.ejs_decls
-                        when LabeledStatement      then exp.ejs_free_vars = @free exp.body
-                        when BlockStatement        then exp.ejs_free_vars = @free_blocklike exp, exp.body
-                        when TryStatement          then exp.ejs_free_vars = @setUnion.apply null, [@free(exp.block)].concat exp.handlers.map @call_free
-                        when CatchClause
-                                param_set = if exp.param?.name? then new Set [exp.param.name] else new Set
-                                exp.ejs_free_vars = @free(exp.body).subtract param_set
-                                exp.ejs_decls = exp.body.ejs_decls.union param_set
-                        when VariableDeclaration   then exp.ejs_free_vars = @setUnion.apply null, exp.declarations.map @call_free
-                        when VariableDeclarator    then exp.ejs_free_vars = @free exp.init
-                        when ExpressionStatement   then exp.ejs_free_vars = @free exp.expression
-                        when Identifier            then exp.ejs_free_vars = new Set [exp.name]
-                        when ThrowStatement        then exp.ejs_free_vars = @free exp.argument
-                        when ForStatement
-                                decls = null
-                                if exp.init?.type is VariableDeclaration
-                                        decls = @decl_names [exp.init]
-
-                                uses = @setUnion.call null, @free(exp.init), @free(exp.test), @free(exp.update), @free(exp.body)
-                                exp.ejs_decls = decls
-                                exp.ejs_free_vars = uses.subtract decls
-                        when ForInStatement        then exp.ejs_free_vars = @setUnion.call null, @free(exp.left), @free(exp.right), @free(exp.body)
-                        when ForOfStatement        then exp.ejs_free_vars = @setUnion.call null, @free(exp.left), @free(exp.right), @free(exp.body)
-                        when WhileStatement        then exp.ejs_free_vars = @setUnion.call null, @free(exp.test), @free(exp.body)
-                        when DoWhileStatement      then exp.ejs_free_vars = @setUnion.call null, @free(exp.test), @free(exp.body)
-                        when SwitchStatement       then exp.ejs_free_vars = @setUnion.apply null, [@free exp.discriminant].concat exp.cases.map @call_free
-                        when SwitchCase            then exp.ejs_free_vars = @free_blocklike exp, exp.consequent
-                        when EmptyStatement        then exp.ejs_free_vars = new Set
-                        when BreakStatement        then exp.ejs_free_vars = new Set
-                        when ContinueStatement     then exp.ejs_free_vars = new Set
-                        when SpreadElement         then exp.ejs_free_vars = @free exp.argument
-                        when UpdateExpression      then exp.ejs_free_vars = @free exp.argument
-                        when ReturnStatement       then exp.ejs_free_vars = @free exp.argument
-                        when UnaryExpression       then exp.ejs_free_vars = @free exp.argument
-                        when BinaryExpression      then exp.ejs_free_vars = @free(exp.left).union @free exp.right
-                        when LogicalExpression     then exp.ejs_free_vars = @free(exp.left).union @free exp.right
-                        when MemberExpression      then exp.ejs_free_vars = @free(exp.object) # we don't traverse into the property
-                        when CallExpression        then exp.ejs_free_vars = @setUnion.apply null, [@free exp.callee].concat exp.arguments.map @call_free
-                        when NewExpression         then exp.ejs_free_vars = @setUnion.apply null, [@free exp.callee].concat exp.arguments.map @call_free
-                        when SequenceExpression    then exp.ejs_free_vars = @setUnion.apply null, exp.expressions.map @call_free
-                        when ConditionalExpression then exp.ejs_free_vars = @setUnion.call null, @free(exp.test), @free(exp.consequent), @free(exp.alternate)
-                        when TaggedTemplateExpression then exp.ejs_free_vars = @free exp.quasi
-                        when TemplateLiteral       then exp.ejs_free_vars = @setUnion.apply null, exp.expressions.map @call_free
-                        when Literal               then exp.ejs_free_vars = new Set
-                        when ThisExpression        then exp.ejs_free_vars = new Set
-                        when ComputedPropertyKey   then exp.ejs_free_vars = @free exp.expression
-                        when Property
-                                exp.ejs_free_vars = @free exp.value
-                                if exp.key.type is ComputedPropertyKey
-                                        # we only do this when the key is computed, or else identifiers show up as free
-                                        exp.ejs_free_vars = exp.ejs_free_vars.union @free exp.key
-                                exp.ejs_free_vars
-                        when ObjectExpression
-                                exp.ejs_free_vars = if exp.properties.length is 0 then (new Set) else @setUnion.apply null, (@free p for p in exp.properties)
-                        when ArrayExpression
-                                exp.ejs_free_vars = if exp.elements.length is 0 then (new Set) else @setUnion.apply null, exp.elements.map @call_free
-                        when IfStatement           then exp.ejs_free_vars = @setUnion.call null, @free(exp.test), @free(exp.consequent), @free(exp.alternate)
-                        when AssignmentExpression  then exp.ejs_free_vars = @free(exp.left).union @free exp.right
-                        when ModuleDeclaration     then exp.ejs_free_vars = @free exp.body
-                        when ExportDeclaration
-                                exp.ejs_free_vars = @free exp.declaration
-                                exp.ejs_decls = exp.declaration.ejs_decls
-                        when ImportDeclaration
-                                exp.ejs_decls = new Set exp.specifiers.map ((specifier) -> specifier.id.name)
-                                # no free vars in an ImportDeclaration
-                                exp.ejs_free_vars = new Set
-
-                        else throw "Internal error: unhandled node '#{JSON.stringify exp}' in free()"
-                exp.ejs_free_vars
-
-
-
-# 1) allocates the environment at the start of the n
-# 2) adds mappings for all .closed variables
-class SubstituteVariables extends TransformPass
-        constructor: ->
-                super
-                @function_stack = new Stack
-                @mappings = new Stack
-
-        currentMapping: -> if @mappings.depth > 0 then @mappings.top else Object.create null
-
-        visitIdentifier: (n) ->
-                if hasOwnProperty.call @currentMapping(), n.name
-                        return @currentMapping()[n.name]
-                n
-
-        visitFor: (n) ->
-                # for loops complicate things.
-                # if any of the variables declared in n.init are closed over
-                # we promote all of them outside of n.init.
-
-                @skipExpressionStatement = true
-                init = @visit n.init
-                @skipExpressionStatement = false
-                n.test = @visit n.test
-                n.update = @visit n.update
-                n.body = @visit n.body
-                if Array.isArray init
-                        n.init = null
-                        return b.blockStatement(init.concat([n]))
-
-                n.init = init
-                n
-
-        visitForIn: (n) ->
-                # for-in loops complicate things.
-
-                left = @visit n.left
-                n.right = @visit n.right
-                n.body = @visit n.body
-                if Array.isArray left
-                        console.log "whu?"
-                        n.left = b.identifier(left[0].declarations[0].id.name)
-                        return b.blockStatement(left.concat([n]))
-
-                n.left = left
-                n
-
-        visitVariableDeclaration: (n) ->
-                # here we do some magic depending on whether or not
-                # variables are closed over (i.e. pushed into the
-                # environment).
-                #
-                # 1. for variables that are closed over that aren't
-                #    initialized (that is, they're implicitly
-                #    'undefined'), we just remove their declaration
-                #    entirely.  it's already been converted to a slot
-                #    everywhere else, and env slots are explicitly
-                #    initialized to undefined by the runtime.
-                #
-                # 2. for variables that are closed over that *are*
-                #    initialized, we splice them into the list and
-                #    split the VariableDeclaration node into two, so
-                #    if 'y' is closed over in the following input:
-                #
-                #    let x = 2, y = x * 2, z = 10;
-                #
-                #    we'll end up with this in the output:
-                #
-                #    let x = 2;
-                #    %slot(%env, 1, 'y') = x * 2;
-                #    let z = 10;
-                #
-                decls = n.declarations
-
-                rv = []
-
-                new_declarations = []
-
-                # we loop until we find a variable that's closed over *and* has an initializer.
-                for decl in decls
-                        decl.init = @visit decl.init
-
-                        closed_over = hasOwnProperty.call @currentMapping(), decl.id.name
-                        if closed_over
-                                # for variables that are closed over but undefined, we skip them (thereby removing them from the list of decls)
-
-                                if decl.init? # FIXME: we should also check for an explicit 'undefined' here
-
-                                        # push the current set of new_declarations if there are any
-                                        if new_declarations.length > 0
-                                                rv.push b.variableDeclaration(n.kind, new_declarations)
-
-                                        # splice in this assignment
-                                        rv.push b.expressionStatement(b.assignmentExpression(@currentMapping()[decl.id.name], "=", decl.init))
-
-                                        # then re-init the new_declarations array
-                                        new_declarations = []
-
-                        else
-                                # for variables that aren't closed over, we just add them to the currect decl list.
-                                new_declarations.push decl
-
-
-                # push the last set of new_declarations if there were any
-                if new_declarations.length > 0
-                        rv.push b.variableDeclaration(n.kind, new_declarations)
-
-                if rv.length is 0
-                        rv = b.emptyStatement()
-                rv
-
-        visitProperty: (n) ->
-                if n.key.type is ComputedPropertyKey
-                        n.key = @visit n.key
-                n.value = @visit n.value
-                n
-
-        visitBlock: (n) ->
-                return super(n) if not n.ejs_env
-
-                this_env_id = b.identifier("%env_#{n.ejs_env.id}")
-                if n.ejs_env.parent?
-                        parent_env_name = "%env_#{n.ejs_env.parent.id}"
-
-                env_prepends = []
-                new_mapping = shallow_copy_object @currentMapping()
-
-                if n.ejs_env.closed.empty() and not n.ejs_env.nested_requires_env
-                        env_prepends.push b.letDeclaration(this_env_id, b.null())
-                else
-                        # insert environment creation (at the start of the block)
-                        env_prepends.push b.letDeclaration(this_env_id, intrinsic makeClosureEnv_id, [b.literal n.ejs_env.closed.size() + if n.ejs_env.parent? then 1 else 0])
-
-                        n.ejs_env.slot_mapping = Object.create null
-                        i = 0
-                        if n.ejs_env.parent?
-                                n.ejs_env.slot_mapping[parent_env_name] = i
-                                i += 1
-                        n.ejs_env.closed.map (el) ->
-                                n.ejs_env.slot_mapping[el] = i
-                                i += 1
-
-
-                        if n.ejs_env.parent?
-                                parent_env_slot = n.ejs_env.slot_mapping[parent_env_name]
-                                env_prepends.push b.expressionStatement(intrinsic setSlot_id, [this_env_id, b.literal(parent_env_slot), b.literal(parent_env_name), b.identifier(parent_env_name) ]);
-
-                        # XXX here's where function handling pushes closed over parameters.  i'm guessing we need special logic for incoming environment slots for loop variables?
-
-                        new_mapping["%slot_mapping"] = n.ejs_env.slot_mapping
-
-                        flatten_memberexp = (exp, mapping) ->
-                                if exp.type isnt CallExpression
-                                        [b.literal(mapping[exp.name])]
-                                else
-                                        flatten_memberexp(exp.arguments[0], mapping).concat [exp.arguments[1]]
-
-                        prepend_environment = (exps) ->
-                                obj = this_env_id
-                                for prop in exps
-                                        obj = intrinsic(slot_id, [obj, prop])
-                                obj
-
-                        # if there are existing mappings prepend "%env." (a MemberExpression) to them
-                        for mapped of new_mapping
-                                val = new_mapping[mapped]
-                                if mapped isnt "%slot_mapping"
-                                        new_mapping[mapped] = prepend_environment(flatten_memberexp(val, n.ejs_env.slot_mapping))
-
-                        # and add mappings for all variables in .closed from "x" to "%env.x"
-
-                        new_mapping["%env"] = this_env_id
-                        n.ejs_env.closed.map (sym) ->
-                                new_mapping[sym] = intrinsic slot_id, [this_env_id, b.literal(n.ejs_env.slot_mapping[sym]), b.literal(sym)]
-
-                # remove all mappings for variables declared in this block
-                if n.ejs_decls?
-                        new_mapping = reject new_mapping, (sym) -> (n.ejs_decls.has sym) and not (n.ejs_env.closed.has sym)
-
-                @mappings.push new_mapping
-                super(n)
-                if env_prepends.length > 0
-                        n.body = env_prepends.concat n.body
-                @mappings.pop()
-                n
-
-        visitFunctionBody: (n) ->
-                n.scratch_size = 0
-
-                # we use this instead of calling super in visitFunction because we don't want to visit parameters
-                # during this pass, or they'll be substituted with an %env.
-
-                @function_stack.push n
-                n.body = @visit n.body
-                @function_stack.pop()
-
-                n
-
-        visitFunction: (n) ->
-            try
-                this_env_id = b.identifier("%env_#{n.ejs_env.id}")
-                if n.ejs_env.parent?
-                        parent_env_name = "%env_#{n.ejs_env.parent.id}"
-
-                env_prepends = []
-                new_mapping = shallow_copy_object @currentMapping()
-                if n.ejs_env.closed.empty() and not n.ejs_env.nested_requires_env
-                        env_prepends.push b.letDeclaration(this_env_id, b.null())
-                else
-                        # insert environment creation (at the start of the function body)
-                        env_prepends.push b.letDeclaration(this_env_id, intrinsic makeClosureEnv_id, [b.literal n.ejs_env.closed.size() + if n.ejs_env.parent? then 1 else 0])
-
-                        n.ejs_env.slot_mapping = Object.create null
-                        i = 0
-                        if n.ejs_env.parent?
-                                n.ejs_env.slot_mapping[parent_env_name] = i
-                                i += 1
-                        n.ejs_env.closed.map (el) ->
-                                n.ejs_env.slot_mapping[el] = i
-                                i += 1
-
-
-                        if n.ejs_env.parent?
-                                parent_env_slot = n.ejs_env.slot_mapping[parent_env_name]
-                                env_prepends.push b.expressionStatement(intrinsic setSlot_id, [this_env_id, b.literal(parent_env_slot), b.literal(parent_env_name), b.identifier(parent_env_name) ]);
-
-
-                        # we need to push assignments of any closed over parameters into the environment at this point
-                        for param in n.params
-                                if n.ejs_env.closed.has param.name
-                                        env_prepends.push b.expressionStatement(intrinsic setSlot_id, [ this_env_id, b.literal(n.ejs_env.slot_mapping[param.name]), b.literal(param.name), b.identifier(param.name) ])
-
-                        new_mapping["%slot_mapping"] = n.ejs_env.slot_mapping
-
-                        flatten_memberexp = (exp, mapping) ->
-                                if exp.type isnt CallExpression
-                                        [b.literal(mapping[exp.name])]
-                                else
-                                        flatten_memberexp(exp.arguments[0], mapping).concat [exp.arguments[1]]
-
-                        prepend_environment = (exps) ->
-                                obj = this_env_id
-                                for prop in exps
-                                        obj = intrinsic(slot_id, [obj, prop])
-                                obj
-
-                        # if there are existing mappings prepend "%env." (a MemberExpression) to them
-                        for mapped of new_mapping
-                                val = new_mapping[mapped]
-                                if mapped isnt "%slot_mapping"
-                                        new_mapping[mapped] = prepend_environment(flatten_memberexp(val, n.ejs_env.slot_mapping))
-
-                        # and add mappings for all variables in .closed from "x" to "%env.x"
-
-                        new_mapping["%env"] = this_env_id
-                        n.ejs_env.closed.map (sym) ->
-                                new_mapping[sym] = intrinsic slot_id, [this_env_id, b.literal(n.ejs_env.slot_mapping[sym]), b.literal(sym)]
-
-                # remove all mappings for variables declared in this function
-                if n.ejs_decls?
-                        new_mapping = reject new_mapping, (sym) -> (n.ejs_decls.has sym) and not (n.ejs_env.closed.has sym)
-
-                @mappings.push new_mapping
-                @visitFunctionBody n
-                if env_prepends.length > 0
-                        n.body.body = env_prepends.concat n.body.body
-                @mappings.pop()
-
-                # convert function expressions to an explicit closure creation, so:
-                #
-                #    function X () { ...body... }
-                #
-                # replace inline with:
-                #
-                #    makeClosure(%current_env, "X", function X () { ...body... })
-
-                if not n.toplevel
-                        if n.type is FunctionDeclaration
-                                throw "there should be no FunctionDeclarations at this point"
-                        else # n.type is FunctionExpression
-                                intrinsic_args = []
-                                intrinsic_args.push(if n.ejs_env.parent? then b.identifier(parent_env_name) else b.null())
-
-                                if n.id?
-                                        intrinsic_id = makeClosure_id
-                                        if n.id.type is Identifier
-                                                intrinsic_args.push(b.literal(n.id.name))
-                                        else
-                                                intrinsic_args.push(b.literal(escodegen.generate n.id))
-                                else
-                                        intrinsic_id = makeAnonClosure_id
-
-                                intrinsic_args.push(n)
-
-                                return intrinsic intrinsic_id, intrinsic_args
-                n
-            catch e
-                console.warn "exception: " + e
-                #console.warn "compiling the following code:"
-                #console.warn escodegen.generate n
-                throw e
-
-        visitCallExpression: (n) ->
-                n = super
-
-                # replace calls of the form:
-                #   X (arg1, arg2, ...)
-                #
-                # with
-                #   invokeClosure(X, %this, %argCount, arg1, arg2, ...);
-
-                return n if is_intrinsic(n)
-                @function_stack.top.scratch_size = Math.max @function_stack.top.scratch_size, n.arguments.length
-                intrinsic invokeClosure_id, [n.callee].concat n.arguments
-
-        visitNewExpression: (n) ->
-                super
-
-                # replace calls of the form:
-                #   new X (arg1, arg2, ...)
-                #
-                # with
-                #   invokeClosure(X, %this, %argCount, arg1, arg2, ...);
-
-                @function_stack.top.scratch_size = Math.max @function_stack.top.scratch_size, n.arguments.length
-
-                rv = intrinsic invokeClosure_id, [n.callee].concat n.arguments
-                rv.type = NewExpression
-                rv
-
+
 #
 #   This pass walks the tree and moves all function expressions to the toplevel.
 #
@@ -1298,127 +736,6 @@
                 if rhs.type is FunctionExpression and not rhs.id?.name
                         rhs.displayName = escodegen.generate lhs
                 n
-
-class MarkLocalAndGlobalVariables extends TransformPass
-        constructor: (options, @filename) ->
-                super
-                # initialize the scope stack with the global (empty) scope
-                @scope_stack = new Stack new Map
-
-        findIdentifierInScope: (ident) ->
-                for scope in @scope_stack.stack
-                        return true if scope.has(ident.name)
-                # at this point it's going to be a global reference.
-                # make sure the identifier is one of our globals
-                if hasOwnProperty.call runtime_globals, ident.name
-                        return false
-
-                if @options.warn_on_undeclared
-                        reportWarning("undeclared identifier `#{ident.name}'", @filename, ident.loc)
-                else
-                        reportError(ReferenceError, "undeclared identifier `#{ident.name}'", @filename, ident.loc)
-                false
-
-        intrinsicForIdentifier: (id) ->
-                is_local = @findIdentifierInScope id
-                if is_local then getLocal_id else getGlobal_id
-
-        visitWithScope: (scope, children) ->
-                @scope_stack.push scope
-                if Array.isArray children
-                        rv = (@visit child for child in children)
-                else
-                        rv = @visit children
-                @scope_stack.pop()
-                rv
-
-        visitVariableDeclarator: (n) ->
-                @scope_stack.top.set(n.id.name, true)
-                n
-
-        visitImportSpecifier: (n) ->
-                @scope_stack.top.set(n.id.name, true)
-                n
-
-        visitObjectExpression: (n) ->
-                for property in n.properties
-                        property.value = @visit property.value
-                n
-
-        visitAssignmentExpression: (n) ->
-                lhs = n.left
-                visited_rhs = @visit n.right
-
-                if is_intrinsic lhs, "%slot"
-                        intrinsic setSlot_id, [lhs.arguments[0], lhs.arguments[1], visited_rhs], lhs.loc
-                else if lhs.type is Identifier
-                        if @findIdentifierInScope lhs
-                                intrinsic setLocal_id, [lhs, visited_rhs], lhs.loc
-                        else
-                                intrinsic setGlobal_id, [lhs, visited_rhs], lhs.loc
-                else
-                        n.left = @visit n.left
-                        n.right = visited_rhs
-                        n
-
-        visitBlock: (n) ->
-                n.body = @visitWithScope(new Map(), n.body)
-                n
-
-        visitCallExpression: (n) ->
-                # at this point there shouldn't be call expressions
-                # for anything other than intrinsics, so we leave
-                # callee alone and just iterate over the args.  we
-                # skip the first one since that is guaranteed to be an
-                # identifier that we don't want rewrapped, or an
-                # intrinsic already wrapping the identifier.
-
-                if n.arguments.length > 0
-                        if n.arguments[0].type is Identifier
-                                @findIdentifierInScope n.arguments[0]
-                                new_args = @visit n.arguments.slice 1
-                                new_args.unshift n.arguments[0]
-                        else
-                                new_args = @visit n.arguments
-                        n.arguments = new_args
-                n
-
-        visitNewExpression: (n) ->
-                # at this point there shouldn't be call expressions
-                # for anything other than intrinsics, so we leave
-                # callee alone and just iterate over the args.  we
-                # skip the first one since that is guaranteed to be an
-                # identifier that we don't want rewrapped, or an
-                # intrinsic already wrapping the identifier.
-
-                if n.arguments[0].type is Identifier
-                        @findIdentifierInScope n.arguments[0]
-                new_args = @visit n.arguments.slice 1
-                new_args.unshift n.arguments[0]
-                n.arguments = new_args
-                n
-
-        visitFunction: (n) ->
-                new_scope = new Map
-                new_scope.set(p.name, true) for p in n.params
-                new_scope.set("arguments", true)
-                new_body = @visitWithScope new_scope, n.body
-                n.body = new_body
-                n
-
-        visitLabeledStatement: (n) ->
-                n.body  = @visit n.body
-                n
-
-        visitCatchClause: (n) ->
-                new_scope = new Map
-                new_scope.set(n.param.name, true)
-                n.guard = @visit n.guard
-                n.body = @visitWithScope new_scope, n.body
-                n
-
-        visitIdentifier: (n) ->
-                intrinsic @intrinsicForIdentifier(n), [n]

 #
 # special pass to inline some common idioms dealing with IIFEs


Remove clickable target line legend

Remove clickable target line legend

Removes the clickable target line legend item on the dynamic demand
chart. The total demand line can no longer be toggled off, but this
doesn't seem like a major loss. A more complete solution would be to
port this chart to D3v6, with our new legend system, but likely it's
worth is with a refresh coming soon.

Closes #3510

--- app/assets/javascripts/d3/dynamic_demand_curve.coffee
+++ app/assets/javascripts/d3/dynamic_demand_curve.coffee
@@ -108,14 +108,6 @@

       legendSeries

-    legend_click: (e) ->
-      serie = @series.find((a) -> (a.id == e.attributes.id))
-
-      if serie.attributes.is_target_line
-        serie.set('skip', !serie.get('skip'))
-
-        @refresh()
-
     initialDraw: (xScale, yScale, area, line) ->
       @svg.selectAll('g.serie')
         .data(@stackedData)


nicer player names

nicer player names

--- app/assets/javascripts/views/name_input_screen.coffee
+++ app/assets/javascripts/views/name_input_screen.coffee
@@ -4,7 +4,10 @@

   constructor: ->
     super
-    @on "gamepadButtonPressed", -> gameView.goto(new GameInstructionsScreen)
+    @on "gamepadButtonPressed", ->
+      Controllers.stopPollingPlayers = true
+      Controllers.stopPollingStates = true
+      gameView.goto(new GameInstructionsScreen)

     @categories = new Categories()
     @categories.fetch().then @renderCategories
@@ -19,14 +22,14 @@
     '

     button = @$el.append('<button>Start!</button>')
-    button.on 'click', => gameView.goto(new GameInstructionsScreen)
+    button.on 'click', => @trigger "gamepadButtonPressed"

   addPlayer: (index, gamepad) =>
     player = gameView.gameState.players.get index
     return if player
     player = new Player id: index
     gameView.gameState.players.add player
-    li = "
#{player.get('name')} (player id: #{index})
"
+    li = "
Player #{index}
"
     $('.players').append li

     Controllers.startPollingStates @checkIfGameButtonPressed
@@ -36,8 +39,6 @@
     return unless player

     if state.buttons[16] is 1
-      Controllers.stopPollingPlayers = true
-      Controllers.stopPollingStates = true
       @trigger "gamepadButtonPressed"

   renderCategories: =>


Cloud config default SR. (Fix #548)

Cloud config default SR. (Fix #548)

--- app/modules/new-vm/index.coffee
+++ app/modules/new-vm/index.coffee
@@ -176,9 +176,6 @@
         VDI.id = VDI_id++
         VDI.size = bytesToSizeFilter VDI.size
         VDI.SR or= default_SR
-        # store the first SR for later use (e.g: CloudConfig)
-        if VDI.id == 0
-          $scope.firstSR = VDI.SR or= default_SR
       # if the template is labeled CoreOS
       # we'll use config drive setup
       if template.name_label == 'CoreOS'
@@ -203,6 +200,10 @@
       # Does not edit the displayed data directly.
       VDIs = cloneDeep VDIs
       for VDI, index in VDIs
+        # store the first VDI's SR for later use (e.g: CloudConfig)
+        if VDI.id == 0
+          $scope.firstSR = VDI.SR or default_SR
+
         # Removes the dummy identifier used for AngularJS.
         delete VDI.id


Renamed user_group to selected_user_group_id

--- app/pages/project/classify.cjsx
+++ app/pages/project/classify.cjsx
@@ -157,7 +157,7 @@
           subjects: [subject.id]

       if @state.validUserGroup
-        classification.update({ 'metadata.user_group': @props.location.query.group })
+        classification.update({ 'metadata.selected_user_group_id': @props.location.query.group })

       # If the user hasn't interacted with a classification resource before,
       # we won't know how to resolve its links, so attach these manually.


Client: Activity: Deleted unused component

--- client/activity/lib/components/threadheader/index.coffee
+++ client/activity/lib/components/threadheader/index.coffee
@@ -1,166 +0,0 @@
-kd                   = require 'kd'
-React                = require 'kd-react'
-classnames           = require 'classnames'
-Encoder              = require 'htmlencode'
-KeyboardKeys         = require 'app/constants/keyboardKeys'
-ActivityFlux         = require 'activity/flux'
-ButtonWithMenu       = require 'app/components/buttonwithmenu'
-StartVideoCallLink   = require 'activity/components/common/startvideocalllink'
-VideoComingSoonModal = require 'activity/components/videocomingsoonmodal'
-ChannelLabel         = require 'activity/components/channellabel'
-isGroupChannel       = require 'app/util/isgroupchannel'
-
-
-module.exports = class ThreadHeader extends React.Component
-
-  @defaultProps =
-    thread                     : null
-    onInvitePeople             : kd.noop
-    onUpdatePurpose            : kd.noop
-    onLeaveChannel             : kd.noop
-    onShowNotificationSettings : kd.noop
-
-
-  constructor: (props) ->
-
-    super props
-
-    @state =
-      editingPurpose : no
-      isModalOpen    : no
-      thread         : @props.thread
-
-
-  channel: (keyPath...) -> @state.thread.getIn ['channel'].concat keyPath
-
-
-  componentWillReceiveProps: (nextProps) ->
-
-    return  unless @props.thread and nextProps.thread
-
-    nextState = { thread: nextProps.thread }
-
-    id = @props.thread.get 'channelId'
-    nextId = nextProps.thread.get 'channelId'
-
-    # make sure that editing purpose is set back to no if channel is changing.
-    nextState['editingPurpose'] = no  if id isnt nextId
-
-    @setState nextState
-
-
-  getMenuItems: ->
-
-    channel = @state.thread.get('channel').toJS()
-    result  = [
-      title   : 'Invite people'
-      key     : 'invitepeople'
-      onClick : @props.onInvitePeople
-    ,
-      title   : 'Update purpose'
-      key     : 'updatepurpose'
-      onClick : @bound 'onUpdatePurpose'
-    ]
-
-    # if channel isn't a team channel,
-    # add "Leave channel" at the 2nd position of the list
-    unless isGroupChannel channel
-      result.splice 1, 0, {
-        title   : 'Leave channel'
-        key     : 'leavechannel'
-        onClick : @props.onLeaveChannel
-      }
-
-    unless channel.typeConstant is 'privatemessage'
-      result.push {
-        title   : 'Notification settings'
-        key     : 'notificationsettings'
-        onClick : @props.onShowNotificationSettings
-      }
-
-    return result
-
-
-  onUpdatePurpose: ->
-
-    @setState { editingPurpose: yes }, =>
-      kd.utils.moveCaretToEnd @refs.purposeInput
-
-
-  onVideoStart: -> @setState { isModalOpen: yes }
-
-
-  onModalClose: -> @setState { isModalOpen: no }
-
-
-  getPurposeAreaClassNames: ->
-    classnames
-      'ChannelThreadPane-purposeWrapper': yes
-      'editing': @state.editingPurpose
-
-
-  handlePurposeInputChange: (newValue) ->
-
-    thread = @state.thread
-
-    unless @channel '_originalPurpose'
-      thread = thread.setIn ['channel', '_originalPurpose'], @channel 'purpose'
-
-    thread = thread.setIn ['channel', 'purpose'], newValue
-    @setState { thread }
-
-
-  onKeyDown: (event) ->
-
-    { ENTER, ESC } = KeyboardKeys
-    thread         = @state.channelThread
-
-    if event.which is ESC
-      _originalPurpose = @channel '_originalPurpose'
-      purpose = _originalPurpose or @channel 'purpose'
-      thread  = thread.setIn ['channel', 'purpose'], purpose
-      @setState { channelThread: thread }
-      return @setState { editingPurpose: no }
-
-    if event.which is ENTER
-      id = @channel 'id'
-      purpose = @channel('purpose').trim()
-      { updateChannel } = ActivityFlux.actions.channel
-
-      updateChannel({ id, purpose }).then => @setState { editingPurpose: no }
-
-
-  renderPurposeArea: ->
-
-    return  unless @props.thread
-
-    purpose = Encoder.htmlDecode @channel 'purpose'
-
-    valueLink =
-      value         : purpose
-      requestChange : @bound 'handlePurposeInputChange'
-
-

-      {purpose}
-      <input
-        ref='purposeInput'
-        type='text'
-        valueLink={valueLink}
-        onKeyDown={@bound 'onKeyDown'} />
-

-
-
-  render: ->
-    return null  unless @state.thread
-
-

-      <ChannelLabel channel={@state.thread.get 'channel'} />
-      <ButtonWithMenu
-        listClass='ChannelThreadPane-menuItems'
-        items={@getMenuItems()} />
-      {@renderPurposeArea()}
-      <StartVideoCallLink onStart={@bound 'onVideoStart'}/>
-      <VideoComingSoonModal
-        onClose={@bound 'onModalClose'}
-        isOpen={@state.isModalOpen}/>
-


Fix unread comment count tooltip rendering

JIRA: FOR-434

--- common/static/coffee/src/discussion/views/discussion_thread_list_view.coffee
+++ common/static/coffee/src/discussion/views/discussion_thread_list_view.coffee
@@ -174,12 +174,14 @@
         content.addClass("resolved")
       if thread.get('read')
         content.addClass("read")
-      if thread.get('unread_comments_count') > 0
+      unreadCount = thread.get('unread_comments_count')
+      if unreadCount > 0
         content.find('.comments-count').addClass("unread").attr(
           "data-tooltip",
           interpolate(
-            ngettext('%(unread_count)s new comment', '%(unread_count)s new comments', {'unread_count': thread.get('unread_comments_count')}),
-            [thread.get('unread_comments_count')]
+            ngettext('%(unread_count)s new comment', '%(unread_count)s new comments', unreadCount),
+            {unread_count: thread.get('unread_comments_count')},
+            true
           )
         )
       @highlight(content)


Destroy bindings before subviews.

Destroy bindings before subviews.

--- src/view/view.coffee
+++ src/view/view.coffee
@@ -263,8 +263,8 @@
     if @_batman.events
       event.clearHandlers() for _, event of @_batman.events

+    @destroyBindings()
     @destroySubviews()
-    @destroyBindings()

     @removeFromSuperview()


Allow calling Batman.View.options multiple times.

--- src/view/view.coffee
+++ src/view/view.coffee
@@ -6,6 +6,7 @@

   @option: (keys...) ->
     Batman.initializeObject(this)
+    keys = options.concat(keys) if options = @_batman.options
     @_batman.set('options', keys)

   @viewForNode: (node, climbTree) ->


Allow target lookups for null properties.

--- src/view/view.coffee
+++ src/view/view.coffee
@@ -164,7 +164,7 @@
     lookupNode = proxiedObject || this

     while lookupNode
-      if Batman.get(lookupNode, base)?
+      if typeof Batman.get(lookupNode, base) isnt 'undefined'
         return lookupNode

       controller = lookupNode.controller if lookupNode.isView and lookupNode.controller


bugfix instantiation error: Can't call super with @params in derived class constructors

--- lib/error/Unauthorized.coffee
+++ lib/error/Unauthorized.coffee
@@ -13,5 +13,6 @@
         name: 'floyd.error.Unauthorized'
         title: 'Autorisierung erforderlich'

-        constructor: (@realm)->
-            super floyd.tools.strings.sprintf(message, @realm), 401
+        constructor: (realm)->
+            super floyd.tools.strings.sprintf(message, realm), 401
+            @realm = realm


Handle ENOTCONN open errors

Handle ENOTCONN open errors

--- src/workspace.coffee
+++ src/workspace.coffee
@@ -442,7 +442,7 @@
         when 'EACCES'
           atom.notifications.addWarning("Permission denied '#{error.path}'")
           return Q()
-        when 'EPERM', 'EBUSY', 'ENXIO', 'EIO'
+        when 'EPERM', 'EBUSY', 'ENXIO', 'EIO', 'ENOTCONN'
           atom.notifications.addWarning("Unable to open '#{error.path}'", detail: error.message)
           return Q()
         else


Inlined loadUrl

Inlined loadUrl

--- core/app/assets/javascripts/intermediate.coffee
+++ core/app/assets/javascripts/intermediate.coffee
@@ -32,20 +32,19 @@
   if last_created_text == text
     remote.highlightNewFactlink(text, id)

+window.onModalReady = ->
+
 showUrl = (url, successFn) ->
   window.onModalReady = ->
     window.onModalReady = ->
     successFn()

-  loadUrl url
-
-loadUrl = (url)->
   backbone = showFrame.contentWindow.Backbone
   history = backbone?.history
   if history && backbone.History.started
     history.navigate url, true
   else
-    showFrame.src = url
+    showFrame.onload = -> window.onModalReady()
+    showFrame.src = showUrl

-showFrame.onload = -> window.onModalReady?()
 showFrame.src = '/client/blank'


added grep for tests

added grep for tests

--- services/docstore/Gruntfile.coffee
+++ services/docstore/Gruntfile.coffee
@@ -54,6 +54,7 @@
 			unit:
 				options:
 					reporter: grunt.option('reporter') or 'spec'
+					grep: grunt.option("grep")
 				src: ["test/unit/js/**/*.js"]
 			acceptance:
 				options:


DataTable: Add "reload" to the DataTableNode. Use to reload a Node.

--- src/elements/DataTable/DataTableNode.coffee
+++ src/elements/DataTable/DataTableNode.coffee
@@ -77,6 +77,10 @@
 	getData: ->
 		@__data

+	reload: ->
+		for df in @__fields
+			df.reload()
+
 	addedToListView: ->
 		for df in @__fields
 			df.start()


remove grunt file for generated project

remove grunt file for generated project

--- app/templates/_Gruntfile.coffee
+++ app/templates/_Gruntfile.coffee
@@ -1,302 +0,0 @@
-module.exports = (grunt) ->
-
-	pkg = grunt.file.readJSON('package.json')
-	pvt = grunt.file.readJSON('private.json') if grunt.file.exists('private.json')
-
-	#*------------------------------------*\
-	#   $LOAD DEPENDENCIES
-	#*------------------------------------*/
-	dependencies = Object.keys(pkg.devDependencies).filter (o) ->
-		/^grunt-.+/.test(o)
-
-	for dep in dependencies
-		grunt.loadNpmTasks(dep)
-
-	#
-	# Grunt configuration:
-	#
-	# https://github.com/cowboy/grunt/blob/master/docs/getting_started.md
-	#
-	grunt.initConfig
-		pkg: pkg,
-		pvt: pvt,
-
-		# Project configuration
-		# ---------------------
-
-		#*------------------------------------*\
-		#   $CONTRIB-SASS
-		#*------------------------------------*/
-		sass:
-			options:
-				quiet: false,
-				cacheLocation: '<%= pkg.path.scss %>/.sass-cache'
-			dist:
-				files:
-					'<%= pkg.path.css %>/style.css': '<%= pkg.path.scss %>/style.scss'
-			minify:
-				options:
-					style: 'compressed'
-				files:
-					'<%= pkg.path.css %>/style.min.css': '<%= pkg.path.scss %>/style.scss'
-
-
-		#*------------------------------------*\
-		#   $IMAGEOPTIM
-		#*------------------------------------*/
-		imageoptim:
-			options:
-				imageAlpha: true,
-				# jpegMini: true,
-				quitAfter: true
-			files:
-				['<%= pkg.path.img %>']
-
-
-		#*------------------------------------*\
-		#   $SVGMIN
-		#*------------------------------------*/
-		svgmin:
-			options:
-				plugins: [{
-					removeViewBox: false
-				}]
-			dist:
-				files: [{
-					expand: true,
-					cwd: '<%= pkg.path.img %>',
-					src: ['**/*.svg'],
-					dest: '<%= pkg.path.img %>'
-				}]
-
-
-		#*------------------------------------*\
-		#   $SHELL
-		#*------------------------------------*/
-		shell:
-			styleSymlinks:
-				command: [
-					'cd styleguide/public'
-					'ln -s ../../<%= pkg.path.assets %> assets'
-				].join('&&'),
-				options:
-					stdout:true
-
-
-		#*------------------------------------*\
-		#   $CONTRIB-COFFEE
-		#*------------------------------------*/
-		coffee:
-			dist:
-				files: [{
-					expand: true
-					cwd: '<%= pkg.path.coffee %>'
-					src: '{,*/}*.coffee'
-					dest: '<%= pkg.path.js %>'
-					ext: '.js'
-				}]
-
-
-		#*------------------------------------*\
-		#   $CONTRIB-WATCH
-		#*------------------------------------*/
-		watch:
-			css:
-				files: ['<%= pkg.path.scss %>/**/*.scss'],
-				tasks: ['sass:dist']
-			coffee:
-				files: ['<%= pkg.path.coffee %>/**/*.coffee'],
-				tasks: ['coffee:dist']
-
-
-		#*------------------------------------*\
-		#   $CONTRIB-UGLIFY
-		#*------------------------------------*/
-		uglify:
-			target:
-				files:
-					'<%= pkg.path.js %>/main.min.js': '<%= pkg.path.js %>/main.js'
-
-
-		#*------------------------------------*\
-		#   $MYSQL-DUMP
-		#*------------------------------------*/
-		db_dump:
-			local:
-				options:
-					title: "local db"
-					database: "[local db]"
-					user: "root"
-					pass: "password"
-					host: "localhost"
-					backup_to: '<%= pkg.path.db_backup %>/dev/dev_<%= grunt.template.date("yyyymmdd-HHmmss") %>.sql'
-			prod:
-				options:
-					title: "prod db"
-					database: "<%= pvt.db_prod.name %>"
-					user: "<%= pvt.db_prod.user %>"
-					pass: "<%= pvt.db_prod.pass %>"
-					host: "<%= pvt.db_prod.host %>"
-					ssh_host: "<%= pvt.username %>@<%= pvt.domain %>"
-					backup_to: '<%= pkg.path.db_backup %>/prod/<%= pvt.db_prod.name %>_<%= grunt.template.date("yyyymmdd-HHmmss") %>.sql'
-
-
-		#*------------------------------------*\
-		#   $RSYNC
-		#*------------------------------------*/
-		# rsync files to and from production
-		rsync:
-			options:
-				args: ["--archive", "--itemize-changes", "--progress", "--compress"]
-				exclude: [
-					".git*",
-					".DS_Store",
-					"node_modules",
-					".sass-cache",
-					"*.scss",
-					"*.css.map",
-					"assets/css/style.css",
-					"assets/js/main.js",
-					"*.js.map",
-					"*.coffee",
-					"config-dev.php",
-					"assets/cache",
-					"assets/files",
-					"assets/sessions",
-					"assets/logs"
-				]
-				recursive: true
-
-			# dry-run down
-			downdry:
-				options:
-					args: ["--dry-run", "--verbose"]
-					src: "<%= pvt.username %>@<%= pvt.domain %>:public_html/"
-					dest: "src"
-					syncDestIgnoreExcl: true
-
-			# sync down
-			down:
-				options:
-					src: "<%= pvt.username %>@<%= pvt.domain %>:public_html/"
-					dest: "src"
-					syncDestIgnoreExcl: true
-
-			# staging dry-run down
-			#
-			# only sync files that have been uploaded
-			stagingdowndry:
-				options:
-					args: ["--dry-run", "--verbose"]
-					src: "<%= pvt.username %>@<%= pvt.domain %>:public_html/staging.<%= pvt.domain %>/site/assets/files/"
-					dest: "src/site/assets/files"
-					syncDestIgnoreExcl: true
-
-			# sync staging to local
-			#
-			# only sync files that have been uploaded
-			stagingdown:
-				options:
-					src: "<%= pvt.username %>@<%= pvt.domain %>:public_html/staging.<%= pvt.domain %>/site/assets/files/"
-					dest: "src/site/assets/files"
-					syncDestIgnoreExcl: true
-
-			# dry-run sync to prod
-			updry:
-				options:
-					args: ["--dry-run", "--verbose"]
-					src: "src/"
-					dest: "public_html"
-					host: "<%= pvt.username %>@<%= pvt.domain %>"
-
-			# sync to pro
-			up:
-				options:
-					src: "src/"
-					dest: "public_html"
-					host: "<%= pvt.username %>@<%= pvt.domain %>"
-
-			# dry-run deploy to staging
-			stagingupdry:
-				options:
-					args: ["--dry-run", "--verbose"]
-					exclude: [
-						".git*",
-						".DS_Store",
-						"node_modules",
-						"config-dev.php",
-						".sass-cache",
-						"*.scss",
-						"*.css.map",
-						"assets/css/style.css",
-						"assets/js/main.js",
-						"*.js.map",
-						"*.coffee",
-						"assets/cache",
-						"assets/files",
-						"assets/logs",
-						"assets/sessions",
-						"config.php",
-						"robots.txt"
-					]
-					src: "src/"
-					dest: "public_html/staging.<%= pvt.domain %>"
-					host: "<%= pvt.username %>@<%= pvt.domain %>"
-
-			# deploy local changes to staging
-			stagingup:
-				options:
-					src: "src/"
-					exclude: [
-						".git*",
-						".DS_STORE",
-						"node_modules",
-						"config-dev.php",
-						".sass-cache",
-						"*.scss",
-						"*.css.map",
-						"assets/css/style.css",
-						"assets/js/main.js",
-						"*.js.map",
-						"*.coffee",
-						"assets/cache",
-						"assets/files",
-						"assets/logs",
-						"assets/sessions",
-						"config.php",
-						"robots.txt"
-					]
-					dest: "public_html/staging.<%= pvt.domain %>"
-					host: "<%= pvt.username %>@<%= pvt.domain %>"
-
-
-		#*------------------------------------*\
-		#   $DEV UPDATE
-		#*------------------------------------*/
-		devUpdate:
-			options:
-				reportUpdated: false
-				semver: true
-				packages:
-					devDependencies: true
-					dependencies: false
-				packageJson: null
-			check:
-				updateType: 'report'
-			ask:
-				options:
-					updateType: 'prompt'
-			up:
-				options:
-					updateType: 'force'
-
-
-	#*------------------------------------*\
-	#   $TASKS
-	#*------------------------------------*/
-	grunt.registerTask 'default', ['watch']
-	grunt.registerTask 'optim', ['imageoptim', 'svgmin']
-	grunt.registerTask 'build', ['uglify', 'sass:minify', 'optim']
-	grunt.registerTask 'depcheck', ['devUpdate:check']
-	grunt.registerTask 'depask', ['devUpdate:ask']
-	grunt.registerTask 'depup', ['devUpdate:up']


remove setup status logging

remove setup status logging

--- src/server.coffee
+++ src/server.coffee
@@ -80,7 +80,6 @@

       dbPlugin = System.getPlugin 'kerplunk-database'

-      console.log 'Setting up websockets'
       websockets = SetupWebsockets System, server, httpsServer
       websockets.primus[0].save "#{System.baseDir}/public/js/primus.js"


handle focusing text area for current step

--- src/components/exercise/index.cjsx
+++ src/components/exercise/index.cjsx
@@ -39,6 +39,7 @@
     <ExercisePart
       {...props}
       {...partProps}
+      focus={@isSinglePart()}
       step={part}
       id={part.id}
       taskId={part.task_id}/>
@@ -126,6 +127,9 @@
     if nextProps.currentStep isnt @props.currentStep
       @scrollToSelector("[data-step='#{nextProps.currentStep}']")

+  onAfterScroll: ->
+    textArea = @_scrollingTargetDOM().querySelector("[data-step='#{@props.currentStep}'] textarea")
+    textArea?.focus()

   render: ->
     {parts, footer, pinned} = @props


make model accessible

make model accessible

--- src/opensong.coffee
+++ src/opensong.coffee
@@ -28,6 +28,9 @@
   setLyrics: (lyrics) ->
     @model = opensong.helper.parseLyrics lyrics
     this.renderLyrics()
+
+  getModel: ->
+    @model

   renderLyrics: ->
     # clear Html Element and add opensong class
@@ -215,4 +218,3 @@
         else
           console?.log "no suppport for '#{line}'"
   dataModel
-


using Coffee class now

using Coffee class now

--- src/opensong.coffee
+++ src/opensong.coffee
@@ -10,7 +10,7 @@
 if jQuery?
   jQuery.fn.extend
     openSongLyrics: (lyrics) ->
-      openSong.renderLyrics this, lyrics
+      new OpenSong this, lyrics

 Handlebars.registerHelper 'human_header', (abbr) ->
@@ -29,21 +29,17 @@
       abbr

-openSong =
-
-  getDomElem: (domElem) ->
-    if typeof domElem is 'string'
-      return document.getElementById domElem
-
-    if domElem.jquery
-      return domElem.get(0)
-
-    if domElem.nodeType
-      return domElem
-
-    undefined
-
-  renderLyrics: (element, lyrics) ->
+class OpenSong
+
+  constructor: (element, lyrics) ->
+    @el = getDomElem element
+    @model = parseLyrics lyrics
+
+    #render initially
+    this.renderLyrics()
+
+
+  renderLyrics: ->
     # TODO: support comments
     templateSrc = """
       {{#this}}
@@ -69,10 +65,21 @@
     template = Handlebars.compile templateSrc

     # clear Html Element and add opensong class
-    domElem = this.getDomElem element
-    domElem.innerHTML = template this.parseLyrics lyrics
-    domElem.className += " opensong" unless /opensong/.test domElem.className
-
+    @el.innerHTML = template @model
+    @el.className += " opensong" unless /opensong/.test @el.className
+
+
+  getDomElem = (domElem) ->
+    if typeof domElem is 'string'
+      return document.getElementById domElem
+
+    if domElem.jquery
+      return domElem.get(0)
+
+    if domElem.nodeType
+      return domElem
+
+    undefined

   ###

@@ -94,7 +101,7 @@
   ]

   ###
-  parseLyrics: (lyrics) ->
+  parseLyrics = (lyrics) ->
     lyricsLines = lyrics.split("\n")

     dataModel = []
@@ -169,7 +176,7 @@
           console?.log "no support for: #{line}"
     dataModel

-  transposeChord: (chord, amount) ->
+  transposeChord = (chord, amount) ->
     chords = [
       "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B",
       "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"


修复 MessageBox 国际化问题

修复 MessageBox 国际化问题


runtime: Fix exported edges not reset on new graph

Caused microflo-core FBP spec tests to fail when running more than
one suite

--- lib/runtime.coffee
+++ lib/runtime.coffee
@@ -189,6 +189,9 @@
         graph.connections = []
         graph.name = payload.name or ''
         graph.nodeMap = {} # nodeName->numericNodeId
+        # FIXME: should be on the graph!
+        runtime.exportedEdges = []
+        runtime.edgesForInspection = []
         sendAck connection, { protocol: 'graph', command: command, payload: payload }
     else if command is "addnode"
         graph.processes[payload.id] = payload
@@ -233,7 +236,6 @@
             port: payload.port
         sendExportedPorts connection, runtime
         # For subscribing to output packets
-        runtime.exportedEdges = [] if not runtime.exportedEdges?
         runtime.exportedEdges.push
             src:
                 process: payload.node
@@ -324,8 +326,7 @@
     runtime.device.sendCommands data, (err) ->
         # Subscribe to change notifications
         # TODO: use a dedicated mechanism for this based on subgraphs
-        runtime.exportedEdges = [] if not runtime.exportedEdges?
-        edges = runtime.exportedEdges.concat runtime.edgesForInspection or []
+        edges = runtime.exportedEdges.concat runtime.edgesForInspection
         handleNetworkEdges runtime, connection, edges, (err) ->
             runtime.uploadInProgress = false

@@ -370,7 +371,6 @@
     else if command is "edges"
         # TOD: merge with those of exported outports
         runtime.edgesForInspection = payload.edges
-        runtime.exportedEdges = [] if not runtime.exportedEdges?
         edges = runtime.edgesForInspection.concat runtime.exportedEdges
         handleNetworkEdges runtime, connection, edges
         sendAck connection, { protocol: 'network', command: command, payload: payload }


Tests: Updated activity tests.

Tests: Updated activity tests.

--- tests/src/activity/activity.coffee
+++ tests/src/activity/activity.coffee
@@ -37,20 +37,20 @@
       .end()

-  # unlikePost: (browser) ->
-
-  #   user = helpers.beginTest(browser)
-  #   helpers.postActivity(browser, no)
-  #   selector    = activitySelector + ' [testpath=activity-like-link]'
-  #   likeElement = activitySelector + ' .like-summary'
-
-  #   browser
-  #     .waitForElementVisible    selector, 10000
-  #     .click                    selector
-  #     .waitForElementVisible    selector + '.liked', 10000
-  #     .click                    selector + '.liked'
-  #     .waitForElementNotVisible likeElement, 10000
-  #     .end()
+  unlikePost: (browser) ->
+
+    user = helpers.beginTest(browser)
+    helpers.postActivity(browser, no)
+    selector    = activitySelector + ' [testpath=activity-like-link]'
+    likeElement = activitySelector + ' .like-summary'
+
+    browser
+      .waitForElementVisible    selector, 10000
+      .click                    selector
+      .waitForElementVisible    selector + '.liked', 10000
+      .click                    selector + '.liked'
+      .waitForElementNotVisible likeElement, 10000
+      .end()

   editPost: (browser) ->
@@ -172,19 +172,19 @@
       .end()

-  # searchActivity: (browser) ->
-
-  #   post     = helpers.postActivity(browser)
-  #   selector = '[testpath=activity-list] [testpath=ActivityListItemView]:first-child'
-  #   word     = post.split(' ')[0]
-
-  #   browser
-  #     .setValue                 '.kdtabhandlecontainer .search-input', word + '\n'
-  #     .waitForElementVisible    '.kdtabpaneview.search', 10000
-  #     .waitForElementVisible    selector, 10000
-  #     .pause                    10000
-  #     .assert.containsText      selector, word # Assertion
-  #     .end()
+  searchActivity: (browser) ->
+
+    post     = helpers.postActivity(browser)
+    selector = '[testpath=activity-list] [testpath=ActivityListItemView]:first-child'
+    word     = post.split(' ')[0]
+
+    browser
+      .setValue                 '.kdtabhandlecontainer .search-input', word + '\n'
+      .waitForElementVisible    '.kdtabpaneview.search', 10000
+      .waitForElementVisible    selector, 10000
+      .pause                    10000
+      .assert.containsText      selector, word # Assertion
+      .end()

   showMoreCommentLink: (browser) ->
@@ -206,29 +206,29 @@
     browser.end()

-  # followTopic: (browser) ->
-
-  #   helpers.doFollowTopic(browser)
-  #   browser.end()
-
-
-  # unfollowTopic: (browser) ->
-
-  #   hashtag = helpers.doFollowTopic(browser)
-  #   selector = '.activity-sidebar .followed.topics'
-
-  #   browser
-  #     .waitForElementVisible   '[testpath=channel-title]' + ' .following', 2000
-  #     .pause                    10000
-  #     .click                   '[testpath=channel-title]' + ' .following'
-  #     .waitForElementVisible   '[testpath="public-feed-link/Activity/Topic/public"]', 2000
-  #     .click                   '[testpath="public-feed-link/Activity/Topic/public"]'
-  #     .refresh()
-  #     .pause 2000 # reguired
-
-  #   browser.getText selector
-  #   assert.notEqual(hashtag)
-  #   browser.end()
+  followTopic: (browser) ->
+
+    helpers.doFollowTopic(browser)
+    browser.end()
+
+
+  unfollowTopic: (browser) ->
+
+    hashtag = helpers.doFollowTopic(browser)
+    selector = '.activity-sidebar .followed.topics'
+
+    browser
+      .waitForElementVisible   '[testpath=channel-title]' + ' .following', 2000
+      .pause                    10000
+      .click                   '[testpath=channel-title]' + ' .following'
+      .waitForElementVisible   '[testpath="public-feed-link/Activity/Topic/public"]', 2000
+      .click                   '[testpath="public-feed-link/Activity/Topic/public"]'
+      .refresh()
+      .pause 2000 # reguired
+
+    browser.getText selector
+    assert.notEqual(hashtag)
+    browser.end()

   postLongMessage: (browser) ->
@@ -296,20 +296,20 @@
       .end()

-  # postMessageWithLink: (browser) ->
-
-  #   helpers.beginTest(browser)
-
-  #   link = 'http://nightwatchjs.org/' # last '/' is the trick!
-  #   linkSelector = activitySelector + ' .activity-content-wrapper article a'
-
-  #   helpers.doPostActivity(browser, link)
-
-  #   browser.getAttribute linkSelector, 'href', (result) ->
-  #     href = result.value
-  #     assert.equal(link, href)
-
-  #   browser.end()
+  postMessageWithLink: (browser) ->
+
+    helpers.beginTest(browser)
+
+    link = 'http://nightwatchjs.org/' # last '/' is the trick!
+    linkSelector = activitySelector + ' .activity-content-wrapper article a'
+
+    helpers.doPostActivity(browser, link)
+
+    browser.getAttribute linkSelector, 'href', (result) ->
+      href = result.value
+      assert.equal(link, href)
+
+    browser.end()

   postMessageAndSeeIfItsPostedOnlyOnce: (browser) ->


Use Workspace::registerOpener

Use Workspace::registerOpener

--- lib/timecop.coffee
+++ lib/timecop.coffee
@@ -11,7 +11,7 @@

 module.exports =
   activate: ->
-    atom.project.registerOpener (filePath) ->
+    atom.workspace.registerOpener (filePath) ->
       createView(uri: viewUri) if filePath is viewUri

     atom.workspaceView.command 'timecop:view', -> atom.workspaceView.open(viewUri)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -1,6 +1,7 @@
 module "Engine"

-test "#c"
+test "#closest", ->
+

 test "#each", ->
   engine = Engine()


Added appending to MenuManager

Added appending to MenuManager

--- lib/utils/menu-manager.coffee
+++ lib/utils/menu-manager.coffee
@@ -3,20 +3,20 @@
 module.exports =
   # Get root menu
   getMenu: ->
-    ideMenu = atom.menu.template.filter (value) ->
+    devMenu = atom.menu.template.filter (value) ->
       value.label == 'Spark'

-    ideMenu[0]
+    devMenu[0]

   # Update menu
   update: ->
-    ideMenu = @getMenu()
+    devMenu = @getMenu()

     if SettingsHelper.isLoggedIn()
       # Menu items for logged in user
       username = SettingsHelper.get('username')

-      ideMenu.submenu = [{
+      devMenu.submenu = [{
         label: 'Log out ' + username,
         command: 'spark-dev:logout'
       },{
@@ -28,7 +28,7 @@

       if SettingsHelper.hasCurrentCore()
         # Menu items depending on current core
-        ideMenu.submenu = ideMenu.submenu.concat [{
+        devMenu.submenu = devMenu.submenu.concat [{
           label: 'Rename ' + SettingsHelper.getLocal('current_core_name') + '...',
           command: 'spark-dev:rename-device'
         },{
@@ -42,7 +42,7 @@
           command: 'spark-dev:flash-cloud'
         }]

-      ideMenu.submenu = ideMenu.submenu.concat [{
+      devMenu.submenu = devMenu.submenu.concat [{
         type: 'separator'
       },{
         label: 'Claim device...',
@@ -61,12 +61,12 @@
       }]
     else
       # Logged out user can only log in
-      ideMenu.submenu = [{
+      devMenu.submenu = [{
         label: 'Log in to Spark Cloud...',
         command: 'spark-dev:login'
       }]

-    ideMenu.submenu = ideMenu.submenu.concat [{
+    devMenu.submenu = devMenu.submenu.concat [{
       type: 'separator'
     },{
       label: 'Show serial monitor',
@@ -75,3 +75,8 @@

     # Refresh UI
     atom.menu.update()
+
+  append: (items) ->
+    devMenu = @getMenu()
+    devMenu.submenu = devMenu.submenu.concat items
+    atom.menu.update()


activity: remove empty lines

activity: remove empty lines

--- client/Social/Activity/sidebar/activitysidebar.coffee
+++ client/Social/Activity/sidebar/activitysidebar.coffee
@@ -58,9 +58,7 @@
     {typeConstant, id}     = channel

     listController = @getListController typeConstant
-
     item = listController.itemForId id
-
     item.setUnreadCount unreadCount  if item?.unreadCount


Activity: minor code style

Activity: minor code style

--- client/Social/Activity/sidebar/activitysidebar.coffee
+++ client/Social/Activity/sidebar/activitysidebar.coffee
@@ -93,8 +93,8 @@
     # we need to get the channel instead of the post
     # the other case of reply being added is followed post
     if typeConstant is 'privatemessage'
-      type = 'channel'
-      id   = update.channel.id
+      type    = 'channel'
+      id      = update.channel.id

     # so we fetch respectively
     socialapi.cacheable type, id, (err, data) =>


Update teammembersview.coffee

Update teammembersview.coffee

--- client/admin/lib/views/members/teammembersview.coffee
+++ client/admin/lib/views/members/teammembersview.coffee
@@ -1,4 +1,3 @@
-KDView                = kd.View
 TeamMembersCommonView = require './teammemberscommonview'


Change icon

Change icon

--- client/apps/edit/components/section_tool/index.coffee
+++ client/apps/edit/components/section_tool/index.coffee
@@ -167,5 +167,5 @@
             }, 'Callout',
               div {
                 className: 'edit-menu-icon-callout'
-                dangerouslySetInnerHTML: __html: $(icons()).filter('.embed').html()
+                dangerouslySetInnerHTML: __html: $(icons()).filter('.hero-fullscreen').html()
               }


Remove oskite depended codes from kiteController

--- client/landing/app/MainApp/kite/kitecontroller.coffee
+++ client/landing/app/MainApp/kite/kitecontroller.coffee
@@ -83,33 +83,33 @@
       command = options
       options = {}

+    options.method   or= "exec"
     options.kiteName or= "os"
-    options.method   or= "exec"
-
-    KD.getSingleton("vmController").fetchDefaultVmName (defaultVmName)=>
-      vmName = if options.vmName then options.vmName else defaultVmName
-      unless vmName
-        return callback message: 'There is no VM for this account.'
-
-      options.vmName = vmName
-
-      kite = @getKite options.kiteName, vmName
-
-      if command
-        options.withArgs = command
-      else
-        options.withArgs or= {}
-
-      if KD.logsEnabled and KD.showKiteCalls
-        notify """
-                Calling #{options.method} method,
-                from #{options.kiteName} kite
-               """
-
-      log "Kite Request:", options
-
-      kite.tell options, (err, response)=>
-        @parseKiteResponse {err, response}, options, callback
+
+    correlationName = options.correlationName or ""
+
+    if options.kiteName is "os" and not correlationName
+      warn """OS kite call requested without providing
+              correlationName, using default if exists."""
+      correlationName = KD.getSingleton('vmController').defaultVmName
+
+    kite = @getKite options.kiteName, correlationName
+
+    if command
+      options.withArgs = command
+    else
+      options.withArgs or= {}
+
+    if KD.logsEnabled and KD.showKiteCalls
+      notify """
+              Calling #{options.method} method,
+              from #{options.kiteName} kite
+             """
+
+    log "Kite Request:", options
+
+    kite.tell options, (err, response)=>
+      @parseKiteResponse {err, response}, options, callback

   setListeners:->


Reorder topic and reply functions

Reorder topic and reply functions

--- src/response.coffee
+++ src/response.coffee
@@ -17,6 +17,15 @@
   send: (strings...) ->
     @robot.adapter.send @message.user, strings...

+  # Public: Posts a message mentioning the current user.
+  #
+  # strings - One or more strings to be posted. The order of these strings
+  #           should be kept intact.
+  #
+  # Returns nothing.
+  reply: (strings...) ->
+    @robot.adapter.reply @message.user, strings...
+
   # Public: Posts a topic changing message
   #
   # strings - One or more strings to set as the topic of the
@@ -25,15 +34,6 @@
   # Returns nothing.
   topic: (strings...) ->
     @robot.adapter.topic @message.user, strings...
-
-  # Public: Posts a message mentioning the current user.
-  #
-  # strings - One or more strings to be posted. The order of these strings
-  #           should be kept intact.
-  #
-  # Returns nothing.
-  reply: (strings...) ->
-    @robot.adapter.reply @message.user, strings...

   # Public: Picks a random item from the given items.
   #


directions not needed here

directions not needed here

--- dwim.coffee
+++ dwim.coffee
@@ -116,10 +116,4 @@
   render: ->
     @gfx.render()

-  UP: UP
-  DOWN: DOWN
-  LEFT: LEFT
-  RIGHT: RIGHT
-
-
 window.Dwim = Dwim


pin down bug with autoclosing approving tags

--- src/test/xml.coffee
+++ src/test/xml.coffee
@@ -357,6 +357,9 @@
         results = [
             '<apple>'
             '<wurm color="red">'
+            '<type>'
+            'caterpillar'
+            '</type>'
             '<seed>'
             '<is dead=true>'
             '</is>'
@@ -368,8 +371,10 @@
         seed = null
         apple = xml.tag 'apple', ->
             xml.stream.pause()
-            @$tag 'wurm', color:'red', ->
-                seed = @tag('seed')
+            wurm = @tag 'wurm', color:'red', ->
+                @$tag 'type', "caterpillar"
+            seed = wurm.tag('seed')
+            wurm.end()
             @end()

         setTimeout ( ->


lru arguments fix

lru arguments fix

--- lib/query_cache.coffee
+++ lib/query_cache.coffee
@@ -16,7 +16,7 @@
     @hardReset() # Clear previous cache, reset counts

     lru_options = {}
-    (lru_options[inflection.camelize(key)] = value) for key, value of options
+    (lru_options[inflection.camelize(key, true)] = value) for key, value of options

     @cache = new LRU(lru_options)
     return @


But we have to close overlay manually now.

--- client/import.coffee
+++ client/import.coffee
@@ -154,5 +154,6 @@
       Meteor.Router.to Meteor.Router.publicationPath finishedImportingFiles[0].publicationId
     else
       Meteor.Router.to Meteor.Router.profilePath Meteor.personId()
+    Session.set 'importOverlayActive', false

   ImportingFiles.remove({})


added short descriptions in ` completion list

--- client/keymap.coffee
+++ client/keymap.coffee
@@ -17,11 +17,28 @@
            ⍺⌈⌊_∇∆∘\'⎕⍎⍕⊢  ⍺⌈⌊_∇∆⍤⌸⌷≡≢⊣
            ⊂⊃∩∪⊥⊤|⍝⍀⌿     ⊂⊃∩∪⊥⊤|⍪⍙⍠    '''.replace(/^\s*|\s*$/g, '').split /\s*/g

+  ds =
+    '¨':'each', '¯':'negative', '∨':'or (GCD)', '∧':'and (LCM)',
+    '×':'sgn/times', '÷':'reciprocal/divide', '?':'roll/deal', '⍵':'right arg',
+    '∊':'enlist/in', '⍴':'shape/reshape', '~':'not/without', '↑':'mix/take',
+    '↓':'split/drop', '⍳':'indices/index of', '○':'pi/trig', '*':'exp/power',
+    '←':'assignment', '→':'branch', '⍺':'left arg', '⌈':'ceil/max', '⌊':'floor/min',
+    '∇':'recur', '∘':'compose', '⎕':'eval\'ed I/O', '⍎':'eval', '⍕':'format',
+    '⊢':'right', '⊂':'enclose/partition', '⊃':'disclose/pick', '∩':'intersect',
+    '∪':'uniq/union', '⊥':'decode (1 2 3→123)', '⊤':'encode (123→1 2 3)', '|':'abs/mod',
+    '⍝':'comment', '⍀':'\\[⎕io]', '⌿':'/[⎕io]', '⋄':'statement sep', '⌶':'I-beam',
+    '⍒':'grade down', '⍋':'grade up', '⌽':'reverse/rotate', '⍉':'transpose',
+    '⊖':'⌽[⎕io]', '⍟':'logarithm', '⍱':'nor', '⍲':'nand', '!':'factorial/binomial',
+    '⌹':'matrix inv/div', '⍷':'find', '⍨':'switch', '⍣':'power operator',
+    '⍞':'char I/O', '⍬':'zilde (⍳0)', '⍤':'rank', '⌸':'key', '⌷':'default/index',
+    '≡':'depth/match', '≢':'tally/not match', '⊣':'left', '⍪':'table / ,[⎕io]',
+    '⍠':'variant'
+
   if ks.length != vs.length then console.error? 'bad configuration of backquote keymap'

   do ->
     for k, i in ks when k != (v = vs[i]) || k == '`'
-      Dyalog.bqCompletions.push text: v, displayText: v + ' `' + k + '   '
+      Dyalog.bqCompletions.push text: v, displayText: "#{v} `#{k} #{ds[v] || ''}  "
       bqKeybindings[k] = v
       Dyalog.reverseKeyMap[v] = k


:art: I want select this function if cursor is at foldStart.

--- lib/text-object.coffee
+++ lib/text-object.coffee
@@ -454,7 +454,7 @@
     @language = @editor.getGrammar().scopeName.replace(/^source\./, '')

   getFoldRowRangesContainsForRow: (row) ->
-    rowRanges = super(row)
+    rowRanges = getCodeFoldRowRangesContainesForRow(@editor, row)?.reverse()
     rowRanges?.filter (rowRange) =>
       isIncludeFunctionScopeForRow(@editor, rowRange[0])


Add loading and empty message

Add loading and empty message

--- lib/theme-panel.coffee
+++ lib/theme-panel.coffee
@@ -30,6 +30,8 @@

       @div class: 'section themes', =>
         @div class: 'section-heading theme-heading icon icon-cloud-download', 'Install Themes'
+        @div outlet: 'loadingMessage', class: 'padded text icon icon-hourglass', 'Loading themes\u2026'
+        @div outlet: 'emptyMessage', class: 'padded text icon icon-heart', 'You have every theme installed already!'
         @div outlet: 'themeContainer', class: 'container theme-container', =>
           @div outlet: 'themeRow', class: 'row'

@@ -102,10 +104,17 @@

   # Load and display themes available to install.
   loadAvailableThemes: ->
+    @loadingMessage.show()
+    @emptyMessage.hide()
+
     @packageManager.getAvailable (error, packages=[]) =>
       installedThemes = atom.themes.getAvailableNames()
       themes = packages.filter ({name, theme}) ->
         theme and not (name in installedThemes)

-      for theme in themes
-        @themeRow.append(new ThemeView(theme, @packageManager))
+      @loadingMessage.hide()
+      if themes.length > 0
+        for theme in themes
+          @themeRow.append(new ThemeView(theme, @packageManager))
+      else
+        @emptyMessage.show()


Add tests for sync.

Add tests for sync.

--- tests/unit_tests/settings_test.coffee
+++ tests/unit_tests/settings_test.coffee
@@ -30,3 +30,15 @@
     Settings.set 'scrollStepSize', 20
     Settings.clear 'scrollStepSize'
     assert.equal Settings.get('scrollStepSize'), 60
+
+  should "remote changes take effect locally, non-default value", ->
+    Settings.set 'scrollStepSize', 20
+    assert.equal Settings.get('scrollStepSize'), 20
+    Sync.listener { scrollStepSize: { newValue: "40" } }
+    assert.equal Settings.get('scrollStepSize'), 40
+
+  should "remote changes take effect locally, default value", ->
+    Settings.set 'scrollStepSize', 20
+    assert.equal Settings.get('scrollStepSize'), 20
+    Sync.listener { scrollStepSize: { newValue: "60" } }
+    assert.isFalse Settings.has 'scrollStepSize'


thingy: Cleanup

thingy: Cleanup

--- client/thingy.coffee
+++ client/thingy.coffee
@@ -498,24 +498,27 @@
 # When constructing a thingy delegate in an initializer, it should provide
 # the same methods as documented below.
 #
-# @method #set( attrs, local_data )
+# @method #set( thingy. attrs, local_data )
 #   Set attributes given in `attrs`.
-#   @param [Object] attrs      Attributes to set.
-#   @param [any]    local_data false for remote operations; true by default
-#     for local operations, but could be anything setter wants.
+#   @param [Heron.Thingy] thingy     Thingy.
+#   @param [Object]       attrs      Attributes to set.
+#   @param [any]          local_data false for remote operations; true by
+#     default for local operations, but could be anything setter wants.
 #   @return [any] Ignored.
 #
-# @method #get( attr_keys... )
+# @method #get( thingy, attr_keys... )
 #   Return an object with a member for each key in `attr_keys...` with value
 #   of that attribute.  Allowed to include additional keys.  Return value will
 #   be treated as immutable.
+#   @param [Heron.Thingy]  thingy       Thingy.
 #   @param [Array<String>] attr_keys... Keys to return.
 #   @return [Object] Object with values of each key in `attr_keys`.
 #
-# @method #remove( local_data )
+# @method #remove( thingy, local_data )
 #   Do anything necessary before thingy removal.
-#   @param [any] local_data false for remote operation; true by default for
-#     local operations, but could be anything remover wants.
+#   @param [Heron.Thingy] thingy     Thingy.
+#   @param [any]          local_data false for remote operation; true by
+#     default for local operations, but could be anything remover wants.
 #   @return [any] Ignored.
 class Heron.ThingyDelegate

@@ -722,6 +725,8 @@
     # Subscribe to domain.
     receiver = new Receiver( this )
     dictionary.subscribe( @_.domain, receiver )
+
+    this

   # Define a new Thingy Type.
   #


Removed test files.

Removed test files.

--- test/lib/test.coffee
+++ test/lib/test.coffee
@@ -1,38 +0,0 @@
-	# casper.start('http://espn.com/', () ->
-	# 	console.log('Opened page: "' + @.getTitle() + '"')
-	# 	casper.capture("../images/espn-home.png")
-	# ).run()
-
-	# testCount = 2
-	# casper.test.begin "Testing Reddit", testCount, redditTest = (test) ->
-	# 	casper.start("http://reddit.com/r/programming", ->
-	# 		test.assertTitleMatch /programming/, "Title is what we expect"
-	# 		casper.click "a[href*='programming/new/']"
-	# 		casper.waitForUrl /\/programming\/new\/$/, ->
-	# 			test.assertElementCount "p.title", 26, "26 links on first page"
-	# 			casper.capture "../images/reddit-programming-new.png"
-	# 			return
-	# 		return
-	# 	).run ->
-	# 		test.done()
-	# 		return
-	# 	return
-
-casper.test.begin "Searching Reddit", 1, (test) ->
-
-	casper.start "http://reddit.com/r/programming", ->
-		casper.fill "form#search",
-			q: "javascript"
-			restrict_sr: true
-		, true
-		casper.then ->
-			test.assertElementCount "p.title", 25, "25 links on first page"
-			@capture "../images/Reddit-search.png"
-			return
-		return
-
-	casper.run ->
-		test.done()
-		return
-
-	return


Improve tests

Improve tests

--- test/registry.coffee
+++ test/registry.coffee
@@ -1,19 +1,33 @@
 expect = require('chai').expect
 Registry = require('../src/registry')
-_ = require('underscore')

 describe 'Registry', ->

+  describe 'info()', ->
+    it 'returns a object', ->
+      registry = Registry.open('HKLM',
+        'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall')
+      info = registry.info()
+      registry.close()
+      expect(info).to.be.an.any('object')
+
   describe 'keys()', ->
-    it 'does not throw an error', ->
-      expect(->
-        registry = Registry.open('HKLM', '')
-        console.log registry.info()
-        console.log registry.keys()
-        registry.close()
-      ).to.not.throw(Error)
+    it 'returns an array', ->
+      registry = Registry.open('HKLM',
+        'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall')
+      keys = registry.keys()
+      registry.close()
+      expect(keys).to.be.an.any('array')

   describe 'values()', ->
+    it 'returns a object', ->
+      console.log 'items', Registry.ERROR_NO_MORE_ITEMS
+      key = 'Software\\Microsoft\\Windows\\CurrentVersion'
+      registry = Registry.open('HKLM', key)
+      values = registry.values()
+      registry.close()
+      expect(values).to.be.an.any('object')
+
     it 'does not throw an error', ->
       getAppKeys = ->
         keys = []
@@ -21,11 +35,10 @@
         registry = Registry.open('HKLM', parent)
         keys = registry.keys()
         registry.close()
-        return _.map keys, (key) -> parent + '\\' + key.key
+        return keys.map (key) -> parent + '\\' + key.key
       expect(->
-        keys = getAppKeys()
-        child = keys[5]
-        registry = Registry.open('HKLM', child)
-        console.log registry.values()
-        registry.close()
+        for key in getAppKeys()
+          registry = Registry.open('HKLM', key)
+          values = registry.values()
+          registry.close()
       ).to.not.throw(Error)


remove stray comment

remove stray comment

--- exercises/src/components/exercise.cjsx
+++ exercises/src/components/exercise.cjsx
@@ -1,4 +1,3 @@
-# @csx React.DOM
 React = require 'react'
 _ = require 'underscore'
 BS = require 'react-bootstrap'


Override meta-w to be a noop on tool-panels

--- src/app/keymaps/atom.cson
+++ src/app/keymaps/atom.cson
@@ -33,3 +33,4 @@
 '.tool-panel':
   'meta-escape': 'tool-panel:unfocus'
   'escape': 'core:close'
+  'meta-w': 'noop'


Set input encoding to utf8

Set input encoding to utf8

--- src/app/pasteboard.coffee
+++ src/app/pasteboard.coffee
@@ -5,7 +5,7 @@
   signatureForMetadata: null

   md5: (text) ->
-    crypto.createHash('md5').update(text).digest('hex')
+    crypto.createHash('md5').update(text, 'utf8').digest('hex')

   write: (text, metadata) ->
     @signatureForMetadata = @md5(text)


Syntax is extended

Syntax is extended

--- src/syntax.coffee
+++ src/syntax.coffee
@@ -9,7 +9,7 @@
 {$, $$} = require './space-pen-extensions'
 Token = require './token'

-# Public: Syntax class holding the grammars used for tokenizing.
+# Extended: Syntax class holding the grammars used for tokenizing.
 #
 # An instance of this class is always available as the `atom.syntax` global.
 #


hide parameters from settings

hide parameters from settings

--- jsapp/xlform/src/view.rowDetail.coffee
+++ jsapp/xlform/src/view.rowDetail.coffee
@@ -177,11 +177,8 @@
       @listenForInputChange()

   viewRowDetail.DetailViewMixins.parameters =
-    html: ->
-      @$el.addClass("card__settings__fields--active qwerty")
-      viewRowDetail.Templates.textbox(@cid, @model.key, _t("Parameters"), 'text')
-    afterRender: ->
-      @listenForInputChange()
+    html: -> false
+    insertInDOM: (rowView)-> return

   viewRowDetail.DetailViewMixins.relevant =
     html: ->


payment: save products belonging to a plan

--- client/landing/app/Applications/Dashboard.kdapplication/views/planaddproductsmodal.coffee
+++ client/landing/app/Applications/Dashboard.kdapplication/views/planaddproductsmodal.coffee
@@ -42,12 +42,14 @@
       cssClass: "formline button-field clearfix"

     @buttonField.addSubView new KDButtonView
-      title: 'Save'
-      cssClass: 'modal-clean-green'
+      title     : 'Save'
+      cssClass  : 'modal-clean-green'
+      callback  : => @save @bound 'destroy'

     @buttonField.addSubView new KDButtonView
-      title: 'cancel'
-      cssClass: 'modal-cancel'
+      title     : 'cancel'
+      cssClass  : 'modal-cancel'
+      callback  : @bound 'destroy'

     @addSubView @planExplanation
     @addSubView @planView
@@ -55,6 +57,21 @@
     @addSubView @products.getView()
     @addSubView @buttonField

+  save: (callback) ->
+    quantities = {}
+
+    plan = @getData()
+
+    @products.getItemsOrdered().forEach (item) ->
+      { planCode } = item.getData()
+      qty = item.qtyView.getValue()
+      quantities[planCode] = qty  if qty > 0
+
+    plan.quantities = quantities
+
+    plan.modify { quantities }, callback
+
+    @emit 'ProductsAdded'

   setProducts: (products) ->
     @loader.hide()
@@ -62,6 +79,6 @@
     plan = @getData()

     for product in products
-      qty = plan.quatities?[product.planCode] ? 0
+      qty = plan.quantities?[product.planCode] ? 0
       item = @products.addItem product
       item.setQuantity qty


provide scope on digest exception

provide scope on digest exception

--- src/changeDetector.coffee
+++ src/changeDetector.coffee
@@ -379,7 +379,7 @@
     index = 0
     cd = topCD
     while cd
-        scope = cd.scope
+        scope = result.scope = cd.scope

         # default watchers
         total += cd.watchList.length
@@ -439,6 +439,7 @@
     result.total = total
     result.changes = changes
     result.extraLoop = extraLoop
+    result.scope = null
     return

@@ -456,6 +457,7 @@
             changes: 0
             extraLoop: false
             src: ''
+            scope: null

         while mainLoop
             mainLoop--
@@ -479,6 +481,7 @@
     catch e
         alight.exceptionHandler e, '$scan, error in expression: ' + result.src,
             src: result.src
+            scope: result.scope
             result: result
     result.mainLoop = mainLoop
     result.totalChanges = totalChanges


Issue #9: add new output functions to the Atom plugin

--- tools/atom-plugin/language-micro/grammars/micro.cson
+++ tools/atom-plugin/language-micro/grammars/micro.cson
@@ -47,7 +47,7 @@
 	}
 	{
 		'comment': 'Built-in functions (it should be described before functions)'
-		'match': '\\b(nil|num|type|arity|floor|ceil|trunc|sin|cos|tn|arcsin|arccos|arctn|angle|pow|sqrt|exp|ln|lg|abs|random|head|tail|if|str|in|out|err|exit)\\b'
+		'match': '\\b(nil|num|type|arity|floor|ceil|trunc|sin|cos|tn|arcsin|arccos|arctn|angle|pow|sqrt|exp|ln|lg|abs|random|head|tail|if|str|in|out|outln|err|errln|exit)\\b'
 		'name': 'variable.function.micro'
 	}
 	{


double tap remove bug fix

double tap remove bug fix

--- JSKit/02_JSView.coffee
+++ JSKit/02_JSView.coffee
@@ -205,19 +205,19 @@
         switch tapnum
             when 1
                 if (@_userInteractionEnabled == true)
-                    $(@_viewSelector).unbind("click").bind "click", (event) =>
+                    $(@_viewSelector).unbind("tap").bind "tap", (event) =>
                         event.stopPropagation()
                 else
                     @_tapAction = null
-                    $(@_viewSelector).unbind("click")
+                    $(@_viewSelector).unbind("tap")

             when 2
                 if (@_userInteractionEnabled == true)
-                    $(@_viewSelector).unbind("dblclick").bind "dblclick", (event) =>
+                    $(@_viewSelector).unbind("doubletap").bind "doubletap", (event) =>
                         event.stopPropagation()
                 else
                     @_tapAction2 = null
-                    $(@_viewSelector).unbind("dblclick")
+                    $(@_viewSelector).unbind("doubletap")

     addTapGesture:(tapAction, tapnum = 1)=>
         if (tapnum == 1)


Deprecation warning for fs-form-for element in red color

--- src/coffee/formFor.coffee
+++ src/coffee/formFor.coffee
@@ -42,7 +42,7 @@
   replace: false
   template: (el, attrs) ->
     if el[0].tagName == "FS-FORM-FOR"
-      template = "
DEPRECATED: <fs-form-for></fs-form-for>
 \
+      template = "
DEPRECATED: <fs-form-for></fs-form-for>
 \

<fs-form-for> usage as element was deprecated. \
         Use <form fs-form-for> instead.
"
     else


Gallery animation is now smoother by hiding the items later.

--- src/coffee/presets.coffee
+++ src/coffee/presets.coffee
@@ -119,7 +119,7 @@
       special:
         itemPadding: 2
       # Standard rondell options
-      visibleItems: 4
+      visibleItems: 5
       theme: "dark"
       cropThumbnails: true
       center:


Remove symlink before creating a new one

--- build/tasks/install-task.coffee
+++ build/tasks/install-task.coffee
@@ -33,6 +33,8 @@

       # Create relative symbol link for apm.
       process.chdir(binDir)
-      fs.symlinkSync(path.join('..', '..', 'share', 'atom', 'resources', 'app', 'apm', 'node_modules', '.bin', 'apm'), 'apm')
+      apmSymlinkPath = path.join('..', '..', 'share', 'atom', 'resources', 'app', 'apm', 'node_modules', '.bin', 'apm')
+      rm(apmSymlinkPath)
+      fs.symlinkSync(apmSymlinkPath, 'apm')

       fs.chmodSync(path.join(shareDir, 'atom'), "755")


allow declaration of important selects and input boxes that take precedence like css important selector mod.

--- vendor/assets/javascripts/dependent-fields.js.coffee
+++ vendor/assets/javascripts/dependent-fields.js.coffee
@@ -19,28 +19,42 @@
     else
       $parent.hide(duration)

-showOrHideDependentFields = (duration = 'fast') ->
+
+showOrHideDependentFieldsSelect = (duration = 'fast') ->
   $select = $(this)

-  # fields that depend on a select option
-  $(".js-dependent-fields[data-select-id=#{$select.attr('id')}]").each ->
+  showOrHideFields = ->
     $this = $(this)
     # use attr here instead of data because we do not want jquery to cast the string into js types
     showOrHide = _.contains($this.attr('data-option-value').split('|'), $select.val())
     toggle($this, showOrHide, $this.data('method'), duration)

-  # fields that depend on a checkbox
-  $(".js-dependent-fields[data-checkbox-id=#{$select.attr('id')}]").each ->
+  $(".js-dependent-fields[data-select-id=#{$select.attr('id')}]").each showOrHideFields
+
+
+showOrHideDependentFieldsCheckbox = (duration = 'fast') ->
+  $checkbox = $(this)
+
+  showOrHideFields = ->
     $this = $(this)
-    showOrHide = $this.data('checkbox-value') == $select.is(':checked')
+    showOrHide = $this.data('checkbox-value') == $checkbox.is(':checked')
     toggle($this, showOrHide, $this.data('method'), duration)

+  $(".js-dependent-fields[data-checkbox-id=#{$checkbox.attr('id')}]").each showOrHideFields
+
+
 bind = ->
-  $('select').each _.partial(showOrHideDependentFields, 0)
-  $('select').change showOrHideDependentFields
+  $selects = $('select')
+  $selects.not('[data-important]').each _.partial(showOrHideDependentFieldsSelect, 0)
+  $selects.filter('[data-important]').each _.partial(showOrHideDependentFieldsSelect, 0)

-  $('input[type=checkbox]').each _.partial(showOrHideDependentFields, 0)
-  $('input[type=checkbox]').change showOrHideDependentFields
+  $selects.change showOrHideDependentFieldsSelect
+
+  $inputs = $('input[type=checkbox]')
+  $inputs.not('[data-important]').each _.partial(showOrHideDependentFieldsCheckbox, 0)
+  $inputs.filter('[data-important]').each _.partial(showOrHideDependentFieldsCheckbox, 0)
+
+  $inputs.change showOrHideDependentFieldsCheckbox

 @DependentFields = {


quality.coffee Style Cleanup

quality.coffee Style Cleanup

--- src/coffee/quality.coffee
+++ src/coffee/quality.coffee
@@ -7,11 +7,11 @@
     api =
       register: (id, name, options) ->
         quality = Object.freeze new Quality()
-        library[id] = makeGameState quality
+        library[id] = makeGameState quality # Qualities are stored in state form
         return this # Allow Chaining
       resolve: (q) ->
         if q instanceof Quality
           q
         else
           library[q.toString()]
-    return Object.freeze(api)
+    return Object.freeze api


update.

update.


[JS] minor clean up

[JS] minor clean up

--- app/assets/javascripts/admin/admin_assessor_automated_polling_of_session.js.coffee
+++ app/assets/javascripts/admin/admin_assessor_automated_polling_of_session.js.coffee
@@ -12,7 +12,6 @@
           if response.status == 401
             window.location.href = "/" + namespace + "s/sign_in?session_expired=true"
             return
-
           return
         dataType: 'json'
       return


Remove unused callback argument

Remove unused callback argument

--- server/mixins/page_model.coffee
+++ server/mixins/page_model.coffee
@@ -9,7 +9,7 @@

 module.exports = {
   statics:
-    populateDescriptionsFromPages: (models, callback) ->
+    populateDescriptionsFromPages: (models) ->
       deferred = Q.defer()

       populateDescriptions = (model, callback) ->


Added license to the upload.coffee file

Added license to the upload.coffee file

--- coffee/upload.coffee
+++ coffee/upload.coffee
@@ -1,3 +1,24 @@
+###
+Copyright (c) 2013 José Luis García <jl.garhdez@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in the
+Software without restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+###
+
 class window.Upload

   # This will contain all the convenience configuration for the upload class.


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/color.coffee
+++ test/color.coffee
@@ -36,17 +36,19 @@
   equals color.r(), 255
   equals color.g(), 255
   equals color.b(), 255
-
+
+test "Color should parse length 3 hex string", ->
+  color = Color('a94')
+  equals color.r(), 170
+  equals color.g(), 153
+  equals color.b(), 68
+
+test "Color should parse length 3 hex string with leading #", ->
   color = Color('#3ef')
   equals color.r(), 51
   equals color.g(), 238
   equals color.b(), 255

-  color = Color('a94')
-  equals color.r(), 170
-  equals color.g(), 153
-  equals color.b(), 68
-
 test "Color should know what Fuzzy Wuzzy Brown is", ->
   color = Color("Fuzzy Wuzzy Brown")
   equals color.r(), 196


Stub for API connection test

Stub for API connection test

--- test/front.coffee
+++ test/front.coffee
@@ -14,4 +14,8 @@

   it 'should start a WSS', ->
     @front.start
-    # test for WSS existence+    # test for WSS existence
+
+  it 'should connect to the API', ->
+    @front.start
+    # test connection to API