Agent pie: test globalizing variables

Agent pie: test globalizing variables

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -3,6 +3,44 @@
     @accessor 'data'

     #@oldPieData: ''
+    #
+    # CONFIG ZONE
+    #
+
+    # Width of the SVG area
+    @width = (Dashing.widget_base_dimensions[0] * container.data('sizex')) - Dashing.widget_margins[0] * 4 * (container.data('sizex') - 1)
+
+    # Height of the SVG area allowing for header and footer text
+    @height = (Dashing.widget_base_dimensions[1] * container.data('sizey')) - 120
+
+    # Calculated min dimension of the SVG area
+    @radius = Math.min(width, height) / 2
+
+    # Outer radius of the pie
+    @radiuso = Math.min(width, height) / 3
+
+    # Inner radius of the pie (zero = pie, non-zero = donut)
+    @radiusi = radiuso * 2 / 3
+
+    # Color scale for pie slices
+    @color = d3.scale.category20()
+
+    # X-offset for drop shadow filter
+    @dropshadowx = 2
+
+    # Y-offset for drop shadow filter
+    @dropshadowy = 2
+
+    # [STRING] Blur value for drop shadow filter
+    @dropshadowblur = '1.2'
+
+    #
+    # END CONFIG ZONE
+    #
+
+    @pie = d3.layout.pie().value((d) -> d.value).sort(null)
+    @arc = d3.svg.arc().innerRadius(radiusi).outerRadius(radiuso)
+    @svg = d3.select(@node).append('svg').attr('width', width).attr('height', height).append('g').attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')')

     onData: (data) ->
         #$(@node).fadeOut().fadeIn()
@@ -20,31 +58,31 @@
         #

         # Width of the SVG area
-        width = (Dashing.widget_base_dimensions[0] * container.data('sizex')) - Dashing.widget_margins[0] * 4 * (container.data('sizex') - 1)
+        width = @width#(Dashing.widget_base_dimensions[0] * container.data('sizex')) - Dashing.widget_margins[0] * 4 * (container.data('sizex') - 1)

         # Height of the SVG area allowing for header and footer text
-        height = (Dashing.widget_base_dimensions[1] * container.data('sizey')) - 120
+        height = @height#(Dashing.widget_base_dimensions[1] * container.data('sizey')) - 120

         # Calculated min dimension of the SVG area
-        radius = Math.min(width, height) / 2
+        radius = @radius#Math.min(width, height) / 2

         # Outer radius of the pie
-        radiuso = Math.min(width, height) / 3
+        radiuso = @radiuso#Math.min(width, height) / 3

         # Inner radius of the pie (zero = pie, non-zero = donut)
-        radiusi = radiuso * 2 / 3
+        radiusi = @radiusi#radiuso * 2 / 3

         # Color scale for pie slices
-        color = d3.scale.category20()
+        color = @color#d3.scale.category20()

         # X-offset for drop shadow filter
-        dropshadowx = 2
+        dropshadowx = @dropshadowx#2

         # Y-offset for drop shadow filter
-        dropshadowy = 2
+        dropshadowy = @dropshadowy#2

         # [STRING] Blur value for drop shadow filter
-        dropshadowblur = '1.2'
+        dropshadowblur = @dropshadowblur#'1.2'

         #
         # END CONFIG ZONE
@@ -55,9 +93,9 @@
         if !dataSet
             return

-        pie = d3.layout.pie().value((d) -> d.value).sort(null)
-        arc = d3.svg.arc().innerRadius(radiusi).outerRadius(radiuso)
-        svg = d3.select(@node).append('svg').attr('width', width).attr('height', height).append('g').attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')')
+        pie = @pie#d3.layout.pie().value((d) -> d.value).sort(null)
+        arc = @arc#d3.svg.arc().innerRadius(radiusi).outerRadius(radiuso)
+        svg = @svg#d3.select(@node).append('svg').attr('width', width).attr('height', height).append('g').attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')')
         #console.log 'update pie', dataSet

         piedata = pie(dataSet)


