Fix cpp semicolon line ending on autocomplete (#5732)

--- app/views/play/level/tome/SpellView.coffee
+++ app/views/play/level/tome/SpellView.coffee
@@ -505,7 +505,7 @@
       autoLineEndings:
         javascript: ';'
         java: ';'
-        cpp: ';'
+        c_cpp: ';' # Match ace editor language mode
       popupFontSizePx: popupFontSizePx
       popupLineHeightPx: 1.5 * popupFontSizePx
       popupWidthPx: 380


moved version to apollo

moved version to apollo

--- src/Observatory.coffee
+++ src/Observatory.coffee
@@ -43,12 +43,6 @@
   settings:
     maxSeverity: 3
     printToConsole: true
-
-  # This is KEY for handshakes and stuff
-  version:
-    major: 0
-    minor: 3
-    patch: 2

   # Initializing the system - creating loggers, subscribing etc
   # Currently creates 1 ConsoleLogger and subscribes it system-wide.


collision with regular bounds

collision with regular bounds

--- test/collision.coffee
+++ test/collision.coffee
@@ -54,6 +54,6 @@
     width: 10
     height: 10

-  C
+  Collision.
 module()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/expirable.coffee
+++ test/expirable.coffee
@@ -4,7 +4,7 @@
   obj = GameObject
     duration: 5

-  obj.include(Durable)
+  obj.include Expirable

   5.times ->
     obj.update()
@@ -17,4 +17,3 @@
   equals obj.I.active, false, "object is inactive after duration"

 module()
-module()


Defer inspector renders

Defer inspector renders

--- assets/inspector/inspector_controller.coffee
+++ assets/inspector/inspector_controller.coffee
@@ -1,9 +1,12 @@
 #= require trix/utilities/dom
+#= require trix/utilities/helpers
 #= require ./selection_view
 #= require ./inspector_panel_view
 #= require ./text_panel_view
 #= require ./undo_panel_view
 #= require ./render_count_view
+
+{defer} = Trix.Helpers

 class Trix.InspectorController
   constructor: (@element, @editorController) ->
@@ -58,10 +61,10 @@
   findPanelElement: (name) ->
     @element.querySelector("[data-inspector-panel-name=#{name}]")

-  incrementRenderCount: ->
+  incrementRenderCount: -> defer =>
     @renderCountView.incrementAndRender()

-  render: ->
+  render: -> defer =>
     @selectionView.render()
     @renderCountView.render()
     @activePanelView?.render()


Add exclusions test

Add exclusions test


Make rerolling Pokemon work.

Make rerolling Pokemon work.

--- js/app.coffee
+++ js/app.coffee
@@ -25,7 +25,7 @@
     @rerolls += 1
     {players} = @controller
     r = +@controller.participants + Math.floor Math.random() * (players.length - +@controller.participants)
-    [players[i].pokemon, players[r].pokemon] = [players[r].pokemon, players[i].pokemon]
+    [@pokemon, players[r].pokemon] = [players[r].pokemon, @pokemon]

 angular.module 'ceApp', []
 .controller 'CeController', ['$http', ($http) ->


removed console statement

removed console statement

--- src/viz/types/helpers/graph/includes/axes.coffee
+++ src/viz/types/helpers/graph/includes/axes.coffee
@@ -112,7 +112,6 @@
     values = vars.axes.dataset.map (d) -> fetchValue vars, d, vars[axis].value
     if typeof values[0] is "string"
       sortKey = vars.order.value
-      console.log sortKey
       if sortKey
         sort = vars.order.sort.value
         agg = vars.aggs.value[sortKey] or "sum"


Updated attribute references in log statements.

--- src/api.coffee
+++ src/api.coffee
@@ -81,10 +81,10 @@

             reconnect = =>
               @connect().then =>
-                console.log "Push WebSocket replaced for namespace '#{@namespace}' topic [#{_(@attributes).join(",")}]"
+                console.log "Push WebSocket replaced for namespace '#{@namespace}' topic [#{@attributes}]"
                 @emit 'reconnect'
               .catch (error) =>
-                console.error "Error replacing push WebSocket for namespace '#{@namespace}' topic [#{_(@attributes).join(",")}] : ${error}\n${error.stack}"
+                console.error "Error replacing push WebSocket for namespace '#{@namespace}' topic [#{@attributes}] : ${error}\n${error.stack}"
                 @emit 'error', error

             console.log "Connection closed. Reconnecting in 5 seconds."
@@ -93,11 +93,11 @@

           else
             @emit 'close'
-            console.log "Push WebSocket closed for namespace '#{@namespace}' topic [#{_(@attributes).join(",")}]"
+            console.log "Push WebSocket closed for namespace '#{@namespace}' topic [#{@attributes}]"

         # The WebSocket connection has been established
         @sock.on 'open', =>
-          console.log "Push WebSocket opened for namespace '#{@namespace}' topic [#{_(@attributes).join(",")}]"
+          console.log "Push WebSocket opened for namespace '#{@namespace}' topic [#{@attributes}]"

           @emit 'open'

@@ -113,7 +113,7 @@
         @sock.on 'error', (error) =>
           @emit 'error', error

-          console.error "WebSocket error for namespace '#{@namespace}' topic [#{_(@attributes).join(",")}] : #{error}\n#{error.stack}"
+          console.error "WebSocket error for namespace '#{@namespace}' topic [#{@attributes}] : #{error}\n#{error.stack}"

         # Received a message
         @sock.on 'message', (msg) =>


Comment out sniperino

Comment out sniperino

--- scripts/sniperino.coffee
+++ scripts/sniperino.coffee
@@ -1,6 +1,4 @@
-#Does not work.
 ###
-# coffeelint: disable=max_line_length
 module.exports = (robot) ->
   dongerOutcome = ['alive','dead']
   gameOutcome = ['winning against', 'losing to']
@@ -62,4 +60,5 @@

   # Generate a random number between 1 and 100 inclusive
   rng = () ->
-    return (Math.floor(Math.random() * 100) + 1)+    return (Math.floor(Math.random() * 100) + 1)
+###


work_mem should count max_worker_processes

--- source/javascripts/pgtune.coffee
+++ source/javascripts/pgtune.coffee
@@ -114,16 +114,6 @@
         dw: Math.floor(memoryInKB * 3 / 4),
         desktop: Math.floor(memoryInKB / 4),
         mixed: Math.floor(memoryInKB * 3 / 4)
-      }[@dbType]
-      # work_mem is assigned any time a query calls for a sort, or a hash, or any other structure that needs a space allocation, which can happen multiple times per query. So you're better off assuming max_connections * 2 or max_connections * 3 is the amount of RAM that will actually use in reality. At the very least, you need to subtract shared_buffers from the amount you're distributing to connections in work_mem.
-      # The other thing to consider is that there's no reason to run on the edge of available memory. If you do that, there's a very high risk the out-of-memory killer will come along and start killing PostgreSQL backends. Always leave a buffer of some kind in case of spikes in memory usage. So your maximum amount of memory available in work_mem should be ((RAM - shared_buffers) / 2 / (max_connections * 3)).
-      workMem = (memoryInKB - gConfig['shared_buffers']) / (gConfig['max_connections'] * 3)
-      gConfig['work_mem'] = {
-        web: Math.floor(workMem),
-        oltp: Math.floor(workMem),
-        dw: Math.floor(workMem / 2),
-        desktop: Math.floor(workMem / 6),
-        mixed: Math.floor(workMem / 2)
       }[@dbType]
       # maintenance_work_mem
       gConfig['maintenance_work_mem'] = {
@@ -207,14 +197,28 @@
         san: '300'
       }[$('#pgtHarddriveValue').val()]
     # cpu
+
+    cpuCounter = 1
     if @dbVersion >= 9.5
       cpuNum = parseInt($('#pgtCPUValue').val(), 10) || 1
       if cpuNum > 1
+        cpuCounter = cpuNum
         gConfig['max_worker_processes'] = cpuNum
         if @dbVersion >= 9.6
           gConfig['max_parallel_workers_per_gather'] = Math.ceil(cpuNum / 2)
         if @dbVersion >= 10
           gConfig['max_parallel_workers'] = cpuNum
+
+    # work_mem is assigned any time a query calls for a sort, or a hash, or any other structure that needs a space allocation, which can happen multiple times per query. So you're better off assuming max_connections * 2 or max_connections * 3 is the amount of RAM that will actually use in reality. At the very least, you need to subtract shared_buffers from the amount you're distributing to connections in work_mem.
+    # The other thing to consider is that there's no reason to run on the edge of available memory. If you do that, there's a very high risk the out-of-memory killer will come along and start killing PostgreSQL backends. Always leave a buffer of some kind in case of spikes in memory usage. So your maximum amount of memory available in work_mem should be ((RAM - shared_buffers) / 2 / (max_connections * 3 * (max_worker_processes / 2))).
+    workMem = (memoryInKB - gConfig['shared_buffers']) / (gConfig['max_connections'] * 3 * Math.ceil(cpuCounter / 2)) / 2
+    gConfig['work_mem'] = {
+      web: Math.floor(workMem),
+      oltp: Math.floor(workMem),
+      dw: Math.floor(workMem / 2),
+      desktop: Math.floor(workMem / 6),
+      mixed: Math.floor(workMem / 2)
+    }[@dbType]

     arrayConfig = ("#{key} = #{@_formatedValue(key, value)}" for key, value of gConfig)
     @codeOut.text("#{infoMsg}#{settingsInfo.join("\n")}\n\n#{arrayConfig.join("\n")}")


Set correct active tab when routing from hash

If the URL ends with one of the tab URLs, eg. #maps or #settings, then
change the active tab from the default (raw) to the active one.

--- frontend/coffeescript/app/viz/views.coffee
+++ frontend/coffeescript/app/viz/views.coffee
@@ -43,28 +43,33 @@
         el: '#viz-options'

         events:
-            'click li': 'switch_event'
+          'click li': 'switch_tabs'

-        switch_event: ( event ) ->
-            # Prevents URL from changing back to '#'
-            event.preventDefault()
+        # Set the starting view as the active one if present, e.g. /#map
+        initialize: ->
+          current_route = Backbone.history.getFragment()
+          return if not current_route
+          @$('li.active').removeClass 'active'
+          @$("li[data-type=#{current_route}]").addClass 'active'

-            target = $( event.currentTarget )
+        switch_tabs: ( event ) ->
+          # Prevents URL from changing back to '#'
+          event.preventDefault()

-            if @selected().data('type') is target.data('type')
-                return
+          target = @$(event.currentTarget)

-            if target.hasClass( 'disabled' )
-                return
+          # Do nothing if the tab is disabled or is already displayed
+          return if @selected().data('type') is target.data('type')
+          return if target.hasClass 'disabled'

-            @selected().removeClass( 'active' )
-            target.addClass( 'active' )
+          # Otherwise set the clicked tab as the active one and trigger an
+          # event for the other components.
+          @selected().removeClass 'active'
+          target.addClass 'active'
+          @trigger "switch:#{target.data('type')}"

-            @trigger( 'switch:' + target.data( 'type' ) )
-
-        selected: ->
-            # Return the currently selected tab
-            return @$('li.active')
+        # Returns the currently selected tab as a jQuery element
+        selected: -> @$('li.active')

     class VizChrome extends Backbone.Marionette.Region
         el: '#viz-chrome'


removed utils-purpose.coffee

removed utils-purpose.coffee

--- frontend/purpose-tree/utils-purpose.coffee
+++ frontend/purpose-tree/utils-purpose.coffee
@@ -1,69 +0,0 @@
-root = exports ? this
-
-
-
-root.nestPurposeDataByCategories = (csv) ->
-  purposesNested = d3.nest()
-    .key((p) -> p.category)
-    .key((p) -> p.subcategory)
-    .key((p) -> p.subsubcategory)
-    #.key((p) -> p.name)
-    .rollup((ps) ->
-      #if ps.length == 1 then ps[0].code else ps.map (p) -> p.code
-      ps.map (p) ->
-        key : "#{p.name} - #{p.code}"
-        num : +p.total_num
-        amount : +p.total_amount
-    )
-    .entries(csv)
-  data =
-    key : "AidData"
-    values : purposesNested
-
-
-root.removeSingleChildNodes = (tree) ->
-  if not tree.values?
-    return tree
-
-  if tree.values.length == 1
-    name = tree.key
-    node = removeSingleChildNodes(tree.values[0])
-    if not node.key or node.key.trim().length == 0
-      node.key = name
-    return node
-
-  for i, child of tree.values
-    tree.values[i] = removeSingleChildNodes(child)
-
-
-  ###
-  values = []
-  for i, child of tree.values
-    console.log("Check in '#{tree.key}' '"+child.key + "'")
-    if child.key.trim().length == 0  or child.values?.length == 1
-      console.log("Replace '#{tree.key}' '"+child.key+"' with " + child.values.length + " children: " + child.values.map((d)->d.key).join(","))
-      for c in child.values
-        values.push removeSingleChildNodes(c)
-    else
-      values.push removeSingleChildNodes child
-
-    #res = removeSingleChildNodes(child)
-    #tree.values[i] = res
-  tree.values = values
-  ###
-
-  return tree
-
-
-
-
-
-
-
-root.provideWithTotalAmount = (tree) ->
-  if tree.amount or not tree.values? then return
-  total = 0
-  for child in tree.values
-    provideWithTotalAmount child
-    total += if child.amount then +child.amount else 0
-  tree.amount = total


Port MakeRandom to Process API

Port MakeRandom to Process API

--- components/MakeRandom.coffee
+++ components/MakeRandom.coffee
@@ -1,57 +1,28 @@
 noflo = require 'noflo'

-class MakeRandom extends noflo.Component
-  description: 'Make an array of random numbers'
-  icon: 'random'
-  constructor: ->
-    @min = null
-    @max = null
-    @count = null
-
-    @inPorts = new noflo.InPorts
-      min:
-        datatype: 'number'
-        required: true
-      max:
-        datatype: 'number'
-        required: true
-      count:
-        datatype: 'int'
-        required: true
-      # integer:
-      #   datatype: 'boolean'
-      #   required: false
-
-    @outPorts = new noflo.OutPorts
-      numbers:
-        datatype: 'array'
-
-    @inPorts.min.on 'data', (data) =>
-      @min = data
-      @compute()
-
-    @inPorts.max.on 'data', (data) =>
-      @max = data
-      @compute()
-
-    @inPorts.count.on 'data', (data) =>
-      @count = data
-      @compute()
-
-  compute: ->
-    return unless @outPorts.numbers.isAttached()
-    return unless @min? and @max? and @count? and @count >= 1
-
-    spread = @max - @min
-    if @count is 1
-      number = @min + Math.random()*spread
-      @outPorts.numbers.send number
-    else
-      numbers = []
-      for i in [0..@count-1]
-        numbers[i] = @min + Math.random()*spread
-      @outPorts.numbers.send numbers
-
-    @outPorts.numbers.disconnect()
-
-exports.getComponent = -> new MakeRandom
+exports.getComponent = ->
+  c = new noflo.Component
+  c.description = 'Make an array of random numbers'
+  c.icon = 'random'
+  c.inPorts.add 'min',
+    datatype: 'number'
+  c.inPorts.add 'max',
+    datatype: 'number'
+  c.inPorts.add 'count',
+    datatype: 'int'
+  c.outPorts.add 'numbers',
+    datatype: 'array'
+  c.process (input, output) ->
+    return unless input.hasData 'min', 'max', 'count'
+    [min, max, count] = input.getData 'min', 'max', 'count'
+    spread = max - min
+    if count is 1
+      number = min + Math.random()*spread
+      output.sendDone
+        numbers: [number]
+      return
+    numbers = []
+    for i in [0..count-1]
+      numbers[i] = min + Math.random()*spread
+    output.sendDone
+      numbers: numbers


Remove selector first() after render

Remove selector first() after render

--- source/core/output.coffee
+++ source/core/output.coffee
@@ -38,7 +38,7 @@

     @_createIfBindings()
     # Public attributes
-    @el = Atoms.$(@_mustache(@constructor.template)(@attributes)).first()
+    @el = Atoms.$(@_mustache(@constructor.template)(@attributes))
     @el.attr "data-#{@constructor.type}", @constructor.name.toLowerCase()
     # Attributes for constructor
     @constructor.parent = Atoms.$(@attributes.parent).first()


[staging-config] changed neo4j address

[staging-config] changed neo4j address

--- config/main.staging.coffee
+++ config/main.staging.coffee
@@ -30,8 +30,8 @@
     enabled     : yes
     port        : 1337
   neo4j         :
-    read        : "neo4j-staging.in.koding.com"
-    write       : "neo4j-staging.in.koding.com"
+    read        : "neo4j-dev.in.koding.com"
+    write       : "neo4j-dev.in.koding.com"
     port        : 7474
   mongo         : 'dev:k9lc4G1k32nyD72@mongodb-staging.in.koding.com:27017/koding'
   runNeo4jFeeder: yes


only enable express' static file functionality when we're in the testing environment

--- server/code/index.coffee
+++ server/code/index.coffee
@@ -143,8 +143,9 @@

   # Add Connect Assets
   app.use assets({src: 'client'})
-  # Set the public folder as static assets
-  app.use express.static(process.cwd() + '/shared')
+  if not process.env.NODE_ENV
+    # Set the public folder as static assets
+    app.use express.static(process.cwd() + '/shared')

 passport.use 'local', new LocalStrategy(verify)


remove nodetime to fix botched rebase

remove nodetime to fix botched rebase

--- server/code/index.coffee
+++ server/code/index.coffee
@@ -235,8 +235,7 @@
   # is served statically by nginx, so this has no effect. It's
   # used in dev, and not harmful in production.
   app.use express.static(process.cwd() + '/shared')
-  if process.env.NODETIME_KEY
-    app.use nodetimeLog
+
   if true or process.env.CU_REQUEST_LOG
     app.use requestLog


[♻] Cleaned up `shady`.

[♻] Cleaned up `shady`.

--- vendor/assets/javascripts/jquery/plugins/shadify/shady.js.coffee
+++ vendor/assets/javascripts/jquery/plugins/shadify/shady.js.coffee
@@ -244,10 +244,8 @@
       @element.addClass 'no-renderer-found'
     else
       @container = @element[0]
-
-      @now   = do Date.now
-      @start = do Date.now
-
+      @now       = do Date.now
+      @start     = do Date.now
       @center    = do FSS.Vector3.create
       @attractor = do FSS.Vector3.create

@@ -301,8 +299,7 @@
     do @renderer.clear

     # Create some geometry (`width`, `height`, `segments`, `slices`) & a material, pass them to mesh constructor, and
-    # add the mesh to the scene
-
+    # add the mesh to the scene.
     @geometry = new FSS.Plane(
       @rendering.mesh.width * @renderer.width
       @rendering.mesh.height * @renderer.height
@@ -358,7 +355,6 @@

     while l < @rendering.light.count
       light = new FSS.Light @rendering.light.ambient, @rendering.light.diffuse
-
       light.ambientHex = do light.ambient.format
       light.diffuseHex = do light.diffuse.format

@@ -372,7 +368,6 @@

       # Ring SVG Circle
       light.ring = document.createElementNS FSS.SVGNS, 'circle'
-
       light.ring.setAttributeNS null, 'stroke', light.ambientHex
       light.ring.setAttributeNS null, 'stroke-width', '0.5'
       light.ring.setAttributeNS null, 'fill', 'none'
@@ -380,7 +375,6 @@

       # Core SVG Circle
       light.core = document.createElementNS FSS.SVGNS, 'circle'
-
       light.core.setAttributeNS null, 'fill', light.diffuseHex
       light.core.setAttributeNS null, 'r', '4'


fix the plan details logic such that re-publishing published plans will show details

--- src/components/course-calendar/plan-details.cjsx
+++ src/components/course-calendar/plan-details.cjsx
@@ -78,18 +78,19 @@
       {viewOrEdit} {assignmentOrEvent}
     </Router.Link>

-    body = if isPublishing
-
This plan is publishing.

-    else if type is 'event'
-      <EventModalShell id={id} courseId={courseId} />
-    else
-      <StatsModalShell id={id} courseId={courseId} />
-
-    footer = unless isPublishing
-

+    body = if isPublished
+      footer =

         {reviewButton}
         {editButton}

+
+      if type is 'event'
+        <EventModalShell id={id} courseId={courseId} />
+      else
+        <StatsModalShell id={id} courseId={courseId} />
+
+    else if isPublishing
+
This plan is publishing.

     classes = classnames 'plan-modal', className,
       'in': keepVisible


Disable the HTTP server during tests

Disable the HTTP server during tests

--- test/kerb-test.coffee
+++ test/kerb-test.coffee
@@ -13,10 +13,9 @@
       .reply(200, [{title: 'black', attributes: ['colour']}])
       .get('/data/animals.json')
       .reply(200, [{title: 'bat', attributes: ['air', 'mammal']}])
-    @room = helper.createRoom(http: false)
+    @room = helper.createRoom(httpd: false)

   afterEach ->
-    @room.destroy()
     nock.cleanAll()

   context 'when the user supplies an invalid date', ->


virtual-device model

virtual-device model

--- src/controllers/virtual-config-controller.coffee
+++ src/controllers/virtual-config-controller.coffee
@@ -1,62 +1,20 @@
 _           = require 'lodash'
 debug       = require('debug')('shadow-service:virtual-config-controller')
 MeshbluHttp = require 'meshblu-http'
-
-OMITTED_FIELDS = [
-  'uuid'
-  'meshblu'
-  'owner'
-  'type'
-  'name'
-  'token'
-  'sendWhitelist'
-  'receiveWhitelist'
-  'configureWhitelist'
-  'discoverWhitelist'
-  'sendBlacklist'
-  'recieveBlacklist'
-  'configureBlacklist'
-  'discoverBlacklist'
-  'sendAsWhitelist'
-  'receiveAsWhitelist'
-  'configureAsWhitelist'
-  'discoverAsWhitelist'
-  'shadowing'
-  'shadows'
-  'geo'
-  'hash'
-  'ip'
-]
+VirtualDevice = require '../models/virtual-device'

 class VirtualConfigController
   update: (request, response) =>
-    return response.sendStatus 204 unless request.body.shadowing?.uuid?
+    meshbluConfig     = request.meshbluAuth
+    realDeviceUuid    = request.body.shadowing?.uuid
+    virtualDeviceUuid = request.body.uuid
+    virtualDevice     = new VirtualDevice {meshbluConfig}

-    realDeviceUuid   = request.body.shadowing.uuid
-    virtualDeviceUuid = request.body.uuid
-
-    debug 'virtualDevice: updateReal'
-
-    meshbluHttp = new MeshbluHttp request.meshbluAuth
-    meshbluHttp.device virtualDeviceUuid, (error, virtualDevice) =>
+    virtualDevice.updateRealDevice {virtualDeviceUuid, realDeviceUuid}, (error) =>
       return @sendError {response, error} if error?
-
-      virtualDeviceConfig = _.omit virtualDevice, OMITTED_FIELDS
-      meshbluHttp.device realDeviceUuid, (error, realDevice) =>
-        return @sendError {response, error} if error?
-
-        realDeviceConfig = _.omit realDevice, OMITTED_FIELDS
-        return response.sendStatus(204) if _.isEqual virtualDeviceConfig, realDeviceConfig
-
-        meshbluHttp.update realDeviceUuid, virtualDeviceConfig, (error) =>
-          return @sendError {response, error} if error?
-          debug "204: update success"
-          response.sendStatus(204)
+      response.sendStatus 204

   sendError: ({response,error}) =>
-    debug "500: #{error.message}" unless error.code?
-    return response.status(500).send error.message unless error.code?
-    debug "#{error.code}: #{error.message}"
-    return response.status(error.code).send error.message
+    return response.status(error.code || 500).send error.message

 module.exports = VirtualConfigController


fixed code style on servers.lib.crawlers.staticpages.styleblock.coffee

--- servers/lib/crawler/staticpages/styleblock.coffee
+++ servers/lib/crawler/staticpages/styleblock.coffee
@@ -1,3 +1,4 @@
+# coffeelint: disable=no_unnecessary_double_quotes
 module.exports = ->
   """
   <meta charset="utf-8" />


Added minification-safe boilerplate to the focus service.

--- resources/assets/scripts/app/services/focus.coffee
+++ resources/assets/scripts/app/services/focus.coffee
@@ -19,8 +19,9 @@
 # using a jQuery selector.
 #
 # Based on: https://stackoverflow.com/a/25597540/3225811
-angular.module('ponyfm').factory 'focus', ($timeout, $window) ->
+angular.module('ponyfm').factory('focus', ['$timeout', '$window', ($timeout, $window) ->
     (selector) ->
         $timeout () ->
             element = $window.jQuery("#{selector}")
             element.focus() # will do nothing if the selector doesn't select anything
+])


Emitted SwitchStateChange event in KDOnOffSwitch.

--- client/Framework/components/inputs/KDOnOffSwitch.coffee
+++ client/Framework/components/inputs/KDOnOffSwitch.coffee
@@ -62,6 +62,7 @@

   switchStateChanged:()->
     # log "new state of #{@getName()} is #{@getValue()}",@getCallback()?
+    @emit 'SwitchStateChanged', @getValue()
     @getCallback().call @,@getValue() if @getCallback()?

   mouseDown:(event)->


Login: reset from error handling fixed

Login: reset from error handling fixed

--- client/landing/site.landing/coffee/login/AppView.coffee
+++ client/landing/site.landing/coffee/login/AppView.coffee
@@ -257,9 +257,10 @@
       url       : '/Reset'
       data      : { recoveryToken, password }
       type      : 'POST'
-      error     : ->
-        new KDNotificationView
-          title : "An error occurred: #{err.message}"
+      error     : (xhr) =>
+        {responseText} = xhr
+        @resetForm.button.hideLoader()
+        new KDNotificationView title : responseText
       success   : =>
         @resetForm.button.hideLoader()
         @resetForm.reset()


Fix formatting in model spec

Fix formatting in model spec

--- spec/brainstem-model-spec.coffee
+++ spec/brainstem-model-spec.coffee
@@ -80,7 +80,8 @@
           name: 'tasks',
           parse: true,
           error: jasmine.any(Function),
-          cache: false, returnValues: jasmine.any(Object)
+          cache: false,
+          returnValues: jasmine.any(Object)
         }
       )


Improve examples

Improve examples

--- spec/components/card.cjsx
+++ spec/components/card.cjsx
@@ -25,23 +25,24 @@
     text  = "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
     legend = "Lorem Ipsum is simply dummy text"

-
Card

+
Cards

+

Basic properties

       <Card title="Default Card" />
       <Card title="Default Card with text" text={text} />
       <Card title="Default Card with legend" legend={legend} />
       <Card title="Default Card with actions" actions={actions} />
-      <Card title="Defaulr Card with image" text={text} legend={legend}
+      <Card title="Defaulr Card with text & image" text={text}
             image="http://cdn.tapquo.com/photos/soyjavi.jpg" />
-      <Card title="Default Card with color and onClick event"
-            text={text} legend={legend} color="#e91e63" onClick={@onClick} />
+      <Card title="Default Card with text, color & onClick event" text={text}
+            color="#e91e63" onClick={@onClick} />

Sizes using type property

-      <Card type="small" title="Small Card"
-            text={text} legend={legend} color="#00bcd4" onClick={@onClick} />
-      <Card type="square" title="Square Card"
-            text={text} legend={legend} color="#00bcd4" onClick={@onClick} />
-      <Card type="wide" title="Wide card"
-            text={text} legend={legend} color="#00bcd4" onClick={@onClick} />
+      <Card type="small" title="Small Card with text & onClick event"
+            text={text} color="#00bcd4" onClick={@onClick} />
+      <Card type="square" title="Square Card with text & onClick event"
+            text={text} color="#00bcd4" onClick={@onClick} />
+      <Card type="wide" title="Wide card with text & onClick event"
+            text={text} color="#00bcd4" onClick={@onClick} />


Use `atom.activatePackage` directly in specs

--- spec/command-palette-spec.coffee
+++ spec/command-palette-spec.coffee
@@ -9,7 +9,7 @@
   beforeEach ->
     window.rootView = new RootView
     rootView.open('sample.js')
-    window.loadPackage("command-palette")
+    atom.activatePackage("command-palette")
     rootView.attachToDom().focus()
     rootView.trigger 'command-palette:toggle'
     palette = rootView.find('.command-palette').view()


Return a clone of @buffers from Project.getBuffers

Previously, we traversed the EditSessions. Not necessary.

--- src/app/project.coffee
+++ src/app/project.coffee
@@ -190,10 +190,7 @@
   #
   # Returns an {Array} of {Buffer}s.
   getBuffers: ->
-    buffers = []
-    for editSession in @editSessions when not _.include(buffers, editSession.buffer)
-      buffers.push editSession.buffer
-    buffers
+    new Array(@buffers...)

   # Given a file path, this retrieves or creates a new {Buffer}.
   #


Only relativize stuff under the project root

--- src/app/project.coffee
+++ src/app/project.coffee
@@ -87,6 +87,7 @@
     fs.absolute filePath

   relativize: (fullPath) ->
+    return fullPath unless fullPath.lastIndexOf(@getPath()) is 0
     fullPath.replace(@getPath(), "").replace(/^\//, '')

   getSoftTabs: -> @softTabs


test vim-mode tile content in status-bar

Signed-off-by: Max Brunsfeld <78036c9b69b887700d5846f26a788d53b201ffbb@gmail.com>

--- spec/vim-mode-spec.coffee
+++ spec/vim-mode-spec.coffee
@@ -1,16 +1,20 @@
 {Workspace} = require 'atom'

 describe "VimMode", ->
-  [editor, editorElement] = []
+  [editor, editorElement, workspaceElement] = []

   beforeEach ->
     atom.workspace = new Workspace
+    workspaceElement = atom.views.getView(atom.workspace)

     waitsForPromise ->
       atom.workspace.open()

     waitsForPromise ->
       atom.packages.activatePackage('vim-mode')
+
+    waitsForPromise ->
+      atom.packages.activatePackage('status-bar')

     runs ->
       editor = atom.workspace.getActiveTextEditor()
@@ -20,6 +24,12 @@
     it "puts the editor in command-mode initially by default", ->
       expect(editorElement.classList.contains('vim-mode')).toBe(true)
       expect(editorElement.classList.contains('command-mode')).toBe(true)
+
+    it "shows the current vim mode in the status bar", ->
+      statusBarTile = workspaceElement.querySelector("#status-bar-vim-mode")
+      expect(statusBarTile.textContent).toBe("Command")
+      atom.commands.dispatch(editorElement, "vim-mode:activate-insert-mode")
+      expect(statusBarTile.textContent).toBe("Insert")

     it "doesn't register duplicate command listeners for editors", ->
       editor.setText("12345")


They can just hit save, no?

They can just hit save, no?

--- spec/symbol-provider-spec.coffee
+++ spec/symbol-provider-spec.coffee
@@ -149,19 +149,3 @@
       editor.insertText('somēthingNew')
       editor.insertText(' ')
       expect(provider.symbolList.indexOf('somēthingNew')).not.toEqual(-1)
-
-    # Fixing This Fixes #196
-    xit 'removes words from the wordlist when they no longer exist in any open buffers', ->
-      # Not sure we should fix this; could have a significant performance impacts
-      provider = autocompleteManager.providerManager.fuzzyProvider
-
-      expect(provider.symbolList.indexOf('bogos')).toEqual(-1)
-      editor.insertText('bogos = 1')
-      editor.insertText(' ')
-      expect(provider.symbolList.indexOf('bogos')).not.toEqual(-1)
-      expect(provider.symbolList.indexOf('bogus')).toEqual(-1)
-      editor.backspace() for [1..7]
-      editor.insertText('us = 1')
-      editor.insertText(' ')
-      expect(provider.symbolList.indexOf('bogus')).not.toEqual(-1)
-      expect(provider.symbolList.indexOf('bogos')).toEqual(-1)


Connect editor to highlighter change events

--- src/atom/editor.coffee
+++ src/atom/editor.coffee
@@ -121,6 +121,9 @@
       @setCursorPosition(row: 0, column: 0)

       @buffer.on 'change', (e) =>
+        @cursor.bufferChanged(e)
+
+      @highlighter.on 'change', (e) =>
         { preRange, postRange } = e

         if postRange.end.row > preRange.end.row
@@ -138,8 +141,6 @@
             else
               @updateLineElement(row)

-        @cursor.bufferChanged(e)
-
     updateLineElement: (row) ->
       @getLineElement(row).replaceWith(@buildLineElement(row))


Define backspace and delete in terms of deleteLeft and deleteRight.

--- src/atom/editor.coffee
+++ src/atom/editor.coffee
@@ -3,6 +3,7 @@
 Point = require 'point'
 Cursor = require 'cursor'
 Selection = require 'selection'
+Range = require 'range'
 $ = require 'jquery'
 $$ = require 'template/builder'
 _ = require 'underscore'
@@ -41,8 +42,8 @@
         'shift-up': 'select-up'
         'shift-down': 'select-down'
         enter: 'newline'
-        backspace: 'backspace'
-        delete: 'delete'
+        backspace: 'delete-left'
+        delete: 'delete-right'
         'meta-c': 'copy'

       @on 'move-right', => @moveCursorRight()
@@ -54,8 +55,8 @@
       @on 'select-up', => @selectUp()
       @on 'select-down', => @selectDown()
       @on 'newline', =>  @insertNewline()
-      @on 'backspace', => @backspace()
-      @on 'delete', => @delete()
+      @on 'delete-left', => @deleteLeft()
+      @on 'delete-right', => @deleteRight()
       @on 'copy', => @copySelection()

@@ -191,11 +192,18 @@
     selectLeft: -> @selection.selectLeft()
     selectUp: -> @selection.selectUp()
     selectDown: -> @selection.selectDown()
-    selectToPosition: (position) -> @selection.selectToPosition(position)
+    selectToPosition: (position) ->
+      @selection.selectToPosition(position)

     insertText: (text) -> @selection.insertText(text)
     insertNewline: -> @selection.insertNewline()
-    backspace: -> @selection.backspace()
-    delete: -> @selection.delete()
     copySelection: -> @selection.copy()

+    deleteLeft: ->
+      @selectLeft() if @selection.isEmpty()
+      @selection.delete()
+
+    deleteRight: ->
+      @selectRight() if @selection.isEmpty()
+      @selection.delete()
+


Added tests for array routing

Added tests for array routing

--- tests/routes.coffee
+++ tests/routes.coffee
@@ -85,12 +85,21 @@
       @get '/string/:id', load_user, -> 'string'
       @get '/return/:id', load_user, -> 'return'
       @get '/send/:id', load_user, -> @send 'send'
+
+      @get '/string1/:id': [load_user, -> 'string']
+      @get '/return1/:id': [load_user, -> 'return']
+      @get '/send1/:id': [load_user, -> @send 'send']

     c = t.client(zapp.server)
     c.get '/string/bob', (err, res) -> t.equal 1, res.body, 'string'
     c.get '/return/bob', (err, res) -> t.equal 2, res.body, 'return'
     c.get '/send/bob', (err, res) -> t.equal 3, res.body, 'send'
     c.get '/send/bar', (err, res) -> t.equal 3, res.body, 'Failed to load user bar'
+
+    c.get '/string1/bob', (err, res) -> t.equal 1, res.body, 'string'
+    c.get '/return1/bob', (err, res) -> t.equal 2, res.body, 'return'
+    c.get '/send1/bob', (err, res) -> t.equal 3, res.body, 'send'
+    c.get '/send1/bar', (err, res) -> t.equal 3, res.body, 'Failed to load user bar'

   methods: (t) ->
     t.expect [1..6]...


atom-latex: uninstall

atom-latex: uninstall


Fixed dictionary instantiation in set constructor

--- src/builtin/set.coffee
+++ src/builtin/set.coffee
@@ -1,7 +1,7 @@
 # http://docs.python.org/library/stdtypes.html#set-types-set-frozenset
 class Set extends Iterable
   constructor: (iterable) ->
-    @value = Dictionary() # set just is a wrapped version of our own Dictionary class
+    @value = Dict() # set just is a wrapped version of our own Dict class
     for item in iterable?.value # Handles empty constructor call too
       @value.__setitem__(item, true)


added negative warp test

added negative warp test

--- test/driver/wikiDay.mocha.coffee
+++ test/driver/wikiDay.mocha.coffee
@@ -757,3 +757,89 @@
         }
       ]
     }
+
+    it "should work with a time split, negative warp (sort on time)", testEquality {
+      drivers: ['druid', 'mySql']
+      query: [
+        {
+          operation: 'dataset'
+          name: 'futureDate'
+          source: 'base'
+          filter: {
+            operation: 'filter'
+            type: 'within'
+            attribute: 'time'
+            range: [
+              new Date("2013-02-26T12:00:00Z")
+              new Date("2013-02-27T00:00:00Z")
+            ]
+          }
+        }
+        {
+          operation: 'dataset'
+          name: 'currentData'
+          source: 'base'
+          filter: {
+            operation: 'filter'
+            type: 'within'
+            attribute: 'time'
+            range: [
+              new Date("2013-02-26T00:00:00Z")
+              new Date("2013-02-26T12:00:00Z")
+            ]
+          }
+        }
+        {
+          operation: 'split'
+          name: 'TimeByHour'
+          bucket: 'parallel'
+          splits: [
+            {
+              dataset: 'futureDate'
+              bucket: 'timePeriod'
+              attribute: 'time'
+              timezone: 'Etc/UTC'
+              period: 'PT1H'
+              warp: 'PT12H'
+              warpDirection: -1
+            }
+            {
+              dataset: 'currentData'
+              bucket: 'timePeriod'
+              attribute: 'time'
+              timezone: 'Etc/UTC'
+              period: 'PT1H'
+            }
+          ]
+        }
+        {
+          operation: 'apply'
+          name: 'EditsDiff'
+          arithmetic: 'subtract'
+          operands: [
+            {
+              dataset: 'currentData'
+              arithmetic: 'divide'
+              operands: [
+                { aggregate: 'sum', attribute: 'count' }
+                { aggregate: 'constant', value: 2 }
+              ]
+            }
+            {
+              dataset: 'futureDate'
+              arithmetic: 'divide'
+              operands: [
+                { aggregate: 'sum', attribute: 'count' }
+                { aggregate: 'constant', value: 2 }
+              ]
+            }
+          ]
+        }
+        {
+          operation: 'combine'
+          method: 'slice'
+          sort: { prop: 'TimeByHour', compare: 'natural', direction: 'ascending' }
+        }
+      ]
+    }
+


stop calling preventDefault on event if it isn't present

--- shared/src/components/question/answers-table.cjsx
+++ shared/src/components/question/answers-table.cjsx
@@ -77,7 +77,7 @@
       @setState(answer_id: answer.id)
       @props.onChange(answer)
     else
-      changeEvent.preventDefault()
+      changeEvent?.preventDefault()
       @props.onChangeAttempt?(answer)

   shouldInstructionsShow: ->


Fix rendering on invisible container

Fix rendering on invisible container

Don't continue resizing if the container has invalid size.

--- resources/assets/coffee/_classes/line-chart.coffee
+++ resources/assets/coffee/_classes/line-chart.coffee
@@ -104,10 +104,12 @@
   setDimensions: =>
     areaDims = @area.node().getBoundingClientRect()

-    return unless areaDims.width > 0 && areaDims.height > 0
+    return false unless areaDims.width > 0 && areaDims.height > 0

     @width = areaDims.width - (@margins.left + @margins.right)
     @height = areaDims.height - (@margins.top + @margins.bottom)
+
+    true

   setScalesRange: =>
@@ -251,7 +253,9 @@

   resize: =>
-    @setDimensions()
+    hasDimensions = @setDimensions()
+
+    return unless hasDimensions

     @setScalesRange()


Change commands from string to array.

Change commands from string to array.

--- indexer.coffee
+++ indexer.coffee
@@ -16,7 +16,7 @@
 		result = {}
 		conda_output = child_process.execSync ' conda search ".*" --names-only '
 		names = conda_output.toString().split('\n').slice(1)  # skip first line of output
-		(result[name] = {name: name, description: null, url: null, summary: null,command: "conda install -y #{name}"} for name in names)
+		(result[name] = {name: name, description: null, url: null, summary: null,command: ["conda", "install", "-y", name]} for name in names)
 		return result

 	getPipPackages: (callback) ->
@@ -54,7 +54,7 @@
 							description: p?.details?.info.description
 							url: p?.details?.info.package_url
 							summary: p?.details?.info.summary
-							command: "pip install '#{p.name}'"
+							command: ["pip", "install", p.name]
 					callback null, packages
 			)

@@ -112,7 +112,7 @@
 					summary: summary
 					description: null
 					url: null
-					command: "sudo apt-get install #{name}"
+					command: ["sudo", "apt-get", "install", name]
 				}
 		result = {}
 		for p in _.without(packages, undefined)
@@ -132,13 +132,12 @@
 				summary: row.Title
 				description: row.Description
 				url: "https://cran.rstudio.com/web/packages/#{row.Package}/index.html"
-				command: """
-					sudo Rscript -e '
-						installPackages(#{row.Package});
-						suppressMessages(suppressWarnings(if(!require('#{row.Package}')) {
-							stop('Could not load package', call.=FALSE)
-						}))
-				"""
+				command: [
+					"sudo", "Rscript", "-e", "install.packages('#{$scope.installedPackage}');
+					suppressMessages(suppressWarnings(if(!require('#{$scope.installedPackage}')) {
+						stop('Could not load package', call.=FALSE)
+					}))"
+				]
 			result = {}
 			for p in packages
 				result[p.name] = p


throw Error if condition fails in fetcher

--- shared/fetcher.coffee
+++ shared/fetcher.coffee
@@ -160,6 +160,7 @@
     # Also support getting all models for a collection.
     else if summary.collection?
       collectionData = collectionStore.get(summary.collection, summary.params)
+      throw new Error("Collection of type \"#{summary.collection}\" not found for params: #{JSON.stringify(summary.params)}") unless collectionData?
       models = retrieveModelsForCollectionName(summary.collection, collectionData.ids)
       options =
         params: summary.params


Add # Multi-thread support

Add # Multi-thread support

--- server/app.coffee
+++ server/app.coffee
@@ -37,6 +37,7 @@

   cluster.on 'exit', (worker, code, signal)->
     console.log "Worker #{worker.process.pid} died."
+    cluster.fork()

 else


max size for post to 100MB

max size for post to 100MB

--- server/app.coffee
+++ server/app.coffee
@@ -12,7 +12,7 @@
     FORM_OPTIONS =
             keepExtensions : true
             uploadDir : basedir + "/tmp" #minimum global option (default is root tmp "/tmp")
-            maxFieldsSize : 2 * 1024 * 1024
+            maxFieldsSize : 100 * 1024 * 1024
             encoding : "utf-8"

     app = express.createServer(form(FORM_OPTIONS))


create Documents dir before copying files to it

--- docset.coffee
+++ docset.coffee
@@ -20,6 +20,7 @@
 </html>
 """
 # copy CSS files
+fs.mkdirSync PATH
 fs.writeFileSync "#{PATH}/github-markdown.css",
   fs.readFileSync('node_modules/github-markdown-css/github-markdown.css')
 fs.writeFileSync "#{PATH}/github-highlight.css",


checking job interval

checking job interval

--- server/job.coffee
+++ server/job.coffee
@@ -389,7 +389,7 @@
     match = must_not:[{term:{available:false}}] # TODO check this will get matched properly to something where available = false
     match.must_not.push({term: 'group.exact':g}) for g of API.job._ignoregroups
     match.must_not.push({term: '_id.exact':m}) for m of API.job._ignoreids
-    #console.log(JSON.stringify match) if API.settings.dev
+    console.log(JSON.stringify match) if API.settings.dev
     p = job_process.find match, {sort:{priority:{order:'desc'}}, random:true} # TODO check if random sort works - may have to be more complex
     if p?
       if job_processing.get(p._id)? # because job_process is searched, there can be a delay before it reflects deleted jobs, so accept this extra load on ES


change to job completion default alert email

--- server/job.coffee
+++ server/job.coffee
@@ -527,7 +527,7 @@
     catch
       if job.group isnt 'JOBTEST'
         text = 'Job ' + (if job.name then job.name else job._id) + ' is complete.'
-        email = job.email ? job.user and API.accounts.retrieve(job.user)?.emails[0].address
+        email = job.email ? API.accounts.retrieve(job.user)?.emails[0].address
         API.mail.send to:email, subject:text, text:text
   return true


Create test for semicolon adaptation

Create test for semicolon adaptation

--- test/src/ctest.coffee
+++ test/src/ctest.coffee
@@ -284,6 +284,60 @@
     )
   ]

+asyncTest 'Controller: ANTLR paren wrap rules for C semicolons', ->
+  window.editor = editor = new droplet.Editor(document.getElementById('test-main'), {
+    mode: 'c',
+    palette: []
+  })
+
+  editor.setValue '''
+    int main() {
+      puts("Hello");
+      puts("World");
+    }
+  '''
+
+  executeAsyncSequence [
+    (->
+      pickUpLocation editor, 0, {
+        row: 1
+        col: 2
+        type: 'block'
+      }
+      dropLocation editor, 0, {
+        row: 2
+        col: 7
+        type: 'socket'
+      }
+    ), (->
+      equal editor.getValue(), '''
+      int main() {
+        puts(puts("Hello"));
+      }\n
+      ''', 'Removed semicolon dropping function into other function'
+    ), (->
+      pickUpLocation editor, 0, {
+        row: 1
+        col: 7
+        type: 'block'
+      }
+      dropLocation editor, 0, {
+        row: 1
+        col: 2
+        type: 'block'
+      }
+    ), (->
+      equal editor.getValue(), '''
+      int main() {
+        puts("World");
+        puts("Hello");
+      }\n
+      ''', 'Added semicolon dropping function into block'
+
+      start()
+    )
+  ]
+
 asyncTest 'Controller: ANTLR reparse rules', ->
   document.getElementById('test-main').innerHTML = ''
   window.editor = editor = new droplet.Editor(document.getElementById('test-main'), {


Check for brackets and quotes when matching Pic labels

If a function-call contains a string with a colon, and no whitespace was
used to separate the arguments, it broke the highlighting of the rest of
the document. For example: object(ACT,"SSE: CalAct");

--- grammars/pic.cson
+++ grammars/pic.cson
@@ -343,7 +343,7 @@

 	# Labelled position
 	label:
-		match: "([A-Z][^#\\s:]*)(:)"
+		match: "([A-Z][^#(\"\\s:]*)(:)"
 		captures:
 			1: name: "storage.type.label.pic"
 			2: name: "punctuation.separator.key-value.pic"


AA :: Call emoticonize_me() function to show smiley transformation in form hint

--- vendor/assets/javascripts/active_admin.js.coffee
+++ vendor/assets/javascripts/active_admin.js.coffee
@@ -36,6 +36,8 @@

 $ ->
   $.datetimepicker.setLocale('fr')
+
+  emoticonize_me()

   if $('#newsletter_setting_send_welcome_email').length
     $this = $('#newsletter_setting_send_welcome_email')


NEW class-method: getConcreteProps

NEW class-method: getConcreteProps

--- source/Art/Engine/Core/EpochedElementMixin.coffee
+++ source/Art/Engine/Core/EpochedElementMixin.coffee
@@ -481,6 +481,10 @@
               ret[k] = value
       ret

+  @getConcreteProps: ->
+    for k, mp of @getMetaProperties() when !mp.virtual
+      k
+
   ##########################
   # OVERRIDES
   ##########################


:art: cleanup!

:art: cleanup!

--- lib/visual-blockwise.coffee
+++ lib/visual-blockwise.coffee
@@ -9,20 +9,19 @@
   @extend()
   complete: true

-  clearTail: ->
+  eachSelection: (fn) ->
     for s in @editor.getSelections()
-      @updateProperty(s, {tail: false})
+      fn(s)

-  clearHead: ->
-    for s in @editor.getSelections()
-      @updateProperty(s, {head: false})
-      s.cursor.setVisible(false)
-
-  updateProperty: (selection, prop) ->
-    swrap(selection).updateProperties(blockwise: prop)
+  updateProperties: ({head, tail}) ->
+    @eachSelection (s) ->
+      prop = {}
+      prop.head = (s is head) if head?
+      prop.tail = (s is tail) if tail?
+      swrap(s).updateProperties(blockwise: prop)

   getTop: ->
-    _.first @editor.getSelectionsOrderedByBufferPosition()
+    @editor.getSelectionsOrderedByBufferPosition()[0]

   getBottom: ->
     _.last @editor.getSelectionsOrderedByBufferPosition()
@@ -32,7 +31,6 @@
       false
     else
       @getTail() is @getBottom()
-      # @getTail().marker.isEqual @getBottom().marker

   isSingleLine: ->
     @editor.getSelections().length is 1
@@ -41,33 +39,18 @@
     if @isReversed() then @getTop() else @getBottom()

   getTail: ->
-    _.detect @editor.getSelections(), ((s) -> swrap(s).isBlockwiseTail())
+    _.detect @editor.getSelections(), (s) -> swrap(s).isBlockwiseTail()

-  setTail: (newTail) ->
-    @clearTail()
-    @updateProperty(newTail, tail: true)
-
-  # Only for making cursor visible.
-  setHead: (newHead) ->
-    @clearHead()
-    @updateProperty(newHead, head: true)
-
-  constructor: ->
-    super
+  initialize: ->
+    # PlantTail
     unless @getTail()?
-      @setTail @getTop()
-      @setHead @getBottom()
-
-  reverse: ->
-    [newHead, newTail] = [@getTail(), @getHead()]
-    @setTail newTail
-    @setHead newHead
+      @updateProperties {tail: @getTop(), head: @getBottom()}

 class BlockwiseOtherEnd extends VisualBlockwise
   @extend()
   execute: ->
     unless @isSingleLine()
-      @reverse()
+      @updateProperties {tail: @getHead(), head: @getTail()}
     @vimState.reverseSelections()

 class BlockwiseMoveDown extends VisualBlockwise
@@ -83,7 +66,7 @@
       @vimState.syncSelectionsReversedState @getTail()
     else
       @getHead().destroy()
-    @setHead @getHead()
+    @updateProperties {head: @getHead()}

 class BlockwiseMoveUp extends BlockwiseMoveDown
   @extend()
@@ -95,8 +78,8 @@
   @extend()
   delegateTo: 'DeleteToLastCharacterOfLine'
   execute: ->
-    for s in @editor.getSelections()
-      start = s.getBufferRange().start
+    @eachSelection (s) ->
+      {start} = s.getBufferRange()
       s.cursor.setBufferPosition(start)
     @vimState.activate('normal')
     @new(@delegateTo).execute()
@@ -124,8 +107,8 @@
         cursorsAdjusted.push cursor
       cursor.setBufferPosition(pointTarget)

-    for selection in @editor.getSelections()
-      adjustCursor(selection)
+    @eachSelection (s) ->
+      adjustCursor(s)
     @vimState.activate('normal')
     @vimState.activate('insert')


remove test for google maps api

remove test for google maps api

--- spec/javascripts/lib/maps/map_manager_spec.coffee
+++ spec/javascripts/lib/maps/map_manager_spec.coffee
@@ -1,4 +1,4 @@
-require ['public/assets/javascripts/lib/maps/map_manager', 'gpt'], (MapManager) ->
+require ['public/assets/javascripts/lib/maps/map_manager'], (MapManager) ->

   describe 'MapManager', ->

@@ -10,19 +10,6 @@
     describe 'object', ->
       it 'is defined', ->
         expect(MapManager).toBeDefined()
-
-    describe 'on page load:', ->
-      beforeEach ->
-        loadFixtures('map_manager.html')
-        window.mapManager = new MapManager
-          centerTrigger: '.js-map-center-trigger'
-          centerDelay: 500
-          minimalUI: true
-
-      it 'Loads successfully', ->
-        waitsFor ->
-          return !$('#js-map-canvas').hasClass('is-loading')
-        , '`is-loading` class to be removed', 10000

     describe 'event based load:', ->
       beforeEach ->


Updated util test to support new line regex.

--- test/util_test.coffee
+++ test/util_test.coffee
@@ -22,6 +22,7 @@
       name:         'coffeescript'
       symbol:       '#'
       block:        '###'
+      lineRegex: /^\s*#{1,2}\s*(.*)/
       commentRegex: /^\s*#{1,2}\s*(?:@(\w+))?(?:\s*(.*))?/
       blockRegex:   /###/


Render errors during install

Render errors during install

--- client/source/views/install/firstuser.coffee
+++ client/source/views/install/firstuser.coffee
@@ -27,5 +27,5 @@

     @model.save(data).always( ->
       btn.ladda 'stop'
-    ).done ->
+    ).fail(@renderServerErrors).done ->
       toastr.success 'User created!'


Synchronize x-axis only

Synchronize x-axis only

--- app/script.coffee
+++ app/script.coffee
@@ -23,7 +23,7 @@

     allGraphs.push(@graph)
     synchronization.detach() if synchronization
-    synchronization = Dygraph.synchronize(allGraphs) if allGraphs.length > 1
+    synchronization = Dygraph.synchronize(allGraphs, {range: false}) if allGraphs.length > 1
     # @zoomLastMinutes 1440
     @graph


Update property

Update property

--- grunt/6to5.coffee
+++ grunt/6to5.coffee
@@ -1,7 +1,7 @@
 module.exports =
   options:
     sourceMap: true
-    loose: ['classes']
+    loose: ['es6.classes']
   dist:
     options:
       modules: 'amd'


Allow follow collection to be managed from outside the view

--- components/artist_fillwidth_list/view.coffee
+++ components/artist_fillwidth_list/view.coffee
@@ -10,13 +10,14 @@
   defaults:
     page: 1
     per: 10
+    syncFollows: true

   initialize: (options = {}) ->
-    { @user } = options
-    { @page, @per } = _.defaults @defaults, options
+    { @user, @following } = options
+    { @page, @per, @syncFollows } = _.defaults @defaults, options
     @$document = $(document)
     @user?.initializeDefaultArtworkCollection()
-    @following = new Following(null, kind: 'artist') if @user
+    @following = new Following(null, kind: 'artist') if @user and not @following?
     @

   fetchAndRender: =>
@@ -63,6 +64,7 @@
           fillwidthView.removeHiddenItems()

   syncFollowsOnAjaxStop: ->
+    return if not @syncFollows
     @$document.one 'ajaxStop', =>
       @following?.syncFollows @collection.pluck('id')


Tests: Fix pause timers.

Tests: Fix pause timers.

--- tests/src/helpers/helpers.coffee
+++ tests/src/helpers/helpers.coffee
@@ -81,7 +81,7 @@
       .click                  '[testpath=ActivityInputView]'
       .setValue               '[testpath=ActivityInputView]', post
       .click                  '[testpath=post-activity-button]'
-      .pause                  5000 # required
+      .pause                  6000 # required

     browser.assert.containsText '[testpath=ActivityListItemView]:first-child', post # Assertion

@@ -95,7 +95,7 @@
     browser
       .click        '[testpath=ActivityListItemView]:first-child [testpath=CommentInputView]'
       .setValue     '[testpath=ActivityListItemView]:first-child [testpath=CommentInputView]', comment + '\n'
-      .pause        5000 # required
+      .pause        6000 # required

     browser.assert.containsText  '[testpath=ActivityListItemView]:first-child .comment-body-container', comment # Assertion


Tests: Pricing: Payment: Added downgradeAccount test.

--- tests/src/pricing/payment.coffee
+++ tests/src/pricing/payment.coffee
@@ -45,4 +45,25 @@
             .end()

+  downgradeAccount: (browser) ->

+    helpers.beginTest(browser)
+    browser
+      .url                     helpers.getUrl() + '/Pricing'
+      .waitForElementVisible   '.content-page.pricing', 20000
+
+    helpers.selectPlan(browser, 'developer')
+
+    browser
+      .waitForElementVisible   '.payment-modal', 20000
+      .click                   '.payment-modal button'
+      .waitForElementVisible   '.payment-modal', 20000
+      .pause                   5000
+      .click                   '.payment-modal button'
+      .waitForElementVisible   '[testpath=main-sidebar]', 20000
+      .url                     helpers.getUrl() + '/Pricing'
+      .waitForElementVisible   '.content-page.pricing', 20000
+      .waitForElementVisible   '.single-plan.' + 'developer' + '.current', 20000
+      .end()
+
+


rename toCanvasXCoord() to toPixels()

rename toCanvasXCoord() to toPixels()

--- app/lib/canvas-graph.coffee
+++ app/lib/canvas-graph.coffee
@@ -290,11 +290,11 @@

       # draw ticks (bottom)
       @ctx.beginPath()
-      @ctx.moveTo( @toCanvasXCoord(tick)+@leftPadding, @canvas.height )
+      @ctx.moveTo( @toPixels(tick)+@leftPadding, @canvas.height )
       if i % majorTickInterval is 0
-        @ctx.lineTo( @toCanvasXCoord(tick)+@leftPadding, @canvas.height - tickMajorLength ) # major tick
+        @ctx.lineTo( @toPixels(tick)+@leftPadding, @canvas.height - tickMajorLength ) # major tick
       else
-        @ctx.lineTo( @toCanvasXCoord(tick)+@leftPadding, @canvas.height - tickMinorLength ) # minor tick
+        @ctx.lineTo( @toPixels(tick)+@leftPadding, @canvas.height - tickMinorLength ) # minor tick
       @ctx.lineWidth = tickWidth
       @ctx.strokeStyle = tickColor
       @ctx.stroke()
@@ -305,29 +305,29 @@

       # draw numbers (bottom)
       if (i % majorTickInterval) is 0 # zoomed out
-        @ctx.fillText( tick, @toCanvasXCoord(tick)+@leftPadding, @canvas.height - textSpacing )
+        @ctx.fillText( tick, @toPixels(tick)+@leftPadding, @canvas.height - textSpacing )
       else if (i % majorTickInterval) is 0
-        @ctx.fillText( tick, @toCanvasXCoord(tick)+@leftPadding, @canvas.height - textSpacing )
+        @ctx.fillText( tick, @toPixels(tick)+@leftPadding, @canvas.height - textSpacing )
       else if (i % majorTickInterval) is 0
-        @ctx.fillText( tick, @toCanvasXCoord(tick)+@leftPadding, @canvas.height - textSpacing )
+        @ctx.fillText( tick, @toPixels(tick)+@leftPadding, @canvas.height - textSpacing )

       # axis header
       @ctx.fillText( 'DAYS', textSpacing+10+@leftPadding, @canvas.height - textSpacing )

       # draw ticks (top)
       @ctx.beginPath()
-      @ctx.moveTo( @toCanvasXCoord(tick)+@leftPadding, 0 )
+      @ctx.moveTo( @toPixels(tick)+@leftPadding, 0 )
       if i % majorTickInterval is 0
-        @ctx.lineTo( @toCanvasXCoord(tick)+@leftPadding, 0 + tickMajorLength ) # major tick
+        @ctx.lineTo( @toPixels(tick)+@leftPadding, 0 + tickMajorLength ) # major tick
       else
-        @ctx.lineTo( @toCanvasXCoord(tick)+@leftPadding, 0 + tickMinorLength ) # minor tick
+        @ctx.lineTo( @toPixels(tick)+@leftPadding, 0 + tickMinorLength ) # minor tick
       @ctx.lineWidth = tickWidth
       @ctx.strokeStyle = tickColor
       @ctx.stroke()

       # top numbers
       if (i % 4) is 0 # zoomed out
-        @ctx.fillText( (tick + @originalMin).toFixed(2), @toCanvasXCoord(tick)+@leftPadding, 0 + textSpacing+10 )
+        @ctx.fillText( (tick + @originalMin).toFixed(2), @toPixels(tick)+@leftPadding, 0 + textSpacing+10 )

   drawYTickMarks: (yMin, yMax) ->

@@ -452,7 +452,7 @@

   clearCanvas: -> @ctx.clearRect(0,0,@canvas.width, @canvas.height)

-  toCanvasXCoord: (dataPoint) -> ((parseFloat(dataPoint) - parseFloat(@xMin)) / (parseFloat(@xMax) - parseFloat(@xMin))) * (parseFloat(@canvas.width)-parseFloat(@leftPadding))
+  toPixels: (dataPoint) -> ((parseFloat(dataPoint) - parseFloat(@xMin)) / (parseFloat(@xMax) - parseFloat(@xMin))) * (parseFloat(@canvas.width)-parseFloat(@leftPadding))
   toCanvasYCoord: (dataPoint) -> ((parseFloat(dataPoint) - parseFloat(@yMin)) / (parseFloat(@yMax) - parseFloat(@yMin))) * (parseFloat(@canvas.height))
   toDays: (canvasPoint) -> ((parseFloat(canvasPoint) / (parseFloat(@canvas.width)-parseFloat(@leftPadding))) * (parseFloat(@xMax) - parseFloat(@xMin))) + parseFloat(@xMin)
   toDataYCoord: (canvasPoint) -> ((parseFloat(canvasPoint) / parseFloat(@canvas.height)) * (parseFloat(@yMax) - parseFloat(@yMin))) + parseFloat(@yMin)
@@ -557,8 +557,8 @@
     @element.addEventListener 'mouseover', @onMouseOver
     @element.addEventListener 'mouseout', @onMouseOut

-  minWidth: -> parseFloat(@canvasGraph.toCanvasXCoord(0.5)) #15 * (@canvasGraph.scale || 1)
-  maxWidth: -> parseFloat(@canvasGraph.toCanvasXCoord(3))    # * (@canvasGraph.scale || 1)
+  minWidth: -> parseFloat(@canvasGraph.toPixels(0.5)) #15 * (@canvasGraph.scale || 1)
+  maxWidth: -> parseFloat(@canvasGraph.toPixels(3))    # * (@canvasGraph.scale || 1)
   handleWidth: -> 16 * (@canvasGraph.scale || 1)

   draw: (e) ->
@@ -572,11 +572,11 @@
     # no overlapping of marks
     markLeftX = Math.max markLeftX,
                         (@closestXBelow + @handleWidth() || markLeftX),
-                        (@canvasGraph.toCanvasXCoord(@canvasGraph.smallestX))
+                        (@canvasGraph.toPixels(@canvasGraph.smallestX))

     markRightX = Math.min markRightX,
                          (@closestXAbove - @handleWidth() || markRightX),
-                         (@canvasGraph.toCanvasXCoord(@canvasGraph.largestX))
+                         (@canvasGraph.toPixels(@canvasGraph.largestX))

     # max and min width on creating / resizing marks
     width = (Math.min (Math.max (Math.abs parseFloat(markRightX) - parseFloat(markLeftX)), parseFloat(@minWidth())), parseFloat(@maxWidth()))


Improve formatting on ArgumentError messages

--- app/lib/world/errors.coffee
+++ app/lib/world/errors.coffee
@@ -9,13 +9,13 @@
       Error.captureStackTrace @, @constructor

   toString: ->
-    s = "#{@functionName}"
+    s = "`#{@functionName}`"
     if @argumentName is 'return'
       s += "'s return value"
     else if @argumentName is '_excess'
       s += " takes only #{@numArguments} argument#{if @numArguments > 1 then 's' else ''}."
     else if @argumentName
-      s += "'s argument #{@argumentName}"
+      s += "'s argument `#{@argumentName}`"
     else
       s += ' takes no arguments.'

@@ -39,7 +39,7 @@
       else if @actualValue instanceof Vector
         v = @actualValue.toString()
       showValue = showValue or @actualValue instanceof Vector
-      s += " should have type #{@intendedType}, but got #{actualType}#{if v then ': ' + v else ''}."
+      s += " should have type `#{@intendedType}`, but got `#{actualType}`#{if v then ": `#{v}`" else ''}."
     else if @argumentName and @argumentName isnt '_excess'
       s += ' has a problem.'
     s += '\n' + @message if @message


Ensure we have graph ID

Ensure we have graph ID

--- src/RemoteSubGraph.coffee
+++ src/RemoteSubGraph.coffee
@@ -52,6 +52,7 @@

         noflo.graph.loadFile definition.graph, (err, graph) =>
           throw err if err
+          graph.properties.id = definition.graph unless graph.properties.id
           @setGraph graph, (err) ->
             throw err if err


test add anti-spam

test add anti-spam

--- site/js/script.coffee
+++ site/js/script.coffee
@@ -56,6 +56,7 @@
   section: "new"
   sectiontitle: type + ga_to_hash(getGoogleAnalyticsId())
   text: text
+  ct_checkjs: "cb2b2fb6bee3251f032a965d4a36e99b"
   summary: "Input from website"
   bot: ""
   token: api_key
@@ -104,4 +105,4 @@
   'Uranus', 'Utah', 'Vegan', 'Venus', 'Vermont', 'Victor', 'Video', 'Violet',
   'Virginia', 'Washington', 'West', 'Whiskey', 'White', 'William', 'Winner', 'Winter',
   'Wisconsin', 'Wolfram', 'Wyoming', 'Xray', 'Yankee', 'Yellow', 'Zebra', 'Zulu',
-]+]


