Use the atom-text-editor tag instead of the editor class.

--- keymaps/agda-mode.cson
+++ keymaps/agda-mode.cson
@@ -7,7 +7,7 @@

 # For more detailed documentation see
 # https://atom.io/docs/latest/advanced/keymaps
-'.editor.agda':
+'.atom-text-editor.agda':
   'ctrl-c ctrl-l': 'agda-mode:load'
   'ctrl-c ctrl-x ctrl-q': 'agda-mode:quit'
   'ctrl-c ctrl-x ctrl-r': 'agda-mode:restart'


enable button title

enable button title

--- modules/gui/lib/widgets/UploadButton.coffee
+++ modules/gui/lib/widgets/UploadButton.coffee
@@ -42,11 +42,18 @@

                         input _attr

+                    _attr =
+                        class:@data.button.class
+
+                    if _title = @data.button.title
+                        _attr.title = _title
+
                     if @data.button.type is 'link'
-                        a class:@data.button.class, href:'#', (@data.button.html || @data.button.text)
+                        _attr.href = '#'
+                        a _attr, (@data.button.html || @data.button.text)

                     else
-                        button class:@data.button.class, (@data.button.html || @data.button.text)
+                        button _attr, (@data.button.html || @data.button.text)

                     iframe id:'upload-frame-'+@id, name:'upload-frame-'+@id, width:'0px', height:'0px', frameborder:0, style: 'width:0;height:0;visibility:hidden'


Make UndoManager.clear not cancel the transaction

If an exception is thrown while running an operation, we clear the
undo manager and re-throw it. But if we were in a transaction, we will
commit it in a `finally` block. If the transaction is set to null,
committing the transaction will then throw an exception which hides
the original exception… we don't want that. Now clear just empties the
current transaction out.

--- src/app/undo-manager.coffee
+++ src/app/undo-manager.coffee
@@ -11,7 +11,7 @@
     @clear()

   clear: ->
-    @currentTransaction = null
+    @currentTransaction = [] if @currentTransaction?
     @undoHistory = []
     @redoHistory = []


avoid null callback

avoid null callback

--- services/spelling/app/coffee/ASpellWorker.coffee
+++ services/spelling/app/coffee/ASpellWorker.coffee
@@ -41,8 +41,11 @@
 			output = output + chunk
 			# We receive the language code from Aspell as the end of data marker
 			if chunk.toString().match(endMarker)
-				@callback(null, output.slice())
-				@callback = null # only allow one callback in use
+				if @callback?
+					@callback(null, output.slice())
+					@callback = null # only allow one callback in use
+				else
+					logger.err process: @pipe.pid, lang: @language, "end of data marker received when callback already used"
 				@state = 'ready'
 				output = ""
 				error = ""


Better tests for `changed` option

Better tests for `changed` option

--- test/property.spec.coffee
+++ test/property.spec.coffee
@@ -314,12 +314,24 @@
       expect(@object.result).to.eql(2)

   describe "with `changed` option", ->
-    it "triggers a change event if changed option evaluates to true", ->
-      defineProperty @object, "name", changed: (oldVal, newVal) -> oldVal isnt newVal
+    it "triggers a change event if value of property has changed if option not given", ->
+      defineProperty @object, "name"

       expect(=> @object.name = "jonas").to.triggerEvent(@object.name_property)
       expect(=> @object.name = "jonas").not.to.triggerEvent(@object.name_property)
       expect(=> @object.name = "kim").to.triggerEvent(@object.name_property)
+
+    it "triggers a change event if changed option evaluates to true", ->
+      defineProperty @object, "name", value: "jonas", changed: (oldVal, newVal) -> oldVal is newVal
+
+      expect(=> @object.name = "jonas").to.triggerEvent(@object.name_property)
+      expect(=> @object.name = "jonas").to.triggerEvent(@object.name_property)
+      expect(=> @object.name = "kim").not.to.triggerEvent(@object.name_property)
+
+    it "always triggers a change event the first time a property is changed when a function is given since we don't know the initial value", ->
+      defineProperty @object, "name", changed: -> false
+      expect(=> @object.name = "jonas").to.triggerEvent(@object.name_property)
+      expect(=> @object.name = "kim").not.to.triggerEvent(@object.name_property)

     it "does not trigger dependencies when not changed", ->
       defineProperty @object, "name", changed: (oldVal, newVal) -> oldVal isnt newVal


Change api_url to reflect Gist raw file URI change

https://developer.github.com/changes/2014-02-21-gist-raw-file-url-change/

--- src/scripts/code-name-generator.coffee
+++ src/scripts/code-name-generator.coffee
@@ -13,7 +13,7 @@
 # Author:
 #   Scott J Roberts - @sroberts

-api_url = "https://gist.github.com"
+api_url = "https://gist.githubusercontent.com"
 request_url = api_url + "/sroberts/6529712/raw/1e979071f6a9e8747d2c44cf5af7c4998e068d49/wordlist"

 module.exports = (robot) ->


Fix syntax error

Fix syntax error

--- src/server/models/dao/sequelize.coffee
+++ src/server/models/dao/sequelize.coffee
@@ -248,7 +248,6 @@
     params = {}

     if _.keys(options.conditions).length > 0
-      options.conditions = App.sequelize.and.apply null, pairs
       params.where = options.conditions

     if options.limit > 0


In status bar spec, wait for tile to show up

--- spec/deprecation-cop-status-bar-view-spec.coffee
+++ spec/deprecation-cop-status-bar-view-spec.coffee
@@ -19,7 +19,7 @@
     waitsForPromise -> atom.packages.activatePackage('status-bar')
     waitsForPromise -> atom.packages.activatePackage('deprecation-cop')

-    runs ->
+    waitsFor ->
       statusBarView = workspaceElement.querySelector('.deprecation-cop-status')

   afterEach ->


remove console log

remove console log

--- user-goals.coffee
+++ user-goals.coffee
@@ -47,8 +47,6 @@
     @el.find("button[name='user-goal-submit']").on 'click', => @setUserGoal()
     @el.find("button[name='user-goal-close']").on 'click', => @el.remove()

-    # User.current.setPreference ""
-
   create: -> $(".readymade-classify-page").append html

   feedback: -> @el.show().html(FEEDBACK).delay(2000).fadeOut()
@@ -80,7 +78,6 @@

   setUserGoal: ->
     @goal or= @el.find("#user-goal-form input[type='radio']:checked").val()
