Added vx to sx conversion

Added vx to sx conversion

--- bokehjs/src/coffee/models/annotations/title.coffee
+++ bokehjs/src/coffee/models/annotations/title.coffee
@@ -8,6 +8,7 @@
 class TitleView extends Renderer.View
   initialize: (options) ->
     super(options)
+    @canvas = @plot_model.get('canvas')

     @_set_data()
     @_set_visuals()
@@ -64,19 +65,22 @@
       when "rad" then angle = -1 * @mget('angle')
       when "deg" then angle = -1 * @mget('angle') * Math.PI/180.0

+    sx = @canvas.vx_to_sx(@mget('x'))
+    sy = @canvas.vy_to_sy(@mget('y'))
+
     if @mget('render_mode') == 'canvas'
-      @_canvas_text(ctx, 0, @mget('text'), @mget('x'), @mget('y'), angle)
+      @_canvas_text(ctx, 0, @mget('text'), sx, sy, angle)
     else
-      @_css_text(ctx, 0, @mget('text'), @mget('x'), @mget('y'), angle)
+      @_css_text(ctx, 0, @mget('text'), sx, sy, angle)

-  _canvas_text: (ctx, i, text, x, y, angle) ->
+  _canvas_text: (ctx, i, text, sx, sy, angle) ->
     [text_width, text_height] = @_calculate_text_dimensions(ctx, i, text)
     [ x_rect_offset, y_rect_offset ] = @_calculate_rect_offset(ctx, i, text_width, text_height)

     ctx.save()

     ctx.beginPath()
-    ctx.translate(x, y)
+    ctx.translate(sx, sy)
     ctx.rotate(angle)

     ctx.rect(x_rect_offset, y_rect_offset, text_width, text_height)
@@ -95,7 +99,7 @@

     ctx.restore()

-  _css_text: (ctx, i, text, x, y, angle) ->
+  _css_text: (ctx, i, text, sx, sy, angle) ->
     [text_width, text_height] = @_calculate_text_dimensions(ctx, i, text)
     [ x_rect_offset, y_rect_offset ] = @_calculate_rect_offset(ctx, i, text_width, text_height)

