Added udefine.inject.remove + add & remove functions for udefine.modules

--- src/udefine.coffee
+++ src/udefine.coffee
@@ -71,10 +71,10 @@

   udefine.inject.modules = {}

-  udefine.inject.add = (name) ->
-    udefine.inject.modules[name] = undefined
+  udefine.inject.add = (name) -> udefine.inject.modules[name] = undefined
+  udefine.inject.remove = (name) -> delete udefine.inject.modules[name]

-  udefine.inject.reset = -> udefine.inject.modules = {}
+  udefine.inject.clear = -> udefine.inject.modules = {}

   # TODO: Reflect if these two object could and should be merged together
   # Dependencies for browser (global object)
@@ -89,8 +89,15 @@
     globals: {}
     commonjs: {}

-    add: (name) ->
-    remove: (name) ->
+    add: (name) ->
+      if typeof name is 'object'
+      udefine.modules[platform][name] = undefined
+    remove: (name) ->
+      if Object.hasOwnProperty.call udefine.modules.globals, name
+        delete udefine.modules['globals'][name]
+
+      if Object.hasOwnProperty.call udefine.modules.commonjs, name
+        delete udefine.modules['commonjs'][name]

     get: ->
     set: ->


Fix code style issues

Fix code style issues

--- test/serializationTest.coffee
+++ test/serializationTest.coffee
@@ -5,8 +5,8 @@

 describe "Serialization", ->
   it "should serialize a basic graph", ->
-    base =
-      int:1
+    base =
+      int:1
       float:2.99e81
       str:"test"
       obj:
@@ -59,7 +59,7 @@
     deserialized.y.z.y.should.equal deserialized.y

   it "should serialize a function which knows about 'this'", ->
-    x =
+    x =
       value:"hello"
       func: ->
         @value


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/string_extensions.coffee
+++ test/string_extensions.coffee
@@ -33,7 +33,7 @@

 test "#startsWith", ->
   ok "cool".startsWith("coo")
-  equals f
+  equals "cool".startsWith(), false

 test "#titleize", ->
   equals "man from the boondocks".titleize(), "Man From The Boondocks"


chorus: better code for libraries

chorus: better code for libraries

--- scripts-src/application.coffee
+++ scripts-src/application.coffee
@@ -1019,17 +1019,18 @@
           @_putRecord rec
       @updateLibrarySize()
       null
-
+    _libraryKey: (name) -> "library-"+name
+
     load: (storage, name) ->
+      unless (@_libraryKey name) of storage
+        alert "Library \"#{name}\" is not present in the storage."
+        return
       if @modified
         unless confirm "Current library has unsaved modifications. Do you want to discard them?"
           return
-      unless ("library-"+name) of storage
-        alert "Library \"#{name}\" is not present in storage."
-        return
       @clear()
       @name = name
-      @_importData JSON.parse storage["library-"+name]
+      @_importData JSON.parse storage[ @_libraryKey name]
       @modified = false
       @updateLibrarySize()
       @updateLibraryName()
@@ -1041,19 +1042,19 @@
       if newName or (name is "")
         name = prompt "Please enter library name", @defaultLibraryForRule @golApp.gol.rule
         if not name then return
-        if ("library-" + name) of storage
+        if (@_libraryKey name) of storage
           unless confirm "Library #{name} already exists in the storage. Do you want to overwrite it?"
             return
         @name = name
         @updateLibraryName()
-      storage["library-" + name] = @data2string()
+      storage[@_libraryKey name] = @data2string()
       @modified = false
       @updateLibrarySize()
     deleteCurrent: (storage)->
       unless @name
         alert "Library is not saved"
         return
-      delete storage["library-"+@name]
+      delete storage[@_libraryKey @name]
       @clear()

     addRecord: (record)->


<tests> Rule - Removed useless preparations.

--- tests/controllers/rule.coffee
+++ tests/controllers/rule.coffee
@@ -65,21 +65,8 @@
                 module: require '../../server/drivers/' + fixturesDriver.basicActuatorDriver.name + '/' + fixturesDriver.basicActuatorDriver.name
             done null

-    before (done) ->
-        sensor = fixturesSensor.supportedSensor1
-        sensor.driverId = store.driverSensor.instance.id
-        helpers.createActuator(sensor) () ->
-            store["sensor"] = helpers.getInStore('sensor')
-            done null

-    before (done) ->
-        actuator = fixturesActuator.supportedActuator1
-        actuator.driverId = store.driverActuator.instance.id
-        helpers.createActuator(actuator) () ->
-            store["actuator"] = helpers.getInStore('actuator')
-            done null
-
-    after  helpers.killServer
+    after helpers.killServer
     after helpers.clearFiles

     describe 'When we create a Rule (POST /rules)', ->


Removed trailing whitespace

Removed trailing whitespace

--- tests/src/coffee/tests.coffee
+++ tests/src/coffee/tests.coffee
@@ -126,7 +126,7 @@
                         steps.push(myAnimation._step)
                         myAnimation.play()

