github-op: remove duplicated repositories.

--- scripts/github-op.coffee
+++ scripts/github-op.coffee
@@ -34,6 +34,13 @@
   unless (url_api_base = process.env.HUBOT_GITHUB_API)?
     url_api_base = "https://api.github.com"

+  removeDuplicates = (ary) ->
+    if ary.length == 0
+      return []
+    res = []
+    res[ary[key]] = ary[key] for key in [0..ary.length-1]
+    value for key, value of res
+
   robot.respond /github\s+show\s+repos\s*$/i, (msg) ->
     repos = robot.brain.get("github_default_target_repos")
     unless repos
@@ -50,7 +57,7 @@
       unless repos
         repos = []
       repos.push repo
-      robot.brain.set("github_default_target_repos", repos)
+      robot.brain.set("github_default_target_repos", removeDuplicates(repos))
       msg.send "対象のリポジトリに #{repo} を追加しました"

   robot.respond /github\s+show\s+(PRs?|pull\s+req(uests?)?)\s*([a-z0-9._/-]+)?$/i, (msg)->


Update zh-HANS.coffee

Update zh-HANS.coffee

--- app/locale/zh-HANS.coffee
+++ app/locale/zh-HANS.coffee
@@ -598,12 +598,12 @@
     jose_blurb: "放轻松"
     retrostyle_title: "插画师"
     retrostyle_blurb: "复古风格的游戏"
-#    rob_title: "Compiler Engineer"
-#    rob_blurb: "Codes things and stuff"
-#    josh_c_title: "Game Designer"
-#    josh_c_blurb: "Designs games"
-#    carlos_title: "Region Manager, Brazil"
-#    carlos_blurb: "Celery Man"
+    rob_title: "编译器工程师"
+    rob_blurb: "编代码之类的"
+    josh_c_title: "游戏设计师"
+    josh_c_blurb: "设计游戏" # or what
+    carlos_title: "地区经理, 巴西"
+    carlos_blurb: "食草男" # unless you have a better one for "celery man"

   teachers:
     more_info: "教师的说明"
@@ -724,16 +724,16 @@
     wrong_password: "密码错误"
     upload_picture: "上传一张图片"
     delete_this_account: "永久删除账户"
-#    reset_progress_tab: "Reset All Progress"
-#    reset_your_progress: "Clear all your progress and start over"
+    reset_progress_tab: "重置所有进度"
+    reset_your_progress: "清除记录并重新开始"
     god_mode: "上帝模式"
     password_tab: "密码"
     emails_tab: "邮件"
     admin: "管理"
     new_password: "新密码"
     new_password_verify: "再次输入密码"
-    type_in_email: "输入您的邮箱地址来确认删除"
-#    type_in_email_progress: "Type in your email to confirm deleting your progress."
+    type_in_email: "输入您的邮箱地址"
+    type_in_email_progress: "输入邮箱地址来确认删除"
     type_in_password: "同样的，输入您的密码。"
     email_subscriptions: "邮箱订阅"
     email_subscriptions_none: "取消订阅"
@@ -846,8 +846,8 @@
     last_played: "最后玩了"
     leagues_explanation: "在部落里与其他成员组成联盟一起参加下面的多人竞技场。"
 #    track_concepts1: "Track concepts"
-#    track_concepts2a: "learned by each student"
-#    track_concepts2b: "learned by each member"
+    track_concepts2a: "由每位学生学习"
+    track_concepts2b: "由每位成员学习"
 #    track_concepts3a: "Track levels completed for each student"
 #    track_concepts3b: "Track levels completed for each member"
 #    track_concepts4a: "See your students'"


Added analytics to Job Timer.  Issue #77.

--- scripts/job_timer.coffee
+++ scripts/job_timer.coffee
@@ -15,6 +15,7 @@

 	start = (toff) ->
 		$('#main').show 'fast'
+                mixpanel.track "User Started Timer"
 		start_time = new Date().valueOf() + toff * 1000
 		update = ->
 			$('#foo').text((new Date() - start_time) / 1000)
@@ -32,7 +33,7 @@
 			if confirm 'Are you sure you want to complete this job?  This cannot be undone.'
 				clearInterval timerInterval
 				clearInterval checkCompleteInterval
-
+                                mixpanel.track "User Completed Job"
 				$rpc.job.complete id, ->
 					$('#main').hide 'fast'
 					$('#feedback').show 'fast'


more love

more love

--- scripts/fierce.coffee
+++ scripts/fierce.coffee
@@ -93,5 +93,5 @@
   robot.hear /(pause|paws)/i, (msg) ->
     msg.send "http://www.wppl.org/kidsteens/paws.jpg"

-  robot.hear /(phil|philip|phillip)/i, (msg) ->
+  robot.hear /(phil|philip|phillip|fill)/i, (msg) ->
     msg.send "https://fiercemarkets.campfirenow.com/room/470540/uploads/3179113/philweb1.jpg"


activity: remove unused util

activity: remove unused util

--- client/activity/lib/util/isPublicChatChannel.coffee
+++ client/activity/lib/util/isPublicChatChannel.coffee
@@ -1,8 +0,0 @@
-immutable = require 'immutable'
-
-module.exports = isPublicChatChannel = (channel) ->
-
-  if immutable.Iterable.isIterable channel
-  then channel.getIn(['payload', '__publicChat'])?
-  else channel.payload.__publicChat?
-


Collaboration: Don't add collaboration owner to collaboration as participant

--- client/ide/lib/views/chat/idechatmessagepane.coffee
+++ client/ide/lib/views/chat/idechatmessagepane.coffee
@@ -9,6 +9,7 @@
 isMyChannel          = require 'app/util/isMyChannel'
 isMyPost             = require 'app/util/isMyPost'
 envDataProvider      = require 'app/userenvironmentdataprovider'
+nick                 = require 'app/util/nick'

 CollaborationChannelParticipantsModel = require 'activity/models/collaborationchannelparticipants'
 IDEChatParticipantHeads               = require './idechatparticipantheads'
@@ -304,6 +305,8 @@

   participantAdded: (participant) ->

+    return  if participant.profile.nickname is nick()
+
     @removeOnboarding()

     appManager = kd.getSingleton 'appManager'


Collaboration: Create change object for cursor events at every turn

--- client/ide/lib/workspace/panes/ideeditorpane.coffee
+++ client/ide/lib/workspace/panes/ideeditorpane.coffee
@@ -277,15 +277,15 @@

   bindChangeListeners: ->

+    @getAce()
+      .on 'ace.change.cursor', @bound 'handleCursorChange'
+      .on 'FileContentChanged', @bound 'handleFileContentChange'
+      .on 'FileContentRestored', @bound 'handleFileContentChange'
+
+
+  handleCursorChange: (cursor) ->
+
     change = @getInitialChangeObject()
-
-    @getAce()
-      .on 'ace.change.cursor',   @lazyBound 'handleCursorChange',      change
-      .on 'FileContentChanged',  @lazyBound 'handleFileContentChange', change
-      .on 'FileContentRestored', @lazyBound 'handleFileContentChange', change
-
-
-  handleCursorChange: (change, cursor) ->

     change.type = 'CursorActivity'
     change.context.cursor = cursor
@@ -293,9 +293,11 @@
     @emit 'ChangeHappened', change

-  handleFileContentChange: (change) ->
-
-    return if @dontEmitChangeEvent
+  handleFileContentChange: ->
+
+    change = @getInitialChangeObject()
+
+    return  if @dontEmitChangeEvent

     change.type = 'ContentChange'
     change.context.file.content = @getContent()


Add defensive check

Add defensive check

--- client/ide/lib/workspace/panes/ideeditorpane.coffee
+++ client/ide/lib/workspace/panes/ideeditorpane.coffee
@@ -425,4 +425,4 @@
     super

-  updateAceViewDelegate: (ideView) -> @aceView.setDelegate ideView
+  updateAceViewDelegate: (ideView) -> @aceView?.setDelegate ideView


Get brain data from object.

Get brain data from object.

--- scripts/points.coffee
+++ scripts/points.coffee
@@ -126,4 +126,5 @@
     robot.respond /allpoints$/i, (msg) ->
         if robot.auth.hasRole(msg.envelope.user, ['admin', 'moderator'])

+            allpoints = robot.brain.get('points')
             msg.send "Stored points: #{points.username.points}"


Fixed navbar status bug.

Fixed navbar status bug.

--- web/coffee/navbar.coffee
+++ web/coffee/navbar.coffee
@@ -1,6 +1,16 @@

 apiOffline =
   News: "/news"
+
+teacherLoggedIn =
+  Problems: "/problems"
+  Scoreboard: "/scoreboard"
+  Stats: "/stats"
+  About:
+    FAQ: "/faq"
+    Sponsors: "/sponsors"
+    News: "/news"
+  Logout: "/logout"

 userLoggedIn =
   Problems: "/problems"
@@ -21,17 +31,6 @@
     News: "/news"
   Login: "/login"

