Start cleaning up stock item add using model

--- backend/app/assets/javascripts/spree/backend/stock_management/index_add_forms.coffee
+++ backend/app/assets/javascripts/spree/backend/stock_management/index_add_forms.coffee
@@ -63,25 +63,22 @@

   onSubmit: (ev) ->
     ev.preventDefault()
-    variantId = $(ev.currentTarget).data('variant-id')
-    countInput = $("#variant-count-on-hand-#{variantId}")
-    locationSelect = $("#variant-stock-location-#{variantId}")
+    variantId = @model.get('variant_id')
+    countInput = @$("[name='count_on_hand']")
+    locationSelect = @$("[name='stock_location_id']")
     locationSelectContainer = locationSelect.siblings('.select2-container')
     resetErrors(locationSelectContainer, countInput)
     validate(locationSelect, locationSelectContainer, countInput)
     return if hasErrors(locationSelectContainer, countInput)

-    stockLocationId = locationSelect.val()
-    backorderable = $("#variant-backorderable-#{variantId}").prop("checked")
-    stockItem = new Spree.StockItem
-      variant_id: variantId
-      backorderable: backorderable
+    @model.set
+      backorderable: @$("[name='backorderable']").prop("checked")
       count_on_hand: countInput.val()
-      stock_location_id: stockLocationId
+      stock_location_id: locationSelect.val()
     options =
       success: successHandler
       error: errorHandler
-    stockItem.save(null, options)
+    @model.save(null, options)

 $ ->
   $('.js-add-stock-item').each ->


fix form submit with vanilla js method

fix form submit with vanilla js method

--- assets/coffeescript/pupil_store.coffee
+++ assets/coffeescript/pupil_store.coffee
@@ -456,9 +456,10 @@
         field = $(event.target)
         fieldId = $(field).attr('id')
         bFieldVal = $(field).val()
-        type = fieldId.split('_').shift()
+        type = fieldId.split('_').slice(0,-1)
         try
-          sField = if type is 'address' then type+"_s0" else type+"_s"
+          type.push("s")
+          sField = type.join("_")
           $("[id=#{ sField }]").val(bFieldVal)
         catch e

@@ -543,12 +544,10 @@

           xhr = new XMLHttpRequest()

-          xhr.addEventListener "readystatechange", =>
-            console.log @readyState
+          xhr.addEventListener "readystatechange", ->

             if @readyState is 4
               if @status is 200
-                console.log "status: #{@status}, responseText: #{@responseText}"
                 window.location.replace "#{window.location.origin}/order_success"
               else
                 console.warn "Request Error: #{@statusText}"
@@ -558,24 +557,6 @@
           xhr.setRequestHeader "cache-control", "no-cache"

           xhr.send formData_formatted_JSON
-          # $.ajax
-          #   type: 'POST'
-          #   crossDomain: true
-          #   url: url
-          #   dataType: "json"
-          #   data: formData
-          #   error: (jqXHR, textStatus, errorThrown) ->
-          #     # console.warn "AJAX Error: #{textStatus}"
-          #     if navigator.userAgent.search "Safari"  >= 0 and navigator.userAgent.search "Chrome" < 0
-          #         # Known Safari Error see: https://code.google.com/p/google-apps-script-issues/issues/detail?id=3226
-          #         # We continue anyways to the success page.
-          #         console.log "Successful AJAX call with Safari."
-          #         $(location).attr('href',location.origin + "/order_success")
-          #   success: (data, textStatus, jqXHR) ->
-          #     console.log "Successful AJAX call: #{textStatus}"
-          #     $(location).attr('href',location.origin + "/order_success")
-          #   complete: (jqXHR,textStatus) ->
-          #     $('label[for="form-submit"]').removeClass("loading")

   countryValidator: ->


draft3/medium/schema should match draft 3

--- benchmarks/draft3/medium/schema.coffee
+++ benchmarks/draft3/medium/schema.coffee
@@ -2,31 +2,34 @@
   description: "A moderately complex schema with some nesting and value constraints"
   type: "object"
   additionalProperties: false
-  required: ["api_server", "transport", "storage", "chain"]
   properties:

     api_server:
       description: "Settings for the HTTP API server"
       type: "object"
       additionalProperties: false
-      required: ["url", "host", "port"]
+      required: true
       properties:
         url:
           type: "string"
           format: "uri"
+          required: true
         host:
           type: "string"
+          required: true
         port:
           type: "integer"
           minimum: 1000
+          required: true

     transport:
       description: "Settings for the Redis tranport"
       additionalProperties: false
-      required: ["server"]
+      required: true
       properties:
         server:
           type: "string"
+          required: true
         options:
           type: "object"
         queues:
@@ -37,23 +40,28 @@

     storage:
       description: "Settings for the PostgreSQL storage"
-      required: ["server", "database", "user"]
+      required: true
       properties:
         server:
           type: "string"
+          required: true
         database:
           type: "string"
+          required: true
         user:
           type: "string"
+          required: true
         options:
           type: "object"

     chain:
       description: "Settings for the Chain.com client"
-      required: ["api_key_id", "api_key_secret"]
+      required: true
       properties:
         api_key_id:
           type: "string"
+          required: true
         api_key_secret:
           type: "string"
+          required: true


[benchmarks] fix for ssh server.

[benchmarks] fix for ssh server.

--- benchmarks/framework/ssh_server.coffee
+++ benchmarks/framework/ssh_server.coffee
@@ -9,8 +9,7 @@
          printEventsPerSec,
          printEverything} = opts

-        @sshOpts = ['-tt']
-        @sshOpts = @sshOpts.concat(host.split(' '))
+        @sshOpts = host.split(' ')

         @server = Spawn('ssh', @sshOpts.concat(cmd))
         @server.stderr.setEncoding('utf8')


improve error handling for api error

improve error handling for api error

--- plugins/kubernetes/app/assets/javascripts/kubernetes/components/clusters/list.coffee
+++ plugins/kubernetes/app/assets/javascripts/kubernetes/components/clusters/list.coffee
@@ -54,7 +54,10 @@
             else
               tr null,
                 td colSpan: '5',
-                  'No clusters found'
+                  if error
+                    'Could not retrieve clusters'
+                  else
+                    'No clusters found'


Added abilitity to specify html4 root path

--- lib/assets/javascripts/wiselinks.js.coffee
+++ lib/assets/javascripts/wiselinks.js.coffee
@@ -19,8 +19,8 @@
       @assets_digest = $("meta[name='assets-digest']").attr("content")

       if History.emulated.pushState && @options.html4 == true
-        if window.location.href.indexOf('#!') == -1 && window.location.pathname != '/'
-          window.location.href = "#{window.location.protocol}//#{window.location.host}/#!#{window.location.pathname}"
+        if window.location.href.indexOf('#!') == -1 && @options.html4_root_path != null && window.location.pathname != @options.html4_root_path
+          window.location.href = "#{window.location.protocol}//#{window.location.host}#{@options.html4_root_path}#!#{window.location.pathname}"

         if window.location.hash.indexOf('#!') != -1
           self._call(window.location.hash.substring(2))
@@ -28,9 +28,7 @@
       History.Adapter.bind(
         window,
         "statechange"
-        (event, data) ->
-          return false if (!History.ready)
-
+        (event, data) ->
           state = History.getState()
           self._call(state.url, state.data.target, state.data.render)
       )
@@ -58,16 +56,15 @@
   enabled: ->
     !History.emulated.pushState || @options.html4 == true

-  load: (url, target, render = 'template') ->
-    History.ready = true
+  load: (url, target, render = 'template') ->
     History.pushState({ timestamp: (new Date().getTime()), render: render, target: target }, document.title, url )

-  reload: () ->
-    History.ready = true
+  reload: () ->
     History.replaceState({ timestamp: (new Date().getTime()), render: 'template' }, document.title, History.getState().url )

   _defaults: ->
     html4: true
+    html4_root_path: '/'

   _call: (url, target, render = 'template') ->
     self = this


Implemented the core jQuery like selector!

--- src/cheerio.coffee
+++ src/cheerio.coffee
@@ -6,127 +6,202 @@
 parser = require "./parser"
 renderer = require "./renderer"

-cheerio = (dom) ->
-
-  selector = (select) ->
-    # Create new instance
-    if !(this instanceof arguments.callee)
-      return new selector select
-
-    if select is null
-      @context = []
-
-    else if _.isString select
-      @context =  soupselect.select dom, select
+cheerio = do ->
+  cheerio = (selector, context, root) ->
+    return new cheerio.fn.init selector, context, root
+
+  # A simple way to check for HTML strings or ID strings
+  # Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+  quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/
+
+  # Used for trimming whitespace
+  trimLeft = /^\s+/
+  trimRight = /\s+$/
+
+  # Save a reference to some core methods
+  toString = Object.prototype.toString
+  hasOwn = Object.prototype.hasOwnProperty
+  push = Array.prototype.push
+  slice = Array.prototype.slice
+  trim = String.prototype.trim
+  indexOf = Array.prototype.indexOf
+
+  # [[Class]] -> type pairs
+  class2type = {}
+
+  cheerio.fn = cheerio.prototype =
+    constructor: cheerio
+    init: (selector, context, root) ->
+      # Handle $(""), $(null), or $(undefined)
+      if not selector
+        return this
+
+      if root
+        if _.isString context
+          selector = "#{context} #{selector}"
+        context = root
+
+      # Handle strings
+      if typeof selector == "string"
+        # Handle HTML strings
+        if selector.charAt(0) == "<" && selector.charAt( selector.length - 1 ) == ">" && selector.length >= 3
+          match = [ null, selector, null ]
+        else
+          match = quickExpr.exec selector
+
+        if match && (match[1] || !context)
+          if match[1]
+            # It's an HTML string
+            return cheerio.merge this, parser.parse selector
+          else
+            console.log 'selector', selector
+            console.log 'root', root
+            # Classes, IDs just defer to soupselect
+            elems = soupselect.select context, selector
+            this.selector = selector
+            return cheerio.merge this, elems
+
+
+        # console.log 'selector', selector
+        # console.log 'context', context
+        # console.log 'root', root
+
+        # HANDLE: $(expr, $(...))
+        if !context or context.cheerio
+          return (context or root).find selector

-    else if select.context
-      @context = select.context
-
-    # May do more ifs but for now assume it's an object otherwise and
-    # we want to wrap it.
-    else
-      @context = select
-
-    return this
-
-  ###
-    PUBLIC METHODS
-  ###
-
-  selector::dom = () ->
-    return @context
-
-  selector::html = () ->
-    return renderer.render @context
-
-  selector::text = (text, value) ->
-    if @context.length is 1
-      elem = @context[0]
-    else
-      return ""
-
-    exists = (elem.children.length is 1 and elem.children[0].type is "text")
-    if not value
-      if exists
-        return elem.children[0].data
+        # HANDLE: $(expr, context)
+        else
+          if _.isString context
+            context = parser.parse context
+          return this.constructor(context).find selector
+
+      return cheerio.makeArray( selector, this );
+      # if context
+        # return cheerio selector, parser.parse con
+
+    cheerio : "0.0.1"
+    length : 0
+    selector : ""
+    root : null
+    size : () ->
+      this.length
+
+    toArray : () ->
+      return slice.call this, 0
+
+    # Get the Nth element in the matched element set OR
+    # Get the whole matched element set as a clean array
+    get : (num) ->
+      (if num == null then this.toArray() else (if num < 0 then this[this.length + num] else this[num]))
+
+    pushStack : (elems, name, selector) ->
+      ret = this.constructor()
+      if cheerio.isArray(elems)
+        push.apply ret, elems
       else
-        return ""
-    else
-      if exists
-        elem.children[0].data = value
+        cheerio.merge ret, elems
+
+      ret.prevObject = this
+      ret.context = this.context
+
+      if name == "find"
+        ret.selector = this.selector + (if this.selector then " " else "") + selector
+      else
+        ret.selector = this.selector + "." + name + "(" + selector + ")"  if name
+
+      return ret
+
+    sort : [].sort
+    splice : [].splice
+
+  # Give the init function the jQuery prototype for later instantiation
+  cheerio.fn.init.prototype = cheerio.fn
+
+  # Use underscores extend
+  cheerio.extend = cheerio.fn.extend = (obj) ->
+    return _.extend this, obj
+
+  cheerio.extend
+
+    type : ( obj ) ->
+    		if obj == null then String obj else class2type[ toString.call(obj) ] or "object"
+
+    isArray : (array) ->
+      return _(this).isArray()
+
+    merge : (first, second) ->
+      i = first.length
+      j = 0
+
+      if typeof second.length == "number"
+        l = second.length
+
+        while j < l
+          first[i++] = second[j]
+          j++
+
       else
