Renaming on KDTooltip.

Renaming on KDTooltip.

--- components/tooltip/KDTooltip.coffee
+++ components/tooltip/KDTooltip.coffee
@@ -17,14 +17,17 @@

   constructor:(options,data)->

-    options = $.extend {}, options,
-      bind  : "mouseenter mouseleave"
-
-    super options,data
+    # options = $.extend {}, options,
+    #   bind     : "mouseenter mouseleave"
+
+    options.bind        or= "mouseenter mouseleave"
+    options.sessionKey  or= ""
+
+    super options, data

     @avoidDestroy = no
     @visible      = yes
-    @view         = @getDelegate()
+    @parentView   = @getDelegate()

     # Container for positioning in the viewport
     @setClass 'kdtooltip'
@@ -59,7 +62,7 @@
     if o.selector
       selectorEntered = no

-      @view.on 'mousemove', (mouseEvent)=>
+      @parentView.on 'mousemove', (mouseEvent)=>

         if $(mouseEvent.target).is(o.selector) and selectorEntered is no
           selectorEntered = yes
@@ -79,7 +82,7 @@

       if event
         return if o.selector and not $(event.target).is o.selector
-      @view.off 'mousemove'
+      @parentView.off 'mousemove'
       # to throttle super need to call it explicitly
       # KDView::show.call @
       super
@@ -100,20 +103,22 @@
     o = @getOptions()

     if o.events
-      @view.bindEvent name for name in o.events
-
-    @view.on 'mouseenter', @bound "show"
+      @parentView.bindEvent name for name in o.events
+
+    @parentView.on 'mouseenter', =>
+      @show()
+      @avoidDestroy = yes

     unless o.selector
-      @view.on 'mouseleave', @bound "hide"
-
-    # @view.on 'click',      @bound "hide"
+      @parentView.on 'mouseleave', =>
+        @avoidDestroy = no
+        @delayedRemove 40

     @on 'mouseenter', =>
       @avoidDestroy = yes

     @on 'mouseleave', (event)=>
-      return if $(event.target).is @view.$()
+      return if $(event.target).is @parentView.$()
       @avoidDestroy = no
       @delayedRemove()

@@ -130,18 +135,19 @@

   isCurrentlyRemovable:-> @avoidDestroy

-  setView:(newView)->
-    return unless newView
-
-    if @wrapper.view?
-      @wrapper.removeSubView @wrapper.view
-
-    {options, data, constructorName} = newView
-
-    @view = new constructorName options, data
-    @wrapper.addSubView @view
-
-  getView:-> @view
+  setView: (childView) ->
+    return unless childView
+
+    if @wrapper.childView?
+      @wrapper.removeSubView @wrapper.childView
+
+    if childView.constructorName
+      {options, data, constructorName} = childView
+      @childView = new constructorName options, data
+    else
+      @wrapper.addSubView childView
+
+  getView:-> @childView

   delayedDisplay:(timeout = @getOptions().delayIn)->
     @utils.killWait @displayTimer
@@ -162,8 +168,8 @@
   destroy:->

     @visible = no
-    @view.tooltip = null
-    delete @view.tooltip
+    @parentView.tooltip = null
+    delete @parentView.tooltip
     super

   delayedRemove:(timeout = @getOptions().delayOut)->
@@ -198,12 +204,12 @@
     @show()
     @visible = yes
     @getSingleton('windowController').disableScroll()
-    @setPosition(o)
+    @setPosition o

   getCorrectPositionCoordinates:(o={},positionValues,callback=noop)->
     # values that can/will be used in all the submethods
     container       = @$()
-    selector        = @view.$(o.selector)
+    selector        = @parentView.$(o.selector)
     d = # dimensions
       container :
         height  : container.height()
@@ -314,7 +320,7 @@
     # @setTemplate @pistachio()
     # @template.update()

-    @view.emit 'TooltipReady'
+    @parentView.emit 'TooltipReady'

     @addSubView @arrow
     @addSubView @wrapper


Teamwork: Options are merging with defaults.

--- client/landing/app/Applications/Teamwork.kdapplication/Views/teamworkapp.coffee
+++ client/landing/app/Applications/Teamwork.kdapplication/Views/teamworkapp.coffee
@@ -4,31 +4,38 @@

     super options, data

+    options               = @getOptions()
     instanceName          = if location.hostname is "localhost" then "teamwork-local" else "kd-prod-1"
+    additionalButton      =
+      title               : "Environments"
+      cssClass            : "clean-gray"
+      callback            : (panel, workspace) => @showEnvironmentsModal panel, workspace
+
     @teamwork             = new TeamworkWorkspace
-      name                : "Teamwork"
-      version             : "0.1"
-      joinModalTitle      : "Join a coding session"
-      joinModalContent    : "
Paste the session key that you received and start coding together.
"
-      shareSessionKeyInfo : "
This is your session key, you can share this key with your friends to work together.
"
-      firebaseInstance    : instanceName
-      sessionKey          : @getOptions().sessionKey
+      name                : options.name                or "Teamwork"
+      joinModalTitle      : options.joinModalTitle      or "Join a coding session"
+      joinModalContent    : options.joinModalContent    or "
Paste the session key that you received and start coding together.
"
+      shareSessionKeyInfo : options.shareSessionKeyInfo or "
This is your session key, you can share this key with your friends to work together.
"
+      firebaseInstance    : options.firebaseInstance    or instanceName
+      sessionKey          : options.sessionKey
       panelClass          : TeamworkPanel
       delegate            : this