-    console.log "user Goal SET!", @goal

     @el.html("
Goal set for #{@goal} Classifications
")


KDEventEmitter: #emit should return "this"

--- client/Framework/core/KDEventEmitter.coffee
+++ client/Framework/core/KDEventEmitter.coffee
@@ -102,6 +102,8 @@
     listenerStack = listenerStack.concat @_e[eventName].slice(0)
     listenerStack.forEach (listener)=> listener.apply @, args

+    return this
+
   on  :(eventName, listener) ->
     unless 'function' is typeof listener
       throw new Error 'listener is not a function'


VMController: Fixed not calling the callback issue on createPaidVM.

--- client/Main/VirtualizationController.coffee
+++ client/Main/VirtualizationController.coffee
@@ -429,14 +429,13 @@
         return callback err  if err

         @provisionVm {stackId, subscription, productData: {pack}}, (err, nonce) =>
-          return  unless err
-
-          if err.message is "quota exceeded"
-            if KD.getGroup().slug is "koding"
-              @showUpgradeModal()
-              callback()
-            else
-              callback message: "Your group is out of VM quota"
+          if err
+            if err.message is "quota exceeded"
+              if KD.getGroup().slug is "koding"
+                @showUpgradeModal()
+                callback()
+              else
+                callback message: "Your group is out of VM quota"
           else callback err
         , fireEvent


[options] allow removal of "" manifest

[options] allow removal of "" manifest

--- src/coffee/data/data.coffee
+++ src/coffee/data/data.coffee
@@ -45,7 +45,7 @@
             if not Object.isString(parentData.key) or parentData.key.isBlank()
                 if err?
                     err.push 'Cannot resolve key ' + key
-                return false
+                return ''

             data.key = exports.spreadsheets.parseKey(parent).key

@@ -456,7 +456,7 @@
             tmpErr = []
             key = resolveKey keys[i], '', tmpErr

-            if key is false
+            if key is ''
                 err[keys[i]] = tmpErr
                 step i + 1
                 return


Check for threshold definition

Check for threshold definition

--- src/components/Group.coffee
+++ src/components/Group.coffee
@@ -32,9 +32,10 @@

     @inPorts.group.on 'data', (data) =>
       # Get rid of groups in the past to make room for the new one
-      diff = @newGroups.length - @threshold + 1
-      if diff > 0
-        @newGroups = @newGroups.slice(diff)
+      if @threshold
+        diff = @newGroups.length - @threshold + 1
+        if diff > 0
+          @newGroups = @newGroups.slice(diff)

       @newGroups.push data


double duty but w/e

double duty but w/e

--- components/artwork_item/test/artwork.coffee
+++ components/artwork_item/test/artwork.coffee
@@ -29,10 +29,16 @@
       $('.artwork-item-image').attr('src').should.containEql 'large'

     it 'displays missing image if the size is not available', ->
-      @artwork.attributes
+      @artwork.set images: fabricate('artwork_image', image_versions: [])
       $ = cheerio.load render('artwork')({ artwork: @artwork, artworkSize: 'banana' })
       $('.artwork-item-image').attr('src').should.not.containEql 'banana'
       $('.artwork-item-image').attr('src').should.containEql 'missing'
+
+    it 'displays a fallback nothing available', ->
+      @artwork.set images: fabricate('artwork_image', image_versions: ['small'])
+      $ = cheerio.load render('artwork')({ artwork: @artwork, artworkSize: 'banana' })
+      $('.artwork-item-image').attr('src').should.not.containEql 'banana'
+      $('.artwork-item-image').attr('src').should.containEql 'small'

     it 'renders with a fixed with', ->
       $ = cheerio.load render('artwork')({ artwork: @artwork, imageWidth: 500 })


修正自定义控件中item in ?@bindItems这样的绑定不生效的BUG

修正自定义控件中item in ?@bindItems这样的绑定不生效的BUG

--- src/core/dom-feature.coffee
+++ src/core/dom-feature.coffee
@@ -74,12 +74,6 @@
 		domBinding.scope = new cola.AliasScope(domBinding.scope, @expression)
 		domBinding.subScopeCreated = true
 		return
-
-	evaluate: (domBinding, dynaExpressionOnly, dataCtx = {}, loadMode) ->
-		dataCtx.vars ?= {}
-		dataCtx.vars.$dom = domBinding.dom
-		scope = domBinding.scope
-		return scope.evaluate(scope, dynaExpressionOnly, loadMode, dataCtx)

 	_refresh: (domBinding, dynaExpressionOnly, dataCtx)->
 		data = @evaluate(domBinding, dynaExpressionOnly, dataCtx)
@@ -181,12 +175,6 @@

 		domBinding.subScopeCreated = true
 		return
-
-	evaluate: (domBinding, dynaExpressionOnly, dataCtx = {}, loadMode) ->
-		dataCtx.vars ?= {}
-		dataCtx.vars.$dom = domBinding.dom
-		scope = domBinding.scope
-		return scope.evaluate(scope, dynaExpressionOnly, loadMode, dataCtx)

 	_refresh: (domBinding, dynaExpressionOnly, dataCtx) ->
 		if @isDyna and not dynaExpressionOnly


Prevent LinesComponent from updating on simple cursor movement

--- src/editor-component.coffee
+++ src/editor-component.coffee
@@ -2,6 +2,7 @@
 {div, span} = require 'reactionary-atom-fork'
 {debounce, defaults, isEqualForProperties} = require 'underscore-plus'
 scrollbarStyle = require 'scrollbar-style'
+{Range, Point} = require 'text-buffer'

 GutterComponent = require './gutter-component'
 InputComponent = require './input-component'
@@ -214,10 +215,14 @@

     selectionScreenRanges = {}
     for selection, index in editor.getSelections()
-      # Rendering artifacts occur on the lines GPU layer if we remove the last selection
       screenRange = selection.getScreenRange()
-      if index is 0 or (not screenRange.isEmpty() and screenRange.intersectsRowRange(renderedStartRow, renderedEndRow))
+
+      if not screenRange.isEmpty() and screenRange.intersectsRowRange(renderedStartRow, renderedEndRow)
         selectionScreenRanges[selection.id] = screenRange
+
+      else if index is 0 # Rendering artifacts occur on the lines GPU layer if we remove the last selection
+        selectionScreenRanges[selection.id] = new Range(new Point(renderedStartRow, 0), new Point(renderedStartRow, 0))
+
     selectionScreenRanges

   observeEditor: ->


Properly disable nextTick when calling requestAnimationFrame

My previous commit was nonsense because it set the ::performSyncUpdates
flag back to false before the animation frame callback ever got fired.

/cc again @benogle

--- src/editor-component.coffee
+++ src/editor-component.coffee
@@ -217,8 +217,9 @@
   requestAnimationFrame: (fn) ->
     prevPerformSyncUpdates = @performSyncUpdates
     @performSyncUpdates = true
-    requestAnimationFrame(fn)
-    @performSyncUpdates = prevPerformSyncUpdates
+    requestAnimationFrame =>
+      fn()
+      @performSyncUpdates = prevPerformSyncUpdates

   getRenderedRowRange: ->
     {editor, lineOverdrawMargin} = @props


Moves through the levels on mouse clicks.

--- src/game/states/game.coffee
+++ src/game/states/game.coffee
@@ -51,8 +51,17 @@
   @player = null

   create: ->
+    @levelnum = 0
+    @drawLevel(@levelnum)
+    @input.onDown.add @onDown, this
+
+  onDown: ->
+    if @levelcomplete
+       @levelnum++
+       @drawLevel(@levelnum)
+
+  drawLevel: (@levelnum) ->
     #setup game window
-    @levelnum = 0
     @level = LEVELS[@levelnum]
     x = @level.starsArray[@level.startingStar].x
     y = @level.starsArray[@level.startingStar].y


order keys in config.cson alphabetically

--- src/config.coffee
+++ src/config.coffee
@@ -827,6 +827,7 @@

     allSettings = {'*': @settings}
     allSettings = _.extend allSettings, @scopedSettingsStore.propertiesForSource(@getUserConfigPath())
+    allSettings = sortObject(allSettings)
     try
       CSON.writeFileSync(@configFilePath, allSettings)
     catch error
@@ -1190,6 +1191,13 @@
 isPlainObject = (value) ->
   _.isObject(value) and not _.isArray(value) and not _.isFunction(value) and not _.isString(value) and not (value instanceof Color)

+sortObject = (value) ->
+  return value unless isPlainObject(value)
+  result = {}
+  for key in Object.keys(value).sort()
+    result[key] = sortObject(value[key])
+  result
+
 withoutEmptyObjects = (object) ->
   resultObject = undefined
   if isPlainObject(object)


clean up stubs

clean up stubs

--- apps/fairs/test/client.coffee
+++ apps/fairs/test/client.coffee
@@ -23,6 +23,8 @@
       done()

   after ->
+    Backbone.sync.restore()
+    Fair.prototype.isPast.restore()
     benv.teardown()

   beforeEach (done) ->


Teamwork: Reimplemented Playground support.

--- client/Teamwork/Views/teamworkdashboard.coffee
+++ client/Teamwork/Views/teamworkdashboard.coffee
@@ -22,14 +22,13 @@
       click       : => @getDelegate().teamwork.showImportModal()

     manifests?.forEach (manifest) =>
-      @setClass "ready"
       @playgrounds.addSubView view = new KDCustomHTMLView
         cssClass  : "tw-playground-item"
         partial   : "
#{manifest.name}
"
         click     : =>
-          # @getDelegate().handlePlaygroundSelection manifest.name, manifest.manifestUrl
-          new KDNotificationView
-            title : "Coming Soon"
+          @getDelegate().handlePlaygroundSelection manifest.name, manifest.manifestUrl
+
+    @setClass "ready"

   fetchManifests: ->
     delegate = @getDelegate()


Removed unnecessary configuration properties

--- config.example.coffee
+++ config.example.coffee
@@ -8,9 +8,5 @@
   app:
     port: 3000
     sessionSecret: 'secret key'
-  versions:
-    angularUi: '0.12.1'
-    angular: '1.3.14'
-    jquery: '2.1.3'

 module.exports = config


Don't repeat typing if we don't have any text

--- lib/operators/input.coffee
+++ lib/operators/input.coffee
@@ -16,6 +16,7 @@

   execute: ->
     if @typingCompleted
+      return unless @typedText? and @typedText.length > 0
       @undoTransaction =>
         @editor.getBuffer().insert(@editor.getCursorBufferPosition(), @typedText, true)
     else


Remove outlets

Remove outlets

--- lib/styleguide-view.coffee
+++ lib/styleguide-view.coffee
@@ -542,14 +542,14 @@

         @h2 'Error messages'
         @exampleCode '''
-          @ul outlet: 'errorMessages', class: 'error-messages block', =>
+          @ul class: 'error-messages block', =>
             @li 'This is an error!'
             @li 'And another'
         '''

         @h2 'Info messages'
         @exampleCode '''
-          @ul outlet: 'infoMessages', class: 'info-messages block', =>
+          @ul class: 'info-messages block', =>
             @li 'Info line'
             @li 'Another info line'
         '''


Check that text is something

Check that text is something

Closes #475

--- lib/symbol-provider.coffee
+++ lib/symbol-provider.coffee
@@ -211,7 +211,7 @@
     candidates = []
     for symbol in symbolList
       text = (symbol.snippet or symbol.text)
-      continue unless prefix[0].toLowerCase() is text[0].toLowerCase() # must match the first char!
+      continue unless text and prefix[0].toLowerCase() is text[0].toLowerCase() # must match the first char!
       score = fuzzaldrin.score(text, prefix)
       score *= @getLocalityScore(bufferPosition, symbol.bufferRowsForBufferPath?(bufferPath))
       candidates.push({symbol, score, locality, rowDifference}) if score > 0


Remove unneeded pending test

Remove unneeded pending test

--- test/javascripts/integration/reporting_guidelines_test.js.coffee
+++ test/javascripts/integration/reporting_guidelines_test.js.coffee
@@ -179,6 +179,3 @@
     additionalDataText = questionLi.find('.additional-data').first().text().trim()
     ok additionalDataText.indexOf('Select & upload') > -1
     ok additionalDataText.indexOf('Provide a completed PRISMA checklist as supporting information.') > -1
-
-test 'clinical trial question is auto-checked based on answer from ethics question', ->
-  ok true


Add locality scoring

Add locality scoring

So matches closer are scored higher. It’s not super aggressive right now.

--- lib/symbol-provider.coffee
+++ lib/symbol-provider.coffee
@@ -46,7 +46,6 @@

     return unless @paneItemIsValid(currentPaneItem)

-
     @editor = currentPaneItem
     @buffer = @editor.getBuffer()

@@ -109,22 +108,47 @@
   # prefix - {String} The prefix
   #
   # Returns an {Array} of Suggestion instances
-  findSuggestionsForWord: (prefix) =>
+  findSuggestionsForWord: (options) =>
     return unless @wordList?
     # Merge the scope specific words into the default word list
     wordList = @wordList.concat(@getCompletionsForCursorScope())

     words =
       if atom.config.get("autocomplete-plus.strictMatching")
-        wordList.filter((match) -> match.word?.indexOf(prefix) is 0)
+        wordList.filter((match) -> match.word?.indexOf(options.prefix) is 0)
       else
-        fuzzaldrin.filter(wordList, prefix, key: 'word')
+        @fuzzyFilter(wordList, options)

     for word in words
-      word.prefix = prefix
+      word.prefix = options.prefix
       word.label = word.type

     return words
+
+  fuzzyFilter: (symbolList, {position, prefix}) ->
+    # Probably inefficient to do a linear search
+    candidates = []
+    for symbol in symbolList
+      score = fuzzaldrin.score(symbol.word, prefix)
+      if symbol.bufferRow?
+        rowDifference = symbol.bufferRow - position.row
+        locality = @computeLocalityModifier(rowDifference)
+        score *= locality
+      candidates.push({symbol, score, locality, rowDifference}) if score > 0
+
+    candidates.sort(@sortReverse)
+
+    for {symbol, score, locality, rowDifference}, i in candidates
+      break if i >= 20
+      # console.log 'match', symbol.word, score, locality, rowDifference
+      symbol
+
+  sortReverse: (a, b) -> b.score - a.score
+
+  computeLocalityModifier: (rowDifference) ->
+    rowDifference = Math.abs(rowDifference)
+    # Will be between 1 and ~2.75
+    1 + Math.max(-Math.pow(.2 * rowDifference - 3, 3) / 25 + .5, 0)

   settingsForScopeDescriptor: (scopeDescriptor, keyPath) =>
     atom.config.getAll(keyPath, scope: scopeDescriptor)


axes with user bounds should re-tick as necessary when zoomed in and out or panned

--- static/coffee/renderers/guide/linear_axis.coffee
+++ static/coffee/renderers/guide/linear_axis.coffee
@@ -375,8 +375,8 @@
     range_bounds = [ranges[i].get('min'), ranges[i].get('max')]

     if _.isArray(user_bounds)
-      start = Math.min(user_bounds[0], user_bounds[1])
-      end = Math.max(user_bounds[0], user_bounds[1])
+      start = Math.max(Math.min(user_bounds[0], user_bounds[1]), range_bounds[0])
+      end = Math.min(Math.max(user_bounds[0], user_bounds[1]), range_bounds[1])
     else
       [start, end] = range_bounds


fix filerev file checks

fix filerev file checks

--- lib/grunt/task_helpers/filerev/filerev.coffee
+++ lib/grunt/task_helpers/filerev/filerev.coffee
@@ -59,8 +59,13 @@

     _.each files, (path) =>
       f = @getMapping()[path]
-      if f && f != path && @grunt.file.exists(f)
-        @grunt.file.delete(f, { force: true })
+
+      return if _.isUndefined(f)
+      return if _.isNull(f)
+      return if f == path
+      return unless @grunt.file.exists(f)
+
+      @grunt.file.delete(f, { force: true })

   createRevisionFiles: (files) ->
     _.each files, (path) =>
@@ -79,6 +84,10 @@
       sourceMapPath   = "#{path}.map"
       resultFilePath  = @getMapping()[path]

+      return if _.isUndefined(resultFilePath)
+      return if _.isUndefined(sourceMapPath)
+      return if _.isNull(resultFilePath)
+      return if _.isNull(sourceMapPath)
       return unless @grunt.file.exists(resultFilePath)
       return unless @grunt.file.exists(sourceMapPath)


added getActionType method to the engine

--- src/engine.coffee
+++ src/engine.coffee
@@ -13,6 +13,7 @@
 symbols = require './symbols'
 Node = require './node'
 Entity = require './entity'
+Action = require './action'

 Engine = (initializer) ->

@@ -27,6 +28,14 @@

 	engine.getNodeType = (componentTypes) ->
 		return Node componentTypes, nodeMap
+
+	actionMap = new Map
+
+	engine.getActionType = (actionName) ->
+		unless actionType = actionMap.get actionName
+			actionType = Action actionName
+			actionMap.set actionName, actionType
+		return actionType

 	# List of all entities in this engine
 	engine.entityList = Lill.attach {}


First implementation of Entity#toString()

--- src/entity.coffee
+++ src/entity.coffee
@@ -136,6 +136,9 @@
   class: -> @constructor.name

+  toString: -> "<#{@class()} position={ x: #{@position.x}, y: #{@position.y}}>"
+
+
   # Apply gravitational effects any directional changes each frame, and resolve any
   # resulting collisions (ex running into a wall)
   #


Documenting events.

Documenting events.

--- src/events.coffee
+++ src/events.coffee
@@ -12,10 +12,11 @@
         @_callbacks[event].push(callback)
         return this

-    # Unbind the given callback from the named event.
+    # Unbind one or many callbacks. If callback is null, remove all callbacks
+    # for the given event. If event is null, remove all callbacks for all
+    # events. If neither are null, remove the given callback.
     unbind : (event=null, callback=null) ->
         @_callbacks ?= {}
-
         if not event?
             @_callbacks = {}
         else if not callback?
@@ -23,9 +24,10 @@
         else
             callbacks = @_callbacks[event] || []
             (callbacks[i] = null for c, i in callbacks when c? and c == callback)
-
         return this

+    # Trigger the given named event. Any additional arguments will be passed to
+    # the bound callback functions.
     trigger : (event) ->
         callbacks = @_callbacks?[event] || []
         args = Array::slice.call(arguments, 1)


EDSC-263: Avoid conflicts between shapefile selection and granule selection.  Granule selection pauses while shapefile selection is available and resumes afterward.

--- app/assets/javascripts/modules/map/leaflet-plugins/shapefile_layer.js.coffee
+++ app/assets/javascripts/modules/map/leaflet-plugins/shapefile_layer.js.coffee
@@ -83,16 +83,19 @@
     hide: ->
       $('.dz-preview').hide()
       @map.removeLayer(@_jsonLayer) if @_jsonLayer?
+      @map.fire 'draw:drawstop'

     show: ->
       $('.dz-preview').show()
       @map.addLayer(@_jsonLayer) if @_jsonLayer?
+      @map.fire 'draw:drawstart'

     remove: ->
       @_dropzone.removeFile(@_file) if @_file?

     _removeFile: =>
       @map.removeLayer(@_jsonLayer) if @_jsonLayer?
+      @map.fire 'draw:drawstop'
       @_file = null

     _geoJsonResponse: (file, response) =>
@@ -120,6 +123,7 @@
       @_jsonLayer = jsonLayer

       @map.addLayer(jsonLayer)
+      @map.fire 'draw:drawstart'
       @map.fitBounds(jsonLayer.getBounds())

       children = jsonLayer.getLayers()
@@ -156,7 +160,6 @@

       if layer?
         map = @map
-        map.fire 'draw:drawstart'
         map.fire 'draw:created',
           target: map
           layer: layer


refs #21 Implement option competitor_name_proc for CompetitiveList constructor.

--- app/assets/javascripts/voluntary/dom_manipulation/competitive_list.js.coffee
+++ app/assets/javascripts/voluntary/dom_manipulation/competitive_list.js.coffee
@@ -1,7 +1,10 @@
 window.Voluntary or= {}; window.Voluntary.DomManipulation or= {}

 window.Voluntary.DomManipulation.CompetitiveList = class CompetitiveList
-  constructor: ->
+  constructor: (options) ->
+    window.competitiveListOptions = options
+    window.competitiveListOptions ||= {}
+
     $(document.body).on "click", ".competitive_list_start_link", (event) ->
       event.preventDefault()
       window.Voluntary.DomManipulation.CompetitiveList.start()
@@ -119,8 +122,13 @@
         competitorDomElement = $('#competitor_' + competitorId)
         checked = ' checked="checked"'
         checked = '' if i == 1
-        radioButtons += '<input type="radio" ' + checked + ' name="winner" value="' + competitorId + '" style="position:relative; left: -10px; top:-5px "/>' +
-        $(competitorDomElement).find('.competitorName').html()
+        radioButtons += '<input type="radio" ' + checked + ' name="winner" value="' + competitorId + '" style="position:relative; left: -10px; top:-5px "/>'
+
+        if window.competitiveListOptions['competitor_name_proc'] == undefined || $(competitorDomElement).find('.competitor_name').data('proc-argument') == undefined
+          radioButtons += $(competitorDomElement).find('.competitor_name').html()
+        else
+          radioButtons += window.competitiveListOptions['competitor_name_proc']($(competitorDomElement).find('.competitor_name').data('proc-argument'))
+
         radioButtons += '  VS.      ' if i == 0
         i += 1


Support the navigator ui when user agent is PC

--- views/2574.coffee
+++ views/2574.coffee
@@ -8,6 +8,9 @@
   center: position.toArray()
   zoom: 8
 }