-        return this
-
-
-  selector::attr = (attribute, value) ->
-    this.each (elem) ->
-      if not value
-        if elem.attribs and elem.attribs[attribute]
-          return elem.attribs[attribute]
+        while second[j] != undefined
+          first[i++] = second[j++]
+
+      first.length = i
+
+      return first
+
+    makeArray : (array, results) ->
+      ret = results or []
+      if array?
+        type = cheerio.type(array)
+        if not array.length? or type == "string" or type == "function" or type == "regexp"
+          push.call ret, array
         else
-          return ""
-
-      else
-        if elem.attribs
-          elem.attribs[attribute] = value
-
-        return this
-
-  selector::remove = () ->
-    this.each (elem) ->
-      elem.raw = null
-
-    return this
-
-  selector::each = (fn) ->
-    for elem, i in @context
-      selected = selector elem
-      fn.call selected, elem, i
-
-    return this
-
-  selector::parent = () ->
-
-    if @context[0].parent
-      return selector @context[0].parent
-    else
-      return selector null
-
-  selector::prev = () ->
-
-    if @context[0].prev
-      return selector @context[0].parent
-    else
-      return selector null
-
-  selector::next = () ->
-    if @context[0].next
-      return selector @context[0].next
-    else
-      return selector null
-
-  selector::size = () ->
-    return @context.length
-
-  selector::singular = () ->
-    if @.size() is 1
-      return true
-    else return false
-
-  ###
-    STATIC METHODS
-  ###
-
-  selector.html = () ->
-    return renderer.render dom
-
-  selector.dom = () ->
-    return dom
-
-  return selector
-
-
-
-module.exports = (content) ->
-  return cheerio parser.parse content
-
+          cheerio.merge ret, array
+
+      return ret
+
+    load : (html) ->
+      root = parser.parse html
+
+      return (selector, context) ->
+        cheerio selector, context, root
+
+
+  # Populate class2type map
+  _.each "Boolean Number String Function Array Date Regex Object".split(" "), (name, i) ->
+    class2type[ "[object #{name}]" ] = name.toLowerCase()
+
+  # Actual API
+  cheerio.fn.extend
+
+    find : (selector) ->
+      elem = soupselect.select this.toArray(), selector
+      return cheerio elem
+
+  return cheerio
+
+
+fs = require "fs"
+basic = fs.readFileSync '../tests/initial/basic.html', 'utf8'
+$ = cheerio.load basic
+dom = parser.parse basic
+# console.log $('#footer', 'body') # works
+
+# console.log $('#footer', dom)
+
+# console.log cheerio dom
+# console.log cheerio "<h2>hihihi</h2"
+# console.log cheerio('.header', 'body', basic)
+
+# console.log cheerio("body #footer", basic).get 0
+
+# cheerio.fn.addClass = () ->
+#   console.log 'hi'
+#
+# cheerio.fn.extend
+#   blah : () ->
+#     console.log 'balh'
+
+
+module.exports = cheerio
+


--runtime isn't a valid flag

--runtime isn't a valid flag

--- src/command.coffee
+++ src/command.coffee
@@ -112,7 +112,7 @@
       "--msvs_version=#{vsVersion}"

   getNpmBuildFlags: ->
-    ["--runtime=electron", "--target=#{@electronVersion}", "--dist-url=#{config.getElectronUrl()}", "--arch=#{config.getElectronArch()}"]
+    ["--target=#{@electronVersion}", "--dist-url=#{config.getElectronUrl()}", "--arch=#{config.getElectronArch()}"]

   updateWindowsEnv: (env) ->
     env.USERPROFILE = env.HOME


Got rid of merge garbage...

Got rid of merge garbage...

--- src/command.coffee
+++ src/command.coffee
@@ -30,10 +30,7 @@
           total: parseInt getbot.size, 10

       getbot.on 'data', (data, rate) ->
-<<<<<<< HEAD
         rate = "#{makeReadable rate}/s"
-=======
->>>>>>> 8063a78fcb6d95529dc0da2ab9850f386d435e05
         bar.tick(data.length, {'rate': rate})
       return
     else


#2490. A bit more of the style.

#2490. A bit more of the style.

--- src/command.coffee
+++ src/command.coffee
@@ -119,27 +119,31 @@
   try
     t = task = {file, input, options}
     CoffeeScript.emit 'compile', task
-    if      o.tokens      then printTokens CoffeeScript.tokens t.input, t.options
-    else if o.nodes       then printLine CoffeeScript.nodes(t.input, t.options).toString().trim()
-    else if o.run         then CoffeeScript.run t.input, t.options
-    else if o.join and t.file isnt o.join
-      t.input = helpers.invertLiterate t.input if helpers.isLiterate file
-      sourceCode[sources.indexOf(t.file)] = t.input
-      compileJoin()
-    else
-      compiled = CoffeeScript.compile t.input, t.options
-      t.output = compiled
-      if o.map
-        t.output = compiled.js
-        t.sourceMap = compiled.v3SourceMap
-
-      CoffeeScript.emit 'success', task
-      if o.print
-        printLine t.output.trim()
-      else if o.compile || o.map
-        writeJs base, t.file, t.output, options.jsPath, t.sourceMap
-      else if o.lint
-        lint t.file, t.output
+    if
+      o.tokens
+        printTokens CoffeeScript.tokens t.input, t.options
+      o.nodes
+        printLine CoffeeScript.nodes(t.input, t.options).toString().trim()
+      o.run
+        CoffeeScript.run t.input, t.options
+      o.join and t.file isnt o.join
+        t.input = helpers.invertLiterate t.input if helpers.isLiterate file
+        sourceCode[sources.indexOf(t.file)] = t.input
+        compileJoin()
+      else
+        compiled = CoffeeScript.compile t.input, t.options
+        t.output = compiled
+        if o.map
+          t.output = compiled.js
+          t.sourceMap = compiled.v3SourceMap
+        CoffeeScript.emit 'success', task
+        if
+          o.print
+            printLine t.output.trim()
+          o.compile or o.map
+            writeJs base, t.file, t.output, options.jsPath, t.sourceMap
+          o.lint
+            lint t.file, t.output
   catch err
     CoffeeScript.emit 'failure', err, task
     return if CoffeeScript.listeners('failure').length


fix up running and current contexts

fix up running and current contexts

--- src/context.coffee
+++ src/context.coffee
@@ -7,6 +7,8 @@

   ignore = new Object

+  running_context_binding = null
+
   # statement result handlers. return truthy if handled.
   ignored = (object) -> object == ignore

@@ -55,7 +57,7 @@
     bind_fn = (name, op) ->
       bound = (args...) ->
         # if the function returned a value, unwrap it. otherwise, ignore it
-        op.fn.apply(run_context.root_context.current_context, args)?._lead_context_fn_value ? ignore
+        op.fn.apply(run_context.active_context(), args)?._lead_context_fn_value ? ignore
       bound._lead_context_fn = op
       bound._lead_context_name = name
       bound
@@ -108,6 +110,11 @@
     run_context = _.extend {}, extra_contexts...,
       current_options: {}
       output: output $el
+      active_context: ->
+        console.warn 'no active running context. did you call an async function without keeping the context?' unless running_context_binding?
+        run_context.current_context
+
+      running_context: -> running_context_binding

       options: -> @current_options

@@ -115,9 +122,31 @@
         previous_context = run_context.current_context
         run_context.current_context = context
         try
-          fn.apply(context)
+          fn.apply context
         finally
           run_context.current_context = previous_context
+
+      in_running_context: (fn) ->
+        throw new Error 'no active running context. did you call an async function without keeping the context?' unless running_context_binding?
+        run_context.in_context running_context_binding, fn
+
+      # returns a function that calls its argument in the current context
+      capture_context: ->
+        context = run_context.current_context
+        running_context = running_context_binding
+        (fn) ->
+          previous_running_context_binding = running_context_binding
+          running_context_binding = running_context
+          try
+            run_context.in_context context, -> fn.apply run_context.current_context
+          finally
+            running_context_binding = previous_running_context_binding
+
+      keeping_context: (fn) ->
+        restoring_context = run_context.capture_context()
+        ->
+          args = arguments
+          restoring_context -> fn.apply @, args

       render: (o) ->
         @nested 'renderable', handle_renderable, o
@@ -136,8 +165,7 @@

         nested_context = _.extend {}, run_context,
           output: output $item
-        nested_context.current_context = nested_context
-        nested_context.fns = bind_context_fns nested_context, run_context.imported_context_fns
+        run_context.current_context = nested_context
         fn.apply nested_context, args

       handle_exception: (e, compiled) ->
@@ -183,7 +211,6 @@
       else
         run_context[name] = mod
     run_context.current_context = run_context
-    run_context.root_context = run_context

     run_context

@@ -207,6 +234,8 @@

   run_in_context = (run_context, string) ->
     try
+      previous_running_context_binding = running_context_binding
+      running_context_binding = run_context
       context_scope = scope run_context
       `with (context_scope) {`
       result = (-> eval string).call run_context
@@ -214,5 +243,7 @@
       run_context.display_object result
     catch e
       run_context.handle_exception e, string
+    finally
+      running_context_binding = previous_running_context_binding

   {create_base_context, create_context, create_run_context, create_standalone_context, run_coffeescript_in_context, run_in_context, scope, collect_extension_points}


hitting /products when fetching product feeds

--- app/assets/javascripts/mobile/fetch_products.js.coffee
+++ app/assets/javascripts/mobile/fetch_products.js.coffee
@@ -46,7 +46,7 @@
 fetch_more_products = ->
     increment_pagination_page()

-    url_root = if gon.page is 'products_index' then '/' else "/#{gon.store_slug}/"
+    url_root = if gon.page is 'products_index' then '/products' else "/#{gon.store_slug}/"
     url = "#{url_root}?page=#{gon.pagination_page}"

     params =


prevent repeat of climbs in list

prevent repeat of climbs in list

--- app/assets/javascripts/views/climb_list_view.js.coffee
+++ app/assets/javascripts/views/climb_list_view.js.coffee
@@ -2,7 +2,7 @@
   template: JST['templates/climb_list']

   initialize: =>
-    @listenTo @collection, 'add', @addOne
+    @listenTo @collection, 'add', @render
     @listenTo @collection, 'remove', @render

   render: =>


Add "extension" keyword to gramma (#1194)

--- grammars/dart.cson
+++ grammars/dart.cson
@@ -206,7 +206,7 @@
         'name': 'keyword.control.new.dart'
       }
       {
-        'match': '(?<!\\$)\\b(abstract|class|enum|extends|external|factory|implements|get|mixin|native|operator|set|typedef|with|covariant)\\b(?!\\$)'
+        'match': '(?<!\\$)\\b(abstract|class|enum|extends|extension|external|factory|implements|get|mixin|native|operator|set|typedef|with|covariant)\\b(?!\\$)'
         'name': 'keyword.declaration.dart'
       }
       {


Minor cleanup

Minor cleanup

--- grammars/rust.cson
+++ grammars/rust.cson
@@ -327,6 +327,14 @@
     ]
   }

+  ## Other
+
+  'boolean_literal': {
+    'comment': 'Boolean constant'
+    'name': 'constant.language.boolean.rust'
+    'match': '\\b(true|false)\\b'
+  }
+
   # Keywords

   ## Types
@@ -539,6 +547,7 @@
   { 'include': '#raw_string_literal' }
   { 'include': '#character_literal' }
   { 'include': '#number_literal' }
+  { 'include': '#boolean_literal' }

   # Language
   {
@@ -547,11 +556,6 @@
     'match': '\\bstatic\\b'
   }
   {
-    'comment': 'Boolean constant'
-    'name': 'constant.language.boolean.rust'
-    'match': '\\b(true|false)\\b'
-  }
-  {
     'comment': 'Control keyword'
     'name': 'keyword.control.rust'
     'match': '\\b(break|continue|else|if|in|for|loop|match|return|while)\\b'
@@ -560,11 +564,6 @@
     'comment': 'Keyword'
     'name': 'keyword.other.rust'
     'match': '\\b(crate|extern|mod|let|proc|ref|use|super|as|move)\\b'
-  }
-  {
-    'comment': 'Unsafe code keyword'
-    'name': 'keyword.other.unsafe.rust'
-    'match': '\\bunsafe\\b'
   }
   { 'include': '#unsafe' }
   { 'include': '#sigils' }
