修复 Subview 装载顺序问题 修复 Dropdown 禁用模式下清空值按钮仍然显示的问题

--- src/core/loader.coffee
+++ src/core/loader.coffee
@@ -175,7 +175,8 @@
 	return

 _loadJs = (context, url, callback, index) ->
-	initFuncs = cola._jsCache[url]
+	# initFuncs = cola._jsCache[url]
+	initFuncs = null #TODO DELETE ME
 	if initFuncs
 		Array.prototype.push.apply(context.suspendedInitFuncs, initFuncs)
 		cola.callback(callback, true)


* Trigger change:<attribute> quem attribute is a valid relation

--- app/assets/javascripts/backbone.rails_store.js.coffee
+++ app/assets/javascripts/backbone.rails_store.js.coffee
@@ -1178,6 +1178,7 @@
           id = null
         belongsToIds["#{key}_id"] = id
         belongsToIdsCounter++
+        @trigger("change:#{key}", @)

       # Check if updating hasOne relation
       klass = _.result(@hasOne, key)
@@ -1199,6 +1200,7 @@
           @_hasOneCache[@cid] = {col: null, ids: []} unless @_hasOneCache[@cid]
           @_hasOneCache[@cid].ids.push(id)
           @_hasOneCache[@cid].col.refresh() if @_hasOneCache[@cid].col
+          @trigger("change:#{key}", @)

       # In case trying to update hasMany relation, iterate
       if @hasMany[key]
@@ -1226,6 +1228,9 @@
             unless model
               throw "Model should have been refreshed! API BUG!"

+            @trigger("change:#{key}", @)
+
+
       # In case trying to update hasAndBelongsToMany relation, iterate
       if @hasAndBelongsToMany[key]
         opts = @hasAndBelongsToMany[key]
@@ -1258,6 +1263,7 @@
             opts.subset[@cid].ids = _.uniq(opts.subset[@cid].ids.concat(model.cid))

           opts.subset[@cid].collection.refresh() if opts.subset[@cid].collection
+          @trigger("change:#{key}", @)

     if belongsToIdsCounter
       @set(belongsToIds, options)


removing propTypes

removing propTypes

--- app/classifier/tasks/drawing-task-details-editor.cjsx
+++ app/classifier/tasks/drawing-task-details-editor.cjsx
@@ -3,10 +3,6 @@

 module.exports = React.createClass
   displayName: 'DrawingTaskDetailsEditor'
-
-  propTypes:
-    project: React.PropTypes.object.isRequired
-    task: React.PropTypes.object.isRequired

   getDefaultProps: ->
     workflow: null


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color2.coffee
+++ src/color2.coffee
@@ -142,7 +142,7 @@
       other.a == @a

     grayscale: ->
-      @copy().grayscale()
+      @copy().grayscale$()

     grayscale$: ->
       hsl = @toHsl()


improve context error

improve context error

--- src/context.coffee
+++ src/context.coffee
@@ -32,7 +32,7 @@
     for host, ctx of @hosts
       servers.push host if ctx.modules.indexOf(module) isnt -1
     throw new Error "Too many hosts with module #{module}: #{servers.length}" if servers.length > 1
-    throw new Error "Expect #{qtt} host(s) for module #{module} but got #{servers.length}" if strict and servers.length isnt 1
+    throw new Error "No host found for module #{module}" if strict and servers.length is 0
     servers[0]
   hosts_with_module: (module, qtt, strict) ->
     servers = []


Added StartingPointCtrl

Added StartingPointCtrl

--- src/coffee/controllers.coffee
+++ src/coffee/controllers.coffee
@@ -13,6 +13,15 @@
     scope.$watch "showWelcome", (val) -> cookies.ShowWelcome = String val

   Controllers.controller 'IndexCtrl', ->
+
+  Controllers.controller 'StartingPointCtrl', Array '$scope', '$routeParams', 'startHistory', (scope, params, startHistory) ->
+
+    startHistory scope
+    console.log params.tool
+
+    scope.$watch 'startingPoints', (startingPoints) -> if startingPoints
+      scope.tool = L.find startingPoints, (sp) -> sp.ident is params.tool
+      console.log scope.tool

   Controllers.controller 'AboutCtrl', Array '$http', '$scope', 'startHistory', (http, scope, startHistory) ->
     http.get('/tools', {params: {capabilities: 'initial'}})


Revert "Enable debug output"

Revert "Enable debug output"

This reverts commit 186b3ed69fcffb15bb29ea4a864de7d5ff732b26.

--- src/common.coffee
+++ src/common.coffee
@@ -1,7 +1,7 @@

 # TODO: add proper option for debug
 debug = console.log
-#debug = () ->
+debug = () ->

 exports.debug = debug


A better Date->String format for us all

A better Date->String format for us all

--- lib/app.coffee
+++ lib/app.coffee
@@ -22,7 +22,7 @@
   helpers:
     comicUrl: (at) -> "/at/#{at}/"
     baseUrl: -> "http://ayp.wtf.cat" # TODO: Switch on development mode
-    xmlDate: (at) -> (new Date(parseInt(at))).toString()
+    xmlDate: (at) -> (new Date(parseInt(at))).toUTCString()

 # View, static, and LESS paths on disk
 app.set 'views', path.resolve(ROOT, 'views')


Update error messages to read good

Update error messages to read good

--- src/config.coffee
+++ src/config.coffee
@@ -646,44 +646,44 @@
   'integer':
     coercion: (keyPath, value, schema) ->
       value = parseInt(value)
-      throw new Error("Cannot set #{keyPath}, #{JSON.stringify(value)} cannot be coerced into an int") if isNaN(value) or not isFinite(value)
+      throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} cannot be coerced into an int") if isNaN(value) or not isFinite(value)
       value

   'number':
     coercion: (keyPath, value, schema) ->
       value = parseFloat(value)
-      throw new Error("Cannot set #{keyPath}, #{JSON.stringify(value)} cannot be coerced into a number") if isNaN(value) or not isFinite(value)
+      throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} cannot be coerced into a number") if isNaN(value) or not isFinite(value)
       value

   'boolean':
     coercion: (keyPath, value, schema) ->
       switch typeof value
         when 'string'
-          if value.toLowerCase() in ['true']
+          if value.toLowerCase() is 'true'
             true
-          else if value.toLowerCase() in ['false']
+          else if value.toLowerCase() is 'false'
             false
           else
-            throw new Error("Cannot coerce #{keyPath}, #{JSON.stringify(value)} must be a boolean or the string 'true' or 'false'")
+            throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be a boolean or the string 'true' or 'false'")
         when 'boolean'
           value
         else
-          throw new Error("Cannot coerce #{keyPath}, #{JSON.stringify(value)} must be a boolean or the string 'true' or 'false'")
+          throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be a boolean or the string 'true' or 'false'")

   'string':
     coercion: (keyPath, value, schema) ->
-      throw new Error("Cannot set #{keyPath}, #{JSON.stringify(value)} must be a string") if typeof value isnt 'string'
+      throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be a string") if typeof value isnt 'string'
       value

   'null':
     # null sort of isnt supported. It will just unset in this case
     coercion: (keyPath, value, schema) ->
-      throw new Error("Cannot set #{keyPath}, #{JSON.stringify(value)} must be null") unless value == null
+      throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be null") unless value == null
       value

   'object':
     coercion: (keyPath, value, schema) ->
-      throw new Error("Cannot set #{keyPath}, #{JSON.stringify(value)} must be an object") unless isPlainObject(value)
+      throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be an object") unless isPlainObject(value)
       return value unless schema.properties?

       newValue = {}
@@ -697,7 +697,7 @@

   'array':
     coercion: (keyPath, value, schema) ->
-      throw new Error("Cannot set #{keyPath}, #{JSON.stringify(value)} must be an array") unless Array.isArray(value)
+      throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be an array") unless Array.isArray(value)
       itemSchema = schema.items
       if itemSchema?
         newValue = []
@@ -727,7 +727,7 @@
         # Using `isEqual` for possibility of placing enums on array and object schemas
         return value if _.isEqual(possibleValue, value)

-      throw new Error("Cannot set #{keyPath}, #{JSON.stringify(value)} is not one of #{JSON.stringify(possibleValues)}")
+      throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} is not one of #{JSON.stringify(possibleValues)}")

 isPlainObject = (value) ->
   _.isObject(value) and not _.isArray(value) and not _.isFunction(value) and not _.isString(value)


fix value and default value object checks

--- src/config.coffee
+++ src/config.coffee
@@ -628,7 +628,7 @@

     if value?
       value = _.deepClone(value)
-      _.defaults(value, defaultValue) if isPlainObject(defaultValue) and isPlainObject(defaultValue)
+      _.defaults(value, defaultValue) if isPlainObject(value) and isPlainObject(defaultValue)
     else
       value = _.deepClone(defaultValue)


Show turtles

Show turtles

--- src/config.coffee
+++ src/config.coffee
@@ -31,8 +31,8 @@
   }
   _CHILDREN: [
     game
+    layout
     turtles
-    layout
     inspector
   ]
 }


client: remove registrations disabled cookie logic x2

--- client/app/lib/maincontroller.coffee
+++ client/app/lib/maincontroller.coffee
@@ -46,7 +46,6 @@
 KodingFluxReactor              = require './flux/base/reactor'
 DesktopNotificationsController = require './desktopnotificationscontroller'
 bowser                         = require 'bowser'
-setRegistrationCookie          = require 'app/util/setregistrationcookie'

 module.exports = class MainController extends KDController
@@ -79,9 +78,6 @@

     @detectIdleUser()
     @setTeamCookie()
-
-    # this call should be activated when we decide to switch solo product-hakan
-    # @setRegistrationClosed()

   createSingletons:->
@@ -157,11 +153,6 @@
     return no

-  setRegistrationClosed: ->
-
-    setRegistrationCookie yes  unless kookies.get 'isRegistrationClosed'
-
-
   accountChanged: (account, firstLoad = no)->

     unless account instanceof remote.api.JAccount


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera_fade.coffee
+++ src/camera_fade.coffee
@@ -40,6 +40,7 @@
   @param {Color} [color="black"] The color to fade from
   ###
   fadeIn: (options={}) ->
+    {duration, intensity} = Object.reverseMerge(options, defaultParams)
     configureFade(duration, color, 0)

   ###*


Adding visibility attribute.

Adding visibility attribute.

--- src/element.coffee
+++ src/element.coffee
@@ -19,6 +19,7 @@
     #   speed: The element's initial speed. Defaults to zero.
     #   mass: The element's mass. Defaults to 1000.
     #   dragCoefficient: The element's drag co-efficient. Defaults to 0.7.
+    #   visible: The element's visiblity status. Defaults to true.
     constructor : (opts = {}) ->
         # Set default variables if necessary.
         @x = opts.x or 0
@@ -27,6 +28,7 @@
         @mass = opts.mass or 1000
         @direction = opts.direction or new timber.Vector(0, 0)
         @dragCoefficient = if opts.dragCoefficient? then opts.dragCoefficient else 0.7
+        @visible = if opts.visible? then opts.visible else true

         # Ensure the Element class has a unique key, used for registering
         # class collision events.


Fix error not being defined in wrong describe block

--- services/web/test/unit/coffee/Collaborators/CollaboratorsInviteControllerTests.coffee
+++ services/web/test/unit/coffee/Collaborators/CollaboratorsInviteControllerTests.coffee
@@ -108,6 +108,7 @@
 			}
 			@LimitationsManager.canAddXCollaborators = sinon.stub().callsArgWith(2, null, true)
 			@CollaboratorsInviteHandler.inviteToProject = sinon.stub().callsArgWith(4, null, @invite)
+			@err = new Error('woops')
 			@callback = sinon.stub()
 			@next = sinon.stub()

@@ -163,7 +164,6 @@
 			beforeEach ->
 				@CollaboratorsInviteController._checkShouldInviteEmail = sinon.stub().callsArgWith(1, null, true)
 				@CollaboratorsInviteController._checkRateLimit = sinon.stub().yields(null, true)
-				@err = new Error('woops')
 				@LimitationsManager.canAddXCollaborators = sinon.stub().callsArgWith(2, @err)
 				@CollaboratorsInviteController.inviteToProject @req, @res, @next


removed .value when retrieving outline_line_width for tile attribution

--- bokehjs/src/coffee/renderer/tile/tile_renderer.coffee
+++ bokehjs/src/coffee/renderer/tile/tile_renderer.coffee
@@ -36,7 +36,7 @@
       if @attributionEl?
         @attributionEl.html(attribution)
       else
