Wip before simplifying alg data to just use dot-value

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -168,6 +168,13 @@
     if token in tokens
       cb word

+teas = (fn, string) ->
+  ast = astize tokenize string
+  compiled = fn (ctx = new Context), ast
+  syntax: collapse toHtml ast
+  types: values mapMap (__ highlightType, _type), subtractMaps ctx._scope(), builtInContext new Context
+  translation: '\n' + compiled
+
 mapCompile = (fn, string) ->
   fn (new Context), astize tokenize string

@@ -176,10 +183,27 @@
   fn (ctx = new Context), ast
   expressions = []
   visitExpressions ast, (expression) ->
-    expressions.push [(collapse toHtml expression), printType expression.tea] if expression.tea
-  types: values mapMap (__ printType, _type), subtractMaps ctx._scope(), builtInContext new Context
-  subs: values mapMap printType, ctx.substitution
+    expressions.push "#{collapse toHtml expression} :: #{highlightType expression.tea}" if expression.tea
+  types: values mapMap (__ highlightType, _type), subtractMaps ctx._scope(), builtInContext new Context
+  subs: values mapMap highlightType, ctx.substitution
   ast: expressions
+  deferred: ctx.deferredBindings()
+
+mapTypingBare = (fn, string) ->
+  ast = astize tokenize string
+  fn (ctx = new Context), ast
+  expressions = []
+  visitExpressions ast, (expression) ->
+    expressions.push [(collapse toHtml expression), expression.tea] if expression.tea
+  types: values mapMap _type, subtractMaps ctx._scope(), builtInContext new Context
+  subs: values ctx.substitution
+  ast: expressions
+  deferred: ctx.deferredBindings()
+
+highlightType = (type) ->
+  typeAst = astize tokenize printType type
+  syntaxType typeAst
+  collapse toHtml typeAst

 _type = (declaration) ->
   declaration.type
@@ -194,30 +218,58 @@
     @_macros = builtInMacros
     @expand = {}
     @names = []
+    @_isOperator = []
     @variableIndex = 0
     @typeVariabeIndex = 0
     @substitution = newMap()
     @statement = []
     @cacheScopes = [[]]
     @_assignTos = []
-    @scopes = [builtInContext this] # dangerous passing itself in constructor
-    @_scope().deferred = []
+    @scopes = [@_augmentScope builtInContext this] # dangerous passing itself in constructor
     @_defer = undefined

   macros: ->
     @_macros

   _name: ->
-    (@names[@names.length - 1] ? {}).token
+    if @_onTopName()
+       @_currentName().name

   _nameExpression: ->
+    if @_onTopName()
+      @_currentName().expression
+
+  _currentName: ->
     @names[@names.length - 1]

-  setName: (name) ->
-    @names.push name
+  setName: (expression) ->
+    @names.push
+      name: expression.token
+      expression: expression
+      deferredBindings: []
+      definedNames: []
+      subs: []
+
+  subName: ->
+    @_currentName().subs.push yes

   resetName: ->
-    @names.pop()
+    if @_onTopName()
+      @names.pop()
+    else
+      @_currentName().subs.pop()
+
+  _onTopName: ->
+    @_currentName().subs.length is 0
+
+  isOperator: ->
+    @_isOperator[@_isOperator.length - 1]
+
+  setIsOperator: (isOperator) ->
+    @_isOperator.push isOperator
+
+  resetIsOperator: ->
+    @_isOperator.pop()

   setAssignTo: (compiled) ->
     @_assignTos.push compiled
@@ -232,12 +284,22 @@
     @scopes[@scopes.length - 1]

   newScope: ->
-    scope = newMap()
+    @scopes.push @_augmentScope newMap()
+
+  _augmentScope: (scope) ->
     scope.deferred = []
-    @scopes.push scope
+    scope.deferredBindings = []
+    scope
+
+  newLateScope: ->
+    @newScope()
+    @_scope().late = yes

   closeScope: ->
     @scopes.pop()
+
+  isInLateScope: ->
+    @_scope().late

   declaration: (name) ->
     @_declarationInScope @scopes.length - 1, name
@@ -248,10 +310,32 @@
       undefined # throw "Could not find declaration for #{name}"

   addType: (name, type) ->
+    throw new "Trying to add a non ForAll type" if type not instanceof ForAll
     if lookupInMap @_scope(), name
       (lookupInMap @_scope(), name).type = type
     else
       addToMap @_scope(), name, {type}
+
+  addToDeferredNames: (binding) ->
+    @_currentName().deferredBindings.push binding
+
+  addToDeferred: (binding) ->
+    @_scope().deferredBindings.push binding
+
+  addToDefinedNames: (binding) ->
+    @_currentName().definedNames.push binding
+
+  definedNames: ->
+    @_currentName().definedNames
+
+  deferredNames: ->
+    @_currentName().deferredBindings
+
+  deferredBindings: ->
+    @_scope().deferredBindings
+
+  addToScope: (name) ->
+    addToMap @_scope(), name, {}

   addArity: (name, arity) ->
     if lookupInMap @_scope(), name
@@ -264,10 +348,10 @@
       @addType name, types[i]

   type: (name) ->
-    (@declaration name).type
+    (@declaration name)?.type

   arity: (name) ->
-    (@declaration name).arity
+    (@declaration name)?.arity

   freshTypeVariable: (kind) ->
     if not kind
@@ -276,6 +360,10 @@

   extendSubstitution: (substitution) ->
     @substitution = joinSubs substitution, @substitution
+
+  applySubstitution: ->
+    for name, {type, arity} of values @_scope() when type
+      @addType name, substitute @substitution, type

   newJsVariable: ->
     "i#{@variableIndex++}"
@@ -311,6 +399,7 @@

   deferred: ->
     @_scope().deferred
+

 expressionCompile = (ctx, expression) ->
   throw "invalid expressionCompile args" unless ctx instanceof Context and expression
@@ -336,14 +425,17 @@
 #   expression.compiled

 callCompile = (ctx, call) ->
-  op = _operator call
-  if isName op
-    (if op.token of ctx.macros()
+  operator = _operator call
+  operatorName = _token operator
+  if isName operator
+    (if operatorName of ctx.macros()
       macroCompile
-    else
-      callKnownCompile) ctx, call
-  else
-    expandedOp = termCompile ctx, op
+    else if ctx.arity operatorName
+      callKnownCompile
+    else
+      callUnknownCompile) ctx, call
+  else
+    expandedOp = termCompile ctx, operator
     if isTranslated expandedOp
       callUnknownTranslate ctx, expandedOp, call
     else
@@ -364,15 +456,18 @@
 isTranslated = (result) ->
   typeof result is 'string' or result instanceof String

+callUnknownCompile = (ctx, call) ->
+  callUnknownTranslate ctx, (operatorCompile ctx, call), call
+
 callKnownCompile = (ctx, call) ->
   operator = _operator call
   args = _labeled _arguments call
   labeledArgs = labeledToMap args
-  operator.label = 'operator'

   return 'malformed' if tagFreeLabels args

   paramNames = ctx.arity operator.token
+  log "param names", paramNames
   if not paramNames
     return ctx.setDefer operator.token
   positionalParams = filter ((param) -> not (lookupInMap labeledArgs, param)), paramNames
@@ -428,13 +523,12 @@
     arg.tea = ctx.freshTypeVariable star

   # Typing operator like inside a known call
-  operator.tea = freshInstance ctx, ctx.type operator.token
+  precsForData = operatorCompile ctx, call

   # Gets the general type as if the extra arguments were supplied
   callTyping ctx, call

-  combinePatterns join [
-    (precs: [(cond_ "#{ctx.assignTo()} instanceof #{operator.token}")])], compiledArgs
+  combinePatterns join precsForData, compiledArgs

 jsObjectAccess = (fieldName) ->
   if (validIdentifier fieldName) is fieldName
@@ -446,16 +540,13 @@
   operator = _operator call
   args = _arguments call

-  # TODO: instead of freshInstance here should be using type schemes
-  operator.tea = freshInstance ctx, ctx.type operator.token
-  # log "compiling saturated", operator, printType operator.tea
+  compiledOperator = operatorCompile ctx, call
+
   compiledArgs = termsCompile ctx, args
-  # log "call typing for #{collapse crawl call, _token}"
+
   callTyping ctx, call

-  opName = validIdentifier operator.token
-  translatedOperator = if isCapital operator then "#{opName}.create" else opName
-  assignCompile ctx, call, "#{translatedOperator}(#{listOf compiledArgs})"
+  assignCompile ctx, call, "#{compiledOperator}(#{listOf compiledArgs})"

 labeledToMap = (pairs) ->
   labelNaming = ([label, value]) -> [(_labelName label), value]
@@ -467,12 +558,23 @@
   freeLabels.map (label) -> label.label = 'malformed'
   return freeLabels.length > 0

+operatorCompile = (ctx, call) ->
+  ctx.setIsOperator yes
+  log "compiling operator"
+  compiledOperator = atomCompile ctx, _operator call
+  ctx.resetIsOperator()
+  compiledOperator
+
 callUnknownTranslate = (ctx, translatedOperator, call) ->
   args = _arguments call
   argList = listOf termsCompile ctx, args
+
+  callTyping ctx, call
+
   assignCompile ctx, call, "_#{args.length}(#{translatedOperator}, #{argList})"

 callTyping = (ctx, call) ->
+  return if ctx.shouldDefer()
   call.tea = callInfer ctx, _terms call

 callInfer = (ctx, terms) ->
@@ -493,8 +595,10 @@
   termCompile ctx, term for term in list

 termCompile = (ctx, term) ->
-  ctx.setName()
+  ctx.subName()
+  ctx.setIsOperator no
   compiled = expressionCompile ctx, term
+  ctx.resetIsOperator()
   ctx.resetName()
   compiled

@@ -596,11 +700,14 @@
 #     (call_ (token_ 'cons-array'), [x, (arrayToConses xs)])

 assignCompile = (ctx, expression, translatedExpression) ->
+  if not translatedExpression
+    log expression
   if to = ctx._nameExpression()

     ctx.setGroupTranslation()
     {precs, assigns} = patternCompile ctx, to, expression, translatedExpression

+    # log "assigning #{ctx._name()}", ctx.shouldDefer()
     if ctx.shouldDefer()
       ctx.addDeferred ctx.shouldDefer(), to, expression
       return 'deferred'
@@ -612,7 +719,6 @@
     translatedExpression

 patternCompile = (ctx, pattern, matched, translatedMatched) ->
-  return {} if ctx.shouldDefer()

   ctx.setAssignTo translatedMatched
   # caching can occur while compiling the pattern
@@ -620,10 +726,46 @@
   {precs, assigns} = expressionCompile ctx, pattern
   ctx.resetAssignTo()

+  definedNames = ctx.definedNames()
+
+  # Make sure deferred names are added to scope so they are compiled withing functions
+  if ctx.shouldDefer()
+    for {name} in definedNames
+      if not ctx.arity name
+        ctx.addToScope name
+    return {}
+
   # Check the types
   unify ctx, matched.tea, pattern.tea
+
+  # And substitute to get correct types TODO: make sure this works for match as well
+
+  # A big map of free typevar names to lists of value names
+  tempVars = concatConcatMaps (for {name, type} in ctx.deferredNames()
+    # ctx.addToDeferred {name, type}
+    # or use the substitution instead of type below:
+    mapMap (-> {name, type}), findFree substitute ctx.substitution, type)
+
+  for {name, type} in definedNames
+    currentType = substitute ctx.substitution, type
+    deps = concat mapToArray intersectRight (findFree currentType), tempVars
+    if deps.length > 0
+      depsNames =  deps
+      log "adding top level lhs to deferred #{name}"
+      ctx.addToDeferred {name, type, deps: (map (({name}) -> name), deps)}
+      for dep in deps
+        ctx.addToDeferred {name: dep.name, type: dep.type, deps: [name]}
+      ctx.addType name, new TempType type
+    else
+      log "adding type for lhs #{name}"
+      ctx.addArity name, [] unless ctx.arity name
+      ctx.addType name, quantify (findFree currentType), currentType
+  # here I will create type schemes for all definitions
+  # The problem is I don't know which are impricise, because the names are done inside the
+  # pattern. I can use the context to know which types where added in the current assignment.
+
+
   # TODO: malformed "LHS\'s type doesn\'t match the RHS in assignment", pattern
-
   precs: precs ? []
   assigns: assigns ? []

@@ -632,22 +774,44 @@
   for [lhs, rhs] in pairs _terms form
     topLevelPairCompile ctx, compiledPairs, lhs, rhs

-  if ctx.deferred()
-    log ctx.deferred()
+  if _notEmpty ctx.deferred()
     deferredCount = 0
     while (_notEmpty ctx.deferred()) and deferredCount < ctx.deferred().length
+      prevSize = ctx.deferred().length
       [dependencyName, lhs, rhs] = deferred = ctx.deferred().shift()
       if ctx.declaration dependencyName