@@ -116,8 +120,8 @@

     div_style = {
       'position': 'absolute'
-      'left': "#{x + x_rect_offset}px"
-      'top': "#{y + y_rect_offset}px"
+      'left': "#{sx + x_rect_offset}px"
+      'top': "#{sy + y_rect_offset}px"
       'color': "#{@visuals.text.text_color.value()}"
       'opacity': "#{@visuals.text.text_alpha.value()}"
       'font-size': "#{@visuals.text.text_font_size.value()}"


Fix: com in with artists numbers.

Fix: com in with artists numbers.

--- apps/algorithms/client.coffee
+++ apps/algorithms/client.coffee
@@ -60,7 +60,7 @@

     relativeSize = 150 + 1000 * gene.artists_count / maxGeneCount
     rotation = _.random(0, 360)
-    number = $("
#{gene.artists_count}
")
+    number = $("
#{gene.artists_count}
")
     number
       .css('transform', "rotate(#{rotation}deg)")
       .css('font-size', "#{relativeSize}%")


authenticate after connecting

authenticate after connecting

--- zechat/static/core.coffee
+++ zechat/static/core.coffee
@@ -77,12 +77,21 @@
 class zc.Transport extends Backbone.Marionette.Controller

   initialize: (options) ->
+    @queue = []
     @options.app.vent.on('start', _.bind(@connect, @))

   connect: ->
     transport_url = @options.app.request('urls')['transport']
     @ws = new WebSocket(transport_url)
     @ws.onmessage = _.bind(@on_receive, @)
+    @ws.onopen = _.bind(@on_open, @)
+    @send(authenticate: @options.app.request('identity').get('fingerprint'))
+
+  on_open: ->
+    current_queue = @queue
+    @queue = []
+    current_queue.forEach (msg) =>
+      @send(msg)

   on_receive: (evt) ->
     msg = JSON.parse(evt.data)
@@ -91,8 +100,11 @@
     if msg.type == 'message' and msg.recipient == my_fingerprint
       @options.app.vent.trigger('message', msg.message)

-  send: (data) ->
-    @ws.send(JSON.stringify(data))
+  send: (msg) ->
+    if @ws.readyState == WebSocket.OPEN
+      @ws.send(JSON.stringify(msg))
+    else
+      @queue.push(msg)

 class zc.Persist extends Backbone.Marionette.Controller


tests refactoring

tests refactoring

--- spec/update-package-dependencies-spec.coffee
+++ spec/update-package-dependencies-spec.coffee
@@ -54,9 +54,10 @@
         exit(0)

       it "shows a success notification message", ->
-        [notifications] = atom.notifications.getNotifications()
+        [notification] = atom.notifications.getNotifications()
         expect(atom.workspace.getModalPanels().length).toEqual(0)
-        expect(atom.notifications.getNotifications()[0].getMessage()).toEqual("Success!")
+        expect(notification.getType()).toEqual("success")
+        expect(notification.getMessage()).toEqual("Success!")

     describe "when the update fails", ->
       beforeEach ->
@@ -65,7 +66,7 @@
         exit(127)

       it "shows a failure message in the modal", ->
-        [modal] = atom.workspace.getModalPanels()
-        [notifications] = atom.notifications.getNotifications()
+        [notification] = atom.notifications.getNotifications()
         expect(atom.workspace.getModalPanels().length).toEqual(0)
-        expect(atom.notifications.getNotifications()[0].getMessage()).toEqual("Error!")
+        expect(notification.getType()).toEqual("error")
+        expect(notification.getMessage()).toEqual("Error!")


hear instead of respond

hear instead of respond

チャンネルに追加されたとき使えるように

--- scripts/example.coffee
+++ scripts/example.coffee
@@ -13,32 +13,32 @@
   # 現在のレコード数
   length = robot.brain.get('records.length') >> 0

-  robot.respond /(\d+).*(add|\ふえた)/i, (res) ->
+  robot.hear /(\d+).*(add|\ふえた)/i, (res) ->
     # e.g. res.match[1] === '1234'
     amount = parseInt res.match[1]
     robot.brain.set "records.#{length}", "#{amount}\tadd"
     robot.brain.set "records.length", ++length
-    res.reply "すごーい！お金がふえたよ +#{amount}円"
+    res.send "すごーい！お金がふえたよ +#{amount}円"

-  robot.respond /(\d+).*(sub|\へった)/i, (res) ->
+  robot.hear /(\d+).*(sub|\へった)/i, (res) ->
     # e.g. res.match[1] === '1234'
     amount = parseInt res.match[1]
     robot.brain.set "records.#{length}", "#{amount}\tsub"
     robot.brain.set "records.length", ++length
-    res.reply "ざんねん！お金がへったよ -#{amount}円"
+    res.send "ざんねん！お金がへったよ -#{amount}円"

-  robot.respond /back|\もどす/, (res) ->
+  robot.hear /back|\もどす/, (res) ->
     if length > 0
       robot.brain.set "records.length", --length
-      res.reply "もどしたよ！" + robot.brain.get "records.#{length}"
+      res.send "もどしたよ！" + robot.brain.get "records.#{length}"
     else
-      res.reply "えっ？"
+      res.send "えっ？"

-  robot.respond /history|\りれき/i, (res) ->
+  robot.hear /history|\りれき/i, (res) ->
     records = [0..length - 1].map (i) -> robot.brain.get "records.#{i}"
-    res.reply "けんすう: #{length}件\n" + records.join('\n')
+    res.send "けんすう: #{length}件\n" + records.join('\n')

-  robot.respond /how much|\いくら/i, (res) ->
+  robot.hear /how much|\いくら/i, (res) ->
     if length > 0
       records = [0..length - 1].map (i) -> robot.brain.get "records.#{i}"
       money = 0
@@ -47,6 +47,6 @@
         matches = /(\d+)\s(add|sub)/i.exec record
         if matches[2] == 'add' then money += parseInt matches[1]
         if matches[2] == 'sub' then money -= parseInt matches[1]
-      res.reply "#{money}円"
+      res.send "#{money}円"
     else
-      res.reply "0円"
+      res.send "0円"


modificati dei messaggi

modificati dei messaggi

--- scripts/example.coffee
+++ scripts/example.coffee
@@ -6,14 +6,17 @@
 	robot.hear /vado via/i, (res) ->
 		res.reply "Allora non hai capito il momento!"

+	robot.hear /devo andare/i, (res) ->
+		res.reply "Non sai cosa c'è là fuori!"
+
 	robot.hear /buongiorno/i, (res) ->
-		res.reply "Buongiorno il cazzo!!"
+		res.reply "Buongiorno? è questa l'ora di arrivare???"

 	robot.respond /ringrazia (.*)/i, (res) ->
-		res.reply "Grazie " + res.match[1] + ", sei tutti noi!"
+		res.reply "Grazie " + res.match[1] + ", sei un grande!"

 	robot.respond /insulta (.*)/i, (res) ->
-		res.reply "A " + res.match[1] + ", non capisci un cazzo!"
+		res.reply "A coso, " + res.match[1] + ", se le cose non le sai, salle!"

 	robot.respond /segnati (.*) = (.*)/i, (res) ->
 		robot.brain.set ''+res.match[1] , res.match[2]
@@ -29,5 +32,4 @@
 			res.reply 'Eccotelo: ' + ricordo

 	robot.respond /grazie/i, (res) ->
-		res.reply 'prego, dovere'
-
+		res.reply 'Prego, dovere'


removed some useless code

removed some useless code

--- scripts/example.coffee
+++ scripts/example.coffee
@@ -1,16 +1,4 @@
 module.exports = (robot) ->
-
-	robot.hear /ciao a/i, (res) ->
-		res.reply "Ciao bello! (si fa per dire)"
-
-	robot.hear /vado via/i, (res) ->
-		res.reply "Allora non hai capito il momento!"
-
-	robot.hear /devo andare/i, (res) ->
-		res.reply "Non sai cosa c'è là fuori!"
-
-	robot.hear /buongiorno/i, (res) ->
-		res.reply "Buongiorno? è questa l'ora di arrivare???"

 	robot.respond /ringrazia (.*)/i, (res) ->
 		res.reply "Grazie " + res.match[1] + ", sei un grande!"


Hero: slightly faster exploded speed

Hero: slightly faster exploded speed

--- app/_src/components/hero-noise/hero-noise.coffee
+++ app/_src/components/hero-noise/hero-noise.coffee
@@ -1,13 +1,23 @@
 class FOURTEEN.HeroNoise extends FOURTEEN.BaseComponent

+	explodedSpreadX = () =>
+		return window.innerWidth * 0.3
+	explodedSpreadY = () =>
+		return window.innerHeight * 0.6
+	explodedSpeed = 0.04
+	explodedRotation = Math.PI*5
+	explodedParallax = 0.2
+	explodedScale = 1
+
 	env = {
-		spreadX:  window.innerWidth * 0.5
-		spreadY: window.innerHeight * 0.66
-		speed: 0.02
-		rotation: Math.PI*5
+		spreadX: explodedSpreadX()
+		spreadY: explodedSpreadY()
+		speed: explodedSpeed
+		rotation: explodedRotation
 		scaleEffect: 0 # start with no scale to avoid blur
-		parallaxEffect: 0.2
+		parallaxEffect: explodedParallax
 	}
+

 	mouseCurrent = {mouseX: window.innerWidth/2, mouseY: window.innerHeight/2}
 	mouseTarget = {mouseX: -1, mouseY: -1}
@@ -40,12 +50,12 @@
 		@animateOut(=>
 			@isAnimating = false
 			# set back to initial env (copy somehow?)
-			env.spreadX = window.innerWidth * 0.5
-			env.spreadY = window.innerHeight * 0.66
-			env.speed = 0.02
-			env.rotation = Math.PI*5
+			env.spreadX = explodedSpreadX()
+			env.spreadY = explodedSpreadY()
+			env.speed = explodedSpeed
+			env.rotation = explodedRotation
 			env.scaleEffect = 0
-			env.parallaxEffect = 0.2
+			env.parallaxEffect = explodedParallax
 		)

 	resumeAnimation: =>
@@ -91,7 +101,7 @@
 	animateIn: (complete) =>
 		# add scale effect with delay so they render at full size to avoid blur
 		TweenMax.to(env, 1.0, {
-			scaleEffect: 1,
+			scaleEffect: explodedScale,
 			ease: Power2.easeInOut,
 			delay: 0.15,
 			onComplete: complete
@@ -137,12 +147,12 @@
 		@timeline = new TimelineMax({paused: false, delay: 2})

 		@timeline.fromTo(env, 2, {
-			spreadX:  window.innerWidth * 0.5
-			spreadY: window.innerHeight * 0.66
-			speed: 0.02
-			rotation: Math.PI*5
-			scaleEffect: 1
-			parallaxEffect: 0.2
+			spreadX: explodedSpreadX()
+			spreadY: explodedSpreadY()
+			speed: explodedSpeed
+			rotation: explodedRotation
+			scaleEffect: explodedScale
+			parallaxEffect: explodedParallax
 		},{
 			spreadX: @logoEl.clientWidth * 0.7 * 0.01
 			spreadY: @logoEl.clientWidth * 0.7 * 0.01


EDSC-516, fixed config in map.js.coffee

EDSC-516, fixed config in map.js.coffee

--- app/assets/javascripts/modules/map/map.js.coffee
+++ app/assets/javascripts/modules/map/map.js.coffee
@@ -10,11 +10,12 @@
              SpatialSelection = ns.SpatialSelection,
              GranuleVisualizationsLayer = ns.GranuleVisualizationsLayer,
              MouseEventsLayer = ns.MouseEventsLayer,
-             page = @edsc.page) ->
+             page = @edsc.page
+             config = @edsc.config) ->

   L.Map.include
     fitBounds: (bounds, options={}) ->
-      options.animate = false if config.animateMap
+      options.animate = config.animateMap
       bounds = bounds.getBounds?() ? L.latLngBounds(bounds)

       paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0])


.

Former-commit-id: a6813b1c7c0715e6a3aaa5064c71a1b0324c63fd [formerly 12b1f9d942bc93ba8742e4b1a7542ca7d18854e9] [formerly 4bdb52bb9899d8c0460be24349f7c260da7d7518 [formerly 991de7ef7543c7b227a7c4014ae2de8078191b57]] [formerly 6f3d14a56e9de1b36b322507051d43590dd0b484 [formerly 24ce4fa2da51b36205f32b9da039b2ae5a84daa6] [formerly 8acaf1400b4f9b2dea2ff47fa8cac47f2a41bd28 [formerly 8acaf1400b4f9b2dea2ff47fa8cac47f2a41bd28 [formerly e01323809a66f7a89eb04dafa78e27fcb9bcc7e5]]]]
Former-commit-id: a807c135eeccd282b46b201250f1cf1e8e5d2ac0 [formerly 867e00560fd2d2c9e7699cbe8bf646281336b742] [formerly 34f35e711bf4b895e2280a7e1fd78e2bc260d42d [formerly ed65385177d80f706b1f5eeb090e741c79866987]]
Former-commit-id: e0199b6f87b9353e38e39b61d377780e735c199a [formerly 9e1d1095a26c248b588222310db01b53163dda03]
Former-commit-id: 9840a632a290f5f4f25f6f99964965c156ed1821
Former-commit-id: ed038f5d9ca53aaacc2b89ce77af2d9bfd1e1e9e

--- @client/customizations.coffee
+++ @client/customizations.coffee
@@ -1714,7 +1714,7 @@
   collapse_descriptions_at: 600

   homie_histo_title: "Members' Opinions"
-  collapse_descriptions_at: 600
+  collapse_descriptions_at: 300

   'cluster/Candidates':
     slider_pole_labels: support_oppose


fix file parser regex to exclude external links to md files

--- parsers/file_parser.coffee
+++ parsers/file_parser.coffee
@@ -12,8 +12,8 @@
   failures: []

 RegExplorer =
-  sameDirMarkdownLink:  /href="(?!\.\.)(.*\.md)/
-  otherDirMarkdownLink: /href="(\.\..*?\.md)/
+  sameDirMarkdownLink:  /href="(?!http)(?!\.\.)(.*\.md)/
+  otherDirMarkdownLink: /href="(?!http)(\.\..*?\.md)/
   relativeImageLink:    /.*"(\.\.\/images.*?\.png|jpg)/

 FileParser =


Trying to replace tabs with spaces so chat bots look better

--- scripts/octobot.coffee
+++ scripts/octobot.coffee
@@ -64,7 +64,8 @@
             row = [name, env.Name, version, state]
             table.push(row)

-        msg.send "_We're currently rolling with_: \n\n#{table.toString()}"
+        table = table.toString().replace(/\t/g, '    ')
+        msg.send "_We're currently rolling with_: \n\n#{table}"

   robot.respond /(promote) (.+) from (.+) to (.+)/i, (msg) ->


uncomment line

uncomment line

--- app/assets/javascripts/backend/interventions.js.coffee
+++ app/assets/javascripts/backend/interventions.js.coffee
@@ -403,21 +403,21 @@
       if unitName
         intervention['unit_name'] = unitName

-      # $.ajax
-      #   url: "/backend/interventions/costs/parameter_cost",
-      #   data: { intervention: intervention }
-      #   success: (data, status, request) ->
-      #     if !data.human_amount.nature || data.human_amount.nature != "failed"
-      #       nestedProductParameter = $(target).closest('.nested-product-parameter')
-
-            # if $(nestedProductParameter).find('.product-parameter-cost').length > 0
-            #   $(nestedProductParameter).find('.product-parameter-cost-value').text(data.human_amount)
-            # else
-            #   parameterCostBlock = $('

')
-            #   parameterCostBlock.append('Coût : ')
-            #   parameterCostBlock.append('' + data.human_amount + '')
-            #
-            #   $(nestedProductParameter).find('.intervention_inputs_quantity').append(parameterCostBlock)
+      $.ajax
+        url: "/backend/interventions/costs/parameter_cost",
+        data: { intervention: intervention }
+        success: (data, status, request) ->
+          if !data.human_amount.nature || data.human_amount.nature != "failed"
+            nestedProductParameter = $(target).closest('.nested-product-parameter')
+
+            if $(nestedProductParameter).find('.product-parameter-cost').length > 0
+              $(nestedProductParameter).find('.product-parameter-cost-value').text(data.human_amount)
+            else
+              parameterCostBlock = $('

')
+              parameterCostBlock.append('Coût : ')
+              parameterCostBlock.append('' + data.human_amount + '')
+
+              $(nestedProductParameter).find('.intervention_inputs_quantity').append(parameterCostBlock)

   $(document).ready ->


Fix javascript taskboard error

Fix javascript taskboard error

--- app/assets/javascripts/backend/interventions.js.coffee
+++ app/assets/javascripts/backend/interventions.js.coffee
@@ -230,7 +230,7 @@
             @workingTimesModal.getModalContent().append(data)
             @workingTimesModal.getModal().modal 'show'

-    addLazyLoading: ->
+    addLazyLoading: (taskboard) ->
       loadContent = false
       currentPage = 1
       taskHeight = 60
@@ -434,7 +434,7 @@
       taskboard = new InterventionsTaskboard
       taskboard.initTaskboard()

-      E.interventions.addLazyLoading()
+      E.interventions.addLazyLoading(taskboard)

   class InterventionsTaskboard


don't mark as read if an entry is collapsed

Change-Id: Ie902071fba4de070a63f297821dd07b3db01ff09
Reviewed-on: https://gerrit.instructure.com/9693
Reviewed-by: Zach Wily <9de8c4480303b5335cd2a33eefe814615ba3612a@instructure.com>
Tested-by: Zach Wily <9de8c4480303b5335cd2a33eefe814615ba3612a@instructure.com>

--- app/coffeescripts/discussions/MarkAsReadWatcher.coffee
+++ app/coffeescripts/discussions/MarkAsReadWatcher.coffee
@@ -25,6 +25,12 @@
     # @param {EntryView} view
     constructor: (@view) ->
       MarkAsReadWatcher.unread.push this
+      @view.model.bind 'change:collapsedView', (model, collapsedView) =>
+        @ignore = collapsedView
+        if collapsedView
+          @clearTimer()
+        else
+          @createTimer()

     createTimer: ->
       @timer ||= setTimeout @markAsRead, MS_UNTIL_READ
@@ -48,6 +54,7 @@
       topOfViewport = $window.scrollTop()
       bottomOfViewport = topOfViewport + $window.height()
       for entry in @unread
+        continue if entry.ignore
         topOfElement = entry.view.$el.offset().top
         inView = (topOfElement < bottomOfViewport) &&
                  (topOfElement + entry.view.$el.height() > topOfViewport)


make sure only one of the weather forecast commands is executed

--- scripts/weather.coffee
+++ scripts/weather.coffee
@@ -96,7 +96,7 @@
     location = msg.match[1]
     lookupAddress(msg, location, lookupWeather)

-  robot.respond /weather\s*?/i, (msg) ->
+  robot.respond /weather\s*?$/i, (msg) ->
     location = "Leipzig, Germany"
     lookupAddress(msg, location, lookupWeather)

@@ -104,6 +104,6 @@
     location = msg.match[1]
     lookupAddress(msg, location, lookupForecast)

-  robot.respond /forecast\s*?/i, (msg) ->
+  robot.respond /forecast\s*?$/i, (msg) ->
     location = "Leipzig, Germany"
     lookupAddress(msg, location, lookupForecast)


Beautify code

Beautify code

--- handlers/util.coffee
+++ handlers/util.coffee
@@ -179,10 +179,10 @@

 			# Unless the given vote option is known add it to the voted options
 			unless votes[message.roomID].votes[option]?
-				votes[message.roomID].votes[option] = 1
-			else
-				votes[message.roomID].votes[option]++
+				votes[message.roomID].votes[option] = 0

+			votes[message.roomID].votes[option]++
+
 			callback?()
 		when 'stopVote'
 			db.checkPermissionByMessage message, 'util.startVote', (hasPermission) ->
@@ -191,7 +191,7 @@
 					return

 				# Run the “onTimeout” function of the currently running vote for this room
-				votes[message.roomID].timeoutFunction() if votes[message.roomID]?.timeoutFunction? and typeof votes[message.roomID].timeoutFunction is 'function'
+				votes[message.roomID]?.timeoutFunction?()

 				callback?()
 		else


Typo.

Typo.

--- server/lib/exit.coffee
+++ server/lib/exit.coffee
@@ -1,4 +1,4 @@
 Meteor.startup ->
-  # Allow exiting immediatelly after startup to allow starting
+  # Allow exiting immediately after startup to allow starting
   # Meteor in a way to only update all NPM packages
   process.exit 0 if process.env.EXIT_ON_STARTUP


enable autocomplete on citations like `citeauthor`

--- services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee
+++ services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee
@@ -47,7 +47,7 @@
 					lineUpToCursor = editor.getSession().getTextRange(upToCursorRange)
 					commandFragment = getLastCommandFragment(lineUpToCursor)
 					if commandFragment
-						citeMatch = commandFragment.match(/^~?\\([a-z]*cite[a-z]?(?:\[.*])?){([^}]*,)?(\w*)/)
+						citeMatch = commandFragment.match(/^~?\\([a-z]*cite[a-z]*(?:\[.*])?){([^}]*,)?(\w*)/)
 						if citeMatch
 							beyondCursorRange = new Range(pos.row, pos.column, pos.row, 99999)
 							lineBeyondCursor = editor.getSession().getTextRange(beyondCursorRange)


Fixed ace editor instantiation for introduction admin.

--- client/app/MainApp/sidebar/modals/adminmodal.coffee
+++ client/app/MainApp/sidebar/modals/adminmodal.coffee
@@ -706,7 +706,8 @@

     super options, data

-    @utils.defer => @setAceEditor()
+    {type, actionType} = @getOptions()
+    @utils.defer => @setAceEditor() if (type is "Group" and actionType is "Insert") or type is "Item"

   save: ->
     {actionType} = @getOptions()
@@ -745,9 +746,9 @@
     {actionType} = options
     itemData     = {}

-    snippet = @aceEditor.getValue()
+    snippet = @aceEditor?.getValue()
     if @snippetType is "Text"
-      snippet = """new KDView({partial: "#{@aceEditor.getValue()}"});"""
+      snippet = """new KDView({partial: "#{@aceEditor?.getValue()}"});"""

     if type is "Item" or (type is "Group" and actionType is "Insert")
       itemData = {
@@ -755,8 +756,6 @@
         introTitle : inputs.IntroTitle.getValue()
         snippet
       }
-
-    return log itemData

     if type is "Group"
       data = {


Some comments on sentence selection to make it easier to understand

--- annotran/static/scripts/annotator/plugin/sentenceselection.coffee
+++ annotran/static/scripts/annotator/plugin/sentenceselection.coffee
@@ -106,6 +106,7 @@
     if currentTarget == undefined
         currentTarget = initialTarget

+    # matches for a full stop, question mark, or exclamation mark
     desiredText = $(currentTarget).text()
     match = /[.!?][\b\s]/.test(desiredText)
     desiredText = desiredText.split(/[.!?]\s/)
@@ -124,6 +125,7 @@
     for sentence in desiredText
       if counter == this.currentSentence
         break
+      # this offset should be the length of the break split (i.e. a full-stop + a space = 2)
       offset_to_use = offset_to_use + sentence.length + 2
       counter = counter + 1

@@ -154,14 +156,12 @@
       this.anchorToPage(data)
     else
       tagName = $(currentTarget).prop('tagName').toLowerCase()
-      console.log(tagName)

       if tagName == 'tr'
         # if we hit a table row, select the first td
         currentTarget = currentTarget.find(">:first-child")
         initialTarget = currentTarget
         length = $(currentTarget).text().length - 1
-        console.log($(currentTarget).text())
         data = this.packageData(initialTarget, currentTarget, length, 0)
         this.anchorToPage(data)
         return
@@ -172,13 +172,16 @@
         this.anchorToPage(data)
       else
         if desiredText == undefined
+          # Just start in the next jump element without saving the current position in the document
           nextSibling = this.returnNext(currentTarget)
           this.currentIndex = 0
           this.currentSentence = 0
           this.selectSentence nextSibling
         else if desiredText.endsWith(".") or desiredText.endsWith("!") or desiredText.endsWith("?")
+          # just select the next sentence and force it through
           this.selectSentence initialTarget, currentTarget, true
         else
+          # jump to next sibling
           this.scanForNextSibling initialTarget, currentTarget, offset_to_use, endIndex

   findASentence: (event = {}) =>


fix for messages

fix for messages

--- app/assets/javascripts/app/controllers/messages/article.js.coffee
+++ app/assets/javascripts/app/controllers/messages/article.js.coffee
@@ -89,7 +89,7 @@
         @renderHeader()

     Message.bind 'create', (record) =>
-      if record.conversation().eql?(@current)
+      if record.conversation()?.eql?(@current)
         @add([record])

     @active (params = {}) ->
@@ -114,16 +114,17 @@
     @replace @view('messages/article')(@current)
     @compose.append(new Compose(record: @current).render())

-    @delay ->
-      messages = @current?.messages().all().sort(Message.sentAtDesc)
-      @add(messages)
+    messages = @current?.messages().all().sort(Message.sentAtDesc)
+    @add(messages)

   add: (records = []) ->
+    @items.hide()
     if @items.is(':empty')
       @items.append(new Subject(record: records[0]).render())

     for record in records
       @items.append(new Item(record: record).render())
+    @items.show()
     @scrollToBottom()

   scrollToBottom: ->


more informative demo results

more informative demo results

--- cistrans/sparql_demo.coffee
+++ cistrans/sparql_demo.coffee
@@ -17,33 +17,40 @@
 	document.getElementById("genotext").innerHTML = "Parsed Markers/LODs/gene for probe #{probe_number}";
 	document.getElementById("phenoparsedtext").innerHTML = "Parsed Pheno/Geno/individual for probe #{probe_number}, marker #{marker}";
 	document.getElementById("phenotext").innerHTML = "Raw JSON for Pheno/Geno/individual for probe #{probe_number}, marker #{marker}";
-	document.getElementById("probe").innerHTML = "Loading..."
-	document.getElementById("phenoparsed").innerHTML = "Loading..."
+	document.getElementById("probe").innerHTML = "Loading Query..."
+	document.getElementById("phenoparsed").innerHTML = "Loading Query..."
+	document.getElementById("pheno").innerHTML = "Loading Query..."

 	$.ajax 'queries/probe.rq',
 		type: 'GET',
 		success:(data) ->
+			document.getElementById("probe").innerHTML = "Querying..."
 			$.ajax query_url + encodeURIComponent(data.replace(/497638/g,probe_number)),
 				type: 'GET',
 				success: (data) ->
-					# parsed.markers = data.results.bindings.map (b) -> b.marker.value ;
+					document.getElementById("probe").innerHTML = "Parsing..."
 					parsed = []
-					parsed.push {gene: data.results.bindings[0].gene.value}
-					data.results.bindings.map (b) ->
-						parsed.push
-							marker: b.marker.value,
-							lod: b.lod.value,
-
-					# parsed.lods = data.results.bindings.map (b) -> b.lod.value ;
-					# console.log "got probe,",parsed.markers.length ;
-					document.getElementById("probe").innerHTML = JSON.stringify(parsed);
+					if data.results.bindings[0].gene
+						parsed.push {gene: data.results.bindings[0].gene.value}
+						data.results.bindings.map (b) ->
+							parsed.push
+								marker: b.marker.value,
+								lod: b.lod.value,
+
+						document.getElementById("probe").innerHTML = JSON.stringify(parsed);
+					else
+						document.getElementById("probe").innerHTML = "no data for #{probe_number}";
+
+

 	$.ajax 'queries/pheno.rq',
 		type: 'GET',
 		success:(data) ->
+			document.getElementById("phenoparsed").innerHTML = "Querying..."
 			$.ajax query_url + encodeURIComponent(data.replace(/511932/g,probe_number).replace(/rs13475697/g,marker)),
 				type: 'GET',
 				success: (data) ->
+					document.getElementById("phenoparsed").innerHTML = "Parsing..."
 					parsed = []
 					data.results.bindings.map (b) ->
 						parsed.push
@@ -51,10 +58,7 @@
 							pheno: b.pheno.value,
 							sex: b.sex.value,
 							geno: b.geno.value
-
-					# parsed = mouse: data.results.bindings.map (b) -> b.mouse.value ;
-					# parsed.pheno = data.results.bindings.map (b) -> b.pheno.value
-					# parsed.geno = data.results.bindings.map (b) -> b.geno.value
+
 					document.getElementById("phenoparsed").innerHTML = JSON.stringify(parsed);
 					document.getElementById("pheno").innerHTML = JSON.stringify(data);


Fixed: bank alert were shown for all bank accounts

--- server/controllers/bankalerts.coffee
+++ server/controllers/bankalerts.coffee
@@ -37,7 +37,7 @@
             res.send 200, alert

 module.exports.getForBankAccount = (req, res) ->
-    BankAlert.allFromBankAccount req.params.accountID, (err , alerts) ->
+    BankAlert.allFromBankAccount id: req.params.accountID, (err , alerts) ->
         if err?
             res.send 500, error: "Server error while getting bank alerts"
         else


Use getShortTaskIDMiddleEllipsis on historical tasks table

--- SingularityUI/app/views/request.coffee
+++ SingularityUI/app/views/request.coffee
@@ -97,7 +97,7 @@
                         pagination: HistoryPaginationView
                     partials: [
                         header: 'Name	'
-                        cell: '{{#hardBreak name}}{{/hardBreak}}	'
+                        cell: '{{#getShortTaskIDMiddleEllipsis name}}{{/getShortTaskIDMiddleEllipsis}}	'
                     ,
                         header: 'Status	'
                         cell: '{{ lastStatusHuman }}	'


Pass mounted machine for terminal

Pass mounted machine for terminal

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -943,7 +943,7 @@
   addInitialViews: ->

     @ideViews.first.createEditor()
-    @ideViews.last.createTerminal { machine }
+    @ideViews.last.createTerminal machine: @mountedMachine
     @setActiveTabView @ideViews.first.tabView


config: rename to 'supervisor', add to help

--- config/main.dev.coffee
+++ config/main.dev.coffee
@@ -602,6 +602,7 @@
         echo "  run testendpoints         : to test every URL endpoint programmatically."
         echo "  run printconfig           : to print koding config environment variables (output in json via --json flag)"
         echo "  run worker [worker]       : to run a single worker"
+        echo "  run supervisor [env]      : to show status of workers in that environment"
         echo "  run help                  : to show this list"
         echo ""

@@ -881,7 +882,7 @@
           eval "worker_$2"
         fi

-      elif [ "$1" == "supervisor_status" ]; then
+      elif [ "$1" == "supervisor" ]; then

         SUPERVISOR_ENV=$2
         if [ $SUPERVISOR_ENV == "" ]; then


Graph: added status filtering based on an array of statuses

--- workers/social/lib/social/models/graph/graph.coffee
+++ workers/social/lib/social/models/graph/graph.coffee
@@ -405,11 +405,16 @@
     if timestamp?
         timeStampQuery = "AND groupOwnedNodes.requestedAt > \"#{timestamp}\""

+    if typeof status is "string" then status = [status]
+
+    # convert status array into string array
+    status   = "[\"" + status.join("\",\"") + "\"]"
+
     query = """
         START group=node:koding("id:#{groupId}")
         MATCH group-[r:owner]->groupOwnedNodes
         WHERE groupOwnedNodes.name = 'JInvitationRequest'
-        AND groupOwnedNodes.status = "#{status}"
+        AND groupOwnedNodes.status IN #{status}
         #{timeStampQuery}
         #{regexSearch}
         RETURN groupOwnedNodes


SocialWorker: remove daisy and dash usage

--- workers/social/lib/social/traits/slugifiable.coffee
+++ workers/social/lib/social/traits/slugifiable.coffee
@@ -1,6 +1,7 @@
 module.exports = class Slugifiable

-  { dash, daisy, secure } = require 'bongo'
+  async      = require 'async'
+  { secure } = require 'bongo'

   KodingError = require '../error'

@@ -141,33 +142,6 @@
             else
               callback null, nextName

-  # @updateAllSlugsResourceIntensively = (options, callback)->
-  #   [callback, options] = [options, callback] unless callback
-  #   options ?= {}
-  #   selector = if options.force then {} else {slug_: $exists: no}
-  #   subclasses = @encapsulatedSubclasses ? [@]
-  #   JName = require '../models/name'
-  #   JName.someData {},{name:1,_id:1,constructorName:1},{},(err,names)->
-  #     console.log "namesArr in"
-  #     names.toArray (err,namesArr)->
-  #       contentTypeQueue = subclasses.map (subclass)->->
-  #         console.log "2"
-  #         subclass.someData {},{title:1,_id:1},{limit:1000},(err,cursor)->
-  #           console.log "3"
-  #           if err
-  #             callback err
-  #           else
-  #             cursor.toArray (err,arr)->
-  #               if err
-  #                 callback err
-  #               else
-  #                 a.contructorName = subclass.name for a in arr
-  #                 console.log "4"
-  #                 console.log "arr ->",arr,"namesArr -> ",namesArr
-  #                 callback null #,arr,namesArr
-  #
-  #       dash contentTypeQueue, callback
-
   @updateSlugsByBatch = (batchSize, konstructors) ->
     konstructors = [konstructors]  unless Array.isArray konstructors
     konstructors.forEach (konstructor) ->
@@ -182,21 +156,22 @@
     options ?= {}
     selector = if options.force then {} else { slug_: { $exists: no } }
     subclasses = @encapsulatedSubclasses ? [this]
-    contentTypeQueue = subclasses.map (subclass) -> ->
+
+    async.each subclasses, (subclass, next) ->
       subclass.cursor selector, options, (err, cursor) ->
-        if err then console.error err #contentTypeQueue.next err
+        if err then console.error err
         else
           postQueue = []
           cursor.each (err, post) ->
-            if err then console.error err#postQueue.next err
+            if err then console.error err
             else if post?
-              postQueue.push ->
+              postQueue.push (seriesNext) ->
                 post.updateSlug (err, slug) ->
                   callback null, slug
-                  postQueue.next()
+                  seriesNext()
             else
-              daisy postQueue, -> contentTypeQueue.fin()
-    dash contentTypeQueue, callback
+              async.series postQueue, -> next()
+    , callback

   updateSlug:(callback) ->
     @createSlug (err, slug) =>


fix indentation

fix indentation

--- app/coffee/MongoAWS.coffee
+++ app/coffee/MongoAWS.coffee
@@ -85,7 +85,7 @@
 		outputStream = inputStream.pipe gunzip
 		parts = []
 		outputStream.on 'error', (err) ->
-				return callback(err)
+			return callback(err)
 		outputStream.on 'end', () ->
 			logger.log {project_id, doc_id, pack_id}, "download from s3 completed"
 			try


Include db, table and indexes fields in outdated index issue

--- admin/static/coffee/app.coffee
+++ admin/static/coffee/app.coffee
@@ -258,8 +258,11 @@
                     tables: issue('info')('tables').map(
                         issue_id('info')('tables'),
                         (table, table_id) ->
+                            db: table('db')
                             db_id: table_id('db')
                             table_id: table_id('table')
+                            table: table('table')
+                            indexes: table('indexes')
                     )
                 invalid_config =
                     table_id: issue_id('info')('table')


fixed for mr notes.

fixed for mr notes.

--- client/landing/app/MainApp/maintabs/maintabview.coffee
+++ client/landing/app/MainApp/maintabs/maintabview.coffee
@@ -25,6 +25,12 @@

     mainViewController = KD.getSingleton "mainViewController"
     mainViewController.on "UILayoutNeedsToChange", @bound "changeLayout"
+
+    @on "PaneDidShow", @bound "focusActiveSubPane"
+
+  focusActiveSubPane: (pane)->
+    {tabView} = pane.getMainView()
+    tabView.getActivePane().getHandle().$().click()  if tabView

   changeLayout:(options)->


Prevent showing video speeds that aren't set by course author.

--- common/lib/xmodule/xmodule/js/src/video/display.coffee
+++ common/lib/xmodule/xmodule/js/src/video/display.coffee
@@ -26,11 +26,15 @@
     @videos[speed || @speed]

   parseVideos: (videos) ->
-    @videos =
-      '0.75': @el.data('youtube-id-0-75')
-      '1.0': @el.data('normal-speed-video-id')
-      '1.25': @el.data('youtube-id-1-25')
-      '1.50': @el.data('youtube-id-1-5')
+    @videos = {}
+    if @el.data('youtube-id-0-75')
+      @videos['0.75'] = @el.data('youtube-id-0-75')
+    if @el.data('normal-speed-video-id')
+      @videos['1.0'] = @el.data('normal-speed-video-id')
+    if @el.data('youtube-id-1-25')
+      @videos['1.25'] = @el.data('youtube-id-1-25')
+    if @el.data('youtube-id-1-5')
+      @videos['1.50'] = @el.data('youtube-id-1-5')

   parseSpeed: ->
     @setSpeed($.cookie('video_speed'))


permissible iframe for now.

permissible iframe for now.

--- coffee/src/util/util.coffee
+++ coffee/src/util/util.coffee
@@ -89,6 +89,7 @@
   allowFullScreen: 'true'
   webkitAllowFullScreen: 'true'
   mozallowfullscreen: 'true'
+  sandbox: 'allow-forms allow-same-origin allow-scripts allow-top-navigation'

 # construct an <iframe> element, with `src` and `id`


more cleanup and clarification

more cleanup and clarification

--- source/javascripts/master-map.coffee
+++ source/javascripts/master-map.coffee
@@ -5,7 +5,7 @@
   path        = d3.geo.path().projection(projection)
   fill        = d3.scale.log().clamp(true).range ['#111', '#00ff00']
   starCount   = 'total'
-  geometries  = null
+  zoomGroup   = null
   colors      = ['#a634f4', '#f1f42f', '#bcf020', '#eeb016', '#ec180c']

   # Main objects
@@ -49,11 +49,12 @@
   #
   # Returns nothing
   drawRecruitPathsToSchool = (school) ->
-    players = recruits.filter (r) -> r.institution in [school.team, school.alt]
-    features = players.map (player) -> lineStringFromPlayerToSchool(player, school)
+    schoolRecruits = recruits.filter((r) -> r.institution in [school.team, school.alt])
+    recruitFeatures = schoolRecruits.map((player) -> lineStringFromPlayerToSchool(player, school))

-    connections = geometries.selectAll('.connection')
-      .data(features, (d) -> "#{d.properties.name}:#{d.properties.school}")
+    connections = zoomGroup
+      .selectAll('.connection')
+      .data(recruitFeatures, (d) -> "#{d.properties.name}:#{d.properties.school}")

     connections.enter().append('path')
       .attr('class', 'connection')
@@ -62,10 +63,10 @@

     connections.exit().remove()

-    recs = geometries.selectAll('.recruit')
-      .data(players, (d) -> "#{d.name}:#{d.school}")
+    recruitNodes = zoomGroup.selectAll('.recruit')
+      .data(schoolRecruits, (d) -> "#{d.name}:#{d.school}")

-    recs.enter().append('circle')
+    recruitNodes.enter().append('circle')
       .attr('cx', (d) -> d.coordinates[0])
       .attr('cy', (d) -> d.coordinates[1])
       .attr('r', 2)
@@ -74,21 +75,22 @@
       .on('mouseover', tip.show)
       .on('mouseout', tip.hide)

-    recs.exit().remove()
+    recruitNodes.exit().remove()

   $.when($.ajax('/data/counties.json'),
          $.ajax('/data/schools.csv'),
          $.ajax('/data/recruits.csv')).then (r1, r2, r3) ->

     usa      = r1[0]
-    schools = d3.csv.parse(r2[0])
-    recruits = d3.csv.parse(r3[0])
+    schools = d3.csv.parse r2[0]
+    recruits = d3.csv.parse r3[0]

     # Convert to GeoJSON
     states   = topojson.mesh usa, usa.objects.states, (a, b) -> a.id != b.id
     counties = topojson.feature usa, usa.objects.counties
     nation   = topojson.mesh usa, usa.objects.nation

+    # Set the fill domain based on the total number of recruits
     fill.domain [0.1, d3.max(counties.features, (d) -> d.properties[starCount])]

     # Auto scale map based on bounds
@@ -98,10 +100,16 @@
     t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2]
     projection.scale(s).translate(t)

-    geometries = map.append('g')
+    for recruit in recruits
+      recruit.coordinates = projection [recruit.lat, recruit.lon]
+
+    for school in schools
+      school.position = projection [school.lat, school.lon]
+
+    zoomGroup = map.append('g')

     # Add counties
-    geometries.append('g')
+    zoomGroup.append('g')
       .attr('class', 'counties')
     .selectAll('path.county')
       .data(counties.features)
@@ -116,24 +124,18 @@
         if stars > 0 then fill(stars || 0) else '#333')

     # Add states mesh
-    geometries.append('path')
+    zoomGroup.append('path')
       .datum(states)
       .attr('class', 'states')
       .attr('d', path)

     # Add nation mesh
-    geometries.append('path')
+    zoomGroup.append('path')
       .datum(nation)
       .attr('class', 'nation')
       .attr('d', path)

-    for recruit in recruits
-      recruit.coordinates = projection [recruit.lat, recruit.lon]
-
-    for school in schools
-      school.position = projection [school.lat, school.lon]
-
-    geometries.selectAll('.schools')
+    zoomGroup.selectAll('.schools')
       .data(schools)
     .enter().append('circle')
       .attr('cx', (d) -> d.position[0])


#243 Fix undefined variable

#243 Fix undefined variable

--- app/assets/javascripts/oxalis/model/skeletontracing/skeletontracing.coffee
+++ app/assets/javascripts/oxalis/model/skeletontracing/skeletontracing.coffee
@@ -540,7 +540,7 @@

     if notify
       if confirm("Do you really want to delete the whole tree?")
-        @reallyDeleteTree(id, deleteBranchesAndComments, informServer)
+        @reallyDeleteTree(id, deleteBranchesAndComments, notifyServer)
       else
         return
     else


EnvironmentsDomainContainer: remove not used codes, update code to work with new backend

--- client/Environments/views/scene/environmentdomaincontainer.coffee
+++ client/Environments/views/scene/environmentdomaincontainer.coffee
@@ -1,23 +1,26 @@
 class EnvironmentDomainContainer extends EnvironmentContainer

-  EnvironmentDataProvider.addProvider "domains", ->
+  # EnvironmentDataProvider.addProvider "domains", ->

-    new Promise (resolve, reject)->
+  #   new Promise (resolve, reject)->

-      KD.remote.api.JDomain.fetchDomains (err, domains)->
-        if err or not domains or domains.length is 0
-          warn "Failed to fetch domains", err  if err
-          return resolve []
+  #     KD.remote.api.JDomain.fetchDomains (err, domains)->
+  #       if err or not domains or domains.length is 0
+  #         warn "Failed to fetch domains", err  if err
+  #         return resolve []

-        resolve domains
+  #       resolve domains

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

-    options.cssClass  = 'domains'
-    options.title     = 'domains'
-    options.itemClass = EnvironmentDomainItem
+    options     =
+      title     : 'domains'
+      cssClass  : 'domains'
+      itemClass : EnvironmentDomainItem

     super options, data
+
+    @stack = @getData()

     # Plus button on domainsContainer opens up the domainCreateModal
     @on 'PlusButtonClicked', =>
@@ -42,12 +45,6 @@
             callback   : =>
               paneType = domainCreateForm.tabView.getActivePane().getOption 'type'

-              # @buttons?.createButton.hideLoader()
-              # @off  "FormValidationPassed"
-              # @once "FormValidationPassed", =>
-              #   @emit 'registerDomain'
-              #   @buttons?.createButton.showLoader()
-
               if paneType is "redirect"
                 domainCreateForm.handleRedirect()
               else
@@ -63,8 +60,8 @@
       domain      : domain

   getDomainCreateForm: ->
-    {stack} = @getDelegate().getOptions()
-    domainCreateForm = new DomainCreateForm {}, { stack }
+
+    domainCreateForm = new DomainCreateForm {}, { @stack }

     @on "itemRemoved", domainCreateForm.bound "updateDomains"
     domainCreateForm.on "DomainSaved", (domain) =>


ApplicationTabView: leave enough room

ApplicationTabView: leave enough room

we need to leave enough room for both the "plus tab box" and the "settings menu" so that the two don't overlap each other when there are many tabs.

--- client/Main/CommonViews/applicationview/applicationtabview.coffee
+++ client/Main/CommonViews/applicationview/applicationtabview.coffee
@@ -3,7 +3,7 @@
   constructor: (options = {}, data) ->

     options.resizeTabHandles            ?= yes
-    options.lastTabHandleMargin         ?= 40
+    options.lastTabHandleMargin         ?= 80
     options.sortable                    ?= yes
     options.closeAppWhenAllTabsClosed   ?= yes
     options.saveSession                 ?= no


groups controller: remove some derpy code

--- client/app/Applications/Groups.kdapplication/AppController.coffee
+++ client/app/Applications/Groups.kdapplication/AppController.coffee
@@ -40,7 +40,6 @@
     mainController = @getSingleton 'mainController'
     router         = @getSingleton 'router'
     {entryPoint}   = KD.config
-    mainController.on 'AccountChanged', @bound 'resetUserArea'
     mainController.on 'NavigationLinkTitleClick', (pageInfo)=>
       return unless pageInfo.path
       if pageInfo.topLevel
@@ -86,7 +85,6 @@
       then {group: KD.config.entryPoint.slug}

   setUserArea:(userArea)->
-    @emit 'UserAreaChanged', userArea  if not _.isEqual userArea, @userArea
     @userArea = userArea

   getGroupSlug:-> @currentGroupName
@@ -95,11 +93,6 @@
     @currentGroupName = groupName
     @setUserArea {
       group: groupName, user: KD.whoami().profile.nickname
-    }
-
-  resetUserArea:(account)->
-    @setUserArea {
-      group: @currentGroupName ? 'koding', user: account.profile.nickname
     }

   onboardingText =


groups: better intro text

groups: better intro text

--- client/app/Applications/Groups.kdapplication/AppController.coffee
+++ client/app/Applications/Groups.kdapplication/AppController.coffee
@@ -122,13 +122,14 @@

Koding groups is a simple way to connect and interact with people who share
             your interests.

-
When you join a group within a community such as your univeristy or you
-company, you can share virtual machines, files and stay up to date on the
-activites of others in your group.

-
-
Easy to get started and safe

-
-
Groups are free to create. You decide who can join and what they see.

+
When you join a group such as your univeristy or your company, you can share virtual
+            machines, collaborate on projects and stay up to date on the activites of others in your
+            group.

+
+
Easy to get started

+
+
Groups are free to create. You decide who can join, what actions they can do inside the
+            group and what they see.

           """
         mine                : "
yooo onboard me for my groops!!!
"
       filter                :


Fix JEmailConfirmation schema

Fix JEmailConfirmation schema

--- workers/social/lib/social/models/emailconfirmation.coffee
+++ workers/social/lib/social/models/emailconfirmation.coffee
@@ -18,7 +18,7 @@
         email   : yes
       salt      : String
       token     : String
-      name      : String
+      username  : String
       status    :
         type    : String
         enum    : [


Support custom message

Support custom message

--- client/templates/Step/StartWorkflowExecution/StartWorkflowExecution.coffee
+++ client/templates/Step/StartWorkflowExecution/StartWorkflowExecution.coffee
@@ -48,6 +48,7 @@
     else
       suffix = "simple" # e.g. "Downloaded 4 Twitter followers"
       count = @total or @current
+
     if @isSkipped
       key += ".skipped"
     else if @isFailed
@@ -56,6 +57,7 @@
       key += ".loaded_#{suffix}"
     else if @isStarted
       if count
+        suffix += "_message" if @message
         key += ".loading_#{suffix}"
       else
         key += ".connecting"
@@ -63,7 +65,7 @@
       key += ".cancelled"
     else
       key += ".waiting"
-    i18n.t(key, _.extend({count: count}, @, step)) # example i18n string where step data is necessary: "Reused {{spreadsheet.name}} (created earlier)"
+    i18n.t(key, _.extend({count: count, message: @message}, @, step)) # example i18n string where step data is necessary: "Reused {{spreadsheet.name}} (created earlier)"
   progressBarIconClass: (command) ->
     return "fa-check" if @isSkipped
     return "fa-exclamation-circle" if @isFailed


In startup-spec check pane item count after editor has been loaded

--- spec/integration/startup-spec.coffee
+++ spec/integration/startup-spec.coffee
@@ -28,13 +28,12 @@
     it "opens the parent directory and creates an empty text editor", ->
       runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: atomHome}, (client) ->
         client
-          .waitForPaneItemCount(1, 1000)
-
           .treeViewRootDirectories()
           .then ({value}) -> expect(value).toEqual([tempDirPath])

           .waitForExist("atom-text-editor", 5000)
           .then (exists) -> expect(exists).toBe true
+          .waitForPaneItemCount(1, 1000)
           .click("atom-text-editor")
           .keys("Hello!")
           .execute -> atom.workspace.getActiveTextEditor().getText()


returns created filenames

returns created filenames

--- modules/gui/platforms/node/tools/images.coffee
+++ modules/gui/platforms/node/tools/images.coffee
@@ -17,15 +17,22 @@

             im.convert [src, '-resize', size+'\>', dest], next

+        data =
+            src: dest
+            thumbnails: {}
+
         floyd.tools.objects.process dimensions,
-            done: done
+            done: (err)->
+                return done(err) if err
+
+                done null, data

             each: (name, size, next)->
                 if name is 'full'
                     _dest = dest

                 else
-                    _dest = dest.replace /\.([a-zA-Z]+)$/, ('.'+name+'.$1')
+                    data.thumbnails[name] = _dest = dest.replace /\.([a-zA-Z]+)$/, ('.'+name+'.$1')

                 _scale size, src, _dest, next


Tag::watch() bugs fixes

Tag::watch() bugs fixes

--- Element/element/tag/query.coffee
+++ Element/element/tag/query.coffee
@@ -240,6 +240,7 @@

 	constructor: (@node, @queries) ->
 		super()
+		@nodes = []
 		Object.preventExtensions @

 	signal.Emitter.createSignal @, 'onAdd'
@@ -255,10 +256,18 @@
 	disconnect: ->
 		assert.ok utils.has(@node._watchers, @)

+		for node in @nodes
+			utils.removeFromUnorderedArray node._inWatchers, @
+			emitSignal @, 'onRemove', node
+		utils.clear @nodes
+
 		@onAdd.disconnectAll()
 		@onRemove.disconnectAll()
+
 		index = @node._watchers.indexOf @
 		@node._watchers[index] = null
+
+		@node = @queries = null
 		pool.push @
 		return

@@ -306,21 +315,22 @@

 		queries = getQueries(selector, OPTS_REVERSED | OPTS_ADD_ANCHOR)
 		watcher = Watcher.create @, queries
+		checkWatchersDeeply @
 		watcher

-	checkWatchersDeeply: checkWatchersDeeply = (tag) ->
-		if inWatchers = tag._inWatchers
+	checkWatchersDeeply: checkWatchersDeeply = (node) ->
+		if inWatchers = node._inWatchers
 			i = n = inWatchers.length
 			while i-- > 0
-				unless inWatchers[i].test(tag)
-					emitSignal inWatchers[i], 'onRemove', tag
-					if i is n - 1
-						inWatchers.pop()
-					else
-						inWatchers.splice i, 1
+				unless inWatchers[i].test(node)
+					watcher = inWatchers[i]
+					inWatchers[i] = inWatchers[n-1]
+					inWatchers.pop()
+					utils.removeFromUnorderedArray watcher.nodes, node
+					emitSignal watcher, 'onRemove', node
 					n--

-		tmp = tag
+		tmp = node
 		while tmp
 			if watchers = tmp._watchers
 				i = 0
@@ -330,15 +340,16 @@
 					if watcher is null
 						watchers.splice i, 1
 						i--; n--
-					else if (not tag._inWatchers or !utils.has(tag._inWatchers, watcher)) and watcher.test(tag)
-						tag._inWatchers ?= []
-						tag._inWatchers.push watcher
-						emitSignal watcher, 'onAdd', tag
+					else if (not node._inWatchers or !utils.has(node._inWatchers, watcher)) and watcher.test(node)
+						node._inWatchers ?= []
+						node._inWatchers.push watcher
+						watcher.nodes.push node
+						emitSignal watcher, 'onAdd', node
 					i++
 			tmp = tmp._parent

-		if tag.children
-			for child in tag.children
+		if node.children
+			for child in node.children
 				if child instanceof Tag
 					checkWatchersDeeply child


Fix whitespace issues and constructor

Fix whitespace issues and constructor

--- js/flight.coffee
+++ js/flight.coffee
@@ -15,35 +15,27 @@
   speed: '0.4s'
   back: false

-  constructor: (options) ->
-    if options?
-      if options.transitionAnimation?
-        @transitionAnimation = options.transitionAnimation
-      if options.speed?
-        @speed = options.speed
-      # check if main menu id has been passed as an option, if not set using default.
-      if options.mainMenu?
-         if typeof options.mainMenu is "string"
-            @mainMenu = document.querySelector options.mainMenu
-          else
-            @mainMenu = options.mainMenu
-      else
-        @mainMenu = document.querySelector @mainMenu
+  constructor: (options = {}) ->
+    if options.transitionAnimation?
+      @transitionAnimation = options.transitionAnimation
+
+    if options.speed?
+      @speed = options.speed
+
+    if options.mainMenu?
+       if typeof options.mainMenu is "string"
+          @mainMenu = document.querySelector options.mainMenu or @mainMenu
+        else
+          @mainMenu = options.mainMenu

-    # get main menu dom element if not yet been set
-    if typeof @mainMenu is "string"
-      @mainMenu = document.querySelector @mainMenu
-
-    # see what device we're using
     @detectUserAgent()

-    # don't bother using transition animation on older android devices as they look terrible
     if @os.android and @os.version <= "2.1" then @transitionAnimation = false

-    if @hideUrlBar is true then @hideUrlBar()
+    @hideUrlBar() if @hideUrlBar

   # Goes to page, transitionAnimation defines if transition happens or not
-  goto: (targetPage, options) =>
+  goto: (targetPage, options) =>

     if typeof targetPage is "string"
       @targetPage = document.querySelector targetPage
@@ -58,23 +50,23 @@
       @targetPage.style.display = "-webkit-box"
       @pageHistory = [window.location.hash]
       @currentPage = @targetPage
-      return
+      return

     # if already transitioning then return
-    if @isTransitioning is true then return else @isTransitioning = true
+    if @isTransitioning is true then return else @isTransitioning = true

     # any page transition should close the slide out menu (for now)
-    @menuOpen = false
+    @menuOpen = false

     if @pageHistory.length > 1 and window.location.hash is @pageHistory[@pageHistory.length - 2]
       @back = true

     if @back is true and @pageHistory.length != 1
       transitionType = @currentPage.getAttribute("data-transition")
-      @pageHistory.pop()
+      @pageHistory.pop()
     else
       transitionType = @targetPage.getAttribute("data-transition")
-      @pageHistory.push(window.location.hash)
+      @pageHistory.push(window.location.hash)

     # Delay transition to prevent flickering
     window.setTimeout =>
@@ -87,12 +79,11 @@
       if @transitionAnimation isnt true
         @displayPage()

-    ,10
-
-
+    , 10
+
   # performs slide animation transition
   slideTransition: () ->
-    @targetPage.style.display = "-webkit-box"
+    @targetPage.style.display = "-webkit-box"

     if @back is true
       # must perform this initial tranform to get animation working in the next step
@@ -141,14 +132,14 @@
      @resetState()

   slideOutMenu: () =>
-    if @menuOpen is false
+    if @menuOpen is false
       @mainMenu.style.display = "block"
-      @translate(@currentPage,"X", "250px","0.3s")
+      @translate(@currentPage,"X", "250px","0.3s")

       @menuOpen = true
     else
-      @translate(@currentPage,"X", "0%","0.3s")
-      @menuOpen = false
+      @translate(@currentPage,"X", "0%","0.3s")
+      @menuOpen = false

   # call on transition end
   finishTransition: =>
@@ -159,13 +150,13 @@

    resetState: =>
     @back = false
-    @isTransitioning = false
-
+    @isTransitioning = false
+
    # translate page on secified axis. Duration defaults to speed property when not passed. Delay defaults to 0.
-   translate: (page, axis, distance, duration) =>
+   translate: (page, axis, distance, duration) =>
     if not duration? then duration = @speed
     page.style.webkitTransition = "#{duration} ease"
-    page.style.webkitTransform = "translate#{axis}(#{distance})"
+    page.style.webkitTransform = "translate#{axis}(#{distance})"

    # displays pages when transiton is false, back animations do not matter here.
    displayPage: =>
@@ -194,24 +185,8 @@
     @os.desktop = not (@os.ios or @os.android or @os.blackberry or @os.opera or @os.fennec)

   hideUrlBar: ->
-    setTimeout (->
+    setTimeout ->
         window.scrollTo 0, 1
-      ), 50
+    , 50

-root           = this
-previousFlight = root.Flight
-
-$ = window?.jQuery or window?.Zepto or (el) -> el
-
-Flight.setDomLibrary = (library) ->
-  $ = library
-
-Flight.noConflict = ->
-  root.Flight = previousFlight
-  this
-
-if exports?
-  module?.exports = exports = Flight
-else
-  root.Flight = Flight
-
+window.Flight = Flight


Set left to 0 to stop page disappearing.

--- js/flight.coffee
+++ js/flight.coffee
@@ -115,6 +115,8 @@
       window.setTimeout =>
         @currentPanel.style.webkitTransition = "#{@speed} ease"
         @currentPanel.style.webkitTransform = "translateX(-100%)"
+        @currentPanel.style.left = "0%"
+
       , 10

       # shortern the delay here to stop a gap appearing in android


Set height from visible content only.

Set height from visible content only.

--- js/flight.coffee
+++ js/flight.coffee
@@ -130,9 +130,10 @@
     @addClass(@targetPanel, 'visible')
     @isTransitioning = false

+  # fits viewport to content height
   fitHeightToContent: ->
     flightViewport = document.getElementById 'flight'
-    content = document.getElementsByClassName('content')[0]
+    content = document.getElementsByClassName('visible')[0].getElementsByClassName('content')[0]
     if flightViewport? and content?
       flightViewport.style.height = content.offsetHeight + "px"
     else


* Release model when requesting destroy from server

--- app/assets/javascripts/backbone.rails_store.js.coffee
+++ app/assets/javascripts/backbone.rails_store.js.coffee
@@ -118,6 +118,7 @@
     If summond, model will be constructed from server data
   ###
   release: (model, options) ->
+    @stopListening(model)
     col = @getCollectionFromModel(model)
     col.remove(model,options)
     modelType = @getModelType(model)
@@ -601,13 +602,9 @@
     @listenTo model, 'change', (model) => @_registerModelChange(model)

   registerDestroyRequest: (model) ->
-    @stopListening model
+    @release(model)
     if model.id
       @_deletedModels.push(model)
-    modelType = @getModelType(model)
-    if @_changedModels[modelType]
-      @_changedModels[modelType] = _.without(@_changedModels[modelType], model)
-

   reportSync: (model) ->
     model.syncAttributes = _.clone(model.attributes)


Add destroy method to collaborate

Add destroy method to collaborate

--- app/assets/javascripts/collaborate/collaborate.coffee
+++ app/assets/javascripts/collaborate/collaborate.coffee
@@ -6,3 +6,9 @@

   addAttribute: (attribute) =>
     @attributes[attribute] = new Collaborate.CollaborativeAttribute(@, attribute)
+
+  destroy: ->
+    for name, attribute of @attributes
+      attribute.destroy()
+
+    @cable.destroy()


remove old conflicting code

remove old conflicting code

--- app/assets/javascripts/components/subject-viewer.cjsx
+++ app/assets/javascripts/components/subject-viewer.cjsx
@@ -87,7 +87,7 @@

   # Handle initial mousedown:
   handleInitStart: (e) ->
-    return null if ! @props.subToolIndex? # this may not be needed anymore? --STI
+    console.log 'handleInitStart()'
     return null if ! @props.annotation?.subToolIndex?
     subTool = @props.task.tool_config.tools[@props.annotation.subToolIndex]
     return null if ! subTool?


Genehmigungen > Berechtigungen

Genehmigungen > Berechtigungen

--- app/assets/javascripts/uploadcare/locale/de.js.coffee
+++ app/assets/javascripts/uploadcare/locale/de.js.coffee
@@ -63,7 +63,7 @@
         camera:
           capture: 'Machen Sie ein Foto'
           mirror: 'Spiegel'
-          retry: 'Genehmigungen erneut anfordern'
+          retry: 'Berechtigungen erneut anfordern'
           pleaseAllow:
             title: 'Bitte erlauben Sie den Zugriff auf Ihre Kamera'
             text: 'Sie wurden gebeten, dieser Website den Zugriff auf Ihre Kamera zu erlauben. Um mit Ihrer Kamera Fotos machen zu können, müssen Sie diese Erlaubnis erteilen.'


Make Ace fonts bigger, 12px default

Make Ace fonts bigger, 12px default

--- client/app/Applications/Ace.kdapplication/ace.coffee
+++ client/app/Applications/Ace.kdapplication/ace.coffee
@@ -41,7 +41,7 @@
     @setHighlightActiveLine @appStorage.getValue 'highlightActiveLine', yes
     @setShowInvisibles      @appStorage.getValue 'showInvisibles',      no
     @setSoftWrap            @appStorage.getValue 'softWrap',            'off'
-    @setFontSize            @appStorage.getValue 'fontSize',            10
+    @setFontSize            @appStorage.getValue 'fontSize',            12
     @setTabSize             @appStorage.getValue 'tabSize',             4
     @setEditorListeners()

@@ -123,7 +123,7 @@
     @appStorage.getValue 'showInvisibles', @editor.getShowInvisibles()

   getFontSize:->
-    @appStorage.getValue 'fontSize', parseInt(@$("#editor#{@getId()}").css("font-size"), 10)
+    @appStorage.getValue 'fontSize', parseInt(@$("#editor#{@getId()}").css("font-size"), 12)

   getTabSize:->
     @appStorage.getValue 'tabSize', @editor.getSession().getTabSize()


Do not save all preferences when each Ace instance created again and again.

--- client/app/Applications/Ace.kdapplication/ace.coffee
+++ client/app/Applications/Ace.kdapplication/ace.coffee
@@ -39,15 +39,15 @@
     @setSyntax()
     @setEditorListeners()
     @appStorage.fetchStorage (storage)=>
-      @setUseSoftTabs         @appStorage.getValue('useSoftTabs')         ? yes
-      @setShowGutter          @appStorage.getValue('showGutter')          ? yes
-      @setUseWordWrap         @appStorage.getValue('useWordWrap')         ? no
-      @setShowPrintMargin     @appStorage.getValue('showPrintMargin')     ? no
-      @setHighlightActiveLine @appStorage.getValue('highlightActiveLine') ? yes
-      @setShowInvisibles      @appStorage.getValue('showInvisibles')      ? no
-      @setSoftWrap            @appStorage.getValue('softWrap')            or 'off'
-      @setFontSize            @appStorage.getValue('fontSize')            ? 12
-      @setTabSize             @appStorage.getValue('tabSize')             ? 4
+      @setUseSoftTabs         @appStorage.getValue('useSoftTabs')         ? yes    ,no
+      @setShowGutter          @appStorage.getValue('showGutter')          ? yes    ,no
+      @setUseWordWrap         @appStorage.getValue('useWordWrap')         ? no     ,no
+      @setShowPrintMargin     @appStorage.getValue('showPrintMargin')     ? no     ,no
+      @setHighlightActiveLine @appStorage.getValue('highlightActiveLine') ? yes    ,no
+      @setShowInvisibles      @appStorage.getValue('showInvisibles')      ? no     ,no
+      @setSoftWrap            @appStorage.getValue('softWrap')            or 'off' ,no
+      @setFontSize            @appStorage.getValue('fontSize')            ? 12     ,no
+      @setTabSize             @appStorage.getValue('tabSize')             ? 4      ,no

   setEditorListeners:->

@@ -189,13 +189,6 @@

   setContents:(contents)-> @editor.getSession().setValue contents

-  setTheme:(themeName)->
-    themeName or= @appStorage.getValue('theme') or 'merbivore_soft'
-    require ["ace/theme/#{themeName}"], (callback) =>
-      @editor.setTheme "ace/theme/#{themeName}"
-      @appStorage.setValue 'theme', themeName, =>
-        callback
-
   setSyntax:(mode)->

     file = @getData()
@@ -212,49 +205,65 @@
       @editor.getSession().setMode new Mode
       @syntaxMode = mode

-  setUseSoftTabs:(value)->
+  setTheme:(themeName, save = yes)->
+    themeName or= @appStorage.getValue('theme') or 'merbivore_soft'
+    require ["ace/theme/#{themeName}"], (callback) =>
+      @editor.setTheme "ace/theme/#{themeName}"
+      return  unless save
+      @appStorage.setValue 'theme', themeName, =>
+        callback
+
+  setUseSoftTabs:(value, save = yes)->

     @editor.getSession().setUseSoftTabs value
+    return  unless save
     @appStorage.setValue 'useSoftTabs', value

-  setShowGutter:(value)->
+  setShowGutter:(value, save = yes)->

     @editor.renderer.setShowGutter value
+    return  unless save
     @appStorage.setValue 'showGutter', value

-  setShowPrintMargin:(value)->
+  setShowPrintMargin:(value, save = yes)->

     @editor.setShowPrintMargin value
+    return  unless save
     @appStorage.setValue 'showPrintMargin', value

-  setHighlightActiveLine:(value)->
+  setHighlightActiveLine:(value, save = yes)->

     @editor.setHighlightActiveLine value
+    return  unless save
     @appStorage.setValue 'highlightActiveLine', value

   # setHighlightSelectedWord:(value)-> @editor.setHighlightActiveLine value

-  setShowInvisibles:(value)->
+  setShowInvisibles:(value, save = yes)->

     @editor.setShowInvisibles value
+    return  unless save
     @appStorage.setValue 'showInvisibles', value

-  setFontSize:(value, store = yes)->
+  setFontSize:(value, save = yes)->

     @$("#editor#{@getId()}").css 'font-size', "#{value}px"
-    if store
-      @appStorage.setValue 'fontSize', value
-
-  setTabSize:(value)->
+    return  unless save
+    @appStorage.setValue 'fontSize', value
+
+  setTabSize:(value, save = yes)->
+
     @editor.getSession().setTabSize +value
+    return  unless save
     @appStorage.setValue 'tabSize', value

-  setUseWordWrap:(value)->
+  setUseWordWrap:(value, save = yes)->

     @editor.getSession().setUseWrapMode value
+    return  unless save
     @appStorage.setValue 'useWordWrap', value

-  setSoftWrap:(value)->
+  setSoftWrap:(value, save = yes)->
     softWrapValueMap =
       'off'  : [ null, 80 ]
       '40'   : [ 40,   40 ]
@@ -267,6 +276,7 @@
     @editor.renderer.setPrintMarginColumn margin
     @setUseWordWrap no if value is "off"

+    return  unless save
     @appStorage.setValue 'softWrap', value

   focus: -> @editor?.focus()


Make editable

Make editable

--- src/scripts/modules/media/title/title.coffee
+++ src/scripts/modules/media/title/title.coffee
@@ -2,12 +2,12 @@
   _ = require('underscore')
   Backbone = require('backbone')
   router = require('cs!router')
-  BaseView = require('cs!helpers/backbone/views/base')
+  EditableView = require('cs!helpers/backbone/views/editable')
   #MailPopoverView = require('cs!./popovers/mail/mail')
   template = require('hbs!./title-template')
   require('less!./title')

-  return class MediaTitleView extends BaseView
+  return class MediaTitleView extends EditableView
     template: template
     templateHelpers: () ->
       title = @model.get('title')
@@ -30,6 +30,11 @@

       return {share: share, encodedTitle: encodeURI(title)}

+    editable:
+      '.media-title > .title > h1':
+        value: 'title'
+        type: 'contenteditable'
+
     initialize: () ->
       super()
       @listenTo(@model, 'change:title change:loaded', @render)


Changed reference to config back to configurationService

--- app/scripts/controllers/local_media_controller.coffee
+++ app/scripts/controllers/local_media_controller.coffee
@@ -1,6 +1,6 @@
 namespace 'camfire', (exports) ->
   class exports.LocalMediaCtrl
-    constructor: ($scope, config, userService, peerConnectionService, localMediaService) ->
+    constructor: ($scope, configurationService, userService, peerConnectionService, localMediaService) ->
       $scope.localStreams = localMediaService.localStreams
       $scope.state = 'ready'


Redirect new registers to dashboard instead of discover

--- app/coffee/modules/auth.coffee
+++ app/coffee/modules/auth.coffee
@@ -299,15 +299,10 @@
         $scope.data = {}
         form = $el.find("form").checksley({onlyOneErrorElement: true})

-        if $routeParams['next'] and $routeParams['next'] != $navUrls.resolve("register")
-            $scope.nextUrl = decodeURIComponent($routeParams['next'])
-        else
-            $scope.nextUrl = $navUrls.resolve("home")
+        $scope.nextUrl = $navUrls.resolve("home")

         onSuccessSubmit = (response) ->
             $analytics.trackEvent("auth", "register", "user registration", 1)
-
-            $confirm.notify("success", $translate.instant("LOGIN_FORM.SUCCESS"))

             $location.url($scope.nextUrl)


#1275 Fix wrong attribute

#1275 Fix wrong attribute

--- app/assets/javascripts/dashboard/models/user_model.coffee
+++ app/assets/javascripts/dashboard/models/user_model.coffee
@@ -8,7 +8,8 @@
     lastName : ""

   url : ->
-    if userID = @get("userID")
+
+    if userID = @get("id")
       return "/api/users/#{userID}"
     else
       return "/api/user"


Adding some line breaks.

Adding some line breaks.


Fix contact details localisation

Fix contact details localisation

--- templates/team-page.coffee
+++ templates/team-page.coffee
@@ -71,8 +71,8 @@

#{translate 'span', 'contact.contactUs'}

-
#{translate 'contact.contactUsMessage'}

-
#{translate 'contact.contactUsSchools'}

+        #{translate 'p', 'contact.contactUsMessage'}
+        #{translate 'p', 'contact.contactUsSchools'}

   "


Parses the AMS response for the taxons endpoint

--- app/assets/javascripts/sprangular/services/catalog.coffee
+++ app/assets/javascripts/sprangular/services/catalog.coffee
@@ -29,7 +29,7 @@
     taxon: (path) ->
       $http.get("/api/taxons/#{path}")
         .then (response) ->
-          response.data
+          response.data.taxon

     find: (id) ->
       $http.get("/api/products/#{id}", class: Sprangular.Product)


9226: fixed bug

9226: fixed bug

--- app/assets/javascripts/views/batch_actions_view.js.coffee
+++ app/assets/javascripts/views/batch_actions_view.js.coffee
@@ -82,6 +82,8 @@
         "</a>"
       @alert.html(msg)
       @alert.addClass('alert-info').show()
+    else if @pages == 1 and @select_all_page
+      @select_all_rows_field.val('1')

   # gets all checkboxes in batch_form
   get_batch_checkboxes: ->


Removed logic for subscribing to collections since this should be handled per app.

--- src/Collections.coffee
+++ src/Collections.coffee
@@ -109,13 +109,7 @@
       if handler
         observeArgs[methodName] = createHandler(handler)
     handle = @getCursor(collection).observe(observeArgs)
-    # If on the client, wait for the collection subscription to finish to avoid triggering
-    # the create handler as new items are added. Don't subscribe to unmanaged local collections
-    # which are unnamed.
-    if Meteor.isClient && !@isTemporary(collection)
-      Meteor.subscribe @getName(collection), -> observing = true
-    else
-      observing = true
+    observing = true
     handle

 # @param {Array.<Meteor.Collection>} collections


adds scroll frame

adds scroll frame

--- apps/browse2/client.coffee
+++ apps/browse2/client.coffee
@@ -15,6 +15,7 @@
 PillboxView = require '../../components/commercial_filter/views/pillbox/pillbox_view.coffee'
 ArtworkColumnsView = require '../../components/artwork_columns/view.coffee'
 Sticky = require '../../components/sticky/index.coffee'
+scrollFrame = require 'scroll-frame'
 sd = require('sharify').data

 module.exports.init = ->
@@ -109,6 +110,8 @@
       current: params.whitelisted()
       changed: params.changedAttributes()

+  scrollFrame '.cf-artworks a' unless sd.EIGEN
+
   # Handles sticky sidebar
   @sticky = false
   filter.artworks.on 'reset zero:artworks', =>


joyent/node#1914: REPL no longer hides `undefined` results

--- repl.coffee
+++ repl.coffee
@@ -54,8 +54,7 @@
     }
     if returnValue is undefined
       global._ = _
-    else
-      process.stdout.write inspect(returnValue, no, 2, enableColours) + '\n'
+    process.stdout.write inspect(returnValue, no, 2, enableColours) + '\n'
   catch err
     error err
   repl.prompt()


Cleanup.

Cleanup.

--- src/EntityUtils.coffee
+++ src/EntityUtils.coffee
@@ -217,11 +217,7 @@
   renderAll: (args) ->
     df = Q.defer()
     @renderingEnabledDf.promise.then Meteor.bindEnvironment =>
-      # renderDfs = []
-      # models = Entities.findByProject().fetch()
       @_chooseDisplayMode()
-      # _.each models, (model) => renderDfs.push(@render(model._id))
-      # df.resolve(Q.all(renderDfs))
       promise = @renderQueue.add 'bulk', => @_renderBulk(args)
       df.resolve(promise)
     df.promise


fix(email-frame): Listening for mouse events not necessary?

--- internal_packages/message-list/lib/email-frame.cjsx
+++ internal_packages/message-list/lib/email-frame.cjsx
@@ -123,7 +123,6 @@
     doc = @getDOMNode().contentDocument
     doc?.removeEventListener?("click")
     doc?.removeEventListener?("keydown")
-    @_delegateMouseEvents(doc, "removeEventListener")

   shouldComponentUpdate: (newProps, newState) ->
     # Turns out, React is not able to tell if props.children has changed,
@@ -141,7 +140,6 @@
     doc.close()
     doc.addEventListener "click", @_onClick
     doc.addEventListener "keydown", @_onKeydown
-    @_delegateMouseEvents(doc, "addEventListener")

   _setFrameHeight: ->
     _.defer =>
@@ -186,14 +184,5 @@
         target = target.parentElement

   _onKeydown: (event) ->
+    return if event.metaKey or event.altKey or event.ctrlKey
     @getDOMNode().dispatchEvent(new KeyboardEvent(event.type, event))
-
-  _delegateMouseEvents: (doc, method="addEventListener") ->
-    for type in ["mouseup", "mousedown"]
-      doc?[method]?(type, @_onMouseEvent)
-
-  _onMouseEvent: (event) ->
-    {top, left} = @getDOMNode().getBoundingClientRect()
-    new_coords = {clientX: event.clientX + left, clientY: event.clientY + top}
-    new_event = _.extend {}, event, new_coords
-    @getDOMNode().dispatchEvent(new MouseEvent(event.type, new_event))


Clear entries column so previous selection does not show. Preload entries on mobile.

--- app/assets/javascripts/_site.js.coffee
+++ app/assets/javascripts/_site.js.coffee
@@ -41,7 +41,7 @@
     $('[data-behavior~=entries_target]').html('')

   clearEntry: ->
-    $('[data-behavior~=toolbar_target_entry], [data-behavior~=entry_content_target]' ).html('')
+    $('[data-behavior~=entry_content_target]' ).html('')

   syntaxHighlight: ->
     $('[data-behavior~=entry_content_target] pre').each (i, e) ->
@@ -323,7 +323,9 @@
       $(document).on 'click', '[data-behavior~=back_to_feeds]', ->
         $('.app').addClass('nothing-selected').removeClass('feed-selected entry-selected')

-      $(document).on 'click', '[data-behavior~=show_entries]', ->
+      $(document).on 'click', '[data-behavior~=show_entries]', (event) ->
+        unless $(event.target).hasClass('back-button')
+          feedbin.clearEntries()
         $('.app').addClass('feed-selected').removeClass('nothing-selected entry-selected')

       $(document).on 'click', '[data-behavior~=show_entry_content]', ->
@@ -421,7 +423,7 @@
       $(document).on 'ajax:beforeSend', '[data-behavior~=open_item]', (event, xhr) ->
         id = $(@).parents('li').data('entry-id')
         entry = feedbin.entries[id]
-        if entry && false == feedbin.data.mobile
+        if entry
           xhr.abort()
           feedbin.updateEntryContent(entry.content)
           feedbin.formatEntryContent()


Update domready script

Update domready script

--- app/assets/javascripts/domready.coffee
+++ app/assets/javascripts/domready.coffee
@@ -6,8 +6,7 @@

 jQuery ($) ->

-  domready = ->
-
+  documentReady = ->
     Orientation.accordion()
     Orientation.autoSubmit()
     Orientation.dropdown()
@@ -16,8 +15,9 @@
     Orientation.tableBank.init()

   # -------------------------------------
-  #   Turbolinks & DOM Ready Handlers
+  #   Set Event Handlers
   # -------------------------------------

-  $( document ).ready( domready )
-  $( document ).on( 'page:load', domready )
+  $( document ).on
+    'ready'     : documentReady
+    'page:load' : documentReady


Fixing failing tests

Fixing failing tests

--- app/assets/javascripts/forms.js.coffee
+++ app/assets/javascripts/forms.js.coffee
@@ -1,17 +1,12 @@

 initRadioButtons = (delegateFor) ->
-  delegateFor.delegate ".status-buttons .radio input,.buttons .radio input", "click", () ->
+  delegateFor.delegate ".status-buttons .radio input,.buttons .radio input", "change", () ->
     buttons = $(this).parents('.status-buttons,.buttons').first()
     buttons.find('.btn').removeClass('checked')
-#    buttons.find('input').attr('checked', false).change()
     $(this).parents('.btn:first').addClass('checked')
- #   $(this).attr('checked', true).change()
-
-

 uniformify = (node) ->
   $("select, input:checkbox, input:radio, input:file, input:text, textarea, submit", node).uniform()
-

 initOrganPage = (delegateFor) ->
   toggleArchived = (visible) ->


Stop zooming in on hero during real-time playback, because it can mess with ability to place flags.

--- app/lib/surface/Surface.coffee
+++ app/lib/surface/Surface.coffee
@@ -558,7 +558,7 @@
     @playing = false  # Will start when countdown is done.
     if @heroLank
       @previousCameraZoom = @camera.zoom
-      @camera.zoomTo @heroLank.sprite, 2, 3000
+      #@camera.zoomTo @heroLank.sprite, 2, 3000  # This makes flag placement hard, now that we're only rarely using this as a coolcam.

   onRealTimePlaybackEnded: (e) ->
     return unless @realTime


Decreased severity of camera jerkiness during real-time playback.

--- app/lib/surface/Surface.coffee
+++ app/lib/surface/Surface.coffee
@@ -142,10 +142,8 @@

   setWorld: (@world) ->
     @worldLoaded = true
-    lastFrame = Math.min(@getCurrentFrame(), @world.frames.length - 1)
-    @world.getFrame(lastFrame).restoreState() unless @options.choosing
     @spriteBoss.world = @world
-
+    @restoreWorldState() unless @options.choosing
     @showLevel()
     @updateState true if @loaded
     @onFrameChanged()


Adds remove_fields, add_fields and autocomplete handlers

--- app/assets/javascripts/base.js.coffee
+++ app/assets/javascripts/base.js.coffee
@@ -1,6 +1,34 @@
 $(document).ready ->
-  $( ".accordions" ).each (k, v) ->
+  $( '.accordions' ).each (k, v) ->
     $(v).accordion({ autoHeight: false });

-  $(".tabs").each (k, v) ->
-    $(v).tabs({ autoHeight: false });+  $('.tabs').each (k, v) ->
+    $(v).tabs({ autoHeight: false });
+
+  $('form').on 'click', '.remove_fields', (event) ->
+    #$(this).prev('input[type=hidden]').val('1')
+    $(this).closest('fieldset').remove()
+    event.preventDefault()
+
+  $('form').on 'click', '.add_fields', (event) ->
+    time = new Date().getTime()
+    regexp = new RegExp($(this).data('id'), 'g')
+    target = $(this)
+
+    if $(this).data('number-of-parents') == 3
+      target = target.parent().parent().parent()
+
+    target.after($(this).data('fields').replace(regexp, time))
+    event.preventDefault()
+
+  $('input[data-autocomplete]').each (k, v) ->
+    $(v).autocomplete({
+      source: $(this).attr('data-autocomplete'),
+      select: (event, ui) ->
+        $(this).val(ui.item.value)
+
+        if ($(this).attr('id_element'))
+          $($(this).attr('id_element')).val(ui.item.id)
+
+        return false;
+    });


Automatically scroll down to last error

Automatically scroll down to last error

--- app/assets/javascripts/home.js.coffee
+++ app/assets/javascripts/home.js.coffee
@@ -4,6 +4,7 @@

 $(document).on "page:change", ->
   displayFormErrors()
+  scrollToLastToolTip()

 @displayFormErrors = () ->
   $('.form-control').each ->
@@ -14,3 +15,6 @@
   tooltip = $("#{message}")
   targetElement.after tooltip
   tooltip.css 'right', -(tooltip.outerWidth() + 10) + 'px'
+
+scrollToLastToolTip = () ->
+  $('html, body').animate({scrollTop: $('.error').last().offset().top}, 100);


Remove findSubjectInCollection

Remove findSubjectInCollection

--- app/collections/favorites-button.cjsx
+++ app/collections/favorites-button.cjsx
@@ -40,12 +40,6 @@
     apiClient.type('collections')
       .get({project_ids: @props.project?.id, favorite: true, owner: @props.user.login})
       .then ([favorites]) -> if favorites? then favorites else null
-
-  findSubjectInCollection: () ->
-    if @props.subject.hasOwnProperty 'favorite'
-      Promise.resolve @props.subject.favorite
-    else
-      Promise.resolve false

   componentWillMount: ->
     favorited = @props.isFavorite


make minified files even smaller and make sure source map is generated

--- configs/webpack/base.coffee
+++ configs/webpack/base.coffee
@@ -149,7 +149,9 @@
       rules: BASE_BUILD_LOADERS
     plugins: makeBuildPlugins({styleFilename}).concat([
       # Minify
-      new webpack.optimize.UglifyJsPlugin(minimize: true)
+      # https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
+      # https://github.com/webpack/webpack/issues/2704
+      new webpack.optimize.UglifyJsPlugin(comments: false, sourceMap: true)

       # Use the production version of React (no warnings/runtime checks)
       new webpack.DefinePlugin(


customview: fix for incorrect constant name

--- lib/components/scrollview/customscrollviewinner.coffee
+++ lib/components/scrollview/customscrollviewinner.coffee
@@ -8,7 +8,7 @@

 module.exports = class KDCustomScrollViewWrapper extends KDScrollView

-  BACKSPACE = 32
+  SPACEBAR  = 32
   PAGEUP    = 33
   PAGEDOWN  = 34
   END       = 35
@@ -164,12 +164,12 @@
     return yes  if @getScrollHeight() <= @verticalThumb.getTrackSize()

     shouldPropagate = no
-    if event.which is BACKSPACE and event.shiftKey
+    if event.which is SPACEBAR and event.shiftKey
       @pageUp()
     else
       switch event.which
         when PAGEUP then @pageUp()
-        when BACKSPACE, PAGEDOWN then @pageDown()
+        when SPACEBAR, PAGEDOWN then @pageDown()
         when END then @scrollToBottom()
         when HOME then @scrollTo top : 0
         else shouldPropagate = yes


Edit csscomb setting

Edit csscomb setting

--- app/templates/Gruntfile.coffee
+++ app/templates/Gruntfile.coffee
@@ -136,11 +136,9 @@
     csscomb:
       dynamic_map:
         expand: true
-        src: [
-          '../htdocs/**/*.css'
-          '!../htdocs/common/css/extras/*.css'
-        ]
-        dest: '../htdocs/**/*.css'
+        cwd: '../htdocs/common/css/'
+        src: '*.css'
+        dest: '../htdocs/common/css/'

     combine_mq:
       default_options:


Upgrade CODAP-connect to API v2.0

Upgrade CODAP-connect to API v2.0

--- src/code/models/codap-connect.coffee
+++ src/code/models/codap-connect.coffee
@@ -36,19 +36,54 @@

     @codapPhone = new IframePhoneRpcEndpoint( @codapRequestHandler,
-      'codap-game', window.parent )
-
-    @codapPhone.call( {
-      action: 'initGame'
-      args:
-        name: @name
-        dimensions:
-          width: 800
+      'data-interactive', window.parent )
+
+    # set frame size
+    @codapPhone.call
+      action: 'update',
+      resource: 'interactiveFrame',
+      values: {
+        title: @name,
+        dimensions: {
+          width: 800,
           height: 600
-        collections: [
-          {
-            name: 'Simulation'
-            attrs: [
+        }
+      }
+
+    # load any previous data
+    @codapPhone.call
+      action: 'get',
+      resource: 'interactiveFrame'
+    , (ret) =>
+      state = ret.values.savedState
+      if state?
+        @graphStore.deleteAll()
+        @graphStore.loadData state
+
+
+    timeUnit = TimeUnits.toString SimulationStore.store.settings.stepUnits, true
+    sampleDataAttrs = [
+      {
+        name: timeUnit
+        type: "numeric"
+      }
+    ]
+
+    # create collections, then kick-off init
+    @codapPhone.call
+      action: 'create',
+      resource: 'dataContext',
+      values: {
+        name: 'Sage Simulation',
+        title: 'Sage Simulation'
+        collections: [ {
+          name: 'Simulation',
+          title: 'Sage Simulation',
+          labels: {
+            singleCase: 'run',
+            pluralCase: 'runs'
+          },
+          attrs: [
               {
                 name: tr '~CODAP.SIMULATION.RUN'
                 formula: 'caseIndex'
@@ -62,25 +97,33 @@
                 precision: 0
               }
             ]
+          },
+          {
+            parent: "Simulation",
+            name: 'Samples',
+            title: 'Samples',
+            labels: {
+              singleCase: 'sample',
+              pluralCase: 'samples'
+            }
+            attrs: sampleDataAttrs
           }
         ]
-        contextType: 'DG.DataContext'
-    }, @initGameHandler)
+      }
+    , @initGameHandler

   _openNewCase: (nodeNames) ->
     @currentCaseID = null

     @_createCollection(nodeNames)

-    @codapPhone.call {
-      action: 'openCase'
-      args: {
-        collection: 'Simulation',
-        values: [null, null]
-      }
-    }, (result) =>
+    @codapPhone.call
+      action: 'create',
+      resource: 'collection[Simulation].case',
+      values: [ {} ]
+    , (result) =>
       if result?.success
-        @currentCaseID = result.caseID
+        @currentCaseID = result.values[0].id
         @stepsInCurrentCase = 0
         @_flushQueue()
         if not @standaloneMode
@@ -116,10 +159,9 @@
         addSampleDataAttr(node)

     @codapPhone.call
-      action: 'createCollection'
-      args:
-        name: 'Samples'
-        attrs: sampleDataAttrs
+      action: 'create',
+      resource: 'collection[Samples].attribute',
+      values: sampleDataAttrs

   _sendSimulationData: (data) ->
     if not @currentCaseID
@@ -127,39 +169,40 @@
       @queue.push data
       return

+    timeUnit = TimeUnits.toString SimulationStore.store.settings.stepUnits, true
+
     # Create the sample data values (node values array)
-    sampleData = _.map data, (frame) ->
-      sample     = [frame.time]
-      _.each frame.nodes, (n) -> sample.push n.value
+    sampleData = _.map data, (frame) =>
+      sample = {
+        parent: @currentCaseID
+        values: {}
+      }
+      sample.values[timeUnit] = frame.time
+      _.each frame.nodes, (n) -> sample.values[n.title] = n.value
       sample

     # Send the data, if any
     if sampleData.length > 0
       @codapPhone.call
-        action: 'createCases'
-        args: {
-          collection: 'Samples',
-          parent: @currentCaseID,
-          values: sampleData
-        }
-
-    # Update the parent case with the current number of steps
-#    @stepsInCurrentCase += sampleData.length
-#    @codapPhone.call
-#      action: 'updateCase'
-#      args: {
-#        collection: 'Simulation',
-#        caseID: @currentCaseID
-#        values: [null, @stepsInCurrentCase]
-#      }
+        action: 'create',
+        resource: "collection[Samples].case",
+        values: sampleData

   _sendUndoToCODAP: ->
     @codapPhone.call
-      action: 'undo'
+      action: 'notify',
+      resource: 'UndoChangeNotice'
+      values: {
+        operation: 'undoAction'
+      }

   _sendRedoToCODAP: ->
     @codapPhone.call
-      action: 'redo'
+      action: 'notify',
+      resource: 'UndoChangeNotice'
+      values: {
+        operation: 'redoAction'
+      }

   _flushQueue: ->
     for data in @queue
@@ -168,102 +211,79 @@

   sendUndoableActionPerformed: (logMessage) ->
     @codapPhone.call
-      action: 'undoableActionPerformed'
-      args: {
+      action: 'notify',
+      resource: 'UndoChangeNotice'
+      values: {
+        operation: 'undoableActionPerformed',
         logMessage: logMessage
       }

   createGraph: (yAttributeName)->
-    timeUnit = TimeUnits.toString SimulationStore.store.settings.stepUnits, true
-    nodes = @graphStore.getNodes()
-
-    # First column definition is the time index
-    sampleDataAttrs = [
-      {
-        name: timeUnit
-        type: "numeric"
-      }
-    ]
-
-    # Append node names to column descriptions.
-    _.each nodes, (node) ->
-      type = if node.valueDefinedSemiQuantitatively then 'qualitative' else 'numeric'
-      sampleDataAttrs.push
-        name: node.title
-        type: type
-
-    @codapPhone.call
-      action: 'createCollection'
-      args:
-        name: 'Samples'
-        attrs: sampleDataAttrs
-
-    @codapPhone.call
-      action: 'createComponent'
-      args: {
-        type: 'DG.GraphView',
+    @_createCollection()
+
+    @codapPhone.call
+      action: 'create',
+      resource: 'component',
+      values:
+        type: 'graph'
         xAttributeName: timeUnit,
         yAttributeName: yAttributeName,
         size: { width: 242, height: 221 },
         position: 'bottom'
-        log: false
-      }

   createTable: (yAttributeName)->
     @codapPhone.call
-      action: 'createComponent'
-      args: {
-        type: 'DG.TableView',
-        log: false
-      }
+      action: 'create',
+      resource: 'component',
+      values:
+        type: 'caseTable'

   codapRequestHandler: (cmd, callback) =>
-    operation = cmd.operation
-    args = cmd.args
+    resource = cmd.resource
+    action = cmd.action
+    operation = cmd.values?.operation
     paletteManager = require '../stores/palette-store'
-    switch operation
-      when 'saveState'
-        log.info 'Received saveState request from CODAP.'
-        callback
-          success: true
-          state: @graphStore.serialize paletteManager.store.palette
-
-      when 'restoreState'
-        log.info 'Received restoreState request from CODAP.'
-        @graphStore.deleteAll()
-        @graphStore.loadData args.state
-        callback
-          success: true
-
-      when 'externalUndoAvailable'
-        log.info 'Received externalUndoAvailable request from CODAP.'
-        CodapActions.hideUndoRedo()
-
-      when 'standaloneUndoModeAvailable'
-        log.info 'Received standaloneUndoModeAvailable request from CODAP.'
-        @standaloneMode = true
-        @graphStore.setCodapStandaloneMode true
-
-      when 'undoAction'
-        log.info 'Received undoAction request from CODAP.'
-        successes = @graphStore.undo(true)
-        callback {success: @reduceSuccesses(successes) isnt false}
-
-      when 'redoAction'
-        log.info 'Received redoAction request from CODAP.'
-        successes = @graphStore.redo(true)
-        callback {success: @reduceSuccesses(successes) isnt false}
-
-      when 'clearUndo'
-        log.info 'Received clearUndo request from CODAP.'
-        @graphStore.undoRedoManager.clearHistory()
-
-      when 'clearRedo'
-        log.info 'Received clearRedo request from CODAP.'
-        @graphStore.undoRedoManager.clearRedo()
-
+
+    switch resource
+      when 'interactiveState'
+        if action is 'get'
+          log.info 'Received saveState request from CODAP.'
+          callback
+            success: true
+            state: @graphStore.serialize paletteManager.store.palette
+      when 'UndoChangeNotice'
+        if operation is 'undoAction'
+          log.info 'Received undoAction request from CODAP.'
+          successes = @graphStore.undo(true)
+          callback
+            success: @reduceSuccesses(successes) isnt false
+        if operation is 'redoAction'
+          log.info 'Received redoAction request from CODAP.'
+          successes = @graphStore.redo(true)
+          callback
+            success: @reduceSuccesses(successes) isnt false
+        if operation is 'clearUndo'
+          log.info 'Received clearUndo request from CODAP.'
+          @graphStore.undoRedoManager.clearHistory()
+        if operation is 'clearRedo'
+          log.info 'Received clearRedo request from CODAP.'
+          @graphStore.undoRedoManager.clearRedo()
       else
-        log.info 'Unknown request received from CODAP: ' + operation
+        log.info 'Unknown request received from CODAP: ' + JSON.stringify cmd
+
+
+    # switch operation
+
+    #   when 'externalUndoAvailable'
+    #     log.info 'Received externalUndoAvailable request from CODAP.'
+    #     CodapActions.hideUndoRedo()
+
+    #   when 'standaloneUndoModeAvailable'
+    #     log.info 'Received standaloneUndoModeAvailable request from CODAP.'
+    #     @standaloneMode = true
+    #     @graphStore.setCodapStandaloneMode true
+
+

   # undo/redo events can return an array of successes
   # this reduces that array to true iff every element is not explicitly false


Capitalize factory names.

Capitalize factory names.

--- test/javascripts/support/factories.js.coffee
+++ test/javascripts/support/factories.js.coffee
@@ -159,7 +159,7 @@
     ETahi.Factory.createRecord('litePaper', paperAttrs)

 ETahi.FactoryAttributes = {}
-ETahi.FactoryAttributes.user =
+ETahi.FactoryAttributes.User =
   _rootKey: 'user'
   id: null
   full_name: "Fake User"
@@ -168,7 +168,7 @@
   email: "fakeuser@example.com"
   admin: false
   affiliation_ids: []
-ETahi.FactoryAttributes.journal =
+ETahi.FactoryAttributes.Journal =
   _rootKey: 'journal'
   id: null
   name: "Fake Journal"
@@ -192,7 +192,7 @@
   ]
   manuscript_css: null

-ETahi.FactoryAttributes.paper =
+ETahi.FactoryAttributes.Paper =
   _rootKey: 'paper'
   id: 1
   short_title: "Paper"
@@ -211,7 +211,7 @@
   tasks: []
   journal_id: null

-ETahi.FactoryAttributes.litePaper =
+ETahi.FactoryAttributes.LitePaper =
   _rootKey: 'lite_paper'
   id: null
   title: "Foo"
@@ -219,7 +219,7 @@
   short_title: "Paper"
   submitted: false

-ETahi.FactoryAttributes.messageTask =
+ETahi.FactoryAttributes.MessageTask =
   _rootKey: 'task'
   id: null
   title: "Message Time"
@@ -236,7 +236,7 @@
   participant_ids: []
   comment_ids: []

-ETahi.FactoryAttributes.comment =
+ETahi.FactoryAttributes.Comment =
   _rootKey: 'comment'
   id: null
   commenter_id: null
@@ -245,7 +245,7 @@
   created_at: null
   comment_look_id: null

-ETahi.FactoryAttributes.phase =
+ETahi.FactoryAttributes.Phase =
   _rootKey: 'phase'
   id: null
   name: "Submission Data"


Tests highscore after game

Tests highscore after game

--- test/highscore_spec.coffee
+++ test/highscore_spec.coffee
@@ -36,11 +36,28 @@
           text.should.match /Highscore liste/)

     test.it "should see highscore after game", ->
+      points = undefined
+
       utils.load_new_game(driver, 'askeladden')
-        .then( -> utils.answer_question(driver, true))
-        driver.findElement(css: '#ratio').getText()
-          .then (text) ->
-            text.should.match /Du fik \d+\/\d+ rigtige svar\!/
-        driver.findElement(css: '#points').getText()
-          .then (text) ->
-            text.should.match /Point\: \d+/
+        .then ->
+          utils.answer_question(driver, true)
+            .then ->
+              driver.findElement(css: '#ratio').getText()
+                .then (text) ->
+                  text.should.match /Du fik \d+\/\d+ rigtige svar\!/
+              driver.findElement(css: '#points').getText()
+                .then (text) ->
+                  points = text.match(/Point\: (\d+)/)[1]
+              driver.findElement(css: '#restart').click()
+              driver.findElement(css: '#highscores').click()
+              driver.findElement(css: '#heading').getText()
+                .then (text) ->
+                  text.should.match /Highscore liste/
+              driver.findElements(tagName: 'tr')
+                .then (elements) ->
+                  for element in elements
+                    element.getText()
+                      .then (text) ->
+                        if text.match /askeladden.*/
+                          text.should.match "askeladden #{points}"
+                          return


Whitespace

Whitespace

--- keymaps/git-experiment.cson
+++ keymaps/git-experiment.cson
@@ -10,9 +10,6 @@
 'atom-workspace':
   'cmd-shift-h': 'git:view-history'
   'cmd-shift-c': 'git:view-and-commit-changes'
-
-
-
   'cmd-ctrl-b': 'git:checkout-branch'
   'cmd-ctrl-shift-b': 'git:create-branch'

@@ -34,9 +31,6 @@
   'a': 'git:select-active-lines'
   'shift-up': 'git:expand-selection-up'
   'shift-down': 'git:expand-selection-down'
-
-
-
   'escape': 'git:clear-selections'
   'tab': 'git:focus-commit-message'
   'o': 'git:open-file-to-line'


in not of

in not of

--- scripts/pokebattle.coffee
+++ scripts/pokebattle.coffee
@@ -168,7 +168,7 @@
     msg.send "A wild #{poke} appears!"
     msg.send "http://serebii.net/Pkmn_Green/#{pad(pokemon.indexOf(poke) + 1, 3)}.gif"

-for poke of pokemon
+for poke in pokemon
   module.exports = (robot) ->
     robot.hear new RegExp(poke, 'i'), (msg) ->
       msg.send "#{poke}, I choose you!"


Fix bug in Project.scan that was getting the state machine into a bad state

Chunks of stdout data are being buffered by lines. But then we were splitting these chunks on \n and the last fragment was therefore always "". This caused problems. Still need to test this.

--- src/app/project.coffee
+++ src/app/project.coffee
@@ -165,9 +165,6 @@
     readMatches = (matchInfo, lineText) ->
       [lineNumber, matchPositionsText] = matchInfo.match(/(\d+);(.+)/)[1..]
       row = parseInt(lineNumber) - 1
-
-
-
       matchPositions = matchPositionsText.split(',').map (positionText) -> positionText.split(' ').map (pos) -> parseInt(pos)

       for [column, length] in matchPositions
@@ -177,19 +174,9 @@

     ChildProcess.exec command , bufferLines: true, stdout: (data) ->
       lines = data.split('\n')
-      try
-        for line in lines
-          readPath(line) if state is 'readingPath'
-          readLine(line) if state is 'readingLines'
-      catch e
-        console.log e.stack
-
-
-
-
-
-
-
-
+      lines.pop() # the last segment is a spurios '' because data always ends in \n due to bufferLines: true
+      for line in lines
+        readPath(line) if state is 'readingPath'
+        readLine(line) if state is 'readingLines'

 _.extend Project.prototype, EventEmitter


Only select the fields we need to compare/update apps.

--- src/application.coffee
+++ src/application.coffee
@@ -182,6 +182,11 @@
 			resource: 'application'
 			options:
 				expand: 'environment_variable'
+				select: [
+					'id'
+					'git_repository'
+					'commit'
+				]
 				filter:
 					'device/uuid': uuid
 			customOptions:


Activity: minor code styling

Activity: minor code styling

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

     return switch data.typeConstant
-      when 'post' then KD.singletons.socialapi.message.revive message: data
-      when 'topic' then KD.singletons.socialapi.mapChannel data
+      when 'post'  then KD.singletons.socialapi.message.revive message: data  #mapActivity
+      when 'topic' then KD.singletons.socialapi.channel.revive data
       else data


ActivityItem: ActivityDelete event is emitted in deleteActivity method

--- client/Social/Activity/views/activityitemchild.coffee
+++ client/Social/Activity/views/activityitemchild.coffee
@@ -59,9 +59,10 @@

     data = @getData()

-    deleteActivity = (activityItem)->
+    deleteActivity = (activityItem)=>
       activityItem.destroy() #FIXME
-      activityItem.slideOut -> activityItem.destroy()
+      # activityItem.slideOut -> activityItem.destroy()
+      @emit 'ActivityIsDeleted'

     @settingsButton.on 'ActivityIsDeleted', =>
       activityItem = @getDelegate()


Tests: Raise timeout on slave handoff new slave spawn

--- test/slave/handoffs.coffee
+++ test/slave/handoffs.coffee
@@ -185,7 +185,7 @@

         describe "New Slave", ->
             before (done) ->
-                this.timeout 5000
+                this.timeout 20000

                 s2 = cp.fork "./index.js", ["--handoff",slave_config...]
                 process.on "exit", -> s2.kill()