-                        setTimeout( ->
+                        setTimeout( ->
                             steps.push(myAnimation._step)
                             strictEqual(steps[0], 0, "step should remain the same after pause")
                             strictEqual(steps[1], 1, "animation should continue after used play")


#43 links are opened on a new tab

#43 links are opened on a new tab

--- src/client/common_stat.coffee
+++ src/client/common_stat.coffee
@@ -45,10 +45,10 @@
         $('.stat-tables').show()
         players = extended(players)
         for player in players
-            $("
	#{player.name}	#{player.averageRating}	#{player.gamesTotal}	#{player.winsTotal}	#{player.rating}
").appendTo('.common-rating tbody')
-            $("
	#{player.name}	#{player.winsTotal}	#{player.winsCitizen}	#{player.winsSheriff}	#{player.winsMafia}	#{player.winsDon}
").appendTo('.wins tbody')
-            $("
	#{player.name}	#{player.gamesTotal}	#{player.gamesCitizen}	#{player.gamesSheriff}	#{player.gamesMafia}	#{player.gamesDon}
").appendTo('.roles tbody')
-            $("
	#{player.name}	#{player.likes}	#{player.bestPlayer}	#{player.bestMoveAccuracy}	#{player.firstKilledNight}	#{player.firstKilledDay}	#{player.fouls}
").appendTo('.impact tbody')
+            $("
	#{player.name}	#{player.averageRating}	#{player.gamesTotal}	#{player.winsTotal}	#{player.rating}
").appendTo('.common-rating tbody')
+            $("
	#{player.name}	#{player.winsTotal}	#{player.winsCitizen}	#{player.winsSheriff}	#{player.winsMafia}	#{player.winsDon}
").appendTo('.wins tbody')
+            $("
	#{player.name}	#{player.gamesTotal}	#{player.gamesCitizen}	#{player.gamesSheriff}	#{player.gamesMafia}	#{player.gamesDon}
").appendTo('.roles tbody')
+            $("
	#{player.name}	#{player.likes}	#{player.bestPlayer}	#{player.bestMoveAccuracy}	#{player.firstKilledNight}	#{player.firstKilledDay}	#{player.fouls}
").appendTo('.impact tbody')

     updateTables = (urlString)->
         request = {


Fix typos

Fix typos

--- src/coffee/controllers.coffee
+++ src/coffee/controllers.coffee
@@ -409,7 +409,7 @@

     twitterShareUrl = ->
         event = event or window.event
-        if event.stoppPropagation then event.stopPropagation()
+        if event.stopPropagation then event.stopPropagation()
         else (event.cancelBubble = true)

         place = $scope.place
@@ -436,7 +436,7 @@

     $scope.facebookShare = ->
         event = event || window.event
-        if event.stoppPropagation then event.stopPropagation()
+        if event.stopPropagation then event.stopPropagation()
         else (event.cancelBubble = true)
         place = $scope.place
         if place


Better output.

Better output.

--- src/coffee/stockimport.coffee
+++ src/coffee/stockimport.coffee
@@ -220,7 +220,7 @@
       else
         @client.inventoryEntries.create(entry)

-    @_log "POST requests: #{_.size posts}"
+    @_log "Requests: #{_.size posts}"
     Q.all(posts)

 module.exports = StockImport


cleaned up add function

cleaned up add function

--- src/commands/lifecycle.coffee
+++ src/commands/lifecycle.coffee
@@ -108,15 +108,11 @@
         )
         @brain.set('tflobby.lobby', lobby)

-      players = lobby.players()
-      format = lobby.slots()
-
       unless lobby.isFull()

         unless lobby.isAdded(target)
           @brain.set('tflobby.lobby', lobby.add(target))
-          added = lobby.totalPlayers()
-          msg.send(":: #{lobby.server.name} : #{lobby.map} : #{added}/#{format} : [ #{lobby.players().join(', ')} ] ::")
+          msg.send(":: #{lobby.server.name} : #{lobby.map} : #{lobby.totalPlayers()}/#{lobby.slots()} : [ #{lobby.players().join(', ')} ] ::")

           return unless lobby.isFull() and not lobby.finalising


slightly improve test reliability

slightly improve test reliability

--- test/integration/login.coffee
+++ test/integration/login.coffee
@@ -56,7 +56,8 @@
       before (done) ->
         browser.fill '#username', 'ickletest'
         browser.fill '#password', 'toottoot'
-        browser.pressButton '#login', done
+        browser.pressButton '#login', ->
+          browser.wait done

       it 'shows my name', ->
         browser.text('nav').should.include 'Mr Ickle Test'


add genereate question method

add genereate question method

--- app/assets/javascripts/game.js.coffee
+++ app/assets/javascripts/game.js.coffee
@@ -112,6 +112,10 @@
       obj1.val - obj2.val
     p1_question = sort_measures[Math.round(sort_measures.length / 2)].name

+  generate_question = ->
+    values = comp_question().split('|').reverse()
+    if values[0]=='null' then "hasn't #{values[1]}" else "has a #{values[0]} #{values[1]}"
+
   proc_question_panel = ->
     data = if state == states['player1'] # comp turn
       # TODO if opened pictures <=3 then close cards rnd(3) else comp_question()
@@ -119,7 +123,7 @@

Comp turn

-          A person has a #{comp_question().split('|').reverse()} ?
+          A person #{generate_question()} ?

@@ -130,7 +134,7 @@
     else
       """

Your turn

-
Please ask a question or choose face on apponent board (you have #{max_click_try - p2_click_try} attempts)

+
Please ask a question or choose face on opponent board (you have #{max_click_try - p2_click_try} attempts)

           A person
           <select class="relation"><option value="+">have</option><option value="-">dont have</option></select>


Add place holder bound calculator

Add place holder bound calculator

--- server/models/indicator.coffee
+++ server/models/indicator.coffee
@@ -135,6 +135,7 @@
       row[fieldName]
     )[fieldName]
     return bounds
+  text: () -> "It's text, dummy"

 # Probably going to need a refactor at some point
 indicatorSchema.methods.getCurrentYAxis = (callback) ->


Run specs serially

Run specs serially

--- tasks/spec-task.coffee
+++ tasks/spec-task.coffee
@@ -52,7 +52,6 @@
       continue unless isAtomPackage(packagePath)
       packageSpecQueue.push(packagePath)

-    packageSpecQueue.concurrency = 1
     packageSpecQueue.drain = -> callback(null, failedPackages)

   runCoreSpecs = (callback) ->
@@ -77,14 +76,13 @@
       if process.platform is 'win32'
         process.stdout.write(fs.readFileSync('ci.log'))
         fs.unlinkSync('ci.log')
-      packageSpecQueue.concurrency = 2
       callback(null, error)

   grunt.registerTask 'run-specs', 'Run the specs', ->
     done = @async()
     startTime = Date.now()

-    async.parallel [runCoreSpecs, runPackageSpecs], (error, results) ->
+    async.series [runCoreSpecs, runPackageSpecs], (error, results) ->
       [coreSpecFailed, failedPackages] = results
       elapsedTime = Math.round((Date.now() - startTime) / 100) / 10
       grunt.verbose.writeln("Total spec time: #{elapsedTime}s")


#830 Add comment

#830 Add comment

--- app/assets/javascripts/oxalis/view/tracing_layout_view.coffee
+++ app/assets/javascripts/oxalis/view/tracing_layout_view.coffee
@@ -136,6 +136,8 @@

   renderSettings : ->

+    # This method will be invoked again once the model is initialized as part of
+    # the "sync" event callback.
     return unless @model.initialized

     if @isSkeletonMode()


support for scraperwiki.tool.pushSQL

support for scraperwiki.tool.pushSQL

--- shared/code/scraperwiki.coffee
+++ shared/code/scraperwiki.coffee
@@ -229,7 +229,7 @@

 # HERE BE DEPRECATED FUNCTIONS:

-scraperwiki.tool.pushSql = scraperwiki.dataset.installTool
+scraperwiki.tool.pushSql = scraperwiki.tool.pushSQL = scraperwiki.dataset.installTool
 scraperwiki.tool.rename = scraperwiki.dataset.name
 scraperwiki.tool.getUrl = scraperwiki.tool.getURL = scraperwiki.tool.redirect = scraperwiki.url
 scraperwiki.sql = scraperwiki.dataset.sql


more verbose test output

more verbose test output

--- test/create_zip.coffee
+++ test/create_zip.coffee
@@ -34,7 +34,7 @@

   zip.compress (err, bytes) ->
     t.error err, 'zip is created'
-    t.true fs.existsSync(zipFilePath), 'zip file is created'
+    t.true fs.existsSync(zipFilePath), "#{zipFilePath} is there"
     t.true (bytes > 0), 'file has contents'
     t.end()


Removed test dir

Removed test dir

--- test/karma.conf.coffee
+++ test/karma.conf.coffee
@@ -1,77 +0,0 @@
-# Karma configuration
-# http://karma-runner.github.io/0.12/config/configuration-file.html
-# Generated on 2014-08-06 using
-# generator-karma 0.8.3
-
-module.exports = (config) ->
-  config.set
-    # base path, that will be used to resolve files and exclude
-    basePath: '../'
-
-    # testing framework to use (jasmine/mocha/qunit/...)
-    frameworks: ['jasmine']
-
-    # list of files / patterns to load in the browser
-    files: [
-      'bower_components/angular/angular.js'
-      'bower_components/angular-mocks/angular-mocks.js'
-      'bower_components/angular-sanitize/angular-sanitize.js'
-      'bower_components/angular-touch/angular-touch.js'
-      'bower_components/angular-superswipe/superswipe.js'
-      'syncCollections.js'
-      'test/spec/**/*.coffee'
-    ]
-
-    # list of files / patterns to exclude
-    exclude: []
-
-    # web server port
-    port: 8081
-
-    # level of logging
-    # possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
-    logLevel: config.LOG_INFO
-
-    # Start these browsers, currently available:
-    # - Chrome
-    # - ChromeCanary
-    # - Firefox
-    # - Opera
-    # - Safari (only Mac)
-    # - PhantomJS
-    # - IE (only Windows)
-    browsers: [
-      'Chrome'
-    ]
-
-    # Which plugins to enable
-    plugins: [
-      'karma-phantomjs-launcher'
-      'karma-chrome-launcher'
-      'karma-jasmine'
-      'karma-coverage'
-      'karma-coffee-preprocessor'
-    ]
-
-    # enable / disable watching file and executing tests whenever any file changes
-    autoWatch: true
-
-    # Continuous Integration mode
-    # if true, it capture browsers, run tests and exit
-    singleRun: false
-
-    colors: true
-
-    preprocessors:
-      '**/*.coffee': ['coffee']
-      '.tmp/scripts/**/*.js': 'coverage'
-
-    # Uncomment the following lines if you are using grunt's server to run the tests
-    # proxies: '/': 'http://localhost:9000/'
-    # URL root prevent conflicts with the site root
-    # urlRoot: '_karma_'
-
-    reporters: ['progress', 'coverage']
-    coverageReporter:
-      type: 'html'
-      dir: 'docs/coverage/'


activity: fix comment form reference in "ReplyLinkClicked" event handler function

--- client/Social/Activity/views/comments/commentview.coffee
+++ client/Social/Activity/views/comments/commentview.coffee
@@ -38,7 +38,7 @@
     @commentForm.on "Submit", @commentController.bound "reply"

     @commentList.on 'ReplyLinkClicked', (username) =>
-      input = @commentForm.commentInput
+      {input} = @commentForm
       value = input.getValue()
       value = if value.indexOf("@#{username}") >= 0 then value else if value.length is 0 then "@#{username} " else "#{value} @#{username} "


Fix notification for guest

Fix notification for guest

--- client/landing/app/MainApp/notificationcontroller.coffee
+++ client/landing/app/MainApp/notificationcontroller.coffee
@@ -16,7 +16,8 @@
     super

     @getSingleton('mainController').on "AccountChanged", (account)=>
-      @setListeners account
+      if account.bongo_.constructorName is 'JAccount'
+        @setListeners account

   setListeners:(account)->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/color2.coffee
+++ test/color2.coffee
@@ -159,7 +159,7 @@
   color1 = Color2(255, 255, 255, 1)
   color2 = Color2([255, 255, 255])

-  log color1
+  log Point()

 module()


Added support for notifying of progress.

--- src/data/DeferredQueue.coffee
+++ src/data/DeferredQueue.coffee
@@ -19,7 +19,7 @@
     fin = => @queue.shift()
     execute = ->
       result = callback()
-      Q.when(result).then(df.resolve, df.reject)
+      Q.when(result).then(df.resolve, df.reject).progress(df.notify)
     execute = Meteor.bindEnvironment(execute)
     if len > 0
       @wait(len - 1).then(execute, df.reject).fin(fin)


Follow mixin

Follow mixin

--- test/follow.coffee
+++ test/follow.coffee
@@ -27,6 +27,6 @@
   fastEnemy.include(Follow)
   fastEnemy.follow(player)

-  ok fastTnemy.I.velocity
+  ok fastEnemy.I.velocity

 module()


Follow mixin

Follow mixin

--- test/follow.coffee
+++ test/follow.coffee
@@ -23,7 +23,7 @@
     y: 100
     width: 10
     height: 10
-    fol
+    followSpeed: 5

   fastEnemy.include(Follow)
   fastEnemy.follow(player)


Follow mixin

Follow mixin

--- test/follow.coffee
+++ test/follow.coffee
@@ -39,6 +39,6 @@
   rightEnemy.include(Follow)
   rightEnemy.follow(player)

-  ok rightEnemy.I.velocity.equ
+  ok rightEnemy.I.velocity.equalP()

 module()


Follow mixin

Follow mixin

--- test/follow.coffee
+++ test/follow.coffee
@@ -1,6 +1,6 @@
 module "Follow"

 test "testing for equality", ->
-  obj = Game
+  player = Game

 module()


refactor(formatters): extract documentation formatter

--- src/formatters/console.coffee
+++ src/formatters/console.coffee
@@ -10,6 +10,49 @@
     spectacular.utils.colorize CHAR_MAP[state], COLOR_MAP[state], @options.colors

 class spectacular.formatters.console.DocumentationFormatter
+  constructor: (@example, @options) ->
+
+  format: ->
+    state = @example.result.state
+
+    @options.lastDepth ||= 0
+    @options.lastAncestorsStack ||= []
+
+    ancestors = @example.ancestors.filter (e) -> e.ownDescription isnt ''
+    dif = @cropAncestors ancestors, @options.lastAncestorsStack
+    start = ancestors.length - dif.length
+    res = @formatDocumentation @example, dif, start, COLOR_MAP[state]
+
+    @options.lastAncestorsStack = ancestors
+    res
+
+  formatDocumentation: (example, stack, start, color) ->
+    reverseStack = []
+    reverseStack.unshift e for e in stack
+    res = ''
+
+    for e,i in reverseStack
+      res += '\n' if i is 0
+      res += '\n'
+      res += utils.indent(utils.strip(e.ownDescription), (start + 1) * 2)
+      start += 1
+
+    res += '\n'
+    res += utils.indent(
+      spectacular.utils.colorize(utils.strip(example.ownDescriptionWithExpectations), color, @options.colors),
+      (start + 1) * 2
+    )
+
+    @options.lastDepth = start
+
+    res
+
+  cropAncestors: (ancestors, lastAncestorsStack) ->
+    a = []
+    a.push elder for elder in ancestors when elder not in lastAncestorsStack
+    a
+
+

 class spectacular.formatters.console.ResultsFormatter
   constructor: (@runner, @results) ->


groups: hide "Create a Group" button if user already has a "custom-plan" subscription

--- client/Main/avatararea/avatarareagroupswitcherpopup.coffee
+++ client/Main/avatararea/avatarareagroupswitcherpopup.coffee
@@ -69,12 +69,15 @@
     createGroupLink = new KDCustomHTMLView
       tagName    : 'a'
       attributes : href : '/Pricing/Team'
-      cssClass   : 'bottom bb'
+      cssClass   : 'bottom bb hidden'
       partial    : 'Create a group'
       click      : (event)=>
         KD.utils.stopDOMEvent event
         router.handleRoute '/Pricing/CreateGroup', entryPoint : 'koding'
         @hide()
+
+    KD.singleton("paymentController").fetchSubscriptionsWithPlans tags: ["custom-plan"], (err, subscriptions) ->
+      createGroupLink.show()  unless subscriptions.length

     backToKoding = new KDCustomHTMLView
       tagName    : 'a'


activity test: removed unused dependecies test folder

--- client/activity/lib/test/helpers/expectCorrectRoute.coffee
+++ client/activity/lib/test/helpers/expectCorrectRoute.coffee
@@ -1,5 +1,4 @@
 kd          = require 'kd'
-React       = require 'kd-react'
 expect      = require 'expect'
 toImmutable = require 'app/util/toImmutable'
 TestUtils   = require 'react-addons-test-utils'


fix #1002

fix #1002

--- views/components/etc/icon.cjsx
+++ views/components/etc/icon.cjsx
@@ -16,7 +16,7 @@
   render: ->
     svgAvailable = true
     try
-      fs.accessSync("file://#{ROOT}/assets/svg/material/#{@props.materialId}.svg")
+      fs.accessSync("#{ROOT}/assets/svg/material/#{@props.materialId}.svg")
     catch error
       svgAvailable = false
     if useSVGIcon && svgAvailable


Improved error reporting in tests.

Improved error reporting in tests.

--- tests-src/test-factory.coffee
+++ tests-src/test-factory.coffee
@@ -1,14 +1,14 @@
 echo_factory_factory = (protocol, messages) ->
     return ->
-        expect(3 + messages.length)
+        expect(2 + messages.length)
         a = messages.slice(0)
         r = new SockJS(sockjs_url + '/echo', [protocol])
-        ok(r)
         r.onopen = (e) ->
-            log('onopen', e)
+            log('onopen' + e)
             ok(true)
             r.send(a[0])
         r.onmessage = (e) ->
+            #log('onmessage');
             deepEqual(e.data, a[0])
             a.shift()
             if typeof a[0] is 'undefined'
@@ -16,8 +16,11 @@
             else
                 r.send(a[0])
         r.onclose = (e) ->
-            log('onclose', ''+e)
-            ok(true)
+            if a.length
+                ok(false, "Transport closed prematurely.")
+            else
+                log('onclose' + e)
+                ok(true)
             start()

 factor_echo_basic = (protocol) ->


:fire: Remove test focus

:fire: Remove test focus

--- spec/color-project-spec.coffee
+++ spec/color-project-spec.coffee
@@ -666,10 +666,8 @@

           describe 'writing an invalid rule in the editor', ->
             beforeEach ->
-              waitsFor -> null
-              runs ->
-                popup.ignoreRulesEditor.insertText(', +(')
-                popup.ignoreRulesEditor.getBuffer().emitter.emit('did-stop-changing')
+              popup.ignoreRulesEditor.insertText(', +(')
+              popup.ignoreRulesEditor.getBuffer().emitter.emit('did-stop-changing')

             fit 'ignores the invalid rules', ->
               expect(popup.querySelectorAll('li.active').length).toEqual(6)


Add test for forms

Add test for forms

--- spec/nested_models.spec.coffee
+++ spec/nested_models.spec.coffee
@@ -10,7 +10,7 @@
     this.addMatchers
       htmlToBeEqual: (expected) ->
         #TODO: Refactor to spec_helper.coffee or something
-        this.actual = this.actual.replace(/\s\s+/g, '')
+        this.actual = this.actual.replace(/\s\s+/g, '')
         expected    = expected.replace(/\s\s+/g, '')
         this.actual == expected

@@ -32,9 +32,9 @@
     data =
       title:    'Hello World'
       post:     'Hi there it is me'
-      comments: [ {
+      comments: [ {
           name:    'John'
-          text: 'That rules' }, {
+          text: 'That rules' }, {
           name:    'Arnold'
           text: 'Great post!'}
       ]
@@ -159,7 +159,7 @@
       release: "1.2"
       profiles: [
         name: 'Core'
-        testsets: [
+        testsets: [
           name: "Sanity"
           products: [
             name: "N900"
@@ -174,7 +174,7 @@
             name: "Pinetrail"
           ]
         ]
-      ,
+      ,
         name: 'Handset'
         testsets: [
           name: "Feature"
@@ -273,4 +273,58 @@

')

     doc.find('.test_reports').render(data, directives)
+    expect(doc.html()).htmlToBeEqual(expected.html())
+
+  it "should render forms", ->
+    doc = jQuery(
+     '

+        <form class="hotel_reservation">
+          Name
+            <input class="name_input" type="text" />
+
+          Room type
+            <select class="room_types">
+              <option class="name"></option>
+            </select>
+
+        </form>
+
')
+
+    data =
+      name: "Michael Jackson"
+      room_types: [
+          name: "Single"
+          id: "1"
+        ,
+          name: "Double"
+          id: "2"
+        ,
+          name: "King Size"
+          id: "3"
+          selected: "true"
+        ]
+
+    directives =
+      'name_input@value': -> @name
+      room_types:
+        'name@value': -> @id
+        'name@selected': -> @selected
+
+    expected = jQuery(
+     '

+        <form class="hotel_reservation">
+          Name
+            <input class="name_input" type="text" value="Michael Jackson"/>
+
+          Room type
+            <select class="room_types">
+              <option class="name" value="1">Single</option>
+              <option class="name" value="2">Double</option>
+              <option class="name" value="3" selected="selected">King Size</option>
+            </select>
+
+        </form>
+
')
+
+    doc.find('.hotel_reservation').render(data, directives)
     expect(doc.html()).htmlToBeEqual(expected.html())


Restore assertion verifying issue title truncation

Prior to #114, this test asserted that the issue title gets truncation,
but that assertion was removed in #114. Since the essence of this test
involves the truncation of the issue title, it seems appropriate to
assert that the issue title gets correctly truncation.

--- spec/notifications-spec.coffee
+++ spec/notifications-spec.coffee
@@ -699,8 +699,8 @@

             runs ->
               button = fatalError.querySelector('.btn')
-              encodedMessage = encodeURIComponent(truncatedMessage)
               expect(button.textContent).toContain 'Create issue'
+              expect(fatalError.issue.getIssueTitle()).toBe(truncatedMessage)

       describe "when the package is out of date", ->
         beforeEach ->


Edited isNaN check in fullpie.coffee

Edited isNaN check in fullpie.coffee

--- widgets/fullpie/fullpie.coffee
+++ widgets/fullpie/fullpie.coffee
@@ -62,7 +62,7 @@
 #      .text((d,i) -> data[i].value + ' (' + Math.round(data[i].value/sum * 100) + '%)')

     arcs.append("svg:text").attr("transform", (d, i) ->
-      percent_val = if _.isNan(Math.round(data[i].value/sum * 100)) then 0 else Math.round(data[i].value/sum * 100)
+      percent_val = getpercentval()
       d.innerRadius = (radius * (100-percent_val)/100) - 45  #45=max text size/2
       d.outerRadius = radius
       "translate(" + arc.centroid(d) + ")")
@@ -73,3 +73,9 @@
       .attr('dy', 25)
       .attr('font-size', '90%')
       .text((d,i) -> data[i].value + ' (' + percent_val + '%)')
+
+    getpercentval: ->
+      if _.isNan(Math.round(data[i].value/sum * 100))
+        0
+      else
+        Math.round(data[i].value/sum * 100)


add queue for moments when socket not open

--- vendor/assets/javascripts/webmate/client.coffee
+++ vendor/assets/javascripts/webmate/client.coffee
@@ -7,19 +7,24 @@
     @clientId = Math.random().toString(36).substr(2)
     if window.Webmate.websocketsEnabled isnt false && window.WebSocket
       @websocket = new WebSocket("ws://#{@fullPath}")
-      @websocket.onmessage = (e)->
+      # prepare queue to store requests if socket not ready
+      @callsQueue = new Array()
+      @websocket.onmessage = (e) ->
         data = JSON.parse(e.data)
         eventBinding = self.bindings[data.action]
         _.each eventBinding, (binding)->
           binding(data.response, data.params)
-      @websocket.onopen = (e)->
-        callback()
+      @websocket.onopen = (e) ->
+        # process pending queues
+        while data = self.callsQueue.pop()
+          self.websocket.send(JSON.stringify(data))
+        callback() if callback
     else
       if window.Webmate.websocketsEnabled is false
         console.log("Websockets is disabled. Using http.")
       else
         console.log("Websocket not supported. Using http.")
-      callback()
+      callback() if callback
     @
   on: (action, callback)->
     @bindings[action] = [] if !@bindings[action]
@@ -31,34 +36,18 @@
     data.action = action
     data.channel = @channel
     data._client_id = @clientId
+
     if @websocket
-      @websocket.send(JSON.stringify(data))
+      if @websocket.readyState == @websocket.OPEN
+        @websocket.send(JSON.stringify(data))
+      else
+        @callsQueue.push(data)
     else
-      $.ajax("http://#{@fullPath}/#{action}", type: method).success (data)->
+      $.ajax("http://#{@fullPath}/#{action}", type: method).success (data) ->
         console.log(data)
     @
-  bindDefaultEvents: (connection)->
-    self = @
-    _.each App.Collections, (collectionClass)->
-      obj = new collectionClass()
-      return unless obj
-      collectionName = obj.collectionName()
-      collectionInstance = App[collectionName]
-      return unless collectionInstance
-      self.on "#{collectionName}/update", (response, params)->
-        return unless response._id
-        collectionInstance.get(response._id).set(response)
-      self.on "#{collectionName}/read", (response, params)->
-        collectionInstance.reset(response)
-        collectionInstance.trigger "sync", collectionInstance, response
-      self.on "#{collectionName}/create", (response, params)->
-        unless self.clientId is params._client_id
-          collectionInstance.add(response)
-        if self.clientId is params._client_id
-          collectionInstance.get(params._cid).set(response)

 Webmate.connect = (channel, callback)->
   client = new Webmate.Client(channel, callback)
   Webmate.channels[channel] = client
-  client.bindDefaultEvents()
   client


Change Item -> Ítem

Change Item -> Ítem

Signed-off-by: Santos Gallegos <c7d20f0b590f7c49e45e22db249ad9b63899f894@outlook.com>

--- def/es/menu_darwin.cson
+++ def/es/menu_darwin.cson
@@ -40,7 +40,7 @@
       "Add Project Folder…":
         value: "Agregar Carpeta al Proyecto..."
       "Reopen Last Item":
-        value: "Reabrir Último Item"
+        value: "Reabrir Último Ítem"
       Save:
         value: "Guardar"
       "Save As…":


fix leg disposal fail

fix leg disposal fail

--- web/js/views/map_route_leg_view.coffee
+++ web/js/views/map_route_leg_view.coffee
@@ -7,6 +7,8 @@

     dispose: ->
       Reitti.Event.off 'routes:change', @onRoutesChanged
+      @line?.setMap null
+      @marker?.setMap null
       @hideMarkers()
       this


todo was done :)

todo was done :)

--- core/app/backbone/controllers/channels_controller.coffee
+++ core/app/backbone/controllers/channels_controller.coffee
@@ -7,7 +7,6 @@
   onAction: -> @unbindFrom @permalink_event if @permalink_event?

   # <topics>
-  # TODO: refactor until we don't refer to channels any more
   loadTopic: (slug_title, callback) ->
     topic = new Topic {slug_title}
     topic.fetch success: (model) -> callback(model)


Remove Host header for AmazonS3 request

Remove Host header for AmazonS3 request

--- deployment/nginx.coffee
+++ deployment/nginx.coffee
@@ -302,7 +302,6 @@
       # // kd/klient installers
       location ~^/d/(.*)$ {
         proxy_pass            "https://s3.amazonaws.com/koding-dl/$1";
-        proxy_set_header      Host            $host;
         proxy_set_header      X-Host          $host; # for customisation
         proxy_set_header      X-Real-IP       $remote_addr;
         proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;


test for Epoch.Chart.Canvas#redraw method on whether QueryCSS.purge and chart.draw are called exactly once each

--- tests/unit/core/charts.coffee
+++ tests/unit/core/charts.coffee
@@ -1,3 +1,5 @@
+sinon = require 'sinon'
+
 describe 'Epoch.Chart', ->
   [defaultWidth, defaultHeight] = [320, 240]

@@ -547,3 +549,25 @@
         chart.option 'height', newHeight
         assert.equal chart.canvas.attr('height'), pixelRatio * newHeight
         assert.equal chart.canvas.height(), newHeight
+
+    describe 'redraw', ->
+      chart = null
+      drawSpy = null
+      purgeSpy = null
+
+      before ->
+        chart = new Epoch.Chart.Canvas()
+
+      beforeEach ->
+        drawSpy = sinon.spy chart, 'draw'
+        purgeSpy = sinon.spy Epoch.QueryCSS, 'purge'
+
+      afterEach ->
+        chart.draw.restore()
+        Epoch.QueryCSS.purge.restore()
+
+      it 'should purge QueryCSS cache and redraw the canvas based chart with new styles', ->
+        chart.redraw()
+
+        assert drawSpy.calledOnce
+        assert purgeSpy.calledOnce


Add check for page 1

Add check for page 1

--- SingularityUI/app/views/expandableTableSubview.coffee
+++ SingularityUI/app/views/expandableTableSubview.coffee
@@ -41,7 +41,7 @@
     render: ->
         # If we've already rendered stuff and now we're trying to render
         # an empty collection (`next` returned an empty list)
-        if not @collection.length and @collection.currentPage isnt 1
+        if not @collection.length
             # Disable the next button and don't render anything
             $nextButton = @$('[data-action="next-page"]')
             $nextButton.attr 'disabled', true


adding ssl config option

adding ssl config option

--- lib/assets/javascripts/firehose/long_poll.js.coffee
+++ lib/assets/javascripts/firehose/long_poll.js.coffee
@@ -15,10 +15,12 @@

   constructor: (args) ->
     super args
+
+    @config.ssl              ?= false
     # Configrations specifically for web sockets
     @config.longPoll         ||= {}
     # Protocol schema we should use for talking to WS server.
-    @config.longPoll.url     ||= "http:#{@config.uri}"
+    @config.longPoll.url     ||= "#{@_protocol()}:#{@config.uri}"
     # How many ms should we wait before timing out the AJAX connection?
     @config.longPoll.timeout ||= 25000
     # TODO - What is @_lagTime for? Can't we just use the @_timeout value?
@@ -27,6 +29,9 @@
     @_timeout         = @config.longPoll.timeout + @_lagTime
     @_okInterval      = 0
     @_stopRequestLoop = false
+
+  _protocol: =>
+    if @config.ssl then 'https' else 'http'

   _request: =>
     return if @_stopRequestLoop


Update Helpers.minimalEntity

Update Helpers.minimalEntity

--- lib/assets/javascripts/helpers/formatting.js.coffee
+++ lib/assets/javascripts/helpers/formatting.js.coffee
@@ -15,11 +15,7 @@
     "#{options.max}+"

   minimalEntity: (entity) ->
-    return unless entity
-    if TentStatus.config.tent_host_domain && entity.match(new RegExp("([a-z0-9]{2,})\.#{TentStatus.config.tent_host_domain}"))
-      RegExp.$1
-    else
-      entity
+    @formatUrlWithPath(entity)

   formatUrlWithPath: (url = '') ->
     url.replace(/^\w+:\/\/(.*)$/, '$1')


fix(dashboard): fix render dashboards

fix(dashboard): fix render dashboards

--- lib/assets/javascripts/my_dashboard.gridster.coffee
+++ lib/assets/javascripts/my_dashboard.gridster.coffee
@@ -0,0 +1,51 @@
+# This file enables gridster integration (http://gridster.net/)
+# Delete it if you'd rather handle the layout yourself.
+# You'll miss out on a lot if you do, but we won't hold it against you.
+
+MyDashboard.gridsterLayout = (positions) ->
+  MyDashboard.customGridsterLayout = true
+  positions = positions.replace(/^"|"$/g, '')
+  positions = $.parseJSON(positions)
+  widgets = $("[data-row]")
+  maxRow = 1
+  maxCol = 1
+  numColumns = MyDashboard.numColumns || 1
+  for widget, index in widgets
+    if positions? and index < positions.length
+      $(widget).attr('data-row', positions[index].row)
+      $(widget).attr('data-col', positions[index].col)
+      if positions[index].row > maxRow
+        maxRow = positions[index].row
+        maxCol = positions[index].col + 1
+      else if positions[index].row == maxRow and positions[index].col >= maxCol
+        maxCol = positions[index].col + 1
+    else
+      if maxCol > numColumns
+        maxRow += 1
+        maxCol = 1
+      $(widget).attr('data-row', maxRow)
+      $(widget).attr('data-col', maxCol)
+      maxCol += 1
+
+MyDashboard.getWidgetPositions = ->
+  $(".gridster ul:first").gridster().data('gridster').serialize()
+
+MyDashboard.showGridsterInstructions = ->
+  newWidgetPositions = MyDashboard.getWidgetPositions()
+
+  unless JSON.stringify(newWidgetPositions) == JSON.stringify(MyDashboard.currentWidgetPositions)
+    MyDashboard.currentWidgetPositions = newWidgetPositions
+    $('#save-gridster').slideDown()
+    $('#gridster-code').text("
+      <script type='text/javascript'>\n
+      $(function() {\n
+      \ \ MyDashboard.gridsterLayout('#{JSON.stringify(MyDashboard.currentWidgetPositions)}')\n
+      });\n
+      </script>
+    ")
+
+$ ->
+  $('#save-gridster').leanModal()
+
+  $('#save-gridster').click ->
+    $('#save-gridster').slideUp()


Fixed loading of cartridges without VROM banks.

--- src/loaders/INESLoader.coffee
+++ src/loaders/INESLoader.coffee
@@ -82,13 +82,13 @@
         @cartridge.trainer = @readArray 0x200 if @cartridge.hasTrainer # 512B

     readROMBanks: ->
-        @cartridge.romBanks = (@readROMBank() for [1..@cartridge.romBanksCount])
+        @cartridge.romBanks = (@readROMBank() for [0...@cartridge.romBanksCount])

     readROMBank: ->
         @readArray 0x4000 # 16KB

     readVROMBanks: ->
-        @cartridge.vromBanks = (@readVROMBank() for [1..@cartridge.vromBanksCount])
+        @cartridge.vromBanks = (@readVROMBank() for [0...@cartridge.vromBanksCount])

     readVROMBank: ->
         @readArray 0x2000 # 8KB


Update exec for literals since they are now in the elm namespace

--- Src/coffeescript/cql-execution/src/elm/literal.coffee
+++ Src/coffeescript/cql-execution/src/elm/literal.coffee
@@ -3,10 +3,10 @@
 module.exports.Literal = class Literal extends Expression
   @from: (json) ->
     switch(json.valueType)
-      when "{http://www.w3.org/2001/XMLSchema}bool" then new BooleanLiteral(json)
-      when "{http://www.w3.org/2001/XMLSchema}int" then new IntegerLiteral(json)
-      when "{http://www.w3.org/2001/XMLSchema}decimal" then new DecimalLiteral(json)
-      when "{http://www.w3.org/2001/XMLSchema}string" then new StringLiteral(json)
+      when "{urn:hl7-org:elm:r1}Boolean" then new BooleanLiteral(json)
+      when "{urn:hl7-org:elm:r1}Integer" then new IntegerLiteral(json)
+      when "{urn:hl7-org:elm:r1}Decimal" then new DecimalLiteral(json)
+      when "{urn:hl7-org:elm:r1}String" then new StringLiteral(json)
       else new Literal(json)

   constructor: (json) ->


whoops

whoops

--- web/coffee/scoreboard.coffee
+++ web/coffee/scoreboard.coffee
@@ -11,7 +11,8 @@
           teamscore: resp.data.score
         })
       when 0
-        apiNotify(resp)
+        0
+        # apiNotify(resp)

 load_scoreboard = ->
   apiCall "GET", "/api/stats/scoreboard", {}
@@ -25,8 +26,7 @@

         window.drawTopTeamsProgressionGraph "#top-team-score-progression-graph"
       when 0
-        0
-        #apiNotify(data)
+        apiNotify(data)

 $ ->
   load_scoreboard()


Fix title issue

Fix title issue

--- docpad.coffee
+++ docpad.coffee
@@ -17,7 +17,7 @@
         'styles/main.css'
       ]

-    getPreparedTitle: -> if @document.title then '#{@document.title} | #{@site.title}' else @site.title
+    getPreparedTitle: -> if @document.title then "#{@document.title} | #{@site.title}" else @site.title

     plugins:


Fixed KDBlockingModalView.

Fixed KDBlockingModalView.

--- client/Framework/components/modals/KDBlockingModalView.coffee
+++ client/Framework/components/modals/KDBlockingModalView.coffee
@@ -4,8 +4,7 @@
     $(window).off "keydown.modal"

   putOverlay:()->
-    @$overlay = $("<div/>")
-      class : "kdoverlay"
+    @$overlay = $("<div/>", class : "kdoverlay")
     @$overlay.hide()
     @$overlay.appendTo "body"
     @$overlay.fadeIn 200


MachineStateModal: Fixed browserify glitches.

+ showError = require 'app/util/showError'

- unless kd.showError err
+ unless showError err

--- client/app/lib/providers/environmentsmachinestatemodal.coffee
+++ client/app/lib/providers/environmentsmachinestatemodal.coffee
@@ -16,6 +16,7 @@
 ComputeHelpers = require './computehelpers'
 sendDataDogEvent = require '../util/sendDataDogEvent'
 HelpSupportModal = '../commonviews/helpsupportmodal'
+showError = require 'app/util/showError'

 module.exports = class EnvironmentsMachineStateModal extends EnvironmentsModalView
@@ -50,6 +51,8 @@
     whoami().isEmailVerified (err, verified)=>

       kd.warn err  if err?
+
+      debugger

       if not verified
         @buildVerifyView()
@@ -277,7 +280,7 @@
       callback : =>
         @showBusy "Working..."
         @machine.jMachine.approve (err)=>
-          unless kd.showError err
+          unless showError err
             @_busy = no
             @buildInitial()

@@ -293,7 +296,7 @@

           @_busy = no

-          unless kd.showError err
+          unless showError err
             computeController.once 'RenderMachines', ->
               router.handleRoute '/IDE'
             computeController.reset yes


EnvironmentMachineStateModal: make sure to call it Build Stack by checking machine state

--- client/app/lib/providers/environmentsmachinestatemodal.coffee
+++ client/app/lib/providers/environmentsmachinestatemodal.coffee
@@ -556,7 +556,7 @@
         { groupsController } = kd.singletons
         return  unless groupsController.currentGroupHasStack()

-    else if not isKoding() and @stack
+    else if not isKoding() and @stack and @state is NotInitialized
       title    = 'Build Stack'
       callback = 'turnOnMachine'
     else


include dotfiles in the listing (for the FileOps test)

--- tools/gen_dir_listings.coffee
+++ tools/gen_dir_listings.coffee
@@ -9,7 +9,7 @@
   files = fs.readdirSync(dpath)
   for file in files
     # ignore non-essential directories / files
-    continue if file in ['.git', 'node_modules'] or file[0] is '.'
+    continue if file in ['.git', 'node_modules']
     fpath = dpath + '/' + file
     try
       # Avoid infinite loops.


`get` takes a default value

`get` takes a default value

--- plugins/project/project.coffee
+++ plugins/project/project.coffee
@@ -85,9 +85,9 @@
     if value == undefined then delete object[key] else object[key] = value
     localStorage[@dir] = JSON.stringify(object)

-  get: (key) ->
+  get: (key, defaultValue=null) ->
     try
-      JSON.parse(localStorage[@dir])[key]
+      JSON.parse(localStorage[@dir])[key] or defaultValue
     catch error
       console.log(error)
-      undefined
+      defaultValue


Change Atom editor font size

Change Atom editor font size

--- .atom/config.cson
+++ .atom/config.cson
@@ -5,7 +5,7 @@
       "solarized-dark-syntax"
     ]
   editor:
-    fontSize: 15
+    fontSize: 16
   "exception-reporting":
     userId: "76d6bd0a-16fd-42b8-0163-bce5c8c7e379"
   welcome:


Revert "atom: fix emmet tab expension in angular html mode"

This reverts commit fce45969455d1bbf1c5cd5865890d8500d63a754.

--- .atom/keymap.cson
+++ .atom/keymap.cson
@@ -43,7 +43,3 @@

 'atom-text-editor:not(.mini).vim-mode-plus:not(.insert-mode):not(.jumpy-jump-mode)':
   '-': 'advanced-open-file:toggle'
-
-
-'atom-text-editor[data-grammar="text html angular"].vim-mode-plus.insert-mode:not([mini])':
-    'tab': 'emmet:expand-abbreviation-with-tab'


References #102, remove macroinvertebrate toggle JQuery functions

--- app/assets/javascripts/biodiversity_reports.js.coffee
+++ app/assets/javascripts/biodiversity_reports.js.coffee
@@ -34,14 +34,6 @@
     $(@).find('#biodiversity_report_lichen_sample_attributes__destroy').val('1')
     $('#lnk-toggle-lichen-sample-fields').text('Add lichen sample')

-  $('#macroinvertebrate_sample_fields').on 'shown.bs.collapse', (event) ->
-    $('#lnk-toggle-macroinvertebrate-sample-fields').text('Omit macroinvertebrate sample')
-
-  $('#macroinvertebrate_sample_fields').on 'hidden.bs.collapse', (event) ->
-    $(@).find(':input:not([type=hidden])').val('')
-    $(@).find('#biodiversity_report_macroinvertebrate_sample_attributes__destroy').val('1')
-    $('#lnk-toggle-macroinvertebrate-sample-fields').text('Add macroinvertebrate sample')
-
   $('#nonvascular_plant_sample_fields').on 'shown.bs.collapse', (event) ->
     $('#lnk-toggle-nonvascular-plant-sample-fields').text('Omit non-vascular plant sample')


fix routes in frond-end

fix routes in frond-end

--- app/assets/javascripts/components/dynamic-router.cjsx
+++ app/assets/javascripts/components/dynamic-router.cjsx
@@ -11,24 +11,22 @@
     project: null

   componentDidMount: ->
-    $.getJSON '/project', (result) =>
-      @setState project:           result
-      @setState home_page_content: result.home_page_content
-      @setState pages:             result.pages
+    $.getJSON '/projects', (result) =>
+      @setState project:           result.project
+      @setState home_page_content: result.project.home_page_content
+      @setState pages:             result.project.pages

-      for workflow in @state.project.workflows
-        @setState mark_tasks: workflow.tasks if workflow.key is 'mark'
-        @setState transcribe_tasks: workflow.tasks if workflow.key is 'transcribe'
   controllerForPage: (page) ->
     React.createClass
       displayName: "#{page.name}Page"
       render: ->

+  # TODO: workflow being passed as an object in an array. why?
   render: ->
-    # do nothing until project loads from API
-    # return null # just for now
-    return null if @state.project is null or @state.mark_tasks is null or @state.transcribe_tasks is null
+    return null unless @state.pages? # do nothing until project loads from API
+    workflows = @state.project.workflows
+

       <MainHeader pages={@state.pages} />


reading image.height and image.width from props instead of state in subject-viewer

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

   componentDidMount: ->
     console.log "____>>componen DID mount"
-    @setView 0, 0, @state.imageWidth, @state.imageHeight
+    @setView 0, 0, @props.subject.width, @props.subject.height
     @loadImage @props.subject.location.standard
     window.addEventListener "resize", this.updateDimensions

@@ -60,8 +60,8 @@
       scale = @getScale()
       props =
         size:
-          w: scale.horizontal * @state.imageWidth
-          h: scale.vertical * @state.imageHeight
+          w: scale.horizontal * @props.subject.width
+          h: scale.vertical * @props.subject.height
           scale: scale

       @props.onLoad props
@@ -171,12 +171,12 @@

   # PB This is not returning anything but 0, 0 for me; Seems like @refs.sizeRect is empty when evaluated (though nonempty later)
   getScale: ->
-    console.log "getScale()"
+    console.log "getScale() is being called"
     rect = @refs.sizeRect?.getDOMNode().getBoundingClientRect()
     return {horizontal: 1, vertical: 1} if ! rect? || ! rect.width?
     rect ?= width: 0, height: 0
-    horizontal = rect.width / @state.imageWidth
-    vertical = rect.height / @state.imageHeight
+    horizontal = rect.width / @props.subject.width
+    vertical = rect.height / @props.subject.height
     # TODO hack fallback:
     return {horizontal, vertical}

@@ -239,9 +239,7 @@

   render: ->
     return null if ! @props.active
-
-    viewBox = [0, 0, @state.imageWidth, @state.imageHeight]
-    # ToolComponent = @state.tool # AMS:from classification refactor.
+    viewBox = [0, 0, @props.subject.width, @props.subject.height]
     scale = @getScale()

     # if @props.workflow.name is 'transcribe'
@@ -255,20 +253,19 @@
         <ActionButton onClick={@nextSubject} text="Next Page" />

     if @state.loading
-      # console.log "loading..."
       markingSurfaceContent = <LoadingIndicator />
     else
       markingSurfaceContent =
         <svg
           className = "subject-viewer-svg"
-          width = {@state.imageWidth}
-          height = {@state.imageHeight}
+          width = {@props.subject.width}
+          height = {@props.subject.height}
           viewBox = {viewBox}
           data-tool = {@props.selectedDrawingTool?.type} >
           <rect
             ref = "sizeRect"
-            width = {@state.imageWidth}
-            height = {@state.imageHeight} />
+            width = {@props.subject.width}
+            height = {@props.subject.height} />
           <MouseHandler
             onStart = {@handleInitStart}
             onDrag  = {@handleInitDrag}
@@ -276,8 +273,8 @@
             inst    = "marking surface">
             <SVGImage
               src = {@props.subject.location.standard}
-              width = {@state.imageWidth}
-              height = {@state.imageHeight} />
+              width = {@props.subject.width}
+              height = {@props.subject.height} />
           </MouseHandler>

           { # HIGHLIGHT SUBJECT FOR TRANSCRIPTION


Call the callback, really

Call the callback, really

--- app/assets/javascripts/player/data_unpacker.js.coffee
+++ app/assets/javascripts/player/data_unpacker.js.coffee
@@ -11,4 +11,4 @@
         data = ArchUtils.bz2.decode data
         callback data
     else
-      data
+      callback data


FIX: iOS layout bug for text inputs

FIX: iOS layout bug for text inputs

--- source/Art/Engine/Forms/SynchronizedDomOverlay.coffee
+++ source/Art/Engine/Forms/SynchronizedDomOverlay.coffee
@@ -23,7 +23,7 @@
     @_detachDomElement()

     @_domElement = domElement
-    @_domElement.style.position = "fixed"
+    @_domElement.style.position = "absolute"
     @_domElement.style.top = "0"

     @onNextReady => @_attachDomElement()


Update atom config

Update atom config

--- .atom/config.cson
+++ .atom/config.cson
@@ -8,6 +8,12 @@
       "one-light-ui"
       "one-light-syntax"
     ]
+    customFileTypes:
+      "source.js": [
+        "jsx"
+        "es5"
+        "es6"
+      ]
   editor:
     invisibles: {}
     scrollPastEnd: true


References #82, clean up typo in JQuery toggle methods

--- app/assets/javascripts/biodiversity_reports.js.coffee
+++ app/assets/javascripts/biodiversity_reports.js.coffee
@@ -43,9 +43,9 @@
     $('#lnk-toggle-macroinvertebrate-sample-fields').text('Add macroinvertebrate sample')

   $('#nonvascular_plant_sample_fields').on 'shown.bs.collapse', (event) ->
-    $('#lnk-toggle-nonvascular_plant-sample-fields').text('Omit lichen sample')
+    $('#lnk-toggle-nonvascular-plant-sample-fields').text('Omit non-vascular plant sample')

   $('#nonvascular_plant_sample_fields').on 'hidden.bs.collapse', (event) ->
     $(@).find(':input:not([type=hidden])').val('')
     $(@).find('#biodiversity_report_nonvascular_plant_sample_attributes__destroy').val('1')
-    $('#lnk-toggle-nonvascular_plant-sample-fields').text('Add non-vascular plant sample')
+    $('#lnk-toggle-nonvascular-plant-sample-fields').text('Add non-vascular plant sample')


fix to borked mousehandling when page scrolled

--- app/assets/javascripts/components/subject-viewer.cjsx
+++ app/assets/javascripts/components/subject-viewer.cjsx
@@ -218,8 +218,8 @@
   getEventOffset: (e) ->
     rect = @refs.sizeRect.getDOMNode().getBoundingClientRect()
     scale = @state.scale # @getScale()
-    x = ((e.pageX - rect.left) / scale.horizontal) + @state.viewX
-    y = ((e.pageY - rect.top) / scale.vertical) + @state.viewY
+    x = ((e.pageX - window.pageXOffset - rect.left) / scale.horizontal) + @state.viewX
+    y = ((e.pageY - window.pageYOffset - rect.top) / scale.vertical) + @state.viewY
     return {x, y}

   # Set mark to currently selected:


Fix api.coffee media deletion implementation

--- scripts/api.coffee
+++ scripts/api.coffee
@@ -90,7 +90,7 @@

     self.deleteFile = (file) ->
         xhr = new XMLHttpRequest()
-        xhr.open('GET', "/api/#{file}/delete")
+        xhr.open('DELETE', "/api/#{file}")
         xhr.send()
         UserHistory.remove(file)


fix(search): Switching accounts while searching no longer breaks app

Fixes #850

--- internal_packages/thread-list/lib/thread-list-store.coffee
+++ internal_packages/thread-list/lib/thread-list-store.coffee
@@ -113,7 +113,7 @@
     accountMatcher = (m) ->
       m.attribute() is Thread.attributes.accountId and m.value() is accountId

-    return if @_view and _.find(@_view.matchers(), accountMatcher)
+    return if @_view instanceof DatabaseView and _.find(@_view.matchers(), accountMatcher)
     @createView()

   _onDataChanged: (change) ->


[Backport] Issue 5121 github links are broken

--- app/modules/components/wysiwyg/wysiwyg.service.coffee
+++ app/modules/components/wysiwyg/wysiwyg.service.coffee
@@ -78,16 +78,6 @@
             title = linkParams[1] || linkParams[0]

             return '[' + title + '](' + link  + ')'
-
-
-    linkTitleWithSpaces: (text) ->
-        link = /\[[^\]]*\]\(([^\)]*)\)/g # [Title-with-spaces](Title with spaces)
-
-        return text.replace link, (match, p1, offset, str) ->
-            if p1.indexOf(' ') >= 0
-                return match.replace /\(.*\)/, '(' + taiga.slugify(p1) + ')'
-            else
-                return match

     replaceUrls: (html) ->
         el = document.createElement( 'html' )
@@ -185,7 +175,7 @@

     autoLinkHTML: (html) ->
         # override Autolink parser
-
+
         matchRegexStr = String(Autolinker.matcher.Mention.prototype.matcherRegexes.twitter)
         if matchRegexStr.indexOf('.') == -1
             matchRegexStr = '@[^\s]{1,50}[^.\s]'
@@ -222,8 +212,7 @@
         }

         text = @.replaceEmojiNameByImgs(text)
-        text = @.pipeLinks(text)
-        text = @.linkTitleWithSpaces(text)
+        text = @.pipeLinks(text)

         md = window.markdownit({
             breaks: true


Auth: Stop cluttering Redis key space with keys.

--- server/auth.coffee
+++ server/auth.coffee
@@ -9,6 +9,7 @@
 config = require './config'
 db = require './database'

+USERS_KEY = "users"
 AUTH_KEY = "auth"

 # This middleware checks if a user is authenticated through the site. If yes,
@@ -25,14 +26,14 @@
     req.user = _.clone(body)
     hmac = crypto.createHmac('sha256', config.SECRET_KEY)
     req.user.token = hmac.update("#{req.user.id}").digest('hex')
-    db.set("users:#{body.id}", JSON.stringify(body), next)
+    db.hset(USERS_KEY, body.id, JSON.stringify(body), next)

 # If the id and token match, the associated user object is returned.
 exports.matchToken = (id, token, next) ->
   hmac = crypto.createHmac('sha256', config.SECRET_KEY)
   if hmac.update("#{id}").digest('hex') != token
     return next(new Error("Invalid session!"))
-  db.get "users:#{id}", (err, jsonString) ->
+  db.hget USERS_KEY, id, (err, jsonString) ->
     if err then return next(err)
     json = JSON.parse(jsonString)
     return next(new Error("Invalid session!"))  if !json


fix issue where isVoltageAuthorized() doesn't return true/false properly

--- server/boot.coffee
+++ server/boot.coffee
@@ -30,11 +30,13 @@
         return false

       # if role AND group is passed
-      if Voltage.settings.adminRole and Voltage.settings.adminGroup and not Roles.userIsInRole(Meteor.user(), Voltage.settings.adminRole, Voltage.settings.adminGroup)
-        return false
+      if Voltage.settings.adminRole and Voltage.settings.adminGroup
+        if not Roles.userIsInRole(Meteor.user(), Voltage.settings.adminRole, Voltage.settings.adminGroup)
+          return false

       # if only role is passed
-      if Voltage.settings.adminRole and not Roles.userIsInRole(Meteor.user(), Voltage.settings.adminRole)
-        return false
+      else if Voltage.settings.adminRole
+        if not Roles.userIsInRole(Meteor.user(), Voltage.settings.adminRole)
+          return false

       true


Add created to test

Add created to test

--- server/test.coffee
+++ server/test.coffee
@@ -1,10 +1,13 @@
 if Groups.find().count() == 0
   Groups.insert
     name: 'compgeom'
+    created: new Date
   Groups.insert
     name: '6.890'
+    created: new Date
   Groups.insert
     name: 'test'
+    created: new Date
     anonymous: ['read', 'post', 'edit']

 ## This code would add version numbers to MessageDiff objects, instead of


Upgrades tests

Upgrades tests

--- test/spec/sync/relational/many_to_many.tests.coffee
+++ test/spec/sync/relational/many_to_many.tests.coffee
@@ -156,7 +156,7 @@
             shared_reverse_json = another_reverses[0].toJSON()

             if unload
-              BackboneORM.model_cache.reset(->) # TODO: make async # reset cache
+              BackboneORM.model_cache.reset() # reset cache
               owner = new Owner({id: owner.id})

             owner.patchAdd 'reverses', shared_reverse_id, (err) ->
@@ -211,7 +211,7 @@
             shared_reverse_json = another_reverses[0].toJSON()

             if unload
-              BackboneORM.model_cache.reset(->) # TODO: make async # reset cache
+              BackboneORM.model_cache.reset() # reset cache
               owner = new Owner({id: owner.id})
             owner.patchAdd 'reverses', shared_reverse_json, (err) ->
               assert.ok(!err, "No errors: #{err}")
@@ -266,7 +266,7 @@
             shared_reverse_json = shared_reverse.toJSON()

             if unload
-              BackboneORM.model_cache.reset(->) # TODO: make async # reset cache
+              BackboneORM.model_cache.reset() # reset cache
               owner = new Owner({id: owner.id})
             owner.patchAdd 'reverses', shared_reverse, (err) ->
               assert.ok(!err, "No errors: #{err}")
@@ -314,7 +314,7 @@
             destroyed_model = reverses[0]
             other_model = reverses[1]
             if unload
-              BackboneORM.model_cache.reset(->) # TODO: make async # reset cache
+              BackboneORM.model_cache.reset() # reset cache
               owner = new Owner({id: owner.id})
             owner.patchRemove 'reverses', destroyed_model.id, (err) ->
               assert.ok(!err, "No errors: #{err}")
@@ -350,7 +350,7 @@
             destroyed_model = reverses[0]
             other_model = reverses[1]
             if unload
-              BackboneORM.model_cache.reset(->) # TODO: make async # reset cache
+              BackboneORM.model_cache.reset() # reset cache
               owner = new Owner({id: owner.id})
             owner.patchRemove 'reverses', destroyed_model.toJSON(), (err) ->
               assert.ok(!err, "No errors: #{err}")
@@ -386,7 +386,7 @@
             destroyed_model = reverses[0]
             other_model = reverses[1]
             if unload
-              BackboneORM.model_cache.reset(->) # TODO: make async # reset cache
+              BackboneORM.model_cache.reset() # reset cache
               owner = new Owner({id: owner.id})
             owner.patchRemove 'reverses', destroyed_model, (err) ->
               assert.ok(!err, "No errors: #{err}")
@@ -422,7 +422,7 @@
             destroyed_model = reverses[0]
             other_model = reverses[1]
             if unload
-              BackboneORM.model_cache.reset(->) # TODO: make async # reset cache
+              BackboneORM.model_cache.reset() # reset cache
               owner = new Owner({id: owner.id})
             owner.patchRemove 'reverses', [destroyed_model, other_model], (err) ->
               assert.ok(!err, "No errors: #{err}")
@@ -453,7 +453,7 @@

             destroyed_model = owners[0]
             if unload
-              BackboneORM.model_cache.reset(->) # TODO: make async # reset cache
+              BackboneORM.model_cache.reset() # reset cache
               reverse = new Reverse({id: reverse.id})
             reverse.patchRemove 'owners', destroyed_model.id, (err) ->
               assert.ok(!err, "No errors: #{err}")
@@ -484,7 +484,7 @@

             destroyed_model = owners[0]
             if unload
-              BackboneORM.model_cache.reset(->) # TODO: make async # reset cache
+              BackboneORM.model_cache.reset() # reset cache
               reverse = new Reverse({id: reverse.id})
             reverse.patchRemove 'owners', destroyed_model.toJSON(), (err) ->
               assert.ok(!err, "No errors: #{err}")
@@ -515,7 +515,7 @@

             destroyed_model = owners[0]
             if unload
-              BackboneORM.model_cache.reset(->) # TODO: make async # reset cache
+              BackboneORM.model_cache.reset() # reset cache
               reverse = new Reverse({id: reverse.id})
             reverse.patchRemove 'owners', destroyed_model, (err) ->
               assert.ok(!err, "No errors: #{err}")
@@ -546,7 +546,7 @@

             destroyed_model = owners[0]
             if unload
-              BackboneORM.model_cache.reset(->) # TODO: make async # reset cache
+              BackboneORM.model_cache.reset() # reset cache
               reverse = new Reverse({id: reverse.id})
             reverse.patchRemove 'owners', [destroyed_model], (err) ->
               assert.ok(!err, "No errors: #{err}")


fix bug where clicking "re-sort" removed selection filters

--- @client/proposal_sort_and_search.coffee
+++ @client/proposal_sort_and_search.coffee
@@ -70,6 +70,7 @@
     v = fetch sort_key
     v.force_resort = true
     save v
+

 window.sorted_proposals = (proposals, sort_key, require_force) ->

@@ -720,7 +721,10 @@

         # 'data-tooltip': if !browser.is_mobile then translator "engage.sort_order.out-of-order-tooltip", "A re-sort may be needed because someone else added or updated their opinion, or you selected an opinion view that filtered or weighed opinions differently."

-        onClick: invalidate_proposal_sorts
+        onClick: (e) =>
+          invalidate_proposal_sorts()
+          e.stopPropagation()
+          e.preventDefault()

         SVG
           width: 17


docpad.coffee: make the doc navigation order consistent with the doc overview

--- docpad.coffee
+++ docpad.coffee
@@ -145,6 +145,7 @@

       database.findAllLive(query, sorting).on 'add', (document) ->
         a = document.attributes
+        index = 0
         layout = 'doc'
         urls = ['/documentation/' + a.basename.replace(/^[\-0-9]+/,'')]
         categoryName = 'getting_started'
@@ -157,6 +158,7 @@
           categoryName
           categoryTitle
           editUrl
+          index
         }).addUrl(urls)

     tutorial: (database) ->
@@ -168,6 +170,7 @@

       database.findAllLive(query, sorting).on 'add', (document) ->
         a = document.attributes
+        index = 1
         layout = 'doc'
         categoryName = 'tutorial'
         categoryTitle = 'Tutorial'
@@ -180,6 +183,7 @@
           categoryName
           categoryTitle
           editUrl
+          index
         }).addUrl(urls)

     handbook: (database) ->
@@ -191,6 +195,7 @@

       database.findAllLive(query, sorting).on 'add', (document) ->
         a = document.attributes
+        index = 2
         layout = 'doc'
         categoryName = 'handbook'
         categoryTitle = "Handbook"
@@ -203,6 +208,7 @@
           categoryName
           categoryTitle
           editUrl
+          index
         }).addUrl(urls)

     resources: (database) ->
@@ -214,6 +220,7 @@

       database.findAllLive(query, sorting).on 'add', (document) ->
         a = document.attributes
+        index = 3
         layout = 'doc'
         categoryName = 'resources'
         categoryTitle = 'Resources'
@@ -226,6 +233,7 @@
           categoryName
           categoryTitle
           editUrl
+          index
         }).addUrl(urls)

     community: (database) ->
@@ -237,6 +245,7 @@

       database.findAllLive(query, sorting).on 'add', (document) ->
         a = document.attributes
+        index = 4
         layout = 'doc'
         categoryName = 'community'
         categoryTitle = 'Community'
@@ -249,6 +258,7 @@
           editUrl
           categoryName
           categoryTitle
+          index
         }).addUrl(urls)

     rootDocuments: (database) ->
@@ -257,7 +267,7 @@
         relativeOutDirPath: $startsWith: 'documentation'
         body: $ne: ""
         rootDoc: true
-      sorting = [categoryDirectory:1, relativeDirPath:1]
+      sorting = [index:1]

       database.findAllLive(query, sorting).on 'add', (document) ->
         a = document.attributes


documentation added for visualization.Paths

--- app/assets/javascripts/visualization/paths.js.coffee
+++ app/assets/javascripts/visualization/paths.js.coffee
@@ -1,3 +1,31 @@
+# visualization.Paths class
+# displays crumbs by intervention as a path
+#
+# @data is an array of hashes containing info to display
+# @layer is the layer name
+#
+# ==== examples
+#
+# @data is an array of hashes built according to the following model:
+# * minimal example of a hash representing a crumb:
+#   item  {
+#           name:         <intervention name>,  # may be the date, the doer's name, whatever you want as long as all the crumbs
+#                                               # for a given intervention have the same one. this is what is called in the
+#                                               # VisualizationHelper to build the legend if you wrote something like:
+#                                               #   = visualization do |v|
+#                                               #     - v.serie :crumbs, my_array_of_crumbs_hashes
+#                                               #     - v.paths :name, :crumbs
+#                                               # :name being the @layer parameter the constructor requires.
+#
+#           nature:       crumb.nature,         # proper to the crumb. May be one of the natures enumerated in Crumb model.
+#                                               # this option is used to display particular points bigger and to change the
+#                                               # path opacity for parts that correspond to actual works (points between a hard_start)
+#                                               # and a hard_stop crumb
+#
+#           shape:        crumb.geolocation,    # proper to the crumb. contains the actual crumb location as a Charta::Geometry object.
+#                                               # This is what is used to draw the crumb on the map
+#         }
+
 class visualization.Paths

   constructor: (@layer, @data, options = {}) ->
@@ -49,7 +77,7 @@
         group.push(crumbLayer)
     group

-  # Build HTML legend for given categories computed layer
+  # Build HTML legend for given paths computed layer
   buildLegend: () ->
     html  = "
"
     html += "
#{@layer.label}
"
@@ -70,7 +98,7 @@
     @items.find (item, index, array) ->
       item.name == name

-  # Check if categories are valid
+  # Check if paths are valid
   valid: () ->
     @items.length > 0


Port InPort tests

Port InPort tests

--- spec/InPort.coffee
+++ spec/InPort.coffee
@@ -1,18 +1,12 @@
-chai = require 'chai' unless chai
 if typeof process isnt 'undefined' and process.execPath and process.execPath.match /node|iojs/
-  inport = require '../src/lib/InPort'
-  outport = require '../src/lib/OutPort'
-  socket = require '../src/lib/InternalSocket'
-  ports = require '../src/lib/Ports'
+  chai = require 'chai' unless chai
+  noflo = require '../src/lib/NoFlo.coffee'
 else
-  inport = require 'noflo/src/lib/InPort.js'
-  outport = require 'noflo/src/lib/OutPort'
-  socket = require 'noflo/src/lib/InternalSocket.js'
-  ports = require 'noflo/src/lib/Ports'
+  noflo = require 'noflo'

 describe 'Inport Port', ->
   describe 'with default options', ->
-    p = new inport
+    p = new noflo.InPort
     it 'should be of datatype "all"', ->
       chai.expect(p.getDataType()).to.equal 'all'
     it 'should not be required', ->
@@ -22,7 +16,7 @@
     it 'should not be buffered', ->
       chai.expect(p.isBuffered()).to.equal false
   describe 'with custom type', ->
-    p = new inport
+    p = new noflo.InPort
       datatype: 'string'
       type: 'text/url'
     it 'should retain the type', ->
@@ -30,7 +24,7 @@
       chai.expect(p.options.type).to.equal 'text/url'

   describe 'without attached sockets', ->
-    p = new inport
+    p = new noflo.InPort
     it 'should not be attached', ->
       chai.expect(p.isAttached()).to.equal false
       chai.expect(p.listAttached()).to.eql []
@@ -43,8 +37,8 @@

   describe 'with processing function called with port as context', ->
     it 'should set context to port itself', (done) ->
-      s = new socket.InternalSocket
-      p = new inport
+      s = new noflo.internalSocket.InternalSocket
+      p = new noflo.InPort
       p.on 'data', (packet, component) ->
         chai.expect(@).to.equal p
         chai.expect(packet).to.equal 'some-data'
@@ -55,9 +49,9 @@
   describe 'with default value', ->
     p = s = null
     beforeEach ->
-      p = new inport
+      p = new noflo.InPort
         default: 'default-value'
-      s = new socket.InternalSocket
+      s = new noflo.internalSocket.InternalSocket
       p.attach s
     it 'should send the default value as a packet, though on next tick after initialization', (done) ->
       p.on 'data', (data) ->
@@ -82,7 +76,7 @@
         description: 'Person'
         required: true
         weNeverExpectThis: 'butWeStoreItAnyway'
-      p = new inport options
+      p = new noflo.InPort options
       for name, option of options
         chai.expect(p.options[name]).to.equal option

@@ -90,7 +84,7 @@
     right = 'all string number int object array'.split ' '
     wrong = 'not valie data types'.split ' '
     f = (datatype) ->
-      new inport
+      new noflo.InPort
         datatype: datatype
     right.forEach (r) ->
       it "should accept a '#{r}' data type", =>
@@ -101,7 +95,7 @@

   describe 'with TYPE (i.e. ontology) information', ->
     f = (type) ->
-      new inport
+      new noflo.InPort
         type: type
     it 'should be a URL or MIME', ->
       chai.expect(-> f 'http://schema.org/Person').to.not.throw()
@@ -125,7 +119,7 @@
         'buffered-data-3'
       ]

-      p = new inport
+      p = new noflo.InPort
         buffered: true
       , (eventName) ->
           expectedEvent = expectedEvents.shift()
@@ -137,7 +131,7 @@
             chai.expect(packet.payload).to.equal expectedData.shift()
           if expectedEvents.length is 0
             done()
-      s = new socket.InternalSocket
+      s = new noflo.internalSocket.InternalSocket
       p.attach s
       s.send 'buffered-data-1'
       s.send 'buffered-data-2'
@@ -146,9 +140,9 @@
       s.disconnect()

     it 'should be able to tell the number of contained data packets', ->
-      p = new inport
+      p = new noflo.InPort
         buffered: true
-      s = new socket.InternalSocket
+      s = new noflo.internalSocket.InternalSocket
       p.attach s
       s.send 'buffered-data-1'
       s.beginGroup 'foo'
@@ -160,16 +154,16 @@
       chai.expect(p.contains()).to.equal 3

     it 'should return undefined when buffer is empty', ->
-      p = new inport
+      p = new noflo.InPort
         buffered: true
       chai.expect(p.receive()).to.be.undefined

     it 'shouldn\'t expose the receive method without buffering', ->
-      p = new inport
+      p = new noflo.InPort
         # Specified here simply for illustrative purpose, otherwise implied
         # `false`
         buffered: false
-      s = new socket.InternalSocket
+      s = new noflo.internalSocket.InternalSocket
       p.attach s

       p.once 'data', (data) ->
@@ -182,9 +176,9 @@

   describe 'with accepted enumerated values', ->
     it 'should accept certain values', (done) ->
-      p = new inport
+      p = new noflo.InPort
         values: 'noflo is awesome'.split ' '
-      s = new socket.InternalSocket
+      s = new noflo.internalSocket.InternalSocket
       p.attach s
       p.on 'data', (data) ->
         chai.expect(data).to.equal 'awesome'
@@ -192,9 +186,9 @@
       s.send 'awesome'

     it 'should throw an error if value is not accepted', ->
-      p = new inport
+      p = new noflo.InPort
         values: 'noflo is awesome'.split ' '
-      s = new socket.InternalSocket
+      s = new noflo.internalSocket.InternalSocket
       p.attach s
       p.on 'data', ->
         # Fail the test, we shouldn't have received anything
@@ -204,29 +198,29 @@

   describe 'with processing shorthand', ->
     it 'should create a port with a callback', ->
-      s = new socket.InternalSocket
-      ps =
-        outPorts: new ports.OutPorts
-          out: new outport
-        inPorts: new ports.InPorts
+      s = new noflo.internalSocket.InternalSocket
+      ps =
+        outPorts: new noflo.OutPorts
+          out: new noflo.OutPort
+        inPorts: new noflo.InPorts
       ps.inPorts.add 'in', (event, payload) ->
         return unless event is 'data'
         chai.expect(payload).to.equal 'some-data'
-      chai.assert ps.inPorts.in instanceof inport
+      chai.assert ps.inPorts.in instanceof noflo.InPort
       ps.inPorts.in.attach s
       s.send 'some-data'

     it 'should also accept metadata (i.e. options) when provided', (done) ->
-      s = new socket.InternalSocket
+      s = new noflo.internalSocket.InternalSocket
       expectedEvents = [
         'connect'
         'data'
         'disconnect'
       ]
       ps =
-        outPorts: new ports.OutPorts
-          out: new outport
-        inPorts: new ports.InPorts
+        outPorts: new noflo.OutPorts
+          out: new noflo.OutPort
+        inPorts: new noflo.InPorts
       ps.inPorts.add 'in',
         datatype: 'string'
         required: true
@@ -242,11 +236,11 @@

   describe 'with IP handle callback option', ->
     it 'should pass IP objects to handler', (done) ->
-      s = new socket.InternalSocket
-      ps =
-        outPorts: new ports.OutPorts
-          out: new outport
-        inPorts: new ports.InPorts
+      s = new noflo.internalSocket.InternalSocket
+      ps =
+        outPorts: new noflo.OutPorts
+          out: new noflo.OutPort
+        inPorts: new noflo.InPorts
       ps.inPorts.add 'in',
         datatype: 'string'
         required: true
@@ -261,16 +255,16 @@
       s.send type: 'data', data: 'some-data'

     it 'should translate legacy events to IP objects', (done) ->
-      s = new socket.InternalSocket
+      s = new noflo.internalSocket.InternalSocket
       expectedEvents = [
         'openBracket'
         'data'
         'closeBracket'
       ]
       ps =
-        outPorts: new ports.OutPorts
-          out: new outport
-        inPorts: new ports.InPorts
+        outPorts: new noflo.OutPorts
+          out: new noflo.OutPort
+        inPorts: new noflo.InPorts
       ps.inPorts.add 'in',
         datatype: 'string'
         required: true
@@ -290,16 +284,16 @@
       s.disconnect()

     it 'should translate IP objects to legacy events', (done) ->
-      s = new socket.InternalSocket
+      s = new noflo.internalSocket.InternalSocket
       expectedEvents = [
         'connect'
         'data'
         'disconnect'
       ]
       ps =
-        outPorts: new ports.OutPorts
-          out: new outport
-        inPorts: new ports.InPorts
+        outPorts: new noflo.OutPorts
+          out: new noflo.OutPort
+        inPorts: new noflo.InPorts
       ps.inPorts.add 'in',
         datatype: 'string'
         required: true


Changed: Atom: trying Operator Mono

Changed: Atom: trying Operator Mono

--- dotfiles/.atom/config.cson
+++ dotfiles/.atom/config.cson
@@ -45,7 +45,7 @@
       "duotone-dark-sea-syntax"
     ]
   editor:
-    fontFamily: "Fira Code"
+    fontFamily: "Operator Mono"
     fontSize: 15
     invisibles:
       space: "‧"


SplitView: setView improved

SplitView: setView improved

--- src/components/split/splitview.coffee
+++ src/components/split/splitview.coffee
@@ -323,10 +323,12 @@
   removePanel:(index)->

-  setView:(view,index)->
-    if index > @panels.length or not view
-      warn "Either 'view' or 'index' is missing at KDSplitView::setView!"
-      return
+  setView: (view, index) ->
+
+    return warn "view is missing at KDSplitView::setView"   unless view
+    return warn "index is missing at KDSplitView::setView"  if index > @panels.length
+    return warn "index is missing at KDSplitView::setView"  unless view instanceof KDView
+
     @panels[index].addSubView view


fixed iReading when initial due date is set

--- src/components/task-plan/reading.cjsx
+++ src/components/task-plan/reading.cjsx
@@ -66,6 +66,12 @@
   contextTypes:
     router: React.PropTypes.func

+  getInitialState: ->
+    if TaskPlanStore.isNew(@props.id) and @context?.router?.getCurrentQuery().date
+      dueAt = new Date(@context.router.getCurrentQuery().date)
+      @setDueAt(dueAt)
+    {}
+
   setOpensAt: (value) ->
     {id} = @props
     TaskPlanActions.updateOpensAt(id, value)
@@ -96,9 +102,6 @@
     headerText = if TaskPlanStore.isNew(id) then 'Add Reading' else 'Edit Reading'
     topics = TaskPlanStore.getTopics(id)
     formClasses = ['create-reading']
-
-    if TaskPlanStore.isNew(id) and @context?.router?.getCurrentQuery().date
-      plan.due_at = new Date(@context.router.getCurrentQuery().date)

     # Restrict the due date to be after the open date
     # and restrict the open date to be before the due date


upload form CSS class

upload form CSS class

--- upload.coffee
+++ upload.coffee
@@ -3,6 +3,8 @@
 User = require 'zooniverse/models/user'

 class UploadForm extends Controller
+
+  className: 'readymade-generic-page'

   template: (context) ->
     logged_in = """


activity: fix docs typo

activity: fix docs typo

--- client/activity/lib/views/activitypane.coffee
+++ client/activity/lib/views/activitypane.coffee
@@ -266,7 +266,7 @@

     @searchResults.clear()  unless options.dontClear

-    # algolia doesn't need to dontClear paramete
+    # algolia doesn't need dontClear parameter
     delete options.dontClear  if options.dontClear

     kd.singletons.search


collaboration: broadcast message before ending

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -678,6 +678,8 @@

   endCollaborationForHost: (callbacks) ->

+    @broadcastMessage { type: 'SessionEnded' }
+
     fileName = @getRealtimeFileName()
     realtimeHelpers.deleteCollaborationFile @rtm, fileName, (err) =>
       return callbacks.error err  if err


In coffee set TileRenderer.tile_source to null rather than undefined

This matches what we'll get when the attribute comes from Python.

--- bokehjs/src/coffee/renderer/tile/tile_renderer.coffee
+++ bokehjs/src/coffee/renderer/tile/tile_renderer.coffee
@@ -231,7 +231,7 @@
       alpha: 1.0
       x_range_name: "default"
       y_range_name: "default"
-      tile_source: undefined
+      tile_source: null
     }

   display_defaults: ->


KDModalViewWithForms: add a method #aggregateFormData

--- components/modals/KDModalViewWithForms.coffee
+++ components/modals/KDModalViewWithForms.coffee
@@ -4,6 +4,16 @@
     super options,data
     @addSubView @modalTabs = new KDTabViewWithForms options.tabs

+  aggregateFormData:->
+    data = for own formName, form of @modalTabs.forms
+      name: formName
+      data: form.getData()
+    data.reduce (acc, form) ->
+      for own key, val of form.data
+        console.warn "Property #{key} will be overwitten!"  if key of acc
+        acc[key] = val
+      return acc
+    , {}

 # new KDModalViewWithForms
 #     title     : "with tabs and forms"


PUBDEV-1653 Refresh ignored columns when training frame is changed (bugfix).

--- src/ext/components/model-input.coffee
+++ src/ext/components/model-input.coffee
@@ -109,17 +109,22 @@
   _canGoToNextPage = lift _maxPages, _currentPage, (maxPages, index) -> index < maxPages - 1

   _searchCaption = lift _entries, _filteredItems, _selectionCount, _currentPage, _maxPages, (entries, filteredItems, selectionCount, currentPage, maxPages) ->
-    (if maxPages is 0 then '' else "Showing page #{currentPage + 1} of #{maxPages}. ") + "Filtered #{filteredItems.length} of #{entries.length}. #{selectionCount} ignored."
-
-  react _entries, -> filterItems()
+    caption = if maxPages is 0 then '' else "Showing page #{currentPage + 1} of #{maxPages}."
+    if filteredItems.length isnt entries.length
+      caption += " Filtered #{filteredItems.length} of #{entries.length}."
+    if selectionCount isnt 0
+      caption += " #{selectionCount} ignored."
+    caption
+
+  react _entries, -> filterItems yes

   _lastUsedSearchTerm = null
   _lastUsedIgnoreNaTerm = null
-  filterItems = ->
+  filterItems = (force=no) ->
     searchTerm = _searchTerm().trim()
     ignoreNATerm = _ignoreNATerm().trim()

-    if searchTerm isnt _lastUsedSearchTerm or ignoreNATerm isnt _lastUsedIgnoreNaTerm
+    if force or searchTerm isnt _lastUsedSearchTerm or ignoreNATerm isnt _lastUsedIgnoreNaTerm
       filteredItems = []
       for entry, i in _entries()
         missingPercent = parseFloat ignoreNATerm


Add browser#joinURI and browser#atURI.

Add browser#joinURI and browser#atURI.

--- application/chrome/content/wesabe/dom/browser.coffee
+++ application/chrome/content/wesabe/dom/browser.coffee
@@ -14,18 +14,33 @@
   #   browser.go('/groups')
   #
   go: (browser, uri) ->
-    curi = browser.currentURI
+    uri = @joinURI(browser, uri)
+    wesabe.debug('Loading uri=', uri)
+    browser.loadURI(wesabe.untaint(uri), null, null)
+
+  #
+  # Get the absolute uri by joining +uri+ to the current uri of +browser+.
+  # +uri+ may be either relative or absolute.
+  #
+  joinURI: (browser, uri) ->
     tainted = wesabe.isTainted(uri)
     uri = wesabe.untaint(uri) if tainted
-    uri = curi.resolve(uri) if curi
-    wesabe.debug('Loading uri=', (if tainted then wesabe.taint(uri.toString()) else uri.toString()))
-    browser.loadURI(uri, null, null)
+    uri = browser.currentURI?.resolve(uri)
+
+    if tainted then wesabe.taint(uri) else uri

   #
-  # Get the current location of this browser, null if it is not on a page.
-  #
-  # @param browser {XULBrowser} A <browser/> element.
-  # @return {String, null} The location of the browser.
+  # Get the current uri of +browser+ as a string.
   #
   getURI: (browser) ->
-    browser.currentURI?.toString()
+    wesabe.taint(browser.currentURI?.resolve(null))
+
+  #
+  # Determines whether +browser+ is currently at +uri+,
+  # which may be relative or absolute.
+  #
+  atURI: (browser, uri) ->
+    currentURI = browser.currentURI
+    return true if currentURI is null and uri is null
+
+    wesabe.untaint(@getURI(browser)) == wesabe.untaint(@joinURI(browser, uri))


more existential

more existential

--- node_modules_koding/kite-amqp/lib/kite-amqp/index.coffee
+++ node_modules_koding/kite-amqp/lib/kite-amqp/index.coffee
@@ -38,8 +38,9 @@
     authenticatedUser = @clients[routingKey]
     @unscrubMessage routingKey, authenticatedUser, scrubbed, (unscrubbed)=>
       [data, callback] = unscrubbed
-      data.withArgs?.username = authenticatedUser
-      {method, withArgs} = data  if data?
+      if data?
+        data.withArgs?.username = authenticatedUser
+        {method, withArgs} = data
       withArgs or= {}
       switch method
         when 'ping' then @handleResponse routingKey, callback.id, 1


Fix PlanningboardApp test to sync up with new css class

--- test/spec/roadmapplanningboard/PlanningBoardSpec.coffee
+++ test/spec/roadmapplanningboard/PlanningBoardSpec.coffee
@@ -107,7 +107,7 @@
     @createCardboard().then =>
       _.each @cardboard.getColumns(), (column) =>
         _.each column.getCards(), (card) =>
-          expect(card.getEl().down('.rui-card-content .PreliminaryEstimate .rui-field-value').dom.innerHTML).toBe "L"
+          expect(card.getEl().down('.rui-card-right-side .PreliminaryEstimate .rui-field-value').dom.innerHTML).toBe "L"

   it 'should have project on the cards', ->
     @createCardboard().then =>


Get all properties of GDrive files; add node#exifOrFileCreated property; readonly GDrive scope;

--- src/adaptor/googleDrive.coffee
+++ src/adaptor/googleDrive.coffee
@@ -11,7 +11,7 @@
       callback "Google API (global 'gapi' object) not found.  See: https://developers.google.com/drive/v3/web/quickstart/js"

     defaults args,
-      scope: 'https://www.googleapis.com/auth/drive'
+      scope: 'https://www.googleapis.com/auth/drive.readonly'
       immediate: true

     gapi.auth.authorize args, (authResult) => @handleAuthResult(authResult, args, callback)
@@ -32,12 +32,7 @@

   addMetadata: (files) ->
     for file in files
-      if file.id? and not file.viewUrl?
-        file.viewUrl ?= "http://drive.google.com/uc?export=view&id=#{file.id}"
-      if file.id? and not file.downloadUrl?
-        file.downloadUrl ?= "http://drive.google.com/uc?export=download&id=#{file.id}"
-      if file.id? and file.mimeType.startsWith('image/') and not file.thumbnailUrl?
-        file.thumbnailUrl ?= "https://drive.google.com/thumbnail?authuser=0&sz=w320&id=#{file.id}"
+      file.exifOrFileCreated ?= file.imageMediaMetadata?.time ? file.createdTime

   toSphere: (rootNodeId, files) =>
     sphere = new Sphere
@@ -48,22 +43,21 @@
         end: sphere.addNode(file)
     sphere

-  getFiles: promisify (filter, callback) ->
-    gapi.client.load 'drive', 'v3', ->
-      retrievePageOfFiles = (request, files) ->
-        request.execute((resp) ->
-          files = files.concat resp.files
-          nextPageToken = resp.nextPageToken
-          if nextPageToken
-            request = gapi.client.drive.files.list
-              q: filter
-              pageToken: nextPageToken
-            retrievePageOfFiles request, result
-          else
-            callback null, files
-        )
-      initialRequest = gapi.client.drive.files.list q: filter
-      retrievePageOfFiles initialRequest, []
+  getFiles: (filter, allFiles=[], nextPageToken=null) ->
+    gapi.client.request
+      path: "drive/v3/files"
+      params:
+        q: filter
+        pageToken: nextPageToken
+        fields: 'files,kind,nextPageToken'
+        pageSize: 1000
+    .then (response) =>
+      {result: {files, nextPageToken}} = response
+      allFiles.push files...
+      if nextPageToken
+        @getFiles filter, allFiles, nextPageToken
+      else
+        allFiles

   # ####################################################################
   # # Filename utilities


Measure memory usage after re-subscribe

Measure memory usage after re-subscribe

--- performance/MemoryTest.coffee
+++ performance/MemoryTest.coffee
@@ -38,7 +38,8 @@
   mean: mean(values)
   stddev: stddev(values)

-printResult = (label, result, prefix = '') ->
+printResult = (label, result, forcePrefix = false) ->
+  prefix = if prefix && result.mean > 0 then '+' else ''
   console.log("  #{rpad(label, 20)}", lpad(prefix + byteFormat(result.mean), 12), '\u00b1', byteFormat(result.stddev, result.mean))
 createNObservable = (count, generator) ->
   n = Math.floor(count / 10)
@@ -48,32 +49,38 @@
     global.gc()
     objects = new Array(n) # Preallocate array of n elements
     unsubscribers = new Array(n)
-
-    withoutSubscriber = measure ->
-      objects[i] = generator(i) for i in [0...objects.length]
-
-    withSubscriber = measure ->
+    subscribe = ->
       for i in [0...objects.length]
         unsubscribers[i] = objects[i].onValue(noop)
-
-    afterCleanup = measure ->
+    unsubscribe = ->
       for i in [0...objects.length]
         unsubscribers[i]()
         unsubscribers[i] = null

+    global.gc()
+    withoutSubscriber = measure ->
+      objects[i] = generator(i) for i in [0...objects.length]
+
+    withSubscriber = measure subscribe
+    afterCleanup = measure unsubscribe
+    reSubscribe = measure subscribe
+    afterReCleanup = measure unsubscribe
+
     objects = null
     unsubscribers = null
-    [withoutSubscriber[0]/n, withSubscriber[0]/n, afterCleanup[0]/n]
+    [withoutSubscriber[0]/n, withSubscriber[0]/n, afterCleanup[0]/n, reSubscribe[0]/n, afterReCleanup[0]/n]

   withoutSubscriber = processResults(results, 0)
   withSubscriber = processResults(results, 1)
   afterCleanup = processResults(results, 2)
+  reSubscribe = processResults(results, 3)
+  afterReCleanup = processResults(results, 4)

-  plusSubscriber = if withSubscriber.mean > 0 then '+' else ''
-  plusCleanup = if afterCleanup.mean > 0 then '+' else ''
   printResult('w/o subscription', withoutSubscriber)
-  printResult('with subscription', withSubscriber, plusSubscriber)
-  printResult('unsubscribe', afterCleanup, plusCleanup)
+  printResult('with subscription', withSubscriber, true)
+  printResult('unsubscribe', afterCleanup, true)
+  printResult('subscribe again', reSubscribe, true)
+  printResult('unsubscribe again', afterReCleanup, true)

 title = (text) -> console.log('\n' + text)
 noop = ->


bugfix

bugfix

--- modules/dnode/platforms/node/lib/cluster/Director.coffee
+++ modules/dnode/platforms/node/lib/cluster/Director.coffee
@@ -21,7 +21,7 @@

             if !floyd.tools.files.exists config.data.workers_dir
                 floyd.tools.files.mkdir config.data.workers_dir
-                if floyd.system.UID == 0 && config UID
+                if floyd.system.UID == 0 && config.UID
                     floyd.tools.files.chown config.data.workers_dir, config.UID, (config.GID || config.UID)
                 floyd.tools.files.chmod config.data.workers_dir, '2755'


Refs #55; Outer padding support for basic bar.

--- coffee/basic/bar.coffee
+++ coffee/basic/bar.coffee
@@ -4,6 +4,9 @@
     style: 'grouped'
     orientation: 'horizontal'
     padding:
+      bar: 0.08
+      group: 0.1
+    outerPadding:
       bar: 0.08
       group: 0.1

@@ -28,7 +31,7 @@
     if @options.orientation == 'horizontal'
       d3.scale.ordinal()
         .domain(Epoch.Util.domain(@data))
-        .rangeRoundBands([0, @innerWidth()], @options.padding.group)
+        .rangeRoundBands([0, @innerWidth()], @options.padding.group, @options.outerPadding.group)
     else
       extent = @extent((d) -> d.y)
       extent[0] = Math.min(0, extent[0])
@@ -40,7 +43,7 @@
   x1: (x0) ->
     d3.scale.ordinal()
       .domain((layer.category for layer in @data))
-      .rangeRoundBands([0, x0.rangeBand()], @options.padding.bar)
+      .rangeRoundBands([0, x0.rangeBand()], @options.padding.bar, @options.outerPadding.bar)

   # @return [Function] The y scale used to render the bar chart.
   y: ->
@@ -53,13 +56,13 @@
     else
       d3.scale.ordinal()
         .domain(Epoch.Util.domain(@data))
-        .rangeRoundBands([0, @innerHeight()], @options.padding.group)
+        .rangeRoundBands([0, @innerHeight()], @options.padding.group, @options.outerPadding.group)

   # @return [Function] The x scale used to render the vertical bar chart.
   y1: (y0) ->
     d3.scale.ordinal()
       .domain((layer.category for layer in @data))
-      .rangeRoundBands([0, y0.rangeBand()], @options.padding.bar)
+      .rangeRoundBands([0, y0.rangeBand()], @options.padding.bar, @options.outerPadding.bar)

   # Remaps the bar chart data into a form that is easier to display.
   # @return [Array] The reorganized data.


added error reporting to stylus callback

--- modules/gui/platforms/node/lib/StylusContext.coffee
+++ modules/gui/platforms/node/lib/StylusContext.coffee
@@ -27,8 +27,17 @@
                     res.cache.lastModified floyd.tools.files.stat(@data.file).mtime, ()=>

                         stylus(floyd.tools.files.read @data.file).render (err, style)=>
-
+                            return next(err) if err
+
                             res.send style

+                ##
+                if @data.file.match /^\/public/
+
+                    @delegate '_addRoute', @data.file.substr(7), (req, res, next)=>
+
+                        next new floyd.error.NotFound req.uri
+
+                ##
                 done()


atom: use smarter indent guide package

atom: use smarter indent guide package

--- .atom/config.cson
+++ .atom/config.cson
@@ -23,7 +23,6 @@
     fontSize: 21
     invisibles: {}
     showInvisibles: true
-    showIndentGuide: true
     softWrap: true
   "exception-reporting":
     userId: "ff49e55f-cf0d-c4b0-dc96-0290b690d294"


Changes to Atom prefs

Changes to Atom prefs

--- .atom/config.cson
+++ .atom/config.cson
@@ -13,12 +13,15 @@
     telemetryConsent: "no"
     titleBar: "custom"
   editor:
-    fontFamily: "SFMono-Light"
+    fontFamily: "Fira Code"
+    fontSize: 13
     scrollPastEnd: true
     showIndentGuide: true
     showInvisibles: true
   "exception-reporting":
     userId: "6e1d0249-4ec9-488e-9ef6-eb08a340860f"
+  "isotope-ui":
+    tabSizing: "Minimum"
   "linter-eslint": {}
   "linter-ui-default":
     panelHeight: 69
@@ -36,5 +39,7 @@
       pigmentsDecorationsZIndex: 0
       selection: true
       selectionDecorationsZIndex: 0
+  "one-dark-ui":
+    fontSize: 11
   welcome:
     showOnStartup: false


atom: update config

atom: update config

--- .atom/config.cson
+++ .atom/config.cson
@@ -100,6 +100,7 @@
     position: "Right"
   "tree-view":
     hideIgnoredNames: true
+    hideVcsIgnoredFiles: true
     squashDirectoryNames: true
   "vim-mode":
     useClipboardAsDefaultRegister: true


whitespace.

whitespace.

--- ansir-cli.coffee
+++ ansir-cli.coffee
@@ -54,4 +54,3 @@
   )

 commander.parse(process.argv)
-


BUG-FIX getter when read with error should return undefined

--- src/modules/controller.coffee
+++ src/modules/controller.coffee
@@ -150,7 +150,11 @@
       try
         getter scope
       catch e
-        throw "#{e} in running accessor '#{original or evaluate}'"
+        if e instanceof TypeError
+          undefined
+        else
+          throw "#{e} in running accessor '#{original or evaluate}'"
+          throw e

   _setter: (scope, evaluate, original)->
     try
@@ -163,6 +167,7 @@
         setter(scope, newValue)
       catch e
         throw "#{e} in running accessor '#{original or evaluate}'"
+        throw e

   watch: (keys, callback, initCall = true)->
     keys = keys.split(' ')


API: Allow forme moveset checking.

API: Allow forme moveset checking.

--- api/index.coffee
+++ api/index.coffee
@@ -91,16 +91,20 @@
         res.send(moves: moves)
         return next()

-      server.get "#{gen}/pokemon/:name/check", (req, res, next) ->
+      checkMoveset = (req, res, next) ->
         name = getName(req.params.name)
         return next(new restify.ResourceNotFoundError("Could not find Pokemon: #{req.params.name}"))  if !name
         pokemon = {name: name}
+        pokemon.forme = req.params.forme  if req.params.forme
         moveset = req.query.moves?.split(/,/) || []
         valid = learnsets.checkMoveset(GenerationJSON, pokemon, intGeneration, moveset)
         errors = []
         errors.push("Invalid moveset")  if !valid
         res.send(errors: errors)
         return next()
+
+      server.get "#{gen}/pokemon/:name/check", checkMoveset
+      server.get "#{gen}/pokemon/:name/:forme/check", checkMoveset

       server.put "#{gen}/damagecalc", (req, res, next) ->
         # todo: catch any invalid data.


Fixes bug not firing update event via set

--- src/observable/observable_base.coffee
+++ src/observable/observable_base.coffee
@@ -96,15 +96,13 @@
     else
       @_data[prop] = val

-    if @_tracking.setter
-      @_createTrack 'setter', prop
-    else if options.notify
-      @_update prop, 'set'
+    @_createTrack 'setter', prop if @_tracking.setter
+    @_update prop if options.notify

     val

   set: ->
-    { keypath, val, options, pairs } = polymorphic
+    { keypath, val, options, pairs } = Leaf.Utils.polymorphic
       '.': 'val'
       'oo?': 'pairs options'
       's.o?': 'keypath val options'


Sidebar: hardcoded public link navitem removed

--- client/Social/Activity/sidebar/activitysidebar.coffee
+++ client/Social/Activity/sidebar/activitysidebar.coffee
@@ -166,7 +166,7 @@

   getItems: ->

-    items = [ @public ]
+    items = []
     items = items.concat @sections.followedTopics.listController.getListItems()
     items = items.concat @sections.conversations.listController.getListItems()
     items = items.concat @sections.messages.listController.getListItems()
@@ -273,13 +273,6 @@

     @deselectAllItems()

-    if type is 'public'
-      @selectedItem = @public
-      @public.setClass 'selected'
-      return
-    else
-      @public.unsetClass 'selected'
-
     type       = 'privatemessage'  if type is 'message'
     candidates = []

@@ -329,7 +322,6 @@

     # @addSubView new GroupDescription  unless KD.getGroup().slug is 'koding'
     @addGroupDescription()  unless KD.isKoding()
-    @addPublicFeedLink()
     # @addHotTopics()
     @addFollowedTopics()
     @addConversations()


Update teammembersview.coffee

Update teammembersview.coffee

--- client/admin/lib/views/members/teammembersview.coffee
+++ client/admin/lib/views/members/teammembersview.coffee
@@ -1,4 +1,3 @@
-kd                    = require 'kd'
 KDView                = kd.View
 TeamMembersCommonView = require './teammemberscommonview'


xit out the last flakey test

xit out the last flakey test

--- client/angular/test/protractor/discussion_spec.coffee
+++ client/angular/test/protractor/discussion_spec.coffee
@@ -25,7 +25,7 @@
       page.expectElement('.timeago')

   describe 'close thread', ->
-    it 'can close and reopen a thread', ->
+    xit 'can close and reopen a thread', ->
       page.loadPath 'setup_open_and_closed_discussions'
       page.expectText '.discussions-card__header', 'Open threads'
       page.expectText '.discussions-card__header', '1 Closed'


Client: fix notification for group channels

--- client/app/lib/maincontroller/groupscontroller.coffee
+++ client/app/lib/maincontroller/groupscontroller.coffee
@@ -79,7 +79,7 @@
       subscriptionData =
         group      : group.slug
         channelType: "group"
-        channelName: group.slug
+        channelName: "public"
         token      : channel.token
         channelId  : group.socialApiChannelId