-        deferredCount = 0
         topLevelPairCompile ctx, compiledPairs, lhs, rhs
       else
         # If can't compile, defer further
+        ctx.addDeferred deferred
+      if prevSize is ctx.deferred().length
         deferredCount++
-        ctx.addDeferred deferred
+
+  if _notEmpty ctx.deferred()
+    log "dependency cycles", ctx.deferred()
+
+  if _notEmpty ctx.deferredBindings()
+    # TODO: proper dependency analysis to get the smallest circular deps
+    names = concatConcatMaps map (({name, type}) -> newMapWith name, type), ctx.deferredBindings()
+    for name, types of values names
+      canonicalType = ctx.freshTypeVariable star
+      for type in types
+        log type.constructor
+        log "unifying", canonicalType, type
+        unify ctx, canonicalType, type
+        log "done unifying one"
+    log "done unifying"
+    for name of values names
+      log "done"
+      ctx.addType name, substitute ctx.substitution, canonicalType
+      log "added"
+
+  log "yay"

   listOfLines compiledPairs

 topLevelPairCompile = (ctx, compiledPairs, lhs, rhs) ->
+  log "COMPILING", lhs, rhs
   ctx.setName lhs
   compiled = expressionCompile ctx, rhs
   ctx.resetName()
@@ -679,34 +843,40 @@
         [body, wheres...] = defs
       paramNames = map _token, params
       # pattern
-      paramTypes = map (-> ctx.freshTypeVariable star), params
-      ctx.newScope()
+      paramTypes = map (-> toForAll ctx.freshTypeVariable star), params
+      ctx.newLateScope()
       # log "adding types", (map _token, params), paramTypes
       ctx.addTypes (map _token, params), paramTypes
       # log "types added"
-      # log "compiling", body
+      log "compiling", body
       compiledBody = termCompile ctx, body
       # log "compiled", body.tea
       ctx.closeScope()

-      # Arity - before deferring
-      if ctx._name()
-        ctx.addArity ctx._name(), paramNames
-
-      return 'deferred' if ctx.shouldDefer()
-
-      # Typing
-      call.tea = typeFn paramTypes..., body.tea
-
-      # Syntax
+      # Syntax - used params in function body
+      # TODO: possibly add to nameCompile instead, or defer to IDE
       isUsedParam = (expression) ->
         (isName expression) and (_token expression) in paramNames
       map (syntaxNameAs '', 'param'), filterAst isUsedParam, body

+      # Arity - before deferring instead go to assignCompile, because this makes the naming of functions special
+      if ctx._name()
+        log "adding arity for #{ctx._name()}", paramNames
+        ctx.addArity ctx._name(), paramNames
+
       assignCompile ctx, call,
-        """λ(function (#{listOf paramNames}) {
-          return #{compiledBody};
-        }"""
+        if ctx.shouldDefer()
+          'deferred'
+        else
+          # Typing
+          if not body.tea
+            log body
+            throw "Body not typed"
+          call.tea = typeFn (map _type, paramTypes)..., body.tea
+
+          """λ(function (#{listOf paramNames}) {
+            return #{compiledBody};
+          }"""
   # data
   #   listing or
   #     pair
@@ -732,14 +902,15 @@
         join (_labeled _terms params).map(_snd).map(_token), [ctx._name()]
       else
         ctx._name()
-      ctx.addType constr.token, constrType
+      # TODO support polymorphic data
+      ctx.addType constr.token, toForAll constrType
       constr.tea = constrType
     # TODO: support polymorphic data
     # We don't add binding to types, but maybe need to store elsewhere
     # ctx.addType ctx._name(), typeConstant ctx._name()
     # Arity
     for [constr, params] in defs when params
-      addArity constr.token,
+      ctx.addArity constr.token,
         (_labeled _terms params).map(_fst).map(_labelName)
     # Translate
     listOfLines (for [constr, params] in defs
@@ -870,7 +1041,7 @@
 malformed = (expression, message) ->
   # TODO support multiple malformations
   expression.malformed = message
-  'malformed'
+  message

 isWellformed = (expression) ->
   if expression.malformed
@@ -912,26 +1083,51 @@
       else
         nameCompile ctx, atom, token
   atom.tea = type if type
+  if ctx.isOperator()
+    # TODO: maybe don't use label here, it's getting confusing what is its purpose
+    atom.label = 'operator'
   if ctx.assignTo()
     pattern
   else
     assignCompile ctx, atom, translation

 nameCompile = (ctx, atom, token) ->
-  if ctx.assignTo()
-    ctx.addType token, (type = ctx.freshTypeVariable star)
-    atom.label = 'name'
-    type: type
-    pattern:
-      assigns:
-        [[(validIdentifier token), ctx.assignTo()]]
-  else
-    if ctx.declaration token
+  if exp = ctx.assignTo()
+    if atom.label is 'const'
+      type: ctx.type token
+      pattern:
+        precs: [_cond
+          switch token
+            when 'True' then "#{exp}"
+            when 'False' then "!#{exp}"
+            else
+              "#{exp} instanceof #{validIdentifier token}"]
+    else
+      atom.label = 'name'
+      ctx.addToDefinedNames {name: token, type: (type = ctx.freshTypeVariable star)}
+      type: type
+      pattern:
+        assigns:
+          [[(validIdentifier token), exp]]
+  else
+    # Name typed, use a fresh instance
+    contextType = ctx.type token
+    if contextType and contextType not instanceof TempType
       {
-        type: ctx.type token
+        type: freshInstance ctx, contextType
         translation: validIdentifier token
       }
-    else
+    # Inside function only defer compilation if we don't know arity
+    else if ctx.isInLateScope() and (ctx.declaration token) or contextType instanceof TempType
+      # Typing deferred, use an impricise type var
+      type = ctx.freshTypeVariable star
+      ctx.addToDeferredNames {name: token, type: type}
+      {
+        type: type
+        translation: validIdentifier token
+      }
+    else
+      log "compilation deferring #{token}"
       ctx.setDefer token
       translation: 'deferred'

@@ -947,15 +1143,20 @@
           when 'False' then "!#{exp}"
           else
             "#{exp} instanceof #{token}"]
-  else
-    type: type
-    translation:
-      switch token
-        when 'True' then 'true'
-        when 'False' then 'false'
-        else
-          field = if isConstructor ctx.type token then 'create' else 'value'
-          "#{validIdentifier token}.#{field}"
+nameTranslate = (ctx, atom, token) ->
+  if atom.label is 'const'
+    switch token
+      when 'True' then 'true'
+      when 'False' then 'false'
+      else
+        field = if isConstructor ctx.type token then 'create' else 'value'
+        "#{validIdentifier token}.#{field}"
+  else
+    validIdentifier token
+
+nameTyping: (ctx, atom, token) ->
+
+

 numericalCompile = (ctx, token) ->
   translation = if token[0] is '~' then "(-#{token})" else token
@@ -2362,9 +2563,11 @@

 desiplifyType = (simple) ->
   if Array.isArray simple
-    typeFn (map typeConstant, simple)...
-  else
+    typeFn (map desiplifyType, simple)...
+  else if /^[A-Z]/.test simple
     typeConstant simple
+  else
+    new TypeVariable simple, star

 # Set/Map implementation
@@ -2402,6 +2605,9 @@
 setToArray = (set) ->
   key for key of set.values

+mapToArray = (map) ->
+  val for key, val of map.values
+
 cloneSet = (set) ->
   clone = newSet()
   addAllToSet clone, setToArray set
@@ -2418,6 +2624,13 @@
   initialized = newMap()
   for key, val of set.values
     addToMap initialized, key, fn val
+  initialized
+
+filterSet =
+filterMap = (fn, set) ->
+  initialized = newMap()
+  for key, val of set.values when fn key
+    addToMap initialized, key, val
   initialized

 newSetWith = (args...) ->
@@ -2446,6 +2659,16 @@
       addToMap concated, k, v
   concated

+concatConcatMaps = (maps) ->
+  concated = newMap()
+  for map in maps
+    for k, v of map.values
+      if list = lookupInMap concated, k
+        list.push v
+      else
+        addToMap concated, k, [v]
+  concated
+
 subtractSets =
 subtractMaps = (from, what) ->
   subtracted = newMap()
@@ -2453,8 +2676,20 @@
     addToMap subtracted, k, v
   subtracted

+arrayToSet = (array) ->
+  addAllToSet newSet(), array
+
 values = (map) ->
   map.values
+
+doIntersect = (setA, setB) ->
+  (subtractSets setA, setB).size isnt setA.size
+
+intersectRight = (mapA, mapB) ->
+  intersection = newMap()
+  for k, v of mapB.values when k of mapA.values
+    addToMap intersection, k, v
+  intersection

 # end of Set

@@ -2496,17 +2731,18 @@
 emptySubstitution = ->
   newMap()

+# Unlike in Jones, we simply use substitue for both variables and quantifieds
+# variables are strings, wheres quantifieds are ints
 substitute = (substitution, type) ->
-  if type instanceof TypeVariable
-    if sub = lookupInMap substitution, type.name
-      sub
-    else
-      type
+  if type instanceof TypeVariable and substitution.values
+    (lookupInMap substitution, type.name) or type
+  else if type instanceof QuantifiedVar
+    substitution[type.var] or type
   else if type instanceof TypeApp
     new TypeApp (substitute substitution, type.op),
       (substitute substitution, type.arg)
-  else if isBinding type
-    newBinding mapMap ((t) -> substitute substitution t) type
+  else if type instanceof ForAll
+    new ForAll type.kinds, (substitute substitution, type.type)
   else
     type

@@ -2521,11 +2757,10 @@
 findBound = (name, binding) ->
   (lookupInMap binding, name) or 'unbound name #{name}'

-# TODO: when using qualified types, replace with
-# freshInst over type schemes
 freshInstance = (ctx, type) ->
-  freshes = mapMap ((kind) -> ctx.freshTypeVariable kind), findFree type
-  substitute freshes, type
+  throw "not a forall in freshInstance" unless type instanceof ForAll
+  freshes = map ((kind) -> ctx.freshTypeVariable kind), type.kinds
+  (substitute freshes, type).type

 # Old type inference

@@ -2723,14 +2958,16 @@
 # TypeVariable (record name: String kind: Kind)
 # TypeConstr (record name: String kind: Kind)

-isBinding = (x) ->
-  if not x
-    throw new Error "nothing passed to isBinding"
-  x.binding
-
-newBinding = (map) ->
-  map.binding = yes
-  map
+
+# I don't know, this was probably meant as a replacement for type schemes
+# isBinding = (x) ->
+#   if not x
+#     throw new Error "nothing passed to isBinding"
+#   x.binding
+
+# newBinding = (map) ->
+#   map.binding = yes
+#   map

 typeConstant = (name) ->
   new TypeConstr name, star
@@ -2757,7 +2994,7 @@
     applyKindFn (applyKindFn fn, arg), args...

 isConstructor = (type) ->
-  (kind type) instanceof KindFn
+  type instanceof TypeApp

 kind = (type) ->
   if type.kind
@@ -2783,28 +3020,54 @@
   constructor: (@op, @arg) ->
 class QuantifiedVar
   constructor: (@var) ->
+class ForAll
+  constructor: (@kinds, @type) ->
+class TempType
+  constructor: (@type) ->
+
+toForAll = (type) ->
+  new ForAll [], type
+
+quantify = (vars, type) ->
+  polymorphicVars = filterMap ((name) -> name in vars), findFree type
+  kinds = mapToArray polymorphicVars
+  varIndex = 0
+  quantifiedVars = mapMap (-> new QuantifiedVar varIndex++), polymorphicVars
+  new ForAll kinds, (substitute quantifiedVars, type)

 star = '*'
 arrowType = new TypeConstr '->', kindFn 2
 arrayType = new TypeConstr 'Array', kindFn 1

-kind = (type) ->
-  if type.kind
-    kind
-  else if type.op
-    kind type.op
-  else
-    throw "Invalid type in kind"

 printType = (type) ->
   if type instanceof TypeVariable
     type.name
+  else if type instanceof QuantifiedVar
+    type.var
   else if type instanceof TypeConstr
     type.name
   else if type instanceof TypeApp
-    "(#{printType type.op} #{printType type.arg})"
-  else
-    type
+    types = collectArgs type
+    if types.length is 1
+      types[0]
+    else
+      "(Fn #{types.join ' '})"
+  else if type instanceof ForAll
+    "(∀ #{printType type.type})"
+  else if type instanceof TempType
+    "(. #{printType type.type})"
+  else if Array.isArray type
+    "\"#{type.join ', '}\""
+
+collectArgs = (type) ->
+  if type.op?.op?.name is '->'
+    join [printType type.op.arg], collectArgs type.arg
+  else if type.op
+    ["(#{printType type.op} #{printType type.arg})"]
+  else
+    [printType type]
+

 # ignoreTypeErrors = (fn) ->
 #   try
