Fix issue in hand-entry where handfound would not fire after reconnect

--- main/hand-entry/leap.hand-entry.coffee
+++ main/hand-entry/leap.hand-entry.coffee
@@ -7,20 +7,9 @@
 handEntry = ->
   activeHandIds = []

-  #http://stackoverflow.com/questions/3954438/remove-item-from-array-by-value
-  `activeHandIds.remove = function() {
-      var what, a = arguments, L = a.length, ax;
-      while (L && this.length) {
-          what = a[--L];
-          while ((ax = this.indexOf(what)) !== -1) {
-              this.splice(ax, 1);
-          }
-      }
-      return this;
-  }`
-
   @on "deviceDisconnected",  ->
-    for id in activeHandIds
+    for id, i in activeHandIds
+      activeHandIds.splice(i, 1)
       @emit('handLost', @lastConnectionFrame.hand(id))

   {
@@ -30,7 +19,7 @@
       `for (var i = 0, len = activeHandIds.length; i < len; i++){
         id = activeHandIds[i];
         if(  newValidHandIds.indexOf(id) == -1){
-          activeHandIds.remove(id)
+          activeHandIds.splice(i, 1);
           // this gets executed before the current frame is added to the history.
           this.emit('handLost', this.frame(1).hand(id))
           i--;


bugFixes: Passwords should be at least 8 characters error is fixed

--- client/account/lib/views/accounteditusername.coffee
+++ client/account/lib/views/accounteditusername.coffee
@@ -177,7 +177,10 @@
       =>
         # update firstname and lastname
         me = whoami()
-
+        {profile:{firstName:oldFirstName, lastName:oldLastName}} = me
+        # do not do anything if current firstname and lastname is same
+        return queue.next() if oldFirstName is firstName and oldLastName is lastName
+
         me.modify {
           "profile.firstName": firstName,
           "profile.lastName" : lastName
@@ -216,7 +219,7 @@
           @emailForm.buttons.Save.hideLoader()
           return
         #check passworg lenght
-        if password.length < 8
+        if password is not "" and password.length < 8
           notify "Passwords should be at least 8 characters"
           @emailForm.buttons.Save.hideLoader()
           return


Oops. Don't overwrite user config w/ defaults before its loaded

--- src/app/config.coffee
+++ src/app/config.coffee
@@ -17,9 +17,9 @@
   settings: null

   constructor: ->
-    @settings = {}
-    @setDefaults "core", require('root-view').configDefaults
-    @setDefaults "editor", require('editor').configDefaults
+    @settings =
+      core: require('root-view').configDefaults
+      editor: require('editor').configDefaults

   load: ->
     @loadUserConfig()


Assign global 'platform' variable on window at eval time

--- src/app/window.coffee
+++ src/app/window.coffee
@@ -13,6 +13,7 @@
   rootViewParentSelector: 'body'
   rootView: null
   keymap: null
+  platform: $native.getPlatform()

   setUpKeymap: ->
     Keymap = require 'keymap'


Change reporting from versionString to version

--- src/background.coffee
+++ src/background.coffee
@@ -4,7 +4,7 @@
     "v#{chrome.runtime.getManifest().version}"

   @reportVersion: ->
-    @trackEvent 'Background', 'versionString', @version()
+    @trackEvent 'Background', 'version', @version()

   @reportButtonClick: ->
     @trackEvent 'YouTubeVideoPage', 'popoutButtonClick'


Tabpaneview: keeping scrollposition on detached panes regression fixed

--- src/components/tabs/tabpaneview.coffee
+++ src/components/tabs/tabpaneview.coffee
@@ -33,17 +33,15 @@

     @active = yes
     @emit "KDTabPaneActive"
+
     KD.utils.defer =>
-      {body, documentElement}         = document
       @getElement().scrollTop         = @lastScrollTops.self
-      documentElement.scrollTop       = @lastScrollTops.window
+      @parent?.getElement().scrollTop = @lastScrollTops.parent

   hide:->

     return  unless @active
-
-    {body, documentElement} = document

     @lastScrollTops.parent = @parent?.getElement().scrollTop or 0
     @lastScrollTops.self   = @getElement().scrollTop


Sends a tracking call when the user logs in or logs out

--- src/client/api.coffee
+++ src/client/api.coffee
@@ -236,5 +236,9 @@

         app.core.mediator.on    'hull.login', clearModelsCache
         app.core.mediator.on    'hull.logout', clearModelsCache
+        app.core.mediator.on 'hull.login', ->
+          app.sandbox.track 'hull.auth.login', app.core.data.api.model('me').toJSON()
+        app.core.mediator.on 'hull.logout', ->
+          app.sandbox.track 'hull.auth.logout', app.core.data.api.model('me').toJSON()

     module


Show seconds between 44-119

Show seconds between 44-119

--- resources/assets/coffee/main.coffee
+++ resources/assets/coffee/main.coffee
@@ -6,6 +6,7 @@
 Turbolinks.setProgressBarDelay(0)

 Lang.setLocale(@currentLocale)
+moment.relativeTimeThreshold('ss', 44)
 moment.relativeTimeThreshold('s', 120)
 moment.relativeTimeThreshold('m', 120)
 moment.relativeTimeThreshold('h', 48)


update sprint when changing active sprint

--- src/sprint/states/list/controller.coffee
+++ src/sprint/states/list/controller.coffee
@@ -53,3 +53,4 @@
       if s.isActive and s != sprint
         Sprint.deactivateSprint s
     Sprint.setActiveSprint sprint
+    $scope.$emit 'sprint:update', {sprint: sprint}


swap to a valid sort if sort mode is not valid in incoming mode.

--- resources/assets/coffee/react/beatmap-discussions/discussions.coffee
+++ resources/assets/coffee/react/beatmap-discussions/discussions.coffee
@@ -48,6 +48,14 @@

     @state =
       sortField: if @props.mode == 'timeline' then 'timeline' else 'created_at'
+
+
+  componentWillReceiveProps: (nextProps) =>
+    if _.includes(['created_at', 'timeline'], @state.sortField)
+      if nextProps.mode == 'timeline'
+        @setState sortField: 'timeline'
+      else
+        @setState sortField: 'created_at'

   render: =>


test: reorganize and add granularity to TRIV tests

clean up TimeRangeInputView tests for min and max times

--- coffee/test/views/time_range_input_view.spec.coffee
+++ coffee/test/views/time_range_input_view.spec.coffee
@@ -80,64 +80,68 @@
       expect(widgets.startInputView.value()).toBe 10
       expect(widgets.endInputView.value()).toBe 40

-    it 'should abide by min and max restrictions', ->
-      [triv, widgets] = setupTRIV
-        start: 0
-        end: 50
-        min: 0
-        max: 100
-
-      # confirm background assumptions
-      expect(widgets.rangeSliderView.values()[0]).toBe 0
-      expect(widgets.rangeSliderView.values()[1]).toBe 50
-      expect(widgets.startInputView.value()).toBe 0
-      expect(widgets.endInputView.value()).toBe 50
-
-      triv.values {start: 10, end: 140}
-      expect(widgets.rangeSliderView.values()[0]).toBe 10
-      expect(widgets.rangeSliderView.values()[1]).toBe 100
-      expect(widgets.startInputView.value()).toBe 10
-      expect(widgets.endInputView.value()).toBe 100
-
-      triv.values {start: -40, end: 60}
-      expect(widgets.rangeSliderView.values()[0]).toBe 0
-      expect(widgets.rangeSliderView.values()[1]).toBe 60
-      expect(widgets.startInputView.value()).toBe 0
-      expect(widgets.endInputView.value()).toBe 60
-
-    it 'should propagate setMin and setMax to its widgets', ->
-      [triv, widgets] = setupTRIV
-        start: 0
-        end: 50
-        min: 0
-        max: 100
-
-      # confirm background assumptions
-      expect(widgets.rangeSliderView.values()[0]).toBe 0
-      expect(widgets.rangeSliderView.values()[1]).toBe 50
-      expect(widgets.startInputView.value()).toBe 0
-      expect(widgets.endInputView.value()).toBe 50
-
-      triv.setMin 20
-      expect(widgets.rangeSliderView.values()[0]).toBe 0
-      expect(widgets.rangeSliderView.values()[1]).toBe 30*100/80
-      expect(widgets.startInputView.value()).toBe 20
-      expect(widgets.endInputView.value()).toBe 50
-
-      triv.setMax 35
-      expect(widgets.rangeSliderView.values()[0]).toBe 0
-      expect(widgets.rangeSliderView.values()[1]).toBe 100
-      expect(widgets.startInputView.value()).toBe 20
-      expect(widgets.endInputView.value()).toBe 35
-
-      # expect values to stay at upper and lower bounds when individual widgets
-      # are given values that exceed these bounds
-      widgets.startInputView.value 10
-      widgets.endInputView.value 60
-      expect(widgets.rangeSliderView.values()[0]).toBe 0
-      expect(widgets.rangeSliderView.values()[1]).toBe 100
-      expect(widgets.startInputView.value()).toBe 20
-      expect(widgets.endInputView.value()).toBe 35
+
+    describe 'TimeRangeInputView: min and max', ->
+
+      it 'should abide by min and max restrictions', ->
+        [triv, widgets] = setupTRIV
+          start: 0
+          end: 50
+          min: 0
+          max: 100
+
+        # confirm background assumptions
+        expect(widgets.rangeSliderView.values()[0]).toBe 0
+        expect(widgets.rangeSliderView.values()[1]).toBe 50
+        expect(widgets.startInputView.value()).toBe 0
+        expect(widgets.endInputView.value()).toBe 50
+
+        triv.values {start: 10, end: 140}
+        expect(widgets.rangeSliderView.values()[0]).toBe 10
+        expect(widgets.rangeSliderView.values()[1]).toBe 100
+        expect(widgets.startInputView.value()).toBe 10
+        expect(widgets.endInputView.value()).toBe 100
+
+        triv.values {start: -40, end: 60}
+        expect(widgets.rangeSliderView.values()[0]).toBe 0
+        expect(widgets.rangeSliderView.values()[1]).toBe 60
+        expect(widgets.startInputView.value()).toBe 0
+        expect(widgets.endInputView.value()).toBe 60
+
+      it 'should propagate setMin and setMax to its widgets', ->
+        [triv, widgets] = setupTRIV
+          start: 0
+          end: 50
+          min: 0
+          max: 100
+
+        # confirm background assumptions
+        expect(widgets.rangeSliderView.values()[0]).toBe 0
+        expect(widgets.rangeSliderView.values()[1]).toBe 50
+        expect(widgets.startInputView.value()).toBe 0
+        expect(widgets.endInputView.value()).toBe 50
+
+        triv.setMin 20
+        expect(widgets.rangeSliderView.values()[0]).toBe 0
+        expect(widgets.rangeSliderView.values()[1]).toBe 30*100/80
+        expect(widgets.startInputView.value()).toBe 20
+        expect(widgets.endInputView.value()).toBe 50
+
+        triv.setMax 35
+        expect(widgets.rangeSliderView.values()[0]).toBe 0
+        expect(widgets.rangeSliderView.values()[1]).toBe 100
+        expect(widgets.startInputView.value()).toBe 20
+        expect(widgets.endInputView.value()).toBe 35
+
+        # expect values to stay at upper and lower bounds when individual widgets
+        # are given values that exceed these bounds
+        widgets.startInputView.value 10
+        widgets.endInputView.value 60
+        expect(widgets.rangeSliderView.values()[0]).toBe 0
+        expect(widgets.rangeSliderView.values()[1]).toBe 100
+        expect(widgets.startInputView.value()).toBe 20
+        expect(widgets.endInputView.value()).toBe 35
+

     it 'should fire events correctly on _change', ->
       [triv, widgets] = setupTRIV


LocalSync: add file timestamp to localStorage to check version

--- client/Main/localsynccontroller.coffee
+++ client/Main/localsynccontroller.coffee
@@ -33,7 +33,12 @@
     index    = @filesToSave.indexOf fileName
     @filesToSave.push fileName if index is -1
     @storage.setValue "saveRequestedFiles", @filesToSave
+    @addSaveRequestTime file
     @initializeListeners()
+
+  addSaveRequestTime: (file)->
+    path = FSHelper.getFullPath file
+    @storage.setValue "#{path}-savetime", Date.now()

   removeFromSaveArray: (file) ->
     fileName = FSHelper.getFullPath file


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/fadeable.coffee
+++ src/fadeable.coffee
@@ -2,26 +2,7 @@
 The Fadeable module provides a method to fade a sprite to transparent.
 You may also provide a callback function that is executed when the sprite has finished fading out.

-

-player = GameObject()
-
-player.include(Fadeable)
-
-fadedOut = false
-
-# this will fade the player object out over the next 30 frames.
-# once the player is faded out the fadedOut variable will be set to true.
-player.fadeOut 30, (player) ->
-  fadedOut = true
-
-30.times ->
-  player.update()
-
-fadedOut
-# => true
-

-
-@name Movable
+@name Fadeable
 @module
 @constructor
 @param {Object} I Instance variables
@@ -42,7 +23,36 @@
       I.fadeCooldown = null
       I.fadeCallback?(self)

+  ###*
+  A convenient way to set the fade instance variables on a sprite. You can modify the
+  instance variables by hand but the suggested way to do it is through this method.
+
+

+  player = GameObject()
+
+  player.include(Fadeable)
+
+  fadedOut = false
+
+  # this will fade the player object out over the next 30 frames.
+  # once the player is faded out the fadedOut variable will be set to true.
+  player.fadeOut 30, (player) ->
+    fadedOut = true
+
+  30.times ->
+    player.update()
+
+  fadedOut
+  # => true
+

+
+  @name fadeOut
+  @methodOf GameObject#
+  @param {Number} [duration=30] How long the effect lasts
+  @param {Function} [callback=null] The function to execute when the sprite has finished fading.
+  ###
   fadeOut: (duration = 30, callback) ->
     I.fadeDuration = duration
     I.fadeCooldown = duration
     I.fadeCallback = callback
+


Fixes precise floating point math in equation builder #3809068

--- javascripts/lib/math/expression_equality.coffee
+++ javascripts/lib/math/expression_equality.coffee
@@ -121,7 +121,7 @@
         # The real "todo" here is that
         # numbers are internally of questionable state.
         # Im not entirely sure how to state that number expresison components are equal
-        check = "#{@value()}" == "#{other.value()}"
+        check = parseFloat("#{@value()}").toFixed(2) == parseFloat("#{other.value()}").toFixed(2)
         eq_calc.saveFalseForReport(check, @unrefined(), other, "Numeric values not equal")
     })


add social/activity fetching autocomplete list item missing def

--- client/Social/Activity/includes.coffee
+++ client/Social/Activity/includes.coffee
@@ -55,6 +55,7 @@
   "views/chatheadautocompleteitem.coffee"
   "views/alltopicsmodal.coffee"
   "views/activityautocompleteuseritemview.coffee"
+  "views/fetchingactivityautocompleteuseritemview.coffee"
   "views/searchinputview.coffee"

   "views/embedbox.coffee"


some new fun facts

some new fun facts

--- scripts/facts.coffee
+++ scripts/facts.coffee
@@ -13,13 +13,23 @@
 funfacts = [
   "You can fit over 1,300 Earth-sized things inside Jupiter but over 1,300,000 Earth sized things inside our Sun!",
   "If you drove to the Sun it would take 152 years.",
-  "There’s more water on Europa than there is on Earth",
+  "There’s more water on Europa than there is on Earth.",
   "Io smells like rotten eggs because of the sulphur volcanoes. Stinkiest place in the Solar System?",
   "The giant planets have likely moved since they formed, and Neptune and Uranus might have switched places.",
   "You could float Saturn in the bath. If you had a Saturn-sized bath.",
   "If the Sun is a big beach ball, then the Earth is a small marble about a football field away",
-  "There’s Red helium-neon rain on Jupiter and metallic snow/frost on Venus",
-  "The rain on Saturn’s moon Titan is flammable (but there’s no oxygen there so it never burns)."
+  "There’s Red helium-neon rain on Jupiter and metallic snow/frost on Venus.",
+  "The rain on Saturn’s moon Titan is flammable (but there’s no oxygen there so it never burns).",
+  "During a Martian sunset, the Sun looks blue and the rest of the sky turns red.",
+  "If you want to visit our nearest spiral galaxy, wait a couple billion years: it's on a collision course with us.",
+  "If Saturn's rings shrunk to the thickness of 1 sheet of paper, the paper would be 500 meters wide.",
+  "The Sun is rounder than it should be.",
+  "During a collision of galaxies made of hundreds of billions of stars, the number of stars that collide is usually 0.",
+  "The full Moon takes up the same space in the sky as our nearest spiral galaxy neighbor (which is very faint).",
+  "Dust in galaxies smells like fried chicken.",
+  "All of the gold in the Universe was made in the explosions of dying stars.",
+  "All of the planets in the solar system lined end-to-end would just fit between the Earth and the Moon.",
+  "We think there are as many planets in the galaxy as there are stars. We just haven't found most of them (yet)."
 ]

 module.exports = (robot) ->


fix values for "looks like" filter

fix values for "looks like" filter

--- app/lib/animals.coffee
+++ app/lib/animals.coffee
@@ -7,7 +7,7 @@

 # The order of these values must match the order in the spreadsheet.
 values = [
-  'likeCatDog', 'likeCowHorse', 'likeAntelopeDeer', 'likePrimate', 'likeWeasel', 'likeBird', 'likeOther'
+  'likeCatdog', 'likeCowhorse', 'likeAntelopedeer', 'likePrimate', 'likeWeasel', 'likeBird', 'likeOther'
   'patternSolid', 'patternStripes', 'patternBands', 'patternSpots'
   'coatTanYellow', 'coatRed', 'coatBrown', 'coatWhite', 'coatGray', 'coatBlack'
   'hornsStraight', 'hornsCurved', 'hornsSpiral', 'hornsUshaped'


Fix damage bug

Fix damage bug

--- src/components/player/PlayerSpaceship.coffee
+++ src/components/player/PlayerSpaceship.coffee
@@ -82,20 +82,21 @@

     @backFire.colorOverride(c)

-    @addComponent('Invincible').invincibleDuration(2000)
+    @addComponent('Invincible').invincibleDuration(1500)

     @setDetectionOffset 60, 0
-    @onHit 'Hostile', (collision) ->
-      return if Game.paused
-      return if @has('Invincible')
-      hit = no
-      damage = 0
-      for e in collision
-        if e.obj.damage and e.obj.damage > damage and !e.obj.damageHandled
-          damage = e.obj.damage
-          e.obj.damageHandled = true
-        hit = yes unless e.obj.hidden
-      @trigger('Hit', { damage }) if hit
+    @onHit('Hostile',
+      (collision) ->
+        return if Game.paused
+        return if @has('Invincible')
+        hit = no
+        damage = 0
+        for e in collision
+          if e.obj.damage and e.obj.damage > damage
+            damage = e.obj.damage
+          hit = yes unless e.obj.hidden
+        @trigger('Hit', { damage }) if hit
+    )

     @onHit 'PowerUp', (e) ->
       return if Game.paused
@@ -103,7 +104,7 @@
         @pickUp(pu.obj) unless pu.obj.pickedUp

     @bind 'Hit', ->
-      @addComponent('Invincible').invincibleDuration(1000)
+      @addComponent('Invincible').invincibleDuration(2000)
       Crafty.e('Blast, Explosion').explode(
         x: @x + (@w / 2)
         y: @y + (@h / 2)


Anims: Stat-up anims, defenders get hurt anim.

--- client/app/js/views/battle_view.coffee
+++ client/app/js/views/battle_view.coffee
@@ -290,6 +290,7 @@

     if 'contact' in moveData.flags
       # Simple attack animation
+      # Tackling the opponent
       [targetPlayer, targetSlot] = targetSlots[0]
       $attacker = @$sprite(player, slot)
       $defender = @$sprite(targetPlayer, targetSlot)
@@ -297,9 +298,14 @@
       scale = (if a.top < d.top then 1.3 else 1/1.3)
       $attacker
         .transition(x: d.left - a.left, y: d.top - a.top, scale: scale, 250, 'in')
-        .transition(x: 0, y: 0, scale: 1, 250, 'out', done)
+        .transition(x: 0, y: 0, scale: 1, 250, 'out')
+      $defender.delay(400)
+        .transition(x: -4, 0, 'linear').delay(50)
+        .transition(x: 4, 0, 'linear').delay(50)
+        .transition(x: 0, 0, 'linear', done)
     else if moveData['power'] > 0
       # Non-contact attacking move
+      # Projectile
       [targetPlayer, targetSlot] = targetSlots[0]
       $attacker = @$sprite(player, slot)
       $defender = @$sprite(targetPlayer, targetSlot)
@@ -313,12 +319,20 @@
       )
       [transX, transY] = [(d.left - a.left), (d.top - a.top)]
       $projectile
-        .transition(x: transX / 2, y: transY / 2, scale: (scale + 1) / 2, 250, 'easeOutCubic')
-        .transition x: transX, y: transY, scale: scale, 250, 'easeOutCubic', ->
-          $projectile.remove()
-          done()
+        .transition(x: transX / 2, y: transY / 2, scale: (scale + 1) / 2, 200, 'easeOutCubic')
+        .transition(x: transX, y: transY, scale: scale, 200, 'easeOutCubic')
+        .transition(opacity: 0, 100, -> $projectile.remove())
+      $defender.delay(400)
+        .transition(x: -4, 0, 'linear').delay(50)
+        .transition(x: 4, 0, 'linear').delay(50)
+        .transition(x: 0, 0, 'linear', done)
     else
-      done()
+      # Side-to-side movement
+      $attacker = @$sprite(player, slot)
+      $attacker
+        .transition(x: -16, 125, 'easeInOutSine')
+        .transition(x: 16, 250, 'easeInOutSine')
+        .transition(x: 0, 125, 'easeInOutSine', done)

   cancelSuccess: (done) =>
     @enableButtons()


set formats to default to []

set formats to default to []

It's required, but this will at least render without errors

--- src/components/question/formats-listing.cjsx
+++ src/components/question/formats-listing.cjsx
@@ -10,6 +10,9 @@
   propTypes:
     formats: React.PropTypes.arrayOf(React.PropTypes.string).isRequired

+  getDefaultProps: ->
+    formats: []
+
   render: ->

Formats:


Fix missing membership case

Fix missing membership case

--- client/shared/models/user_model.coffee
+++ client/shared/models/user_model.coffee
@@ -120,7 +120,7 @@
   titleFor: (model) ->
     return unless model
     if model.isA('group')
-      @membershipFor(model).title
+      (@membershipFor(model) or {}).title
     else if model.isA('discussion')
       @titleFor(model.guestGroup()) or @titleFor(model.group())
     else if model.isA('poll')


fix #114

fix #114

--- client/views/common/shift/shift.coffee
+++ client/views/common/shift/shift.coffee
@@ -83,6 +83,7 @@
 						return 'approved'
 					for pending in team.pending when pending._id == Meteor.userId()
 						return 'pending'
+			@status

 	getTeamStatus: (team) ->
 		if @date < parseInt moment().format 'YYYYDDDD'


fix of https://github.com/apiaryio/gavel.js/issues/41

--- src/validators/json-schema.coffee
+++ src/validators/json-schema.coffee
@@ -63,7 +63,7 @@
   # Validates given data against given schema
   #@return [ValidationErrors]
   validate: ->
-    if ((@data instanceof Object) and Object.keys(@data).length == 0) or ((@data instanceof Object) and @schema['empty'])
+    if (@data instanceof Object) and @schema['empty']
       @output = {
         "length":0,
         "errorMessages":{


fixes and tweaks

fixes and tweaks

--- scripts/slugs.coffee
+++ scripts/slugs.coffee
@@ -13,18 +13,14 @@
   return err if err

   async.mapSeries teams, (team, next) ->
-    console.log "EMPTY TEAM - nodeknockout.com/teams/#{team.slug} (#{team.name})" if team.peopleIds.length is 0
-
-    return next(null, team) if team.peopleIds.length is 0  # skip empty
-    # return next(null, team) if team.slug is team.slugBase
     # return next(null, team) # don't modify right now

+    if team.peopleIds.length is 0
+      console.log "EMPTY TEAM - nodeknockout.com/teams/#{team.slug} (#{team.name})"
+      return next(null, team)

     # don't change any team that's already being setup
     return next(null, team) if team.setup?.status
-
-    team.setup ?= {}
-    team.setup.status = "ready"

     changes =
       "-1": "theteam"
@@ -43,7 +39,7 @@
       "bam-green-eggs-and-h": "green-eggs-and-ham"
       "node-group-tbd": "xyzzy"
       "tmp": "walbril"
-      "software-niagara-tea": "software-niagara"
+      "software-niagara-tea": "niagara-team"
       "swhite": "pimps-love"
       "front-end-developers": "fed-brazil"
       "cold-brew-rocket-fue": "brew-rocket-fuel"
@@ -100,7 +96,6 @@
       "its-always-been-brok": "always-broken"
       "figure-it-out-guys": "makeshift"

-
     if team.name == "ヽ( ´¬`)ノ" #special that there was no slug previously
       old = team.slug
       team.slug = 'waving'
