Changed to no longer extend base Object class. Added `haveHtml` matcher.

--- lib/Spec.coffee
+++ lib/Spec.coffee
@@ -1,6 +1,7 @@
 # Seaweed Coffeescript spec framework
 window.Spec = {
   EnvironmentInitialized: false
+  _extended: []

   # Adds   indentation to a string
   Pad: (string, times) ->
@@ -35,7 +36,9 @@
       s = "{"
       first = true
       for key of object
-        if object.hasOwnProperty key
+        # Access hasOwnProperty through Object.prototype to work around bug
+        # in IE6/7/8 when calling hasOwnProperty on a DOM element
+        if Object.prototype.hasOwnProperty.call(object, key)
           if first
             first = false
           else
@@ -113,18 +116,21 @@
       when 'terminal'
         $('body').append('

')

-    # Tests for a positive match
-    Object.prototype.should = (matcher) ->
-      if typeof matcher is 'function'
-        result = matcher(this)
-        Spec.fail "expected #{result[1]}" unless result[0]
-
-    # Tests for a negative match
-    Object.prototype.shouldNot = (matcher) ->
-      if typeof matcher is 'function'
-        result = matcher(this)
-        Spec.fail "expected not #{result[1]}" if result[0]
-
+    @extend Array
+    @extend Boolean
+    @extend Date
+    @extend Function
+    @extend Number
+    @extend RegExp
+    @extend String
+    @extend Element
+    @extend jQuery
+
+    window.SpecObject = (object) ->
+      $.extend this, object if object
+      this
+    @extend SpecObject
+
     # Sets up an expectation
     window.expectation = (message) ->
       exp = {
@@ -155,47 +161,6 @@
       Spec.expectations.push exp
       exp

-    # Creates a stub method with an expectation
-    Object.prototype.shouldReceive = (name) ->
-      object = this
-
-      received = expectation "to receive “#{name}”"
-
-      passthrough = object[name]
-      object[name] = -> received.meet()
-
-      received.with = (expectArgs...) ->
-        object[name] = (args...) ->
-          received.meet()
-          correct = true
-          correct = false if expectArgs.length != args.length
-          if correct
-            for i in [0..args.length]
-              correct = false unless String(expectArgs[i]) == String(args[i])
-          unless correct
-            Spec.fail "expected ##{name} to be called with arguments “#{expectArgs.join ', '}”, actual arguments: “#{args.join ', '}”"
-        received
-
-      received.andReturn = (returnValue) ->
-        fn = object[name]
-        object[name] = ->
-          fn.apply this, arguments
-          returnValue
-        received
-
-      received.andPassthrough = ->
-        fn = object[name]
-        object[name] = ->
-          fn.apply this, arguments
-          passthrough.apply this, arguments
-        received
-
-      received
-
-    # Creates a stub method, with an expectation of no calls
-    Object.prototype.shouldNotReceive = (name) ->
-      @shouldReceive(name).exactly(0).times
-
     # Allows an assertion on a non-object value
     window.expect = (object) ->
       {
@@ -347,6 +312,75 @@
           [match, "to include #{Spec.Display expected}, actual #{Spec.Display value}, missing #{Spec.Display missing}"]
       else
         include([expected])
+
+    window.haveHtml = (expected) ->
+      (value) ->
+        div = $(document.createElement 'div')
+        div.html expected
+        normalized = div.html()
+        actual = value.html()
+        [actual == normalized, "to have html #{Spec.Display normalized}, actual #{Spec.Display actual}"]
+
+  extend: (klass) ->
+    @_extended.push klass
+
+    @extendObject klass
+    @extendObject klass.prototype if klass.prototype
+
+  extendObject: (extend) ->
+
+    # Tests for a positive match
+    extend.should = (matcher) ->
+      if typeof matcher is 'function'
+        result = matcher(this)
+        Spec.fail "expected #{result[1]}" unless result[0]
+
+    # Tests for a negative match
+    extend.shouldNot = (matcher) ->
+      if typeof matcher is 'function'
+        result = matcher(this)
+        Spec.fail "expected not #{result[1]}" if result[0]
+
+    # Creates a stub method with an expectation
+    extend.shouldReceive = (name) ->
+      object = this
+
+      received = expectation "to receive “#{name}”"
+
+      passthrough = object[name]
+      object[name] = -> received.meet()
+
+      received.with = (expectArgs...) ->
+        object[name] = (args...) ->
+          received.meet()
+          correct = true
+          correct = false if expectArgs.length != args.length
+          if correct
+            for i in [0..args.length]
+              correct = false unless String(expectArgs[i]) == String(args[i])
+          unless correct
+            Spec.fail "expected ##{name} to be called with arguments “#{expectArgs.join ', '}”, actual arguments: “#{args.join ', '}”"
+        received
+
+      received.andReturn = (returnValue) ->
+        fn = object[name]
+        object[name] = ->
+          fn.apply this, arguments
+          returnValue
+        received
+
+      received.andPassthrough = ->
+        fn = object[name]
+        object[name] = ->
+          fn.apply this, arguments
+          passthrough.apply this, arguments
+        received
+
+      received
+
+    # Creates a stub method, with an expectation of no calls
+    extend.shouldNotReceive = (name) ->
+      @shouldReceive(name).exactly(0).times

   # Fails test, with an error message
   fail: (message, location) ->
@@ -366,11 +400,21 @@
   uninitializeEnvironment: ->
     @EnvironmentInitialized = false

-    delete Object.prototype.should
-    delete Object.prototype.shouldNot
+    for klass in @_extended
+      delete klass.should
+      delete klass.shouldNot
+      delete klass.shouldReceive
+      delete klass.shouldNotReceive
+      if klass.prototype
+        delete klass.prototype.should
+        delete klass.prototype.shouldNot
+        delete klass.prototype.shouldReceive
+        delete klass.prototype.shouldNotReceive
+
+    @_extended = []
+
+    delete window.SpecObject
     delete window.expectation
-    delete Object.prototype.shouldReceive
-    delete Object.prototype.shouldNotReceive
     delete window.expect
     delete window.beforeEach
     delete window.describe
@@ -388,4 +432,5 @@
     delete window.beAnInstanceOf
     delete window.equal
     delete window.include
+    delete window.haveHtml
 }


Dynamically load chart.js

Dynamically load chart.js

--- client/stats.coffee
+++ client/stats.coffee
@@ -1,10 +1,3 @@
-import Chart from 'chart.js'
-
-Chart.defaults.global.hover.intersect = false
-Chart.defaults.global.hover.mode = 'index'
-Chart.defaults.global.tooltips.intersect = false
-Chart.defaults.global.tooltips.mode = 'index'
-
 defaultUnit = 'week'
 currentUnit = ->
   Template.currentData().unit or defaultUnit
@@ -132,23 +125,29 @@
       stats.chart?.update 1000

 Template.statsGood.onRendered ->
-  for key, stats of @stats
-    dom = @find "canvas.#{key}Stats"
-    stats.chart = new Chart dom,
-      type: 'line'
-      data: stats
-      options:
-        scales:
-          yAxes: [
-            ticks:
-              beginAtZero: true
-              ## Integer workaround from https://github.com/chartjs/Chart.js/issues/2539
-              callback: (tick) ->
-                if 0 <= tick.toString().indexOf '.'
-                  null
-                else
-                  tick.toLocaleString()
-          ]
+  `import('chart.js')`.then (Chart) =>
+    Chart.defaults.global.hover.intersect = false
+    Chart.defaults.global.hover.mode = 'index'
+    Chart.defaults.global.tooltips.intersect = false
+    Chart.defaults.global.tooltips.mode = 'index'
+
+    for key, stats of @stats
+      dom = @find "canvas.#{key}Stats"
+      stats.chart = new Chart.Chart dom,
+        type: 'line'
+        data: stats
+        options:
+          scales:
+            yAxes: [
+              ticks:
+                beginAtZero: true
+                ## Integer workaround from https://github.com/chartjs/Chart.js/issues/2539
+                callback: (tick) ->
+                  if 0 <= tick.toString().indexOf '.'
+                    null
+                  else
+                    tick.toLocaleString()
+            ]

 Template.statsGood.helpers
   hideIfNoUser: ->


improved example slide

improved example slide

--- client/utils.coffee
+++ client/utils.coffee
@@ -7,35 +7,30 @@
 utils.guidGenerator = ->
   (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4())

-utils.mock = """

-
Getting Started wdsdsith deck.js

+utils.mock = """

+
Getting Started with Flips.io

-

-
How to Make a Dedsafsadck

+

+
How to Make a Slide?

-
Write Slides

-
Slide content is simple HTML.

+
Add a slide

+
<div class="slide">...</div>

+
Slide content is simple HTML.

Choose Thememks

-
One for slide styles and one for deck transitions.

+
One for slide styles and one for deck transitions.

Include Extensions

-
Add extra functionality to youreck, or leave it stripped down.

+
Add extra functionality to youreck, or leave it stripped own.

"""

 utils.getSocket = -> io.connect window.location.origin
-
-
-
-
-
-

 class Messaging extends Backbone.View


Allow form to take an onSubmit argument

Allow form to take an onSubmit argument

--- apps/settings/components/form_card/index.coffee
+++ apps/settings/components/form_card/index.coffee
@@ -1,7 +1,7 @@
 Promise = require 'bluebird-q'
 Serializer = require '../../../../components/form/serializer.coffee'

-module.exports = ($el) ->
+module.exports = ($el, onSubmit) ->
   $submit = $el.find('button')
   $errors = $el.find('.js-form-errors')

@@ -12,15 +12,22 @@

     serializer = new Serializer $el

+    onSubmit = if onSubmit then onSubmit else ->
+      promise = new Promise
+      promise.resolve()
+
     $submit
       .prop 'disabled', true
       .text 'Saving...'

-    Promise $.ajax
-      url: $el.data('action')
-      method: $el.data('method')
-      data: serializer.data()
-
+    Promise.all [
+      $.ajax(
+        url: $el.data('action')
+        method: $el.data('method')
+        data: serializer.data()
+      ),
+      onSubmit()
+    ]
     .then ->
       Promise $.get('/me/refresh')


Use complete_exercise_count to determine status

--- src/components/student-dashboard/reading-row.cjsx
+++ src/components/student-dashboard/reading-row.cjsx
@@ -15,7 +15,7 @@
   render: ->
     feedback = switch
       when @props.event.complete then 'Complete'
-      when @props.event.exercise_count > 0 then 'In progress'
+      when @props.event.complete_exercise_count > 0 then 'In progress'
       else 'Not started'
     <EventRow {...@props} feedback={feedback} className='reading'>
       { @props.event.title}


bugfix announcing stand alone polls

bugfix announcing stand alone polls

--- vue/src/shared/services/ability_service.coffee
+++ vue/src/shared/services/ability_service.coffee
@@ -106,7 +106,7 @@

   canAnnounceTo: (model) ->
     return false if model.discardedAt
-    return false if model.discussion().membersCount == 1
+    return false if (model.discussion() || {}).membersCount == 1
     model.group().adminsInclude(Session.user()) or
     (model.membersInclude(Session.user()) and model.group().membersCanAnnounce)


fix a regression in expression precedence handling, introduced by @parse/@call refactoring

--- src/GrammarGenerator.coffee
+++ src/GrammarGenerator.coffee
@@ -1,8 +1,8 @@
 # Grammar generator
 #

-log = ->
-#log = print
+enableLogs = false
+if enableLogs then log = print else log = ->

 this.exports = this unless process?

@@ -70,8 +70,8 @@
     # Run the parser on the token stream `lx', consumming tokens out of it
     # if applicable. Return the object `fail' and leaves the token stream
     # unchanged if parsing fails.
-    call: (lx) ->
-        x = @parse(lx)
+    call: (args...) ->
+        x = @parse(args...)
         return fail if x==fail
         if @builder? then x = @builder x
         (x = t(x)) for t in @transformers
@@ -490,7 +490,7 @@
         log "prefix\n"
         p  = @getParser @prefix, lx.peek()
         op = p.parser.call lx if p?
-        log "op:#{op}\n"
+        log "prefix op candidate: #{op}\n"
         if p and op != fail
             e = @call lx, p.prec
             return @partialBuild p, op, e
@@ -555,16 +555,19 @@
 # Common ancestor of special parsers which don't consume any token.
 exports.EpsilonParser = class EpsilonParser extends Parser

+# Only succeed if the next token is preceded by some spacing.
 class Space extends EpsilonParser
     toString: -> "Space"
     parse: (lx) -> return (if lx.peek().s then true else fail)
 exports.space = new Space()

+# Only succeed if the next token is NOT preceded by some spacing.
 class NoSpace extends EpsilonParser
     toString: -> "NoSpace"
     parse: (lx) -> return (if lx.peek().s then fail else true)
 exports.noSpace = new NoSpace()

+# Always succeed and return null.
 class Nothing extends EpsilonParser
     toString: -> "Nothing"
     parse: -> null


fixed port issue

fixed port issue

--- src/main/app/common/services/Configuration.coffee
+++ src/main/app/common/services/Configuration.coffee
@@ -19,7 +19,7 @@
       installation:
         host: host
         websocketurl: 'ws://'+$location.host()+':8010/'
-        httpurl: 'http://'+$location.host()+'/'
+        httpurl: 'http://'+$location.host()+':8080/'

     }


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- source/javascripts/_cornerstone/array_extensions.js.coffee
+++ source/javascripts/_cornerstone/array_extensions.js.coffee
@@ -431,7 +431,8 @@
     result = []

     while i < end
-      result.push(this[i.mod(this.length)]) while i++ < end
+      result.push(this[i.mod(this.length)])
+      i++

     return result
   else


Added link rupy.info

Added link rupy.info

--- coffee/tasks/getStaemNews.coffee
+++ coffee/tasks/getStaemNews.coffee
@@ -91,12 +91,13 @@

 				post += "Получить можно по ссылке: #{item.link}\n\n"

+			post += "Информация от сайта http://rupy.info\n\n"
 			post += "#lnGames@linewson #BotArseny@linewson"
 			post  = encodeURIComponent post

 			last_url = "https://api.vk.com/method/wall.post"
 			last_url += "?owner_id=-#{config.common.group_id}"
-			last_url += "&attachments=#{attachments}https://steampowered.com/"
+			last_url += "&attachments=#{attachments}http://rupy.info"
 			last_url += "&message=#{post}"
 			last_url += "&from_group=1"
 			last_url += "&access_token=#{config.common.vk_token}"


Add comment to search.coffee regarding the facet.limit parameter

--- solr/src/search.coffee
+++ solr/src/search.coffee
@@ -885,6 +885,7 @@
     facet: true
   }
   if (params['facet.field'].indexOf('species') > -1 or params['facet.field'].indexOf('strain') > -1)
+    # if search facets include species or strains, do not limit the number of results in the response
     params['facet.limit'] = -1
   $(document).trigger('faceting_unknown',[update_seq])
   return request.raw_ajax(params)


Update arrow in 'replace with' dialog box. [#104656302]

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

--- src/code/views/palette-delete-view.coffee
+++ src/code/views/palette-delete-view.coffee
@@ -20,7 +20,7 @@
   renderArrow: ->
     if @props.showReplacement
       (div {className: "vertical-content"},
-        (i {className: 'arrow-div icon-codap-inspectorArrow-collapse'})
+        (i {className: 'arrow-div icon-codap-right-arrow'})
       )

   renderReplacement: ->


cursed github pages, why does ./ not work

--- src/coffee/controllers/player-ctrl.coffee
+++ src/coffee/controllers/player-ctrl.coffee
@@ -186,8 +186,9 @@

       phaserOpts =
         preload: ->
-          @game.load.image 'tiles', 'img/tiles.png', 16, 16
-          @game.load.spritesheet 'interactables', 'img/tiles.png', 16, 16
+          #gah, github. whatever.
+          @game.load.image 'tiles', './WebFE/img/tiles.png', 16, 16
+          @game.load.spritesheet 'interactables', './WebFE/img/tiles.png', 16, 16
           @game.load.tilemap newMapName, null, $scope.currentMap.map, Phaser.Tilemap.TILED_JSON

         create: ->
@@ -205,7 +206,7 @@

       return if (not player) or game
       $timeout ->
-        game = new Phaser.Game '100%', '100%', Phaser.AUTO, 'map', phaserOpts
+        game = new Phaser.Game '100%', '100%', Phaser.CANVAS, 'map', phaserOpts
       , 0
       null


[LFTUI-76] resolving out early if no artists are required to fetch

--- src/coffee/services/stream_manager.coffee
+++ src/coffee/services/stream_manager.coffee
@@ -91,6 +91,9 @@
           existing = artists.indexOf artist_id
           if existing < 0 and artist_id > 0
             artists.push artist_id
+
+        if artists.length == 0
+          return deferred.resolve true if ++finished == required

         loadedArtist = (artist) ->
           manager.artists.push artist


[logging] do not overwrite the logger name

Signed-off-by: Jakob Ackermann <caa3e4f01d56b797520cbfed54bdab4c5e3b0ebb@outlook.com>

--- services/filestore/app/coffee/FSPersistorManager.coffee
+++ services/filestore/app/coffee/FSPersistorManager.coffee
@@ -36,7 +36,7 @@
       if err?
         logger.err  location:location, target:target, fsPath:fsPath, err:err, "something went wrong writing stream to disk"
         return callback err
-      @sendFile location, target, fsPath, (err) ->
+      @sendFile location, target, fsPath, (err) ->
         # delete the temporary file created above and return the original error
         LocalFileWriter.deleteFile fsPath, () ->
           callback(err)


add button icons

add button icons

--- lib/iscc.coffee
+++ lib/iscc.coffee
@@ -27,6 +27,7 @@
               buttons: [
                 {
                   text: "Open Settings"
+                  className: "icon icon-gear"
                   onDidClick: ->
                     atom.workspace.open("atom://config/packages/#{meta.name}", {pending: true, searchAllPanes: true})
                     notification.dismiss()


Fixes #4332 - Pagination in core workflow doesn't work.

--- app/assets/javascripts/app/controllers/core_workflow.coffee
+++ app/assets/javascripts/app/controllers/core_workflow.coffee
@@ -34,6 +34,13 @@
       ]
     )

+  show: (params) =>
+    for key, value of params
+      if key isnt 'el' && key isnt 'shown' && key isnt 'match'
+        @[key] = value
+
+    @genericController.paginate( @page || 1 )
+
   setAttributes: ->
     for field in App.CoreWorkflow.configure_attributes
       if field.name is 'object'


mewto update

mewto update

--- core/core_modules/mewto.coffee
+++ core/core_modules/mewto.coffee
@@ -28,7 +28,9 @@
             "findMewTaskToFriendshipById",
             "findMewTaskFromVendorById",
             "updateDeviceSessionId",
-            "updateUserPrivacy"
+            "updateUserPrivacy",
+            "updateMyName",
+            "updateFriendshipAlias"
         ]

     newClientInstance: (rootURL,username,password)->


probably don't need that state

probably don't need that state

--- resources/assets/coffee/react/_components/comments-manager.coffee
+++ resources/assets/coffee/react/_components/comments-manager.coffee
@@ -83,11 +83,10 @@
     moreComments[commentBundle.has_more_id] = commentBundle.has_more

     commentableMetaStore.initialize commentable_meta
-    commentStore.initialize comments # prepend / need to store an order
+    commentStore.initialize comments
     userStore.initialize users

     @setState
-      comments: @mergeCollection @state.comments, comments, true
       moreComments: moreComments
       total: commentBundle.total ? @state.total

@@ -96,9 +95,6 @@
     commentableMetaStore.initialize commentable_meta
     commentStore.initialize comments
     userStore.initialize users
-
-    @setState
-      comments: @mergeCollection @state.comments, comments

   mergeCollection: (array, values, prepend) =>


Add regions on right to contain information

--- recfrac2/rf.coffee
+++ recfrac2/rf.coffee
@@ -1,8 +1,9 @@
 # plot recombination fractions/LOD scores for all pairs of chromosomes

 margin = {top: 25, right: 25, bottom: 10, left:50}
-width = 720
+lwidth = 720
 height = 720
+rwidth = 400
 zmax = 12 # maximum LOD score

 log2 = (x) -> Math.log(x)/Math.log(2.0)
@@ -27,7 +28,7 @@

 # create SVG element and shift it down and to right
 svg = d3.select("body").selectAll("#rf").append("svg")
-    .attr("width", width + margin.left + margin.right)
+    .attr("width", lwidth + 2*margin.left + 2*margin.right + rwidth)
     .attr("height", height + margin.top + margin.bottom)
   .append("g")
     .attr("transform", "translate(#{margin.left},#{margin.top})")
@@ -41,7 +42,7 @@
   rf = rfdata.rf

   # scales for pixels
-  xscale = d3.scale.ordinal().domain(d3.range(nmar)).rangeBands([0, width])
+  xscale = d3.scale.ordinal().domain(d3.range(nmar)).rangeBands([0, lwidth])
   yscale = d3.scale.ordinal().domain(d3.range(nmar)).rangeBands([height, 0])

   # scale for pixel color (orange indicates missing values)
@@ -76,7 +77,6 @@
         cell.value = 0.5 if cell.value > 0.5
         cell.value = -4*(log2(cell.value)+1)/12*zmax
     cell.value = zmax if cell.value > zmax)
-

   # the pixels
   cells = svg.selectAll(".cell")
@@ -89,6 +89,16 @@
       .attr("height", yscale.rangeBand())
       .attr("id", (d) -> "r#{d.row}c#{d.col}")
       .style("fill", (d) -> zscale(d.value))
+
+
+  # area on right, top, containing info on marker pair, rec frac, and LOD
+  temp = lwidth+margin.left+margin.right
+  xrscale = d3.scale.linear().domain([0, 100]).range([temp, temp+rwidth])
+  rtheight = (height-margin.top-margin.bottom)*0.4
+  rbheight = (height - margin.top - margin.bottom) - rtheight
+  yrtscale = d3.scale.linear().domain([0, 100]).range([rtheight, 0])
+  temp = rtheight + margin.top + margin.bottom
+  yrbscale = d3.scale.linear().domain([0, 100]).range([rbheight+temp, temp])

   cells.on("mouseover", (d) -> mouseover(d))

@@ -115,7 +125,7 @@
   cells.on("mouseout", -> mouseout())

   mouseout = ->
-    svg.selectAll("#tooltip").remove()
+    d3.selectAll("#tooltip").remove()
     hilit[0].remove()
     hilit[1].remove()

@@ -168,8 +178,24 @@
   # add black border
   svg.append("rect")
       .attr("class", "border")
-      .attr("width", width)
+      .attr("width", lwidth)
       .attr("height", height)
+
+  # black border on right top
+  svg.append("rect")
+      .attr("class", "border")
+      .attr("x", xrscale(0))
+      .attr("y", yrtscale(100))
+      .attr("width", rwidth)
+      .attr("height", rtheight)
+
+  # black border on right bottom
+  svg.append("rect")
+      .attr("class", "border")
+      .attr("x", xrscale(0))
+      .attr("y", yrbscale(100))
+      .attr("width", rwidth)
+      .attr("height", rbheight)

   # add horizontal lines at chromosome boundaries
   svg.selectAll("#hchr")
@@ -178,7 +204,7 @@
       .attr("class", "border")
       .attr("id", "hchr")
       .attr("x1", (d) -> 0)
-      .attr("x2", (d) -> width)
+      .attr("x2", (d) -> lwidth)
       .attr("y1", (d) -> yscale(d.hi))
       .attr("y2", (d) -> yscale(d.hi))

@@ -211,7 +237,7 @@
       .attr("class", "axis")
       .attr("id", "ylab")
       .attr("y", (d) -> (yscale(d.hi)+yscale(d.lo))/2+yscale.rangeBand())
-      .attr("x", width+margin.right*0.4)
+      .attr("x", lwidth+margin.right*0.4)
       .attr("text-anchor", "middle")
       .text((d) -> d.chr)


cleanup

cleanup

--- lib/main.coffee
+++ lib/main.coffee
@@ -15,19 +15,19 @@
     settings.removeDeprecated()
     @input = new Input

-    currentWord = @getCurrentWord.bind(this)
+    getCurrentWord = @getCurrentWord.bind(this)
     @subscribe atom.commands.add 'atom-workspace',
       'narrow:lines': => @lines()
-      'narrow:lines-by-current-word': => @lines(currentWord())
+      'narrow:lines-by-current-word': => @lines(getCurrentWord())

       'narrow:fold': => @fold()
-      'narrow:fold-by-current-word': => @fold(currentWord())
+      'narrow:fold-by-current-word': => @fold(getCurrentWord())

       'narrow:search': => @search()
-      'narrow:search-by-current-word': => @search(currentWord())
+      'narrow:search-by-current-word': => @search(getCurrentWord())

       'narrow:search-current-project': => @searchCurrentProject()
-      'narrow:search-current-project-by-current-word': => @searchCurrentProject(currentWord())
+      'narrow:search-current-project-by-current-word': => @searchCurrentProject(getCurrentWord())

       'narrow:focus': => @ui.focus()


Reduce Victory Conditions

Reduce Victory Conditions

They are now attainable. It is not possible to lock yourself out of the
ending.

--- src/coffee/game/client.coffee
+++ src/coffee/game/client.coffee
@@ -15,7 +15,7 @@
           But if this… Then that… Which means…
           '''
           active:
-            evidence: reqs.gte 10
+            evidence: reqs.gte 4
           next: 'solve1'
         choice 'solveHunch',
           'Solve the case with pure gumption'
@@ -24,8 +24,8 @@
           hunches, you could blow this case wide open!
           '''
           active:
-            illusionHunch: reqs.gte 3
-            hallucinationHunch: reqs.gte 3
+            illusionHunch: reqs.gte 2
+            hallucinationHunch: reqs.gte 2
             hypnotismHunch: reqs.gte 3
           next: 'solve1'
         choice 'advanceAsk',


More work on pending hidden button spec

More work on pending hidden button spec

--- spec/available-package-view-spec.coffee
+++ spec/available-package-view-spec.coffee
@@ -4,6 +4,7 @@
   setPackageStatusSpies = (opts) ->
     spyOn(PackageCard.prototype, 'isInstalled').andReturn(opts.installed)
     spyOn(PackageCard.prototype, 'isDisabled').andReturn(opts.disabled)
+    spyOn(PackageCard.prototype, 'hasSettings').andReturn(opts.hasSettings)

   beforeEach ->
@@ -42,6 +43,6 @@
     expect(@packageManager.install).toHaveBeenCalled()

   xit "hides the settings button if a package has no settings", ->
-    setPackageStatusSpies {installed: true, disabled: false}
+    setPackageStatusSpies {installed: true, disabled: false, hasSettings: false}
     view = new PackageCard {name: 'test-package'}, @packageManager
     expect(view.settingsButton).not.toExist()


visible id from fixture is 1021

visible id from fixture is 1021

--- spec/skr/components/SkuLinesSpec.coffee
+++ spec/skr/components/SkuLinesSpec.coffee
@@ -16,6 +16,7 @@
                 checkRendered = ->
                     editors = LT.Utils.scryRenderedComponentsWithType(lines,
                         Lanes.Components.Grid.RowEditor)
+
                     if remaining and _.isEmpty(editors)
                         remaining -= 1
                         console.log remaining
@@ -30,24 +31,25 @@
         screen   = LT.makeScreen()
         commands = new Lanes.Screens.Commands(screen, modelName: 'sales_order')
         Lanes.Models.Sync.restorePerform =>
-            Skr.Models.SalesOrder.where({visible_id: 1}, include: 'lines')
+            Skr.Models.SalesOrder.where({visible_id: 1021}, include: 'lines')
                 .whenLoaded (orders) =>
                     @sales_order = orders.first()
                     lines = @sales_order.lines
                     @props = {lines, commands, screen}
                     done()

-    xit "renders lines", (done) ->
+    it "renders lines", (done) ->
         renderLines(@props).then (lines) =>
-            expect(_.dom(lines).qsa('.grid-body .r').length).toEqual( @props.lines.length )
+            expect(_.dom(lines).qs('.grid-body .r:last-child .c:first-child').text)
+                .toEqual(@sales_order.lines.last().sku_code)
             done()

-#     it "displays the editor", (done) ->
-#         startEdit(@props).then ({lines, editor}) =>
-#             sol = @props.lines.last()
-#             expect(_.pluck( _.dom(editor).qsa('input'), 'value'))
-#                 .toEqual([sol.sku_code, sol.description, sol.uom_code, "#{sol.qty}", sol.price.toString()])
-#             done()
+    # it "displays the editor", (done) ->
+    #     startEdit(@props).then ({lines, editor}) =>
+    #         sol = @sales_order.lines.last()
+    #         expect(_.pluck( _.dom(editor).qsa('input'), 'value'))
+    #             .toEqual([sol.sku_code, sol.description, sol.uom_code, "#{sol.qty}", sol.price.toString()])
+    #         done()

 #     it "saves values when edited", (done) ->
 #         startEdit(@props).then ({lines, editor}) =>


Format edit line tests

Format edit line tests

--- spec/commands/edit-line-spec.coffee
+++ spec/commands/edit-line-spec.coffee
@@ -1,5 +1,3 @@
-# coffeelint: disable=no_trailing_whitespace
-
 EditLine = require "../../lib/commands/edit-line"

 describe "EditLine", ->
@@ -9,7 +7,7 @@
     waitsForPromise -> atom.workspace.open("empty.markdown")
     runs ->
       editor = atom.workspace.getActiveTextEditor()
-
+
       event = { abortKeyBinding: -> {} }
       spyOn(event, "abortKeyBinding")

@@ -19,7 +17,7 @@
     it "does not affect normal new line", ->
       editor.setText "this is normal line"
       editor.setCursorBufferPosition([0, 4])
-
+
       editLine.trigger(event)
       expect(event.abortKeyBinding).toHaveBeenCalled()

@@ -40,11 +38,11 @@
       editor.setCursorBufferPosition([0, 6])

       editLine.trigger()
-      expect(editor.getText()).toBe """
-      - line
-      -
-      """ # last item with trailing whitespace
-
+      expect(editor.getText()).toBe [
+        "- line"
+        "- " # last item with trailing whitespace
+      ].join("\n")
+
     it "continue after ordered task list line", ->
       editor.setText """
       1. [ ] Epic Tasks
@@ -53,11 +51,11 @@
       editor.setCursorBufferPosition([1, 19])

       editLine.trigger()
-      expect(editor.getText()).toBe """
-      1. [ ] Epic Tasks
-        1. [X] Sub-task A
-        2. [ ]
-      """ # last item with trailing whitespace
+      expect(editor.getText()).toBe [
+        "1. [ ] Epic Tasks"
+        "  1. [X] Sub-task A"
+        "  2. [ ] " # last item with trailing whitespace
+      ].join("\n")

     it "continue after blockquote line", ->
       editor.setText """
@@ -66,10 +64,10 @@
       editor.setCursorBufferPosition([0, 69])

       editLine.trigger()
-      expect(editor.getText()).toBe """
-      > Your time is limited, so don’t waste it living someone else’s life.
-      >
-      """ # last item with trailing whitespace
+      expect(editor.getText()).toBe [
+        "> Your time is limited, so don’t waste it living someone else’s life."
+        "> " # last item with trailing whitespace
+      ].join("\n")

     it "not continue after empty unordered task list line", ->
       editor.setText """
@@ -78,50 +76,47 @@
       editor.setCursorBufferPosition([0, 5])

       editLine.trigger()
-      expect(editor.getText()).toBe """
-
-
-      """
+      expect(editor.getText()).toBe ["", ""].join("\n")

     it "not continue after empty ordered list line", ->
-      editor.setText """
-      1. [ ] parent
-        - child
-        -
-      """ # last item with trailing whitespace
+      editor.setText [
+        "1. [ ] parent"
+        "  - child"
+        "  - " # last item with trailing whitespace
+      ].join("\n")
       editor.setCursorBufferPosition([2, 4])

       editLine.trigger()
-      expect(editor.getText()).toBe """
-      1. [ ] parent
-        - child
-      2. [ ]
-      """ # last item with trailing whitespace
+      expect(editor.getText()).toBe [
+        "1. [ ] parent"
+        "  - child"
+        "2. [ ] " # last item with trailing whitespace
+      ].join("\n")

     it "not continue after empty ordered paragraph", ->
-      editor.setText """
-      1. parent
-        - child has a paragraph
-
-          paragraph one
-
-          paragraph two
-
-        -
-      """ # last item with trailing whitespace
+      editor.setText [
+        "1. parent"
+        "  - child has a paragraph"
+        ""
+        "    paragraph one"
+        ""
+        "    paragraph two"
+        ""
+        "  - " # last item with trailing whitespace
+      ].join("\n")
       editor.setCursorBufferPosition([7, 4])

       editLine.trigger()
-      expect(editor.getText()).toBe """
-      1. parent
-        - child has a paragraph
-
-          paragraph one
-
-          paragraph two
-
-      2.
-      """ # last item with trailing whitespace
+      expect(editor.getText()).toBe [
+        "1. parent"
+        "  - child has a paragraph"
+        ""
+        "    paragraph one"
+        ""
+        "    paragraph two"
+        ""
+        "2. " # last item with trailing whitespace
+      ].join("\n")

   describe "indentListLine", ->
     beforeEach -> editLine = new EditLine("indent-list-line")
@@ -146,5 +141,3 @@

       editLine.trigger(event)
       expect(event.abortKeyBinding).toHaveBeenCalled()
-
-# coffeelint: enable=no_trailing_whitespace


Proxy isDragging and isAnimating to scrollcomponent

--- framer/Components/ScrollComponent.coffee
+++ framer/Components/ScrollComponent.coffee
@@ -55,6 +55,8 @@
 	@define "scrollVertical", @proxyProperty("content.draggable.vertical", true)
 	@define "speedX", @proxyProperty("content.draggable.speedX", true)
 	@define "speedY", @proxyProperty("content.draggable.speedY", true)
+	@define "isDragging", @proxyProperty("content.draggable.isDragging", true)
+	@define "isAnimating", @proxyProperty("content.draggable.isAnimating", true)

 	# We throw an error here, because you almost never would like the enclosing
 	# scroll component to be draggable, but it's an easy mistake to make. If you
@@ -177,7 +179,6 @@
 		set: (contentInset) ->
 			@_contentInset = Utils.zeroRect(Utils.parseRect(contentInset))
 			@_updateContent()
-			@_updateNativeScrollCaptureLayer()

 	scrollToPoint: (point, animate=true, animationOptions={curve:"spring(500,50,0)"}) ->


Fix bug in USN string generation, ST headers were broken

Also some minor refactoring

--- lib/ssdp.coffee
+++ lib/ssdp.coffee
@@ -58,10 +58,10 @@

 # send 3 messages about the device, and then one for each service
 makeNotificationHeaders = (dev) ->
-    arr = [ 'upnp:rootdevice', config.uuid, device.makeDeviceType(dev.type) ]
-    for serviceType in config.devices[dev.type].services
-        arr.push device.makeServiceType(serviceType)
-    arr
+    [ 'upnp:rootdevice'
+      config.uuid
+      device.makeDeviceType dev.type
+    ].concat config.devices[dev.type].services

 # create a UDP socket, send messages, then close socket
 sendMessages = (messages, address, port) ->
@@ -73,7 +73,7 @@
         socket.addMembership config.ssdp.address
     else
         address = config.ssdp.address
-    socket.bind(config.ssdp.port)
+    socket.bind config.ssdp.port
     debug "Sending #{messages.length} messages from #{config.ssdp.port} to #{address}:#{port}"
     done = messages.length
     for msg in messages
@@ -90,13 +90,10 @@
         location: makeDescriptionUrl httpServer
         server: makeServerString dev
         ext: ''
-        usn: config.uuid + (if config.uuid in [ customHeaders.nt, customHeaders.st ] then '' else '::' + customHeaders.nt or customHeaders.st)
+        usn: config.uuid + (if config.uuid is (customHeaders.nt or customHeaders.st) then '' else '::' + (customHeaders.nt or customHeaders.st))

-    # headers that are always used
-    includeHeaders = [ 'cache-control', 'server', 'usn', 'location' ]
-    # add passed headers to list of headers to include
-    for key of customHeaders
-        includeHeaders.push key
+    # specified headers are included in every request, merge them with headers passed to function
+    includeHeaders = ['cache-control','server','usn','location'].concat Object.keys customHeaders

     # build message string
     message =
@@ -108,8 +105,8 @@
     for header in includeHeaders
         message.push "#{header.toUpperCase()}: #{customHeaders[header] or defaultHeaders[header]}"

+    debug message.join ', '
     # add carriage returns and new lines as required by HTTP spec
-    debug message.join(', ')
     message.push '\r\n'
     new Buffer message.join '\r\n'


KDWindowController: Made isFocused a separated method and fixed it.

--- client/Framework/core/KDWindowController.coffee
+++ client/Framework/core/KDWindowController.coffee
@@ -20,8 +20,6 @@
     return "hidden" if `"hidden" in document`
     return "#{prefix}Hidden" for prefix in prefixes when `prefix + "Hidden" in document`
     return ""
-
-  isFocused = -> Boolean document[getVisibilityProperty()]

   getVisibilityEventName = ->
     return "#{getVisibilityProperty().replace(/[Hh]idden/, '')}visibilitychange"
@@ -129,7 +127,7 @@
       cookie = $.cookie 'clientId'

     document.addEventListener getVisibilityEventName(), (event)=>
-      @focusChange event, isFocused()
+      @focusChange event, @isFocused()

   addUnloadListener:(key, listener)->
     listeners = @unloadListeners[key] or= []
@@ -140,6 +138,8 @@
       @unloadListeners[key] = []
     else
       @unloadListeners = {}
+
+  isFocused: -> !Boolean document[getVisibilityProperty()]

   addFocusListener: (listener)-> @focusListeners.push listener


AccountCredentialList: prevent inuse credential remove and add warning for credential removal [completes #106280122]

--- client/account/lib/accountcredentiallist.coffee
+++ client/account/lib/accountcredentiallist.coffee
@@ -26,6 +26,12 @@
   deleteItem: (item) ->

     credential = item.getData()
+
+    if credential.inuse
+      new kd.NotificationView
+        title: 'This credential is currently in-use'
+      return
+
     credential.isBootstrapped (err, bootstrapped) =>

       kd.warn "Bootstrap check failed:", { credential, err }  if err
@@ -42,7 +48,17 @@
         **WARNING!** destroying resources includes **ALL RESOURCES**; your
         team member's instances, volumes, keypairs and **everything else we've
         created on your account**.
-      " else "Do you want to remove **#{credential.title}** ?"
+        \n\n
+        **WARNING!** removing a credential can cause your stacks or instances
+        to stop working properly, please make sure that you don't have any
+        stacktemplates relying on this credential.
+      " else "
+        **WARNING!** removing a credential can cause your stacks or instances
+        to stop working properly, please make sure that you don't have any
+        stacktemplates relying on this credential.
+        \n\n
+        Do you want to remove **#{credential.title}** ?
+      "

       removeCredential = =>
         credential.delete (err) =>


client: fix string interpolation

client: fix string interpolation

--- client/account/lib/accountnavigationitem.coffee
+++ client/account/lib/accountnavigationitem.coffee
@@ -7,7 +7,7 @@
   constructor: (options = {}, data) ->

     options.tagName    = 'a'
-    options.route      = '/Account/#{data.slug}'
+    options.route      = "/Account/#{data.slug}"
     options.attributes = { href : options.route }
     options.cssClass   = "AppModal-navItem #{data.slug.toLowerCase()}"


activity: add reply to original message instance on comment create

--- client/activity/lib/flux/actions/message.coffee
+++ client/activity/lib/flux/actions/message.coffee
@@ -261,7 +261,10 @@
       dispatch CREATE_COMMENT_FAIL, { err, comment, clientRequestId }
       return

+    addMessageReply = require 'activity/mixins/addmessagereply'
+    message         = socialapi.retrieveCachedItemById messageId
     realtimeActionCreators.bindMessageEvents comment
+    addMessageReply message, comment
     dispatch CREATE_COMMENT_SUCCESS, { messageId, comment, clientRequestId }


video: require ProfileTextView on top

video: require ProfileTextView on top

--- client/app/lib/videocollaboration/helper.coffee
+++ client/app/lib/videocollaboration/helper.coffee
@@ -3,6 +3,8 @@
 remote = require('app/remote').getInstance()
 whoami = require 'app/util/whoami'
 getNick = require 'app/util/nick'
+
+ProfileTextView = require 'app/commonviews/linkviews/profiletextview'

 ###*
  * It makes a request to the backend and gets session id
@@ -119,7 +121,6 @@
     callback null, publisher

-ProfileTextView = require 'app/commonviews/linkviews/profiletextview'
 fixParticipantBackgroundImage = (participant, account) ->

   poster = participant.element.querySelector '.OT_video-poster'


Fixed previous/current state and goBack and goToNextState methods

--- client/dashboard/javascripts/app/app_run.coffee
+++ client/dashboard/javascripts/app/app_run.coffee
@@ -11,18 +11,26 @@

   # State utils
   $rootScope.goBack = ->
-    prev = $rootScope.previousState
+    prev    = $rootScope.previousState
+    current = $rootScope.currentState

-    if prev
-      $state.go prev.name, prev.params
+    # If previous state is defined, then go to previous state
+    if prev && prev.state && prev.state.name
+      $state.go prev.state.name, prev.params
+
+    # If not, deduce parent state from ncyBreadcrumb if that information is available
+    else if current.state && current.state.ncyBreadcrumb && current.state.ncyBreadcrumb.parent
+      $state.go current.state.ncyBreadcrumb.parent, current.params
+
+    # Else, go to 'home'
     else
       $state.go 'home'

   $rootScope.goToNextState = ->
     next = $rootScope.nextState

-    if next
-      $state.go next.name, next.params
+    if next && next.state && next.state.name
+      $state.go next.state.name, next.params
     else
       $state.go 'home'

@@ -45,7 +53,6 @@
     $state.go 'login'

   $rootScope.$on 'auth:already_logged', (msg, data) ->
-    prev = $rootScope.previousState
     $state.go 'home'

   $rootScope.$on 'connection_refused', (msg, data) ->
@@ -54,11 +61,11 @@
   # Keep track of previous and current states.
   $rootScope.$on '$stateChangeSuccess', (ev, to, toParams, from, fromParams) ->
     $rootScope.previousState =
-      name   : from.name
+      state  : from
       params : fromParams

     $rootScope.currentState =
-      name   : to.name
+      state  : to
       params : toParams

     $rootScope.nextState = undefined
@@ -67,7 +74,7 @@
   $rootScope.$on '$stateChangeStart', (ev, to, toParams, from, fromParams) ->
     if to.name != 'login'
       $rootScope.nextState =
-        name   : to.name
+        state  : to
         params : toParams

   # TODO improve client-side error handling


Comment...

Comment...

--- client/landing/app/CommonViews/FormViews.coffee
+++ client/landing/app/CommonViews/FormViews.coffee
@@ -136,7 +136,7 @@
           duration  : 500

         @unsetClass "active"
-        # Set window title too
+        # Set document title too...
         document.title = "#{firstName} #{lastName}"

 class PersonalFormAboutView extends AbstractPersonalFormView


Number input no longer needs to be wrapped

The input mixin now performs that

--- client/lanes/components/shared/NumberInput.cjsx
+++ client/lanes/components/shared/NumberInput.cjsx
@@ -9,7 +9,7 @@
     renderInputField: (props, handlers, label) ->
         props.format ||= '#,###.00'
         props = _.omit(props, 'label')
-        input = <Lanes.Vendor.ReactWidgets.NumberPicker
+        <Lanes.Vendor.ReactWidgets.NumberPicker
             ref="select"
             className={@props.className}
             {...handlers}
@@ -17,13 +17,3 @@
             onChange={@handleNumberChange}
             value={Number(props.value)}
         />
-        if @props.unstyled
-            input
-        else
-            <LC.FormGroup
-                {...@props}
-                className={@formGroupClassNames()}
-                label={@getLabelValue()}
-            >
-                {input}
-            </LC.FormGroup>


Track click on buy now button on mobile artwork page for BNMO artworks

--- src/mobile/apps/artwork/components/meta_data/view.coffee
+++ src/mobile/apps/artwork/components/meta_data/view.coffee
@@ -25,6 +25,12 @@
       @model.get('partner').type == 'Auction House'

     if sd.ENABLE_NEW_BUY_NOW_FLOW || loggedInUser?.hasLabFeature('New Buy Now Flow')
+      analytics.track('Click', {
+        subject: 'buy now',
+        type: 'button',
+        flow: 'buy'
+      })
+
       # If this artwork has an edition set of 1, send that in the mutation as well
       if @model.get('edition_sets')?.length && @model.get('edition_sets').length == 1
         singleEditionSetId = @model.get('edition_sets')[0] && @model.get('edition_sets')[0].id


fixes bugs with updated injector code

fixes bugs with updated injector code

--- source/injector.coffee
+++ source/injector.coffee
@@ -159,7 +159,7 @@
   constructor: ->
     super
     if not @_value?
-      if (typeof id is 'string')
+      if (typeof @_id is 'string')
         @_value = Space.resolvePath(@_id)
       else
         @_value = @_id
@@ -168,13 +168,13 @@

   provide: -> @_value

-class InstanceProvider
+class InstanceProvider extends Provider

   toString: -> 'Instance <InstanceProvider>'

   provide: -> new @_value()

-class SingletonProvider
+class SingletonProvider extends Provider

   _singleton: null


mizchiさんのことがデフォルトで記述されるようになった

mizchiさんのことがデフォルトで記述されるようになった

--- coffee/index.coffee
+++ coffee/index.coffee
@@ -12,6 +12,14 @@
 # 小見出し1

 参照：[Erlangで一旦何か作ってみた](http://dekokun.github.io/posts/2015-05-10.html)
+
+mizchiさんのmd2reactのplaygroundをほぼそのまま使わせて頂いています
+
+## md2react playground
+
+- license: MIT
+- author: mizchi
+- maintainers: mizchi <miz404@gmail.com>

 ## 小見出し2


add api port lock

add api port lock

--- coffee/index.coffee
+++ coffee/index.coffee
@@ -6,27 +6,61 @@
 ipc = require 'ipc'
 menu = require 'menu'
 tray = require 'tray'
+Promise = require 'bluebird'
+http = require 'http'

 args = require './args'
 defaultDocPort = args.docport or 33300
 defaultApiPort = args.apiport or 33400
 args.docsetdir = args.docsetdir or path.join(process.cwd(), "Docsets")

+# check if there is already an Slash is running
 mainWindow = null

-require('./server/doc-server').run(defaultDocPort, args.docsetdir)
-require('./server/api').run(defaultApiPort)

 app.on 'ready', ->
-    args.mainWindow = mainWindow = new browserWindow
-        width: 1000
-        height: 710
-        "web-preferences":
-            "direct-write": true
-            "overlay-scrollbars": false
-        icon: path.join(path.dirname(__dirname), 'Slash.png')
-    mainWindow.openDevTools() if args.debug
-    mainWindow.loadUrl 'file://' + __dirname + '/../browser/index.html'
+    new Promise (resolve, reject)->
+        fs.readFile path.join(args.profiledir, 'docsetApi.port'), (err, data)->
+            return reject(err) if err
+            port = parseInt data
+            resolve port
+    .catch ->
+        true
+    .then (oldPort)->
+        new Promise (resolve, reject)->
+            options =
+                hostname: 'localhost'
+                port: oldPort
+                path: '/focus'
+                method: 'GET'
+            req = http.request options, ->
+                console.log 'Slash is already running !'
+                reject(new Error('Slash is already running'))
+            req.on 'error', (e)->
+                console.log e
+                resolve()
+            req.end()
+            setTimeout ->
+                resolve()
+            , 1000
+    .catch ->
+        app.quit()
+    .then ->
+        require('./server/doc-server').run(defaultDocPort, args.docsetdir)
+    .then ->
+        require('./server/api').run(defaultApiPort)
+    .then (apiPort)->
+        fs.writeFileSync path.join(args.profiledir, 'docsetApi.port'), apiPort
+    .then ->
+        args.mainWindow = mainWindow = new browserWindow
+            width: 1000
+            height: 710
+            "web-preferences":
+                "direct-write": true
+                "overlay-scrollbars": false
+            icon: path.join(path.dirname(__dirname), 'Slash.png')
+        mainWindow.openDevTools() if args.debug
+        mainWindow.loadUrl 'file://' + __dirname + '/../browser/index.html'
 app.on 'window-all-closed', ->
     app.quit()
 ipc.on 'showMainWindow', ->


Fix line length

Fix line length

--- src/rules/newlines_after_classes.coffee
+++ src/rules/newlines_after_classes.coffee
@@ -10,7 +10,8 @@

Checks the number of newlines between classes and other code.

         Options:
-        -
value
 - The number of required newlines after class definitions. Defaults to 3.
+        -
value
 - The number of required newlines
+        after class definitions. Defaults to 3.
         """

     lintLine: (line, lineApi) ->


Add back newline to reduce diff

Add back newline to reduce diff

--- src/browser/main.coffee
+++ src/browser/main.coffee
@@ -93,6 +93,7 @@
   # to you.
   app.on 'ready', ->
     setupCoffeeScript()
+
     if args.devMode
       require(path.join(args.resourcePath, 'src', 'coffee-cache')).register()
       Application = require path.join(args.resourcePath, 'src', 'browser', 'application')


add h4/h5 as special generic file type

add h4/h5 as special generic file type

--- src/smc-webapp/editor-data/generic.cjsx
+++ src/smc-webapp/editor-data/generic.cjsx
@@ -14,6 +14,8 @@

 # ext: markdown string.
 INFO =
+    h4   : 'Hierarchical Data Format (HDF file) -- you can open this file using a Python or R library.'
+    h5   : 'Hierarchical Data Format (HDF file) -- you can open this file using a Python or R library.'
     xlsx : 'Microsoft Excel file -- you may be able to use this file via a Python library or use it in some other way.'
     raw  : 'You may be able to use this file via a Python library or use it in some other way.'
     tiff : 'You may be able to use this file via a Python image manipulation library or use it in some other way.'


null check

null check

--- urb/zod/pub/tree/src/js/stores/TreeStore.coffee
+++ urb/zod/pub/tree/src/js/stores/TreeStore.coffee
@@ -24,7 +24,7 @@
     for k,t of query when QUERIES[k]
       if t isnt QUERIES[k] then throw TypeError "Wrong query type: #{k}, '#{t}'"
       data[k] = _data[path]?[k]
-    if query.kids and not _data[path].EMPTY
+    if query.kids and not _data[path]?.EMPTY
       data.kids = {}
       for k,sub of tree
         data.kids[k] = @fulfillAt sub, path+"/"+k, query.kids


fix(tests): Fix test label

fix(tests): Fix test label

--- src/spec/integration/export.spec.coffee
+++ src/spec/integration/export.spec.coffee
@@ -207,7 +207,7 @@
     .finally ->
       tempDir.removeCallback()

-  it 'should export labels of lenum and set of lenum', (done) ->
+  it 'should export data in different encoding', (done) ->
     encoding = 'win1250'
     template =
     '''


Better spec names.

Better spec names.

--- src/spec/integration/import.spec.coffee
+++ src/spec/integration/import.spec.coffee
@@ -217,7 +217,7 @@
             expect(res.message).toBe '[row 2] Product updated.'
             done()

-    it 'should handle set of SameForAll enums', (done) ->
+    it 'should handle set of SameForAll enums with new variants', (done) ->
       csv =
         """
         productType,name,variantId,slug,sku,multiSamelEnum,descU,descCU1
@@ -253,7 +253,7 @@
             expect(res.message).toBe '[row 2] Product updated.'
             done()

-    it 'should addVariant include SameForAll attribute change', (done) ->
+    it 'should execute SameForAll attribute change before addVariant', (done) ->
       csv =
         """
         productType,name,variantId,slug,descU,descCU1,descS


Add test for failing partial update of SEO attributes.

--- src/spec/integration/import.spec.coffee
+++ src/spec/integration/import.spec.coffee
@@ -521,3 +521,36 @@
       .fail (err) ->
         done(_.prettify err)
       .done()
+
+    it 'should fail a partial update of SEO attribute', (done) ->
+      csv =
+        """
+        productType,variantId,sku,name,metaTitle,metaDescription,metaKeywords
+        #{@productType.id},1,a111,mySeoProdcut,a,b,c
+        """
+      @importer.import(csv)
+      .then (result) =>
+        expect(_.size result).toBe 1
+        expect(result[0]).toBe '[row 2] New product created.'
+        csv =
+          """
+          productType,variantId,sku,name,metaTitle,metaDescription
+          #{@productType.id},1,a111,mySeoProdcut,x,y
+          """
+        im = createImporter()
+        im.import(csv)
+      .then (result) =>
+        expect(_.size result).toBe 1
+        expect(result[0]).toBe '[row 2] Product update not necessary.'
+        @client.products.where("productType(id=\"#{@productType.id}\")").fetch()
+      .then (result) ->
+        expect(_.size result.body.results).toBe 1
+        p = result.body.results[0].masterData.staged
+        expect(p.name.en).toBe 'mySeoProdcut'
+        expect(p.metaTitle.en).toBe 'a'
+        expect(p.metaDescription.en).toBe 'b'
+        expect(p.metaKeywords.en).toBe 'c'
+        done()
+      .fail (err) ->
+        done(_.prettify err)
+      .done()


CleanUp args

CleanUp args

--- src/Meteor.coffee
+++ src/Meteor.coffee
@@ -32,8 +32,8 @@
     "app-packages"        : true #TODO Add Support
     "timeout"             : 120000 # 2 minutes
     "packages"            : null
-    "meteor_ready_text"   : "=> App running at:"
-    "meteor_error_text"   : "Waiting for file change."
+    "meteor-ready-text"   : "=> App running at:"
+    "meteor-error-text"   : "Waiting for file change."
   }

@@ -132,12 +132,12 @@

   hasErrorText: ( buffer )=>
-    if buffer.lastIndexOf( @testPackagesOpts["meteor_error_text"] ) isnt -1
+    if buffer.lastIndexOf( @testPackagesOpts["meteor-error-text"] ) isnt -1
       @emit "error"

   hasReadyText: ( buffer )=>
-    if buffer.lastIndexOf( @testPackagesOpts["meteor_ready_text"] ) isnt -1
+    if buffer.lastIndexOf( @testPackagesOpts["meteor-ready-text"] ) isnt -1
       @emit "ready"

   kill:->


Let's not overwrite the default options

Let's not overwrite the default options

--- core/app/backbone/factlink/tooltip_mixin.coffee
+++ core/app/backbone/factlink/tooltip_mixin.coffee
@@ -19,7 +19,7 @@
     margin: 0

   tooltipAdd: (selector, title, text, options) ->
-    @tooltip_options = _.extend @default_options, options
+    @tooltip_options = _.extend {}, @default_options, options

     @_tooltips ?= {}
     if @_tooltips[selector]?


interface UI

interface UI

--- lib/gitCreatePackage/gitCreatePackage-login-view.coffee
+++ lib/gitCreatePackage/gitCreatePackage-login-view.coffee
@@ -23,7 +23,7 @@
           @button 'Cancel', click: 'destroy', class: 'inline-block-tight btn'

         @div class: 'pull-right block', =>
-          @button 'Certain', click: 'certainFun', outlet: 'certain', class: 'inline-block-tight btn btn-primary'
+          @button 'Confirm', click: 'certainFun', outlet: 'certain', class: 'inline-block-tight btn btn-primary'

   initialize: ->
     @passwordEditorView @password


Expose page when rendering Paginated pages

Useful if your templates have things like menu blocks and
expect locals similar to the markdown pages

--- examples/blog/plugins/paginator.coffee
+++ examples/blog/plugins/paginator.coffee
@@ -46,7 +46,7 @@
         return callback new Error "unknown paginator template '#{ options.template }'"

       # setup the template context
-      ctx = {@articles, @pageNum, @prevPage, @nextPage}
+      ctx = {@articles, @pageNum, @prevPage, @nextPage, page: this}

       # extend the template context with the enviroment locals
       env.utils.extend ctx, locals


Fix diffColour coloring everything black

...along with another serious issue

--- resources/assets/coffee/osu_common.coffee
+++ resources/assets/coffee/osu_common.coffee
@@ -44,10 +44,10 @@

     colour = {}

-    if (difficulty? || difficulty > 8)
+    if (difficulty == null || difficulty > 8)
       colour = { red: 0, green: 0, blue: 0 }
     else
-      i = stops.findIndex((stop) -> starRating <= stop.starRating)
+      i = stops.findIndex((stop) -> difficulty <= stop.offset)

       if (i == -1)
         colour = { red: 0, green: 0, blue: 0 }


improve logging

improve logging

--- extension/chrome/js/src/content.coffee
+++ extension/chrome/js/src/content.coffee
@@ -1,7 +1,9 @@
 (($, window) ->

 	log = (args...) ->
-		console.log.apply console, args if console?.log and mb?.debug is true
+		if console?.log and mb?.debug is true
+			args.unshift "[#{M.CLS}]"
+			console.log.apply console, args
 		return

 	#__msg = (args...) ->


Indexes on out must be de-duplicated

Indexes on out must be de-duplicated

--- components/Fork.coffee
+++ components/Fork.coffee
@@ -21,6 +21,10 @@
     @inPorts.port.on "data", (index) =>
       index = parseInt index
       @indexes.push index if _.isNumber(index) and not isNaN(index)
+
+    @inPorts.port.on "disconnect", =>
+      # De-duplicate
+      @indexes = _.uniq @indexes

     @inPorts.in.on "begingroup", (group) =>
       if @indexes.length > 0


Remove semi-colons

Remove semi-colons

--- static/src/scripts/app/AppRouter.coffee
+++ static/src/scripts/app/AppRouter.coffee
@@ -14,7 +14,7 @@
       'teams/:slug':  'team'

     initialize: ->
-      ga('create', jailbreak.ga_id, 'auto');
+      ga('create', jailbreak.ga_id, 'auto')
       @bind 'route', @_trackPageview

     index: ->
@@ -37,4 +37,4 @@

     _trackPageview: ->
       url = Backbone.history.getFragment()
-      ga('send', 'pageview', "/#{url}");
+      ga('send', 'pageview', "/#{url}")


Suppress console.log

Suppress console.log

--- src/client/Gruntfile.coffee
+++ src/client/Gruntfile.coffee
@@ -51,8 +51,6 @@
     'tools/**'
     '**/*mock.{js,coffee}'
   ].map((_)-> Path.join config.find('client.root'), _))
-
-  console.log config.find 'client.test.tools'

   grunt.Config =
     karma:


RIP Debug info. Long live graphics.

RIP Debug info. Long live graphics.

--- scripts/ayp.coffee
+++ scripts/ayp.coffee
@@ -89,13 +89,6 @@
             s3.put name, info, (err) ->
               return msg.reply "Woooops! Failed to upload: #{err}" if err
               msg.reply "I made a thing: http://s3.amazonaws.com/#{AYP_AWS_BUCKET}/#{name}"
-
-      # Echo the lines to the channel
-      count = 0
-      for log in lines
-        do (log) ->
-          [who, what] = log
-          msg.reply "=#{count += 1}> [#{who}] '#{what}'"

 # Build a comic and invoke the cb(err, res) with res
 # being the resulting image. `err` will be true if an error


Might as well preempt this 🤒

Might as well preempt this 🤒

--- scripts/ayp.coffee
+++ scripts/ayp.coffee
@@ -145,6 +145,10 @@
   # I don't even know how to joke about this anymore
   if /nomikos/i.test(name)
     name = 'nomikos'
+
+  # I was feeling left out
+  if /skalnik/i.test(name)
+    name = 'skalnik'

   return name


WIP: Can I hear myself yet?

WIP: Can I hear myself yet?

--- scripts/ayp.coffee
+++ scripts/ayp.coffee
@@ -68,11 +68,11 @@
   if /minus/i.test(name)
     # Another one fond of aliases
     name = 'minusx'
-
+
   if /jense/i.test(name) or /prawn/i.test(name)
     # Has bouncer, bounces anyway
     name = 'prawn'
-
+
   if /geckomuerto/i.test(name)
     # ;_;
     name = 'geckomuerto'
@@ -80,9 +80,9 @@
   if /laura/i.test(name)
     # Some kind of laura is one kind of laura
     name = 'laura'
-
+
   if /arbo/i.test(name)
-    # Bouncers are hard or something, whatever.
+    # Bouncers are hard or something, whatever.
     name = 'arbo'

   return name
@@ -91,7 +91,7 @@
 filterText = (text) ->
   # Urls are secret. Not for you. Not for anyone.
   text = text.replace(/(https?:\/\/[^\s]+)/, "[redacted]")
-
+
   # Emails 'R' Secret
   text = text.replace(/([^@\s]+@)[^@\s]+\.[^@\s]+/, "$1[redacted]")

@@ -108,6 +108,9 @@
 ## Robot event bindings
 module.exports = (robot) ->
   buffer = new PantsBuffer()
+
+  robot.adapter.on 'say', (target, target, str) ->
+    console.log "WOULD ADD: #{target.user.name}: #{str}"

   # We listen to everything.
   # Everything.


Handle problems on create.

Handle problems on create.

--- src/coffee/xmlimport.coffee
+++ src/coffee/xmlimport.coffee
@@ -40,8 +40,13 @@
         callback(diffResult)
       else
         @rest.POST "/products", JSON.stringify(p), (error, response, body)->
-          console.log("BODY %j", body)
-          callback(body)
+          if response.statusCode is 201
+            d =
+              message:
+                status: true
+            callback d
+          else
+            returnError 'Problem on creating product.', callback

 exports.XmlImport.prototype.getAndFix = (raw)->
   #TODO: decode base64 - make configurable for testing


Fixed a bug causing basename instead of filename to be returned for file stats.

--- src/common/FileUtils.coffee
+++ src/common/FileUtils.coffee
@@ -130,7 +130,7 @@

     getFileStats: (file) ->
       if Paths.isUrl(file)
-        name = Paths.filename(file)
+        name = Paths.basename(file)
         url = file
       if file instanceof FS.File
         name = file.name()


fix reload bug

fix reload bug

--- app/assets/javascripts/deals.js.coffee
+++ app/assets/javascripts/deals.js.coffee
@@ -133,8 +133,8 @@
         resultUrl = null
         resultUrlWithHash = null
         if result.redirect_to
-          resultUrl = result.redirect_to
-          resultUrlWithHash = resultUrl
+          resultUrlWithHash = result.redirect_to
+          resultUrl = resultUrlWithHash.split('#')[0]
         else
           if dealHasAccountId(result.deal, $('#deal_form_option').data("condition-account-id")) # 遷移先に条件がついていて適合していればそちらのURLにする
             resultUrl = $('#deal_form_option').data("condition-match-url").replace(/_YEAR_/, result.year).replace(/_MONTH_/, result.month)


fixes #88

fixes #88

--- app/assets/javascripts/lectures.coffee
+++ app/assets/javascripts/lectures.coffee
@@ -320,7 +320,7 @@
     else
       $('#newLectureTerm').show()
       $('#lecture_term_id').prop('disabled', false)
-      $('#newLectureSort').hide()
+      $('#newLectureSort').show()
     return

   return


Bind JavaScript initialization code to page:load, not page:change.

--- app/assets/javascripts/pants.js.coffee
+++ app/assets/javascripts/pants.js.coffee
@@ -22,7 +22,6 @@
   ga('send', 'pageview') if (ga?)

-$(document).on 'page:change', initPage
-
-$ ->
-  initPage()
+$(document)
+  .on 'page:load', initPage
+  .on 'ready', initPage


fixed score in progress view

fixed score in progress view

--- app/assets/javascripts/progress.coffee
+++ app/assets/javascripts/progress.coffee
@@ -77,7 +77,7 @@
 		bounds = new L.LatLngBounds(@_SW, @_NE)
 		@map.fitBounds bounds

-		@updateScore(data.all_polygons_Nession)
+		@updateScore(data.all_polygons_session)

 		# marker clustering layer
 		markers = new L.MarkerClusterGroup


Social: update package version

Social: update package version

--- config/main.dev.coffee
+++ config/main.dev.coffee
@@ -479,7 +479,7 @@

         OLD_COOKIE=$(npm list tough-cookie -s | grep 0.9.15 | wc -l | awk \'{printf "%s", $1}\')
         if [  $OLD_COOKIE -ne 0 ]; then
-            echo "You have tough-cookie@0.9 installed on your system, please remove node_modules directory and do npm i again";
+            echo "You have tough-cookie@0.9.15 installed on your system, please remove node_modules directory and do npm i again";
             exit 1;
         fi
       }


only handle cc resize when cc is opened

only handle cc resize when cc is opened

--- src/scripts/modules/media/body/body.coffee
+++ src/scripts/modules/media/body/body.coffee
@@ -113,7 +113,7 @@
       )

       Backbone.on('window:optimizedResize', =>
-        @cc.handleResize()
+        @cc?.handleResize?()
       )

     updateCCOptions: ->


Always keep handle within slider

Always keep handle within slider

[#134443309]

--- src/code/views/value-slider-view.coffee
+++ src/code/views/value-slider-view.coffee
@@ -89,7 +89,7 @@
       grab: handlePos / 2

   sliderLocation: ->
-    (@props.value - @props.min) / (@props.max - @props.min)
+    @clamp (@props.value - @props.min) / (@props.max - @props.min), 0, 1

   sliderPercent: ->
     p = @sliderLocation() * 100


change indentation

change indentation

--- src/coffee/directives/controller.coffee
+++ src/coffee/directives/controller.coffee
@@ -5,7 +5,6 @@
 ## This file is subject to the terms and conditions defined in
 ## file 'LICENSE.txt', which is part of this source code package.
 ##
-

 angular.module('CoolForm').
   directive('coolform', (definitionService, validatorService) ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/controllable.coffee
+++ src/controllable.coffee
@@ -3,7 +3,7 @@
 when up, down, left, or right are held.

-  # create a player and include ClampBounds
+  # create a player and include Con
   player = GameObject
     includedModules: ["ClampBounds"]
     width: 5


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/controllable.coffee
+++ src/controllable.coffee
@@ -1,5 +1,5 @@
 ###*
-The Controllable module adds
+The Controllable module adds simple

   # create a player and include ClampBounds


Correct coffeescript in previous commit

Correct coffeescript in previous commit

--- app/assets/javascripts/app/spaces/new.js.coffee
+++ app/assets/javascripts/app/spaces/new.js.coffee
@@ -1,5 +1,4 @@
 $ ->

   $("#new-space-basic-info input#space_public").on 'click', ->
-    checked = $(this).attr('checked') == 'checked'
-    $("#new-space-webconf-area").toggle(!checked)
+    $("#new-space-webconf-area").toggle(! $(this).is(':checked'))


disabled lastfm cache which uses localstorage (not available on IE)

--- app/assets/javascripts/classes/lastfm.js.coffee
+++ app/assets/javascripts/classes/lastfm.js.coffee
@@ -1,31 +1,10 @@
 class Molamp.LastfmWrapper
   constructor: ->
     # Create a cache object
-    cache = new LastFMCache()
-
-    # TODO: Cache component is not working on IE
+    #cache = new LastFMCache()

     # Create and return the LastFM object
     return new LastFM
       apiKey: Molamp.Defaults::LASTFM_OPTIONS.apiKey
       apiSecret: Molamp.Defaults::LASTFM_OPTIONS.apiSecret
-      cache: cache
-
-  # similarTracks: (mbid) ->
-    # @LF.track.getSimilar({
-      # mbid: mbid
-      # limit: 5
-    # }, {
-      # success: (data) ->
-        # if typeof data.similartracks.track is 'object'
-          # Alike.appendSimilarTracks mbid, data
-        # else
-          # $.gritter.add
-            # title: 'Similar tracks...'
-            # text: 'We couldn\'t find any similar tracks'
-#
-      # error: (code, message) ->
-        # $.gritter.add
-          # title: 'Similar tracks...'
-          # text: 'We couldn\'t find any similar tracks'
-    # })+      #cache: cache


Fixed error in iceberg when code is executed in purchases form

--- app/assets/javascripts/cocoon/iceberg.js.coffee
+++ app/assets/javascripts/cocoon/iceberg.js.coffee
@@ -173,7 +173,7 @@
           name: $(this).find('input.hidden').val()
       data = zones: zones

-      @line.find('#storing-display')[0].innerHTML = storing_display_template(zones)
+      @line.find('#storing-display:first').innerHTML = storing_display_template(zones)

     retrievePreviousItemValue: ->
       line = @line


fix toggle chevron logic

fix toggle chevron logic

--- app/assets/javascripts/components/question.cjsx
+++ app/assets/javascripts/components/question.cjsx
@@ -33,13 +33,14 @@

         {@props.data.question}
+        {@renderToggleChevron()}

       {@renderQuestionBody()}

   renderToggleChevron: =>
-     unless @props.mode != "show"
+     if @props.mode != "show"

   toggleClassName: =>
     className = "fa u-pull-right"


fixing product thumbnail gallery behaviour

--- app/assets/javascripts/mobile/_mobile.js.coffee
+++ app/assets/javascripts/mobile/_mobile.js.coffee
@@ -98,7 +98,6 @@
             $('.product').each ->
                 fetch_product_images(($ @), render_single_product_image)

-
             ($ '.products').on('tap', '.product', ->
                 return if ($ @).data('user-owns-store') is 'true'
                 destination = ($ @).find('.product-link > a').attr('href')
@@ -112,21 +111,24 @@

             fetch_product_images($('.product'), render_multiple_product_images)

-            ($ '.product-thumbnail').swipeLeft ->
-                next_index = ($ @).next().data('index')
-                if next_index?
-                    ($ @).addClass('hide')
-                    ($ @).next().removeClass('hide')
-                    ($ '.product-gallery-control.on')
-                        .removeClass('on').next().addClass('on')
-
-            ($ '.product-thumbnail').swipeRight ->
-                previous_index = ($ @).prev().data('index')
-                if previous_index?
-                    ($ @).addClass('hide')
-                    ($ @).prev().removeClass('hide')
-                    ($ '.product-gallery-control.on')
-                        .removeClass('on').prev().addClass('on')
+
+            ($ '.product-thumbnail-gallery')
+                .on('swipeLeft', (e) ->
+                    $this = ($ e.target)
+                    next_index = $this.next().data('index')
+                    if next_index?
+                        $this.addClass('hide')
+                        $this.next().removeClass('hide')
+                        ($ '.product-gallery-control.on')
+                            .removeClass('on').next().addClass('on'))
+                .on('swipeRight', (e) ->
+                    $this = ($ e.target)
+                    previous_index = $this.prev().data('index')
+                    if previous_index?
+                        $this.addClass('hide')
+                        $this.prev().removeClass('hide')
+                        ($ '.product-gallery-control.on')
+                            .removeClass('on').prev().addClass('on'))

             # setTimeout is required because
             # tap was clicking the purchase


Removed erroneous if statement and replaced with more clear operator.

--- app/assets/javascripts/provider_chart.js.coffee
+++ app/assets/javascripts/provider_chart.js.coffee
@@ -60,8 +60,7 @@
         nodes.forEach (d) ->
           d.y = heightScale(d.depth)
           d.x = widthScale(d.x)
-          if not d.size?
-            d.size = 8#if d.active then 15 else 8
+          d.size ?= 8

         node = svg.selectAll("g.node")
           .data(nodes, (d) -> d.id || d.id = ++nodeId)


Uncomment preventing undefined responses

--- app/assets/javascripts/ultimate/flash.js.coffee
+++ app/assets/javascripts/ultimate/flash.js.coffee
@@ -195,7 +195,7 @@
       thrownError = text
       text = @t('defaultErrorText')
     # prevent undefined responses
-    #return false  if jqXHR.status < 100
+    return false  if jqXHR.status < 100
     # prevent recall
     return false  if jqXHR.breakFlash
     jqXHR.breakFlash = true


Tell browser not to cache json responses

--- app/assets/javascripts/views/map_view.js.coffee
+++ app/assets/javascripts/views/map_view.js.coffee
@@ -98,7 +98,7 @@
     @$('.icon-down-dir').toggleClass 'rotate'

   refreshLocations: ->
-    @collection.fetch reset: true
+    @collection.fetch reset: true, cache: false

   updateCurrentStudent: (event) ->
     @currentAssignment = @collection.find (assignment) ->


fix other author's typo

fix other author's typo

--- app/assets/javascripts/zfix-fb-turbolink.coffee
+++ app/assets/javascripts/zfix-fb-turbolink.coffee
@@ -7,7 +7,7 @@
     .on('page:fetch', saveFacebookRoot)
     .on('page:change', restoreFacebookRoot)
     .on('page:load', ->
-      FB?.XFBML.parse()
+      FB.XFBML.parse()
     )
   @fbEventsBound = true


Fix body class check to avoid initialize Visualization or Story classes in templates different to show or edit

--- app/frontend/javascripts/app.js.coffee
+++ app/frontend/javascripts/app.js.coffee
@@ -9,14 +9,14 @@
   $body = $('body')

   # visualizations
-  if $body.hasClass 'visualizations'
+  if $body.hasClass('visualizations') and ($body.hasClass('show') or $body.hasClass('edit'))
     # /visualizations/:id
     # /visualizations/:id/edit
     appVisualization = new App.Visualization $('body').data('visualization-id'), $body.hasClass('edit')
     appVisualization.render()
     $( window ).resize appVisualization.resize
   # stories
-  else if $body.hasClass 'stories'
+  else if $body.hasClass('stories') and ($body.hasClass('show') or $body.hasClass('edit'))
     # /stories/:id
     # /stories/:id/edit
     appStory = new App.Story $('body').data('story-id'), $('body').data('visualization-id'), $body.hasClass('edit')


Also don't propagate other mouse / touch / drag events

--- app/js/core.coffee
+++ app/js/core.coffee
@@ -15,7 +15,13 @@
 Factlink.el = $("#fl")

 # Prevent event bubbling outside our container
-Factlink.el.on 'mouseup click', (event) -> event.stopPropagation()
+mouse_touch_drag_events = """
+  mouseup mousedown click mouseenter mouseleave mousemove mouseout mouseover dblclick
+  show contextmenu
+  drag dragstart dragenter dragover dragleave dragend drop
+  touchstart touchmove touchleave touchenter touchend touchcancel
+"""
+Factlink.el.on mouse_touch_drag_events, (event) -> event.stopPropagation()

 # Add the stylesheet
 $style = $("<link>").attr


Boolean fix and fix grammar a bit.

Boolean fix and fix grammar a bit.

--- src/coffee.coffee
+++ src/coffee.coffee
@@ -182,7 +182,7 @@

     brewing.dibs.push(dibber)

-    if bounty.issuer is dibber and hasBounty()
+    if hasBounty() and bounty.issuer is dibber
         threadedMsg(msg).send "@#{dibber} has been automatically granted :coffee: spot ##{brewing.dibs.length} for their _outstanding_ bounty! " +
             "#{statusEmoji.random('success')}"
     else
@@ -209,7 +209,7 @@
     barista = robot.brain.usersForFuzzyName(msg.message.user['name'])[0].name

     if bounty.reward > 0 and barista is bounty.issuer
-      msg.send "Hey @#{bounty.issuer} can't collect your own bounty! Your bounty has been cancelled. #{statusEmoji.random('failure')}"
+      msg.send "Hey @#{bounty.issuer} you can't collect your own bounty! **Your bounty has been cancelled.** #{statusEmoji.random('failure')}"
       clearBounty
       return


Load default plugins at the same time as user plugins

--- src/core/environment.coffee
+++ src/core/environment.coffee
@@ -33,13 +33,6 @@
     @workDir = path.resolve @workDir
     @contentsPath = @resolvePath @config.contents
     @templatesPath = @resolvePath @config.templates
-
-    # load default plugins
-    async.forEachSeries @constructor.defaultPlugins, (plugin, callback) =>
-      @logger.verbose "loading default plugin '#{ plugin }'"
-      fn = require "./../plugins/#{ plugin }"
-      fn.call null, this, callback
-    , (error) -> throw error if error?

   resolvePath: (pathname) ->
     ### Resolve *pathname* in working directory, returns an absolute path. ###
@@ -126,9 +119,12 @@

   loadPluginModule: (module, callback) ->
     ### Load a plugin *module*. ###
-    @logger.verbose "loading plugin: #{ module }"
-    async.waterfall [
-      (callback) => @loadModule module, callback
+    async.waterfall [
+      (callback) =>
+        if typeof module is 'string'
+          @loadModule module, callback
+        else
+          callback null, module
       (fn, callback) =>
         try
           if not fn.__loaded
@@ -158,7 +154,21 @@

   loadPlugins: (callback) ->
     ### Loads any plugin found in *@config.plugins*. ###
-    async.forEachSeries @config.plugins, @loadPluginModule.bind(this), callback
+    async.series [
+      # load default plugins
+      (callback) =>
+        async.forEachSeries @constructor.defaultPlugins, (plugin, callback) =>
+          @logger.verbose "loading default plugin: #{ plugin }"
+          module = require "./../plugins/#{ plugin }"
+          @loadPluginModule module, callback
+        , callback
+      # load user plugins
+      (callback) =>
+        async.forEachSeries @config.plugins, (plugin, callback) =>
+          @logger.verbose "loading plugin: #{ plugin }"
+          @loadPluginModule plugin, callback
+        , callback
+    ], callback

   loadViews: (callback) ->
     ### Loads files found in the *@config.views* directory and registers them as views. ###


Modification to how axes scale.

Modification to how axes scale.

--- app/scripts/directives/compare-bar-chart.coffee
+++ app/scripts/directives/compare-bar-chart.coffee
@@ -17,37 +17,31 @@
         .style('fill', '#ddd')
         .attr('width', "100%") # arbitrary
         .attr('height', 100) # arbitrary
+
+      scope.drawBarChart = () ->
+        raw_data = JSON.parse(d3.select(element[0]).attr('data'))
+        this_data = [-raw_data[0], raw_data[1]]
+        x0 = Math.max(-d3.min(this_data), d3.max(this_data))

-      scope.drawBarChart = () ->
-        scope.$watch 'data', (newVals, oldVals) ->
-          console.log newVals, oldVals
-          svg.selectAll('*').remove
-          if not newVals
-            return # no change, do nothing
+        x = d3.scale.linear()
+          .domain([-x0, x0])
+          .range([0 , 900]) #arbitrary
+          .nice()

-          this_data = [-newVals.amount2, newVals.amount1]
-
-          x0 = Math.max(-d3.min(this_data), d3.max(this_data))
-
-          x = d3.scale.linear()
-            .domain([-x0, x0])
-            .range([0, '100%'])
-            .nice()
-
-          svg.selectAll("rect")
-            .data(this_data)
-            .enter().append("rect")
-            .attr('class', (d, i) ->
-              return 'bar' + (i+1)
-            ).attr("x", x(0))
-            .attr("y", 0)
-            .attr("width", 0)
-            .attr("height", 30)
-            .transition()
-              .duration(1000)
-              .attr("width", x)
-              .attr("x", (d, i) -> return x(Math.min(0, d)))
-
+        svg.selectAll("rect")
+          .data(this_data)
+          .enter().append("rect")
+          .attr('class', (d, i) ->
+            return 'bar' + (i+1)
+          ).attr("x", x(0))
+          .attr("y", 0)
+          .attr("width", 0)
+          .attr("height", 30)
+          .transition()
+            .duration(1000)
+            .attr("width", (d, i) ->
+              return Math.abs(x(d) - x(0))
+            ).attr("x", (d, i) -> return x(Math.min(0, d)))

       scope.drawBarChart()


F1 shows popup even if it can't guess the help page

--- client/keymap.coffee
+++ client/keymap.coffee
@@ -3,13 +3,21 @@
     fallthrough: 'default'
     "'`'": (cm) -> cm.setOption 'keyMap', 'dyalogBackquote'
     F1: (cm) ->
-      c = cm.getCursor(); s = cm.getLine c.line
-      x = s[s[...c.ch].replace(/.[áa-z]*$/i, '').length..].replace(/^(\)[a-z]+|⎕[áa-z]*|.).*$/i, '$1').toLowerCase()
-      if u = helpURLs[x]
-        w = screen.width; h = screen.height
-        open "help/#{u}.html", 'help',
-          "width=#{w / 2},height=#{h / 2},left=#{w / 4},top=#{h / 4}," +
-          "scrollbars=1,location=1,toolbar=0,menubar=0,resizable=1"
+      c = cm.getCursor(); s = cm.getLine(c.line).toLowerCase()
+      u =
+        if m = /^ *(\)[a-z]+).*$/.exec s
+          helpURLs[m[1]] || 'lang/syscmds/intro'
+        else if m = /^ *(\][a-z]+).*$/.exec s
+          helpURLs[m[1]] || 'userguide/the-apl-environment/user-commands'
+        else
+          x = s[s[...c.ch].replace(/.[áa-z]*$/i, '').length..].replace /^(⎕[áa-z]*|.).*$/i, '$1'
+          helpURLs[x] ||
+            if x[0] == '⎕' then 'lang/sysfns/sysfns-categorised'
+            else 'lang/intro/lang-elements'
+      w = screen.width; h = screen.height
+      open "help/#{u}.html", 'help',
+        "width=#{w / 2},height=#{h / 2},left=#{w / 4},top=#{h / 4}," +
+        "scrollbars=1,location=1,toolbar=0,menubar=0,resizable=1"
       return

   window.onhelp = -> false # prevent IE from being silly


focus help window after opening it

focus help window after opening it

This matters when a help window is already present.

--- client/keymap.coffee
+++ client/keymap.coffee
@@ -18,9 +18,10 @@
             else if x[0] == ':' then 'lang/control-structures/control-structures-intro'
             else 'lang/intro/lang-elements'
       w = screen.width; h = screen.height
-      open "help/#{u}.html", 'help',
+      popup = open "help/#{u}.html", 'help',
         "width=#{w / 2},height=#{h / 2},left=#{w / 4},top=#{h / 4}," +
         "scrollbars=1,location=1,toolbar=0,menubar=0,resizable=1"
+      popup.focus?()
       return

   window.onhelp = -> false # prevent IE from being silly


fix initial theme and transition state for a new record

--- client/models.coffee
+++ client/models.coffee
@@ -49,7 +49,7 @@

     if not @get "id"
       console.log "using mock"
-      @set code: utils.mock, mode: 'html'
+      @set code: utils.mock, mode: 'html', transition: 'nothing', theme: 'nothing'
       @triggerInitialFetch "default"
       origCb? e
       opts.success @


fix double loading

fix double loading

--- app/js/routes/application_route.coffee
+++ app/js/routes/application_route.coffee
@@ -15,14 +15,16 @@
     newPerson: ->
       @transitionTo 'people.new'
     loading: ->
-      view = Ember.View.create(
-        templateName: 'loading'
-        elementId: 'loading'
-        controller: @controllerFor('loading')
-      ).append()
+      unless @get('loadingView')
+        view = Ember.View.create(
+          templateName: 'loading'
+          elementId: 'loading'
+          controller: @controllerFor('loading')
+        ).append()
+        @set('loadingView', view)

-      @router.one('didTransition', ->
-        view.destroy()
+      @router.one('didTransition', =>
+        @get('loadingView').destroy()
       )

   model: ->


Scroll up the page every time we navigate a new location

--- client/routes.coffee
+++ client/routes.coffee
@@ -9,3 +9,9 @@
 Router.configure
   layout: 'layout'
   loadingTemplate: 'loading'
+
+
+Deps.autorun ->
+  Router.current()
+  Deps.afterFlush ->
+    $(window).scrollTop(0)


Fixed rotation of icons

Fixed rotation of icons

--- client/script.coffee
+++ client/script.coffee
@@ -91,7 +91,7 @@
   rotateIcons()

 rotateIcons = ->
-  lineLayer.eachLayer (layer) ->
+  pointLayer.eachLayer (layer) ->
     if layer._heading?
       icon = $(layer._icon)
       icon.css '-webkit-transform',


not error in case of stderr is not empty

--- lib/atom-gibo.coffee
+++ lib/atom-gibo.coffee
@@ -56,14 +56,14 @@
       return

     execFile giboPath, [args[0].trim()], (err, stdout, stderr) =>
-      if err? and !(err.startsWith('Cloning'))
+      if err?
         console.error "Faile gibo\n #{err}"
         @showError err
         callback?()
         return
-      if stderr or /unknown/i.test(stdout)
-        console.error "Unknown boilerplate\n #{stderr + stdout}"
-        @showError stderr + stdout
+      if /unknown/i.test(stdout)
+        console.error "Unknown boilerplate\n #{stderr}"
+        @showError stdout
         callback?()
         return


Ace: Put editor bottom bar back and make it optional.

--- client/Ace/AppView.coffee
+++ client/Ace/AppView.coffee
@@ -14,6 +14,7 @@
     super options, file

     options.advancedSettings         ?= no
+    options.createBottomBar          ?= yes
     options.createFindAndReplaceView ?= yes

     @listenWindowResize()
@@ -31,10 +32,13 @@
     else
       @findAndReplaceView = new KDCustomHTMLView

-    @caretPosition    = new KDCustomHTMLView
-      tagName         : 'div'
-      cssClass        : 'caret-position section'
-      partial         : '1:1'
+    @caretPosition = new KDCustomHTMLView
+
+    if @getOptions().createBottomBar
+      @caretPosition  = new KDCustomHTMLView
+        tagName       : 'div'
+        cssClass      : 'caret-position section'
+        partial       : '1:1'

     @advancedSettings = new KDButtonViewWithMenu
       style           : 'editor-advanced-settings-menu'
@@ -49,12 +53,13 @@

     @advancedSettings.disable()

-    unless options.advancedSettings
-      @advancedSettings.hide()
+    @advancedSettings.hide()  unless options.advancedSettings

     @setViewListeners()

   setViewListeners:->
+    hasBottomBar = @getOptions().createBottomBar
+
     @ace.on 'ace.ready', => @advancedSettings.enable()

     @ace.on 'ace.changeSetting', (setting, value) =>
@@ -62,11 +67,13 @@

     @advancedSettings.emit 'ace.settingsView.setDefaults', @ace

-    $spans = @caretPosition.$ 'span'
-
-    @ace.on 'ace.change.cursor', (cursor) =>
-      $spans.eq(0).text ++cursor.row
-      $spans.eq(1).text ++cursor.column
+    if hasBottomBar
+      $spans = @caretPosition.$ 'span'
+
+      @ace.on 'ace.change.cursor', (cursor) =>
+        log '...........'
+        $spans.eq(0).text ++cursor.row
+        $spans.eq(1).text ++cursor.column

     @ace.on 'ace.requests.saveAs', (contents, options) =>
       @openSaveDialog options
@@ -193,13 +200,24 @@
     @_windowDidResize()

   pistachio:->
+    hasBottomBar = @getOptions 'createBottomBar'
+    template     = """
+

+        {{> @ace}}
+        {{> @findAndReplaceView}}
+

     """
-

-      {{> @ace}}
-

-        {{> @caretPosition}}
-        {{> @advancedSettings}}
-

-      {{> @findAndReplaceView}}
-

-    """
+
+    if hasBottomBar
+      template = """
+

+          {{> @ace}}
+

+            {{> @caretPosition}}
+            {{> @advancedSettings}}
+

+          {{> @findAndReplaceView}}
+

+      """
+
+    return template


Fixed clone.

Fixed clone.

--- lib/cake/dist.coffee
+++ lib/cake/dist.coffee
@@ -106,7 +106,7 @@
       packageOpts.homepage = repo.html_url
       packageOpts.repository = {type: "git", url: repo.git_url}
       packageOpts.bugs = {url: repo.html_url+"/issues"}
-      Git.Clone repo.clone_url, path.join out, tag
+      Git.Clone repo.ssh_url, path.join out, tag
     .then (repo) ->
       npmOrg = opts["npm-org"] ? pkg.name
       Promise.all [


KDData: handle all cases on set trap, create proxies recursively on init

--- lib/core/data.coffee
+++ lib/core/data.coffee
@@ -1,3 +1,4 @@
+debug = require('debug') 'kd:data'
 KD = require './kd'
 KDEventEmitter = require './eventemitter'

@@ -11,23 +12,45 @@
     console.warn 'Proxies are not supported on this platform!'
     return new Object data

+isValid = (value) ->
+  value and typeof value is 'object' and value not instanceof Date
+
+
 module.exports = class KDData

   @EMITTER = createSymbol 'kddata'
   @NAME    = createSymbol 'name'

-  constructor: (data = {}) ->
+  constructor: (data = {}, options = {}) ->

-    emitter = new KDEventEmitter
-    emitter.__data__ = data
-    emitter.isArray  = Array.isArray data
+    @emitter = new KDEventEmitter
+    @emitter.__data__  = data
+    @emitter.__event__ = options.updateEvent ? 'update'
+    @emitter.maxdepth  = options.max_depth ? 2

-    proxy = createProxy data, proxyHandler emitter
-    Object.defineProperty proxy, KDData.EMITTER, value: emitter
+    @proxy = createProxy data, KDData::proxyHandler.call this
+    Object.defineProperty @proxy, KDData.EMITTER, {
+      value: @emitter, configurable: yes
+    }

-    return proxy
+    initialize = (data, key = null, depth = 0) =>
+      return  if not isValid data
+
+      depth += 1
+      for _key, child of data
+        path = if key then "#{key}.#{_key}" else _key
+        if depth < @emitter.maxdepth and isValid child
+          initialize child, path, depth
+          KD.utils.JsPath.setAt @proxy, path, child
+
+    initialize data
+    @initialized = yes
+
+    return @proxy
+

   @isSupported = -> !!window.Proxy?
+

   @getEmitter = (data) ->

@@ -38,44 +61,65 @@
       return data

-  getFullPath = (parent, child) ->
+  emit: (updates) ->

-    if root = parent[KDData.NAME]
-      return "#{root}.#{child}"
-    return child
+    return  if not @initialized
+    @emitter.emit @emitter.__event__, [ updates ]

-  proxyHandler = (base) ->
+  createObjectProxy: (obj, key) ->

-    set: (target, key, value, receiver) ->
+    value = createProxy obj, @proxyHandler.call this
+    return value  unless key

-      if base.isArray
+    Object.defineProperty value, KDData.NAME, {
+      value: key, configurable: yes
+    }
+    return value
+
+
+  proxify: (value, key, depth = 0) ->
+
+    return value  if not isValid value
+
+    depth += 1
+
+    for _key, child of value
+      path = if key then "#{key}.#{_key}" else _key
+      debug 'path on', _key, path
+      if depth < @emitter.maxdepth and isValid child
+        value[_key] = @createObjectProxy child, path
+        @proxify child, path, depth
+
+    debug 'creating proxy', value, key
+
+    if isValid value
+      return @createObjectProxy value, key
+    else
+      return value
+
+
+  proxyHandler: ->
+
+    set: (target, key, value, receiver) =>
+
+      debug 'setting', key, value
+
+      if isArray = Array.isArray target
         currentLength = target.length

-      if value instanceof Object and value not instanceof Date
-        if root = receiver[KDData.NAME]
-          key = "#{root}.#{key}"
-        value = createProxy value, proxyHandler base
-        Object.defineProperty value, KDData.NAME, {
-          value: key, configurable: yes
-        }
+      if parent = receiver[KDData.NAME] ? ''
+        path = "#{parent}.#{key}"

-      target[key] = value
+      target[key] = @proxify value, path ? key

-      if base.isArray
+      if isArray
         lengthChanged = target.length isnt currentLength
         return true  if key is 'length' and not lengthChanged

-      return true  if typeof key is 'symbol' or /^__|__$/.test key
+      @emit path ? key

-      if root = receiver[KDData.NAME]
-        key = "#{root}.#{key}"
-      else
-        root = ''
+      if lengthChanged and key isnt 'length'
+        @emit if parent then "#{parent}.length" else 'length'

-      if lengthChanged
-        prefix = if key.indexOf('.') >= 0 then "#{root}." else ''
-        base.emit 'update', [ "#{prefix}length" ]
-
-      base.emit 'update', [ key ]
       return true


[dev] add activation log when reload

[dev] add activation log when reload

--- lib/developer.coffee
+++ lib/developer.coffee
@@ -39,7 +39,7 @@
       pack = atom.packages.getLoadedPackage(packName)

       if pack?
-        console.log "deactivating #{packName}"
+        console.log "- deactivating #{packName}"
         atom.packages.deactivatePackage(packName)
         atom.packages.unloadPackage(packName)

@@ -51,6 +51,7 @@
             delete require.cache[p]

         atom.packages.loadPackage(packName)
+        console.log "+ activating #{packName}"
         atom.packages.activatePackage(packName)

   toggleReloadPackagesOnSave: ->


Make yu an obstacle

Make yu an obstacle

--- src/game/example.coffee
+++ src/game/example.coffee
@@ -16,14 +16,14 @@

 yu = my.dup me, {
   name: 'yu'
-  position: [2,2]
+  position: [3,1]
   fill: 'green'
 }

 exit = {
   name: 'exit'
   shape: 'diamond'
-  position: [1,4]
+  position: [5,1]
   stroke: 'gold'
   fill: 'red'
   behavior: {turtle: ['victory']}


precious ephemeris mv'd to bin

precious ephemeris mv'd to bin

--- lib/ephemeris.coffee
+++ lib/ephemeris.coffee
@@ -50,7 +50,7 @@
         apath = thing.substring 0, thing.lastIndexOf '/'
         apath += '/../lib/node_modules/precious/'
         @defaults.data = apath + 'node_modules/gravity/data/'
-        @defaults.prep = apath + 'lib/'
+        @defaults.prep = apath + 'bin/'
         cb()


moving files around

moving files around

--- hubot-scripts/jenkins-script.coffee
+++ hubot-scripts/jenkins-script.coffee
@@ -51,5 +51,3 @@
   #   note if 'robot' is out of scope you can also use msg.robot.emit
   robot.on "jenkins-script", (_script, _params, _msg) ->
     jenkinsScript(_script, _params, _msg)
-
-


asはいらない

asはいらない

--- src/js/components/Auth.coffee
+++ src/js/components/Auth.coffee
@@ -28,4 +28,4 @@

 export default reduxForm({
   form: "auth"
-})(Auth as any) as any
+})(Auth)


Ace: Let aceView do the stuff for modified mark.

--- client/ace/lib/ace.coffee
+++ client/ace/lib/ace.coffee
@@ -668,29 +668,7 @@

   removeModifiedFromTab: ->

-    aceView      = @parent
-
-    unless aceView
-      # happens when collab is active and when you have tabs open
-      # and when you reload the page - SY
-      kd.warn 'possible race condition, shadowing the error! @acet'
-      return
-
-    { tabView }     = aceView.delegate
-    return  unless tabView
-
-    activeTabHandle = tabView.getActivePane().getHandle()
-
-    { handles }  = tabView
-    targetHandle = null
-
-    for handle in handles when activeTabHandle.id is handle.id
-      targetHandle = handle
-      targetHandle.setClass 'saved'
-
-      kd.utils.wait 500, ->
-        targetHandle.unsetClass 'modified'
-        targetHandle.unsetClass 'saved'
+    @emit 'RemoveModifiedFromTab', @getData().path

   trimTrailingWhitespaces: ->


Require authentication in recipe routes

Require authentication in recipe routes

--- src/handlers/beers/RecipeHandler.coffee
+++ src/handlers/beers/RecipeHandler.coffee
@@ -29,18 +29,19 @@
 			{
 				path: '/beers/add'
 				method: 'GET'
-				handler: (req, reply) =>
-					@onRequest(req, reply, 'Add new beer', 'recipe')
+				auth: true
 			}
 			{
 				path: '/beers/{id}/edit'
 				method: 'GET'
+				auth: true
 				handler: (req, reply) =>
 					@onRequest(req, reply, "Edit #{req.params.id}", 'recipe')
 			}
 			{
 				path: '/beers/{id}/fork'
 				method: 'GET'
+				auth: true
 				handler: (req, reply) =>
 					@onRequest(req, reply,  "Fork #{req.params.id}", 'beers')
 			}


:memo: fix comment

:memo: fix comment


Scripts: update test key path

Scripts: update test key path

--- scripts/node-testing/shell-scripts.coffee
+++ scripts/node-testing/shell-scripts.coffee
@@ -3,21 +3,21 @@
 ###

 module.exports =
-
+
   get     :
-
+
     socialWorker : (publicIpAddress) ->
-
+
       return "ssh -o 'StrictHostKeyChecking no' \
-      -i $KODING_DEPLOYMENT_KEY \
+      -i ./scripts/test-instance/koding-test-instances-2015-06.pem \
       ubuntu@#{publicIpAddress} \
       'sudo /opt/koding/run socialworkertests'"

   asArray : (publicIpAddress) ->
-
+
     return [
-
+
       @get.socialWorker publicIpAddress
-
+
     ]


fix deck_id

fix deck_id


RIP Wat

RIP Wat

It doesn't work, watserv is over.

--- scripts/wat.coffee
+++ scripts/wat.coffee
@@ -1,21 +0,0 @@
-# Description:
-#   Get a random WAT image - warning, this includes NSFW content!
-#
-# Dependencies:
-#   None
-#
-# Configuration:
-#   None
-#
-# Commands:
-#   hubot wat - Random WAT
-#
-# Author:
-#   john-griffin
-
-module.exports = (robot) ->
-
-  robot.respond /wat/i, (msg) ->
-    msg.http("http://watme.herokuapp.com/random")
-      .get() (err, res, body) ->
-        msg.send JSON.parse(body).wat


NumberAnimation bug with duplicated processing fixed

In some cases, a NumberAnimation was processed twice.
This wasn't change the animation behaviour.

--- impl/base/level1/animation/number.coffee
+++ impl/base/level1/animation/number.coffee
@@ -27,6 +27,7 @@
 				pending[i] = pending[n-1]
 				pending[n-1] = pending[pending.length-1]
 				pending.pop()
+				anim._impl.pending = false
 				n--

 		requestAnimationFrame vsync
@@ -51,15 +52,9 @@
 			val = data.easing anim._duration * progress, data.from, (data.to - data.from), anim._duration
 		target = anim._target

-		# if data.isIntegerProperty is true and progress isnt 1
-		# 	val = round val
-
 		if val is val and target and (property = anim._property) # isNaN hack
 			if not running or anim._updateProperty or not data.propertySetter
 				anim._updatePending = true
-				# when animation has been started in a signal which stopped propagation
-				if not running and target[data.internalPropertyName] is val
-					target[data.internalPropertyName] = data.from
 				target[property] = val
 				anim._updatePending = false

@@ -81,6 +76,7 @@

 	DATA =
 		type: 'number'
+		pending: false
 		startTime: 0
 		pauseTime: 0
 		from: 0
@@ -99,7 +95,9 @@
 			data = @_impl
 			data.from = @_from
 			data.to = @_to
-			pending.push @
+			unless data.pending
+				pending.push @
+				data.pending = true

 			data.startTime = nowTime
 			updateAnimation @
@@ -119,7 +117,9 @@
 		_super.call @
 		if @_impl.type is 'number'
 			data = @_impl
-			pending.push @
+			unless data.pending
+				pending.push @
+				data.pending = true

 			data.startTime += Date.now() - data.pauseTime
 			data.pauseTime = 0


client/enumeration: Fix bug with non-cycling enumerations.

--- client/enumeration.coffee
+++ client/enumeration.coffee
@@ -114,7 +114,7 @@
       # above % l gives [ 0, l - 1]
       ( ( index % l ) + l ) % l
     else
-      Math.max( Math.min( index, 0 ), l - 1 )
+      Math.min( Math.max( index, 0 ), l - 1 )

   # Increment index by `n`.
   #


Fix incorrect console.error

Fix incorrect console.error

--- coffee/server.coffee
+++ coffee/server.coffee
@@ -6,7 +6,7 @@
 ObjectID = require('mongodb').ObjectID

 pg.connect config.conString, (err, client) ->
-  return console.err err if err
+  return console.error err if err

   helpers.insertOIDsForTables client, config.from, config.oid, (err, data) ->
     return console.log err if err


Add downloadAllSubmits api

Add downloadAllSubmits api

--- server/api/setupApi.coffee
+++ server/api/setupApi.coffee
@@ -15,6 +15,7 @@
 import {updateAllResults} from '../calculations/updateResults'
 import downloadMaterials from '../cron/downloadMaterials'
 import * as downloadContests from '../cron/downloadContests'
+import * as downloadSubmits from "../cron/downloadSubmits"

 export default setupApi = (app) ->
     app.post '/api/register', (req, res, next) ->
@@ -82,3 +83,9 @@
             res.status(403).send('No permissions')
         downloadContests.run()
         res.send('OK')
+
+    app.get '/api/downloadAllSubmits', connectEnsureLogin.ensureLoggedIn(), (req, res) ->
+        if not req.user?.admin
+            res.status(403).send('No permissions')
+        downloadSubmits.runAll()
+        res.send('OK')


On registeredUsers page, show only recently registered (fix #96)

--- server/api/setupApi.coffee
+++ server/api/setupApi.coffee
@@ -295,7 +295,7 @@
             promises.push(addUserName(user))
             result.push(user)
         await awaitAll(promises)
-        result = result.filter((user) -> not user.dormant)
+        result = result.filter((user) -> (not user.dormant) and (user.registerDate > new Date() - 1000 * 60 * 60 * 24 * 100))
         result.sort((a, b) -> (a.registerDate || new Date(0)) - (b.registerDate || new Date(0)))
         res.json(result)


Rename selection to highlight.

Rename selection to highlight.

--- client/publication.coffee
+++ client/publication.coffee
@@ -60,10 +60,10 @@
   closestElementIndex

 setupTextSelection = (publication, page, $textLayer) ->
-  selectionStartIndex = -1
+  highlightStartIndex = -1

   $textLayer.mousemove (e) ->
-    return if selectionStartIndex is -1
+    return if highlightStartIndex is -1

     offset = $textLayer.offset()
     currentPosition =
@@ -78,22 +78,22 @@
     $elements.css
       'background-color': 'rgba(0,0,0,0)'

-    $selection = $elements.slice Math.min(selectionStartIndex, currentPositionIndex), Math.max(selectionStartIndex, currentPositionIndex) + 1
-
-    $selection.css
+    $highlight = $elements.slice Math.min(highlightStartIndex, currentPositionIndex), Math.max(highlightStartIndex, currentPositionIndex) + 1
+
+    $highlight.css
       'background-color': 'rgba(255,0,0,0.3)'

   $textLayer.mousedown (e) ->
     offset = $textLayer.offset()
-    selectionStartIndex = findClosestElement $textLayer.children(),
+    highlightStartIndex = findClosestElement $textLayer.children(),
       left: e.pageX - offset.left
       top: e.pageY - offset.top

   $textLayer.mouseup (e) ->
-    selectionStartIndex = -1
+    highlightStartIndex = -1

   $textLayer.mouseleave (e) ->
-    selectionStartIndex = -1
+    highlightStartIndex = -1

 displayPublication = (publication) ->
   PDFJS.getDocument(publication.url()).then (pdf) ->