-        border_width = @map_plot.get('outline_line_width').value
+        border_width = @map_plot.get('outline_line_width')
         bottom_offset = @map_plot.get('min_border_bottom') + border_width
         right_offset = @map_frame.get('right') - @map_frame.get('width')
         max_width = @map_frame.get('width') - border_width


Properly empty `fixture.json` array when loading JSON fixture with `append=false`

--- src/fixture.coffee
+++ src/fixture.coffee
@@ -16,9 +16,11 @@
       filenames.push(append)
       append = false

+    @cleanup() if append is false
+
     # return created fixtures in an array
     results = []
-    for filename, index in filenames
+    for filename in filenames
       string = __html__?["#{@base}/#{filename}"] or ''

       if filename.indexOf('.json') isnt -1
@@ -28,7 +30,7 @@
           results.push json
         catch err
       else
-        results.push @_add_fixture(string, append or index > 0)
+        results.push @_add_fixture string

     results = results[0] if results.length is 1
     return results
@@ -37,15 +39,16 @@
     unless typeof(append) is 'boolean'
       strings.push(append)
       append = false
-    @_add_fixture(string, append or index > 0) for string, index in strings
+
+    @cleanup() if append is false
+
+    @_add_fixture string for string in strings

   cleanup: ->
     @json = []
     @el.innerHTML = ''

-  _add_fixture: (html_string, append = false) ->
-    @cleanup() if append is false
-
+  _add_fixture: (html_string) ->
     temp_div = document.createElement('div')
     temp_div.innerHTML = html_string


shell.spec: stylefix - camelcase

shell.spec: stylefix - camelcase

--- coffee/test/shells/shell.spec.coffee
+++ coffee/test/shells/shell.spec.coffee
@@ -10,50 +10,50 @@
     expect(Shell).toBeDefined()

   it 'should contain required properties', ->
-    required_properties = [ 'id', 'title', 'description' ]
-    _.each required_properties, (property) ->
+    requiredProperties = [ 'id', 'title', 'description' ]
+    _.each requiredProperties, (property) ->
       expect(Shell[property]).toBeDefined()
       expect(_.isString Shell[property]).toBe true

   it 'should contain required Model and View classes', ->
-    required_classes = [ 'Model', 'ContentView', 'RemixView' ]
-    _.each required_classes, (property) ->
+    requiredClasses = [ 'Model', 'ContentView', 'RemixView' ]
+    _.each requiredClasses, (property) ->
       expect(Shell[property]).toBeDefined()
       expect(_.isFunction Shell[property]).toBe true

   describe 'acorn.shells.Shell.Model class', ->

-    model_instance = new Shell.Model { a: 1, b: 2 }
+    modelInstance = new Shell.Model { a: 1, b: 2 }

     it 'should derive from Backbone.Model', ->
       expect(athena.lib.util.derives Shell.Model, Backbone.Model).toBe true

     it 'should correctly assign attributes', ->
-      expect(model_instance.get 'a').toBe 1
-      expect(model_instance.get 'b').toBe 2
+      expect(modelInstance.get 'a').toBe 1
+      expect(modelInstance.get 'b').toBe 2

     it 'should correctly support setting of attributes', ->
-      model_instance.set 'a', 2
-      model_instance.set 'b', 3
-      expect(model_instance.get 'a').toBe 2
-      expect(model_instance.get 'b').toBe 3
+      modelInstance.set 'a', 2
+      modelInstance.set 'b', 3
+      expect(modelInstance.get 'a').toBe 2
+      expect(modelInstance.get 'b').toBe 3

     it 'should throw an exception on save/sync', ->
-      expect(model_instance.save).toThrow()
-      expect(model_instance.sync).toThrow()
+      expect(modelInstance.save).toThrow()
+      expect(modelInstance.sync).toThrow()

     it 'should correctly support clone', ->
-      model_clone = model_instance.clone()
-      model_clone.set 'a', 42
-      expect(model_instance.get 'a').toBe 2
-      expect(model_clone.get 'a').toBe 42
+      modelClone = modelInstance.clone()
+      modelClone.set 'a', 42
+      expect(modelInstance.get 'a').toBe 2
+      expect(modelClone.get 'a').toBe 42

   describe 'acorn.shells.Shell.Model factory constructors', ->

     it 'should correctly construct a model from data', ->
-      model_instance = Shell.Model.withData { id: 'acorn.Shell' }
-      expect(model_instance).toBeDefined()
-      expect(model_instance.get 'id').toBe 'acorn.Shell'
+      modelInstance = Shell.Model.withData { id: 'acorn.Shell' }
+      expect(modelInstance).toBeDefined()
+      expect(modelInstance.get 'id').toBe 'acorn.Shell'

     it 'should throw an error on attempts to construct unregistered shells', ->
       fn = -> Shell.Model.withData { id: 'foobar' }


Activity: sidebar realtime fixes for messages' and topics' sidebar

--- client/Social/Activity/sidebar/activitysidebar.coffee
+++ client/Social/Activity/sidebar/activitysidebar.coffee
@@ -36,6 +36,7 @@

   #   return sanitized.reverse()

+  revive = (obj) -> KD.singletons.socialapi.mapChannels(obj).first

   constructor: ->

@@ -51,19 +52,28 @@

     notificationController.on 'AddedToChannel', (channel) =>

-      [topic] = socialapi.mapChannels channel
-
-      @sections.followedTopics.listController.addItem topic
+      revived        = revive channel
+      listController = @getListController revived.typeConstant
+
+      listController.addItem revived

     notificationController.on 'RemovedFromChannel', (channel) =>

-      {listController} = @sections.followedTopics
-
-      [topic] = socialapi.mapChannels channel
-      item    = listController.itemsIndexed[topic.id]
-
+      revived        = revive channel
+      listController = @getListController revived.typeConstant
+      item           = listController.itemsIndexed[revived.id]
       listController.removeItem item
+
+
+  getListController: (type) ->
+
+    section = switch type
+      when 'topic'          then @sections.followedTopics
+      when 'privatemessage' then @sections.messages
+      else {}
+
+    return section.listController

   # fixme:


sidebar: add default value to callback param

--- client/Social/Activity/sidebar/activitysidebar.coffee
+++ client/Social/Activity/sidebar/activitysidebar.coffee
@@ -403,7 +403,7 @@
   workspacesFetched  = no
   fetchingWorkspaces = no

-  fetchWorkspaces: do (callbackQueue = []) -> (callback) ->
+  fetchWorkspaces: do (callbackQueue = []) -> (callback = noop) ->

     activitySidebar = this


Activity: minor code style

Activity: minor code style

--- client/Social/Activity/sidebar/activitysidebar.coffee
+++ client/Social/Activity/sidebar/activitysidebar.coffee
@@ -16,8 +16,8 @@
   revive = (data) ->

     return switch data.typeConstant
-      when 'post' then (KD.singleton 'socialapi').message.revive message: data
-      when 'topic' then (KD.singleton 'socialapi').mapChannel data
+      when 'post' then KD.singletons.socialapi.message.revive message: data
+      when 'topic' then KD.singletons.socialapi.mapChannel data
       else data


groups: added select box to form builder, soon to come: radio, checkbox and text area. style adjustments for the data collection views

--- components/inputs/KDSelectBox.coffee
+++ components/inputs/KDSelectBox.coffee
@@ -7,7 +7,7 @@
     options = $.extend
       type     : "select"       # mandatory
       cssClass : ""
-    ,options
+    ,options
     super options

   setDomElement:(cssClass)->
@@ -32,7 +32,7 @@
       @handleEvent event
     super

-  setDefaultValue:(value)->
+  setDefaultValue:(value)->
     @getDomElement().val value if value isnt ""
     @_$select.val value
     @_$title.text @_$select.find("option[value=\"#{value}\"]").text()
@@ -40,7 +40,7 @@
   getDefaultValue:()-> @inputDefaultValue

   getValue:()-> @_$select.val()
-  setValue:(value)->
+  setValue:(value)->
     @_$select.val value
     @change()

@@ -64,12 +64,15 @@
         @_$select.append "<option value='#{option.value}'>#{option.title}</option>"
     else
       warn "no valid options specified for the input:", @
-
+
     @_$select.val @getDefaultValue()

     value = @getDefaultValue() + "" # casting number to string
     # escapedDefault = value.replace /\//g, '\\/'
     @_$title.text @_$select.find("option[value=\"#{value}\"]").text()
+
+  removeSelectOptions:->
+    @_$select.find("option").remove()

   change:->
     @_$title.text @_$select.find("option[value=\"#{@getValue()}\"]").text()


Une native backbone events

Une native backbone events

--- src/client/auth.coffee
+++ src/client/auth.coffee
@@ -50,8 +50,7 @@
       dfd = isAuthenticating
       try
         me = app.sandbox.data.api.model('me')
-        dfd.done -> me.trigger('change')
-        me.fetch(silent: true).then(dfd.resolve, dfd.reject)
+        me.fetch().then(dfd.resolve, dfd.reject)
       catch err
         console.error "Error on auth promise resolution", err
       finally


version = dev

version = dev

--- src/coffeetable.coffee
+++ src/coffeetable.coffee
@@ -1,6 +1,6 @@
 ###

-# CoffeeTable v0.2.0
+# CoffeeTable vDEV

 A drop-in, CoffeeScript-fluent console for web pages.


Simplify wording a bit more, don't show job IDs

--- src/deploy.coffee
+++ src/deploy.coffee
@@ -20,7 +20,8 @@
     job.on('success', () ->
       chat.send "Pending changes for #{@app} #{@env}:\n#{@data.stdout}"
     ).on('error', (error)->
-      chat.send "#{@} failed due to #{JSON.stringify(error)}"
+      chat.send "Pending changes failed: #{JSON.stringify(error)}"
+      chat.send "More info: #{@data.url}"
     )
     pulsarApi.runJob(job)

@@ -36,9 +37,9 @@
     deployJob = pulsarApi.createJob(app, env, 'deploy')
     deploymentMonitor.setDeployJob(deployJob, chat)
     deployJob.on('create', () ->
-      chat.send "Deployment started.\nMore info: #{@data.url}"
+      chat.send "Deployment started: #{@data.url}"
     ).on('success', () ->
-      chat.send "#{@} finished."
+      chat.send "Deployment finished."
     ).on('error', (error) ->
       chat.send "Deployment failed: #{JSON.stringify(error)}"
     )