@@ -575,6 +574,7 @@
   { 'include': '#ref_lifetime' }
   { 'include': '#const' }
   { 'include': '#pub' }
+
   # Operators
   {
     'comment': 'Miscellaneous operator'
@@ -724,7 +724,6 @@
           { 'include': '#ref_lifetime' }
           { 'include': '#where' }
           {
-            'name': ''
             'match': '\\b(for)\\s+([\\p{Alpha}_][\\w]*)'
             'captures': {
               '1': { 'name': 'storage.type.rust' }


Update wallet recovery tests

Update wallet recovery tests

--- app/spec/tasks/wallet_layout_recovery_task_spec.coffee
+++ app/spec/tasks/wallet_layout_recovery_task_spec.coffee
@@ -28,7 +28,7 @@

-  xdescribe " - zero account", ->
+  describe " - zero account", ->
     beforeAll (done) ->
       spyOn(task, '_restoreChronocoinLayout')
       dongle = ledger.specs.fixtures.dongles.dongle2
@@ -72,7 +72,7 @@
       init dongle.pin, dongle.masterSeed, dongle.pairingKeyHex, done

     it "should have 2 accounts", ->
-      l 'ledger.wallet.Wallet.instance', ledger.wallet.Wallet.instance.getAccount(1)
+      expect(ledger.wallet.Wallet.instance.getAccountsCount()).toBe(2)
       expect(typeof ledger.wallet.Wallet.instance.getAccount(0)).toBe('object')
       expect(typeof ledger.wallet.Wallet.instance.getAccount(1)).toBe('object')
       expect(ledger.wallet.Wallet.instance.getAccount(2)).toBeUndefined()


Add link to global header

Add link to global header

--- app/assets/javascripts/components/GlobalHeader.js.cjsx
+++ app/assets/javascripts/components/GlobalHeader.js.cjsx
@@ -5,7 +5,9 @@
       imageTitle: React.PropTypes.string.isRequired
     render: ->

-
+
+
+

   globalHeader = document.querySelector('.GlobalHeader')


Add javascript for search button

Add javascript for search button

--- app/assets/javascripts/neighborly/neighborly.js.coffee
+++ app/assets/javascripts/neighborly/neighborly.js.coffee
@@ -23,6 +23,13 @@
     init: ->
       $(document).foundation('reveal', {animation: 'fadeIn', animationSpeed: 100})
       $(document).foundation()
+      $('.search-button').click ->
+        if $('.discover-form-input').val() != ''
+          $('form.discover-form').submit()
+        else
+          $('.discover-form-input').toggleClass('show').focus()
+
+        return false

     finish: ->


OX-402 fixed assertion

OX-402 fixed assertion

--- app/assets/javascripts/oxalis/model/statelogger.coffee
+++ app/assets/javascripts/oxalis/model/statelogger.coffee
@@ -96,9 +96,10 @@
   createNode : (node, treeId) ->
     $.assert(node.neighbors.length <= 1,
       "New node can't have more than one neighbor", node.neighbors.length)
-    $.assert(node.treeId == node.neighbors[0].treeId,
-      "Neighbot has different treeId",
-      {treeId1 : node.treeId, treeId2 : node.neighbors[0].treeId})
+    if node.neighbors[0]
+      $.assert(node.treeId == node.neighbors[0].treeId,
+        "Neighbot has different treeId",
+        {treeId1 : node.treeId, treeId2 : node.neighbors[0].treeId})

     @pushDiff("createNode", @nodeObject(node, treeId))
     if node.neighbors.length == 1


minor entropy calc bugfix

minor entropy calc bugfix

--- scoring.coffee
+++ scoring.coffee
@@ -40,7 +40,7 @@
   # walk backwards and decode the best sequence
   match_sequence = []
   k = password.length - 1
-  while k > 0
+  while k >= 0
     match = backpointers[k]
     if match
       match_sequence.push match
@@ -224,7 +224,8 @@
     S = (chr for chr in match.token.split('') when chr == subbed).length   # number of subbed characters.
     U = (chr for chr in match.token.split('') when chr == unsubbed).length # number of unsubbed characters.
     possibilities += nCk(U + S, i) for i in [0..Math.min(U, S)]
-  lg possibilities
+  # corner: return 1 bit for single-letter subs, like 4pple -> apple, instead of 0.
+  lg(possibilities) or 1

 # utilities --------------------------------------------------------------------


add group lookups and validation to config processing

--- src/decking.coffee
+++ src/decking.coffee
@@ -42,6 +42,19 @@

         details.dependencies[i] = name
         details.aliases[i] = alias
+
+    if not Object.keys(config.clusters || {}).length
+      throw new Error "No clusters defined!"
+
+    for name, details of config.clusters
+      # explicit group; check it exists
+      if details.group and not config.groups[details.group]
+        err = "Cluster #{name} references invalid group #{details.group}"
+        throw new Error err
+
+      # no group, but does the key match one?
+      if not details.group and config.groups[name]
+        details.group = name

     return config

@@ -387,8 +400,10 @@
     group = config.groups[groupName]
   else
     if cluster.containers
+      # longhand, explicit container list
       containers = cluster.containers
     else
+      # shorthand, just an array of container names
       containers = cluster

   containerDetails = {}


fix glyph legend rendering issue due to missing update _render method signature

--- bokehjs/src/coffee/renderer/glyph/marker/marker.coffee
+++ bokehjs/src/coffee/renderer/glyph/marker/marker.coffee
@@ -39,7 +39,7 @@
       size = { }
       size[reference_point] = Math.min(Math.abs(x1-x0), Math.abs(y1-y0))*0.4

-      @_render(ctx, indices, @props, sx, sy, size)
+      @_render(ctx, indices, sx, sy, size)

     _set_data: () ->
       @max_size = _.max(@size)


:lipstick:

:lipstick:

--- src/install.coffee
+++ src/install.coffee
@@ -115,8 +115,7 @@
     @updateWindowsEnv(env) if config.isWin32()
     @addNodeBinToEnv(env)
     installOptions = {env}
-
-    installOptions['streaming'] = true if @verbose
+    installOptions.streaming = true if @verbose

     installGlobally = options.installGlobally ? true
     if installGlobally


Build module cache after install

Build module cache after install

--- src/install.coffee
+++ src/install.coffee
@@ -126,6 +126,9 @@
             destination = path.join(@atomPackagesDirectory, child)
             do (source, destination) ->
               commands.push (callback) -> fs.cp(source, destination, callback)
+
+          commands.push (callback) => @buildModuleCache(pack.name, callback)
+
           async.waterfall commands, (error) =>
             if error?
               @logFailure()
@@ -387,6 +390,14 @@
     else
       config.getResourcePath (@resourcePath) => callback(@resourcePath)

+  buildModuleCache: (packageName, callback) ->
+    packageDirectory = path.join(@atomPackagesDirectory, packageName)
+
+    config.getResourcePath (resourcePath) ->
+      ModuleCache = require(path.join(resourcePath, 'src', 'module-cache'))
+      ModuleCache.create(packageDirectory)
+      callback()
+
   isBundledPackage: (packageName, callback) ->
     @getResourcePath (resourcePath) ->
       try


Map proxy config to env vars for spawned processes

--- src/install.coffee
+++ src/install.coffee
@@ -63,25 +63,24 @@

     fs.makeTreeSync(@atomDirectory)

-    config.loadNpm (error, npm) =>
-      # node-gyp doesn't currently have an option for this so just set the
-      # environment variable to bypass strict SSL
-      # https://github.com/TooTallNate/node-gyp/issues/448
-      useStrictSsl = npm.config.get('strict-ssl') ? true
-      env.NODE_TLS_REJECT_UNAUTHORIZED = 0 unless useStrictSsl
-
-      # Pass through configured proxy to node-gyp
-      proxy = npm.config.get('https-proxy') or npm.config.get('proxy')
-      installNodeArgs.push("--proxy=#{proxy}") if proxy
-
-      opts = {env, cwd: @atomDirectory}
-      opts.streaming = true if @verbose
-
-      @fork @atomNodeGypPath, installNodeArgs, opts, (code, stderr='', stdout='') ->
-        if code is 0
-          callback()
-        else
-          callback("#{stdout}\n#{stderr}")
+    # node-gyp doesn't currently have an option for this so just set the
+    # environment variable to bypass strict SSL
+    # https://github.com/TooTallNate/node-gyp/issues/448
+    useStrictSsl = @npm.config.get('strict-ssl') ? true
+    env.NODE_TLS_REJECT_UNAUTHORIZED = 0 unless useStrictSsl
+
+    # Pass through configured proxy to node-gyp
+    proxy = @npm.config.get('https-proxy') or @npm.config.get('proxy')
+    installNodeArgs.push("--proxy=#{proxy}") if proxy
+
+    opts = {env, cwd: @atomDirectory}
+    opts.streaming = true if @verbose
+
+    @fork @atomNodeGypPath, installNodeArgs, opts, (code, stderr='', stdout='') ->
+      if code is 0
+        callback()
+      else
+        callback("#{stdout}\n#{stderr}")

   updateWindowsEnv: (env) ->
     env.USERPROFILE = env.HOME
@@ -100,6 +99,17 @@
       env[pathKey] = "#{nodeBinFolder}#{path.delimiter}#{env[pathKey]}"
     else
       env[pathKey]= nodeBinFolder
+
+  addProxyToEnv: (env) ->
+    httpProxy = @npm.config.get('proxy')
+    if httpProxy
+      env.HTTP_PROXY ?= httpProxy
+      env.http_proxy ?= httpProxy
+
+    httpsProxy = @npm.config.get('https-proxy')
+    if httpsProxy
+      env.HTTPS_PROXY ?= httpsProxy
+      env.https_proxy ?= httpsProxy

   installModule: (options, pack, modulePath, callback) ->
     installArgs = ['--globalconfig', config.getGlobalConfigPath(), '--userconfig', config.getUserConfigPath(), 'install']
@@ -116,6 +126,7 @@
     env = _.extend({}, process.env, HOME: @atomNodeDirectory)
     @updateWindowsEnv(env) if config.isWin32()
     @addNodeBinToEnv(env)
+    @addProxyToEnv(env)
     installOptions = {env}
     installOptions.streaming = true if @verbose

@@ -178,6 +189,7 @@
     env = _.extend({}, process.env, HOME: @atomNodeDirectory)
     @updateWindowsEnv(env) if config.isWin32()
     @addNodeBinToEnv(env)
+    @addProxyToEnv(env)
     installOptions = {env}
     installOptions.cwd = options.cwd if options.cwd
     installOptions.streaming = true if @verbose
@@ -391,6 +403,7 @@
       env = _.extend({}, process.env, HOME: @atomNodeDirectory)
       @updateWindowsEnv(env) if config.isWin32()
       @addNodeBinToEnv(env)
+      @addProxyToEnv(env)
       buildOptions = {env}
       buildOptions.streaming = true if @verbose

@@ -511,6 +524,7 @@
       packageNames.push('.') if packageNames.length is 0

     commands = []
+    commands.push (callback) => config.loadNpm (error, @npm) => callback()
     commands.push (callback) => @loadInstalledAtomVersion(callback)
     packageNames.forEach (packageName) ->
       commands.push (callback) -> installPackage(packageName, callback)


fix parse for riffs

fix parse for riffs

--- src/marktab.coffee
+++ src/marktab.coffee
@@ -111,6 +111,8 @@
 				part = part.match(riffPattern)[0]
 				i += part.length
 				tabMapPart = this.parseRiff(part)
+				tabMap = this.addTabMaps(tabMap, tabMapPart)
+				continue
 			else if part.search(setVariablePattern) is 0
 				# set variable
 				part = part.match(setVariablePattern)[0]


updated comments

updated comments

--- src/message.coffee
+++ src/message.coffee
@@ -131,7 +131,7 @@

 	###
-	 Query would be something like ?name=craig&last=condon
+	 data that has been cleaned up after validation
 	###

 	sanitized: (value) -> @_param 'sanitized', arguments


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -18,17 +18,14 @@

 someOtherObject.include Metered

-player.meter
-  name: 'health'
+player.meter 'health'
 # => Sets up a health meter that will be drawn during the player overlay event

-enemy.meter
-  name: 'health'
+enemy.meter 'health'
 # => Sets up a health meter that will be drawn during the enemy overlay event.
 # Since maxHealth wasn't provided, it is set to the value of I.health (500)

-someOtherObject.meter
-  name: 'turbo'
+someOtherObject.meter 'turbo'
 # => Sets up a turbo meter that will be drawn during the someOtherObject overlay event.
 # Since neither turbo maxTurbo were provided, they are both set to 100.

@@ -44,10 +41,15 @@

 Metered = (I={}, self) ->
   Object.reverseMerge I,
-    meters: []
+    meters: {}
+
+  setMeter = (name, value) ->
+    for meterName, meterData of I.meters
+      if meterName is name
+        meterData.show = value

   self.bind 'overlay', (canvas) ->
-    I.meters.each (meterData) ->
+    for name, meterData of I.meters
       {
         borderColor,
         borderWidth,
@@ -55,13 +57,15 @@
         font,
         height,
         nameColor,
-        name,
         position: {x, y}
         radius,
+        show,
         showName,
         text,
         width
       } = meterData
+
+      return unless show

       ratio = I[name] / I["max#{name.capitalize()}"]

@@ -98,12 +102,11 @@

   player.include Metered

-  player.meter
+  player.meter 'health',
     borderColor: 'brown'
     color: 'pink'
     font: '30px Comic Sans'
     height: 20
-    name: 'health'
     position:
       x: 5
       y: 5
@@ -117,6 +120,7 @@

   @name meter
   @methodOf Metered#
+  @param {String} name The name of the property to meter
   @param {Object} options The meter configuration options
   @param {String} borderColor Color of the meter's border
   @param {Number} borderWidth Width of the meter's border
@@ -130,7 +134,7 @@
   @param {String} text A String to display over the meter. Overrides default name attribute
   @param {Number} width How wide the meter is
   ###
-  meter: (options={}) ->
+  meter: (name, options={}) ->
     Object.reverseMerge options,
       borderColor: 'white'
       borderWidth: 1.5
@@ -142,12 +146,11 @@
         x: 0
         y: 0
       radius: 2
+      show: true
       showName: false
       text: null
       width: 100
-
-    {name} = options
-
+
     if not I[name]
       I[name] = 100

@@ -157,4 +160,11 @@
       else
         I["max#{name.capitalize()}"] = 100

-    I.meters.push options+    I.meters[name] = options
+
+  showMeter: (name) ->
+    setMeter(name, true)
+
+  hideMeter: (name) ->
+    setMeter(name, false)
+


better curve for undercurl

better curve for undercurl

--- src/nvim/ui.coffee
+++ src/nvim/ui.coffee
@@ -217,7 +217,7 @@
       @ctx.stroke()

     if @attrs.undercurl
-      offs = [1.5, 0.5, 0.5, 0.5, 1.5, 2.5, 2.5, 2.5]
+      offs = [1.5, 0.8, 0.5, 0.8, 1.5, 2.2, 2.5, 2.2]
       @ctx.strokeStyle = @get_cur_fg_color()
       @ctx.lineWidth = @devicePixelRatio
       @ctx.beginPath()


fix tar/et to target

fix tar/et to target

--- src/persist.coffee
+++ src/persist.coffee
@@ -31,7 +31,7 @@

   push: (target) ->
     return if target.id? and target.id of @index
-    @onCreate tar/et
+    @onCreate target

   listen: (target) ->
     target.on 'save', (e) => @onSave target


Use fat arrow

Use fat arrow

--- src/publish.coffee
+++ src/publish.coffee
@@ -264,7 +264,7 @@
           @logFailure()
           return callback(error)

-        config.getSetting 'git', (gitCommand) ->
+        config.getSetting 'git', (gitCommand) =>
           gitCommand ?= 'git'
           @spawn gitCommand, ['add', 'package.json'], (code, stderr='', stdout='') =>
             unless code is 0


Also retry on ECONNRESET errors

Also retry on ECONNRESET errors

--- src/request.coffee
+++ src/request.coffee
@@ -28,7 +28,7 @@
       retryCount = requestOptions.retries ? 0
       tryRequest = ->
         request.get requestOptions, (error, response, body) ->
-          if error?.code is 'ETIMEDOUT' and retryCount > 0
+          if retryCount > 0 and error?.code in ['ETIMEDOUT', 'ECONNRESET']
             retryCount--
             tryRequest()
           else


only display modal on non-404 errors

only display modal on non-404 errors

--- src/api.coffee
+++ src/api.coffee
@@ -46,7 +46,7 @@
         successAction(results, args...) # Include listenAction for faking
       rejected = (jqXhr, statusMessage, err) ->
         statusCode = jqXhr.status
-        ErrorsActions.setServerError(statusCode, jqXhr.responseText, {url, opts})
+
         if statusMessage is 'parsererror' and statusCode is 200 and IS_LOCAL
           if httpMethod is 'PUT' or httpMethod is 'PATCH'
             # HACK for PUT
@@ -62,6 +62,7 @@
             msg = JSON.parse(jqXhr.responseText)
           catch e
             msg = jqXhr.responseText
+          ErrorsActions.setServerError(statusCode, jqXhr.responseText, {url, opts})
           Actions.FAILED(statusCode, msg, args...)

       $.ajax(url, opts)


Bugfix: don't clear empty search results.

Explanation: the name of the typeahead event typeahead:opened is a
bit misleading. It is called not only when the autosuggestions are shown but also
when the input field regains focus after the user has for example
responded to a native browser ui dialog like a geolocating permission dialog.
https://github.com/twitter/typeahead.js/issues/130#issuecomment-15687492

The event was used to clear overlapping search results from under
an autosuggest menu. However, the event was also fired when showing
a unit details view and the search input regained focus. Here the
resulting search_results collection reset caused the region to be
reset.

Solution: made the clearSearch command more robust so it
won't fire events when the search results are already empty.

Closes #108.

--- src/app.coffee
+++ src/app.coffee
@@ -132,7 +132,8 @@
                     )
                     @services.set []
         clearSearch: ->
-            @search_results.reset []
+            unless @search_results.isEmpty()
+                @search_results.reset []

     app = new Backbone.Marionette.Application()


stop on error

stop on error

--- src/app.coffee
+++ src/app.coffee
@@ -55,18 +55,20 @@

             Agent.initFromDatabase callback

-    ], ->
+    ], (err) ->