Agentpie: testing path start/end angle change

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -167,9 +167,13 @@
             .attrTween('d', (d,i) ->
                 s0 = 2 * Math.PI
                 e0 = 2 * Math.PI
+                s1 = d.startAngle
+                e1 = d.endAngle
+                if s1 != 0 then s1 = s1 + ((2 * Math.PI) / 360) # shrink start angle by one degree
+                if e1 != 0 then e1 = e1 - ((2 * Math.PI) / 360) # shrink end angle by one degree
                 exitInterpolater = d3.interpolate({
-                    startAngle: d.startAngle
-                    endAngle: d.endAngle
+                    startAngle: s1
+                    endAngle: e1
                 },{
                     startAngle: s0
                     endAngle: e0


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -201,11 +201,7 @@
 #            .remove();

         labels = labelGroup.selectAll("text")
-            .data(data
-                .sort((p1,p2) ->
-                    return p1.startAngle - p2.startAngle
-                )
-            )
+            .data(data.sort((p1,p2) -> return p1.startAngle - p2.startAngle))
         labels.enter()
             .append("text")
             .attr("text-anchor", "middle")


Agentpie: label layout changes

Agentpie: label layout changes

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -293,12 +293,12 @@
                 #d.x = d.l + bbox.width / 2 + 2#5
                 #d.r = d.l + bbox.width + 5#10
                 rads = ((d.endAngle - d.startAngle) / 2) + d.startAngle
-                if (rads >= 0 && rads <= 3 * Math.PI / 4)
+                if (rads >= 0 && rads <= 4 * Math.PI / 4)
                     d.t = bottomEdge + 2
-                else if (rads > 3 * Math.PI / 4 && rads < 4 * Math.PI / 4)
-                    d.l = rightEdge
-                    d.x = d.l + bbox.width / 2 + 2
-                    d.r = d.l + bbox.width + 5
+                #else if (rads > 3 * Math.PI / 4 && rads < 4 * Math.PI / 4)
+                #    d.l = rightEdge
+                #    d.x = d.l + bbox.width / 2 + 2
+                #    d.r = d.l + bbox.width + 5
                 else if (rads >= 4 * Math.PI / 4 && rads < 5 * Math.PI / 4)
                     d.r = leftEdge
                     d.x = d.r - bbox.width / 2 - 2


vm: take a whack at the createVm method

vm: take a whack at the createVm method

--- workers/social/lib/social/models/vm.coffee
+++ workers/social/lib/social/models/vm.coffee
@@ -51,22 +51,21 @@

   # TODO: this needs to be rethought in terms of bundles, as per the
   # discussion between Devrim, Chris T. and Badahir  C.T.
-  # @createVm = (target, groupSlug, limit, callback)->
-  #   unless 0 < limit.getValue()
-  #     callback new KodingError 'Quota exceeded'
-  #   else
-  #     target.fetchUser (err, user)->
-  #       return callback err  if err
-  #       { usage } = limit
-  #       vm = new JVM {
-  #         name: "#{user.username}#{unless usage then '' else "~#{usage}"}"
-  #         users: [{ id: user.getId(),  sudo: yes }]
-  #       }
-  #       vm.save (err)->
-  #         return callback err  if err
-  #         limit.update {$inc: usage: 1}, (err)->
-  #           return callback err  if err
-  #           callback null, vm
+  @createVm = ({account, groupSlug, usage}, callback)->
+    JGroup = require '../group'
+    JGroup.one {slug: groupSlug}, (err, group) ->
+      return callback err  if err
+      account.fetchUser (err, user) ->
+        return callback err  if err
+        vm = new JVM {
+          name    : "#{groupSlug}~#{user.username}"
+          users   : [{ id: user.getId(), sudo: yes }]
+          groups  : [{ id: group.getId() }]
+          usage
+        }
+        vm.save (err) ->
+          return callback err  if err
+          callback null, vm

   # @create = permit 'create vms',
   #   success: (client, callback) ->


Remove list all/default vms permissions

Remove list all/default vms permissions

--- workers/social/lib/social/models/vm.coffee
+++ workers/social/lib/social/models/vm.coffee
@@ -27,8 +27,6 @@
       'sudoer'          : []
       'create vms'      : ['member','moderator']
       'delete vms'      : ['member','moderator']
-      'list all vms'    : ['member','moderator']
-      'list default vm' : ['member','moderator']
     sharedMethods       :
       static            : [
                            'fetchVms','fetchVmsByContext', 'fetchVMInfo'
@@ -278,8 +276,7 @@
   #           return acc
   #       , @getUsageTemplate()

-  # @calculateUsage$ = permit 'list all vms',
-  #   success: (client, groupSlug, callback)->
+  # @calculateUsage$ = secure (client, groupSlug, callback)->
   #     {delegate} = client.connection
   #     @calculateUsage delegate, groupSlug, callback

@@ -318,8 +315,7 @@
           return callback err  if err
           callback null, arr.map (vm)-> vm.hostnameAlias

-  @fetchVmsByContext = permit 'list all vms',
-    success: (client, options, callback) ->
+  @fetchVmsByContext = secure (client, options, callback) ->
       {connection:{delegate}, context:{group}} = client
       JGroup = require './group'

@@ -331,8 +327,7 @@
         selector = groups: { $elemMatch: id: group.getId() }
         @fetchAccountVmsBySelector delegate, selector, options, callback

-  @fetchVms = permit 'list all vms',
-    success: (client, options, callback) ->
+  @fetchVms = secure (client, options, callback) ->
       {delegate} = client.connection
       @fetchAccountVmsBySelector delegate, {}, options, callback

@@ -354,8 +349,7 @@

   # Public(shared) static method to fetch domains
   # which points to given hostnameAlias
-  @fetchDomains$ = permit 'list all vms',
-    success:(client, hostnameAlias, callback)->
+  @fetchDomains$ = secure (client, hostnameAlias, callback)->
       {delegate} = client.connection

       delegate.fetchUser (err, user) ->


Minor fix to trasnaction API - getTransactionById()

--- src/api/transactions.coffee
+++ src/api/transactions.coffee
@@ -154,7 +154,7 @@
     result = yield transactions.Transaction.findById(transactionId, projectionFiltersObject).exec()

     # Test if the result if valid
-    if result?.length is 0
+    if not result
       this.body = "Could not find transaction with ID: #{transactionId}"
       this.status = 'not found'
     # Test if the user is authorised


:speak_no_evil:

--- src/app/edit-session.coffee
+++ src/app/edit-session.coffee
@@ -43,15 +43,9 @@
       {tabLength, softTabs, @softWrap} = @state.toObject()
       @buffer = project.bufferForId(@state.get('bufferId'))

-      console.log @buffer.getMarkers().map (m) -> m.getAttributes()
-
       @displayBuffer = new DisplayBuffer(@buffer, { tabLength })

-      console.log "looking for", @getSelectionMarkerAttributes()
-
       for marker in @findMarkers(@getSelectionMarkerAttributes())
-
-        console.log marker
         @addSelection(marker)
       @setScrollTop(@state.get('scrollTop'))
       @setScrollLeft(@state.get('scrollLeft'))


add @update to AtomEnvironment

add @update to AtomEnvironment

--- src/atom-environment.coffee
+++ src/atom-environment.coffee
@@ -41,6 +41,7 @@
 TextBuffer = require 'text-buffer'
 Gutter = require './gutter'
 TextEditorRegistry = require './text-editor-registry'
+Update = require './update'

 WorkspaceElement = require './workspace-element'
 PanelContainerElement = require './panel-container-element'
@@ -191,6 +192,7 @@
     @themes.workspace = @workspace

     @textEditors = new TextEditorRegistry
+    @update = new Update()

     @config.load()


Push all commits

Push all commits

--- src/bin/gulp-library.coffee
+++ src/bin/gulp-library.coffee
@@ -212,6 +212,9 @@
     )
   )
   .then(() ->
+    exec('git push origin')
+  )
+  .then(() ->
     exec('git push origin --tags')
   )
   .catch((error) ->


"Fixed" detection of finished downloads

"Fixed" detection of finished downloads

--- cs_app/app.coffee
+++ cs_app/app.coffee
@@ -174,7 +174,7 @@
       catch e
         return res.send 500

-    speedObj = {res: res, startTime: new Date().getTime(), lastTime: new Date().getTime(), transferred: 0, speed: 0}
+    speedObj = {res: res, startTime: new Date().getTime(), lastTime: new Date().getTime(), transferred: 0, speed: 0, lastPart: end == filesize - 1}
     speeds.push speedObj

     res.on 'close', () ->
@@ -182,15 +182,18 @@

     res.on 'finish', () ->
       speeds = _.without speeds, speedObj
-      logger.info 'user "' + req.user + '" finished download of "' + req.params.filename + '"'
-      userNZBs = functions.getUserNZBs()
-      nzb = _.find(userNZBs, (n) -> n.nzb + '.tar' is req.params.filename)
-      if nzb
-        if nzb.downloads?
-          nzb.downloads += 1
-        else
-          nzb.downloads = 1
-        functions.writeUserNZBs(userNZBs)
+      if speedObj.lastPart and ((end - start > 2000000 and filesize > 2000000) or filesize < 2000000)
+        logger.info 'user "' + req.user + '" finished download of "' + req.params.filename + '"'
+        userNZBs = functions.getUserNZBs()
+        nzb = _.find(userNZBs, (n) -> n.nzb + '.tar' is req.params.filename)
+        if nzb
+          if nzb.downloads?
+            nzb.downloads += 1
+          else
+            nzb.downloads = 1
+          functions.writeUserNZBs(userNZBs)
+      else
+        logger.info 'user "' + req.user + '" finished partial download of "' + req.params.filename + '"'

     if partial
       res.writeHead 206, { 'Content-Length': end - start + 1, 'Content-Range': 'bytes ' + start + '-' + end + '/' + filesize }


Small fixes.

Small fixes.

--- src/coffee/pricesync.coffee
+++ src/coffee/pricesync.coffee
@@ -35,7 +35,7 @@
       @getCustomerGroup(@retailerClient, CUSTOMER_GROUP_SALE)
       @getPublishedProducts(@retailerClient)
     ]).spread (retailerChannelInMaster, masterCustomerGroup, retailerCustomerGroup, retailerProducts) =>
-      @logger.debug "Retailer products: #{_.size retailerProducts.results}" if @logger
+      console.log "Retailer products: #{_.size retailerProducts}"

       if _.size(retailerProducts) is 0
         @returnResult true, "Nothing to do.", callback
@@ -43,7 +43,7 @@
         updates = []
         _.each retailerProducts, (retailerProduct) =>
           current = retailerProduct.masterData.current
-          current.variant or= []
+          current.variants or= []
           variants = [current.masterVariant].concat current.variants
           _.each variants, (retailerVariant) =>
             updates.push @syncVariantPrices(retailerVariant, retailerCustomerGroup, masterCustomerGroup, retailerChannelInMaster)


Fix passing config to store constructor

Fix passing config to store constructor

Added method to determine the store ID.

--- src/common/FileUtils.coffee
+++ src/common/FileUtils.coffee
@@ -38,8 +38,9 @@
           createTempStore(tempStoreArgs)

       stores = []
-      _.each result, (args, adapterId) ->
-        stores.push createStore(adapterId, id + '-' + adapterId, args.config)
+      _.each result, (adapterArgs, adapterId) =>
+        Setter.merge(adapterArgs, args)
+        stores.push createStore(adapterId, @getStoreId(id, adapterId), adapterArgs.config)

       args = _.extend({
         stores: stores
@@ -66,6 +67,8 @@

       df.resolve(collection)
     df.promise
+
+  getStoreId: (collectionId, adapterId) -> collectionId + '-' + adapterId

 if Meteor.isClient


Display user profile

Display user profile

--- src/concept-coach/base.cjsx
+++ src/concept-coach/base.cjsx
@@ -4,13 +4,15 @@

 {Task} = require '../task'
 {Navigation} = require './navigation'
+CourseRegistration = require '../course/registration'
 UserLoginButton = require '../user/login-button'
 UserLogin = require '../user/login'
+UserProfile = require '../user/profile'

 {ExerciseStep} = require '../exercise'
 {Dashboard} = require '../dashboard'

-CourseRegistration = require '../course/registration'
+
 User = require '../user/model'

 {channel} = require './model'
@@ -48,6 +50,9 @@
     {view} = eventData
     @setState({view}) if view?

+  showTasks: ->
+    @updateView(view: 'task')
+
   getUserState: ->
     course = User.getCourse(@props.collectionUUID)

@@ -72,11 +77,13 @@
       course = User.getCourse(@props.collectionUUID)

       if view is 'task'
-        coach = <Task {...@props} key='task'/>
+        <Task {...@props} key='task'/>
       else if view is 'dashboard'
-        coach = <Dashboard id={course.id}/>
+        <Dashboard id={course.id}/>
       else if view is 'profile'
-        coach = <CourseRegistration {...@props} onComplete={@updateUser} />
+        <UserProfile onComplete={@showTasks} />
+      else
+
bad internal state, no view is set

   render: ->
     {isLoaded, isLoggedIn} = @state


set-current

set-current

--- src/config/inspector.coffee
+++ src/config/inspector.coffee
@@ -33,25 +33,26 @@
     strategy.add_child display_program(child.label(), child.get('value'))
   strategy.put 'height', my.row.spacing*programs._child_count()

+set_current = (world, args) ->
+  current = world.get('current')
+  #console.log "inspect current", current, "args", args
+  if args?
+    current.put('selected', false) if current?
+    current = args
+    current.put('selected', true)
+    world.put('current', current)
+  my.assert current, "No current turtle"
+  current
+
 exports.inspector = {
   _LABEL: "inspector"
   _EXPORTS: ['inspect', 'step']
-  step: (world, args) -> world.call('inspect')
+  step: (world, args) -> world.call('inspect')
   inspect: (world, args) ->
-    current = world.get('current')
-    #console.log "inspect current", current, "args", args
-    if args?
-      current.put('selected', false) if current?
-      current = args
-      current.put('selected', true)
-      world.put('current', current)
-
-    my.assert current, "No current turtle"
+    current = set_current(world, args)
     programs = current.get('programs')
-    my.assert programs, "No programs"
     program = programs.get('program')
     world.replace_child display_program('executing', program) if program?
-    my.assert world.find_child('info'), "has no info"

     strategy = world.find_child('strategy')
     strategy.authority = world.make_world ROW_AUTHORITY


Dynamic children

Dynamic children

--- src/config/inspector.coffee
+++ src/config/inspector.coffee
@@ -53,6 +53,13 @@
       _AUTHORITY: ROW_AUTHORITY
       _CHILDREN: ['curr', 'name', 'pos', 'dir']
     }
+    {
+      _LABEL: 'commands'
+      _AUTHORITY: ROW_AUTHORITY
+      _CHILDREN: (world, args) ->
+        signals = world.get('signals')
+        if signals? then Object.keys signals else []
+    }
   ]

 }


Check if targetPanel is passed as string. If so get the DOM element.

--- js/flight.coffee
+++ js/flight.coffee
@@ -45,6 +45,9 @@
         @pageHistory.push(@targetPanel)
         # target panel passed from options
         @targetPanel = document.querySelector(options.targetPanel)
+        if typeOf @targetPanel is string
+          @targetPanel = document.querySelector(options.targetPanel)
+
         transitionType = @targetPanel.getAttribute("data-transition")
       else
         if options.back


Add setup menu function to be used backbone to assign click to open menu on menu button.

--- js/flight.coffee
+++ js/flight.coffee
@@ -134,6 +134,16 @@
       , 10

     @back = false
+
+  # Private: Binds click event to open menu on menu button
+  #
+  # Returns nothing.
+  setupMenu: (page) ->
+    page.querySelector('.main-menu-btn').addEventListener 'click', =>
+      @slideOutMenu()
+
+    @menuCloseButton.addEventListener 'click', =>
+      @slideOutMenu()

   # Private: Perform a slide out transition for the menu.
   #


Fixed bug in sparse array change handler

--- packages/emberella/lib/controllers/sparse_array_controller.coffee
+++ packages/emberella/lib/controllers/sparse_array_controller.coffee
@@ -521,7 +521,7 @@
   sparseContentArrayDidChange: (array, idx, removedCount, addedCount) ->
     removedObjects = @_PREVIOUS_SPARSE_CONTENT
     addedObjects = array.slice(idx, idx + addedCount)
-    delta = +(addedObjects.length || 0) - +(removedObjects.length || 0)
+    delta = (addedObjects?.length || 0) - (removedObjects?.length || 0)
     set(@, '_length', get(@, '_length') + delta)
     for item, i in removedObjects
       @didReplaceSparseArrayItem(item, addedObjects[i]) if item and item.isSparseArrayItem


compute tool-specific coordinates

compute tool-specific coordinates

--- app/assets/javascripts/components/transcribe/tools/text-tool/index.cjsx
+++ app/assets/javascripts/components/transcribe/tools/text-tool/index.cjsx
@@ -30,11 +30,25 @@

   getInitialState: ->
     # console.log 'TEXT-TOOL::getInitialState(), props = ', @props
+
+    # compute component location
+    data = @props.subject.data
+    switch data.toolName
+      when 'rectangleTool'
+        x = data.x
+        y = data.y + data.height
+      when 'textRowTool'
+        x = data.x
+        y = data.yLower
+      else # default for pointTool
+        x = data.x
+        y = data.y
+    dx: x
+    dy: y
+
     viewerSize: @props.viewerSize
     annotation:
       value: ''
-    dx: @props.subject.data.x# * @props.scale.horizontal
-    dy: @props.subject.data.y# * @props.scale.vertical

   getDefaultProps: ->
     # console.log 'getDefaultProps()'
@@ -115,6 +129,8 @@
   render: ->
     # return null unless @props.viewerSize? && @props.subject?

+    console.log 'PROPS: ', @props
+
     # If user has set a custom position, position based on that:
     style =
       left: "#{@state.dx*@props.scale.horizontal}px"


fix console copying

fix console copying

*again*...

--- keymaps/ink.cson
+++ keymaps/ink.cson
@@ -21,10 +21,10 @@
   'cmd-c': 'native!'

 'ink-console .platform-win32 .ink, .platform-linux .ink':
-  'ctrl-c': 'core:copy!'
+  'ctrl-c': 'core:copy'

 'ink-console .platform-darwin .ink':
-  'cmd-c': 'core:copy!'
+  'cmd-c': 'core:copy'

 'atom-text-editor:not([mini])':
   'escape': 'inline:clear-current'


get ip returns first public ip

get ip returns first public ip

--- code/linode.coffee
+++ code/linode.coffee
@@ -177,7 +177,8 @@
    @client.call 'linode.ip.list',
      'LinodeID': linode_id
      , (err, res) ->
-       callback err, res[0]['IPADDRESS']
+       record = _.find res, (r) -> r.ISPUBLIC is 1
+       callback err, record.IPADDRESS

 # Convert the Linode API JSON representation for a linode server
 # into an instance of the Linode class.


Correct minor copy & paste error

Correct minor copy & paste error

--- knmi-weather.coffee
+++ knmi-weather.coffee
@@ -1,4 +1,4 @@
-# Yamaha AVR plugin
+# KNMI Weather plugin
 module.exports = (env) ->

   events = require 'events'
@@ -198,4 +198,4 @@
   # ###Finally
   # Create a instance of my plugin
   # and return it to the framework.
-  return new KnmiWeatherPlugin+  return new KnmiWeatherPlugin


Fix #193 - Use the new grammar map API

Fix #193 - Use the new grammar map API

--- lib/grammars.coffee
+++ lib/grammars.coffee
@@ -113,10 +113,10 @@
   LiveScript:
     "Selection Based":
       command: "livescript"
-      args: (code)  -> ['-e', code]
+      args: (context)  -> ['-e', context.getCode()]
     "File Based":
       command: "livescript"
-      args: (filename) -> [filename]
+      args: (context) -> [context.filepath]

   Lua:
     "Selection Based":


Update atom theme.

Update atom theme.

--- atom/atom/symlinks/config.cson
+++ atom/atom/symlinks/config.cson
@@ -2,10 +2,10 @@
   "atom-material-ui":
     colors:
       abaseColor:
+        alpha: 1
+        blue: 243
+        green: 150
         red: 33
-        green: 150
-        blue: 243
-        alpha: 1
       genAccent: true
       predefinedColor: "Blue"
     fonts: {}
@@ -17,6 +17,7 @@
     disabledPackages: [
       "linter-eslint"
       "term2"
+      "incompatible-packages"
     ]
     excludeVcsIgnoredPaths: false
     ignoredNames: [
@@ -25,12 +26,11 @@
       ".DS_Store"
     ]
     themes: [
-      "atom-material-ui"
-      "firewatch-syntax"
+      "seti-ui"
+      "monokai-seti"
     ]
   editor:
-    fontFamily: "Anonymous Pro"
-    fontSize: 15
+    fontFamily: "Source Code Pro "
     invisibles: {}
     preferredLineLength: 120
     showInvisibles: true
@@ -47,8 +47,7 @@
   term2: {}
   "trailing-spaces":
     enableForIndentation: true
-  "tree-view":
-    hideVcsIgnoredFiles: true
+  "tree-view": {}
   "vim-mode": {}
   welcome:
     showOnStartup: false


Unregister frame port on onDisconnect.

Unregister frame port on onDisconnect.

I seems that we cannot rely upon either the "unload" event in the
content script or the port's onDisconnect handler there to unregister
frames.

To see this, go to a frame-busy page like this one:

- https://www.theguardian.com/technology/2016/apr/26/apple-iphone-first-revenue-decline-13-years

and then navigate to any other simple page (in the same tab).  Navigate
back and forward with `H` and `L`.

If you watch frames registering anf unregistering, almost all of the
frames from the frame-busy page do not unregister.

Here, we unregister frames on onDisconnect in the background page too.

It is possible that this is the source of the problem mentioned as point
1 in this comment:

- https://github.com/philc/vimium/issues/2081#issuecomment-210980903

And for which #2116 is a workaround.

--- background_scripts/main.coffee
+++ background_scripts/main.coffee
@@ -289,6 +289,7 @@
 Frames =
   onConnect: (sender, port) ->
     [tabId, frameId] = [sender.tab.id, sender.frameId]
+    port.onDisconnect.addListener -> Frames.unregisterFrame {tabId, frameId}
     port.postMessage handler: "registerFrameId", chromeFrameId: frameId

     # Return our onMessage handler for this port.
@@ -390,9 +391,12 @@

   # If an unregistering frame is participating in link-hints mode, then we need to tidy up after it.
   unregisterFrame: (tabId, frameId) ->
-    delete @tabState[tabId]?.ports?[frameId]
-    # We fake "postHintDescriptors" for an unregistering frame.
-    @postHintDescriptors tabId, frameId, hintDescriptors: [] if @tabState[tabId]?.frameIds
+    if @tabState[tabId]?
+      if @tabState[tabId].ports?[frameId]?
+        delete @tabState[tabId].ports[frameId]
+      if @tabState[tabId].frameIds? and frameId in @tabState[tabId].frameIds
+        # We fake an empty "postHintDescriptors" because the frame has gone away.
+        @postHintDescriptors tabId, frameId, hintDescriptors: []

 # Port handler mapping
 portHandlers =


fix support for position=end on Firefox

fix support for position=end on Firefox

--- background_scripts/main.coffee
+++ background_scripts/main.coffee
@@ -116,7 +116,7 @@
     switch position
       when "start" then tabIndex = 0
       when "before" then tabIndex = request.tab.index
-      when "end" then tabIndex = null
+      when "end" then tabIndex = (if Utils.isFirefox() then 9999 else null)
       # "after" is the default case when there are no options.
       else tabIndex = request.tab.index + 1
     tabConfig.index = tabIndex


rollbar: duplicate arrived new activities

--- client/app/Applications/Activity.kdapplication/activitylistcontroller.coffee
+++ client/app/Applications/Activity.kdapplication/activitylistcontroller.coffee
@@ -25,6 +25,8 @@
     options.startWithLazyLoader = yes

     super
+
+    @newActivityArrivedList = {}

     @_state = 'public'

@@ -115,7 +117,18 @@
       view = @addHiddenItem activity, 0
       @activityHeader.newActivityArrived()

+  logNewActivityArrived:(activity)->
+    id = activity.getId?()
+    return unless id
+
+    if @newActivityArrivedList[id]
+      KD.logToExternal msg:"duplicate new activity", activity:activity
+    else
+      @newActivityArrivedList[id] = true
+
   newActivityArrived:(activity)->
+
+    @logNewActivityArrived(activity)

     return unless @_state is 'public'
     unless @isMine activity


typo in homeloginbar

typo in homeloginbar

--- client/landing/app/Applications/Home.kdapplication/Views/homeloginbar.coffee
+++ client/landing/app/Applications/Home.kdapplication/Views/homeloginbar.coffee
@@ -49,7 +49,7 @@
         {entryPoint} = KD.config
         if entryPoint
           requiresLogin =>
-            @appManager.tell 'groups', "showRequestAccessModal", @group, @policy, (err)=>
+            @appManager.tell 'Groups', "showRequestAccessModal", @group, @policy, (err)=>
               unless err
                 @request.hide()
                 @requested.show()
@@ -91,7 +91,7 @@
         href      : "#"
       click       : (event)=>
         @utils.stopDOMEvent event
-        requiresLogin => @appManager.tell 'groups', "joinGroup", @group
+        requiresLogin => @appManager.tell 'Groups', "joinGroup", @group

     @requested    = new CustomLinkView
       tagName     : "a"
@@ -122,7 +122,7 @@
                   color    : "#ffffff"
                   diameter : 16
                 callback   : =>
-                  @appManager.tell 'groups', 'cancelGroupRequest', @group, (err)=>
+                  @appManager.tell 'Groups', 'cancelGroupRequest', @group, (err)=>
                     modal.buttons.Cancel.hideLoader()
                     @handleBackendResponse err, 'Successfully cancelled request!'
                     modal.destroy()


remove useless string quotes and add use time

--- js/inner/build.coffee
+++ js/inner/build.coffee
@@ -285,7 +285,7 @@
       run = @run_queued_time()
       if run
         if use < 1000
-          "#{time(run)}"
+          time(run + use)
         else
           "#{time(use)} waiting, #{time(run)} queued"
       else


Conditionally include deprecations in GrammarRegistry

--- src/grammar-registry.coffee
+++ src/grammar-registry.coffee
@@ -1,14 +1,6 @@
-_ = require 'underscore-plus'
-{deprecate} = require 'grim'
-{specificity} = require 'clear-cut'
-{Subscriber} = require 'emissary'
 {Emitter} = require 'event-kit'
+{includeDeprecations, deprecate} = require 'grim'
 FirstMate = require 'first-mate'
-{ScopeSelector} = FirstMate
-ScopedPropertyStore = require 'scoped-property-store'
-PropertyAccessors = require 'property-accessors'
-
-{$, $$} = require './space-pen-extensions'
 Token = require './token'

 # Extended: Syntax class holding the grammars used for tokenizing.
@@ -19,16 +11,12 @@
 # language-specific comment regexes. See {::getProperty} for more details.
 module.exports =
 class GrammarRegistry extends FirstMate.GrammarRegistry
-  PropertyAccessors.includeInto(this)
-  Subscriber.includeInto(this)
-
   @deserialize: ({grammarOverridesByPath}) ->
     grammarRegistry = new GrammarRegistry()
     grammarRegistry.grammarOverridesByPath = grammarOverridesByPath
     grammarRegistry

   atom.deserializers.add(this)
-  atom.deserializers.add(name: 'Syntax', deserialize: @deserialize) # Support old serialization

   constructor: ->
     super(maxTokensPerLine: 100)
@@ -49,28 +37,38 @@
   # Returns a {Grammar}, never null.
   selectGrammar: (filePath, fileContents) -> super

+  clearObservers: ->
+    @off() if includeDeprecations
+    @emitter = new Emitter
+
+if includeDeprecations
+  PropertyAccessors = require 'property-accessors'
+  PropertyAccessors.includeInto(GrammarRegistry)
+
+  {Subscriber} = require 'emissary'
+  Subscriber.includeInto(GrammarRegistry)
+
+  # Support old serialization
+  atom.deserializers.add(name: 'Syntax', deserialize: GrammarRegistry.deserialize)
+
   # Deprecated: Used by settings-view to display snippets for packages
-  @::accessor 'propertyStore', ->
+  GrammarRegistry::accessor 'propertyStore', ->
     deprecate("Do not use this. Use a public method on Config")
     atom.config.scopedSettingsStore

-  addProperties: (args...) ->
+  GrammarRegistry::addProperties = (args...) ->
     args.unshift(null) if args.length == 2
     deprecate 'Consider using atom.config.set() instead. A direct (but private) replacement is available at atom.config.addScopedSettings().'
     atom.config.addScopedSettings(args...)

-  removeProperties: (name) ->
+  GrammarRegistry::removeProperties = (name) ->
     deprecate 'atom.config.addScopedSettings() now returns a disposable you can call .dispose() on'
     atom.config.scopedSettingsStore.removeProperties(name)

-  getProperty: (scope, keyPath) ->
+  GrammarRegistry::getProperty = (scope, keyPath) ->
     deprecate 'A direct (but private) replacement is available at atom.config.getRawScopedValue().'
     atom.config.getRawScopedValue(scope, keyPath)

-  propertiesForScope: (scope, keyPath) ->
+  GrammarRegistry::propertiesForScope = (scope, keyPath) ->
     deprecate 'Use atom.config.getAll instead.'
     atom.config.settingsForScopeDescriptor(scope, keyPath)
-
-  clearObservers: ->
-    @off()
-    @emitter = new Emitter


fix for redrawing the marker, too

fix for redrawing the marker, too

Former-commit-id: 2ab56e8047c15b6ba9010ada877086f77f7aab8f [formerly 9c5931c5f813862fb83e4cb3c264f288e33c4347]
Former-commit-id: a0e724b532a0e1af26ba5ecafd5916cf5390ced5

--- js/msa/zoombar.coffee
+++ js/msa/zoombar.coffee
@@ -37,7 +37,7 @@
       @msa.zoomer.setZoomLevel(value)
       @msa.config.autofit = false
       @msa.redraw('stage')
-      #@msa.redraw('marker')
+      @msa.redraw('marker')
       @locked = false

     draw: ->


fixed error message

fixed error message

--- src/crystal/update.coffee
+++ src/crystal/update.coffee
@@ -96,7 +96,7 @@
 					tarball_url = release.tarball_url
 					break
 			if !module_version
-				throw new Error "No matches for Module (#{module_name}) with version (#{module_version_query}). Try: crystal update"
+				throw new Error "No matches for Module (#{module_name}) with version (#{module_version_query})"

 			console.log "Found version (#{module_version}) for module (#{module_name}).".green


Simplify directory-view's unsubscription from its model

We can just namespace it by the extension name since this the tree view
will only have one directory view for a given directory. There's no need
to disambiguate further.

--- src/directory-view.coffee
+++ src/directory-view.coffee
@@ -63,13 +63,13 @@
     @isExpanded = false

   watchEntries: ->
-    @directory.on "contents-change.#{@directory.path}", =>
+    @directory.on "contents-change.tree-view", =>
       @buildEntries()
       @trigger "tree-view:directory-modified"

   unwatchEntries: ->
     @unwatchDescendantEntries()
-    @directory.off ".#{@directory.path}"
+    @directory.off ".tree-view"

   unwatchDescendantEntries: ->
     @find('.expanded.directory').each ->


<model> Driver - Correcting how paths are handled.

--- server/models/driver.coffee
+++ server/models/driver.coffee
@@ -111,12 +111,14 @@
 	###
 	@create: (data, callback) ->
 		superCreate = super
-
-		file = data.file
-		unless file.ext = path.extname(file.originalFilename) and file.ext in ['.zip', '.tar', '.tar.bz2', '.tar.gz', '.js', '.coffee']
+
+		file =
+			path : data.path
+
+		unless file.ext = path.extname(file.path) and file.ext in ['.zip', '.tar', '.tar.bz2', '.tar.gz', '.js', '.coffee']
 			callback 'Unknown file extension', null
 			return cleanUp()
-		unless file.name = path.basename(file.originalFilename, file.ext)
+		unless file.name = path.basename(file.path, file.ext)
 			callback 'Unknown file name', null
 			return cleanUp()


Properly normalize code before comparing (fix #110)

--- server/models/submit.coffee
+++ server/models/submit.coffee
@@ -4,6 +4,7 @@
 import User from './user'

 import calculateHashes from '../hashes/calculateHashes'
+import normalizeCode from '../lib/normalizeCode'

 import awaitAll from '../../client/lib/awaitAll'
 import logger from '../log'
@@ -56,11 +57,9 @@

 submitsSchema.methods.equivalent = (other) ->
     if @user == "394891" and @_id == "18336986p2951" and other._id == "2088r683956p2951"
-        logger.log "Compare submits ", @_id, other._id, @comments.length > 0, @outcome == "AC" or @outcome == "IG" or @outcome == "DQ", @force, @user == other.user, @problem == other.problem, outcomeType(@outcome) == outcomeType(other.outcome), @source.replace("\r", "") == other.source.replace("\r", ""), Math.abs(@time - other.time)
-        logger.log "s1=`#{Buffer.from(@source)}` `#{Buffer.from(@source.replace("\r", ""))}`"
-        logger.log "s2=`#{Buffer.from(other.source)}`, `#{Buffer.from(other.source.replace("\r", ""))}`"
-        s1 = @source.replace("\r", "")
-        s2 = other.source.replace("\r", "")
+        logger.log "Compare submits ", @_id, other._id, @comments.length > 0, @outcome == "AC" or @outcome == "IG" or @outcome == "DQ", @force, @user == other.user, @problem == other.problem, outcomeType(@outcome) == outcomeType(other.outcome), @source.replace(/\r/g, "") == other.source.replace(/\r/g, ""), Math.abs(@time - other.time)
+        s1 = normalizeCode(@source)
+        s2 = normalizeCode(other.source)
         logger.log "s1,s2.length=", s1.length, s2.length, @_id, other._id
         ll = ""
         ll += "s1,s2.length=#{s1.length}, #{s2.length} "
@@ -80,7 +79,7 @@
     return @user == other.user \
         and @problem == other.problem \
         and outcomeType(@outcome) == outcomeType(other.outcome) \
-        and @source.replace("\r", "") == other.source.replace("\r", "") \
+        and normalizeCode(@source) == normalizeCode(other.source) \
         and (@language == other.language \
              or Math.abs(@time - other.time) < 1500 \
              or Math.abs(Math.abs(@time - other.time) - 3 * 60 * 60 * 1000) < 1500)


Remove delay It doesn't prevent the function from being called a million times, it just delays the million calls by 300 milliseconds.

--- plugins/image.coffee
+++ plugins/image.coffee
@@ -276,17 +276,15 @@
                     position = helper.calcPosition(ui, offset)
                     $(event.target).remove() if internalDrop

-                    createTmpObject = ->
-                        if position is "middle"
-                            if tmpObject.parent("div").length is 0
-                                tmpObject.wrap $("<div/>")
-                                tmpObject.css "display", "none"
-                            tmpObject.parent("div").addClass "tmpBig inlineImage-" + position
-                        else
-                            $(".tmpBig").replaceWith $(".tmp, editable")  if $(".tmpBig")
-                            tmpObject.removeClass("inlineImage-middle inlineImage-left inlineImage-right").addClass("inlineImage-" + position).css "display", "block"
-                        helper.showOverlay position
-                    helper.delayAction createTmpObject, 150
+                    if position is "middle"
+                        if tmpObject.parent("div").length is 0
+                            tmpObject.wrap $("<div/>")
+                            tmpObject.css "display", "none"
+                        tmpObject.parent("div").addClass "tmpBig inlineImage-" + position
+                    else
+                        $(".tmpBig").replaceWith $(".tmp, editable")  if $(".tmpBig")
+                        tmpObject.removeClass("inlineImage-middle inlineImage-left inlineImage-right").addClass("inlineImage-" + position).css "display", "block"
+                    helper.showOverlay position

                 handleStartEvent: (event, ui) ->
                     $(document).trigger('startPreventSave');


Close autocomplete on no results

Close autocomplete on no results

--- app/assets/javascripts/site_search.js.coffee
+++ app/assets/javascripts/site_search.js.coffee
@@ -29,6 +29,8 @@
                     suggestionHighlighted: item.suggestionHighlighted
                     value: item.suggestion
                   }
+              else
+                $searchField.autocomplete("close")
         minLength: 2
         select: (event, ui) ->
           $searchField.val(ui.item.value)


prevent drop in userstory in taskboard

prevent drop in userstory in taskboard

--- app/coffee/modules/taskboard/sortable.coffee
+++ app/coffee/modules/taskboard/sortable.coffee
@@ -62,6 +62,7 @@
                 copySortSource: false,
                 copy: false,
                 mirrorContainer: $el[0],
+                accepts: (el, target) -> return !$(target).hasClass('taskboard-userstory-box')
                 moves: (item) -> return $(item).hasClass('taskboard-task')
             })