+
+if not /iPhone|iPad|iPod|Android/.test(navigator.userAgent)
+  map.addControl(new mapboxgl.Navigation())

 source = new mapboxgl.GeoJSONSource {data: 'data.geojson'}


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/follow.coffee
+++ src/follow.coffee
@@ -3,6 +3,7 @@
     velocity: Point(0, 0)

   follow: (obj) ->
+    I.

   self.bind "update", ->
     I.velocity = player.position().subtract(self.position()).norm().scale(5)


fixed display mode single character bug

fixed display mode single character bug


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

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

 This method relies on both objects having position methods.

-include this module by calling
+include this module by calling self.include Follow

 player = GameObject


Emits a gitlab-commit message for every commit

--- src/gitlab.coffee
+++ src/gitlab.coffee
@@ -119,6 +119,13 @@
                   merger = []
                   for i in [0...hook.commits.length]
                     merger[i] = "> " + hook.commits[i].id.slice(0,7) + ": " + hook.commits[i].message.replace /\n.*$/gm, ''
+                    robot.emit "gitlab-commit", {
+                        user: user,
+                        repo: hook.repository.name,
+                        message: hook.commits[i].message,
+                        commit: hook.commits[i]
+                      }
+
                   message += "\r\n" + merger.join "\r\n"
           robot.send user, message
         # not code? must be a something good!


add instanceFound hook

add instanceFound hook

--- src/hinoki.coffee
+++ src/hinoki.coffee
@@ -84,6 +84,7 @@
             container = result.containers[0]

             if result.instance?
+                container.hooks?.instanceFound? newChain, result.instance
                 resolved[id] = result.instance
                 return


Only wrap JSON.parse() call in try/catch

--- src/lister.coffee
+++ src/lister.coffee
@@ -29,9 +29,12 @@
         continue unless @isFile(manifest)
         try
           packageJson = JSON.parse(fs.readFileSync(manifest, 'utf8'))
-          name = packageJson.name ? child
-          version = packageJson.version ? '0.0.0'
-          packages.push({name, version})
+        catch e
+          continue
+
+        name = packageJson.name ? child
+        version = packageJson.version ? '0.0.0'
+        packages.push({name, version})

     console.log @atomModulesDirectory
     for pack, index in packages


Improved several management functions, fixed issues with atomicity and fixed pdf processor to copy the solution over for the last time before locking it.

--- src/manage.coffee
+++ src/manage.coffee
@@ -12,19 +12,6 @@

   # For pdfs
   API =
-    getUnprocessedSolutionSample: ->
-      rdb
-      .table("Solutions")
-      .eqJoin("exercise", rdb.table("Exercises"))
-      .filter(
-        # Is due, not processed so far and not in process?
-        rdb.row("right")("dueDate").lt(new Date()).and(
-          rdb.row("left")("processed").default(false).ne(true)
-        ).and(
-          rdb.row("left")("processingLock").default(false).ne(true)
-        )
-      ).sample(1)("left").nth(0).default(null).run con
-
     storeTutor: (tutor) ->
       if !tutor.name? or !tutor.password? or !tutor.contingent?
         Promise.reject("You must provide a name, password and contingent field")
@@ -71,19 +58,43 @@
       rdb.table("Solutions").filter( (s) ->
         s("id").match(solution_id)).without("pdf").limit(10).coerceTo('array').run(con)

+    # Also stores the last sharejs data
     lockSpecificSolutionForPdfProcessor: (id) ->
-      rdb.table("Solutions").get(id).update({"processingLock": true}, {returnChanges: true}).run con
-
+      rdb.do(
+        API.storeSolution(id),
+        rdb.table("Solutions").get(id).update({"processingLock": true}, {returnChanges: true})
+      )
+
+    ############################################################################
     # Locks a single solution which is due.
     # Returns the locked solution, or undefined if none is available
+    #
+    # A solution sample must fulfill the following conditions, to be processable
+    # - the exercise must be due
+    # - it must not have benn processed so far
+    # - it must not be in process (processingLock)
+    ############################################################################
     lockSolutionForPdfProcessor: ->
-      API.getUnprocessedSolutionSample().then (solution) ->
-        if (!solution)
-          Promise.reject "No more processable solution."
-          #new Promise (resolve) ->
-          #  resolve undefined
-        else
-          API.lockSpecificSolutionForPdfProcessor(solution.id)
+      rdb.do(
+        rdb
+        .table("Solutions")
+        .eqJoin("exercise", rdb.table("Exercises"))
+        .filter((sol) ->
+          # Is due, not processed so far and not in process?
+          sol("right")("dueDate").lt(new Date()).and(
+            sol("left")("processed").default(false).ne(true)
+          ).and(
+            sol("left")("processingLock").default(false).ne(true)
+          )
+        ).sample(1).nth(0).default(null), (solution) ->
+          rdb.branch(
+            rdb.expr(solution).ne(null),
+            API.lockSpecificSolutionForPdfProcessor(solution("left")("id")).do(
+              rdb.expr(solution)("left")
+            ),
+            rdb.expr(solution) # return null
+          )
+      ).run con

     resetPdfForSolution: (solutionId) ->
       rdb.table("Solutions").get(solutionId).run(con).then( (result) ->
@@ -94,6 +105,11 @@
             solution.without("processed").without("processingLock").without("pdf")
           ).run con
       )
+
+    resetPdfForAllSolutions: () ->
+      rdb.table("Solutions").replace((solution) ->
+        solution.without("processed").without("processingLock").without("pdf")
+      ).run con

     # Save the finished pdf file into the solution
     insertFinishedPdf: (solutionId, pdfData)->
@@ -138,13 +154,16 @@
         })
       )).coerceTo("array").run con

-    # Store just one solution, does not perform checkings and is meant to be used for admins.
-    storeSolution: (sid) ->
-      rdb.table("Solutions").eqJoin("exercise", rdb.table("Exercises"))
-      .filter(rdb.row("left")("id").eq(sid))
-      .map( (solution) ->
+    # Stores just one final solution, for load balancing
+    storeFinalSolutionSample: () ->
+      rdb.table("Solutions").eqJoin("exercise", rdb.table("Exercises")).filter(
+        rdb.row("left")("finalSolutionStored")
+        .default(false)
+        .eq(false)
+        .and(rdb.row("right")("dueDate").lt(rdb.now()))
+      ).sample(1).map( (solution) ->
         solution.merge({
-          finalSolutionStored: rdb.table("Exercises").get(solution("right")("id")),
+          finalSolutionStored: true,
           tasks: solution("right")("tasks").map( (task) ->
             rdb
             .db(config.sharejs.rethinkdb.db)
@@ -160,12 +179,79 @@
             )
           )
         })
-      ).coerceTo('array').run con
-
+      ).run con
+
+    # Store just one solution, does not perform checkings and is meant to be used for admins.
+    storeSolution: (sid) ->
+      rdb.table("Solutions").eqJoin("exercise", rdb.table("Exercises"))
+      .filter((solution) -> solution("left")("id").eq(sid))
+      .map( (solution) ->
+        solution.merge({
+          #finalSolutionStored: rdb.table("Exercises").get(solution("right")("id")),
+          finalSolutionStored: solution("right")("dueDate").lt(rdb.now()),
+          tasks: solution("right")("tasks").map( (task) ->
+            rdb
+            .db(config.sharejs.rethinkdb.db)
+            .table(config.sharejs.tableName)
+            .get(
+              rdb.add(
+                solution("left")("group").coerceTo("string"),
+                ":",
+                solution("left")("exercise").coerceTo("string"),
+                ":",
+                task("number").coerceTo("string")
+              )
+            )
+          )
+        })
+      ).coerceTo('array')
+
+    ############################################################################
+    # UpdateOldestSolution copies the sharejs data over into the solution table
+    # for the solution that hasn't been updated the longest.
+    #
+    # In order to update this solution, the stored solution must not be final
+    # and older than minAge seconds.
+    ############################################################################
     updateOldestSolution: (minAge) ->
       minAge = minAge or 300
       if !config.sharejs?.rethinkdb?.db?
         return Promise.reject "No sharejs database defined"
+
+      rdb.do(
+        rdb.table("Solutions")
+          .orderBy({index: "lastStore"})
+          .filter(
+            rdb.row("lastStore").add(minAge).lt(rdb.now()).and(
+              rdb.row("finalSolutionStored").default(false).eq(false)
+            )
+          )
+          .eqJoin('exercise', rdb.table("Exercises")).nth(0).default(null),
+        (oldest) ->
+          rdb.branch(
+            rdb.expr(oldest).ne(null),
+            rdb.table("Solutions").get(oldest("left")("id")).update({
+              lastStore: rdb.now()
+              finalSolutionStored: oldest("right")("dueDate").lt(rdb.now())
+              tasks: oldest("right")("tasks").map( (task) ->
+                # left = Solutions
+                # right = Exercises
+                # id = group : exercise : task("number")
+                rdb.db(config.sharejs.rethinkdb.db)
+                  .table(config.sharejs.tableName)
+                  .get(
+                    rdb.add(oldest("left")("group").coerceTo("string"),":",oldest("right")("id").coerceTo("string"),":",task("number").coerceTo("string"))
+                  ).pluck("_data")
+              ).map (s) ->
+                s.merge({"solution": s("_data")}).without("_data")
+              } , {nonAtomic: true}
+            ),
+            {} # noop
+          )
+      ).run con
+
+      # old less robust and slower implementation, kept in case something was missed
+      ###
       rdb.do(
         rdb.table("Solutions")
           .orderBy({index: "lastStore"})
@@ -190,3 +276,4 @@
               s.merge({"solution": s("_data")}).without("_data")
             } , {nonAtomic: true})
           ).run(con)