append notice method to Adapter and Robot.Response

--- src/irc.coffee
+++ src/irc.coffee
@@ -14,6 +14,17 @@
       else
         console.log "#{user.name} #{str}"
         @bot.say(user.name, str)
+
+  notice: (user, strings...) ->
+    for str in strings
+      if not str?
+        continue
+      if user.room
+        console.log "notice #{user.room} #{str}"
+        @bot.notice(user.room, str)
+      else
+        console.log "notice #{user.name} #{str}"
+        @bot.notice(user.name, str)

   reply: (user, strings...) ->
     for str in strings
@@ -108,6 +119,15 @@

     @bot = bot

+class IrcResponse extends Robot.Response
+  notice: (strings...) ->
+    @robot.adapter.notice @message.user, strings...
+
 exports.use = (robot) ->
+  robot.notice = (user, strings...) ->
+    @adapter.notice user, strings...
+
+  robot.Response = IrcResponse
+
   new IrcBot robot


Consistency

Consistency

--- tapestry-core/src/main/coffeescript/META-INF/modules/core/exceptionframe.coffee
+++ tapestry-core/src/main/coffeescript/META-INF/modules/core/exceptionframe.coffee
@@ -16,7 +16,6 @@
 #
 # Manages a special element used to present a HTML exception report from an Ajax request (where a non-markup response
 # was expected, including a partial page render response).