Add shortcuts for pageup and pagedown

Add shortcuts for pageup and pagedown

--- keymaps/vim-mode.cson
+++ keymaps/vim-mode.cson
@@ -103,8 +103,10 @@
   'g g': 'vim-mode:move-to-start-of-file'
   'ctrl-u': 'vim-mode:scroll-half-screen-up'
   'ctrl-b': 'vim-mode:scroll-full-screen-up'
+  'pageup': 'vim-mode:scroll-full-screen-up'
   'ctrl-d': 'vim-mode:scroll-half-screen-down'
   'ctrl-f': 'vim-mode:scroll-full-screen-down'
+  'pagedown': 'vim-mode:scroll-full-screen-down'
   'ctrl-e': 'vim-mode:scroll-down'
   'ctrl-y': 'vim-mode:scroll-up'
   'z enter': 'vim-mode:scroll-cursor-to-top'


Fix test descriptions

Fix test descriptions

--- tests/src/ScriptsTests.coffee
+++ tests/src/ScriptsTests.coffee
@@ -92,7 +92,7 @@
         '--production'
       )

-    it "should launch meteor with --port $TEST_PORT, set PORT to TEST_PORT and ROOT_URL to 'http://localhost:$TEST_PORT/'", (done)->
+    it "should launch meteor with --port $TEST_PORT, set PORT to $TEST_PORT and ROOT_URL to 'http://localhost:$TEST_PORT/'", (done)->
       execOptions.env.TEST_PORT = 3200
       execTestPackages(
         done,


Fixes bug where sliders may display in 'simple mode' #104658206

https://www.pivotaltracker.com/story/show/104658206

--- src/code/stores/simulation-store.coffee
+++ src/code/stores/simulation-store.coffee
@@ -1,8 +1,9 @@
-GraphStore   = require('./graph-store').store
-Simulation   = require "../models/simulation"
-CodapConnect = require '../models/codap-connect'
-TimeUnits    = require '../utils/time-units'
-tr           = require '../utils/translate'
+GraphStore         = require('./graph-store').store
+AppSettingsActions = require('./app-settings-store').actions
+Simulation         = require "../models/simulation"
+CodapConnect       = require '../models/codap-connect'
+TimeUnits          = require '../utils/time-units'
+tr                 = require '../utils/translate'

 SimulationActions = Reflux.createActions(
   [
@@ -17,7 +18,7 @@
 )

 SimulationStore   = Reflux.createStore
-  listenables: [SimulationActions]
+  listenables: [SimulationActions, AppSettingsActions]

   init: ->
     defaultUnit = TimeUnits.defaultUnit
@@ -36,6 +37,10 @@
       stepUnitsName: unitName
       timeUnitOptions: options
     @codapConnect = CodapConnect.instance 'building-models'
+
+  # From AppSettingsStore actions
+  onDiagramOnly: ->
+    SimulationActions.collapseSimulationPanel()

   onExpandSimulationPanel: ->


Remove debugging comments

Remove debugging comments

--- src/code/views/value-slider-view.coffee
+++ src/code/views/value-slider-view.coffee
@@ -39,9 +39,7 @@
     "editing-max": false

   updateValue: (locValue,dragging) ->
-    console.log("locValue = "+locValue)
     value = @valueFromSliderUI(locValue)
-    console.log("  value = "+value)
     @props.onValueChange value

   updateRange: (property, value) ->


add dynamic service

add dynamic service

--- src/coffee/services/registration.coffee
+++ src/coffee/services/registration.coffee
@@ -8,6 +8,7 @@

 angular.module('CoolFormServices').
   factory('registrationService', (
+    directivesService,
     validationService,
     eventService,
     networkService,
@@ -57,6 +58,7 @@
           changeValue(k, null)

       services =
+        directives: directivesService()
         display: display
         registerField: registerField
         validateField: (fieldName) -> validation.validateField(fieldName, values)


more windows path fixes

more windows path fixes

--- lib/build.coffee
+++ lib/build.coffee
@@ -107,16 +107,14 @@
     if(@isDeployRunning())
       clearTimeout @finishedTimer
       if(atom.workspace.getActiveTextEditor().buffer?.file?)
-
+        isWin = /^win/.test(process.platform)
         path = atom.workspace.getActiveTextEditor().buffer.file.path
-
-        projectPath = @root+'/src/'
+        projectPath = if isWin then @root+'\\src\\' else @root+'/src/'
         pathHeRegex = ///#{projectPath}///
         if(path.match(pathHeRegex))
           fileBaseName = atom.workspace.getActiveTextEditor().buffer.file.getBaseName()
           folderNamePath = path.replace ///#{fileBaseName}///, ''
           folderNamePath = folderNamePath.replace pathHeRegex, ''
-          isWin = /^win/.test(process.platform)
           folderName =  if isWin then folderNamePath.split("\\") else folderNamePath.split "/"
           fileName = fileBaseName.split "."
           if(fileName.length > 1)


Added Comic.atUrl

Added Comic.atUrl

And some extra noise in Comic.at on error

--- lib/comic.coffee
+++ lib/comic.coffee
@@ -94,6 +94,12 @@
       @votes = res or 0
       gotVotes = true

+  # Fetch a comic by the @url paramater, which is the URL of the
+  # image. Does a lookup of the time, then forwards it to `Comic.at`
+  @atUrl: (url, cb) ->
+    redis.zscore @key(), url, (err, res) =>
+      return cb(err) if err
+      return Comic.at(res, cb)

   # Return a comic stamped at `stamp` to caller by
   # invoking callback as `cb(err, Comic)` if it is found.
@@ -101,7 +107,7 @@
   @at: (stamp, cb) ->
     redis.zrangebyscore [@key(), stamp, stamp], (err, res) ->
       return cb(err) if err
-      return cb("Not found") unless res.length > 0
+      return cb("Not found: #{stamp}") unless res.length > 0

       # If we found a comic, we'll stuff what we know about it
       # and invoke `Comic#update` and pass our callback down to it


Observe J.ReactivesQueue and perform recalcs as orders are queued along with status updates

--- reactives.coffee
+++ reactives.coffee
@@ -1,2 +1,9 @@
 J.ReactivesQueue = new Mongo.Collection "jframework_reactives"
 J.ReactivesQueue._ensureIndex priority: -1
+
+J.ReactivesQueue.find({ status: "new" }, { sort: { priority: -1 } }).observe
+    added: (recalcItem) ->
+        J.models[recalcItem.mName].rawCollection.findAndModify recalcItem.mId, [], $set: { status: "inProgress" }
+        instance = J.models[recalcItem.mName].find recalcItem.mId
+        J.denorm.recalc instance, recalcItem.rName, new Date(), ->
+            J.models[recalcItem.mName].update recalcItem.mId, [], $set: { status: "done" }


remove _path fix, no longer needed

remove _path fix, no longer needed

--- lib/index.coffee
+++ lib/index.coffee
@@ -142,7 +142,6 @@
     set_locals = (types) ->
       W.map types, (t) =>
         @roots.config.locals.contentful[t.name] = t.content
-        @roots.config.locals._path = undefined

     ###*
      * Compiles single entry views for content types


Exits when connection gets closed

Exits when connection gets closed

--- api/lib/db.coffee
+++ api/lib/db.coffee
@@ -7,7 +7,12 @@
 fs = require 'fs'
 path = require 'path'
 { MONGOHQ_URL } = process.env
+debug = require('debug') 'api'

 collections = ['articles', 'users', 'sections', 'artists']
-module.exports = mongojs MONGOHQ_URL, collections
+db = mongojs MONGOHQ_URL, collections
+db.on 'close', ->
+  process.exit(1)
+
+module.exports = db
 module.exports.collections = collections


Make sure the container is visible also

Make sure the container is visible also

--- js-library/app/js/jail_iframe/classes/paragraph_buttons.coffee
+++ js-library/app/js/jail_iframe/classes/paragraph_buttons.coffee
@@ -34,8 +34,11 @@
       'div#page', 'div.page', 'div#site', 'div.site'
     ]

-    for s in selectors when $(s).length == 1 # Only match if selector is unique
-      return "#{s} p, #{s} h2, #{s} h3, #{s} h4, #{s} h5, #{s} h6, #{s} li, #{s} dd, #{s} dt"
+    for s in selectors
+      $element = $(s)
+      # Only match if selector is unique
+      if $element.length == 1 && $element.is(':visible')
+        return "#{s} p, #{s} h2, #{s} h3, #{s} h4, #{s} h5, #{s} h6, #{s} li, #{s} dd, #{s} dt"

     null


Remove custom TPR/FPR computations.

Remove custom TPR/FPR computations.

--- src/ext/modules/routines.coffee
+++ src/ext/modules/routines.coffee
@@ -333,26 +333,6 @@
     cms = for tp, i in tps
       [[tns[i], fps[i]], [fns[i], tp]]

-    tprs = for tp, i in tps
-      tp / (tp + fns[i])
-
-    fprs = for fp, i in fps
-      fp / (fp + tns[i])
-
-    scores.columns.push
-      name: 'TPR'
-      description: 'True Positive Rate'
-      format: '%f'
-      type: 'double'
-    scores.data.push tprs
-
-    scores.columns.push
-      name: 'FPR'
-      description: 'False Positive Rate'
-      format: '%f'
-      type: 'double'
-    scores.data.push fprs
-
     scores.columns.push
       name: 'CM'
       description: 'CM'
@@ -361,7 +341,6 @@
     scores.data.push cms

     metrics
-

   extendCloud = (cloud) ->
     render_ cloud, H2O.CloudOutput, cloud
@@ -604,20 +583,6 @@
     render_ models, H2O.ModelsOutput, models

   read = (value) -> if value is 'NaN' then null else value
-
-  #TODO obsolete
-  inspectBinomialConfusionMatrices = (opts, predictions) -> ->
-    vectors = [
-      createList 'CM', (concatArrays (prediction.confusion_matrices for prediction in predictions)), formatConfusionMatrix
-      createVector 'TPR', TNumber, concatArrays (map prediction.confusion_matrices, computeTruePositiveRate for prediction in predictions)
-      createVector 'FPR', TNumber, concatArrays (map prediction.confusion_matrices, computeFalsePositiveRate for prediction in predictions)
-      createFactor 'key', TString, concatArrays (repeatValues prediction.confusion_matrices.length, prediction.model.name + ' on ' + prediction.frame.name for prediction in predictions)
-    ]
-
-    createDataframe 'Confusion Matrices', vectors, (sequence (head vectors).count()), null,
-      description: "Confusion matrices for the selected predictions"
-      origin: formulateGetPredictionsOrigin opts
-      plot: "plot inspect 'Confusion Matrices', #{formulateGetPredictionsOrigin opts}"

   extendPredictions = (opts, predictions) ->
     render_ predictions, H2O.PredictsOutput, opts, predictions


Check executable path before prefixing cmd

--- lib/linter-scalac.coffee
+++ lib/linter-scalac.coffee
@@ -1,4 +1,5 @@
 {exec, child} = require('child_process')
+path = require('path')
 fs = require('fs')
 Linter = require(atom.packages.getLoadedPackage('linter').path + '/lib/linter')

@@ -40,7 +41,11 @@
 		@optionsSubscription.dispose()

 	lintFile: (filePath, callback) ->
-		command = @executablePath + '/' + @cmd + ' ' + filePath + ' ' + @options
+		if @executablePath
+			command = @executablePath + '/' + @cmd
+		else
+			command = @cmd
+		command += ' ' + filePath + ' ' + @options
 		exec(command, cwd: @cwd, (error, stdout, stderr) => if stderr then @processMessage(stderr, callback))

 module.exports = LinterScalac


Don't show duplicate packages

Don't show duplicate packages

Package metadata can have duplicates for linked packages so run
a _.uniq on it so duplicates will be filtered out.

Closes #13

--- lib/package-panel.coffee
+++ lib/package-panel.coffee
@@ -79,7 +79,8 @@
     @installedPackages.empty()
     @installedPackages.append @createLoadingView('Loading installed packages\u2026')

-    packages = _.sortBy(atom.getAvailablePackageMetadata(), 'name')
+    packages = _.uniq atom.getAvailablePackageMetadata(), ({name}) -> name
+    packages = _.sortBy(packages, 'name')
     packageManager.renderMarkdownInMetadata packages, =>
       @installedPackages.empty()
       @installedThemes.empty()


test/mock: added test for findById

test/mock: added test for findById

--- test/mock.coffee
+++ test/mock.coffee
@@ -37,3 +37,10 @@
           students[1].properties (err, data) =>
             assert.deepEqual data, {foo: 'baz'}
             done()
+
+  _.each ['51a5a56f4867bbdf51054055', '51a5a56f4867bbdf51054054'], (id) ->
+    it "supports findById(#{id})", (done) ->
+      @clever.Student.findById id, (err, student) ->
+        assert.ifError err
+        assert.equal student.get('id'), id
+        done()


test #9

test #9

--- lib/touch-gesture.coffee
+++ lib/touch-gesture.coffee
@@ -8,7 +8,7 @@
 module.exports =
 class TouchGesture
   constructor: (options) ->
-    {@onThreeLeft,@element} = options
+    {@onThreeLeft,@element=document.body} = options

     @addEvent 'touchstart',@touchStart
     @addEvent 'touchmove',@touchMove


Add missing label

Add missing label

--- app/lib/en.coffee
+++ app/lib/en.coffee
@@ -1380,6 +1380,7 @@
     sdss_id: 'SDSS ObjectID'
     iau_id: 'IAU designation'
     hubble_id: 'Hubble ID'
+    gama_cataid: 'GAMA CATAID'
     petro_rad: 'Size (Petrosian radius)'
     kron_rad: 'Size (Kron radius)'
     band: 'Bands'


Add tipsy support for tooltips and make it default

--- core/KDView.coffee
+++ core/KDView.coffee
@@ -722,13 +722,23 @@

   setTooltip:(o = {})->

+    placementMap =
+           above : "s"
+           below : "n"
+           left  : "e"
+           right : "w"
+
     o.title     or= "Default tooltip title!"
     o.placement or= "above"
     o.offset    or= 0
     o.delayIn   or= 0
     o.html      or= yes
     o.animate   or= no
+    o.opacity   or= 0.9
     o.selector  or= null
+    o.engine    or= "tipsy" # we still can use twipsy
+    o.gravity   or= placementMap[o.placement]
+    o.fade      or= o.animate

     @listenTo
       KDEventTypes        : "viewAppended"
@@ -736,7 +746,17 @@
       callback            : =>
         # log "get rid of this timeout there should be an event after template update"
         @utils.wait =>
-          @$(o.selector).twipsy o
+          @$(o.selector)[o.engine] o
+
+  getTooltip:(o = {})->
+    o.selector or= null
+    return @$(o.selector)[0].getAttribute "original-title" or @$(o.selector)[0].getAttribute "title"
+
+  updateTooltip:(o = {})->
+    o.selector or= null
+    o.title    or= ""
+    if o.title
+      @$(o.selector)[0].setAttribute "original-title", o.title

   listenWindowResize:->


add tests calling zlib.gzip directly (for debugging)

--- services/document-updater/test/unit/coffee/ZipManager/ZipManager.coffee
+++ services/document-updater/test/unit/coffee/ZipManager/ZipManager.coffee
@@ -4,6 +4,7 @@
 zipModulePath = "../../../../app/js/ZipManager"
 redisModulePath = "../../../../app/js/RedisManager"
 SandboxedModule = require('sandboxed-module')
+zlib = require('zlib')

 MIN_SIZE = 9999

@@ -57,6 +58,16 @@
 				@docLines.should.eql lines
 				done()

+	describe "calling node zlib.gzip directly", ->
+		it "should compress the string 'hello world' within the timeout", (done) ->
+			zlib.gzip "hello world", done
+
+		it "should compress a 10k string within the timeout", (done) ->
+			text = ""
+			while text.length < 10*1024
+				text = text + "helloworld"
+			zlib.gzip text, done
+
 	describe "for a large document (with compression enabled)", ->
 		rclient = null
 		beforeEach (done) ->
@@ -90,6 +101,7 @@
 			@docLines = []
 			while @docLines.join('').length <= MIN_SIZE
 				@docLines.push "this is a long line in a long document"
+			console.log "length of doclines", @docLines.join('').length
 			@callback = sinon.stub()
 			@RedisManager.setDocument @doc_id, @docLines, @version, () =>
 				@callback()


Modify structure.

Modify structure.

--- lib/movie.coffee
+++ lib/movie.coffee
@@ -8,16 +8,16 @@

 class Movie
-  constructor : (string_of_id_or_unixtime) ->
-    @.set_type string_of_id_or_unixtime
+  constructor : (@provisional_id) ->
+    @type = get_type()

-  set_type : (string_of_id_or_unixtime) ->
-    if _(string_of_id_or_unixtime).startsWith 'nm'
-      @type = 'Niconico Movie Maker'
-    else if _(string_of_id_or_unixtime).startsWith 'sm'
-      @type = 'Smile Video'
-    else
-      @type = 'unknown'
-
+  get_type : ->
+    switch _(@provisional_id)
+      when startsWith 'nm'
+        'Niconico Movie Maker'
+      when startsWith 'sm'
+        'Smile Video'
+      else
+        'unknown'

 module.exports = Movie


Small change in observer code

Small change in observer code

--- lib/pages.coffee
+++ lib/pages.coffee
@@ -584,7 +584,7 @@

     handle2 = c.observeChanges
       movedBefore: ((sub, id, before) ->
-        at=-1
+        at = -1
         ref = false
         (@Collection.find get "filters",
           sort: get "sort"
@@ -592,12 +592,11 @@
           skip: skip
           limit: get "perPage"
         ).forEach (o, i) =>
-          if !ref and o._id is before
+          if ref
+            sub.changed(@id, o._id, _.object([["_#{@id}_i", i + 1]]))
+          else if o._id is before
             ref = true
             at = i
-          if ref
-            sub.changed(@id, o._id, _.object([["_#{@id}_i", i + 1]]))
-
         sub.changed(@id, id, _.object([["_#{@id}_i", at]]))
       ).bind @, sub


Specify address listened by proxy as 127.1

--- lib/proxy.coffee
+++ lib/proxy.coffee
@@ -245,7 +245,7 @@
       if err.code == 'EADDRINUSE'
         @_setStatus 'EADDRINUSE'
     listenPort = config.get 'poi.port', 12450
-    @server.listen listenPort, =>
+    @server.listen listenPort, '127.0.0.1', =>
       log "Proxy listening on #{listenPort}"
       @_setStatus "LISTENING"
   _setStatus: (str) ->


Don't print undefined when you mean empty string

--- lib/proxy.coffee
+++ lib/proxy.coffee
@@ -29,8 +29,8 @@
   proxyServer = httpProxy.createServer(options)
   proxyServer.listen(config.listen)
   logger.info(
-    "#{"SSL enabled. " if use_ssl}Listening for HTTP#{"S" if use_ssl} " +
-    "on port #{config.listen}"
+    "#{if use_ssl then "SSL enabled. " else ""}Listening for " +
+    "HTTP#{if use_ssl then "S" else ""} on port #{config.listen}"
   )

 module.exports = {start}


Cleanup

Cleanup

--- lib/spigg.coffee
+++ lib/spigg.coffee
@@ -1,81 +1,26 @@
-events =  require("events")
-crypto =  require("crypto")
-
 class spiggEntity
   constructor: (d, defs) ->
     @data = {}
     @default_val = @default_val ? null
     @_setDefaults() if @defaults and !defs
     @fields = @fields ? {}
-    @events = new events.EventEmitter()
-    @events.on "change", @_setChanged
-    @revision = 0
-    @revisions = {}
-    @set(d)
+    #events =  require("events")
+    #crypto =  require("crypto")
+    #@events = new events.EventEmitter()
+    #@events.on "change", @_setChanged
+    #@revision = 0
+    #@revisions = {}
+    @_setObject(d) if d

-  _setDefaults: ->
-    @data[k] = v for k, v of @defaults if @defaults isnt {}
-    @
-
   get: (k) ->
     return @data unless k
     @data[k] ? @default_val

   set: (k, v) ->
-    return @setObject(k) unless v
-
-
-
-  _set: (k, v, self) ->
-
-    method = '_set' + k.substr(0, 1).toUpperCase() + k.substr(1)
-
-    if typeof self[method] isnt 'function'
-      if Object.keys(self.fields).length >= 1
-        self.data[k] = v if self.fields[k]
-      else
-        self[k] = v
-
-    else
-
-      self[method](v, self.data, ->
-        console.log "IN CALLBACK"
-        self.events.emit "change", k, arguments[0]
-        self.data[k] = arguments[0]
-        console.log "args", arguments
-      )
+    return @_setObject(k) if typeof k is 'object'
+    @_set k, v
+

-    ucfirst = (str) -> str.substr(0, 1).toUpperCase() + str.substr(1)
-
-    if typeof @['_set'+ ucfirst(k)] is 'function'
-      v = @['_set'+ ucfirst(k)](v, @.data)
-
-    if Object.keys(@fields).length >= 1
-      @data[k] = v if @fields[k]
-    else
-      @data[k] = v
-    @
-
-  set: (k, v) ->
-    return @setObject(k) unless v
-    customSetter = '_set'+k.substr(0, 1).toUpperCase()+k.substr(1)
-    @events.emit "change", @
-
-    if typeof @[customSetter] is 'function'
-      @data[k] = @[customSetter] v, @data
-    else
-      if Object.keys(@fields).length >= 1
-        @data[k] = v if @fields[k]
-      else
-        @data[k] = v
-    @
-
-
-  setObject: (o) ->
-    for k, v of o
-      @set(k, v)
-    @
-
   setUnsafe: (k, v) ->
     @data[k] = v
     @
@@ -103,9 +48,25 @@
     @data = fn @data
     @

+  _setDefaults: ->
+    @data[k] = v for k, v of @defaults if @defaults isnt {}
+    @
+
+  _set: (k, v) ->
+    method = '_set' + k.substr(0, 1).toUpperCase() + k.substr(1)
+    v = @[method](v, @.data) if typeof @[method] is 'function'
+
+    if @fields isnt {}
+      @data[k] = v if @fields[k]
+    else
+      @data[k] = v
+
+   _setObject: (o) ->
+     @_set(k, v) for k, v of o
+
   _setChanged: (context) ->
     context.revision++
-    #md5 = crypto.createHash('md5').update(JSON.stringify context.data).digest("hex")
+    md5 = crypto.createHash('md5').update(JSON.stringify context.data).digest("hex")
     context.revisions[context.revision] = context.data
     context.changed = true


verbose rpc on deploy

verbose rpc on deploy

--- lib/token.coffee
+++ lib/token.coffee
@@ -24,7 +24,7 @@

   @deployContract: ->
     quiet = nodeEnv is 'test'
-    {output} = run "node_modules/.bin/truffle deploy -e #{nodeEnv}", {quiet}
+    {output} = run "node_modules/.bin/truffle deploy -e #{nodeEnv} --verbose-rpc", {quiet}
     pattern = /Deployed.+to address.+(0x[0-9a-f]{40})/
     contractAddress = pattern.exec(output)?[1]
     unless contractAddress


Bug fix for url parsing

Bug fix for url parsing

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -24,15 +24,15 @@
   @parseUrl: (url) ->
     url_parts = URL.parse(url)
     database_parts = url_parts.pathname.split('/')
-    database_parts.pop()
-    database_parts = url_parts.pathname.split('/')
     table = database_parts.pop()
+    database = database_parts[database_parts.length-1]
     url_parts.pathname = database_parts.join('/')

     result = {
       host: url_parts.hostname
       port: url_parts.port
-      database: URL.format(url_parts)
+      database_path: URL.format(url_parts)
+      database: database
       table: table
       model_name: inflection.classify(inflection.singularize(table))
     }
@@ -73,14 +73,14 @@
   @createJoinTableModel: (relation1, relation2) ->
     model_name1 = inflection.pluralize(inflection.underscore(relation1.model_type.model_name))
     model_name2 = inflection.pluralize(inflection.underscore(relation2.model_type.model_name))
-    table_name = if model_name1.localeCompare(model_name2) < 0 then "#{model_name1}_#{model_name2}" else "#{model_name2}_#{model_name1}"
+    table = if model_name1.localeCompare(model_name2) < 0 then "#{model_name1}_#{model_name2}" else "#{model_name2}_#{model_name1}"

     schema = {}
     schema[relation1.foreign_key] = ['Integer', indexed: true]
     schema[relation2.foreign_key] = ['Integer', indexed: true]

     class JoinTable extends Backbone.Model
-      url: "#{Utils.parseUrl(relation1.model_type::url).database}/#{table_name}"
+      url: "#{Utils.parseUrl(relation1.model_type::url).database_path}/#{table}"
       @schema = schema
       sync: relation1.model_type.createSync(JoinTable)


Make 'git apply' handling more robust

Make 'git apply' handling more robust

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -128,7 +128,18 @@
     ret = err: [], out: [], cmd: git + ' ' + options.join ' '
     child.stdout.on 'data', (chunk)-> ret.out.push ''+chunk
     child.stderr.on 'data', (chunk)-> ret.err.push ''+chunk
-    child.on 'exit', (code, signal)-> resolve Object.assign ret, {code, signal}
+    child.on 'exit', (code, signal)->
+      if code
+        reject Object.assign ret, {code, signal}
+        # If you are listening to both the 'exit' and 'error' events,
+        # it is important to guard against accidentally invoking handler
+        # functions multiple times.
+        reject = ->
+      else
+        resolve Object.assign ret, {code, signal}
+    child.on 'error', (err)->
+      reject Object.assign ret, {err}
+      reject = ->
     child.stdin.write patch
     child.stdin.end()


Use getDirectories instead of getRootDirectory

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -38,7 +38,7 @@
     fxn() if @isDartProject()

   @isDartProject: =>
-    pubspec = atom.project.getRootDirectory().getFile('pubspec.yaml')
+    pubspec = atom.project.getDirectories()[0].getFile('pubspec.yaml')
     pubspec.existsSync()

   @isDartFile: (filename = '') =>


split is a String method, not an Underscore method Use a falsey check (rather than explicit null) to see if subscriber list exists

--- tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/pubsub.coffee
+++ tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/pubsub.coffee
@@ -38,7 +38,7 @@
     return

   addSub = (stimulusName, addFirst, responder) ->
-    [simpleName, namespaces...] = _.split stimulusName, '.'
+    [simpleName, namespaces...] = stimulusName.split '.'

     subscriber =
       stimulus: simpleName
@@ -47,7 +47,7 @@

     list = subscribers[simpleName]

-    if list is null
+    if not list
       subscribers[simpleName] = [subscriber]
     else
       # If iterating the list (during a publish), then do a copy-on-write.
@@ -103,7 +103,7 @@
       responder = stimulusName
       stimulusName = ""

-    [simpleName, namespaces...] = _.split stimulusName, '.'
+    [simpleName, namespaces...] = stimulusName.split '.'

     if simpleName isnt ""
       kullSubs simpleName, namespaces, responder
@@ -124,7 +124,7 @@
   exports.fire = (stimulusName, memo, context) ->
     list = subscribers[stimulusName]

-    return exports if list is null
+    return exports if not list

     event =
       running: true


Hook up loading collection form values from the given URN.

--- src/js/collection-editor.coffee
+++ src/js/collection-editor.coffee
@@ -19,6 +19,8 @@
   if arguments.length == 4
     urn += ".#{version}"
   return urn
+
+pagedown_editors = {}

 disable_collection_form = ->
   $('#collection_form').children().prop('disabled',true)
@@ -143,7 +145,7 @@
             loaded_urn += urn_prefix_matches[2]
           else
             loaded_urn += ".#{existing_versions}"
-          console.log "Loading data from: #{loaded_urn}"
+          load_collection_form_from_urn(loaded_urn)
           callback(latest_urn)
         else # invalid URN passed in, strip and retry
           console.log "No existing versions for passed URN, constructing latest URN from scratch"
@@ -223,6 +225,25 @@
         else
           $(child).val(localStorage["#{collection}:#{$(child).attr('id')}"])

+# populate collection form values from a given URN
+load_collection_form_from_urn = (loaded_urn) ->
+  collection = $('#collection_select').val()
+  # don't clobber saved/loaded data
+  unless localStorage["#{collection}:#{$('input[data-urn=true]').attr('id')}"]?
+    console.log "Loading data from: #{loaded_urn}"
+    fusion_tables_query "SELECT * FROM #{collection} WHERE '#{$('input[data-urn=true]').attr('id')}' = '#{loaded_urn}'", (data) ->
+      console.log "Existing data:"
+      console.log data
+      for header, i in data['columns']
+        unless $("##{header}").prop('disabled')
+          console.log "Setting #{header} to #{data['rows'][0][i]}"
+          if $("##{header}").attr('class') == 'pagedown_container'
+            $("#wmd-input-#{header}").val(data['rows'][0][i])
+            if pagedown_editors[header]?
+              pagedown_editors[header].refreshPreview()
+          else
+            $("##{header}").val(data['rows'][0][i])
+
 # remove form values from localStorage and reset the form
 clear_collection_form = ->
   collection = $('#collection_select').val()
@@ -289,8 +310,8 @@
   converter = new Markdown.Converter()
   for suffix in $(".pagedown_suffix")
     console.log "Running Markdown editor for: #{$(suffix).val()}"
-    editor = new Markdown.Editor(converter,"-#{$(suffix).val()}")
-    editor.run()
+    pagedown_editors[$(suffix).val()] = new Markdown.Editor(converter,"-#{$(suffix).val()}")
+    pagedown_editors[$(suffix).val()].run()

   # if we have Flash, put clippy helpers on all the inputs
   if swfobject.hasFlashPlayerVersion('9')


more tests for fromEvent

more tests for fromEvent

--- spec/specs/fromevent.coffee
+++ spec/specs/fromevent.coffee
@@ -54,17 +54,36 @@
     dispose()
     expect(emitter.listeners("click").length).to.deep.equal(0)

-  mockSource = {
+  onOffSource = -> {
     on: (type, callback) -> callback(type)
-    off: (callback) ->
+    off: (callback) -> this.cleaned = true
   }

   it "should create EventStream from on/off event", ->
     values = []
-    take(1, Bacon.fromEvent(mockSource, "test")).onValue (value) ->
+    src = onOffSource()
+    take(1, Bacon.fromEvent(src, "test")).onValue (value) ->
       values.push(value)
+    expect(values).to.deep.equal ["test"]
+    expect(src.cleaned).to.equal(true)
+
+  bindUnbindSource = -> {
+    bind: (type, callback) -> callback(type)
+    unbind: (callback) -> this.cleaned = true
+    on: -> throw "bait method"
+    addEventListener: -> throw "bait method"
+    addListener: -> throw "bait method"
+  }
+
+  it "should create EventStream from bind/unbind event", ->
+    values = []
+    src = bindUnbindSource()
+    take(1, Bacon.fromEvent(src, "test")).onValue (value) ->
+      values.push(value)
+    expect(values).to.deep.equal ["test"]
+    expect(src.cleaned).to.equal(true)

   it "toString", ->
-    expect(Bacon.fromEvent(mockSource, "click").toString()).to.equal("Bacon.fromEvent({on:function,off:function},click)")
+    expect(Bacon.fromEvent(onOffSource(), "click").toString()).to.equal("Bacon.fromEvent({on:function,off:function},click)")


Missed update to the newer transformer scheme

--- resources/assets/coffee/react/beatmap-discussions/overview.coffee
+++ resources/assets/coffee/react/beatmap-discussions/overview.coffee
@@ -70,7 +70,7 @@
             className: "#{bn}__meta-text"
             dangerouslySetInnerHTML:
               __html: Lang.get 'beatmaps.listing.mapped-by',
-                mapper: "#{osu.link Url.user(user.user_id), user.username}"
+                mapper: "#{osu.link Url.user(user.id), user.username}"

         div className: 'text-right',
           @stats()


Use space pen to generate error html

Use space pen to generate error html

--- src/markdown-preview.coffee
+++ src/markdown-preview.coffee
@@ -42,11 +42,14 @@
     @rootView.getActiveEditor()?.getText()

   getErrorHtml: (error) ->
-    '
Previewing Markdown Failed

-
Possible Reasons

-

-
You aren\'t online or are unable to reach github.com

-
'
+    $$$ ->
+      @h2 'Previewing Markdown Failed'
+      @h3 'Possible Reasons'
+      @ul =>
+        @li =>
+          @span 'You aren\'t online or are unable to reach '
+          @a 'github.com', href: 'https://github.com'
+          @span '.'

    getLoadingHtml: ->
      $$$ ->


Fix inbox count

Fix inbox count

--- app/controllers/lists.coffee
+++ app/controllers/lists.coffee
@@ -107,6 +107,7 @@
     true

   updateAll: =>
+    @inboxCount.text Task.active("inbox").length
     @allCount.text Task.active().length
     @completedCount.text Task.completed().length


Add TODO comment.

Add TODO comment.

--- app/javascripts/image.coffee
+++ app/javascripts/image.coffee
@@ -65,7 +65,6 @@
           @xtkVolume.filedata = data
           # Set the state to loaded.
           @state = Image.STATES.LOADED
-          # Return the loaded image.
         .catch (res) =>
           # Display an alert with the status text.
           alert("The image volume file load was unsuccessful: " +
@@ -73,6 +72,8 @@
           # Set the state to 'error'.
           @state = Image.STATES.ERROR

+        # TODO - this load function should return the above promise,
+        #   which should resolve to the loaded image.
         this

       isLoaded: ->


Don't handle error code 0 globally

Don't handle error code 0 globally

--- app/js/services/error.coffee
+++ app/js/services/error.coffee
@@ -26,6 +26,8 @@
         $location.path("/home")
       else if error_msg.match(/No such wallet exists/)
         $location.path("/createwallet")
+      else if response.data.error.code==0
+        console.log('wallet not open')
       method = response.config.data?.method
       error_msg = if method then "In method '#{method}': #{error_msg}" else error_msg

@@ -34,7 +36,8 @@

     console.log "#{error_msg.substring(0, 512)} (#{response.status})", response
     method_in_dont_report_list = method and (dont_report_methods.filter (x) -> x == method).length > 0
-    if !promise and !method_in_dont_report_list
+    #response.data.error.code!=0 is handled externally
+    if !promise and !method_in_dont_report_list and response.data.error.code!=0
       Shared.message = "RPC Server Error: " + error_msg.split("\n")[0]
       #Growl.error "RPC Server Error", "#{error_msg.substring(0,512)} (#{response.status})"
     return (if promise then promise else $q.reject(response))


add missing argument parameter to wordcount call

--- services/clsi/app/coffee/CompileManager.coffee
+++ services/clsi/app/coffee/CompileManager.coffee
@@ -231,7 +231,7 @@
 		timeout = 10 * 1000
 		compileName = getCompileName(project_id, user_id)

-		CommandRunner.run compileName, command, directory, image, timeout, (error) ->
+		CommandRunner.run compileName, command, directory, image, timeout, {}, (error) ->
 			return callback(error) if error?
 			try
 				stdout = fs.readFileSync(directory + "/" + file_name + ".wc", "utf-8")


Remove coffee version of ez-plus

Remove coffee version of ez-plus


Parse today, tomorrow, and (next) [day of week]

--- src/scripts/whoisout.coffee
+++ src/scripts/whoisout.coffee
@@ -34,10 +34,28 @@
       msg.send 'unable to save date'

 plugin.parseDate = (fuzzyDateString)->
-  if (@thisDate = (moment fuzzyDateString)).isValid()
-    return {start: @thisDate.toDate(), end: null}
-  else
-    return false
+  fuzzyDateString = fuzzyDateString.toLowerCase()
+  if fuzzyDateString.split(" ")[0] is "next"
+    plusOneWeek = true
+    fuzzyDateString = fuzzyDateString.split(" ")[1]
+  day = 1000*60*60*24
+  week = day*7
+  switch fuzzyDateString
+    when "tomorrow"
+      return new Date((new Date).getTime() + day)
+    when "today"
+      return new Date()
+    when "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"
+      days = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"]
+      date = new Date()
+      date = new Date(date.getTime() + day) until days[date.getDay()] == fuzzyDateString
+      date = new Date(date.getTime() + week) if plusOneWeek
+      return date
+    else
+      if (@thisDate = (moment fuzzyDateString)).isValid()
+        return {start: @thisDate.toDate(), end: null}
+      else
+        return false

 plugin.save = (robot, vacationDateRange, msg)->
   userOutList = robot.brain.data.outList


[Jax.Mesh.Icosahedron] Clean up

[Jax.Mesh.Icosahedron] Clean up

--- spec/javascripts/jax/builtin/meshes/icosahedron_spec.js.coffee
+++ spec/javascripts/jax/builtin/meshes/icosahedron_spec.js.coffee
@@ -39,27 +39,25 @@
   - its sides are of the same length
   - its vertices are at the same distance of the center

-Maybe this should not rely on the center being computed ?
-
 @return {Boolean}
 ###
 Jax.Geometry.Triangle.prototype.isEquilateral = () ->
-  distA = vec3.dist @center, @a
-  distB = vec3.dist @center, @b
-  distC = vec3.dist @center, @c
+  distA = vec3.dist @a, @b
+  distB = vec3.dist @b, @c
+  distC = vec3.dist @c, @a

   Math.equalish(distA, distB) && Math.equalish(distB, distC)

+###################################

 ###
-Returns an array containing the elements of iterable,
+Returns an array containing the elements of passed array,
 but without any duplicates
-Todo: make results of the same type as iterable

-@param {Array|Object} iterable
+@param {Array} array with duplicates
 @return {Array}
 ###
-unique = (iterable) ->
+trim_duplicates = (array) ->
   results = []

   contains = (haystack, needle) ->
@@ -70,15 +68,15 @@
       return true if match
     false

-  for item in iterable
+  for item in array
     results.push(item) unless contains(results, item)

   results

-
 ###################################

 describe "Jax.Mesh.Icosahedron", ->
+
   icosa = null
   verts = colors = texes = norms = null

@@ -132,7 +130,7 @@

     beforeEach ->
       vertices = icosa.getVerticesAsVectors()
-      uniqueVertices = unique vertices
+      uniqueVertices = trim_duplicates vertices

     it "should be 60 overall (20 faces, 3 vertices each)", ->
       expect(vertices.length).toBe(60)


stub setupArtworkFilter

stub setupArtworkFilter

--- apps/home/test/client.coffee
+++ apps/home/test/client.coffee
@@ -105,6 +105,7 @@
     sinon.stub Backbone.history, 'start'
     sinon.stub Backbone, 'sync'
     sinon.stub @HomeView::, 'renderArtworks'
+    sinon.stub @HomeView::, 'setupArtworkFilter'
     @init()

   afterEach ->


Classroom: Added progress bar to course thumb view.

--- client/app/Applications/Classroom.kdapplication/Views/classroomcoursethumbview.coffee
+++ client/app/Applications/Classroom.kdapplication/Views/classroomcoursethumbview.coffee
@@ -15,9 +15,11 @@
     @on "EnrollmentRequested", => appView.enrollToCourse data

   createElements: ->
-    data              = @getData()
-    devModeOptions    = {}
-    cancelIconOptions = {}
+    data               = @getData()
+    devModeOptions     = {}
+    cancelIconOptions  = {}
+    @progressContainer = new KDView
+      cssClass         : "progress-container"

     if data.devMode
       devModeOptions.cssClass = "top-badge gray"
@@ -32,6 +34,17 @@
         e.stopPropagation()
         @destroy()
         @emit "EnrollmentCancelled"
+
+      percent = if data.completed then Math.round (100 * data.completed.length) / data.totalChapters else 0
+
+      @progressContainer.addSubView new KDView
+        cssClass   : "progress-bar"
+        attributes :
+          style    : "width:#{percent}%"
+        tooltip    :
+          title    : "You completed #{percent}% of this course."
+    else
+      @progressContainer.setClass "hidden"

     @cancelIcon = new KDCustomHTMLView cancelIconOptions

@@ -58,4 +71,5 @@
         #{data.name}
         #{data.version}

+      {{> @progressContainer}}
     """


payment: productsController#fetchProducts

--- client/app/Applications/Dashboard.kdapplication/controllers/productscontroller.coffee
+++ client/app/Applications/Dashboard.kdapplication/controllers/productscontroller.coffee
@@ -11,9 +11,9 @@

     konstructor = getConstructor category

-    do reload = ->
-      KD.getGroup().fetchProducts category, (err, results) ->
-        view.setProducts category, results
+    do reload = =>
+      @fetchProducts category, (err, products) ->
+        view.setProducts category, products

     handleResponse = (err) ->
       return  if KD.showError err
@@ -39,13 +39,11 @@

       .on("EditRequested", handleEdit)

+      .on("AddProductsRequested", @bound 'showAddProductsModal')
+
       .on "DeleteRequested", (data) ->
         confirmDelete data, ->
           konstructor.removeByCode data.planCode, handleResponse
-
-      .on "AddProductsRequested", (data) ->
-        modal = new GroupPlanAddProductsModal {}, data
-        modal.on 'ProductsAdded', -> debugger

       .on "BuyersReportRequested", (data) ->
         debugger # needs to be implemented
@@ -108,3 +106,16 @@

   getConstructor = (category) ->
     KD.remote.api["JPayment#{ category.capitalize() }"]
+
+  fetchProducts: (category, callback) ->
+    KD.getGroup().fetchProducts category, callback
+
+  showAddProductsModal: (plan) ->
+
+    modal = new GroupPlanAddProductsModal {}, plan
+    modal.on 'ProductsAdded', -> debugger
+
+    @fetchProducts 'product', (err, products) ->
+      return  if KD.showError err
+
+      modal.setProducts products


Fix query by type id

Fix query by type id

--- storage/lib/geocache.coffee
+++ storage/lib/geocache.coffee
@@ -43,7 +43,7 @@

         if query.typeIds?
             sql = sql
-                .where 'GeocacheTypeId = ANY(?)', query.typeIds
+                .where 'GeocacheTypeId IN ?', query.typeIds.map (x) -> parseInt x

         # query.attributeIds is currently not supported


Set popover max-width

Set popover max-width

--- src/resources-packaged/ops/javascript/orbeon/xforms/control/LHHA.coffee
+++ src/resources-packaged/ops/javascript/orbeon/xforms/control/LHHA.coffee
@@ -1,3 +1,106 @@
+State =
+
+    # Keep track of whether a tooltip is shown and this is because a control got the focus
+    # - used to diactivate hiding/showing tooltip based on mouse movements
+    tooltipShownBecauseOfFocus: false
+
+    # Keep track of the control for which we've last shown the tooltip/popover
+    # - used not to re-show tooltip/popover, which causes blinks
+    # - used to be able to hide popover on mouseleave for the popover
+    tooltipPopoverShownForControlEl: null
+
+Events =
+
+    onControl: (event) ->
+        controlEl = $(event.target).closest('.xforms-control')
+        lhhaEls = controlEl.find('.xforms-appearance-tooltip, .xforms-appearance-popover')
+        controlHasTooltipPopover = lhhaEls.is('*')
+        if controlHasTooltipPopover
+            TooltipPopover.init(controlEl, lhhaEls)
+            if ! State.tooltipShownBecauseOfFocus
+                if event.type == 'mouseenter'
+                    TooltipPopover.show(controlEl)
+                if event.type == 'mouseleave'
+                    # Allow mouse to be on popover, e.g. to click on link
+                    mouseOnPopover = $('.popover:hover').is('*')
+                    TooltipPopover.hide(controlEl, event) if ! mouseOnPopover
+            if event.type == 'focusin'
+                TooltipPopover.show(controlEl)
+                State.tooltipShownBecauseOfFocus = true
+            if event.type == 'focusout'
+                TooltipPopover.hide(controlEl, event)
+                State.tooltipShownBecauseOfFocus = false
+
+    onPopover: (event) ->
+        # Also test on popover being shown, as by the time we get the mouseleave on the popover,
+        # it might have been hidden for some other reason
+        if ! State.tooltipShownBecauseOfFocus && State.tooltipPopoverShownForControlEl?
+            TooltipPopover.hide(State.tooltipPopoverShownForControlEl, event)
+
+# Facade for Bootstrap's Tooltip component
+# - ensures we don't show an already visible tooltip, which would make it "blink"
+TooltipPopover =
+
+    DataPrefix: 'xforms-tooltip-popover-'
+    Initialized: @DataPrefix + 'initialized'
+    Methods: @DataPrefix + 'methods'
+
+    # Create the underlying Bootstrap tooltip (but don't show it just yet)
+    init: (controlEl, lhhaEls) ->
+        alreadyInitialized = controlEl.data(@Initialized) == 'true'
+        if ! alreadyInitialized
+            methods = []
+            _.each lhhaEls, (lhhaEl) ->
+                lhhaEl = $(lhhaEl)
+                if lhhaEl.hasClass('xforms-appearance-tooltip')
+                    controlEl.tooltip
+                        placement: 'bottom',
+                        trigger: 'manual',
+                        title: lhhaEl.text()
+                        html: true
+                    methods.push('tooltip')
+                if lhhaEl.hasClass('xforms-appearance-popover')
+                    beforeLastColumn = $(controlEl).closest('td').next().is('*')
+                    controlEl.popover
+                        placement: if beforeLastColumn then 'right' else 'left',
+                        trigger: 'manual',
+                        title: controlEl.find('.xforms-label').text()
+                        content: lhhaEl.text()
+                        html: true
+                        container:'.popover-container'
+                        template: do ->
+                            # Set max-width of popover to be the width of the remaining columns
+                            # - use 90% thereof, so if over controls, we can still get a hint of their presence
+                            defaultTemplate = $($.fn.popover.defaults.template)
+                            maxWidth = 0.9 * (controlEl.closest('table').width() - controlEl.closest('td').width())
+                            defaultTemplate.attr('style', "max-width: #{maxWidth}px")
+                            $('<div>').append(defaultTemplate).html()
+                    methods.push('popover')
+            controlEl.data(@Methods, methods)
+
+    # Show tooltip for control
+    # - but don't show if the tooltip is alrady shown for this control
+    show: (controlEl) ->
+        sameControl = controlEl.is(State.tooltipPopoverShownForControlEl)
+        if ! sameControl
+            @_callMethods(State.tooltipPopoverShownForControlEl, 'hide') if State.tooltipPopoverShownForControlEl?
+            @_callMethods(controlEl, 'show')
+            State.tooltipPopoverShownForControlEl = controlEl
+
+    # Hide tooltip for control
+    # - but don't hide if the element we're going to (if any) is the same as the current one
+    hide: (controlEl, event) ->
+        toTargetEl = $(event.relatedTarget || event.toElement)
+        toControlEl = toTargetEl.closest('.xforms-control')
+        sameControl = controlEl.is(toControlEl)
+        if ! sameControl
+            @_callMethods(controlEl, 'hide')
+            State.tooltipPopoverShownForControlEl = null
+
+    _callMethods: (controlEl, arg) ->
+        methods = controlEl.data(@Methods)
+        _.each methods, (method) -> controlEl[method].call(controlEl, arg)
+
 $ ->

     # Change DOM as we expect the server to sent it to us, when implemented
@@ -12,98 +115,9 @@
             el.addClass('xforms-hidden')
             el.addClass(appearance)

-    State =
-
-        # Keep track of whether a tooltip is shown and this is because a control got the focus
-        # - used to diactivate hiding/showing tooltip based on mouse movements
-        tooltipShownBecauseOfFocus: false
-
-        # Keep track of the control for which we've last shown the tooltip/popover
-        # - used not to re-show tooltip/popover, which causes blinks
-        # - used to be able to hide popover on mouseleave for the popover
-        tooltipPopoverShownForControlEl: null
-
-    Events =
-
-        onControl: (event) ->
-            controlEl = $(event.target).closest('.xforms-control')
-            lhhaEls = controlEl.find('.xforms-appearance-tooltip, .xforms-appearance-popover')
-            controlHasTooltipPopover = lhhaEls.is('*')
-            if controlHasTooltipPopover
-                TooltipPopover.init(controlEl, lhhaEls)
-                if ! State.tooltipShownBecauseOfFocus
-                    if event.type == 'mouseenter'
-                        TooltipPopover.show(controlEl)
-                    if event.type == 'mouseleave'
-                        # Allow mouse to be on popover, e.g. to click on link
-                        mouseOnPopover = $('.popover:hover').is('*')
-                        TooltipPopover.hide(controlEl, event) if ! mouseOnPopover
-                if event.type == 'focusin'
-                    TooltipPopover.show(controlEl)
-                    State.tooltipShownBecauseOfFocus = true
-                if event.type == 'focusout'
-                    TooltipPopover.hide(controlEl, event)
-                    State.tooltipShownBecauseOfFocus = false
-
-        onPopover: (event) ->
-            # Also test on popover being shown, as by the time we get the mouseleave on the popover,
-            # it might have been hidden for some other reason
-            if ! State.tooltipShownBecauseOfFocus && State.tooltipPopoverShownForControlEl?
-                TooltipPopover.hide(State.tooltipPopoverShownForControlEl, event)
-
+    # Register event listeners
     $('.fr-body').on('mouseenter mouseleave focusin focusout', '.xforms-control', Events.onControl)
     $('body'    ).on('mouseleave'                            , '.popover'       , Events.onPopover)

-    # Facade for Bootstrap's Tooltip component
-    # - ensures we don't show an already visible tooltip, which would make it "blink"
-    TooltipPopover =
+    $('#xforms-form').append('<div class="popover-container">')

-        DataPrefix: 'xforms-tooltip-popover-'
-        Initialized: @DataPrefix + 'initialized'
-        Methods: @DataPrefix + 'methods'
-
-        # Create the underlying Bootstrap tooltip (but don't show it just yet)
-        init: (controlEl, lhhaEls) ->
-            alreadyInitialized = controlEl.data(@Initialized) == 'true'
-            if ! alreadyInitialized
-                methods = []
-                _.each lhhaEls, (lhhaEl) ->
-                    lhhaEl = $(lhhaEl)
-                    if lhhaEl.hasClass('xforms-appearance-tooltip')
-                        controlEl.tooltip
-                            placement: 'bottom',
-                            trigger: 'manual',
-                            title: lhhaEl.text()
-                        methods.push('tooltip')
-                    if lhhaEl.hasClass('xforms-appearance-popover')
-                        beforeLastColumn = $(controlEl).closest('td').next().is('*')
-                        controlEl.popover
-                            placement: if beforeLastColumn then 'right' else 'left',
-                            trigger: 'manual',
-                            title: controlEl.find('.xforms-label').text()
-                            content: lhhaEl.text()
-                        methods.push('popover')
-                controlEl.data(@Methods, methods)
-
-        # Show tooltip for control
-        # - but don't show if the tooltip is alrady shown for this control
-        show: (controlEl) ->
-            sameControl = controlEl.is(State.tooltipPopoverShownForControlEl)
-            if ! sameControl
-                @_callMethods(State.tooltipPopoverShownForControlEl, 'hide') if State.tooltipPopoverShownForControlEl?
-                @_callMethods(controlEl, 'show')
-                State.tooltipPopoverShownForControlEl = controlEl
-
-        # Hide tooltip for control
-        # - but don't hide if the element we're going to (if any) is the same as the current one
-        hide: (controlEl, event) ->
-            toTargetEl = $(event.relatedTarget || event.toElement)
-            toControlEl = toTargetEl.closest('.xforms-control')
-            sameControl = controlEl.is(toControlEl)
-            if ! sameControl
-                @_callMethods(controlEl, 'hide')
-                State.tooltipPopoverShownForControlEl = null
-
-        _callMethods: (controlEl, arg) ->
-            methods = controlEl.data(@Methods)
-            _.each methods, (method) -> controlEl[method].call(controlEl, arg)


Make sure the show command always gets registered

--- lib/atomatigit.coffee
+++ lib/atomatigit.coffee
@@ -26,6 +26,7 @@

   # Public: Package activation.
   activate: (state) ->
+    @insertShowCommand()
     ErrorView = require './views/error-view'
     return @errorNoGitRepo() unless atom.project.getRepo()
     Repo      = require './models/repo'
@@ -55,7 +56,10 @@
   errorNoGitRepo: ->
     new ErrorView(message: 'Project is no git repository!')

+  # Internal: Register show command with atom.
+  insertShowCommand: ->
+    atom.workspaceView.command 'atomatigit:show', => @show()
+
   # Internal: Register package commands with atom.
   insertCommands: ->
-    atom.workspaceView.command 'atomatigit:show', => @show()
     atom.workspaceView.command 'atomatigit:close', => @hide()


meteorite branching route fallthough works properly.

--- meteorite.coffee
+++ meteorite.coffee
@@ -13,6 +13,6 @@
       Meteor.call( 'use_branch', branch )
       if other?
         Backbone.history.navigate(other, trigger: true)
-        @navigate("/branch/#{branch}")
+        @navigate("/branch/#{branch}#{other}")

   Router = new Router()


Add back accidentally dropped code to only emit debug events while Connection still open.

--- lib/connection.coffee
+++ lib/connection.coffee
@@ -13,7 +13,8 @@

     @debug = new Debug(@options.debug)
     @debug.on('debug', (message) =>
-      @emit('debug', message)
+      if !@closed
+        @emit('debug', message)
     )

     @closed = false


Adding more time between SO polls

Adding more time between SO polls

--- scripts/stackoverflow-poller.coffee
+++ scripts/stackoverflow-poller.coffee
@@ -8,7 +8,7 @@
 Poller = require '../support/poller'

 PROD_MODE        = process.env.NODE_ENV is 'production'
-POLL_INTERVAL    = 1000 * 60 * 30
+POLL_INTERVAL    = 1000 * 60 * 74
 ANNOUNCE_ROOMS   = []

 do =>


solved express-session warnings

solved express-session warnings

--- src/private/server.coffee
+++ src/private/server.coffee
@@ -32,6 +32,8 @@
     cookie:
         maxAge: 60000
     secret: "easy money"
+    saveUninitialized: false
+    resave: false
 )
 app.use connectFlash()

@@ -155,4 +157,4 @@
     return re.test email

 app.listen port
-console.log '[BIGSALES-WEB] Listening on port ' + port+console.log '[BIGSALES-WEB] Listening on port ' + port


Update classification counts Save the subject group ID on subject load. Update the count for that group on subject finish, and render the project stats template. #14

--- overrides.coffee
+++ overrides.coffee
@@ -61,6 +61,7 @@

 current_tool = null
 rect_index = 0
+group_id = null

 bhl_link = document.querySelector('a[target=bhl]')
 page_zoom = document.querySelector('input[name=pagezoom]')
@@ -141,6 +142,12 @@

   group = (group for group in currentProject.groups when group.zooniverse_id is subject.group.zooniverse_id)
   classify_page.el.find('h2.group-title').text group[0].metadata.title
+  group_id = group[0].id
+
+classify_page.on classify_page.FINISH_SUBJECT,  ->
+  User.current?.project.groups[group_id].classification_count++
+  profile_stats.el.html ''
+  profile_stats.renderTemplate()

 Group.on 'fetch', (e, groups) ->
   currentProject.groups = groups


Image cropping Experimental feature: crop the svg dimensions down to the selected rectangle. Remember to rescale to original dimensions when you go back.

--- overrides.coffee
+++ overrides.coffee
@@ -60,9 +60,11 @@
   @rescale() if @magnification is 0

 LAST_TASK = false
-index = 0
 INITIAL_STEPS = 2 # number of initial steps before annotating rectangles
 ANNOTATION_STEPS = 2 # number of annotation steps per rectangle
+MARGIN = 25 # margin on cropped images
+
+index = 0
 # moving back and forward through the array of marked SVG rectangles
 classify_page.el.on decisionTree.LOAD_TASK, ({originalEvent: detail: {task}})->
   rectangles = []
@@ -78,9 +80,14 @@

   if rectangles.length > 0
     tool = rectangles[rect_index]
-    ms.rescale tool.mark.left - 10, tool.mark.top - 10, tool.mark.width + 20, tool.mark.height + 20
+    w = tool.mark.width + MARGIN * 2
+    h = tool.mark.height + MARGIN * 2
+    ms.svg.attr 'width', w
+    ms.svg.attr 'height', h
+    ms.rescale tool.mark.left - MARGIN, tool.mark.top - MARGIN, w, h

   if task.key is 'illustration'
+    subjectViewer.rescale()
     ms.rescale(0,0,subjectViewer.maxWidth,subjectViewer.maxHeight)
     DetailsTask.currentIndex = 0


Updated Buttercoin API url

Updated Buttercoin API url

--- server/exchanges/Buttercoin.coffee
+++ server/exchanges/Buttercoin.coffee
@@ -32,7 +32,7 @@
     try
       ws.close() if ws?
       clearInterval wsLoop if wsLoop?
-      ws = new WebSocket 'wss://api.buttercoin.com/api/v1/websocket', { protocolVersion: 13, origin: 'https://www.buttercoin.com' }
+      ws = new WebSocket 'wss://wsio.buttercoin.com/api/v1/websocket', { protocolVersion: 13, origin: 'https://www.buttercoin.com' }

       ws.on 'message', (data) ->
         handleMessage data


Don't add logs in development

Don't add logs in development

--- server/initializers/logging.coffee
+++ server/initializers/logging.coffee
@@ -4,9 +4,10 @@
 LOG_DIRECTORY = './logs'

 module.exports = (app) ->
-  fs.mkdirSync(LOG_DIRECTORY) unless fs.statSync(LOG_DIRECTORY)
-  app.use express.logger(
-    stream:
-      fs.createWriteStream("./#{LOG_DIRECTORY}/#{app.get('env')}.log",
-      {flags: 'a'})
-  )
+  unless app.get('env') is 'development'
+    fs.mkdirSync(LOG_DIRECTORY) unless fs.statSync(LOG_DIRECTORY)
+    app.use express.logger(
+      stream:
+        fs.createWriteStream("./#{LOG_DIRECTORY}/#{app.get('env')}.log",
+        {flags: 'a'})
+    )


[es6] Static property fix.

[es6] Static property fix.

--- src/ChatServiceError.coffee
+++ src/ChatServiceError.coffee
@@ -8,7 +8,7 @@
 class ChatServiceError extends Error

   # @property [Object] Error strings.
-  @::errorStrings =
+  errorStrings:
     badArgument : 'Bad argument at position %d, value %j'
     invalidName : 'String %s contains invalid characters'
     invalidSocket : 'Socket %s is not connected'


changed wording of Demo menu items

changed wording of Demo menu items

requested by Morten

--- client/ide.coffee
+++ client/ide.coffee
@@ -268,9 +268,9 @@
     (
       if D.nwjs
         {'': '_Tools', items: [
-          {'': '_Load Demo...', action: demoLoad}
-          {'': '_Next Line from Demo',     key: 'Ctrl+Shift+N', action: demoNext}
-          {'': '_Previous Line from Demo', key: 'Ctrl+Shift+P', action: demoPrev}
+          {'': 'Run Demo Script...', action: demoLoad}
+          {'': 'Next Line of Demo',     key: 'Ctrl+Shift+N', action: demoNext}
+          {'': 'Previous Line of Demo', key: 'Ctrl+Shift+P', action: demoPrev}
         ]}
     )
     {'': '_Help', items: [


[#59677630] rollback record when changes cancelled

--- app/assets/javascripts/trade/controllers/shipments_controller.js.coffee
+++ app/assets/javascripts/trade/controllers/shipments_controller.js.coffee
@@ -238,6 +238,7 @@
       )

     cancelShipment: () ->
+      @get('currentShipment').rollback()
       @set('currentShipment', null)
       $('.shipment-form-modal').modal('hide')


Run auth config after ember-data

Run auth config after ember-data

--- app/initializers/auth.coffee
+++ app/initializers/auth.coffee
@@ -11,6 +11,7 @@

 AuthInitializer =
   name: 'auth'
+  after: 'ember-data'
   initialize: initialize

 `export {initialize}`


OHM-115: Added extra projection filtering for bulkrerun requests

--- src/api/transactions.coffee
+++ src/api/transactions.coffee
@@ -30,9 +30,9 @@
     when "full"
       # view all transaction data
       return {}
-    when "idsOnly"
-      # view only '_id's
-      return { "_id": 1 }
+    when "bulkrerun"
+      # view only 'bulkrerun' properties
+      return { "_id": 1, "childIDs": 1, "canRerun": 1, "channelID": 1 }
     else
       # no filterRepresentation supplied - simple view
       # view minimum required data for transactions


Upgrading deprecated methods.

Upgrading deprecated methods.

--- lib/jumpy-view.coffee
+++ lib/jumpy-view.coffee
@@ -48,7 +48,7 @@
       if location == null
           console.log "Jumpy canceled jump.  No location found."
           return
-      editor = atom.workspaceView.getActivePaneItem()
+      editor = atom.workspace.getActivePaneItem()
       editor.setCursorBufferPosition(location)
       console.log "Jumpy jumped to: #{@firstChar}#{@secondChar} at (#{location})"

@@ -84,7 +84,7 @@

   getAllPixelLocations: ->
       pixels = []
-      for line, lineIndex in atom.workspaceView.getActivePaneItem().buffer.lines
+      for line, lineIndex in atom.workspace.getActivePaneItem().buffer.lines
           pixels.push([])
           for char, charIndex in line
               pixelPosition = atom.workspaceView.getActiveView().pixelPositionForBufferPosition([lineIndex, charIndex])