+      ###


fix(lint)

fix(lint)

--- spec/stores/file-download-store-spec.coffee
+++ spec/stores/file-download-store-spec.coffee
@@ -289,11 +289,11 @@
         expect(shell.showItemInFolder).toHaveBeenCalledWith(@userSelectedPath)

       it "should update the NylasEnv.savedState.lastDownloadDirectory", ->
-          NylasEnv.savedState.lastDownloadDirectory = null
-          @userSelectedPath = "/Users/imaginary/.nylas/Another Random Folder/file.jpg"
-          FileDownloadStore._fetchAndSave(@testfile)
-          advanceClock(1)
-          expect(NylasEnv.savedState.lastDownloadDirectory).toEqual('/Users/imaginary/.nylas/Another Random Folder')
+        NylasEnv.savedState.lastDownloadDirectory = null
+        @userSelectedPath = "/Users/imaginary/.nylas/Another Random Folder/file.jpg"
+        FileDownloadStore._fetchAndSave(@testfile)
+        advanceClock(1)
+        expect(NylasEnv.savedState.lastDownloadDirectory).toEqual('/Users/imaginary/.nylas/Another Random Folder')

       describe "file extensions", ->
         it "should allow the user to save the file with a different extension", ->


Use IS_MOBILE instead of IS_RESPONSIVE

Use IS_MOBILE instead of IS_RESPONSIVE

--- components/marketing_signup_modal/index.coffee
+++ components/marketing_signup_modal/index.coffee
@@ -48,7 +48,7 @@

   initialize: ->
     @inner = new MarketingSignupModalInner
-    width = if sd.IS_RESPONSIVE then '100%' else '900px'
+    width = if sd.IS_MOBILE then '100%' else '900px'
     @modal = modalize @inner, backdropCloses: false, dimensions: width: width
     @modal.view.$el.addClass 'marketing-signup-modal-container'
     @inner.on 'close', => @modal.close()


warnとerrorのログが出力されるように修正

warnとerrorのログが出力されるように修正

--- lib/easy-mincer.coffee
+++ lib/easy-mincer.coffee
@@ -22,6 +22,10 @@
       console.log("    appendPath:[#{target}]")

   start: () ->
+    Mincer.logger.use({
+      warn: console.warn
+      error: console.error
+    })
     @app = connect()
     @app.use("/", Mincer.createServer(@environment))
     @app.listen(3000, (err) ->
@@ -92,7 +96,7 @@
     file = "#{@config.destDir}/#{target}"
     code = fs.readFileSync("#{@config.manifestDir}/#{assetsData.assets[target]}")
     fs.writeFileSync(file, code)
-    return dest = {
+    return {
       file: file
       code: code
     }


:art: Rename a variable for readability

:art: Rename a variable for readability

--- lib/linter-plus.coffee
+++ lib/linter-plus.coffee
@@ -32,14 +32,14 @@
     @subscriptions.add atom.workspace.onDidChangeActivePaneItem =>
       @commands.lint()

-    ignoreUpdateTabs = true
+    ignoreTabUpdates = true
     @subscriptions.add atom.config.observe 'linter.showErrorTabLine', =>
-      @views.updateTabs() unless ignoreUpdateTabs
+      @views.updateTabs() unless ignoreTabUpdates
     @subscriptions.add atom.config.observe 'linter.showErrorTabFile', =>
-      @views.updateTabs() unless ignoreUpdateTabs
+      @views.updateTabs() unless ignoreTabUpdates
     @subscriptions.add atom.config.observe 'linter.showErrorTabProject', =>
-      @views.updateTabs() unless ignoreUpdateTabs
-    ignoreUpdateTabs = false
+      @views.updateTabs() unless ignoreTabUpdates
+    ignoreTabUpdates = false

     @subscriptions.add atom.workspace.observeTextEditors (editor) =>
       currentEditorLinter = new EditorLinter @, editor


Updated destroying pinned tabs

Updated destroying pinned tabs

Updated the code behind destorying pinned tabs to be in line with the
changes from the previous commit.

The package should now work for issue #21

--- lib/pinned-tabs.coffee
+++ lib/pinned-tabs.coffee
@@ -43,7 +43,7 @@
         # This timeout ensures that the DOM elements can be edited.
         setTimeout (=>
             tabbars = document.querySelectorAll '.tab-bar'
-            state = this.PinnedTabsState.data
+            state = @PinnedTabsState.data

             for tabbar in tabbars
                 for i in [0...tabbar.children.length]
@@ -78,25 +78,8 @@

         # Reduce the amount of pinned tabs when one is destoryed
         atom.workspace.onWillDestroyPaneItem (event) =>
-            tabIndex = Array.prototype.indexOf.call(event.pane.getItems(), event.item)
-            textEditor = event.item.element
-
-            # If a tab has not been opened yet, it is not yet in the DOM,
-            # so get the active element of the pane (which is opened by definition)
-            if textEditor == undefined || textEditor.parentNode == null
-                textEditor = event.pane.activeItem.element
-
-                if textEditor == undefined
-                    return;
-
-            atomPane = textEditor.parentNode.parentNode
-            return if atomPane == null
-            tabbarNode = atomPane.querySelector '.tab-bar'
-            tabbars = document.querySelectorAll '.tab-bar'
-            tabbarIndex = Array.prototype.indexOf.call(tabbars, tabbarNode)
-
-            if tabbarNode.children[tabIndex].classList.contains('pinned')
-                @PinnedTabsState.data[tabbarIndex] -= 1
+            index = @PinnedTabsState.data.indexOf event.item.id
+            @PinnedTabsState.data.splice(index, 1) if index >= 0

     setCommands: ->
         @subscriptions = new CompositeDisposable


Update find editor given tab method

Update find editor given tab method

--- lib/pinned-tabs.coffee
+++ lib/pinned-tabs.coffee
@@ -174,15 +174,21 @@
   getEditor: (tab) ->
     return null if tab == null

-    tabbarNode = tab.parentNode
-    paneNode = tabbarNode.parentNode
-    axisNode = paneNode.parentNode
-
-    tabIndex = Array.prototype.indexOf.call tabbarNode.children, tab
-    paneIndex = Array.prototype.indexOf.call axisNode.children, paneNode
-
-    pane = atom.workspace.getPanes()[paneIndex / 2]
-    return pane.itemAtIndex tabIndex
+    target = null
+    atom.workspace.getPanes().forEach (pane) =>
+      return if target != null
+      pane.items.forEach (item) =>
+        return if target != null
+        if item.filePath
+          target = item if tab.querySelector '.title[data-path="' + item.filePath.replace(/\\/g, '\\\\') + '"]'
+        if item.getTitle
+          target = item if tab.querySelector '.title[data-name="' + item.getTitle() + '"]'
+        if item.element && item.element.classList.contains 'about'
+          target = item if tab.getAttribute('data-type') == 'AboutView'
+        if item.element && item.element.classList.contains 'settings-view'
+          target = item if tab.getAttribute('data-type') == 'SettingsView'
+
+    return target

   getItemID: (item) ->
     if item.getURI && item.getURI()


Added comment.

Added comment.

--- lib/serializers.coffee
+++ lib/serializers.coffee
@@ -1,3 +1,5 @@
+# Functions for final serialization of respresentation into string
+

 json = (obj, cb) ->
   try


payment: added a field for tags to the payment form

+ allow more granular options to be passed to the constructor

--- client/app/Applications/Dashboard.kdapplication/views/producteditform.coffee
+++ client/app/Applications/Dashboard.kdapplication/views/producteditform.coffee
@@ -17,25 +17,25 @@
         cssClass  : "modal-cancel"
         callback  : => @emit 'CancelRequested'

-    options.fields ?=
+    options.fields ?= {}

-      title             :
-        label           : "Title"
-        placeholder     : options.placeholders?.title
-        defaultValue    : data.decoded 'title'
-        required        : 'Title is required!'
+    options.fields.title ?=
+      label           : "Title"
+      placeholder     : options.placeholders?.title
+      defaultValue    : data.decoded 'title'
+      required        : 'Title is required!'

-      description       :
-        label           : "Description"
-        placeholder     : options.placeholders?.description or "(optional)"
-        defaultValue    : data.decoded 'description'
+    options.fields.description ?=
+      label           : "Description"
+      placeholder     : options.placeholders?.description or "(optional)"
+      defaultValue    : data.decoded 'description'

-      subscriptionType  :
-        label           : "Subscription type"
-        itemClass       : KDSelectBox
-        defaultValue    : data.subscriptionType ? "mo"
-        selectOptions   : @getSubscriptionTypes options
-        callback        : @bound 'subscriptionTypeChanged'
+    options.fields.subscriptionType ?=
+      label           : "Subscription type"
+      itemClass       : KDSelectBox
+      defaultValue    : data.subscriptionType ? "mo"
+      selectOptions   : @getSubscriptionTypes options
+      callback        : @bound 'subscriptionTypeChanged'

     options.fields.feeAmount ?=
       label           : "Amount"
@@ -52,23 +52,28 @@
           cssClass    : 'fr'

     if options.showPriceIsVolatile
-      options.fields.priceIsVolatile =
+      options.fields.priceIsVolatile ?=
         label         : "Price is volatile"
         itemClass     : KDOnOffSwitch
         defaultValue  : data.priceIsVolatile
         callback      : @bound 'priceVolatilityChanged'

     if options.showOverage
-      options.fields.overageEnabled =
+      options.fields.overageEnabled ?=
         label         : "Overage enabled"
         itemClass     : KDOnOffSwitch
         defaultValue  : data.overageEnabled

     if options.showSoldAlone
-      options.fields.soldAlone =
+      options.fields.soldAlone ?=
         label         : "Sold alone"
         itemClass     : KDOnOffSwitch
         defaultValue  : data.soldAlone
+
+    options.fields.tags ?=
+      label         : "Tags"
+      defaultValue  : data.tags?.join ', '
+      change        : @bound 'tagsChanged'

     super options, data

@@ -95,6 +100,7 @@
       feeAmount       =
         unless priceIsVolatile
         then i.feeAmount.getValue() * 100
+      tags            = @utils.splitTrim i.tags?.getValue()

       { subscriptionType, feeUnit, feeInterval } = @getPlanInfo()

@@ -108,6 +114,7 @@
         overageEnabled
         soldAlone
         priceIsVolatile
+        tags
       }

   getSubscriptionTypes: (options) ->
@@ -142,4 +149,8 @@

   priceVolatilityChanged: ->
     enabled = @inputs.priceIsVolatile.getValue()
-    do @fields.feeAmount[if enabled then 'hide' else 'show']+    do @fields.feeAmount[if enabled then 'hide' else 'show']
+
+  tagsChanged: ->
+    { tags } = @inputs
+    tags.setValue (@utils.splitTrim tags.getValue()).join ', '


Update changeCount when sort changes

Update changeCount when sort changes

--- client/lanes/models/Query.coffee
+++ client/lanes/models/Query.coffee
@@ -209,6 +209,7 @@
         autoRetrieve: ['boolean', true, true]
         title: { type: 'string', default: 'Find Record' }
         sortField: 'object'
+        defaultSort: 'any'
         changeCount: {type: 'integer', default: 0}
         sortAscending: ['boolean', true, true]

@@ -253,26 +254,34 @@
         this.on('change:src change:results', ->
             this.trigger('load')
         )
-        if options.defaultSort
-            @setSortField( @fields.findWhere(id: options.defaultSort), true )
+        this.on('load', ->
+            @changeCount += 1
+        )
+
         if @initialFieldIndex
             @initialField = this.fields.at(@initialFieldIndex)
+
         @initialField ||= this.fields.findWhere(id: "code") ||
             this.fields.findWhere(id: "visibleId") ||
             this.fields.first()
-        this.addNewClause()
+
+        @reset()
         this

     reset: ->
+        unless @defaultSort is false
+            sort = @defaultSort or @fields.findWhere(visible: true).id
+            @setSortField( @fields.findWhere(id: sort), sortAscending: true, silent: true )
+
         @clauses.reset([
             {query: this, available_fields: @fields, field: @initialField}
         ])

-    setSortField: (field, silent = false) ->
+    setSortField: (field, options = {silent: false}) ->
         @set({
-            sortAscending: (if @sortField is field then !@sortAscending else true)
+            sortAscending: options.sortAscending || (if @sortField is field then !@sortAscending else true)
             sortField: field
-        }, {silent})
+        }, options)

     ensureLoaded: -> @results.ensureLoaded()