@@ -56,7 +57,7 @@
     showNextRevisionJob = pulsarApi.createJob(app, env, 'deploy:show_next_revision')
     showNextRevisionJob.on('success', ()->
       if(!@data.stdout || !@data.stdout.trim())
-        @.emit('error', new Error("#{@} does not have a revision number."))
+        @.emit('error', new Error("Cannot retrieve revision number."))
         return
       revision = @data.stdout.trim()
       pendingJob.taskVariables = revision: revision


Fix issue when checking the branch you are on

--- src/deploy.coffee
+++ src/deploy.coffee
@@ -82,7 +82,7 @@

 	# Check if the branch you are working on can be deployed to that server
 	checkBranch: ->
-		@setupGit() unless @config.branch
+		return @setupGit() unless @config.branch

 		@config.branch = [@config.branch] if typeof @config.branch is "string"


repository: implement getForks

repository: implement getForks

--- src/octonode/repository.coffee
+++ src/octonode/repository.coffee
@@ -56,5 +56,10 @@
   getIssues: (cb) ->
     @_invokeGet "/repos/#{@name}/issues",200,"getIssues",cb

+  # Get the forks for a repository
+  # '/repos/pkumar/hub/forks' GET
+  getForks: (cb) ->
+    @_invokeGet "/repos/#{@name}/forks",200,"getForks",cb
+
 # Export module
 module.exports = Repository


Exit correctly.

Exit correctly.

--- src/helpers.coffee
+++ src/helpers.coffee
@@ -46,7 +46,7 @@
     {config} = require sysPath.resolve configPath
   catch error
     logger.error "couldn\'t load config.coffee. #{error}"
-    exports.exit()
+    process.exit 1
   config

 exports.loadPlugins = (config, callback) ->


:memo: fix return doc

:memo: fix return doc

--- src/editor.coffee
+++ src/editor.coffee
@@ -643,7 +643,8 @@
   # text - A {String} representing the text to insert.
   # options - See {Selection::insertText}.
   #
-  # Returns a {Boolean} indicating whether or not the text was inserted.
+  # Returns a {Range} when the text has been inserted
+  # Returns a {Bool} false when the text has not been inserted
   insertText: (text, options={}) ->
     willInsert = true
     cancel = -> willInsert = false


Fixing indent issue, surprised this didn't come up sooner

--- src/entity.coffee
+++ src/entity.coffee
@@ -12,36 +12,39 @@
 #       constructor: (opts={}) ->
 #         super(opts)
 #         # custom code here ...
-
-
-  # A superconstructor initializing some basic fields.
-  # Game object constructors should call this. For example:
-  #
-  #     class Enemy extends Kona.Entity
-  #       constructor: (opts={}) ->
-  #         super(opts)
-  #         @isEvil = true
-  #
-  # Options:
-  #
-  #   * __group__ - (String) The group this entity belongs to, ex: `'enemies'`
-  #   * __solid__ - (Boolean) Whether or not this entity is solid, e.g., can this collide with other entities. Default: true.
-  #   * __gravity__ - (Boolean) Whether or not this entity is subject to gravity. Default: true
-  #   * __speed__ - (Integer) The speed of this entity when moving.
-  #   * __facing__ - (String) The direction this entity is facing. Possible values: `'left'` or `'right'`
-  #   * __position__ - (Object)
-  #     * x: integer x-coordinate on the canvas
-  #     * y: integer y-coordinate on the canvas
-  #   * __direction__ - (Object) Values representing the current direction of the entity.
-  #     * dx: `-1 = left, 1 = right, 0 = stationary`
-  #     * dy: `-1 = up, 1 = down, 0 = stationary`
-  #   * __box__ - (Object) Values representing the dimensions of the entity. Collisions
-  #     are resolved in terms of a rectangular box model.
-  #     * width: An integer width, in pixels
-  #     * height: An integer height, in pixels
-  #   * __sprite__ - (Type)
-  #
- class Kona.Entity
+#
+
+
+# A superconstructor initializing some basic fields.
+# Game object constructors should call this. For example:
+#
+#     class Enemy extends Kona.Entity
+#       constructor: (opts={}) ->
+#         super(opts)
+#         @isEvil = true
+#
+# Options:
+#
+#   * __group__ - (String) The group this entity belongs to, ex: `'enemies'`
+#   * __solid__ - (Boolean) Whether or not this entity is solid, e.g., can this collide with other entities. Default: true.
+#   * __gravity__ - (Boolean) Whether or not this entity is subject to gravity. Default: true
+#   * __speed__ - (Integer) The speed of this entity when moving.
+#   * __facing__ - (String) The direction this entity is facing. Possible values: `'left'` or `'right'`
+#   * __position__ - (Object)
+#     * x: integer x-coordinate on the canvas
+#     * y: integer y-coordinate on the canvas
+#   * __direction__ - (Object) Values representing the current direction of the entity.
+#     * dx: `-1 = left, 1 = right, 0 = stationary`
+#     * dy: `-1 = up, 1 = down, 0 = stationary`
+#   * __box__ - (Object) Values representing the dimensions of the entity. Collisions
+#     are resolved in terms of a rectangular box model.
+#     * width: An integer width, in pixels
+#     * height: An integer height, in pixels
+#   * __sprite__ - (Type)
+#
+class Kona.Entity
+
+  # Class methods
   @grav = 8

   @loadAnimations = (group, animations) ->
@@ -54,6 +57,7 @@
           ent.loadAnimations(animations) if ent instanceof @

+  # Instance methods
   constructor: (opts={}) ->
     @group   = opts.group or fail ("entity must have a group")
     @solid   = if opts.solid?   then opts.solid   else true


a little more space between navigation and products.

--- public/views/widget_view.coffee
+++ public/views/widget_view.coffee
@@ -13,6 +13,9 @@

Loading ...


Add more control on return

Add more control on return

--- src/filter.coffee
+++ src/filter.coffee
@@ -8,17 +8,19 @@
 request = require 'request'

 makeRequest = (validate, beautify, fn) ->
-  req = request.post params, (error, response, body) ->
+  stream = request.post params, (error, response, body) ->
     fn error, false if error

-  req.on 'end', () ->
-    req = makeRequest validate, beautify, fn
+  stream.on 'end', ->
+    makeRequest validate, beautify, fn
+    return

-  req.on 'data', (buffer) ->
+  stream.on 'data', (buffer) ->
     try
       tweet = JSON.parse buffer.toString()
-      if tweet.disconnect
-        req = makeRequest validate, beautify, fn
+      if tweet and tweet.disconnect
+        makeRequest validate, beautify, fn
+        return
     catch error
       tweet = false

@@ -26,12 +28,12 @@
       tweet = beautify tweet, false if beautify

       fn null, tweet
-
-  req
-
+      return
+  return

 module.exports = (options) ->
   params = params options

   (validate, beautify, fn) ->
-    req = makeRequest validate, beautify, fn
+    makeRequest validate, beautify, fn
+    return


router: remove application specific code

--- src/core/router.coffee
+++ src/core/router.coffee
@@ -112,7 +112,6 @@
     @addRoute route, listener  for own route, listener of routes

   handleRoute:(userRoute, options={})->
-    return @handleRoute '/Activity'  if /<|>/.test userRoute
     userRoute = userRoute.slice 1  if (userRoute.indexOf '!') is 0
     @visitedRoutes.push userRoute  if @visitedRoutes.last isnt userRoute


Using crazy new include lookup for non-string modules

--- src/core_object.coffee
+++ src/core_object.coffee
@@ -172,7 +172,7 @@
         self[name](args...)

     # Initial module inclue, for reconstructing objects from JSON
-    for moduleName of
+    for moduleName is

     return self
 )()


Using default args in Core constructor

Using default args in Core constructor

--- src/core_object.coffee
+++ src/core_object.coffee
@@ -9,9 +9,7 @@
 @param {Object} I Instance variables
 ###

-Core = (I) ->
-  I ||= {}
-
+Core = (I={}) ->
   self =
     ###*
     External access to instance variables. Use of this property should be avoided


Web renderer now uses graphics-ascii too

--- src/io/web.coffee
+++ src/io/web.coffee
@@ -2,6 +2,8 @@

 log = require '../log'
 vectorMath = require '../vector-math'
+
+graphics = require './graphics-ascii'

 viewport = null

@@ -126,12 +128,25 @@
 		map = @game.currentMap
 		center = vectorMath.add playerScreenPos, {x: 6, y: 6}
 		@camera = vectorMath.sub center, vectorMath.div canvasSize, 2
+		@camera.target = @game.player.creature

 		log 'Hello world! Render time!'

+		mapSymbols =
+			'#': graphics.get 'wall'
+			'.': graphics.get 'floor'
+
+		graphicAt = (x, y) =>
+			if @camera.target.canSee {x, y}
+				t = map.data[y][x]
+				mapSymbols[t]
+
+			else ' '
+
 		for cx in [0...map.w]
 			for cy in [0...map.h]
-				@renderSymbolAtSlot cx, cy, map.data[cy][cx]
+				graphic = graphicAt cx, cy
+				@renderGraphicAtSlot cx, cy, graphic

 		entityLayer =
 			'creature': 3
@@ -146,10 +161,16 @@
 		log 'Done rendering!!'

 	renderEntities: (x, y, entities) ->
-		# c = @game.camera
+		for e in entities when @camera.target.canSee e
+
+			graphic = graphics.get _.result e, 'symbol'
+			@renderGraphicAtSlot e.x, e.y, graphic

-		for e in entities
-			@renderSymbolAtSlot e.x, e.y, (_.result e, 'symbol')
+	renderGraphicAtSlot: (x, y, graphic) ->
+		if _.isString graphic
+			graphic = symbol: graphic
+
+		@renderSymbolAtSlot x, y, graphic.symbol, graphic.color

 	renderSymbolAtSlot: (x, y, symbol, color) ->
 		c = @camera


Change software copyleft question wording to be closer of data share-alike question.

--- src/definitions.coffee
+++ src/definitions.coffee
@@ -420,7 +420,7 @@
     @answer 'Next', nextAction, (state) -> !_.any state.options, (option) -> option.selected

   Copyleft: ->
-    @question 'Do you want others who modify your code to be forced to also release it under open source license?'
+    @question 'Do you require others who modify your code to release it under a compatible licence?'
     @yes ->
       @include 'copyleft'
       if @has('weak') and @has('strong')


Add method to generate UUID from javascript

--- src/static/guid-convert.coffee
+++ src/static/guid-convert.coffee
@@ -15,6 +15,13 @@
             GuidTool.query $('#guid').val()
             $('#guid').val('').focus()

+    # RFC 4122 Section 4.4 GUID generation from pseudo-random numbers
+    @generate: =>
+        'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace /[xy]/g, (c) =>
+            r = Math.random() * 16 | 0
+            v = if c is 'x' then r else r & 0x3 | 0x8
+            return v.toString 16
+
     # Query the server for a given GUID
     @query: (guid) =>
         $.ajax


Make IP objects easier to identify

Make IP objects easier to identify

--- src/lib/IP.coffee
+++ src/lib/IP.coffee
@@ -16,6 +16,7 @@
     @owner = null # packet owner process
     @clonable = false # cloning safety flag
     @index = null # addressable port index
+    @isIP = true
     for key, val of options
       this[key] = val


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/game_object.coffee
+++ src/game_object.coffee
@@ -41,7 +41,7 @@

   self = Core(I).extend
     ###*
-    Destroys the object and triggers the destroyed callback.
+    Update the game object. This is generally called by the engine.

     @name update
     @methodOf GameObject#


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -129,7 +129,7 @@
   @param {Object} options The meter configuration options
     borderColor - The color of the meter's border
     borderWidth - The width of the meter's border
-
+    co
   ###
   meter: (options={}) ->
     Object.reverseMerge options,


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -122,7 +122,7 @@
   @param {Number} borderWidth Width of the meter's border
   @param {String} color Color of the meter's inner rectangle
   @param {String} nameColor Color of the property name displayed above the meter
-    font - Size and style of the meter's font
+  @param {String} font - Size and style of the meter's font
     height - Height of the meter
     position - An x, y object representing the position of the meter
     radius - Border radius of the meter


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -109,7 +109,7 @@
   player.meter
     borderColor: 'brown'
     color: 'pink'
-    font: '30'
+    font: '30px Com'
     name: 'health'
     position:
       x: 5


got String#format to work!

got String#format to work!

the Strings test still fails on String#valueOf, though…

--- src/methods.coffee
+++ src/methods.coffee
@@ -73,6 +73,9 @@
             rs.push (oref = rs.init_object(classname))
             rs.method_lookup({'class':classname,'sig':{'name':'<init>'}}).run(rs)
             rs.push oref
+        o 'forName(L!/!/String;)L!/!/!;', (rs) -> #again, to avoid reflection
+            classname = rs.jvm2js_str rs.get_obj(rs.curr_frame().locals[0])
+            rs.push rs.init_object 'java/lang/Class', { name:classname }
       ]
       System: [
         o 'setJavaLangAccess()V', (rs) -> # NOP
@@ -104,14 +107,14 @@
             o 'compareAndSetState(II)Z', (rs) -> rs.push 1 # always true
             o 'release(I)Z', (rs) -> rs.push 1 # always true
           ]