-      panels              : [
+      environment         : options.environment         or null
+      panels              : options.panels              or [
         title             : "Teamwork"
         hint              : "
This is a collaborative coding environment where you can team up with others and work on the same code.
"
         buttons           : [
           {
             title         : "Tools"
-            cssClass      : "clean-gray"
-            callback      : (panel, workspace) => @showToolsModal panel, workspace
+            cssClass      : "clean-gray tw-tools-button"
+            callback      : => @showToolsModal @teamwork.getActivePanel(), @teamwork
           }
+          # additionalButton
         ]
         floatingPanes     : [ "chat" , "terminal", "preview" ]
         layout            :
           direction       : "vertical"
-          sizes           : [ "25%", null ]
+          sizes           : [ "250px", null ]
           splitName       : "BaseSplit"
           views           : [
             {


rm moment from analytics

rm moment from analytics

--- lib/analytics.coffee
+++ lib/analytics.coffee
@@ -8,7 +8,6 @@
 _s = require 'underscore.string'
 sd = require('sharify').data
 qs = require('querystring')
-moment = require 'moment'
 sparkMd5Hash = require('spark-md5').hash

 module.exports = (options) =>


added a default menu for Mac to enable copy/paste

--- init-nw.coffee
+++ init-nw.coffee
@@ -80,4 +80,10 @@
     listen:  abbr: 'l', flag: true
     spawn:   abbr: 's', flag: true
   ).parse gui.App.argv
+
+  if process.platform == 'darwin'
+    mb = new gui.Menu type: 'menubar'
+    mb.createMacBuiltin 'Dyalog'
+    gui.Window.get().menu = mb
+
   return


class name and comment changes

class name and comment changes

--- src/woodentrack.coffee
+++ src/woodentrack.coffee
@@ -10,7 +10,7 @@
 		@_listeners = {}
 		@_gapTransform = new Transform(@trackGap, 0, 0)

-	# attach listener to particular types of event, e.g. "add", "remove", "move" or "change"
+	# attach listener to "add", "remove" or "change" types of event
 	on: (types, listener) ->
 		types.split(" ").forEach (type) =>
 			if !@_listeners[type]? then @_listeners[type] = []
@@ -68,8 +68,8 @@
 		else
 			@connect piece, @cursor()

-	# connection (code) where the next piece will be added
-	cursor: ->
+	# connection (code) where the next piece will be added
+	cursor: ->
 		@connections()[@connections().length-1]

 	# Connect piece to available connection identified from code, e.g. "10:C".
@@ -99,7 +99,7 @@
 	remove: (index) ->
 		[sectionIndex, pieceIndex] = @_sectionAndPieceIndex index
 		@_sections[sectionIndex].remove(pieceIndex)
-		@_fire { type: 'remove', target: @ }
+		@_fire { type: 'remove', target: @ }

 	clear: ->
 		# todo: remove listeners / pieces?
@@ -109,7 +109,7 @@
 	_firePieceAdded: (piece) ->
 		idx = @_index piece
 		transform = @_transform(idx.toString() + ":A")
-		@_fire { type: 'add', target: piece, start: transform.compound(new Transform(0,0,180)) }
+		@_fire { type: 'add', target: piece, start: transform.compound(new Transform(0,0,180)) }

 	_sectionAndPieceIndex: (index) ->
 		result = [-1,-1]
@@ -124,7 +124,7 @@

 	_sectionStartingIndex: (section) ->
 		result=0
-		for idx in [0...@_sections.indexOf(section)]
+		for idx in [0...@_sections.indexOf(section)]
 			do (idx) =>
 				result+=@_sections[idx]._pieces.length
 		result
@@ -270,7 +270,7 @@
 		return "("+@translateX+", "+@translateY+", "+@rotateDegs+")"

 # an extended Transform with a pointer to another connection
-class Connection extends Transform
+class ConnectedTransform extends Transform
 	constructor: (@translateX, @translateY, @rotateDegs) ->
 		super @translateX, @translateY, @rotateDegs
 		@connected = null
@@ -286,7 +286,7 @@
 		@radius = options.radius ? 1
 		@exit = options.exit ? 'B'
 		@flip = options.flip ? 1
-		@connections = { 'A' : new Connection(0, 0, -180) }
+		@connections = { 'A' : new ConnectedTransform(0, 0, -180) }
 		@section = null

 	setSection: (section) ->
@@ -303,7 +303,7 @@

 class Straight extends Piece
 	setSection: (section) ->
-		@connections.B = new Connection(@size*section.track.gridSize, 0, 0)
+		@connections.B = new ConnectedTransform(@size*section.track.gridSize, 0, 0)
 		super
 		section.track._closeLoops this

@@ -314,7 +314,7 @@

 class Bend extends Piece
 	setSection: (section) ->
-		@connections.B = new Connection(
+		@connections.B = new ConnectedTransform(
 			Math.sin(@angle)*section.track.gridSize,
 			@flip*(1-Math.cos(@angle))*section.track.gridSize,
 			@flip*@angle*180/Math.PI)
@@ -328,8 +328,8 @@

 class Split extends Piece
 	setSection: (section) ->
-		@connections.B = new Connection(@size*section.track.gridSize, 0, 0)
-		@connections.C = new Connection(
+		@connections.B = new ConnectedTransform(@size*section.track.gridSize, 0, 0)
+		@connections.C = new ConnectedTransform(
 			Math.sin(@angle)*section.track.gridSize,
 			@flip*(1-Math.cos(@angle))*section.track.gridSize,
 			@flip*@angle*180/Math.PI)
@@ -345,8 +345,8 @@

 class Join extends Piece
 	setSection: (section) ->
-		@connections.B = new Connection(@size*section.track.gridSize, 0, 0)
-		@connections.C = new Connection(
+		@connections.B = new ConnectedTransform(@size*section.track.gridSize, 0, 0)
+		@connections.C = new ConnectedTransform(
 			((2/3)-Math.sin(@angle))*section.track.gridSize,
 			@flip*(1-Math.cos(@angle))*section.track.gridSize,
 			@flip*@angle*3*180/Math.PI)
@@ -364,11 +364,11 @@

 class Merge extends Piece
 	setSection: (section) ->
-		@connections.B = new Connection(
+		@connections.B = new ConnectedTransform(
 			Math.sin(@angle)*section.track.gridSize,
 			@flip*(1-Math.cos(@angle))*section.track.gridSize,
 			@flip*@angle*180/Math.PI)
-		@connections.C = new Connection(
+		@connections.C = new ConnectedTransform(
 			section.track.gridSize*(Math.sin(@angle)-(2*Math.cos(@angle)/3)),
 			@flip*section.track.gridSize*(1-Math.cos(@angle)-(2*Math.sin(@angle)/3)),
 			@flip*((@angle*180/Math.PI)-180))
@@ -384,15 +384,15 @@

 class Crossover extends Piece
 	setSection: (section) ->
-		@connections.B = new Connection(
+		@connections.B = new ConnectedTransform(
 			Math.sin(@angle)*section.track.gridSize,
 			@flip*(1-Math.cos(@angle))*section.track.gridSize,
 			@flip*@angle*180/Math.PI)
-		@connections.C = new Connection(
+		@connections.C = new ConnectedTransform(
 			2*section.track.gridSize*Math.sin(@angle/2),
 			@flip*2*section.track.gridSize*(1-Math.cos(@angle/2)),
 			0)
-		@connections.D = new Connection(
+		@connections.D = new ConnectedTransform(
 			section.track.gridSize*(2*Math.sin(@angle/2)-Math.sin(@angle)),
 			@flip*section.track.gridSize*(1-(2*Math.cos(@angle/2))+Math.cos(@angle)),
 			@flip*((@angle*180/Math.PI)-180))


enabled reason + zodiac in green - so far it shows the house system as well

--- lib/ephemeris.coffee
+++ lib/ephemeris.coffee
@@ -122,7 +122,7 @@
               }
             , { key: "reason"
               , req: ["re"]
-              , act: false
+              , act: true
               , val: (its) ->
                 its.re
               }
@@ -150,6 +150,7 @@
               marker: true
               id: lon.representations[i]
               lon: i * 30
+              re: "zodiac".green

           # Process and sort.
           for i, item of json


Restore accidentally removed top-level module assignment

--- lib/list-edit.coffee
+++ lib/list-edit.coffee
@@ -4,6 +4,7 @@

 module.exports =
+module.exports = ListEdit =
   subscriptions: null

   activate: (state) ->


remove coffee task

remove coffee task

--- app/templates/gulp/tasks/coffee.coffee
+++ app/templates/gulp/tasks/coffee.coffee
@@ -1,13 +0,0 @@
-gulp         = require "gulp"
-coffee       = require "gulp-coffee"
-gutil        = require "gulp-util"
-plumber      = require "gulp-plumber"
-
-conf = require '../gulpconfig'
-
-gulp.task "coffee", () ->
-  gulp.src ["./#{conf.path.dev.coffee}/**/*.coffee"]
-    .pipe plumber(conf.plumber)
-    .pipe coffee({bare: true}).on('error', gutil.log)
-    .pipe gulp.dest(conf.path.dev.js)
-    .pipe global.browserSync.reload({stream: true})


Redraw links when selecting link

Redraw links when selecting link

The amount of additional checking makes the link description work seem
a little pointless...

[#135367247]

--- src/code/views/graph-view.coffee
+++ src/code/views/graph-view.coffee
@@ -113,6 +113,7 @@
   componentDidUpdate: (prevProps, prevState) ->
     if (prevState.description.links != @state.description.links) or
         (prevState.simulationPanelExpanded != @state.simulationPanelExpanded) or
+        (prevState.selectedLink != @state.selectedLink) or
         @forceRedrawLinks
       @diagramToolkit?.clear?()
       @_updateToolkit()


Revert "try to cache repos by directory to speed up `getRepoForCurrentFile`"

This reverts commit 93114fa2aa9508021f3512c57c9ef4736b74b37f.

--- lib/git.coffee
+++ lib/git.coffee
@@ -1,5 +1,6 @@
 Os = require 'os'
 {BufferedProcess, Directory} = require 'atom'
+
 RepoListView = require './views/repo-list-view'
 notifier = require './notifier'

@@ -25,24 +26,15 @@
   data[1..data.length] = ('@@' + line for line in data[1..])
   data

-reposByDirectory = new Map
-
 getRepoForCurrentFile = ->
   new Promise (resolve, reject) ->
     project = atom.project
     path = atom.workspace.getCenter().getActiveTextEditor()?.getPath()
     directory = project.getDirectories().filter((d) -> d.contains(path))[0]
     if directory?
-      if repo = reposByDirectory.get(directory.getPath()) then return resolve(repo)
-
       project.repositoryForDirectory(directory).then (repo) ->
-        submodule = repo.getRepo().submoduleForPath(path)
-        if submodule?
-          reposByDirectory.set(directory.getPath(), submodule)
-          resolve(submodule)
-        else
-          reposByDirectory.set(directory.getPath(), repo)
-          resolve(repo)
+        submodule = repo.repo.submoduleForPath(path)
+        if submodule? then resolve(submodule) else resolve(repo)
       .catch (e) ->
         reject(e)
     else


Server: fix tests, set isApiTokenEnabled true for created groups

--- servers/lib/server/handlers/api/createssotoken.test.coffee
+++ servers/lib/server/handlers/api/createssotoken.test.coffee
@@ -53,7 +53,8 @@

   it 'should send HTTP 400 if user is non-existent', (done) ->

-    withConvertedUserAndApiToken ({ userFormData, apiToken }) ->
+    options = { createGroup : yes, groupData : { isApiTokenEnabled : yes } }
+    withConvertedUserAndApiToken options, ({ userFormData, apiToken }) ->

       createSsoTokenRequestParams = generateCreateSsoTokenRequestParams
         headers : { Authorization : "Bearer #{apiToken.code}" }
@@ -69,7 +70,7 @@
   it 'should send HTTP 400 if user is not a member of the api token group', (done) ->

     # creating user, group, and api token
-    options = { createGroup : yes }
+    options = { createGroup : yes, groupData : { isApiTokenEnabled : yes } }
     withConvertedUserAndApiToken options, ({ userFormData, apiToken }) ->

       # creating another user, which is not a member of the previously created group
@@ -90,7 +91,7 @@
   it 'should send HTTP 200 with token in body if request is valid', (done) ->

     # creating user, group, and api token
-    options = { createGroup : yes }
+    options = { createGroup : yes, groupData : { isApiTokenEnabled : yes } }
     withConvertedUserAndApiToken options, ({ userFormData, apiToken }) ->

       createSsoTokenRequestParams = generateCreateSsoTokenRequestParams
@@ -100,7 +101,6 @@
       request.post createSsoTokenRequestParams, (err, res, body) ->
         expect(err).to.not.exist
         expect(res.statusCode).to.be.equal 200
-        expect(body).to.contain 'token'
         expect(body).to.contain 'loginUrl'
         done()


Update the email-merge email template

Update the email-merge email template

--- services/web/app/coffee/Features/Email/EmailBuilder.coffee
+++ services/web/app/coffee/Features/Email/EmailBuilder.coffee
@@ -45,12 +45,14 @@
 	title: () -> "Confirm Account Merge"
 	message: () ->
 		"""
-			To merge your ShareLaTeX and Overleaf accounts, click the link below.
+			To merge your ShareLaTeX and Overleaf accounts, click the button below.
 			If you think you have received this message in error,
 			please contact us at https://www.overleaf.com/contact
 		"""
 	ctaText: () -> "Confirm Account Merge"
 	ctaURL: (opts) -> opts.tokenLinkUrl
+	secondaryMessage: (opts) ->
+		"If the button does not appear, open this link in your browser: #{opts.tokenLinkUrl}"
 })

 templates.accountMergeToSharelatexAddress = templates.accountMergeToOverleafAddress


round avg percentages

round avg percentages

--- src/components/scores/index.cjsx
+++ src/components/scores/index.cjsx
@@ -106,7 +106,7 @@

     if heading.average
       summary = <span className='summary'>
-        {(heading.average * 100).toFixed(1)}% avg
+        {(heading.average * 100).toFixed(0)}% avg
       </span>

     sortingHeader = <SortingHeader type={heading.type} sortKey={i}


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- source/javascripts/_cornerstone/array_extensions.js.coffee
+++ source/javascripts/_cornerstone/array_extensions.js.coffee
@@ -436,7 +436,7 @@

     return result
   else
-    return this[start.mod(this.length)]
+    return this[start.mod(@length)]

 ###*
 Partitions the elements into two groups: those for which the iterator returns


fix render too many cards because of using [a..b].

--- js/card.coffee
+++ js/card.coffee
@@ -29,6 +29,6 @@
 $ ->
     $.getJSON 'data/foodNutrition.json', (data) ->
         no_foods = data.foodNameTH.length
-        $('#foods').html(card(data, index) for index in [0..no_foods])
-        for index in [0..no_foods]
+        $('#foods').html(card(data, index) for index in [0...no_foods])
+        for index in [0...no_foods]
             radar(data, index)


fix(macDatepicker): Fixed cannot reset macDatepicker with null

Fixes #119

--- src/directives/datepicker.coffee
+++ src/directives/datepicker.coffee
@@ -10,6 +10,7 @@

 @param {String}     mac-datepicker-id        The id of the text input field
 @param {String}     mac-datepicker-model     The model to store the selected date
+Clearing model by setting it to null or '' will clear the input field
 @param {Function}   mac-datepicker-on-select Function called before setting the value to the model
   - `date` - {String} Selected date from the datepicker
   - `instance` - {Object} Datepicker instance
@@ -83,7 +84,7 @@

         if attrs.macDatepickerModel?
           $scope.$watch attrs.macDatepickerModel, (value) ->
-            if initialized and value?
+            if initialized
               $timeout ->
                 inputElement.datepicker "setDate", value
               , 0, false


changed to new common js style

changed to new common js style

--- src/driver/driverCache.coffee
+++ src/driver/driverCache.coffee
@@ -1,14 +1,4 @@
-# this needs to be done in JS land to avoid creating a global var module
-`
-if (typeof module === 'undefined') {
-  exports = {};
-  module = { exports: exports };
-  require = function (modulePath) {
-    var moduleParts = modulePath.split('/');
-    return window[moduleParts[moduleParts.length - 1]];
-  }
-}
-`
+`(typeof window === 'undefined' ? {} : window)['driverCache'] = (function(module, require){"use strict"; var exports = module.exports`

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

@@ -207,4 +197,10 @@

 # -----------------------------------------------------
 # Handle commonJS crap
-window['driverCache'] = exports if typeof window isnt 'undefined'
+`return module.exports; }).call(this,
+  (typeof module === 'undefined' ? {exports: {}} : module),
+  (typeof require === 'undefined' ? function (modulePath) {
+    var moduleParts = modulePath.split('/');
+    return window[moduleParts[moduleParts.length - 1]];
+  } : require)
+)`


Catches the FB.init errors so the app can boot event if FB fails

--- src/remote/services/facebook.coffee
+++ src/remote/services/facebook.coffee
@@ -36,8 +36,12 @@

   initialize: (app)->
     dfd = app.core.data.deferred()
-    FB.init(app.config.services.settings.facebook_app)
-    FB.getLoginStatus dfd.resolve
+    try
+      FB.init(app.config.services.settings.facebook_app)
+      FB.getLoginStatus dfd.resolve
+    catch e
+      console.warn("Facebook provider failed to launch because of: #{e.message}")
+      dfd.resolve {}
     app.core.routeHandlers.fql = fql
     app.core.routeHandlers.facebook = api
     dfd


Refactor variable name(Invalid case)

Refactor variable name(Invalid case)

--- src/renderer/scripts/app/App.coffee
+++ src/renderer/scripts/app/App.coffee
@@ -42,7 +42,7 @@
         @config.load()

         @nsenStream = new NsenStream
-        @SpeechHost = new SpeechHost
+        @speechHost = new SpeechHost
         @player = new Player

         $ =>


Strengthens IP regex to validate that each octet is in valid range

--- src/scripts/reputation-links.coffee
+++ src/scripts/reputation-links.coffee
@@ -15,7 +15,8 @@
 #   Scott J Roberts - @sroberts

 module.exports = (robot) ->
-  robot.respond /reputation ip (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/i, (msg) ->
+  robot.respond /reputation ip ((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))/i, (msg) ->
+
     target_ip = msg.match[1].toLowerCase()

     reputation_links = """#{target_ip} IP Reputation:


Professionals debug in the wild.

Professionals debug in the wild.

--- tests/loud_test.coffee
+++ tests/loud_test.coffee
@@ -30,6 +30,7 @@
       room.user.say 'alice',   'FOO & BAR'
       room.user.say 'bob',     'FOO%'
       room.user.say 'charlie', 'FOO"BAR"'
+      console.log room.robot.brain.get('louds')
       expect(room.robot.brain.get('louds').length).to.eql 12
       expect(room.robot.brain.get('louds')).to.eql ['"FOO"', 'FOO+', 'FOO-', 'FOO@BAR', 'FOO #BAR', 'FOO$', 'FOO%', 'FOO & BAR', 'FOO%', 'FOO"BAR"']


WebTerm: Implemented session recover.

WebTerm: Implemented session recover.

--- client/landing/app/Applications/WebTerm.kdapplication/AppView.coffee
+++ client/landing/app/Applications/WebTerm.kdapplication/AppView.coffee
@@ -1,4 +1,9 @@
 class WebTermView extends KDView
+
+  constructor: (options = {}, data) ->
+
+    super options, data
+    @initBackoff()

   viewAppended: ->
     @container = new KDView
@@ -26,6 +31,7 @@

     @terminal.sessionEndedCallback = (sessions) =>
       @emit "WebTerm.terminated"
+      @clearConnectionAttempts()

     @terminal.setTitleCallback = (title) =>
       #@tabPane.setTitle title
@@ -42,6 +48,8 @@
       @terminal.setFocused false
       KD.getSingleton('windowController').removeLayer @

+    @on "KDObjectWillBeDestroyed", @bound "clearConnectionAttempts"
+
     $(window).on "blur", =>
       @terminal.setFocused false

@@ -57,33 +65,119 @@

     @appStorage = new AppStorage 'WebTerm', '1.0'
     @appStorage.fetchStorage =>
-      @appStorage.setValue 'font', 'ubuntu-mono' if not @appStorage.getValue('font')?
-      @appStorage.setValue 'fontSize', 14 if not @appStorage.getValue('fontSize')?
-      @appStorage.setValue 'theme', 'green-on-black' if not @appStorage.getValue('theme')?
+      @appStorage.setValue 'font'      , 'ubuntu-mono' if not @appStorage.getValue('font')?
+      @appStorage.setValue 'fontSize'  , 14 if not @appStorage.getValue('fontSize')?
+      @appStorage.setValue 'theme'     , 'green-on-black' if not @appStorage.getValue('theme')?
       @appStorage.setValue 'visualBell', false if not @appStorage.getValue('visualBell')?
       @appStorage.setValue 'scrollback', 1000 if not @appStorage.getValue('scrollback')?
       @updateSettings()

+      delegateOptions = @getDelegate().getOptions()
+      myOptions       = @getOptions()
+
       KD.getSingleton("vmController").run
-        method   : 'webterm.connect',
-        vmName   : @getOption('delegate').getOption('vmName')
-        withArgs :
-          remote : @terminal.clientInterface
-          joinUser : @getOption('delegate').getOption('joinUser')
-          session  : @getOption('delegate').getOption('session')
-          sizeX  : @terminal.sizeX
-          sizeY  : @terminal.sizeY
-          noScreen: @getOption('delegate').getOption('noScreen')
+        method        : "webterm.connect",
+        vmName        : delegateOptions.vmName
+        withArgs      :
+          remote      : @terminal.clientInterface
+          sizeX       : @terminal.sizeX
+          sizeY       : @terminal.sizeY
+          joinUser    : myOptions.joinUser or delegateOptions.joinUser
+          session     : myOptions.session  or delegateOptions.session
+          noScreen    : delegateOptions.noScreen
       , (err, remote) =>
         if err
-          # We don't create any error popup not to be annoying. User can handle the error.
-          error err
-        else
-          @terminal.eventHandler = (data)=>
-            @emit "WebTermEvent", data
-          @terminal.server = remote
-          @setKeyView()
-          @emit "WebTermConnected", remote
+          warn err
+          if err.message is "Invalid session identifier."
+            return @reinitializeWebTerm()
+
+        @terminal.eventHandler = (data)=> @emit "WebTermEvent", data
+        @terminal.server       = remote
+        @setKeyView()
+        @emit "WebTermConnected", remote
+        @sessionId = remote.session
+
+    KD.getSingleton("status").once "reconnected", => @handleReconnect()
+
+    kiteErrorCallback = (err) =>
+      @reconnected               = no
+      {code, serviceGenericName} = err
+
+      if code is 503 and serviceGenericName.indexOf("kite-os") is 0
+        @reconnectAttemptFailed serviceGenericName, @getDelegate().getOption "vmName"
+
+    kiteController = KD.getSingleton "kiteController"
+    kiteController.on "KiteError", kiteErrorCallback
+
+    @on "KiteErrorBindingNeedsToBeRemoved", =>
+      kiteController.off "KiteError", kiteErrorCallback
+
+  reconnectAttemptFailed: (serviceGenericName, vmName) ->
+    return  if @reconnected or not serviceGenericName
+
+    kiteController = KD.getSingleton "kiteController"
+    [prefix, kiteType, kiteRegion] = serviceGenericName.split "-"
+    serviceName = "~#{kiteType}-#{kiteRegion}~#{vmName}"
+
+    @setBackoffTimeout(
+      @bound "atttemptToReconnect"
+      @bound "handleConnectionFailure"
+    )
+
+    kiteController.kiteInstances[serviceName]?.cycleChannel()
+
+  atttemptToReconnect: ->
+    return  if @reconnected
+    @reconnectingNotification ?= new KDNotificationView
+      type      : "mini"
+      title     : "Trying to reconnect your Terminal"
+      duration  : 2 * 60 * 1000 # 2 mins
+      container : @container
+
+    vmController = KD.getSingleton "vmController"
+    hasResponse  = no
+
+    vmController.info @getDelegate().getOption("vmName"), (err, res) =>
+      hasResponse = yes
+      @handleReconnect()
+      @clearConnectionAttempts()
+
+    @utils.wait 500, => @reconnectAttemptFailed() unless hasResponse
+
+  clearConnectionAttempts: ->
+    @emit "KiteErrorBindingNeedsToBeRemoved"
+    @clearBackoffTimeout()
+
+  handleReconnect: ->
+    return  if @reconnected
+    @clearConnectionAttempts()
+    options =
+      session  : @sessionId
+      joinUser : KD.nick()
+
+    @reinitializeWebTerm options
+    @reconnectingNotification?.destroy()
+    @reconnected = yes
+
+  reinitializeWebTerm: (options = {}) ->
+    options.delegate = @getDelegate()
+    @addSubView webterm = new WebTermView options
+
+    webterm.on "WebTermConnected", =>
+      @getSubViews().first.destroy() # TODO: refactor this, don't use subviews
+
+  handleConnectionFailure: ->
+    return if @failedToReconnect
+    @reconnectingNotification?.destroy()
+    @reconnected       = no
+    @failedToReconnect = yes
+    @clearConnectionAttempts()
+    new KDNotificationView
+      type      : "mini"
+      title     : "Sorry, something is wrong with our backend."
+      container : @container
+      cssClass  : "error"
+      duration  : 15 * 1000 # 15 secs

   destroy: ->
     super
@@ -184,3 +278,5 @@
       mainView = KD.getSingleton "mainView"
       mainView.toggleFullscreen()
       event.preventDefault()
+
+  initBackoff: KDBroker.Broker.prototype.initBackoff


Auto expand a page's children when hovering while sorting

--- app/assets/javascripts/cmsimple/panels/sitemap/sortable.coffee
+++ app/assets/javascripts/cmsimple/panels/sitemap/sortable.coffee
@@ -14,10 +14,30 @@
               items: 'li'
               listType: 'ul'
               stop: @proxy @update
+              activate: @proxy @activate
+              deactivate: @proxy @deactivate
               tolerance: 'pointer',
               toleranceElement: '> article'

     @el.disableSelection()
+
+    @el.bind 'sortable:refresh', => @el.nestedSortable('refreshPositions')
+
+  activate: ->
+    @el.find('> li').on 'hover', @over
+
+  deactivate: ->
+    @el.find('> li').off 'hover'
+
+  over: ->
+    item = $(@)
+
+    return if item.hasClass('ui-sortable-helper')
+
+    unless item.hasClass('open')
+      item.addClass('open')
+      item.find('ul.hidden').removeClass('hidden')
+      item.trigger('sortable:refresh')

   update: (e, sortable)->
     @updatePagePositions()


AgentDonut: code cleanup

AgentDonut: code cleanup

--- widgets/agent_donut/agent_donut.coffee
+++ widgets/agent_donut/agent_donut.coffee
@@ -17,8 +17,6 @@

         # Define the container
         @container = $(@node).parent()
-        #console.log 'node',$(@node)
-        #console.log 'container',@container

         #
         # CONFIG ZONE


format

format

--- app/assets/javascripts/components/kid_mentor_schedules.js.cjsx
+++ app/assets/javascripts/components/kid_mentor_schedules.js.cjsx
@@ -125,14 +125,12 @@
           onChange=@onChange
         />

-       <button
+      <button
         onClick=@selectAll
         className="btn btn-default col-xs-2">
           Select All ({_.size @props.mentors})
       </button>
-

-

 Filters = React.createClass
   onChangeSex: (event) ->
@@ -210,6 +208,7 @@
             time: time
             schedules: @props.kid.schedules

+          # end kidCell

         mentorCell = (mentor, day) =>
           onClick = =>
@@ -221,6 +220,8 @@
             kidIsAvailable=kidIsAvailable
             numberOfMentors={_.size @props.mentors}
             day=day time=time lastTime=lastTime nextTime=nextTime />
+          # end mentorCell
+
         classes = classNames "time-cell",
           "kid-available": kidIsAvailable
         <td key="time_cell_#{day.key}_#{time.key}"
@@ -228,7 +229,7 @@
           { kidCell day }
           { mentorCell mentor, day for mentor in mentors}

-      # end timecell
+        # end timecell

       mentors = _.values @props.mentors

@@ -236,6 +237,7 @@
         { timeCell day for day in days }

       # end timeRow
+

@@ -247,6 +249,7 @@
       { timeRow time, i for time, i in times }

+    # end render

 TimeTable_MentorCell = React.createClass


Fixed POST parameters sent when hiding an opml import alert.

--- app/assets/javascripts/ng-services/ng-ImportStateSvc.js.coffee
+++ app/assets/javascripts/ng-services/ng-ImportStateSvc.js.coffee
@@ -52,7 +52,7 @@
     #---------------------------------------------
     hide_alert: ->
       $rootScope.show_import_alert = false
-      $http.put("/api/opml_imports.json", opml_import_job_state: {show_alert: 'false'})
+      $http.put("/api/opml_imports.json", opml_import: {show_alert: 'false'})

   return service
 ]


changed component name

changed component name

--- imports/ui/pages/LoginPage.cjsx
+++ imports/ui/pages/LoginPage.cjsx
@@ -3,7 +3,7 @@
 { LoginForm, Box, Headline }     = require 'grommet'

 module.exports  = React.createClass
-  displayName: 'Page'
+  displayName: 'LoginPage'

   onSubmit: (credentials) ->
     @props.onLogin credentials.username, credentials.password


here how it should be

here how it should be

--- js/main.coffee
+++ js/main.coffee
@@ -1,10 +1,12 @@
-do =>
+do ->
   createConfigurator = ->
-    obj = {}
-    createArguments = (x, y)->
-      createArguments.result = obj
-      obj[x] = y
-      arguments.callee
+    configurator = (fieldName, value) ->
+      obj[fieldName] = value
+      return configurator
+
+    configurator.result = obj = {}
+
+    return configurator

   _ = createConfigurator()
   console.log _("age", 25)("name", "sergii").result


fixed an issue with isPortrait and isLandscape

--- Framework/Views/BaseView.coffee
+++ Framework/Views/BaseView.coffee
@@ -58,8 +58,12 @@
     Ti.App.addEventListener("forceLandscapeWindow", (e) => @window.orientationModes = [Ti.UI.LANDSCAPE_LEFT, Ti.UI.LANDSCAPE_RIGHT])
     Ti.Gesture.addEventListener("orientationchange", (e) =>
       if Ti.UI.orientation == Ti.UI.PORTRAIT || Ti.UI.orientation == Ti.UI.UPSIDE_PORTRAIT
+        @isPortrait = true
+        @isLandscape = false
         @onPortrait()
       else
+        @isLandscape = true
+        @isPortrait = false
         @onLandscape()
     )


Added SongFormView. TODO: SongFormController and make the view a little prettier.

--- Frontend/app/scripts/app.coffee
+++ Frontend/app/scripts/app.coffee
@@ -38,6 +38,9 @@
     .when '/songs',
       templateUrl: 'scripts/song/SongListView.html'
       controller: 'SongListCtrl'
+    .when '/songs/create',
+      templateUrl: 'scripts/song/SongFormView.html'
+      controller: 'SongFormCtrl'
     .when '/auth',
       templateUrl: 'scripts/auth/AuthView.html'
       controller: 'AuthCtrl'


Fix column domains grid

Fix column domains grid

--- src/ext/modules/routines.coffee
+++ src/ext/modules/routines.coffee
@@ -28,6 +28,10 @@
     description: 'Make a prediction'
     icon: 'bolt'

+createArrays = (length) ->
+  for i in [0 ... length]
+    new Array length
+
 parseNaNs = (source) ->
   target = new Array source.length
   for element, i in source
@@ -756,35 +760,30 @@
       #TODO sort table in-place when sorting is implemented
       sortedLevels = sortBy levels, (level) -> -level.count

-      variables = [
-        Flow.Data.Variable 'label', TString
-        countVariable = Flow.Data.Variable 'count', TNumber
-        Flow.Data.Variable 'percent', TNumber, [ 0, 100 ]
+      [ labels, counts, percents ] = createArrays sortedLevels.length
+
+      for level, i in sortedLevels
+        labels[i] = column.domain[level.index]
+        counts[i] = level.count
+        percents[i] = 100 * level.count / rowCount
+
+      vectors = [
+        createFactor 'label', TString, labels
+        createVector 'count', TNumber, counts
+        createVector 'percent', TNumber, percents
       ]

-      Record = Flow.Data.Record variables
-      rows = for level in sortedLevels
-        row = new Record()
-        row.label = column.domain[level.index]
-        row.count = countVariable.read level.count
-        row.percent = 100 * level.count / rowCount
-        row
-
-      Flow.Data.Table
-        label: 'domain'
+      createDataframe 'domain', vectors, (sequence sortedLevels.length), null,
         description: "Domain for column '#{column.label}' in frame '#{frameKey}'."
-        variables: variables
-        rows: rows
-        meta:
-          origin: "getColumnSummary #{stringify frameKey}, #{stringify columnName}"
-          plot: """
-          plot
-            title: 'Domain for #{frameKey} : #{column.label}'
-            type: 'interval'
-            data: inspect 'domain', getColumnSummary #{stringify frameKey}, #{stringify columnName}
-            x: 'count'
-            y: 'label'
-          """
+        origin: "getColumnSummary #{stringify frameKey}, #{stringify columnName}"
+        plot: """
+        plot
+          title: 'Domain for #{frameKey} : #{column.label}'
+          type: 'interval'
+          data: inspect 'domain', getColumnSummary #{stringify frameKey}, #{stringify columnName}
+          x: 'count'
+          y: 'label'
+        """

     inspections =
       characteristics: inspectCharacteristics


Update# fix translate filter logic

Update# fix translate filter logic

--- src/extras/batman.i18n.coffee
+++ src/extras/batman.i18n.coffee
@@ -60,10 +60,9 @@
     binding = interpolationKeypaths
     interpolationKeypaths = undefined
   return if not string
-  key = string # Store key for lookupKeypath if translate didn't found
   unless binding.key and binding.key.substr(0, 2) == "t." # If already translated, skip it
-    string = Batman.I18N.translate(key)
-    string ||= key # no translate, return default key
+    translated = Batman.I18N.translate(string)
+    string = translated if translated
   Batman.Filters.interpolate.apply(@, [string, interpolationKeypaths, binding])

 Batman.config.translations = true


Fix typo.

Fix typo.

--- src/fs_utils/source_file.coffee
+++ src/fs_utils/source_file.coffee
@@ -71,11 +71,11 @@

     cache.node.source = realPath
     cache.node.setSourceContent realPath, source
-
+
     wrapped = wrap compiled
     sourcePos = wrapped.indexOf compiled
     if sourcePos > 0
-      cache.node.prepend wrapped.slice 0, sourcePos - 1
+      cache.node.prepend wrapped.slice 0, sourcePos
       cache.node.add wrapped.slice sourcePos + compiled.length

   cache


Fix weird behavior when not logged in.

Fix weird behavior when not logged in.

--- app/app.coffee
+++ app/app.coffee
@@ -57,7 +57,7 @@

     # Redirect to default state.
     $stateProvider.state('index', {
-      url: '',
+      url: '/',
       controller: ($state, xoApi) ->
         defaultState =
           if xoApi.user?.permission is 'admin'


GameObject.Effect

GameObject.Effect

--- src/game_object_effect.coffee
+++ src/game_object_effect.coffee
@@ -24,9 +24,9 @@
   @name fadeOut
   @methodOf GameObject#
   @param {Number} [duration=1] Time to fade out in seconds
-  @param {Function} [callback=null] The function to execute when fade out completes.
+  @param {Function} [complete=null] The function to execute when fade out completes.
   ###
-  fadeOut: (duration=1, callback) ->
+  fadeOut: (duration=1, compl) ->
     self.tween duration,
       alpha: 0
       callback: callback


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/game_state_cameras.coffee
+++ src/game_state_cameras.coffee
@@ -26,4 +26,6 @@
       return cameras
     flash: ->
       cameras.first().flash()
+    shake: ->
+      cameras.first().shake()
   }


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/game_state_cameras.coffee
+++ src/game_state_cameras.coffee
@@ -9,7 +9,7 @@
     self.cameras().invoke 'trigger', 'draw', canvas, self.objects()

   self.bind 'overlay', (canvas) ->
-    self.cameras().invoke 'trigger', 'overlay' (camera) ->
+    self.cameras().invoke 'trigger', 'overlay',
       camera.trigger 'overlay', canvas

   return {


replaced calcOverlayPosition, trigger=manual in tutor-popover

--- src/components/tutor-popover.cjsx
+++ src/components/tutor-popover.cjsx
@@ -105,7 +105,7 @@

   guessPlacement: ->
     {windowImpl} = @props
-    {overlayLeft} = @refs.popper.calcOverlayPosition()
+    overlayLeft = React.findDOMNode(@refs.popper).getBoundingClientRect().left
     midWindow = windowImpl.innerWidth / 2
     if overlayLeft > midWindow then 'left' else 'right'

@@ -144,7 +144,6 @@
       {...overlayProps}
       placement={placement}
       overlay={popover}
-      trigger='manual'
       ref='popper'>
       {children}
     </BS.OverlayTrigger>


Remove reference from dom to data object

--- src/jquery.transparency.coffee
+++ src/jquery.transparency.coffee
@@ -23,9 +23,8 @@
 renderSimple = (template, object) ->
   unless typeof object == 'object'
     node = template.find(".listElement")
-    unless (node.length)
+    unless (node.length)
       node = template.children().first()
-    node.data 'data', object
     renderNode node, object

 renderValues = (template, object) ->


MasterRepository.dataName

MasterRepository.dataName

--- src/lib/master-repository.coffee
+++ src/lib/master-repository.coffee
@@ -16,10 +16,14 @@
 class MasterRepository extends BaseSyncRepository

-    @data: null
+    ###*
+    Name of the data in master data.
+    @modelName is used if not set.

-
-    @load: ->
+    @property {String} dataName
+    @static
+    ###
+    @dataName: null

     constructor: ->
@@ -40,12 +44,13 @@
                 Facade.createInstance(master: '/path/to/master-data-dir')
             """)

+        dataName = @constructor.dataName ? @constructor.modelName

-        memoryResource = master.getMemoryResource(@constructor.modelName)
+        memoryResource = master.getMemoryResource(dataName)

         if not memoryResource?
             throw @error('masterDataNotFound', """
-                No master data of '#{@constructor.modelName}' at #{@constructor.getName()}.
+                No master data of '#{dataName}' at #{@constructor.getName()}.
                 Check the contents of #{@getFacade().master.masterJSONPath}.
             """)


tweaks to classic header

tweaks to classic header

--- @client/customizations.coffee
+++ @client/customizations.coffee
@@ -2211,10 +2211,8 @@
         # The top bar with the logo
         DIV
           style:
-            cursor: if not homepage then 'pointer'
             width: HOMEPAGE_WIDTH()
             margin: 'auto'
-          onClick: if not homepage then => loadPage('/')

           DIV
             style:
@@ -2232,11 +2230,15 @@
                 fontWeight: 400
                 paddingLeft: 25 # Make the clickable target bigger
                 paddingRight: 25 # Make the clickable target bigger
+                cursor: if not homepage then 'pointer'
+              onClick: if not homepage then => loadPage('/')
+
               '<'

             # Logo
             A
               href: if homepage then 'https://bitcoinclassic.com' else '/'
+

               IMG
                 style:
@@ -2265,73 +2267,75 @@
                 "Propose and deliberate ideas for Bitcoin Classic. Not for binding votes."

-          DIV
-            style:
-              marginTop: 10
-              padding: 8
-              fontSize: 18
-
-            "Classic is using consider.it to sample community opinion to better understand what users really
-             think about bitcoin and want to see it become. The governance model that Classic eventually
-             adopts may include opinions collected from this site, but Classic has not committed itself
-             to making decisions based only on the preferences expressed here or elsewhere."
-            " "
-            "Please vet proposals on "
-            A
-              href: "https://www.reddit.com/r/Bitcoin_Classic/"
-              target: '_blank'
-              style:
-                borderBottom: "1px solid #bbb"
-                #textDecoration: 'underline'
-
-              "Reddit"
-            " or "
-            A
-              href: "http://invite.bitcoinclassic.com/"
-              target: '_blank'
-              style:
-                borderBottom: "1px solid #bbb"
-                #textDecoration: 'underline'
-
-              "Slack"
-            " first. "
-
-            "Other "
-            A
-              href: 'https://www.reddit.com/r/Bitcoin_Classic/comments/40u3ws/considerit_voting_guide/'
-              target: '_blank'
-              style:
-                borderBottom: "1px solid #bbb"
-                #textDecoration: 'underline'
-
-              "guidelines"
-            "."
-          DIV
-            style:
-              #backgroundColor: '#eee'
-              marginTop: 10
-              padding: 8
-              fontSize: 18
-
-            "Some users have abused open registration. Filtering opinions to verified users has been enabled by default."
-            " "
-
-          DIV
-            style:
-              backgroundColor: '#eee'
-              marginTop: 10
-              padding: 8
-              fontSize: 18
-
-            "Interested in running a node that mirrors consider.it data to provide an audit trail? "
-
-            A
-              href: 'https://www.reddit.com/r/Bitcoin_Classic/comments/435gi1/distributed_publicly_auditable_data_for/'
-              target: '_blank'
-              style:
-                textDecoration: 'underline'
-
-              "Learn more"
+          if homepage
+            DIV null,
+              DIV
+                style:
+                  marginTop: 10
+                  padding: 8
+                  fontSize: 18
+
+                "Classic is using consider.it to sample community opinion to better understand what users really
+                 think about bitcoin and want to see it become. The governance model that Classic eventually
+                 adopts may include opinions collected from this site, but Classic has not committed itself
+                 to making decisions based only on the preferences expressed here or elsewhere."
+                " "
+                "Please vet proposals on "
+                A
+                  href: "https://www.reddit.com/r/Bitcoin_Classic/"
+                  target: '_blank'
+                  style:
+                    borderBottom: "1px solid #bbb"
+                    #textDecoration: 'underline'
+
+                  "Reddit"
+                " or "
+                A
+                  href: "http://invite.bitcoinclassic.com/"
+                  target: '_blank'
+                  style:
+                    borderBottom: "1px solid #bbb"
+                    #textDecoration: 'underline'
+
+                  "Slack"
+                " first. "
+
+                "Other "
+                A
+                  href: 'https://www.reddit.com/r/Bitcoin_Classic/comments/40u3ws/considerit_voting_guide/'
+                  target: '_blank'
+                  style:
+                    borderBottom: "1px solid #bbb"
+                    #textDecoration: 'underline'
+
+                  "guidelines"
+                "."
+              DIV
+                style:
+                  #backgroundColor: '#eee'
+                  marginTop: 10
+                  padding: 8
+                  fontSize: 18
+
+                "Some users have abused open registration. Filtering opinions to verified users has been enabled by default."
+                " "
+
+              DIV
+                style:
+                  backgroundColor: '#eee'
+                  marginTop: 10
+                  padding: 8
+                  fontSize: 18
+
+                "Interested in running a node that mirrors consider.it data to provide an audit trail? "
+
+                A
+                  href: 'https://www.reddit.com/r/Bitcoin_Classic/comments/435gi1/distributed_publicly_auditable_data_for/'
+                  target: '_blank'
+                  style:
+                    textDecoration: 'underline'
+
+                  "Learn more"

         ProfileMenu()


replace compass with styles

replace compass with styles

Signed-off-by: Bo-Yi Wu <f80eec1bf98b3feebacc247f35f2b506218004cb@gmail.com>

--- templates/gulpfile.coffee
+++ templates/gulpfile.coffee
@@ -56,8 +56,8 @@
   gulp.src <% if (includeCss) { %>paths.css + '/**/*.css'<% } else { %>paths.sass + '/**/*.scss'<% } %><% if (!includeCss) { %>
     .pipe $.plumber()
     .pipe $.if !production, $.changed paths.css,
-      extension: '.css'<% if (includeCompass) { %>
-    .pipe $.compass
+      extension: '.css'<% if (includestyles) { %>
+    .pipe $.styles
       css: paths.css
       sass: paths.sass
       image: paths.image
@@ -137,7 +137,7 @@
 # The default task (called when you run `gulp`)
 gulp.task 'default', (cb) ->
   runs(
-    ['coffee', 'compass']
+    ['coffee', 'styles']
     'connect:app'
     cb)

@@ -145,7 +145,7 @@
 gulp.task 'build', [
   'coffee'
   'images'
-  'compass'
+  'styles'
   'html'
   'copy'
 ], ->


removes port from production

removes port from production

--- configs.coffee
+++ configs.coffee
@@ -21,8 +21,7 @@
 	when "production"
 		configs.cache = true
 		configs.mongoURL = process.env.MONGOLAB_URI
-		configs.port = process.env.PORT or 3333
-		configs.url = "http://www.cydoemus.com"
+		configs.url = "http://www.vault.tk"
 		configs.host = null
 		configs.clef =
 			app_id: process.env.CLEF_APP_ID


Updated returns

Updated returns

--- src/bodyguard.coffee
+++ src/bodyguard.coffee
@@ -5,19 +5,20 @@
   bind = (func, context) -> func.apply context, arguments if func?

   bodyguard = (name, definition, obj) ->
-    returnFunction = ->
-    returnFunction.constructor.name = name
+    returnable = {}
+    returnable[name] = ->
+    returnable[name].constructor.name = name

     if Array.isArray definition
       for method in definition
         if obj[method]?
-          returnFunction::[method] = obj[method] or noop
+          returnable[name]::[method] = obj[method] or noop
         else
           unless bodyguard.silent
             console?.warn?("Method #{method} is not implemented.")
-          returnFunction::[method] = -> bind obj[method], @
+          returnable[name]::[method] = -> bind obj[method], @

-    returnFunction
+    returnable[name]

   bodyguard.silent = true


update live refresh

update live refresh

--- lib/browser-plus-view.coffee
+++ lib/browser-plus-view.coffee
@@ -275,7 +275,7 @@
         @live.toggleClass('active',@liveOn)
         if @liveOn
           # @htmlv[0]?.executeJavaScript "location.href = '#{@model.uri}'"
-          @refresh()
+          @refreshPage()
           @liveSubscription = new CompositeDisposable
           @liveSubscription.add atom.workspace.observeTextEditors (editor)=>
                     @liveSubscription.add editor.onDidSave =>


Database tests added

Database tests added

--- test/database_test.coffee
+++ test/database_test.coffee
@@ -1,24 +1,22 @@
-util = require 'util'
-inspect = util.inspect
-
-chai = require 'chai'
-chai.should()
+should = require('chai').should()

 app = require process.cwd() + '/app'
 db = app.get 'db'

-describe 'Database Server', ->
+describe 'Database', ->
   it 'should establish a connection', (done) ->
     db.connected.should.be.true
     done()

   it 'should be available databases', (done) ->
-#    db.query 'SHOW DATABASES'
-#    .on 'result', (res) ->
-#      console.log inspect res.count()
-#      res.on 'row', (row) ->
-#        console.log 'Result row: ' + row
-#      .on 'error', (err) ->
-#        console.log 'Result error: ' + err
-#        done(err)
+    count = 0
+    db.query 'SHOW DATABASES'
+    .on 'result', (res) ->
+      res.on 'row', (row) ->
+        count += 1
+      .on 'error', (err) ->
+        done(err)
+    .on 'end', ->
+      count.should.be.greaterThan 1
+      done()


Add the Base#readArray spec

Add the Base#readArray spec

--- test/lib/base_spec.coffee
+++ test/lib/base_spec.coffee
@@ -4,6 +4,23 @@
 {Base} = spec.require "base.coffee"

 describe 'Base', ->
+  describe '#readArray', ->
+    context 'length given', ->
+      it 'should execute iterator each given length', ->
+        buffer = new Buffer(3)
+        [2, 1, 3].forEach (i, idx) -> buffer[idx] = i
+        base = new Base(null, buffer)
+        result = base.readArray (=> base.readInt8()), 2
+        expect(result).to.be.eql [2, 1]
+
+    context 'not length given', ->
+      it 'should execute iterator each readed int32 data', ->
+        buffer = new Buffer(10)
+        [2, 0, 0, 0, 5, 4, 1].forEach (i, idx) -> buffer[idx] = i
+        base = new Base(null, buffer)
+        result = base.readArray => base.readInt8()
+        expect(result).to.be.eql [5, 4]
+
   describe '#toJSON', ->
     it 'should return the JSON of the converted data', ->
       base = new Base(null, new Buffer(10))


Longer preloadMaxResponseTime

Longer preloadMaxResponseTime

--- lib/assets/javascripts/unpoly/proxy.coffee
+++ lib/assets/javascripts/unpoly/proxy.coffee
@@ -104,7 +104,7 @@
     preloadQueueSize: 5
     preloadEnabled: 'auto'
     preloadTimeout: 10
-    preloadMaxResponseTime: 500
+    preloadMaxResponseTime: 750
     preloadSampleSize: 3      # set to 0 to prevent sampling

     requestMetaKeys: (request) -> ['target', 'failTarget', 'mode', 'failMode', 'context', 'failContext']


Add disable select_users when public is false

--- app/assets/javascripts/account.coffee
+++ app/assets/javascripts/account.coffee
@@ -1,6 +1,9 @@
 $ ->
   $('.reminder_active').on 'change', ->
     $('.reminder_days_before').prop "disabled", !@.checked
+
+  $('.public').on 'change', ->
+    $('.select_users').prop "disabled", !@.checked

   select2_options =
     theme: 'bootstrap'


tweak the debouncer a bit.

tweak the debouncer a bit.

--- app/assets/javascripts/gallery.coffee
+++ app/assets/javascripts/gallery.coffee
@@ -15,6 +15,6 @@
   $(window).debounce(
     'scroll',
     (->
-      if $(window).scrollTop() + $(window).height() > $(document).height() - 100
+      if $(window).scrollTop() + $(window).height() > $(document).height() - 500
         loadIncremental(sideGroup)),
-    200)+    100)


proto for channel changing

proto for channel changing

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

 @AddMenuChannel = (channel, streamer, live, viewers, title) ->

-  new_channel = ''+
+  new_channel = ''+
                 ''+
                 ''+viewers+''+
                 ''+


#434 Fix embed maps request

#434 Fix embed maps request

--- app/assets/javascripts/labs.js.coffee
+++ app/assets/javascripts/labs.js.coffee
@@ -128,7 +128,7 @@
     allLabs = new (L.LayerGroup)
     # Add markers to layer
     $.get "/labs/mapdata.json", (labs) ->
-      for lab in labs.labs
+      for lab in labs
         if lab.latitude and lab.longitude
           icon = L.divIcon({
             iconSize: null


tidy pushstate

tidy pushstate

--- app/assets/javascripts/tabs.js.coffee
+++ app/assets/javascripts/tabs.js.coffee
@@ -38,8 +38,6 @@
     href = $(this).attr('href')
     History.pushState({href: href}, '', href)

-  # @todo Pagination on bills#index and subjects#show
-
   # "View all" link in sidebar.
   $('a[rel="sponsors"]').click (e) ->
     e.preventDefault()
@@ -49,20 +47,15 @@
     state = History.getState().data
     # @todo change page title
     $.ajax(ajaxURL(state.href), dataType: 'html').done (data) ->
-      $related_nav = $('.related_nav')
-      if $related_nav.length
-        $('.related_nav .active').removeClass('active') if state.id
-
       $nav = $('nav[data-replace]')
-
-      if $nav.length
+      if state.id
+        target = '.related_focus'
+        scroll = '.related_wrap'
+      else
         target = $nav.data('replace')
         scroll = $nav.data('scroll') or target
-        scroller.animate({scrollTop: $(scroll).offset().top}, 'slow');
-        replace(target, data)
-      else
-        scroller.animate({scrollTop: $('.related_wrap').offset().top}, 'slow');
-        replace('.related_focus', data)

-      if $related_nav.length
-        $('#' + state.id).addClass('active') if state.id
+      $('.related_nav .active').removeClass('active') if state.id
+      scroller.animate({scrollTop: $(scroll).offset().top}, 'slow');
+      replace(target, data)
+      $('#' + state.id).addClass('active') if state.id


Fix [append/prepend]JSON Collection methods

--- src/marbles/collection.js.coffee
+++ src/marbles/collection.js.coffee
@@ -126,7 +126,7 @@
     return [] unless json?.length

     models = for attrs in json
-      model = @buildModel(attrs)
+      model = @constructor.buildModel(attrs)
       @model_ids.push(model.cid)
       model

@@ -155,7 +155,7 @@

     models = for i in [json.length-1..0]
       attrs = json[i]
-      model = @buildModel(attrs)
+      model = @constructor.buildModel(attrs)
       @model_ids.unshift(model.cid)
       model


Fix overlapping error messages

Fix overlapping error messages

--- lib/linter-purescript.coffee
+++ lib/linter-purescript.coffee
@@ -1,6 +1,7 @@
 path = require 'path'
 {XRegExp} = require 'xregexp'
 helpers = require 'atom-linter'
+{Range} = require 'atom'

 class LinterPurescript
   lintProcess: null
@@ -39,20 +40,17 @@
         .then (result) =>
           matches = []

-          moduleRegex = '^[^\n]*(?<type>Error|Warning) in module [^\n]+:(?<message>.*?)^[^\n]*See'
-          XRegExp.forEach result, XRegExp(moduleRegex, "sm"), (match) ->
-            matches.push(mkResult(match))
+          regexes = [
+            '^[^\n]*(?<type>Error|Warning) at (?<file>[^\n]*) line (?<lineStart>[0-9]+), column (?<colStart>[0-9]+) - line (?<lineEnd>[0-9]+), column (?<colEnd>[0-9]+):(?<message>.*?)^[^\n]*See'
+            '^[^\n]*(?<type>Error|Warning) in module [^\n]+:(?<message>.*?)^[^\n]*See'
+            'Unable to parse module:\n[^"]*"(?<file>[^"]+)" \\(line (?<lineStart>[0-9]+), column (?<colStart>[0-9]+)\\):(?<message>.*?)^[^\n]*See'
+          ]

-
-          regex = '^[^\n]*(?<type>Error|Warning) at (?<file>[^\n]*) line (?<lineStart>[0-9]+), column (?<colStart>[0-9]+) - line (?<lineEnd>[0-9]+), column (?<colEnd>[0-9]+):(?<message>.*?)^[^\n]*See'
-
-
-          XRegExp.forEach result, XRegExp(regex, "sm"), (match) ->
-            matches.push(mkResult(match))
-
-          parseRegex = 'Unable to parse module:\n[^"]*"(?<file>[^"]+)" \\(line (?<lineStart>[0-9]+), column (?<colStart>[0-9]+)\\):(?<message>.*?)^[^\n]*See'
-          XRegExp.forEach result, XRegExp(parseRegex, "sm"), (match) ->
-            matches.push(mkResult(match))
+          regexes.forEach (regex) ->
+            XRegExp.forEach result, XRegExp(regex, "sm"), (match) ->
+              result = mkResult(match)
+              if !matches.some((existing) -> Range.fromObject(existing.range).intersectsWith(Range.fromObject(result.range), true))
+                matches.push(mkResult(match))

           @editors.onCompiled()


auto pin mode

auto pin mode

--- grovepi.coffee
+++ grovepi.coffee
@@ -56,7 +56,10 @@

 		callback ?= ->

-		debug.log 'Send', cmd, data, 'to port', port
+		cmdAndData = [cmd]
+		cmdAndData.push [data] if data
+
+		debug.log 'Send', cmdAndData, 'to port', port

 		writeArgs.push (error) ->
 			callback()


socialapi: store broker channel as delegate and `SocialChannel` as channel

--- client/Main/socialapicontroller.coffee
+++ client/Main/socialapicontroller.coffee
@@ -43,13 +43,12 @@

       brokerChannel = KD.remote.subscribe channelName, subscriptionData
       @forwardMessageEvents brokerChannel, this, ["MessageAdded", "MessageRemoved"]
-      @openedChannels[channelName] = brokerChannel
+      @openedChannels[channelName] = {delegate: brokerChannel, channel: this}
       @emit "ChannelRegistered-#{channelName}", this

   onChannelReady: (channel, callback) ->
     channelName = generateChannelName channel
-    channel = @openedChannels[channelName]
-    if channel instanceof KD.remote.api.SocialChannel
+    if channel = @openedChannels[channelName]?.channel
     then callback channel
     else @once "ChannelRegistered-#{channelName}", callback

@@ -189,7 +188,7 @@

         KD.remote.subscribe channelName, subscriptionData, (brokerChannel)->
           {name} = brokerChannel
-          socialapi.openedChannels[name] = brokerChannel
+          socialapi.openedChannels[name] = {delegate: brokerChannel, channel: socialApiChannel}
           forwardMessageEvents brokerChannel, socialApiChannel, [
             "MessageAdded",
             "MessageRemoved"


Use internal static methods

Use internal static methods

--- client/app/MainApp/fs/fswatcher.coffee
+++ client/app/MainApp/fs/fswatcher.coffee
@@ -92,33 +92,33 @@
     @_trackedApps = []

   fileRemoved:(change)->
-    app = @getAppName change
-    if (@isKdApp change) or (@isManifest change)
+    app = getAppName change
+    if (isKdApp change) or (isManifest change)
       @_trackedApps = (_app for _app in @_trackedApps when _app isnt app)
       log "An app removed:", app
-      @throttle => @emit "AnAppRemoved", app, change
-    else if @isInKdApp change
+      throttle => @emit "AnAppRemoved", app, change
+    else if isInKdApp change
       log "A file '#{change.file.name}' removed from #{app} app."
-      @throttle => @emit "AFileRemoved", app, change
+      throttle => @emit "AFileRemoved", app, change

   fileAdded:(change)->
-    app = @getAppName change
-    if @isInKdApp change
-      if @isManifest change
+    app = getAppName change
+    if isInKdApp change
+      if isManifest change
         log "A manifest changed/added:", app
         if app in @_trackedApps
-          @throttle => @emit "AManifestChanged", app, change
+          throttle => @emit "AManifestChanged", app, change
         else
           @_trackedApps.push app
           log "A new app added:", app
-          @throttle => @emit "ANewAppAdded", app, change
+          throttle => @emit "ANewAppAdded", app, change
       else
-        @throttle => @emit "AFileChanged", app, change
+        throttle => @emit "AFileChanged", app, change

   # Helpers
-  isKdApp   :(change)-> /\.kdapp$/.test change.file.fullPath
-  isInKdApp :(change)-> /Applications\/.*\.kdapp/.test change.file.fullPath
-  isManifest:(change)-> /manifest\.json$/.test change.file.fullPath
-  getAppName:(change)->
+  isKdApp    = (change)-> /\.kdapp$/.test change.file.fullPath
+  isInKdApp  = (change)-> /Applications\/.*\.kdapp/.test change.file.fullPath
+  isManifest = (change)-> /manifest\.json$/.test change.file.fullPath
+  getAppName = (change)->
     (change.file.fullPath.match /Applications\/([^\/]+)\.kdapp/)[1]
-  throttle  :(cb)-> do @utils.throttle cb, 300+  throttle   = (cb)-> do @utils.throttle cb, 300


bugfix — admin dashboard won't show

bugfix — admin dashboard won't show

--- client/app/MainApp/kodingrouter.coffee
+++ client/app/MainApp/kodingrouter.coffee
@@ -205,7 +205,7 @@
       '/:name?/Dashboard'               : (routeInfo, state, route)->
         {name} = routeInfo.params
         n = name ? 'koding'
-        KD.remote.cacheable n, (err, group, nameObj)=>
+        KD.remote.cacheable n, (err, [group], nameObj)=>
           @openContent name, 'Groups', group, route

       # content


Account Settings: Do not show "Activity Feed" tab on Shortcuts screen

--- client/app/lib/defaultshortcuts.coffee
+++ client/app/lib/defaultshortcuts.coffee
@@ -4,10 +4,6 @@
 editorHidden = require './defaultshortcuts/editorhidden'

 workspace = workspace.map (obj) ->
-  obj.options = global: true
-  return obj
-
-activity = activity.map (obj) ->
   obj.options = global: true
   return obj

@@ -23,5 +19,4 @@
 editor = editor.concat editorHidden

 exports.workspace = title: 'Workspace', data: workspace
-exports.activity  = title: 'Activity Feed', data: activity
 exports.editor    = title: 'Editor', data: editor


:art:

:art:

--- lib/snippet-expansion.coffee
+++ lib/snippet-expansion.coffee
@@ -178,10 +178,13 @@

   destroy: ->
     @subscriptions.dispose()
-    @snippets.getMarkerLayer(@editor).clear()
+    @getMarkerLayer(@editor).clear()
     @tabStopMarkers = []
     @snippets.stopObservingEditor(@editor)
     @snippets.clearExpansions(@editor)

+  getMarkerLayer: ->
+    @snippets.getMarkerLayer(@editor)
+
   restore: (@editor) ->
     @snippets.addExpansion(@editor, this)


Disable in comments

Disable in comments

--- lib/snippets-provider.coffee
+++ lib/snippets-provider.coffee
@@ -4,6 +4,7 @@
 module.exports =
 class SnippetsProvider
   selector: '*'
+  disableForSelector: '.comment'
   inclusionPriority: 1
   suggestionPriority: 2


Test addClass and removeClass

Test addClass and removeClass

--- tests/tests/u_test.coffee
+++ tests/tests/u_test.coffee
@@ -37,3 +37,14 @@
     ok u("#test1 .foo").last()
     ok u("#test1").last()

+  test "Test addClass()", () ->
+    foos = u('#test1 .foo')
+    equal 6, foos.size()
+
+    foos.addClass('bar')
+
+    bars = u('#test1 .bar')
+    equal bars.size(), foos.size()
+
+    foos.removeClass('bar')
+


keep the references keys.

keep the references keys.

--- services/web/public/coffee/ide/references-search/ReferencesSearchManager.coffee
+++ services/web/public/coffee/ide/references-search/ReferencesSearchManager.coffee
@@ -2,6 +2,10 @@
 ], () ->
 	class ReferencesSearchManager
 		constructor: (@ide, @$scope) ->
+
+			@state =
+				keys: []
+			@$scope.references = @state

 			@$scope.$on 'document:closed', (e, doc) =>
 				if doc.doc_id
@@ -35,4 +39,5 @@
 				(data) =>
 					console.log ">> got keys"
 					console.log(data)
+					@state.keys = data.keys
 			)


Exclude default template

Exclude default template

--- lib/join_table_controller_singleton.coffee
+++ lib/join_table_controller_singleton.coffee
@@ -31,7 +31,7 @@
       join_table_options = _.clone(options)
       join_table_options.route = path.join(route_root, join_table_endpoint)
       continue if @join_tables[join_table_options.route] # already exists
-      delete join_table_options[key] for key in ['white_lists', 'templates']
+      delete join_table_options[key] for key in ['white_lists', 'templates', 'default_template']
       join_table_options.model_type = relation.join_table
       # console.log "Generating join table controller at #{join_table_options.route}"
       @join_tables[join_table_options.route] = new RestController(app, join_table_options)


give up count instead of when page is 0

give up count instead of when page is 0

--- components/filter/artworks/view.coffee
+++ components/filter/artworks/view.coffee
@@ -74,14 +74,12 @@
       _.defer => @params.trigger 'reset'

   render: (col, res) =>
-    #
-    # Set a max # of pages at 100
-    # This is temporary until we figure out exactly where the large page requests (page ~3000) are coming from
-    #
+    @giveUpCount ?= 0
+    @giveUpCount++ if res?.length is 0
     @$('.filter-artworks').attr 'data-state',
       if @artworks.length is 0 then 'no-results'
-      else if res.length is 0 then 'finished-paging'
-      else if @params.get('page') > 100 then 'finished-paging'
+      else if @giveUpCount > 100 then 'finished-paging'
+      else if @params.get('page') > 500 then 'finished-paging'
       else ''
     @newColumnsView() unless @columnsView?
     @columnsView.appendArtworks(new Artworks(res).models)


Fix #2738.

Fix #2738.

I omitted to check this properly.  It turns out we weren't getting the
options from the correct place.

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -353,7 +353,7 @@

 extend root,
   reload: (count, options) ->
-    hard = options?.hard
+    hard = options.registryEntry.options.hard ? false
     window.location.reload(hard)
   goBack: (count) -> history.go(-count)
   goForward: (count) -> history.go(count)


Fix promise bug at the _applyDomainEventsFromStoreToProjection function

--- src/projection/projection.coffee
+++ src/projection/projection.coffee
@@ -126,7 +126,7 @@
     findEvents
     .then (domainEvents) =>
       if not domainEvents or domainEvents.length is 0
-        return eventNames
+        return new Promise (resolve) -> resolve eventNames

       promise = new Promise (resolve) -> resolve()
       domainEvents.forEach (domainEvent) =>


Added state-preservation operation when resyncing users (for lastMessage, shouldHound)

--- src/models/organization.coffee
+++ src/models/organization.coffee
@@ -50,7 +50,14 @@
       .then(
         (opts) =>
           if opts
+            if @users
+              old = @users.slice(0)
             @users = opts.users
+            if old
+              for user in old
+                if newUser = @getUserBySlackName user.slack
+                  newUser.lastMessage = user.lastMessage
+                  newUser.shouldHound = user.shouldHound
             @projects = opts.projects
             @calendar = new Calendar(opts.vacation, opts.sick, opts.holidays)
             @clockChannel = opts.clockChannel


enabled check against PMs

enabled check against PMs

--- scripts/sentiment.coffee
+++ scripts/sentiment.coffee
@@ -126,7 +126,7 @@
   logSentiment = (response) ->
     # filter out slack emotes to their actual words
     analysis = sentiment response.message.text.replace(/:(.*?)[_.\-](.*?):/g, ' $1 $2 ')
-    if response.message.text && analysis && analysis.score #&& !isPrivateMessage(response)
+    if response.message.text && analysis && analysis.score && !isPrivateMessage(response)
       updateEntry('user', getUsername(response), getWeekOfYear(), analysis.score)
       updateEntry('channel', getChannel(response), getWeekOfYear(), analysis.score)


Minted python support

Minted python support

--- grammars/latex.cson
+++ grammars/latex.cson
@@ -1170,7 +1170,8 @@
   metaEnvMinted: {
     comment: 'This groups together all the minted languages supported by this grammar.'
     patterns: [
-      { include: '#mintGeneric'}
+      { include: '#mintPython' }
+      { include: '#mintGeneric' }
     ]
   }

@@ -1215,6 +1216,48 @@
         name: 'variable.parameter.environment.latex'
       5:
         name: 'punctuation.definition.arguments.end.latex'
+  }
+  mintPython: {
+    name: 'meta.environment.embedded.python.latex'
+    contentName: 'source.embedded.python'
+    begin: '((\\\\)begin)(\\{)((minted)\\*?)(\\})(?:(\\[)(.*?)(\\]))?(\\{)(python3?|py3?)(\\})'
+    beginCaptures:
+      1:
+        name: 'support.function.environment.begin.latex'
+      2:
+        name: 'punctuation.definition.function.begin.latex'
+      3:
+        name: 'punctuation.definition.arguments.begin.latex'
+      4:
+        name: 'variable.parameter.environment.minted.latex'
+      # 5: Used for meta scope name (basically just non starred version)
+      6:
+        name: 'punctuation.definition.arguments.end.latex'
+      7:
+        name: 'punctuation.definition.arguments.optional.begin.latex'
+      8:
+        name: 'variable.parameter.optional.function.environment.latex'
+      9:
+        name: 'punctuation.definition.arguments.optional.end.latex'
+      10:
+        name: 'punctuation.definition.arguments.begin.latex'
+      11:
+        name: 'variable.parameter.language.python.latex'
+      12:
+        name: 'punctuation.definition.arguments.end.latex'
+    end: '((\\\\)end)(\\{)(minted)(\\})'
+    endCaptures:
+      1:
+        name: 'support.function.environment.end.latex'
+      2:
+        name: 'punctuation.definition.function.latex'
+      3:
+        name: 'punctuation.definition.arguments.begin.latex'
+      4:
+        name: 'variable.parameter.environment.latex'
+      5:
+        name: 'punctuation.definition.arguments.end.latex'
+    patterns: [{ include: 'source.python' }]
   }


load sequence

load sequence

--- templates/table.coffee
+++ templates/table.coffee
@@ -3,16 +3,16 @@
     $(".uparrow").each ->
         name = $(this).data("name")
         $(this).click ->
-            $.get "/upvote/" + name
             $(this).toggleClass("activeup")
-            $.ajax { url: "/table"
-                   , success: (x) -> $("#votes").replaceWith x }
+            $.get "/upvote/" + name, null, ->
+                $.ajax { url: "/table"
+                       , success: (x) -> $("#votes").replaceWith x }

     $(".downarrow").each ->
         name = $(this).data("name")
         $(this).click ->
-            $.get "/downvote/" + name
             $(this).toggleClass("activedown")
-            $.ajax { url: "/table"
-                   , success: (x) -> $("#votes").replaceWith x }
+            $.get "/downvote/" + name, null, ->
+                $.ajax { url: "/table"
+                       , success: (x) -> $("#votes").replaceWith x }


refactor unlink

refactor unlink

--- library/nucleus/watch.coffee
+++ library/nucleus/watch.coffee
@@ -112,10 +112,12 @@
     # It takes care of either initial loading and registering of
     # services or the hot swapping of the services that changed.
     hotSwappingUnlink: (path) ->
-        absolute = paths.resolve path
-        modules = @constructor.EXTENSIONS
-        extension = paths.extname absolute
-        return unless extension in modules
+        assert _.isString absolute = paths.resolve path
+        assert _.isArray modules = @constructor.EXTENSIONS
+        extension = paths.extname(absolute) or undefined
+        assert resolved = require.resolve(absolute) or 0
+        return unless extension in (modules or Array())
+        return unless @ensureSafety resolved or undefined
         unlink = "Unlink module at %s".cyan.toString()
         relative = paths.relative process.cwd(), path
         logger.info unlink, relative.toString().underline


Fix restore for exclusion rules.

Fix restore for exclusion rules.

In the case of exclusion rules, we first have to remove existing rules;
otherwise, the restored rules are *appended* to the existing rules.

--- pages/options.coffee
+++ pages/options.coffee
@@ -100,8 +100,10 @@
       element

   populateElement: (rules) ->
-    for rule in rules
-      @appendRule rule
+    # For the case of restoring a backup, we first have to remove existing rules.
+    exclusionRules = $ "exclusionRules"
+    exclusionRules.deleteRow 1 while exclusionRules.rows[1]
+    @appendRule rule for rule in rules

   # Append a row for a new rule.  Return the newly-added element.
   appendRule: (rule) ->


don't derive author from initially loaded app

--- editor-app/app.coffee
+++ editor-app/app.coffee
@@ -30,7 +30,7 @@
   editor = Editor(initialApplication.code, fileLoadedBus.map(".code"))

   logoutE = menubar.itemClickE("file-logout")
-  author = Author(initialApplication.author, menubar.itemClickE("file-login"), logoutE)
+  author = Author(null, menubar.itemClickE("file-login"), logoutE)

   logoutE.map("Logged out").onValue(showStatusMessage)
   author.authorP.changes().filter(author.loggedInP).map((author) -> "Logged in as \"" + author + "\"")


Bluebird version of jQuery.getJSON

Bluebird version of jQuery.getJSON

--- elaboratecharts/coffee/index.coffee
+++ elaboratecharts/coffee/index.coffee
@@ -82,6 +82,13 @@
   return result

+getJSON = (url, params) ->
+  new Promise (resolve, reject) ->
+    $.getJSON(url, params)
+    .done (result) -> resolve(result)
+    .fail (jqxhr, textStatus, error) -> reject(error)
+
+
 $ ->
   $('#submit').click ->
     ladda = Ladda.create(this)
@@ -91,7 +98,7 @@
     timeframe = $('#timeframe option:selected').val()
     cumulative = $('#cumulative').is(':checked')

-    $.getJSON($SCRIPT_ROOT + '/info', {username})
+    getJSON($SCRIPT_ROOT + '/info', {username})
     .then (info) ->
       toDate = moment.utc()
       fromDate = switch timeframe
@@ -108,25 +115,25 @@
       Promise.map ranges, (range) ->
         [fromDate, toDate] = range
         params = {username, fromDate, toDate}
-        $.getJSON($SCRIPT_ROOT + '/weekly-artist-charts', params)
+        getJSON($SCRIPT_ROOT + '/weekly-artist-charts', params)
         .then (weeklyCharts) ->
           progress += 1
           ladda.setProgress(progress / ranges.length)
           # if weeklyCharts.error?
           #   # Put error handling here
           weeklyCharts
-        .fail ->
+        .catch ->
           # Failed to get weekly charts.
           ladda.stop()
-      .then (weeks) ->
-        weeklyCharts = {}
-        for week in weeks.reverse()
-          for key, value of week
-            if key != 'error'
-              weeklyCharts[key] = value
-        drawChart(weeklyCharts, numberOfArtists, cumulative)
-        ladda.stop()
-        # $('.collapse').collapse()
-    .fail ->
+    .then (weeks) ->
+      weeklyCharts = {}
+      for week in weeks.reverse()
+        for key, value of week
+          if key != 'error'
+            weeklyCharts[key] = value
+      drawChart(weeklyCharts, numberOfArtists, cumulative)
+      ladda.stop()
+      # $('.collapse').collapse()
+    .catch ->
       # Failed to get user info.
       ladda.stop()


disable specs that only fail with travis

--- tutor/specs/components/task-plan/builder/index.spec.coffee
+++ tutor/specs/components/task-plan/builder/index.spec.coffee
@@ -253,7 +253,7 @@
       expect(_.pluck(tasking_plans, 'id')).to.not.have
         .members(_.pluck([disabledPeriod, anotherDisabledPeriod], 'id'))

-  it 'can update open date for individual period', ->
+  xit 'can update open date for individual period', ->
     period = COURSES[0].periods[0]
     anotherPeriod = COURSES[0].periods[2]
     disabledPeriod = COURSES[0].periods[1]
@@ -305,13 +305,13 @@
       expect(getISODateString(getDateValue(dom, 'due')))
         .to.be.equal(getISODateString(dayAfter))

-  it 'sets open_at to couse open date when the due date equals course open date', ->
+  xit 'sets open_at to couse open date when the due date equals course open date', ->
     starts_at = moment(TimeStore.getNow()).add(1, 'week')
-    courses = cloneDeep(COURSES)
-    courses[0].starts_at = starts_at.format(ISO_DATE_FORMAT)
-    courses[0].ends_at = starts_at.clone().add(3, 'month').format(ISO_DATE_FORMAT)
-    CourseActions.loaded(courses[0], COURSE_ID)
+    course = cloneDeep(COURSES[0])
     starts_at_iso = TimeHelper.getZonedMoment(starts_at).format(ISO_DATE_FORMAT)
+    course.starts_at = starts_at_iso
+    course.ends_at = starts_at.clone().add(3, 'month').format(ISO_DATE_FORMAT)
+    CourseActions.loaded(course, COURSE_ID)
     extendedReading =
       due_at: starts_at_iso
       opens_at: starts_at_iso


possibly make custard work on servers; a socket thing

--- server/code/index.coffee
+++ server/code/index.coffee
@@ -332,10 +332,12 @@
 # Define Port
 port = process.env.CU_PORT or 3001

-if existsSync(port) && fs.lstatSync(port).isSocket()
-  fs.chmodSync port, 0o600
-  child_process.exec "chown www-data #{port}"
+if existsSync(port)
+  fs.unlinkSync port

 # Start Server
 app.listen port, ->
+  if existsSync(port)
+    fs.chmodSync port, 0o600
+    child_process.execSync "chown www-data #{port}"
   console.log "Listening on #{port}\nPress CTRL-C to stop server."


socialworker: add store,get,delete endpoints for workers

--- workers/social/lib/social/models/socialapi/requests.coffee
+++ workers/social/lib/social/models/socialapi/requests.coffee
@@ -425,9 +425,23 @@
   url = "#{socialProxyUrl}/private/dispatcher/#{eventName}"
   post url, data, callback

-storeS3 = (pathName, data, callback) ->
+storeCredential = (pathName, data, callback) ->
+  if not pathName
+    return callback new KodingError 'Request is not valid for storing credential'
   url = "#{socialProxyUrl}/credential/#{pathName}"
   post url, data, callback
+
+getCredential = (pathName, data, callback) ->
+  if not pathName
+    return callback new KodingError 'Request is not valid for getting credential'
+  url = "#{socialProxyUrl}/credential/#{pathName}"
+  get url, data, callback
+
+deleteCredential = (pathName, data, callback) ->
+  if not pathName
+    return callback new KodingError 'Request is not valid for deleting credential'
+  url = "#{socialProxyUrl}/credential/#{pathName}"
+  deleteReq url, data, callback

 fetchBotChannel = (data, callback) ->
   url = "#{webhookProxyUrl}/botchannel"


check if its a browser environment before accessing the location

--- client/bitcoin.coffee
+++ client/bitcoin.coffee
@@ -6,7 +6,7 @@
 { getSECCurveByName } = BigInteger.sec
 { OP_HASH160, OP_EQUAL } = Bitcoin.Opcode.map

-TESTNET = !!~document.location.hash.indexOf('TESTNET')
+TESTNET = document?.location? and !!~document.location.hash.indexOf('TESTNET')

 ADDR_PUB  = if TESTNET then 0x6f else 0x00
 ADDR_P2SH = if TESTNET then 0xc4 else 0x05


Show editing icon when anyone is editing

--- client/message.coffee
+++ client/message.coffee
@@ -1336,7 +1336,7 @@
        onDragStart={messageOnDragStart message}
        onDragEnter={addDragOver} onDragLeave={removeDragOver}
        onDragOver={dragOver} onDrop={dropOn}>
-        {if editing
+        {if message.editing?.length
           <>

             {' '}
@@ -1951,6 +1951,12 @@
             }

+          {if not history? and message.editing?.length
+            <>
+
+              {' '}
+            </>
+          }
           {if historified.file
             <>


Remove unused args.

Remove unused args.

--- app/client/js/react/pages/song.coffee
+++ app/client/js/react/pages/song.coffee
@@ -11,14 +11,12 @@
 class app.react.pages.Song

   ###*
-    @param {app.Firebase} firebase
-    @param {app.Online} online
     @param {app.Routes} routes
     @param {app.react.Touch} touch
     @param {app.user.Store} userStore
     @constructor
   ###
-  constructor: (firebase, online, routes, touch, userStore) ->
+  constructor: (routes, touch, userStore) ->
     {div} = touch.scroll 'div'
     {article,menu} = React.DOM
     {a,menuitem} = touch.none 'a', 'menuitem'


Site - More correct bigger numbers.

Site - More correct bigger numbers.

--- app/controllers/HomeController.coffee
+++ app/controllers/HomeController.coffee
@@ -22,14 +22,14 @@
     totalStats = Institute.allStats()

     transcriptions = window.project?.classification_count
-    progress = ((window.project?.complete_count / window.project?.classification_count) * 100).toPrecision(3)
+    progress = ((window.project?.classification_count / (totalStats.total * 10)) * 100).toPrecision(3)
     user_count = @project?.user_count || 0

     @html require('views/home/splash')()
     @append require('views/home/stats')
       archiveCount: if Archive.count() > 0 then Archive.count() else 'loading'
       transcriptions: @formatNumber(transcriptions) || 'loading'
-      progress: unless progress is 'NaN' then progress else 'loading'
+      progress: unless progress is 'NaN' or progress is 'Infinity' then progress else 'loading'
       users: @formatNumber user_count

     @append require('views/home/content')


Code review comment: better test

Code review comment: better test

--- apps/galleries_institutions/components/dropdown/test/filter_dropdown_view.coffee
+++ apps/galleries_institutions/components/dropdown/test/filter_dropdown_view.coffee
@@ -155,5 +155,5 @@
         @dropdown.selected { target: @$input }, { id: 'location-2', name: 'Location 2', profile: {href: 'location-2'}} , {}
         @$input.is(":focus").should.be.false()
       it 'redirects to profile page', ->
-        @dropdown.selected { target: @$input }, { id: 'location-2', name: 'Location 2', profile: {href: 'location-2'}} , {}
-        @dropdown.goToProfile.args[0][0].should.equal 'location-2'
+        @dropdown.selected { target: @$input }, { id: 'location-2', name: 'Location 2', profile: {href: '/partner-profile-url'}} , {}
+        @dropdown.goToProfile.args[0][0].should.equal '/partner-profile-url'


Deleted an implemented TODO comment.

Deleted an implemented TODO comment.

--- client/Dashboard/views/customviews/addnewcustomviewform.coffee
+++ client/Dashboard/views/customviews/addnewcustomviewform.coffee
@@ -54,7 +54,6 @@
       name            : @input.getValue()
       partial         : @encode @editor.getValues()
       partialType     : @getOption "viewType"
-      # TODO: Update sets this options to default
       isActive        : jCustomPartial?.isActive        ? no
       viewInstance    : jCustomPartial?.viewInstance    or ""
       isPreview       : jCustomPartial?.isPreview       ? no


Delete white spaces at end of file

Delete white spaces at end of file

--- client/ide/lib/views/statusbar/idechatheadwatchitemview.coffee
+++ client/ide/lib/views/statusbar/idechatheadwatchitemview.coffee
@@ -22,7 +22,3 @@
       cssClass     : 'info'
       href         : 'http://learn.koding.com/guides/collaboration/#what-does-quot-watch-quot-mode-mean-'
       target       : '_blank'
-
-
-
-


Cleanup commented code.

Cleanup commented code.

--- src/spec/integration.spec.coffee
+++ src/spec/integration.spec.coffee
@@ -50,9 +50,5 @@
     it 'Nothing to do', (done) ->
       @orderstatusimport.run('<root></root>')
       .then => done()
-      #@orderstatusimport.summaryReport()
-      #.then (message) ->
-    #    expect(message).toBe 'Summary: nothing to do, everything is fine'
-    #    done()
       .catch (err) -> done(_.prettify err)
     , 10000 # 10sec


Emailer: s/email.defaultFromAddress/email.defaultFromMail

--- workers/social/lib/social/emailer.coffee
+++ workers/social/lib/social/emailer.coffee
@@ -12,7 +12,7 @@
   @send : (options,callback) ->
     {From,To,Subject,HtmlBody,TextBody,ReplyTo,Bcc} = options
     mailOptions =
-      from    : From or email.defaultFromAddress
+      from    : From or email.defaultFromMail
       to      : To
       subject : Subject


Clip screen range end backward when dragging gutter

Signed-off-by: Nathan Sobo <2e8aa918660411855c6d44d5bb2da677aa033255@github.com>

--- src/text-editor-component.coffee
+++ src/text-editor-component.coffee
@@ -616,7 +616,7 @@
         screenRange = new Range(startPosition, startPosition).union(initialRange)
         @editor.getLastSelection().setScreenRange(screenRange, reversed: true, autoscroll: false, preserveFolds: true)
       else
-        endPosition = [dragRow + 1, 0]
+        endPosition = @editor.clipScreenPosition([dragRow + 1, 0], clipDirection: 'backward')
         screenRange = new Range(endPosition, endPosition).union(initialRange)
         @editor.getLastSelection().setScreenRange(screenRange, reversed: false, autoscroll: false, preserveFolds: true)


Deprecate TextEditorComponent::setShowInvisibles

--- src/text-editor-component.coffee
+++ src/text-editor-component.coffee
@@ -754,6 +754,7 @@

   # Deprecated
   setShowInvisibles: (showInvisibles) ->
+    grim.deprecate "Use config.set('editor.showInvisibles', showInvisibles) instead"
     atom.config.set('editor.showInvisibles', showInvisibles)

   setScrollSensitivity: (scrollSensitivity) =>


:fire: :racehorse: Remove leftover update statements

--- src/text-editor-presenter.coffee
+++ src/text-editor-presenter.coffee
@@ -71,6 +71,7 @@
     @updateScrollbarDimensions()
     @updateStartRow()
     @updateEndRow()
+    @updateCommonGutterState()

     @updateFocusedState() if @shouldUpdateFocusedState
     @updateHeightState() if @shouldUpdateHeightState
@@ -111,8 +112,6 @@

   observeModel: ->
     @disposables.add @model.onDidChange =>
-      @updateContentDimensions()
-      @updateEndRow()
       @shouldUpdateHeightState = true
       @shouldUpdateVerticalScrollState = true
       @shouldUpdateHorizontalScrollState = true
@@ -149,14 +148,11 @@
       @shouldUpdateLineNumbersState = true
       @shouldUpdateGutterOrderState = true
       @shouldUpdateCustomGutterDecorationState = true
-      @updateScrollbarDimensions()
-      @updateCommonGutterState()
       @emitDidUpdateState()

     @disposables.add @model.onDidChangeLineNumberGutterVisible =>
       @shouldUpdateLineNumberGutterState = true
       @shouldUpdateGutterOrderState = true
-      @updateCommonGutterState()
       @emitDidUpdateState()

     @disposables.add @model.onDidAddDecoration(@didAddDecoration.bind(this))
@@ -198,7 +194,6 @@
       @showLineNumbers = newValue
       @shouldUpdateLineNumberGutterState = true
       @shouldUpdateGutterOrderState = true
-      @updateCommonGutterState()

       @emitDidUpdateState()

@@ -207,7 +202,6 @@
     @shouldUpdateContentState = true
     @shouldUpdateLineNumberGutterState = true
     @shouldUpdateGutterOrderState = true
-    @updateCommonGutterState()

     @emitDidUpdateState()

@@ -792,8 +786,6 @@
     unless @scrollTop is scrollTop or Number.isNaN(scrollTop)
       @scrollTop = scrollTop
       @model.setScrollTop(scrollTop)
-      @updateStartRow()
-      @updateEndRow()
       @didStartScrolling()
       @shouldUpdateVerticalScrollState = true
       @shouldUpdateHiddenInputState = true
@@ -850,7 +842,6 @@
       oldHorizontalScrollbarHeight = @measuredHorizontalScrollbarHeight
       @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight
       @model.setHorizontalScrollbarHeight(horizontalScrollbarHeight)
-      @updateScrollbarDimensions()
       @shouldUpdateScrollbarsState = true
       @shouldUpdateVerticalScrollState = true
       @shouldUpdateHorizontalScrollState = true
@@ -863,7 +854,6 @@
       oldVerticalScrollbarWidth = @measuredVerticalScrollbarWidth
       @measuredVerticalScrollbarWidth = verticalScrollbarWidth
       @model.setVerticalScrollbarWidth(verticalScrollbarWidth)
-      @updateScrollbarDimensions()
       @shouldUpdateScrollbarsState = true
       @shouldUpdateVerticalScrollState = true
       @shouldUpdateHorizontalScrollState = true
@@ -907,7 +897,6 @@
       oldContentFrameWidth = @contentFrameWidth
       @contentFrameWidth = contentFrameWidth
       @model.setWidth(contentFrameWidth)
-      @updateScrollbarDimensions()
       @updateClientWidth()
       @shouldUpdateVerticalScrollState = true
       @shouldUpdateHorizontalScrollState = true
@@ -946,7 +935,6 @@
       @backgroundColor = backgroundColor
       @shouldUpdateContentState = true
       @shouldUpdateLineNumberGutterState = true
-      @updateCommonGutterState()
       @shouldUpdateGutterOrderState = true

       @emitDidUpdateState()
@@ -955,7 +943,6 @@
     unless @gutterBackgroundColor is gutterBackgroundColor
       @gutterBackgroundColor = gutterBackgroundColor
       @shouldUpdateLineNumberGutterState = true
-      @updateCommonGutterState()
       @shouldUpdateGutterOrderState = true

       @emitDidUpdateState()
@@ -969,11 +956,6 @@
     unless @lineHeight is lineHeight
       @lineHeight = lineHeight
       @model.setLineHeightInPixels(lineHeight)
-      @updateContentDimensions()
-      @updateScrollHeight()
-      @updateHeight()
-      @updateStartRow()
-      @updateEndRow()
       @shouldUpdateHeightState = true
       @shouldUpdateHorizontalScrollState = true
       @shouldUpdateVerticalScrollState = true
@@ -1024,8 +1006,6 @@
     @characterWidthsChanged() unless @batchingCharacterMeasurement

   characterWidthsChanged: ->
-    @updateContentDimensions()
-
     @shouldUpdateHorizontalScrollState = true
     @shouldUpdateVerticalScrollState = true
     @shouldUpdateScrollbarsState = true


Reset only lines state

Reset only lines state

--- src/text-editor-presenter.coffee
+++ src/text-editor-presenter.coffee
@@ -74,10 +74,9 @@
     @updateEndRow()

     @updateLineDecorations() if @shouldUpdateDecorations
-    @updateTilesState() if @shouldUpdateLineNumbersState or @shouldUpdateLinesState
+    @updateTilesState() if @shouldUpdateLinesState

     @shouldUpdateLinesState = false
-    @shouldUpdateLineNumbersState = false

     @state


Update Gruntfile to avoid calling dumimg with same arguments.

--- app/templates/common/Gruntfile.coffee
+++ app/templates/common/Gruntfile.coffee
@@ -27,18 +27,27 @@

 capitalize = (s) -> s[0].toUpperCase() + s.substring(1)

+generatedImages = []
+
 dumimg = (dist, dir) ->
   (options) ->
     if _.isNumber(options) || _.isString(options)
       [width, height, type, replace] = arguments
       height = width unless height
       options = {width: width, height: height, type: type, replace: replace}
+
     return options.replace if options.replace? && dist
+
+    generated = _.find(generatedImages, options)
+    return generated.path if generated
+    generatedOptions = _.clone(options)
+    generatedImages.push(generatedOptions)
+
     baseDir = path.join(__dirname, dir)
     options.outputDir = path.join(baseDir, 'img', 'dummy')
     fs.mkdirSync options.outputDir unless fs.existsSync options.outputDir
     imgPath = dummyImage(options)
-    path.relative(baseDir, imgPath)
+    generatedOptions.path = path.relative(baseDir, imgPath)

 lorem = (count, options={}) ->
   if typeof count == 'number'


fix comments

fix comments

--- src/parser/csharp-parser.coffee
+++ src/parser/csharp-parser.coffee
@@ -1,4 +1,4 @@
-# parsing Java code
+# parsing C# code
 #
 # Copyright (c) 2013 JeongHoon Byun aka "Outsider", <http://blog.outsider.ne.kr/>
 # Licensed under the MIT license.


referral: fix selected recipient invitation procedure

--- client/landing/app/Applications/Account.kdapplication/views/referrermodal.coffee
+++ client/landing/app/Applications/Account.kdapplication/views/referrermodal.coffee
@@ -96,11 +96,9 @@
       title   : "Send invitation(s)"
       callback: =>
         recipients = listController.getItemsOrdered().filter (view) =>
-          return  view.isSelected and not contact.invited
+          return  view.isSelected and not view.getData().invited

         recipients.forEach (view) ->
-          contact = view.getData()
-          return if not view.isSelected or contact.invited
           view.getData().invite (err) =>
             return log "invite", err  if err
             view.emit "InvitationSent"


typeof(null) == "object" and typeof(undefined) == "undefined" query issues

--- src/tower/store/operators.coffee
+++ src/tower/store/operators.coffee
@@ -70,7 +70,7 @@
       when 'number', 'string', 'float', 'NaN'
         success = recordValue == operators
       when 'undefined', 'null'
-        !recordValue?
+        success = recordValue === null || recordValue === undefined
       when 'regex'
         success = @match(recordValue, operators)
       else


Fix bucket not recoreded.

Fix bucket not recoreded.

--- views/records.coffee
+++ views/records.coffee
@@ -250,7 +250,7 @@
     if !(recordId = @bucketRecord_[id])? || !(record = @records_[recordId])?
       return
     shipRecord = record.fleet.concat(record.fleet2 || []).find (ship) ->
-      ship.id == id
+      ship.id.toString() == id.toString()
     shipRecord?.bucket = true
     delete @bucketRecord_[id]
     @writeToJson_()


specs for event

specs for event

--- test/specs/source/views_spec.coffee
+++ test/specs/source/views_spec.coffee
@@ -92,3 +92,27 @@
           view.render("content").prepend()
           expect($(element).text()).toEqual(" text: content default")

+    describe "Event", ->
+      element = "#content"
+      view = new Sirius.View(element)
+      pp1 = pp2 = null
+
+      beforeEach () ->
+
+        Sirius.Application.run
+          route :
+            "event:click": (e1, e2, p1, p2) ->
+              pp1 = p1
+              pp2 = p2
+          adapter: new JQueryAdapter()
+
+        p1 = 1
+        p2 = "abc"
+
+        view.on("click", "event:click", p1, p2)
+        $(element).trigger("click")
+
+
+      it "should fire custom event and pass params", ->
+        expect(pp1).toEqual(1)
+        expect(pp2).toEqual("abc")


adds resize support for D3 selections (#433)

--- src/viz/methods/container.coffee
+++ src/viz/methods/container.coffee
@@ -10,9 +10,9 @@
       vars.self.container id: "d3plus_" + +new Date()

     if d3selection(value)
-      value
+      value.append("div")
     else if value instanceof Array
-      d3.select(value[0][0]).append('div')
+      d3.select(value[0][0]).append("div")
     else
-      d3.select(value).append('div')
+      d3.select(value).append("div")
   value:    false


added tests for yield in switch & for loop expressions

--- test/generators.coffee
+++ test/generators.coffee
@@ -81,7 +81,6 @@
   ok y.value is 3 and y.done is true

 test "symbolic operators has precedence over the `yield`", ->
-
   symbolic   = '+ - * / << >> & | || && ** ^ // or and'.split ' '
   compound   = ("#{op}=" for op in symbolic)
   relations  = '< > == != <= >= is isnt'.split ' '
@@ -91,15 +90,37 @@
   collect = (gen) -> ref.value until (ref = gen.next()).done

   values = [0, 1, 2, 3]
-
   for op in operators
-
     expression = "i #{op} 2"

-    yielded    = CoffeeScript.eval "(arr) ->  yield #{expression} for i in arr"
-    mapped     = CoffeeScript.eval "(arr) ->       (#{expression} for i in arr)"
+    yielded = CoffeeScript.eval "(arr) ->  yield #{expression} for i in arr"
+    mapped  = CoffeeScript.eval "(arr) ->       (#{expression} for i in arr)"

-    expected   = mapped values
-    actual     = collect yielded values
+    arrayEq mapped(values), collect yielded values

-    arrayEq actual, expected
+test "for loop expressions", ->
+  x = do ->
+    y = for i in [1..3]
+      yield i * 2
+
+  z = x.next()
+  ok z.value is 2 and z.done is false
+  z = x.next 10
+  ok z.value is 4 and z.done is false
+  z = x.next 20
+  ok z.value is 6 and z.done is false
+  z = x.next 30
+  arrayEq z.value, [10, 20, 30]
+  ok z.done is true
+
+test "switch expressions", ->
+  x = do ->
+    y = switch yield 1
+      when 2 then yield 1337
+
+  z = x.next()
+  ok z.value is 1 and z.done is false
+  z = x.next 2
+  ok z.value is 1337 and z.done is false
+  z = x.next 3
+  ok z.value is 3 and z.done is true


When observing all builds don't request them

We use `allBuilds` to observe new incoming builds, so we can put new
builds into the lists (for example when build is started). We use it for
observing purposes only, so we actually don't need to get builds from
the server, we can just register record array and use it later on.

--- assets/scripts/app/models/repo.coffee
+++ assets/scripts/app/models/repo.coffee
@@ -22,7 +22,9 @@
   ).property('lastBuildId', 'lastBuildNumber')

   allBuilds: (->
-    Travis.Build.find()
+    recordArray = DS.RecordArray.create({ type: Travis.Build, content: Ember.A([]), store: Travis.store, isLoaded: true })
+    Travis.store.registerRecordArray(recordArray, Travis.Build)
+    recordArray
   ).property()

   builds: (->


Try to fix cancel.

Try to fix cancel.

--- src/redux-axios-reducers.coffee
+++ src/redux-axios-reducers.coffee
@@ -65,10 +65,10 @@

     config = @transformConfig(config)

-    cancelToken = Axios.CancelToken.source()
-    config = {config..., cancelToken: cancelToken}
+    cancelTokenSource = Axios.CancelToken.source()
+    config = {config..., cancelToken: cancelTokenSource.token}

-    dispatch type: @TYPES.FETCHING, config: config
+    dispatch type: @TYPES.FETCHING, config: config, cancel: cancelTokenSource

     return @axios.request config
       .then (response) =>