replacing mistakenly-deleted nodes.coffee

error: pathspec 'nodes.coffee' did not match any file(s) known to git

--- nodes.coffee
+++ nodes.coffee
@@ -0,0 +1,1569 @@
+# `nodes.coffee` contains all of the node classes for the syntax tree. Most
+# nodes are created as the result of actions in the [grammar](grammar.html),
+# but some are created by other nodes as a method of code generation. To convert
+# the syntax tree into a string of JavaScript code, call `compile()` on the root.
+
+{Scope} = require './scope'
+
+# Import the helpers we plan to use.
+{compact, flatten, extend, merge, del, starts, ends, last} = require './helpers'
+
+exports.extend = extend  # for parser
+
+# Constant functions for nodes that don't need customization.
+YES  = -> yes
+NO   = -> no
+THIS = -> this
+
+#### Base
+
+# The **Base** is the abstract base class for all nodes in the syntax tree.
+# Each subclass implements the `compileNode` method, which performs the
+# code generation for that node. To compile a node to JavaScript,
+# call `compile` on it, which wraps `compileNode` in some generic extra smarts,
+# to know when the generated code needs to be wrapped up in a closure.
+# An options hash is passed and cloned throughout, containing information about
+# the environment from higher in the tree (such as if a returned value is
+# being requested by the surrounding function), information about the current
+# scope, and indentation level.
+exports.Base = class Base
+
+  constructor: -> @tags = {}
+
+  # Common logic for determining whether to wrap this node in a closure before
+  # compiling it, or to compile directly. We need to wrap if this node is a
+  # *statement*, and it's not a *pureStatement*, and we're not at
+  # the top level of a block (which would be unnecessary), and we haven't
+  # already been asked to return the result (because statements know how to
+  # return results).
+  compile: (o, lvl) ->
+    o        = if o then extend {}, o else {}
+    o.level  = lvl if lvl?
+    node     = @unfoldSoak(o) or this
+    node.tab = o.indent
+    if o.level is LEVEL_TOP or node.isPureStatement() or not node.isStatement(o)
+      node.compileNode o
+    else
+      node.compileClosure o
+
+  # Statements converted into expressions via closure-wrapping share a scope
+  # object with their parent closure, to preserve the expected lexical scope.
+  compileClosure: (o) ->
+    if @containsPureStatement()
+      throw SyntaxError 'cannot include a pure statement in an expression.'
+    o.sharedScope = o.scope
+    Closure.wrap(this).compileNode o
+
+  # If the code generation wishes to use the result of a complex expression
+  # in multiple places, ensure that the expression is only ever evaluated once,
+  # by assigning it to a temporary variable. Pass a level to precompile.
+  cache: (o, level, reused) ->
+    unless @isComplex()
+      ref = if level then @compile o, level else this
+      [ref, ref]
+    else
+      ref = new Literal reused or o.scope.freeVariable 'ref'
+      sub = new Assign ref, this
+      if level then [sub.compile(o, level), ref.value] else [sub, ref]
+
+  # Compile to a source/variable pair suitable for looping.
+  compileLoopReference: (o, name) ->
+    src = tmp = @compile o, LEVEL_LIST
+    unless NUMBER.test(src) or IDENTIFIER.test(src) and o.scope.check(src, immediate: on)
+      src = "#{ tmp = o.scope.freeVariable name } = #{src}"
+    [src, tmp]
+
+  # Convenience method to grab the current indentation level, plus tabbing in.
+  idt: (tabs) ->
+    (@tab or '') + Array((tabs or 0) + 1).join TAB
+
+  # Construct a node that returns the current node's result.
+  # Note that this is overridden for smarter behavior for
+  # many statement nodes (eg If, For)...
+  makeReturn: -> new Return this
+
+  # Does this node, or any of its children, contain a node of a certain kind?
+  # Recursively traverses down the *children* of the nodes, yielding to a block
+  # and returning true when the block finds a match. `contains` does not cross
+  # scope boundaries.
+  contains: (block, arg) ->
+    contains = no
+    @traverseChildren false, (node, arg) ->
+      if (rearg = block node, arg) is true then not contains = true else if arg? then rearg
+    , arg
+    contains
+
+  # Is this node of a certain type, or does it contain the type?
+  containsType: (type) ->
+    this instanceof type or @contains (node) -> node instanceof type
+
+  # Convenience for the most common use of contains. Does the node contain
+  # a pure statement?
+  containsPureStatement: ->
+    @isPureStatement() or @contains (node, func) ->
+      func(node) or if node instanceof While or node instanceof For
+        (node) -> node instanceof Return
+      else func
+    , (node) -> node.isPureStatement()
+
+  # `toString` representation of the node, for inspecting the parse tree.
+  # This is what `coffee --nodes` prints out.
+  toString: (idt, override) ->
+    idt or= ''
+    children = (child.toString idt + TAB for child in @collectChildren()).join('')
+    klass = override or @constructor.name + if @soakNode then '?' else ''
+    '\n' + idt + klass + children
+
+  # Passes each child to a function, breaking when the function returns `false`.
+  eachChild: (func) ->
+    return this unless @children
+    for attr in @children when @[attr]
+      for child in flatten [@[attr]]
+        return this if func(child) is false
+    this
+
+  collectChildren: ->
+    nodes = []
+    @eachChild (node) -> nodes.push node
+    nodes
+
+  traverseChildren: (crossScope, func, arg) ->
+    @eachChild (child) ->
+      return false if (arg = func child, arg) is false
+      child.traverseChildren crossScope, func, arg
+
+  invert: -> new Op '!', this
+
+  unwrapAll: ->
+    node = this
+    continue until node is node = node.unwrap()
+    node
+
+  # Default implementations of the common node properties and methods. Nodes
+  # will override these with custom logic, if needed.
+  children: []
+
+  isStatement     : NO
+  isPureStatement : NO
+  isComplex       : YES
+  isChainable     : NO
+  isAssignable    : NO
+
+  unwrap     : THIS
+  unfoldSoak : NO
+
+  # Is this node used to assign a certain variable?
+  assigns: NO
+
+#### Expressions
+
+# The expressions body is the list of expressions that forms the body of an
+# indented block of code -- the implementation of a function, a clause in an
+# `if`, `switch`, or `try`, and so on...
+exports.Expressions = class Expressions extends Base
+
+  children: ['expressions']
+
+  isStatement: YES
+
+  constructor: (nodes) ->
+    super()
+    @expressions = compact flatten nodes or []
+
+  # Tack an expression on to the end of this expression list.
+  push: (node) ->
+    @expressions.push node
+    this
+
+  # Remove and return the last expression of this expression list.
+  pop: -> @expressions.pop()
+
+  # Add an expression at the beginning of this expression list.
+  unshift: (node) ->
+    @expressions.unshift node
+    this
+
+  # If this Expressions consists of just a single node, unwrap it by pulling
+  # it back out.
+  unwrap: -> if @expressions.length is 1 then @expressions[0] else this
+
+  # Is this an empty block of code?
+  isEmpty: -> not @expressions.length
+
+  # An Expressions node does not return its entire body, rather it
+  # ensures that the final expression is returned.
+  makeReturn: ->
+    for end, idx in @expressions by -1 when end not instanceof Comment
+      @expressions[idx] = end.makeReturn()
+      break
+    this
+
+  # An **Expressions** is the only node that can serve as the root.
+  compile: (o, level) ->
+    o or= {}
+    if o.scope then super o, level else @compileRoot o
+
+  compileNode: (o) ->
+    @tab = o.indent
+    (@compileExpression node, o for node in @expressions).join '\n'
+
+  # If we happen to be the top-level **Expressions**, wrap everything in
+  # a safety closure, unless requested not to.
+  # It would be better not to generate them in the first place, but for now,
+  # clean up obvious double-parentheses.
+  compileRoot: (o) ->
+    o.indent = @tab = if o.bare then '' else TAB
+    o.scope  = new Scope null, this, null
+    o.level  = LEVEL_TOP
+    code     = @compileWithDeclarations o
+    code     = code.replace TRAILING_WHITESPACE, ''
+    if o.bare then code else "(function() {\n#{code}\n}).call(this);\n"
+
+  # Compile the expressions body for the contents of a function, with
+  # declarations of all inner variables pushed up to the top.
+  compileWithDeclarations: (o) ->
+    code    = @compileNode o
+    {scope} = o
+    if scope.hasAssignments this
+      code = "#{@tab}var #{ multident scope.compiledAssignments(), @tab };\n#{code}"
+    if not o.globals and o.scope.hasDeclarations this
+      code = "#{@tab}var #{ scope.compiledDeclarations() };\n#{code}"
+    code
+
+  # Compiles a single expression within the expressions body. If we need to
+  # return the result, and it's an expression, simply return it. If it's a
+  # statement, ask the statement to do so.
+  compileExpression: (node, o) ->
+    node = node.unwrapAll()
+    node = node.unfoldSoak(o) or node
+    node.tags.front = on
+    o.level = LEVEL_TOP
+    code    = node.compile o
+    if node.isStatement o then code else @tab + code + ';'
+
+  # Wrap up the given nodes as an **Expressions**, unless it already happens
+  # to be one.
+  @wrap: (nodes) ->
+    return nodes[0] if nodes.length is 1 and nodes[0] instanceof Expressions
+    new Expressions nodes
+
+#### Literal
+
+# Literals are static values that can be passed through directly into
+# JavaScript without translation, such as: strings, numbers,
+# `true`, `false`, `null`...
+exports.Literal = class Literal extends Base
+
+  constructor: (@value) -> super()
+
+  makeReturn: -> if @isStatement() then this else super()
+
+  # Break and continue must be treated as pure statements -- they lose their
+  # meaning when wrapped in a closure.
+  isPureStatement: -> @value in ['break', 'continue', 'debugger']
+
+  isAssignable: -> IDENTIFIER.test @value
+
+  isComplex: NO
+
+  assigns: (name) -> name is @value
+
+  compile: -> if @value.reserved then "\"#{@value}\"" else @value
+
+  toString: -> ' "' + @value + '"'
+
+#### Return
+
+# A `return` is a *pureStatement* -- wrapping it in a closure wouldn't
+# make sense.
+exports.Return = class Return extends Base
+
+  children: ['expression']
+
+  isStatement    : YES
+  isPureStatement: YES
+
+  constructor: (@expression) -> super()
+
+  makeReturn: THIS
+
+  compile: (o, level) ->
+    expr = @expression?.makeReturn()
+    if expr and expr not instanceof Return then expr.compile o, level else super o, level
+
+  compileNode: (o) ->
+    o.level = LEVEL_PAREN
+    @tab + "return#{ if @expression then ' ' + @expression.compile o else '' };"
+
+#### Value
+
+# A value, variable or literal or parenthesized, indexed or dotted into,
+# or vanilla.
+exports.Value = class Value extends Base
+
+  children: ['base', 'properties']
+
+  # A **Value** has a base and a list of property accesses.
+  constructor: (base, props, tag) ->
+    return base if not props and base instanceof Value
+    @base       = base
+    @properties = props or []
+    @tags       = if tag then {(tag): on} else {}
+
+  # Add a property access to the list.
+  push: (prop) ->
+    @properties.push prop
+    this
+
+  hasProperties: -> !!@properties.length
+
+  # Some boolean checks for the benefit of other nodes.
+  isArray        : -> not @properties.length and @base instanceof Arr
+  isObject       : -> not @properties.length and @base instanceof Obj
+  isComplex      : -> @hasProperties() or @base.isComplex()
+  isAssignable   : -> @hasProperties() or @base.isAssignable()
+  isSimpleNumber : -> @base instanceof Literal and SIMPLENUM.test @base.value
+  isAtomic       : ->
+    for node in @properties.concat @base
+      return no if node.soakNode or node instanceof Call
+    yes
+
+  isStatement : (o)    -> not @properties.length and @base.isStatement o
+  assigns     : (name) -> not @properties.length and @base.assigns name
+
+  makeReturn: -> if @properties.length then super() else @base.makeReturn()
+
+  # The value can be unwrapped as its inner node, if there are no attached
+  # properties.
+  unwrap: -> if @properties.length then this else @base
+
+  # A reference has base part (`this` value) and name part.
+  # We cache them separately for compiling complex expressions.
+  # `a()[b()] ?= c` -> `(_base = a())[_name = b()] ? _base[_name] = c`
+  cacheReference: (o) ->
+    name = last @properties
+    if @properties.length < 2 and not @base.isComplex() and not name?.isComplex()
+      return [this, this]  # `a` `a.b`
+    base = new Value @base, @properties.slice 0, -1
+    if base.isComplex()  # `a().b`
+      bref = new Literal o.scope.freeVariable 'base'
+      base = new Value new Parens new Assign bref, base
+    return [base, bref] unless name  # `a()`
+    if name.isComplex()  # `a[b()]`
+      nref = new Literal o.scope.freeVariable 'name'
+      name = new Index new Assign nref, name.index
+      nref = new Index nref
+    [base.push(name), new Value(bref or base.base, [nref or name])]
+
+  # We compile a value to JavaScript by compiling and joining each property.
+  # Things get much more insteresting if the chain of properties has *soak*
+  # operators `?.` interspersed. Then we have to take care not to accidentally
+  # evaluate anything twice when building the soak chain.
+  compileNode: (o) ->
+    @base.tags.front = @tags.front
+    props = @properties
+    code  = @base.compile o, if props.length then LEVEL_ACCESS else null
+    code  = "(#{code})" if props[0] instanceof Accessor and @isSimpleNumber()
+    code += prop.compile o for prop in props
+    code
+
+  # Unfold a soak into an `If`: `a?.b` -> `a.b if a?`
+  unfoldSoak: (o) ->
+    if ifn = @base.unfoldSoak o
+      Array::push.apply ifn.body.properties, @properties
+      return ifn
+    for prop, i in @properties when prop.soakNode
+      prop.soakNode = off
+      fst = new Value @base, @properties.slice 0, i
+      snd = new Value @base, @properties.slice i
+      if fst.isComplex()
+        ref = new Literal o.scope.freeVariable 'ref'
+        fst = new Parens new Assign ref, fst
+        snd.base = ref
+      return new If new Existence(fst), snd, soak: on
+    null
+
+#### Comment
+
+# CoffeeScript passes through block comments as JavaScript block comments
+# at the same position.
+exports.Comment = class Comment extends Base
+
+  isPureStatement: YES
+
+  constructor: (@comment) -> super()
+
+  makeReturn: THIS
+
+  compileNode: (o) -> @tab + '/*' + multident(@comment, @tab) + '*/'
+
+#### Call
+
+# Node for a function invocation. Takes care of converting `super()` calls into
+# calls against the prototype's function of the same name.
+exports.Call = class Call extends Base
+
+  children: ['variable', 'args']
+
+  constructor: (variable, @args, @soakNode) ->
+    super()
+    @isNew    = false
+    @isSuper  = variable is 'super'
+    @variable = if @isSuper then null else variable
+    @args   or= []
+
+  # Tag this invocation as creating a new instance.
+  newInstance: ->
+    @isNew = true
+    this
+
+  # Grab the reference to the superclass' implementation of the current method.
+  superReference: (o) ->
+    {method} = o.scope
+    throw SyntaxError 'cannot call super outside of a function.' unless method
+    {name} = method
+    throw SyntaxError 'cannot call super on an anonymous function.' unless name
+    if method.klass
+      "#{method.klass}.__super__.#{name}"
+    else
+      "#{name}.__super__.constructor"
+
+  # Soaked chained invocations unfold into if/else ternary structures.
+  unfoldSoak: (o) ->
+    if @soakNode
+      if @variable
+        return ifn if ifn = If.unfoldSoak o, this, 'variable'
+        [left, rite] = new Value(@variable).cacheReference o
+      else
+        left = new Literal @superReference o
+        rite = new Value left
+      rite = new Call rite, @args
+      rite.isNew = @isNew
+      left = new Literal "typeof #{ left.compile o } === \"function\""
+      return new If left, new Value(rite), soak: yes
+    call = this
+    list = []
+    loop
+      if call.variable instanceof Call
+        list.push call
+        call = call.variable
+        continue
+      break unless call.variable instanceof Value
+      list.push call
+      break unless (call = call.variable.base) instanceof Call
+    for call in list.reverse()
+      if ifn
+        if call.variable instanceof Call
+          call.variable = ifn
+        else
+          call.variable.base = ifn
+      ifn = If.unfoldSoak o, call, 'variable'
+    ifn
+
+  # Compile a vanilla function call.
+  compileNode: (o) ->
+    @variable?.tags.front = @tags.front
+    for arg in @args when arg instanceof Splat
+      return @compileSplat o
+    args = (arg.compile o, LEVEL_LIST for arg in @args).join ', '
+    if @isSuper
+      @compileSuper args, o
+    else
+      (if @isNew then 'new ' else '') + @variable.compile(o, LEVEL_ACCESS) + "(#{args})"
+
+  # `super()` is converted into a call against the superclass's implementation
+  # of the current function.
+  compileSuper: (args, o) ->
+    "#{@superReference(o)}.call(this#{ if args.length then ', ' else '' }#{args})"
+
+  # If you call a function with a splat, it's converted into a JavaScript
+  # `.apply()` call to allow an array of arguments to be passed.
+  # If it's a constructor, then things get real tricky. We have to inject an
+  # inner constructor in order to be able to pass the varargs.
+  compileSplat: (o) ->
+    splatargs = Splat.compileSplattedArray @args, o
+    return "#{ @superReference o }.apply(this, #{splatargs})" if @isSuper
+    unless @isNew
+      base = new Value @variable
+      if (name = base.properties.pop()) and base.isComplex()
+        ref = o.scope.freeVariable 'this'
+        fun = "(#{ref} = #{ base.compile o, LEVEL_LIST })#{ name.compile o }"
+      else
+        fun = ref = base.compile o, LEVEL_ACCESS
+        fun += name.compile o if name
+      return "#{fun}.apply(#{ref}, #{splatargs})"
+    idt = @idt 1
+    """
+    (function(func, args, ctor) {
+    #{idt}ctor.prototype = func.prototype;
+    #{idt}var child = new ctor, result = func.apply(child, args);
+    #{idt}return typeof result === "object" ? result : child;
+    #{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatargs}, function() {})
+    """
+
+#### Extends
+
+# Node to extend an object's prototype with an ancestor object.
+# After `goog.inherits` from the
+# [Closure Library](http://closure-library.googlecode.com/svn/docs/closureGoogBase.js.html).
+exports.Extends = class Extends extends Base
+
+  children: ['child', 'parent']
+
+  constructor: (@child, @parent) -> super()
+
+  # Hooks one constructor into another's prototype chain.
+  compile: (o) ->
+    new Call(new Value(new Literal utility 'extends'), [@child, @parent]).compile o
+
+#### Accessor
+
+# A `.` accessor into a property of a value, or the `::` shorthand for
+# an accessor into the object's prototype.
+exports.Accessor = class Accessor extends Base
+
+  children: ['name']
+
+  constructor: (@name, tag) ->
+    super()
+    @proto    = if tag is 'prototype' then '.prototype' else ''
+    @soakNode = tag is 'soak'
+
+  compile: (o) ->
+    name = @name.compile o
+    @proto + if IS_STRING.test name then "[#{name}]" else ".#{name}"
+
+  isComplex: NO
+
+#### Index
+
+# A `[ ... ]` indexed accessor into an array or object.
+exports.Index = class Index extends Base
+
+  children: ['index']
+
+  constructor: (@index) -> super()
+
+  compile: (o) ->
+    (if @proto then '.prototype' else '') + "[#{ @index.compile o, LEVEL_PAREN }]"
+
+  isComplex: -> @index.isComplex()
+
+#### Obj
+
+# An object literal, nothing fancy.
+exports.Obj = class Obj extends Base
+
+  children: ['properties']
+
+  constructor: (props) ->
+    super()
+    @objects = @properties = props or []
+
+  compileNode: (o) ->
+    for prop, i in @properties when (prop.variable or prop).base instanceof Parens
+      return @compileDynamic o, i
+    o.indent = @idt 1
+    nonComments = (prop for prop in @properties when prop not instanceof Comment)
+    lastNoncom  = last nonComments
+    props = for prop, i in @properties
+      join = if i is @properties.length - 1
+        ''
+      else if prop is lastNoncom or prop instanceof Comment
+        '\n'
+      else
+        ',\n'
+      indent = if prop instanceof Comment then '' else @idt 1
+      if prop instanceof Value and prop.tags.this
+        prop = new Assign prop.properties[0].name, prop, 'object'
+      else if prop not instanceof Assign and prop not instanceof Comment
+        prop = new Assign prop, prop, 'object'
+      indent + prop.compile(o) + join
+    props = props.join ''
+    obj   = "{#{ if props then '\n' + props + '\n' + @idt() else '' }}"
+    if @tags.front then "(#{obj})" else obj
+
+  compileDynamic: (o, idx) ->
+    obj  = o.scope.freeVariable 'obj'
+    code = "#{obj} = #{ new Obj(@properties.slice 0, idx).compile o }, "
+    for prop, i in @properties.slice idx
+      if prop instanceof Assign
+        key   = prop.variable.compile o, LEVEL_PAREN
+        code += "#{obj}[#{key}] = #{ prop.value.compile o, LEVEL_LIST }, "
+        continue
+      if prop instanceof Comment
+        code += prop.compile(o) + ' '
+        continue
+      [sub, ref] = prop.base.cache o, LEVEL_LIST, ref
+      code += "#{obj}[#{sub}] = #{ref}, "
+    code += obj
+    if o.level <= LEVEL_PAREN then code else "(#{code})"
+
+  assigns: (name) ->
+    for prop in @properties when prop.assigns name then return yes
+    no
+
+#### Arr
+
+# An array literal.
+exports.Arr = class Arr extends Base
+
+  children: ['objects']
+
+  constructor: (objs) ->
+    super()
+    @objects = objs or []
+
+  compileNode: (o) ->
+    o.indent = @idt 1
+    for obj in @objects when obj instanceof Splat
+      return Splat.compileSplattedArray @objects, o
+    objects = []
+    for obj, i in @objects
+      code = obj.compile o, LEVEL_LIST
+      objects.push (if obj instanceof Comment
+        "\n#{code}\n#{o.indent}"
+      else if i is @objects.length - 1
+        code
+      else
+        code + ', '
+      )
+    objects = objects.join ''
+    if 0 < objects.indexOf '\n'
+      "[\n#{o.indent}#{objects}\n#{@tab}]"
+    else
+      "[#{objects}]"
+
+  assigns: (name) ->
+    for obj in @objects when obj.assigns name then return yes
+    no
+
+#### Class
+
+# The CoffeeScript class definition.
+exports.Class = class Class extends Base
+
+  children: ['variable', 'parent', 'properties']
+
+  isStatement: YES
+
+  # Initialize a **Class** with its name, an optional superclass, and a
+  # list of prototype property assignments.
+  constructor: (@variable, @parent, props) ->
+    super()
+    @properties = props or []
+    @returns    = false
+
+  makeReturn: ->
+    @returns = true
+    this
+
+  # Instead of generating the JavaScript string directly, we build up the
+  # equivalent syntax tree and compile that, in pieces. You can see the
+  # constructor, property assignments, and inheritance getting built out below.
+  compileNode: (o) ->
+    variable   = @variable or new Literal o.scope.freeVariable 'ctor'
+    extension  = @parent  and new Extends variable, @parent
+    props      = new Expressions
+    me         = null
+    className  = variable.compile o
+    constScope = null
+
+    if @parent
+      applied = new Value @parent, [new Accessor new Literal 'apply']
+      constructor = new Code [], new Expressions [
+        new Call applied, [new Literal('this'), new Literal('arguments')]
+      ]
+    else
+      constructor = new Code [], new Expressions [new Return new Literal 'this']
+
+    for prop in @properties
+      {variable: pvar, value: func} = prop
+      if pvar and pvar.base.value is 'constructor'
+        if func not instanceof Code
+          [func, ref] = func.cache o
+          props.push func if func isnt ref
+          apply = new Call new Value(ref, [new Accessor new Literal 'apply']),
+                           [new Literal('this'), new Literal('arguments')]
+          func  = new Code [], new Expressions([apply])
+        throw SyntaxError 'cannot define a constructor as a bound function.' if func.bound
+        func.name = className
+        func.body.push new Return new Literal 'this'
+        variable = new Value variable
+        variable.namespaced = 0 < className.indexOf '.'
+        constructor = func
+        constructor.comment = props.expressions.pop() if last(props.expressions) instanceof Comment
+        continue
+      if func instanceof Code and func.bound
+        if prop.context is 'this'
+          func.context = className
+        else
+          func.bound = false
+          constScope or= new Scope o.scope, constructor.body, constructor
+          me or= constScope.freeVariable 'this'
+          pname = pvar.compile o
+          constructor.body.push    new Return new Literal 'this' if constructor.body.isEmpty()
+          constructor.body.unshift new Literal "this.#{pname} = function(){ return #{className}.prototype.#{pname}.apply(#{me}, arguments); }"
+      if pvar
+        access = if prop.context is 'this' then pvar.properties[0] else new Accessor(pvar, 'prototype')
+        val    = new Value variable, [access]
+        prop   = new Assign val, func
+      props.push prop
+
+    constructor.className = className.match /[$\w]+$/
+    constructor.body.unshift new Literal "#{me} = this" if me
+    o.sharedScope = constScope
+    construct  = @tab + new Assign(variable, constructor).compile(o) + ';'
+    construct += '\n' + @tab + extension.compile(o) + ';' if extension
+    construct += '\n' + props.compile o                   if !props.isEmpty()
+    construct += '\n' + new Return(variable).compile o    if @returns
+    construct
+
+#### Assign
+
+# The **Assign** is used to assign a local variable to value, or to set the
+# property of an object -- including within object literals.
+exports.Assign = class Assign extends Base
+
+  # Matchers for detecting class/method names
+  METHOD_DEF: /^(?:(\S+)\.prototype\.)?([$A-Za-z_][$\w]*)$/
+
+  children: ['variable', 'value']
+
+  constructor: (@variable, @value, @context) -> super()
+
+  assigns: (name) ->
+    @[if @context is 'object' then 'value' else 'variable'].assigns name
+
+  unfoldSoak: (o) -> If.unfoldSoak o, this, 'variable'
+
+  # Compile an assignment, delegating to `compilePatternMatch` or
+  # `compileSplice` if appropriate. Keep track of the name of the base object
+  # we've been assigned to, for correct internal references. If the variable
+  # has not been seen yet within the current scope, declare it.
+  compileNode: (o) ->
+    if isValue = @variable instanceof Value
+      return @compilePatternMatch o if @variable.isArray() or @variable.isObject()
+      return @compileConditional  o if @context in ['||=', '&&=', '?=']
+    name = @variable.compile o, LEVEL_LIST
+    if @value instanceof Code and match = @METHOD_DEF.exec name
+      @value.name  = match[2]
+      @value.klass = match[1]
+    val = @value.compile o, LEVEL_LIST
+    return "#{name}: #{val}" if @context is 'object'
+    unless @variable.isAssignable()
+      throw SyntaxError "\"#{ @variable.compile o }\" cannot be assigned."
+    o.scope.find name unless isValue and (@variable.hasProperties() or @variable.namespaced)
+    val = name + " #{ @context or '=' } " + val
+    if o.level <= LEVEL_LIST then val else "(#{val})"
+
+  # Brief implementation of recursive pattern matching, when assigning array or
+  # object literals to a value. Peeks at their properties to assign inner names.
+  # See the [ECMAScript Harmony Wiki](http://wiki.ecmascript.org/doku.php?id=harmony:destructuring)
+  # for details.
+  compilePatternMatch: (o) ->
+    top       = o.level is LEVEL_TOP
+    {value}   = this
+    {objects} = @variable.base
+    return value.compile o unless olength = objects.length
+    isObject = @variable.isObject()
+    if top and olength is 1 and (obj = objects[0]) not instanceof Splat
+      # Unroll simplest cases: `{v} = x` -> `v = x.v`
+      if obj instanceof Assign
+        {variable: {base: idx}, value: obj} = obj
+      else
+        if obj.base instanceof Parens
+          [obj, idx] = new Value(obj.unwrapAll()).cacheReference o
+        else
+          idx = if isObject
+            if obj.tags.this then obj.properties[0].name else obj
+          else
+            new Literal 0
+      acc   = IDENTIFIER.test idx.unwrap().value or 0
+      value = new Value value
+      value.properties.push new (if acc then Accessor else Index) idx
+      return new Assign(obj, value).compile o
+    valVar  = value.compile o, LEVEL_LIST
+    assigns = []
+    splat   = false
+    if not IDENTIFIER.test(valVar) or @variable.assigns(valVar)
+      assigns.push "#{ ref = o.scope.freeVariable 'ref' } = #{valVar}"
+      valVar = ref
+    for obj, i in objects
+      # A regular array pattern-match.
+      idx = i
+      if isObject
+        if obj instanceof Assign
+          # A regular object pattern-match.
+          {variable: {base: idx}, value: obj} = obj
+        else
+          # A shorthand `{a, b, @c} = val` pattern-match.
+          if obj.base instanceof Parens
+            [obj, idx] = new Value(obj.unwrapAll()).cacheReference o
+          else
+            idx = if obj.tags.this then obj.properties[0].name else obj
+      if not splat and obj instanceof Splat
+        val   = new Literal obj.compileValue o, valVar, i, olength - i - 1
+        splat = true
+      else
+        if typeof idx isnt 'object'
+          idx = new Literal(if splat then "#{valVar}.length - #{ olength - idx }" else idx)
+          acc = no
+        else
+          acc = isObject and IDENTIFIER.test idx.unwrap().value or 0
+        val = new Value new Literal(valVar), [new (if acc then Accessor else Index) idx]
+      assigns.push new Assign(obj, val).compile o, LEVEL_LIST
+    assigns.push valVar unless top
+    code = assigns.join ', '
+    if o.level < LEVEL_LIST then code else "(#{code})"
+
+  # When compiling a conditional assignment, take care to ensure that the
+  # operands are only evaluated once, even though we have to reference them
+  # more than once.
+  compileConditional: (o) ->
+    [left, rite] = @variable.cacheReference o
+    return new Op(@context.slice(0, -1), left, new Assign(rite, @value)).compile o
+
+#### Code
+
+# A function definition. This is the only node that creates a new Scope.
+# When for the purposes of walking the contents of a function body, the Code
+# has no *children* -- they're within the inner scope.
+exports.Code = class Code extends Base
+
+  children: ['params', 'body']
+
+  constructor: (params, body, tag) ->
+    super()
+    @params  = params or []
+    @body    = body   or new Expressions
+    @bound   = tag is 'boundfunc'
+    @context = 'this' if @bound
+
+  # Compilation creates a new scope unless explicitly asked to share with the
+  # outer scope. Handles splat parameters in the parameter list by peeking at
+  # the JavaScript `arguments` objects. If the function is bound with the `=>`
+  # arrow, generates a wrapper that saves the current value of `this` through
+  # a closure.
+  compileNode: (o) ->
+    sharedScope = del o, 'sharedScope'
+    o.scope     = scope = sharedScope or new Scope o.scope, @body, this
+    o.indent    = @idt 1
+    empty       = @body.expressions.length is 0
+    delete o.bare
+    delete o.globals
+    splat = undefined
+    params = []
+    for param, i in @params
+      if splat
+        if param.attach
+          param.assign = new Assign new Value new Literal('this'), [new Accessor param.value]
+          @body.expressions.splice splat.index + 1, 0, param.assign
+        splat.trailings.push param
+      else
+        if param.attach
+          {value} = param
+          [param, param.splat] = [new Literal(scope.freeVariable 'arg'), param.splat]
+          @body.unshift new Assign new Value(new Literal('this'), [new Accessor value]), param
+        if param.splat
+          splat           = new Splat param.value
+          splat.index     = i
+          splat.trailings = []
+          splat.arglength = @params.length
+          @body.unshift splat
+        else
+          params.push param
+    scope.startLevel()
+    @body.makeReturn() unless empty or @noReturn
+    params = for param in params
+      scope.parameter param = param.compile o
+      param
+    comm  = if @comment then @comment.compile(o) + '\n' else ''
+    o.indent = @idt 2 if @className
+    idt  = @idt 1
+    code = if @body.expressions.length then "\n#{ @body.compileWithDeclarations o }\n" else ''
+    if @className
+      open  = "(function() {\n#{comm}#{idt}function #{@className}("
+      close = "#{ code and idt }}\n#{idt}return #{@className};\n#{@tab}})()"
+    else
+      open  = "function("
+      close = "#{ code and @tab }}"
+    func = "#{open}#{ params.join ', ' }) {#{code}#{close}"
+    scope.endLevel()
+    return "#{ utility 'bind' }(#{func}, #{@context})" if @bound
+    if @tags.front then "(#{func})" else func
+
+  # Short-circuit `traverseChildren` method to prevent it from crossing scope boundaries
+  # unless `crossScope` is `true`.
+  traverseChildren: (crossScope, func) -> super(crossScope, func) if crossScope
+
+#### Param
+
+# A parameter in a function definition. Beyond a typical Javascript parameter,
+# these parameters can also attach themselves to the context of the function,
+# as well as be a splat, gathering up a group of parameters into an array.
+exports.Param = class Param extends Base
+
+  children: ['name']
+
+  constructor: (name, @attach, @splat) ->
+    super()
+    @value = new Literal @name = name
+
+  compile: (o) -> @value.compile o, LEVEL_LIST
+
+  toString: ->
+    {name} = this
+    name   = '@' + name if @attach
+    name  += '...'      if @splat
+    new Literal(name).toString()
+
+#### Splat
+
+# A splat, either as a parameter to a function, an argument to a call,
+# or as part of a destructuring assignment.
+exports.Splat = class Splat extends Base
+
+  children: ['name']
+
+  isAssignable: YES
+
+  constructor: (name) ->
+    super()
+    @name = if name.compile then name else new Literal name
+
+  assigns: (name) -> @name.assigns name
+
+  compile: (o) -> if @index? then @compileParam o else @name.compile o
+
+  # Compiling a parameter splat means recovering the parameters that succeed
+  # the splat in the parameter list, by slicing the arguments object.
+  compileParam: (o) ->
+    name = @name.compile o
+    o.scope.find name
+    end = ''
+    if @trailings.length
+      len = o.scope.freeVariable 'len'
+      o.scope.assign len, 'arguments.length'
+      variadic = o.scope.freeVariable 'result'
+      o.scope.assign variadic, len + ' >= ' + @arglength
+      end = if @trailings.length then ", #{len} - #{@trailings.length}"
+      for trailing, idx in @trailings
+        if trailing.attach
+          assign        = trailing.assign
+          trailing      = new Literal o.scope.freeVariable 'arg'
+          assign.value  = trailing
+        pos = @trailings.length - idx
+        o.scope.assign trailing.compile(o),
+          "arguments[#{variadic} ? #{len} - #{pos} : #{ @index + idx }]"
+    "#{name} = #{ utility 'slice' }.call(arguments, #{@index}#{end})"
+
+  # A compiling a splat as a destructuring assignment means slicing arguments
+  # from the right-hand-side's corresponding array.
+  compileValue: (o, name, index, trailings) ->
+    trail = if trailings then ", #{name}.length - #{trailings}" else ''
+    "#{ utility 'slice' }.call(#{name}, #{index}#{trail})"
+
+  # Utility function that converts arbitrary number of elements, mixed with
+  # splats, to a proper array
+  @compileSplattedArray: (list, o) ->
+    args = []
+    end  = -1
+    for arg, i in list
+      code = arg.compile o, LEVEL_LIST
+      prev = args[end]
+      if arg not instanceof Splat
+        if prev and starts(prev, '[') and ends(prev, ']')
+          args[end] = "#{prev.slice 0, -1}, #{code}]"
+          continue
+        if prev and starts(prev, '.concat([') and ends(prev, '])')
+          args[end] = "#{prev.slice 0, -2}, #{code}])"
+          continue
+        code = "[#{code}]"
+      args[++end] = if i is 0 then code else ".concat(#{code})"
+    args.join ''
+
+#### While
+
+# A while loop, the only sort of low-level loop exposed by CoffeeScript. From
+# it, all other loops can be manufactured. Useful in cases where you need more
+# flexibility or more speed than a comprehension can provide.
+exports.While = class While extends Base
+
+  children: ['condition', 'guard', 'body']
+
+  isStatement: YES
+
+  constructor: (condition, opts) ->
+    super()
+    @condition = if opts?.invert then condition.invert() else condition
+    @guard     = opts?.guard
+
+  addBody: (body) ->
+    @body = body
+    this
+
+  makeReturn: ->
+    @returns = true
+    this
+
+  # The main difference from a JavaScript *while* is that the CoffeeScript
+  # *while* can be used as a part of a larger expression -- while loops may
+  # return an array containing the computed result of each iteration.
+  compileNode: (o) ->
+    o.indent = @idt 1
+    set      = ''
+    {body}   = this
+    if body.isEmpty()
+      body = ''
+    else
+      if o.level > LEVEL_TOP or @returns
+        rvar = o.scope.freeVariable 'result'
+        set  = "#{@tab}#{rvar} = [];\n"
+        body = Push.wrap rvar, body if body
+      body = Expressions.wrap [new If @guard, body] if @guard
+      body = "\n#{ body.compile o, LEVEL_TOP }\n#{@tab}"
+    code = set + @tab + "while (#{ @condition.compile o, LEVEL_PAREN }) {#{body}}"
+    if @returns
+      o.indent = @tab
+      code += '\n' + new Return(new Literal rvar).compile o
+    code
+
+#### Op
+
+# Simple Arithmetic and logical operations. Performs some conversion from
+# CoffeeScript operations into their JavaScript equivalents.
+exports.Op = class Op extends Base
+
+  # The map of conversions from CoffeeScript to JavaScript symbols.
+  CONVERSIONS:
+    '==': '==='
+    '!=': '!=='
+    'of': 'in'
+
+  # The map of invertible operators.
+  INVERSIONS:
+    '!==': '==='
+    '===': '!=='
+
+  children: ['first', 'second']
+
+  constructor: (op, first, second, flip) ->
+    return new In first, second if op is 'in'
+    if op is 'new'
+      return first.newInstance() if first instanceof Call
+      first = new Parens first   if first instanceof Code and first.bound
+    super()
+    @operator = @CONVERSIONS[op] or op
+    @first    = first
+    @second   = second
+    @flip     = !!flip
+
+  isUnary: -> not @second
+
+  # Am I capable of
+  # [Python-style comparison chaining](http://docs.python.org/reference/expressions.html#notin)?
+  isChainable: -> @operator in ['<', '>', '>=', '<=', '===', '!==']
+
+  invert: ->
+    if op = @INVERSIONS[@operator]
+      @operator = op
+      this
+    else if @second
+      new Parens(this).invert()
+    else
+      super()
+
+  unfoldSoak: (o) ->
+    @operator in ['++', '--', 'delete'] and If.unfoldSoak o, this, 'first'
+
+  compileNode: (o) ->
+    return @compileUnary     o if @isUnary()
+    return @compileChain     o if @isChainable() and @first.isChainable()
+    return @compileExistence o if @operator is '?'
+    @first.tags.front = @tags.front
+    "#{ @first.compile o, LEVEL_OP } #{@operator} #{ @second.compile o, LEVEL_OP }"
+
+  # Mimic Python's chained comparisons when multiple comparison operators are
+  # used sequentially. For example:
+  #
+  #     bin/coffee -e 'console.log 50 < 65 > 10'
+  #     true
+  compileChain: (o) ->
+    [@first.second, shared] = @first.second.cache o
+    fst  = @first .compile o, LEVEL_OP
+    fst  = fst.slice 1, -1 if fst.charAt(0) is '('
+    code = "#{fst} && #{ shared.compile o } #{@operator} #{ @second.compile o, LEVEL_OP }"
+    if o.level < LEVEL_OP then code else "(#{code})"
+
+  compileExistence: (o) ->
+    if @first.isComplex()
+      ref = o.scope.freeVariable 'ref'
+      fst = new Parens new Assign new Literal(ref), @first
+    else
+      fst = @first
+      ref = fst.compile o
+    new Existence(fst).compile(o) + " ? #{ref} : #{ @second.compile o, LEVEL_LIST }"
+
+  # Compile a unary **Op**.
+  compileUnary: (o) ->
+    parts = [op = @operator]
+    parts.push ' ' if op in ['new', 'typeof', 'delete'] or
+                      op in ['+', '-'] and @first instanceof Op and @first.operator is op
+    parts.push @first.compile o, LEVEL_OP
+    parts.reverse() if @flip
+    parts.join ''
+
+  toString: (idt) -> super idt, @constructor.name + ' ' + @operator
+
+#### In
+exports.In = class In extends Base
+
+  children: ['object', 'array']
+
+  constructor: (@object, @array) -> super()
+
+  invert: ->
+    @negated = not @negated
+    this
+
+  compileNode: (o) ->
+    if @array instanceof Value and @array.isArray()
+      @compileOrTest o
+    else
+      @compileLoopTest o
+
+  compileOrTest: (o) ->
+    [sub, ref] = @object.cache o, LEVEL_OP
+    [cmp, cnj] = if @negated then [' !== ', ' && '] else [' === ', ' || ']
+    tests = for item, i in @array.base.objects
+      (if i then ref else sub) + cmp + item.compile o
+    tests = tests.join cnj
+    if o.level < LEVEL_OP then tests else "(#{tests})"
+
+  compileLoopTest: (o) ->
+    [sub, ref] = @object.cache o, LEVEL_LIST
+    code = utility('indexOf') + ".call(#{ @array.compile o }, #{ref}) " +
+           if @negated then '< 0' else '>= 0'
+    return code if sub is ref
+    code = sub + ', ' + code
+    if o.level < LEVEL_LIST then code else "(#{code})"
+
+  toString: (idt) ->
+    super idt, @constructor.name + if @negated then '!' else ''
+
+#### Try
+
+# A classic *try/catch/finally* block.
+exports.Try = class Try extends Base
+
+  children: ['attempt', 'recovery', 'ensure']
+
+  isStatement: YES
+
+  constructor: (@attempt, @error, @recovery, @ensure) -> super()
+
+  makeReturn: ->
+    @attempt  = @attempt .makeReturn() if @attempt
+    @recovery = @recovery.makeReturn() if @recovery
+    this
+
+  # Compilation is more or less as you would expect -- the *finally* clause
+  # is optional, the *catch* is not.
+  compileNode: (o) ->
+    o.indent  = @idt 1
+    errorPart = if @error then " (#{ @error.compile o }) " else ' '
+    catchPart = if @recovery
+      " catch#{errorPart}{\n#{ @recovery.compile o, LEVEL_TOP }\n#{@tab}}"
+    else unless @ensure or @recovery
+      ' catch (_e) {}'
+    """
+    #{@tab}try {
+    #{ @attempt.compile o, LEVEL_TOP }
+    #{@tab}}#{ catchPart or '' }
+    """ + if @ensure then " finally {\n#{ @ensure.compile o, LEVEL_TOP }\n#{@tab}}" else ''
+
+#### Throw
+
+# Simple node to throw an exception.
+exports.Throw = class Throw extends Base
+
+  children: ['expression']
+
+  isStatement: YES
+
+  constructor: (@expression) -> super()
+
+  # A **Throw** is already a return, of sorts...
+  makeReturn: THIS
+
+  compileNode: (o) -> @tab + "throw #{ @expression.compile o };"
+
+#### Existence
+
+# Checks a variable for existence -- not *null* and not *undefined*. This is
+# similar to `.nil?` in Ruby, and avoids having to consult a JavaScript truth
+# table.
+exports.Existence = class Existence extends Base
+
+  children: ['expression']
+
+  constructor: (@expression) -> super()
+
+  compileNode: (o) ->
+    code = @expression.compile o
+    code = if IDENTIFIER.test(code) and not o.scope.check code
+      "typeof #{code} !== \"undefined\" && #{code} !== null"
+    else
+      "#{code} != null"
+    if o.level <= LEVEL_COND then code else "(#{code})"
+
+#### Parens
+
+# An extra set of parentheses, specified explicitly in the source. At one time
+# we tried to clean up the results by detecting and removing redundant
+# parentheses, but no longer -- you can put in as many as you please.
+#
+# Parentheses are a good way to force any statement to become an expression.
+exports.Parens = class Parens extends Base
+
+  children: ['expression']
+
+  constructor: (@expression) -> super()
+
+  unwrap    : -> @expression
+  isComplex : -> @expression.isComplex()
+  makeReturn: -> @expression.makeReturn()
+
+  compileNode: (o) ->
+    expr = @expression
+    if expr instanceof Value and expr.isAtomic()
+      expr.tags.front = @tags.front
+      return expr.compile o
+    bare = o.level < LEVEL_OP and (expr instanceof Op or expr instanceof Call)
+    code = expr.compile o, LEVEL_PAREN
+    if bare then code else "(#{code})"
+
+#### For
+
+# CoffeeScript's replacement for the *for* loop is our array and object
+# comprehensions, that compile into *for* loops here. They also act as an
+# expression, able to return the result of each filtered iteration.
+#
+# Unlike Python array comprehensions, they can be multi-line, and you can pass
+# the current index of the loop as a second parameter. Unlike Ruby blocks,
+# you can map and filter in a single pass.
+exports.For = class For extends Base
+
+  children: ['body', 'source', 'guard', 'step', 'from', 'to']
+
+  isStatement: YES
+
+  constructor: (@body, head) ->
+    if head.index instanceof Value
+      throw SyntaxError 'index cannot be a pattern matching expression'
+    super()
+    extend this, head
+    @step  or= new Literal 1 unless @object
+    @pattern = @name instanceof Value
+    @returns = false
+
+  makeReturn: ->
+    @returns = true
+    this
+
+  compileReturnValue: (val, o) ->
+    return '\n' + new Return(new Literal val).compile o if @returns
+    return '\n' + val if val
+    ''
+
+  # Welcome to the hairiest method in all of CoffeeScript. Handles the inner
+  # loop, filtering, stepping, and result saving for array, object, and range
+  # comprehensions. Some of the generated code can be shared in common, and
+  # some cannot.
+  compileNode: (o) ->
+    {scope} = o
+    name    = not @pattern and @name?.compile o
+    index   = @index?.compile o
+    ivar    = if not index then scope.freeVariable 'i' else index
+    varPart = guardPart = defPart = retPart = ''
+    body    = Expressions.wrap [@body]
+    idt     = @idt 1
+    scope.find(name,  immediate: yes) if name
+    scope.find(index, immediate: yes) if index
+    [step, pvar] = @step.compileLoopReference o, 'step' if @step
+    if @from
+      [tail, tvar] = @to.compileLoopReference o, 'to'
+      vars  = ivar + ' = ' + @from.compile o
+      vars += ', ' + tail if tail isnt tvar
+      cond = if +pvar
+        "#{ivar} #{ if pvar < 0 then '>' else '<' }= #{tvar}"
+      else
+        "#{pvar} < 0 ? #{ivar} >= #{tvar} : #{ivar} <= #{tvar}"
+    else
+      if name or @object and not @raw
+        [sourcePart, svar] = @source.compileLoopReference o, 'ref'
+      else
+        sourcePart = svar = @source.compile o, LEVEL_PAREN
+      namePart = if @pattern
+        new Assign(@name, new Literal "#{svar}[#{ivar}]").compile o, LEVEL_TOP
+      else if name
+        "#{name} = #{svar}[#{ivar}]"
+      unless @object
+        if 0 > pvar and (pvar | 0) is +pvar  # negative int
+          vars = "#{ivar} = #{svar}.length - 1"
+          cond = "#{ivar} >= 0"
+        else
+          lvar = scope.freeVariable 'len'
+          vars = "#{ivar} = 0, #{lvar} = #{svar}.length"
+          cond = "#{ivar} < #{lvar}"
+    if @object
+      forPart   = ivar + ' in ' + sourcePart
+      guardPart = if @raw then '' else
+        idt + "if (!#{ utility 'hasProp' }.call(#{svar}, #{ivar})) continue;\n"
+    else
+      vars   += ', ' + step if step isnt pvar
+      defPart = @tab + sourcePart + ';\n' if svar isnt sourcePart
+      forPart = vars + "; #{cond}; " + ivar + switch +pvar
+        when  1 then '++'
+        when -1 then '--'
+        else (if pvar < 0 then ' -= ' + pvar.slice 1 else ' += ' + pvar)
+    varPart = idt + namePart + ';\n' if namePart
+    code = guardPart + varPart
+    unless body.isEmpty()
+      if o.level > LEVEL_TOP or @returns
+        rvar     = scope.freeVariable 'result'
+        defPart += @tab + rvar + ' = [];\n'
+        retPart  = @compileReturnValue rvar, o
+        body     = Push.wrap rvar, body
+      body     = Expressions.wrap [new If @guard, body] if @guard
+      o.indent = idt
+      code    += body.compile o, LEVEL_TOP
+    code = '\n' + code + '\n' + @tab if code
+    defPart + @tab + "for (#{forPart}) {#{code}}" + retPart
+
+#### Switch
+
+# A JavaScript *switch* statement. Converts into a returnable expression on-demand.
+exports.Switch = class Switch extends Base
+
+  children: ['subject', 'cases', 'otherwise']
+
+  isStatement: YES
+
+  constructor: (@subject, @cases, @otherwise) -> super()
+
+  makeReturn: ->
+    pair[1].makeReturn() for pair in @cases
+    @otherwise?.makeReturn()
+    this
+
+  compileNode: (o) ->
+    idt1 = @idt 1
+    idt2 = o.indent = @idt 2
+    code = @tab + "switch (#{ @subject?.compile(o, LEVEL_PAREN) or false }) {\n"
+    for [conditions, block], i in @cases
+      for cond in flatten [conditions]
+        cond  = cond.invert() unless @subject
+        code += idt1 + "case #{ cond.compile o, LEVEL_PAREN }:\n"
+      code += block.compile(o, LEVEL_TOP) + '\n'
+      break if i is @cases.length - 1 and not @otherwise
+      for expr in block.expressions by -1 when expr not instanceof Comment
+        code += idt2 + 'break;\n' unless expr instanceof Return
+        break
+    code += idt1 + "default:\n#{ @otherwise.compile o, LEVEL_TOP }\n" if @otherwise
+    code +  @tab + '}'
+
+#### If
+
+# *If/else* statements. Acts as an expression by pushing down requested returns
+# to the last line of each clause.
+#
+# Single-expression **Ifs** are compiled into conditional operators if possible,
+# because ternaries are already proper expressions, and don't need conversion.
+exports.If = class If extends Base
+
+  children: ['condition', 'body', 'elseBody']
+
+  constructor: (condition, @body, tags) ->
+    @tags      = tags or= {}
+    @condition = if tags.invert then condition.invert() else condition
+    @soakNode  = tags.soak
+    @elseBody  = null
+    @isChain   = false
+
+  bodyNode: -> @body?.unwrap()
+  elseBodyNode: -> @elseBody?.unwrap()
+
+  # Rewrite a chain of **Ifs** to add a default case as the final *else*.
+  addElse: (elseBody) ->
+    if @isChain
+      @elseBodyNode().addElse elseBody
+    else
+      @isChain  = elseBody instanceof If
+      @elseBody = @ensureExpressions elseBody
+    this
+
+  # The **If** only compiles into a statement if either of its bodies needs
+  # to be a statement. Otherwise a conditional operator is safe.
+  isStatement: (o) ->
+    o?.level is LEVEL_TOP or
+      @bodyNode().isStatement(o) or @elseBodyNode()?.isStatement(o)
+
+  compileNode: (o) ->
+    if @isStatement o then @compileStatement o else @compileExpression o
+
+  makeReturn: ->
+    if @isStatement()
+      @body     and= @ensureExpressions @body.makeReturn()
+      @elseBody and= @ensureExpressions @elseBody.makeReturn()
+      this
+    else
+      new Return this
+
+  ensureExpressions: (node) ->
+    if node instanceof Expressions then node else new Expressions [node]
+
+  # Compile the **If** as a regular *if-else* statement. Flattened chains
+  # force inner *else* bodies into statement form.
+  compileStatement: (o) ->
+    child    = del o, 'chainChild'
+    cond     = @condition.compile o, LEVEL_PAREN
+    o.indent = @idt 1
+    body     = @ensureExpressions(@body).compile o
+    ifPart   = "if (#{cond}) {\n#{body}\n#{@tab}}"
+    ifPart   = @tab + ifPart unless child
+    return ifPart unless @elseBody
+    ifPart + ' else ' + if @isChain
+       @elseBodyNode().compile merge o, indent: @tab, chainChild: true
+    else
+      "{\n#{ @elseBody.compile o, LEVEL_TOP }\n#{@tab}}"
+
+  # Compile the If as a conditional operator.
+  compileExpression: (o) ->
+    code = @condition .compile(o, LEVEL_COND) + ' ? ' +
+           @bodyNode().compile(o, LEVEL_LIST) + ' : ' +
+           @elseBodyNode()?.compile o, LEVEL_LIST
+    if o.level >= LEVEL_COND then "(#{code})" else code
+
+  unfoldSoak: -> @soakNode and this
+
+  # Unfold a node's child if soak, then tuck the node under created `If`
+  @unfoldSoak: (o, parent, name) ->
+    return unless ifn = parent[name].unfoldSoak o
+    parent[name] = ifn.body
+    ifn.body     = new Value parent
+    ifn
+
+# Faux-Nodes
+# ----------
+# Faux-nodes are never created by the grammar, but are used during code
+# generation to generate other combinations of nodes.
+
+#### Push
+
+# The **Push** creates the tree for `array.push(value)`,
+# which is helpful for recording the result arrays from comprehensions.
+Push =
+  wrap: (name, exps) ->
+    return exps if exps.isEmpty() or last(exps.expressions).containsPureStatement()
+    exps.push new Call \
+      new Value(new Literal(name), [new Accessor new Literal 'push']), [exps.pop()]
+
+#### Closure
+
+# A faux-node used to wrap an expressions body in a closure.
+Closure =
+
+  # Wrap the expressions body, unless it contains a pure statement,
+  # in which case, no dice. If the body mentions `this` or `arguments`,
+  # then make sure that the closure wrapper preserves the original values.
+  wrap: (expressions, statement, noReturn) ->
+    return expressions if expressions.containsPureStatement()
+    func = new Parens new Code [], Expressions.wrap [expressions]
+    args = []
+    if (mentionsArgs = expressions.contains @literalArgs) or
+       (               expressions.contains @literalThis)
+      meth = new Literal if mentionsArgs then 'apply' else 'call'
+      args = [new Literal 'this']
+      args.push new Literal 'arguments' if mentionsArgs
+      func = new Value func, [new Accessor meth]
+      func.noReturn = noReturn
+    call = new Call func, args
+    if statement then Expressions.wrap [call] else call
+
+  literalArgs: (node) -> node instanceof Literal and node.value is 'arguments'
+  literalThis: (node) -> node instanceof Literal and node.value is 'this' or
+                         node instanceof Code    and node.bound
+
+# Constants
+# ---------
+
+UTILITIES =
+
+  # Correctly set up a prototype chain for inheritance, including a reference
+  # to the superclass for `super()` calls. See:
+  # [goog.inherits](http://closure-library.googlecode.com/svn/docs/closureGoogBase.js.source.html#line1206).
+  extends: '''
+    function(child, parent) {
+      function ctor() { this.constructor = child; }
+      ctor.prototype = parent.prototype;
+      child.prototype = new ctor;
+      if (typeof parent.extended === "function") parent.extended(child);
+      child.__super__ = parent.prototype;
+    }
+  '''
+
+  # Create a function bound to the current value of "this".
+  bind: '''
+    function(func, context) {
+      return function() { return func.apply(context, arguments); };
+    }
+  '''
+
+  # Discover if an item is in an array.
+  indexOf: '''
+    Array.prototype.indexOf || function(item) {
+      for (var i = 0, l = this.length; i < l; i++) {
+        if (this[i] === item) return i;
+      }
+      return -1;
+    }
+  '''
+
+  # Shortcuts to speed up the lookup time for native functions.
+  hasProp: 'Object.prototype.hasOwnProperty'
+  slice  : 'Array.prototype.slice'
+
+# Levels indicates a node's position in the AST.
+LEVEL_TOP    = 0  # ...;
+LEVEL_PAREN  = 1  # (...)
+LEVEL_LIST   = 2  # [...]
+LEVEL_COND   = 3  # ... ? x : y
+LEVEL_OP     = 4  # !...
+LEVEL_ACCESS = 5  # ...[0]
+
+# Tabs are two spaces for pretty printing.
+TAB = '  '
+
+# Trim out all trailing whitespace, so that the generated code plays nice
+# with Git.
+TRAILING_WHITESPACE = /[ \t]+$/gm
+
+IDENTIFIER = /^[$A-Za-z_][$\w]*$/
+NUMBER     = /// ^ -? (?: 0x[\da-f]+ | (?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)? ) $ ///i
+SIMPLENUM  = /^[+-]?\d+$/
+
+# Is a literal value a string?
+IS_STRING = /^['"]/
+
+# Utility Functions
+# -----------------
+
+# Helper for ensuring that utility functions are assigned at the top level.
+utility = (name) ->
+  ref = "__#{name}"
+  Scope.root.assign ref, UTILITIES[name]
+  ref
+
+multident = (code, tab) -> code.replace /\n/g, '$&' + tab


Ported clock example

Ported clock example

error: pathspec 'example/clock.coffee' did not match any file(s) known to git

--- example/clock.coffee
+++ example/clock.coffee
@@ -0,0 +1,31 @@
+new Sketch ->
+
+  # Override draw function, by default it will be called 60 times per second
+  @draw = =>
+    centerX = @width / 2
+    centerY = @height / 2
+
+    maxArmLength = Math.min centerX, centerY
+
+    drawArm = (position, lengthScale, weight) =>
+      @strokeWeight weight
+      @line centerX, centerY,
+        centerX + Math.sin(position * 2 * Math.PI) * lengthScale * maxArmLength,
+        centerY - Math.cos(position * 2 * Math.PI) * lengthScale * maxArmLength
+
+    # erase background
+    @background 224
+
+    now = Date.now()
+
+    # Moving hours arm by small increments
+    hoursPosition = (now.getHours() % 12 + now.getMinutes() / 60) / 12
+    drawArm hoursPosition, 0.5, 5
+
+    # Moving minutes arm by small increments
+    minutesPosition = (now.getMinutes() + now.getSeconds() / 60) / 60
+    drawArm minutesPosition, 0.80, 3
+
+    # Moving hour arm by second increments
+    secondsPosition = now.getSeconds() / 60
+    drawArm secondsPosition, 0.90, 1


Quickly scrolling through words using arrow keys now more robust

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/PatrickLerner/escrit.git/'


Another update

Another update

--- app/locale/pl.coffee
+++ app/locale/pl.coffee
@@ -289,17 +289,17 @@
     select_your_starting_hero: "Wybierz bohatera:"
     you_can_always_change_your_hero_later: "Zawsze możesz zmienić bohatera później."
     finish: "Zakończ"
-#    teacher_ready_to_create_class: "You're ready to create your first class!"
-#    teacher_students_can_start_now: "Your students will be able to start playing the first course, Introduction to Computer Science, immediately."
-#    teacher_list_create_class: "On the next screen you will be able to create a new class."
-#    teacher_list_add_students: "Add students to the class by clicking the View Class link, then sending your students the Class Code or URL. You can also invite them via email if they have email addresses."
-#    teacher_list_resource_hub_1: "Check out the"
-#    teacher_list_resource_hub_2: "Course Guides"
-#    teacher_list_resource_hub_3: "for solutions to every level, and the"
-#    teacher_list_resource_hub_4: "Resource Hub"
-#    teacher_list_resource_hub_5: "for curriculum guides, activities, and more!"
-#    teacher_additional_questions: "That’s it! If you need additional help or have questions, reach out to __supportEmail__."
-#    dont_use_our_email_silly: "Don't put our email here! Put your parent's email."
+    teacher_ready_to_create_class: "Jesteś gotów stworzyć swoją pierwszą klasę!"
+    teacher_students_can_start_now: "Twoi uczniowie będą mogli od razu zacząć grać w pierwszy kurs, Wprowadzenie do informatyki."
+    teacher_list_create_class: "Na następnej stronie będziesz mógł stworzyć swoją pierwszą klasę."
+    teacher_list_add_students: "Uczniów do klasy można dodać poprzez kliknięcie na link `pokaż klasę`, następnie twoim oczom ukaże się Kod klasy oraz adres URL, który trzeba przekazać uczniom. Można również wysłać tą wiadomość na email, jeśli jakiś już posiadają."
+    teacher_list_resource_hub_1: "Zajrzyj do"
+    teacher_list_resource_hub_2: "Przewodników kursu"
+    teacher_list_resource_hub_3: "po rozwiązania dla każdego z poziomów, oraz do"
+    teacher_list_resource_hub_4: "Bazy wiedzy"
+    teacher_list_resource_hub_5: "po porady na temat organizacji zajęć, oraz wiele więcej!"
+    teacher_additional_questions: "To wszystko! Jeśli potrzebujesz dodatkowej pomocy, albo chcesz nas o coś spytać napisz do __supportEmail__."
+    dont_use_our_email_silly: "Nie wprowadzaj tu swojego adresu email! Wpisz tutaj adres email rodziców."

   recover:
     recover_account_title: "Odzyskaj konto"
@@ -568,7 +568,7 @@
     restart: "Restartuj poziom"
     play: "Zagraj poziom"
     play_more_codecombat: "Graj więcej CodeCombat"
-#    default_student_instructions: "Click to control your hero and win your game!"
+    default_student_instructions: "Kliknij, aby przejąć władzę nad bohaterem i wygrać grę!"

   game_menu:
     inventory_tab: "Ekwipunek"
@@ -679,7 +679,7 @@
     was_free_until: "Twoja obecna darmowa subskrypcja wygaśnie"
     managed_subs: "Managed Subscriptions"
     subscribing: "Zapisywanie do subskrypcji..."
-#    current_recipients: "Current Recipients"
+    current_recipients: "Obecni odbiorcy"
     unsubscribing: "Anulowanie subskrypcji"
     subscribe_prepaid: "Kliknij `Zapisz się`, aby użyć kodu prepaid"
     using_prepaid: "Używasz kodu prepaid dla miesięcznych subskrypcji"
@@ -738,13 +738,13 @@
 #    hero_blurb_2: "Premium Warriors unlock stunning martial skills like Warcry, Stomp, and Hurl Enemy. Or, play as a Ranger, using stealth and bows, throwing knives, traps! Try your skill as a true coding Wizard, and unleash a powerful array of Primordial, Necromantic or Elemental magic!"
     hero_caption: "Nowi ekscytujący bohaterowie!"
 #    pet_blurb_1: "Pets aren't just adorable companions, they also provide unique functionality and methods. The Baby Griffin can fly over obstacles while helping the hero, the Wolf Pup can fetch potions, and the Cougar can speak!"
-#    pet_blurb_2: "Collect all the pets to discover their unique abilities!"
-#    pet_caption: "Adopt pets to accompany your hero!"
+    pet_blurb_2: "Zbierz wszystkie zwierzaki i poznaj ich unikalne zdolności!"
+    pet_caption: "Przygarnij zwierzaka do towarzystwa!"
 #    game_dev_blurb: "Learn game scripting and build new levels to share with your friends! Place the items you want, write code for unit logic and behavior, and see if your friends can beat the level!"
 #    game_dev_caption: "Design your own games to challenge your friends!"
-#    everything_in_premium: "Everything you get in CodeCombat Premium:"
+    everything_in_premium: "Wszystko co dostaniesz wraz z CodeCombat Premium:"
 #    list_gems: "Receive bonus gems every month to buy gear, pets, and heroes"
-#    list_levels: "Gain access to __premiumLevelsCount__ more levels"
+    list_levels: "Dostęp do __premiumLevelsCount__, a nawet więcej poziomów"
 #    list_heroes: "Unlock exclusive heroes, include Ranger and Wizard classes"
 #    list_game_dev: "Make and share games with friends"
 #    list_web_dev: "Build websites and interactive apps"
@@ -944,13 +944,13 @@
 #    purchase_starter_licenses_to_grant: "Purchase Starter Licenses to grant access to __starterLicenseCourseList__"
 #    starter_licenses_can_be_used: "Starter Licenses can be used to assign additional courses immediately after purchase."
     pay_now: "Zapłać teraz"
-    we_accept_all_major_credit_cards: "Akceptujemy większość kart kredytowych."
+    we_accept_all_major_credit_cards: "Akceptujemy większość kart płatniczych."
 #    cs2_description: "builds on the foundation from Introduction to Computer Science, diving into if-statements, functions, events and more."
 #    wd1_description: "introduces the basics of HTML and CSS while teaching skills needed for students to build their first webpage."
 #    gd1_description: "uses syntax students are already familiar with to show them how to build and share their own playable game levels."
     see_an_example_project: "zobacz przykładowy projekt"
     get_started_today: "Zacznij dziś!"
-#    want_all_the_courses: "Want all the courses? Request information on our Full Licenses."
+    want_all_the_courses: "Chcesz wszytskie kursy? Poproś o informacje o pełnej licencji."
     compare_license_types: "Porównaj typy licencji:"
     cs: "Informatyka"
     wd: "Tworzenie stron"
@@ -1009,9 +1009,9 @@
     referrer: "Jak się o nas dowiedziałeś?"
     referrer_help: "Na przykład: od innego nauczyciela, na konferencji, od swoich uczniów, Code.org, itp."
     anything_else: "Coś jeszcze powinniśmy wiedzieć?"
-#    thanks_header: "Request Received!"
-#    thanks_sub_header: "Thanks for expressing interest in CodeCombat for your school."
-#    thanks_p: "We'll be in touch soon! If you need to get in contact, you can reach us at:"
+    thanks_header: "Prośba otrzymana!"
+    thanks_sub_header: "Dziękujemy za okazanie zainteresowania stroną CodeCombat."
+    thanks_p: "Wkrótce się odezwiemy! Jeśli chcesz się z nami skontaktować napisz na:"
     back_to_classes: "Idź do klas"
     finish_signup: "Zakończ tworzenie konta nauczyciela:"
     finish_signup_p: "Create an account to set up a class, add your students, and monitor their progress as they learn computer science."
@@ -1105,12 +1105,12 @@
     continue_script: "Kontynuuj ostatni skrypt."
     skip_scripts: "Pomiń wszystkie pomijalne skrypty."
     toggle_playback: "Graj/pauzuj."
-#    scrub_playback: "Scrub back and forward through time."
-#    single_scrub_playback: "Scrub back and forward through time by a single frame."
-#    scrub_execution: "Scrub through current spell execution."
+    scrub_playback: "Przenoś się w czasie do produ i do tyłu."
+    single_scrub_playback: "Przenoś się w czasie do produ i do tyłu o jedną ramkę"
+    scrub_execution: "Pomiń wykonywanie obecnego czaru."
     toggle_debug: "Pokaż/ukryj debugowanie."
     toggle_grid: "Pokaż/ukryj siatkę."
-#    toggle_pathfinding: "Toggle pathfinding overlay."
+    toggle_pathfinding: "Pokaż/ukryj ścieżkę bohatera."
     beautify: "Upiększ kod standaryzując jego formatowanie."
     maximize_editor: "Maksymalizuj/minimalizuj edytor kodu."

@@ -1181,8 +1181,8 @@
     track_concepts1: "Śledź tematy"
     track_concepts2a: "nauczone przez uczniów"
     track_concepts2b: "nauczone przez członków"
-#    track_concepts3a: "Track levels completed for each student"
-#    track_concepts3b: "Track levels completed for each member"
+    track_concepts3a: "Śledź poziomy ukończone przez każdego z uczniów"
+    track_concepts3b: "Śledź poziomy ukończone przez każdego z członków"
     track_concepts4a: "Obejrzyj swoich uczniów"
     track_concepts4b: "Obejrzyj swoich członków"
     track_concepts5: "Rozwiązania"
@@ -1190,7 +1190,7 @@
     track_concepts6b: "Sortuj członków według postępu, albo nazwy"
     track_concepts7: "Do dołączenia"
     track_concepts8: "wymagane zaproszenie"
-#    private_require_sub: "Private clans require a subscription to create or join."
+    private_require_sub: "Do dołaczenia, bądź stworzenia prywatnych klanów wymagana jest subskrypcja."

   courses:
     create_new_class: "Stwórz nową klasę"
@@ -1209,10 +1209,10 @@
     completed: "Ukończono:"
     enter_emails: "Wpisz emaila uczniów do zaproszenia. Wpisz każdy nowej linii, albo oddziel je przecinkiem"
     send_invites: "Zaproś uczniów"
-#    number_programming_students: "Number of Programming Students"
-#    number_total_students: "Total Students in School/District"
-#    enroll: "Enroll"
-#    enroll_paid: "Enroll Students in Paid Courses"
+    number_programming_students: "Ilość programujących uczniów"
+    number_total_students: "Łączna liczba uczniów w szkole"
+    enroll: "Zapisz"
+    enroll_paid: "Zapisz uczniów na opłacony kurs"
     get_enrollments: "Otrzymaj więcej licencji"
     change_language: "Zmień język kursu"
     keep_using: "Używaj dalej"
@@ -1272,14 +1272,14 @@
     grants_lifetime_access: "Przyznaj dostęp do wszystkich kursów."
     enrollment_credits_available: "Dostępne licencje:"
     language_select: "Wybierz język" # ClassroomSettingsModal
-#    language_cannot_change: "Language cannot be changed once students join a class."
-#    avg_student_exp_label: "Average Student Programming Experience"
+    language_cannot_change: "Gdy uczniowie dołączą do klasy języka nie będzie można zmienić."
+    avg_student_exp_label: "Średnie doświadczenie uczniów z programowaniem"
 #    avg_student_exp_desc: "This will help us understand how to pace courses better."
     avg_student_exp_select: "Wybierz najlepszą opcję"
-#    avg_student_exp_none: "No Experience - little to no experience"
-#    avg_student_exp_beginner: "Beginner - some exposure or block-based"
-#    avg_student_exp_intermediate: "Intermediate - some experience with typed code"
-#    avg_student_exp_advanced: "Advanced - extensive experience with typed code"
+    avg_student_exp_none: "Bez doświadczenia - brak doświadczenia z kodem"
+    avg_student_exp_beginner: "Początkujący - mniej więcej wie jak wygląda kod"
+    avg_student_exp_intermediate: "Średni - potrafi czytać i rozumieć kod"
+    avg_student_exp_advanced: "Zaawansowany - potrafi samemu napisać jakiś prosty program"
     avg_student_exp_varied: "Różny poziom doświadczenia"
     student_age_range_label: "Zakres wieku uczniów"
     student_age_range_younger: "Młodsi niż 6"


Update vi.coffee (#3596)

Update vi.coffee (#3596)

* Translate into Vietnamese

* Translate and edit some Vietnamese strings

* update Vietnamese translate

* try to fix some error

* fix bugs with tab character

* update vi.coffee: play_level

* Update vi.coffee

* update vi.coffee

* update text on Home page

* Vietnamese: update legal

* vi.coffee: edit community page

* vi.coffee: update user's page

* vi.coffee: about page

* update vi.coffee

* update vi.coffee

* vi.coffee: invoices

* vi.coffee: account_prepaid

* update vi.coffee

* vi.coffee: error strings

* Update vi.coffee

--- app/locale/vi.coffee
+++ app/locale/vi.coffee
@@ -115,7 +115,7 @@
     home: "Trang chủ"
     contribute: "Đóng góp"
     legal: "Điều khoản"
-    about: "Về chúng tôi"
+    about: "Chúng tôi"
     contact: "Liên hệ"
     twitter_follow: "Theo dõi"
     students: "Dành cho học viên"
@@ -207,7 +207,7 @@
     this: "this"

   share_progress_modal:
-    blurb: "Bạn đang tiến bộ rõ rệt đấy! Hãy chia sẻ cho ai đó xem bạn đã học được nhiều chừng nào với CodeCombat."
+    blurb: "Bạn đang tiến bộ rõ rệt đấy! Hãy khoe với bạn bè những gì bạn đã học được với CodeCombat."
     email_invalid: "Địa chỉ email không hợp lệ."
     form_blurb: "Nhập địa chỉ email của người bạn muốn chia sẻ."
     form_label: "Địa chỉ Email"
@@ -362,7 +362,7 @@
     next_level: "Màn chơi kế tiếp"
     next_game: "Game kế tiếp"
     show_menu: "Hiện game menu"
-#    home: "Home" # Not used any more, will be removed soon.
+    home: "Home" # Not used any more, will be removed soon.
     level: "Level" # Like "Level: Dungeons of Kithgard"
     skip: "Bỏ qua"
     game_menu: "Game Menu"
@@ -680,22 +680,22 @@
     granularity_change_history: "Lịch sử"

   options:
-#    general_options: "General Options" # Check out the Options tab in the Game Menu while playing a level
+    general_options: "Tùy chỉnh chung" # Check out the Options tab in the Game Menu while playing a level
     volume_label: "Âm lượng"
     music_label: "Âm nhạc"
     music_description: "Bật/tắt nhạc nền."
-#    editor_config_title: "Editor Configuration"
+    editor_config_title: "Cấu hình Editor"
 #    editor_config_keybindings_label: "Key Bindings"
-#    editor_config_keybindings_default: "Default (Ace)"
-#    editor_config_keybindings_description: "Adds additional shortcuts known from the common editors."
-#    editor_config_livecompletion_label: "Live Autocompletion"
-#    editor_config_livecompletion_description: "Displays autocomplete suggestions while typing."
-#    editor_config_invisibles_label: "Show Invisibles"
-#    editor_config_invisibles_description: "Displays invisibles such as spaces or tabs."
-#    editor_config_indentguides_label: "Show Indent Guides"
-#    editor_config_indentguides_description: "Displays vertical lines to see indentation better."
-#    editor_config_behaviors_label: "Smart Behaviors"
-#    editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes."
+    editor_config_keybindings_default: "Mặc định (Ace)"
+    editor_config_keybindings_description: "Thêm shortcuts chung cho các công cụ editor."
+    editor_config_livecompletion_label: "Gợi ý tự động"
+    editor_config_livecompletion_description: "Hiển thị gợi ý tự động trong khi gõ phím."
+    editor_config_invisibles_label: "Hiện kí tự ẩn"
+    editor_config_invisibles_description: "Hiển thị các kí tự ẩn như dấu cách hay tab."
+    editor_config_indentguides_label: "Hỗ trợ căn lề"
+    editor_config_indentguides_description: "Hiển thị các đường dọc hỗ trợ việc căn lề."
+    editor_config_behaviors_label: "Hỗ trợ thông minh"
+    editor_config_behaviors_description: "Tự động hoàn thiện đóng ngoặc tròn, đóng ngoặc nhọn, đóng quote."

   about:
     main_title: "Nếu bạn muốn học lập trình, bạn phải viết (rất nhiều) code."
@@ -708,7 +708,7 @@
     press_link: "Liên hệ"
     mission_title: "Sứ mệnh của chúng tôi: đưa lập trình đến với mọi người trên Trái Đát này."
     mission_description_1: "Lập trình thật kì diệu. Bạn có thể sáng tạo ra một thứ gì đó từ trí tưởng tượng. Chúng tôi bắt đầu CodeCombat để cho học viên những trải nghiệm nhiệm màu khi viết code."
-    mission_description_2: "Thực tế thì, điều này cũng giúp cho bạn học nhanh hơn. Nhanh hơn RẤT NHIỀU. Bạn được thực hành thay vì chỉ đọc lý thuyết. Chúng tôi muốn đưa môi trường thực hành này đến với mọi ngôi trường và đến với mọi học viên, bởi vì mọi người đều cần có cơ hội biết đến sự nhiệm màu của lập trình."
+    mission_description_2: "Thực tế thì, điều này cũng giúp cho bạn học nhanh hơn. Nhanh hơn RẤT NHIỀU. Bạn được thực hành thay vì chỉ đọc lý thuyết. Chúng tôi muốn đưa môi trường thực hành này đến với trường học và đến tay mọi học viên, bởi vì mọi người đều cần có cơ hội biết đến sự nhiệm màu của lập trình."
     team_title: "Đội ngũ của CodeCombat"
 #    team_values: "We value open and respectful dialog, where the best idea wins. Our decisions are grounded in customer research and our process is focused on delivering tangible results for them. Everyone is hands-on, from our CEO to our Github contributors, because we value growth and learning in our team."
     nick_title: "Đồng Sáng Lập, CEO" # {change}
@@ -727,30 +727,30 @@
     robin_title: "Thiết Kế UX & Nghiên Cứu"
 #    robin_blurb: "Scaffolding"
     josh_title: "Game Designer"
-#    josh_blurb: "Floor Is Lava"
-#    phoenix_title: "Software Engineer"
-#    nolan_title: "Territory Manager"
-#    elliot_title: "Partnership Manager"
-#    retrostyle_title: "Illustration"
+    josh_blurb: "Floor Is Lava"
+    phoenix_title: "Kĩ Sư Phần Mềm"
+    nolan_title: "Giám Đốc Khu Vực"
+    elliot_title: "Giám Đốc Quan Hệ"
+    retrostyle_title: "Vẽ Minh Họa"
     retrostyle_blurb: "RetroStyle Games"
-#    jose_title: "Music"
-#    jose_blurb: "Taking Off"
-#    community_title: "...and our open-source community"
+    jose_title: "Âm Nhạc"
+    jose_blurb: "Taking Off"
+    community_title: "...và cộng đồng mã nguồn mở của chúng tôi"
 #    community_subtitle: "Over 450 contributors have helped build CodeCombat, with more joining every week!"
 #    community_description_1: "CodeCombat is a community project, with hundreds of players volunteering to create levels, contribute to our code to add features, fix bugs, playtest, and even translate the game into 50 languages so far. Employees, contributors and the site gain by sharing ideas and pooling effort, as does the open source community in general. The site is built on numerous open source projects, and we are open sourced to give back to the community and provide code-curious players a familiar project to explore and experiment with. Anyone can join the CodeCombat community! Check out our"
 #    community_description_link: "contribute page"
 #    community_description_2: "for more info."
 #    number_contributors: "Over 450 contributors have lent their support and time to this project."
-#    story_title: "Our story so far"
-#    story_subtitle: "Since 2013, CodeCombat has grown from a mere set of sketches to a living, thriving game."
-#    story_statistic_1a: "5,000,000+"
-#    story_statistic_1b: "total players"
-#    story_statistic_1c: "have started their programming journey through CodeCombat"
-#    story_statistic_2a: "We’ve been translated into over 50 languages — our players hail from"
-#    story_statistic_2b: "200+ countries"
-#    story_statistic_3a: "Together, they have written"
-#    story_statistic_3b: "1 billion lines of code and counting"
-#    story_statistic_3c: "across many different programming languages"
+    story_title: "Hãy nghe câu chuyện của chúng tôi"
+    story_subtitle: "Từ năm 2013 cho đến nay, CodeCombat khởi nguồn chỉ là những phác thảo sơ khai đã được hiện thực hóa để trở thành một tựa game đầy lôi cuốn."
+    story_statistic_1a: "5,000,000+"
+    story_statistic_1b: "người chơi"
+    story_statistic_1c: "đã bắt đầu đặt chân vào thế giới lập trình cùng với CodeCombat"
+    story_statistic_2a: "Chúng tôi phục vụ hơn 50 ngôn ngữ — người chơi của chúng tôi đến từ"
+    story_statistic_2b: "200+ quốc gia"
+    story_statistic_3a: "Cùng với nhau, họ đã viết"
+    story_statistic_3b: "hơn 1 tỷ dòng code"
+    story_statistic_3c: "với rất nhiều ngôn ngữ lập trình khác nhau"
 #    story_long_way_1: "Though we've come a long way..."
 #    story_sketch_caption: "Nick's very first sketch depicting a programming game in action."
 #    story_long_way_2: "we still have much to do before we complete our quest, so..."
@@ -767,7 +767,7 @@
 #    jobs_benefit_9: "10-year option exercise window"
 #    jobs_benefit_10: "Maternity leave: 10 weeks paid, next 6 @ 55% salary"
 #    jobs_benefit_11: "Paternity leave: 10 weeks paid"
-#    learn_more: "Learn More"
+    learn_more: "Tìm hiểu thêm"
 #    jobs_custom_title: "Create Your Own"
 #    jobs_custom_description: "Are you passionate about CodeCombat but don't see a job listed that matches your qualifications? Write us and show how you think you can contribute to our team. We'd love to hear from you!"
 #    jobs_custom_contact_1: "Send us a note at"
@@ -777,23 +777,23 @@
 #    screenshots_title: "Game Screenshots"
 #    screenshots_hint: "(click to view full size)"
 #    downloads_title: "Download Assets & Information"
-#    about_codecombat: "About CodeCombat"
-#    logo: "Logo"
-#    screenshots: "Screenshots"
+    about_codecombat: "Về CodeCombat"
+    logo: "Logo"
+    screenshots: "Ảnh chụp màn hình"
 #    character_art: "Character Art"
 #    download_all: "Download All"
-#    previous: "Previous"
-#    next: "Next"
+    previous: "Trước"
+    next: "Tiếp"
 #    location_title: "We're located in downtown SF:"

   teachers:
     who_for_title: "CodeCombat dành cho ai?"
-#    who_for_1: "We recommend CodeCombat for students aged 9 and up. No prior programming experience is needed. We've designed CodeCombat to appeal to both boys and girls."
-#    who_for_2: "Our Courses system allows teachers to set up classrooms, track progress and assign additional content to students through a dedicated interface."
-#    more_info_title: "Where can I find more information?"
-#    more_info_1: "Our"
-#    more_info_2: "teachers forum"
-#    more_info_3: "is a good place to connect with fellow educators who are using CodeCombat."
+    who_for_1: "Chúng tôi khuyến cáo sử dụng CodeCombat cho học sinh từ 9 tuổi trở lên. Không yêu cầu bất cứ kinh nghiệm lập trình nào từ trước. Chúng tôi thiết kế CodeCombat để phù hợp với cả nam và nữ."
+    who_for_2: "Hệ thống Khóa học của chúng tôi cho phép giáo viên tự biên soạn giáo án của mình, theo dõi tiến trình học tập và giao thêm bài tập cho học sinh thông qua giao diện thân thiện."
+    more_info_title: "Tôi có thể tìm thêm thông tin ở đâu?"
+    more_info_1: ""
+    more_info_2: "Diễn đàn Giáo viên"
+    more_info_3: "của chúng tôi là nơi tuyệt vời để kết nối với cộng đồng những giảng viên đang sử dụng CodeCombat."

 #  teachers_quote:
 #    name: "Demo Form"


Redirect user to correct server when launch app via push notification

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/Morgy93/Rocket.Chat.Cordova.git/'


Fixed js issue with jquery

Fixed js issue with jquery

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/agilidee/dorsale.git/'


Added a common util to get project slug.

error: pathspec 'app/assets/javascripts/lib/common_utils.js.coffee' did not match any file(s) known to git

--- app/assets/javascripts/lib/common_utils.js.coffee
+++ app/assets/javascripts/lib/common_utils.js.coffee
@@ -0,0 +1,13 @@
+((w) ->
+
+  w.gl       or= {}
+  w.gl.utils or= {}
+
+  w.gl.utils.getProjectSlug = ->
+
+    $body = $ 'body'
+    isInProjectPage = $body.data('page').split(':')[0] is 'projects'
+
+    return if isInProjectPage then $body.data 'project' else null
+
+) window


Comment out blocks and additional snippets

Comment out blocks of code and additional snippets

error: pathspec 'language-jbase.cson' did not match any file(s) known to git

--- language-jbase.cson
+++ language-jbase.cson
@@ -0,0 +1,121 @@
+'.source.jbase':
+  'CASE':
+    'prefix': 'ca'
+    'body': 'BEGIN CASE\n\tCASE ${1:/* expression statement(s) */}\n\t\t${2:/* statement(s) */}\n\tCASE 1\n\t\t${3:/* default */}\nEND CASE'
+  'CONVERT':
+    'prefix': 'convert'
+    'body': 'CONVERT "${1:/* expression1 */}" TO "${2:/* expression2 */}" IN ${3:/* expression3 */}'
+  'DATE':
+    'prefix': 'date'
+    'body': 'DATE()'
+  'DEFFUN':
+    'prefix': 'deffun'
+    'body': 'DEFFUN ${1:/* FuncName */}()'
+  'DISPLAY':
+    'prefix': 'display'
+    'body': 'DISPLAY ${1:/* expression */}'
+  'EQUATE':
+    'prefix': 'equate'
+    'body': 'EQUATE ${1:/* symbol */} TO ${2:/* expression */}'
+  'EXECUTE':
+    'prefix': 'execute'
+    'body': 'EXECUTE ${1:/* expression */}'
+  'FIELD':
+    'prefix': 'field'
+    'body': 'FIELD(${1:/* string */}, "${2:/* delimiter */}", ${3:/* numeric position */})'
+  'FIND':
+    'prefix': 'find'
+    'body': 'FIND ${1:/* expression1 */} IN ${2:/* expression2 */} SETTING PRT THEN\n\t${3:/* statement */}\nEND'
+  'FIND ELSE':
+    'prefix': 'finde'
+    'body': 'FIND ${1:/* expression1 */} IN ${2:/* expression2 */} SETTING PRT THEN\n\t${3:/* statement1 */}\nEND ELSE\n\t${4:/* statement2 */}\nEND'
+  'FINDSTR':
+    'prefix': 'findstr'
+    'body': 'FINDSTR ${1:/* expression1 */} IN ${2:/* expression2 */} SETTING PRT THEN\n${3:/* statement */}\nEND'
+  'FINDSTR ELSE':
+    'prefix': 'findstre'
+    'body': 'FINDSTR ${1:/* expression1 */} IN ${2:/* expression2 */} SETTING Ap THEN\n\t${3:/* statement1 */}\nEND ELSE\n\t${4:/* statement2 */}\nEND'
+  'FOR':
+    'prefix': 'for'
+    'body': 'FOR ${1:/* var */} = ${2:/* expression1 */} TO ${3:/* expression2 */}\n\t${2:/* statement */}\nNEXT ${1:/* var */}'
+  'FUNCTION':
+    'prefix': 'function'
+    'body': 'FUCNTION ${1:/* name */}(${2:/* variable(s) */})\n\t${3:/* statement(s) */}\n\tRETURN(${4:/* result(s) */})'
+  'GOSUB':
+    'prefix': 'gosub'
+    'body': 'GOSUB ${1:/* label */}'
+  'ICONV':
+    'prefix': 'iconv'
+    'body': 'ICONV(${1:/* expression1 */}, ${2:/* expression2 */})'
+  'IF Condition':
+    'prefix': 'if'
+    'body': 'IF ${1:/* expression */} THEN\n\t${2:/* statement */}\nEND'
+  'IF ELSE':
+    'prefix': 'ife'
+    'body': 'IF ${1:/* expression */} THEN\n\t${2:/* statement1 */}\nEND ELSE\n\t${3:/* statement2 */}\nEND'
+  'LEFT':
+    'prefix': 'left'
+    'body': 'LEFT(${1:/* expression */}, ${2:/* length */})'
+  'LEN':
+    'prefix': 'length'
+    'body': 'LEN(${1:/* expression */})'
+  'LOOP WHILE':
+      'prefix': 'loopwhile'
+      'body': 'LOOP\n\t${1:/* statement1 */}\nWHILE ${2:/* expression */}\n\t${3:/* statement2 */}\nREPEAT'
+  'LOOP UNTIL':
+      'prefix': 'loopuntil'
+      'body': 'LOOP\n\t${1:/* statement1 */}\nUNTIL ${2:/* expression */}\n\t${3:/* statement2 */}\nREPEAT'
+  'MSLEEP':
+    'prefix': 'msleep'
+    'body': 'MSLEEP ${1:/* milliseconds */}'
+  'NUM':
+    'prefix': 'num'
+    'body': 'NUM(${1:/* expression */})'
+  'OCONV':
+    'prefix': 'oconv'
+    'body': 'OCONV(${1:/* expression1 */}, ${2:/* expression2 */})'
+  'OPEN':
+    'prefix': 'open'
+    'body': 'OPEN ${1:/* expression1 */} TO ${2:/* variable */}'
+  'OPENSEQ':
+    'prefix': 'openseq'
+    'body': 'OPENSEQ ${1:/* pathFrom(File) */} TO ${2:/* pathTo(FileVar) */} ELSE\nEND\n\n\t${5:/* statement */}\n\nCLOSESEQ ${2:/* pathTo(FileVar) */}'
+  'PRECISION':
+    'prefix': 'precision'
+    'body': 'PRECISION ${1:/* integer */}'
+  'READ':
+    'prefix': 'read'
+    'body': 'READ ${1:/* variable1 */} FROM ${2:/* variable2 */}, ${3:/* expression */}'
+  'READSEQ':
+    'prefix': 'readseq'
+    'body': 'READSEQ ${1:/* variable ex:line */} FROM ${2:/* pathTo(FileVar) */} THEN\n\t${3:/* statement(s) */}\nEND'
+  'READU':
+    'prefix': 'readu'
+    'body': 'READU ${1:/* variable1 */} FROM ${2:/* variable2 */}, ${3:/* expression */} SETTING ${4:/* setvar */} ON ERROR'
+  'READV':
+    'prefix': 'readv'
+    'body': 'READV ${1:/* variable1 */} FROM ${2:/* variable2 */}, ${3:/* expression1 */}, ${4:/* expression2 */} THEN\n\t${5:/* code */}\nEND'
+  'SLEEP':
+    'prefix': 'sleep'
+    'body': 'SLEEP ${1:/* seconds or time ex: 4 or "14:00" */}'
+  'Subroutine':
+    'prefix': 'subroutine'
+    'body': '${1:/* label */}:\n\t${2:/* statement */}\nRETURN'
+  'SUBSTRINGs':
+    'prefix': 'substrings'
+    'body' : 'SUBSTRINGS (${1:/* DynArr */}, ${2:/* Start */}, ${3:/* Length */})'
+  'SQUOTE':
+    'prefix': 'squote'
+    'body': 'SQUOTE(${1:/* expression */})'
+  'TRIM':
+    'prefix': 'trim'
+    'body': 'TRIM(${1:/* expression1 */}, "${2:/* expression2 */}", "${3:/* expression3 */}")'
+  'UPCASE':
+    'prefix': 'upcase'
+    'body': 'UPCASE(${1:/* expression */})'
+  'WRITELIST':
+    'prefix': 'writelist'
+    'body': 'WRITELIST ${1:/* variable */} ON ${2:/* expression */}'
+  'WRITEU':
+    'prefix': 'writeu'
+    'body': 'WRITEU ${1:/* variable1 */} TO ${2:/* variable2 */}, ${3:/* expression */} SETTING ${4:/* setvar */} ON ERROR'


bug fix

bug fix

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/bubblegroup/bubblebot.git/'


adding welcome message

adding welcome message


bug fix

bug fix


added brilliant.coffee

added brilliant.coffee

error: pathspec 'src/brilliant.coffee' did not match any file(s) known to git

--- src/brilliant.coffee
+++ src/brilliant.coffee
@@ -0,0 +1,23 @@
+# Description:
+# Brilliant
+#
+# Dependencies:
+#   None
+#
+# Configuration:
+#   None
+#
+# Commands:
+#   <brilliant> - Guinness
+#
+# Author:
+#   jboley
+
+brilliantPics = [
+  "http://affordablehousinginstitute.org/blogs/us/wp-content/uploads/guinness_brilliant.jpg"
+]
+
+module.exports = (robot) ->
+  robot.hear /(brilliant)/i, (msg) ->
+    msg.send msg.random brilliantPics
+


Initial commit

Initial commit

pQL®: An efficient Proteome Query Language.
BioQL®: An efficient Query Language for interpreting genome and proteome.
Author: Prabhat Kumar, http://prabhatkumar.org/.
Copyright: Sequømics Corporation, http://sequomics.com/.

error: pathspec 'src/pql/index.coffee' did not match any file(s) known to git

--- src/pql/index.coffee
+++ src/pql/index.coffee
@@ -0,0 +1,38 @@
+###!
+# pQL®: An efficient Proteome Query Language.
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# BioQL®: An efficient Query Language for interpreting genome and proteome.
+# @version   :[1.0.0]
+# ___________________________________________________________________________
+# CBBL®
+# ~~~~~
+# Computational Biology and Bioinformatics Laboratory
+# Υπολογιστικής Βιολογίας και Βιοπληροφορικής Εργαστήριο
+# ___________________________________________________________________________
+# Architecture and Code Handcrafted by Prabhat Kumar.
+# Architectuur en Code handgemaakt door Prabhat Kumar.
+# @author    : Prabhat Kumar [http://prabhatkumar.org/]
+# @copyright : Sequømics Corporation [http://sequomics.com/]
+# ___________________________________________________________________________
+# @date      : 11-May-2016
+# @license   : Apache, version 2.0
+# @require   : Node.js®
+# @require   : NPM
+# @require   : Grunt
+# ___________________________________________________________________________
+#      Licensed under the Apache License, Version 2.0, (the "License");
+#      you may not use this file except in compliance with the License.
+#                  You may obtain a copy of the License at:
+#                 http://www.apache.org/licenses/LICENSE-2.0
+#                                     or
+#            https://github.com/BioQL/BioQL/blob/master/LICENSE
+#    Unless required by applicable law or agreed to in writing, software
+#     distributed under the License is distributed on an "AS-IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#                        limitations under the License.
+# ___________________________________________________________________________
+#
+#              --/The Heart of Query System/-- of "BioQL®".
+# ___________________________________________________________________________
+###


Add evaluator test

Add evaluator test

error: pathspec 'test/evaluator/evaluator_test.coffee' did not match any file(s) known to git

--- test/evaluator/evaluator_test.coffee
+++ test/evaluator/evaluator_test.coffee
@@ -0,0 +1,105 @@
+require '../test_helper'
+require '../../assets/javascripts/descriptors/roots'
+require '../../assets/javascripts/descriptors/operators'
+require '../../assets/javascripts/evaluator/evaluator'
+
+onNext = Rx.ReactiveTest.onNext
+onCompleted = Rx.ReactiveTest.onCompleted
+V = Visualizer
+
+describe 'buildCode', ->
+  structure = memo().is -> {}
+
+  context 'only root', ->
+    subject = -> V.buildCode(structure()).root.getCode()
+    root = memo().is ->
+    structure.is ->
+      root: root()
+      operators: []
+
+    context 'without scheduler', ->
+      root.is -> type: 'of', args: '1,2,3'
+
+      it 'creates correct code', ->
+        expect(subject()).toEqual 'Rx.Observable.of(1,2,3)'
+
+    context 'with scheduler', ->
+      root.is -> type: 'timer', args: '100'
+      it 'creates correct code', ->
+        expect(subject()).toEqual 'Rx.Observable.timer(100, scheduler)'
+
+  context 'non-recursive operator', ->
+    subject = -> V.buildCode(structure()).operators[0].getCode()
+    structure.is ->
+      root: type: 'interval', args: '100'
+      operators: [operator()]
+    operator = memo().is ->
+
+    context 'without scheduler', ->
+      operator.is -> type: 'take', args: '3'
+      it 'creates correct code', ->
+        expect(subject()).toEqual '.take(3)'
+
+    context 'with scheduler', ->
+      operator.is -> type: 'delay', args: '50'
+      it 'creates correct code', ->
+        expect(subject()).toEqual '.delay(50, scheduler)'
+
+  context 'recursive function operator', ->
+    subject = ->
+      V.buildCode(structure()).operators[0].getCode("Rx.Observable.just(x)")
+
+    structure.is ->
+      root: type: 'interval', args: '100'
+      operators: [
+        {
+          type: 'flatMap'
+          args: 'function(x){ return '
+          observable:
+            root: type: 'just', args: 'x'
+            operators: []
+        }
+      ]
+    it 'creates correct code', ->
+      expect(subject())
+        .toEqual ".flatMap(function(x){ return Rx.Observable.just(x)})"
+
+  context 'recursive observable operator', ->
+    subject = ->
+      V.buildCode(structure()).operators[0].getCode("Rx.Observable.just(5)")
+
+    structure.is ->
+      root: type: 'interval', args: '100'
+      operators: [
+        {
+          type: 'merge'
+          observable:
+            root: type: 'just', args: '5'
+            operators: []
+        }
+      ]
+
+    it 'creates correct code', ->
+      expect(subject())
+        .toEqual ".merge(Rx.Observable.just(5))"
+
+  context 'recursive observable with selector operator', ->
+    subject = ->
+      V.buildCode(structure()).operators[0].getCode("Rx.Observable.just(5)")
+
+    structure.is ->
+      root: type: 'interval', args: '100'
+      operators: [
+        {
+          type: 'combineLatest'
+          args: 'function(a, b){ return {a: a, b: b}; }'
+          observable:
+            root: type: 'just', args: '5'
+            operators: []
+        }
+      ]
+
+    it 'creates correct code', ->
+      expect(subject())
+        .toEqual ".combineLatest(Rx.Observable.just(5), function(a, b){ return {a: a, b: b}; })"
+


Show loading overlay when voting

Show loading overlay when voting

--- resources/assets/coffee/react/beatmap-discussions/discussion.coffee
+++ resources/assets/coffee/react/beatmap-discussions/discussion.coffee
@@ -132,6 +132,8 @@

   doVote: (score) ->
+    loadingOverlay.show()
+
     $.ajax Url.beatmapDiscussionVote(@props.discussion.beatmap_id, @props.discussion.id),
       method: 'PUT',
       data:


datasource min index and max index properties

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/zagushka/ui-scroll.git/'


SyncLocalController: add array to hold opened files

--- client/Main/synclocalcontroller.coffee
+++ client/Main/synclocalcontroller.coffee
@@ -7,6 +7,7 @@
     super
     @storage     = KD.singletons.localStorageController.storage "editor"
     @filesToSave = @storage.getValue("saveRequestedFiles") or []
+    @openedFiles = @storage.getValue("openedFiles") or []
     @syncLocalContentIfDiffExists() if @filesToSave.length > 0
     @initializeListeners()


camel case fixing [af14ceaca7ceda7c1e698196bca1d76ec9862e0e]

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/netguru/review.git/'


modals

modals

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/evercam/evercam-dashboard.git/'


Fix formatting

Fix formatting

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/andrewjcasal/koding.git/'


add helper function to retrieve csrf toket from meta tag

error: pathspec 'assets/coffee/helpers.coffee' did not match any file(s) known to git

--- assets/coffee/helpers.coffee
+++ assets/coffee/helpers.coffee
@@ -0,0 +1,4 @@
+# various helper functions
+
+exports.getCsrfToken = () ->
+  document.getElementsByTagName('meta')['csrf-token'].getAttribute('content')


Fix processing time

Fix processing time

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/Arm1stice/prosu.git/'


[parser] Actually, properly handle negative integers,

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/demhydraz/cafe.git/'


[parser] Remove unnescessary redundancy

[parser] Remove unnescessary redundancy

Seriously if you don't have a '.', go grab a keyboard that isn't
split in half.


add metadata[ranges] to cash projection widget

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/xaun/impac-angular.git/'


Finish rebase-strategy

Finish rebase-strategy

Conflicts:
	test/sometest.coffee

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/Industrial/id-server.git/'


testing: react_test_utils file

testing: react_test_utils file

error: pathspec 'salvus/test/react_test_utils.coffee' did not match any file(s) known to git

--- salvus/test/react_test_utils.coffee
+++ salvus/test/react_test_utils.coffee
@@ -0,0 +1,24 @@
+require('app-module-path').addPath(process.env.SALVUS_ROOT+'/page/temp')
+
+React = require('react/addons')
+TestUtils = React.addons.TestUtils
+
+exports.render = (component, props, children...) ->
+    shallowRenderer = TestUtils.createRenderer()
+    shallowRenderer.render(React.createElement(component, props, if children.length > 1 then children else children[0]))
+    return shallowRenderer.getRenderOutput()
+
+exports.render_dom = (component, props, children...) ->
+    x = React.createElement(component, props, if children.length > 1 then children else children[0])
+    return TestUtils.renderIntoDocument(x)
+
+exports.components_with_tag = (c, tag) ->
+    return TestUtils.scryRenderedDOMComponentsWithTag(c, tag)
+
+exports.component_with_tag = (c, tag) ->
+    return TestUtils.findRenderedDOMComponentWithTag(c, tag)
+
+jsdom = require('jsdom')
+global.document = jsdom.jsdom('<!doctype html>')
+global.window = document.parentWindow
+exports.click = React.addons.TestUtils.Simulate.click