+      Currency: [
+        o '<clinit>()V', (rs) -> #NOP, because it uses lots of reflection and we don't need it
+      ]
       ResourceBundle: [
-        o 'getBundle(Ljava/lang/String;Ljava/util/Locale;Ljava/util/ResourceBundle$Control;)Ljava/util/ResourceBundle;', (rs) ->
-            # load in the right ResourceBundle based on the locale
+        o 'getBundle(L!/lang/String;L!/!/Locale;L!/!/ResourceBundle$Control;)L!/!/!;', (rs) ->
+            # load in the default ResourceBundle (ignores locale)
             args = rs.curr_frame().locals
-            base = rs.jvm2js_str(rs.get_obj(args[0]))
-            locale = rs.get_obj(args[1])
-            lang = rs.jvm2js_str(rs.get_obj(locale.fields.language))
-            classname = util.int_classname "#{base}_#{lang}"
+            classname = util.int_classname rs.jvm2js_str(rs.get_obj(args[0]))
             rs.push (b_ref = rs.init_object classname)
             rs.method_lookup({class: classname, sig: {name:'<init>',type:'()V'}}).run(rs)
             rs.push b_ref
@@ -146,7 +149,7 @@
       ]
     util:
       LocaleServiceProviderPool: [
-        o 'getPool(Ljava/lang/Class;)Lsun/util/LocaleServiceProviderPool;', (rs) ->
+        o 'getPool(Ljava/lang/Class;)L!/!/!;', (rs) ->
             # make a mock
             rs.push rs.init_object 'sun/util/LocaleServiceProviderPool'
         o 'hasProviders()Z', (rs) -> rs.push 0  # false, we can't provide anything


Removed debug line.

Removed debug line.

--- src/imagemagick.coffee
+++ src/imagemagick.coffee
@@ -894,7 +894,6 @@
     @

   run: (callback) =>
-    return "convert #{@arguments.join ' '}"
     ChildProcess.exec "convert #{@arguments.join ' '}", (error, stderr, stdout) =>
       if callback
         callback error, stdout, stderr


ADded newline

ADded newline

--- core/app/backbone/collections/suggested_topics.coffee
+++ core/app/backbone/collections/suggested_topics.coffee
@@ -1,4 +1,4 @@
 class window.SuggestedTopics extends Backbone.Collection
 	model: Topic

-	url: -> '/t/top'+	url: -> '/t/top'


Refactored react code

Refactored react code

--- core/app/backbone/views/evidence/react_comment.coffee
+++ core/app/backbone/views/evidence/react_comment.coffee
@@ -10,22 +10,17 @@
       else 'comment-unsure'

   render: ->
-    R.div className: 'comment-post-heading',
-      R.span className: @_typeCss()
-      R.span className:"comment-post-creator-avatar",
-        R.img
-          src: @model().creator().avatar_url(32)
-          className:"avatar-image"
-      R.span className:"comment-post-creator",
-        R.a
-          href: @model().creator().link()
-          className:"comment-post-creator-name"
-          rel: "backbone"
+    _div ['comment-post-heading'],
+      _span [@_typeCss()]
+      _span ["comment-post-creator-avatar"],
+        _img [src: @model().creator().avatar_url(32), "avatar-image"]
+      _span ["comment-post-creator"],
+        _a [href: @model().creator().link(), "comment-post-creator-name", rel: "backbone"]
           @model().creator().get('name')
-        R.span className:"comment-bottom-action comment-post-time",
-            @model().get('time_ago')
-            " "
-            Factlink.Global.t.ago
+        _span ["comment-bottom-action comment-post-time"],
+          @model().get('time_ago')
+          " "
+          Factlink.Global.t.ago

 window.ReactComment = React.createBackboneClass
   displayName: 'ReactComment'
@@ -41,26 +36,21 @@
     @setState show_subcomments: !@state.show_subcomments

   _content: ->
-    R.div
-      className:"comment-content spec-comment-content",
+    _div ["comment-content spec-comment-content"],
       dangerouslySetInnerHTML: {__html: @model().get('formatted_comment_content')}

   _bottom: ->
     sub_comment_count = @model().get('sub_comments_count')

-    R.div className: 'comment-post-bottom',
-      R.ul className: "comment-bottom-actions", [
+    _div ['comment-post-bottom'],
+      _ul ["comment-bottom-actions"], [
         if @model().can_destroy()
-          R.li className: "comment-bottom-action comment-bottom-action-delete",
+          _li ["comment-bottom-action comment-bottom-action-delete"],
             ReactDeleteButton
               model: @model()
               onDelete: @_onDelete
-        R.li className:"comment-reply",
-          R.a
-            className:"spec-sub-comments-link"
-            href:"javascript:"
-            onClick: @_toggleSubcomments
-
+        _li ["comment-reply"],
+          _a ["spec-sub-comments-link", href:"javascript:", onClick: @_toggleSubcomments]
             "(#{sub_comment_count}) Comment"
       ]
       if @state.show_subcomments
@@ -74,11 +64,11 @@
       'comment-irrelevant' unless relevant
     ].join(' ')

-    R.div className: top_classes,
-      R.div className:"comment-container spec-evidence-box",
-        R.div className: "comment-votes-container",
+    _div [top_classes],
+      _div ["comment-container spec-evidence-box"],
+        _div ["comment-votes-container"],
           ReactEvidenceVote model: @model().argumentTally()
-        R.div className: "comment-content-container",
+        _div ["comment-content-container"],
           ReactCommentHeading(model: @model())
           @_content()
           @_bottom()


removed unneeded log statements

removed unneeded log statements

--- app/coffee/dreamfield.coffee
+++ app/coffee/dreamfield.coffee
@@ -10,9 +10,6 @@
     @entryCount = $('.entryCount').data('id')
     @pageSize = $('.pageSize').data('id')
     @totalPages = Math.ceil @entryCount / @pageSize
-    log('entryCount:' + @entryCount)
-    log('pageSize: ' + @pageSize)
-    log('totalPages: ' + @totalPages)
     @dreamfield = dreamfieldModel
     @$container = $('#pagination')


finalizing join and login fix

finalizing join and login fix

--- app/coffee/loginpanel.coffee
+++ app/coffee/loginpanel.coffee
@@ -17,10 +17,10 @@
     $('.joinWrap a').click (event) ->
       event.preventDefault()

-      $(this).find('.join').hide()
-      $(this).find('.joinButton').show()
-      $(this).parent().find('.intro').slideUp()
-      $(this).parent().find('.joinForm').slideDown()
+      $(this).parent().find('.join').hide()
+      $(this).parent().find('.joinButton').show()
+      $(this).parent().parent().find('.intro').slideUp()
+      $(this).parent().parent().find('.joinForm').slideDown()

       $('.haveSeedcode').click =>
         $('.haveSeedcode').slideUp('fast')


adds message in case of not connected and cleans code up

--- src/ui/views/controller.coffee
+++ src/ui/views/controller.coffee
@@ -15,20 +15,26 @@
         # draw view
         conninfo connection

+        startupConnEl = document.querySelector('.state_connecting')
+        startupLoadEl = document.querySelector('.state_contacts')
         # place in layout
         if connection.state == connection.CONNECTED
             el?.hide?()
-            document.querySelector('.state_connecting').classList.add("hide")
-            document.querySelector('.state_contacts').classList.remove("hide")
+            startupConnEl.classList.add("hide")
+            startupLoadEl.classList.remove("hide")
             el = null
         else
-            document.querySelector('.state_connecting').innerHTML = connection.infoText().replace('…','')
+            startupConnEl.innerHTML = connection.infoText()
+                # replace three dots
+                .replace '…',''
+                # add check connection to "Not Connected"
+                .replace /(Not connected)/,
+                         '$1 (check connection)'
             if document.querySelector('.connecting.hide')?
                 el = notr {html:conninfo.el.innerHTML, stay:0, id:'conn'}
             else
-                document.querySelector('.state_connecting').classList.remove("hide")
-                document.querySelector('.state_contacts').classList.add("hide")
-
+                startupConnEl.classList.remove("hide")
+                startupLoadEl.classList.add("hide")

 setLeftSize = (left) ->
     document.querySelector('.left').style.width = left + 'px'


formats code

formats code

--- Upcoming-iCal-Events.widget/main.coffee
+++ Upcoming-iCal-Events.widget/main.coffee
@@ -2,12 +2,17 @@
 # Last Modified: 22/03/18

 # Customisations
+# Refresh Frequency
+REFRESH_FREQUENCY = "1h"
 # Number of days shown from today.
-NO_DAYS_TO_SHOW = 30
+NO_DAYS_TO_SHOW = 2
 # Show which calendar you pulled from before event name.
 SHOW_CALENDER = false
 # Ignore specific calendars.
-IGNORE_CALENDER = [ 'name/UUID of calendar to ignore', 'other calendar etc' ]
+IGNORE_CALENDERS = [
+    'name/UUID of thecalendar to ignore',
+    'other calendar etc'
+]
 # Show full date including time.
 SHOW_DATE_TIME = true
 # Characters after this value will be replaced with ...
@@ -17,18 +22,18 @@

 # Construct bash command using options.
 # icalBuddy has more functionality that can be used here.
-# Refer to https://hasseg.org/icalBuddy/man.html for reference.
+# Refer to https://hasseg.org/icalBuddy/man.html
 executablePath = "/usr/local/bin/icalBuddy "
 baseCommand = ' eventsToday' + '+' + NO_DAYS_TO_SHOW
 options = "-n -eed -tf '%I:%M %p' "
-if IGNORE_CALENDER
-    options = options + '-ec ' + IGNORE_CALENDER.join(',')
+if IGNORE_CALENDERS
+    options = options + '-ec ' + IGNORE_CALENDERS.join(',')

 # Bash command to pull events from icalBuddy
 command: executablePath + options + baseCommand

 # Update is called once per hour
-refreshFrequency: "1h"
+refreshFrequency: REFRESH_FREQUENCY

 # CSS styling
 style: """
@@ -73,9 +78,11 @@
     dom.append("""<div id="head"> Upcoming Events </div>""")

     # Filter out all lines that aren't event headers or dates
-    lines = lines.filter (x) -> ( ( x.startsWith(bullet) ) ||
+    lines = lines.filter (x) -> (
+      ( x.startsWith(bullet) ) ||
       ( x.search('(today|tomorrow)') != -1  ) ||
-      ( x.search('\\d{2}-[a-zA-Z]{3}-\\d{4}') != -1  ))
+      ( x.search('\\d{2}-[a-zA-Z]{3}-\\d{4}') != -1  )
+    )

     #Add No Events tag if nothing upcoming
     if ( lines.length == 0 )
@@ -124,9 +131,6 @@
             if nameAndCalendar[1] != undefined
                 calendar = nameAndCalendar[1].replace(')','')

-            if IGNORE_CALENDER.includes(calendar)
-                continue
-
             if ( name.length > MAX_CHARACTERS )
                 name = name.substr(0, MAX_CHARACTERS) + "..."

@@ -136,9 +140,9 @@

             # Combine all fields
             final = name
-            if (SHOW_DATE_TIME)
+            if SHOW_DATE_TIME
                 final = datePrefix + date + " - " + final
-            if (SHOW_CALENDER)
+            if SHOW_CALENDER
                 final = calendar + " - " + final

             # Add this HTML to previous


Attempted to get linger mode to work

Attempted to get linger mode to work

--- lib/esl.coffee
+++ lib/esl.coffee
@@ -397,8 +397,18 @@
       if exports.debug
         util.log "Received ESL disconnection notice"
       switch call.headers['Content-Disposition']
-        when 'linger'      then @exit()
+        when 'linger'      then @socket.emit 'esl_linger', call
         when 'disconnect'  then @end()
+    #### Linger
+    # The default behavior in linger mode is to disconnect the call
+    # (which is roughly equivalent to not using linger mode).
+    @on 'esl_linger', => @exit()
+    # Use
+    #     call.register_callback("esl_linger",...)
+    # to capture the end of the call. In this case you are responsible
+    # for calling
+    #     call.exit()
+    # If you do not do it, the calls will leak.

 #### Connection Listener (socket events handler)
 # This is modelled after Node.js' http.js


Resolves issue with zencash P2SH transactions

--- app/src/dongle/dongle.coffee
+++ app/src/dongle/dongle.coffee
@@ -705,7 +705,7 @@
         if p2pkhNetworkVersionSize is 1
           return P2shScript(hash160) if hash160WithNetwork.byteAt(0) is ledger.config.network.version.P2SH
         else
-          return P2shScript(hash160) if (hash160WithNetwork.byteAt(0) << 8 + hash160WithNetwork.byteAt(1)) is ledger.config.network.version.P2SH
+          return P2shScript(hash160) if (hash160WithNetwork.byteAt(0) << 8 | hash160WithNetwork.byteAt(1)) is ledger.config.network.version.P2SH
         if ledger.config.network.name is "zencash"
           script =
             OP_DUP


plugins/hipchat/index: fix the constant's name

--- plugins/hipchat/index.coffee
+++ plugins/hipchat/index.coffee
@@ -35,7 +35,7 @@
       notify: config.notify || false
       color: config.color || "yellow"

-    url = "#{BASE_URL}v#{apiVer}"
+    url = "#{API_BASE_URL}v#{apiVer}"

     if apiVer == 2
       url += "/room/#{config.roomId}/notification?auth_token=#{config.authToken}"


killing more useless code

killing more useless code

--- src/opcodes.coffee
+++ src/opcodes.coffee
@@ -289,10 +289,6 @@
   annotate: (idx, pool) -> "\t#{@var_num}"

 class root.SwitchOpcode extends root.BranchOpcode
-  constructor: (name, params) ->
-    super name, params
-    @byte_count = null
-
   annotate: (idx, pool) -> "{\n" +
     ("\t\t#{match}: #{idx + offset};\n" for match, offset of @offsets).join('') +
     "\t\tdefault: #{idx + @_default} }"


Fixed actions showing up under dialogue bubbles on repeated toggling.

--- app/views/play/level/hud_view.coffee
+++ app/views/play/level/hud_view.coffee
@@ -151,7 +151,7 @@
   createActions: ->
     actions = @$el.find('.thang-actions tbody').empty()
     showActions = @thang.world and not _.isEmpty(@thang.actions) and 'action' in @thang.hudProperties ? []
-    @$el.find('.thang-actions').toggle showActions
+    @$el.find('.thang-actions').toggleClass 'secret', showActions
     return unless showActions
     @buildActionTimespans()
     for actionName, action of @thang.actions


:memo: doc public Marker methods

:memo: doc public Marker methods

--- src/marker.coffee
+++ src/marker.coffee
@@ -259,11 +259,15 @@
   hasTail: ->
     @tailed

-  # Public:
+  # Public: Is the marker valid?
+  #
+  # Returns a {Boolean}.
   isValid: ->
     not @isDestroyed() and @valid

-  # Public:
+  # Public: Is the marker destroyed?
+  #
+  # Returns a {Boolean}.
   isDestroyed: ->
     @destroyed

@@ -272,7 +276,11 @@
   isEqual: (other) ->
     isEqual(@toParams(true), other.toParams(true))

-  # Public:
+  # Public: Get the invalidation strategy for this marker.
+  #
+  # Valid values include: `inside`, `never`, `overlap`, and `surround`.
+  #
+  # Returns a {String}.
   getInvalidationStrategy: ->
     @invalidate


testing

testing

--- src/markov.coffee
+++ src/markov.coffee
@@ -63,11 +63,13 @@
     if pct > 0 and Math.random() < pct
       seed = msg.message.text.match /\w+$/
       model.generate seed[0] or '', max, (text) =>
-        if text.length > 3
+        msg.send text.length
+        if text.length >= 3
           msg.send text

   # Generate markov chains on demand, optionally seeded by some initial state.
   robot.respond /markov(\s+(.+))?$/i, (msg) ->
     model.generate msg.match[2] or '', max, (text) =>
-      if text.length > 3
+      msg.send text.length
+      if text.length >= 3
         msg.send text


Show how service could read yum lock file info

--- src/mecano.coffee
+++ src/mecano.coffee
@@ -853,11 +853,18 @@
         if options.startup? and typeof options.startup isnt 'string'
             options.startup = if options.startup then '2345' else ''
         modified = false
+        stderr = new EventEmitter()
+        stderr.writable = true
+        stderr.write = (data) ->
+          # if /Existing lock/.test data.toString()
+          # quit current process, thow an exception
         installed = ->
           mecano.execute
             ssh: options.ssh
             cmd: "yum list installed | grep ^#{pkgname}\\\\."
             code_skipped: 1
+            # stdout: stdout
+            stderr: stderr
           , (err, installed) ->
             return next err if err
             if installed then updates() else install()


:lipstick: Reorganise demo code to allow variations

--- lib/table-edit.coffee
+++ lib/table-edit.coffee
@@ -1,3 +1,4 @@
+[Table, TableView] = []

 module.exports =

@@ -8,15 +9,23 @@

   activate: (state) ->
     atom.workspaceView.command 'table-edit:demo', => @openDemo()
-    @openDemo()
+    atom.workspaceView.command 'table-edit:demo-with-gutter', => @openDemoWithGutter()
+
+    @openDemoWithGutter()

   deactivate: ->

   serialize: ->

-  openDemo: ->
-    Table = require './table'
-    TableView = require './table-view'
+  openDemo: -> @getTableView()
+
+  openDemoWithGutter: ->
+    tableView = @getTableView()
+    tableView.showGutter()
+
+  getTableView: ->
+    Table ?= require './table'
+    TableView ?= require './table-view'

     table = new Table
     table.addColumn 'key'
@@ -36,7 +45,6 @@
     tableView.setRowHeight 30
     tableView.setRowOverdraw 4
     tableView.setRowHeightAt(3, 90)
-    tableView.showGutter()

     tableView.addClass('demo overlay from-top').height(300)
     atom.workspaceView.append(tableView)
@@ -44,3 +52,5 @@
     tableView.on 'core:cancel', -> tableView.destroy()

     tableView.focus()
+
+    tableView


Disable demo opened upon startup

Disable demo opened upon startup

--- lib/table-edit.coffee
+++ lib/table-edit.coffee
@@ -23,7 +23,7 @@
     atom.workspaceView.command 'table-edit:demo', => @openDemo()
     atom.workspaceView.command 'table-edit:demo-with-gutter', => @openDemoWithGutter()

-    @openDemoWithGutter()
+    # @openDemoWithGutter()

   deactivate: ->


:bug: Fix bad percent rounding

:bug: Fix bad percent rounding

--- lib/table-view.coffee
+++ lib/table-view.coffee
@@ -274,4 +274,4 @@

   asDisposable: (subscription) -> new Disposable -> subscription.off()

-  floatToPercent: (w) -> "#{Math.round w * 100}%"
+  floatToPercent: (w) -> "#{Math.round(w * 10000) / 100}%"


Removing pages (just iterate over objects) watch for missing collection and type. adding in empty seo information.

--- lib/lt3.coffee
+++ lib/lt3.coffee
@@ -396,7 +396,7 @@
           users: {}
         }

-        ##Inject collections
+        # Inject collections
         if pkg_config.collections
           collectionsInjected={}
           for key, value of pkg_config.collections
@@ -411,7 +411,7 @@
         # handle null case
         if setup_config
           setup_config_site = setup_config.site
-          #combines data set
+          # combines data set
           new_data =  extend true, setup_config_site, data
         else
           new_data = data
@@ -419,45 +419,36 @@

         # insert into database must happen first to get site _id
         db.get('sites').insert data, (err, site) ->
-
           throw err if err
           log site

-          #no need to load objects/pages if there is no setup_config
+          # no need to load objects/pages if there is no setup_config
           exit() unless setup_config

           # async objects function called later below
           asyncObjects = (nextFunc) =>
             async.forEach setup_config.objects , (object, next) =>
+              object.seo={
+                title: ''
+                description: ''
+                keywords: ''
+                image: ''
+              }
               object.created = Date.now()
               object.site_id = site.get('_id').val()
               db.get('objects').insert object , (err, site) ->
                 throw err if err
+                throw "error missing collection! aborted" unless object.collection
+                throw "error missing type! aborted" unless object.type
                 next()
             ,
             (err) =>
               log "objects loaded"
               nextFunc(err,"page")
-
-          #async pages function called later below
-          asyncPages  = (nextFunc) =>
-            # async pages into objects
-            async.forEach setup_config.pages , (page, next) =>
-              page.created = Date.now()
-              page.site_id = site.get('_id').val()
-              db.get('objects').insert page , (err, site) ->
-                throw err if err
-                next()
-            ,
-            (err) =>
-              log "pages loaded"
-              nextFunc(err,"page")
-
-
-          #parallel sync of functions
+
+          # parallel sync of functions
           async.parallel [
             asyncObjects
-            asyncPages
           ], (err, results) ->
             exit err, err if err
             exit()


remove require pointing to old parser. oops

--- src/plotter.coffee
+++ src/plotter.coffee
@@ -1,7 +1,5 @@
 # svg plotter class

-# use the gerber parser class to parse the file
-Parser = require './gerber-parser-old'
 # unique id generator
 unique = require './unique-id'
 # aperture macro class


稍微改动下，代码会好看些

稍微改动下，代码会好看些

--- lib/emulator/emulator-manager.coffee
+++ lib/emulator/emulator-manager.coffee
@@ -8,6 +8,7 @@
   activate: ->
     atom.workspaceView.command "atom-chameleon:run-on-server", => @cmdRunOnServer()
     atom.workspaceView.command "atom-chameleon:emulator", => @cmdLaunchEmulator()
+    @_setupDebugServer()

   deactivate: ->
     @runOnServerView?.destroy()
@@ -16,9 +17,6 @@
     @debugServer?.stop()

   cmdRunOnServer: ->
-
-    @_setupDebugServer()
-
     RunOnServerView = require './run-on-server-view'
     @runOnServerView = new RunOnServerView()
     @runOnServerView.attach()
@@ -32,9 +30,7 @@
       }

   _setupDebugServer: ->
-
     unless @serverStatusView and @debugServer
-
       ServerStatusView = require './server-status-view'
       @serverStatusView = new ServerStatusView()
       @serverStatusView.on 'stopServer', => @debugServer.stop()
@@ -45,9 +41,6 @@
       @debugServer.on 'stop', => @serverStatusView.detach()

   cmdLaunchEmulator: ->
-    unless @debugServer
-      DebugServer = require './debug-server'
-      @debugServer = new DebugServer()
     if typeof @debugServer.offline() is 'undefined'
       return alert "please launch debug server."
     unless @emulatorView?


Less information

Less information

--- lib/zen.coffee
+++ lib/zen.coffee
@@ -231,15 +231,10 @@
       monitor.append
         at      : new Date()
         pid     : process.pid
-        version : process.version
-        arch    : process.arch
-        platform: process.platform
         uptime  : process.uptime()
         memtotal: process.memoryUsage().heapTotal / MB
-        # memused : process.memoryUsage().heapUsed / MB
         system  :
           uptime  : os.uptime()
-          # totalmem: os.totalmem() / MB
           freemem : os.freemem()/ MB
           loadavg : os.loadavg()
     , ZEN.monitor.process


Now you can server static files (no url)

--- lib/zen.coffee
+++ lib/zen.coffee
@@ -34,9 +34,9 @@
       Hope.shield([ =>
         do @services
       , =>
+        do @statics
+      , =>
         do @endpoints
-      , =>
-        do @statics
       ]).then (error, value) =>
         process.exit() if error
         global.ZEN.br()
@@ -143,12 +143,20 @@
     statics: ->
       promise = new Hope.Promise()
       global.ZEN.br "STATICS"
-      for policy in global.ZEN.statics or []
+      for policy in (global.ZEN.statics or []) when policy.url? or policy.file?
         do (policy) =>
-          @get policy.url + "/:resource", (request, response, next) ->
+          if policy.url
+            static_url = policy.url + "/:resource"
+          else if policy.file
+            static_url = "/#{policy.file}"
+
+          @get static_url, (request, response, next) ->
             folder = policy.folder
-            folder += "/#{request.parameters.folder}" if request.parameters.folder
-            file = request.parameters.resource
+            if policy.url
+              folder += "/#{request.parameters.subfolder}" if request.parameters.subfolder
+              file = request.parameters.resource
+            else if policy.file
+              file = policy.file
             response.file "#{__dirname}/../../../#{folder}/#{file}", policy.maxage
       promise.done undefined, true
       promise


Catch error from realpathSync

Catch error from realpathSync

--- src/link-lister.coffee
+++ src/link-lister.coffee
@@ -27,7 +27,11 @@
     links = @getSymlinks(directoryPath)
     console.log "#{directoryPath.cyan} (#{links.length})"
     tree links, emptyMessage: '(no links)', (link) =>
-      "#{path.basename(link).yellow} -> #{fs.realpathSync(link)}"
+      try
+        realpath = fs.realpathSync(link)
+      catch error
+        realpath = '???'
+      "#{path.basename(link).yellow} -> #{realpath}"

   run: ->
     @logLinks(@devPackagesPath)


adding condition case if analytics script is not async

--- lib/assets/javascripts/turbolinks-analytics.js.coffee
+++ lib/assets/javascripts/turbolinks-analytics.js.coffee
@@ -1,8 +1,10 @@
 if window.history?.pushState and window.history.replaceState
-  document.addEventListener 'page:change', (event) ->
+  document.addEventListener 'page:change', (event) =>

     # Google Analytics
     if window._gaq != undefined
       _gaq.push(['_trackPageview'])
+    else if window.pageTracker != undefined
+      pageTracker._trackPageview();

     # TODO: Gauges


removing window and jQuery reference for exports

--- src/storage.coffee
+++ src/storage.coffee
@@ -1,4 +1,4 @@
-( ($) ->
+( ->
   ###*
   @name Local
   @namespace
@@ -36,7 +36,8 @@
     if value?
       JSON.parse(value)

-  window.Local = $.extend window.Local,
+  # Export
+  (exports ? this)["Local"] =
     get: retrieve
     set: store
     put: store
@@ -60,5 +61,5 @@
       put: (key, value) ->
         store("#{prefix}_key", value)

-)(jQuery)
+)()


Add indirection so that correct next is called.

--- server/code/lib/throttle.coffee
+++ server/code/lib/throttle.coffee
@@ -1,13 +1,16 @@
 _ = require 'underscore'

+callNext = (next) ->
+  next()
+
 exports.throttle = (getIdentifier, timeout = 1000) ->
   cache = {}
   throttleInner = (req, resp, next) ->
     identifier = getIdentifier(arguments)

     unless identifier of cache
-       cache[identifier] = _.throttle(next, timeout, {trailing: false})
+       cache[identifier] = _.throttle(callNext, timeout, {trailing: false})

-    cache[identifier]()
+    cache[identifier](next)

   return throttleInner


Router: add function call for isInAppRoute

--- server/lib/crawler/index.coffee
+++ server/lib/crawler/index.coffee
@@ -77,7 +77,7 @@
       content = kodinghome()
       return res.send 200, content

-    if firstLetter.toUpperCase() is firstLetter
+    if isInAppRoute firstLetter
       if section
         isLoggedIn req, res, (err, loggedIn, account)->
           # Serve homepage for Develop tab, instead of empty content.


only prints leave room message if it isn't a channel

--- server/methods/leaveRoom.coffee
+++ server/methods/leaveRoom.coffee
@@ -34,7 +34,7 @@
 		,
 			multi: true

-		if room.uids.indexOf(Meteor.userId()) isnt -1
+		if room.t isnt 'c' and room.uids.indexOf(Meteor.userId()) isnt -1
 			removedUser = Meteor.users.findOne Meteor.userId()

 			ChatMessage.insert


Report: Moving some for loops out of render.

--- src/report.coffee
+++ src/report.coffee
@@ -39,17 +39,31 @@
         if not e.pause?
             e.duration = log.get_duration i, final_entries

-
     for e in final_entries
         day = Math.floor(e.date/1000/60/60/24)*1000*60*60*24
         e.details = 0
         if day not in days
             days.push day
-            days_state.push {details:0}
+            days_state.push
+                details:0
+                collapsed_entries:{}
+                activity_duration: 0
+                inactivity_duration: 0
         if entries_by_day[day]?
             entries_by_day[day].push e
         else
             entries_by_day[day] = [e]
+        if e.active
+            task = e.task or 'Unknown'
+            day_state = days_state[days.length-1]
+            day_state.activity_duration += e.duration
+            console.log task
+            if day_state.collapsed_entries[task]?
+                day_state.collapsed_entries[task] += e.duration
+            else
+                day_state.collapsed_entries[task] = e.duration
+        else
+            day_state.inactivity_duration += e.duration

     render_all()

@@ -184,17 +198,11 @@
                     WebkitAppRegion: 'drag'
                 ]
                 for day,i in days when @state.date_to + 24*60*60*1000 >= day >= @state.date_from
-                    day_state = days_state[i]
                     date = moment(day)
                     fdate = date.format("dddd [\n\n__]MMM Do[__ -] YYYY")

                     day_entries = entries_by_day[day]
-                    total_activity_time = 0
-                    total_inactivity_time = 0
-                    for {active, duration, pause} in day_entries when not pause?
-                        if active then total_activity_time += duration
-                        else total_inactivity_time += duration
-
+                    console.log days_state[i].activity_duration
                     div
                         key: 'entry_' + i
                         style:[
@@ -241,7 +249,7 @@
                                     width: '20%'
                                     textAlign: 'center'
                                 ]
-                                div {style: {paddingRight:20}}, format_time total_activity_time
+                                div {style: {paddingRight:20}}, format_time days_state[i].activity_duration

                         div
                             style:[
@@ -253,27 +261,19 @@
                                 padding: 10
                                 margin: '10px 20px 40px 20px'
                                 borderRadius: theme.radius.r2
+                                mixins.transition '1s', 'height'

                             ]
                             if days_state[i].details
-                                for e in day_entries when not e.pause?
-                                    console.log e.task
+                                for {task, date, duration, active, pause} in day_entries when not pause?
                                     markdown {}, "
-                                        #{if e.active then "__#{e.task or 'Unknown'}__
+                                        #{if active then "__#{task or 'Unknown'}__
                                           - " else "__Inactivity__
-                                          - "} #{format_time e.duration}
-                                        _(#{moment(e.date).format('h:mm:ss a')})_"
+                                          - "} #{format_time duration}
+                                        _(#{moment(date).format('h:mm:ss a')})_"
+
                             else
-                                collapsed_entries = {}
-                                for e in day_entries
-                                    if e.active
-                                        task = e.task or 'Unknown'
-                                        if collapsed_entries[task]?
-                                            collapsed_entries[task] += e.duration
-                                        else
-                                            collapsed_entries[task] = e.duration
-
-                                for task, duration of collapsed_entries
+                                for task, duration of days_state[i].collapsed_entries
                                     markdown {}, "
                                         __#{task or 'Activity'}__  -  #{format_time duration}"


Fixes komola/prisma-cloud#99

Fixes komola/prisma-cloud#99

--- src/router.coffee
+++ src/router.coffee
@@ -1,4 +1,6 @@
 Router = require("barista").Router
+path = require "path"
+
 router = new Router

 # write our own salad-compatible resource method.
@@ -22,7 +24,9 @@
   # Dispatch the request to the associated controller
   dispatch: (request, response) =>
     # Get the first matching route
-    matching = router.first(request.path, request.method)
+    requestPath = path.normalize request.path
+
+    matching = router.first(requestPath, request.method)

     # No matching route found
     unless matching


setImmediate

setImmediate

--- src/server.coffee
+++ src/server.coffee
@@ -50,13 +50,27 @@
   # at 15ms resolution. recursively call this function using setInterval()
   #
   _write_pipe: ->
-    setInterval (=>
-      return if @buffer.length == 0
-      @ws.write(@buffer, (err, written) =>
-        throw err if err
-        @buffer = ''
-      )
-    ), 15
+    setImmediate (=>
+      if @buffer.length == 0
+        @_write_pipe()
+      else
+        ok = @ws.write @buffer
+        if ok
+          @buffer = ''
+          @_write_pipe()
+        else
+          @ws.once('drain', =>
+            @buffer = ''
+            @_write_pipe
+          )
+    )
+
+    # setImmediate(=>
+    #   @ws.write(@buffer, (err, written) =>
+    #     throw err if err
+    #     @buffer = ''
+    #   )
+    # )

   #
   # convert halo rgba string to a UART instruction
@@ -83,5 +97,6 @@
   #
   _to_buffer: (data) ->
     @buffer = @_data_to_instruction(data)
+    @_write_pipe()

 module.exports = Server


adjusting hipster mapping

adjusting hipster mapping

--- mapping.coffee
+++ mapping.coffee
@@ -2,8 +2,8 @@

 module.exports =
   hipster: affine (face) -> [
-    [128, 60, face.eye_left.x, face.eye_left.y]
-    [329, 60, face.eye_right.x, face.eye_right.y]
+    [138, 80, face.eye_left.x, face.eye_left.y]
+    [314, 80, face.eye_right.x, face.eye_right.y]
   ]

   mustache: affine (face) -> [


Using lastIndexOf method to find last selectable object

This reduces remote queries

--- packages/emberella/lib/mixins/selectable_mixin.coffee
+++ packages/emberella/lib/mixins/selectable_mixin.coffee
@@ -374,7 +374,7 @@
   previous: (expandSelection = false, count = 1) ->
     len = get(@, 'length')
     indices = @indexOfSelection()
-    lastIdx = +@indexOf(get(@, 'lastSelectableObject'))
+    lastIdx = +@lastIndexOf(get(@, 'lastSelectableObject'))

     if indices
       targetIdx = indices.first - count


:white_check_mark: Add go-to-line spec

:white_check_mark: Add go-to-line spec

--- spec/built-in-tiles-spec.coffee
+++ spec/built-in-tiles-spec.coffee
@@ -2,6 +2,7 @@
 fs = require 'fs-plus'
 path = require 'path'
 os = require 'os'
+{$} = require 'atom-space-pen-views'

 describe "Built-in Status Bar Tiles", ->
   [statusBar, workspaceElement, dummyView] = []
@@ -241,6 +242,13 @@

         atom.config.set('status-bar.cursorPositionFormat', 'baz %C quux %L')
         expect(cursorPosition.textContent).toBe 'baz 3 quux 2'
+
+      describe "when clicked", ->
+        it "triggers the go-to-line toggle event", ->
+          eventHandler = jasmine.createSpy('eventHandler')
+          atom.commands.add('atom-text-editor', 'go-to-line:toggle', eventHandler)
+          cursorPosition.click()
+          expect(eventHandler).toHaveBeenCalled()

   describe "the git tile", ->
     gitView = null


Remove unnecessary "if" in article.coffee

--- models/article.coffee
+++ models/article.coffee
@@ -84,16 +84,14 @@
     stripTags(@get attr)

   toJSONLD: ->       # article metadata tag for parse.ly
-    if @get('title')
-        compactObject {
-          "@context": "http://schema.org"
-          "@type": "NewsArticle"
-          "headline": @get('title')
-          "url": @href()
-          "thumbnailUrl": @get('thumbnail_image')
-          "dateCreated": @get('published_at')
-          "articleSection": "Editorial"
-          "creator": @get('author')?.name
-          "keywords": ""  # this is from the parsely specs, i'm told we don't
-          # have keywords for articles at the moment
-        }
+    compactObject {
+      "@context": "http://schema.org"
+      "@type": "NewsArticle"
+      "headline": @get('title')
+      "url": @href()
+      "thumbnailUrl": @get('thumbnail_image')
+      "dateCreated": @get('published_at')
+      "articleSection": "Editorial"
+      "creator": @get('author')?.name
+      "keywords": ""
+    }


remove anemic method

remove anemic method

--- models/article.coffee
+++ models/article.coffee
@@ -58,7 +58,7 @@
           data: section_id: @get('section_ids')[0], published: true, limit: 50
         )
       # Get related articles for super articles
-      if @isSuperArticle() and @get('super_article').related_articles?.length
+      if @get('is_super_article') and @get('super_article').related_articles?.length
         for id in @get('super_article').related_articles
           dfds.push new Article(id: id).fetch
             success: (article) ->
@@ -82,9 +82,6 @@

   authorHref: ->
     if @get('author') then "/#{@get('author').profile_handle}" else @href()
-
-  isSuperArticle: ->
-    @get('is_super_article')

   cropUrlFor: (attr, args...) ->
     crop @get(attr), args...


Add project delete confirmation and info

--- src/smc-webapp/project_settings.cjsx
+++ src/smc-webapp/project_settings.cjsx
@@ -780,8 +780,18 @@
     propTypes :
         project : rtypes.object.isRequired

+    getInitialState : ->
+        show_delete_conf : false
+
+    show_delete_conf : ->
+        @setState(show_delete_conf : true)
+
+    hide_delete_conf : ->
+        @setState(show_delete_conf : false)
+
     toggle_delete_project : ->
         @actions('projects').toggle_delete_project(@props.project.get('project_id'))
+        @hide_delete_conf()

     toggle_hide_project : ->
         @actions('projects').toggle_hide_project(@props.project.get('project_id'))
@@ -807,6 +817,37 @@
                 This only impacts you, not your collaborators, and you can easily unhide it.
             </span>

+    render_delete_undelete_button : (is_deleted, is_expanded) ->
+        if is_deleted
+            text = "Undelete Project"
+            onClick = @toggle_delete_project
+            disabled = false
+        else
+            text = "Delete Project..."
+            onClick = @show_delete_conf
+            disabled = is_expanded
+
+        <Button bsStyle='danger' style={float: 'right'} onClick={onClick} disabled={disabled}>
+            <Icon name='trash' /> {text}
+        </Button>
+
+    render_expanded_delete_info : ->
+        <Well>
+            <Alert bsStyle="info" style={padding:'8px', marginTop:'4px'} >
+                All of your upgrades from this project will be removed automatically. Undeleting the project will not automatically restore them.
+                <br/>
+                This will not affect upgrades other people have applied.
+            </Alert>
+            <ButtonToolbar style={textAlign:'center'} >
+                <Button bsStyle='danger' onClick={@toggle_delete_project}>
+                    Delete Project
+                </Button>
+                <Button onClick={@hide_delete_conf}>
+                    Cancel
+                </Button>
+            </ButtonToolbar>
+        </Well>
+
     render : ->
         user = @props.project.getIn(['users', salvus_client.account_id])
         if not user?
@@ -827,16 +868,16 @@
             <Row>
                 <Col sm=8>
                     {@delete_message()}
-                    {<Alert bsStyle="info" style={padding:'8px', marginTop:'4px'} >
-                        <b>New -- </b>This will also clear all upgrades from this project. Undeleting the project will not automatically restore them.
-                    </Alert> if not @props.project.get('deleted')}
                 </Col>
                 <Col sm=4>
-                    <Button bsStyle='danger' onClick={@toggle_delete_project} style={float: 'right'}>
-                        <Icon name='trash' /> {if @props.project.get('deleted') then 'Undelete Project' else 'Delete Project'}
-                    </Button>
+                    {@render_delete_undelete_button(@props.project.get('deleted'), @state.show_delete_conf)}
                 </Col>
             </Row>
+            {<Row style={marginTop:'10px'} >
+                <Col sm=12>
+                    {@render_expanded_delete_info()}
+                </Col>
+            </Row> if @state.show_delete_conf and not @props.project.get('deleted')}
         </ProjectSettingsPanel>

 SageWorksheetPanel = rclass


Add a minimum finger distance

Add a minimum finger distance

A sane minimum for finger distance so that we can never have events where fingers overlay exactly, messing up scale and rotation.

--- framer/GestureInputRecognizer.coffee
+++ framer/GestureInputRecognizer.coffee
@@ -8,6 +8,7 @@
 GestureInputForceTapDesktop = MouseEvent.WEBKIT_FORCE_AT_FORCE_MOUSE_DOWN
 GestureInputForceTapMobile = 0.7
 GestureInputForceTapMobilePollTime = 1/30
+GestureInputMinimumFingerDistance = 30

 {DOMEventManager} = require "./DOMEventManager"

@@ -287,7 +288,7 @@
 		if @session.started.pinch and event.fingers == 1
 			@pinchend(event)
 		# If we did not start yet and get two fingers, start
-		else if not @session.started.pinch and event.fingers == 2
+		else if not @session.started.pinch and event.fingers == 2
 			@pinchstart(event)
 		# If we did start send pinch events
 		else if @session.started.pinch
@@ -363,7 +364,7 @@
 			touchPointB = @_getTouchPoint(event, 1)
 			event.touchCenter = Utils.pointCenter(touchPointB, touchPointA)
 			event.touchOffset = Utils.pointSubtract(touchPointB, touchPointA)
-			event.touchDistance = Utils.pointDistance(touchPointA, touchPointB)
+			event.touchDistance = _.max([GestureInputMinimumFingerDistance, Utils.pointDistance(touchPointA, touchPointB)])
 			event.rotation = Utils.pointAngle(touchPointA, touchPointB)

 		# Special cases


No longer use ready in view_helper#render.

--- tests/batman/view/view_helper.coffee
+++ tests/batman/view/view_helper.coffee
@@ -107,17 +107,16 @@
   context.html = html
   view = new Batman.View(context)

-  view.once 'ready', ->
-    Batman.setImmediate ->
-      outstandingNodes.push(view.get('node'))
-      node = if jqueryize then $(view.get('node')).children() else view.get('node')
-      callback(node, view)
-
   node = view.get('node')
   view.propagateToSubviews('viewWillAppear')
   view.initializeBindings()
   view.propagateToSubviews('isInDOM', true)
   view.propagateToSubviews('viewDidAppear')
+
+  Batman.setImmediate ->
+    outstandingNodes.push(view.get('node'))
+    node = if jqueryize then $(view.get('node')).children() else view.get('node')
+    callback(node, view)

   return node


add notification for issue/issue_comment event.

--- scripts/github-notify.coffee
+++ scripts/github-notify.coffee
@@ -63,6 +63,14 @@
         when "pull_request_review_comment"
           announcePullRequestReviewComment robot, data, (what) ->
             for room in repo2rooms(robot, repo)
+              robot.messageRoom room, what
+        when "issues"
+          announceIssue robot, data, (what) ->
+            for room in repo2room(robot, repo)
+              robot.messageRoom room, what
+        when "issues_comment"
+          announceIssueComment robot, data, (what) ->
+            for room in repo2room(robot, repo)
               robot.messageRoom room, what
     catch error
       console.log "github pull request notifier error: #{error}. Request: #{JSON.stringify(req.body)}"
@@ -134,3 +142,28 @@
         mentioned_line = ''

       cb "\"#{data.pull_request.title}\" コメント追加 by #{data.comment.user.login}: #{data.comment.html_url}#{mentioned_line}"
+
+announceIssue = (robot, data, cb) ->
+  switch data.action
+    when 'opened'
+      mentioned = extract_mentions(robot, data.issue.body)
+
+      if mentioned.length > 0
+        mentioned_line = "\nMentioned: #{mentioned.join(", ")}"
+      else
+        mentioned_line = ''
+
+      cb "Issue が作成されました \"#{data.issue.title}\" by #{data.issue.user.login}: #{data.issue.html_url}#{mentioned_line}"
+
+    when "closed"
+      cb "Issue が close されました \"#{data.issue.title}\" by #{data.sender.login}: #{data.issue.html_url}"
+
+announceIssueComment = (robot, data, cb) ->
+  switch data.action
+    when 'created'
+      mentioned = extract_mentions(robot, data.comment.body)
+      if mentioned.length > 0
+        mentioned_line = "\nMentioned: #{mentioned.join(", ")}"
+      else
+        mentioned_line = ''
+      cb "\"#{data.issue.title}\" コメント追加 by #{data.comment.user.login}: #{data.comment.html_url}#{mentioned_line}\n#{data.comment.body}"


Add BC layer to widget constructor

Add BC layer to widget constructor

--- src/widget.coffee
+++ src/widget.coffee
@@ -25,6 +25,11 @@
   constructor: (el, key, optionsHash = {}) ->

     wrapper = $(el)
+
+    if $.isPlainObject key
+      optionsHash = key
+      key = optionsHash.app
+
     options = $.extend({}, wrapper.data(), optionsHash)

     if options.events?


require.resolve none of the things

require.resolve none of the things

--- src/window.coffee
+++ src/window.coffee
@@ -58,11 +58,11 @@

   loadKeyBindings: ->
     KeyBinder.load "#{@appRoot}/static/key-bindings.coffee"
-    if fs.isFile require.resolve "~/.atomicity/key-bindings.coffee"
+    if fs.isFile "~/.atomicity/key-bindings.coffee"
       KeyBinder.load "~/.atomicity/key-bindings.coffee"

   loadSettings: ->
-    if fs.isFile require.resolve "~/.atomicity/settings.coffee"
+    if fs.isFile "~/.atomicity/settings.coffee"
       require "~/.atomicity/settings.coffee"

   showConsole: ->


Simple sanity check on the id3 tag..

Simple sanity check on the id3 tag..

--- start.coffee
+++ start.coffee
@@ -52,7 +52,11 @@
 		async.each files, ( file, cb ) ->

 			# Sanity check to make sure the file_info contains at least a title and artist..
-			#TODO
+			# For now just skip the files that do not match..
+			for req, reg of { "artist": /[a-zA-Z]/, "title": /[a-zA-Z]/ }
+				if not file['info']['id3'][req]? or not file['info']['id3'][req].match reg
+					log "Skipping invalid ID3 tagged file #{file['path']}.."
+					return cb null

 			# Check runtime['db'] for file['info']['id3']['artist'] and file['info']['id3']['title']...
 			runtime['db'].view 'songs/by-artist-and-title', { key: [ file['info']['id3']['artist'], file['info']['id3']['title'] ] }, ( err, docs ) ->


Adjust.

Adjust.

--- snippets/vue_element_ui.cson
+++ snippets/vue_element_ui.cson
@@ -4,4 +4,4 @@
     prefix: 'vue:el-menu'
     leftLabelHTML: 'Ⓢ'
     rightLabelHTML: 'Vue Element UI - el-menu'
-    body: '<el-menu\n\t:default-active="activeIndex2"\n\tclass="el-menu-demo"\n\tmode="horizontal"\n\t@select="handleSelect"\n\tbackground-color="#545c64"\n\ttext-color="#fff"\n\tactive-text-color="#ffd04b">\n\t<el-menu-item index="1">Processing Center</el-menu-item>\n\t<el-submenu index="2">\n\t\t<template slot="title">Workspace</template>\n\t\t<el-menu-item index="2-1">item one</el-menu-item>\n\t\t<el-menu-item index="2-2">item two</el-menu-item>\n\t\t<el-menu-item index="2-3">item three</el-menu-item>\n\t</el-submenu>\n\t<el-menu-item index="3">Orders</el-menu-item>\n</el-menu>'
+    body: '<el-menu\n\t:default-active="activeIndex2"\n\tclass="el-menu-demo"\n\tmode="horizontal"\n\t@select="handleSelect"\n\tbackground-color="#545c64"\n\ttext-color="#fff"\n\tactive-text-color="#ffd04b">\n\t<el-menu-item index="1">Processing Center</el-menu-item>\n\t<el-submenu index="2">\n\t\t<template slot="title">Workspace</template>\n\t\t<el-menu-item index="2-1">item one</el-menu-item>\n\t\t<el-menu-item index="2-2">item two</el-menu-item>\n\t\t<el-menu-item index="2-3">item three</el-menu-item>\n\t</el-submenu>\n\t<el-menu-item index="3">Orders</el-menu-item>\n</el-menu>'


:white_check_mark:   spec for new quote behavior

--- spec/text-object-spec.coffee
+++ spec/text-object-spec.coffee
@@ -1,4 +1,5 @@
 {getVimState, dispatch, TextData} = require './spec-helper'
+settings = require '../lib/settings'

 describe "TextObject", ->
   [set, ensure, keystroke, editor, editorElement, vimState] = []
@@ -285,6 +286,53 @@
         ensure 'a q', selectedText: "'efg'"

   describe "DoubleQuote", ->
+    describe "#635 new behavior of inner-double-quote", ->
+      beforeEach ->
+        # Just for spec easy to read/write, cursor position is not so important
+        # settings.set('stayOnTransformString', true)
+        atom.keymaps.add "test",
+          'atom-text-editor.vim-mode-plus:not(.insert-mode)':
+            'g r': 'vim-mode-plus:replace'
+
+      describe "quote is un-balanced", ->
+        it "case1", ->
+          set                 textC_: '_|_"____"____"'
+          ensure 'g r i " +', textC_: '__"|++++"____"'
+        it "case2", ->
+          set                 textC_: '__"__|__"____"'
+          ensure 'g r i " +', textC_: '__"|++++"____"'
+        it "case3", ->
+          set                 textC_: '__"____"__|__"'
+          ensure 'g r i " +', textC_: '__"____"|++++"'
+        it "case4", ->
+          set                 textC_: '__|"____"____"'
+          ensure 'g r i " +', textC_: '__"|++++"____"'
+        it "case5", ->
+          set                 textC_: '__"____|"____"'
+          ensure 'g r i " +', textC_: '__"|++++"____"'
+        xit "case6", -> # FIXME
+          set                 textC_: '__"____"____|"'
+          ensure 'g r i " +', textC_: '__"____"|++++"'
+      describe "quote is balanced", ->
+        it "case1", ->
+          set                 textC_: '_|_"===="____"==="'
+          ensure 'g r i " +', textC_: '__"|++++"____"==="'
+        it "case2", ->
+          set                 textC_: '__"==|=="____"==="'
+          ensure 'g r i " +', textC_: '__"|++++"____"==="'
+        it "case3", ->
+          set                 textC_: '__"===="__|__"==="'
+          ensure 'g r i " +', textC_: '__"===="|++++"==="'
+        it "case4", ->
+          set                 textC_: '__|"===="____"==="'
+          ensure 'g r i " +', textC_: '__"|++++"____"==="'
+        it "case5", ->
+          set                 textC_: '__"====|"____"==="'
+          ensure 'g r i " +', textC_: '__"|++++"____"==="'
+        it "case6", ->
+          set                 textC_: '__"===="____|"==="'
+          ensure 'g r i " +', textC_: '__"===="____"|+++"'
+
     describe "inner-double-quote", ->
       beforeEach ->
         set
@@ -307,6 +355,7 @@
         ensure 'd i "',
           text: '" something in here and in "here" " and over here'
           cursor: [0, 39]
+
       describe "cursor is on the pair char", ->
         check = getCheckFunctionFor('i "')
         text = '-"+"-'


:white_check_mark: improve test for TextObject.Fold

--- spec/text-object-spec.coffee
+++ spec/text-object-spec.coffee
@@ -856,7 +856,6 @@
       atom.packages.deactivatePackage('language-coffee-script')

     describe 'inner-fold', ->
-
       it 'select fold row range except start row', ->
         set cursor: [13, 0]
         ensure 'viz', selectedBufferRange: rangeForRows(10, 25)
@@ -865,9 +864,25 @@
         set cursor: [19, 0]
         ensure 'viz', selectedBufferRange: rangeForRows(19, 23)

-      # it 'can expand selection', ->
-      #   set cursor: [23, 0]
-      #   ensure 'viz', selectedBufferRange: [[19, 0], [24, 0]]
+      it 'can expand selection', ->
+        set cursor: [23, 0]
+        keystroke 'v'
+        ensure 'iz', selectedBufferRange: rangeForRows(23, 23)
+        ensure 'iz', selectedBufferRange: rangeForRows(19, 23)
+        ensure 'iz', selectedBufferRange: rangeForRows(10, 25)
+        ensure 'iz', selectedBufferRange: rangeForRows(9, 28)
+
+      describe 'when start of selection is on fold start row', ->
+        it 'select outer fold(skip)', ->
+          set cursor: [20, 7]
+          ensure 'viz', selectedBufferRange: rangeForRows(19, 23)
+
+      describe 'when endRow of selection is greater than fold end row', ->
+        it "doesn't care just search based on startRow and adjust selection", ->
+          set cursor: [20, 0]
+          ensure 'VG', selectedBufferRange: rangeForRows(20, 30)
+          ensure 'iz', selectedBufferRange: rangeForRows(19, 23)
+
     describe 'a-fold', ->
       it 'select fold row range', ->
         set cursor: [13, 0]
@@ -876,6 +891,25 @@
       it 'select fold row range', ->
         set cursor: [19, 0]
         ensure 'vaz', selectedBufferRange: rangeForRows(18, 23)
+
+      it 'can expand selection', ->
+        set cursor: [23, 0]
+        keystroke 'v'
+        ensure 'az', selectedBufferRange: rangeForRows(22, 23)
+        ensure 'az', selectedBufferRange: rangeForRows(18, 23)
+        ensure 'az', selectedBufferRange: rangeForRows(9, 25)
+        ensure 'az', selectedBufferRange: rangeForRows(8, 28)
+
+      describe 'when start of selection is on fold start row', ->
+        it 'select outer fold(skip)', ->
+          set cursor: [20, 7]
+          ensure 'vaz', selectedBufferRange: rangeForRows(18, 23)
+
+      describe 'when endRow of selection is greater than fold end row', ->
+        it "doesn't care just search based on startRow and adjust selection", ->
+          set cursor: [20, 0]
+          ensure 'VG', selectedBufferRange: rangeForRows(20, 30)
+          ensure 'az', selectedBufferRange: rangeForRows(18, 23)

   # Although following test picks specific language, other langauages are alsoe supported.
   describe 'Function', ->


Fix american area codes

Fix american area codes


Update mysql

Update mysql

--- actions/mysql_server.coffee
+++ actions/mysql_server.coffee
@@ -8,6 +8,7 @@
 mecano = require 'mecano'
 each = require 'each'
 module.exports = []
+escape = (text) -> text.replace(/[\\"]/g, "\\$&")

 # Install the mysql driver
 module.exports.push 'histi/actions/mysql_client'
@@ -77,7 +78,6 @@
       modified = true if started
       do_sql()
   do_sql = ->
-    escape = (text) -> text.replace(/[\\"]/g, "\\$&")
     each(sql_on_install)
     .on 'item', (sql, next) ->
       cmd = "mysql -uroot -e \"#{escape sql}\""
@@ -152,12 +152,14 @@
           stream.end()
     stream.on 'close', ->
       return next error if error
-      return next null, if modified then ctx.OK else ctx.PASS if disallow_remote_root_login
+      if disallow_remote_root_login then return next null, if modified then ctx.OK else ctx.PASS
+      sql = """
+      USE mysql;
+      GRANT ALL PRIVILEGES ON *.* TO root@'%' IDENTIFIED BY "#{password}";
+      FLUSH PRIVILEGES;
+      """
       ctx.execute
-        cmd: """
-        GRANT ALL PRIVILEGES ON *.* TO root@'%' IDENTIFIED BY "#{password}";
-        FLUSH PRIVILEGES;
-        """
+        cmd: "mysql -uroot -p#{password} -e \"#{escape sql}\""
       , (err, executed) ->
         next err, if modified then ctx.OK else ctx.PASS


Drop watch.coffee, it's not necessary anymore

--- tools/watch.coffee
+++ tools/watch.coffee
@@ -1,75 +0,0 @@
-#  Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
-#
-#  Redistribution and use in source and binary forms, with or without
-#  modification, are permitted provided that the following conditions are met:
-#
-#    * Redistributions of source code must retain the above copyright
-#      notice, this list of conditions and the following disclaimer.
-#    * Redistributions in binary form must reproduce the above copyright
-#      notice, this list of conditions and the following disclaimer in the
-#      documentation and/or other materials provided with the distribution.
-#
-#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-#  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
-#  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-#  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-#  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-#  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-#  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-#  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-fs = require 'fs'
-path = require 'path'
-child_process = require 'child_process'
-root = path.join __dirname, '..'
-coffee = require 'coffee-script'
-compiler = path.join(root, 'node_modules', '.bin', 'coffee')
-
-libdir = path.join root, '' + process.argv[2]
-srcdir = path.join root, '' + process.argv[3]
-watchers = []
-
-if not fs.watch
-    console.error 'fs.watch is not provided'
-    process.exit 1
-
-timeLog = (message) ->
-    console.log "#{(new Date).toLocaleTimeString()} - #{message}"
-
-compile = (src, dst) ->
-    child_process.exec "#{compiler} -j < #{JSON.stringify src} > #{JSON.stringify dst}", (err) ->
-        timeLog "compiled #{path.relative root, src}"
-
-fs.mkdir libdir, ->
-    fs.readdir srcdir, (err, files) ->
-        for file in files
-            do ->
-                src = path.join srcdir, file
-                dst = path.join libdir, "#{path.basename file, '.coffee'}.js"
-                compile src, dst
-
-        refresh = ->
-            console.log 'watch', srcdir
-            watcher.close() for watcher in watchers
-            fs.readdir srcdir, (err, files) ->
-                console.log files
-                for file in files
-                    do ->
-                        src = path.join srcdir, file
-                        dst = path.join libdir, "#{path.basename file, '.coffee'}.js"
-                        watcher = fs.watch src, (event, filename) ->
-                            console.log 'starting...', event
-                            if event is 'change'
-                                compile src, dst
-                        watchers.push watcher
-
-        # notify directory file list change
-        # fs.watch srcdir, (event, filename) ->
-        #     console.log event
-        #     do refresh
-
-        do refresh
-
-# vim: set sw=4 ts=4 et tw=80 :


Explicitly specify string encoding

Explicitly specify string encoding

--- src/dnt-connect.coffee
+++ src/dnt-connect.coffee
@@ -55,10 +55,10 @@
 #
 # Encipher plaintext and prepend iv
 #
-# @param <String> plaintext - plaintext to encipher
+# @param <string-utf8> plaintext - plaintext to encipher
 # @param <Buffer> iv - initialization vector
 #
-# @return base64 encoded <String> of the iv prepended to the ciphertext
+# @return <string-base64> of the iv prepended to the ciphertext
 #
 ###
 Connect.prototype.encryptPlaintext = (plaintext, iv) ->
@@ -73,7 +73,7 @@
 # @param <Buffer> ciphertext - ciphertext to decipher
 # @param <Buffer> iv - initialization vector
 #
-# @return utf-8 encoded <String> with plaintext
+# @return <string-utf8> with plaintext
 #
 ###
 Connect.prototype.decryptCiphertext = (ciphertext, iv) ->
@@ -84,10 +84,10 @@
 #
 # Encrypt plaintext and hmac it
 #
-# @param <String> plaintext - plaintext to encipher
+# @param <string-utf8> plaintext - plaintext to encipher
 # @param <Buffer> iv - initialization vector
 #
-# @return <Array> with <String> ciphertext and <String> hmac
+# @return <Array> with <string-base64> ciphertext and <string-base64> hmac
 #
 ###
 Connect.prototype.encryptAndHash = (plaintext, iv) ->
@@ -97,10 +97,10 @@
 #
 # Decrypt ciphertext and verify hmac
 #
-# @param <String> ciphertext - ciphertext to decipher
-# @param <String> hmac - hmac of plaintext and iv
+# @param <string-base64> ciphertext - ciphertext to decipher
+# @param <string-base64> hmac - hmac of plaintext and iv
 #
-# @return <Array> with <String> plaintext and <Boolean> verification
+# @return <Array> with <string-utf8> plaintext and <boolean> verification
 #
 ###
 Connect.prototype.decryptAndVerify = (ciphertext, hmac) ->
@@ -113,10 +113,10 @@
 #
 # Decrypt encrypted data from DNT Connect
 #
-# @param <String> data - encrypted data
-# @param <String> hmac - hmaced data verification
+# @param <string-base64> data - encrypted data
+# @param <string-base64> hmac - hmaced data verification
 #
-# @return <Array> with <Object> decrypted data and <Boolean> verification
+# @return <Array> with <object> decrypted data and <boolean> verification
 #
 ###
 Connect.prototype.decryptJSON = (data, hmac) ->
@@ -133,10 +133,10 @@
 #
 # Encrypt JSON and return ciphertext and hmac
 #
-# @param <Object> json - json data to encrypt
+# @param <object> json - json data to encrypt
 # @param <Buffer> iv - initialization vector
 #
-# @return <Array> with <String> ciphertext and <String> hmac
+# @return <Array> with <string-base64> ciphertext and <string-base64> hmac
 #
 ###
 Connect.prototype.encryptJSON = (json, iv) ->
@@ -147,10 +147,10 @@
 #
 # Get DNT Connect url for service type
 #
-# @param <String> type - authentication type
-# @param <String> redirectUrl - url to redirect user back to
+# @param <string-utf8> type - authentication type
+# @param <string-utf8> redirectUrl - url to redirect user back to
 #
-# @return <String> url to DNT Connect
+# @return <string-utf8> url to DNT Connect
 #
 ###
 Connect.prototype.getUrl = (type, redirectUrl) ->
@@ -165,9 +165,9 @@
 #
 # Bounce user to DNT Connect to check authentication
 #
-# @param <String> redirectUrl - url to redirect user back to
+# @param <string-utf8> redirectUrl - url to redirect user back to
 #
-# @return <String> url to DNT Connect
+# @return <string-utf8> url to DNT Connect
 #
 ###
 Connect.prototype.bounce = (redirectUrl) ->
@@ -177,9 +177,9 @@
 #
 # Make user sign on using DNT Connect
 #
-# @param <String> redirectUrl - url to redirect user back to
+# @param <string-utf8> redirectUrl - url to redirect user back to
 #
-# @return <String> url to DNT Connect
+# @return <string-utf8> url to DNT Connect
 #
 ###
 Connect.prototype.signon = (redirectUrl) ->


Remove log messages used for testing

Remove log messages used for testing

--- admin/static/coffee/namespaces/shards.coffee
+++ admin/static/coffee/namespaces/shards.coffee
@@ -298,9 +298,6 @@
                     empty_master_pin[shard] = null
                     empty_replica_pins[shard] = []

-                console.log shard_set
-                console.log @model.get('key_distr_sorted')
-
                 data =
                     shards: shard_set
                     primary_pinnings: empty_master_pin
@@ -419,10 +416,6 @@
                 primary_pinnings: empty_master_pin
                 secondary_pinnings: empty_replica_pins

-            console.log shard_set
-            console.log @model.get('key_distr_sorted')
-            console.log '======'
-
             @data_sent = data

             $.ajax


Create firebase key hash based only on source and target, so a user can update a rating without creating duplicates.

--- src/adaptors/firebase.coffee
+++ src/adaptors/firebase.coffee
@@ -18,8 +18,11 @@

   putClaim: ({ source, target, value, content }, options={}) ->
     trustAtom = pick { source, target, value, content }, (value, key) -> value? and key?
-    json = canonicalJson trustAtom
-    atomId = "sha256-#{sha256 json}"
+
+    # hash should only include source & target. otherwise, duplicates are created when user update rating.
+    # json = canonicalJson trustAtom
+    # atomId = "sha256-#{sha256 json}"
+    atomId = sha256(canonicalJson({ source, target }))

     key = if options?.firebase?.path?
             "#{options.firebase.path}/#{atomId}"


Remove common chunks plugin when testing

--- karma.conf.coffee
+++ karma.conf.coffee
@@ -1,5 +1,6 @@
 webpackConfig = require('./webpack.config.coffee')
 webpackConfig.entry = {}
+webpackConfig.plugins = []

 module.exports = (config)  ->
   config.set