-teacherLoggedIn =
-  Problems: "/problems"
-  Scoreboard: "/scoreboard"
-  Stats: "/stats"
-  About:
-    FAQ: "/faq"
-    Sponsors: "/sponsors"
-    News: "/news"
-  Logout: "/logout"
-
-
 loadNavbar = (renderNavbarLinks, renderNestedNavbarLinks) ->

   navbarLayout = {
@@ -42,13 +41,14 @@
   apiCall "GET", "/api/user/status", {}
   .done (data) ->
     navbarLayout.links = userNotLoggedIn
-
-    if data["status"] == 0
+
+    console.log data
+    if data["status"] == 1
       if data.data["teacher"]
         navbarLayout.links = teacherLoggedIn
       else if data.data["logged_in"]
         navbarLayout.links = userLoggedIn
-
+    console.log navbarLayout.links
     $("#navbar-links").html renderNavbarLinks(navbarLayout)

   .fail ->


Refactored Twitch.coffee

Refactored Twitch.coffee

--- scripts/twitch.coffee
+++ scripts/twitch.coffee
@@ -1,5 +1,5 @@
 # Description:
-#   Twitch API - Find live streams
+#   Twitch Public API
 #
 # Dependencies:
 #   None
@@ -8,67 +8,60 @@
 #   None
 #
 # Commands:
-#   hubot ttv <category> - Perform a case-sensitive search on Twitch.tv for live streams in a game category (returns the first 5)
-#   hubot ttv featured - Return the first 5 featured live streams on Twitch.tv
+#   hubot ttv game <category> - Performs a case-sensitive search on Twitch.tv for live streams in a game <category> (returns the first 5)
+#   hubot ttv featured - Returns the first 5 featured live streams on Twitch.tv
 #   hubot ttv stream <name> - Returns information about stream <name>
 #
 # Author:
 #   MrSaints
+#   mbwkarl
+#
+# Todo:
+# - Save favourites?
+#

 module.exports = (robot) ->
-    robot.respond /ttv (.*)/i, (msg) ->
-        tempv = msg.match[1].indexOf "stream",0
-        if msg.match[1] is "featured"
-            getStreams msg, true
-        else if tempv is 0
-            getStreams msg, false, true
-        else
-            getStreams msg
-
-
-getStreams = (msg, featured, channel) ->
-    category = msg.match[1]
-
-    API = "/streams"
-    type = "streams"
-
-    if featured
-        API = "/streams/featured"
-        type = "featured"
-
-    if channel
-        streamsplit = msg.match[1].split " "
-        API = "/streams/#{streamsplit[1]}"
-        type = "stream"
-
-
-    msg.http("https://api.twitch.tv/kraken#{API}")
-        .query
-            game: category
-            limit: 5
-        .get() (err, res, body) ->
-            data = JSON.parse body
-
-            if channel
-                if not data[type]
-                    msg.reply "The stream is either offline, or does not exist."
-                    return
-
-                if data[type]
-                    stream = data[type]
-                    msg.send "#{stream.channel.display_name} is streaming #{stream.channel.game} @ #{stream.channel.url}"
-                    msg.send "Stream status: \"#{stream.channel.status}\""
-                    msg.send "Viewers: #{stream.viewers}"
-                    return
-
-            if data._total is 0
-                msg.reply "No live streams were found in '#{category}'. Try a different category or try again later."
+    robot.respond /ttv game (.*)/i, (msg) ->
+        category = msg.match[1]
+        twitch_request msg, '/streams', { game: category, limit: 5 }, (object) ->
+            if object._total is 0
+                msg.reply "No live streams were found in \"#{category}\". Try a different category or try again later."
                 return

-            for stream in data[type][0..4]
-                stream = stream.stream if featured
-                msg.send "#{stream.channel.display_name} (#{stream.channel.status}) - #{stream.channel.url} [Viewers: #{stream.viewers}]"
+            for stream in object.streams
+                channel = stream.channel
+                msg.send "#{channel.display_name} (\"#{channel.status}\") - #{channel.url} [Viewers: #{stream.viewers}]"

-            if !featured and data._total > 5
-                msg.reply "There are #{data._total - 5} other '#{category}' live streams."
+            if object._total > 5
+                msg.reply "There are #{object._total - 5} other \"#{category}\" live streams."

+    robot.respond /ttv featured/i, (msg) ->
+        twitch_request msg, '/streams/featured', { limit: 5 }, (object) ->
+            for feature in object.featured
+                channel = feature.stream.channel
+                msg.send "#{feature.stream.game}: #{channel.display_name} (#{channel.status}) - #{channel.url} [Viewers: #{feature.stream.viewers}]"
+
+    robot.respond /ttv stream (.*)/i, (msg) ->
+        twitch_request msg, "/streams/#{msg.match[1]}", null, (object) ->
+            if object.status is 404
+                msg.reply "The stream you have entered (\"#{msg.match[1]}\") does not exist."
+                return
+
+            if not object.stream
+                msg.reply "The stream you have entered (\"#{msg.match[1]}\") is currently offline."
+                return
+
+            channel = object.stream.channel
+            msg.send "#{channel.display_name} is streaming #{channel.game} @ #{channel.url}"
+            msg.send "Stream status: \"#{channel.status}\""
+            msg.send "Viewers: #{object.stream.viewers}"
+
+twitch_request = (msg, api, params = {}, handler) ->
+    msg.http("https://api.twitch.tv/kraken#{api}")
+        .query(params)
+        .get() (err, res, body) ->
+            if err
+                msg.reply "An error occurred while attempting to process your request: #{err}"
+                return
+
+            handler JSON.parse(body)


-am by mistake

-am by mistake

--- server/code/index.coffee
+++ server/code/index.coffee
@@ -17,7 +17,6 @@
 eco = require 'eco'
 checkIdent = require 'ident-express'
 request = require 'request'
-connectDomain = require 'connect-domain'

 {User} = require 'model/user'
 {Dataset} = require 'model/dataset'
@@ -125,10 +124,6 @@
   app.use assets({src: 'client'})
   # Set the public folder as static assets
   app.use express.static(process.cwd() + '/shared')
-
-  app.use connectDomain()
-  app.use (err, req, res, next) ->
-    res.end err.message

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


Allow overriding options.

Allow overriding options.

--- server/lib/worker.coffee
+++ server/lib/worker.coffee
@@ -10,9 +10,15 @@
   run: ->
     throw new Error "Not implemented"

+  # Method so that job class can set or override enqueue options
+  enqueueOptions: (options) ->
+    options
+
   enqueue: (options) ->
     # We use EJSON.toJSONValue to convert to an object with only fields and no methods
     job = JobQueue.Meta.collection.createJob @type(), EJSON.toJSONValue @
+
+    options = @enqueueOptions options

     job.depends options.depends if options?.depends?
     job.priority options.priority if options?.priority?


onbeforeunload callback taken to its own method

--- core/KDWindowController.coffee
+++ core/KDWindowController.coffee
@@ -105,42 +105,47 @@
     , yes

     # unless window.location.hostname is 'localhost'
-    window.addEventListener 'beforeunload', (event) =>
-      # fixme: fix this with appmanager
-
-      if @getSingleton('mainView')?.mainTabView?.panes
-        for pane in @getSingleton('mainView').mainTabView.panes
-          msg = no
-
-          # For open Tabs (apps, editors)
-          if pane.getOptions().type is "application" and pane.getOptions().name isnt "New Tab"
-            msg = "Please make sure that you saved all your work."
-
-          # This cssClass needs to be added to the KDInputView OR
-          # to the wrapper (for ace)
-          pane.data.$(".warn-on-unsaved-data").each (i,element) =>
-
-            checkForUnsavedData = (el)=>
-              foundUnsavedData = no
-
-              # ACE-specific content check
-              $(el).find(".ace_editor div.ace_line > span").each (i,e)=>
-                if $(e).text()
-                  foundUnsavedData = yes
-
-              foundUnsavedData
-
-            # If the View is a KDInputview, we don"t need to look
-            # further than the .val(). For ACE and others, we call
-            # the checkForUnsavedData function above
-            if ($(element).hasClass("kdinput") and $(element).val() or checkForUnsavedData(element))
-              msg = "You may lose some input that you filled in."
-
-
-      if msg # has to be created in the above checks
-        event or= window.event
-        event.returnValue = msg if event # For IE and Firefox prior to version 4
-        return msg
+    window.addEventListener 'beforeunload', @bound "beforeUnload"
+
+  beforeUnload:(event)->
+
+    # fixme: fix this with appmanager
+
+    if @getSingleton('mainView')?.mainTabView?.panes
+      for pane in @getSingleton('mainView').mainTabView.panes
+        msg = no
+
+        # For open Tabs (apps, editors)
+        if pane.getOptions().type is "application" and pane.getOptions().name isnt "New Tab"
+          msg = "Please make sure that you saved all your work."
+
+        # This cssClass needs to be added to the KDInputView OR
+        # to the wrapper (for ace)
+        pane.data.$(".warn-on-unsaved-data").each (i,element) =>
+
+          checkForUnsavedData = (el)=>
+            foundUnsavedData = no
+
+            # ACE-specific content check
+            $(el).find(".ace_editor div.ace_line > span").each (i,e)=>
+              if $(e).text()
+                foundUnsavedData = yes
+
+            foundUnsavedData
+
+          # If the View is a KDInputview, we don"t need to look
+          # further than the .val(). For ACE and others, we call
+          # the checkForUnsavedData function above
+          if ($(element).hasClass("kdinput") and $(element).val() or checkForUnsavedData(element))
+            msg = "You may lose some input that you filled in."
+
+
+    if msg # has to be created in the above checks
+      event or= window.event
+      event.returnValue = msg if event # For IE and Firefox prior to version 4
+      return msg
+
+

   setDragInAction:(action = no)->


Show on Strava button in activity view

Show on Strava button in activity view

--- client.coffee
+++ client.coffee
@@ -117,12 +117,16 @@
 				Page.state.set 2, activity.key()

 	Dom.div !->
-		activity = group.ref(Page.state.get(2))
+		activityId = Page.state.get(2)
+		activity = group.ref(activityId)
 		Dom.div !->
-			Dom.text tr("%1 km in %2 minutes averaging %3 km/h",
+			Dom.text tr("%1 km in %2 minutes averaging %3 km/h.",
 				round(activity.get('distance')*.001,2),
 				round(activity.get('duration')/60),
 				round(activity.get('distance')*3.6/activity.get('duration'),2))
+
+			Ui.button tr("Show on Strava"), !->
+				Plugin.openUrl "https://www.strava.com/activities/#{activityId}"

 	Social.renderComments path: [period, id]


fix bug

fix bug

--- views/akashic-advanced-module.cjsx
+++ views/akashic-advanced-module.cjsx
@@ -244,7 +244,7 @@
         retData.push logItem[9]
         retData
       data = data.filter (log) ->
-        log.length is 8
+        log.length is 9
     else
       e = new Error()
       e.message = "不支持的编码或文件格式！"


o Separate configuration files for development and production mode

--- simple_tiles.coffee
+++ simple_tiles.coffee
@@ -4,10 +4,13 @@
 path = require("path")
 fs = require("fs")

-nconf.argv().
-    env().
-    file({ file: 'simple_tiles.cfg' }).
-    file({ file: '/etc/simple_tiles.cfg' })
+app = module.exports = express.createServer()
+
+
+if app.settings.env == "development"
+    nconf.argv().env().file({ file: 'simple_tiles.cfg' })
+else
+    nconf.argv().env().file({ file: '/etc/simple_tiles.cfg' })

 nconf.defaults({
     'port': 3000,
@@ -16,8 +19,6 @@
     'layers': []
 })

-
-app = module.exports = express.createServer()

 if nconf.get('logfile') == 'console'
     app.use express.logger({ format: 'tiny' })


Corrected inconsistencies in snippet definitions

- incorrect title for Rightarrow definition
- mathit and mathbf defined twice
- prefix bb used for mathrm already used for mathbb -> propose prefix rm for mathrm

--- snippets/latex.cson
+++ snippets/latex.cson
@@ -143,7 +143,7 @@
   'longrightarrow':
     'prefix': 'rightarrow'
     'body': 'longrightarrow'
-  'Leftarrow':
+  'Rightarrow':
     'prefix': 'Rar'
     'body': '\\\\Rightarrow'
   'Longrightarrow':
@@ -180,14 +180,8 @@
   'mathbb':
     'prefix': 'bb'
     'body': '\\\\mathbb{$1}$0'
-  'mathit':
-    'prefix': 'it'
-    'body': '\\\\mathit{$1}$0'
-  'mathbf':
-    'prefix': 'bf'
-    'body': '\\\\mathbf{$1}$0'
   'mathrm':
-    'prefix': 'bb'
+    'prefix': 'rm'
     'body': '\\\\mathrm{$1}$0'
   'mathsf':
     'prefix': 'sf'


Ignore both .cache and .archive and other hidden files in finding output files

--- services/clsi/app/coffee/OutputFileFinder.coffee
+++ services/clsi/app/coffee/OutputFileFinder.coffee
@@ -29,7 +29,7 @@
 			_callback(error, fileList)
 			_callback = () ->

-		args = [directory, "-name", ".cache", "-prune", "-o", "-type", "f", "-print"]
+		args = [directory, "-name", ".*", "-prune", "-o", "-type", "f", "-print"]
 		logger.log args: args, "running find command"

 		proc = spawn("find", args)


fix deletion not working when first element is blank

--- app/scripts/editor.coffee
+++ app/scripts/editor.coffee
@@ -172,7 +172,7 @@
 				@status.cmd = true
 				$('.cmd').removeClass('hidden')
 			when 8
-				if $('#editor').html().match /^<(h1|h2|p|pre|code) name=".{4}">
<\/(h1|h2|p|pre|code)>/
+				if $('#editor').html().match /^<(h1|h2|p|pre|code) name=".{4}">
<\/(h1|h2|p|pre|code)>$/
 					e.preventDefault()
 					e.stopPropagation()


set routes

set routes

--- app/scripts/routes.coffee
+++ app/scripts/routes.coffee
@@ -1,3 +1,3 @@
-@Yabyap.Router.map (->
-
+@Clean.Router.map (->
+
 )


syncer: fixing bug where error handler wasn't being called properly

--- shared/syncer.coffee
+++ shared/syncer.coffee
@@ -41,7 +41,8 @@
       # Pass through the statusCode, so lower-level code can handle i.e. 401 properly.
       body.status = err.status
       if options.error
-        options.error(model, body)
+        # This `error` has signature of $.ajax, not Backbone.sync.
+        options.error(body)
       else
         throw err
     else


Simplify how we remove user-defined search paths

--- atom/browser/lib/init.coffee
+++ atom/browser/lib/init.coffee
@@ -7,28 +7,21 @@
 # we need to restore it here.
 process.argv.splice 1, 1

-# Add browser/api/lib to require's search paths,
-# which contains javascript part of Atom's built-in libraries.
+# Global module search paths.
+globalPaths = module.globalPaths
+
+# Don't lookup modules in user-defined search paths, see http://git.io/vf8sF.
 homeDir =
   if process.platform is 'win32'
     process.env.USERPROFILE
   else
     process.env.HOME
+if homeDir  # Node only add user-defined search paths when $HOME is defined.
+  userModulePath = path.resolve homeDir, '.node_modules'
+  globalPaths.splice globalPaths.indexOf(userModulePath), 2

-syspath = []
-
-if homeDir
-  syspath.push(path.resolve(homeDir, '.node_modules'))
-  syspath.push(path.resolve(homeDir, '.node_libraries'))
-
-# Remove system paths from module lookups as it may contain modules not
-# shipped with the app or compiled with wrong v8 headers.
-syspath.map (path) ->
-  index = module.globalPaths.indexOf path
-  if index > -1
-    module.globalPaths.splice(index,1)
-
-globalPaths = module.globalPaths
+# Add browser/api/lib to module search paths, which contains javascript part of
+# Electron's built-in libraries.
 globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')

 # Import common settings.


Upgrade SpacePen to 98bd6cf5f62e596bb6bfcff8e2dcea07ce007de4 to get views w/ multiple args

--- vendor/space-pen.coffee
+++ vendor/space-pen.coffee
@@ -1,5 +1,4 @@
-# Modified from e2c7296822952f9dcb4b7d3a39e16cca7b5dd462
-# Add require 'jquery'
+# Modified from 98bd6cf5f62e596bb6bfcff8e2dcea07ce007de4 -- add require `jquery`
 $ = jQuery = require('jquery')

 elements =
@@ -58,8 +57,8 @@
     step(fragment) for step in postProcessingSteps
     fragment

-  constructor: (params={}) ->
-    [html, postProcessingSteps] = @constructor.buildHtml -> @content(params)
+  constructor: (args...) ->
+    [html, postProcessingSteps] = @constructor.buildHtml -> @content(args...)
     jQuery.fn.init.call(this, html)
     @constructor = jQuery # sadly, jQuery assumes this.constructor == jQuery in pushStack
     @wireOutlets(this)
@@ -67,7 +66,7 @@
     @find('*').andSelf().data('view', this)
     @attr('triggerAttachEvents', true)
     step(this) for step in postProcessingSteps
-    @initialize?(params)
+    @initialize?(args...)

   buildHtml: (params) ->
     @constructor.builder = new Builder
@@ -79,7 +78,9 @@
   wireOutlets: (view) ->
     @find('[outlet]').each ->
       element = $(this)
-      view[element.attr('outlet')] = element
+      outlet = element.attr('outlet')
+      view[outlet] = element
+      element.attr('outlet', null)

   bindEventHandlers: (view) ->
     for eventName in events
@@ -164,15 +165,16 @@

 # Trigger attach event when views are added to the DOM
 triggerAttachEvent = (element) ->
-  if element.attr?('triggerAttachEvents') and element.parents('html').length
+  if element?.attr?('triggerAttachEvents') and element.parents('html').length
     element.find('[triggerAttachEvents]').add(element).trigger('attach')

 for methodName in ['append', 'prepend', 'after', 'before']
   do (methodName) ->
     originalMethod = $.fn[methodName]
     jQuery.fn[methodName] = (args...) ->
-      result = originalMethod.apply(this, args)
-      triggerAttachEvent(args[0])
+      flatArgs = [].concat args...
+      result = originalMethod.apply(this, flatArgs)
+      triggerAttachEvent arg for arg in flatArgs
       result

 for methodName in ['prependTo', 'appendTo', 'insertAfter', 'insertBefore']


Amend: remove unused params

Amend: remove unused params

--- services/filestore/app/coffee/BucketController.coffee
+++ services/filestore/app/coffee/BucketController.coffee
@@ -9,7 +9,6 @@
 	getFile: (req, res)->
 		{bucket} = req.params
 		key = req.params[0]
-		{format, style} = req.query
 		credentials = settings.filestore.s3[bucket]
 		options = {
 			key: key,
@@ -20,11 +19,11 @@
 		logger.log key:key, bucket:bucket, "receiving request to get file from bucket"
 		FileHandler.getFile bucket, key, options, (err, fileStream)->
 			if err?
-				logger.err err:err, key:key, bucket:bucket, format:format, style:style, "problem getting file from bucket"
+				logger.err err:err, key:key, bucket:bucket, "problem getting file from bucket"
 				if err instanceof Errors.NotFoundError
 					return res.send 404
 				else
 					return res.send 500
 			else
-				logger.log key:key, bucket:bucket, format:format, style:style, "sending bucket file to response"
+				logger.log key:key, bucket:bucket, "sending bucket file to response"
 				fileStream.pipe res


FIX: Ensure redirect to home if project id is missing

--- src/app/projects/states/index/index.coffee
+++ src/app/projects/states/index/index.coffee
@@ -20,7 +20,7 @@
 .controller("ProjectsIndexStateCtrl", ($scope, $rootScope, $state, $stateParams, UnitRole, unitService, projectService, listenerService) ->
   # Error - required projectId is missing!
   projectId = +$stateParams.projectId
-  return $state.go('home') unless projectId?
+  return $state.go('home') unless projectId

   # Load in project
   projectService.getProject(projectId, null,


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/approachable.coffee
+++ src/approachable.coffee
@@ -8,7 +8,7 @@

       I[name] = I[name].approach(target, approachBy)

-  addCooldown: (name, value=100, options={target: 0, approachBy: 1}) ->
+  addCooldown: (name, options={target: 0, approachBy: 1, value: 100}) ->
     unless I.cooldowns[name]
       I.cooldowns[name] = options
       I[name] = value


Return false when app is not defined on config method

--- lib/assets/javascript/init.js.coffee
+++ lib/assets/javascript/init.js.coffee
@@ -55,6 +55,7 @@
         @App.currentModules.push @initView(module)

   config: (name)->
+    return false unless @App?
     @App.configs = { turbolinks: true, pjax: false } unless @App.configs
     return @App.configs[name] if @App.configs and @App.configs[name]


Fix NPC migration

Fix NPC migration

--- db/migrations/seed_npcs.coffee
+++ db/migrations/seed_npcs.coffee
@@ -1,7 +1,7 @@
 mongoose = require("mongoose")
 User = mongoose.model("User")

-users = require("../fixtures/npc")
+users = require("../fixtures/npcs")

 exports.up = (next) ->
   users = users.map (user) ->


main.coffee -> a small error

main.coffee -> a small error

--- src/backend/main.coffee
+++ src/backend/main.coffee
@@ -14,4 +14,4 @@
     chunksTimeout: CONFIGS.CHUNKS_TIMEOUT

 rfid.run()
-.on 'data-received' dataStorage.log
+.on 'data-received', dataStorage.log


Fix #116. Switch from setText to setTextViaDiff, preserve folds

--- src/beautify.coffee
+++ src/beautify.coffee
@@ -117,7 +117,7 @@
           else

             # console.log "setText"
-            editor.setText text
+            editor.getBuffer().setTextViaDiff(text)

           # console.log "setCursors"
           setCursors editor, posArray


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/core_object.coffee
+++ test/core_object.coffee
@@ -51,7 +51,7 @@
     test: true

   o = Core()
-
+
   o.include(M)
   o.include(M)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/cooldown.coffee
+++ src/cooldown.coffee
@@ -29,7 +29,7 @@

     player.I.shootTimer # => 9

-    # Tur
+    # Turbo
     player = GameObject()

     # by default the cooldown


cooldown finilazation

cooldown finilazation

--- src/cooldown.coffee
+++ src/cooldown.coffee
@@ -10,7 +10,7 @@

   cooldown: (name, options={}) ->
     {target, approachBy, value} = options
-    options.target ||= 0
+    target ||= 0
     options.approachBy = 1 unless options.approachBy?

     unless I.cooldowns[name]


bounded

bounded

--- src/bounded.coffee
+++ src/bounded.coffee
@@ -94,22 +94,22 @@
   and increased if collision margin is negative.

-    player = Core
-      collisionMargin:
-        x: -2
-        y: -4
-      x: 50
-      y: 50
-      width: 20
-      height: 20
-
-    player.include(Bounded)
-
-    player.collisionBounds()
-    => {x: 38, y: 36, height: 28, width: 24}
-
-    player.collisionBounds(10, 10)
-    => {x: 48, y: 46, height: 28, width: 24}
+  player = Core
+    collisionMargin:
+      x: -2
+      y: -4
+    x: 50
+    y: 50
+    width: 20
+    height: 20
+
+  player.include(Bounded)
+
+  player.collisionBounds()
+  => {x: 38, y: 36, height: 28, width: 24}
+
+  player.collisionBounds(10, 10)
+  => {x: 48, y: 46, height: 28, width: 24}

   @name collisionBounds


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/clamp_bounds.coffee
+++ src/clamp_bounds.coffee
@@ -6,6 +6,6 @@
     height: 32

   self.bind "update", ->
-    de
+    log App.
     I.x = I.x.clamp(I.width / 2, App.width - I.width / 2)
     I.y = I.y.clamp(I.height / 2, App.height - I.height / 2)


:lipstick:

:lipstick:

--- src/coffee-cache.coffee
+++ src/coffee-cache.coffee
@@ -5,20 +5,23 @@
 CoffeeScript = require 'coffee-script'
 mkdir = require('mkdirp').sync

-getCachePath = (coffeeContents)->
-  digest = crypto.createHash('sha1').update(coffeeContents, 'utf8').digest('hex')
+getCachePath = (coffee) ->
+  digest = crypto.createHash('sha1').update(coffee, 'utf8').digest('hex')
   path.join('/tmp/atom-compile-cache/coffee', "#{digest}.coffee")

+getCachedJavaScript = (cachePath) ->
+  try
+    fs.readFileSync(cachePath, 'utf8') if fs.statSync(cachePath).isFile()
+
+compileCoffeeScript = (coffee, filePath, cachePath) ->
+  js = CoffeeScript.compile(coffee, filename: filePath)
+  try
+    mkdir(path.dirname(cachePath))
+    fs.writeFileSync(cachePath, js)
+  js
+
 require.extensions['.coffee'] = (module, filePath) ->
-  coffeeContents = fs.readFileSync(filePath, 'utf8')
-  cachePath = getCachePath(coffeeContents)
-  try
-    jsContents = fs.readFileSync(cachePath, 'utf8') if fs.statSync(cachePath).isFile()
-
-  unless jsContents?
-    jsContents = CoffeeScript.compile(coffeeContents, filename: filePath)
-    try
-      mkdir(path.dirname(cachePath))
-      fs.writeFileSync(cachePath, jsContents)
-
-  module._compile(jsContents, filePath)
+  coffee = fs.readFileSync(filePath, 'utf8')
+  cachePath = getCachePath(coffee)
+  js = getCachedJavaScript(cachePath) ? compileCoffeeScript(coffee, filePath, cachePath)
+  module._compile(js, filePath)


Do not re-throw error.

Do not re-throw error.

- Add temporarily some progress feedback

--- src/coffee/utils.coffee
+++ src/coffee/utils.coffee
@@ -99,16 +99,19 @@
 # @param {Integer} index Index of the date to start with (default: 0)
 # @return {Array} Promise results to write into
 ###
-exports.batchSeq = (rest, createPromise, data, index = 0, allResult = []) =>
+exports.batchSeq = (rest, createPromise, data, index = 0, allResult = [], percent = 0) =>
   createPromise(rest, data[index])
   .then (result) =>
+    dataSize = _.size(data)
+    newIndex = index + 1
+    donePercent = _s.numberFormat((newIndex * 100) / dataSize)
+    if (donePercent - percent) >= 1
+      console.log "Processed #{newIndex} out of #{dataSize}. Done: #{donePercent}%"
     newResult = allResult.concat result
-    if (index + 1) < _.size(data)
-      @batchSeq(rest, createPromise, data, index + 1, newResult)
+    if (newIndex) < dataSize
+      @batchSeq(rest, createPromise, data, newIndex, newResult, donePercent)
     else
       Q(newResult)
-  .fail (error) ->
-    throw error

 ###
 # Returns localized values for all detected languages.


Implement tool tips for cichart

Implement tool tips for cichart

--- src/cichart.coffee
+++ src/cichart.coffee
@@ -93,20 +93,6 @@
         xscale = myframe.xscale()
         yscale = myframe.yscale()

-        tip = d3.tip()
-                .attr('class', "d3-tip #{tipclass}")
-                .html((d,i) ->
-                      index = i % mean.length
-                      f = d3panels.formatAxis([low[index],mean[index]], 1)
-                      "#{f(mean[index])} (#{f(low[index])} - #{f(high[index])})")
-                .direction(() ->
-                    return 'n' if horizontal
-                    'e')
-                .offset(() ->
-                    return [-10,0] if horizontal
-                    [0,10])
-        svg.call(tip)
-
         segmentGroup = svg.append("g").attr("id", "segments")

         # lines from low to high
@@ -130,8 +116,6 @@
                 .attr("stroke", (d,i) -> vertsegcolor[i])
                 .attr("stroke-width", segstrokewidth)
                 .attr("shape-rendering", "crispEdges")
-                .on("mouseover.paneltip", tip.show)
-                .on("mouseout.paneltip", tip.hide)

         # lines at low, mean, and high
         yval = mean.concat(low,high)
@@ -168,8 +152,13 @@
                 .attr("stroke", (d,i) -> segcolor[i % mean.length])
                 .attr("stroke-width", segstrokewidth)
                 .attr("shape-rendering", "crispEdges")
-                .on("mouseover.paneltip", tip.show)
-                .on("mouseout.paneltip", tip.hide)
+
+        direction = if horizontal then "north" else "east"
+        tipfunc = (d,i) ->
+                      index = i % mean.length
+                      f = d3panels.formatAxis([low[index],mean[index]], 1)
+                      "#{f(mean[index])} (#{f(low[index])} - #{f(high[index])})"
+        tip = d3panels.tooltip_create(d3.select("body"), segments, {direction:direction,tipclass:tipclass}, tipfunc)

         # move box to front
         myframe.box().raise()
@@ -184,7 +173,7 @@
     # function to remove chart
     chart.remove = () ->
                       svg.remove()
-                      tip.destroy()
+                      d3panels.tooltip_destroy(tip)
                       return null

     # return the chart function


remove the fork2 server command

remove the fork2 server command

--- src/cli/cli.coffee
+++ src/cli/cli.coffee
@@ -2,7 +2,7 @@
   require("./help")
   require("./compile-template")
   require("./build-project")
-  require("./server")
+  # require("./server")
   require("./run")
 ]


Use git .apmrc setting in develop command

--- src/develop.coffee
+++ src/develop.coffee
@@ -54,16 +54,17 @@
         callback("Request for package information failed: #{message}")

   cloneRepository: (repoUrl, packageDirectory, options) ->
-    command = "git"
-    args = ['clone', '--recursive', repoUrl, packageDirectory]
-    process.stdout.write "Cloning #{repoUrl} "
-    @spawn command, args, (code, stderr='', stdout='') =>
-      if code is 0
-        @logSuccess()
-        @installDependencies(packageDirectory, options)
-      else
-        @logFailure()
-        options.callback("#{stdout}\n#{stderr}".trim())
+    config.getSetting 'git', (command) =>
+      command ?= "git"
+      args = ['clone', '--recursive', repoUrl, packageDirectory]
+      process.stdout.write "Cloning #{repoUrl} "
+      @spawn command, args, (code, stderr='', stdout='') =>
+        if code is 0
+          @logSuccess()
+          @installDependencies(packageDirectory, options)
+        else
+          @logFailure()
+          options.callback("#{stdout}\n#{stderr}".trim())

   installDependencies: (packageDirectory, options) ->
     process.chdir(packageDirectory)


Fix bug where includes without dependencies were ignored

--- src/enfield.coffee
+++ src/enfield.coffee
@@ -382,6 +382,7 @@

   # Grab the plain contents of all files, including within subdirectories
   contents = {}
+  noDependencies = []
   dependencyEdges = []
   files = ['']
   while files.length
@@ -399,17 +400,17 @@
       matches = content.match includeRegExp

       if matches
-        dependencies = matches.map (str) ->
+        for match in matches
           match = str.match /\{%\s*include\s+([^\s%]+)\s*%\}/im
           dependencyEdges.push [filepath, match[1]]
       else
-        dependencies = []
+        noDependencies.push filepath

   # Topological sort for processing includes since tinyliquid needs includes to
   # be precompiled
   # Note, can contain dupes
   try
-    sorted = toposort(dependencyEdges).reverse()
+    sorted = noDependencies.concat toposort(dependencyEdges).reverse()
   catch err
     console.error "Error: Cyclic dependency within includes".red
     console.error err.toString()


do not test existence of app data dir on linux

--- src/fs-plus.coffee
+++ src/fs-plus.coffee
@@ -53,14 +53,13 @@
   # Linux: /var/lib
   getAppDataDirectory: ->
     if process.platform is 'win32'
-      return process.env.APPDATA
+      process.env.APPDATA
     else if process.platform is 'darwin'
-      return fsPlus.absolute '~/Library/Application Support'
+      fsPlus.absolute '~/Library/Application Support'
     else if process.platform is 'linux'
-      dir = '/var/lib'
-      return dir if fsPlus.existsSync dir
-
-    null
+      '/var/lib'
+    else
+      null

   # Public: Is the given path absolute?
   #


with query

with query

--- src/grammar.coffee
+++ src/grammar.coffee
@@ -13,11 +13,25 @@

   Root: [
     o 'Query EOF'
+    o "WithQuery EOF"
   ]

   Query: [
     o "SelectQuery"
     o "SelectQuery Unions",                                -> $1.unions = $2; $1
+  ]
+
+  WithQuery: [
+    o "WITH NamedQueries Query",                     -> new WithQuery($2, $3)
+  ]
+
+  NamedQueries: [
+    o "NamedQuery",                                         -> [$1]
+    o "NamedQueries SEPARATOR NamedQuery",                  -> $1.concat($3)
+  ]
+
+  NamedQuery: [
+    o "Literal AS LEFT_PAREN Query RIGHT_PAREN",    -> new NamedQuery($1, $4)
   ]

   SelectQuery: [


Make scopesFromStack an instance method

Make scopesFromStack an instance method

--- src/grammar.coffee
+++ src/grammar.coffee
@@ -183,5 +183,5 @@
   getMaxTokensPerLine: ->
     @maxTokensPerLine

-  scopesFromStack = (stack) ->
+  scopesFromStack: (stack) ->
     _.compact(_.pluck(stack, "scopeName"))


Add 'type instance' keyword

Add 'type instance' keyword

--- src/haskell.coffee
+++ src/haskell.coffee
@@ -273,7 +273,7 @@
       ]
     ,
       name: 'meta.declaration.type.type.haskell'
-      begin: /{maybeBirdTrack}(\s*)(type(?:\s+family)?)\s+({typeDecl})/
+      begin: /{maybeBirdTrack}(\s*)(type(?:\s+(?:family|instance))?)\s+({typeDecl})/
       end: /{indentBlockEnd}|(?=\bwhere\b)/
       contentName: 'meta.type-signature.haskell'
       beginCaptures:


Add serialization version to History

Add serialization version to History

This is required because we dropped `markerPatches` from the serialized
data for `BufferPatch`, which causes exceptions when deserializing in
older versions.

--- src/history.coffee
+++ src/history.coffee
@@ -9,6 +9,7 @@
 # Manages undo/redo for {TextBuffer}
 module.exports =
 class History extends Serializable
+  @version: 1
   @registerDeserializers(Transaction, BufferPatch)

   currentTransaction: null


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/controllable.coffee
+++ src/controllable.coffee
@@ -11,7 +11,7 @@
     x: 15
     y: 30

-  # hold one of th
+  # hold one of the move

   # update the player so ClampBounds can set
   # his position back inside the viewport.


Use fs.stat to traverse directores

Use fs.stat to traverse directores

--- src/core/content.coffee
+++ src/core/content.coffee
@@ -189,7 +189,7 @@
     ### Create plugin or subtree instance for *filepath*. ###
     setImmediate ->
       async.waterfall [
-        async.apply fs.lstat, filepath.full
+        async.apply fs.stat, filepath.full
         (stats, callback) ->
           basename = path.basename filepath.relative


tabs replaced with spaces as indentation

--- src/kamuran.coffee
+++ src/kamuran.coffee
@@ -11,49 +11,49 @@
 places = require '../places.json'

 request.get 'https://raw.githubusercontent.com/egemsoft/kamuran/master/places.json', (error, response, body) ->
-	if !error and response.statusCode is 200
-  	places = JSON.parse body
+  if !error and response.statusCode is 200
+    places = JSON.parse body

   places.lunch = places.common.concat places.lunch
-	places.dinner = places.common.concat places.dinner
+  places.dinner = places.common.concat places.dinner

-	# unchain kamuran
-	do understand
+  # unchain kamuran
+  do understand

 suggestParams = [
-	'suggest'
-	'nereye gidelim'
-	'nereye gidelim?'
-	'nereye gideyim'
-	'nereye gideyim?'
-	'ne dersin'
-	'ne dersin?'
+  'suggest'
+  'nereye gidelim'
+  'nereye gidelim?'
+  'nereye gideyim'
+  'nereye gideyim?'
+  'ne dersin'
+  'ne dersin?'
 ]

 # return random responses
 suggestResponse = (place) ->
-	responses =[
-		"#{ place } hiç fena olmaz."
-		"#{ place } nasıl fikir?"
-		"Ne dersin, #{ place } uyar mı?"
-		"#{ place } iyidir #{ do place.toLowerCase }"
-		"Neden #{ place } olmasın?"
-	]
-	responses[Math.floor Math.random()*responses.length]
+  responses =[
+    "#{ place } hiç fena olmaz."
+    "#{ place } nasıl fikir?"
+    "Ne dersin, #{ place } uyar mı?"
+    "#{ place } iyidir #{ do place.toLowerCase }"
+    "Neden #{ place } olmasın?"
+  ]
+  responses[Math.floor Math.random()*responses.length]

 unknownResponse = ->
-	console.log 'Her şeyi bilmiyorum maalesef.'
+  console.log 'Her şeyi bilmiyorum maalesef.'

 # suggest a random place
 suggest = ->
-	date = new Date()
-	type = if date.getHours() < 14 then 'lunch' else 'dinner'
-	console.log suggestResponse places[type][Math.floor Math.random() * (places[type].length)]
+  date = new Date()
+  type = if date.getHours() < 14 then 'lunch' else 'dinner'
+  console.log suggestResponse places[type][Math.floor Math.random() * (places[type].length)]

 # understand the parameters
 understand = ->
-	return console.log 'Efendim?' if process.argv.length is 2
-	return do suggest if process.argv.length is 3 and suggestParams.indexOf(process.argv[2]) isnt -1
-	return do suggest if process.argv.length is 4 and suggestParams.indexOf(process.argv[2] + ' ' + process.argv[3]) isnt -1
-
-	return do unknownResponse+  return console.log 'Efendim?' if process.argv.length is 2
+  return do suggest if process.argv.length is 3 and suggestParams.indexOf(process.argv[2]) isnt -1
+  return do suggest if process.argv.length is 4 and suggestParams.indexOf(process.argv[2] + ' ' + process.argv[3]) isnt -1
+
+  return do unknownResponse


fix "NaN" appearing in generated tab sometimes

--- src/marktab.coffee
+++ src/marktab.coffee
@@ -289,7 +289,7 @@
 			notes = tabMap[stringNum]
 			line = @stringNames[stringNum] + "|-"
 			for note in notes
-				note = if note is undefined then '-' else note
+				note = if note isnt undefined && !_.isNaN(note) then note else '-'
 				noteLen = note.toString().length
 				numDashes = 3 - noteLen
 				line += note


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -118,7 +118,7 @@
   @name meter
   @methodOf Metered#
   @param {Object} options The meter configuration options
-  @param {}borderColor - Color of the meter's border
+  @param {String} borderColor - Color of the meter's border
     borderWidth - Width of the meter's border
     color - Color of the meter's inner rectangle
     nameColor - Color of the property name displayed above the meter


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -104,6 +104,14 @@
   player.include Metered

   player.meter 'health',
+
+  self.addMeter
+    showName: true
+    name: "health"
+    position:
+      x: 5
+      y: 5
+
   # =>
   </pre></code>


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -119,7 +119,7 @@
   @methodOf Metered#
   @param {Object} options The meter configuration options
   @param {String} borderColor - Color of the meter's border
-    borderWidth - Width of the meter's border
+  @param {Number} borderWidth - Width of the meter's border
     color - Color of the meter's inner rectangle
     nameColor - Color of the property name displayed above the meter
     font - Size and style of the meter's font


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -126,7 +126,7 @@
   @name meter
   @methodOf Metered#
   @param {Object} options The meter configuration options
-    borderColor - The color of the border
+    borderColor - The color of the meter's border
   ###
   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
@@ -106,7 +106,7 @@
   player.meter 'health',

-  self.addMeter
+  .addMeter
     showName: true
     name: "health"
     position:


Atom: Add git-history package

Atom: Add git-history package

--- atom/packages.cson
+++ atom/packages.cson
@@ -9,6 +9,7 @@
   "date"
   "elmjutsu"
   "file-icons"
+  "git-history"
   "git-plus"
   "highlight-selected"
   "language-elixir"


Add Elm Doc Comment Snippet

Add Elm Doc Comment Snippet

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -16,3 +16,11 @@
 # This file uses CoffeeScript Object Notation (CSON).
 # If you are unfamiliar with CSON, you can read more about it here:
 # https://github.com/bevry/cson#what-is-cson
+
+'.source.elm':
+  'Doc Comment':
+    'prefix': 'doc'
+    'body': """
+      {-| $1
+      -}
+    """


format snippets

format snippets

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -40,14 +40,16 @@
     'body': '''
       // pipe(...functions: [...Function]) => initial => result
       // Create a pipeline of functions to iterate over left to right
-      const pipe = (...functions) => initial => functions.reduce((accumulator, current) => current(accumulator), initial)
+      const pipe = (...functions) => initial =>
+        functions.reduce((accumulator, current) => current(accumulator), initial)
       '''
   'compose':
     'prefix': 'compose#functional'
     'body': '''
       // compose(...functions: [...Function]) => initial => result
       // Create a pipeline of functions to iterate over right to left
-      const compose = (...functions) => initial => functions.reduceRight((accumulator, current) => current(accumulator), initial)
+      const compose = (...functions) => initial =>
+        functions.reduceRight((accumulator, current) => current(accumulator), initial)
     '''
   'curry':
     'prefix': 'curry#functional'


Don't close verification modal when escape key is pressed

--- resources/assets/coffee/_classes/user-verification.coffee
+++ resources/assets/coffee/_classes/user-verification.coffee
@@ -137,8 +137,10 @@
       $('.js-user-verification--box').html html

     @$modal()
-    .modal backdrop: 'static'
-    .modal 'show'
+    .modal
+      backdrop: 'static'
+      keyboard: false
+      show: true
     .addClass 'js-user-verification--active'

     @reposition()


check if click started and ended on the same element

--- resources/assets/coffee/react/beatmapset-page/info.coffee
+++ resources/assets/coffee/react/beatmapset-page/info.coffee
@@ -42,12 +42,26 @@
     $(window).off '.beatmapsetPageInfo'

+  # onclick's event does not include where a click started.
+  # onclick's target is the outermost element that is involved in a click;
+  # starting a click on the outer element and ending on an inner element will have the outer element as the event target,
+  # likewise, starting on an inner element end ending on the outer element will still use the outer element as the event target.
   dismissEditor: (e) =>
-    @setState isEditing: false if e.target == @overlay
+    @setState isEditing: false if e.button == 0 &&
+                                  e.target == @overlay &&
+                                  @clickEndTarget == @clickStartTarget

   editStart: =>
     @setState isEditing: true
+
+
+  handleClickEnd: (e) =>
+    @clickEndTarget = e.target
+
+
+  handleClickStart: (e) =>
+    @clickStartTarget = e.target

   onEditorChange: (action) =>
@@ -131,6 +145,8 @@
           div
             className: 'beatmapset-description-editor__overlay'
             onClick: @dismissEditor
+            onMouseDown: @handleClickStart
+            onMouseUp: @handleClickEnd
             ref: (element) => @overlay = element

             div className: 'beatmapset-description-editor__container osu-page',


Treat anything with duration as playable

Fixes #4032

--- web/volume/slot.coffee
+++ web/volume/slot.coffee
@@ -298,7 +298,7 @@
         $scope.playing = 0
         return unless $scope.asset && isFinite(p = $scope.asset.segment.u)
         # look for something else to play:
-        for i in $scope.assets when i.asset && !i.asset.pending && i.asset.format.type == 'video' && i.asset.checkPermission(constants.permission.VIEW) && i.lBounded && i.ut.o > p
+        for i in $scope.assets when i.asset && i.asset.duration && !i.asset.pending && i.asset.checkPermission(constants.permission.VIEW) && i.lBounded && i.ut.o > p
           a = i
           break
         return unless a


guild icon

guild icon

--- src/coffee/controllers/player/player-overview-ctrl.coffee
+++ src/coffee/controllers/player/player-overview-ctrl.coffee
@@ -38,6 +38,7 @@
       'combat':           'fa-newspaper-o faa-pulse animated'
       'event':            'fa-gift faa-shake animated'
       'pet':              'fa-paw'
+      'guild':            'fa-network'

     $scope.praying = no
     $scope.prayText = 'Pray to RNGesus'


Bring back request - and show an error when talking to delta server fails

--- src/docker-utils.coffee
+++ src/docker-utils.coffee
@@ -6,6 +6,8 @@
 config = require './config'
 _ = require 'lodash'
 knex = require './db'
+
+{ request } = require './request'

 docker = Promise.promisifyAll(new Docker(socketPath: config.dockerSocket))
 # Hack dockerode to promisify internal classes' prototypes
@@ -56,7 +58,7 @@
 				onProgress(percentage: 100)
 			.on 'response', (res) ->
 				if res.statusCode isnt 200
-					reject()
+					reject(new Error("Got #{res.statusCode} when requesting image from delta server."))
 				else
 					resolve(res)
 			.on 'error', reject


Fix example loading

Fix example loading

--- spec/schemas.coffee
+++ spec/schemas.coffee
@@ -2,6 +2,7 @@
 tv4 = require 'tv4'
 chai = require 'chai' if not chai
 yaml = require 'js-yaml'
+path = require 'path'

 lib = require '../index'

@@ -21,7 +22,7 @@
   schemas.forEach (schema) ->
     describe "#{schema.id} (#{schema.title})", ->
       try
-        cases = lib.getExamples schemaName
+        cases = lib.getExamples path.basename schema.id, path.extname schema.id
       catch e
         it.skip "does not have examples"
         return


Fix integer type error

Fix integer type error

--- src/movable.coffee
+++ src/movable.coffee
@@ -53,7 +53,7 @@
   getPositionNum = (value) ->
     res = value.match /(\d+)px/
     if res?
-      res[1]
+      getNumberData(res[1])
     else
       0


cat says amount of meows as words

cat says amount of meows as words

--- cat.coffee
+++ cat.coffee
@@ -10,19 +10,19 @@
       .option '-c, --cat', 'have the cat talk in its native language'
       .parse process.argv

-    @say = cmd.args.join " "
-    @catSpeak = cmd.cat
+    @say = cmd.args
+    if cmd.cat
+      @say = _.map @say, (word) ->
+        return "Meow"
+    @say = @say.join " "

   run: =>
     @parseOptions()

     return @die new Error('No text specified') unless @say?
-    return @catsay "meow meow meow" if @catSpeak
-    @catsay @say

-  catsay: (text) =>
     console.log(" /\\_/\\ ")
-    console.log("( o.o )  ---#{text}")
+    console.log("( o.o )  ---#{@say}")
     console.log(" m   m ")

   die: (error) =>


attempt to parse JSON encoded errors

attempt to parse JSON encoded errors

--- src/flux/app.coffee
+++ src/flux/app.coffee
@@ -68,6 +68,10 @@
     {displayError} = requestDetails
     return unless displayError
     @_currentServerError = status
+    unless _.isObject(message)
+      try
+        message = JSON.parse(message)
+      catch e
     @emit('server-error', statusCode, message)

   setServerSuccess: (statusCode, message, requestDetails) ->


Move vars to higher scope, check for needed vars

In this way, we can DRY up the use of these vars, and also ensure
that they exist, which is necessary to work at all.

--- src/forecast.coffee
+++ src/forecast.coffee
@@ -29,6 +29,9 @@
 KV_KEY = 'forecast-alert-datapoint'
 LOCATION = process.env.HUBOT_LATITUDE + ',' + process.env.HUBOT_LONGITUDE
 PROBABILITY_THRESHOLD = process.env.HUBOT_FORECAST_PROBABILITY_THRESHOLD || 0.75
+FORECASTKEY = process.env.HUBOT_FORECAST_KEY
+UNITTYPE = process.env.HUBOT_FORECAST_UNITS || 'si'
+EXCLUDE = 'flags'

 activeDays = (process.env.HUBOT_FORECAST_DAYS ? 'mon,tue,wed,thu,fri')
   .toLowerCase()
@@ -44,6 +47,10 @@
 last_json = {}

 module.exports = (robot) ->
+  unless FORECASTKEY? and LOCATION?
+    return robot.logger.error 'hubot-forecast is not loaded due to missing configuration.
+      HUBOT_FORECAST_KEY, HUBOT_LATITUDE, & HUBOT_LONGITUDE are required.'
+
   postWeatherAlert = (json, callback) ->
     postMessage = callback
     now = new Date()
@@ -274,12 +281,8 @@
           handleWeather(json, callback)

   fetchForecast = (callback) ->
-    forecastKey = process.env.HUBOT_FORECAST_KEY
-    unitType = process.env.HUBOT_FORECAST_UNITS || 'si'
-    exclude = 'flags'
-
-    base_url = "https://api.forecast.io/forecast/#{forecastKey}/#{LOCATION}"
-    url = "#{base_url}?units=#{unitType}&exclude=#{exclude}"
+    base_url = "https://api.forecast.io/forecast/#{FORECASTKEY}/#{LOCATION}"
+    url = "#{base_url}?units=#{UNITTYPE}&exclude=#{EXCLUDE}"

     console.log "[Forecast] Requesting forecast data: #{url}"


Added default values reference in help message.

--- src/options.coffee
+++ src/options.coffee
@@ -72,20 +72,20 @@
   --version [-v]            : display version/build
   --help [-h]               : this help
   --delay [-d]              : add a delay (in ms) between requests
-                            : (default: 500, empty: random)
-  --debug [-D]              : enable more debug output (default: false)
-  --cache [-c]              : enable/disable cache (default: true)
-  --check [-C]              : enforce additional consistency checks (slower)
-  --force [-f]              : force overwrite if file exists (default: false)
-  --retries [-r]            : number of retries before giving up (default: 3)
+                            : (default: #{DEFAULT_OPTIONS['delay']}, empty: random)
+  --debug [-D]              : enable more debug output (default: #{DEFAULT_OPTIONS['debug']})
+  --cache [-c]              : enable/disable cache (default: #{DEFAULT_OPTIONS['cache']})
+  --check [-C]              : enforce additional consistency checks (slower) (default: #{DEFAULT_OPTIONS['check']})
+  --force [-f]              : force overwrite if file exists (default: #{DEFAULT_OPTIONS['force']})
+  --retries [-r]            : number of retries before giving up (default: #{DEFAULT_OPTIONS['retries']})
   --threads [-t]            : maximum simultaneous connections to tumblr.com
-                            : (default: 5)
+                            : (default: #{DEFAULT_OPTIONS['threads']})
   --retry-factor [-rf]      : if throttling, multiply delay by this factor
-                            : (default: 2)
-  --refresh-db [-rd]        : update database (default: true)
-  --refresh-photos [-rp]    : update photos (default: true)
+                            : (default: #{DEFAULT_OPTIONS['retry-factor']})
+  --refresh-db [-rd]        : update database (default: #{DEFAULT_OPTIONS['refresh-db']})
+  --refresh-photos [-rp]    : update photos (default: #{DEFAULT_OPTIONS['refresh-photos']})
   --startAt [-s]            : start at a specific index in the posts database
-                            : (default: 0)
+                            : (default: #{DEFAULT_OPTIONS['startAt']})
 """

 # Parse command line arguments and define global options.


add `setAttributes` `getAttribute` in util.

--- js/3panorama.coffee
+++ js/3panorama.coffee
@@ -115,6 +115,11 @@
                 domel.className += " " + clazz
             removeClass: (domel, clazz) ->
                 domel.className = domel.className.replace(new RegExp('(\\s|^)' + clazz + '(\\s|$)'), '')
+
+            getAttribute: (domel, attr) ->
+                return domel.getAttribute(attr)
+            setAttributes: (domel, options) ->
+                domel.setAttribute(key, val) for key,val of options

             css: (domel, options) ->
                 for property, value of options


Remove legacy static file

Remove legacy static file

--- serrano/static/serrano/scripts/coffeescript/models.coffee
+++ serrano/static/serrano/scripts/coffeescript/models.coffee
@@ -1,67 +0,0 @@
-define ['underscore', 'backbone'], (_, Backbone) ->
-
-    BRANCH_KEYS = ['children', 'type']
-    CONDITION_KEYS = ['id', 'operator', 'value']
-    LOGICAL_OPERATORS = ['and', 'or']
-
-    class DataField extends Backbone.Model
-        # Enables loading links provided by this resource. Pass in the name
-        # of the link to asynchronously load the resource. Once loaded,
-        # the data is locally cached. Pass `force` to reload the data from
-        # the server.
-        load: (name, callback, force=false) ->
-            # Shift arguments
-            if _.isBoolean(callback)
-                force = callback
-                callback = null
-            if @[name]? and not force
-                callback.apply @, @[name]
-                return
-
-            if not (link = @get('links')[name])
-                throw new Error "No link '#{name}', links available
-                    include: #{_.keys(@get 'links').join(', ')}"
-
-            Backbone.ajax
-                url: link.ref
-                success: (json) =>
-                    @[name] = json
-                    callback.apply @, json
-
-
-    class DataConcept extends Backbone.Model
-
-
-    class Query extends Backbone.Model
-
-
-
-    # Single condition node
-    class ConditionNode extends Backbone.Model
-        validate: (attrs) ->
-            for key in CONDITION_KEYS
-                if not attrs[key]?
-                    return "Property #{key} is required"
-
-
-    # Branch node
-    class BranchNode extends Backbone.Model
-        validate: (attrs) ->
-            for key in BRANCH_KEYS
-                if not attrs[key]?
-                    return "Property #{key} is required"
-            if attrs.children.length < 2
-                return 'Branch nodes must contain two or more child nodes.'
-
-
-    class Condition extends Backbone.Model
-        set: (attrs) ->
-
-
-    noConflict: ->
-
-
-    # Instance
-    session = new DataContextView
-
-    { session }


neo4j: fix type not populating for buckets in overview

--- server/lib/server/graph/decorators/bucket_activity.coffee
+++ server/lib/server/graph/decorators/bucket_activity.coffee
@@ -55,7 +55,7 @@
     overview =
       createdAt : [@convertToISO(createdAt)]
       ids       : [anchorId]
-      type      : @groupName
+      type      : @bucketName
       count     : 1

     return overview


replace deprecated res.send(code) with res.sendStatus(code)

--- services/spelling/app/coffee/SpellingAPIController.coffee
+++ services/spelling/app/coffee/SpellingAPIController.coffee
@@ -9,7 +9,7 @@
 		SpellingAPIManager.runRequest req.params.user_id, req.body, (error, result) ->
 			if error?
 				logger.err err:error, user_id:req?.params?.user_id, word_count: req?.body?.words?.length, "error processing spelling request"
-				return res.send(500)
+				return res.sendStatus(500)
 			res.send(result)

 	learn: (req, res, next) ->


Fix some trailing whitespace

Fix some trailing whitespace

--- vendor/assets/javascripts/brainstem/brainstem-collection.coffee
+++ vendor/assets/javascripts/brainstem/brainstem-collection.coffee
@@ -67,7 +67,7 @@

   fetch: (options) ->
     options = if options then _.clone(options) else {}
-
+
     options.parse = options.parse ? true
     options.name = options.name ? @model?.prototype.brainstemKey
     options.returnValues ?= {}
@@ -83,7 +83,7 @@
     Brainstem.Utils.wrapError(this, options)

     loader = base.data.loadObject(options.name, _.extend({}, @firstFetchOptions, options))
-
+
     @trigger('request', this, options.returnValues.jqXhr, options)

     loader.pipe(-> loader.internalObject.models)


Work around ghc-mod stack root bug

Work around ghc-mod stack root bug

--- lib/ghc-modi-process-redirect.coffee
+++ lib/ghc-modi-process-redirect.coffee
@@ -26,11 +26,12 @@
     options = Util.getProcessOptions(dir.getPath())
     options.timeout = atom.config.get('haskell-ghc-mod.syncTimeout')
     res = CP.spawnSync modPath, ['root'], options
-    dir = if res.error?
-      console.warn "Encountered #{res.error} while getting project root dir"
+    [path] = res.stdout.toString().split(EOL)
+    dir = if res.error? or not path
+      console.warn "Encountered error #{res.error} while getting project root dir"
       Util.getRootDir buffer
     else
-      d = new Directory res.stdout.toString().split(EOL)[0]
+      d = new Directory path
       unless d?.isDirectory?()
         console.warn "Ghc-mod returned non-directory while getting project root dir"
         Util.getRootDir buffer


Pan vs Pinch

Pan vs Pinch

--- framer/GestureInputRecognizer.coffee
+++ framer/GestureInputRecognizer.coffee
@@ -16,12 +16,13 @@
 		@session = null

 	touchstart: (event) =>
-
+		return if event.touches.length > 1
 		@em.wrap(window).addEventListener("touchmove", @touchmove)
 		@em.wrap(window).addEventListener("touchend", @touchend)

 		@session =
 			startEvent: @_getGestureEvent(event)
+			startMultiEvent: null
 			startTime: Date.now()
 			pressTimer: window.setTimeout(@longpressstart, 250)
 			started: {}
@@ -41,6 +42,7 @@
 		@_process(@_getGestureEvent(event))

 	touchend: (event) =>
+		return if event.touches.length != 0
 		@em.wrap(window).removeEventListener("touchmove", @touchmove)
 		@em.wrap(window).removeEventListener("touchend", @touchend)
 		event = @_getGestureEvent(event)
@@ -189,12 +191,16 @@

 		return unless @session

+		# if event.fingers > 1 and not not @session.startMultiEvent
+		# 	@session.startMultiEvent = event
+		# if event.fingers == 1
+		# 	@session.startMultiEvent = null
+
 		# Detect pan events
-		if event.fingers == 1
-			if not @session.started.pan and (Math.abs(event.offset.x) > 0 or Math.abs(event.offset.y) > 0)
-				@panstart(event)
-			else if @session.started.pan
-				@pan(event)
+		if not @session.started.pan and (Math.abs(event.offset.x) > 0 or Math.abs(event.offset.y) > 0)
+			@panstart(event)
+		else if @session.started.pan
+			@pan(event)

 		# Detect pinch, rotate and scale events
 		if @session.started.pinch and event.fingers == 1
@@ -249,7 +255,13 @@
 		if @session?.lastEvent
 			event.deltaTime = event.time - @session.lastEvent.time
 			event.previous = @session.lastEvent.point
-			event.delta = Utils.pointSubtract(event.point, event.previous)
+
+			if @session.lastEvent.fingers != event.fingers
+				event.delta = {x:0, y:0}
+			else if @session.lastEvent.fingers == event.fingers == 2
+				event.delta = Utils.pointSubtract(event.touchCenter, @session.lastEvent.touchCenter)
+			else
+				event.delta = Utils.pointSubtract(event.point, event.previous)

 		if event.touches.length > 0


increased Atom fontSize to 17

increased Atom fontSize to 17

--- dotfiles/config-atom/config.cson
+++ dotfiles/config-atom/config.cson
@@ -2,7 +2,7 @@
   welcome:
     showOnStartup: false
   editor:
-    fontSize: 16
+    fontSize: 17
     lineHeight: 1.1
     scrollPastEnd: true
     showIndentGuide: true


Chrome extension: add warning when settings cannot be persisted to localStorage

--- src/chromeExtension/components/016-settings.cjsx
+++ src/chromeExtension/components/016-settings.cjsx
@@ -19,10 +19,15 @@
     # From Redux.connect
     settings:             React.PropTypes.object.isRequired
     setShowClosedActions: React.PropTypes.func.isRequired
+  getInitialState: ->
+    fCanSave: true
+
+  componentDidMount: -> @checkLocalStorage()

   #-----------------------------------------------------
   render: ->

+      {@renderLocalStorageWarning()}
       <Icon
         icon="close"
         size="lg"
@@ -42,9 +47,27 @@

+  renderLocalStorageWarning: ->
+    return if @state.fCanSave
+

+      Changes to these settings can't be saved (beyond your current session)
+      due to your current Chrome configuration. Please visit
+      chrome://settings/content and
+      uncheck the option "Block third-party cookies and site
+      data". Then close the Chrome DevTools and open them again.
+

+
   #-----------------------------------------------------
   onClickShowClosedActions: (ev) ->
     @props.setShowClosedActions ev.target.checked
+
+  #-----------------------------------------------------
+  checkLocalStorage: ->
+    try
+      ls = localStorage.foo
+      @setState fCanSave: true
+    catch e
+      @setState fCanSave: false

 #-----------------------------------------------------
 _style =
@@ -64,7 +87,12 @@
     right: 5
     top: 5
     cursor: 'pointer'
-
+  localStorageWarning:
+    color: 'red'
+    border: "1px solid red"
+    padding: 15
+    marginBottom: 10
+    borderRadius: 2

 #-----------------------------------------------------
 connect = ReactRedux.connect mapStateToProps, mapDispatchToProps


Be careful not to emit wserror events before we're connected.

--- src/bot.coffee
+++ src/bot.coffee
@@ -437,6 +437,7 @@
   roomRegister: (roomId, callback) ->
     if @ws
       @ws.onclose = ->
+      @ws.onerror = ->
       @ws.close()
     @callback = ->
       rq = api: 'room.register', roomid: roomId


groups: Admin dashboard link changed to group settings

--- client/app/MainApp/sidebar/sidebarcontroller.coffee
+++ client/app/MainApp/sidebar/sidebarcontroller.coffee
@@ -66,7 +66,7 @@
           else if 'admin' in roles
             navController.removeItem dashboardLink  if @dashboardLink?
             @dashboardLink = navController.addItem
-              title     : 'Admin dashboard'
+              title     : 'Group Settings'
               type      : 'admin'
               loggedIn  : yes
               callback  : ->


fix a bug 将两个多选框删除

fix a bug
将两个多选框删除

--- lib/project/project-info-view.coffee
+++ lib/project/project-info-view.coffee
@@ -12,16 +12,6 @@
         @div style: "background-color: #f7ea57;", outlet: "warnPackageText", =>
           @label style: "font-weight: bolder; color: black;padding-left: 5px;padding-top: 5px;",outlet: "warnPackageTextLabel"

-
-      @div class: "checkbox", =>
-        @label =>
-          @input type: "checkbox", id: 'withRatchet'
-          @text('With Ratchet')
-
-      @div class: "checkbox", =>
-        @label =>
-          @input type: "checkbox", id: 'withBootstrap'
-          @text('With Bootstrap')

   initialize: (wizardView) ->
@@ -46,8 +36,6 @@
   onNext: (wizard) ->
     wizard.mergeOptions {
       name: @editor.originalText
-      bootstrap: @find('#withBootstrap').is(":checked")
-      ratchet: @find('#withRatchet').is(":checked")
     }
     wizard.nextStep()


Collaboration: Don't show my markers to me during the collaboration.

--- client/ide/lib/workspace/panes/ideeditorpane.coffee
+++ client/ide/lib/workspace/panes/ideeditorpane.coffee
@@ -6,6 +6,7 @@
 AceView            = require 'ace/aceview'
 IDEAce             = require '../../views/ace/ideace'
 IDEHelpers         = require '../../idehelpers'
+whoami             = require 'app/util/whoami'

 module.exports = class IDEEditorPane extends IDEPane
@@ -217,6 +218,7 @@
   setLineWidgets: (row, col, username) ->

     return  unless editor = @getEditor()
+    return  if username is whoami().profile.nickname

     oldWidget      = @lineWidgets[username]
     {renderer}     = editor


add a few more visual macro tests

add a few more visual macro tests

--- src/plotter.coffee
+++ src/plotter.coffee
@@ -389,8 +389,8 @@
         # are interpolation adds an eliptical (circular) arc to the path
         else if @mode is 'cw' or @mode is 'ccw'
           # throw if tool isn't a circle
-          if not @tools[@currentTool].stroke['stroke-linecap'] is 'round' and
-          not @trace.region
+          if not @trace.region and
+          not @tools[@currentTool].stroke['stroke-linecap'] is 'round'
             throw new Error "tool #{@currentTool} is not circular and cannot
                              stroke arcs"
           r = Math.sqrt end.i**2 + end.j**2


add full page creation

add full page creation

--- BackofficeBundle/Resources/public/coffee/FullPageFormView.coffee
+++ BackofficeBundle/Resources/public/coffee/FullPageFormView.coffee
@@ -21,6 +21,7 @@
   addEventOnForm: ->
     title = @title
     listUrl = @listUrl
+    displayedElements = @displayedElements
     $("form", @$el).on "submit", (e) ->
       e.preventDefault() # prevent native submit
       $(this).ajaxSubmit
@@ -29,6 +30,7 @@
             html: response
             title: title
             listUrl: listUrl
+            displayedElements: displayedElements
           )
       return
 )


:art: show number of free responses

:art: show number of free responses

--- src/components/task-teacher-review/exercise.cjsx
+++ src/components/task-teacher-review/exercise.cjsx
@@ -28,7 +28,7 @@
   render: ->
     {content, answers, answered_count} = @props
     {showAnswers} = @state
-    toggleAnswersText = 'View student text responses'
+    toggleAnswersText = "View student text responses (#{answered_count})"
     toggleAnswersText = 'Hide student text responses' if showAnswers

     # TODO: Assumes 1 question.


users belonging to multiple groups get stripes when colorized by that attribute

--- @client/histogram.coffee
+++ @client/histogram.coffee
@@ -147,6 +147,26 @@
     delete opinion_views.active_views.point_includers
   save opinion_views

+
+window.select_single_opinion = (user, opinions, created_by) ->
+  opinion_views = fetch 'opinion_views'
+  user_opinion = _.findWhere opinions, {user: user.key or user}
+  opinion_views.active_views.single_opinion_selected =
+    created_by: created_by
+    opinion: user_opinion.key
+    opinion_value: user_opinion.stance
+    get_salience: (u, opinion, proposal) =>
+      if (u.key or u) == user_opinion.user
+        1
+      else
+        .1
+    get_weight: (u, opinion, proposal) =>
+      if (u.key or u) == user_opinion.user
+        1
+      else
+        .1
+
+  clear_histogram_managed_opinion_views opinion_views, 'region_selected'

 window.Histogram = ReactiveComponent
   displayName : 'Histogram'
@@ -434,20 +454,13 @@
         user_key = ev.target.getAttribute('data-user')
         user_opinion = _.findWhere @opinions, {user: user_key}

-        is_deselection = (single_selection?.opinion == user_opinion.key || @weights[user_key] == 0 )
-        if is_deselection
-          clear_histogram_managed_opinion_views opinion_views
-        else
-          opinion_views.active_views.single_opinion_selected =
-            created_by: @props.key
-            opinion: user_opinion.key
-            opinion_value: user_opinion.stance
-            get_salience: (u, opinion, proposal) =>
-              if (u.key or u) == user_opinion.user
-                1
-              else
-                .1
-          clear_histogram_managed_opinion_views opinion_views, 'region_selected'
+        if user_opinion
+          is_deselection = (single_selection?.opinion == user_opinion.key || @weights[user_key] == 0 )
+          if is_deselection
+            clear_histogram_managed_opinion_views opinion_views
+          else
+            select_single_opinion user_key, @opinions, @props.key
+
       else
         max = @local.mouse_opinion_value + REGION_SELECTION_WIDTH
         min = @local.mouse_opinion_value - REGION_SELECTION_WIDTH
@@ -714,6 +727,7 @@
     backgrounded_page_avatar_style = _.extend {}, regular_avatar_style,
       opacity: .1

+
     # Draw the avatars in the histogram. Placement is determined by the physics sim
     opinion_views = fetch 'opinion_views'

@@ -722,6 +736,8 @@
     has_groups = !!groups
     if has_groups
       colors = get_color_for_groups groups
+
+

     DIV
@@ -761,10 +777,23 @@
           else
             avatar_style = _.extend {}, regular_avatar_style

-          if has_groups
-            group = @props.groups[user.key]?[0]
-            if group
+          if has_groups && @props.groups[user.key]?
+            if @props.groups[user.key].length == 1
+              group = @props.groups[user.key][0]
               avatar_style.backgroundColor = colors[group]
+            else
+              gcolors = []
+              for group in @props.groups[user.key]
+                gcolors.push colors[group]
+              gradient = ""
+              size = 1 / gcolors.length / 8
+              for gcolor,idx in gcolors
+                gradient += ", #{gcolor} #{100 * idx * size}%, #{gcolor} #{100 * (idx + 1) * size}%"
+
+              avatar_style.background = "repeating-linear-gradient(45deg #{gradient})"
+
+          if @props.backgrounded
+            avatar_style = _.extend {}, backgrounded_page_avatar_style

           pos = @props.histocache?.positions?[user.key]

@@ -790,18 +819,9 @@
           if stance > .01
             alt = "#{(stance * 100).toFixed(0)}%"
           else if stance < -.01
-            alt = "– #{(stance * -100).toFixed(0)}%"
+            alt = "–#{(stance * -100).toFixed(0)}%"
           else
             alt = translator "engage.histogram.user_is_neutral", "is neutral"
-
-          # alt += " #{o.stance}"
-          if opinion.explanation
-            paragraphs = safe_string(opinion.explanation).split(/(?:\r?\n)/g)
-            alt += "
Their explanation:
"
-
-            for paragraph in paragraphs
-              alt += "
#{paragraph}
"
-            alt += '

'

           avatar user,
@@ -810,7 +830,7 @@
             hide_tooltip: @props.backgrounded || salience < 1
             className: className
             alt: "<user>: #{alt}"
-            # anonymous: true
+            anonymous: customization('anonymize_everything')
             style: avatar_style
             set_bg_color: true
             custom_bg_color: has_groups && group


Update TestSuiteExample.coffee

Update TestSuiteExample.coffee

--- examples/TestSuiteExample.coffee
+++ examples/TestSuiteExample.coffee
@@ -1,10 +1,26 @@
 class TestSuiteExample
-
+
   name: "TestSuiteExample"

   suiteSetup: ()->

   setup: ->
+
+  testAsync: (test, done) ->
+    myAsyncFunction done((value) ->
+      test.isNotNull value
+    )
+
+  testIsValid: (test) ->
+    test.isTrue true
+
+  clientTestIsClient: (test) ->
+    test.isTrue Meteor.isClient
+    test.isFalse Meteor.isServer
+
+  serverTestIsServer: (test) ->
+    test.isTrue Meteor.isServer
+    test.isFalse Meteor.isClient

   tests: [
     {
@@ -34,4 +50,4 @@

   suiteTearDown: ->

-TestRunner.run(new TestSuiteExample())+TestRunner.run(new TestSuiteExample())


Use getValues() when iterating over buffers

--- src/project.coffee
+++ src/project.coffee
@@ -282,7 +282,7 @@
       task.on 'scan:paths-searched', (numberOfPathsSearched) ->
         options.onPathsSearched(numberOfPathsSearched)

-    for buffer in @buffers when buffer.isModified()
+    for buffer in @buffers.getValues() when buffer.isModified()
       filePath = buffer.getPath()
       matches = []
       buffer.scan regex, (match) -> matches.push match


Remove event comments, add method section comment

--- src/project.coffee
+++ src/project.coffee
@@ -20,19 +20,6 @@
 # Extended: Represents a project that's opened in Atom.
 #
 # An instance of this class is always available as the `atom.project` global.
-#
-# ## Events
-#
-# ### path-changed
-#
-# Extended: Emit when the project's path has changed. Use {::getPath} to get the new path
-#
-# ### buffer-created
-#
-# Extended: Emit when a buffer is created. For example, when {::open} is called, this is fired.
-#
-# * `buffer` {TextBuffer} the new buffer that was created.
-#
 module.exports =
 class Project extends Model
   atom.deserializers.add(this)
@@ -95,6 +82,10 @@
         deprecate 'Project::on is deprecated. Use event subscription methods instead.'
     EmitterMixin::on.apply(this, arguments)

+  ###
+  Section: Methods
+  ###
+
   serializeParams: ->
     path: @path
     buffers: _.compact(@buffers.map (buffer) -> buffer.serialize() if buffer.isRetained())


Creates a promise module to separate from jquery

--- src/hullbase.coffee
+++ src/hullbase.coffee
@@ -24,6 +24,10 @@
   define("__widget__$#{widgetName}@default", widgetDef)
   return widgetDef

+define 'promises', ['jquery'], ($)->
+  deferred: $.Deferred
+  when: $.when
+
 define ['lib/version', 'underscore'], (version, _) ->
   window.Hull.version ||= version
   window.Hull


Removed commented code

Removed commented code

--- coffeescript/sockets.coffee
+++ coffeescript/sockets.coffee
@@ -6,11 +6,9 @@
   imgur = require("./models/imgur")
   users = require("./models/user")
   Q = require("q")
-  #require "shelljs/global"

   io.use (socket, next) ->
     sessionStore socket.request, socket.request.res, next
-

   default_chat_id = "chat-123"

@@ -79,7 +77,6 @@
                 socket.broadcast.emit "url_data", data

           io.to(default_chat_id).emit "save_chat_message", result
-          #socket.broadcast.emit "save_chat_message", result

     socket.on "load_topic", (data) ->
       chat
@@ -92,7 +89,6 @@
         .save_topic(data)
         .then (result) ->
           io.to(default_chat_id).emit "topic", result
-          #socket.broadcast.emit "topic", result

     socket.on "load_rooms", (data) ->
       rooms
@@ -105,8 +101,6 @@
         .create(data)
         .then (result) ->
           io.to(default_chat_id).emit "room_created", result
-          #socket.broadcast.emit "room_created", result
-

     socket.on "signup", (data) ->
       error = (error) ->
@@ -130,17 +124,5 @@
         .login(data)
         .then success, error

-    # socket.on "update_platform", ->
-    #   if not which "git"
-    #     return
-
-    #   # Run external tool synchronously
-    #   shell_command = "git pull && npm install"
-    #   if (exec shell_command).code is 0
-    #     socket.emit "update_platform", true
-    #     socket.broadcast.emit "update_platform", true
-
-
     socket.on "get_online_count", (data) ->
-      #socket.emit "get_online_count", io.engine.clientsCount
       broadcastClientCount(data)


Fix apm test specs on Windows

Fix apm test specs on Windows

--- spec/test-spec.coffee
+++ spec/test-spec.coffee
@@ -28,15 +28,12 @@
       atomSpawn.callCount is 1

     runs ->
-      if process.platform is 'win32'
-        expect(atomSpawn.mostRecentCall.args[1][2].indexOf('atom')).not.toBe -1
-        expect(atomSpawn.mostRecentCall.args[1][2].indexOf('--dev')).not.toBe -1
-        expect(atomSpawn.mostRecentCall.args[1][2].indexOf('--test')).not.toBe -1
-      else
-        expect(atomSpawn.mostRecentCall.args[0]).toEqual 'atom'
-        expect(atomSpawn.mostRecentCall.args[1][0]).toEqual '--dev'
-        expect(atomSpawn.mostRecentCall.args[1][1]).toEqual '--test'
-        expect(atomSpawn.mostRecentCall.args[1][2]).toEqual specPath
+      # On Windows, there's a suffix (atom.cmd), so we only check that atom is _included_ in the path
+      expect(atomSpawn.mostRecentCall.args[0].indexOf('atom')).not.toBe -1
+      expect(atomSpawn.mostRecentCall.args[1][0]).toEqual '--dev'
+      expect(atomSpawn.mostRecentCall.args[1][1]).toEqual '--test'
+      expect(atomSpawn.mostRecentCall.args[1][2]).toEqual specPath
+      if process.platform isnt 'win32'
         expect(atomSpawn.mostRecentCall.args[2].streaming).toBeTruthy()

   describe 'returning', ->


Mention input file

Mention input file

--- src/cli.coffee
+++ src/cli.coffee
@@ -14,7 +14,7 @@

     Output the syntax highlighted HTML for a file.

-    If no file is specified then the text to highlight is read from standard in.
+    If no input file is specified then the text to highlight is read from standard in.

     If no output file is specified then the HTML is written to standard out.
   """


Fix PageComponent.wrap issue

Fix PageComponent.wrap issue

https://github.com/motif/company/issues/994

--- framer/Components/PageComponent.coffee
+++ framer/Components/PageComponent.coffee
@@ -116,12 +116,12 @@

 	setContentLayer: (contentLayer) ->
 		if @content
-			@_onAminateStop()
-			@content.off(Events.AnimationStart, @_onAminationStart)
-			@content.off(Events.AnimationStop, @_onAminationEnd)
+			@_onAnimationStop()
+			@content.off(Events.AnimationStart, @_onAnimationStart)
+			@content.off(Events.AnimationStop, @_onAnimationStop)
 		super contentLayer
-		@content.on(Events.AnimationStart, @_onAminationStart)
-		@content.on(Events.AnimationStop, @_onAminationEnd)
+		@content.on(Events.AnimationStart, @_onAnimationStart)
+		@content.on(Events.AnimationStop, @_onAnimationStop)

 	horizontalPageIndex: (page) ->
 		(_.sortBy(@content.children, (l) -> l.x)).indexOf(page)
@@ -140,18 +140,18 @@
 			@_previousPages.push(currentPage)
 			@emit("change:currentPage", {old:@previousPage, new:currentPage})

-	_onAminationStart: =>
+	_onAnimationStart: =>
 		@_isMoving = true
 		@_isAnimating = true
-		@content.on("change:frame", @_onAminationStep)
-
-	_onAminationStep: =>
+		@content.on("change:frame", @_onAnimationStep)
+
+	_onAnimationStep: =>
 		@emit(Events.Move, @content.point)

-	_onAminationEnd: =>
+	_onAnimationStop: =>
 		@_isMoving = false
 		@_isAnimating = false
-		@content.off("change:frame", @_onAminationStep)
+		@content.off("change:frame", @_onAnimationStep)

 	_scrollEnd: =>


Clarify docs.

Clarify docs.

--- src/chaplin/views/collection_view.coffee
+++ src/chaplin/views/collection_view.coffee
@@ -22,6 +22,7 @@
     # By default, fading in is done by javascript function which can be
     # slow on mobile devices. CSS animations are faster,
     # but require user's manual definitions.
+    # CSS classes used are: animated-item-view, animated-item-view-end.
     useCssAnimation: false

     # A collection view may have a template and use one of its child elements
@@ -359,6 +360,7 @@
       # Fade the view in if it was made transparent before
       if enableAnimation and included
         if @useCssAnimation
+          # Wait for DOM state change.
           setTimeout =>
             $viewEl.addClass 'animated-item-view-end'
           , 0


Set default settings

Set default settings

--- src/js/popup.coffee
+++ src/js/popup.coffee
@@ -20,16 +20,18 @@
     $title = $('').appendTo($li)
     link = ''
     link += '' + issue.title + ''
-    if localStorage.showLabels == 'yes'
+    if !localStorage.showLabels? or localStorage.showLabels == 'yes'
       $.each issue.labels, (idx, label)->
         link += '' + label.name + ''
     $title.append(link)
     $('ul', $repo).append($li)
-    if localStorage.showMergeable == 'yes' and issue.pull_request?.url
-      window.githubClient.get(issue.pull_request.url).done (data)->
-        state = data.mergeable_state
-        state = 'unknown' if ['clean', 'error', 'unknown', 'unstable', 'merged', 'dirty', 'closed-dirty'].indexOf(state) == -1
-        $title.append('

')
+
+    if !localStorage.showMergeable? or localStorage.showMergeable == 'yes'
+      if issue.pull_request?.url
+        window.githubClient.get(issue.pull_request.url).done (data)->
+          state = data.mergeable_state
+          state = 'unknown' if ['clean', 'error', 'unknown', 'unstable', 'merged', 'dirty', 'closed-dirty'].indexOf(state) == -1
+          $title.append('

')

 failurePage = (jqXHR, textStatus)->
   $list = $('#list')


modified

modified

--- src/jsonsina.coffee
+++ src/jsonsina.coffee
@@ -12,6 +12,16 @@
       year: 年份
       type: day,week,month
 ###
+n = 3
+
+retry = (symbol, err)->
+  if n > 0
+    n--
+    console.error "#{symbol} jsonsina.coffee >> history 將重試: ", err
+    history(param, callback)
+  else
+    throw "#{symbol} jsonsina.coffee >> history 已多次重試: #{err}"
+
 history = (param, callback)->
   if param.symbol.length < 5
     return callback '代碼不對',null
@@ -44,9 +54,6 @@

   request options, (error, res, string)->

-    retry = (err)->
-      console.error "#{c} jsonsina.coffee >> history 將重試: ", err
-      history(param, callback)

     if error?
       return retry(error)
@@ -68,7 +75,7 @@
           #console.log each
       else
         return retry('數據長度為 0')
-
+
       if res?.attempts > 1
         console.log(param.symbol,'數據請求次數: ', res.attempts)


rewirte: removeClass accepts multiple parameters

--- app/assets/javascripts/app/controllers/getting_started.js.coffee
+++ app/assets/javascripts/app/controllers/getting_started.js.coffee
@@ -19,7 +19,7 @@
     @fetch()

   release: =>
-    @el.removeClass('fit').removeClass('getstarted')
+    @el.removeClass('fit', 'getstarted')

   fetch: ->

@@ -74,7 +74,7 @@
     @fetch()

   release: =>
-    @el.removeClass('fit').removeClass('getstarted')
+    @el.removeClass('fit', 'getstarted')

   fetch: ->

@@ -171,14 +171,14 @@
     @$('.base').addClass('hide')
     @$('.base-outbound').removeClass('hide')
     @$('.base-inbound').addClass('hide')
-    @$('.wizard-controls .btn').text('Check').attr('data-form', 'base-outbound').addClass('btn--primary').removeClass('btn--danger').removeClass('btn--success')
+    @$('.wizard-controls .btn').text('Check').attr('data-form', 'base-outbound').addClass('btn--primary').removeClass('btn--danger', 'btn--success')
     @enable( @$('.btn') )

   showInbound: =>
     @$('.base').addClass('hide')
     @$('.base-outbound').addClass('hide')
     @$('.base-inbound').removeClass('hide')
-    @$('.wizard-controls .btn').text('Check').attr('data-form', 'base-inbound').addClass('btn--primary').removeClass('btn--danger').removeClass('btn--success')
+    @$('.wizard-controls .btn').text('Check').attr('data-form', 'base-inbound').addClass('btn--primary').removeClass('btn--danger', 'btn--success')
     @enable( @$('.btn') )

   storeUrl: (e) =>
@@ -197,10 +197,10 @@
       processData: true
       success: (data, status, xhr) =>
         if data.result is 'ok'
-          @$('.wizard-controls .btn').text('Done').removeClass('btn--primary').removeClass('btn--danger').addClass('btn--success')
+          @$('.wizard-controls .btn').text('Done').removeClass('btn--primary', 'btn--danger').addClass('btn--success')
           @delay( @showOutbound, 1500 )
         else
-          @$('.wizard-controls .btn').text( data.message_human || data.message ).addClass('btn--danger').removeClass('btn--primary').removeClass('btn--success')
+          @$('.wizard-controls .btn').text( data.message_human || data.message ).addClass('btn--danger').removeClass('btn--primary', 'btn--success')
           @enable(e)
       fail: =>
         @enable(e)
@@ -221,10 +221,10 @@
       processData: true
       success: (data, status, xhr) =>
         if data.result is 'ok'
-          @$('.wizard-controls .btn').text('Done').removeClass('btn--primary').removeClass('btn--danger').addClass('btn--success')
+          @$('.wizard-controls .btn').text('Done').removeClass('btn--primary', 'btn--danger').addClass('btn--success')
           @delay( @showInbound, 1500 )
         else
-          @$('.wizard-controls .btn').text( data.message_human || data.message ).addClass('btn--danger').removeClass('btn--primary').removeClass('btn--success')
+          @$('.wizard-controls .btn').text( data.message_human || data.message ).addClass('btn--danger').removeClass('btn--primary', 'btn--success')
           @enable(e)
       fail: =>
         @enable(e)
@@ -248,10 +248,10 @@
       success: (data, status, xhr) =>

         if data.result is 'ok'
-          @$('.wizard-controls .btn').text('Done').removeClass('btn--primary').removeClass('btn--danger').addClass('btn--success')
+          @$('.wizard-controls .btn').text('Done').removeClass('btn--primary', 'btn--danger').addClass('btn--success')
           @delay( @goToAdmin, 1500 )
         else
-          @$('.wizard-controls .btn').text( data.message_human || data.message ).addClass('btn--danger').removeClass('btn--primary').removeClass('btn--success')
+          @$('.wizard-controls .btn').text( data.message_human || data.message ).addClass('btn--danger').removeClass('btn--primary', 'btn--success')
         @enable(e)
       fail: =>
         @enable(e)
@@ -289,7 +289,7 @@
     @fetch()

   release: =>
-    @el.removeClass('fit').removeClass('getstarted')
+    @el.removeClass('fit', 'getstarted')

   fetch: ->

@@ -408,7 +408,7 @@

   release: =>
-    @el.removeClass('fit').removeClass('getstarted')
+    @el.removeClass('fit', 'getstarted')

   fetch: ->


Forgot to apply the changes about the submitter

--- app/assets/javascripts/components/annual_report_upload.js.coffee
+++ app/assets/javascripts/components/annual_report_upload.js.coffee
@@ -25,7 +25,7 @@
       download_button.addClass('disabled')
     if @state.submitted
       modal_content.addClass('smaller')
-      text = I18n.t('submitted_at_info_box') + " #{@state.annualReportUpload.submitted_by} "
+      text = I18n.t('submitted_at_info_box') + " " + @getSubmitter()
       text = text + I18n.t('the') + " #{@state.annualReportUpload.submitted_at}"
       info_text.html(text)
     else
@@ -103,7 +103,7 @@
       " #{I18n.t('records_submitted_by')} "
       span(
         {className: 'bold'}
-        @state.annualReportUpload.submitted_by
+        @getSubmitter()
       )
       " #{I18n.t('the')} "
       span(


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/animated.coffee
+++ src/animated.coffee
@@ -32,6 +32,10 @@
         complete: ""
         interruptible: false
         speed: ""
+        transform: [{
+          hflip: false
+          vflip: false
+        }]
         triggers: {
           "0": ["a trigger"]
         }
@@ -43,6 +47,10 @@
       complete: ""
       interruptible: false
       speed: ""
+      transform: [{
+        hflip: false
+        vflip: false
+      }]
       triggers: {
         "0": [""]
       }
@@ -104,6 +112,7 @@
     sprite = I.spriteLookup[frames[I.currentFrameIndex]]

     updateSprite(sprite)
+    I.activeAnimation

   find = (name) ->
     result = null


Fix startup error

Fix startup error

--- src/lib/dnschain.coffee
+++ src/lib/dnschain.coffee
@@ -70,7 +70,7 @@
             @bdns = new BDNSPeer @
             @dns = new DNSServer @
             @http = new HTTPServer @
-            @EncryptedServer = new HTTPSServer @
+            @encryptedserver = new EncryptedServer @
             @log.info "DNSChain started and advertising on: #{gConf.get 'dns:externalIP'}"

             if process.getuid() isnt 0 and gConf.get('dns:port') isnt 53 and require('tty').isatty(process.stdout)
@@ -80,5 +80,5 @@
             @shutdown()
             throw e # rethrow

-    shutdown: -> [@nmc, @dns, @http, @EncryptedServer].forEach (s) -> s?.shutdown?()
+    shutdown: -> [@nmc, @dns, @http, @encryptedserver].forEach (s) -> s?.shutdown?()


OX-590 adjusted move value change

OX-590 adjusted move value change

--- app/assets/javascripts/oxalis/controller/plane_controller.coffee
+++ app/assets/javascripts/oxalis/controller/plane_controller.coffee
@@ -207,8 +207,8 @@
       "o" : => @zoomOut(false)

       #Change move value
-      "h" : => @changeMoveValue(0.1)
-      "g" : => @changeMoveValue(-0.1)
+      "h" : => @changeMoveValue(10)
+      "g" : => @changeMoveValue(-10)

       #Comments
       "n" : => @setActiveNode(@model.route.nextCommentNodeID(false), false)


mongo import: path problem

mongo import: path problem

--- data/imports/aiddata.coffee
+++ data/imports/aiddata.coffee
@@ -11,13 +11,13 @@
 pg = require 'pg'
 pgurl = dbconf.postgres

-DEBUG_updateRowsLimit = null   # set for debugging
+DEBUG_updateRowsLimit = 10   # set for debugging
 OMIT_NULL_VALUE_FIELDS_IN_COMMITMENTS_JSON = false

 PATH = "data/imports/"
 TEMP_DIR = "temp"
-AIDDATA_TEMP_FILE = TEMP_DIR + "/aiddata.json"
-LOCATIONS_TEMP_FILE = TEMP_DIR + "/locations.json"
+AIDDATA_TEMP_FILE = PATH + TEMP_DIR + "/aiddata.json"
+LOCATIONS_TEMP_FILE = PATH + TEMP_DIR + "/locations.json"

 USE_MONGOIMPORT = true

@@ -34,6 +34,7 @@
                 "-d aiddata -c #{collection} --upsert --upsertFields #{upsertFields.join(',')} " +
                 "-u #{dbconf.mongodb.user} -p #{dbconf.mongodb.password} "+
                 "#{file}"
+
     console.log "Running in \"#{__dirname}\":\n#{cmd}"
     os.run cmd,
       (err) ->
@@ -46,7 +47,7 @@
       if err? then callWhenEnded(err)
       else

-        reader = linereader.open PATH + file
+        reader = linereader.open file

         nextRow = ->
           if reader.hasNextLine()
@@ -106,6 +107,18 @@
   q = queue(1)  # no parallelism
   tasks.forEach (t) -> q.defer t
   q.await callWhenEnded
+
+
+
+
+
+
+
+
+
+
+
+

 runTasksSerially [
@@ -239,7 +252,7 @@

           os.mkdir TEMP_DIR
-          fd = fs.openSync(PATH + LOCATIONS_TEMP_FILE, 'w')
+          fd = fs.openSync(LOCATIONS_TEMP_FILE, 'w')
           for r in result.rows
             fs.writeSync fd, JSON.stringify(r) + "\n"
           fs.closeSync fd
@@ -258,7 +271,7 @@
     console.log "> Export aiddata commitments from PostgreSQL to a temporary file"

     os.mkdir TEMP_DIR
-    fd = fs.openSync(PATH + AIDDATA_TEMP_FILE, 'w')
+    fd = fs.openSync(AIDDATA_TEMP_FILE, 'w')

     query = pgclient.query "SELECT * FROM aiddata2 #{if DEBUG_updateRowsLimit? then 'LIMIT '+DEBUG_updateRowsLimit}"
     query.on 'row', (row) ->
@@ -311,7 +324,7 @@
                   "#{file}",
         (err) ->
           unless err?
-            fs.unlink(PATH + AIDDATA_TEMP_FILE)
+            fs.unlink(AIDDATA_TEMP_FILE)

           callWhenEnded(err)

@@ -323,7 +336,7 @@
         if err? then callWhenEnded(err)
         else

-          reader = linereader.open PATH + AIDDATA_TEMP_FILE
+          reader = linereader.open AIDDATA_TEMP_FILE

           nextRow = ->
             if reader.hasNextLine()
@@ -367,8 +380,8 @@
       console.warn "> There was an error: " + err
     else
       console.log("> All tasks finished")
-      fs.unlink(PATH + AIDDATA_TEMP_FILE)
-      fs.unlink(PATH + LOCATIONS_TEMP_FILE)
+      fs.unlink(AIDDATA_TEMP_FILE)
+      fs.unlink(LOCATIONS_TEMP_FILE)

     mongodb.close()
     pgclient.end()


[Cartilage.View] Passing a nil view will no longer wreak havoc.

--- app/assets/javascripts/cartilage/views/view.js.coffee
+++ app/assets/javascripts/cartilage/views/view.js.coffee
@@ -48,6 +48,9 @@
     @observers = []

   addSubview: (view, container = @el, animated = false) ->
+
+    # Don't allow nil objects to be passed...
+    return unless view

     # Maintain a reference to the added subview for later cleanup, or other
     # operations


added comments for dropdown hover in and out events

--- src/coffee/responsive.breadcrumbs.coffee
+++ src/coffee/responsive.breadcrumbs.coffee
@@ -263,9 +263,11 @@
                     o.dropdownWrapper.trigger "#{ o.hoverOut }.#{ pluginName }"
                 , 500)

+            # bind the normalized event for hoverIn to the dropdownWrapper
             o.dropdownWrapper.on "#{ o.hoverIn }.#{ pluginName }", ->
                 window.clearTimeout o.dropdownTimer

+            # bind the normalized event for hoverOut to the dropdownWrapper
             o.dropdownWrapper.on "#{ o.hoverOut }.#{ pluginName }", ->
                 current = $ this


hackery!

hackery!

--- src/forge.iced
+++ src/forge.iced
@@ -14,12 +14,11 @@
     @_links = []
     @_assertions = []
     @_time = 0
+    @_start = null
     @_now = null
     @_expires = 0
-
-  #-------------------
-
-  _forge_link : ({link}, cb) ->
+    @_seqno = 1
+    @_prev = null

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

@@ -29,12 +28,23 @@

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

+  _make_key : ({km, obj}) ->
+    k = new Key { km, ctime : @_compute_now(), expires : (obj.expires or @_expires) }
+    @_keyring[k.get_ekid().toString('hex')] = k
+    k
+
+  #-------------------
+
   _compute_time : (o) ->
     ret = if typeof(o) is 'string'
       if o is 'now' then @_compute_now()
-      else if (m = o.match /^(\+)?(\d+)$/)
-        (if m[1]? then @_compute_now() else 0) + parseInt(m[2])
-      else null
+      else if not (m = o.match /^(\+)?(\d+)$/) then null
+      else if m[1]?
+        tmp = @_compute_now() + parseInt(m[2])
+        @_now = tmp
+        tmp
+      else
+        parseInt(m[2])
     else if typeof(o) isnt 'object' then null
     else if o.sum?
       sum = 0
@@ -49,7 +59,7 @@

   _init : (cb) ->
     try
-      @_time = if (t = @chain.time)? then @_compute_time(t) else @_compute_now()
+      @_start = if (t = @chain.time)? then @_compute_time(t) else @_compute_now()
       @_expires = @chain.expires or 60*60*24*364*10
       @_user = @chain.user or "tester_ralph"
     catch e
@@ -84,7 +94,7 @@
         else
           err = new Error "unknown key type: #{typ}"
     else if required then err = new Error "Required to generate key but none found"
-    key = if km? and not err? then @_make_key(km) else null
+    key = if km? and not err? then @_make_key{km, obj} else null
     cb err, key

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


Allow HTML in chart legend labels

Allow HTML in chart legend labels

--- app/assets/javascripts/lib/views/d3_chart_view.coffee
+++ app/assets/javascripts/lib/views/d3_chart_view.coffee
@@ -149,7 +149,7 @@
         .style("background-color", (d) => d.get 'color')

       scope.append("span")
-        .text((d) ->
+        .html((d) ->
           d.get('label') ||
            I18n.t("output_element_series.labels.#{d.get('key')}")
         )