@@ -2978,6 +3241,7 @@
 ;
 """

+
 exports.compile = (source) ->
   library + compileDefinitions source


Make sure type errors are ignored when tokenizing

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -359,7 +359,8 @@

 tokenizeAndTypeInferDefinitions = (source) ->
   ast = tokenizedDefinitions source
-  inferWheres builtInContext(), (pairs ast), 3
+  if ast.length % 2 is 0
+    ignoreTypeErrors -> inferWheres builtInContext(), (pairs ast), 3
   ast

 # Correct offset by 1 in positions, when we wrap the source in an S-exp
@@ -1309,7 +1310,7 @@
         # TODO: replace free type variables with new unused names in function
         concreteType = lookupInMap context, expression.token
         unless concreteType
-          throw new Error "Unbound variable #{expression.token}"
+          throw new TypeError "Unbound variable #{expression.token}"
         [nextIndex, concreteType] = freshenFree nameIndex, concreteType
         expression.tea = concreteType
         [newMap(), nextIndex, expression]
@@ -1318,7 +1319,8 @@
         {params, body, wheres} = fnDefinition expression
         # TODO: more params
         definedParams = inside params
-        # assume if definedParams.length > 0
+        if definedParams.length is 0
+          throw new TypeError "Typing lambdas without a param not implemented yet"
         argName = freshName nameIndex
         param = definedParams[0]
         context = concatMaps context, newMapWith param.token, argName
@@ -1327,11 +1329,13 @@
         [s1, nextIndex, expression]

       # Call
-      else if (Array.isArray expression) and expression.length > 2
+      else if (Array.isArray expression) and expression.length > 3
         [op..., arg] = inside expression
         [s, nextIndex, tea] = inferCall context, [op, arg], nameIndex
         expression.tea = tea
         [s, nextIndex, expression]
+      else
+        throw new TypeError "Other patterns not typable yet"

 inferCall = (context, pair, nameIndex) ->
   [ops, arg] = pair
@@ -1370,7 +1374,7 @@
       [t2from, t2to] = t2
       unifyWith subs, [[t1from, t2from], [t1to, t2to]].concat rest
     else
-      throw new Error "Types #{t1}, #{t2} could not be unified"
+      throw new TypeError "Types #{t1}, #{t2} could not be unified", [t1, t2]

 subPairs = (subs, pairs) ->
   for [t1, t2] in pairs
@@ -1421,6 +1425,17 @@
 freshName = (nameIndex) ->
   suffix = if nameIndex > 25 then nameIndex // 25 else ''
   String.fromCharCode 97 + nameIndex % 25
+
+ignoreTypeErrors = (fn) ->
+  try
+    ret = fn()
+  catch e
+    unless e instanceof TypeError
+      throw e
+
+class TypeError extends Error
+  # required for instanceof to work
+  constructor: (@message, @data) -> super @message

 # mycroft = (context, node, environment) ->
 #   if node.label is 'numerical'


Printing types

Printing types

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -3605,9 +3605,13 @@
 syntaxedExpHtml = (string) ->
   collapse toHtml astize tokenize string

+syntaxedType = (type) ->
+  collapse toHtml typeCompile new Context, type
+
 compileTopLevel = (source) ->
   {js, ast, ctx} = compileToJs topLevel, "(#{source})", -1, -1
-  {js, ast, types: typeEnumaration ctx}
+  (finalizeTypes ctx, ast)
+  {js, ast: ast, types: typeEnumaration ctx}

 compileTopLevelAndExpression = (source) ->
   topLevelAndExpression source
@@ -3651,6 +3655,9 @@
 astizeExpressionWithWrapper = (source) ->
   parentize astize (tokenize "(#{source})", -1), -1

+finalizeTypes = (ctx, ast) ->
+  visitExpressions ast, (expression) ->
+    expression.tea = highlightType substitute ctx.substitution, expression.tea

 # end of API

@@ -4163,6 +4170,7 @@
 exports.astizeExpression = astizeExpression
 exports.astizeExpressionWithWrapper = astizeExpressionWithWrapper
 exports.syntaxedExpHtml = syntaxedExpHtml
+exports.syntaxedType = syntaxedType

 # exports.compileModule = (source) ->
 #   """


Jump to module from req call

Jump to module from req call

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -2355,7 +2355,7 @@
   [moduleNameAtom] = _validArguments call
   if not moduleNameAtom or not isName moduleNameAtom
     return malformed ctx, call, 'req requires a module name to require from'
-  moduleNameAtom.label = 'param'
+  moduleNameAtom.label = 'module'
   moduleName = moduleNameAtom.symbol
   requiredNames = (arrayToSet (filter _is, (map _symbol, reqs)))
   ctx.req moduleName, requiredNames