Don’t need these

Don’t need these

--- spec/results-view-spec.coffee
+++ spec/results-view-spec.coffee
@@ -282,9 +282,6 @@
       it "renders all results and selects the last item when core:move-to-bottom is triggered; selects the first item when core:move-to-top is triggered", ->
         expect(resultsView.find("li").length).toBeLessThan resultsView.getPathCount() + resultsView.getMatchCount()

-        expect(resultsView.prop('scrollTop')).toBe 0
-        expect(resultsView.prop('scrollHeight')).toBeGreaterThan resultsView.height()
-        previousScrollHeight = resultsView.prop('scrollHeight')
         atom.commands.dispatch resultsView.element, 'core:move-to-bottom'
         expect(resultsView.find("li").length).toBe resultsView.getPathCount() + resultsView.getMatchCount()
         expect(resultsView.find("li:eq(1)")).not.toHaveClass 'selected'


Allow to mark interrest in doing subjects

--- client/views/CalendarItem.coffee
+++ client/views/CalendarItem.coffee
@@ -18,7 +18,7 @@
 	canMarkInterrest: ->
 		user = Meteor.user()

-		return not user?.grade?[@gradeItem._id]?
+		return user?.grade?[@gradeItem._id] isnt 'done'

 	intereseted: ->
 		user = Meteor.user()


Use the value as parameter when the myName field does not exist

--- vendor/assets/javascripts/editable/rails/editable_form.js.coffee
+++ vendor/assets/javascripts/editable/rails/editable_form.js.coffee
@@ -31,6 +31,8 @@
           obj[nestedName + '_attributes'] = nested
         else if myName != ''
           obj[myName] = myValue
+        else
+          obj = myValue

         params[model] = obj


Update editable_form.js.coffee

Update editable_form.js.coffee

--- vendor/assets/javascripts/editable/rails/editable_form.js.coffee
+++ vendor/assets/javascripts/editable/rails/editable_form.js.coffee
@@ -22,11 +22,8 @@

         if nestedName
           nested          = {}
-
-          if myName
-            nested[myName]  = myValue
-          else
-            nested = myValue
+          console.log(myName)
+          nested[myName]  = myValue

           nested['id']    = nestedId


player: create $el on initialize, add defaults

--- coffee/src/player.coffee
+++ coffee/src/player.coffee
@@ -18,7 +18,14 @@
     @initialize()

+  defaults: => {}
+
+
   initialize: =>
+    @$el ?= $('<div>').addClass('acorn-player')
+    @el = @$el[0]
+
+    @options = _.defaults @options, @defaults()

     @model = @options.model ? @options.acornModel
     # TODO initialize from id or data
@@ -58,9 +65,7 @@

   render: =>
-    @$el ?= $('<div>').addClass('acorn-player')
     @$el.append @view.render().el
-    @el = @$el[0]
     @


fix the bug that when user dynamic add panes, the resizable view's previous and next pane will change.

--- src/pane-resize-handle-view.coffee
+++ src/pane-resize-handle-view.coffee
@@ -10,8 +10,6 @@

   attached: ->
     @isHorizontal = @parent().hasClass("horizontal")
-    @prevPane = @prev()
-    @nextPane = @next()

   detached: ->

@@ -23,8 +21,8 @@

   resizeToFitContent: ->
     # clear flex-grow css style of both pane
-    @prevPane.css('flexGrow', '')
-    @nextPane.css('flexGrow', '')
+    @prev().css('flexGrow', '')
+    @next().css('flexGrow', '')

   resizeStarted: (e)->
     e.stopPropagation()
@@ -39,10 +37,10 @@
     parseFloat element.css('flexGrow')

   setFlexGrow: (prevSize, nextSize) ->
-    flexGrow = @getFlexGrow(@prevPane) + @getFlexGrow(@nextPane)
+    flexGrow = @getFlexGrow(@prev()) + @getFlexGrow(@next())
     flexGrows = @calcRatio(prevSize, nextSize, flexGrow)
-    @prevPane.css('flexGrow', flexGrows[0].toString())
-    @nextPane.css('flexGrow', flexGrows[1].toString())
+    @prev().css('flexGrow', flexGrows[0].toString())
+    @next().css('flexGrow', flexGrows[1].toString())

   fixInRange: (val, minValue, maxValue) ->
     Math.min(Math.max(val, minValue), maxValue)
@@ -51,16 +49,16 @@
     return @resizeStopped() unless which is 1

     if @isHorizontal
-      totalWidth = @prevPane.outerWidth() + @nextPane.outerWidth()
+      totalWidth = @prev().outerWidth() + @next().outerWidth()
       #get the left and right width after move the resize view
-      leftWidth = @fixInRange(pageX - @prevPane.offset().left, 0, totalWidth)
+      leftWidth = @fixInRange(pageX - @prev().offset().left, 0, totalWidth)
       rightWidth = totalWidth - leftWidth
       # set the flex grow by the ratio of left width and right width
       # to change pane width
       @setFlexGrow(leftWidth, rightWidth)
     else
-      totalHeight = @prevPane.outerHeight() + @nextPane.outerHeight()
-      topHeight = @fixInRange(pageY - @prevPane.offset().top, 0, totalHeight)
+      totalHeight = @prev().outerHeight() + @next().outerHeight()
+      topHeight = @fixInRange(pageY - @prev().offset().top, 0, totalHeight)
       bottomHeight = totalHeight - topHeight
       @setFlexGrow(topHeight, bottomHeight)


first draft of computing frame on the client

--- src/math3d.coffee
+++ src/math3d.coffee
@@ -250,8 +250,7 @@

     # client code should call this when done adding objects to the scene
     finalize: ->
-        if @opts.frame?
-            @set_frame @opts.frame
+        @set_frame @opts.frame

         if @renderer_type isnt 'dynamic'
             # if we don't have the renderer, swap it in, make a static image, then give it back to whoever had it.
@@ -400,14 +399,25 @@
         @light = new THREE.PointLight color
         @light.position.set 0, d, 0

+    update_bounding_box: (obj) ->
+        if not obj.geometry.boundingBox?
+            obj.geometry.computeBoundingBox()
+        if @bounding_box?
+            @bounding_box.geometry.boundingBox.union obj.geometry.boundingBox
+        else
+            @bounding_box = new THREE.BoxHelper()
+            @bounding_box.geometry.boundingBox = obj.geometry.boundingBox.clone()
+        @bounding_box.update @bounding_box
+
     add_text: (opts) ->
         opts = defaults opts,
-            pos              : [0,0,0]
+            loc              : [0,0,0]
             text             : required
             fontsize         : 12
             fontface         : 'Arial'
             color            : "#000000"   # anything that is valid to canvas context, e.g., "rgba(249,95,95,0.7)" is also valid.
             constant_size    : true  # if true, then text is automatically resized when the camera moves;
+            in_frame         : true
             # WARNING: if constant_size, don't remove text from scene (or if you do, note that it is slightly inefficient still.)

         # make an HTML5 2d canvas on which to draw text
@@ -439,7 +449,7 @@
         sprite = new THREE.Sprite spriteMaterial

         # Move the sprite to its position
-        position = @aspect_ratio_scale opts.pos...
+        position = @aspect_ratio_scale opts.loc...
         sprite.position.set position...

         # If the text is supposed to stay constant size, add it to the list of constant size text,
@@ -451,28 +461,35 @@
                 @_text.push sprite

         # Finally add the sprite to our scene
+        if opts.in_frame
+            @update_bounding_box sprite
         @scene.add sprite

-        return sprite
-
-    add_line : (opts) ->
+    add_line: (opts) ->
         opts = defaults opts,
             points     : required
             thickness  : 1
-            color      : "#000000"
             arrow_head : false  # TODO
+            material   : required
+            in_frame   : true

         geometry = new THREE.Geometry()
         for a in opts.points
             geometry.vertices.push @vector a...
-        line = new THREE.Line geometry, new THREE.LineBasicMaterial(color:opts.color, linewidth:opts.thickness)
+
+        line = new THREE.Line geometry, new THREE.LineBasicMaterial(linewidth:opts.thickness)
+        line.material.color.setRGB opts.material.color
+
+        if opts.in_frame
+            @update_bounding_box line
         @scene.add line

     add_point: (opts) ->
         opts = defaults opts,
             loc  : [0,0,0]
             size : 5
-            color: "#000000"
+            material: required
+            in_frame: true

         if not @_points?
             @_points = []
@@ -497,7 +514,7 @@

                 context.beginPath()
                 context.arc centerX, centerY, radius, 0, 2*Math.PI, false
-                context.fillStyle = opts.color
+                context.fillStyle = rgb_to_hex opts.material.color...
                 context.fill()

                 texture = new THREE.Texture canvas
@@ -517,7 +534,7 @@
                     context.arc 0, 0, 0.5, 0, PI2, true
                     context.fill()
                 material = new THREE.SpriteCanvasMaterial
-                    color   : new THREE.Color opts.color
+                    color   : new THREE.Color opts.material.color
                     program : program
                 particle = new THREE.Sprite material
                 position = @aspect_ratio_scale opts.loc...
@@ -527,19 +544,29 @@
             else
                 throw "bug -- unkown dynamic renderer type = #{@opts.renderer}"

+        if opts.in_frame
+            @update_bounding_box particle
         @scene.add particle

-    add_index_face_set: (obj) ->
+    add_index_face_set: (opts) ->
+        opts = defaults opts,
+            vertices    : required
+            faces       : required
+            material    : required
+            wireframe   : undefined
+            in_frame    : true
+
         geometry = new THREE.Geometry()

-        for vertex in obj.vertex_geometry
-            geometry.vertices.push @vector vertices...
-
-        for points in obj.face_geometry.faces
-            a = points.shift()
-            b = points.shift()
-            while c = points.shift()
-                geometry.faces.push new THREE.Face3 a-1, b-1, c-1
+        for vector in opts.vertices
+            vector = @vector vector...
+            geometry.vertices.push vector
+
+        for vertex in opts.faces
+            a = vertex.shift()
+            b = vertex.shift()
+            while c = vertex.shift()
+                geometry.faces.push new THREE.Face3 a, b, c
                 b = c

         geometry.mergeVertices()
@@ -548,9 +575,9 @@
         #geometry.computeVertexNormals()
         geometry.computeBoundingSphere()

-        if @opts.wireframe or obj.wireframe
-            if typeof obj.wireframe is 'number'
-                line_width = obj.wireframe
+        if @opts.wireframe or opts.wireframe
+            if typeof opts.wireframe is 'number'
+                line_width = opts.wireframe
             else if typeof @opts.wireframe is 'number'
                 line_width = @opts.wireframe
             else
@@ -561,26 +588,26 @@
                 wireframeLinewidth : line_width
                 side               : THREE.DoubleSide

-            material.color.setRGB obj.color...
-        else if not obj.material?
-            console.log "BUG -- couldn't get material for ", obj
-            material = new THREE.MeshBasicMaterial
-                wireframe : false
-                color     : "#000000"
+            material.color.setRGB opts.color...
         else
             material =  new THREE.MeshPhongMaterial
                 shininess   : "1"
                 ambient     : 0x0ffff
                 wireframe   : false
-                transparent : obj.material.opacity < 1
-
-            material.color.setRGB    obj.material.color...
-            material.ambient.setRGB  obj.material.ambient...
-            material.specular.setRGB obj.material.specular...
-            material.opacity = obj.material.opacity
+                transparent : opts.material.opacity < 1
+
+            material.color.setRGB    opts.material.color...
+            material.ambient.setRGB  opts.material.ambient...
+            material.specular.setRGB opts.material.specular...
+            material.opacity = opts.material.opacity
+
+        material.side = THREE.DoubleSide

         mesh = new THREE.Mesh geometry, material
         mesh.position.set 0, 0, 0
+
+        if opts.in_frame
+            @update_bounding_box mesh
         @scene.add mesh

     # always call this after adding things to the scene to make sure track
@@ -588,25 +615,13 @@
     # actually *see* a frame.
     set_frame: (opts) ->
         opts = defaults opts,
