test: Fix tests for environments with Go

--- test/unit/hooks-worker-client-test.coffee
+++ test/unit/hooks-worker-client-test.coffee
@@ -4,6 +4,7 @@
 net = require 'net'
 {assert} = require 'chai'
 clone = require 'clone'
+childProcess = require('child_process')

 crossSpawnStub = require('cross-spawn')
 whichStub = require('../../src/which')
@@ -344,33 +345,25 @@
           assert.include err.message, "composer require ddelnano/dredd-hooks-php --dev"
           done()

-    describe 'when --language=go option is given and go is not installed', ->
-      beforeEach ->
+    describe 'when --language=go option is given and the worker is not installed', ->
+      goBin = undefined
+      goPath = undefined
+      beforeEach ->
+        goBin = process.env.GOBIN
+        goPath = process.env.GOPATH
+        process.env.GOBIN = '/dummy/gobin/path'
+        delete process.env.GOPATH
+
+        sinon.stub(whichStub, 'which').callsFake (command) -> false
+
         runner.hooks['configuration'] =
           options:
             language: 'go'
             hookfiles: 'gobinary'
-
-      it 'should write an error', (done) ->
-        loadWorkerClient (err) ->
-          assert.isOk err
-          assert.include err.message, "Go doesn't seem to be installed"
-          done()
-
-    describe 'when --language=go option is given and the worker is not installed', ->
-      goBin = undefined
-      beforeEach ->
-        goBin = process.env.GOBIN
-        process.env.GOBIN = '/dummy/gobin/path'
-        sinon.stub(whichStub, 'which').callsFake (command) -> false
-
-        runner.hooks['configuration'] =
-          options:
-            language: 'go'
-            hookfiles: 'gobinary'
       afterEach ->
         whichStub.which.restore()
         process.env.GOBIN = goBin
+        process.env.GOPATH = goPath

       it 'should write a hint how to install', (done) ->
         loadWorkerClient (err) ->
@@ -380,9 +373,13 @@

     describe 'when --language=go option is given and the worker is installed', ->
       goBin = undefined
+      goPath = undefined
       beforeEach ->
         goBin = process.env.GOBIN
+        goPath = process.env.GOPATH
         process.env.GOBIN = '/dummy/gobin/path'