Fix student pacing suggestion calculation to ignore arena/project levels (#6587)

--- app/views/teachers/TeacherStudentView.coffee
+++ app/views/teachers/TeacherStudentView.coffee
@@ -228,10 +228,13 @@
     for versionedCourse in @classroom.getSortedCourses() or []
       course = @courses.get(versionedCourse._id)
       numbers = []
+      performanceNumbers = []
       studentCourseTotal = 0
+      performanceStudentCourseTotal = 0
       members = 0 #this is the COUNT for our standard deviation, number of members who have played all of the levels this student has played.
       for member in @classroom.get('members')
         number = 0
+        performanceNumber = 0
         memberPlayed = 0 # number of levels a member has played that this student has also played
         for versionedLevel in versionedCourse.levels
           sessions = (levelSessionsByStudentByLevel[member] ? {})[versionedLevel.original] ? []
@@ -239,26 +242,34 @@
             playedLevel = levelDataByLevel[session.get('level').original]
             if playedLevel.levelProgress is 'complete' or playedLevel.levelProgress is 'started'
               number += session.get('playtime') or 0
+              performanceNumber += not playedLevel.isLadder and not playedLevel.isProject and session.get('playtime') or 0
               memberPlayed += 1
             if session.get('creator') is @studentID
               studentCourseTotal += session.get('playtime') or 0
+              performanceStudentCourseTotal += not playedLevel.isLadder and not playedLevel.isProject and session.get('playtime') or 0
         if memberPlayed > 0 then members += 1
         numbers.push number
+        performanceNumbers.push performanceNumber

       # add all numbers[]
       sum = numbers.reduce (a,b) -> a + b
+      performanceSum = performanceNumbers.reduce (a,b) -> a + b

       # divide by members to get MEAN, remember MEAN is only an average of the members' performance on levels THIS student has done.
       mean = sum/members
+      performanceMean = performanceSum/members

       # # for each number in numbers[], subtract MEAN then SQUARE, add all, then divide by COUNT to get VARIANCE
       diffSum = numbers.map((num) -> (num-mean)**2).reduce (a,b) -> a+b
+      performanceDiffSum = performanceNumbers.map((num) -> (num-performanceMean)**2).reduce (a,b) -> a+b
       variance = (diffSum / members)
+      performanceVariance = (performanceDiffSum / members)

       # square root of VARIANCE is standardDev
       StandardDev = Math.sqrt(variance)
-
-      perf = -(studentCourseTotal - mean) / StandardDev
+      PerformanceStandardDev = Math.sqrt(performanceVariance)
+
+      perf = -(performanceStudentCourseTotal - performanceMean) / PerformanceStandardDev
       perf = if perf > 0 then Math.ceil(perf) else Math.floor(perf)

       @courseComparisonMap.push {
@@ -448,6 +459,8 @@
     @levelData = []
     for versionedCourse in @classroom.getSortedCourses() or []
       course = @courses.get(versionedCourse._id)
+      ladderLevel = this.classroom.getLadderLevel(course.get('_id'))
+      projectLevel = this.classroom.getProjectLevel(course.get('_id'))
       for versionedLevel in versionedCourse.levels
         playTime = 0 # TODO: this and timesPlayed should probably only count when the levels are completed
         timesPlayed = 0
@@ -476,6 +489,8 @@
           classAvg: classAvg
           studentTime: if studentTime then studentTime else 0
           levelProgress: levelProgress
+          isLadder: ladderLevel?.attributes.original is versionedLevel.original
+          isProject: projectLevel?.attributes.original is versionedLevel.original
           # required:
         }


Added constants to classes

Added constants to classes

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -1204,11 +1204,7 @@
         ctx.declareArity name, paramNames
         # Explicit typing
         if type
-          explicitType = quantifyUnbound ctx, typeConstrainedCompile ctx, type
-          if ctx.isTyped name
-            malformed ctx.definitionPattern(), 'This name is already taken'
-          else
-            ctx.assignType name, explicitType
+          explicitType = assignExplicitType ctx, typeConstrainedCompile ctx, type

       paramTypeVars = map (-> ctx.freshTypeVariable star), params
       paramTypes = map (__ toForAll, toConstrained), paramTypeVars
@@ -1268,6 +1264,16 @@
             #     params: paramNames
             #     body: (join compiledWheres, [(jsReturn compiledBody)]))])

+# Assumes definition name
+assignExplicitType = (ctx, type) ->
+  explicitType = quantifyUnbound ctx, type
+  name = ctx.definitionName()
+  if ctx.isTyped name
+    malformed ctx.definitionPattern(), 'This name is already taken'
+  else
+    ctx.assignType name, explicitType
+  explicitType
+
 ms.type = ms_type = (ctx, call) ->
   hasName = requireName ctx, 'Name required to declare new type alias'
   alias = ctx.definitionName()
@@ -1407,15 +1413,26 @@
       (call_ (token_ 'data'),
         [typeParamTuple, (token_ ctx.definitionName()), (tuple_ args)])

-  # # Type an expression
-  # ':': (ctx, call) ->
-  #   [expression, type] = _arguments call
-  #   if not type
-  #     return malformed 'Missing type', call
-  #   ctx.setIsType true
-  #   ctx.setIsType false
-
-  # Adds a class to the scope or defers if superclass doesn't exist
+  # Type an expression
+ms[':'] = ms_typed = (ctx, call) ->
+    hasName = requireName ctx, 'Name required to declare typed values for now'
+    [type, constraintSeq, rest...] = _arguments call
+    compiledType =
+      if isSeq constraintSeq
+        constraints = typeConstraintsCompile ctx, _terms constraintSeq
+        if type
+          new Constrained constraints, typeCompile ctx, type
+      else
+        typeConstrainedCompile ctx, call
+    if hasName
+      ctx.declare ctx.definitionName()
+      assignExplicitType ctx, compiledType
+    # TODO: support typing of expressions,
+    #watch out of definition patterns without a name
+    jsNoop()
+
+
+# Adds a class to the scope or defers if superclass doesn't exist
 ms.class = ms_class = (ctx, call) ->
     hasName = requireName ctx, 'Name required to declare a new class'
     [paramList, defs...] = _validArguments call
@@ -5132,6 +5149,27 @@
   """
   "a", 2

+  'constants in classes'
+  """
+  A (class [c e]
+    empty (: c)
+
+    first (fn [x] (: (Fn c e))))
+
+  list-a (instance (A (Array a) a)
+    empty {}
+
+    first (macro [list]
+      (: (Fn (Array a) a))
+      (Js.call (Js.access list "first") {})))
+
+  unshift (macro [what to]
+    (: (Fn a (Array a) (Array a)))
+    (Js.call (Js.access to "unshift") {what}))
+  """
+  "(first (unshift 3 empty))", 3
+
+
   # The following doesn't work because the Collection type class specifies
   # that the constructor takes only one argument.
   #


filta me out

filta me out

--- app/assets/javascripts/components/sort_filter_form.coffee
+++ app/assets/javascripts/components/sort_filter_form.coffee
@@ -30,8 +30,8 @@
 					type: 'text'
 					className: 'form-control'
 					placeholder: 'fliter'
-					name: 'flita'
-					value: @state.flita
+					name: 'filta'
+					value: @state.filta
 					onChange: @handleValueChange
 				React.DOM.span
 					className: 'input-group-button'


Increase left margin of electricity load chart

Ensures the "MW" label may always be read.

--- app/assets/javascripts/d3/electricity_network_load.coffee
+++ app/assets/javascripts/d3/electricity_network_load.coffee
@@ -9,7 +9,7 @@
     margins:
       top: 20
       bottom: 20
-      left: 50
+      left: 75
       right: 20
       label_left: 20


Added extend for the accordon plugin to allow custom active classes

--- app/assets/javascripts/lib/components/accordion.js.coffee
+++ app/assets/javascripts/lib/components/accordion.js.coffee
@@ -3,6 +3,9 @@
 #   parent: parent element
 #   multiplePanels: can you have multiple panels open
 #   callback: optional function
+#   activeClass: optional args
+#     elem: element to add/remove the class
+#     className: classname to add/remove
 # }
 #

@@ -14,20 +17,25 @@
       multiplePanels: false

     openPanel : (panel) ->
-      console.log config.multiplePanels
       if config.multiplePanels is false then @closeAllPanels()
       panel = @sanitisePanel(panel)
       panel.removeClass('is-hidden')
+      if config.hasOwnProperty('activeClass')
+        panel.closest(config.activeClass.elem).addClass(config.activeClass.className)

     closePanel : (panel) ->
       panel = @sanitisePanel(panel)
       panel.addClass('is-hidden')
+      if config.hasOwnProperty('activeClass')
+        panel.closest(config.activeClass.elem).removeClass(config.activeClass.className)

     closeAllPanels : (panels) ->
       @panels.addClass('is-hidden')
+      @parent.find(config.activeClass.elem).removeClass(config.activeClass.className)

     constructor : (args) ->
       config = $.extend config, args
+      window.x = config
       @parent = $(config.parent)
       @panels = @parent.find('.js-accordion-panel')


replacing rails delete js for delete-product

--- app/assets/javascripts/templates/product_widget.js.coffee
+++ app/assets/javascripts/templates/product_widget.js.coffee
@@ -22,7 +22,7 @@
         {{/sizes}}

Status: {{status}}

-
+

 """


prefer the include() helper to 'in', except for array literals.

--- rewriter.coffee
+++ rewriter.coffee
@@ -59,8 +59,8 @@
     loop
       break unless token = @tokens[i]
       return action token, i if !levels and condition token, i
-      levels += 1 if token[0] in EXPRESSION_START
-      levels -= 1 if token[0] in EXPRESSION_END
+      levels += 1 if include EXPRESSION_START, token[0]
+      levels -= 1 if include EXPRESSION_END, token[0]
       i += 1
     i - 1


Use the new Browser class into zoneselection.

--- src/FileManager/ZoneSelectionDirective.coffee
+++ src/FileManager/ZoneSelectionDirective.coffee
@@ -1,11 +1,8 @@
 angular.module('fileManager').
-directive('zoneSelection', (Selection, $document)->
+directive('zoneSelection', (Selection, $document, Browser)->
   return {
     restrict: 'A'
     link: (scope, element, attrs)->
-      w    = window
-      e    = window.document.documentElement
-      g    = window.document.getElementsByTagName('body')[0]
       body = window.document.getElementsByTagName('body')[0]
       zone = window.document.getElementById('zone')
       scope.last = 0
@@ -18,16 +15,13 @@

       # IsInSelection
       isInSelection = (file)->
-        x = w.innerWidth || e.clientWidth || g.clientWidth
-        y = w.innerHeight|| e.clientHeight|| g.clientHeight
-
         selection = zone.getBoundingClientRect()
-        selection.right  = x-selection.right
-        selection.bottom = y-selection.right
+        selection.right  = Browser.width()  - selection.right
+        selection.bottom = Browser.height() - selection.right

         file = file.getBoundingClientRect()
-        file.right  = x-file.right
-        file.bottom = y-file.bottom
+        file.right  = Browser.width()  - file.right
+        file.bottom = Browser.height() - file.bottom

         if (file.top <= selection.top <= file.bottom or
         file.top <= selection.bottom <= file.bottom or
@@ -53,8 +47,8 @@
           scope.last = actual
           scope.end  = $event

-          x = w.innerWidth || e.clientWidth || g.clientWidth
-          y = w.innerHeight|| e.clientHeight|| g.clientHeight
+          x = Browser.width()
+          y = Browser.height()

           if scope.start.clientY < scope.end.clientY
             zone.style.top    = "#{scope.start.clientY}px"


fix(keymaps): typo

fix(keymaps): typo

--- keymaps/base.cson
+++ keymaps/base.cson
@@ -63,10 +63,10 @@
   'ctrl-left': 'native!'
   'ctrl-down': 'native!'
   'ctrl-right': 'native!'
-  'shfit-up':   'native!'
-  'shfit-left': 'native!'
-  'shfit-down': 'native!'
-  'shfit-right': 'native!'
+  'shift-up':   'native!'
+  'shift-left': 'native!'
+  'shift-down': 'native!'
+  'shift-right': 'native!'
   'escape': 'native!'
   'pageup': 'native!'
   'pagedown': 'native!'


else next, not just next

else next, not just next

--- controllers/teams.coffee
+++ controllers/teams.coffee
@@ -10,7 +10,8 @@
       return res.send 404 unless team
       req.team = team
       next()
-  next()
+  else
+    next()

 loadPeople = (req, res, next) ->
   req.team.people (err, people) ->


remove whitespace

remove whitespace

--- lib/highlight-bad-chars.coffee
+++ lib/highlight-bad-chars.coffee
@@ -62,7 +62,6 @@
   '\u00B8',  # cadilla
   '\u01C0',  # latin letter dental click
   '\u2223',  # divides
-
 ]

 charRegExp = '[' + chars.join('') + ']'


Remove all enabled

Remove all enabled

--- lib/highlight-line-view.coffee
+++ lib/highlight-line-view.coffee
@@ -7,7 +7,6 @@

 module.exports =
   configDefaults:
-    allEnable: true
     enableBackgroundColor: true
     backgroundRgbColor: "100, 100, 100"
     opacity: "50%"
@@ -96,8 +95,7 @@

   updateSelectedLine: =>
     @resetBackground()
-    if atom.config.get('highlight-line.allEnable')
-      @showHighlight()
+    @showHighlight()

   resetBackground: ->
     $('.line').css('background-color', '')


Start work on #130

Start work on #130

--- src/command/push_and_keygen.iced
+++ src/command/push_and_keygen.iced
@@ -25,6 +25,10 @@
       alias : "secret"
       action : "storeTrue"
       help : "push the secret key to the server"
+    u  :
+      alias : "update"
+      action : "storeTrue"
+      help : "update the public key with new key fields"

   #----------

@@ -162,8 +166,8 @@
     if ckres.remote and @argv.secret
       log.info "Public key already uploaded; pushing only secret key"
       @_secret_only = true
-    else if ckres.remote and not(@argv.secret)
-      err = new E.KeyExistsError "You already have a key registered; you must revoke first"
+    else if ckres.remote and not(@argv.secret) and not(@argv.update)
+      err = new E.KeyExistsError "You already have a key registered; you must revoke or specify --update"
     cb err

   #----------


:lipstick: Fix typo in benchmark label

:lipstick: Fix typo in benchmark label

--- lib/minimap-editor-view.coffee
+++ lib/minimap-editor-view.coffee
@@ -57,7 +57,7 @@
     setImmediate =>
       @startBench()
       @update()
-      @endBench('minimpap update')
+      @endBench('minimap update')
       @frameRequested = false

   scrollTop: (scrollTop, options={}) ->


:warning: Fix deprecated method call

:warning: Fix deprecated method call

--- lib/minimap-editor-view.coffee
+++ lib/minimap-editor-view.coffee
@@ -191,7 +191,7 @@

   drawLines: (context, firstRow, lastRow, offsetRow) ->
     return if firstRow > lastRow
-    lines = @editor.linesForScreenRows(firstRow, lastRow)
+    lines = @editor.tokenizedLinesForScreenRows(firstRow, lastRow)
     lineHeight = @getLineHeight()
     charHeight = @getCharHeight()
     charWidth = @getCharWidth()


Try to fix an issue with multiple times a collection is synced with the server

--- src/admin/backbone.admin.appcontroller.coffee
+++ src/admin/backbone.admin.appcontroller.coffee
@@ -174,11 +174,9 @@

   actionExecuted = (action) ->
     unless _.isNull(action.updatedRegions)
-  #    for name in @regionNames
-  #      @[name].close()
-
       for key in _.keys(action.updatedRegions)
         unless @[key] is undefined
+          @[key].close()
           @[key].show action.updatedRegions[key].view

       @router.navigate action.route() if not _.isNull(@router) and action.isRoutable


Fix more sticking logic for mobile

Fix more sticking logic for mobile

--- resources/assets/coffee/_classes/forum-topic-reply.coffee
+++ resources/assets/coffee/_classes/forum-topic-reply.coffee
@@ -97,9 +97,10 @@

     @stickyFooter.markerDisable @marker()
     @setState 'active', '0'
+    delete @box[0].dataset.state if @box[0].dataset.state?
     button.classList.remove 'js-activated' for button in @toggleButtons
     $.publish 'stickyFooter:check'
-    delete @box[0].dataset.state if @box[0].dataset.state?
+    @stickOrUnstick() if osu.isMobile()
     @disableFlash()


Fix builds appending logic

Fix builds appending logic

--- resources/assets/coffee/react/changelog-index/main.coffee
+++ resources/assets/coffee/react/changelog-index/main.coffee
@@ -30,14 +30,8 @@
   constructor: (props) ->
     super props

-    builds = props.data.builds
-    hasMore = builds.length == props.data.search.limit
-
-    @state =
-      # remove one so there's at least one more to be loaded
-      builds: osu.jsonClone(if hasMore then builds[..-2] else builds)
-      hasMore: hasMore
-      loading: false
+    @state = @newStateFromData(props.data)
+    @state.loading = false

   componentDidMount: =>
@@ -111,8 +105,15 @@

     $.get laroute.route('changelog.index'), search
     .done (data) =>
-      @setState
-        builds: @state.builds.concat(data.builds[..-2])
-        hasMore: data.search.limit == data.builds.length
+      @setState @newStateFromData(data)
     .always =>
       @setState loading: false
+
+
+  newStateFromData: (data) =>
+    hasMore = data.builds.length == data.search.limit
+    builds = (@state?.builds ? []).concat data.builds
+    # remove one so there's at least one more to be loaded
+    builds.pop() if hasMore
+
+    {hasMore, builds}


bugfix

bugfix

--- controllers/people.coffee
+++ controllers/people.coffee
@@ -1,3 +1,4 @@
+_ = require 'underscore'
 app = require '../config/app'
 { ensureAdmin, loadPerson, loadPersonTeam } = require '../lib/route-middleware'
 Person = app.db.model 'Person'


Use CourseGroupingLabel when referring to sections

--- src/components/cc-dashboard/blank-course.cjsx
+++ src/components/cc-dashboard/blank-course.cjsx
@@ -2,7 +2,7 @@
 React = require 'react'
 BS = require 'react-bootstrap'
 DesktopImage = require './desktop-image'
-
+CourseGroupingLabel = require '../course-grouping-label'
 BlankCourse = React.createClass

   propTypes:
@@ -18,15 +18,21 @@

-              Add sections to your course by clicking on your name in the top
+              Add <CourseGroupingLabel plural courseId={@props.courseId} /> to
+              your course by clicking on your name in the top
               right corner and selecting "Course Settings and Roster."

-              Generate a student enrollment code for each section you create.
+              Generate a student enrollment code for
+              each <CourseGroupingLabel courseId={@props.courseId} /> you
+              create.

-              Distribute the enrollment codes for each section and textbook URL
-              (which is the same for each section) to your students.
+              Distribute the enrollment codes for
+              each <CourseGroupingLabel courseId={@props.courseId} /> and
+              textbook URL (which is the same for
+              each <CourseGroupingLabel courseId={@props.courseId} />) to
+              your students.

               Encourage your students to login to Concept Coach as part of their
@@ -39,6 +45,7 @@

           <DesktopImage courseId={@props.courseId} />

+


Oops, paths are broken on github.io

Oops, paths are broken on github.io

--- packages/shrub-grunt/dox/dynamic.coffee
+++ packages/shrub-grunt/dox/dynamic.coffee
@@ -304,7 +304,7 @@
           packageName = parts.join '/'

           types = types.map (type) ->
-            "
#{_sourcePath file} (#{type})	#{key}
"
+            "
#{_sourcePath file} (#{type})	#{key}
"
           types.join ''

         render += instances.join ''
@@ -466,7 +466,7 @@
       render += '
Implements hooks
'
       render += '
\n'
       render += fileStats.implementations.map((hook, index) ->
-        "
#{hook}	implementation
\n"
+        "
#{hook}	implementation
\n"
       ).join ''
       render += '
\n'
       render += '
'
@@ -478,7 +478,7 @@
       render += '
Implements hooks
'
       render += '
\n'
       render += fileStats.implementations.map((hook, index) ->
-        "
#{hook}	invocation
\n"
+        "
#{hook}	invocation
\n"
       ).join ''
       render += '
\n'
       render += '
'


ListView: Don't try to open nodes which "isLeaf" methods returns "true".

This avoids the little node is open icon next to a node if a loadChildren method
tried to load more children, although the node reported that it is a leaf.

--- src/elements/ListView/ListViewTreeNode.coffee
+++ src/elements/ListView/ListViewTreeNode.coffee
@@ -334,7 +334,7 @@
 		# we could return loading_deferred here
 		CUI.util.assert(not @isLoading(), "ListViewTreeNode.open", "Cannot open node #{@getUniqueId()}, during opening. This can happen if the same node exists multiple times in the same tree.", node: @)

-		if @is_open
+		if @is_open or @isLeaf()
 			return CUI.resolvedPromise()

 		# console.error @getUniqueId(), "opening...", "is open:", @is_open, open_counter


Add 'regions' as configurable property when constructing a view

--- src/chaplin/views/view.coffee
+++ src/chaplin/views/view.coffee
@@ -77,7 +77,12 @@
     # Copy some options to instance properties.
     if options
       _.extend this, _.pick options, [
-        'autoAttach', 'autoRender', 'container', 'containerMethod', 'region'
+        'autoAttach'
+        'autoRender'
+        'container'
+        'containerMethod'
+        'region'
+        'regions'
       ]

     # Wrap `render` so `attach` is called afterwards.


Added frames index comment

Added frames index comment

--- src/coffee/frame/index.coffee
+++ src/coffee/frame/index.coffee
@@ -1,3 +1,4 @@
+# A map to all frames
 module.exports =
   moment: require './moment'
   thought: require './thought'


Use underscore mixin

Use underscore mixin

--- src/coffee/stockimport.coffee
+++ src/coffee/stockimport.coffee
@@ -1,4 +1,5 @@
 _ = require 'underscore'
+_.mixin require('underscore-mixins')
 Csv = require 'csv'
 Promise = require 'bluebird'
 {ElasticIo} = require 'sphere-node-utils'
@@ -207,13 +208,8 @@
         ElasticIo.returnSuccess msg, next
       Promise.resolve "#{LOG_PREFIX}elastic.io messages sent."
     else
-      _batchList = (tickList, acc = []) ->
-        return acc if _.isEmpty tickList
-        acc.push _.head tickList, 30 # max parallel elem to process
-        tail = _.tail tickList, 30 # max parallel elem to process
-        _batchList tail, acc
-
-      Promise.map _batchList(stocks), (stocksToProcess) =>
+      batchedList = _.batchList(stocks, 30) # max parallel elem to process
+      Promise.map batchedList, (stocksToProcess) =>
         ie = @client.inventoryEntries.all().whereOperator('or')
         @logger.debug stocksToProcess, 'Stocks to process'
         uniqueStocksToProcessBySku = _.reduce stocksToProcess, (acc, stock) ->


Uses CoffeeScript classes on controller

Uses CoffeeScript classes on controller

--- examples/controllers/HealthCheckController.coffee
+++ examples/controllers/HealthCheckController.coffee
@@ -1,3 +1,7 @@
-module.exports.healthCheck = (req, res) => res.send 'I\'m alive'
-module.exports.index = (req, res) => res.send 'It works!'
+class HealthCheckController
+  @healthCheck: (req, res) =>
+    res.send 'I\'m alive'
+  @index: (req, res) =>
+    res.send 'It works!'

+module.exports = HealthCheckController


Refactor and implement the proper objective abstraction

--- library/visualize/trees.coffee
+++ library/visualize/trees.coffee
@@ -74,11 +74,17 @@
         return if event.suppressing or @supermassive
         try @parent?.emit event, origin, parameters...

-# This class represents an implementation of the abstract tree node
-# that implements semantics of the hierarhical tree branch, equal to
-# XML element. This node can contain child elements in the preserved
-# order that they were added in. Also contains the name of the tag.
-module.exports.Element = class Element extends Abstract
+# This is an abstract base class for nodes that have the identity
+# attached next to them. The identify consists of an optional prefix
+# and not mandatory name, both expressed as strings. This class is
+# a conretization of the top-level tree node abstract base class
+module.exports.Identity = class Identity extends Abstract
+
+    # This is a marker that indicates to some internal substsems
+    # that this class has to be considered abstract and therefore
+    # can not be treated as a complete class implementation. This
+    # mainly is used to exclude or account for abstract classes.
+    @abstract yes

     # Either get or set the identification name string for this
     # element. For the semantics of the name please refer to the
@@ -103,6 +109,12 @@
         throw new Error invalid unless correct
         @emit "prefix", this, @$prefix, prefix
         @$prefix = prefix.toString()
+
+# This class represents an implementation of the abstract tree node
+# that implements semantics of the hierarhical tree branch, equal to
+# XML element. This node can contain child elements in the preserved
+# order that they were added in. Also contains the name of the tag.
+module.exports.Element = class Element extends Identity

     # Resolve the specific node by its tag. The method is recursive
     # and will look under the entire tree of this element. If no node


Fix the leak in #101

Fix the leak in #101

Each time you would run a new search, it would create a new
ResultsViewPane. The worst part is that the old one would still be
bound to the model, and so still run the search, create nodes, etc.
No more. This reuses the paneView.

--- lib/find.coffee
+++ lib/find.coffee
@@ -27,8 +27,11 @@
     # See https://github.com/atom/find-and-replace/issues/63
     ResultsPaneView.model = @resultsModel

+    @paneView = null
     atom.project.registerOpener (filePath) =>
-      new ResultsPaneView() if filePath is ResultsPaneView.URI
+      if filePath is ResultsPaneView.URI
+        @paneView = new ResultsPaneView() unless @paneView
+        @paneView

     atom.workspaceView.command 'project-find:show', =>
       @findView.detach()


Rewrite

Rewrite

--- coffee/webdb.coffee
+++ coffee/webdb.coffee
@@ -16,6 +16,13 @@

     _CACHE = {}

+    defaultConfig =
+        type: null
+        version: '1'
+        storeName: 'webdb'
+        blob: false
+        size: 5 * 1024 * 1024  # option, required by websql
+
     globalDBConfig =
         type: null
         version: 1
@@ -31,6 +38,66 @@
         globalDBConfig.type = 'websql'

     if globalDBConfig.type is null then return
+
+    class DBBase
+        constructor: (@options) ->
+        open: ->
+        create: ->
+        create: ->
+        update: ->
+        read: ->
+        readAll: ->
+        remove: ->
+        clear: ->
+        _toObject: ->
+            if @config.blob
+                return {id: arguments[1], blob: arguments[0]}
+            else
+                try
+                    return JSON.parse(arguments[0])
+                catch e
+                    return record
+
+    class WebSQL extends DBBase
+        open: ->
+            config = @config
+            dbName = config.dbName
+            storeName = config.storeName
+            version = config.version
+            maxsize = 1024 * 1024 * 50  # 50MB
+            dtd = $.Deferred()
+
+            try
+                db = openDatabase(dbName, version, dbName, maxsize)
+            catch e
+                if e.name is "SECURITY_ERR"
+                    db = openDatabase(dbName, "", dbName, 1024 * 1024 * 20)
+                else
+                    throw e
+            finally
+                # On android 2.x, openDatabase return null instead of throw quote exceed exception.
+                if db is null
+                    db = openDatabase(dbName, '', dbName, 1024 * 1024 * 5)
+
+                if db is null
+                    console.log('db is null')
+                    setTimeout(
+                        -> dtd.reject()
+                        0
+                    )
+                    return dtd
+
+            db.transaction (transaction) ->
+                transaction.executeSql(
+                    "CREATE TABLE IF NOT EXISTS #{storeName} (id TEXT PRIMARY KEY, data);"
+                    []
+                    ->
+                        dtd.resolve(db)
+                    (_t, e) ->
+                        console.log(e.stack)
+                )
+
+            return dtd

     open =
         websql: (config) ->


* editItem use the standard send data

* editItem use the standard send data

--- src/abstract-api.coffee
+++ src/abstract-api.coffee
@@ -42,8 +42,7 @@
         expect(response.body).to.containSubset expected
       response
   editItem: (aItem, stCode = 200)->
-    @put encodeURIComponent aItem.id
-    .send aItem
+    @put encodeURIComponent aItem.id, data: aItem
     .expect stCode
     .then (response)->
       if stCode is 200


Fallback to file directory

Fallback to file directory

If the project path is unable to be determined fall back to the directory of the current file since that is the best guess we have for the file's project directory.

--- lib/init.coffee
+++ lib/init.coffee
@@ -44,16 +44,14 @@
       projPath = atom.project.relativizePath(editorPath)[0]
       if projPath?
         return projPath
-      null
+      return path.dirname(editorPath)

     isMixProject = (textEditor) ->
       project = projectPath(textEditor)
-      return false if not project
       return fs.existsSync(path.join(project, 'mix.exs'))

     isTestFile = (textEditor) ->
       project = projectPath(textEditor)
-      return false if not project
       relativePath = path.relative(project, textEditor.getPath())
       relativePath.split(path.sep)[0] == 'test'

@@ -65,7 +63,6 @@

     isPhoenixProject = (textEditor) ->
       project = projectPath(textEditor)
-      return false if not project
       mixLockPath = path.join(project, 'mix.lock')
       try
         mixLockContent = fs.readFileSync mixLockPath, 'utf-8'
@@ -119,7 +116,7 @@
         ret.push
           type: "Warning"
           text: reResult[3]
-          filePath: projectPath(textEditor) + '/' + reResult[1]
+          filePath: path.join(projectPath(textEditor), reResult[1])
           range: helpers.rangeFromLineNumber(textEditor, reResult[2] - 1)
         reResult = re.exec(toParse)
       ret
@@ -130,10 +127,6 @@
         errorStack = parseError(resultString, textEditor)
         warningStack = parseWarning(resultString, textEditor)
         (error for error in errorStack.concat(warningStack) when error?)
-
-    getFilePathDir = (textEditor) ->
-      filePath = textEditor.getPath()
-      path.dirname(filePath)

     getOpts = (textEditor) ->
       opts =


revert added option convertAllErrorsToWarnings for now

--- lib/init.coffee
+++ lib/init.coffee
@@ -3,9 +3,6 @@
     pyflakesExecutablePath:
       type: 'string'
       default: 'pyflakes'
-    convertAllErrorsToWarnings:
-      type: 'boolean'
-      default: true

   activate: ->

@@ -17,9 +14,6 @@
       lintOnFly: true
       lint: (textEditor)->
         filePath = textEditor.getPath()
-        msgtype = if atom.config.get(
-          'linter-pyflakes.convertAllErrorsToWarnings'
-        ) then 'Warning' else 'Error'

         return helpers.exec(atom.config.get(
           'linter-pyflakes.pyflakesExecutablePath'
@@ -30,7 +24,7 @@
           while (match = regex.exec(result)) isnt null
             line = parseInt(match[1]) or 0
             toReturn.push({
-              type: msgtype
+              type: 'Warning'
               text: match[2]
               filePath
               range: [[line - 1, 0], [line - 1, 1]]


Extend setting description

Extend setting description

--- lib/init.coffee
+++ lib/init.coffee
@@ -6,12 +6,13 @@
       enum: ['external', 'internal']
       description: 'Switch between internal Pylama (with Virtualenv detection
       and other cool things) or external stable Pylama (do not forget to
-      specify executable path).'
+      specify executable path)'
       order: 0
     interpreter:
       type: 'string'
       default: 'python'
-      description: 'Python interpreter for internal Pylama.'
+      description: 'Python interpreter for internal Pylama
+      (python, python3, /usr/bin/python, /usr/local/bin/python3, etc.)'
       order: 1
     executablePath:
       type: 'string'
@@ -48,25 +49,25 @@
     lintOnFly:
       type: 'boolean'
       default: true
-      description: "Enable linting on the fly. Need to restart Atom."
+      description: "Enable linting on the fly. Need to restart Atom"
       order: 7
     usePep8:
       type: 'boolean'
       default: true
       title: 'Use pycodestyle/pep8'
-      description: 'Use pycodestyle/pep8 style guide checker.'
+      description: 'Use pycodestyle/pep8 style guide checker'
       order: 8
     usePep257:
       type: 'boolean'
       default: true
       title: 'Use pydocstyle/pep257'
-      description: 'Use pydocstyle/pep257 docstring conventions checker.'
+      description: 'Use pydocstyle/pep257 docstring conventions checker'
       order: 9
     usePyflakes:
       type: 'boolean'
       default: true
       title: 'Use Pyflakes'
-      description: 'Use Pyflakes checker.'
+      description: 'Use Pyflakes checker'
       order: 10
     usePylint:
       type: 'boolean'
@@ -74,24 +75,24 @@
       title: 'Use PyLint'
       description: 'Use PyLint linter. May be unstable for internal Pylama.
       For use with external Pylama you should install pylama_pylint module
-      ("pip install pylama-pylint").'
+      ("pip install pylama-pylint")'
       order: 11
     useMccabe:
       type: 'boolean'
       default: true
       title: 'Use McCabe'
-      description: 'Use McCabe complexity checker.'
+      description: 'Use McCabe complexity checker'
       order: 12
     useIsort:
       type: 'boolean'
       default: false
       title: 'Use isort'
-      description: 'Use isort imports checker.'
+      description: 'Use isort imports checker'
       order: 13
     isortOnSave:
       type: 'boolean'
       default: false
-      title: 'isort imports on save (experimental).'
+      title: 'isort imports on save (experimental)'
       order: 14

@@ -99,6 +100,7 @@
     require('atom-package-deps').install 'linter-pylama'
     console.log 'Linter-Pylama: package loaded,
                  ready to get initialized by AtomLinter.'
+

   provideLinter: ->
     LinterPylama = require './linter-pylama.coffee'


a bit of music

a bit of music

--- commands/wit.coffee
+++ commands/wit.coffee
@@ -10,4 +10,14 @@
     /what(\'s| is) the problem\?*/i
     /what are you talking about\?*/i
     /I don'?t know what you('?re| are) talking about/i
+]
+
+brain.addAct 'astley', new brain.Act [
+    "Never gonna let you down"
+    "Never gonna make you cry"
+    "Never gonna tell a lie and hurt you"
+], [
+    /(I'?m )?Never gonna give (you|u) up/i
+    /(I'?m )?Never gonna run around (and|n) desert (you|u)/i
+    /(I'?m )?Never gonna say goodbye/i
 ]


Changed a bad usage of window to create new instances. Now It's used CUI instead window

--- src/base/Element.coffee
+++ src/base/Element.coffee
@@ -61,7 +61,7 @@

 	# create a new instance from the same opts
 	copy: ->
-		new window[@__cls](@opts)
+		new CUI[@__cls](@opts)

 	# returns the merged opt
 	mergeOpt: (key, check_map={}) ->


Remove debugger line

Remove debugger line

--- lib/main.coffee
+++ lib/main.coffee
@@ -21,7 +21,6 @@
   createRecentFiles: (state )->
     unless @recentFiles?
       RecentFiles = require './recent-files'
-      debugger
       if atom.config.get('recent-files-fuzzy-finder.restoreSession')
         @recentFiles = atom.deserializers.deserialize(state)
       @recentFiles ||= new RecentFiles


fix auto update bash script for windows

fix auto update bash script for windows

fixes #54

--- lib/main.coffee
+++ lib/main.coffee
@@ -137,12 +137,12 @@
  * @param {String} Current asar archive
  * @param {String} New downloaded asar archive created by runUpdaets
 ###
-reloadUpdate = (appAsar, updateAsar) ->
+reloadUpdate = (app_asar, update_asar) ->
   if process.platform == 'darwin'
-    fs.unlink appAsar, (err) ->
+    fs.unlink app_asar, (err) ->
       return endSession(new cErrors.UpdateError('Can\'t unlink file').causedBy(err)) if err

-      fs.rename updateAsar, appAsar, (err) ->
+      fs.rename update_asar, app_asar, (err) ->
         return endSession(new cErrors.UpdateError('Can\'t rename app.asar').causedBy(err)) if err

         appPath = __dirname.replace('/Contents/Resources/app.asar', '')
@@ -150,19 +150,26 @@
         app.quit()

   else
-    cmdArgs = [
-      '@echo off'
-      'ping 1.1.1.1 -n 1 -w 3000 > nul',
-      'del "'+appAsar+'"',
-      'ren "'+updateAsar+'" app.asar',
-      'start "" "'+process.execPath+'"',
-      'exit']
-
-    fs.writeFile 'update.bat', cmdArgs.join('\n'), 'utf8', (err) ->
+    cmd = _.template('
+      @echo off\n
+      echo Updating Championify, please wait...\n
+      taskkill /IM championify.exe /f\n
+      ping 1.1.1.1 -n 1 -w 3000 > nul\n
+      del "${app_asar}"\n
+      ren "${update_asar}" app.asar\n
+      start "" "${exec_path}"\n
+      exit\n
+    ')
+
+    params = {
+      app_asar: app_asar
+      update_asar: update_asar
+      exec_path: process.execPath
+    }
+
+    fs.writeFile 'update.bat', cmd(params), 'utf8', (err) ->
       return endSession(new cErrors.UpdateError('Can\'t write update.bat').causedBy(err)) if err
-
       exec 'START update.bat'
-      app.quit()

 ###*


fix function call

fix function call

--- lib/main.coffee
+++ lib/main.coffee
@@ -3,8 +3,6 @@
 # Dependencies
 {spawn} = require 'child_process'
 os = require 'os'
-
-

 module.exports = InnoSetupCore =
   config:
@@ -130,7 +128,7 @@
     if pathToISCC.length > 0
       return callback(pathToISCC)

-    which = spawn @which, ["ISCC"]
+    which = spawn @which(), ["ISCC"]

     which.stdout.on 'data', ( data ) ->
       path = data.toString().trim()
@@ -145,4 +143,4 @@
     if os.platform() is 'win32'
       return "where"

-    return "which"+    return "which"


Eat file paths containing colons (for Windows)

--- lib/main.coffee
+++ lib/main.coffee
@@ -2,7 +2,7 @@
 { BufferedProcess } = require 'atom'

 executablePath = "jolie"
-pattern = ".+:\\s*(?<file>[^:]+):\\s*(?<line>\\d+):\\s*(?<type>error|warning)\\s*:(?<message>.+)"
+pattern = ".+:\\s*(?<file>.+):\\s*(?<line>\\d+):\\s*(?<type>error|warning)\\s*:(?<message>.+)"

 module.exports =
   config: {}


fix admin import redactor twice problem

fix admin import redactor twice problem

--- app/assets/javascripts/admin.js.coffee
+++ app/assets/javascripts/admin.js.coffee
@@ -8,7 +8,6 @@
 #= require redactor-rails
 #= require redactor-rails/plugins
 #= require redactor-rails/langs/zh_tw
-#= require redactor-rails/config
 #= require_self

 # admin menu auto active


fix(win10): Prevent duplicate taskbar items

Fixes #368, #184

Related to #351

--- src/browser/main.coffee
+++ src/browser/main.coffee
@@ -16,6 +16,9 @@
     SquirrelUpdate = require './squirrel-update'
     squirrelCommand = process.argv[1]
     return if SquirrelUpdate.handleStartupEvent(app, squirrelCommand)
+
+  # This prevents Win10 from showing dupe items in the taskbar
+  app.setAppUserModelId('com.squirrel.nylas.nylas')

   addPathToOpen = (event, pathToOpen) ->
     event.preventDefault()


delete redundant keys

delete redundant keys

--- core/app/assets/javascripts/local_storage_polyfill.coffee
+++ core/app/assets/javascripts/local_storage_polyfill.coffee
@@ -23,6 +23,14 @@

   window.localStorageIsEnabled = false

+bad_keys = []
+for i in [0...safeLocalStorage.length]
+  key = safeLocalStorage.key i
+  if key.startsWith('add_comment_to_fact_') && !safeLocalStorage.getItem key
+    bad_keys.push key
+
+for key in bad_keys
+  safeLocalStorage.removeItem key

 for property, value of csrfDataForLocalStorage
   window.safeLocalStorage[property] = value


Replace jQuery .live method by .on

Replace jQuery .live method by .on

--- app/assets/javascripts/links.js.coffee
+++ app/assets/javascripts/links.js.coffee
@@ -2,17 +2,17 @@
 # All this logic will automatically be available in application.js.
 # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
 $(document).ready () ->
-  $('.line a').live 'click', (event) ->
+  $('.line a').on 'click', (event) ->
     window.open $(this).attr('href')
     event.preventDefault()
-  $('.youtube_button').live 'click', (event) ->
+  $('.youtube_button').on 'click', (event) ->
       $(this).parents('.link').children('.youtube_video').toggle()
       event.preventDefault()
-  $('.image_button').live 'click', (event) ->
+  $('.image_button').on 'click', (event) ->
       $(this).parents('.link').children('.image').toggle()
       event.preventDefault()

-  $('.show_all').live 'click', (event) ->
+  $('.show_all').on 'click', (event) ->
     $('.link:not(.nws)').children('.image, .youtube_video').show()
     event.preventDefault()


IP comment

IP comment

--- mrfogg-front/app/coffee/app.coffee
+++ mrfogg-front/app/coffee/app.coffee
@@ -76,7 +76,7 @@

 angular.module('mrfogg.config', []).value('config', {
     host: "144.76.249.158:8080"
-    host: "mrfogg.apiary.io"
+    #    host: "mrfogg.apiary.io"
     #    host: "localhost:8080"
     scheme: "http"
     defaultLanguage: "en"


Hide contact form, restore after Elastic migration

--- app/client/js/react/pages/about.coffee
+++ app/client/js/react/pages/about.coffee
@@ -19,7 +19,8 @@
       render: ->
         div className: 'page',
           p {}, About.MSG_ABOUT
-          if usersStore.isLogged()
+          # TODO: Migrate to Elastic Search.
+          if false && usersStore.isLogged()
             form className: 'contact-form',
               div className: 'form-group',
                 textarea
@@ -31,8 +32,7 @@
                   value: message
               button
                 className: 'btn btn-default'
-                # disabled: !message.length
-                disabled: true
+                disabled: !message.trim().length
                 onClick: @onContactFromSubmit
                 type: 'button'
               , About.MSG_SEND_BUTTON_LABEL


Add partial slice support

Add partial slice support

--- lib/pool.coffee
+++ lib/pool.coffee
@@ -4,6 +4,7 @@
 port = 6379
 host = '127.0.0.1'
 opts = detect_buffers: true
+slice = process.env['SLICE']

 module.exports = ->
   Pool
@@ -11,6 +12,7 @@
     # log: true
     create: (callback) ->
       client = redis.createClient port, host, opts
+      client.select(slice) if slice
       callback null, client
     destroy: (client) ->
       client.end()


Save serialized text after each render

Save serialized text after each render

--- src/trix/controllers/editor_controller.coffee
+++ src/trix/controllers/editor_controller.coffee
@@ -46,8 +46,6 @@

   compositionDidChangeDocument: (document) ->
     @documentController.render()
-    @saveSerializedText()
-    @toolbarController.updateActions()

   compositionDidChangeCurrentAttributes: (currentAttributes) ->
     @toolbarController.updateAttributes(currentAttributes)
@@ -94,6 +92,8 @@
     @mutationObserver.start()
     @selectionManager.unlock() unless @skipSelectionLock
     delete @skipSelectionLock
+    @saveSerializedText()
+    @toolbarController.updateActions()
     @delegate?.didRenderDocument?()

   documentControllerDidFocus: ->


Support options argument for fetchDict and fetchId

--- models.coffee
+++ models.coffee
@@ -619,7 +619,7 @@

         _.extend modelClass,
             collection: collection,
-            fetchDict: (docIdsOrQuery) ->
+            fetchDict: (docIdsOrQuery, options = {}) ->
                 if docIdsOrQuery instanceof J.List or _.isArray docIdsOrQuery
                     if J.List.unwrap(docIdsOrQuery).length is 0
                         return J.Dict()
@@ -629,19 +629,19 @@
                         _id: $in: docIdsOrQuery
                     else
                         docIdsOrQuery
-                instances = @fetch query
+                instances = @fetch query, options
                 instanceById = J.Dict()
                 instances.forEach (instance) ->
                     instanceById.setOrAdd instance._id, instance
                 instanceById

-            fetchIds: (docIds, includeHoles = false) ->
-                instanceDict = @fetchDict docIds
+            fetchIds: (docIds, options = {}) ->
+                instanceDict = @fetchDict docIds, options
                 instanceList = J.List()
                 for docId in J.List.unwrap docIds
                     if instanceDict.get(docId)?
                         instanceList.push instanceDict.get(docId)
-                    else if includeHoles
+                    else if options.includeHoles
                         instanceList.push null
                 instanceList


ClampBounds docs

ClampBounds docs

--- src/clamp_bounds.coffee
+++ src/clamp_bounds.coffee
@@ -25,7 +25,7 @@
   # => 2.5 # half the player's width

   player.I.y
-  #
+  # =>


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/clamp_bounds.coffee
+++ src/clamp_bounds.coffee
@@ -6,7 +6,7 @@
     height: 32

   # This is kind of gross, but we need to make sure
-  # App is around for the tes
+  # App is around for the tests.
   App ||= {}
   App.width ||= 480
   App.height ||= 320


ClampBounds docs

ClampBounds docs

--- src/clamp_bounds.coffee
+++ src/clamp_bounds.coffee
@@ -14,7 +14,7 @@
   player.I.x = -400

   # update the player so ClampBounds can set
-
+  # h
   player.update()
 </pre></code>


fixed loading in main.coffee

fixed loading in main.coffee

--- app/assets/javascripts/main.coffee
+++ app/assets/javascripts/main.coffee
@@ -37,8 +37,11 @@
   "jquery"
   "underscore"
   "bootstrap"
-  "./main/enhancements"
-  "./main/routing"
 ], ->
+
+  require [
+    "./main/enhancements"
+    "./main/routing"
+  ], ->


view cleaned; calls Model for new colors

--- app/assets/javascripts/view.coffee
+++ app/assets/javascripts/view.coffee
@@ -14,7 +14,7 @@

 	#ProgramObjects
 	#One Shader for each Geometry-Type
-	meshProgramObject = null
+	trianglesplaneProgramObject = null
 	pointcloudProgramObject = null

 	#mouse (not used)
@@ -44,9 +44,7 @@
 		#cam.move [+6.3,0,0]

 		engine.background [0.9, 0.9 ,0.9 ,1]
-		#engine.background [0, 0 ,0 ,1]
 		engine.pointSize 100
-		#engine.perspective 30, cvs.width / cvs.height, clippingDistance, clippingDistance + 1
 		engine.perspective 60, cvs.width / cvs.height, 0.0001, 100000

 		engine.onRender renderFunction
@@ -89,49 +87,14 @@
 				engine.deleteSingleBuffer g.vertices.VBO
 				g.setVertices (View.createArrayBufferObject newVertices), newVertices.length

-				newColors = new Float32Array(128*128)
-
-				for j in [0..128*128-1]
-					newColors[j]=0.5
-				###
-				for j in [0...newVertices.length] by 3
-					x = Math.round newVertices[j]
-					y = Math.round newVertices[j + 1]
-					z = newVertices[j + 2]
-					z1 = Math.floor newVertices[j + 2]
-					z2 = Math.ceil newVertices[j + 2]
-
-					xb = Math.floor x/colorcloudWidth
-					yb = Math.floor y/colorcloudWidth
-					z1b = Math.floor z1/colorcloudWidth
-					z2b = Math.floor z2/colorcloudWidth
-					b1 = xb + yb * colorcloudsWidth + z1b * colorcloudsWidth * colorcloudsWidth
-					b2 = xb + yb * colorcloudsWidth + z2b * colorcloudsWidth * colorcloudsWidth
-
-					#p = x + y*colorcloudWidth*colorcloudsWidth + z*colorcloudWidth*colorcloudWidth*colorcloudsWidth*colorcloudsWidth
-					#b = Math.floor(p / (colorcloudWidth*colorcloudWidth*colorcloudWidth))
-					ind1 = (x % colorcloudWidth) + (y % colorcloudWidth) * colorcloudWidth + (z1 % colorcloudWidth) * colorcloudWidth * colorcloudWidth
-					ind2 = (x % colorcloudWidth) + (y % colorcloudWidth) * colorcloudWidth + (z2 % colorcloudWidth) * colorcloudWidth * colorcloudWidth
-					if setColorclouds[b1] isnt 0 and setColorclouds[b2] isnt 0 and x>=0 and y>=0 and z>=0
-						c = colorclouds[b1][ind1] * (1-(z-z1)) + colorclouds[b2][ind2] * (1-(z2-z))
-
-						newColors[j] = c
-						newColors[j+1] = c
-						newColors[j+2] = c
-
-					#if j is 0
-					#console.log "b: " + b + "ind: " + ind + "p: " + p + " z: " + z
-				###
-
-				engine.deleteSingleBuffer g.colors.VBO
-				g.setColors (View.createArrayBufferObject newColors), newColors.length
-
-
-				#engine.deleteEBOBuffer geometries[i]
-				#geometries[i].setVertexIndex (View.createElementArrayBufferObject geometries[i].ind), geometries[i].vertexIndex.length
-				engine.useProgram = meshProgramObject
-
-
+				#get colors for new coords from Model
+				Model.Binary.get(newVertices, (err, colors) ->
+					throw err if err
+					engine.deleteSingleBuffer g.colors.VBO
+					g.setColors (View.createArrayBufferObject colors), colors.length
+				)
+
+				engine.useProgram = trianglesplaneProgramObject

 			engine.useProgram = pointcloudProgramObject if g.getClassType() is "Pointcloud"
 			#counts vertices of all geometries
@@ -148,7 +111,7 @@
 	addGeometry: (geometry) ->
 		geometries.push geometry
 		if geometry.getClassType() is "Trianglesplane"
-				meshProgramObject ?= engine.createShaderProgram geometry.vertexShader, geometry.fragmentShader
+				trianglesplaneProgramObject ?= engine.createShaderProgram geometry.vertexShader, geometry.fragmentShader
 		if geometry.getClassType() is "Pointcloud"
 				pointcloudProgramObject ?= engine.createShaderProgram geometry.vertexShader, geometry.fragmentShader


Add test for referencing native model attributes directly

--- tests/batman/view/simple_rendering_test.coffee
+++ tests/batman/view/simple_rendering_test.coffee
@@ -252,6 +252,19 @@
       ok spy.called
       equal spy.lastCallArguments[0], node[0]

+asyncTest 'allows data-event-click attributes to reference native model properties directly', ->
+  debugger
+  spy = createSpy()
+  class Foo extends Batman.Model
+    handleClick: spy
+  context =
+    foo: new Foo()
+  source = '<button data-event-click="foo.handleClick"></button>'
+  helpers.render source, context, (node) ->
+    helpers.triggerClick(node[0])
+    delay ->
+      ok spy.called
+      equal spy.lastCallArguments[0], node[0]

 asyncTest 'it should allow change events on checkboxes to be bound', 1, ->
   context = new Batman.Object


Simplify timing report

Simplify timing report

--- src/commands/run.coffee
+++ src/commands/run.coffee
@@ -15,34 +15,26 @@
     "#{time}ms"

 module.exports = ->
-  running = []
+  # running = []
   rl = readline.createInterface process.stdin, process.stdout
   rl.setPrompt ''
-  process.on 'uncaughtException', (err) ->
-    rl.write '\n'
-    rl.write "\x1b[31m#{err.stack or err.message}\x1b[39m"
-    rl.close()
   hostlength = 20
   for s in config.servers then hostlength = Math.max(hostlength, s.host.length+2)
   params = params.parse()
   multihost = params.hosts?.length isnt 1 and config.servers.length isnt 1
+  times = {}
   run(config, params)
   .on 'context', (ctx) ->
     ctx
     .on 'action', (status) ->
       return if ctx.action.hidden
       status ?= ctx.DISABLED
-      time = null
       if status is ctx.STARTED
-        running.push [ctx.config.host, ctx.action.name, Date.now()]
+        times[ctx.config.host] = Date.now()
       else
-        for i in [running.length-1..0]
-          if running[i][0] is ctx.config.host and running[i][1] is ctx.action.name
-            time = Date.now() - running[i][2]
-            running.splice(i, 1)
-            break
+        time = Date.now() - times[ctx.config.host]
       line = ''
-      line += "#{pad ctx.config.host, hostlength}" #if config.servers.length
+      line += "#{pad ctx.config.host, hostlength}"
       line += "#{pad ctx.action.name, 40}"
       statusmsg = switch status
         when ctx.PASS then "\x1b[36m#{ctx.PASS_MSG}\x1b[39m"
@@ -58,7 +50,7 @@
         when ctx.INAPPLICABLE then "\x1b[36m#{ctx.INAPPLICABLE_MSG}\x1b[39m"
         else (if typeof status is 'number' then "INVALID CODE" else "\x1b[36m#{status}\x1b[39m")
       line += "#{pad statusmsg, 20}"
-      line += "#{print_time time}" if status isnt ctx.STARTED
+      line += "#{print_time time}" if time
       if status is ctx.STARTED
         rl.write line unless multihost
       else


Update# add Batman.I18N t and translate filter correctly get keypath value to display translation

--- src/extras/batman.i18n.coffee
+++ src/extras/batman.i18n.coffee
@@ -51,5 +51,14 @@

 Batman.I18N.set 'locales', new Batman.I18N.LocalesStorage

-Batman.Filters.t = Batman.Filters.translate = Batman.Filters.interpolate
-Batman.config.translations = true+#Batman.Filters.t = Batman.Filters.translate = Batman.Filters.interpolate
+Batman.mixin Batman.Filters,
+  translate: (args...) ->
+    binding = if args[2] then args[2] else args[1]
+    key = args[0] # Store key for lookupKeypath if translate didn't found
+    unless binding.key and binding.key.substr(0, 2) == "t." # If already translated, skip it
+      args[0] = Batman.I18N.translate(key)
+      args[0] ||= key # no translate, return default key
+    Batman.Filters.interpolate.apply(@, args)
+Batman.Filters.t = Batman.Filters.translate
+Batman.config.translations = true


Fix ladder simulation exception (#5937)

Fix ladder simulation exception (#5937)

* handle malformed sessions

* handle malformed sessions

* grammar update

Co-authored-by: smallst_wsl <6c42689ff77371401bf43b7d56b93ac1ca3e92d3@163.com>


server: Add configFilename to require options

--- server.coffee
+++ server.coffee
@@ -28,7 +28,7 @@
     @port = opts?.port ? process.env.PORT ? 1341

     # Path to config.json
-    @configFilename = "#{@basedir}/config/config.json"
+    @configFilename = opts?.configFilename ? "#{@basedir}/config/config.json"

     # EJS template for formatting pages
     @pageTemplateFilename = "#{@basedir}/config/page.ejs"


Remove reference to unused decorator

Remove reference to unused decorator

--- lib/analysis_component.coffee
+++ lib/analysis_component.coffee
@@ -1,6 +1,5 @@
 AnalysisServer = require './analysis_server'
 AnalysisView = require './views/analysis_view'
-AnalysisDecorator = require './analysis_decorator'
 AnalysisAPI = require './analysis_api'
 BufferUpdateComponent = require './buffer_update_component'
 Utils = require './utils'
@@ -14,7 +13,6 @@
   subscriptions: []
   analysisView: null
   analysisServer: null
-  analysisDecorator: null
   analysisAPI: new AnalysisAPI()

   quickIssueView: null
@@ -26,7 +24,6 @@
     @subscriptions.push atom.project.onDidChangePaths @watchDartProject
     @watchDartProject()
     # @createAnalysisView()
-    # @analysisDecorator = new AnalysisDecorator(this)
     # @createQuickIssueView()

     atom.workspace.observeTextEditors (editor) =>


Fix a bug

Fix a bug

--- lib/util.coffee
+++ lib/util.coffee
@@ -26,7 +26,7 @@
     add = (m, x) -> m + (f?(x) ? x ? 0)
     _.reduce list, add, 0

-  in_groups_of: (list, n) ->
+  in_groups_of: (list, n, f) ->
     groups = []
     sub = []
     for item in list
@@ -36,6 +36,8 @@
         sub = []
     if sub.length
       groups.push sub
+    if typeof(f) == 'function'
+      _.each groups, f
     groups

   without: (arr, elem) ->


Break endless cycle in getRootDir on undefined dir

--- lib/util.coffee
+++ lib/util.coffee
@@ -30,10 +30,10 @@
       d.getEntriesSync().some (file) ->
         file.isFile() and (file.getBaseName() is 'cabal.sandbox.config')
     findProjectRoot = (d, check) ->
-      until d?.isRoot?() or check d
+      until d?.isRoot?() or not d? or check d
         d = d?.getParent?()
       d if check d
-    dir = buffer.file?.getParent?()
+    dir = buffer.file?.getParent?() ? Util.getRootDirFallback buffer
     dir = findProjectRoot(dir, dirHasCabalFile) ? findProjectRoot(dir, dirHasSandboxFile)
     unless dir?.isDirectory?()
       dir = Util.getRootDirFallback buffer


GameObject.Effect

GameObject.Effect

--- src/game_object_effect.coffee
+++ src/game_object_effect.coffee
@@ -1,5 +1,5 @@
 ###*
-The `Effect` module provides a method to fade a sprite to transparent.
+`Effect` module provides a method to fade a sprite to transparent.
 You may also provide a callback function that is executed when the sprite has finished fading out.

 @name Effect


Archivos

Archivos

--- modules/player/commands.coffee
+++ modules/player/commands.coffee
@@ -9,7 +9,7 @@

     # Play
     @registerCommand 'play', { argSeparator: '|' }, (msg,args)=>
-      return msg.reply 'No video specified.' if not args[0].trim()
+      return msg.reply 'No video specified.' if not args[0].trim() and not msg.attachments[0]
       return msg.reply 'You must be in a voice channel to request songs.' if not msg.member.getVoiceChannel()
       urlToFind = args[0]
       if msg.attachments[0]


Updated documentation for SearchView

Updated documentation for SearchView


#193: fix for dynamic tabs where the class was being removed by using the newly added palette.borderContext

--- modules/tabs/main/index.coffee
+++ modules/tabs/main/index.coffee
@@ -5,7 +5,7 @@
   hx.select(element).classed('hx-tab-active', true)

   context = hx.palette.context(element)
-  selection.select('.hx-tabs-content').class('hx-tabs-content' + (if context then ' hx-border-' + context else ''))
+  hx.palette.borderContext(selection.select('.hx-tabs-content'), context)

   hx.select(tabs.selector).selectAll('.hx-tab-content').classed('hx-tab-content-hidden', true)
   hx.select('#' + hx.select(element).attr('data-content')).classed('hx-tab-content-hidden', false)


Background padding tweak

Background padding tweak

--- moon-phase.widget/index.coffee
+++ moon-phase.widget/index.coffee
@@ -47,6 +47,8 @@
   border-radius     : 25px
   line-height       : 1.5
   padding           : 5px
+  padding-left      : 15px
+  padding-right     : 15px

   icon-size = #{option.fontSize * 7}px


[minor] wording

[minor] wording

--- test/src/backbone.websql.deferred-test.coffee
+++ test/src/backbone.websql.deferred-test.coffee
@@ -346,7 +346,7 @@
         done()

   describe 'Backbone.WebSQL.promiseType', ->
-    context 'Backbone.WebSQL.promiseType is set to use Q', ->
+    context 'when Backbone.WebSQL.promiseType is set to use Q', ->
       beforeEach (done) ->
         Backbone.WebSQL.promiseType = 'q'

@@ -366,7 +366,7 @@
           expect(fetchedUser.get 'name').to.eq @user.get 'name'
           done()

-    context 'Backbone.WebSQL.promiseType is set unknown type', ->
+    context 'when Backbone.WebSQL.promiseType is set unknown type', ->
       beforeEach ->
         Backbone.WebSQL.promiseType = 'foo'


click activated on the url within url popover

--- app/views/CNeditor/CNeditor.coffee
+++ app/views/CNeditor/CNeditor.coffee
@@ -1010,10 +1010,12 @@
         if href == '' or href == 'http:///'
             href = 'http://'
         pop.urlInput.value = href
+        pop.link.href = href
         txt = ''
         txt += seg.textContent for seg in segments
         pop.textInput.value = txt
         pop.initialTxt = txt
+

         # Insert the popover
         seg.parentElement.parentElement.appendChild(pop)
@@ -1189,7 +1191,7 @@
             Link
             (Ctrl+K)

-                Open link (Ctrl+click)

+                Open link (Ctrl+click)

                 url<input type="text">

                 Text<input type="text">

                 <button>ok</button>
@@ -1197,6 +1199,7 @@
                 <button>Delete</button>

             """
+        pop.link = pop.getElementsByTagName('A')[0]
         b = document.querySelector('body')
         # b.insertBefore(frag,b.firstChild)
         [btnOK, btnCancel, btnDelete] = pop.querySelectorAll('button')


Use String() instead of toString()

Use String() instead of toString()

--- tutor/src/components/performance-forecast/statistics.cjsx
+++ tutor/src/components/performance-forecast/statistics.cjsx
@@ -46,7 +46,7 @@

           { for key, value of @props.section.clue
             value = value.join(' ') if _.isArray(value)
-
{key}: {value.toString()}
}
+
{key}: {String(value)}
}

       </SpyMode.Content>


Speed up smooth scrolling a bit

Speed up smooth scrolling a bit

--- assets/javascripts/lib/util.coffee
+++ assets/javascripts/lib/util.coffee
@@ -234,13 +234,13 @@

   if smoothScroll
     newDistance = smoothEnd - smoothStart
-    smoothDuration += Math.min 400, Math.abs(smoothDistance - newDistance)
+    smoothDuration += Math.min 300, Math.abs(smoothDistance - newDistance)
     smoothDistance = newDistance
     return

   smoothStart = el.scrollTop
   smoothDistance = smoothEnd - smoothStart
-  smoothDuration = Math.min 400, Math.abs(smoothDistance)
+  smoothDuration = Math.min 300, Math.abs(smoothDistance)
   startTime = Date.now()

   smoothScroll = ->


Translate undo message action

Translate undo message action

--- client/app/stores/layout_store.coffee
+++ client/app/stores/layout_store.coffee
@@ -135,7 +135,7 @@
                 smart_count: smart_count

         makeUndoAction = (ref) ->
-            label: 'undo'
+            label: t 'action undo'
             onClick: -> getMessageActionCreator().undo ref

         handle ActionTypes.MESSAGE_TRASH_SUCCESS, ({target, ref, updated}) ->


Fix currentSubmit for component update

Fix currentSubmit for component update

--- client/components/ReviewResult.coffee
+++ client/components/ReviewResult.coffee
@@ -66,7 +66,7 @@
         if prevProps.result._id != @props.result._id
             @setState
                 commentText: ""
-                currentSubmit: @props.data?[0]
+                currentSubmit: if @props.data then @props.data[@props.data.length - 1] else null

     accept: () ->
         @setResult("AC")


get rid of the owner field

get rid of the owner field

--- workers/social/lib/social/models/domain.coffee
+++ workers/social/lib/social/models/domain.coffee
@@ -27,7 +27,6 @@
         type        : String
         required    : yes
         set         : (value)-> value.toLowerCase()
-      owner         : ObjectId
       regYears      : Number
       orderId       :
         recurly     : String


Equality Chains tests added to spec

Equality Chains tests added to spec

--- spec/vfl.coffee
+++ spec/vfl.coffee
@@ -234,7 +234,70 @@
               '#b1[width] == #b2[height]'
             ]
           ]
-
-
-
-
+
+
+  # Equality Chains
+  # --------------------------------------------------
+
+  describe '/* Equality Chains */', ->
+
+    parse """
+            @horizontal [#b1][#b2] equal-height(!strong) equal-width(250); // basic equality chains
+          """
+        ,
+          [
+            [
+              'ccss'
+              '#b1[right] == #b2[left]'
+              '#b1[height] == #b2[height] !strong'
+              '#b1[width] == 250 == #b2[width]'
+            ]
+          ]
+
+    parse """
+            @vertical [#b1][#b2][#b3][#b4] equal-centerX equal-width(!weak10) equal-height(150!required) !medium; // adv equality chains
+          """
+        ,
+          [
+            [
+              'ccss'
+              '#b1[bottom] == #b2[top] !medium'
+              '#b2[bottom] == #b3[top] !medium'
+              '#b3[bottom] == #b4[top] !medium'
+              '#b1[centerX] == #b2[centerX] == #b3[centerX] == #b4[centerX]'
+              '#b1[width] == #b2[width] == #b3[width] == #b4[width] !weak10'
+              '#b1[height] == 150 == #b2[height] == 150 == #b3[height] == 150 == #b4[height] !required;'
+            ]
+          ]
+
+    parse """
+            @vertical [#b1(==100!strong)] equal-centerX equal-width( 50 !weak10); // single view w/ equality chains
+          """
+        ,
+          [
+            [
+              'ccss'
+              '#b1[height] == 100 !strong'
+              '#b1[width] == 50 !weak10'
+            ]
+          ]
+
+    parse """
+            @vertical |-8-[#b1(==100!strong)][#b2]-8-| in(#panel) equal-centerX( #panel[centerX] !required) equal-width(50!weak10); // adv w/ super views & equality chains
+          """
+        ,
+          [
+            [
+              'ccss'
+              '#b1[height] == 100 !strong'
+              '#panel[top] + 8 == #b1[top]'
+              '#b1[bottom] == #b2[top]'
+              '#b2[bottom] + 8 == #panel[bottom]'
+              '#b1[centerX] == #panel[centerX] == #b2[centerX] !required'
+              '#b1[width] == 50 == #b2[width]'
+            ]
+          ]
+
+
+
+


controlsView: add Random control

controlsView: add Random control

--- coffee/src/views/controls_view.coffee
+++ coffee/src/views/controls_view.coffee
@@ -306,6 +306,15 @@
   tooltip: => title: 'Pause', delay: show: 1500
   defaults: => _.extend super,
     icon: 'pause'
+
+
+
+class RandomControlView extends IconControlView
+  controlName: => 'RandomControl'
+  className: @classNameExtend 'random'
+  tooltip: => title: 'Random', delay: show: 1500
+  defaults: => _.extend super,
+    icon: 'magic'

@@ -448,6 +457,7 @@
 acorn.player.controls.GridControlView = GridControlView
 acorn.player.controls.PlayControlView = PlayControlView
 acorn.player.controls.PauseControlView = PauseControlView
+acorn.player.controls.RandomControlView = RandomControlView

 acorn.player.controls.ImageControlView = ImageControlView
 acorn.player.controls.AcornControlView = AcornControlView


fix style.coffee

fix style.coffee

--- app/templates/gulp/tasks/styles.coffee
+++ app/templates/gulp/tasks/styles.coffee
@@ -32,7 +32,7 @@
       "opera >=10"
     ]
   ]
-  if PROP.isDev
+  unless PROP.isDev
     postprocessors = postprocessors.concat [
       mqpacker
       csswring


Allow smoother absorbing effect

Allow smoother absorbing effect

--- src/Blob.coffee
+++ src/Blob.coffee
@@ -41,7 +41,7 @@
       # Set weight to preferred weight
       if entBlob.weightCap
         entBlob.weight += (entBlob.weightCap - entBlob.weight) / 4
-        if Math.abs entBlob.weight - entBlob.weightCap < 1
+        if Math.abs entBlob.weight - entBlob.weightCap < 3
           entBlob.weight = entBlob.weightCap
           entBlob.weightCap = null
         else continue
@@ -71,6 +71,7 @@
           expectedWeight = square Math.max 0, smallPos.radius - diff
           expectedWeight = 0 if expectedWeight < 10
           weightGain = smallBlob.weight - expectedWeight
+          weightGain /= 5 if weightGain > 10
           # Velocity sharing doesn't work as well as expected.
           #bigBlob.velX = (bigBlob.velX + smallBlob.velX) * bigBlob.weight / (bigBlob.weight + weightGain)
           #bigBlob.velY = (bigBlob.velY + smallBlob.velY) * bigBlob.weight / (bigBlob.weight + weightGain)


Fixed duplication of configuration in CI files

--- src/interactive-config.coffee
+++ src/interactive-config.coffee
@@ -116,11 +116,11 @@

   config['dependencies'] = {} unless config['dependencies']?
   config['dependencies']['pre'] = [] unless config['dependencies']['pre']
-  config['dependencies']['pre'].push "npm install -g dredd"
+  config['dependencies']['pre'].push("npm install -g dredd")if config['dependencies']['pre'].indexOf("npm install -g dredd") == -1

   config['test'] = {} unless config['test']?
   config['test']['pre'] = [] unless config['test']['pre']
-  config['test']['pre'].push "dredd"
+  config['test']['pre'].push("dredd") if config['test']['pre'].indexOf("dredd") == -1

   yamlData = yaml.safeDump config
   fs.writeFileSync file, yamlData
@@ -134,10 +134,10 @@
     config = {}

   config['before_install'] = [] unless config['before_install']?
-  config['before_install'].push "npm install -g dredd"
+  config['before_install'].push("npm install -g dredd") if config['before_install'].indexOf("npm install -g dredd") == -1

   config['before_script'] = [] unless config['before_script']?
-  config['before_script'].push "dredd"
+  config['before_script'].push("dredd") if config['before_script'].indexOf("dredd") == -1

   yamlData = yaml.safeDump config
   fs.writeFileSync file, yamlData


KDFramework: list item getItemDataId fixed

--- components/list/KDListItemView.coffee
+++ components/list/KDListItemView.coffee
@@ -45,4 +45,4 @@
     @unsetClass "selected"
     @unsetClass "dimmed"

-  getItemDataId:-> @getData().getId?()+  getItemDataId:-> @getData().getId?() or @getData().id or @getData()._id


Fixed comment typo

Fixed comment typo

--- src/Demo.coffee
+++ src/Demo.coffee
@@ -8,25 +8,25 @@
   run: () ->
     @client.connect();

-    # Attempt to reconnect when the connection is dropped
+    # Attempt to reconnect when the connection is dropped.
     @client.on 'disconnect', =>
       @client.reconnect()

-    # Subscript to posts and comments when connected
+    # Subscripe to posts and comments when connected.
     @client.on 'connect', =>
       @client.subscribe 'posts'
       @client.subscribe 'comments'

-    # Print a comment when it is received
+    # Print a comment when it is received.
     @client.on 'comment', (comment) =>
       @print comment

-    # Print a post when it is received
+    # Print a post when it is received.
     @client.on 'post', (post) =>
       @print post

-  # Pads a string to a target length with whitespace to the right
+  # Pads a string to a target length with whitespace to the right.
   rpad: (string, targetLength) ->
     if string.length <= targetLength
       for _ in [0...targetLength - string.length]


Update jquery.logosDistort.coffee

Update jquery.logosDistort.coffee

- Some `destroy` function side effects fixed

--- src/jquery.logosDistort.coffee
+++ src/jquery.logosDistort.coffee
@@ -268,7 +268,7 @@
           el.style[t] = 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)'
           support3d = window.getComputedStyle el
           support3d = support3d.getPropertyValue transforms[t]
-
+			document.body.removeChild(el)
       if support3d? then support3d isnt 'none' else false

     destroy: ->
@@ -277,8 +277,8 @@
       @$el.removeData "plugin_#{pluginName}";

     hook: (hookName) ->
-      if options[hookName]?
-        options[hookName].call @element
+      if @settings[hookName]?
+        @settings[hookName].call @element

   $.fn[pluginName] = (options) ->
     @each ->
@@ -315,4 +315,4 @@

   if !window.cancelAnimationFrame
     window.cancelAnimationFrame = (id) ->
-      clearTimeout(id)+      clearTimeout(id)