-            xmin      : required
-            xmax      : required
-            ymin      : required
-            ymax      : required
-            zmin      : required
-            zmax      : required
             color     : @opts.foreground
             thickness : .4
             labels    : true  # whether to draw three numerical labels along each of the x, y, and z axes.
             fontsize  : 14
             draw      : true

-        eps = 0.1
-        x0 = opts.xmin
-        x1 = opts.xmax
-        y0 = opts.ymin
-        y1 = opts.ymax
-        z0 = opts.zmin
-        z1 = opts.zmax
+        ###
         if Math.abs(x1 - x0) < eps
             x1 += 1
             x0 -= 1
@@ -616,35 +631,26 @@
         if Math.abs(z1 - z0) < eps
             z1 += 1
             z0 -= 1
-
-        mx = (x0+x1)/2
-        my = (y0+y1)/2
-        mz = (z0+z1)/2
-        @_center = @vector mx, my, mz
+        ###
+
+        min = @bounding_box.geometry.boundingBox.min
+        max = @bounding_box.geometry.boundingBox.max
+        avg = min.clone().add(max).divideScalar(2)
+        dim = max.clone().sub(min)
+
+        @_center = @vector avg.x, avg.y, avg.z

         if @camera?
-            d = 1.5*Math.max @aspect_ratio_scale(x1-x0, y1-y0, z1-z0)...
-            @camera.position.set mx+d, my+d, mz+d/2
+            d = 1.5*Math.max @aspect_ratio_scale(dim.x, dim.y, dim.z)...
+            @camera.position.set avg.x+d, avg.y+d, avg.z+d/2

         if opts.draw
-            if @frame?
-                # remove existing frame
-                for x in @frame
-                    @scene.remove x
-                delete @frame
-            @frame = []
-            # trace the edges of a cube
-            v = [[[x0,y0,z0], [x1,y0,z0], [x1,y1,z0], [x0,y1,z0], [x0,y0,z0],
-                  [x0,y0,z1], [x1,y0,z1], [x1,y1,z1], [x0,y1,z1], [x0,y0,z1]],
-                 [[x1,y0,z0], [x1,y0,z1]],
-                 [[x0,y1,z0], [x0,y1,z1]],
-                 [[x1,y1,z0], [x1,y1,z1]]]
-            for points in v
-                line = @add_line
-                    points    : points
-                    color     : opts.color
-                    thickness : opts.thickness
-                @frame.push line
+            # set the color and linewidth of the bounding box
+            @bounding_box.material.color.setRGB opts.color
+            @bounding_box.material.linewidth = opts.thickness
+
+            # add the bounding box to the scene
+            @scene.add @bounding_box

         if opts.draw and opts.labels

@@ -654,75 +660,74 @@

             @_frame_labels = []

-            l = (a, b) ->
-                if not b?
-                    z = a
-                else
-                    z = (a+b)/2
-                z = z.toFixed 2
-                return (z*1).toString()
-
-            txt = (x, y, z, text) =>
+            format = (num) ->
+                Number(num.toFixed 2).toString()
+
+            add_label = (loc, text) =>
                 @_frame_labels.push(
                     @add_text
-                        pos           : [x,y,z]
+                        loc           : loc
                         text          : text
                         fontsize      : opts.fontsize
                         color         : opts.color
                         constant_size : false
+                        in_frame      : false
                     )

             offset = 0.075
-            if opts.draw
-                e = (y1 - y0)*offset
-                txt x1, y0-e, z0, l z0
-                txt x1, y0-e, mz, "z=#{l z0, z1}"
-                txt x1, y0-e, z1, l z1
-
-                e = (x1 - x0)*offset
-                txt x1+e, y0, z0, l y0
-                txt x1+e, my, z0, "y=#{l y0, y1}"
-                txt x1+e, y1, z0, l y1
-
-                e = (y1 - y0)*offset
-                txt x1, y1+e, z0, l x1
-                txt mx, y1+e, z0, "x=#{l x0, x1}"
-                txt x0, y1+e, z0, l x0
-
-        v = @vector mx, my, mz
-        @camera.lookAt v
+
+            e = (max.y - min.y)*offset
+            add_label [max.x, min.y-e, min.z], format(min.z)
+            add_label [max.x, min.y-e, avg.z], "z = #{format avg.z}"
+            add_label [max.x, min.y-e, max.z], format(max.z)
+
+            e = (max.x - min.x)*offset
+            add_label [max.x+e, min.y, min.z], format(min.y)
+            add_label [max.x+e, avg.y, min.z], "y = #{format avg.y}"
+            add_label [max.x+e, max.y, min.z], format(max.y)
+
+            e = (max.y - min.y)*offset
+            add_label [max.x, max.y+e, min.z], format(max.x)
+            add_label [avg.x, max.y+e, min.z], "x = #{format avg.x}"
+            add_label [min.x, max.y+e, min.z], format(min.x)
+
+        @camera.lookAt @_center
         if @controls?
             @controls.target = @_center
         @render_scene()

-    add_3dgraphics_obj: (opts) ->
+    add_obj: (opts) ->
         opts = defaults opts,
             obj       : required
             wireframe : undefined
             set_frame : undefined

-        for obj in opts.obj
-            switch obj.type
-                when 'text'
-                    delete obj.type
-                    @add_text obj
-                when 'index_face_set'
-                    delete obj.type
-                    if opts.wireframe?
-                        obj.wireframe = opts.wireframe
-                    @add_index_face_set obj
-                    if obj.mesh and not obj.wireframe  # draw a wireframe mesh on top of the surface we just drew.
-                        obj.material.color = [0, 0, 0]
-                        obj.wireframe = obj.mesh
-                        @add_index_face_set obj
-                when 'line'
-                    delete obj.type
-                    @add_line obj
-                when 'point'
-                    delete obj.type
-                    @add_point obj
-                else
-                    console.log "ERROR: bad object type #{obj.type}"
+        switch opts.obj.type
+            when 'group'
+                for obj in opts.obj.subobjs
+                    opts.obj = obj
+                    @add_obj opts
+            when 'text'
+                delete opts.obj.type
+                @add_text opts.obj
+            when 'index_face_set'
+                delete opts.obj.type
+                if opts.wireframe?
+                    opts.obj.wireframe = opts.wireframe
+                @add_index_face_set opts.obj
+                if opts.obj.mesh and not opts.obj.wireframe
+                    # draw a wireframe mesh on top of the surface we just drew.
+                    opts.obj.material.color = [0, 0, 0]
+                    opts.obj.wireframe = opts.obj.mesh
+                    @add_index_face_set opts.obj
+            when 'line'
+                delete opts.obj.type
+                @add_line opts.obj
+            when 'point'
+                delete opts.obj.type
+                @add_point opts.obj
+            else
+                console.log "ERROR: bad object type #{opts.obj.type}"

         if opts.set_frame?
             @set_frame opts.set_frame
@@ -839,7 +844,7 @@
         scene.opts.callback = (error, sceneobj) ->
             if not error
                 if scene.obj?
-                    sceneobj.add_3dgraphics_obj obj : scene.obj
+                    sceneobj.add_obj obj : scene.obj
                 sceneobj.finalize()
             opts.callback? error, sceneobj


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/matrix.coffee
+++ src/matrix.coffee
@@ -269,7 +269,7 @@
     return scaleMatrix

   ###*
-  Returns a matrix that corresponds to a skew of skew.
+  Returns a matrix that corresponds to a skew of skewX, skewY.
   @see Matrix#translate
   @param {Number} tx The amount to translate in the x direction.
   @param {Number} ty The amount to translate in the y direction.


Removed mock-stdin require breaking build

--- src/expand-uri-template-with-parameters.coffee
+++ src/expand-uri-template-with-parameters.coffee
@@ -19,7 +19,7 @@
     for param in expression['params']
       uriParameters.push param['name']

-  # check if all parameters have an expression in URI
+  # check if all parameters from blueprint have an expression in URI
   for parameter in Object.keys(parameters)
     if uriParameters.indexOf(parameter) == -1
       text = "\nURI template: #{uriTemplate}\nDoesn\'t contain expression for parameter" + \
@@ -34,8 +34,8 @@
     for uriParameter in uriParameters
       if Object.keys(parameters).indexOf(uriParameter) == -1
         ambigous = true
-        text = "\nAmbigous URI template: #{uriTemplate} " + \
-               "\nParameter not defined:" + \
+        text = "\nAmbigous URI parameter in template: #{uriTemplate} " + \
+               "\nParameter not defined in blueprint:" + \
                "'" + uriParameter + "'"
         result['warnings'].push text

@@ -46,8 +46,8 @@
         if param['required'] == true
           if param['example'] == undefined or param['example'] == ""
             ambigous = true
-            text = "\nAmbigous URI template: #{uriTemplate} " + \
-                   "\nNo example value for required parameter:" + \
+            text = "\nAmbigous URI parameter in template: #{uriTemplate} " + \
+                   "\nNo example value for required parameter in blueprint:" + \
                    "'" + uriParameter + "'"
             result['warnings'].push text
           else


JMachine: remove outdated setDomain

JMachine: remove outdated setDomain

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -310,39 +310,6 @@
       daisy queue

-  setDomain: permit 'set domain',
-
-    success: revive
-
-      shouldReviveClient   : yes
-      shouldReviveProvider : no
-
-    , (client, domain, callback)->
-
-      { r: { user } } = client
-
-      unless isOwner user, this
-        return callback new KodingError 'Access denied'
-
-      { nickname } = client.connection.delegate.profile
-      { userSitesDomain } = KONFIG
-
-      suffix  = "#{nickname}.#{userSitesDomain}"
-      _suffix = suffix.replace ".", "\\."
-
-      unless ///(^|\.)#{_suffix}$///.test domain
-        return callback new KodingError \
-          "Domain is invalid, it needs to be end with #{suffix}", "INVALIDDOMAIN"
-
-      JMachine.count {domain}, (err, count)=>
-
-        if err or count > 0
-          return callback new KodingError \
-            "The domain #{domain} already exists", "DUPLICATEDOMAIN"
-
-        @update $set: { domain }, (err)-> callback err
-
-
   setLabel: permit 'set domain',

     success: revive


change to asynchronous

change to asynchronous

--- Crawler/crawler.coffee
+++ Crawler/crawler.coffee
@@ -6,11 +6,9 @@
   password: ""
   database: ""
 )
-
 connection.connect()

-
-getDay = (url) ->
+getData = (url,callback,parameter = '') ->
   http.get(url, (res) ->
     buffers = []
     nread = 0
@@ -35,42 +33,24 @@
             chunk.copy buffer, pos
             pos += chunk.length
             i++
-      obj = JSON.parse buffer
-      if typeof(obj.news) != "undefined"
-        for news, i in obj.news
-          dealDay news.url,obj.news.length - i,obj.date
-        getDay "http://news-at.zhihu.com/api/2/news/before/" + obj.date
+      Json = JSON.parse buffer
+      callback Json,parameter if parameter != ''
+      callback Json if parameter == ''
   )

-dealDay = (url,index,date) ->
-  http.get(url, (res) ->
-    buffers = []
-    nread = 0
+addMysql = (storyJson) ->
+  connection.query "INSERT ignore INTO `daily` (title,share_url,id,body,date,image,image_source,date_index) VALUES (#{connection.escape(storyJson.title)},#{connection.escape(storyJson.share_url)},#{connection.escape(storyJson.id)},#{connection.escape(storyJson.body)},#{connection.escape(storyJson.date)},#{connection.escape(storyJson.image)},#{connection.escape(storyJson.image_source)},#{connection.escape(storyJson.date_index)})", (err, rows, fields) ->
+    console.log storyJson.date

-    res.on "data", (chunk) ->
-      buffers.push chunk
-      nread += chunk.length
-    res.on 'end', () ->
-      buffer = null
-      switch buffers.length
-        when 0
-          buffer = new Buffer(0)
-        when 1
-          buffer = buffers[0]
-        else
-          buffer = new Buffer(nread)
-          i = 0
-          pos = 0
-          l = buffers.length
-
-          while i < l
-            chunk = buffers[i]
-            chunk.copy buffer, pos
-            pos += chunk.length
-            i++
-      obj = JSON.parse buffer
-      connection.query "INSERT ignore INTO `daily` (title,share_url,id,body,date,image,image_source,date_index) VALUES (#{connection.escape(obj.title)},#{connection.escape(obj.share_url)},#{connection.escape(obj.id)},#{connection.escape(obj.body)},#{connection.escape(date)},#{connection.escape(obj.image)},#{connection.escape(obj.image_source)},#{connection.escape(index)})", (err, rows, fields) ->
-      console.log date
-  )
+getDay = (url) ->
+  getData url, (dayJson) ->
+    if typeof(dayJson.news) != "undefined"
+      for news, index in dayJson.news
+        getData(news.url, (storyJson,index) ->
+          storyJson.date = dayJson.date
+          storyJson.date_index = dayJson.news.length - index
+          addMysql storyJson
+        ,index)
+      getDay "http://news-at.zhihu.com/api/2/news/before/" + dayJson.date

 getDay "http://news-at.zhihu.com/api/2/news/latest"