@@ -110,6 +105,8 @@
       old = team.slug
       team.slug = changes[team.slug]
       console.log "#{old.red} -> #{team.slug.green} (#{team.name})"
+
+    team.setup = { status: 'ready' }

     team.save (err) -> next(err, team)


remove old test

remove old test

--- static/coffee/unittest/glyph_test.coffee
+++ static/coffee/unittest/glyph_test.coffee
@@ -1,920 +0,0 @@
-base = require("../base")
-Collections = base.Collections
-testutils = require("../testutils")
-line_plot = testutils.line_plot
-scatter_plot = testutils.scatter_plot
-glyph_plot = testutils.glyph_plot
-
-test('circles_glyph', () ->
-  expect(0)
-  data_source = Collections('ObjectArrayDataSource').create(
-    data : [
-      {x : 1, y : 5, z:3, radius:10},
-      {x : 2, y : 4, z:3},
-      {x : 3, y : 3, z:3, color:"red"},
-      {x : 4, y : 2, z:3, radius:8, alpha:0.5},
-      {x : 5, y : 1, z:3},
-    ]
-  )
-  plot_model = Collections('Plot').create()
-  xdr = Collections('DataRange1d').create(
-    sources : [{ref : data_source.ref(), columns : ['x']}]
-  )
-  ydr = Collections('DataRange1d').create(
-    sources : [{ref : data_source.ref(), columns : ['y']}]
-  )
-  glyph_renderer = Collections('GlyphRenderer').create(
-    data_source : data_source.ref()
-    xdata_range : xdr.ref()
-    ydata_range : ydr.ref()
-    scatter_size : 10
-    color : 'black'
-    x : 'x'
-    y : 'y'
-    glyphs : [
-        type : 'circles'
-        #xfield: 'x'
-        #yfield: 'y'
-        #radiusfield: "radius"
-        #radius: 5
-        color: 'blue'
-      ,
-        #  type : 'circle'
-        #  index : 0
-        #,
-        #  type : 'square'
-        #  index : 1
-        #,
-        #  type : 'square'
-        #  index : 2
-        #  color : 'red'
-        #,
-          #  type : 'square'
-          #  index : 2
-          #  color : 'green'
-          #  x : ['x', 0, 0.1]
-          #,
-          #  type : 'square'
-          #  index : 2
-          #  color : 'green'
-          #  x : ['x', 0, -0.1]
-    ]
-
-  )
-  xaxis = Collections('LinearAxis').create(
-    orientation : 'bottom'
-    parent : plot_model.ref()
-    data_range : xdr.ref()
-  )
-  yaxis = Collections('LinearAxis').create(
-    orientation : 'left',
-    parent : plot_model.ref()
-    data_range : ydr.ref()
-  )
-  plot_model.set(
-    renderers : [glyph_renderer.ref()],
-    axes : [xaxis.ref(), yaxis.ref()]
-  )
-  div = $('

')
-  $('body').append(div)
-  myrender  =  ->
-    view = new plot_model.default_view(model : plot_model)
-    div.append(view.$el)
-    view.render()
-  console.log('Test circles_glyph')
-  _.defer(myrender)
-)
-
-
-test('line_glyph', () ->
-  expect(0)
-  data_source = Collections('ObjectArrayDataSource').create(
-    data : [
-      {x: 1, y: 4}
-      {x: 2, y: 4}
-      {x: 3, y: 3}
-      {x: 4, y: 2}
-      {x: 5, y: 2}
-    ]
-  )
-  ds2 = Collections('ObjectArrayDataSource').create(
-    data: [
-      {x2: 1, y2: 1}
-      {x2: 2, y2: 1.5}
-      {x2: 2.5, y2: 3}
-      {x2: 3, y2: 3.5}
-      {x2: 3.5, y2: 2.8}
-      {x2: 4, y2: 2.9}
-      {x2: 5, y2: 3.5}
-    ]
-  )
-  plot_model = Collections('Plot').create()
-  xdr = Collections('DataRange1d').create(
-    sources : [{ref : data_source.ref(), columns : ['x']},
-               {ref : ds2.ref(), columns : ['x2']}]
-  )
-  ydr = Collections('DataRange1d').create(
-    sources : [{ref : data_source.ref(), columns : ['y']},
-               {ref : ds2.ref(), columns: ['y2']}]
-  )
-  glyph_renderer = Collections('GlyphRenderer').create(
-    data_source : data_source.ref()
-    xdata_range : xdr.ref()
-    ydata_range : ydr.ref()
-    glyphs : [
-        type : 'line'
-        line_width: 4
-        line_color: 'red'
-        alpha: 1
-    ]
-  )
-  renderer2 = Collections('GlyphRenderer').create(
-    data_source: ds2.ref()
-    xdata_range : xdr.ref()
-    ydata_range : ydr.ref()
-    glyphs : [
-        type : 'line'
-        x: "x2"
-        y: "y2"
-        line_width: 2
-        line_color: 'blue'
-        alpha: 0.5
-    ]
-  )
-  xaxis = Collections('LinearAxis').create(
-    orientation : 'bottom'
-    parent : plot_model.ref()
-    data_range : xdr.ref()
-  )
-  yaxis = Collections('LinearAxis').create(
-    orientation : 'left',
-    parent : plot_model.ref()
-    data_range : ydr.ref()
-  )
-  plot_model.set(
-    renderers : [glyph_renderer.ref(), renderer2.ref()],
-    axes : [xaxis.ref(), yaxis.ref()]
-  )
-  div = $('

')
-  $('body').append(div)
-  myrender  =  ->
-    view = new plot_model.default_view(model : plot_model)
-    div.append(view.$el)
-    view.render()
-  console.log('Test line_glyph')
-  _.defer(myrender)
-)
-
-test('stacked_lines_glyph', () ->
-  expect(0)
-  data_source = Collections('ObjectArrayDataSource').create(
-    data : [
-      {x: 1, y0: 1, y1: 3}
-      {x: 2, y0: 1.5, y1: 2}
-      {x: 3, y0: 3.5, y1: 0.2}
-      {x: 4, y0: 1.5, y1: 0.75}
-      {x: 5, y0: 2.5, y1: 0.5}
-    ]
-  )
-  plot_model = Collections('Plot').create()
-  xdr = Collections('DataRange1d').create(
-    sources : [{ref : data_source.ref(), columns : ['x']}]
-  )
-  ydr = Collections('DataRange1d').create(
-    sources : [{ref : data_source.ref(), columns : ['y0','y1']}]
-  )
-  glyph_renderer = Collections('GlyphRenderer').create(
-    data_source : data_source.ref()
-    xdata_range : xdr.ref()
-    ydata_range : ydr.ref()
-    glyphs : [
-        type : 'stacked_lines'
-        x: 'x',
-        y: ['y0', 'y1']
-        fills: {
-          y0:
-            fill_color: "red"
-            fill_alpha: 0.5
-          y1:
-            fill_color: "blue"
-            fill_alpha: 0.5
-        }
-        lines: {
-          y0:
-            line_width: 1
-            line_color: "black"
-            line_alpha: 0.8
-          y1:
-            line_width: 1
-            line_color: "black"
-            line_alpha: 0.8
-        }
-    ]
-  )
-  xaxis = Collections('LinearAxis').create(
-    orientation : 'bottom'
-    parent : plot_model.ref()
-    data_range : xdr.ref()
-  )
-  yaxis = Collections('LinearAxis').create(
-    orientation : 'left',
-    parent : plot_model.ref()
-    data_range : ydr.ref()
-  )
-  plot_model.set(
-    renderers : [glyph_renderer.ref()],
-    axes : [xaxis.ref(), yaxis.ref()]
-  )
-  div = $('

')
-  $('body').append(div)
-  myrender  =  ->
-    view = new plot_model.default_view(model : plot_model)
-    div.append(view.$el)
-    view.render()
-  console.log('Test stacked_lines_glyph')
-  _.defer(myrender)
-)
-
-test('stacked_rects_glyph', () ->
-  expect(0)
-  data_source = Collections('ObjectArrayDataSource').create(
-    data : [
-      {x: 1, y0: 1, y1: 3, y2: 1.5}
-      {x: 2, y0: 1.5, y1: 2, y2: 1}
-      {x: 3, y0: 6, y1: 0.1, y2: 0.1}
-      {x: 4, y0: 1.5, y1: 0.75, y2: 1.25}
-      {x: 5, y0: 2.5, y1: 0.5, y2: 1}
-    ]
-  )
-  plot_model = Collections('Plot').create()
-  xdr = Collections('DataRange1d').create(
-    sources : [{ref : data_source.ref(), columns : ['x']}]
-  )
-  ydr = Collections('DataRange1d').create(
-    sources : [{ref : data_source.ref(), columns : ['y0','y1','y2']}]
-  )
-  glyph_renderer = Collections('GlyphRenderer').create(
-    data_source : data_source.ref()
-    xdata_range : xdr.ref()
-    ydata_range : ydr.ref()
-    glyphs : [
-        type : 'stacked_rects'
-        x: 'x',
-        y: ['y0', 'y1', 'y2']
-        fills: {
-          y0:
-            fill_color: "red"
-            fill_alpha: 0.5
-          y1:
-            fill_color: "blue"
-            fill_alpha: 0.5
-          y2:
-            fill_color: "orange"
-            fill_alpha: 0.5
-        }
-        lines: {
-          y0:
-            line_width: 1
-            line_color: "black"
-            line_alpha: 0.8
-          y1:
-            line_width: 1
-            line_color: "black"
-            line_alpha: 0.8
-          y2:
-            line_width: 1
-            line_color: "black"
-            line_alpha: 0.8
-        }
-    ]
-  )
-  xaxis = Collections('LinearAxis').create(
-    orientation : 'bottom'
-    parent : plot_model.ref()
-    data_range : xdr.ref()
-  )
-  yaxis = Collections('LinearAxis').create(
-    orientation : 'left',
-    parent : plot_model.ref()
-    data_range : ydr.ref()
-  )
-  plot_model.set(
-    renderers : [glyph_renderer.ref()],
-    axes : [xaxis.ref(), yaxis.ref()]
-  )
-  div = $('

')
-  $('body').append(div)
-  myrender  =  ->
-    view = new plot_model.default_view(model : plot_model)
-    div.append(view.$el)
-    view.render()
-  console.log('Test stacked_rects_glyph')
-  _.defer(myrender)
-)
-
-test('rects_glyph', () ->
-  expect(0)
-  data_source = Collections('ObjectArrayDataSource').create(
-    data : [
-      {x: 1, y: 2, height: 0.5, width: 0.25}
-      {x: 2, y: 3, height: 0.3, width: 0.3, color: "blue"}
-      {x: 3, y: 4, height: 0.2, width: 0.35, outline_color: "none"}
-      {x: 4, y: 3, height: 0.6, width: 0.4 }
-      {x: 4.5, y: 3, height: 0.3, width: 0.4, angle: 20 }
-      {x: 5, y: 5, height: 0.15, width: 0.4, alpha: 0.4}
-    ]
-  )
-  plot_model = Collections('Plot').create()
-  xdr = Collections('DataRange1d').create(
-    sources : [{ref : data_source.ref(), columns : ['x']}]
-  )
-  ydr = Collections('DataRange1d').create(
-    sources : [{ref : data_source.ref(), columns : ['y']}]
-  )
-  glyph_renderer = Collections('GlyphRenderer').create(
-    data_source : data_source.ref()
-    xdata_range : xdr.ref()
-    ydata_range : ydr.ref()
-    scatter_size : 10
-
-    glyphs : [
-        type : 'rects'
-        x : 'x'
-        color: 'red'
-        outline_color: 'black'
-      ,
-
-        type : 'rects'
-        color: 'gray'
-        x: 'x'
-
-        # Uncommenting the following block will cause all of the
-        # Y values to be set to 2.5
-        #y:
-        #  field: 'bogus'
-        #  default: 2.5
-        #  units: 'data'
-
-        # Uncommenting the following will set a fixed height and width
-        # for every rect.(By specifying the name 'bogus' for the field,
-        # we can be certain that none of the datapoints will override
-        # this height value, and the default will always be used.)
-        height:
-          field: 'bogus'
-          default: 12
-          units: 'screen'
-        width:
-          field: 'bogus'
-          default: 0.25
-          units: 'data'
-    ]
-
-  )
-  xaxis = Collections('LinearAxis').create(
-    orientation : 'bottom'
-    parent : plot_model.ref()
-    data_range : xdr.ref()
-  )
-  yaxis = Collections('LinearAxis').create(
-    orientation : 'left',
-    parent : plot_model.ref()
-    data_range : ydr.ref()
-  )
-  plot_model.set(
-    renderers : [glyph_renderer.ref()],
-    axes : [xaxis.ref(), yaxis.ref()]
-  )
-  div = $('

')
-  $('body').append(div)
-  myrender  =  ->
-    view = new plot_model.default_view(model : plot_model)
-    div.append(view.$el)
-    view.render()
-  console.log('Test rects_glyph')
-  _.defer(myrender)
-)
-
-test('rects_glyph2', () ->
-  expect(0)
-  data_source = Collections('ObjectArrayDataSource').create(
-    data : [
-      {x : 1, y : 2, height: 0.5, width: 0.25}
-      {x : 2, y : 3, height: 0.3, width: 0.3, color: "blue"}
-      {x : 3, y : 4, height: 0.2, width: 0.35, outline_color: "none"}
-      {x : 4, y : 3, height: 0.6, width: 0.4 }
-      {x: 4.5, y: 3, height: 0.3, width: 0.4, angle: 20 }
-      {x : 5, y : 5, height: 0.15, width: 0.4, alpha: 0.4}
-    ]
-  )
-  renderer = Collections('GlyphRenderer').create(
-    data_source : data_source.ref()
-
-    glyphs : [
-        type : 'rects'
-        x : 'x'
-        color: 'blue'
-        outline_color: 'black'
-      ,
-
-        type : 'rects'
-        color: 'gray'
-        x: 'x'
-
-        # Uncommenting the following block will cause all of the
-        # Y values to be set to 2.5
-        #y:
-        #  field: 'bogus'
-        #  default: 2.5
-        #  units: 'data'
-
-        # Uncommenting the following will set a fixed height and width
-        # for every rect.(By specifying the name 'bogus' for the field,
-        # we can be certain that none of the datapoints will override
-        # this height value, and the default will always be used.)
-        height:
-          field: 'bogus'
-          default: 12
-          units: 'screen'
-        width:
-          field: 'bogus'
-          default: 0.25
-          units: 'data'
-    ]
-
-  )
-
-  #glyph_plot(data_source, renderer, $('body'))
-  plot_model = glyph_plot(data_source, renderer)
-  div = $('

')
-  $('body').append(div)
-  myrender = ->
-    div.append("
rects_glyph_2
")
-    view = new plot_model.default_view(model: plot_model)
-    div.append(view.$el)
-    view.render()
-  _.defer(myrender)
-
-)
-
-
-test('rect_regions_glyph_test', () ->
-  expect(0)
-  data_source = Collections('ObjectArrayDataSource').create(
-    data : [
-      {left: 1, right: 1.5, top: 1.5, bottom: 1.0}
-      {left: 2, right: 2.6, top: 2.3, color: "blue"}
-      {left: 3, right: 3.2, top: 3.2, outline_color: "none"}
-      {left: 4, right: 4.2, top: 2.6, bottom: 1.0}
-      {left: 4.8, right: 5.2, top: 2.6, alpha: 0.4}
-    ]
-  )
-  plot_model = Collections('Plot').create()
-  xdr = Collections('DataRange1d').create(
-    sources : [{ref : data_source.ref(), columns : ['left', 'right']}]
-  )
-  ydr = Collections('DataRange1d').create(
-    sources : [{ref : data_source.ref(), columns : ['bottom', 'top']}]
-  )
-  renderer = Collections('GlyphRenderer').create(
-    data_source: data_source.ref()
-    xdata_range: xdr.ref()
-    ydata_range: ydr.ref()
-    glyphs : [
-      type : 'rectregions'
-      left: 'left'
-      right: 'right'
-      bottom:
-        field: 'bogus'
-        default: 1.0
-        units: 'data'
-
-      color: 'red'
-      outline_color: 'black'
-    ]
-  )
-  xaxis = Collections('LinearAxis').create(
-    orientation : 'bottom'
-    parent : plot_model.ref()
-    data_range : xdr.ref()
-  )
-  yaxis = Collections('LinearAxis').create(
-    orientation : 'left',
-    parent : plot_model.ref()
-    data_range : ydr.ref()
-  )
-  plot_model.set(
-    renderers : [renderer.ref()],
-    axes : [xaxis.ref(), yaxis.ref()]
-  )
-
-  div = $('

')
-  $('body').append(div)
-  myrender = ->
-    div.append("
rect_regions_glyph_test
")
-    view = new plot_model.default_view(model: plot_model)
-    div.append(view.$el)
-    view.render()
-  _.defer(myrender)
-)
-
-
-test('vector_data_test', () ->
-  expect(0)
-  data_source = Collections('ColumnDataSource').create(
-    data : {
-      x : [1, 2, 3, 4, 4.5, 5]
-      y : [2, 3, 4, 3, 3, 5]
-      height : [0.5, 0.3, 0.2, 0.6, 0.3, 0.15]
-      width : [0.25, 0.3, 0.35, 0.4, 0.4, 0.4]
-    }
-  )
-  renderer = Collections('GlyphRenderer').create(
-    data_source : data_source.ref()
-
-    glyphs : [
-        type : 'rects'
-        x : 'x'
-        color: 'blue'
-        outline_color: 'black'
-      ,
-
-        type : 'rects'
-        color: 'gray'
-        x: 'x'
-
-        # Uncommenting the following block will cause all of the
-        # Y values to be set to 2.5
-        #y:
-        #  field: 'bogus'
-        #  default: 2.5
-        #  units: 'data'
-
-        # Uncommenting the following will set a fixed height and width
-        # for every rect.(By specifying the name 'bogus' for the field,
-        # we can be certain that none of the datapoints will override
-        # this height value, and the default will always be used.)
-        height:
-          field: 'bogus'
-          default: 12
-          units: 'screen'
-        width:
-          field: 'bogus'
-          default: 0.25
-          units: 'data'
-    ]
-
-  )
-
-  #glyph_plot(data_source, renderer, $('body'))
-  plot_model = glyph_plot(data_source, renderer)
-  div = $('

')
-  $('body').append(div)
-  myrender = ->
-    div.append("
vector_data_test
")
-    view = new plot_model.default_view(model: plot_model)
-    div.append(view.$el)
-    view.render()
-  _.defer(myrender)
-)
-
-test('area_glyph', () ->
-  expect(0)
-  data_source = Collections('ObjectArrayDataSource').create(
-    data : [
-      {x: 1, y: 1}
-      {x: 2, y: 2}
-      {x: 2, y: 3}
-      {x: 1, y: 3}
-      {x: 0.5, y: 2}
-    ]
-  )
-  plot_model = Collections('Plot').create()
-  xdr = Collections('DataRange1d').create(
-    sources : [{ref : data_source.ref(), columns : ['x']}]
-  )
-  ydr = Collections('DataRange1d').create(
-    sources : [{ref : data_source.ref(), columns : ['y']}]
-  )
-  glyph_renderer = Collections('GlyphRenderer').create(
-    data_source : data_source.ref()
-    xdata_range : xdr.ref()
-    ydata_range : ydr.ref()
-    glyphs : [
-        type: 'area'
-        color: 'blue'
-        outline_width: 4
-        outline_color: 'black'
-        alpha: 0.6
-    ]
-  )
-  xaxis = Collections('LinearAxis').create(
-    orientation : 'bottom'
-    parent : plot_model.ref()
-    data_range : xdr.ref()
-  )
-  yaxis = Collections('LinearAxis').create(
-    orientation : 'left',
-    parent : plot_model.ref()
-    data_range : ydr.ref()
-  )
-  plot_model.set(
-    renderers : [glyph_renderer.ref()],
-    axes : [xaxis.ref(), yaxis.ref()]
-  )
-  div = $('

')
-  $('body').append(div)
-  myrender  =  ->
-    view = new plot_model.default_view(model : plot_model)
-    div.append(view.$el)
-    view.render()
-  console.log('Test area_glyph')
-  _.defer(myrender)
-)
-
-
-test('boxplots_test', () ->
-  expect(0)
-  data_source = Collections('ObjectArrayDataSource').create(
-    # style ['plain', 'notched', 'tufte']
-    # x, median, width, q1, q3
-    # fill, upper_fill, lower_fill
-    # center_line_width, center_line_color, center_line_alpha, center_line_dash
-    # outline_width, outline_color, outline_alpha, outline_dash
-    # upper_line_width, upper_line_color, upper_line_alpha, upper_line_dash
-    # lower_line_width, lower_line_color, lower_line_alpha, lower_line_dash
-    # whisker_size, whisker_line_width, whisker_line_alphe
-    # upper_whisker_size, upper_whisker_line_width, upper_whisker_line_alphe
-    # lower_whisker_size, lower_whisker_line_width, lower_whisker_line_alphe
-    # outliers
-    # outliers_glyph, outliers_size, outliers_fill, outliers_outline, outliers_alpha
-    # mean
-    # mean_glyph, mean_size, mean_fill, mean_outline, mean_alpha
-    data : [
-      {x: 1, median: 4.0, size: 0.4, q1: 3.0, q3: 5.2 }
-      {x: 2, median: 4.2, size: 0.6, q1: 3.0, q3: 5.0 }
-      {x: 4, median: 3.7, size: 1.4, q1: 2.9, q3: 4.5 }
-      {x: 6, median: 3.5, size: 0.5, q1: 2.6, q3: 4.1 }
-    ]
-  )
-
-  plot_model = Collections('Plot').create()
-
-  xdr = Collections('Range1d').create()
-  xdr.set('start', 0)
-  xdr.set('end', 7)
-
-  ydr = Collections('Range1d').create()
-  ydr.set('start', -2)
-  ydr.set('end', 10)
-
-  glyph_renderer = Collections('GlyphRenderer').create(
-    data_source : data_source.ref()
-    xdata_range : xdr.ref()
-    ydata_range : ydr.ref()
-    glyphs : [
-        type: 'boxplots'
-    ]
-  )
-  xaxis = Collections('LinearAxis').create(
-    orientation : 'bottom'
-    parent : plot_model.ref()
-    data_range : xdr.ref()
-  )
-  yaxis = Collections('LinearAxis').create(
-    orientation : 'left',
-    parent : plot_model.ref()
-    data_range : ydr.ref()
-  )
-  plot_model.set(
-    renderers : [glyph_renderer.ref()],
-    axes : [xaxis.ref(), yaxis.ref()]
-  )
-  div = $('

')
-  $('body').append(div)
-  myrender  =  ->
-    view = new plot_model.default_view(model : plot_model)
-    div.append(view.$el)
-    view.render()
-  console.log('Test boxplots_glyph')
-  _.defer(myrender)
-
-)
-
-test('lines_test', () ->
-  expect(0)
-  data_source = Collections('ObjectArrayDataSource').create(
-    data : [
-      {
-        xs: [1, 3, 7, 9],
-        ys: [-1, 5, 3, 8],
-        line_width: 0.5, line_color: "red", alpha: 1.0
-      }
-      {
-        xs: [0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5],
-        ys: [9.0, 8.9, 8.8, 8.6, 8.2, 6.6, 2.9, 2.3, 2.2, 2.05, 2.03, 2.02, 2.01, 2.01, 2.01, 2.01, 2.01, 2.0],
-        line_width: 1, line_color: "blue", alpha: 0.6, line_dash: [6]
-      }
-      {
-        xs: [ 0.0       ,   0.1010101 ,   0.2020202 ,   0.3030303 , 0.4040404 ,   0.50505051,   0.60606061,   0.70707071, 0.80808081,   0.90909091,   1.01010101,   1.11111111, 1.21212121,   1.31313131,   1.41414141,   1.51515152, 1.61616162,   1.71717172,   1.81818182,   1.91919192, 2.02020202,   2.12121212,   2.22222222,   2.32323232, 2.42424242,   2.52525253,   2.62626263,   2.72727273, 2.82828283,   2.92929293,   3.03030303,   3.13131313, 3.23232323,   3.33333333,   3.43434343,   3.53535354, 3.63636364,   3.73737374,   3.83838384,   3.93939394, 4.04040404,   4.14141414,   4.24242424,   4.34343434, 4.44444444,   4.54545455,   4.64646465,   4.74747475, 4.84848485,   4.94949495,   5.05050505,   5.15151515, 5.25252525,   5.35353535,   5.45454545,   5.55555556, 5.65656566,   5.75757576,   5.85858586,   5.95959596, 6.06060606,   6.16161616,   6.26262626,   6.36363636, 6.46464646,   6.56565657,   6.66666667,   6.76767677, 6.86868687,   6.96969697,   7.07070707,   7.17171717, 7.27272727,   7.37373737,   7.47474747,   7.57575758, 7.67676768,   7.77777778,   7.87878788,   7.97979798, 8.08080808,   8.18181818,   8.28282828,   8.38383838, 8.48484848,   8.58585859,   8.68686869,   8.78787879, 8.88888889,   8.98989899,   9.09090909,   9.19191919, 9.29292929,   9.39393939,   9.49494949,   9.5959596 , 9.6969697 ,   9.7979798 ,   9.8989899 ,  10.0],
-        ys: [ 1.0       ,   1.02928051,   1.05941838,   1.09043869, 1.1223673 ,   1.15523079,   1.18905654,   1.22387273, 1.25970836,   1.29659327,   1.33455818,   1.37363473, 1.41385547,   1.45525388,   1.49786447,   1.54172271, 1.58686514,   1.63332937,   1.6811541 ,   1.73037915, 1.78104555,   1.83319548,   1.88687238,   1.94212098, 1.99898728,   2.05751866,   2.11776386,   2.17977308, 2.24359796,   2.30929166,   2.37690891,   2.44650603, 2.51814098,   2.59187345,   2.66776483,   2.74587836, 2.82627909,   2.909034  ,   2.99421201,   3.08188408, 3.17212324,   3.26500464,   3.36060565,   3.45900592, 3.56028739,   3.66453444,   3.7718339 ,   3.88227513, 3.99595015,   4.11295363,   4.23338303,   4.35733866, 4.48492378,   4.61624466,   4.75141068,   4.89053443, 5.03373179,   5.18112205,   5.33282797,   5.48897592, 5.64969596,   5.81512197,   5.98539173,   6.16064708, 6.341034  ,   6.52670274,   6.71780796,   6.91450883, 7.11696921,   7.32535774,   7.53984798,   7.76061861, 7.98785352,   8.22174198,   8.46247882,   8.71026456, 8.96530559,   9.22781435,   9.49800951,   9.77611612, 10.06236583,  10.35699708,  10.66025529,  10.97239305, 11.29367037,  11.62435485,  11.96472194,  12.31505516, 12.67564632,  13.04679577,  13.42881266,  13.82201521, 14.22673093,  14.64329694,  15.07206021,  15.5133779, 15.96761759,  16.43515765,  16.91638753,  17.41170806],
-        line_width: 1.5, line_color: "green", alpha: 0.6, line_dash: [8,2]
-      }
-      {
-        xs: [ 0.0       ,   0.1010101 ,   0.2020202 ,   0.3030303 , 0.4040404 ,   0.50505051,   0.60606061,   0.70707071, 0.80808081,   0.90909091,   1.01010101,   1.11111111, 1.21212121,   1.31313131,   1.41414141,   1.51515152, 1.61616162,   1.71717172,   1.81818182,   1.91919192, 2.02020202,   2.12121212,   2.22222222,   2.32323232, 2.42424242,   2.52525253,   2.62626263,   2.72727273, 2.82828283,   2.92929293,   3.03030303,   3.13131313, 3.23232323,   3.33333333,   3.43434343,   3.53535354, 3.63636364,   3.73737374,   3.83838384,   3.93939394, 4.04040404,   4.14141414,   4.24242424,   4.34343434, 4.44444444,   4.54545455,   4.64646465,   4.74747475, 4.84848485,   4.94949495,   5.05050505,   5.15151515, 5.25252525,   5.35353535,   5.45454545,   5.55555556, 5.65656566,   5.75757576,   5.85858586,   5.95959596, 6.06060606,   6.16161616,   6.26262626,   6.36363636, 6.46464646,   6.56565657,   6.66666667,   6.76767677, 6.86868687,   6.96969697,   7.07070707,   7.17171717, 7.27272727,   7.37373737,   7.47474747,   7.57575758, 7.67676768,   7.77777778,   7.87878788,   7.97979798, 8.08080808,   8.18181818,   8.28282828,   8.38383838, 8.48484848,   8.58585859,   8.68686869,   8.78787879, 8.88888889,   8.98989899,   9.09090909,   9.19191919, 9.29292929,   9.39393939,   9.49494949,   9.5959596 , 9.6969697 ,   9.7979798 ,   9.8989899 ,  10.0],
-        ys: [ 0.0       ,  0.10083842,  0.20064886,  0.2984138 ,  0.39313661, 0.48385164,  0.56963411,  0.64960951,  0.72296256,  0.78894546, 0.84688556,  0.8961922 ,  0.93636273,  0.96698762,  0.98775469, 0.99845223,  0.99897117,  0.98930624,  0.96955595,  0.93992165, 0.90070545,  0.85230712,  0.79522006,  0.73002623,  0.65739025, 0.57805259,  0.49282204,  0.40256749,  0.30820902,  0.21070855, 0.11106004,  0.01027934, -0.09060615, -0.19056796, -0.28858706, -0.38366419, -0.47483011, -0.56115544, -0.64176014, -0.7158225 , -0.7825875 , -0.84137452, -0.89158426, -0.93270486, -0.96431712, -0.98609877, -0.99782778, -0.99938456, -0.99075324, -0.97202182, -0.94338126, -0.90512352, -0.85763861, -0.80141062, -0.73701276, -0.66510151, -0.58640998, -0.50174037, -0.41195583, -0.31797166, -0.22074597, -0.12126992, -0.0205576 ,  0.0803643 ,  0.18046693, 0.27872982,  0.37415123,  0.46575841,  0.55261747,  0.63384295, 0.7086068 ,  0.77614685,  0.83577457,  0.8868821 ,  0.92894843, 0.96154471,  0.98433866,  0.99709789,  0.99969234,  0.99209556, 0.97438499,  0.94674118,  0.90944594,  0.86287948,  0.8075165 , 0.74392141,  0.6727425 ,  0.59470541,  0.51060568,  0.42130064, 0.32770071,  0.23076008,  0.13146699,  0.03083368, -0.07011396, -0.17034683, -0.26884313, -0.36459873, -0.45663749, -0.54402111],
-        line_width: 3, line_color: "orange", alpha: 0.4, line_dash: [2,4,4,2]
-      }
-    ]
-  )
-
-  plot_model = Collections('Plot').create()
-
-  xdr = Collections('Range1d').create()
-  xdr.set('start', 0)
-  xdr.set('end', 10)
-
-  ydr = Collections('Range1d').create()
-  ydr.set('start', -2)
-  ydr.set('end', 10)
-
-  glyph_renderer = Collections('GlyphRenderer').create(
-    data_source : data_source.ref()
-    xdata_range : xdr.ref()
-    ydata_range : ydr.ref()
-    glyphs : [
-        type: 'lines'
-        line_dash: []
-    ]
-  )
-  xaxis = Collections('LinearAxis').create(
-    orientation : 'bottom'
-    parent : plot_model.ref()
-    data_range : xdr.ref()
-  )
-  yaxis = Collections('LinearAxis').create(
-    orientation : 'left',
-    parent : plot_model.ref()
-    data_range : ydr.ref()
-  )
-  plot_model.set(
-    renderers : [glyph_renderer.ref()],
-    axes : [xaxis.ref(), yaxis.ref()]
-  )
-  div = $('

')
-  $('body').append(div)
-  myrender  =  ->
-    view = new plot_model.default_view(model : plot_model)
-    div.append(view.$el)
-    view.render()
-  console.log('Test lines_glyph')
-  _.defer(myrender)
-
-)
-
-
-test('areas_glyph', () ->
-  expect(0)
-  data_source = Collections('ObjectArrayDataSource').create(
-    data : [
-      {
-        xs: [1, 3, 5],
-        ys: [1, 3.4, 1],
-        color: "red",
-      }
-      {
-        xs: [6, 4, 6, 8],
-        ys: [2, 4, 6, 4],
-        color: "blue",
-        alpha: 0.3,
-        outline_width: 0.1,
-      }
-      {
-        xs: [6, 6.5, 8.5, 9],
-        ys: [0, 1, 1, 0],
-        color: "green",
-        alpha: 0.6,
-        outline_width: 3,
-      }
-      {
-        xs: [2.0, 1.7, 3.0, 4.3, 4.0],
-        ys: [6.0, 7.4, 8.7, 7.4, 6.0],
-        color: "orange",
-        alpha: 0.8,
-        outline_color: "#df4f4f",
-        outline_dash: [6,2]
-      }
-      {
-        xs: [7,6,7,9,9.5,7.8],
-        ys: [6,7,9,9,8.2,8],
-        color: "#df4f7f"
-        outline_dash: [2]
-      }
-    ]
-  )
-  plot_model = Collections('Plot').create()
-
-  xdr = Collections('Range1d').create()
-  xdr.set('start', 0)
-  xdr.set('end', 10)
-
-  ydr = Collections('Range1d').create()
-  ydr.set('start', -2)
-  ydr.set('end', 10)
-
-  glyph_renderer = Collections('GlyphRenderer').create(
-    data_source : data_source.ref()
-    xdata_range : xdr.ref()
-    ydata_range : ydr.ref()
-    glyphs : [
-        type: 'areas'
-        outline_width: 1
-        outline_color: 'black'
-        outline_dash: []
-        alpha: 0.8
-    ]
-  )
-
-  xaxis = Collections('LinearAxis').create(
-    orientation : 'bottom'
-    parent : plot_model.ref()
-    data_range : xdr.ref()
-  )
-  yaxis = Collections('LinearAxis').create(
-    orientation : 'left',
-    parent : plot_model.ref()
-    data_range : ydr.ref()
-  )
-  plot_model.set(
-    renderers : [glyph_renderer.ref()],
-    axes : [xaxis.ref(), yaxis.ref()]
-  )
-  div = $('

')
-  $('body').append(div)
-  myrender  =  ->
-    view = new plot_model.default_view(model : plot_model)
-    div.append(view.$el)
-    view.render()
-  console.log('Test areas_glyph')
-  _.defer(myrender)
-)
-
-test('rect_glyph_performance', () ->
-  expect(0)
-  x = ( (x/30) for x in _.range(600) )
-  y = (Math.sin(y) for y in x)
-  widths = (0.02 for i in x)
-  heights = (0.2 for i in x)
-  source = Collections('ColumnDataSource').create(
-    data :
-      x : x
-      y : y
-      width : widths
-      height : heights
-  )
-  plot = Collections('Plot').create(height : 400, width:800)
-  xdr = Collections('DataRange1d').create(
-    sources : [{ref : source.ref(), columns : ['x']}]
-  )
-  ydr = Collections('DataRange1d').create(
-    sources : [{ref : source.ref(), columns : ['y']}]
-  )
-  pantool = Collections('PanTool').create(
-     dataranges : [xdr.ref(), ydr.ref()]
-     dimensions : ['width', 'height']
-  )
-  rectglyph = {
-    'color': 'red',
-    'height': 'height',
-    'outline_color': null,
-    'outline_width': null,
-    'type': 'rects',
-    'width': 'width',
-    'x': 'x',
-    'y': 'y'}
-  glyph_renderer = Collections('GlyphRenderer').create(
-    data_source : source.ref()
-    xdata_range : xdr.ref()
-    ydata_range : ydr.ref()
-    glyphs : [rectglyph]
-  )
-  xaxis = Collections('LinearAxis').create(
-    orientation : 'bottom'
-    parent : plot.ref()
-    data_range : xdr.ref()
-  )
-  yaxis = Collections('LinearAxis').create(
-    orientation : 'left'
-    parent : plot.ref()
-    data_range : ydr.ref()
-  )
-  plot.set('renderers', [glyph_renderer.ref()])
-  plot.set('axes', [xaxis.ref(), yaxis.ref()])
-  plot.set('tools', [pantool])
-  myrender  =  ->
-    div = $('

')
-    $('body').append(div)
-    view = new plot.default_view(model : plot)
-    div.append(view.$el)
-    view.render()
-  _.defer(myrender)
-)


fixed defect where the time was being incorrectly calculated

--- src/analytics-router/representative-model.coffee
+++ src/analytics-router/representative-model.coffee
@@ -1,15 +1,14 @@
 _ = require('lodash')
 moment = require('moment')

-secondsReferences = []
+secondsReferences = {}
 model = {}
 onLoopCompletes = []
 maximumTimeInSeconds = Infinity
 startTime = null

-determineSeconds = (loopReference) ->
-  reference = _.find secondsReferences, (reference) -> reference.loopReference == loopReference
-  reference.seconds if (reference)
+determineSeconds = (loopReference) -> secondsReferences[loopReference]
+

 calculateTime = (timeInSeconds) ->
   if !timeInSeconds
@@ -31,14 +30,12 @@
       # seconds elapsed is the first metric sent, so lets notify others of the model at this point
       _.each onLoopCompletes, (onLoopComplete) -> onLoopComplete(model)

-      secondsReferences.push
-        loopReference: point.loopReference
-        seconds: point.value
+      secondsReferences[point.loopReference] = point.value

     model[point.metric] =
       value: point.value
       loopReference: point.loopReference
-      time: calculateTime(determineSeconds(point.loopReference))
+      time: calculateTime(secondsReferences[point.loopReference])
       isStale: ->
         if !model[point.metric] || !model['secondsElapsed']
           return false


Whitespace before links.

Whitespace before links.

--- app/assets/javascripts/autocompleter.js.coffee
+++ app/assets/javascripts/autocompleter.js.coffee
@@ -6,9 +6,9 @@
       callback result
     search_call.fail -> callback([],true)
   replace: (entry)->
-    "[#{entry.nice_name}](/users/#{entry.sha}) "
+    " [#{entry.nice_name}](/users/#{entry.sha}) "
   template: (entry)->
-    "@#{entry.nice_name}"
+    " @#{entry.nice_name}"

 idea_title_strategy =
   match: /(^|\s)#(\w*)$/;
@@ -18,9 +18,9 @@
       callback result
     search_call.fail -> callback([],true)
   replace: (entry)->
-    "[#{entry.title.substring(0,10).replace(" ","_")}](/ideas/#{entry.sha}) "
+    " [#{entry.title.substring(0,10).replace(" ","_")}](/ideas/#{entry.sha}) "
   template: (entry)->
-    "#{entry.title}"
+    " #{entry.title}"

 strategies = [username_strategy, idea_title_strategy ]


charts: lock chart in table view mode. Closes #903

--- app/assets/javascripts/lib/models/chart.coffee
+++ app/assets/javascripts/lib/models/chart.coffee
@@ -164,6 +164,8 @@

   shown_as_table: => @view.display_as_table

+  can_be_shown_as_table: => @view.can_be_shown_as_table()
+
 class @ChartList extends Backbone.Collection
   model : Chart

@@ -188,6 +190,9 @@
   #    to show multiple charts on the same page
   #  - alternate: id of the chart to load if the first one fails. Watch out for
   #    loops!
+  #
+  # TODO: refactor, too much stuff is happening here!
+  #
   load : (chart_id, holder_id = 'main_chart', options = {}) =>
     if @pinned_chart_in(holder_id) || @current_chart_in(holder_id) == chart_id
       return false
@@ -227,16 +232,27 @@
           s.owner = holder_id
           new_chart.series.add(s)

+        # if the chart was pinned as table let's set the instance variable
+        show_as_table = App.settings.get('charts')[holder_id].format == 'table'
+        if show_as_table
+          new_chart.view.display_as_table = true
+
         # Now it's time to upate the buttons and links for the chart
         root = $('#' + holder_id).parents('.chart_holder')
+
         # show/hide default chart button - only for the chart holders that
         # actually define a default chart. The dashboard popups charts don't.
         if container_info = App.settings.get('charts')[holder_id]
           default_chart_for_holder = container_info.default
           root.find("a.default_chart").toggle(chart_id != default_chart_for_holder)
+
         # show/hide format toggle button
-        root.find("a.table_format").toggle( new_chart.view.can_be_shown_as_table() )
-        root.find("a.chart_format").hide()
+        root.find("a.chart_format, a.table_format").hide()
+        if show_as_table && new_chart.can_be_shown_as_table()
+          root.find("a.chart_format").show()
+        if new_chart.can_be_shown_as_table() && !show_as_table
+          root.find("a.table_format").show()
+
         # update chart information link
         root.find(".actions a.chart_info").attr(
           "href", "/descriptions/charts/#{chart_id}")
@@ -282,12 +298,18 @@
   # there are some issues with the event bindings leaving zombies around:
   # http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/
   setup_callbacks: ->
-    # chart selection pop-up
+    # chart selection pop-up. Drops pinned chart for that holder and resets the
+    # chart format
     $(document).on "click", "a.pick_charts", (e) =>
-      chart_holder = $(e.target).parents('a').data('chart_holder')
+      holder_id = $(e.target).parents('a').data('chart_holder')
       chart_id = $(e.target).parents('a').data('chart_id')
-      @remove_pin(chart_holder)
-      @load chart_id, chart_holder
+
+      chart_settings = App.settings.get('charts')
+      chart_settings[holder_id].chart_id = null
+      chart_settings[holder_id].format = null
+      App.settings.save({charts: chart_settings})
+
+      @load chart_id, holder_id
       close_fancybox()

     $(document).on 'click', "a.pin_chart", (e) =>


Trigger title change for electron integration.

--- app/assets/javascripts/app/controllers/_application_controller.coffee
+++ app/assets/javascripts/app/controllers/_application_controller.coffee
@@ -88,7 +88,9 @@
     title = name
     if translate
       title = App.i18n.translatePlain(name)
-    document.title = @Config.get('product_name') + ' - ' + title
+    documentTitle = "#{@Config.get('product_name')} - #{title}"
+    document.title = documentTitle
+    App.Event.trigger('window-title-set', documentTitle)

   copyToClipboard: (text) ->
     if window.clipboardData # IE


match country name with country-list npm package instead of utils for trialRequest (#6468)

--- app/views/core/CreateAccountModal/teacher/SchoolInfoPanel.coco.coffee
+++ app/views/core/CreateAccountModal/teacher/SchoolInfoPanel.coco.coffee
@@ -11,7 +11,7 @@
 SchoolInfoPanel =
   name: 'school-info-panel'
   template: require('templates/core/create-account-modal/school-info-panel')()
-
+
   data: ->
     # TODO: Store ncesData in just the store?
     ncesData = _.zipObject(['nces_'+key, ''] for key in SCHOOL_NCES_KEYS)
@@ -37,7 +37,7 @@

   components:
     'nces-search-input': NcesSearchInput
-
+
   methods:
     updateValue: (name, value) ->
       @[name] = value
@@ -47,11 +47,11 @@
       if name is 'district'
         @clearSchoolNcesValues()
         @clearDistrictNcesValues()
-
+
     clearDistrictNcesValues: ->
       for key in DISTRICT_NCES_KEYS
         @['nces_' + key] = ''
-
+
     clearSchoolNcesValues: ->
       for key in _.difference(SCHOOL_NCES_KEYS, DISTRICT_NCES_KEYS)
         @['nces_' + key] = ''
@@ -67,7 +67,7 @@
       NCES_KEYS = if displayKey is 'name' then SCHOOL_NCES_KEYS else DISTRICT_NCES_KEYS
       for key in NCES_KEYS
         @['nces_'+key] = suggestion[key]
-
+
     onChangeCountry: ->
       if @['country'] == 'United States' && !@usaStatesAbbreviations.includes(@['state'])
         @['state'] = ''
@@ -101,8 +101,10 @@
     if me.showChinaRegistration()
       @country = 'China'
     else
-      if me.get('country') and !!_.find(countries, (c) => c.country is _.string.slugify(me.get('country')))
-        @country = _.string.titleize(_.string.humanize(me.get('country')))
+      userCountry = me.get('country')
+      matchingCountryName = if userCountry then _.find(countryList.getNames(), (c) => c is _.string.slugify(userCountry) or c.toLowerCase() is userCountry.toLowerCase()) else undefined
+      if matchingCountryName
+        @country = matchingCountryName
       else
         @country = 'United States'


fix nullpointer

fix nullpointer

--- atmospheric/002-accumulated-heat/csmain.coffee
+++ atmospheric/002-accumulated-heat/csmain.coffee
@@ -80,13 +80,15 @@
             return if map == null
             tao = planet.period / 30 #SI
             lights = starlight.evolve(au.fromSI_T(tao))
-            data = accumulator.accumulate(tao, time, lights[0], lights[1])
+            heats = accumulator.accumulate(tao, time, lights[0], lights[1])

-            viewer.paint(transformer.target(frame, (time / planet.period)), map, data)
-            counter = (counter + 1) % 30
+            viewer.paint(transformer.target(frame, (time / planet.period)), map, heats)

+            avg = accumulator.avg
+            data = accumulator.data
             $("#msg").html('<ul>' + li(data, avg, 16) + li(data, avg, 48) + li(data, avg, 80) + li(data, avg, 112) + '</ul>')
             time += tao
+            counter = (counter + 1) % 30
         handle = setInterval(evolve, 3333)

        true


fix coordiunate

fix coordiunate

--- atmospheric/002-accumulated-heat/viewer.coffee
+++ atmospheric/002-accumulated-heat/viewer.coffee
@@ -59,7 +59,7 @@
                     height = heights[pos] / 64

                     context.fillStyle = colorGeo(height)
-                    context.fillRect(Math.floor(128 + 250 * x), Math.floor(128 + 250 * y), 5, 5)
+                    context.fillRect(Math.floor(256 + 250 * x), Math.floor(256 + 250 * y), 5, 5)

     lng = (col) -> 2 * Math.PI * col / 128
     lat = (row) -> Math.PI * (0.5 - row / 128)


doesn't import contact without name

doesn't import contact without name

--- server/utils/import_contacts.coffee
+++ server/utils/import_contacts.coffee
@@ -23,34 +23,42 @@

     name = fromGoogle.getName()
     log.debug "looking or #{name}"
-
-    # look for same, take the first one
-    fromCozy = null
-    for cozyContact in cozyContacts
-        if CompareContacts.isSamePerson cozyContact, fromGoogle
-            fromCozy = cozyContact
-            break
-
-    endCb = (err, updatedContact) ->
-        log.debug "updated #{name} err=#{err}"
-        return callback err if err
-        addContactPicture updatedContact, gContact, (err) ->
-            log.debug "picture err #{err}"
-            setTimeout callback, 10
+    if name is ""
         numberProcessed += 1
         realtimer.sendContacts
             number: numberProcessed
             total: total

-    if fromCozy? #  merge
-        log.debug "merging #{name}"
-        toCreate = CompareContacts.mergeContacts fromCozy, fromGoogle
-        toCreate.save endCb
+        callback null
+    else

-    else # create
-        fromGoogle.revision = new Date().toISOString()
-        log.debug "creating #{name}"
-        Contact.create fromGoogle, endCb
+        # look for same, take the first one
+        fromCozy = null
+        for cozyContact in cozyContacts
+            if CompareContacts.isSamePerson cozyContact, fromGoogle
+                fromCozy = cozyContact
+                break
+
+        endCb = (err, updatedContact) ->
+            log.debug "updated #{name} err=#{err}"
+            return callback err if err
+            addContactPicture updatedContact, gContact, (err) ->
+                log.debug "picture err #{err}"
+                setTimeout callback, 10
+            numberProcessed += 1
+            realtimer.sendContacts
+                number: numberProcessed
+                total: total
+
+        if fromCozy? #  merge
+            log.debug "merging #{name}"
+            toCreate = CompareContacts.mergeContacts fromCozy, fromGoogle
+            toCreate.save endCb
+
+        else # create
+            fromGoogle.revision = new Date().toISOString()
+            log.debug "creating #{name}"
+            Contact.create fromGoogle, endCb

 createContact = (gContact, callback) ->
@@ -58,35 +66,39 @@
     toCreate = new Contact Contact.fromGoogleContact gContact

     name = toCreate.getName()
-    log.debug "looking or #{name}"
-    Contact.request 'byName', key: name, (err, contacts) ->
-        if err
-            numberProcessed += 1
-            realtimer.sendContacts
-                number: numberProcessed
-                total: contact
-            log.debug "err #{err}"
-            callback null
-        else if contacts.length is 0
-            toCreate.revision = new Date().toISOString()
-            log.debug "creating #{name}"
-            Contact.create toCreate, (err, created) ->
-                log.debug "created #{name} err=#{err}"
-                return callback err if err
-                addContactPicture created, gContact, (err) ->
-                    log.debug "picture err #{err}"
-                    setTimeout callback, 100
-            numberProcessed += 1
-            realtimer.sendContacts
-                number: numberProcessed
-                total: total
-        else
-            numberProcessed += 1
-            realtimer.sendContacts
-                number: numberProcessed
-                total: total
-            log.debug "existing #{name}"
-            callback null
+    console.log "empty name ?", name
+    if name is ""
+        callback null
+    else
+        log.debug "looking for #{name}"
+        Contact.request 'byName', key: name, (err, contacts) ->
+            if err
+                numberProcessed += 1
+                realtimer.sendContacts
+                    number: numberProcessed
+                    total: contact
+                log.debug "err #{err}"
+                callback null
+            else if contacts.length is 0
+                toCreate.revision = new Date().toISOString()
+                log.debug "creating #{name}"
+                Contact.create toCreate, (err, created) ->
+                    log.debug "created #{name} err=#{err}"
+                    return callback err if err
+                    addContactPicture created, gContact, (err) ->
+                        log.debug "picture err #{err}"
+                        setTimeout callback, 100
+                numberProcessed += 1
+                realtimer.sendContacts
+                    number: numberProcessed
+                    total: total
+            else
+                numberProcessed += 1
+                realtimer.sendContacts
+                    number: numberProcessed
+                    total: total
+                log.debug "existing #{name}"
+                callback null

 PICTUREREL = "http://schemas.google.com/contacts/2008/rel#photo"
 addContactPicture = (cozyContact, gContact, done) ->


coach needs promise polyfill for IE

coach needs promise polyfill for IE

--- shared/src/helpers/polyfills.coffee
+++ shared/src/helpers/polyfills.coffee
@@ -1,2 +1,3 @@
 # adds Object.assign to browsers that lack it (IE)
 require('es6-object-assign').polyfill()
+require('es6-promise').polyfill()


feat(snippets): add SO, P2T, DubShow, A2T2, A2P_MQSA, A2P_SQMA

--- snippets/language-coursescript.cson
+++ snippets/language-coursescript.cson
@@ -13,7 +13,7 @@
     'body': """
       [TYPE HW]
       ID: $1
-      TEXT: $2
+      Text: $2
     """
   'T2P':
     'prefix': 't2p'
@@ -552,4 +552,85 @@
         pos: $3
       \"""
       """
-
+  'SO':
+    'prefix': 'so'
+    'body': """
+      [TYPE SO$1]
+      ID: $2
+      Pic: $3
+      Audio: $4
+      TR: $5
+    """
+  'P2T':
+    'prefix': 'p2t'
+    'body': """
+      [TYPE P2T]
+      ID: $1
+      Pic: $2
+      Opts:
+      Text(checked=true): $3
+      Text: $4
+    """
+  'DubShow':
+    'prefix':'dubshow'
+    'body':"""
+      [TYPE DubShow]
+      ID: $1
+      Video: $2
+      VideoClip: $3
+      VideoClip: $4
+      VideoClip: $5
+      Audio: $6
+      Audio(isBGM=true): $7
+    """
+  'A2T2':
+    'prefix': 'a2t2'
+    'body': """
+      [TYPE A2T2]
+      ID: $1
+      Audio: $2
+      Pic: $3
+      Opts:
+        Text: $4
+        Text(checked=true): $5
+        Text: $6
+        Text: $7
+      TR: $8
+    """
+  'A2P_MQSA':
+    'prefix': 'mqsa'
+    'body': """
+      [TYPE A2P_MQSA]
+      ID: $1
+      Opts:
+      Mix:
+        Pic: $2
+        Audio: $3
+        Text: $4
+      Scene:
+        Pic: $5
+        coordinate: x=$6,y=$7,w=$8,h=$9
+      QuestionPart:
+        Pic: $10
+        Audio: $11
+    """
+  'A2P_SQMA':
+    'prefix': 'sqma'
+    'body': """
+      [TYPE A2P_SQMA]
+      ID: $1
+      Audio: $2
+      Opts:
+      Mix:
+        Pic(checked=true): $3
+        Audio: $4
+        Text: $5
+      Mix:
+        Pic: $6
+        Audio: $7
+        Text: $8
+      Scene:
+        Pic: $9
+        coordinate: x=$10,y=$11,w=$12,h=$13
+        coordinate: x=$14,y=$15,w=$16,h=$17
+    """


fix inappropriate input regression

fix inappropriate input regression

--- source/renderer/views/editor.coffee
+++ source/renderer/views/editor.coffee
@@ -98,12 +98,15 @@
       if pathIsDuplicate
         @renderDuplicate()
         @messageEls.$message.addClass "editor--message-error"
+        @messageEls.$nameInput.hide()
       else if pathHasInvalidExtension
         @renderInvalidExtension()
         @messageEls.$message.addClass "editor--message-error"
+        @messageEls.$nameInput.hide()
       else
         @renderDropPrompt()
         @messageEls.$message.addClass "editor--message-action"
+        @messageEls.$nameInput.show()
         @newLibraryPath = libraryPath

       @messageEls.$message.removeClass "hidden"


Add spec on content size.

Add spec on content size.

--- spec/api-browser-window-spec.coffee
+++ spec/api-browser-window-spec.coffee
@@ -11,7 +11,7 @@
   w = null
   beforeEach ->
     w.destroy() if w?
-    w = new BrowserWindow(show: false)
+    w = new BrowserWindow(show: false, width: 400, height: 400)
   afterEach ->
     w.destroy() if w?
     w = null
@@ -68,6 +68,44 @@
         assert.equal image.constructor.name, 'Buffer'
         done()

+  describe 'BrowserWindow.setSize(width, height)', ->
+    it 'sets the window size', ->
+      # No way to reliably set size when window has not been shown on Linux.
+      return if process.platform is 'linux'
+
+      size = [400, 400]
+      w.setSize size[0], size[1]
+      after = w.getSize()
+      assert.equal after[0], size[0]
+      assert.equal after[1], size[1]
+
+  describe 'BrowserWindow.setContentSize(width, height)', ->
+    it 'sets the content size', ->
+      # No way to reliably set size when window has not been shown on Linux.
+      return if process.platform is 'linux'
+
+      size = [400, 400]
+      w.setContentSize size[0], size[1]
+      after = w.getContentSize()
+      assert.equal after[0], size[0]
+      assert.equal after[1], size[1]
+
+  describe '"use-content-size" option', ->
+    it 'make window created with content size when used', ->
+      w.destroy()
+      w = new BrowserWindow(show: false, width: 400, height: 400, 'use-content-size': true)
+      contentSize = w.getContentSize()
+      assert.equal contentSize[0], 400
+      assert.equal contentSize[1], 400
+
+    it 'make window created with window size when not used', ->
+      # No way to reliably set size when window has not been shown on Linux.
+      return if process.platform is 'linux'
+
+      contentSize = w.getSize()
+      assert.equal contentSize[0], 400
+      assert.equal contentSize[1], 400
+
   describe 'beforeunload handler', ->
     it 'returning true would not prevent close', (done) ->
       w.on 'closed', ->


Avoid ensure_comprehensions warning in coffeelint

--- spec/chinese-translator-spec.coffee
+++ spec/chinese-translator-spec.coffee
@@ -3,8 +3,8 @@

   hasCommand = (element, name) ->
     commands = atom.commands.findCommands(target: element)
-    found = true for command in commands when command.name is name
-    found
+    for command in commands when command.name is name
+      return true

   translate = (command, callback) ->
     atom.commands.dispatch(editorView, "chinese-translator:#{command}")


params are missing

params are missing

--- src/backbone.websql.deferred.coffee
+++ src/backbone.websql.deferred.coffee
@@ -82,6 +82,7 @@
       @_executeSql "INSERT #{orReplace} INTO `#{@tableName}`(#{colNames.join(",")}) VALUES (#{placeholders.join(",")});", params

     find: (model, doneCallback, failCallback, options) ->
+      params = []
       sql = "SELECT `id`, `value` FROM `#{@tableName}`"
       if options.where
         if typeof options.where is "string"


Fix for newly added feature

Fix for newly added feature

--- src/coffeemake.coffee
+++ src/coffeemake.coffee
@@ -142,7 +142,7 @@
           rule = (compile x for x in rule)
           ->
             x.call @ for x in rule
-        expandVars = (x)->
+        expandVars = (x)=>
           y = [ ]
           for z in x
             if (match = /^[$][(]([^)]*)[)]$/.exec z)?


Add comment particle color

Add comment particle color

--- app/scripts/app.coffee
+++ app/scripts/app.coffee
@@ -33,6 +33,7 @@
     "string.attribute-value.xml": [249, 255, 0]
     "string.unquoted.attribute-value.html": [249, 255, 0]
     "entity.other.attribute-name.xml": [129, 148, 244]
+    "comment.xml": [0, 255, 121]

   EXCLAMATION_EVERY: 10
   EXCLAMATIONS: ["Super!", "Radical!", "Fantastic!", "Great!", "OMG",


Moved to BS3.

Moved to BS3.

--- app/assets/javascripts/app/controllers/_application_controller.js.coffee
+++ app/assets/javascripts/app/controllers/_application_controller.js.coffee
@@ -191,7 +191,7 @@
       if diff > 0
         escalated = '-'
       if diff >= 0
-        style = "class=\"label label-important\""
+        style = "class=\"label label-danger\""
       else if diff > -60 * 60
         style = "class=\"label label-warning\""
       else


KnowledgeRule apply and reset views use Loading component


Fix deprecation warning for #243.

Fix deprecation warning for #243.

--- src/connection.coffee
+++ src/connection.coffee
@@ -648,7 +648,7 @@
       payload.toString '  '

   initiateTlsSslHandshake: ->
-    credentials = crypto.createCredentials(@config.options.cryptoCredentialsDetails)
+    credentials = tls.createSecureContext(@config.options.cryptoCredentialsDetails)
     @securePair = tls.createSecurePair(credentials)

     @securePair.on('secure', =>


Fade out cursor

Fade out cursor

--- src/controller.coffee
+++ src/controller.coffee
@@ -2299,7 +2299,8 @@

         if count < ANIMATION_FRAME_RATE
           @paletteWrapper.style.opacity =
-            @mainCanvas.style.opacity = Math.max 0, 1 - 2 * (count / ANIMATION_FRAME_RATE)
+            @mainCanvas.style.opacity =
+            @highlightCanvas.style.opacity = Math.max 0, 1 - 2 * (count / ANIMATION_FRAME_RATE)

         else
           for element in translatingElements
@@ -2424,7 +2425,8 @@
         @iceElement.appendChild div

       @paletteWrapper.style.opacity =
-        @mainCanvas.style.opacity = 0
+        @mainCanvas.style.opacity =
+        @highlightCanvas.style.opacity = 0

       tick = (count) =>
         if count < ANIMATION_FRAME_RATE * 2
@@ -2442,7 +2444,8 @@

         else
           @paletteWrapper.style.opacity =
-            @mainCanvas.style.opacity = Math.max 0, 1 - 2 * (2 - count / ANIMATION_FRAME_RATE)
+            @mainCanvas.style.opacity =
+            @highlightCanvas.style.opacity = Math.max 0, 1 - 2 * (2 - count / ANIMATION_FRAME_RATE)

         if count is ANIMATION_FRAME_RATE * 2
           @currentlyAnimating = false


Fix gutter scrolling.

Fix gutter scrolling.

--- src/controller.coffee
+++ src/controller.coffee
@@ -4251,8 +4251,8 @@
     lineDiv.className = 'droplet-gutter-line'
     if @gutterDecorations[line]
       lineDiv.className += ' ' + @gutterDecorations[line].join(' ')
-    lineDiv.style.top = "#{treeView.bounds[line].y}px"
-    lineDiv.style.paddingTop = "#{treeView.distanceToBase[line].above - @view.opts.textHeight - @fontAscent - @scrollOffsets.main.y}px"
+    lineDiv.style.top = "#{treeView.bounds[line].y - @scrollOffsets.main.y}px"
+    lineDiv.style.paddingTop = "#{treeView.distanceToBase[line].above - @view.opts.textHeight - @fontAscent}px"
     lineDiv.style.height =  treeView.bounds[line].height + 'px'
     lineDiv.style.fontSize = @fontSize + 'px'


Non-chrome env support

Non-chrome env support

--- src/controller.coffee
+++ src/controller.coffee
@@ -18,7 +18,7 @@
     The AppWindow instance
   @readonly
   ###
-  @property("appWindow", get: -> chrome.app.window.current())
+  @property("appWindow", get: -> chrome?.app.window?.current())

   ###*
   @property {Window} window


Much better naming

Much better naming

--- components/buttons/KDButtonView.coffee
+++ components/buttons/KDButtonView.coffee
@@ -21,7 +21,7 @@
     @setCallback options.callback
     @setTitle options.title
     @setIconClass options.iconClass if options.iconClass
-    @unhideIcon()                   if options.icon
+    @showIcon()                     if options.icon
     @setIconOnly options.iconOnly   if options.iconOnly
     @disable()                      if options.disabled

@@ -47,7 +47,7 @@

   getCallback:()-> @buttonCallback

-  unhideIcon:()->
+  showIcon:()->
     @setClass "with-icon"
     @$('span.icon').removeClass 'hidden'


OnOffSwitch: new switch WIP

OnOffSwitch: new switch WIP

--- components/inputs/KDOnOffSwitch.coffee
+++ components/inputs/KDOnOffSwitch.coffee
@@ -1,14 +1,10 @@
-#####
-# On Off Switch Class (Old KDRySwitch)
-#####
-
 class KDOnOffSwitch extends KDInputView
   constructor:(options = {}, data)->

     options.type           = "switch"
     options.title        or= ""
     options.size         or= "small"        # a String tiny/small/big
-    options.labels       or= ["ON", "OFF"]
+    options.labels       or= ["ON"  , "OFF"]
     options.defaultValue  ?= off
     super options, data

@@ -19,7 +15,7 @@

   setDomElement:(cssClass)->
     {title, labels, name} = @getOptions()
-    title       = "#{title}" if title
+    title       = "#{title}" if title isnt ''
     @inputName  = name
     @domElement = $ """

@@ -74,3 +70,23 @@
     options.attributes ?= {}
     options.attributes.checked ?= options.defaultValue or no
     super options, data
+
+class KodingSwitch extends KDOnOffSwitch
+
+
+  constructor:(options = {}, data)->
+
+    options.labels       or= ['', '']
+    options.defaultValue  ?= off
+
+    super options, data
+
+
+  setDomElement:(cssClass)->
+
+    {name} = @getOptions()
+    @domElement = $ """
+

+
+

+      """


build a basic event system

build a basic event system

--- src/init/pre.coffee
+++ src/init/pre.coffee
@@ -3,6 +3,14 @@
 @R = {}

 R.component = (name, data) ->
+  data.trigger = ->
+    I.trigger @, arguments...
+    undefined
+
+  data.dispatch = ->
+    I.dispatch @, arguments...
+    undefined
+
   data.displayName = "R.#{name}"
   cl = React.createClass(data)
   R[name] = React.createFactory(cl)
@@ -17,5 +25,27 @@
 I.start = ->
   React.render (R.LoginPage {}), document.body

-

+I.dispatch = (c, table) ->
+  node = c.getDOMNode()
+  console.log node
+
+  wrapped = for own key, fn of table
+    do (key, fn) ->
+      [key, (event) -> fn event.detail, event]
+
+  for [key, fn] in wrapped
+    node.addEventListener key, fn, false
+
+  detach = ->
+    for [key, fn] in wrapped
+      node.removeEventListener key, fn, false
+
+  detach
+
+I.trigger = (c, name, data) ->
+  c.getDOMNode().dispatchEvent new CustomEvent name, {
+    bubbles: true
+    detail: data
+  }
+


Guard against there being no load handler.

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -91,7 +91,7 @@
     @values = response.values if response.values?
     @values[response.key] = response.value if response.key? and response.value?
     @isLoaded = true
-    listener() while listener = @eventListeners["load"].pop()
+    listener() while listener = @eventListeners.load?.pop()

   addEventListener: (eventName, callback) ->
     (@eventListeners[eventName] ||= []).push callback


added extension box, domain extensions will be selected from selectbox from now on

--- client/app/Applications/Environments.kdapplication/views/domains/domaincreationform.coffee
+++ client/app/Applications/Environments.kdapplication/views/domains/domaincreationform.coffee
@@ -1,11 +1,5 @@
 class DomainCreationForm extends KDTabViewWithForms
-#  domainNameValidation =
-#    rules      :
-#      required : yes
-#      regExp   : /^([\da-z\.-]+)\.([a-z\.]{2,6})$/i
-#    messages   :
-#      required : "Enter your domain name"
-#      regExp   : "This doesn't look like a valid domain name."
+
   domainOptions = [
       { title : "Create a subdomain", value : "subdomain" }
       { title : "I want to register a domain", value : "new" }
@@ -35,7 +29,7 @@
                 @registerDomain()
             createButton              :
               title                   : "Add Domain"
-              style                   : "cupid-green hidden"
+              style                   : "cupid-green"
               type                    : "submit"
               loader                  :
                 color                 : "#ffffff"
@@ -75,14 +69,16 @@
               defaultValue            : "subdomain"
               radios                  : domainOptions
               change                  : =>
-                {DomainOption, domainName, domains, regYears} = @forms["Domain Address"].inputs
+                {DomainOption, domainName, domains, regYears, extensionSelect} = @forms["Domain Address"].inputs
                 {checkButton, registerButton} = @forms["Domain Address"].buttons
                 actionState = DomainOption.getValue()
+                domainName.setValue ''
                 domainName.getElement().setAttribute 'placeholder', switch actionState
                   when "new"
                     @suggestionBox?.show()
                     # domainName.setValidation domainNameValidation
                     domains.hide()
+                    extensionSelect.show()
                     regYears.show()
                     createButton.hide()
                     checkButton.show()
@@ -92,6 +88,7 @@
                     @suggestionBox?.hide()
                     # domainName.setValidation domainNameValidation
                     domains.hide()
+                    extensionSelect.hide()
                     regYears.hide()
                     checkButton.hide()
                     registerButton.hide()
@@ -100,6 +97,7 @@
                   when "subdomain"
                     # domainName.unsetValidation()
                     @suggestionBox?.hide()
+                    extensionSelect.hide()
                     domains.show()
                     regYears.hide()
                     checkButton.hide()
@@ -136,6 +134,14 @@
                       required        : yes
                     messages          :
                       required        : "Please select a parent domain."
+                extensionSelect       :
+                  cssClass            : "domains hidden"
+                  itemClass           : KDSelectBox
+                  validate            :
+                    rules             :
+                      required        : yes
+                    messages          :
+                      required        : "Please select an extension"
             suggestionBox             :
               type                    : "hidden"
     form = @forms["Domain Address"]
@@ -151,17 +157,22 @@
       for domain in userDomains
         if not domain.regYears > 0
           domainList.push {title:".#{domain.domain}", value:domain.domain}
-      @forms["Domain Address"].inputs.domains.setSelectOptions domainList
+      {domains, extensionSelect} = @forms["Domain Address"].inputs
+      domains.setSelectOptions domainList
+      availableTldList = ["com", "net", "org"]
+      extensionsList = ({title:'.'+ext, value:ext} for ext in availableTldList)
+      extensionSelect.setSelectOptions extensionsList
+      extensionSelect.setDefaultValue availableTldList[0]

   checkAvailability: ->
     form = @forms["Domain Address"]
-    domainInput       = domainName
-    domainName        = form.inputs.domainName.getValue()
-    splittedDomain    = domainName.match(/([\w\-]+)\.(.*)/)
-    domain            = splittedDomain[1]
-    tld               = splittedDomain[2]
-
+    domain            = form.inputs.domainName.getValue()
+    tld               = form.inputs.extensionSelect.getValue()
     {createButton, checkButton, registerButton} = form.buttons
+    unless domain.match(/^\w+$/)
+      notifyUser "Please select the extension from the select box"
+      checkButton.hideLoader()
+      return
     @clearSuggestions()
     KD.remote.api.JDomain.getTldPrice tld, (tldPrice) =>
       KD.remote.api.JDomain.isDomainAvailable domain, tld, (avErr, status, price, suggestions) =>
@@ -194,13 +205,14 @@
     {createButton, registerButton} = form.buttons
     @clearSuggestions()

-    {DomainOption, domainName, regYears, domains} = form.inputs
+    {DomainOption, domainName, regYears, domains, extensionSelect} = form.inputs
     domainInput       = domainName
-    domainName        = form.inputs.domainName.getValue()
-    splittedDomain    = domainName.match(/([\w\-]+)\.(.*)/)
-    domain            = splittedDomain[1]
-    tld               = splittedDomain[2]
-
+    domain            = domainName.getValue()
+    tld               = extensionSelect.getValue()
+    unless domain.match(/^\w+$/)
+      notifyUser "Please select the extension from the select box"
+      registerButton.hideLoader()
+      return
     domainOptionValue = DomainOption.getValue()

     if domainOptionValue is 'new'
@@ -233,7 +245,7 @@

     else if domainOptionValue is 'existing'
-      @createDomain {domainName, regYears:0, domainType:'existing'}, (err, domain)=>
+      @createDomain {domain, regYears:0, domainType:'existing'}, (err, domain)=>
         createButton.hideLoader()
         if err
           warn err
@@ -246,12 +258,12 @@

     else # create a subdomain
       subDomainPattern = /^([a-z0-9]([_\-](?![_\-])|[a-z0-9]){0,60}[a-z0-9]|[a-z0-9])$/
-      unless subDomainPattern.test domainName
+      unless subDomainPattern.test domain
         createButton.hideLoader()
         return notifyUser "#{domainName} is an invalid subdomain."
-      domainName = "#{domainName}.#{domains.getValue()}"
-
-      @createDomain {domainName, regYears:0, domainType:'subdomain'}, (err, domain)=>
+      domain = "#{domainName}.#{domains.getValue()}"
+
+      @createDomain {domain, regYears:0, domainType:'subdomain'}, (err, domain)=>
         createButton.hideLoader()
         if err
           warn err
@@ -285,7 +297,7 @@
     {domainName}    = form.inputs
     {suggestionBox} = form.fields
     if not available
-      partial         = "
This domain is already registered. #{'You may click and try one below.' ? suggestions.length > 0 : ''}
"
+      partial         = "
This domain is already registered. #{if suggestions.length > 0 then 'You may click and try one below.' else ''}
"
     else
       partial         = "
Domain price is: #{price}$
"

@@ -302,7 +314,7 @@
   showSuccess:(domain) ->
     @clearSuggestions()
     form            = @forms["Domain Address"]
-    {domainName}    = form.inputs
+    {domainName, extensionSelect}    = form.inputs
     {suggestionBox} = form.fields
     {close, createButton, cancel, another} = form.buttons

@@ -321,7 +333,7 @@
       # partial : "Thank you!
Your domain #{domainName.getValue()} has been added to our database. Please go to your provider's website and add a CNAME record mapping to kontrol.in.koding.com."

       # change this part when registering is there.
-      partial : "Thank you!
Your subdomain #{domainName.getValue()} has been added to our database. You can dismiss this panel and point your new domain to one of your VMs on the settings screen."
+      partial : "Thank you!
Your subdomain #{domainName.getValue()}.#{extensionSelect.getValue()} has been added to our database. You can dismiss this panel and point your new domain to one of your VMs on the settings screen."
       click   : => @reset()


WTF RangerError. Where/² Fix?

WTF RangerError. Where/² Fix?

--- src/core/karma.coffee
+++ src/core/karma.coffee
@@ -284,7 +284,7 @@
 			$set: {
 				updated_at: Date.now()
 				'items.$.updated_at': Date.now()
-				'items.$.object': item.object # Update object, just in case
+				'items.$.object': JSON.stringify(item.object) # Update object, just in case
 			}
 			$inc: { 'items.$.multiplier': 1 }
 			$push: { 'items.$.instances': item.instances[0] }


chore(e2e): add refresh() to pageHelper

chore(e2e): add refresh() to pageHelper

--- vue/tests/e2e/helpers/pageHelper.coffee
+++ vue/tests/e2e/helpers/pageHelper.coffee
@@ -1,4 +1,7 @@
 module.exports = (test) ->
+  refresh: ->
+    test.refresh()
+
   loadPath: (path, opts = {}) ->
     test.url "http://localhost:8080/dev/#{opts.controller || 'nightwatch'}/#{path}?vue=1"


vm/buildlogs: minor copy update

vm/buildlogs: minor copy update

--- client/home/lib/virtualmachines/components/machineslist/machinedetails.coffee
+++ client/home/lib/virtualmachines/components/machineslist/machinedetails.coffee
@@ -8,7 +8,7 @@
 SharingAutocomplete = require './sharing/autocomplete'
 SharingUserList     = require './sharing/userlist'
 ContentModal        = require 'app/components/contentModal'
-HomeBuildLogs = require 'home/buildlogs'
+
 module.exports = class MachineDetails extends React.Component

   @propTypes =
@@ -174,7 +174,7 @@
     state = machine.getIn ['status', 'state']
     isMachineRunning = state is 'Running'

-    description = 'Logs we have created while you build your VM.'
+    description = 'Logs that were created while we built your VM.'

     description = 'Turn on your VM to see the build logs.' unless isMachineRunning

@@ -193,6 +193,7 @@

     machineUid = @props.machine.get 'uid'
     kd.singletons.router.handleRoute "/Home/build-logs/#{machineUid}"
+

   render: ->


Revert "Comments."

Revert "Comments."

This reverts commit 62bc8dc073f1bce3a971d4076500ed9b8ee1f1ec.


doesn't handle empty error message...

doesn't handle empty error message...

--- src/coffee/services/validation.coffee
+++ src/coffee/services/validation.coffee
@@ -37,7 +37,8 @@
             vl = validators.get(rule.validator)
             if vl and vl.validator?
               if !vl.validator(fieldName, values, rule)
-                return setError(fieldName, rule.options.message)
+                if rule.options? then return setError(fieldName, rule.options.message)
+                else return setError(fieldName)
         return removeError(fieldName)

       validateFields = (fieldList, values) ->


Fix %NA display in column list

Fix %NA display in column list

--- src/ext/components/model-input.coffee
+++ src/ext/components/model-input.coffee
@@ -228,7 +228,7 @@
       if responseColumnParameter or ignoredColumnsParameter
         act trainingFrameParameter.value, (frameKey) ->
           if frameKey
-            _.requestFrame frameKey, (error, frame) ->
+            _.requestFrameSummary frameKey, (error, frame) ->
               unless error
                 columnValues = map frame.columns, (column) -> column.label
                 columnLabels = map frame.columns, (column) ->


Fix reference bug

Fix reference bug

--- components/Client.coffee
+++ components/Client.coffee
@@ -2,8 +2,8 @@
 pg = require("pg")
 noflo = require("noflo")

-# Pool all queries through a single connection
-client = null
+# Pool all queries through a single connection for each database
+client = {}

 class Client extends noflo.Component

@@ -22,49 +22,48 @@
       error: new noflo.Port()

     # Close connection on application exit, SIGINT, and SIGTERM
-    endServer = _.bind(@endServer, this)
-    process.on("exit", endServer)
-    process.on("SIGINT", endServer)
-    process.on("SIGTERM", endServer)
-    process.on("SIGHUP", endServer)
-
-    @inPorts.quit.on "disconnect", =>
-      @endServer()
+    endServer = _.bind @endServer, this
+    process.on "exit", endServer
+    process.on "SIGINT", endServer
+    process.on "SIGTERM", endServer
+    process.on "SIGHUP", endServer

     @inPorts.token.on "data", (@token) =>

-    @inPorts.server.on "data", (url) =>
-      @startServer url
+    @inPorts.server.on "data", (@url) =>
+      @startServer @url
+    @inPorts.quit.on "data", (@url) =>
+      @endServer @url

     @inPorts.in.on "connect", =>
       @sqls = []

     @inPorts.in.on "data", (data) =>
-      @sqls.push(data)
+      @sqls.push data

     @inPorts.in.on "disconnect", =>
       token = @token
       query = _.flatten(@sqls).join(";\n")

-      unless client?
+      unless client[@url]?
         throw new Error "Server connection has not yet been established"
       unless token?
         throw new Error "Missing token for return connection"
       unless query?
         throw new Error "Missing query to execute"

-      result = client.query query
+      result = client[@url].query query

       # Send row forward
       result.on "row", (row, result) =>
-        result.addRow(row)
+        result.addRow row

       # Send to error port
       result.on "error", (e) =>
         unless @outPorts.error.isAttached()
           throw new Error "No error port attached"

-        @outPorts.error.send(e)
+        @outPorts.error.send e
         @outPorts.error.disconnect()

       result.on "end", (result) =>
@@ -74,11 +73,11 @@
         @outPorts.out.disconnect()

   startServer: (url) ->
-    @endServer()
-    client = new pg.Client(url)
-    client.connect()
+    @endServer url
+    client[url] = new pg.Client url
+    client[url].connect()

-  endServer: ->
-    client?.end()
+  endServer: (url) ->
+    client[url]?.end()

 exports.getComponent = -> new Client


chore: add terminal-fusion colors

chore: add terminal-fusion colors

--- atom/config.cson
+++ atom/config.cson
@@ -67,7 +67,6 @@
       "graphviz-preview"
       "ide-flow"
       "linter-shellcheck"
-      "emmet"
       "git-diff-details"
       "tablr"
       "multi-wrap-guide"
@@ -209,6 +208,42 @@
     showIcons: true
     usePreviewTabs: true
   term3: {}
+  "terminal-fusion":
+    ansiColors:
+      normal:
+        black: "#212121"
+        blue: "#81a2be"
+        cyan: "#8abeb7"
+        green: "#b5bd68"
+        magenta: "#b294bb"
+        red: "#cc6666"
+        white: "#ededed"
+        yellow: "#f0c674"
+      zBright:
+        brightBlack: "#343d46"
+        brightBlue: "#81a2be"
+        brightCyan: "#8abeb7"
+        brightGreen: "#b5bd68"
+        brightMagenta: "#b294bb"
+        brightRed: "#cc6666"
+        brightWhite: "#ededed"
+        brightYellow: "#f0c674"
+    iconColors:
+      blue: "#81a2be"
+      cyan: "#8abeb7"
+      green: "#b5bd68"
+      magenta: "#f351f3"
+      pink: "#ea9bc2"
+      purple: "#b294bb"
+      red: "#cc6666"
+      yellow: "#f0c674"
+    style:
+      defaultPanelHeight: "200px"
+      fontFamily: "Fantasque Sans Mono"
+      fontSize: "14"
+      theme: "dracula"
+    toggles:
+      autoClose: true
   "test-status":
     autorun: false
   "theme-switcher":


atom: Update config.cson

atom: Update config.cson

- Disable audio beep
- Enable incompatible-packages to rebuild package if needed
- Hide ignored files in tree-view

--- atom/config.cson
+++ atom/config.cson
@@ -2,13 +2,13 @@
   "bracket-matcher":
     highlightMatchingLineNumber: true
   core:
+    audioBeep: false
     disabledPackages: [
       "background-tips"
       "dalek"
       "deprecation-cop"
       "dev-live-reload"
       "exception-reporting"
-      "incompatible-packages"
       "metrics"
       "package-generator"
       "styleguide"
@@ -42,5 +42,7 @@
     ]
   tabs:
     enableVcsColoring: true
+  "tree-view":
+    hideIgnoredNames: true
   whitespace:
     ignoreWhitespaceOnCurrentLine: false


Use getConfigDirPath() instead of configDirPath

--- atom/init.coffee
+++ atom/init.coffee
@@ -10,7 +10,7 @@
 LOCAL_PKG_DIR_PATH = atom.packages.getPackageDirPaths()[0]
 # Path to the remote package list used for comparison when syncing
 REMOTE_PKG_LIST_PATH = fs.readlinkSync(
-  path.join(atom.configDirPath, 'packages.txt'))
+  path.join(atom.getConfigDirPath(), 'packages.txt'))
 # Limit the rate of sync pushes to one second
 PKG_SYNC_DELAY = 1000
 # The name used for Python virtualenv directories
@@ -40,7 +40,7 @@

 # Retrieves the list of all user-installed local packages
 getLocalPkgList = ->
-  pkgList = fs.readdirSync LOCAL_PKG_DIR_PATH
+  pkgList = fs.readdirSync(LOCAL_PKG_DIR_PATH)
   return pkgList.filter (pkg) -> pkg.indexOf('.') is -1

@@ -138,5 +138,6 @@
 process.env.PYTHONIOENCODING = 'utf_8'
 # Prevent Python from generating bytecode (.pyc, .pyo) files
 process.env.PYTHONDONTWRITEBYTECODE = '1'
-
+# Pull package list from remote; install missing packages and uninstall
+# extraneous packages
 pullPkgList(-> initializePackageSync())


menus: Upcoming: ignore calendar metadata from trakt.tv

--- src/js/menus.coffee
+++ src/js/menus.coffee
@@ -307,7 +307,7 @@
               seasonNumber: item.episode.season
               episodeNumber: item.episode.number

-          } for item in items when moment(item.airs_at).isAfter(@fromDate)
+          } for item in items when moment(item.airs_at).isAfter(@fromDate) and not (typeof item == "string")
       } for date, items of Settings.data 'calendar'

     # console.log "---- #{JSON.stringify sections}"