-
 define ["core/spi", "core/builder", "_"],
   (spi, builder, _) ->
     container = null


Datetime form default

Datetime form default

--- src/core/javascripts/schema_form_config.js.coffee
+++ src/core/javascripts/schema_form_config.js.coffee
@@ -10,6 +10,16 @@
       f

   schemaFormProvider.defaults.string.unshift(timepicker)
+
+  datetimepicker = (name, schema, options) ->
+    if schema.type == 'string' && (schema.format == 'datetime')
+      f = schemaFormProvider.stdFormObj(name, schema, options)
+      f.key = options.path
+      f.type = 'datetime'
+      options.lookup[sfPathProvider.stringify(options.path)] = f
+      f
+
+  schemaFormProvider.defaults.string.unshift(datetimepicker)

   schemaFormDecoratorsProvider.addMapping(
     'bootstrapDecorator'


Update userFor<X> call

Update userFor<X> call

--- src/scripts/rhubot.coffee
+++ src/scripts/rhubot.coffee
@@ -37,7 +37,7 @@

   robot.router.post routerPost, (req, res) ->
-    user = robot.userForId 'broadcast'
+    user = robot.brain.userForId 'broadcast'
     user.room = req.body.room
     user.type = 'groupchat'
     result = req.body.result


organizes our options printout in `lineman help`

--- lib/cli/setup-options.coffee
+++ lib/cli/setup-options.coffee
@@ -1,10 +1,10 @@
 _ = require("grunt").util._

 module.exports = (commander, gruntCli) ->
-  commander.option("--install", "Perform an `npm install` when creating a new project, effectively freezing lineman with the project")
+  commander.option("--install", "lineman new - Perform an `npm install` when creating a new project, effectively freezing lineman with the project")
   _(gruntCli.optlist).each (option, name) ->
     unless name in ["help", "version"]
       desc = "--#{name}"
       desc = "-#{option.short}, #{desc}" if option.short
-      commander.option(desc, option.info)
+      commander.option(desc, "grunt - #{option.info}")


Make tests backwards compatible

Make tests backwards compatible

--- spec/tabs-spec.coffee
+++ spec/tabs-spec.coffee
@@ -43,25 +43,6 @@
       pane.splitRight()
       expect(workspaceElement.querySelectorAll('.pane').length).toBe 3
       expect(workspaceElement.querySelectorAll('.pane > .tab-bar').length).toBe 0
-
-    it "serializes preview tab state", ->
-      waitsForPromise ->
-        atom.workspace.open('sample.txt', pending: true)
-
-      runs ->
-        expect(workspaceElement.querySelectorAll('.tab.preview-tab .title').length).toBe 1
-        expect(workspaceElement.querySelector('.tab.preview-tab .title')?.textContent).toBe 'sample.txt'
-
-        atom.packages.deactivatePackage('tabs')
-
-        expect(workspaceElement.querySelectorAll('.tab.preview-tab .title').length).toBe 0
-
-      waitsForPromise ->
-        atom.packages.activatePackage('tabs')
-
-      runs ->
-        expect(workspaceElement.querySelectorAll('.tab.preview-tab .title').length).toBe 1
-        expect(workspaceElement.querySelector('.tab.preview-tab .title')?.textContent).toBe 'sample.txt'

 describe "TabBarView", ->
   [deserializerDisposable, item1, item2, editor1, pane, tabBar] = []
@@ -848,186 +829,187 @@
         expect(pane.getItems().length).toBe 1
         expect(tabBar).toHaveClass 'hidden'

-  describe "when tab is pending", ->
-    beforeEach ->
-      pane.destroyItems()
-
-    describe "when opening a new tab", ->
-      it "adds tab with class 'temp'", ->
-        editor1 = null
-        waitsForPromise ->
-          atom.workspace.open('sample.txt', pending: true).then (o) -> editor1 = o
-
-        runs ->
-          pane.activateItem(editor1)
-          expect($(tabBar).find('.tab .temp').length).toBe 1
-          expect($(tabBar).find('.tab:eq(0) .title')).toHaveClass 'temp'
-
-    describe "when tabs:keep-preview-tab is trigger on the pane", ->
-      it "removes the 'temp' class", ->
-        editor1 = null
-        waitsForPromise ->
-          atom.workspace.open('sample.txt', pending: true).then (o) -> editor1 = o
-
-        runs ->
-          pane.activateItem(editor1)
-          expect($(tabBar).find('.tab .temp').length).toBe 1
-          atom.commands.dispatch(atom.views.getView(atom.workspace.getActivePane()), 'tabs:keep-preview-tab')
-          expect($(tabBar).find('.tab .temp').length).toBe 0
-
-    describe "when there is a temp tab already", ->
-      it "it will replace an existing temporary tab", ->
-        editor1 = null
+  if atom.workspace.buildTextEditor().isPending?
+    describe "when tab's pane item is pending", ->
+      beforeEach ->
+        pane.destroyItems()
+
+      describe "when opening a new tab", ->
+        it "adds tab with class 'temp'", ->
+          editor1 = null
+          waitsForPromise ->
+            atom.workspace.open('sample.txt', pending: true).then (o) -> editor1 = o
+
+          runs ->
+            pane.activateItem(editor1)
+            expect($(tabBar).find('.tab .temp').length).toBe 1
+            expect($(tabBar).find('.tab:eq(0) .title')).toHaveClass 'temp'
+
+      describe "when tabs:keep-preview-tab is trigger on the pane", ->
+        it "removes the 'temp' class", ->
+          editor1 = null
+          waitsForPromise ->
+            atom.workspace.open('sample.txt', pending: true).then (o) -> editor1 = o
+
+          runs ->
+            pane.activateItem(editor1)
+            expect($(tabBar).find('.tab .temp').length).toBe 1
+            atom.commands.dispatch(atom.views.getView(atom.workspace.getActivePane()), 'tabs:keep-preview-tab')
+            expect($(tabBar).find('.tab .temp').length).toBe 0
+
+      describe "when there is a temp tab already", ->
+        it "it will replace an existing temporary tab", ->
+          editor1 = null
+          editor2 = null
+
+          waitsForPromise ->
+            atom.workspace.open('sample.txt', pending: true).then (o) ->
+              editor1 = o
+              atom.workspace.open('sample2.txt', pending: true).then (o) ->
+                editor2 = o
+
+          runs ->
+            expect(editor1.isDestroyed()).toBe true
+            expect(editor2.isDestroyed()).toBe false
+            expect(tabBar.tabForItem(editor1)).not.toExist()
+            expect($(tabBar.tabForItem(editor2)).find('.title')).toHaveClass 'temp'
+
+        it 'makes the tab permanent when clicking the tab', ->
+          editor2 = null
+
+          waitsForPromise ->
+            atom.workspace.open('sample.txt', pending: true).then (o) -> editor2 = o
+
+          runs ->
+            pane.activateItem(editor2)
+            expect($(tabBar.tabForItem(editor2)).find('.title')).toHaveClass 'temp'
+            triggerMouseEvent('mousedown', tabBar.tabForItem(editor2), which: 1)
+            expect($(tabBar.tabForItem(editor2)).find('.title')).not.toHaveClass 'temp'
+            waits 0 # To prevent uncaught error "Pane has been destroyed"
+
+      describe 'when opening views that do not have file paths', ->
         editor2 = null
-
-        waitsForPromise ->
-          atom.workspace.open('sample.txt', pending: true).then (o) ->
-            editor1 = o
+        settingsView = null
+
+        beforeEach ->
+          waitsForPromise ->
+            atom.workspace.open('sample.txt', pending: true).then (o) ->
+              editor2 = o
+
+          waitsForPromise ->
+            atom.packages.activatePackage('settings-view').then ->
+              atom.workspace.open('atom://config').then (o) ->
+                settingsView = o
+
+        it 'creates a permanent tab', ->
+          expect(tabBar.tabForItem(settingsView)).toExist()
+          expect($(tabBar.tabForItem(settingsView)).find('.title')).not.toHaveClass 'temp'
+
+        it 'destroys an existing temp tab', ->
+          expect(tabBar.tabForItem(editor2)).not.toExist()
+
+      describe 'when editing a file', ->
+        it 'makes the tab permanent', ->
+          editor1 = null
+          waitsForPromise ->
+            atom.workspace.open('sample.txt').then (o) ->
+              editor1 = o
+              pane.activateItem(editor1)
+              editor1.insertText('x')
+              advanceClock(editor1.buffer.stoppedChangingDelay)
+
+          runs ->
+            expect($(tabBar.tabForItem(editor1)).find('.title')).not.toHaveClass 'temp'
+
+      describe 'when saving a file', ->
+        it 'makes the tab permanent', ->
+          editor1 = null
+          waitsForPromise ->
+            atom.workspace.open(path.join(temp.mkdirSync('tabs-'), 'sample.txt')).then (o) ->
+              editor1 = o
+              pane.activateItem(editor1)
+              editor1.save()
+
+          runs ->
+            expect($(tabBar.tabForItem(editor1)).find('.title')).not.toHaveClass 'temp'
+
+      describe 'when switching from a preview tab to a permanent tab', ->
+        it "closes the preview tab", ->
+          editor1 = null
+          editor2 = null
+
+          waitsForPromise ->
+            atom.workspace.open('sample.txt').then (o) ->
+              editor1 = o
+
+          waitsForPromise ->
             atom.workspace.open('sample2.txt', pending: true).then (o) ->
               editor2 = o

-        runs ->
-          expect(editor1.isDestroyed()).toBe true
-          expect(editor2.isDestroyed()).toBe false
-          expect(tabBar.tabForItem(editor1)).not.toExist()
-          expect($(tabBar.tabForItem(editor2)).find('.title')).toHaveClass 'temp'
-
-      it 'makes the tab permanent when clicking the tab', ->
-        editor2 = null
-
-        waitsForPromise ->
-          atom.workspace.open('sample.txt', pending: true).then (o) -> editor2 = o
-
-        runs ->
-          pane.activateItem(editor2)
-          expect($(tabBar.tabForItem(editor2)).find('.title')).toHaveClass 'temp'
-          triggerMouseEvent('mousedown', tabBar.tabForItem(editor2), which: 1)
-          expect($(tabBar.tabForItem(editor2)).find('.title')).not.toHaveClass 'temp'
-          waits 0 # To prevent uncaught error "Pane has been destroyed"
-
-    describe 'when opening views that do not have file paths', ->
-      editor2 = null
-      settingsView = null
-
-      beforeEach ->
-        waitsForPromise ->
-          atom.workspace.open('sample.txt', pending: true).then (o) ->
-            editor2 = o
-
-        waitsForPromise ->
-          atom.packages.activatePackage('settings-view').then ->
-            atom.workspace.open('atom://config').then (o) ->
-              settingsView = o
-
-      it 'creates a permanent tab', ->
-        expect(tabBar.tabForItem(settingsView)).toExist()
-        expect($(tabBar.tabForItem(settingsView)).find('.title')).not.toHaveClass 'temp'
-
-      it 'destroys an existing temp tab', ->
-        expect(tabBar.tabForItem(editor2)).not.toExist()
-
-    describe 'when editing a file', ->
-      it 'makes the tab permanent', ->
-        editor1 = null
-        waitsForPromise ->
-          atom.workspace.open('sample.txt').then (o) ->
-            editor1 = o
+          runs ->
             pane.activateItem(editor1)
-            editor1.insertText('x')
-            advanceClock(editor1.buffer.stoppedChangingDelay)
-
-        runs ->
-          expect($(tabBar.tabForItem(editor1)).find('.title')).not.toHaveClass 'temp'
-
-    describe 'when saving a file', ->
-      it 'makes the tab permanent', ->
-        editor1 = null
-        waitsForPromise ->
-          atom.workspace.open(path.join(temp.mkdirSync('tabs-'), 'sample.txt')).then (o) ->
-            editor1 = o
+            expect(pane.getItems().length).toBe 1
+            expect(pane.getItems()).toEqual [editor1]
+            expect($(tabBar.tabForItem(editor1)).find('.title')).not.toHaveClass 'temp'
+
+      describe "when splitting a preview tab", ->
+        it "makes the tab permanent in the new pane", ->
+          editor1 = null
+          waitsForPromise ->
+            atom.workspace.open('sample.txt').then (o) -> editor1 = o
+
+          runs ->
             pane.activateItem(editor1)
-            editor1.save()
-
-        runs ->
-          expect($(tabBar.tabForItem(editor1)).find('.title')).not.toHaveClass 'temp'
-
-    describe 'when switching from a preview tab to a permanent tab', ->
-      it "closes the preview tab", ->
-        editor1 = null
-        editor2 = null
-
-        waitsForPromise ->
-          atom.workspace.open('sample.txt').then (o) ->
-            editor1 = o
-
-        waitsForPromise ->
-          atom.workspace.open('sample2.txt', pending: true).then (o) ->
-            editor2 = o
-
-        runs ->
-          pane.activateItem(editor1)
-          expect(pane.getItems().length).toBe 1
-          expect(pane.getItems()).toEqual [editor1]
-          expect($(tabBar.tabForItem(editor1)).find('.title')).not.toHaveClass 'temp'
-
-    describe "when splitting a preview tab", ->
-      it "makes the tab permanent in the new pane", ->
-        editor1 = null
-        waitsForPromise ->
-          atom.workspace.open('sample.txt').then (o) -> editor1 = o
-
-        runs ->
-          pane.activateItem(editor1)
-          pane2 = pane.splitRight(copyActiveItem: true)
-          tabBar2 = new TabBarView
-          tabBar2.initialize(pane2)
-
-          expect($(tabBar2.tabForItem(pane2.getActiveItem())).find('.title')).not.toHaveClass 'temp'
-
-    describe "when dragging a preview tab to a different pane", ->
-      it "makes the tab permanent in the other pane", ->
-        editor1 = null
-        waitsForPromise ->
-          atom.workspace.open('sample.txt').then (o) -> editor1 = o
-
-        runs ->
-          pane.activateItem(editor1)
-          pane2 = pane.splitRight()
-
-          tabBar2 = new TabBarView
-          tabBar2.initialize(pane2)
-          tabBar2.moveItemBetweenPanes(pane, 0, pane2, 1, editor1)
-
-          expect($(tabBar2.tabForItem(pane2.getActiveItem())).find('.title')).not.toHaveClass 'temp'
-
-    describe "when double clicking a file in the tree view", ->
-      it "makes the tab for that file permanent", ->
-        editor1 = null
-        workspaceElement = atom.views.getView(atom.workspace)
-        jasmine.attachToDOM(workspaceElement)
-
-        waitsForPromise ->
-          atom.packages.activatePackage('tree-view')
-
-        runs ->
-          atom.commands.dispatch(workspaceElement, 'tree-view:show')
-
-        waitsFor ->
-          workspaceElement.querySelector('.tree-view')
-
-        waitsForPromise ->
-          atom.workspace.open('sample.js', pending: true).then (o) -> editor1 = o
-
-        runs ->
-          expect($(tabBar.tabForItem(editor1)).find('.title')).toHaveClass 'temp'
-
-          fileNode = workspaceElement.querySelector(".tree-view [data-path=\"#{path.join(__dirname, 'fixtures', 'sample.js')}\"]")
-          fileNode.dispatchEvent(new MouseEvent('click', detail: 1, bubbles: true, cancelable: true))
-          fileNode.dispatchEvent(new MouseEvent('click', detail: 2, bubbles: true, cancelable: true))
-          fileNode.dispatchEvent(new MouseEvent('dblclick', detail: 2, bubbles: true, cancelable: true))
-
-          expect($(tabBar.tabForItem(editor1)).find('.title')).not.toHaveClass 'temp'
-          waits(10) # async nature causes uncaught exceptions, so wait a little bit before we cleanup
+            pane2 = pane.splitRight(copyActiveItem: true)
+            tabBar2 = new TabBarView
+            tabBar2.initialize(pane2)
+
+            expect($(tabBar2.tabForItem(pane2.getActiveItem())).find('.title')).not.toHaveClass 'temp'
+
+      describe "when dragging a preview tab to a different pane", ->
+        it "makes the tab permanent in the other pane", ->
+          editor1 = null
+          waitsForPromise ->
+            atom.workspace.open('sample.txt').then (o) -> editor1 = o
+
+          runs ->
+            pane.activateItem(editor1)
+            pane2 = pane.splitRight()
+
+            tabBar2 = new TabBarView
+            tabBar2.initialize(pane2)
+            tabBar2.moveItemBetweenPanes(pane, 0, pane2, 1, editor1)
+
+            expect($(tabBar2.tabForItem(pane2.getActiveItem())).find('.title')).not.toHaveClass 'temp'
+
+      describe "when double clicking a file in the tree view", ->
+        it "makes the tab for that file permanent", ->
+          editor1 = null
+          workspaceElement = atom.views.getView(atom.workspace)
+          jasmine.attachToDOM(workspaceElement)
+
+          waitsForPromise ->
+            atom.packages.activatePackage('tree-view')
+
+          runs ->
+            atom.commands.dispatch(workspaceElement, 'tree-view:show')
+
+          waitsFor ->
+            workspaceElement.querySelector('.tree-view')
+
+          waitsForPromise ->
+            atom.workspace.open('sample.js', pending: true).then (o) -> editor1 = o
+
+          runs ->
+            expect($(tabBar.tabForItem(editor1)).find('.title')).toHaveClass 'temp'
+
+            fileNode = workspaceElement.querySelector(".tree-view [data-path=\"#{path.join(__dirname, 'fixtures', 'sample.js')}\"]")
+            fileNode.dispatchEvent(new MouseEvent('click', detail: 1, bubbles: true, cancelable: true))
+            fileNode.dispatchEvent(new MouseEvent('click', detail: 2, bubbles: true, cancelable: true))
+            fileNode.dispatchEvent(new MouseEvent('dblclick', detail: 2, bubbles: true, cancelable: true))
+
+            expect($(tabBar.tabForItem(editor1)).find('.title')).not.toHaveClass 'temp'
+            waits(10) # async nature causes uncaught exceptions, so wait a little bit before we cleanup

   describe "integration with version control systems", ->
     [repository, tab, tab1] = []


Allow layout tests to be run individually

--- spec/tabs-spec.coffee
+++ spec/tabs-spec.coffee
@@ -881,6 +881,13 @@
           atom.config.set("tabs.addNewTabsAtEnd", false)

     describe "when a tab is dragged over a pane item", ->
+      beforeEach ->
+        layout.activate()
+
+      afterEach ->
+        layout.deactivate()
+        layout.test = {}
+
       it "draws an overlay over the item", ->
         expect(tabBar.getTabs().map (tab) -> tab.element.textContent).toEqual ["Item 1", "sample.js", "Item 2"]
         tab = tabBar.tabAtIndex(2).element


tableview label position change

tableview label position change

--- JSKit/04_JSTableView.coffee
+++ JSKit/04_JSTableView.coffee
@@ -76,7 +76,7 @@
     super()
     if (!@_tableView?)
       if (!@_titleBar?)
-        @_titleBar = new JSLabel(JSRectMake(0, 0, @_frame.size.width, @_rowHeight))
+        @_titleBar = new JSLabel(JSRectMake(4, 0, @_frame.size.width - 8, @_rowHeight))
         @_titleBar.setText(@_title)
         @_titleBar.setTextAlignment("JSTextAlignmentLeft")
         @_titleBar.setTextSize(11)


Fixed bad copy/paste.

Fixed bad copy/paste.

--- src/log.coffee
+++ src/log.coffee
@@ -68,7 +68,7 @@
         duration = 0
         first = log.entries[index]
         if not first then return 0
-        for i in [index...log.entries.length]
+        for i in [index...entries.length]
             e = log.entries[i]
             if not e.pause? and ((e.task != first.task) or (e.active != first.active)) then break
             duration += @_get_segment_duration i, false, entries
@@ -77,9 +77,9 @@

     get_activity_duration: (index, entries=@entries)->
         duration = 0
-        first = log.entries[index]
+        first = entries[index]
         if not first then return 0
-        for i in [index...log.entries.length]
+        for i in [index...entries.length]
             e = log.entries[i]
             if not e.pause? and e.active != first.active then break
             duration += @_get_segment_duration i, false, entries


Added support for overriding enrollment and password reset emails. Returned cloned copy of the config.

--- src/AccountsUi.coffee
+++ src/AccountsUi.coffee
@@ -45,6 +45,7 @@
               'the link below:
' + args.loginUrl + ''
           # Uses the default in Meteor.
           verifyEmail: {}
+          resetPassword: {}

       setUpRoutes: ->
         config = @config()
@@ -68,14 +69,15 @@
           onBeforeAction: -> if Meteor.isAdmin() then @next() else AccountsUi.goToLogin()

     Setter.merge(@_config, config)
-    unless config then return @_config
+    clonedConfig = Setter.clone(@_config)
+    unless config then return clonedConfig
     unless @_config.email.adminAddress
       throw new Error('AccountsUi: Admin email address not provided')
     unless @_config.email.fromAddress
       throw new Error('AccountsUi: From email address not provided')
     setUpRoutes(@_config.setUpRoutes) if Meteor.isClient
     @setUpTemplates() if Meteor.isServer
-    @_config
+    clonedConfig

   signInRequired: (router, args) ->
     args = Setter.merge({
@@ -172,5 +174,7 @@
       @sendEmail(email)

     setUpTemplates: ->
+      # Merges any email template overrides into the Meteor config.
       config = @config()
-      _.extend Accounts.emailTemplates.verifyEmail, config.email.templates.verifyEmail
+      _.each ['resetPassword', 'enrollAccount', 'verifyEmail'], (prop) ->
+        _.extend Accounts.emailTemplates[prop], config.email.templates[prop]


Working max zoom for orto map.

Working max zoom for orto map.

TMS returns empty tiles for >10. Find out why.

--- src/map.coffee
+++ src/map.coffee
@@ -73,7 +73,7 @@
                     "http://geoserver.hel.fi/geoserver/gwc/service/tms/1.0.0/#{layerName}@ETRS-GK25@#{layerFmt}/{z}/{x}/{y}.#{layerFmt}"
                 if opts.style == 'ortographic'
                     new L.Proj.TileLayer.TMS geoserverUrl("hel:orto2013", "jpg"), opts.crs,
-                        maxZoom: 12
+                        maxZoom: 10
                         minZoom: 2
                         continuousWorld: true
                         tms: false


Add new funding btn

Add new funding btn

--- app/assets/javascripts/components/company_profile/content/funding/view.js.coffee
+++ app/assets/javascripts/components/company_profile/content/funding/view.js.coffee
@@ -9,20 +9,21 @@
     company: @props.company

   render: ->
-    if @state.edit_mode
-      @_renderListings()
-    else if @state.funding
+    if @state.funding || @state.new
       CompanyProfile_Content_Funding_Form(funding: @state.funding, saveProfile: @props.saveProfile, onCancel: @_onFormCancel)
     else if _.isEmpty(@state.company.fundings)
       @_renderEmpty()
     else
       @_renderListings()

+  _onNewFunding: ->
+    @setState new: true
+
   _onEditFunding: (object, event)->
     @setState funding: object

   _onFormCancel: (company)->
-    options = form: false, funding: null
+    options = form: false, funding: null, new: null
     options.company = company if company

     @setState(options)
@@ -49,6 +50,12 @@
         (i className: 'button__icon fa fa-pencil')
         (span null, 'Edit'))

+    newBtn = if @state.edit_mode
+      (div className: "col-xs-12 col-sm-12 col-md-12 col-lg-12",
+        (button type: "button", className: "btn btn-primary", onClick: @_onNewFunding,
+          (i className: "button__icon fa fa-plus-circle")
+          (span null, 'Add New') ))
+
     (span null,
       (span className: 'title__btn_edit edit-body__btn-group_in-title',
         editCancelBtn)
@@ -56,8 +63,10 @@
       (div className: 'section__body section__body_view funding_view',
         (div className: "view-body",
           (div className: "view-body__form row",
-            @_fundings()
-          ))))
+            (div className: "edit-body__btn-group edit-body__btn-group_left",
+              newBtn
+              @_fundings()
+            )))))

   _parse_hostname: (url)->
     parser = document.createElement('a')