Disabled simplification of Constants until we can make it work reasonably.

--- coffeequate/src/terminals.coffee
+++ coffeequate/src/terminals.coffee
@@ -28,7 +28,7 @@
 				@denominator *= -1
 				@numerator *= -1

-			@simplifyInPlace()
+			# @simplifyInPlace()

 		evaluate: ->
 			@numerator/@denominator
@@ -84,14 +84,14 @@

 		simplify: ->
 			constant = @copy()
-			constant.simplifyInPlace()
+			# constant.simplifyInPlace()
 			return constant

 		expand: ->
 			@copy()

 		expandAndSimplify: ->
-			@copy()
+			@simplify()

 		substituteExpression: (sourceExpression, variable, equivalencies) ->
 			[@copy()]


Prevent outcome modal from opening if outcome set (#3275)

--- angular/core/components/thread_page/thread_page_controller.coffee
+++ angular/core/components/thread_page/thread_page_controller.coffee
@@ -23,7 +23,7 @@

   @openOutcomeModal = ->
     $routeParams.outcome? and
-    AbilityService.canSetOutcomeFor(@proposal)
+    AbilityService.canCreateOutcomeFor(@proposal)

   @elementToFocus = ->
     if @proposal


BONNIE-755 Set deceased code. (#32)

BONNIE-755 Set deceased code. (#32)

* BONNIE-755 Set deceased code.

--- app/assets/javascripts/datatypes/characteristic_expired.js.coffee
+++ app/assets/javascripts/datatypes/characteristic_expired.js.coffee
@@ -19,12 +19,8 @@
   @returns {Object}
   ###
   getCode: ->
-    # NOTE: Eventually this could be replaced with actual codes. That would
-    # require modifications to the execution engine in order to handle that
-    # change.
     if @_patient.get('deathdate')?
-      code:
-        'Dead'
+      '419099009'
     else
       code:
         ''


Remove broken code in atom init

Remove broken code in atom init

--- atom/atom.symlink/init.coffee
+++ atom/atom.symlink/init.coffee
@@ -12,6 +12,3 @@
 #   editor = editorView.getEditor()
 #   if path.extname(editor.getPath()) is '.md'
 #     editor.setSoftWrap(true)
-
-atom.workspaceView.eachEditorView (editorView) ->
-    editorView.component.props.cursorBlinkPeriod = 100


Only warn when unable to resolve module deps.

--- src/module.coffee
+++ src/module.coffee
@@ -156,32 +156,37 @@
   # transform require expressions in AST to use root-relative paths
   transform: ->
     dependencies = []
-    @walkAst (node) =>
-      if node.type == 'CallExpression' and node.callee.name == 'require'
-        [required, callback] = node.arguments
-
-        if required.type == 'Literal' and typeof required.value is 'string'
-          # skip excluded modules
-          if @exclude?.test required.value
-            return true
-
-          mod = @resolver required.value,
-            basePath:   @basePath
-            extensions: @extensions
-            requiredAs: required.value
-            requiredBy: @absolutePath
-
-          # is async?
-          if mod.async = callback?
-            required.value = path.join @urlRoot, mod.requireAs
-
-          else
-            # transform node
-            required.value = mod.requireAs
-
-          # add to list of dependencies
-          dependencies.push mod
-        return true
+    try
+      @walkAst (node) =>
+        if node.type == 'CallExpression' and node.callee.name == 'require'
+          [required, callback] = node.arguments
+
+          if required.type == 'Literal' and typeof required.value is 'string'
+            # skip excluded modules
+            if @exclude?.test required.value
+              return true
+
+            mod = @resolver required.value,
+              basePath:   @basePath
+              extensions: @extensions
+              requiredAs: required.value
+              requiredBy: @absolutePath
+
+            # is async?
+            if mod.async = callback?
+              required.value = path.join @urlRoot, mod.requireAs
+
+            else
+              # transform node
+              required.value = mod.requireAs
+
+            # add to list of dependencies
+            dependencies.push mod
+          return true
+    catch err
+      # Warn if unable to resolve all dependencies, most likely this is a
+      # previously bundled js file...
+      console.warn err.toString().replace /^Error:/, 'Warning:'
     dependencies

   # traverse dependencies recursively, parsing them as well


Make sure we request capabilities, refs noflo/noflo-ui#363

--- components/ConnectRuntime.coffee
+++ components/ConnectRuntime.coffee
@@ -95,13 +95,17 @@

     rt = new Runtime definition
     rt.setParentElement @element if @element
-    rt.once 'capabilities', onCapabilities
     rt.once 'error', onError
     timeout = setTimeout onTimeout, @timeout unless definition.protocol is 'iframe'
     @outPorts.runtime.beginGroup definition.id
     @outPorts.runtime.send rt
     @outPorts.runtime.endGroup()
     @outPorts.runtime.disconnect()
+    rt.on 'connected', ->
+      rt.once 'capabilities', onCapabilities
+      setTimeout ->
+        rt.sendRuntime 'getruntime', {}
+      , 100
     rt.connect()

 exports.getComponent = -> new ConnectRuntime


spec: Make the "remote listeners" test more reliable

--- spec/api-ipc-spec.coffee
+++ spec/api-ipc-spec.coffee
@@ -89,14 +89,14 @@
       w.loadURL 'file://' + path.join(fixtures, 'api', 'send-sync-message.html')

   describe 'remote listeners', ->
+    w = null
+    afterEach ->
+      w.destroy()
+
     it 'can be added and removed correctly', ->
-      count = 0
       w = new BrowserWindow(show: false)
-      listener = () ->
-        count += 1
-        w.removeListener 'blur', listener
-      w.on 'blur', listener
-      w.emit 'blur'
-      w.emit 'blur'
-      assert.equal count, 1
-      w.destroy()
+      listener = ->
+      w.on 'test', listener
+      assert.equal w.listenerCount('test'), 1
+      w.removeListener 'test', listener
+      assert.equal w.listenerCount('test'), 0


Suggest ?sesame when no user has got opserv.setPermission

--- handlers/opserv.coffee
+++ handlers/opserv.coffee
@@ -60,13 +60,13 @@

 adminKey = null
-db.get "SELECT COUNT(*) AS count FROM user_to_permission", (err, row) ->
+db.get "SELECT COUNT(*) AS count FROM user_to_permission WHERE permission = ?", 'opserv.setPermission', (err, row) ->
 	if err?
 		winston.error "Error while checking whether permissions exist", err
 	else
 		if row.count is 0
 			crypto.randomBytes 20, (ex, buf) ->
-				console.log __("There are no permissions set. Use the following command to gain administrator privileges:")
+				console.log __("There is no user with the opserv.setPermission permission. Use the following command to receive it:")
 				adminKey = (buf.toString 'hex').substring 0, 20
 				console.log "	?sesame #{adminKey}"


Fixed superclass lookup

Fixed superclass lookup

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -388,7 +388,7 @@
       scope.boundTypeVariables)...

   isClassDefined: (name) ->
-    !!@classNamed name
+    !!@_classNamed name

   addClass: (name, classConstraint, superClasses, declarations) ->
     addToMap @_scope().classes, name,
@@ -398,6 +398,9 @@
       declarations: declarations

   classNamed: (name) ->
+    (@_classNamed name) or throw new Error "Class #{name} is not defined"
+
+  _classNamed: (name) ->
     for scope in (reverse @scopes)
       if classDeclaration = lookupInMap scope.classes, name
         return classDeclaration
@@ -2449,10 +2452,11 @@

 findSuperClassChain = (ctx, className, targetClassName) ->
   for s in (ctx.classNamed className).supers
-    if s.className is targetClassName
-      return [s.className]
-    else if chain = findSuperClassChain ctx, s, targetClassName
-      return join [s], chain
+    name = s.className
+    if name is targetClassName
+      return [name]
+    else if chain = findSuperClassChain ctx, name, targetClassName
+      return join [name], chain
   undefined

 typeNamesOfNormalized = (constraint) ->


Using the compiler to give completions on insertion points

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -310,7 +310,7 @@
     @scopes[@scopes.length - 2]

   newScope: ->
-    @scopes.push @_augmentScope newMap(), @scopeIndex++
+    @scopes.push @_augmentScope newMap(), ++@scopeIndex

   _augmentScope: (scope, index) ->
     scope.index = index
@@ -1161,7 +1161,7 @@
 ms = {}
 ms.fn = ms_fn = (ctx, call) ->
     # For now expect the curried constructor call
-    args = _validArguments call
+    args = _arguments call
     [paramList, defs...] = args
     params = paramTupleIn call, paramList
     defs ?= []
@@ -1198,7 +1198,7 @@
       compiledWheres = definitionList ctx, pairs wheres

       # log "types added"
-      #log "compiling", body
+      # log "compiling", body
       if body
         compiledBody = termCompile ctx, body
       # log "compiled", body.tea
@@ -4014,9 +4014,13 @@
 compiledModules = newMap()
 moduleGraph = newMap()

+lookupCompiledModule = (name) ->
+  lookupInMap compiledModules, name
+
+
 compileTopLevel = (source, moduleName = '@unnamed') ->
   required = newSetWith 'Prelude' # TODO: Hardcoded prelude dependency
-  if (not lookupInMap compiledModules, 'Prelude') and moduleName isnt 'Prelude'
+  if (not lookupCompiledModule 'Prelude') and moduleName isnt 'Prelude'
     request: 'Prelude'
   else
     directRequires = subtractSets required, (newSetWith moduleName)
@@ -4041,15 +4045,19 @@
       js: ''
     }
   else
-    module = lookupInMap compiledModules, moduleName
-    toInject = concatSets (collectRequiresFor moduleName), (newSetWith moduleName)
-    ctx = injectedContext toInject
+    module = lookupCompiledModule moduleName
+    {modules, ctx} = contextWithDependencies moduleName
     [expression] = _terms ast
     {js} = compileCtxAstToJs topLevelExpression, ctx, expression
     (finalizeTypes ctx, expression)
-    js: library + immutable + (listOfLines map lookupJs, setToArray toInject) + js
+    js: library + immutable + (listOfLines map lookupJs, modules) + js
     ast: ast
     errors: checkTypes ctx
+
+contextWithDependencies = (moduleName) ->
+  toInject = concatSets (collectRequiresFor moduleName), (newSetWith moduleName)
+  ctx: injectedContext toInject
+  modules: setToArray toInject

 # Primitive type checking for now
 checkTypes = (ctx) ->
@@ -4058,7 +4066,7 @@
     failed

 lookupJs = (moduleName) ->
-  js = (lookupInMap compiledModules, moduleName)?.js
+  js = (lookupCompiledModule moduleName)?.js
   if not js
     console.error "#{moduleName} not found"
   else
@@ -4069,11 +4077,12 @@
   typeNames = subtractMaps ctx._scope().typeNames, what._scope().typeNames
   classes = subtractMaps ctx._scope().classes, what._scope().classes
   macros = subtractMaps (objectToMap ctx._macros), (objectToMap what._macros)
-  {definitions, typeNames, classes, macros}
+  savedScopes = ctx.savedScopes
+  {definitions, typeNames, classes, macros, savedScopes}

 injectedContext = (modulesToInject) ->
   ctx = new Context
-  for name of values modulesToInject when compiled = lookupInMap compiledModules, name
+  for name of values modulesToInject when compiled = lookupCompiledModule name
     injectContext ctx, compiled.declared
   ctx

@@ -4106,6 +4115,21 @@
       (subtractSets requires, acc)
     concatSets collected, acc

+
+findMatchingDefinitions = (moduleName, reference) ->
+  {declared: {savedScopes}} = lookupCompiledModule moduleName
+  {ctx} = contextWithDependencies moduleName
+  {scope, type} = reference
+  return [] unless scope
+  definitions = concatMaps (while scope isnt 0
+    found = savedScopes[scope]
+    scope = found.parent
+    found.definitions)..., ctx._scope()
+  findMatchingDefinitionsOnType type, definitions
+
+findMatchingDefinitionsOnType = (type, definitions) ->
+  setToArray definitions
+
 # API

@@ -4175,6 +4199,7 @@
       expression.tea = substitute ctx.substitution, expression.tea
     return
   return
+

 # end of API

@@ -4894,6 +4919,7 @@

 exports.compileTopLevel = compileTopLevel
 exports.compileExpression = compileExpression
+exports.findMatchingDefinitions = findMatchingDefinitions
 exports.astizeList = astizeList
 exports.astizeExpression = astizeExpression
 exports.astizeExpressionWithWrapper = astizeExpressionWithWrapper


Fix color in syntaxed and dont put another colon into labels

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -125,7 +125,7 @@
   recurse: '#67B3DD'
   param: '#FDA947'
   comment: 'grey'
-  operator: '#cceeff'
+  operator: '#67B3DD'
   normal: 'white'

 colorize = (color, string) ->
@@ -554,7 +554,10 @@
 compileMap = (elems) ->
   [constr, args...] = elems
   items = args.map(compileImpl).join ', '
-  "({\"#{constr.token}\": [#{items}]})"
+  "({\"#{constructorToJsField constr}\": [#{items}]})"
+
+constructorToJsField = (constr) ->
+  constr.token[0...-1]

 compileConst = (token) ->
   "({'#{token.token}': true})"
@@ -823,12 +826,15 @@
 # Pattern matching in assignment (used in Match as well)

 patternMatchingRules = [
+  # Numbers
   (pattern) ->
     trigger: pattern.label is 'numerical'
     cond: (exp) -> ["#{exp}" + " == #{pattern.token}"]
+  # Constants
   (pattern) ->
     trigger: pattern.label is 'const'
     cond: (exp) -> ["'#{pattern.token}' in #{exp}"]
+  # Name
   (pattern) ->
     trigger: pattern.label is 'name'
     assignTo: (exp) ->
@@ -848,12 +854,14 @@
   #       [head, "#{exp}.head"]
   #       [tail, "#{exp}.tail"]
   #     ]
+
+  # Maps
   (pattern) ->
     # expect lists from here on
     if not Array.isArray pattern
       throw new Error "pattern match expected pattern but saw token #{pattern.token}"
     [constr, elems...] = inside pattern
-    label = "'#{constr.token}'" if constr
+    label = "'#{constructorToJsField constr}'" if constr
     trigger: isMap pattern
     cache: true
     cacheMore: (exp) -> if elems.length > 1 then ["#{exp}[#{label}]"] else []
@@ -863,6 +871,7 @@
       value ?= "#{exp}[#{label}]"
       recurse: (for elem, i in elems
         [elem, "#{value}[#{i}]"])
+  # Sequences
   (pattern) ->
     elems = inside pattern
     hasSplat = no
@@ -881,6 +890,7 @@
           [elem, "$sequenceSplat(#{i}, #{elems.length - i - 1}, #{exp})"]
         else
           [elem, "$sequenceAt(#{i}, #{exp})"])
+  # Tuples
   (pattern) ->
     elems = inside pattern
     trigger: isTuple pattern


Let options arg specify cookie or localStorage in constructor

--- src/kissmetrics-anon.coffee
+++ src/kissmetrics-anon.coffee
@@ -118,55 +118,6 @@
     Cookie.set key, '', {expires: -1}

-# ## Kissmetrics Storage
-# ----------------------
-
-# Wrap the `get`, `set`, and `delete` methods and abstract the differences
-# between the storage engines.  Local Storage will be used when available,
-# and browser cookies will be used as a fallback.
-#
-# ##### Arguments
-#
-# `key` (String): The key to associate with the logged out identity. This is
-#   *not* your Kissmetrics API key.
-
-class KissmetricsStorage
-
-  constructor: (@key) ->
-    @store = if window.localStorage? then LocalStorage else Cookie
-
-
-  # #### Get
-  # --------
-
-  # Retrieve the user's logged out identifier.
-
-  get: ->
-    @store.get @key
-
-
-  # #### Set
-  # --------
-
-  # Save the user's identifier.
-  #
-  # ##### Arguments
-  #
-  # `value` (String): The logged out user identity.
-
-  set: (value) ->
-    @store.set @key, value
-
-
-  # #### Delete
-  # -----------
-
-  # Delete the user's logged out identifier.
-
-  delete: ->
-    @store.delete @key
-
-
 # ## Anon Kissmetrics Client
 # --------------------------

@@ -186,11 +137,17 @@
 # ```

 class AnonKissmetricsClient extends KissmetricsClient
-  constructor: (apiKey, options = {storageKey: 'kissmetricsAnon'}) ->
-    unless @storage = options.storage
-      @storage = new KissmetricsStorage options.storageKey
+  constructor: (apiKey, options = {}) ->
+    @storage = switch options.storage
+      when 'cookie' then Cookie
+      when 'localStorage' then LocalStorage
+      when null then (if window.localStorage? then LocalStorage else Cookie)
+      else options.storage

-    @storage.set(person = @createID()) unless person = @storage.get()
+    storageKey = options.storageKey || 'kissmetricsAnon'
+
+    unless person = @storage.get storageKey
+      @storage.set(storageKey, person = @createID())

     super apiKey, person


non-zero height

non-zero height

--- src/layout/inspector.coffee
+++ src/layout/inspector.coffee
@@ -6,6 +6,7 @@

 sprite_inspector = (sprite) ->
   {
+    height: 'auto'
     _LABEL: "inspector_#{sprite.get 'name'}"
     _CHILDREN: [
       inspect_status(sprite)


added groups to stored fields

added groups to stored fields

--- packages/custom/transparency/coffee/public/controllers/flowController.coffee
+++ packages/custom/transparency/coffee/public/controllers/flowController.coffee
@@ -7,7 +7,7 @@
     #console.log "initialize dataPromise"
     dataPromise = $q.defer()
     stateName = "flowState"
-    fieldsToStore = ['slider','periods','typesText','selectedOrganisations','selectedMedia', 'allOrganisations', 'allMedia']
+    fieldsToStore = ['slider','periods','typesText','selectedOrganisations','selectedMedia', 'allOrganisations', 'allMedia', 'selectedOrganisationGroups', 'selectedMediaGroups']
     $scope.init = 'init';
     # Method for setting the intro-options (e.g. after translations)
     setIntroOptions = ->


current-user model {un,}followUser tests

--- www/test/src/model/current-user.coffee
+++ www/test/src/model/current-user.coffee
@@ -50,31 +50,62 @@
                 expect(currentUser.needsToRegister()).not.toBe true

-        describe "realms:", ->
+        describe "following", ->
             server = undefined
             beforeEach ->
                 sinon.spy mixpanel, "track"
                 server = sinon.fakeServer.create()
-                server.respondWith "POST", "/api/follow_realm/blah", [200,
-                    "Content-Type": "application/json"
-                , JSON.stringify(result: "ok")]

             afterEach ->
                 mixpanel.track.restore()
                 server.restore()

-            _.each ["follow", "unfollow"], (t) ->
-                method = t + "Realm"
-                describe method, ->
-                    it "calls mixpanel.track", ->
-                        currentUser[method] "blah"
-                        server.respond()
-                        expect(mixpanel.track.calledOnce).toBe true
-                        expect(mixpanel.track.calledWith(t + " realm")).toBe true
+            describe "realms:", ->
+                beforeEach ->
+                    server.respondWith "POST", "/api/follow_realm/blah", [200,
+                        "Content-Type": "application/json"
+                    , JSON.stringify(result: "ok")]
+                    server.respondWith "POST", "/api/unfollow_realm/blah", [200,
+                        "Content-Type": "application/json"
+                    , JSON.stringify(result: "ok")]

-                    it "posts to API", ->
-                        currentUser[method] "blah"
-                        server.respond()
-                        expect(server.requests.length).toEqual 1
-                        expect(server.requests[0].method).toEqual "POST"
-                        expect(server.requests[0].url).toEqual "/api/" + t + "_realm/blah"
+                _.each ["follow", "unfollow"], (t) ->
+                    method = t + "Realm"
+                    describe method, ->
+                        it "calls mixpanel.track", ->
+                            currentUser[method] "blah"
+                            server.respond()
+                            expect(mixpanel.track.calledOnce).toBe true
+                            expect(mixpanel.track.calledWith(t + " realm")).toBe true
+
+                        it "posts to API", ->
+                            currentUser[method] "blah"
+                            server.respond()
+                            expect(server.requests.length).toEqual 1
+                            expect(server.requests[0].method).toEqual "POST"
+                            expect(server.requests[0].url).toEqual "/api/" + t + "_realm/blah"
+
+            describe "players:", ->
+                beforeEach ->
+                    server.respondWith "POST", "/api/user/somebody/follow", [200,
+                        "Content-Type": "application/json"
+                    , JSON.stringify(result: "ok")]
+                    server.respondWith "POST", "/api/user/somebody/unfollow", [200,
+                        "Content-Type": "application/json"
+                    , JSON.stringify(result: "ok")]
+
+                _.each ["follow", "unfollow"], (t) ->
+                    method = t + "User"
+                    describe method, ->
+                        it "calls mixpanel.track", ->
+                            currentUser[method] "somebody"
+                            server.respond()
+                            expect(mixpanel.track.calledOnce).toBe true
+                            expect(mixpanel.track.calledWith(t + " user")).toBe true
+
+                        it "posts to API", ->
+                            currentUser[method] "somebody"
+                            server.respond()
+                            expect(server.requests.length).toEqual 1
+                            expect(server.requests[0].method).toEqual "POST"
+                            expect(server.requests[0].url).toEqual "/api/user/somebody/" + t


add some test for 2d unpacking validation of more complete cases


no render button

no render button

--- js/editor.coffee
+++ js/editor.coffee
@@ -36,9 +36,6 @@
         @$.elems.textarea = @textarea ".editor",
          autocomplete: "off"
          spellcheck: "false"
-        @$.elems.parse = @button ".button-primary",
-         on: {click: @$.on.parse}
-         "Render"

       @$.elems.preview = @div ".preview.seven.columns", ->
        @$.elems.errors = @div ".row.error", null
@@ -157,8 +154,8 @@
     @editor.on 'change', @on.change
     height = window.innerHeight
     console.log height
-    @editor.setSize null, "#{height - 120}px"
-    @elems.preview.style.maxHeight = "#{height - 120}px"
+    @editor.setSize null, "#{height - 100}px"
+    @elems.preview.style.maxHeight = "#{height - 50}px"
     @editor.setValue Sample

    render: ->


Add ease to transition.

Add ease to transition.

--- js/flight.coffee
+++ js/flight.coffee
@@ -77,7 +77,7 @@

       # use window timeout to delay transition or will not work on android device
       window.setTimeout =>
-        @currentPanel.style.webkitTransition = "#{@speed}"
+        @currentPanel.style.webkitTransition = "#{@speed} ease"
         @currentPanel.style.webkitTransform = "translateX(100%)"
         @targetPanel.className += " visible"
       , 10
@@ -88,14 +88,14 @@
       @targetPanel.style.webkitTransform = "translateX(200%)"

       window.setTimeout =>
-        @currentPanel.style.webkitTransition = "#{@speed}"
+        @currentPanel.style.webkitTransition = "#{@speed} ease"
         @currentPanel.style.webkitTransform = "translateX(-100%)"
       , 10

     # shortern the delay here to stop a gap appearing in android
     window.setTimeout =>

-      @targetPanel.style.webkitTransition = "#{@speed}"
+      @targetPanel.style.webkitTransition = "#{@speed} ease"
       @targetPanel.style.webkitTransform = "translateX(100%)"

       @currentPanel.addEventListener("webkitTransitionEnd", =>


Added @tvanfosson caniuse operation

Added @tvanfosson caniuse operation

--- server.coffee
+++ server.coffee
@@ -202,6 +202,11 @@
   subtitle = "- #{req.params.from}"
   dooutput(res, message, subtitle)

+app.get '/caniuse/:tool/:from', (req, res) ->
+  message = "Can you use #{req.params.tool}? Fuck no!"
+  subtitle = "- #{req.params.from}"
+  dooutput(res, message, subtitle)
+
 ###
   Additional routes should go above the catch all /:thing/ route
 ###