-        async.eachSeries pluginList, (plugin, callback) ->
-
-            if plugin.onBootstrap
-                plugin.onBootstrap callback
-            else
-                callback()
+        if not err

-        , (err) ->
-
-            Database.db.close()
+            async.eachSeries pluginList, (plugin, callback) ->
+
+                if plugin.onBootstrap
+                    plugin.onBootstrap callback
+                else
+                    callback()
+
+            , (err) ->
+
+                Database.db.close()

 #######################
 # main


avoid exposure of raw api resource

avoid exposure of raw api resource

--- app/assets/javascripts/app.coffee
+++ app/assets/javascripts/app.coffee
@@ -499,17 +499,33 @@
 # ----------------------------------------------------------------------------------------------------------------------
 # Service: apiClient
 # ----------------------------------------------------------------------------------------------------------------------
-markever.factory 'apiClient', ['$resource', ($resource) ->
-  Notes = $resource('/api/v1/notes/:id', {id: '@id'}, {
+markever.factory 'apiClient', ['$resource', ($resource) -> new class APIClient
+  note_resource: $resource('/api/v1/notes/:id', {id: '@id'}, {
     all: {method : 'GET', params : {id: ''}},
     note: {method : 'GET', params: {}},
     newest: {method : 'GET', params : {id: 'newest'}},
     save: {method : 'POST', params: {id: ''}},
   })

-  return {
-    notes : Notes
-  }
+  # return promise with all notes
+  get_all_notes: () =>
+    return @note_resource.all().$promise.then (data) =>
+      return data['notes']
+
+  # return promise with the note
+  get_note: (guid) =>
+    return @note_resource.note({id: guid}).$promise.then (data) =>
+      return data.note
+
+  # return promise with saved note that is returned from remote
+  save_note: (guid, title, enml) =>
+    _post_data = {
+      guid: guid
+      title: title
+      enml: enml
+    }
+    return @note_resource.save(_post_data).$promise.then (data) =>
+      return data.note
 ]

 # ----------------------------------------------------------------------------------------------------------------------
@@ -932,13 +948,13 @@
         return note
       else
         console.log('Local note fetch missed, fetch from remote: ' + guid)
-        return apiClient.notes.note({id: guid}).$promise.then (data) =>
+        return apiClient.get_note(guid).then (note) =>
           _note =
             guid: guid
-            title: data.note.title
-            md: data.note.md
+            title: note.title
+            md: note.md
             status: @NOTE_STATUS.SYNCED_ALL
-            resources: data.note.resources
+            resources: note.resources
           return @update_note(_note)

   # ------------------------------------------------------------
@@ -947,8 +963,8 @@
   # ------------------------------------------------------------
   load_remote_notes: =>
     # TODO handle failure
-    return apiClient.notes.all().$promise.then (data) =>
-      @_merge_remote_notes(data['notes']).then(
+    return apiClient.get_all_notes().then (notes) =>
+      @_merge_remote_notes(notes).then(
         () =>
           console.log('finish merging remote notes')
           return @get_all_notes()
@@ -1080,21 +1096,18 @@
   sync_up_note: (is_new_note, guid, jq_div, md) =>
     console.log('enter sync_up_note() for note ' + guid)
     return enmlRenderer.get_enml_and_title_promise(jq_div, md).then (enml_and_title) =>
-      _post_data = {
-        title: enml_and_title.title
-        enml: enml_and_title.enml
-      }
+      title = enml_and_title.title
+      enml = enml_and_title.enml
+      request_guid = guid
       if is_new_note
-        _post_data['guid'] = ''
-      else
-        _post_data['guid'] = guid
-      return apiClient.notes.save(_post_data).$promise.then(
-        (data) =>
+        request_guid = ''
+      return apiClient.save_note(request_guid, title, enml).then(
+        (note) =>
           # change note status to SYNCED_ALL, using old guid
           p = @update_note({guid: guid, status: @NOTE_STATUS.SYNCED_ALL}).then () =>
             # then update guid if is new note (when saving new note, tmp guid will be updated to real one)
             if is_new_note
-              new_guid = data.note.guid
+              new_guid = note.guid
               # @update_note_guid will return Promise containing the updated note
               return @update_note_guid(guid, new_guid)
             else


Fix bug in Trivia

Fix bug in Trivia

...where the first item would not show up until 4000ms after page load.

--- app/assets/javascripts/app.coffee
+++ app/assets/javascripts/app.coffee
@@ -12,13 +12,13 @@
   pointer = if pointer < length-1 then pointer + 1 else 0

   trivia.data('pointer', pointer)
-  trivia.css('display', 'inline-block')

 triviaInit = ->
   trivia = $('ul.trivia')
   items = trivia.find('li')

   items.hide()
+  items.eq(0).show()
   trivia.css('display', 'inline-block')

   triviaCycle()


change the mechanism by which global is found

--- app/js/jasmine-fixture.coffee
+++ app/js/jasmine-fixture.coffee
@@ -1,5 +1,5 @@
 (($) ->
-  root = @
+  root = `(1, eval)('this')`

   originalJasmineFixture = root.jasmineFixture
   originalJasmineDotFixture = root.jasmine?.fixture
@@ -289,7 +289,7 @@
   regId = /(?:^|\b)#([\w-!]+)/i
   regTagNotContent = /((([#\.]?[\w-]+)?(\[([\w!]+(="([^"]|\\")+")? {0,})+\])?)+)/i
   ###
-   See lookahead syntax (?!) at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
+   See lookahead syntax (?!) at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
   ###
   regClasses = /(\.[\w-]+)(?!["\w])/g
   regClass = /\.([\w-]+)/i


AdminModal: Remove old comment out code.

--- client/admin/lib/views/groupgeneralsettingsview.coffee
+++ client/admin/lib/views/groupgeneralsettingsview.coffee
@@ -145,156 +145,3 @@
       cssClass     : 'solid medium red'
       description  : 'Note: Don\'t delete your team if you just want to change your team\'s name or URL. You also might want to export your data before deleting your team.'
       title        : 'DELETE TEAM'
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-  # createFormFields: (formOptions) ->
-
-  #   group              = @getData()
-  #   formOptions.fields = {}
-
-  #   if group.slug isnt "koding"
-  #     formOptions.fields.Logo =
-  #       label                 : "Logo"
-  #       itemClass             : GroupLogoSettings
-
-  #   formOptions.fields.Title  =
-  #     label                   : "Group Name"
-  #     name                    : "title"
-  #     defaultValue            : Encoder.htmlDecode group.title ? ""
-  #     placeholder             : 'Please enter a title here'
-
-  #   formOptions.fields.Description =
-  #     label                   : "Description"
-  #     type                    : "textarea"
-  #     name                    : "body"
-  #     defaultValue            : Encoder.htmlDecode group.body ? ""
-  #     placeholder             : 'Please enter a description here.'
-  #     autogrow                : yes
-
-  #   formOptions.fields.Stack =
-  #     itemClass               : KDSelectBox
-  #     label                   : "Stack"
-  #     type                    : "select"
-  #     name                    : "stackTemplates"
-  #     selectOptions           : [
-  #       { title: "Loading stack templates...", disabled: yes }
-  #     ]
-  #     nextElement             :
-  #       showTemplate          :
-  #         itemClass           : KDButtonView
-  #         title               : "Show Template"
-  #         cssClass            : "solid green mini hidden"
-  #         callback            : =>
-
-  #           { Stack } = @settingsForm.inputs
-  #           data = @_templates["_#{Stack.getValue()}"]
-  #           return new KDNotificationView title: "No data found!"  unless data
-
-  #           { title, description, rules, domains, machines, extras } = data
-  #           data = { title, description, rules, domains, machines, extras }
-
-  #           try
-  #             parsed = JSON.stringify data, null, 2
-  #           catch e
-  #             kd.warn e; kd.log data
-  #             return new KDNotificationView
-  #               title: "An error occurred"
-
-  #           new KDModalView
-  #             content : "<pre>#{parsed}</pre>"
-
-
-  #   formOptions.fields["Visibility settings"] =
-  #     itemClass               : KDSelectBox
-  #     label                   : "Visibility"
-  #     type                    : "select"
-  #     name                    : "visibility"
-  #     defaultValue            : group.visibility ? "visible"
-  #     selectOptions           : [
-  #       { title : "Visible"   , value : "visible" }
-  #       { title : "Hidden"    , value : "hidden"  }
-  #     ]
-
-  # createFormButtons: (formOptions) ->
-  #   formOptions.buttons   =
-  #     Save                :
-  #       style             : "solid medium green"
-  #       type              : "submit"
-  #       loader            : yes
-
-  # saveSettings: (formData) ->
-  #   saveButton = @settingsForm.buttons.Save
-  #   group      = @getData()
-
-  #   if formData.stackTemplates is "none"
-  #     formData.stackTemplates = [ ]
-  #   else if not formData.stackTemplates?
-  #     delete formData.stackTemplates
-  #   else
-  #     formData.stackTemplates = [ formData.stackTemplates ]
-
-  #   group.modify formData, (err)->
-  #     saveButton.hideLoader()
-  #     return showError err if err
-
-  #     new KDNotificationView
-  #       title    : "Group settings saved"
-  #       type     : "mini"
-  #       cssClass : "success"
-  #       duration : 4000
-
-  # viewAppended:->
-  #   super
-
-  #   { stackTemplates } = @getData()
-  #   { Stack } = @settingsForm.inputs
-
-  #   remote.api.JStackTemplate.some {}, (err, templates)=>
-
-  #     Stack.removeSelectOptions()
-
-  #     if err
-
-  #       Stack.setSelectOptions "Failed to fetch templates": []
-  #       kd.warn err
-
-  #     else if templates.length is 0
-
-  #       Stack.setSelectOptions "No template available": []
-
-  #     else
-
-  #       @_templates   = {}
-  #       selectOptions = []
-
-  #       for t in templates
-  #         selectOptions.push { title:t.title, value:t._id }
-  #         @_templates["_#{t._id}"] = t
-
-  #       selectOptions.push title: "Do not create anything.", value: "none"
-
-  #       Stack.setSelectOptions "Select stack template..." : selectOptions
-
-  #       showButton = @settingsForm.inputs["Show Template"]
-  #       showButton.setCss margin: "7px"
-  #       showButton.show()
-
-  #       if stackTemplates?.length > 0
-  #         Stack.setDefaultValue stackTemplates.first
-  #       else
-  #         Stack.setDefaultValue "none"


StacksCustomViews: Helpers for jsonToYaml, yamlToJson conversion over js-yaml package

--- client/admin/lib/views/stacks/stackscustomviews.coffee
+++ client/admin/lib/views/stacks/stackscustomviews.coffee
@@ -4,6 +4,7 @@

 _                               = require 'lodash'
 hljs                            = require 'highlight.js'
+jsyaml                          = require 'js-yaml'
 Encoder                         = require 'htmlencode'
 dateFormat                      = require 'dateformat'

@@ -331,6 +332,41 @@
     return new kd.ModalView options

+  jsonToYaml = (content) ->
+
+    contentType     = 'json'
+
+    try
+      contentObject = JSON.parse content
+
+      content       = jsyaml.safeDump contentObject
+      contentType   = 'yaml'
+
+    catch err
+      console.error '[JsonToYaml]', err
+
+    console.log '[JsonToYaml]', { content, contentType, err }
+
+    return { content, contentType, err }
+
+
+  yamlToJson = (content) ->
+
+    contentType     = 'yaml'
+
+    try
+      contentObject = jsyaml.safeLoad content
+
+      content       = JSON.stringify contentObject
+      contentType   = 'json'
+    catch err
+      console.error '[YamlToJson]', err
+
+    console.log '[YamlToJson]', { content, contentType, err }
+
+    return { content, contentType, err }
+
+
   _.assign @views,


teams: minor typo showPane

teams: minor typo showPane

--- client/landing/site.landing/coffee/team/AppView.coffee
+++ client/landing/site.landing/coffee/team/AppView.coffee
@@ -28,5 +28,5 @@
     return KD.singletons.router.handleRoute '/Teams'  unless TABS[step]

     if tab = @tabView.getPaneByName step
-    then @tabView.showTab tab
+    then @tabView.showPane tab
     else @tabView.addPane new TABS[step] { query }


Remove dead code.

Remove dead code.

--- core/app/backbone/controllers/client_controller.coffee
+++ core/app/backbone/controllers/client_controller.coffee
@@ -22,8 +22,6 @@
     clientModal = new DiscussionModalContainer
     FactlinkApp.discussionModalRegion.show clientModal

-    csrf_token = $('meta[name=csrf-token]').attr('content')
-
     FactlinkApp.guided = params.guided == 'true'

     if params.fact


allowRNG

allowRNG

--- modules/rng.coffee
+++ modules/rng.coffee
@@ -6,7 +6,7 @@
     @chance = new Chance
     # The classic
     @registerCommand 'roll', (msg, args, d)=>
-      return unless d.data.allowRng
+      return unless d.data.allowRNG
       unless /\d+d\d+/.test(args)
         args = if parseInt(args) then "1d#{parseInt(args)}" else '1d100'
       result = @chance.rpg(args)
@@ -18,7 +18,7 @@

     # Totally not stolen from ChavezBot
     @registerCommand 'choose', { argSeparator: ';' }, (msg, args, d)=>
-      return unless d.data.allowRng
+      return unless d.data.allowRNG
       if args.length < 2
         msg.reply 'Not enough items to choose from. Remember to use `;` to separate them.'
       else
@@ -46,11 +46,11 @@
       'My sources say no'
       'Outlook not so good'
       'Very doubtful'
-    ] if d.data.allowRng
+    ] if d.data.allowRNG

     # Not actually random but ¯\_(ツ)_/¯
     @registerCommand 'rate', (msg, args, d)=>
-      return unless args and d.data.allowRng
+      return unless args and d.data.allowRNG
       for i in [0 ... args.length]
         chr   = args.charCodeAt(i)
         hash  = ((hash << 5) - hash) + chr


updated methods

updated methods

--- src/drm-dropdown-buttons.coffee
+++ src/drm-dropdown-buttons.coffee
@@ -3,6 +3,7 @@
 ###############################################################################
 "use strict"

+$ = jQuery
 class @DrmDropdownButton
     constructor: (@container = $('div.drm-dropdown-solid-btn-holder'), @speed = 300, @button = 'button') ->
         self = @
@@ -29,6 +30,7 @@

             unless openButtons.length is 0
                 self.changeMenu.call openButtons, 'showing', self.speed, self.activeClass
+            e.stopPropagation()

     changeMenu: (status, speed, activeClass) ->
         if status is 'hidden' then $(@).next('ul').addClass(activeClass).slideDown speed else $(@).next('ul').removeClass(activeClass).slideUp speed


hack to abort correctly when exceptions are thrown in <clinit>

--- src/runtime.coffee
+++ src/runtime.coffee
@@ -290,7 +290,8 @@

         @meta_stack().push root.StackFrame.fake_frame('class_lookup')
         class_file.methods['<clinit>()V']?.setup_stack(@)
-        @run_until_finished (->), (->), true
+        unless @run_until_finished (->), (->), true
+          throw 'Error in class initialization'
         @meta_stack().pop()
     class_file

@@ -359,7 +360,9 @@
       done_cb?()
       return true
     catch e
-      if e == ReturnException
+      if e == 'Error in class initialization'
+        return false
+      else if e == ReturnException
         return @run_until_finished (->), done_cb, no_threads
       else if e instanceof YieldIOException
         retval = null


Update cli opts.

Update cli opts.

--- src/cli.coffee
+++ src/cli.coffee
@@ -21,7 +21,7 @@
     -e, --export <name>          export module as <name>
     -i, --include [module, ...]  additional modules to include, in <require as>:<path to module> format
     -m, --minify                 minify output
-    -o, --output <file>          write bundle to file instead of stdout, {} can be used as a placeholder.
+    -o, --output <file>          write bundle to file instead of stdout, {} may be used as a placeholder.
     -p, --prelude <file>         file to use as prelude
         --no-prelude             exclude prelude from bundle
     -s, --strict                 add "use strict" to each bundled module.
@@ -44,6 +44,7 @@

 opts =
   bare:    false
+  dedupe:  false
   exclude: null
   export:  null
   files:   []
@@ -64,6 +65,8 @@
       version()
     when '-b', '--bare'
       opts.bare = true
+    when '-d', '--dedupe'
+      opts.dedupe = true
     when '-x', '--exclude'
       opts.exclude = new RegExp args.shift()
     when '-e', '--export'


Removed the now unnecessary zappa command.

--- src/cli.coffee
+++ src/cli.coffee
@@ -1,100 +0,0 @@
-zappa = require './zappa'
-coffee = require 'coffee-script'
-fs = require 'fs'
-path = require 'path'
-puts = console.log
-{inspect} = require 'util'
-{spawn} = require 'child_process'
-{OptionParser} = require 'coffee-script/lib/optparse'
-child = null
-file = null
-watching = []
-
-argv = process.argv[2..]
-options = null
-
-usage = '''
-  Usage:
-    zappa [OPTIONS] path/to/app.coffee
-'''
-
-switches = [
-  ['-h', '--help', 'Displays this wonderful, elucidative help message']
-  ['-v', '--version', 'Shows zappa version']
-  ['-p', '--port [NUMBER]', 'The port(s) the app(s) will listen on. Ex.: 8080 or 4567,80,3000']
-  ['-n', '--hostname [STRING]', 'If omitted, will accept connections to any ipv4 address (INADDR_ANY)']
-  ['-c', '--compile', 'Compiles the app(s) to a .js file instead of running them.']
-  ['-w', '--watch', 'Keeps watching the file and restarts the app when it changes.']
-]
-
-compile = (coffee_path, callback) ->
-  fs.readFile coffee_path, (err, data) ->
-    if err then callback(err)
-    else
-      js = coffee.compile String(data), bare: yes
-      js = "require('zappa').run(function(){#{js}});"
-      js_path = path.basename(coffee_path, path.extname(coffee_path)) + '.js'
-      dir = path.dirname coffee_path
-      js_path = path.join dir, js_path
-      fs.writeFile js_path, js, (err) ->
-        if err then callback(err)
-        else callback()
-
-remove_watch_option = ->
-  i = argv.indexOf('-w')
-  argv.splice(i, 1) if i > -1
-  i = argv.indexOf('--watch')
-  argv.splice(i, 1) if i > -1
-
-spawn_child = ->
-  child = spawn 'zappa', argv
-  child.stdout.on 'data', (data) ->
-    data = String(data)
-    if data.match /^Included file \".*\.coffee\"/
-      included = data.match(/^Included file \"(.*\.coffee)\"/)[1]
-      watch path.join(path.dirname(file), included) unless included in watching
-      watching.push included
-    puts data
-  child.stderr.on 'data', (data) -> puts String(data)
-
-watch = (file) ->
-  fs.watchFile file, {persistent: true, interval: 500}, (curr, prev) ->
-    return if curr.size is prev.size and curr.mtime.getTime() is prev.mtime.getTime()
-    puts 'Changes detected, reloading...'
-    child.kill() # Infanticide!
-    spawn_child()
-
-@run = ->
-  parser = new OptionParser switches, usage
-  options = parser.parse argv
-  args = options.arguments
-  delete options.arguments
-
-  if options.port
-    options.port = if options.port.match /,/ then options.port.split ',' else [options.port]
-    for i, p of options.port
-      options.port[i] = parseInt(p)
-
-  if args.length is 0
-    puts parser.help() if options.help or argv.length is 0
-    puts zappa.version if options.version
-    process.exit()
-  else
-    file = args[0]
-
-    path.exists file, (exists) ->
-      if not exists
-        puts "\"#{file}\" not found."
-        process.exit -1
-
-      if options.compile
-        compile file, (err) ->
-          if err then puts err; process.exit -1
-          else process.exit()
-      else
-        if options.watch
-          remove_watch_option()
-          spawn_child()
-          watch file
-        else
-          zappa.run_file file, options


Alias apm outdated to apm upgrade --list

Closes #86

--- src/upgrade.coffee
+++ src/upgrade.coffee
@@ -15,7 +15,7 @@

 module.exports =
 class Upgrade extends Command
-  @commandNames: ['upgrade']
+  @commandNames: ['upgrade', 'outdated']

   constructor: ->
     @atomDirectory = config.getAtomDirectory()
@@ -26,6 +26,7 @@
     options.usage """

       Usage: apm upgrade
+             apm upgrade --list

       Upgrade out of date packages installed to ~/.atom/packages

@@ -133,6 +134,7 @@
       tree updates, ({pack, latestVersion}) ->
         "#{pack.name.yellow} #{pack.version.red} -> #{latestVersion.green}"

+      return callback() if options.command is 'outdated'
       return callback() if options.argv.list
       return callback() if updates.length is 0


fix some typos in idle timeout docs; change the default if account settings were to fail to 60 minutes (should never happen, but will be way less annoying noticeable if it does); maybe eliminate a race, but I doubt it.

--- src/smc-webapp/client_browser.coffee
+++ src/smc-webapp/client_browser.coffee
@@ -91,6 +91,10 @@
         # This is used by the base class for marking file use notifications.
         @_redux = require('./smc-react').redux

+        # 60 min default. Correct val will get set when user account settings are loaded.
+        # Set here rather than in @_init_idle to avoid any potential race.
+        @_idle_timeout = 60 * 60 * 1000
+
         setTimeout(@_init_idle, 15 * 1000)

         # Start reporting metrics to the backend if requested.
@@ -139,8 +143,6 @@
         A document.body event listener here and one for each jupyter iframe.body (see jupyter.coffee).
         ###

-        # 15 min default in case it isn't set (it will get set when user account settings are loaded)
-        @_idle_timeout ?= 15 * 60 * 1000
         @_idle_reset()
         setInterval(@_idle_check, 60 * 1000)

@@ -185,20 +187,21 @@
         if not @_idle_time?
             return
         now = (new Date()).getTime()
-        # console.log("idle: checking idle #{@_idle_time} < #{now}")
+        #console.log("idle: checking idle #{@_idle_time} < #{now}")
         if @_idle_time < now
             @emit('idle', 'away')

     # Set @_idle_time to the **moment in in the future** at which the user will be
-    # considered idle, and also emit event indicator using is currently active.
+    # considered idle, and also emit event indicating that user is currently active.
     _idle_reset: =>
         @_idle_time = (new Date()).getTime() + @_idle_timeout + 1000
-        # console.log '_idle_reset', new Date(@_idle_time), ' _idle_timeout=', @_idle_timeout
+        #console.log '_idle_reset', new Date(@_idle_time), ' _idle_timeout=', @_idle_timeout
         @emit('idle', 'active')

     # Change the standby timeout to a particular time in minutes.
     # This gets called when the user configuration settings are set/loaded.
     set_standby_timeout_m: (time_m) =>
+        # console.log 'set_standby_timeout_m', time_m
         @_idle_timeout = time_m * 60 * 1000
         @_idle_reset()


prevent socket.io spamming

prevent socket.io spamming

--- client/app/utils/socketio_utils.coffee
+++ client/app/utils/socketio_utils.coffee
@@ -2,7 +2,11 @@
 {ActionTypes} = require '../constants/app_constants'
 url = window.location.origin
 pathToSocketIO = "#{window.location.pathname}socket.io"
-socket = io.connect url, path: pathToSocketIO
+socket = io.connect url,
+    path: pathToSocketIO
+    reconnectionDelayMax: 60000
+    reconectionDelay: 2000
+    reconnectionAttempts: 3

 dispatchAs = (action) -> (content) ->
     AppDispatcher.handleServerAction


fix load errors

fix load errors

--- src/app.coffee
+++ src/app.coffee
@@ -74,7 +74,7 @@
 		redo: (count) ->
 		load: (data) ->
 			@animations = data
-			console.info data
+			@$options.actor.data = data
 		save: () ->
 			json = JSON.stringify @$data.animations
 			blob = new Blob([json], {type: 'text/json;charset=utf-8'})
@@ -138,7 +138,7 @@

 		loader = new PIXI.AssetLoader(['suika.json'])
 		loader.onComplete = =>
-			actor = new Actor(@$data.animations)
+			actor = @$options.actor = new Actor(@$data.animations)
 			actor.scale.x = actor.scale.y = 0.5
 			container.addChild(actor)
 			actor.currentAnimation = @currentAnimation


Sort imports.

Sort imports.

--- src/index.coffee
+++ src/index.coffee
@@ -1,7 +1,7 @@
 import './utils/patches'

+import El           from 'el.js'
 import Promise      from 'broken'
-import El           from 'el.js'
 import objectAssign from 'es-object-assign'
 import refer        from 'referential'
 import store        from 'akasha'


feat: use strict

feat: use strict

--- src/index.coffee
+++ src/index.coffee
@@ -23,6 +23,9 @@
         ], factory )

 )( ( Q, console, settings, objectUtils, XHR, Polyglot, Moment, accounting ) ->
+
+    'use strict'
+
     ###*
     #   This module is used to handle translations, formatting and locale settings
     #
@@ -31,6 +34,7 @@
     #   @constructor
     #   @version        0.1
     ###
+
     class LocaleManager
         locale:         undefined
         cache:          {}


Spy on some variables.

Spy on some variables.

--- src/index.coffee
+++ src/index.coffee
@@ -155,7 +155,14 @@
     expose.amplify = amplify

+    spy.parseQueryString = parseQueryString
+    spy.Dropbox = Dropbox
+
     spy.coffeeconsole = coffeeconsole
+    spy.path = path
+    spy.dbx = dbx
+    spy.authenticationUrl = authenticationUrl
+    spy.dropboxAccessDenied = dropboxAccessDenied

 window.onload = main


Revert tweaks unrelated to stylus @require support

From 26ea2f94b0be8e13f901c5e4ce1c5e8f0baa136a


Cleanup

Cleanup

--- src/index.coffee
+++ src/index.coffee
@@ -68,7 +68,7 @@
   util.pump reader, writer, ->
     duration = size / SAMPLE_RATE / NUM_CHANNELS / 2
     winston.info 'File added OK', file: src, duration: duration
-
+
     json.spritemap[name] = start: offsetCursor, end: offsetCursor + duration, loop: name == argv.autoplay
     offsetCursor += duration
     appendSilence Math.ceil(duration) - duration + 1, dest, cb
@@ -82,7 +82,7 @@
     winston.info 'Silence gap added', duration: duration
     offsetCursor += duration
     cb()
-
+
 exportFile = (src, dest, ext, opt, store, cb) ->
   outfile = dest + '.' + ext
   ffmpeg = spawn 'ffmpeg', ['-y', '-ac', NUM_CHANNELS, '-f', 's16le', '-i', src].concat(opt).concat outfile
@@ -107,15 +107,15 @@
     cb()

 processFiles = ->
-  formats =
+  formats =
     aiff: []
     ac3: '-acodec ac3'.split ' '
     mp3: '-ab 128 -f mp3'.split ' '
     m4a: []
     ogg: '-acodec libvorbis -f ogg'.split ' '
-
+
   rawparts = if argv.rawparts.length then argv.rawparts.split ',' else null
-
+
   i = 0
   async.forEachSeries files, (file, cb) ->
     i++
@@ -133,10 +133,10 @@
           , cb3
         else
           cb3()
-
+
   , (err) ->
     return winston.error 'Error adding file', err if err
-
+
     async.forEachSeries Object.keys(formats), (ext, cb) ->
       winston.debug 'Start export', format: ext
       exportFile tempFile, argv.output, ext, formats[ext], true, cb


Fix bullshit typo

Fix bullshit typo

--- src/index.coffee
+++ src/index.coffee
@@ -149,7 +149,7 @@
   defineCanvasRenderer:  canvasRenderer.defineCanvasRenderer,
   renderShapeToContext: canvasRenderer.renderShapeToContext,
   renderShapeToCanvas: canvasRenderer.renderShapeToCanvas,
-  renderShapesToCanvas: util.renderShapesToCanvas
+  renderShapesToCanvas: util.renderShapes

   defineSVGRenderer: svgRenderer.defineSVGRenderer,
   renderShapeToSVG: svgRenderer.renderShapeToSVG,


META-68: Debounce mentions of the same ticket in a channel for 5 mins

--- src/index.coffee
+++ src/index.coffee
@@ -25,6 +25,7 @@
 #   ndaversa

 _ = require "underscore"
+moment = require "moment"

 Config = require "./config"
 Github = require "./github"
@@ -35,8 +36,12 @@

 class JiraBot

+  @JIRA_ROOM_TICKET_MENTIONS: "jira-room-ticket-mentions"
+
   constructor: (@robot) ->
     return new JiraBot @robot unless @ instanceof JiraBot
+    @robot.brain.once "loaded", =>
+      @mentions = @robot.brain.get(JiraBot.JIRA_ROOM_TICKET_MENTIONS) or {}

     @webhook = new Jira.Webhook @robot
     Utils.robot = @robot
@@ -52,6 +57,30 @@

   send: (context, message) ->
     @adapter.send context, message
+
+  shouldIncludeAttachmentForTicketKey: (key, msg) ->
+    should = yes
+    return should unless @mentions?
+    room = msg.message.room
+
+    if @mentions[room]
+      if time = @mentions[room].tickets[key]
+        should = moment().isAfter time
+    else
+      @mentions[room] = tickets: {}
+    @mentions[room].tickets[key] = moment().add 5, 'minutes' if should
+
+    #Cleanup other mention expiries
+    for r, obj of @mentions
+      for k, t of @mentions[r].tickets
+        if moment().isAfter t
+          delete @mentions[r].tickets[k]
+
+    @robot.brain.set JiraBot.JIRA_ROOM_TICKET_MENTIONS, @mentions
+    @robot.brain.save()
+
+    @robot.logger.info "Supressing ticket attachment for #{key} in #{room}" unless should
+    return should

   matchJiraTicket: (message) ->
     if message.match?
@@ -72,7 +101,8 @@
     return false

   prepareResponseForJiraTickets: (msg) ->
-    Promise.all(msg.match.map (key) ->
+    Promise.all(msg.match.map (key) =>
+      return unless @shouldIncludeAttachmentForTicketKey key, msg
       _attachments = []
       Jira.Create.fromKey(key).then (ticket) ->
         _attachments.push ticket.toAttachment()
@@ -289,7 +319,8 @@
       @robot.hear Config.transitions.regex, (msg) =>
         msg.finish()
         [ __, key, toState ] = msg.match
-        Jira.Transition.forTicketKeyToState key, toState, msg, yes
+        includeAttachment = @shouldIncludeAttachmentForTicketKey key, msg
+        Jira.Transition.forTicketKeyToState key, toState, msg, includeAttachment

     #Clone
     @robot.hear Config.clone.regex, (msg) =>
@@ -302,16 +333,19 @@
     @robot.hear Config.watch.regex, (msg) =>
       msg.finish()
       [ __, key, remove, person ] = msg.match
+
+      includeAttachment = @shouldIncludeAttachmentForTicketKey key, msg
       if remove
-        Jira.Watch.forTicketKeyRemovePerson key, person, msg, yes
+        Jira.Watch.forTicketKeyRemovePerson key, person, msg, includeAttachment
       else
-        Jira.Watch.forTicketKeyForPerson key, person, msg, yes
+        Jira.Watch.forTicketKeyForPerson key, person, msg, includeAttachment

     #Rank
     @robot.hear Config.rank.regex, (msg) =>
       msg.finish()
       [ __, key, direction ] = msg.match
-      Jira.Rank.forTicketKeyByDirection key, direction, msg, yes
+      includeAttachment = @shouldIncludeAttachmentForTicketKey key, msg
+      Jira.Rank.forTicketKeyByDirection key, direction, msg, includeAttachment

     #Labels
     @robot.hear Config.labels.addRegex, (msg) =>
@@ -320,13 +354,17 @@
       {input: input} = msg.match
       labels = []
       labels = (input.match(Config.labels.regex).map((label) -> label.replace('#', '').trim())).concat(labels)
-      Jira.Labels.forTicketKeyWith key, labels, msg, yes
+
+      includeAttachment = @shouldIncludeAttachmentForTicketKey key, msg
+      Jira.Labels.forTicketKeyWith key, labels, msg, includeAttachment

     #Comment
     @robot.hear Config.comment.regex, (msg) =>
       msg.finish()
       [ __, key, comment ] = msg.match
-      Jira.Comment.forTicketKeyWith key, comment, msg, yes
+
+      includeAttachment = @shouldIncludeAttachmentForTicketKey key, msg
+      Jira.Comment.forTicketKeyWith key, comment, msg, includeAttachment

     #Subtask
     @robot.respond Config.subtask.regex, (msg) =>
@@ -338,10 +376,12 @@
     @robot.hear Config.assign.regex, (msg) =>
       msg.finish()
       [ __, key, remove, person ] = msg.match
+
+      includeAttachment = @shouldIncludeAttachmentForTicketKey key, msg
       if remove
-        Jira.Assign.forTicketKeyToUnassigned key, msg, yes
+        Jira.Assign.forTicketKeyToUnassigned key, msg, includeAttachment
       else
-        Jira.Assign.forTicketKeyToPerson key, person, msg, yes
+        Jira.Assign.forTicketKeyToPerson key, person, msg, includeAttachment

     #Create
     @robot.respond Config.commands.regex, (msg) =>


Remove duplicate line

Remove duplicate line

--- src/index.coffee
+++ src/index.coffee
@@ -23,6 +23,5 @@
   folders = [folders] if typeof folders is "string"

   if arg in tasks
-      folders = [folders] if typeof folders is "string"
       for folder in folders
         deleteFolder(folder)


firefox support

firefox support

--- src/index.coffee
+++ src/index.coffee
@@ -232,13 +232,16 @@
 # ###################################################################################################
 Object.defineProperty global, "__STACK__",
   get: ()->
-    orig = Error.prepareStackTrace
-    Error.prepareStackTrace = (_, stack)->stack
-    err = new Error
-    Error.captureStackTrace err, arguments.callee
-    stack = err.stack
-    Error.prepareStackTrace = orig
-    stack
+    if Error.captureStackTrace
+      orig = Error.prepareStackTrace
+      Error.prepareStackTrace = (_, stack)->stack
+      err = new Error
+      Error.captureStackTrace err, arguments.callee
+      stack = err.stack
+      Error.prepareStackTrace = orig
+      stack
+    else
+      []

 Object.defineProperty global, "__LINE__",
   get: ()->__STACK__[1].getLineNumber()


fix(length): better upper length filtering

--- src/index.coffee
+++ src/index.coffee
@@ -167,7 +167,7 @@

   upperLengths = [16]
   upperLengths = card.length if card
-  upperLengths = [Math.min maxLength, upperLengths[..].pop()] if maxLength
+  upperLengths = upperLengths.filter((x) -> x <= maxLength) if maxLength

   # Return if an upper length has been reached
   for upperLength, i in upperLengths


FIX: Ensure time exceeded does not allow transitions

--- src/app/common/services/task-service.coffee
+++ src/app/common/services/task-service.coffee
@@ -270,7 +270,7 @@
       fix_and_resubmit:  []
       redo:  []
       do_not_resubmit:  ['ready_to_mark', 'not_started', 'working_on_it', 'need_help']
-      time_exceeded: []
+      time_exceeded: ['ready_to_mark', 'not_started', 'working_on_it', 'need_help']
       fail:  ['ready_to_mark', 'not_started', 'working_on_it', 'need_help']

   # This function gets the status CSS class for the indicated status


media api image url repaired

media api image url repaired

--- app/scripts/directives.coffee
+++ app/scripts/directives.coffee
@@ -14,13 +14,20 @@
       op: '='
     },
     template: (x, scope) ->
-      url = "http://media.lefresnoy.net/?url={{ url }}&w={{ width }}&h={{ height }}&fmt=jpg"
-      if scope.op
-        url += "&op=#{ scope.op }"
+      url = "{{ url_image }}&w={{ width }}&h={{ height }}&fmt=jpg"
       return "<img ng-src=\"#{url}\" />"
     controller: ($scope) ->
-      if($scope.url.indexOf("http") == -1)
-        $scope.url = "http://api.lefresnoy.net/"+$scope.url
+      $scope.$watch("url", (value) ->
+          if(value)
+            if(value.indexOf('http') == -1)
+              $scope.url_image = "http://media.lefresnoy.net/?url=http://api.lefresnoy.net/"+value+"&w="+$scope.width+"h="+$scope.height+"&fmt=jpg"
+            else
+              $scope.url_image = "http://media.lefresnoy.net/?url="+value+"&w="+$scope.width+"h="+$scope.height+"&fmt=jpg"
+
+            if $scope.op
+              $scope.url_image += "&op=#{ scope.op }"
+      )
+
   }
 )


KiteSubscription: filter kite plans from group dashboard

--- client/Dashboard/controllers/productscontroller.coffee
+++ client/Dashboard/controllers/productscontroller.coffee
@@ -145,7 +145,7 @@
   fetchProducts: (category, callback) ->
     KD.getGroup().fetchProducts category, (err, products) ->
       return callback err  if err
-
+      products = products.filter (plan)-> not ("kite" in plan.tags)
       queue = products.map (plan) -> ->
         # recursively fetch nested products, if any
         if plan.fetchProducts?


AdminModal: Code refactor.

AdminModal: Code refactor.

--- client/admin/lib/views/groupgeneralsettingsview.coffee
+++ client/admin/lib/views/groupgeneralsettingsview.coffee
@@ -99,7 +99,10 @@
       attributes : accept : 'image/*'
       change     : @bound 'handleUpload'

-    @showAvatar()
+
+    logo = @getData().customize?.logo
+
+    if logo then @showLogo logo else @showPattern()

   handleUpload: ->
@@ -151,13 +154,6 @@
     avatarEl.style.backgroundImage = pattern.toDataUrl()
     avatarEl.style.borderColor     = pattern.color
     @uploadSection.unsetClass 'with-logo'
-
-
-  showAvatar: ->
-
-    logo = @getData().customize?.logo
-
-    if logo then @showLogo logo else @showPattern()

   removeLogo: ->


delete csmain.coffee

delete csmain.coffee

--- js/csmain.coffee
+++ js/csmain.coffee
@@ -1,2 +0,0 @@
-define ['jquery','cs!umobi.core','cs!umobi.main'], (main) ->
-  console.log 'csmain'


update buttons onClickTutorial (resolves #133)

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -300,9 +300,7 @@
   loadSubjectData: () ->
     $('#graph-container').addClass 'loading-lightcurve'
     jsonFile = @subject.selected_light_curve.location
-    jsonFile = ' https://s3.amazonaws.com/demo.zooniverse.org/planet_hunter/beta_subjects/2300039_9-3.json'
-    # console.log 'jsonFile: ', jsonFile # DEBUG CODE
-
+
     # handle ui elements
     @el.find('#loading-screen').fadeIn()
     @el.find('.star-id').hide()
@@ -481,6 +479,8 @@
   onClickTutorial: ->
     clickEvent = { event: 'tutorialClicked', timestamp: (new Date).toUTCString() }
     @recordedClickEvents.push clickEvent
+    @canvasGraph.marks.destroyAll() # clear previous marks
+    @updateButtons()
     @launchTutorial()

   launchTutorial: ->


Refresh tutorial steps

Refresh tutorial steps

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -215,6 +215,10 @@
       firstStep: 'welcome'
       steps: TutorialSteps
       parent: @el[0]
+
+    @tutorial.el.on 'start-tutorial enter-tutorial-step', =>
+      translate.refresh @tutorial.el.get 0
+
     @tutorial.el.bind('end-tutorial', @onTutorialEnd)

     # Set first tutorial subject


finish displaying (faux) previous markings

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -225,11 +225,12 @@

   onClickFinishedMarking: ->
     console.log 'onClickFinishedMarking()'
+    @finishedMarkingButton.hide()
     @giveFeedback()
-    @finishedMarkingButton.hide()
+
+
+  giveFeedback: ->
     @finishedFeedbackButton.show()
-
-  giveFeedback: ->
     console.log 'giveFeedback()'
     if @canvasGraph.showFakePrevMarks() <= 0
       @notify('Loading summary page...')
@@ -238,7 +239,6 @@
     else
       @notify('Here\'s what others have marked...')
       @el.find(".mark").fadeOut(1000)
-

   onClickFinishedFeedback: ->
     console.log 'onClickFinishedFeedback()'


Move UI test event listener assignments under document ready call.

--- js/flight.coffee
+++ js/flight.coffee
@@ -142,24 +142,27 @@
 else
   root.Flight = Flight

-window.flight = new Flight();
+  $ ->

-#backBtn.addEventListener 'touchstart', ->
-#  flight.slideTransition('#panel-1','#panel-2','0.4s',true)
-$('.back').on 'click', =>
-    flight.goToPage('#panel-2',{back:true})
+    window.flight = new Flight();

-$('.forward').on 'click', =>
-  flight.goToPage('#panel-2')
+    $('.back').on 'click', =>
+        flight.goToPage('#panel-2',{back:true})

-$('li').on 'touchstart', ->
-  this.className = "touchstart"
-  flight.goToPage('#panel-2')
+    $('.forward').on 'click', =>
+      flight.goToPage('#panel-2');

-$('li').on 'touchend', ->
-  window.setTimeout =>
-    this.className = ""
-  , 10
+
+
+
+#$('li').on 'touchstart', ->
+#  this.className = "touchstart"
+#  flight.goToPage('#panel-2')
+#
+#$('li').on 'touchend', ->
+#  window.setTimeout =>
+#    this.className = ""
+#  , 10

 #if 'ontouchstart' in window
 #  alert 'ontouchstart'


Make secondary parameters 'always-visible' if they have differences.

--- client/src/scripts/scoring-view.coffee
+++ client/src/scripts/scoring-view.coffee
@@ -176,20 +176,23 @@
     rates = map cms, computeTPRandFPR
     renderRocCurve rates

-  createInputParameter = (key, value, type) ->
-    key: key, value: value, type: type, isDifferent: no
+  createInputParameter = (key, value, isVisible) ->
+    key: key, value: value, isVisible: isVisible, isDifferent: no

   combineInputParameters = (model) ->
     critical = mapWithKey model.critical_parameters, (value, key) ->
-      createInputParameter key, value, 'critical'
+      createInputParameter key, value, yes
     secondary = mapWithKey model.secondary_parameters, (value, key) ->
-      createInputParameter key, value, 'secondary'
+      createInputParameter key, value, no
     concat critical, secondary

   # Side-effects!
   markAsDifferent = (parameterss, index) ->
     for parameters in parameterss
-      parameters[index].isDifferent = yes
+      parameter = parameters[index]
+      # mark this as different to enable special highlighting
+      parameter.isDifferent = yes
+      parameter.isVisible = yes
     return

   # Side-effects!
@@ -217,7 +220,7 @@
     createParameterTable = ({ parameters }) ->
       kvtable [
         tbody map parameters, (parameter) ->
-          trow = if parameter.type is 'critical' then tr else trExpert
+          trow = if parameter.isVisible then tr else trExpert
           trow [
             th parameter.key
             td if parameter.isDifferent then diffSpan parameter.value else parameter.value


:pencil: add a second n to scan*n*ing

:pencil: add a second n to scan*n*ing

--- src/jscpd.coffee
+++ src/jscpd.coffee
@@ -90,8 +90,8 @@
       logger.info '----------------------------------------'
       logger.info 'Run without debug option for start detection process'
     else
-      logger.profile 'Scaning for duplicates time:'
-      logger.info "Scaning #{files.length} files for duplicates..." if files.length
+      logger.profile 'Scanning for duplicates time:'
+      logger.info "Scanning #{files.length} files for duplicates..." if files.length

       strategy = new Strategy options.languages
       detector = new Detector strategy
@@ -103,8 +103,8 @@

       codeMap = detector.start files, options['min-lines'], options['min-tokens']

-      logger.profile 'Scaning for duplicates time:'
-      logger.info 'Scaning... done!\n'
+      logger.profile 'Scanning for duplicates time:'
+      logger.info 'Scanning... done!\n'

       logger.profile 'Generate report time:'
       logger.info 'Start report generation...\n'


debug

debug

--- scripts/heroku-deploy.coffee
+++ scripts/heroku-deploy.coffee
@@ -116,7 +116,7 @@
   { appName, appData, blobRef, env, msg } = options

   requestUrl = "https://kolkrabbi.herokuapp.com/apps/#{appData[env].id}/github/push"
-
+  console.log(requestUrl)
   body = JSON.stringify
     branch: blobRef


Mostly styled crawl able profile page

Mostly styled crawl able profile page

--- server/lib/crawler/staticpages/profile.coffee
+++ server/lib/crawler/staticpages/profile.coffee
@@ -4,7 +4,7 @@
 createLinkToStatusUpdate = (createDate, slug) ->
   content =
     """
-    #{createDate}
+    <time class="kdview">#{createDate}</time>
     """
   return content

@@ -22,11 +22,13 @@
   if statusUpdate?.body?
     statusUpdateContent =
     """
-

-        #{statusUpdate.body} -
-
-        at #{linkToStatusUpdate}
-

+

+      #{authorFullName}
+

+
#{statusUpdate.body}

+

+      #{linkToStatusUpdate}
+

     """
   return statusUpdateContent

@@ -41,10 +43,7 @@
   linkToProfile = createLinkToUserProfile authorFullName, authorNickname
   if statusUpdates?.length > 0
     updates = (createStatusUpdateNode(statusUpdate, authorFullName, authorNickname) for statusUpdate in statusUpdates)
-    updatesContent = "
Last status updates from #{linkToProfile}:
"
-    updatesContent += "
"
-    updatesContent += updates.join("")
-    updatesContent += "
"
+    updatesContent = updates.join("")
   else
     updatesContent = ""
   return updatesContent
@@ -65,37 +64,117 @@
     <title>#{nickname} - Koding</title>
     #{getGraphMeta()}

-
+
       #{putContent(account, sUpdates)}

   """

+getDock = ->
+  """
+
+

+
+
+
+

+

+
+
+                      Activity
+
+
+
+                      Teamwork
+
+
+
+                      Terminal
+
+
+
+                      Editor
+
+
+
+                      Apps
+
+

+

+

+
+  """
+
 putContent = (account, sUpdates)->
-  {profile:{nickname, firstName, lastName}} = account if account
+  getGraphMeta  = require './graphmeta'
+  {profile:{nickname, firstName, lastName, about}} = account if account
   nickname or= "A koding nickname"
   firstName or= "a koding "
   lastName or= "user"
+  about    or= ""

   numberOfLikes = if account.counts.likes then account.counts.likes else "0"
+  numberOfFollowers = if account.counts.followers then account.counts.followers else "0"
+  numberOfFollowing = if account.counts.following then account.counts.following else "0"
   imgURL = "https://gravatar.com/avatar/#{account.profile.hash}?size=90&d=https%3A%2F%2Fapi.koding.com%2Fimages%2Fdefaultavatar%2Fdefault.avatar.90.png"
+
+     # Koding

+     #

+     #

+     #        #{nickname}
+     #

+     #

+     #

+     #
+     #          #{firstName}
+     #          #{lastName}
+     #
+     #

+     #        #{numberOfLikes} likes.
+     #

+     #

+     #   #{sUpdates}
+

   content  =
     """
-      Koding

-

-          <h2itemprop="name">
-            #{nickname}
-

-

-

-
-              #{firstName}
-              #{lastName}
-
-

-            #{numberOfLikes} likes.
-

-

-       #{sUpdates}
+

+      #{getDock()}
+

+

+

+

+

+

+
+
+
+

+                    #{firstName}
+                    #{lastName}
+

+
#{about}

+

+                    #{numberOfFollowers}Followers
+                    #{numberOfFollowing}Following
+                    #{numberOfLikes}Likes
+

+

+

+

+

+

+

+

+                        #{sUpdates}
+

+

+

+

+

+

+

+

+

+

     """


switched to Mac version of DK kbd: ½ → $ and ¤ → €

--- client/prefs-keyboard.coffee
+++ client/prefs-keyboard.coffee
@@ -37,13 +37,13 @@
   DK:
     geometry: 'iso'
     normal: qw '''
-      ☠ ½ 1 2 3 4 5 6 7 8 9 0 + ´ ☠ ☠
+      ☠ $ 1 2 3 4 5 6 7 8 9 0 + ´ ☠ ☠
       ☠ q w e r t y u i o p å ¨ ☠
       ☠ a s d f g h j k l æ ø ' ☠
       ☠ < z x c v b n m , . - ☠ ☠
     '''
     shifted: qw '''
-      ☠ § ! " # ¤ % & / ( ) = ? ` ☠ ☠
+      ☠ § ! " # € % & / ( ) = ? ` ☠ ☠
       ☠ Q W E R T Y U I O P Å ^ ☠
       ☠ A S D F G H J K L Æ Ø * ☠
       ☠ > Z X C V B N M ; : _ ☠ ☠


updated photoGrid to scroll

updated photoGrid to scroll

--- Modules/PhotoPicker/PhotoGrid.coffee
+++ Modules/PhotoPicker/PhotoGrid.coffee
@@ -8,9 +8,20 @@
       cellMargin: 20
       layout: 'horizontal'
       width: '100%'
+      height: Ti.UI.FILL
+      contentWidth: 320
     }, options)
     @controls = []
-    @view = Ti.UI.createView @settings
+    @view = Ti.UI.createScrollView({
+      contentWidth: @settings.contentWidth
+      contentHeight: "auto"
+      showVerticalScrollIndicator: true
+      showHorizontalScrollIndicator: false
+      layout: @settings.layout
+      top: @settings.top
+      width: @settings.width
+      height: @settings.height
+    })

   addPhoto: (url) ->
     cell = Ti.UI.createImageView {


chrome initial document

chrome initial document

--- js/sample.coffee
+++ js/sample.coffee
@@ -42,7 +42,8 @@

   Print Icon

-#Wallapatta Syntax
+#Reference
+
  ##Headings

   Headings have the same syntax as Markdown. ``#`` for level 1 headings, ``##`` for
@@ -101,18 +102,18 @@
   Images can be added with ``!``.

   >>>
-   !/assets/icon128.png
-
-  ```
-   !/assets/icon128.png
+   !https://d13yacurqjgara.cloudfront.net/users/161539/screenshots/1789209/logo.png
+
+  ```
+   !https://d13yacurqjgara.cloudfront.net/users/161539/screenshots/1789209/logo.png

   Inline images can be added by surrounding the image URL with double square brackets (``[[`` and ``]]``).

   ```
-   This is a sentence which contains an [[/assets/icon128.png]] inline image.
-
-  >>>
-   This is a sentence which contains an [[/assets/icon128.png]] inline image.
+   This is a sentence which contains an [[https://d13yacurqjgara.cloudfront.net/users/161539/screenshots/1789209/logo.png]] inline image.
+
+  >>>
+   This is a sentence which contains an [[https://d13yacurqjgara.cloudfront.net/users/161539/screenshots/1789209/logo.png]] inline image.

  ##Side Notes

@@ -126,7 +127,7 @@
     - Two
     - Three

-    !/assets/icon128.png
+    !https://d13yacurqjgara.cloudfront.net/users/161539/screenshots/1789209/logo.png

   >>>
    This is a **side note** containing text, a list and an image.
@@ -135,7 +136,7 @@
    - Two
    - Three

-   !/assets/icon128.png
+   !https://d13yacurqjgara.cloudfront.net/users/161539/screenshots/1789209/logo.png

  ##Special Blocks

@@ -148,14 +149,14 @@

     Can have all the other things like images.

-    !/assets/icon128.png
+    !https://d13yacurqjgara.cloudfront.net/users/161539/screenshots/1814286/d1.png

   +++
    **This is a special segment.

    Can have all the other things like images.

-   !/assets/icon128.png
+   !https://d13yacurqjgara.cloudfront.net/users/161539/screenshots/1814286/d1.png

  ##Code Blocks

@@ -227,6 +228,82 @@
   >>>
    This won't work in online editor since the twitter script will not load

+ ##Javascript Blocks
+
+  HTML blocks are identified by ``<<<js``.
+  The code is evaluated and the html code returned is rendered.
+
+  ```
+   <<<js
+    "" + (7 * 100) + ""
+  >>>
+   <<<js
+    "" + (7 * 100) + ""
+
+ ##CoffeeScript Blocks
+
+  HTML blocks are identified by ``<<<coffee``.
+  The code is evaluated and the html code returned is rendered.
+
+  ```
+   <<<coffee
+    "<strong>#{7 * 100}</strong>"
+
+  >>>
+   <<<coffee
+    "<strong>#{7 * 100}</strong>"
+
+
+ ##Weya Blocks
+
+  HTML blocks are identified by ``<<<weya``.
+  The code is evaluated and the html code returned is rendered.
+
+  >>>
+   <<https://github.com/vpj/weya(Weya on Github)>>
+
+  ```
+   <<<weya
+    G = 1.618
+    H = 13
+    order = [2, 4, 1, 0, 3]
+    heights = (H * Math.pow G, i for i in order)
+    @svg width: 250, height: 250, ->
+     @g transform: "translate(2, 154)", ->
+      for h, i in heights
+       @g ".bar", transform: "translate(#{i * 50}, 0)", ->
+        @rect y: -h * G, width: 46, height: h * G, fill: '#4a4a4a'
+        @rect width: 30.67, height: h,fill: '#98ff98'
+        @rect x: 30.67, width: 15.33, height: h, fill: '#8bea8b'
+
+  >>>
+   It generates the <<https://www.forestpin.com(Forestpin)>> Logo
+
+  <<<weya
+   G = 1.618
+   H = 13
+   order = [2, 4, 1, 0, 3]
+   heights = (H * Math.pow G, i for i in order)
+   @svg width: 250, height: 250, ->
+    @g transform: "translate(2, 154)", ->
+     for h, i in heights
+      @g ".bar", transform: "translate(#{i * 50}, 0)", ->
+       @rect y: -h * G, width: 46, height: h * G, fill: '#4a4a4a'
+       @rect width: 30.67, height: h,fill: '#98ff98'
+       @rect x: 30.67, width: 15.33, height: h, fill: '#8bea8b'
+
+ ##Fullwidth Blocks
+
+  Full width blocks are identified by ``<!>``. They create content spanning the full width of the document; i.e. taking up the space reserved for sidenotes.
+
+  ```
+   <!>
+    !https://static.pexels.com/photos/6547/sky-night-space-galaxy-large.jpeg
+
+  <!>
+   !https://static.pexels.com/photos/6547/sky-night-space-galaxy-large.jpeg
+
+
  ##Bold

   Text can be made bold with ``**``.
@@ -301,19 +378,19 @@
   Comments can be specified with three forward slashes (``///``). All text typed inside a comment will be ignored, along with any other components or formatting used inside.

   ```
-   >>>
-    This is a sentence.
-
-    ///This is a **comment** with some text, which won't appear
-
-    And this is yet another sentence.
-
-  >>>
    This is a sentence.

    ///This is a **comment** with some text, which won't appear

    And this is yet another sentence.
+
+  >>>
+   This is a sentence.
+
+   ///This is a **comment** with some text, which won't appear
+
+   And this is yet another sentence.
+
 '''

  Mod.set 'Wallapatta.Sample', text