Enable dragging only on the current node

not all of its descendants

--- scripts/views/workspace/sidebar/toc-branch.coffee
+++ scripts/views/workspace/sidebar/toc-branch.coffee
@@ -30,7 +30,7 @@
         @$el.removeClass('editor-node-expanded')

       # Add DnD options to content
-      enableContentDragging(@model, @$el.find('*[data-media-type]'))
+      enableContentDragging(@model, @$el.find('> .editor-node-body > *[data-media-type]'))

       return result


Browser: reverse arrow deflection based on direction.

--- community/browser/lib/visualization/utils/pairwiseArcsRelationshipRouting.coffee
+++ community/browser/lib/visualization/utils/pairwiseArcsRelationshipRouting.coffee
@@ -82,6 +82,9 @@
           )
         else
           deflection = 30 * (i - middleRelationshipIndex)
+          if nodePair.nodeA isnt relationship.source
+            deflection *= -1
+
           relationship.arrow = new neo.utils.arcArrow(
               relationship.source.radius,
               relationship.target.radius,


Take into account odd spaces as well

Take into account odd spaces as well

--- src/tokenized-line.coffee
+++ src/tokenized-line.coffee
@@ -110,6 +110,24 @@

       return maxColumn

+  # Calculates how many trailing spaces in this line's indentation cannot fit in a single tab.
+  #
+  # Returns a {Number} representing the odd indentation spaces in this line.
+  getOddIndentationSpaces: ->
+    oddIndentLevel = @indentLevel - Math.floor(@indentLevel)
+    Math.round(@tabLength * oddIndentLevel)
+
+  buildSoftWrapIndentationTokens: (token) ->
+    indentTokens = [0...Math.floor(@indentLevel)].map =>
+      token.buildSoftWrapIndentationToken(@tabLength)
+
+    if @getOddIndentationSpaces()
+      indentTokens.concat(
+        token.buildSoftWrapIndentationToken @getOddIndentationSpaces()
+      )
+    else
+      indentTokens
+
   softWrapAt: (column) ->
     return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column == 0

@@ -123,8 +141,7 @@
       leftTextLength += nextToken.value.length
       leftTokens.push nextToken

-    indentTokens = [0...@indentLevel].map =>
-      leftTokens[0].buildSoftWrapIndentationToken(@tabLength)
+    indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0])

     leftFragment = new TokenizedLine(
       tokens: leftTokens
@@ -136,7 +153,7 @@
       tabLength: @tabLength
     )
     rightFragment = new TokenizedLine(
-      tokens: indentTokens.concat(rightTokens)
+      tokens: indentationTokens.concat(rightTokens)
       startBufferColumn: @bufferColumnForScreenColumn(column)
       ruleStack: @ruleStack
       invisibles: @invisibles


[data] place comment into better position

--- source/data/index.coffee
+++ source/data/index.coffee
@@ -35,8 +35,7 @@
       showContentTitle: true
       showBreadcrumb: true
       showSidebar: false
-    social:
-      # Add any other social services following same pattern
+    social: # Add any other social services following same pattern
       twitter:
         handle: pkg.twitter
         image: "/#{imagesPath}/twitter.png"


range question expansion template wip

range question expansion template wip

--- jsapp/xlform/src/view.row.templates.coffee
+++ jsapp/xlform/src/view.row.templates.coffee
@@ -242,6 +242,12 @@
     </div>
     """

+  rangeQuestionExpansion = ->
+    """
+    <div class="card--rangequestion__expansion">
+      range question expansion
+    </div>
+    """

   selectQuestionExpansion = ->
     """


TextElement now accepts arrays of strings for the text: property - they are joined with new-lines for now.

--- src/art/engine/elements/shapes/text_element.coffee
+++ src/art/engine/elements/shapes/text_element.coffee
@@ -4,7 +4,7 @@
 FillableBase = require '../fillable_base'
 GlobalEpochCycle = require '../../core/global_epoch_cycle'

-{log, BaseObject, shallowClone, pureMerge, merge, createWithPostCreate} = Foundation
+{log, BaseObject, shallowClone, pureMerge, merge, createWithPostCreate, isPlainArray} = Foundation
 {color, Color, point, Point, rect, Rectangle, matrix, Matrix} = Atomic
 {normalizeFontOptions} = Text.Metrics

@@ -71,7 +71,14 @@
         (!overflow   || validOverflows[overflow])

   @drawLayoutProperty
-    text:           default: Text.Layout.defaultText, preprocess: (t) -> ""+t
+    text:
+      default: Text.Layout.defaultText
+      preprocess: (t) ->
+        if isPlainArray t
+          t.join "\n"
+        else
+          "#{t}"
+
     fontOptions:    validate: (v)-> !v
     layoutOptions:  validate: (v)-> !v


Wait for shutdown to complete before re-starting

--- src/lib/Network.coffee
+++ src/lib/Network.coffee
@@ -136,14 +136,15 @@
       process.component = instance

       # Inform the ports of the node name
-      for name, port of process.component.inPorts
-        continue if not port or typeof port is 'function' or not port.canAttach
+      # FIXME: direct process.component.inPorts/outPorts access is only for legacy compat
+      inPorts = process.component.inPorts.ports or process.component.inPorts
+      outPorts = process.component.outPorts.ports or process.component.outPorts
+      for name, port of inPorts
         port.node = node.id
         port.nodeInstance = instance
         port.name = name

-      for name, port of process.component.outPorts
-        continue if not port or typeof port is 'function' or not port.canAttach
+      for name, port of outPorts
         port.node = node.id
         port.nodeInstance = instance
         port.name = name
@@ -567,7 +568,12 @@
       platform.deprecated 'Calling network.start() without callback is deprecated'
       callback = ->

-    do @stop if @started
+    if @started
+      @stop (err) =>
+        return callback err if err
+        @start callback
+      return
+
     @initials = @nextInitials.slice 0
     @startComponents (err) =>
       return callback err if err


somewhat fixes #18 (resizes pane on input, so you can resize the pane as you wish and it will always keep the correct size). this is a very hackish fix, though :) not sure it's the correct way to do it .....

--- lib/TermView.coffee
+++ lib/TermView.coffee
@@ -69,6 +69,8 @@

   input: (data) ->
     @ptyProcess.send event: 'input', text: data
+    @resizeToPane()
+    @focusTerm()

   resize: (cols, rows) ->
     @ptyProcess.send {event: 'resize', rows, cols}


Fix TZ

Fix TZ

--- lib/arrivals.coffee
+++ lib/arrivals.coffee
@@ -15,6 +15,7 @@
   _.each res.data,(i)->
     event_time = moment.tz(i.EVENT_TIME,"America/New_York").unix()
     next_arr = moment.tz(i.NEXT_ARR,'hh:mm:ss A',"America/New_York").unix()
+    console.log("This arrival is at:",next_arr,"compared to now:",moment().unix())
     Arrivals.update {
       train_id: i.TRAIN_ID
       station: i.STATION


Minor style changes

Minor style changes

--- lib/document.coffee
+++ lib/document.coffee
@@ -101,11 +101,13 @@

     return this

-  bufferedPageRange: -> { start: @_pageBufferStart, count: @_pageBuffer.length }
+  bufferedPageRange: ->
+    return { start: @_pageBufferStart, count: @_pageBuffer.length }

   switchToPage: (n) ->
-    unless page = @_pageBuffer[n-@_pageBufferStart]
-      throw new Error("switchToPage(#{n}) out of bounds, current buffer covers pages #{@_pageBufferStart} to #{@_pageBufferStart + @_pageBuffer.length - 1}")
+    unless page = @_pageBuffer[n - @_pageBufferStart]
+      throw new Error "switchToPage(#{n}) out of bounds, current buffer covers pages #{@_pageBufferStart} to #{@_pageBufferStart + @_pageBuffer.length - 1}"
+
     @page = page

   flushPages: ->
@@ -116,7 +118,8 @@
     @_pageBufferStart += pages.length
     for page in pages
       page.end()
-    null
+
+    return

   ref: (data) ->
     ref = new PDFReference(this, @_offsets.length + 1, data)


iterate over leg options instead of manually handling them all

--- src/modules/leg.coffee
+++ src/modules/leg.coffee
@@ -80,18 +80,14 @@

   _setupOptions: ->
     globalOptions = @bus.options.leg
-    @options.class = utils.dataProp( @rawData.class, globalOptions.class )
-    @options.top = utils.dataProp( @rawData.top, globalOptions.top )
-    @options.left = utils.dataProp( @rawData.left, globalOptions.left )
-    @options.scrollTo = utils.dataProp( @rawData.scrollTo, globalOptions.scrollTo )
-    @options.scrollSpeed = utils.dataProp( @rawData.scrollSpeed, globalOptions.scrollSpeed )
-    @options.scrollContext = utils.dataProp( @rawData.scrollContext, globalOptions.scrollContext )
-    @options.margin = utils.dataProp( @rawData.margin, globalOptions.margin )
-    @options.arrow = @rawData.arrow || globalOptions.arrow
-    @options.align = @rawData.align || globalOptions.align
-    @options.width = @rawData.width || globalOptions.width
-    @options.zindex = @rawData.zindex || globalOptions.zindex
-    @options.orientation = @rawData.orientation || globalOptions.orientation
+
+    dataProps = [
+      'class', 'top', 'left', 'scrollTo', 'scrollSpeed',
+      'scrollContext', 'margin', 'arrow', 'align', 'width',
+      'zindex', 'orientation'
+    ]
+    _.each dataProps, ( prop ) =>
+      @options[prop] = utils.dataProp( @rawData[prop], globalOptions[prop] )

   _configureElement: ->
     @$el = $("

")


Canadian dollars should just be mapped to $

--- src/donations-form-model.coffee
+++ src/donations-form-model.coffee
@@ -57,7 +57,7 @@
     self.selectedCurrency = ko.observable(initializeCurrency())
     self.currencySymbol = ko.computed(->
       symbols = {
-        'USD' : '$', 'GBP' : '£', 'EUR' : '€', 'NZD' : 'NZ$', 'AUD' : 'AU$', 'CAD' : 'C$'
+        'USD' : '$', 'GBP' : '£', 'EUR' : '€', 'NZD' : 'NZ$', 'AUD' : 'AU$', 'CAD' : '$'
       }
       return symbols[self.selectedCurrency()] or self.selectedCurrency()
     , this)


[master] flow manage

[master] flow manage

--- translator/run.coffee
+++ translator/run.coffee
@@ -20,7 +20,7 @@
   ]
 )

-http.globalAgent.maxSockets = 10
+http.globalAgent.maxSockets = 5

 if require.main == module
   availableTranslators =
@@ -69,7 +69,7 @@
                 logger.debug 'translated',
                   src: src
                   dst: res
-      Q.all _.map(_.range(100), ->
+      Q.all _.map(_.range(4 * http.globalAgent.maxSockets * (availableTranslators.length + 1)), ->
         loo = ->
           val = keys.pop()
           if val


Remove unused method

Remove unused method

--- lib/git-view.coffee
+++ lib/git-view.coffee
@@ -40,9 +40,6 @@

   getActiveItem: ->
     atom.workspace.getActivePaneItem()
-
-  getActiveView: ->
-    atom.workspaceView.getActiveView()

   subscribeToRepo: =>
     @unsubscribe(@repo) if @repo?


Forgot this was Coffee instead of JS

Forgot this was Coffee instead of JS

Removed JS specificity. Let's see if this passes...

--- lib/grammars.coffee
+++ lib/grammars.coffee
@@ -68,7 +68,7 @@
       "File Based":
         command: "bash"
         args: (context) -> ["-c", "g++ -Wall -include stdio.h -include iostream '" + context.filepath + "' -o /tmp/cpp.out && /tmp/cpp.out"]
-    else if GrammarUtils.OperatingSystem.isWindows() and GrammarUtils.OperatingSystem.release().indexOf("14399") >= 0
+    else if GrammarUtils.OperatingSystem.isWindows() and GrammarUtils.OperatingSystem.release().slice(-1) >= '14399'
       "File Based":
         command: "bash"
         args: (context) -> ["-c", "g++ -Wall -include stdio.h -include iostream '/mnt/" + path.posix.join.apply(path.posix, [].concat([context.filepath.split(path.win32.sep)[0].toLowerCase()], context.filepath.split(path.win32.sep).slice(1))).replace(":", "") + "' -o /tmp/cpp.out && /tmp/cpp.out"]