+        delete process.env.GOPATH
+
         sinon.stub(crossSpawnStub, 'spawn').callsFake( ->
           emitter = new EventEmitter
           emitter.stdout = new EventEmitter
@@ -408,6 +405,7 @@
         whichStub.which.restore()
         HooksWorkerClient.prototype.terminateHandler.restore()
         process.env.GOBIN = goBin
+        process.env.GOPATH = goPath

       it 'should spawn the server process with command "$GOBIN/goodman"', (done) ->
         loadWorkerClient (err) ->


Remove stub for deprecated tabs.onSelectionChanged

--- tests/unit_tests/test_chrome_stubs.coffee
+++ tests/unit_tests/test_chrome_stubs.coffee
@@ -41,8 +41,6 @@
     getViews: -> []

   tabs:
-    onSelectionChanged:
-      addListener: () -> true
     onUpdated:
       addListener: () -> true
     onAttached:


add query string utility function

add query string utility function

--- services/web/public/coffee/ide/pdf/controllers/PdfController.coffee
+++ services/web/public/coffee/ide/pdf/controllers/PdfController.coffee
@@ -18,6 +18,11 @@
 			$scope.modifierKey = "Cmd"
 		else
 			$scope.modifierKey = "Ctrl"
+
+		# utility for making a query string from a hash, could use jquery $.param
+		createQueryString = (args) ->
+			qs_args = ("#{k}=#{v}" for k, v of args)
+			if qs_args.length then "?" + qs_args.join("&") else ""

 		$scope.$on "project:joined", () ->
 			return if !autoCompile


Only perform supertabs if they exist.

Only perform supertabs if they exist.

--- app/assets/javascripts/areas.coffee
+++ app/assets/javascripts/areas.coffee
@@ -10,34 +10,38 @@
       if (textStatus != 'success')
         console.log(textStatus)

+
   supertabs = $(".super-tab")

   firsttab = supertabs[0]
-  chart = firsttab.attributes[1].value
-  cards = firsttab.attributes[2].value
+
+  if supertabs.length
+    chart = firsttab.attributes[1].value
+    cards = firsttab.attributes[2].value

   # Load first tab by default
   loadAJAX(chart, cards)

   # On click toggle classes
-  supertabs.click ->
-    t = $(this)
+  if supertabs.length
+    supertabs.click ->
+      t = $(this)

-    # Don't run if already active
-    if (t.attr('class') != 'super-tab selected')
-      # Toggle classes
-      t.toggleClass('unselected')
-      t.toggleClass('selected')
+      # Don't run if already active
+      if (t.attr('class') != 'super-tab selected')
+        # Toggle classes
+        t.toggleClass('unselected')
+        t.toggleClass('selected')

-      # Deselect other tabs
-      t.siblings().addClass('unselected')
-      t.siblings().removeClass('selected')
+        # Deselect other tabs
+        t.siblings().addClass('unselected')
+        t.siblings().removeClass('selected')

-      chart = t[0].attributes[1].value
-      cards = t[0].attributes[2].value
+        chart = t[0].attributes[1].value
+        cards = t[0].attributes[2].value

-      # Load via ajax
-      loadAJAX(chart, cards)
+        # Load via ajax
+        loadAJAX(chart, cards)

   generateChart = ->
     # Render chart


motion sensor probably fixed

motion sensor probably fixed

--- app/assets/javascripts/input.coffee
+++ app/assets/javascripts/input.coffee
@@ -100,7 +100,7 @@

 				$(window).on(
 					"deviceorientation",
-					({originalEvent : event}) =>
+					@eventHandler = ({originalEvent : event}) =>

 						{ gamma, beta } = event
 						if gamma < -THRESHOLD or gamma > THRESHOLD
@@ -121,18 +121,7 @@
 			unbind : ->
 				$(window).off(
 					"deviceorientation",
-					({originalEvent : event}) =>
-
-						{ gamma, beta } = event
-						if gamma < -THRESHOLD or gamma > THRESHOLD
-							@fire("x", -gamma)
-						else
-							@unfire("x")
-
-						if beta < -THRESHOLD or beta > THRESHOLD
-							@fire("y", -beta)
-						else
-							@unfire("y")
+					@eventHandler
 				)

 			fire : (key, dist) ->


Automatically log in after registering

Automatically log in after registering

--- app/assets/javascripts/users.coffee
+++ app/assets/javascripts/users.coffee
@@ -44,8 +44,8 @@
         url: url
         data:  $("#formRegister").serialize()
         success: (data) ->
-          location.href = "/login"
-          return
+          $("#token").val(data.token)
+          $("#formSession").submit();
         error: (data) ->
           $("#errorMsg").text(data.error)
           alert(data.error);


proxy should abort queued requests

proxy should abort queued requests

--- lib/assets/javascripts/unpoly/proxy.coffee
+++ lib/assets/javascripts/unpoly/proxy.coffee
@@ -342,6 +342,7 @@
         slowEventEmitted = false

   abortRequests = (requestOrConditions = {}) ->
+    throw "should also abort queued requests"
     for request in pendingRequests
       if request == requestOrConditions || u.contains(request, requestOrConditions)
         request.abort()


Only trim classes from actual .line elements.

--- lib/conflict-marker.coffee
+++ lib/conflict-marker.coffee
@@ -82,7 +82,7 @@
     v.detectDirty() for v in @coveringViews

   remark: ->
-    @adapter.linesElement().children().removeClass(CONFLICT_CLASSES)
+    @adapter.linesElement().children('.line').removeClass(CONFLICT_CLASSES)
     @withConflictSideLines (lines, classes) -> lines.addClass classes

   acceptCurrent: ->


Fixed denorm index specs

Fixed denorm index specs

--- denorm.coffee
+++ denorm.coffee
@@ -10,14 +10,9 @@

 J.denorm =
     ensureAllReactiveWatcherIndexes: ->
-        helper = (reactiveModelClass, reactiveName) ->
-            ###
-                Build indexes that let NK (Normalized Kernel) nodes propagate
-                their value change to reset this reactive's value
-            ###
-
-            for nkModelClassname, nkModelClass of J.models
-                continue if nkModelClass in ['JDataSession']
+        for reactiveModelName, reactiveModelClass of J.models
+            for reactiveName, reactiveSpec of reactiveModelClass.reactiveSpecs
+                continue if not reactiveSpec.denorm

                 indexFieldsSpec = {}
                 indexFieldsSpec["_reactives.#{reactiveName}.watching.modelName"] = 1
@@ -25,16 +20,11 @@
                 # indexFieldsSpec["_reactives.#{reactiveName}.watching.selector._id"] = 1
                 # indexFieldsSpec["_reactives.#{reactiveName}.watching.selector._id.$in"] = 1

-                modelClass.collection._ensureIndex(
+                reactiveModelClass.collection._ensureIndex(
                     indexFieldsSpec
                     name: "_jReactiveWatcher_#{reactiveName}"
                     sparse: true
                 )
-
-        for modelClassName, modelClass of J.models
-            for reactiveName, reactiveSpec of modelClass.reactiveSpecs
-                if reactiveSpec.denorm
-                    helper modelClass, reactiveName

     recalc: (instance, reactiveName, timestamp = new Date()) ->


Bugfix in resetWatchers selector for array values

--- denorm.coffee
+++ denorm.coffee
@@ -48,7 +48,7 @@
         value = null
         watchedQuerySpecSet = null

-        console.log "Gonna (re)calculate <#{instance.modelClass.name} #{JSON.stringify instance._id}>.#{reactiveName}..."
+        # console.log "Recalc <#{instance.modelClass.name} #{JSON.stringify instance._id}>.#{reactiveName}"

         J._watchedQuerySpecSet.withValue {}, =>
             value = reactiveSpec.val.call instance
@@ -59,7 +59,7 @@
         else if value instanceof J.Dict
             value = value.toObj()

-        console.log "(Re)calculated <#{instance.modelClass.name} #{JSON.stringify instance._id}>.#{reactiveName}"
+        # console.log "...done recalc <#{instance.modelClass.name} #{JSON.stringify instance._id}>.#{reactiveName}"

         watchedQsStrings = J.util.sortByKey _.keys watchedQuerySpecSet
         watchedQuerySpecs = (
@@ -123,9 +123,15 @@
                 if oldValue?
                     term.$or[0][selectorPath].$in.push oldValue
                     term.$or[1]["#{selectorPath}.*DOLLAR*in"].$elemMatch.$in.push oldValue
+                    if _.isArray oldValue then for elem in oldValue
+                        term.$or[0][selectorPath].$in.push elem
+                        term.$or[1]["#{selectorPath}.*DOLLAR*in"].$elemMatch.$in.push elem
                 if newValue? and not EJSON.equals oldValue, newValue
                     term.$or[0][selectorPath].$in.push newValue
                     term.$or[1]["#{selectorPath}.*DOLLAR*in"].$elemMatch.$in.push newValue
+                    if _.isArray newValue then for elem in newValue
+                        term.$or[0][selectorPath].$in.push elem
+                        term.$or[1]["#{selectorPath}.*DOLLAR*in"].$elemMatch.$in.push elem

                 subFieldSelectorMatcher.push term


[master] filter

[master] filter

--- translator/run.coffee
+++ translator/run.coffee
@@ -13,6 +13,7 @@
 logger = utils.logging.newFileLogger module.filename, 'log'

 http.globalAgent.maxSockets = 5
+averageLoad = 5

 if require.main == module
   availableTranslators =
@@ -51,7 +52,10 @@
               process.stdout.write '\rskip'
               return
             else
-              src = (entry.title + '\n' + entry.content).replace(/
|\u001d|\u2586|\u2587|\u258c|\u00b7|\u0000|\uff0b|\u002e/g, ' ').trim()
+              src = (entry.title + '\n' + entry.content)
+              .replace /
/g, ' '
+              .replace /[^0-9a-zA-Z\u4e00-\u9fa5]/g, ' '
+              .trim()
               currentTranslator = round.get()
               process.stdout.write '\r'
               process.stdout.write JSON.stringify(round.status())
@@ -63,7 +67,7 @@
                 logger.debug 'translated',
                   src: src
                   dst: res
-      Q.all _.map(_.range(4 * http.globalAgent.maxSockets * (availableTranslators.length + 1)), ->
+      Q.all _.map(_.range(averageLoad * Math.min(http.globalAgent.maxSockets, 50) * (availableTranslators.length + 1)), ->
         loo = ->
           val = keys.pop()
           if val


feat(response): add rest options to original request

--- src/coffee/services/base.coffee
+++ src/coffee/services/base.coffee
@@ -541,9 +541,14 @@
             headers: response.headers
       else {}

-    originalRequest = _.extend originalRequest,
-      uri: @_rest._options.uri
-      timeout: @_rest._options.timeout
+    options = _.omit(@_rest._options, ['access_token'])
+    if options.config
+      options.config = _.omit(options.config, ['client_id', 'client_secret'])
+
+    originalRequest = _.extend(
+      originalRequest,
+      options
+    )

     if error
       if error instanceof Error


test autodeploy

test autodeploy

--- deploy.coffee
+++ deploy.coffee
@@ -1,11 +1,6 @@
 http = require('http')
 querystring = require('querystring')
 exec = require('child_process').exec
-
-
-#process.on 'uncaughtException', (error) ->
-#  console.error 'Uncaught exception: ' + error.message
-#  console.trace()

 last_payload = {}


12857: Update logo and logo link for partner tools

--- app/assets/javascripts/syndication/tools.js.coffee
+++ app/assets/javascripts/syndication/tools.js.coffee
@@ -6,11 +6,11 @@
   containerClass: "mas-widget-container"
   containerStyles: "width: 100%; margin: 0 auto;"
   linkClass: "mas-widget-logo-link"
-  linkHref: "https://www.moneyadviceservice.org.uk/"
+  linkHref: "https://www.moneyhelper.org.uk/en"
   linkTarget: "_blank"
-  logoSrc: "https://www.moneyadviceservice.org.uk/assets/logo_en.png"
+  logoSrc: "https://www.moneyhelper.org.uk/etc.clientlibs/maps/core/clientlibs/clientlib-base/resources/logos/logo-en-desktop.svg"
   logoStyles: "display: block; margin-bottom: 8px; width: 300px"
-  logoAltText: "Money Advice Service"
+  logoAltText: "MoneyHelper"

   toolConfig:
     employer_best_practices:


Beginnings of a Prototypal Instantiation System

--- src/coffee/experimental-controller.coffee
+++ src/coffee/experimental-controller.coffee
@@ -1,7 +1,15 @@
 qbnApp = angular.module 'qbnApp', []

 class Quality
-  constructor: (@name, @value) ->
+  constructor: (@name, @defaultValue) ->
+
+  initInstance: () ->
+    @value = @defaultValue
+
+instantiate = (proto) ->
+  instance = Object.create proto
+  instance.initInstance()
+  return instance

 class Storylet
   constructor: (@title, @text, @choices) ->
@@ -11,8 +19,8 @@

 qbnApp.controller 'QBN', ($scope) ->
   $scope.qualities = [
-    new Quality 'Punchiness', 7
-    new Quality 'Thinkyness', 2
+    instantiate new Quality 'Punchiness', 7
+    instantiate new Quality 'Thinkyness', 2
   ]
   $scope.storylets = [
     new Storylet 'The Thinker\'s Apprentice', 'You do some thinking.'


Remove left over debug log line

Remove left over debug log line

--- app/coffee/CompileController.coffee
+++ app/coffee/CompileController.coffee
@@ -11,7 +11,6 @@
 		RequestParser.parse req.body, (error, request) ->
 			return next(error) if error?
 			request.project_id = req.params.project_id
-			logger.log {request}, "got request"
 			ProjectPersistenceManager.markProjectAsJustAccessed request.project_id, (error) ->
 				return next(error) if error?
 				CompileManager.doCompile request, (error, outputFiles = []) ->


apply firefox fix to faq links

apply firefox fix to faq links

--- app/controllers/science-page.coffee
+++ app/controllers/science-page.coffee
@@ -18,7 +18,7 @@
   scrollToLink: (e) ->
     console.log "##{e.target.getAttribute "target"}"
     console.log e.target
-    $('body').animate({
+    $('body,html').animate({
         scrollTop: $("##{e.target.getAttribute "target"}").offset().top
     }, 1000, 'easeInOutExpo');


Fix spell_palette_entry_popover translations not being activated

--- app/views/play/level/tome/SpellPaletteView.coffee
+++ app/views/play/level/tome/SpellPaletteView.coffee
@@ -25,7 +25,7 @@
     'tome:palette-clicked': 'onPalleteClick'
     'surface:stage-mouse-down': 'hide'
     'level:set-playing': 'hide'
-
+

   events:
     'click #spell-palette-help-button': 'onClickHelp'
@@ -375,6 +375,7 @@
     @$el.addClass('open')
     content = @$el.find(".rightContentTarget")
     content.html(e.entry.doc.initialHTML)
+    content.i18n()
     codeLanguage = e.entry.options.language
     oldEditor.destroy() for oldEditor in @aceEditors
     @aceEditors = []


remove old shit

remove old shit

--- app/scripts/controllers/main.coffee
+++ app/scripts/controllers/main.coffee
@@ -184,10 +184,6 @@
             q.promise

-        # Listen for movies changes
-        $rootScope.$on "refresh.movies", () ->
-            $location.path "/"
-
         # Add drop event to document
         document.addEventListener "dragover", (e) -> e.preventDefault() and e.stopPropagation()
         document.addEventListener "dragleave", (e) -> e.preventDefault() and e.stopPropagation()


Shorten plot title

Shorten plot title

--- app/scripts/natdashboardctrl.coffee
+++ app/scripts/natdashboardctrl.coffee
@@ -47,7 +47,7 @@
     $scope.plots = [
       {id:"statusSummary", title: "Waterpoint status (ordered by % Functional)"},
       {id:"percFunLeaders", title: "Leaderboard: Percentage Functional"},
-      {id:"popReach", title: "Leaderboard: Percentage of the Population Served"}]
+      {id:"popReach", title: "Leaderboard: Percentage Served"}]

     $scope.groups = ['region', 'lga', 'ward', 'funder', 'source_type',
                      'construction_year', 'quantity_group',


Remove commented line

Remove commented line

--- src/context-menu-manager.coffee
+++ src/context-menu-manager.coffee
@@ -160,7 +160,6 @@
     menuTemplate = @templateForEvent(event)

     return unless menuTemplate?.length > 0
-    # @executeBuildHandlers(event, menuTemplate)
     remote.getCurrentWindow().emit('context-menu', menuTemplate)
     return


incremental work

incremental work

--- assets/coffeescript/pupil_store.coffee
+++ assets/coffeescript/pupil_store.coffee
@@ -8,7 +8,6 @@
     @orderPage = "Order" #Order form class
     @storeConfigClass = "StoreConfig"
     @storeConfigSelector = "a[class^='#{ @storeConfigClass}-']"
-    @storeConfigSelectorJq = $("a[class^='StoreConfig-']")
     @storeConfigActiveClass = "StoreConfig--state-active"
     @addToCartClass = "a[class='AddToCart']"
     @clearCartClass = "a[id='StoreConfig-clearCart']"
@@ -18,7 +17,7 @@
     @eyeConfigActiveClass = "a[class='StoreConfig-eye #{ @storeConfigActiveClass }']"
     @configSubTotalClass = "p[class='StoreConfig-subTotal']"
     @cartNavCounter = $("sup[class='Nav-cart-itemCount']")
-    @activeLink = null
+    @storeConfigPresetClass = "a[class='Store-nav-link Store-nav-link--preset']"
     ) ->
       @eventAddToCart()
       @eventClearCart()
@@ -55,7 +54,6 @@
     @addToCartButton.click (event)=>
       event.preventDefault()
       addToCartBtn = $(event.target)
-      console.log "addtocart event.target " + event.target
       productType = $(addToCartBtn).data('product')

       if productType is "pupil"
@@ -94,11 +92,12 @@

   eventUpdateConfig: ->
-    @storeConfigSelectorJq.click (event)=>
+    $(@storeConfigSelector).click (event)=>
       event.preventDefault()
-      console.log "Event.target: " + event.target
-      console.log "Event.currentTarget: " + event.currentTarget
-
+      # typically we would use $(this) to refer to the jquery object
+      # within the scope of the `click` function
+      # but in coffeescript when we use the fat arrow (=>)
+      # we are referring to the class itself and not the jquery object
       activeLinks = $(event.target)
       @_setActiveState(activeLinks)
       @_swapImg(activeLinks)


simplify

simplify

--- lib/edit-in-new-tab.coffee
+++ lib/edit-in-new-tab.coffee
@@ -123,7 +123,7 @@
             childEditor.onDidChange ->
               parentSelection.insertText(editor.getText(), { select: true })

-              if atom.config.get('edit-in-new-tab.synchronizeChanges') is true and atom.config.get('edit-in-new-tab.indentOrigin') is true
+              if atom.config.get('edit-in-new-tab.indentOrigin') is true
                 atom.commands.dispatch(atom.views.getView(parentEditor), 'editor:auto-indent')

       .catch (error) ->


Don’t autocomplete in line continuations

--- lib/language-csound.coffee
+++ lib/language-csound.coffee
@@ -29,7 +29,7 @@

   providers: -> {
     selector: '.source.csound'
-    disableForSelector: '.source.csound .comment, .source.csound .string'
+    disableForSelector: '.source.csound .comment, .source.csound .line-continuation, .source.csound .string'
     filterSuggestions: true

     getSuggestions: ({editor, bufferPosition, scopeDescriptor, prefix}) ->


fix port number

fix port number

--- lib/linter-provider.coffee
+++ lib/linter-provider.coffee
@@ -37,7 +37,7 @@
         http = require('https')
         apipath = '/api'
         lthostname = 'languagetool.org'
-        ltport = 80
+        ltport = 443

       post_data = querystring.stringify {
         'language': 'auto'


fix form coffee

fix form coffee

--- app/assets/javascripts/form.coffee
+++ app/assets/javascripts/form.coffee
@@ -1,11 +1,11 @@
 @UiBibzForm = class Form

   constructor: ->
-    @selectPicker() if $('select.selectpicker').length == 1
-    @switch()       if $('.input.switch').length == 1
-    @multiSelect()  if $('.multi-select').length == 1
-    @multiColumn()  if $('.multi-column').length == 1
-    @formula()      if $('.formula_field_input').length == 1
+    @switch()       if $('input.switch').length > 0
+    @selectPicker() if $('select.selectpicker').length > 0
+    @multiSelect()  if $('.multi-select').length > 0
+    @multiColumn()  if $('.multi-column').length > 0
+    @formula()      if $('.formula_field_input').length > 0

   selectPicker: ->
     $('select.selectpicker').selectpicker


fix country switching

fix country switching

--- app/assets/javascripts/list.coffee
+++ app/assets/javascripts/list.coffee
@@ -23,23 +23,31 @@
         $(this).removeClass 'selected'
     false

+  updateCountryTable = (country) ->
+    $('#country-table thead th').text country
+
+    tbody = $('#country-table tbody')
+    tbody.empty()
+    gon.citiesByCountry[country].forEach (city) ->
+      tbody.append '
' + city + '
'
+      return
+    $('#country-table').trigger 'update'
+
   # show country column after clicking on country from directory
   $('a.link-country').click ->
     selected_cell = $(this).children '.directory-entry'
     country = $(this).attr('data-country')
     if $('.col-country').hasClass 'hidden'
-      $('#country-table thead th').text country
-
-      tbody = $('#country-table tbody')
-      tbody.empty()
-      gon.citiesByCountry[country].forEach (city) ->
-        tbody.append '
' + city + "
"
-        return
-      $('#country-table').trigger 'update'
+      updateCountryTable country

       selected_cell.addClass 'selected'
       $('.col-country').removeClass 'hidden'
       $('.country').slideDown 'slow'
+    else if $('#country-table thead th').text isnt country
+      updateCountryTable country
+
+      $('.directory-entry.selected').removeClass 'selected'
+      selected_cell.addClass 'selected'
     else
       $('.country').slideUp 'slow', ->
         $('.col-country').addClass 'hidden'


Remove unused moment reference

Remove unused moment reference

--- app/javascript/packs/legacy.coffee
+++ app/javascript/packs/legacy.coffee
@@ -9,7 +9,6 @@
 import 'jquery.growl'
 import 'sweetalert'
 import Cookies from 'js-cookie'
-import moment from 'moment'

 require('nprogress/nprogress.css')
 require('jquery.growl/stylesheets/jquery.growl.css')
@@ -25,8 +24,6 @@
 import '../legacy/report'
 import '../legacy/locale-box'
 import '../legacy/util'
-
-window.moment = moment

 window.translate = (scope, options) ->
   # for some reason I18n errors when calling it by assign proxy, so we got to wrap it


showing transfer transaction fee as reported by wallet_get_transaction_fee [asset] rpc call

--- app/js/controllers/transfer.coffee
+++ app/js/controllers/transfer.coffee
@@ -86,16 +86,19 @@
         my_transfer_form.payto.error_message = null
         amount_asset = $scope.balances[$scope.transfer_info.symbol]
         transfer_amount = Utils.formatDecimal($scope.transfer_info.amount, amount_asset.precision)
-        Blockchain.get_asset(0).then (fee_asset)->
-            transaction_fee = Utils.formatAsset(Utils.asset(Wallet.info.transaction_fee.amount, fee_asset))
-            trx = {to: $scope.transfer_info.payto, amount: transfer_amount + ' ' + $scope.transfer_info.symbol, fee: transaction_fee, memo: $scope.transfer_info.memo, vote: $scope.vote_options[$scope.transfer_info.vote]}
-            $modal.open
-                templateUrl: "dialog-transfer-confirmation.html"
-                controller: "DialogTransferConfirmationController"
-                resolve:
-                    title: -> "Transfer Authorization"
-                    trx: -> trx
-                    action: -> yesSend
+        WalletAPI.get_transaction_fee($scope.transfer_info.symbol).then (tx_fee) ->
+            transfer_asset = Blockchain.symbol2records[$scope.transfer_info.symbol]
+            Blockchain.get_asset(transfer_asset.id).then (fee_asset)->
+                Blockchain.get_asset(tx_fee.asset_id).then (tx_fee_asset) ->
+                    transaction_fee = Utils.formatAsset(Utils.asset(tx_fee.amount, tx_fee_asset))
+                    trx = {to: $scope.transfer_info.payto, amount: transfer_amount + ' ' + $scope.transfer_info.symbol, fee: transaction_fee, memo: $scope.transfer_info.memo, vote: $scope.vote_options[$scope.transfer_info.vote]}
+                    $modal.open
+                        templateUrl: "dialog-transfer-confirmation.html"
+                        controller: "DialogTransferConfirmationController"
+                        resolve:
+                            title: -> "Transfer Authorization"
+                            trx: -> trx
+                            action: -> yesSend

     $scope.newContactModal = ->
         $modal.open


Env var should be saved with PATCH

Env var should be saved with PATCH

--- assets/scripts/lib/travis/adapters/env_vars.coffee
+++ assets/scripts/lib/travis/adapters/env_vars.coffee
@@ -14,7 +14,7 @@
     url = this.buildURL(record.constructor, get(record, primaryKey), record)
     self = this

-    return this.ajax(url, record.toJSON(), "PUT").then (data) ->
+    return this.ajax(url, record.toJSON(), "PATCH").then (data) ->
       self.didSaveRecord(record, data)
       return record


call fetchMe after fetchMyMemberships

call fetchMe after fetchMyMemberships

--- app/boot.coffee
+++ app/boot.coffee
@@ -13,9 +13,9 @@

   $rootScope.$on 'auth:login-success', (ev, user) ->
     global.cobudgetApp.currentUserId = user.id
-    Records.users.fetchMe().then ->
-      Records.memberships.fetchMyMemberships().then (data) ->
-        membershipsLoadedDeferred.resolve()
+    Records.memberships.fetchMyMemberships().then (data) ->
+      membershipsLoadedDeferred.resolve()
+      Records.users.fetchMe().then ->
         if CurrentUser().hasEverJoinedAGroup()
           if CurrentUser().hasMemberships()
             groupId = data.groups[0].id


:bug: #216 modified file are no longer skipped on initialSearch

And avoid use of atom.project.getDirectoryForProjectPath

--- lib/provider/search.coffee
+++ lib/provider/search.coffee
@@ -14,7 +14,7 @@
   useFirstQueryAsSearchTerm: true
   supportFilePathOnlyItemsUpdate: true
   refreshOnDidStopChanging: true
-  searchInOrdered: false # This is set to true in spec to test easily
+  searchInOrdered: false # FIXME: This is set to true in spec to test easily

   getState: ->
     @mergeState(super, {@projects})
@@ -36,7 +36,7 @@

   search: ->
     projects = @projects.slice()
-    modifiedBuffers = atom.project.getBuffers().filter (buffer) -> buffer.isModified()
+    modifiedBuffers = atom.project.getBuffers().filter (buffer) -> buffer.getPath()? and buffer.isModified()
     modifiedBuffersScanned = []

     scanBuffer = (buffer) =>
@@ -47,8 +47,7 @@
     finished = 0
     onFinish = (project) =>
       finished++
-      dir = atom.project.getDirectoryForProjectPath(project)
-      for buffer in modifiedBuffers when dir.contains(buffer.getPath())
+      for buffer in modifiedBuffers when path.dirname(buffer.getPath()).startsWith(project)
         scanBuffer(buffer)

       if projects.length
@@ -59,15 +58,18 @@
           @finishUpdateItems()

     searchNextProject = =>
-      @searcher.searchProject(projects.shift(), @updateItems, onFinish)
+      @searcher.searchProject(projects.shift(), @updateItemsIfNotModified, onFinish)

     if @searchInOrdered
       searchNextProject()
     else
       searchNextProject() while projects.length

-  updateItems: (items) ->
+  updateItemsIfNotModified: (items) =>
     items = items.filter (item) -> not atom.project.isPathModified(item.filePath)
+    @updateItems(items)
+
+  updateItems: (items) =>
     if @searchInOrdered
       items = _.sortBy(items, (item) -> item.filePath)
     super(items)


fixing a few more deps

fixing a few more deps

--- lib/python-debugger.coffee
+++ lib/python-debugger.coffee
@@ -9,7 +9,7 @@

   insert: ->
     IMPORT_STATEMENT = "import ipdb\n"
-    editor = atom.workspace.activePaneItem
+    editor = atom.workspace.getActivePaneItem()
     cursors = editor.getCursors()
     saved_positions = []

@@ -50,7 +50,7 @@
       cursor.setBufferPosition(saved_positions[index])

   remove: ->
-    editor = atom.workspace.activePaneItem
+    editor = atom.workspace.getActivePaneItem()
     console.log('removing all imports')
     matches = []
     editor.buffer.backwardsScan /ipdb/g, (match) -> matches.push(match)


Move t7e load so menu appears

Move t7e load so menu appears

--- app/main.coffee
+++ app/main.coffee
@@ -1,8 +1,14 @@
+translate = require 't7e'
+enUs = require './lib/en-us'
+translate.load enUs
+
 Api = require 'zooniverse/lib/api'
 api = new Api project: 'cyclone_center'

 Subject = require 'zooniverse/models/subject'
 Subject.group = true
+
+

 $app = $('#app')
 $footerContainer = $('#footer-container')
@@ -19,6 +25,17 @@
   '#/profile': require './controllers/profile'
 $(stack.el).appendTo $app

+LanguageManager = require 'zooniverse/lib/language-manager'
+languageManager = new LanguageManager
+  translations:
+    en: label: 'English', strings: enUs
+    it: label: 'Italiano'
+    zh_tw: label: '繁體中文', strings: './translations/zh-tw.json'
+
+languageManager.on 'change-language', (e, code, strings) ->
+  translate.load strings
+  translate.refresh()
+
 TopBar = require 'zooniverse/controllers/top-bar'
 topBar = new TopBar
 topBar.el.appendTo navigation.el
@@ -30,21 +47,6 @@
 User = require 'zooniverse/models/user'
 User.fetch()

-translate = require 't7e'
-enUs = require './lib/en-us'
-translate.load enUs
-
-LanguageManager = require 'zooniverse/lib/language-manager'
-languageManager = new LanguageManager
-  translations:
-    en: label: 'English', strings: enUs
-    it: label: 'Italiano'
-    zh_tw: label: '繁體中文', strings: './translations/zh-tw.json'
-
-languageManager.on 'change-language', (e, code, strings) ->
-  translate.load strings
-  translate.refresh()
-
 GoogleAnalytics = require 'zooniverse/lib/google-analytics'
 analytics = new GoogleAnalytics account: 'UA-1224199-33'


Throw a custom BufferToScreenConversion error with metadata

--- src/display-buffer.coffee
+++ src/display-buffer.coffee
@@ -9,6 +9,11 @@
 Fold = require './fold'
 Token = require './token'
 DisplayBufferMarker = require './display-buffer-marker'
+
+class BufferToScreenConversionError extends Error
+  constructor: (@message, @metadata) ->
+    super
+    Error.captureStackTrace(this, arguments.callee)

 module.exports =
 class DisplayBuffer extends Model
@@ -291,12 +296,14 @@
     { row, column } = @buffer.clipPosition(bufferPosition)
     [startScreenRow, endScreenRow] = @rowMap.screenRowRangeForBufferRow(row)
     for screenRow in [startScreenRow...endScreenRow]
-      unless screenLine = @screenLines[screenRow]
-        throw new Error """
-          No screen line exists when converting a buffer row to a screen row
-          Soft wrap enabled?: #{@getSoftWrap()}
-          Folds exist?: #{@findFoldMarkers().length > 0}
-        """
+      screenLine = @screenLines[screenRow]
+      unless screenLine?
+        throw new BufferToScreenConversionError "No screen line exists when converting buffer row to screen row",
+          softWrapEnabled: @getSoftWrap()
+          foldCount: @findFoldMarkers().length
+          lastBufferRow: @buffer.getLastRow()
+          lastScreenRow: @getLastRow()
+
       maxBufferColumn = screenLine.getMaxBufferColumn()
       if screenLine.isSoftWrapped() and column > maxBufferColumn
         continue


Test world with Mocha

Test world with Mocha

--- src/god/test_world.coffee
+++ src/god/test_world.coffee
@@ -1,235 +1,216 @@
 {god} = require('../god')

-exports.test_world = (test, rx) ->
-  world = god(rx, {key: "value"})
-  test 'world exists', (t) ->
-    t.ok world, "world"
-    t.end()
-
-  test 'world stores values faithfully', (t) ->
-    test_store = (key, value) ->
+exports.test_world = ->
+  describe 'World', ->
+    world = god(rx, {key: "value"})
+
+    it 'world exists', ->
+      assert.ok world, "world"
+
+    it 'world stores values faithfully', ->
+      test_store = (key, value) ->
+        world.put(key, value)
+        result = world.get(key)
+        assert.equal result, value, "store #{key}"
+      test_store("number", 2)
+      test_store("string", "okay")
+      test_store("dict", {not: "2b"})
+
+    it 'world stores arrays as reactive', ->
+      key = "array"
+      value = [1, "2b"]
       world.put(key, value)
       result = world.get(key)
-      t.equal result, value, "store #{key}"
-    test_store("number", 2)
-    test_store("string", "okay")
-    test_store("dict", {not: "2b"})
-    t.end()
-
-  test 'world stores arrays as reactive', (t) ->
-    key = "array"
-    value = [1, "2b"]
-    world.put(key, value)
-    result = world.get(key)
-    t.equal result.all().toString(), value.toString(), "store #{key}"
-    t.end()
-
-  test 'world can update properties', (t) ->
-    world.put('x', 2)
-    world.update('x', 1)
-    t.equal world.get('x'), 3
-    t.end()
-
-  test 'world contains reactive extensions', (t) ->
-    t.ok world.rx(), "rx()"
-    t.ok world.T(), "T"
-    t.ok world.SVG() ,"SVG"
-    t.ok world.bind(), "bind"
-    t.end()
-
-  test 'world makes sub-worlds', (t) ->
-    value = "42"
-    sub = world.make_world(value)
-    t.equal sub.get("value"), value, "sub.get"
-    t.equal sub.up, world, "sub.up"
-    t.equal sub.get('up'), world, "sub.get('up')"
-    t.ok sub.T(), "sub.T"
-
-    dict = {key: value}
-    sub_m = world.make_world(dict)
-    t.equal sub_m.get("key"), value, "sub_d.get"
-
-    sub_w = world.make_world(world)
-    t.equal sub_w, world, "don't wrap worlds"
-    t.end()
-
-  test 'world imports from dictionaries', (t) ->
-    world.import_dict({a: 1, b:2, _CHILDREN:[{c:3}]})
-    t.equal world.get('a'), 1, "import properties"
-    children = world.get('_CHILDREN')
-    t.ok world.is_array(children), "children is SrcArray"
-    child = children.at(0)
-    t.ok child, "child exists"
-    t.ok world.is_world(child), "child is a world"
-    t.end()
-
-  test 'world returns keys', (t) ->
-    new_world = world.make_world {a: 1, b:2, _CHILDREN:[{c:3}]}
-    t.equal new_world.keys().toString(), ['a', 'b'].toString(), 'my keys'
-    new_child = new_world.find_child()
-    t.equal new_child.keys().toString(), ['c'].toString(), 'child keys'
-    t.equal new_child.keys([]).toString(), ['a', 'b', 'c'].toString(), 'all keys'
-    t.end()
-
-  test 'world has a label', (t) ->
-    t.equal world.label(), "root", "label"
-    t.equal "#{world}", "World_root", "toString"
-    t.end()
-
-  test 'world can find children', (t) ->
-    t.ok world.has_children(), "has some"
-    result = world.find_children()
-    t.ok result, "finds children"
-    t.equal result.length, 1, "1 child"
-
-    result = world.find_children("root")
-    t.equal result.length, 0, "0 child"
-    result = world.find_children("root-0")
-    t.equal result.length, 1, "1 child"
-    t.end()
-
-  test 'world can replace children', (t) ->
-    label = 'root-0'
-    t.equal world.find_index(label), 0, "find_index"
-    original_count = world._child_count()
-    t.equal world.find_child(label).get('c'), 3
-    replacement = {_LABEL: label, c: 9}
-    world.replace_child(replacement)
-    t.equal world.find_child(label).get('c'), 9
-    t.equal world._child_count(), original_count, "changed count"
-    t.end()
-
-  # TODO: Break this up into smaller tests somehow
-  test 'world has children inherit', (t) ->
-    t.ok world.has_children(), "world.has_children"
-    grandma = world.add_child("Premela")
-    t.notOk grandma.has_children(), "grandma.has_children NOT"
-    mom = grandma.add_child("Sandhya")
-    t.ok grandma.has_children(), "grandma.has_children"
-    daughter = mom.add_child("Anjali")
-    t.ok mom.has_children(), "mom.has_children"
-    t.ok daughter, "daughter"
-    t.equal "#{daughter}", "World_Anjali", "daughter name"
-    result = mom.map_children (child) -> "#{child.label()} Prabhakar"
-    t.equal result[0], "Anjali Prabhakar", "map child"
-    t.equal daughter.find_parent("Premela"), grandma, 'Find ancestor'
-    t.equal daughter.find_parent("Abraham"), world, 'Unknown ancestor'
-
-    candy = 'chocolate'
-    t.notOk daughter.get(candy), "No chocolate"
-    t.notOk daughter.owner(candy), "No chocolate owner"
-    grandma.put(candy, 'dark')
-    t.equal grandma.owner(candy), grandma, "chocolate owner self"
-    t.equal daughter.owner(candy), grandma, "chocolate owner"
-    t.equal daughter.get(candy), 'dark', "Inherit chocolate"
-    mom.put(candy, 0)
-    t.equal daughter.owner(candy), mom, "chocolate owner 0"
-    t.equal daughter.get(candy), 0, "Inherit chocolate 0"
-
-    t.ok world.label() == "root", "equals root"
-    t.ok daughter.find_parent("root"), "find_parent root"
-    t.equal world, world.find_path('.'), "find root"
-    t.equal world, daughter.find_path('.'), "find root from below"
-    t.equal mom.find_path('Anjali'), daughter, "find child"
-    t.equal daughter.find_path('.Premela'), grandma, "find ancestor"
-
-    t.equal world.find_path('.Premela.Sandhya.Anjali'), daughter, "find path"
-
-    #t.equal daughter.find_any('Premela'), grandma, "find any ancestor"
-    #t.equal grandma.find_any('Anjali'), daughter, "find any descendant"
-    t.end()
-
-  test 'world passes index as property when mapping', (t) ->
-    count = 0
-    world.map_children (child) ->
-      index = child.index
-      t.equal index, count, "#{child} should have index #{count}, not #{index}"
-      count = count + 1
-    t.end()
-
-  test 'world removes child at index', (t) ->
-    a = world.add_child('a')
-    b = world.add_child('b')
-    a2 = world.add_child('a')
-    world.map_children (child) -> "just to set index"
-    count = world._child_count()
-    t.ok a.index, "a has index"
-    world.remove_child a2
-    t.equal world._child_count(), count - 1
-    world.remove_child a
-    t.equal world._child_count(), count - 2
-    t.end()
-
-  test 'world has authorities', (t) ->
-    comply = world._spawn_world("compliant")
-    authority = world._spawn_world("authority")
-    rebel = world._spawn_world("rebellious")
-    rebel.put("_AUTHORITY", authority)
-
-    world.put("foo", "bar")
-    t.equal comply.get('foo'), 'bar', 'comply foo'
-    t.equal rebel.get('foo'), 'bar', 'rebel foo'
-    authority.put('foo', 'baz')
-    t.equal comply.get('foo'), 'bar', 'comply foo'
-    t.equal rebel.get('foo'), 'baz', 'rebel foo with authority'
-    t.end()
-
-  test 'world has dynamic properties', (t) ->
-    value = "wanna"
-    world.put("fun", -> value)
-    t.equal typeof world.get_raw("fun"), 'function', "raw function"
-    t.equal world.get("fun"), value, "dynamic property"
-    t.end()
-
-  test 'world can call functions', (t) ->
-    world.put("instance", "variable")
-    args = {key: "value"}
-    callme = (world, args) -> [world.get("instance"), args['key']]
-    world.put('callme', callme)
-    result = world.call('callme', args)
-    t.equal result[0], "variable", "world parameter"
-    t.equal result[1], "value", "args parameter"
-    t.end()
-
-  test 'world knows worlds', (t) ->
-    t.ok world.is_world(world), "non-world"
-    t.notOk world.is_world(1), "non-world"
-    t.ok world.is_root(), "is root"
-    branch = world.add_child("branch")
-    t.notOk branch.is_root(), "is not root"
-    t.end()
-
-  test 'world generates CSS labels', (t) ->
-    daughter = world.add_child("daughter")
-    daughter.put("_CSS", "klass")
-    css = daughter.labels(["css"])
-    t.ok css.length > 2, "Traverse label hierarchy"
-    t.ok "klass" in css, "Has explicit class"
-    t.ok "root" in css, "Has root"
-    t.end()
-
-  test 'config handlers', (t) ->
-    t.equal world.handlers_for('begin').length, 0, "1 begin handler"
-    begun = false
-    finished = false
-    world.handle 'begin', -> begun = true
-    t.equal world.handlers_for('begin').length, 1, "1 begin handler"
-    t.equal world.handlers_for('finish').length, 0, "0 finish handler"
-    world.handle 'finish', -> finished = true
-    t.equal world.handlers_for('finish').length, 1, "0 finish handler"
-
-    t.notOk begun, "Has not ran"
-    t.notOk finished , "Has not finished"
-    world.send 'begin'
-    t.ok begun, "Has begun"
-    world.send 'finish'
-    t.ok finished, "Has finished"
-    t.end()
-
-  test 'event callbacks', (t) ->
-    val = 42
-    t.notOk world.get('property'), "no property yet"
-    world.handle 'value', (key, args) -> args
-    world.send 'value', val, (value) -> world.put('property', value)
-    t.equal world.get('property'), val, "property not set"
-    t.end()
+      assert.equal result.all().toString(), value.toString(), "store #{key}"
+
+    it 'world can update properties', ->
+      world.put('x', 2)
+      world.update('x', 1)
+      assert.equal world.get('x'), 3
+
+    it 'world contains reactive extensions', ->
+      assert.ok world.rx(), "rx()"
+      assert.ok world.T(), "T"
+      assert.ok world.SVG() ,"SVG"
+      assert.ok world.bind(), "bind"
+
+    it 'world makes sub-worlds', ->
+      value = "42"
+      sub = world.make_world(value)
+      assert.equal sub.get("value"), value, "sub.get"
+      assert.equal sub.up, world, "sub.up"
+      assert.equal sub.get('up'), world, "sub.get('up')"
+      assert.ok sub.T(), "sub.T"
+
+      dict = {key: value}
+      sub_m = world.make_world(dict)
+      assert.equal sub_m.get("key"), value, "sub_d.get"
+
+      sub_w = world.make_world(world)
+      assert.equal sub_w, world, "don't wrap worlds"
+
+    it 'world imports from dictionaries', ->
+      world.import_dict({a: 1, b:2, _CHILDREN:[{c:3}]})
+      assert.equal world.get('a'), 1, "import properties"
+      children = world.get('_CHILDREN')
+      assert.ok world.is_array(children), "children is SrcArray"
+      child = children.at(0)
+      assert.ok child, "child exists"
+      assert.ok world.is_world(child), "child is a world"
+
+    it 'world returns keys', ->
+      new_world = world.make_world {a: 1, b:2, _CHILDREN:[{c:3}]}
+      assert.equal new_world.keys().toString(), ['a', 'b'].toString(), 'my keys'
+      new_child = new_world.find_child()
+      assert.equal new_child.keys().toString(), ['c'].toString(), 'child keys'
+      assert.equal new_child.keys([]).toString(), ['a', 'b', 'c'].toString(), 'all keys'
+
+    it 'world has a label', ->
+      assert.equal world.label(), "root", "label"
+      assert.equal "#{world}", "World_root", "toString"
+
+    it 'world can find children', ->
+      assert.ok world.has_children(), "has some"
+      result = world.find_children()
+      assert.ok result, "finds children"
+      assert.equal result.length, 1, "1 child"
+
+      result = world.find_children("root")
+      assert.equal result.length, 0, "0 child"
+      result = world.find_children("root-0")
+      assert.equal result.length, 1, "1 child"
+
+    it 'world can replace children', ->
+      label = 'root-0'
+      assert.equal world.find_index(label), 0, "find_index"
+      original_count = world._child_count()
+      assert.equal world.find_child(label).get('c'), 3
+      replacement = {_LABEL: label, c: 9}
+      world.replace_child(replacement)
+      assert.equal world.find_child(label).get('c'), 9
+      assert.equal world._child_count(), original_count, "changed count"
+
+    # TODO: Break this up into smaller tests somehow
+    it 'world has children inherit', ->
+      assert.ok world.has_children(), "world.has_children"
+      grandma = world.add_child("Premela")
+      assert.notOk grandma.has_children(), "grandma.has_children NOT"
+      mom = grandma.add_child("Sandhya")
+      assert.ok grandma.has_children(), "grandma.has_children"
+      daughter = mom.add_child("Anjali")
+      assert.ok mom.has_children(), "mom.has_children"
+      assert.ok daughter, "daughter"
+      assert.equal "#{daughter}", "World_Anjali", "daughter name"
+      result = mom.map_children (child) -> "#{child.label()} Prabhakar"
+      assert.equal result[0], "Anjali Prabhakar", "map child"
+      assert.equal daughter.find_parent("Premela"), grandma, 'Find ancestor'
+      assert.equal daughter.find_parent("Abraham"), world, 'Unknown ancestor'
+
+      candy = 'chocolate'
+      assert.notOk daughter.get(candy), "No chocolate"
+      assert.notOk daughter.owner(candy), "No chocolate owner"
+      grandma.put(candy, 'dark')
+      assert.equal grandma.owner(candy), grandma, "chocolate owner self"
+      assert.equal daughter.owner(candy), grandma, "chocolate owner"
+      assert.equal daughter.get(candy), 'dark', "Inherit chocolate"
+      mom.put(candy, 0)
+      assert.equal daughter.owner(candy), mom, "chocolate owner 0"
+      assert.equal daughter.get(candy), 0, "Inherit chocolate 0"
+
+      assert.ok world.label() == "root", "equals root"
+      assert.ok daughter.find_parent("root"), "find_parent root"
+      assert.equal world, world.find_path('.'), "find root"
+      assert.equal world, daughter.find_path('.'), "find root from below"
+      assert.equal mom.find_path('Anjali'), daughter, "find child"
+      assert.equal daughter.find_path('.Premela'), grandma, "find ancestor"
+
+      assert.equal world.find_path('.Premela.Sandhya.Anjali'), daughter, "find path"
+
+      #t.equal daughter.find_any('Premela'), grandma, "find any ancestor"
+      #t.equal grandma.find_any('Anjali'), daughter, "find any descendant"
+
+    it 'world passes index as property when mapping', ->
+      count = 0
+      world.map_children (child) ->
+        index = child.index
+        assert.equal index, count, "#{child} should have index #{count}, not #{index}"
+        count = count + 1
+
+    it 'world removes child at index', ->
+      a = world.add_child('a')
+      b = world.add_child('b')
+      a2 = world.add_child('a')
+      world.map_children (child) -> "just to set index"
+      count = world._child_count()
+      assert.ok a.index, "a has index"
+      world.remove_child a2
+      assert.equal world._child_count(), count - 1
+      world.remove_child a
+      assert.equal world._child_count(), count - 2
+
+    it 'world has authorities', ->
+      comply = world._spawn_world("compliant")
+      authority = world._spawn_world("authority")
+      rebel = world._spawn_world("rebellious")
+      rebel.put("_AUTHORITY", authority)
+
+      world.put("foo", "bar")
+      assert.equal comply.get('foo'), 'bar', 'comply foo'
+      assert.equal rebel.get('foo'), 'bar', 'rebel foo'
+      authority.put('foo', 'baz')
+      assert.equal comply.get('foo'), 'bar', 'comply foo'
+      assert.equal rebel.get('foo'), 'baz', 'rebel foo with authority'
+
+    it 'world has dynamic properties', ->
+      value = "wanna"
+      world.put("fun", -> value)
+      assert.equal typeof world.get_raw("fun"), 'function', "raw function"
+      assert.equal world.get("fun"), value, "dynamic property"
+
+    it 'world can call functions', ->
+      world.put("instance", "variable")
+      args = {key: "value"}
+      callme = (world, args) -> [world.get("instance"), args['key']]
+      world.put('callme', callme)
+      result = world.call('callme', args)
+      assert.equal result[0], "variable", "world parameter"
+      assert.equal result[1], "value", "args parameter"
+
+    it 'world knows worlds', ->
+      assert.ok world.is_world(world), "non-world"
+      assert.notOk world.is_world(1), "non-world"
+      assert.ok world.is_root(), "is root"
+      branch = world.add_child("branch")
+      assert.notOk branch.is_root(), "is not root"
+
+    it 'world generates CSS labels', ->
+      daughter = world.add_child("daughter")
+      daughter.put("_CSS", "klass")
+      css = daughter.labels(["css"])
+      assert.ok css.length > 2, "Traverse label hierarchy"
+      assert.ok "klass" in css, "Has explicit class"
+      assert.ok "root" in css, "Has root"
+
+    it 'config handlers', ->
+      assert.equal world.handlers_for('begin').length, 0, "1 begin handler"
+      begun = false
+      finished = false
+      world.handle 'begin', -> begun = true
+      assert.equal world.handlers_for('begin').length, 1, "1 begin handler"
+      assert.equal world.handlers_for('finish').length, 0, "0 finish handler"
+      world.handle 'finish', -> finished = true
+      assert.equal world.handlers_for('finish').length, 1, "0 finish handler"
+
+      assert.notOk begun, "Has not ran"
+      assert.notOk finished , "Has not finished"
+      world.send 'begin'
+      assert.ok begun, "Has begun"
+      world.send 'finish'
+      assert.ok finished, "Has finished"
+
+    it 'event callbacks', ->
+      val = 42
+      assert.notOk world.get('property'), "no property yet"
+      world.handle 'value', (key, args) -> args
+      world.send 'value', val, (value) -> world.put('property', value)
+      assert.equal world.get('property'), val, "property not set"


Fix copy diagram bug

Fix copy diagram bug

--- view/coffee/creator/create_diagram.coffee
+++ view/coffee/creator/create_diagram.coffee
@@ -20,13 +20,14 @@
       getTypes: ->
         API.getJSON '/api/train_types', (json) =>
           @types = json
-      getStations: ->
+      getStations: (done) ->
         API.getJSON '/api/line_stations', (json) =>
           @stations = json
           for s in @stations
             s.name = "#{s.line.name} #{s.station.name}"
           @matcher = stationMatcher(@stations)
           @setAutoCompleteAll()
+          done()
       getScrape: ->
         ids = @parseScrapeUrl(@scrape)
         API.getJSON "/api/scrape/train/#{ids[0]}/#{ids[1]}", (json) =>
@@ -111,8 +112,8 @@
             @starts = starts.join(', ')
     ready: ->
       @getTypes()
-      @getStations()
-      @setUpdate()
+      @getStations ->
+        @setUpdate()
     watch:
       stops: ->
         @setAutoCompleteAll()


passphrase update db confirm

passphrase update db confirm

--- web/js/services/passphrase_service.coffee
+++ web/js/services/passphrase_service.coffee
@@ -11,7 +11,7 @@
     @submit = ->
       old_key = $.jStorage.get 'passphrase'

-      if !update_db
+      if !$scope.update_db
         $.jStorage.set 'passphrase', $scope.passphrase
         window.location.reload()
       else


changed modal width

changed modal width

--- client/app/Applications/Account.kdapplication/account/accKiteList.coffee
+++ client/app/Applications/Account.kdapplication/account/accKiteList.coffee
@@ -40,7 +40,7 @@
       list.addItem itemData, null, {type : "slideDown", duration : 100}
       new KDModalView
         title   : "New Kite Information"
-        width   : 550
+        width   : 580
         overlay : yes
         content : """
                   <div class='modalformline'>


demonstrate that each svgo options must be in its own literal

--- app/templates/gulp/tasks/rev.coffee
+++ app/templates/gulp/tasks/rev.coffee
@@ -65,7 +65,8 @@
       progressive: true,
       interlaced: true,
       svgoPlugins: [
-        { removeViewBox: false }
+        { removeViewBox: false },
+        { cleanupIDs: false },
       ],
       use: [pngquant()]
     }


Add Hebrew as a supported language to activate translation ability for a partner

--- app/views/core/RootView.ozar.coffee
+++ app/views/core/RootView.ozar.coffee
@@ -111,7 +111,7 @@
     eventAction = $(e.target)?.closest('a')?.data('event-action')
     if eventAction
       window.tracker?.trackEvent eventAction, { category: 'Teachers' }
-
+
   onClickDashboardToggleLink: (e) ->
     $(e.target)?.parent('.dashboard-button')?.addClass('active')
     $(e.target)?.parent('.dashboard-button')?.siblings('.dashboard-button')?.removeClass('active')
@@ -168,7 +168,7 @@

   addLanguagesToSelect: ($select, initialVal) ->
     # For now, we only want to support a few languages for Ozaria when launching for HoC 2019:
-    supportedLanguages = ['en-US', 'es-419', 'zh-HANS', 'ru']
+    supportedLanguages = ['en-US', 'es-419', 'zh-HANS', 'ru', 'he']
     filteredLocale = _.pick(locale, supportedLanguages)
     codes = _.keys(filteredLocale)


Add inspector for GBM model output

Add inspector for GBM model output

--- src/ext/modules/routines.coffee
+++ src/ext/modules/routines.coffee
@@ -333,6 +333,10 @@
     inspect_ model,
       parameters: inspectModelParameters model

+  extendGBMModel = (model) ->
+    inspect_ model,
+      parameters: inspectModelParameters model
+
   extendGLMModel = (model) ->
     inspect_ model,
       parameters: inspectModelParameters model
@@ -343,6 +347,8 @@
         extendKMeansModel model
       when 'deeplearning'
         extendDeepLearningModel model
+      when 'gbm'
+        extendGBMModel model
       when 'glm'
         extendGLMModel model


Make delete* routines not variadic

Make delete* routines not variadic

--- src/ext/modules/routines.coffee
+++ src/ext/modules/routines.coffee
@@ -1079,7 +1079,7 @@
       else
         go null, extendDeletedKeys frameKeys

-  deleteFrames = (frameKeys...) ->
+  deleteFrames = (frameKeys) ->
     switch frameKeys.length
       when 0
         assist deleteFrames
@@ -1140,7 +1140,7 @@
       else
         go null, extendDeletedKeys modelKeys

-  deleteModels = (modelKeys...) ->
+  deleteModels = (modelKeys) ->
     switch modelKeys.length
       when 0
         assist deleteModels


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/floating_text_effect.coffee
+++ src/floating_text_effect.coffee
@@ -2,7 +2,8 @@
 FloatingTextEffect is a simple subclass of `TextEffect`. It provides some defaults
 to move the text upward and fade it out over 0.5 seconds.

-    # adds a FloatingTextEffect to
+    # adds a FloatingTextEffect to the engine
+    # at
     engine.add 'FloatingTextEffect'
       x: 50
       y: 50


Allow to not use an axis at all in TS plotting API

--- bokehjs/src/coffee/api/plotting.coffee
+++ bokehjs/src/coffee/api/plotting.coffee
@@ -55,8 +55,8 @@
     attrs.x_range = @_get_range(attrs.x_range)
     attrs.y_range = @_get_range(attrs.y_range)

-    x_axis_type = attrs.x_axis_type ? "auto"
-    y_axis_type = attrs.y_axis_type ? "auto"
+    x_axis_type = if _.isUndefined(attrs.x_axis_type) then "auto" else attrs.x_axis_type
+    y_axis_type = if _.isUndefined(attrs.y_axis_type) then "auto" else attrs.y_axis_type
     delete attrs.x_axis_type
     delete attrs.y_axis_type


Has default vm should look at personal vms in koding group.

--- client/app/MainApp/VirtualizationController.coffee
+++ client/app/MainApp/VirtualizationController.coffee
@@ -183,9 +183,18 @@
       @info vm, callback? rest...

   hasDefaultVM:(callback)->
-    @fetchDefaultVmName (defaultVmName)=>
-      @fetchVMs (err, vms)->
-        callback defaultVmName in vms
+    # Default VM should be the personal vm in Koding group
+    @fetchVMs (err, vms)->
+      if err
+        warn "An error occured while fetching VMs:", err
+        return callback yes
+
+      # Check if there is at least one personal vm from koding group
+      for vm in vms
+        if (vm.indexOf 'vm-') is 0 and (vm.indexOf 'koding.kd.io') > -1
+          return callback yes
+
+      callback no

   createDefaultVM:->
     @hasDefaultVM (state)->


video: change click action to change from select

--- client/ide/lib/videocollaborationcontroller.coffee
+++ client/ide/lib/videocollaborationcontroller.coffee
@@ -1,4 +1,5 @@
 VideoCollaborationModel = require 'app/videocollaboration/model'
+socialHelpers = require './collaboration/helpers/social'

 module.exports = VideoCollaborationController =

@@ -14,6 +15,7 @@
       .on 'ParticipantJoined',             @bound 'handleVideoParticipantJoined'
       .on 'ParticipantLeft',               @bound 'handleVideoParticipantLeft'
       .on 'ActiveParticipantChanged',      @bound 'handleVideoActiveParticipantChanged'
+      .on 'SelectedParticipantChanged',    @bound 'handleVideoSelectedParticipantChanged'
       .on 'ParticipantAudioStateChanged',  @bound 'handleVideoParticipantAudioStateChanged'
       .on 'ParticipantCameraStateChanged', @bound 'handleVideoParticipantCameraStateChanged'

@@ -46,7 +48,7 @@

   switchToUserVideo: (nickname) ->

-    @videoModel.changeActiveParticipant nickname
+    @videoModel.changeSelectedParticipant nickname

   handleVideoAccessQuestionAsked: ->
@@ -71,8 +73,21 @@
     @emitToViews 'VideoParticipantDidLeave', participant

-  handleVideoActiveParticipantChanged: (participant) ->
-    @emitToViews 'VideoActiveParticipantDidChange', participant
+  handleVideoSelectedParticipantChanged: (nickname) ->
+
+    unless nickname
+      @emitToViews 'VideoSelectedParticipantDidChange', null, null
+      return
+
+    socialHelpers.fetchAccount nickname, (err, account) =>
+      return console.error err  if err
+      @emitToViews 'VideoSelectedParticipantDidChange', nickname, account
+
+
+  handleVideoActiveParticipantChanged: (nickname) ->
+    socialHelpers.fetchAccount nickname, (err, account) =>
+      return console.error err  if err
+      @emitToViews 'VideoActiveParticipantDidChange', nickname, account

   handleVideoParticipantAudioStateChanged: (participant, state) ->


client: change for copied link text

client: change for copied link text

--- client/ide/lib/views/statusbar/idestatusbar.coffee
+++ client/ide/lib/views/statusbar/idestatusbar.coffee
@@ -53,10 +53,7 @@

     copyLink = new kd.CustomHTMLView
       cssClass: 'copied-link'
-      partial: '''
-        Collaboration link is copied to clipboard.
-        Now, you can share it to invite someone to your session.
-      '''
+      partial: 'Collaboration link is copied to clipboard.'

     @collaborationLinkContainer.addSubView @collaborationLink = new kd.CustomHTMLView


client: ide: collab start/stop logic completely taken to statusbar

--- client/ide/lib/views/statusbar/idestatusbar.coffee
+++ client/ide/lib/views/statusbar/idestatusbar.coffee
@@ -1,32 +1,40 @@
-kd                     = require 'kd'
-globals                = require 'globals'
-nick                   = require 'app/util/nick'
-CustomLinkView         = require 'app/customlinkview'
-HelpSupportModal       = require 'app/commonviews/helpsupportmodal'
-IDEStatusBarAvatarView = require './idestatusbaravatarview'
-isSoloProductLite      = require 'app/util/issoloproductlite'
-isPlanFree             = require 'app/util/isPlanFree'
-isKoding               = require 'app/util/isKoding'
+kd                        = require 'kd'
+globals                   = require 'globals'
+nick                      = require 'app/util/nick'
+CustomLinkView            = require 'app/customlinkview'
+HelpSupportModal          = require 'app/commonviews/helpsupportmodal'
+IDEStatusBarAvatarView    = require './idestatusbaravatarview'
+isSoloProductLite         = require 'app/util/issoloproductlite'
+isPlanFree                = require 'app/util/isPlanFree'
+isKoding                  = require 'app/util/isKoding'
+ButtonViewWithProgressBar = require 'app/commonviews/buttonviewwithprogressbar'
+
+PROGRESS_DELAYS             = [
+    { delay : 500,  progress : 15 }
+    { delay : 1500, progress : 30 }
+    { delay : 2500, progress : 75 }
+    { delay : 3250, progress : 90 }
+  ]

 module.exports = class IDEStatusBar extends kd.View

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

-    options.cssClass = 'status-bar'
+    options.cssClass = 'IDE-StatusBar'

     super options, data

     @participantAvatars = {}
     @avatarTimers       = {}

-    @on 'ShowAvatars',          @bound 'showAvatars'
-    @on 'ParticipantLeft',      @bound 'dimParticipantAvatar'
-    @on 'ParticipantJoined',    @bound 'addParticipantAvatar'
-    @on 'CollaborationLoading', @bound 'handleCollaborationLoading'
-    @on 'CollaborationEnded',   @bound 'handleCollaborationEnded'
-    @on 'CollaborationStarted', @bound 'handleCollaborationStarted'
-    @on 'ParticipantWatched',   @bound 'decorateWatchedAvatars'
-    @on 'ParticipantUnwatched', @bound 'decorateUnwatchedAvatars'
+    @on 'ShowAvatars',                 @bound 'showAvatars'
+    @on 'ParticipantLeft',             @bound 'dimParticipantAvatar'
+    @on 'ParticipantJoined',           @bound 'addParticipantAvatar'
+    @on 'CollaborationLoading',        @bound 'handleCollaborationLoading'
+    @on 'CollaborationEnded',          @bound 'handleCollaborationEnded'
+    @on 'CollaborationStarted',        @bound 'handleCollaborationStarted'
+    @on 'ParticipantWatched',          @bound 'decorateWatchedAvatars'
+    @on 'ParticipantUnwatched',        @bound 'decorateUnwatchedAvatars'

     { mainController, router, appManager } = kd.singletons

@@ -67,8 +75,6 @@
       placement : 'above'
       sticky    : yes

-
-
     @addSubView new kd.CustomHTMLView
       tagName  : 'i'
       cssClass : 'icon help'
@@ -81,19 +87,13 @@
         kd.utils.stopDOMEvent event
         router.handleRoute '/Account/Shortcuts'

-    @addSubView @share = new CustomLinkView
-      href     : "#{kd.singletons.router.getCurrentPath()}/share"
-      title    : 'Loading'
-      cssClass : 'share fr hidden'
-      click    : (event) =>
-        kd.utils.stopDOMEvent event
-
-        return  if @share.hasClass 'loading'
-        return  unless appManager.frontApp.isMachineRunning()
-
-        if @share.hasClass 'active'
-        then @handleSessionEnd()
-        else appManager.tell 'IDE', 'showChat'
+    @addSubView @share = new ButtonViewWithProgressBar
+      cssClass        : 'share fr hidden'
+      buttonOptions   :
+        title         : 'Loading'
+        cssClass      : 'start-session transparent'
+        callback      : @bound 'handleShareButtonClick'
+

     if isKoding() and isSoloProductLite()
       isPlanFree (err, isFree) =>
@@ -117,6 +117,41 @@
       @avatars.show()  unless collabDisabled

+  handleShareButtonClick: (event) ->
+
+    { appManager } = kd.singletons
+
+    kd.utils.stopDOMEvent event
+
+    return  if @share.hasClass 'loading'
+    return  unless appManager.frontApp.isMachineRunning()
+
+    if @share.hasClass 'active'
+    then @handleSessionEnd()
+    else @startSession()
+
+
+  startSession: ->
+
+    console.log 'startSession'
+
+    { appManager } = kd.singletons
+
+    appManager.tell 'IDE', 'setInitialSessionSetting', 'readOnly', yes
+    appManager.tell 'IDE', 'setInitialSessionSetting', 'muteHost', no
+
+    @share.updateProgress 0 # Make sure initial value is 0
+
+    PROGRESS_DELAYS.forEach (item) =>
+      kd.utils.killWait item.timer  if item.timer # Kill already defined waits
+      item.timer = kd.utils.wait item.delay, => @share.updateProgress item.progress
+
+    appManager.tell 'IDE', 'startCollaborationSession', (err) => @resetProgress()  if err
+
+
+  resetProgress: -> @share.resetProgress()
+
+
   showInformation: ->

     @status.updatePartial 'Click the plus button above to create a new panel'
@@ -208,21 +243,24 @@
   handleCollaborationLoading: ->

     if @share
-      @share.setClass      'loading'
-      @share.unsetClass    'active not-started'
-      @share.updatePartial 'Loading'
+      @share.setClass        'loading'
+      @share.unsetClass      'active not-started'
+      @share.button.setTitle 'Loading'
       @share.show()
+      @resetProgress()
+
     @video.hide()

   handleCollaborationEnded: ->

     if @share
-      @share.setClass      'not-started'
-      @share.unsetClass    'active loading red'
-      @share.updatePartial 'START COLLABORATION'
+      @share.setClass        'not-started'
+      @share.unsetClass      'active loading red'
+      @share.button.setTitle 'START COLLABORATION'
+      @resetProgress()
+
     @avatars.destroySubViews()
-
     @updateCollaborationLink ''

     @video.hide()
@@ -233,9 +271,11 @@
   handleCollaborationStarted: (options) ->

     if @share
-      @share.setClass      'active red'
-      @share.unsetClass    'loading not-started green'
-      @share.updatePartial 'END COLLABORATION'
+      @share.setClass        'active red'
+      @share.unsetClass      'loading not-started green'
+      @share.button.setTitle 'END COLLABORATION'
+      @resetProgress()
+
     @video.show()
     @video.setAttribute 'href', "http://appear.in/koding-#{options.channelId}"

@@ -243,7 +283,7 @@
     @updateCollaborationLink options.collaborationLink

     unless @amIHost_()
-      @share?.updatePartial 'LEAVE SESSION'
+      @share?.button.setTitle 'LEAVE SESSION'

   updateCollaborationLink: (collaborationLink) ->
@@ -255,7 +295,8 @@

     ide = kd.singletons.appManager.getFrontApp()

-    if   @amIHost_() then ide.showEndCollaborationModal()
+    if @amIHost_()
+    then ide.showEndCollaborationModal()
     else ide.handleParticipantLeaveAction nick()


form workflow: forward any "Cancel" events from the forms

Any form should be able to send a signal to "cancel" the workflow.  This event can be listened to from outside the workflow

--- client/landing/app/CommonViews/formworkflow.coffee
+++ client/landing/app/CommonViews/formworkflow.coffee
@@ -74,6 +74,7 @@
     @forms[formName] = form
     @addSubView form
     form.hide()
+    @forwardEvent form, 'Cancel'
     @provideData formName, provides
     return this


context switching syntax

context switching syntax

--- grammars/intuicio4.cson
+++ grammars/intuicio4.cson
@@ -179,7 +179,7 @@
 	}
 	{
 		# operation
-		'match': '\\b(call|async|parallel|join|ret|mov|add|sub|mul|div|and|or|xor|neg|lsh|rsh|eq|ls|gr|push|pop|drop|jif|goto|new|del|ptr|val|cast|nil|vargs|vargr|mtxc|mtxd|lock|unlock)\\b'
+		'match': '\\b(call|async|join|ret|mov|add|sub|mul|div|and|or|xor|neg|lsh|rsh|eq|ls|gr|push|pop|drop|ctxc|ctxd|ctxs|jif|goto|jump|address|new|del|ptr|val|cast|nil|vargs|vargr|mtxc|mtxd|lock|unlock)\\b'
 		'name': 'keyword.control.operation.intuicio4'
 	}
 	{


Client: Adjust sprite sizes.

Client: Adjust sprite sizes.

--- client/app/js/views/battle_view.coffee
+++ client/app/js/views/battle_view.coffee
@@ -147,7 +147,7 @@
       gen   = battle.get('generation').toUpperCase()
       {id}  = window.Generations[gen].SpeciesData[name]
       url   = PokemonSprite(id, forme, front: front, shiny: shiny)
-      scale = if front then .75 else 1
+      scale = if front then 1 else 1.3
       addPokemonImage($this, url, scale: scale, callback: callback)

   changeHP: (player, slot, oldPixels, done) =>


fix git mangle take 3

fix git mangle take 3

--- common/static/coffee/src/discussion/content.coffee
+++ common/static/coffee/src/discussion/content.coffee
@@ -150,12 +150,6 @@
       else
         @get("title")

-    comment_count: ->
-      count = 0
-      @get('comments').each (comment) ->
-        count += comment.getCommentsCount() + 1
-      count
-
   class @Comments extends Backbone: ->
       if @has("highlighted_title")
         String(@get("highlighted_title")).replace(/<highlight>/g, '<mark>').replace(/<\/highlight>/g, '</mark>')
@@ -171,7 +165,6 @@

     created_at_time: ->
       new Date(@get("created_at")).getTime()
-

   class @Comment extends @Content
     urlMappers:
@@ -184,8 +177,6 @@
       'delete': -> DiscussionUtil.urlFor('delete_comment', @id)
       'flagAbuse'   : -> DiscussionUtil.urlFor("flagAbuse_#{@get('type')}", @id)
       'unFlagAbuse' : -> DiscussionUtil.urlFor("unFlagAbuse_#{@get('type')}", @id)
-
-

     getCommentsCount: ->
       count = 0


precompute some graph data

precompute some graph data

--- app/graph.coffee
+++ app/graph.coffee
@@ -162,14 +162,6 @@
         line.interpolate params.interpolate
         area.interpolate params.interpolate

-      line_mode = (d, i) ->
-        if params.areaMode is 'all' or params.areaMode is 'stacked'
-          'area'
-        else if params.areaMode is 'first' and i is 0
-          'area'
-        else
-          'line'
-
       stack = d3.layout.stack()
         .offset(params.areaOffset)
         .values((d) -> d.values)
@@ -179,45 +171,22 @@
           d.y0 = y0
           d.value = y)

-      line_fn = (d, i) ->
-        mode = line_mode d, i
-        if mode is 'line'
-          line
-        else
-          area
-
     if params.drawNullAsZero
       transform_value = (v) -> v ? 0
       filter_scatter_values = _.identity
       expand_line_values = _.identity
     else
+      # TODO this won't work well with stack
       transform_value = (v) -> v
       filter_scatter_values = (values) ->
         _.filter values, (d) -> d.value?
-      expand_line_values = (values) ->
-        result = []
-        segment_length = 0
-        previous = null
-        _.each values, (v, i) ->
-          if v.value?
-            segment_length++
-            previous = v
-          else
-            if segment_length is 1
-              result.push previous
-            segment_length = 0
-
-          result.push v
-
-        if segment_length is 1
-          result.push previous
-        result
+      expand_line_values = expandIsolatedValuesToLineSegments

     time_min = null
     time_max = null
     value_min = null
     value_max = null
-    targets = for s in data
+    targets = for s, targetIndex in data
       values = for datapoint, i in s.datapoints
         value = get_value datapoint, i
         timestamp = get_timestamp datapoint, i
@@ -228,7 +197,22 @@
         value_max = Math.max value, value_max
         {value, time: moment(timestamp * 1000), original: datapoint}
       bisector = d3.bisector (d) -> d.time
-      {values, bisector, name: s.target}
+      lineValues = expand_line_values values
+      scatterValues = filter_scatter_values values
+      lineMode =
+        if params.areaMode is 'all' or params.areaMode is 'stacked'
+          'area'
+        else if params.areaMode is 'first' and targetIndex is 0
+          'area'
+        else
+          'line'
+
+      lineFn = if lineMode is 'line'
+        line
+      else
+        area
+      targetColor = color targetIndex
+      {values, bisector, name: s.target, lineValues, scatterValues, lineMode, lineFn, color: targetColor}

     if params.areaMode is 'stacked'
       stack targets
@@ -275,9 +259,6 @@
         .attr('class', 'crosshair-time')
         .attr('y', -6)

-    clearExtent = (v) -> _.extend {}, v, {extent: null}
-    setBrushing = (v) -> _.extend {}, v, {brushing: true}
-    setNotBrushing = (v) -> _.extend {}, v, {brushing: false}
     brushed = ->
       brushBus.push if brush.empty() then clearExtent else (v) -> _.extend {}, v, {extent: brush.extent()}
     brushstart = -> brushBus.push setBrushing
@@ -296,7 +277,6 @@
     externalBrushChanges.onValue ({extent}) ->
       if extent?
         domain = x.domain()
-        []
         brush.extent [Math.min(Math.max(domain[0], extent[0]), domain[1]), Math.max(Math.min(domain[1], extent[1]), domain[0])]
       else
         brush.clear()
@@ -355,11 +335,11 @@
         lineWidth = params.lineWidth

       path = target.append("path")
-          .attr('class', line_mode)
-          .attr('stroke', (d, i) -> color i)
+          .attr('class', (d) -> d.lineMode)
+          .attr('stroke', (d, i) -> d.color)
           .style('stroke-width', lineWidth)
-          .attr('fill', (d, i) -> if line_mode(d, i) is 'area' then color i)
-          .attr('d', (d, i) -> line_fn(d, i)(expand_line_values(d.values)))
+          .attr('fill', (d, i) -> if d.lineMode is 'area' then d.color)
+          .attr('d', (d, i) -> d.lineFn(d.lineValues))
       if hover
         path
         .style('stroke-opacity', 0)
@@ -377,14 +357,16 @@
         radius = 2
         opacity = 1
       target.append('g').attr('class', 'circles')
-        .selectAll('circle')
-          .data((d) -> filter_scatter_values d.values)
-        .enter().append("circle")
-          .attr('cx', (d) -> x d.time)
-          .attr('cy', (d) -> y d.value)
-          .attr('fill', (d, i, j) -> color j)
-          .attr('r', radius)
-          .style('fill-opacity', opacity)
+        .each (d) ->
+          circleColor = d.color
+          d3.select(this).selectAll('circle')
+            .data((d) -> d.scatterValues)
+          .enter().append("circle")
+            .attr('cx', (d) -> x d.time)
+            .attr('cy', (d) -> y d.value)
+            .attr('fill', circleColor)
+            .attr('r', radius)
+            .style('fill-opacity', opacity)

     if type is 'line'
       add_path target, false
@@ -402,7 +384,7 @@
         .attr('data-target', (d) -> d.name)
         .call(observe_mouse)
     legend_target.append('span')
-        .style('color', (d, i) -> color i)
+        .style('color', (d, i) -> d.color)
         .attr('class', 'color')
     legend_target.append('span')
         .text((d) -> d.name)
@@ -410,3 +392,26 @@
         .attr('class', 'crosshair-value')

     svg.style 'background-color', params.bgcolor
+
+clearExtent = (v) -> _.extend {}, v, {extent: null}
+setBrushing = (v) -> _.extend {}, v, {brushing: true}
+setNotBrushing = (v) -> _.extend {}, v, {brushing: false}
+
+expandIsolatedValuesToLineSegments = (values) ->
+  result = []
+  segment_length = 0
+  previous = null
+  _.each values, (v, i) ->
+    if v.value?
+      segment_length++
+      previous = v
+    else
+      if segment_length is 1
+        result.push previous
+      segment_length = 0
+
+    result.push v
+
+  if segment_length is 1
+    result.push previous
+  result


New FB:  fix call to new AjaxServer.Event

Other calls were fixed in 2fc02d5e380f9f153fb9f6811ad5d5886cc0e0c6 but this one escaped.

--- src/resources/forms/orbeon/newbuilder/resources/grid/action-icons.coffee
+++ src/resources/forms/orbeon/newbuilder/resources/grid/action-icons.coffee
@@ -86,7 +86,7 @@
         # Send a DOMActivate to the closest xforms-activable ancestor
         activable = YD.getAncestorByClassName trigger, "xforms-activable"
         form = Controls.getForm activable
-        event = new AjaxServer.Event form, activable.id, null, null, "DOMActivate"
+        event = new AjaxServer.Event form, activable.id, null, "DOMActivate"
         AjaxServer.fireEvents [event]

     # Reposition triggers after an Ajax request


Removed the separate interval for updates

Been waiting for a good reason to do this, and now I have one.
You should be able to (and in the past, were able to) use picking
and other off-screen rendering during controller or model update.
Now, trying to do so introduces a horrible white flickering. This
appears to be related to odd timing in relation to the actual render
process, interrupting it at some level (during back buffer swap?).

The solution is to perform update-related rendering, such as picking,
during the render pass. Hence, update must be performed during the
render pass.

This also removes an internal recurring setTimeout(), so it should
theoretically improve performance and increase battery longevity.

--- lib/assets/javascripts/jax/context.js.coffee
+++ lib/assets/javascripts/jax/context.js.coffee
@@ -45,17 +45,15 @@
         @stopUpdating()
         false

-    @_updateFunc = =>
-      timechange = @refreshUPS()
-      @update timechange
-      if @isUpdating() then @requestUpdateFrame()
-
     @_renderFunc = (time) =>
       # deal with time in seconds, not ms
       time *= 0.001
       @_renderStartTime = time if @_renderStartTime is null
       @uptime = time - @_renderStartTime
       if @_calculateFrameRate then @refreshFPS()
+      if @isUpdating()
+        timechange = @refreshUPS()
+        @update timechange
       @render()
       if @isRendering() then @requestRenderFrame()

@@ -160,7 +158,6 @@
   startUpdating: ->
     return if @isUpdating() or @isDisposed()
     @_isUpdating = true
-    @requestUpdateFrame()

   startRendering: ->
     return if @isRendering() or @isDisposed()
@@ -169,7 +166,6 @@

   stopUpdating: ->
     return unless @isUpdating()
-    @abortUpdateFrame()
     @_isUpdating = false

   stopRendering: ->
@@ -184,16 +180,6 @@
     @startRendering()
     @startUpdating()

-  requestUpdateFrame: ->
-    currTime = new Date().getTime()
-    timeToCall = Math.max 0, @updateSpeed - (currTime - (@_requestUpdateLastTime || 0))
-    @_updateHandle = setTimeout @_updateFunc, timeToCall
-    @_requestUpdateLastTime = currTime + timeToCall
-
-  abortUpdateFrame: ->
-    clearTimeout @_updateHandle if @_updateHandle isnt null
-    @_updateHandle = null
-
   requestRenderFrame: ->
     if Jax.useRequestAnimFrame and @useRequestAnimFrame
       @_requestedAnimFrame = true


util.measure with { full: true } option now measures width and height of the element viewport instead of the client area (which matches our absolute positioning of popups)

--- lib/assets/javascripts/unpoly/util.js.coffee
+++ lib/assets/javascripts/unpoly/util.js.coffee
@@ -943,6 +943,7 @@
       if opts.relative == true
         coordinates = $element.position()
       else
+        # A relative context element is given
         $context = $(opts.relative)
         elementCoords = $element.offset()
         if $context.is(document)
@@ -968,9 +969,9 @@
       box.height = $element.outerHeight()

     if opts.full
-      viewport = clientSize()
-      box.right = viewport.width - (box.left + box.width)
-      box.bottom = viewport.height - (box.top + box.height)
+      $viewport = up.layout.viewportOf($element)
+      box.right = $viewport.width() - (box.left + box.width)
+      box.bottom = $viewport.height() - (box.top + box.height)
     box

   ###*


Add a default perspective to the device context.

--- framer/Components/DeviceComponent.coffee
+++ framer/Components/DeviceComponent.coffee
@@ -113,6 +113,7 @@
 			layer.on "touchmove", (event) -> event.preventDefault()

 		@_context = new Framer.Context(parent:@content, name:"Device")
+		@_context.perspective = 1200

 	_update: =>


No background color for component

No background color for component

--- framer/Components/ScrollComponent.coffee
+++ framer/Components/ScrollComponent.coffee
@@ -43,12 +43,16 @@
 	@define "speedX", @proxyProperty("content.draggable.speedX", true)
 	@define "speedY", @proxyProperty("content.draggable.speedY", true)

-	constructor: ->
+	constructor: (options) ->
+
+		options.backgroundColor ?= null
+
 		super

 		@content = new Layer
 			width: @width
 			height: @height
+			backgroundColor: null
 			superLayer:@
 		@content.draggable.enabled = true
 		@content.draggable.momentum = true


Move import batch size outside method

Move import batch size outside method

--- app/assets/javascripts/admin/product_import/controllers/import_form_controller.js.coffee
+++ app/assets/javascripts/admin/product_import/controllers/import_form_controller.js.coffee
@@ -10,6 +10,7 @@
   $scope.updated_ids = []
   $scope.update_errors = []

+  $scope.batchSize = 50
   $scope.step = 'settings'
   $scope.chunks = 0
   $scope.completed = 0
@@ -51,14 +52,13 @@
   $scope.start = () ->
     $scope.started = true
     total = ams_data.item_count
-    size = 50
-    $scope.chunks = Math.ceil(total / size)
+    $scope.chunks = Math.ceil(total / $scope.batchSize)

     i = 0

     while i < $scope.chunks
-      start = (i*size)+1
-      end = (i+1)*size
+      start = (i * $scope.batchSize) + 1
+      end = (i + 1) * $scope.batchSize
       if $scope.step == 'import'
         $scope.processImport(start, end)
       if $scope.step == 'save'


model_postgres: getNodeListener() filter for null

--- src/local/model_postgres.coffee
+++ src/local/model_postgres.coffee
@@ -296,7 +296,7 @@
         @db.query "SELECT DISTINCT listener FROM subscriptions WHERE node = $1"
         , [node]
         , (err, res) ->
-            cb err, res?.rows?.map((row) -> row.listener)
+            cb err, res?.rows?.map((row) -> row.listener).filter((l) -> l?)

     ##
     # Affiliation management


redraw gorillas and banana

redraw gorillas and banana

--- views/gorillas.coffee
+++ views/gorillas.coffee
@@ -118,7 +118,7 @@
       @clear()
       @draw_the_sun()
       @redraw_buildings()
-      @draw_gorillas()
+      @redraw_gorillas()
     else
       @empty = false
       @draw_the_sun()
@@ -157,9 +157,14 @@
     building = @buildings[Math.floor(Math.random()*3)]
     @player_1 = new Gorilla(@context)
     @player_1.draw(building.position_at_x(), building.position_at_y())
+
     building = @buildings[Math.floor(Math.random()*6)+3]
     @player_2 = new Gorilla(@context)
     @player_2.draw(building.position_at_x(), building.position_at_y())
+
+  redraw_gorillas: ->
+    @player_1.redraw()
+    @player_2.redraw()

   throw_banana:(force, angle, player) ->
     if player == 2
@@ -173,8 +178,9 @@

   animate_banana:(player) ->
     setTimeout (=>
+      @draw_scene()
       this['player_' + player].throw_banana()
-      @draw_scene()
+
       @animate_banana(player)
       ),
       150
@@ -189,12 +195,15 @@
     image

   draw:(x, y) ->
-    @x = x+30
-    @y = y-40
+    @x ||= x+30
+    @y ||= y-40
     @context.drawImage(@image(), @x, @y, 40, 40)

+  redraw:() ->
+    @draw(@x, @y)
+
   grab_banana:(force, angle) ->
-    @banana = new Banana(@context, @x+30, @y-30, force, angle)
+    @banana ||= new Banana(@context, @x+30, @y-30, force, angle)

   throw_banana: ->
     @banana.draw_frame()


Stores should clean up after themselves

Stores should clean up after themselves

Actions should not have any state or listeners to destroy

--- src/smc-webapp/smc-react.coffee
+++ src/smc-webapp/smc-react.coffee
@@ -78,8 +78,6 @@
         @redux._set_state({"#{@name}": obj})
         return

-    destroy: =>
-        @redux.removeActions(@name)
 ###
 store_def =
     reduxState:
@@ -138,7 +136,8 @@
             @emit('change', state)

     destroy: =>
-        @redux.removeStore(@name)
+        @emit('destroy')
+        @removeAllListeners()

     getState: =>
         return @redux._redux_store.getState().get(@name)
@@ -365,14 +364,14 @@
             @_tables[name]._table?.close()
             delete @_tables[name]

+    # Removing a Store also destroys it
     removeStore: (name) =>
         if not name?
             throw Error("name must be a string")
         if @_stores[name]?
             S = @_stores[name]
-            S.emit('destroy')
             delete @_stores[name]
-            S.removeAllListeners()
+            S.destroy()
             @_redux_store.dispatch(action_remove_store(name))

     removeActions: (name) =>
@@ -381,7 +380,6 @@
         if @_actions[name]?
             A = @_actions[name]
             delete @_actions[name]
-            A.destroy()

     getTable: (name) =>
         if not name?


make the if statement & assigment more readable

--- client/landing/app/Applications/Environments.kdapplication/views/DomainMapperView.coffee
+++ client/landing/app/Applications/Environments.kdapplication/views/DomainMapperView.coffee
@@ -60,11 +60,10 @@
           vmName     : @getData().name
           state      : state
         , (err) =>
-          if not err
-            if state is on
-              notificationMsg = "Your domain is connected to the #{@getData().name} VM."
-            if state is off
-              notificationMsg = "Your domain is disconnected from the #{@getData().name} VM."
+          unless err
+            notificationMsg = if state
+            then "Your domain is connected to the #{@getData().name} VM."
+            else "Your domain is disconnected from the #{@getData().name} VM."
             new KDNotificationView {type: "top", title: notificationMsg}
           else
             new KDNotificationView {type: "top", title: err}


centering avatarview's tooltip

centering avatarview's tooltip

--- client/landing/app/Applications/Members.kdapplication/ContentDisplays/profileview.coffee
+++ client/landing/app/Applications/Members.kdapplication/ContentDisplays/profileview.coffee
@@ -353,7 +353,7 @@

     if KD.isMine @memberData
       avatarOptions.tooltip =
-        offset      : top: 0, left: -3
+        # offset      : top: 0, left: -3
         title       : "
Click avatar to edit
"
         placement   : "below"
         arrow       :


Add repocloner settings for easier generating of the site.

--- docpad.coffee
+++ docpad.coffee
@@ -8,10 +8,6 @@
   ignorePaths: [
     __dirname + '/src/documents/documentation/api'
   ]
-
-  #docpad-image-thumbnail plugin has not been updated.
-
-  skipUnsupportedPlugins: true

   # =================================
   # Template Data
@@ -302,6 +298,12 @@
     thumbnails:
       imageMagick: true

+    repocloner:
+      repos: [
+        name: 'HaxeFlixelDocumentation'
+        path: 'src/documents/documentation'
+        url: 'https://github.com/HaxeFlixel/flixel-docs.git'
+      ]
 }

 # Export our DocPad Configuration


docpad.coffee: move redundant doc collection code into a helper function

--- docpad.coffee
+++ docpad.coffee
@@ -111,6 +111,28 @@
       docsCollection = @getCollection(collection)
       return docsCollection.models[docsCollection.length-1]

+    getDocCollection:(database, index, dir, categoryName, categoryTitle) ->
+      query =
+        write: true
+        relativeOutDirPath: $endsWith: dir
+        body: $ne: ""
+      sorting = [categoryDirectory:1, filename:1]
+
+      database.findAllLive(query, sorting).on 'add', (document) ->
+        a = document.attributes
+        layout = 'doc'
+        urls = ['/documentation/' + a.basename.replace(/^[\-0-9]+/,'')]
+        githubEditUrl = 'https://github.com/HaxeFlixel/flixel-docs/blob/master/documentation/' + dir + '/'
+        editUrl = githubEditUrl + a.basename + '.html.md'
+        document.setMetaDefaults({
+          layout
+          url: urls[0]
+          categoryName
+          categoryTitle
+          editUrl
+          index
+        }).addUrl(urls)
+
   # =================================

   collections:
@@ -137,129 +159,19 @@
       database.findAllLive({tags:$has:'homepage_demo'}, [date:-1])

     getting_started: (database) ->
-      query =
-        write: true
-        relativeOutDirPath: $endsWith: '00_getting_started'
-        body: $ne: ""
-      sorting = [categoryDirectory:1, filename:1]
-
-      database.findAllLive(query, sorting).on 'add', (document) ->
-        a = document.attributes
-        index = 0
-        layout = 'doc'
-        urls = ['/documentation/' + a.basename.replace(/^[\-0-9]+/,'')]
-        categoryName = 'getting_started'
-        categoryTitle = 'Getting Started'
-        githubEditUrl = 'https://github.com/HaxeFlixel/flixel-docs/blob/master/documentation/00_getting_started/'
-        editUrl = githubEditUrl + a.basename + '.html.md'
-        document.setMetaDefaults({
-          layout
-          url: urls[0]
-          categoryName
-          categoryTitle
-          editUrl
-          index
-        }).addUrl(urls)
+      docpadConfig.templateData.getDocCollection(database, 0, '00_getting_started', 'getting_started', 'Getting Started')

     tutorial: (database) ->
-      query =
-        write: true
-        relativeOutDirPath: $endsWith: '04_tutorial'
-        body: $ne: ""
-      sorting = [categoryDirectory:1, filename:1]
-
-      database.findAllLive(query, sorting).on 'add', (document) ->
-        a = document.attributes
-        index = 1
-        layout = 'doc'
-        categoryName = 'tutorial'
-        categoryTitle = 'Tutorial'
-        urls = ['/documentation/' + a.basename.replace(/^[\-0-9]+/,'')]
-        githubEditUrl = "https://github.com/HaxeFlixel/flixel-docs/blob/master/documentation/04_tutorial/"
-        editUrl = githubEditUrl + a.basename + '.html.md'
-        document.setMetaDefaults({
-          layout
-          url: urls[0]
-          categoryName
-          categoryTitle
-          editUrl
-          index
-        }).addUrl(urls)
+      docpadConfig.templateData.getDocCollection(database, 1, '04_tutorial', 'tutorial', 'Tutorial')

     handbook: (database) ->
-      query =
-        write: true
-        relativeOutDirPath: $endsWith: '02_handbook'
-        body: $ne: ""
-      sorting = [categoryDirectory:1, filename:1]
-
-      database.findAllLive(query, sorting).on 'add', (document) ->
-        a = document.attributes
-        index = 2
-        layout = 'doc'
-        categoryName = 'handbook'
-        categoryTitle = "Handbook"
-        urls = ['/documentation/' + a.basename.replace(/^[\-0-9]+/,'')]
-        githubEditUrl = 'https://github.com/HaxeFlixel/flixel-docs/blob/master/documentation/02_handbook/'
-        editUrl = githubEditUrl + a.basename + '.html.md'
-        document.setMetaDefaults({
-          layout
-          url: urls[0]
-          categoryName
-          categoryTitle
-          editUrl
-          index
-        }).addUrl(urls)
+      docpadConfig.templateData.getDocCollection(database, 2, '02_handbook', 'handbook', 'Handbook')

     resources: (database) ->
-      query =
-        write: true
-        relativeOutDirPath: $endsWith: '03_resources'
-        body: $ne: ""
-      sorting = [categoryDirectory:1, filename:1]
-
-      database.findAllLive(query, sorting).on 'add', (document) ->
-        a = document.attributes
-        index = 3
-        layout = 'doc'
-        categoryName = 'resources'
-        categoryTitle = 'Resources'
-        urls = ['/documentation/' + a.basename.replace(/^[\-0-9]+/,'')]
-        githubEditUrl = "https://github.com/HaxeFlixel/flixel-docs/blob/master/documentation/03_resources/"
-        editUrl = githubEditUrl + a.basename + '.html.md'
-        document.setMetaDefaults({
-          layout
-          url: urls[0]
-          categoryName
-          categoryTitle
-          editUrl
-          index
-        }).addUrl(urls)
+      docpadConfig.templateData.getDocCollection(database, 3, '03_resources', 'resources', 'Resources')

     community: (database) ->
-      query =
-        write: true
-        relativeOutDirPath: $endsWith: '01_community'
-        body: $ne: ""
-      sorting = [categoryDirectory:1, filename:1]
-
-      database.findAllLive(query, sorting).on 'add', (document) ->
-        a = document.attributes
-        index = 4
-        layout = 'doc'
-        categoryName = 'community'
-        categoryTitle = 'Community'
-        urls = ['/documentation/' + a.basename.replace(/^[\-0-9]+/,'')]
-        githubEditUrl = 'https://github.com/HaxeFlixel/flixel-docs/blob/master/documentation/01_community/'
-        editUrl = githubEditUrl + a.basename + '.html.md'
-        document.setMetaDefaults({
-          layout
-          url: urls[0]
-          editUrl
-          categoryName
-          categoryTitle
-          index
-        }).addUrl(urls)
+      docpadConfig.templateData.getDocCollection(database, 4, '01_community', 'community', 'Community')

     rootDocuments: (database) ->
       query =


Rectified missing referral markup

Rectified missing referral markup

--- views/jsx/referral/all.cjsx
+++ views/jsx/referral/all.cjsx
@@ -105,7 +105,6 @@
                     'Completed'
                   else
                     'Confirmed'
-
                 }
               </small>
             else


added auto-update timeout for menus

added auto-update timeout for menus

--- static/coffee-script/app.coffee
+++ static/coffee-script/app.coffee
@@ -42,6 +42,8 @@
   candidate: ''    #a value we will try to apply asa it becomes valid, if ever
   options: []      #list of valid options

+  _timeout: null   #auto-update timer
+
   wish: (value) ->
     if value in @get 'options'
       @set 'value', value
@@ -50,12 +52,18 @@
       @set 'value', ''
       @set 'candidate', value

-  load: ->
-    #value = @get 'value'
-    #if value
-    #  @set 'candidate', value
-    #  @set 'value', ''
-    #@set 'options', []
+  load: (parentChanged)->
+    #clear auto-update timer
+    clearTimeout @_timeout if @_timeout
+    @_timeout = null
+
+    #reset data befor update
+    value = @get 'value'
+    if value
+      @set 'candidate', value
+    if parentChanged
+      @set 'value', ''
+      @set 'options', []

   _autoSelect: (() ->
     options = @get 'options'
@@ -101,8 +109,8 @@
         @get('parentUrl')+"/"+@get('parentValue')
       ).property('parentValue', 'parentUrl')

-      load: ((cb)->
-        @_super()
+      load: ((parentChanged, cb)->
+        @_super(parentChanged)
         parentValue = @get 'parentValue'
         if parentValue
           $.getJSON @get('databaseurl')+"/"+name+"s", cb
@@ -111,29 +119,37 @@
   else
     ListController.extend {
       databaseurl: baseurl
-      load: ( ->
-        @_super()
+      load: ((parentChanged) ->
+        @_super(parentChanged)
         $.getJSON @get('databaseurl')+"/"+name+"s", (data) =>
-          @set 'options', data
+          if not data.compareArrays(@get 'options')
+            @set 'options', data
+        _load: (-> @load true).observes 'parentValue'
       )
     }
   controller.create(init)

 Weathermaps.groups = createListController "group"
 Weathermaps.maps = createListController "map", "group", {
-  load: (->
-    @_super (data) =>
-       @set 'options', data
-  ).observes 'parentValue'
+  load: ((parentChanged)->
+    @_super true, (data) =>
+      if not data.compareArrays(@get 'options')
+        @set 'options', data
+        @_timeout = setTimeout (=> @load(false)), 60*60*1000#1 hour
+  )
+  _load: (-> @load true).observes 'parentValue'
 }
 Weathermaps.dates = createListController "date", "map", {
   default: 'first'
-  load: (->
-    @_super (data) =>
+  load: ((parentChanged)->
+    @_super true, (data) =>
       data.sort()
       data.reverse()
-      @set 'options', data
-  ).observes 'parentValue'
+      if not data.compareArrays(@get 'options')
+        @set 'options', data
+        @_timeout = setTimeout (=> @load(false)), 10*60*1000#10 min
+  )
+  _load: (-> @load true).observes 'parentValue'
 }
 Weathermaps.times = createListController "time", "date", {
   default: 'first'
@@ -141,19 +157,17 @@
   selected: (->
     @get('cache')[@get 'value']
   ).property 'value'
-  _timeout: null
-  load: (->
-    clearTimeout @_timeout if @_timeout
-    @_timeout = null
-
-    @_super (data) =>
+  load: ((parentChanged)->
+    @_super parentChanged, (data) =>
       k = keys data
       k.sort()
       k.reverse()
-      @set 'options', k
-      @set 'cache', data
-      @_timeout = setTimeout (=> @load()), 60*1000#1 min
-  ).observes 'parentValue'
+      if not k.compareArrays(@get 'options')
+        @set 'options', k
+        @set 'cache', data
+      @_timeout = setTimeout (=> @load(false)), 60*1000#1 min
+  )
+  _load: (-> @load true).observes 'parentValue'
 }

 Weathermaps.current = Ember.Object.create {


fixing comment input expander

fixing comment input expander

--- app/coffee/showentry.coffee
+++ app/coffee/showentry.coffee
@@ -53,9 +53,8 @@
   $('#comment_body').live "blur", =>
     @commentsFocused = false

-  $('#comment_body').bind("keyup", ->
+  $('#comment_body').live "keyup", ->
     fitToContent(this, 0)
-  )

   # Keyboard navigation between entries
   # Check if comment field is focused


Troubleshoot: Modal is not closable until troubleshoot completes

--- client/Main/troubleshoot/troubleshootmodal.coffee
+++ client/Main/troubleshoot/troubleshootmodal.coffee
@@ -7,6 +7,7 @@
         title                 : "Checking Koding Status"
         overlay               : yes
         cssClass              : "troubleshoot-modal"
+        cancelable            : no
         tabs                  :
           forms               :
             Troubleshoot      :
@@ -49,7 +50,9 @@
                   placeholder : "Define the situation"

     super options, data
+    @overlay.off "click"
     @hideFeedback()
+    @modalTabs.forms.Troubleshoot.buttons.close.hide()
     @modalTabs.forms.Troubleshoot.fields.result.hide()
     troubleshoot.off "recoveryCompleted"
     troubleshoot.on "recoveryCompleted", =>
@@ -58,7 +61,7 @@

     troubleshoot.once "troubleshootCompleted", =>
       # show feedback form if there are any errors apart from connection down
-
+      @modalTabs.forms.Troubleshoot.buttons.close.show()
       if troubleshoot.isSystemOK()
         return @modalTabs.forms.Troubleshoot.fields.result.show()
       @showFeedback()  unless troubleshoot.isConnectionFailed()


ComputeController: createGroupStack: quit from all IDE instances on reinit [fixes #109879840]

--- client/app/lib/providers/computecontroller.coffee
+++ client/app/lib/providers/computecontroller.coffee
@@ -1145,9 +1145,8 @@
             new kd.NotificationView
               title : 'Stack reinitialized'

-            # We need to quit here to be able to re-load
-            # IDE with new machine stack, there might be better solution ~ GG
-            frontApp = kd.singletons.appManager.getFrontApp()
-            frontApp.quit()  if frontApp?.options.name is 'IDE'
+            kd.singletons.appManager.quitByName 'IDE'
+            kd.utils.defer ->
+              kd.singletons.router.handleRoute '/IDE'

           .createDefaultStack()


ComputeController: use stack.machines instead

--- client/app/lib/providers/computecontroller.coffee
+++ client/app/lib/providers/computecontroller.coffee
@@ -503,9 +503,7 @@
         kd.warn 'Stack already initialized, skipping.', stack
       return

-    stack.machines.forEach (machineId) =>
-      return  unless machine = @findMachineFromMachineId machineId
-
+    stack.machines.forEach (machine) =>
       @eventListener.triggerState machine,
         status      : Machine.State.Building
         percentage  : 0
@@ -549,8 +547,7 @@
         name    : 'InProgress'
         message : "This stack is currently #{state.toLowerCase()}."

-    if followEvents then stack.machines.forEach (machineId) =>
-      return  unless machine = @findMachineFromMachineId machineId
+    if followEvents then stack.machines.forEach (machine) =>

       @eventListener.triggerState machine,
         status      : Machine.State.Terminating


[client][app][main][login] added modal for long message notifications

--- client/landing/app/MainApp/login/loginview.coffee
+++ client/landing/app/MainApp/login/loginview.coffee
@@ -206,9 +206,23 @@
       {entryPoint} = KD.config

       if err
-        new KDNotificationView
-          title   : err.message
-          duration: 1000
+        if err.message.length > 50
+          new KDModalView
+            title        : "Something is wrong!"
+            width        : 500
+            overlay      : yes
+            cssClass     : "new-kdmodal"
+            content      :
+              """
+                <div class='modalformline'>
+                  #{err.message}
+                </div>
+              """
+        else
+          new KDNotificationView
+            title   : err.message
+            duration: 1000
+
         @loginForm.resetDecoration()
       else
         $.cookie 'clientId', replacementToken  if replacementToken