Better github site.

Better github site.

--- config/jknt-smblott.coffee
+++ config/jknt-smblott.coffee
@@ -127,7 +127,7 @@
 configs.push
   name: "Github Discussions"
   regexps: [
-    "^https?://github.com/.*/(issues?|pulls?)/[1-9]+$"
+    "^https?://github.com/.*/(issues?|pulls?)/[0-9]+$"
   ]
   selectors: [
     "div.discussion-timeline div[id^='issue-']"
@@ -151,6 +151,19 @@
   offset: 30

 configs.push
+  name: "Github Diffs"
+  regexps: [
+    "^https?://github.com/.*/pull/[0-9]+/files"
+  ]
+  selectors: [
+    "td.blob-code-addition"
+    "td.blob-code-deletion"
+    # Navigation bar.
+    "div.tabnav a.tabnav-tab:not(.selected):not(.preview-tab)"
+  ]
+  offset: 250
+
+configs.push
   name: "Google Plus"
   regexps: "^https?://plus\\.google\\.com"
   selectors: [ "div[id^='update-']" ]


OX-403 Improve formatting

OX-403 Improve formatting

--- app/assets/javascripts/oxalis/view/gui.coffee
+++ app/assets/javascripts/oxalis/view/gui.coffee
@@ -69,23 +69,32 @@
     @addCheckbox(fControls, @user, "dynamicSpaceDirection", "d/f-Switching")

     fFlightcontrols = @gui.addFolder("Flighcontrols")
-    @addSlider(fFlightcontrols, @user, "mouseRotateValue", 0.001, 0.02, 0.001, "Mouse Rotation")
-    @addSlider(fFlightcontrols, @user, "rotateValue", 0.001, 0.08, 0.001, "Keyboard Rotation Value")
-    @addSlider(fFlightcontrols, @user, "moveValue3d", 0.1, 10, 0.1, "Move Value")
-    @addSlider(fFlightcontrols, @user, "crosshairSize", 0.1, 1, 0.01, "Crosshair size")
+    @addSlider(fFlightcontrols, @user, "mouseRotateValue",
+      0.001, 0.02, 0.001, "Mouse Rotation")
+    @addSlider(fFlightcontrols, @user, "rotateValue",
+      0.001, 0.08, 0.001, "Keyboard Rotation Value")
+    @addSlider(fFlightcontrols, @user, "moveValue3d",
+      0.1, 10, 0.1, "Move Value")
+    @addSlider(fFlightcontrols, @user, "crosshairSize",
+      0.1, 1, 0.01, "Crosshair size")

     fPlanes = @gui.addFolder("Planes")
-    @addSlider(fPlanes, @user, "moveValue", 0.1, 10, 0.1, "Move Value")
-    @addSlider(fPlanes, @user, "routeClippingDistance", 1, 1000 * @model.scaleInfo.baseVoxel, 1, "Clipping Distance")
+    @addSlider(fPlanes, @user, "moveValue",
+      0.1, 10, 0.1, "Move Value")
+    @addSlider(fPlanes, @user, "routeClippingDistance",
+      1, 1000 * @model.scaleInfo.baseVoxel, 1, "Clipping Distance")
     @addCheckbox(fPlanes, @user, "displayCrosshair", "Show Crosshairs")

     fVoxel = @gui.addFolder("Voxel")
     @addCheckbox(fVoxel, @settings, "fourBit", "4 Bit")
     @brightnessController =
-      @addSlider(fVoxel, @settings, "brightness", -256, 256, 5, "Brightness", @setBrightnessAndContrast)
+      @addSlider(fVoxel, @settings, "brightness",
+        -256, 256, 5, "Brightness", @setBrightnessAndContrast)
     @contrastController =
-      @addSlider(fVoxel, @settings, "contrast", 0.5, 5, 0.1, "Contrast", @setBrightnessAndContrast)
-    @addFunction(fVoxel, @settings, "resetBrightnessAndContrast", "Reset To Default")
+      @addSlider(fVoxel, @settings, "contrast",
+        0.5, 5, 0.1, "Contrast", @setBrightnessAndContrast)
+    @addFunction(fVoxel, @settings, "resetBrightnessAndContrast",
+      "Reset To Default")
     @addCheckbox(fVoxel, @user, "interpolation", "Interpolation")
     (fVoxel.add @settings, "quality", @qualityArray)
                           .name("Quality")
@@ -97,7 +106,8 @@
     @addCheckbox(fSkeleton, @user, "displayPreviewXZ", "Display XZ-Plane")

     fTrees = @gui.addFolder("Trees")
-    @activeTreeIdController = @addNumer(fTrees, @settings, "activeTreeID", 1, 1, "Active Tree ID")
+    @activeTreeIdController = @addNumber(fTrees, @settings, "activeTreeID",
+      1, 1, "Active Tree ID")
     if somaClickingAllowed
       @addCheckbox(fTrees, @settings, "newNodeNewTree", "Soma clicking mode")
     else
@@ -106,7 +116,8 @@
     @addFunction(fTrees, @settings, "deleteActiveTree", "Delete Active Tree")

     fNodes = @gui.addFolder("Nodes")
-    @activeNodeIdController = @addNumer(fNodes, @settings, "activeNodeID", 1, 1, "Active Node ID")
+    @activeNodeIdController = @addNumber(fNodes, @settings, "activeNodeID",
+      1, 1, "Active Node ID")
     @commentController =
     (fNodes.add @settings, "comment")
                           .name("Comment")
@@ -159,16 +170,18 @@
                           .onChange((v) => @set(propertyName, v,  Boolean))

   addSlider : (folder, object, propertyName, start, end, step, displayName, onChange) =>
+    unless onChange?
+      onChange = (v) => @set(propertyName, v, Number)
     return (folder.add object, propertyName, start, end)
                           .step(step)
                           .name(displayName)
-                          .onChange(if onChange? then onChange else(v) => @set(propertyName, v, Number))
+                          .onChange(onChange)

   addFunction : (folder, object, propertyName, displayName) =>
     return (folder.add object, propertyName)
                           .name(displayName)

-  addNumer : (folder, object, propertyName, min, step, displayName) =>
+  addNumber : (folder, object, propertyName, min, step, displayName) =>
     return (folder.add object, propertyName)
                           .min(min)
                           .step(step)


refactor: only load the .users-typeahead element if it's present

This prevents a GET call to /users.json even when the .users-typeahead
element was not present. However this unnecessary request seemed to happen
only on Safari but not on Chrome.

--- app/assets/javascripts/users_typeahead.coffee
+++ app/assets/javascripts/users_typeahead.coffee
@@ -1,7 +1,7 @@
 # SOURCE: http://brandonhilkert.com/blog/organizing-javascript-in-rails-application-with-turbolinks/
 $(document).on 'page:change', ->
   do ( $$ = window.Basimilch, $ = jQuery ) ->
-   if $$.isAdminPage()
+   if $$.isAdminPage() and $('.users-typeahead').some()
       # DOC: https://github.com/twitter/typeahead.js/tree/v0.11.1
       # DOC: https://twitter.github.io/typeahead.js/examples/
       users = new Bloodhound


refactor: end game

refactor: end game

--- app/controllers/currentGame_controller.coffee
+++ app/controllers/currentGame_controller.coffee
@@ -313,34 +313,27 @@
       homePerson = game.get('home')
       awayPerson = game.get('away')
       #And the winner is..
+      homeWins = homePerson.get('wins')
+      homeLoss = homePerson.get('losses')
+      awayWins = awayPerson.get('wins')
+      awayLoss = awayPerson.get('losses')
+      if not homeWins? or homeWins == NaN
+        homeWins = 0
+      if not homeLoss? or homeLoss == NaN
+        homeLoss = 0
+      if not awayWins? or awayWins == NaN
+        awayWins = 0
+      if not awayLoss? or awayLoss == NaN
+        awayLoss = 0
       if game.get('homeScore') > game.get('awayScore')
-        wins = homePerson.get('wins')
-        if not wins? or wins == NaN
-          wins = 0
-        loss = awayPerson.get('losses')
-        if not loss? or loss == NaN
-          loss = 0
-        w = wins + 1
-        l = loss + 1
-        homePerson.set('wins', w)
-        awayPerson.set('losses',l)
-        homePerson.save()
-        awayPerson.save()
-        @gameOver()
+        homePerson.set('wins', homeWins + 1)
+        awayPerson.set('losses', awayLoss + 1)
       if game.get('homeScore') < game.get('awayScore')
-        wins = awayPerson.get('wins')
-        if not wins? or wins == NaN
-          wins = 0
-        loss = homePerson.get('losses')
-        if not loss? or loss == NaN
-          loss = 0
-        w = wins + 1
-        l = loss + 1
-        awayPerson.set('wins', w)
-        homePerson.set('losses',l)
-        homePerson.save()
-        awayPerson.save()
-        @gameOver()
+        awayPerson.set('wins', awayWins + 1)
+        homePerson.set('losses', homeLoss + 1)
+      homePerson.save()
+      awayPerson.save()
+      @gameOver()
       return
     cancelGame: ->
       @set('cancelGameConfirm', false)


Allow specifying scrollTopOffset in options

--- shared/src/components/scroll-to-mixin.cjsx
+++ shared/src/components/scroll-to-mixin.cjsx
@@ -74,13 +74,15 @@
     # The element's postion may have changed if scrolling was initiated while
     # the page was still being manipulated.
     # If that's the case, we begin another scroll to it's current position
-    if options.attemptNumber < MAXIMUM_SCROLL_ATTEMPTS and @props.windowImpl.pageYOffset isnt @_desiredTopPosition(el)
-      @scrollToElement(el, options.attemptNumber + 1)
+    if options.attemptNumber < MAXIMUM_SCROLL_ATTEMPTS and @props.windowImpl.pageYOffset isnt @_desiredTopPosition(el, options)
+      @scrollToElement(el, extend(options, {attemptNumber: options.attemptNumber + 1}))
     else
       @_onAfterScroll(el, options)

-  _desiredTopPosition: (el) ->
-    GetPositionMixin.getTopPosition(el) - _.result(@, 'getScrollTopOffset', DEFAULT_TOP_OFFSET)
+  _desiredTopPosition: (el, options = {} ) ->
+    GetPositionMixin.getTopPosition(el) - (
+      options.scrollTopOffset or result(@, 'getScrollTopOffset', DEFAULT_TOP_OFFSET)
+    )

   scrollToTop: ->
     root = @props.windowImpl.document.body.querySelector('#ox-react-root-container')


Added brain commands

Added brain commands

--- scripts/dweet-brain.coffee
+++ scripts/dweet-brain.coffee
@@ -2,7 +2,11 @@
 #   Dweet.io powered Hubot Brain
 #
 # Dependencies:
-#   None
+#   "moment": "^2.5.1"
+#
+# Commands:
+#   hubot brain save - Forces a save to Dweet.io
+#   hubot brain status - Returns the brain status
 #
 # Configuration:
 #   DWEET_THING
@@ -10,6 +14,8 @@
 #
 # Author:
 #   MrSaints
+
+moment = require 'moment'

 DWEET_THING = process.env.DWEET_THING
 DWEET_KEY = process.env.DWEET_KEY
@@ -36,26 +42,48 @@
     if not DWEET_THING?
         return

+    status =
+        connected: false
+        lastSaved: false
+
+    robot.brain.setAutoSave false
     robot.brain.resetSaveInterval(600)
     #robot.brain.resetSaveInterval(10)

-    dweet_request robot, '/get/latest/dweet', null, (dweet) ->
-        if dweet.with is 404
-            robot.brain.mergeData {}
-            robot.logger.info 'Initializing new data for brain'
-            robot.brain.save()
-            return
-        else if dweet.this is 'failed'
-            return robot.logger.error dweet.because
+    getData = ->
+        dweet_request robot, '/get/latest/dweet', null, (dweet) ->
+            if dweet.with is 404
+                robot.brain.mergeData {}
+                robot.logger.info 'Initializing new data for brain'
+                robot.brain.save()
+            else if dweet.this is 'failed'
+                return robot.logger.error dweet.because

-        content = decodeChildren dweet.with[0].content
-        robot.brain.mergeData content
-        robot.logger.info 'Data for brain retrieved from Dweet.io'
+            robot.brain.setAutoSave true
+            status.connected = true
+            status.lastSaved = dweet.with[0].created
+
+            if dweet.with isnt 404
+                content = decodeChildren dweet.with[0].content
+                robot.brain.mergeData content
+                robot.logger.info 'Data for brain retrieved from Dweet.io'
+    getData()

     robot.brain.on 'save', (data = {}) ->
         dweet_request robot, '/dweet', encodeChildren(data), (dweet) ->
             return robot.logger.error dweet.because if dweet.this is 'failed'
+
+            status.lastSaved = dweet.with.created
             robot.logger.info "Successfully Dweeted to #{DWEET_THING}"
+
+    robot.respond /brain save/i, (msg) ->
+        msg.reply "Saving..."
+        robot.brain.save()
+
+    robot.respond /brain status/i, (msg) ->
+        connected = if status.connected then 'Initialized (Autosaving)' else 'Uninitialized (Autosaving Disabled)'
+        lastSaved = moment(status.lastSaved).fromNow() or 'N/A'
+        msg.reply "Status: #{connected} | Brain last saved: #{lastSaved}"

 dweet_request = (robot, endpoint, params = {}, handler) ->
     params['key'] = DWEET_KEY if DWEET_KEY?


FEM redirect: Corr w/ Quaker via MonorepoRoute

--- app/router.cjsx
+++ app/router.cjsx
@@ -164,6 +164,7 @@
     <MonorepoRoute path="/projects/hughdickinson/superwasp-black-hole-hunters" />
     <MonorepoRoute path="/projects/bogden/scarlets-and-blues" />
     <MonorepoRoute path="/projects/kmc35/peoples-contest-digital-archive" />
+    <MonorepoRoute path="/projects/rachaelsking/corresponding-with-quakers" />

     <Route path="/projects/mschwamb/planet-four/authors" component={() => <ExternalRedirect newUrl='https://authors.planetfour.org/' />} />


Changed scroll behaviors

Changed scroll behaviors

--- app/routes.cjsx
+++ app/routes.cjsx
@@ -2,10 +2,10 @@
 Router = {DefaultRoute, Route, NotFoundRoute} = require 'react-router'

 module.exports =
-  <Route name="root" path="/" handler={require './main'} ignoreScrollBehavior>
-    <DefaultRoute handler={require './pages/home'} />
-    <Route name="classify" path="classify" handler={require './pages/classify'} />
-    <Route name="about-page-controller" path="about" handler={require './pages/about'}>
+  <Route name="root" path="/" handler={require './main'} >
+    <DefaultRoute handler={require './pages/home'} ignoreScrollBehavior/>
+    <Route name="classify" path="classify" handler={require './pages/classify'} ignoreScrollBehavior/>
+    <Route name="about-page-controller" path="about" handler={require './pages/about'} ignoreScrollBehavior>
       <DefaultRoute name="about" handler={require './pages/about/default'} />
       <Route name="team" path="team" handler={require './pages/about/team'} />
       <Route name="organizations" path="organizations" handler={require './pages/about/organizations'} />
@@ -17,5 +17,5 @@
       <DefaultRoute name="field-guide-list" handler={require './partials/field-guide-list'} />
     </Route>

-    <NotFoundRoute handler={require './pages/not-found'} />
+    <NotFoundRoute handler={require './pages/not-found'} ignoreScrollBehavior/>
   </Route>


Reset loaded document on script execution.

--- community/browser/app/scripts/services/Editor.coffee
+++ community/browser/app/scripts/services/Editor.coffee
@@ -49,6 +49,7 @@
           else
             @addToHistory(input) unless (Settings.filemode and @document?.id)
             @maximize(no)
+            @document = null

         execCurrent: ->
           @execScript(@content)


activity: revert changes which broke channel glancing on ESC

--- client/activity/lib/index.coffee
+++ client/activity/lib/index.coffee
@@ -6,6 +6,7 @@
 getGroup                 = require 'app/util/getGroup'
 checkFlag                = require 'app/util/checkFlag'
 isFeedEnabled            = require 'app/util/isFeedEnabled'
+isKoding                 = require 'app/util/isKoding'
 AppStorage               = require 'app/appstorage'
 AppController            = require 'app/appcontroller'
 KodingAppsController     = require 'app/kodingappscontroller'
@@ -149,7 +150,7 @@
     unless e.which is keyboardKeys.ESC
       kd.utils.stopDOMEvent e

-    if isFeedEnabled()
+    if isKoding()
       switch e.model.name
         when 'prevwindow' then @getView().openPrev()
         when 'nextwindow' then @getView().openNext()


Excluded hidden from the size requirement.

--- client/formFieldTemplates.coffee
+++ client/formFieldTemplates.coffee
@@ -21,7 +21,7 @@
       when 'hrule' then 'hrFieldTemplate'
       else 'staticFieldTemplate'

-  if not this.size?
+  if not this.size? and not this.inputType is 'hidden'
       throw new Meteor.Error 'size required', "#{this.inputType} requires a size between 1-12"

   if this.inputType is 'checkbox'


Set location and update totals

Set location and update totals

--- client/skr/models/Invoice.coffee
+++ client/skr/models/Invoice.coffee
@@ -5,7 +5,9 @@
         id:                 {type:"integer", required:true}
         visible_id:         {type:"integer", required:true}
         terms_id:           {type:"integer", required:true}
-        customer_id:        {type:"integer", required:true}
+        customer_id:        {type:"integer", required:true, default: ->
+            Skr.Models.Location.default()?.id
+        }
         location_id:        {type:"integer", required:true}
         sales_order_id:     "integer"
         pick_ticket_id:     "integer"
@@ -27,7 +29,7 @@

     derived:
         total: deps: ['invoice_total'], fn: ->
-            @order_total or @lines.reduce( (t, l) ->
+            @invoice_total or @lines.reduce( (t, l) ->
                 t.plus(l.total)
             , _.bigDecimal(0))

@@ -42,7 +44,9 @@
         shipping_address: { model: "Address" }
         sales_order:      { model: "SalesOrder",  readOnly:true }
         customer:         { model: "Customer",    readOnly:true }
-        location:         { model: "Location",    readOnly:true }
+        location:         { model: "Location",    readOnly:true, default: ->
+            Skr.Models.Location.fetchById(@location_id) if @location_id
+        }
         terms:            { model: "PaymentTerm", readOnly:true }
         pick_ticket:      { model: "PickTicket",  readOnly:true }
         lines:            { collection: "InvLine", inverse: 'invoice'  }
@@ -50,15 +54,17 @@

     constructor: ->
         super
-        @lines.on('change:total', ->
-            @trigger('change', @, {})
-            @unCacheDerived('total')
-            @unset('order_total')
-        , this)
+        @lines.on('change:total', @onChangeTotal, this)
+        @on('change:customer', @onSetCustomer)

-    setCustomer: (cust) ->
-        this.set(customer: cust)
-        @copyAssociationsFrom( @customer, 'billing_address', 'shipping_address')
+    onChangeTotal: ->
+        @trigger('change', @, {})
+        @unCacheDerived('total')
+        @unset('invoice_total')
+
+    onSetCustomer: (newCustomer) ->
+        return if not newCustomer or newCustomer.isNew()
+        @copyAssociationsFrom( newCustomer, 'billing_address', 'shipping_address')

     setFromSalesOrder: (so) ->
         @sales_order_id = so.id


With fetch(add: true), only update existing records with merge: true

The merge option to fetch is introduced in documentcloud/backbone 9ee0358cd, after 0.9.2 was released, and will be included in the next version.

--- backbone.dualstorage.coffee
+++ backbone.dualstorage.coffee
@@ -143,8 +143,9 @@
     when 'clear'
       store.clear()
     when 'create'
-      model = store.create(model)
-      store.dirty(model) if options.dirty
+      unless options.add and not options.merge and store.find(model)
+        model = store.create(model)
+        store.dirty(model) if options.dirty
     when 'update'
       store.update(model)
       if options.dirty then store.dirty(model) else store.clean(model, 'dirty')


Use different index page

Use different index page

--- config/main.dyn-new.coffee
+++ config/main.dyn-new.coffee
@@ -98,7 +98,7 @@
     js          : "js/kd.#{version}.js"
     css         : "css/kd.#{version}.css"
     indexMaster : "index-master.html"
-    index       : "index.html"
+    index       : "default.html"
     useStaticFileServer: no
     staticFilesBaseUrl: 'https://koding.com:4040'
     runtimeOptions:


config: run algolia connector in sandbox

--- config/main.sandbox.coffee
+++ config/main.sandbox.coffee
@@ -297,6 +297,11 @@
       supervisord       :
         command         : "#{GOBIN}/dailyemailnotifier -c #{socialapi.configFilePath}"

+    algoliaconnector    :
+      group             : "socialapi"
+      supervisord       :
+        command         : "#{GOBIN}/algoliaconnector -c #{socialapi.configFilePath}"
+
     notification        :
       group             : "socialapi"
       supervisord       :


janitor: fix sandbox config path

janitor: fix sandbox config path

--- config/main.sandbox.coffee
+++ config/main.sandbox.coffee
@@ -466,7 +466,7 @@
       group             : "environment"
       instances         : 1
       supervisord       :
-        command         : "#{GOBIN}/janitor -kite-init=true"
+        command         : "#{GOBIN}/janitor -c #{socialapi.configFilePath} -kite-init=true"
       healthCheckURL    : "http://localhost:#{socialapi.janitor.port}/healthCheck"
       versionURL        : "http://localhost:#{socialapi.janitor.port}/version"


Make other tests more consistent.

Make other tests more consistent.

--- test/battle_queue.coffee
+++ test/battle_queue.coffee
@@ -32,7 +32,7 @@
       queue.add({})
       queue.add({})
       queue.pairPlayers()
-      queue.queue.should.be.empty
+      queue.queuedPlayers().should.be.empty

     it 'leaves one person out if the queue length is odd', ->
       queue = new BattleQueue()
@@ -40,7 +40,7 @@
       queue.add({})
       queue.add({})
       queue.pairPlayers()
-      queue.queue.should.have.length 1
+      queue.queuedPlayers().should.have.length 1

     it 'returns an array of pairs', ->
       queue = new BattleQueue()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/controllable.coffee
+++ test/controllable.coffee
@@ -30,6 +30,6 @@
 test "should move player down while key is pressed", ->
   ;

-test "should move player back and forth "
+test "should move player back and forth when keys are "

 module()


sudo: fix test after callback migration

sudo: fix test after callback migration

--- test/options/sudo.coffee
+++ test/options/sudo.coffee
@@ -36,7 +36,7 @@
       sudo: false
     .system.execute
       cmd: 'id -u && id -g'
-    , (err, _, stdout) ->
+    , (err, {stdout}) ->
       throw err if err
       [uid, gid] = stdout.split '\n'
     .fs.mkdir


Agent pie: start/end angle pie transition work

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -45,9 +45,6 @@
         #
         # END CONFIG ZONE
         #
-
-        @pie = d3.layout.pie().value((d) -> d.value).sort(null)
-        @arc = d3.svg.arc().innerRadius(@radiusi).outerRadius(@radiuso)

         @update(data.data)

@@ -98,8 +95,8 @@
         if !dataSet
             return

-        #pie = d3.layout.pie().value((d) -> d.value).sort(null)
-        #arc = d3.svg.arc().innerRadius(radiusi).outerRadius(radiuso)
+        pie = d3.layout.pie().value((d) -> d.value).sort(null)
+        arc = d3.svg.arc().innerRadius(radiusi).outerRadius(radiuso)
         svg = d3.select(@node).append('svg').attr('width', width).attr('height', height).append('g').attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')')
         #console.log 'update pie', dataSet


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -106,4 +106,3 @@
           if data[i].value != 0
             data[i].value + ' (' + Math.round(data[i].value/sum * 100) + '%)'
         )
-        .attr("filter","url(#dropshadow)")


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -239,7 +239,7 @@
             .attr("fill", (d, i) ->
                 return color(i)
             )
-
+        console.log("pre-transition")
         path.transition()
             .duration(1500)
             #.attrTween("d", pieTween);
@@ -249,6 +249,7 @@
                     b = i(t);
                     return arc(b)
             )
+        console.log("post-transition")

         #this.path.exit()
         #    .transition()


Remove no longer used test class

Remove no longer used test class

--- test/turbase-spec.coffee
+++ test/turbase-spec.coffee
@@ -1,177 +0,0 @@
-assert = require 'assert'
-turbase = require './../coffee/turbase'
-
-describe '#getTypes()', ->
-  it 'should get all avaiable data types', (done) ->
-    turbase.getTypes {},
-      jsonp: (data) ->
-        assert data.types instanceof Array, 'types should be an Array'
-        assert.equal typeof data.count, 'number', 'count should be a number'
-        assert.equal data.count, data.types.length, 'count should equal data.types.length'
-        assert 'aktiviteter' in data.types, 'types should contain aktiviteter'
-        assert 'bilder' in data.types, 'types should contain bilder'
-        assert 'områder' in data.types, 'types should contain områder'
-        assert 'steder' in data.types, 'types should contain steder'
-        assert 'turer' in data.types, 'types should contain turer'
-        done()
-
-describe '#get()', ->
-  before (done) ->
-    this.timeout 2000
-    setTimeout ->
-      done()
-    ,1500
-
-  it 'should get existing document without errors', (done) ->
-    req =
-      eier: 'dnt'
-      params:
-        object: 'turer'
-        id: '51c7fccf57a4f9770f528841'
-
-    turbase.get req,
-      jsonp: (data) ->
-        throw data if data instanceof Error
-
-        assert.equal typeof data, 'object', 'data should be an object'
-        assert.equal data._id, '51c7fccf57a4f9770f528841', 'data._id should equal the request id'
-        assert.equal typeof data.privat, 'object', 'private object property should show up'
-
-        done()
-
-  it.skip 'should get an error for nonexisting documents', (done) ->
-    req =
-      eier: 'dnt'
-      params:
-        object: 'turer'
-        id: 1
-
-    turbase.get req,
-      jsonp: (data) ->
-        console.log data
-        done()
-
-  it 'should hide private object properties', (done) ->
-    req =
-      eier: 'nrk'
-      params:
-        object: 'turer'
-        id: '51c7fccf57a4f9770f528841'
-
-    turbase.get req,
-      jsonp: (data) ->
-        throw data if data instanceof Error
-
-        assert.equal typeof data, 'object', 'data should be an object'
-        assert.equal data._id, '51c7fccf57a4f9770f528841', 'data._id should equal the request id'
-        assert.equal typeof data.privat, 'undefined', 'private object property should be undefined'
-
-        done()
-
-describe '#list()', ->
-  last = null
-
-  before (done) ->
-    this.timeout 2000
-    setTimeout ->
-      done()
-    ,1500
-
-  it 'should list documents in given collection', (done) ->
-    req =
-      eier: 'dnt'
-      params:
-        object: 'turer'
-
-    turbase.list req,
-      jsonp: (data) ->
-        throw data if data instanceof Error
-
-        assert.equal typeof data, 'object', 'data should be an object'
-        assert data.documents instanceof Array, 'data.documents should be an array'
-        assert.equal typeof data.count, 'number', 'data.count should be a number'
-        assert.equal data.count, 10, 'number of documents should default to 10'
-        assert.equal data.documents.length, data.count, 'data.documents.length should equal data.count'
-
-        done()
-
-  it 'should limit the number of items based on limit query param', (done) ->
-    req =
-      eier: 'dnt'
-      query:
-        limit: 5
-      params:
-        object: 'turer'
-
-    turbase.list req,
-      jsonp: (data) ->
-        throw data if data instanceof Error
-
-        last = data.documents[4]
-
-        assert.equal data.documents.length, 5, 'number of items returned should equal 5'
-        assert.equal data.count, 5, 'count should limit (5)'
-
-        done()
-
-  it 'should skip n items based on offset query param', (done) ->
-    req =
-      eier: 'dnt'
-      query:
-        limit: 1
-        offset: 4
-      params:
-        object: 'turer'
-
-    turbase.list req,
-      jsonp: (data) ->
-        throw data if data instanceof Error
-
-        assert.equal typeof data.documents[0], 'object', 'First element in array should be an object'
-        assert.deepEqual data.documents[0], last, 'First and last last object should be the same'
-
-        done()
-
-  it 'should show items editited after a certain date', (done) ->
-    req =
-      eier: 'dnt'
-      query:
-        after: '2013-01-01'
-      params:
-        object: 'turer'
-
-    turbase.list req,
-      jsonp: (data) ->
-        throw data if data instanceof Error
-
-        for document in data.documents
-          assert document.endret > '2013-01-01', 'document should be edited after 2013-01-01'
-
-        done()
-
-  it 'should only list some object keys', (done) ->
-    req =
-      eier: 'dnt'
-      params:
-        object: 'turer'
-
-    turbase.list req,
-      jsonp: (data) ->
-        throw data if data instanceof Error
-
-        assert.equal Object.keys(data.documents[0]).length, 4
-
-        done()
-
-describe.skip '#insert()', ->
-  it 'should insert all the things'
-
-describe.skip '#update()', ->
-  it 'should update all the things'
-
-describe.skip '#updates()', ->
-  it 'should updates all the things'
-
-describe.skip '#delete()', ->
-  it 'should delete all the things'
-


simplify `wamp_get_uri`

simplify `wamp_get_uri`

--- backbone.wamp.coffee
+++ backbone.wamp.coffee
@@ -13,14 +13,7 @@
     attach_handlers = ->
         connection = @wamp_connection or global.WAMP_CONNECTION

-        get_uri =
-            if (
-                _.has(@, "wamp_get_uri")  or
-                _.has(@constructor::, "wamp_get_uri")
-            )
-                @wamp_get_uri
-            else
-                global.WAMP_GET_URI or @wamp_get_uri
+        get_uri = @wamp_get_uri or global.WAMP_GET_URI or wamp_get_uri

         _.each actions, (action)=>
             connection.session.register(
@@ -42,15 +35,12 @@
         _.extend options,
             wamp            : true
             wamp_connection : entity.wamp_connection
-            wamp_get_uri    :
-                if (
-                    _.has(entity, "wamp_get_uri")  or
-                    _.has(entity.constructor::, "wamp_get_uri")
-                )
-                    _.bind entity.wamp_get_uri, entity
-                else
-                    global.WAMP_GET_URI or
-                     _.bind entity.wamp_get_uri, entity
+            wamp_get_uri    : _.bind if 1
+                entity.wamp_get_uri or
+                global.WAMP_GET_URI or
+                wamp_get_uri
+            ,
+                entity
             wamp_my_id      : entity.collection?.wamp_my_id or
                 entity.wamp_my_id or global.WAMP_MY_ID
             wamp_other_id   : entity.collection?.wamp_other_id or
@@ -151,8 +141,6 @@
                     global `WAMP_MY_ID` or `wamp_my_id` property/method
                 "

-        wamp_get_uri : wamp_get_uri
-

     class WAMP_Collection extends Backbone.Collection
@@ -182,8 +170,6 @@
                     global `WAMP_MY_ID` or `wamp_my_id` property/method
                 "

-        wamp_get_uri : wamp_get_uri
-

     [WAMP_Model, WAMP_Collection]


vm schema: add fields for hostKite (wasn't in the schema!) and region (new)

--- workers/social/lib/social/models/vm.coffee
+++ workers/social/lib/social/models/vm.coffee
@@ -42,6 +42,16 @@
         type            : String
         default         : -> null
       hostnameAlias     : String
+      hostKite          :
+        type            : String
+        default         : -> null
+      region            :
+        type            : String
+        enum            : ['unknown region'
+                          [
+                            'aws' # Amazon Web Services
+                            'sj'  # San Jose
+                          ]]
       webHome           : String
       planOwner         : String
       planCode          : String


update epi descriptive evidence export

update epi descriptive evidence export

--- server/methods/word.coffee
+++ server/methods/word.coffee
@@ -37,6 +37,7 @@
     desc.reference = Reference.findOne(_id: desc.referenceID)
     desc.coexposuresList = desc.coexposures.join(', ')
     desc.isCaseControl = desc.studyDesign in CaseControlTypes
+    desc.notes = desc.comments or ""

 prepareEpiResult = (res) ->
     res.covariatesList = share.capitalizeFirst(res.covariates.join(', '))


Added test to ignore mocha error

Added test to ignore mocha error

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -16,7 +16,8 @@

 # See http://stackoverflow.com/questions/21602332/catching-gulp-mocha-errors
 handleError = (err) ->
-  console.warn err
+  if err.plugin isnt 'gulp-mocha'
+    console.warn err
   this.emit 'end'

@@ -33,8 +34,6 @@
   coff = plugins.coffee { bare: true }
     .on 'error', plugins.util.log

-  console.info config.dest.js
-
   gulp.src config.src.coffee
     .pipe plugins.coffee { bare: true }
     .on 'error', plugins.util.log
@@ -49,9 +48,7 @@

 gulp.task 'mocha', ['coffee'], ->
   gulp.src config.test.coffee, { read: false }
-    .pipe plugins.mocha {
-      reporter: 'spec'
-    }
+    .pipe plugins.mocha { reporter: 'spec' }
     .on 'error', handleError


fix gulpfile.coffee for gh-pages

fix gulpfile.coffee for gh-pages

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -32,7 +32,7 @@

 isRelease = gutil.env.release?
-outputdir = gutil.env.outputdir || 'app'
+

 # sources
 SOURCES  = ['src/*.ls']
@@ -40,6 +40,11 @@
 HTMLS    = ['html/*.html']
 IMAGES   = ['img/*.jpg', 'img/*.png', 'img/*.gif']

+# outdir
+out = (dir) ->
+    ret = gutil.env.outputdir || 'app'
+    return ret unless dir
+    path.join ret, dir

 # compile
@@ -48,7 +53,7 @@
     .pipe filter('!**/main.ls')
     .pipe lsc({bare:true}) .on 'error', gutil.log
     .pipe cond isRelease, uglify()
-    .pipe gulp.dest (path.join outputdir, 'lib')
+    .pipe gulp.dest (out 'lib')

 gulp.task 'browserify', ['script'], ->
   gulp.src SOURCES
@@ -56,14 +61,14 @@
     .pipe lsc({bare:true}) .on 'error', gutil.log
     .pipe browserify()
     .pipe cond isRelease, uglify()
-    .pipe gulp.dest (path.join outputdir, 'lib')
+    .pipe gulp.dest (out 'lib')
     .pipe (livereload server)

 gulp.task 'stylus', ->
   gulp.src STYLUSES
     .pipe (stylus {bare: true}) .on 'error', gutil.log
     .pipe cond isRelease, minifyCss()
-    .pipe (gulp.dest (path.join outputdir, 'css'))
+    .pipe (gulp.dest (out 'css'))
     .pipe (livereload server)

 gulp.task 'html', ->
@@ -71,28 +76,28 @@
   gulp.src HTMLS
     .pipe cond isRelease, minifyHTML {empty:true, cdata: true}
     .pipe cond (not isRelease), header reload_script, {}
-    .pipe (gulp.dest outputdir)
+    .pipe (gulp.dest out())
     .pipe (livereload server)

 gulp.task 'image', ->
     gulp.src IMAGES
         .pipe minImage({progressive:true})
-        .pipe gulp.dest (path.join outputdir, 'img')
+        .pipe gulp.dest (out 'img')

 gulp.task 'bower', ->
 #  bower()
 #    .pipe cond isRelease, uglify({preserveComments:'some'})
 #    .pipe flatten()
-#    .pipe (gulp.dest (path.join outputdir, 'lib'))
+#    .pipe (gulp.dest (out 'lib'))
 #    .pipe (livereload server)

 gulp.task 'copy', ->
   gulp.src 'third_party/**/*.js'
     .pipe cond isRelease, uglify({preserveComments:'some'})
-    .pipe (gulp.dest 'app/lib')
+    .pipe (gulp.dest (out 'lib'))
     .pipe (livereload server)
   gulp.src 'data/*.gexf'
-    .pipe (gulp.dest 'app/data')
+    .pipe (gulp.dest (out 'data'))

 gulp.task 'watch', ->
   server.listen 35729, (err) ->
@@ -114,7 +119,7 @@
     .pipe clean()

 gulp.task 'clean:out', ->
-  gulp.src ['app/css', 'app/lib', '*.html']
+  gulp.src [out 'data', out 'css', out 'lib', out '*.html']
     .pipe clean()


Fix path

Fix path

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -4,7 +4,7 @@

 paths =
 	ts: './src/**/*.ts'
-	webRes: './src/web/resources/**/**'
+	webRes: './src/web/statics/resources/**/**'
 	webViews: './src/web/views/**/*.jade'

 gulp.task 'clean', del.bind(null, ['./bin/**'])


Add version task for watcher

Add version task for watcher

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -75,7 +75,7 @@
 gulp.task "watch", ["test"], ->
 	gulp.watch(["./*.coffee", "framer/**", "test/tests/**", "!Version.coffee"], ["test"])

-gulp.task "watcher", ->
+gulp.task "watcher", ["version"], ->

 	config = _.extend CONFIG,
 		entry: "./framer/Framer.coffee"


fix(syntaxHighlighter): fix sourceMap path

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -200,7 +200,7 @@
 gulp.task 'less', ['copy:temp'], ->
 	options =
 		sourceMap: true
-		sourceMapBasepath: TEMP_DIRECTORY
+		sourceMapBasepath: path.resolve TEMP_DIRECTORY

 	gulp
 		.src '**/*.less', cwd: TEMP_DIRECTORY


clean gulpfile

clean gulpfile

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -34,6 +34,7 @@
 paths =
   bower: 'src/main/vendors/bower_components', web: 'src/main/web', build: 'build'
 reload = browserSync.reload
+

 # preprocessing tasks


Add gulp build task

Add gulp build task

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -30,5 +30,8 @@
   gulp.watch 'src/**/*.coffee*', ->
     gulp.run 'compile'

+gulp.task 'build', ->
+  gulp.run 'libs', 'compile'
+
 gulp.task 'default', ->
   gulp.run   'webserver', 'compile', 'watch'


payment: fix a race condition

payment: fix a race condition

--- client/landing/app/Applications/Dashboard.kdapplication/views/planaddproductsmodal.coffee
+++ client/landing/app/Applications/Dashboard.kdapplication/views/planaddproductsmodal.coffee
@@ -69,9 +69,11 @@

     plan.quantities = quantities

-    plan.modify { quantities }, callback
+    plan.modify { quantities }, (err) =>
+      return callback err  if err
+      callback null

-    @emit 'ProductsAdded'
+      @emit 'ProductsAdded'

   setProducts: (products) ->
     @loader.hide()


Removed poparrowview

Removed poparrowview

--- core/app/backbone/factlink/poparrow_view.coffee
+++ core/app/backbone/factlink/poparrow_view.coffee
@@ -1,48 +0,0 @@
-class Backbone.Factlink.PoparrowView extends Backbone.Marionette.ItemView
-
-  arrowSelector: '.js-poparrow-arrow-selector'
-
-  constructor: (options) ->
-    @ui = _.extend {}, @ui,
-      arrow: @arrowSelector
-      container: '.js-poparrow-container'
-
-    @events = _.extend {}, @events,
-      'click .js-poparrow-arrow-selector': 'togglePoparrowContainer'
-      'click .js-poparrow-container': 'stopPropagation'
-
-    super(options)
-
-    @on "render", @poparrowOnRender, this
-    @on "close", @poparrowOnClose, this
-
-  stopPropagation: (e)-> e.stopPropagation()
-
-  poparrowOnRender: ->
-    if @ui.container.children("li").length <= 0
-      @ui.arrow.hide()
-
-  togglePoparrowContainer: ->
-    if @ui.container.is(":hidden")
-      @showPoparrowContainer()
-    else
-      @hidePoparrowContainer()
-
-  showPoparrowContainer: ->
-    @ui.container.show()
-    @ui.arrow.addClass "active"
-    @bindWindowClick()
-
-  hidePoparrowContainer: ->
-    @ui.container.hide()
-    @ui.arrow.removeClass "active"
-    @unbindWindowClick()
-
-  bindWindowClick: ->
-    $(window).on "click.poparrow." + @cid, (e) =>
-      if $(e.target).closest(@arrowSelector)[0] isnt @ui.arrow[0]
-        @hidePoparrowContainer()
-
-  unbindWindowClick: -> $(window).off "click.poparrow." + @cid
-
-  poparrowOnClose: -> @unbindWindowClick()


Adjust data types in applicants publication(cvs format is crucial)

--- server/publications/applicants.coffee
+++ server/publications/applicants.coffee
@@ -12,13 +12,9 @@
   if !applicant
     applicant =
       _id: "we are done"
-  #console.log 'applicant published', applicant
-  #Set the applicant as blocked until x+10m
   timestamp = +new Date() + 60*1000 #in ms
   Applicants.update { _id: applicant._id }, $set: 'blockedUntil': timestamp
-  #build cursor
   @added('applicants', applicant._id, applicant)
-  #return
   @ready()

 Meteor.publish 'AllFlaggedApplicants', ->
@@ -26,4 +22,4 @@

 Meteor.publish 'OneSpecificApplicant', (_id) ->
   check _id, String
-  Applicants.find(_id)
+  Applicants.find(parseInt(_id))


Preserve order when pressing '+ Post'

Preserve order when pressing '+ Post'

--- scanblog/static/js/moderation/scans.coffee
+++ scanblog/static/js/moderation/scans.coffee
@@ -240,11 +240,19 @@
         @typeCount[type] = (@typeCount[type] or 0) + 1
         title = type
         if @typeCount[type] > 1
-            title = "#{title} #{@typeCount[type]} (#{@choices.length + 1})"
+            console.log @choices, @typeCount
+            for i in [@choices.length-1..0]
+                console.log i, @choices[i]
+                choice = @choices[i]
+                if choice.get("type") == type
+                    pos = i + 1
+                    @choices.splice(pos, 0, doc)
+                    break
+            title = "#{title} #{@typeCount[type]} (#{pos + 1})"
         else
             title = title.replace(new RegExp("(#{@typeAccelerators[type]})"), "$1")
+            @choices.push doc
         doc.set choiceTitle: title
-        @choices.push doc

     userAddChoice: (type) =>
         doc = new btb.Document type: type


NEW - alternate keywords for size: "childrenWithParentHeight" etc...

--- source/Art/Engine/Core/Element.coffee
+++ source/Art/Engine/Core/Element.coffee
@@ -204,8 +204,14 @@
     parentWidthSquare:                        hw:1, ww:1
     parentFitSquare:                          hh:1, wh:1, max: hw:1, ww: 1
     childrenSizeMaxParentWidth:               cs:1, max: ww: 1
+    childrenSizeMaxParentHeight:              cs:1, max: hh: 1
+
     parentHeightChildrenWidth:                hh:1, wcw:1
     parentWidthChildrenHeight:                ww:1, hch:1
+
+    childrenWidthParentHeight:                hh:1, wcw:1
+    childrenHeightParentWidth:                ww:1, hch:1
+
     parentHeightChildrenWidthMaxParentWidth:  wcw:1, hh:1, max: ww:1

   namedSizeLayouts = object namedSizeLayoutsRaw, (v) -> pointLayout v


attach plugin to $ proto to be more agnostic

--- maskew.coffee
+++ maskew.coffee
@@ -176,7 +176,7 @@

 if window.jQuery? or window.$?.data?

-  $.fn.maskew = (angle, options) ->
+  $::maskew = (angle, options) ->

     return @ unless hasSupport


simplifying names of types

simplifying names of types

--- source/javascripts/src/model_xlform.coffee
+++ source/javascripts/src/model_xlform.coffee
@@ -120,7 +120,7 @@

 XLF.lookupRowType = do->
   typeLabels = [
-    ["note", "Note (no response)", preventRequired: true],
+    ["note", "Note", preventRequired: true],
     ["text", "Text"], # expects text
     ["integer", "Integer"], #e.g. 42
     ["decimal", "Decimal"], #e.g. 3.14
@@ -132,8 +132,8 @@
     ["audio", "Audio", isMedia: true], # Can use phone microphone to record audio
     ["video", "Video", isMedia: true], # Can use phone camera to record video
     # ["calculate", "Calculate"],
-    ["select_one", "Select one", orOtherOption: true, specifyChoice: true],
-    ["select_multiple", "Select multiple", orOtherOption: true, specifyChoice: true]
+    ["select_one", "Select", orOtherOption: true, specifyChoice: true],
+    ["select_multiple", "Multiple choice", orOtherOption: true, specifyChoice: true]
   ]

   class Type


Process main docblock separately from trigger block to work around bug

--- build/api-gen.coffee
+++ build/api-gen.coffee
@@ -126,7 +126,7 @@
     # Method for returning the documentation for this block
     getContent: ()->
         if @isFunctionTag(@prevTag) then @code.push("</dl>")
-        return @code.join("\n") + triggerBlock(@triggers) + seeBlock(@see)
+        return marked(@code.join("\n")) + triggerBlock(@triggers) + seeBlock(@see)

 # parse js file
 parseJS = (path) ->


Fix scope

Fix scope

--- client/app/MainApp/kodingappscontroller.coffee
+++ client/app/MainApp/kodingappscontroller.coffee
@@ -134,7 +134,7 @@
           for callback in @_fetchQueue
             callback null, @getManifests()
           @_fetchQueue = []
-    , ->
+    , =>
       warn msg = "Timeout reached for kite request"
       KD.logToExternal msg  unless KD.isGuest()
       callback() for callback in @_fetchQueue


Force to show warning when Apps crashes

Force to show warning when Apps crashes

--- client/app/MainApp/kodingappscontroller.coffee
+++ client/app/MainApp/kodingappscontroller.coffee
@@ -288,7 +288,7 @@
               eval appScript
           catch e
             # if not manifest.ignoreWarnings? # GG FIXME
-            warn "App caused some problems:", e
+            console.warn "App caused some problems:", e
           callback?()
           return appView
         else
@@ -297,7 +297,7 @@
             do ->
               eval appScript
           catch e
-            warn "App caused some problems:", e
+            console.warn "App caused some problems:", e
           callback?()
           return null


shortcuts/view: rm obsolete ShortcutsListHead

--- client/app/lib/shortcuts/views/listhead.coffee
+++ client/app/lib/shortcuts/views/listhead.coffee
@@ -1,24 +0,0 @@
-kd = require 'kd'
-
-module.exports =
-
-class ShortcutsListHead extends kd.View
-
-  constructor: (options={}, data) ->
-
-    options.cssClass = 'list-head'
-
-    super options, data
-
-  viewAppended: ->
-
-    @setPartial """
-
#{@getOptions().description}

-

-

-
Description

-
Binding

-
Enabled

-

-

-    """


video: save videoEnabled state in channel payload

--- client/app/lib/videocollaboration/model.coffee
+++ client/app/lib/videocollaboration/model.coffee
@@ -302,15 +302,16 @@

   ###*
-   * Action for starting VideoCollaboration session. It calls
-   * `startPublishing` method and connects handlers for success and error states.
+   * Action for starting VideoCollaboration session.
    *
    * @param {object} options
   ###
   start: (options) ->

-    @_service.sendSessionStartSignal @channel, (err) ->
+    helper.enableVideo @channel, (err) =>
       return console.error err  if err
+      @_service.sendSessionStartSignal @channel, (err) ->
+        return console.error err  if err

   ###*
@@ -319,8 +320,10 @@
   ###
   end: ->

-    @_service.sendSessionEndSignal @channel, (err) ->
+    helper.disableVideo @channel, (err) =>
       return console.error err  if err
+      @_service.sendSessionEndSignal @channel, (err) ->
+        return console.error err  if err

   ###*


Handle elements removed from dom beter

Handle elements removed from dom beter

--- lib/assets/javascripts/turbolinks.js.coffee
+++ lib/assets/javascripts/turbolinks.js.coffee
@@ -172,7 +172,7 @@

 extractLink = (event) ->
   link = event.target
-  link = link.parentNode until link is document or !link or link.nodeName is 'A'
+  link = link.parentNode until !link.parentNode or link.nodeName is 'A'
   link

 crossOriginLink = (link) ->


Minor update.

Minor update.

--- cms/static/coffee/src/views/module_edit.coffee
+++ cms/static/coffee/src/views/module_edit.coffee
@@ -122,4 +122,5 @@
     # Can it be enough to just remove active-mode?
     editorModeButtonParent.addClass('inactive-mode')
     editorModeButtonParent.removeClass('active-mode')
-    @$el.find('.wrapper-comp-settings').addClass('is-active')+    @$el.find('.wrapper-comp-settings').addClass('is-active')
+    @$el.find('#settings-mode').find("a").addClass('is-set')


:fire: CoffeeScript version of the plugin generator vie

--- lib/minimap-plugin-generator-element.coffee
+++ lib/minimap-plugin-generator-element.coffee
@@ -1,137 +0,0 @@
-_ = require 'underscore-plus'
-fs = require 'fs-plus'
-path = require 'path'
-{BufferedProcess} = require 'atom'
-{CompositeDisposable} = require 'atom'
-{registerOrUpdateElement} = require 'atom-utils'
-
-# Internal: The {MinimapPluginGeneratorElement} is used whenever the user
-# triggers the `minimap:generate-plugin` command.
-module.exports =
-class MinimapPluginGeneratorElement
-  previouslyFocusedElement: null
-  mode: null
-
-  createdCallback: ->
-    @classList.add('minimap-plugin-generator')
-    @classList.add('overlay')
-    @classList.add('from-top')
-
-    @editor = atom.workspace.buildTextEditor(mini: true)
-    @editorElement = atom.views.getView(@editor)
-
-    @error = document.createElement('div')
-    @error.classList.add('error')
-
-    @message = document.createElement('div')
-    @message.classList.add('message')
-
-    @appendChild(@editorElement)
-    @appendChild(@error)
-    @appendChild(@message)
-
-  attachedCallback: ->
-    @previouslyFocusedElement = document.activeElement
-    @message.textContent = "Enter plugin path"
-    @setPathText("my-minimap-plugin")
-    @editorElement.focus()
-
-  attach: ->
-    atom.views.getView(atom.workspace).appendChild(this)
-
-  setPathText: (placeholderName, rangeToSelect) ->
-    rangeToSelect ?= [0, placeholderName.length]
-    packagesDirectory = @getPackagesDirectory()
-    @editor.setText(path.join(packagesDirectory, placeholderName))
-    pathLength = @editor.getText().length
-    endOfDirectoryIndex = pathLength - placeholderName.length
-    @editor.setSelectedBufferRange([[0, endOfDirectoryIndex + rangeToSelect[0]], [0, endOfDirectoryIndex + rangeToSelect[1]]])
-
-  detach: ->
-    return unless @parentNode?
-    @previouslyFocusedElement?.focus()
-    @parentNode.removeChild(this)
-
-  confirm: ->
-    if @validPackagePath()
-      @removeChild(@editorElement)
-      @message.innerHTML = """
-
-        Generate plugin at #{@getPackagePath()}
-      """
-      @createPackageFiles =>
-        packagePath = @getPackagePath()
-        atom.open(pathsToOpen: [packagePath], devMode: atom.config.get('minimap.createPluginInDevMode'))
-
-        @message.innerHTML = """
-          Plugin successfully generated, opening it now...
-        """
-
-        setTimeout =>
-          @detach()
-        , 2000
-
-  getPackagePath: ->
-    packagePath = @editor.getText()
-    packageName = _.dasherize(path.basename(packagePath))
-    path.join(path.dirname(packagePath), packageName)
-
-  getPackagesDirectory: ->
-    atom.config.get('core.projectHome') or
-      process.env.ATOM_REPOS_HOME or
-      path.join(fs.getHomeDirectory(), 'github')
-
-  validPackagePath: ->
-    if fs.existsSync(@getPackagePath())
-      @error.textContent = "Path already exists at '#{@getPackagePath()}'"
-      @error.style.display = 'block'
-      false
-    else
-      true
-
-  initPackage: (packagePath, callback) ->
-    templatePath = path.resolve __dirname, path.join('..','templates',"plugin-#{@template}")
-    @runCommand(atom.packages.getApmPath(), ['init', "-p", "#{packagePath}", "--template", templatePath], callback)
-
-  linkPackage: (packagePath, callback) ->
-    args = ['link']
-    args.push('--dev') if atom.config.get('minimap.createPluginInDevMode')
-    args.push packagePath.toString()
-
-    @runCommand(atom.packages.getApmPath(), args, callback)
-
-  installPackage: (packagePath, callback) ->
-    args = ['install']
-
-    @runCommand(atom.packages.getApmPath(), args, callback, cwd: packagePath)
-
-  isStoredInDotAtom: (packagePath) ->
-    packagesPath = path.join(atom.getConfigDirPath(), 'packages', path.sep)
-    return true if packagePath.indexOf(packagesPath) is 0
-
-    devPackagesPath = path.join(atom.getConfigDirPath(), 'dev', 'packages', path.sep)
-    packagePath.indexOf(devPackagesPath) is 0
-
-  createPackageFiles: (callback) ->
-    packagePath = @getPackagePath()
-    packagesDirectory = @getPackagesDirectory()
-
-    if @isStoredInDotAtom(packagePath)
-      @initPackage packagePath, =>
-        @installPackage packagePath, callback
-    else
-      @initPackage packagePath, =>
-        @linkPackage packagePath, =>
-          @installPackage packagePath, callback
-
-  runCommand: (command, args, exit, options={}) ->
-    new BufferedProcess({command, args, exit, options})
-
-
-module.exports =
-MinimapPluginGeneratorElement = registerOrUpdateElement 'minimap-plugin-generator', MinimapPluginGeneratorElement.prototype
-
-atom.commands.add 'minimap-plugin-generator', {
-  'core:confirm': -> @confirm()
-  'core:cancel': -> @detach()
-}


Changed Release Generator to only add appropriate files

--- src/bin/generate_release.coffee
+++ src/bin/generate_release.coffee
@@ -111,7 +111,7 @@

         opts.env.GIT_MERGE_AUTOEDIT = 'no'

-        Exec 'git add -A', opts
+        Exec 'git add README.md package.json', opts
         Exec 'git commit -am "Release ' + new_version + '"', opts
         Exec 'git flow release finish -m "' + new_version + '" ' + new_version, opts
         Exec 'git push origin develop', opts


Model: Also remove `changed` attributes hash on disposal

--- src/chaplin/models/model.coffee
+++ src/chaplin/models/model.coffee
@@ -86,7 +86,8 @@
       # and event handlers
       properties = [
         'collection',
-        'attributes', '_escapedAttributes', '_previousAttributes',
+        'attributes', 'changed'
+        '_escapedAttributes', '_previousAttributes',
         '_silent', '_pending',
         '_callbacks'
       ]


patched support for components back together

--- src/client/client_engine.coffee
+++ src/client/client_engine.coffee
@@ -140,7 +140,7 @@

         if components?.length > 0
             for component in components
-                @RPCMethods.CreateComponent(component)
+                RPCMethods.CreateComponent(component, this)

     DOMAttrModified : (targetId, name, value, attrChange) ->
         target = @nodes.get(targetId)
@@ -186,15 +186,15 @@
         component[method].apply(component, args)

     # args is an array: [name, targetID, options]
-    CreateComponent : (args) ->
+    CreateComponent : (args, clientEngine) ->
         [name, targetID, options] = args
         console.log("CreateComponent")
         console.log(arguments)
-        node = @nodes.get(targetID)
+        node = clientEngine.nodes.get(targetID)
         Constructor = Components[name]
         if !Constructor
             throw new Error("Invalid component: #{name}")
-        @components[targetID] = new Constructor(@socket, node, options)
+        clientEngine.components[targetID] = new Constructor(clientEngine.socket, node, options)

     close : () ->
         document.write("


Don't overwrite torrent with redis response.

--- src/controllers/torrents.coffee
+++ src/controllers/torrents.coffee
@@ -143,7 +143,7 @@
             torrent.uploader = req.session.user.name
           if fields.useexternaltracker
             torrent.external_tracker = torrentInfo.announce
-          redis.SET 'torrent:'+infohash+':desc', md.toHTML(fields.description), (err, data) ->
+          redis.SET 'torrent:'+infohash+':desc', md.toHTML(fields.description), (err, resdata) ->
             torrent.generatePermalink (err) ->
               torrent.save (err) ->
                 fs.writeFile (__dirname+'/../../torrents/' + infohash + '.torrent'), data, (err) ->


Remove numShapes(); fix some event args; document stuff

--- src/core/LiterallyCanvas.coffee
+++ src/core/LiterallyCanvas.coffee
@@ -66,6 +66,9 @@
   removeEventListener: (name, wrapper) ->
     @canvas.removeEventListener(name, wrapper)

+  # actual ratio of drawing-space pixels to perceived pixels, accounting for
+  # both zoom and displayPixelWidth. use this when converting between
+  # drawing-space and screen-space.
   getRenderScale: -> @scale * @backingScale

   clientCoordsToDrawingCoords: (x, y) ->
@@ -104,7 +107,6 @@

   setColor: (name, color) ->
     @colors[name] = color
-    @trigger "#{name}ColorChange", @colors[name]
     switch name
       when 'background'
         @containerEl.style.backgroundColor = @colors.background
@@ -113,6 +115,7 @@
         @repaintLayer('main')
       when 'secondary'
         @repaintLayer('main')
+    @trigger "#{name}ColorChange", @colors[name]
     @trigger "drawingChange" if name == 'background'

   getColor: (name) -> @colors[name]
@@ -120,9 +123,7 @@
   saveShape: (shape) ->
     @execute(new actions.AddShapeAction(this, shape))
     @trigger('shapeSave', {shape: shape})
-    @trigger('drawingChange', {shape: shape})
-
-  numShapes: -> @shapes.length
+    @trigger('drawingChange')

   pan: (x, y) ->
     # Subtract because we are moving the viewport


setPan, setZoom

setPan, setZoom

--- src/core/LiterallyCanvas.coffee
+++ src/core/LiterallyCanvas.coffee
@@ -126,16 +126,22 @@

   pan: (x, y) ->
     # Subtract because we are moving the viewport
-    @position.x = @position.x - x
-    @position.y = @position.y - y
+    @setPan(@position.x - x, @position.y - y)
+
+  setPan: (x, y) ->
+    @position = {x, y}
     @trigger('pan', {x: @position.x, y: @position.y})

   zoom: (factor) ->
+    newScale = @scale + factor
+    newScale = Math.max(newScale, 0.6)
+    newScale = Math.min(newScale, 4.0)
+    newScale = Math.round(newScale * 100) / 100
+    @setZoom(newScale)
+
+  setZoom: (scale) ->
     oldScale = @scale
-    @scale = @scale + factor
-    @scale = Math.max(@scale, 0.6)
-    @scale = Math.min(@scale, 4.0)
-    @scale = Math.round(@scale * 100) / 100
+    @scale = scale

     @position.x = math.scalePositionScalar(
       @position.x, @canvas.width, oldScale, @scale)


sidebar: apply code style

sidebar: apply code style

--- client/Main/navigation/navigationitem.coffee
+++ client/Main/navigation/navigationitem.coffee
@@ -19,6 +19,7 @@

   createMachineItem: (data) ->
+
     @type  = 'machine'
     @setClass 'machine'
     @child = new NavigationMachineItem {}, data
@@ -58,6 +59,7 @@

   createNewWorkspaceView: ->
+
     @setClass 'workspace'
     { machineUId, machineLabel } = @getData()

@@ -65,6 +67,7 @@

   createAppItem: ->
+
     @setClass 'app'
     @child    = new KDCustomHTMLView
       partial : """
@@ -77,3 +80,4 @@
     """
       {{> @child}}
     """
+


payment: implement group context awareness to `PaymentController#_runWrapper` method

--- client/Main/payment/paymentcontroller.coffee
+++ client/Main/payment/paymentcontroller.coffee
@@ -261,10 +261,9 @@

   _runWrapper: (options, callback) ->
     {fn, subscriptionTag, packTag} = options
-    @fetchSubscriptionsWithPlans tags: [subscriptionTag], (err, subscriptions) =>
-      return  if KD.showError err
-      [subscription] = subscriptions
-
+
+    kallback (err, subscription) =>
+      return callback err  if err
       if subscription
         KD.remote.api.JPaymentPack.one tags: packTag, (err, pack) =>
           return callback err  if err
@@ -273,3 +272,12 @@
             callback null, nonce
       else
         callback()
+
+    group = KD.getGroup()
+    if group.slug is "koding"
+      @fetchSubscriptionsWithPlans tags: [subscriptionTag], (err, subscriptions) =>
+        return  if KD.showError err
+        [subscription] = subscriptions
+        kallback subscription
+    else
+      @fetchGroupSubscription kallback


EditorPane: Added setContent and setCursor methods.

--- client/ide/workspace/panes/editorpane.coffee
+++ client/ide/workspace/panes/editorpane.coffee
@@ -60,8 +60,14 @@
   getContent: ->
     return @getAce().getContents()

+  setContent: (content) ->
+    @getAce().editor.setValue content, -1
+
   getCursor: ->
     return @getEditor().selection.getCursor()
+
+  setCursor: (positions) ->
+    @getEditor().selection.moveCursorTo positions.row, positions.column

   getFile: ->
     return @aceView.getData()


更新手指滑動方向

更新手指滑動方向

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -48,9 +48,9 @@
       console.log direction
       switch direction
         when 'left'
+          $('.next a')[0].click()
+        when 'right'
           $('.previous a')[0].click()
-        when 'right'
-          $('.next a')[0].click()
       return
     threshold: 0


improved turbolinks.visit conditional

improved turbolinks.visit conditional

--- app/assets/javascripts/gl_dropdown.js.coffee
+++ app/assets/javascripts/gl_dropdown.js.coffee
@@ -566,7 +566,7 @@
       e.stopImmediatePropagation()
       $el.first().trigger 'click'
       href = $el.attr 'href'
-      Turbolinks.visit(href) if href
+      Turbolinks.visit(href) if href and href isnt '#'

   addArrowKeyEvent: ->
     ARROW_KEY_CODES = [38, 40]


Animates map automatically

Animates map automatically

Sexy sexy map scroll

--- app/assets/javascripts/modules/map.js.coffee
+++ app/assets/javascripts/modules/map.js.coffee
@@ -10,12 +10,13 @@
     @map = L.mapbox.map(
       $mapContainer.attr('id'),
       'unepwcmc.ijh17499',
-      {minZoom: 2, zoomControl: false, attributionControl: false}
+      {minZoom: 3, zoomControl: false, attributionControl: false}
     )

     @addBaseLayer()
     @addZoomControl()
     @setToBounds()
+    @startAnimation()

     return new map_class(@map, @config)

@@ -66,6 +67,13 @@
       min = Math.min(Math.abs(x1), Math.abs(x2))
       return max - min

+  startAnimation: ->
+    panMap = => @map.panBy(new L.Point(0.5, 0))
+    interval = setInterval(panMap, 200)
+
+    @map.on('dragstart', -> clearInterval(interval))
+    @map.on('zoomstart', -> clearInterval(interval))
+
   normalizeBounds: (bounds) ->
     # If a protected area overlaps the antimeridian ST_Extent does not
     # return a correct bounding box (Ideas to fix this?)


fixed bug with the pop field not connecting to the dropdown

--- app/assets/javascripts/settlements.js.coffee
+++ app/assets/javascripts/settlements.js.coffee
@@ -23,8 +23,8 @@

     #make the selection box a pretty pretty princess
     $('select').selectbox()
-    @pop.keyup => this.updateDrop
-    @pop.keyup => this.forceInt
+    @pop.keyup => this.updateDrop()
+    @pop.keyup => this.forceInt()
     $('#create-settlement').click -> this.createCallback
     $('.selectbox-wrapper').on 'click', =>
       this.sizeSettlement()


Improve log report for multiple errors

Improve log report for multiple errors

--- bootstrap/log.coffee
+++ bootstrap/log.coffee
@@ -39,12 +39,13 @@
       log.out.write '\nFINISHED WITH SUCCESS\n'
       close()
     ctx.on 'error', (err) ->
+      log.out.write 'FINISHED WITH ERROR\n'
       print = (err) ->
-        log.out.write 'FINISHED WITH ERROR\n'
+        log.err.write err.stack or err.message + '\n'
+      unless err.errors
+        print err
+      else if err.errors
         log.err.write err.message + '\n'
-        log.err.write err.stack if err.stack
-      print err
-      if err.errors
         for error in err.errors then print error
       close()
     next null, ctx.PASS


Replace //= by #= in coffee test file

Replace //= by #= in coffee test file

--- spec/javascripts/channels/team_spec.coffee
+++ spec/javascripts/channels/team_spec.coffee
@@ -1,4 +1,4 @@
-//= require support/jasmine-jquery-2.0.0
+#= require support/jasmine-jquery-2.0.0

 # TODO find a way to test that we are subscribing with the correct arguments.
 #   Maybe later commits for tests on ActionCable will help I tried with server


Added option to enable/disable translation mode.

--- app/assets/javascripts/app/index.js.coffee
+++ app/assets/javascripts/app/index.js.coffee
@@ -209,6 +209,7 @@
         # load translation collection
         for object in data

+          # set runtime lookup table
           @map[ object[1] ] = object[2]

           # load in collection if needed
@@ -224,10 +225,13 @@
   translate_content: (string, args...) =>
     translated = @translate(string, args...)
 #    replace = '' + translated + ''
-    replace = '' + translated + ''
-#    if !@_translated
-#       replace += 'XX'
-    replace += ''
+    if window.Config['Translation']
+      replace = '' + translated + ''
+  #    if !@_translated
+  #       replace += 'XX'
+      replace += ''
+    else
+      translated

   translate: (string, args...) =>


refactor all thing things

refactor all thing things

--- app/assets/javascripts/client/index.coffee
+++ app/assets/javascripts/client/index.coffee
@@ -82,31 +82,28 @@
     this

   start: (name, options = {}) =>
-    if previous = @getVariantCookie()
+    if variant = @getPreviousVariant()
       # Use the same variant as before, don't record anything
-      variant = (v for v in @variants when v.name is previous)[0]
+      @chooseVariant(variant)
+      return this

-    else if name?
+    if name?
       # Custom variant provided
-      variant = (v for v in @variants when v.name is name)[0]
+      variant = @getVariantForName(name)
       variant or=
         name:    name
         control: options.control
-      @recordStart(variant)

     else
       # Or choose a random one
       random  = Math.floor(Math.random() * @variants.length)
       variant = @variants[random]

-      throw new Error('No variants added') unless variant
-      @recordStart(variant)
-
-    variant?.callback?()
-    @chosen = variant
+    throw new Error('No variants added') unless variant
+    @recordStart(variant)
+    @chooseVariant(variant)
     this

-  # Complete experiment now
   complete: (name) =>
     # Optionally pass a name, or read from the cookie
     name or= @getVariantCookie()
@@ -132,6 +129,13 @@

   # Private

+  getVariantForName: (name) =>
+    (v for v in @variants when v.name is name)[0]
+
+  chooseVariant: (variant) =>
+    variant?.callback?()
+    @chosen = variant
+
   recordStart: (variant) =>
     # Record which experiment was run on the server
     request(
@@ -149,6 +153,10 @@
     request("#{@endpoint}/complete", experiment: @name, variant: name)

   # Variant Cookie
+
+  getPreviousVariant: =>
+    if name = @getVariantCookie()
+      @getVariantForName(name)

   getVariantCookie: =>
     getCookie("abbaVariant_#{@name}")


Revert "and another quick fix, my bad this time -.-"

This reverts commit f7cb16b8def1ace0a24f49f0ee6945fc99b3999f.

--- app/assets/javascripts/contracts.js.coffee
+++ app/assets/javascripts/contracts.js.coffee
@@ -6,8 +6,9 @@
 $ ->
   $('.contracts').on('mouseenter', 'a[data-toggle=tooltip]', ->
     $(this).popover(
+      selector: ''
       placement: 'left'
-      trigger: 'manual'
+      trigger: 'hover'
       html: true
     ).popover('show')
     # container: 'testcontainer'


shorten nums, add suffix, adapt format for it

--- benchmark/benchmarks.coffee
+++ benchmark/benchmarks.coffee
@@ -1,6 +1,8 @@
 chalk  = require 'chalk'
 pad    = require 'pad'
 format = require 'comma-number'
+
+SEP = /[,\.]/

 class Benchmarks

@@ -48,28 +50,44 @@
     if store then @store()

-  format: (length, string) -> pad length, @crop length, format string
+  format: (length, num) -> pad length, @crop length, num, format num

-  crop: (length, string) ->
-    index = string.indexOf '.'
-    if index < 0 then index = length
-    else if index < 3 then index = 5
-    string[0 ... index]
+  crop: (length, num, string) ->
+
+    match = SEP.exec string
+
+    if match?
+
+      if match[0] is ','
+        string = string[0 ... match.index] + '.' + string[match.index + 1]
+        string +=
+          switch
+            when num < 1e6 then ' G'
+            when num < 1e9 then ' M'
+            when num < 1e12 then ' B'
+            when num < 1e15 then ' T'
+            when num < 1e18 then ' P'
+            else ' !'
+
+      else string[0..5]
+
+    else string[0...length]
+

   reportHeader: ->
-    padSize = 12
-    h1 = chalk.blue pad(padSize, 'old ops/sec')
-    h2 = ' |' + chalk.blue pad padSize, 'new ops/sec'
-    h3 = ' |' + pad 10, 'change'
-    h4 = ' |' + chalk.magenta pad padSize, 'old seconds'
-    h5 = ' |' + chalk.magenta pad padSize, 'new seconds'
+    padSize = 10
+    h1 = chalk.blue pad padSize, 'old ops/s'
+    h2 = ' |' + chalk.blue pad padSize, 'new ops/s'
+    h3 = ' |' + pad padSize - 1, 'change'
+    h4 = ' |' + chalk.magenta pad padSize, ' old secs'
+    h5 = ' |' + chalk.magenta pad padSize, ' new secs'
     h6 = ' |' + chalk.bold ' label'
     console.log h1 + h2 + h3 + h4 + h5 + h6
     console.log '----------------------------------------------------------------------------------------------'

   reportResult: (info) ->
     # info = {benchmark, repeat, elapsed, old}
-    padSize = 12
+    padSize = 10

     if info.old?
       oldTimeNum = info.old.seconds + (info.old.nanos / 1e9)
@@ -92,14 +110,14 @@
         if change > 0.01 then chalk.green
         else if change < -0.01 then chalk.red
         else chalk.black
-      change = color(@format 9, change.toFixed 0) + '%'
+      change = color(@format padSize - 2, change.toFixed 0)

-    else change = '      N/A '
+    else change = pad padSize - 2, 'N/A '

     label = chalk.bold info.benchmark.label

     console.log """
-    #{oldRate} |#{newRate} |#{change} |#{oldTime} |#{newTime} |  #{label}
+    #{oldRate} |#{newRate} |#{change}% |#{oldTime} |#{newTime} |  #{label}
     """


OX-120 basic preloading is working

OX-120 basic preloading is working

--- app/assets/javascripts/model/binary.coffee
+++ app/assets/javascripts/model/binary.coffee
@@ -204,8 +204,6 @@
         loadDirection[1] /= directionMax;
         loadDirection[2] /= directionMax;

-      console.log @lastDirection, newDirection, loadDirection
-
       delta_x = delta_y = delta_z = 0
       direction_x = direction_y = direction_z = 0
       index = buckets.length


dynamic button text

dynamic button text

--- modules/gui/lib/widgets/UploadButton.coffee
+++ modules/gui/lib/widgets/UploadButton.coffee
@@ -14,6 +14,8 @@

                     selector: '.upload.Button'
                     action: './upload/'
+
+                    text: 'hochladen'

                     content: ->
                         iframe id:'upload-frame', name:'upload-frame', width:'0px', height:'0px', frameborder:0
@@ -34,7 +36,7 @@
                             else
                                 input class:'files', type:'file', name:'files'

-                        a class:'button img-next link', href:'#', 'hochladen'
+                        a class:'button img-next link', href:'#', (@data.text)

                 popup:


update api for new

update api for new

--- app/assets/javascripts/models/setup.coffee
+++ app/assets/javascripts/models/setup.coffee
@@ -10,8 +10,8 @@
     @attributes = {}
     template = @opts.template || App[@constructor.name].template

-    if @opts.attrs?
-      $.each @opts.attrs, (key, val) =>
+    if @opts?
+      $.each @opts, (key, val) =>
         @set key, val

     @uuid = @opts.uuid || @attributes.uuid || App.UUID.generate()


remove whitespace in table export

remove whitespace in table export

--- app/assets/javascripts/table-export.coffee
+++ app/assets/javascripts/table-export.coffee
@@ -10,10 +10,11 @@
   .join("%09")
   tsv = row_data.map (row) ->
     row._aData.map (cell) ->
-      try
+      val = try
        $(cell).text().replace(/\s{2,}/g , ' ') || cell
       catch err
         cell
+      val.trim()
     .join("%09")
   .join("%0A")
   data = headers + "%0A" + tsv


FIX: update participants list of events after event insertion or update

--- event_occurences.coffee
+++ event_occurences.coffee
@@ -87,7 +87,10 @@
       else
         doc.recurringEventId = undefined

-  MS.EventOccurences.after.insert (userId, eventOccurence, fieldNames, modifiers, options) ->
+  MS.EventOccurences.after.insert (userId, eventOccurence) ->
+    if !eventOccurence.participantsIds or !eventOccurence.participantsIds.length
+      return
+
     # add the event to the each participant list of events
     participantsModifiers = $addToSet: eventOccurencesIds: eventOccurence._id

@@ -95,11 +98,14 @@
     if !!eventOccurence.recurringEventId
       participantsModifiers.$addToSet.recurringEventsIds = eventOccurence.recurringEventId

-    MS.Participants.update
+    MS.Participants.direct.update
       _id: $in: eventOccurence.participantsIds
       participantsModifiers

-  MS.EventOccurences.after.update (userId, eventOccurence, fieldNames, modifiers, options) ->
+  MS.EventOccurences.after.update (userId, eventOccurence) ->
+    if !eventOccurence.participantsIds or !eventOccurence.participantsIds.length
+      return
+
     # add the event to the each participant list of events
     participantsModifiers = $addToSet: eventOccurencesIds: eventOccurence._id

@@ -107,7 +113,7 @@
     if !!eventOccurence.recurringEventId
       participantsModifiers.$addToSet.recurringEventsIds = eventOccurence.recurringEventId

-    MS.Participants.update
+    MS.Participants.direct.update
       _id: $in: eventOccurence.participantsIds
       participantsModifiers


IDE: Create initial view IDE when machine is not approved.

It doesn't matter the machine is permanently shared or collaboration. Always draw IDE with fake views if machine is not approved.

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -401,12 +401,11 @@
       unless machineItem instanceof Machine
         machineItem = new Machine machine: machineItem

-      if not machineItem.isMine()
-        if machineItem.isPermanent() and not machineItem.isApproved()
-          { activitySidebar } = kd.singletons.mainView
-          box = activitySidebar.getMachineBoxByMachineUId machineItem.uid
-          box.machineItem.showSidebarSharePopup sticky: yes
-          withFakeViews = yes
+      if not machineItem.isMine() and not machineItem.isApproved()
+        { activitySidebar } = kd.singletons.mainView
+        box = activitySidebar.getMachineBoxByMachineUId machineItem.uid
+        box.machineItem.showSidebarSharePopup sticky: yes
+        withFakeViews = yes

       @setMountedMachine machineItem


return method result from plugin method call

--- hexaflip.coffee
+++ hexaflip.coffee
@@ -293,13 +293,13 @@
   return @ unless css.transform
   if typeof sets is 'string'
     methodName = sets
-    return @ unless typeof HexaFlip::[methodName] is 'function'
-    for el in @
-      return unless instance = $.data el, baseName
-      args = Array::slice.call arguments
-      args.shift()
-      instance[methodName] args
-    @
+    return @ unless typeof HexaFlip::[methodName] is 'function' and
+      instance = $.data @[0], baseName
+
+    args = Array::slice.call arguments
+    args.shift()
+    instance[methodName] args
+
   else
     for el in @
       continue if $.data el, baseName


Solids block laser light

Solids block laser light

--- app/scripts/components/LaserTurret.js.coffee
+++ app/scripts/components/LaserTurret.js.coffee
@@ -3,7 +3,7 @@
   init: ->
     @requires '2D, Canvas, Edge, Color'
     @attr w: 20, h: 20
-    @beam = Crafty.e('2D, Canvas, Color')
+    @beam = Crafty.e('2D, Canvas, Color, Collision')

   remove: ->

@@ -13,7 +13,9 @@
     laserStart = @y + @h
     laserEnd = @y + @h + beamLength

-    if config.orientation is 'up'
+    down = config.orientation isnt 'up'
+
+    unless down
       @attr y: @y - @h
       laserStart = @y - beamLength
       laserEnd = beamLength
@@ -26,6 +28,18 @@
         w: 10
         h: laserEnd
       )
+    for object in @beam.hit('Edge')
+      continue if object.obj is this
+      if down
+        collision = object.obj.y - laserStart
+        if collision < laserEnd
+          laserEnd = collision
+      else
+        collision = object.obj.y + object.obj.h
+        if collision > laserStart
+          laserStart = collision
+          laserEnd = @y - collision

+    @beam.attr h: laserEnd, y: laserStart

     this


ensure webpack builds with sourcemaps

ensure webpack builds with sourcemaps

--- app/templates/gulp/webpack.config.base.coffee
+++ app/templates/gulp/webpack.config.base.coffee
@@ -21,6 +21,8 @@
   externals:
     'react': 'React'

+  devtool: 'source-map'
+
   plugins: [
     new HappyPack({
       loaders: [{


parse out d3v5 version

parse out d3v5 version

--- parse.coffee
+++ parse.coffee
@@ -266,7 +266,9 @@
   scripts = parseScriptTags(code)
   version = "NA"
   scripts.forEach (script) ->
-    if script.indexOf("d3.v4") >= 0
+    if script.indexOf("d3.v5") >= 0
+      version = "v5"
+    else if script.indexOf("d3.v4") >= 0
       version = "v4"
     else if script.indexOf("d3/3.") >= 0 or script.indexOf("d3.v3") >= 0
       version = "v3"


Adding hacked up rotation.

Adding hacked up rotation.

--- examples/asteroids.coffee
+++ examples/asteroids.coffee
@@ -24,21 +24,31 @@

     # Apply the shift's thrusters.
     thrust : () ->
-        impulse = @direction.scale(0.5)
+        impulse = @direction.scale(0.8)
         @applyImpulse(impulse)

     # Turn the ship to the starboard side.
     starboard : () ->
-        @turn(-15)
+        @turn(-1)

     # Turn the ship to the port side.
     port : () ->
-        @turn(15)
+        @turn(1)

-    # Turn the ship by the given number of degrees.
-    turn : (degrees) ->
-        @rotate(degrees)
-        @direction = @direction.rotate(degrees)
+    # Turn the ship in the given direction.
+    turn : (orientation) ->
+        magnitude = 20
+
+        doTurn = () =>
+            turn = 5
+            if 0 < magnitude
+                degrees = turn * orientation
+                @rotate(degrees)
+                @direction = @direction.rotate(degrees)
+                setTimeout(doTurn, 40)
+            magnitude -= turn
+
+        doTurn()

 # Asteroids floating around space.


example: chatrooms

example: chatrooms

--- examples/chatrooms.coffee
+++ examples/chatrooms.coffee
@@ -1,4 +1,6 @@
 require('./zappajs') ->
+  @with 'client'
+  @use session: store: new @session.MemoryStore(), secret: 'foo', resave: true, saveUninitialized: true

   @get '/': ->
     @render 'index'
@@ -20,26 +22,25 @@
     @broadcast_to @client.room, 'said', data

   @client '/index.js': ->
-    @connect()
+    $ = require 'component-dom'

     @on said: ->
       $('#panel').append "<p>#{@data.nickname} said: #{@data.msg}</p>"

-    $ =>
-      @emit 'set nickname': {nickname: prompt 'Pick a nickname!'}
+    @emit 'set nickname': {nickname: prompt 'Pick a nickname!'}
+    @emit 'set room': {room: prompt 'Pick a room!'}
+
+    $('#box').focus()
+
+    $('#sendButton').on 'click', (e) =>
+      @emit said: {msg: $('#box').value()}
+      $('#box').value('').focus()
+      e.preventDefault()
+
+    $('#changeButton').on 'click', (e) =>
       @emit 'set room': {room: prompt 'Pick a room!'}
-
-      $('#box').focus()
-
-      $('#sendButton').click (e) =>
-        @emit said: {msg: $('#box').val()}
-        $('#box').val('').focus()
-        e.preventDefault()
-
-      $('#changeButton').click (e) =>
-        @emit 'set room': {room: prompt 'Pick a room!'}
-        $('#box').val('').focus()
-        e.preventDefault()
+      $('#box').value('').focus()
+      e.preventDefault()

   {doctype,html,head,title,script,body,div,form,input,button} = @teacup
   @view index: ->


Remove uploaders from includes, we need to make sure they are usable before putting them back

--- includes.coffee
+++ includes.coffee
@@ -101,8 +101,8 @@
   "components/inputs/KDContentEditableView.coffee",

   # upload
-  "components/upload/KDFileUploadView.coffee",
-  "components/upload/kdmultipartuploader.coffee",
+  # "components/upload/KDFileUploadView.coffee",
+  # "components/upload/kdmultipartuploader.coffee",

   # buttons
   "components/buttons/KDButtonView.coffee",


fixed method renaming issue

fixed method renaming issue

--- src/FileManager/BreadcrumbDirective.coffee
+++ src/FileManager/BreadcrumbDirective.coffee
@@ -27,7 +27,7 @@
           })

           parent_id = file.metadata.parentId
-          if parent_id? and parent_id != session.getRootFolder()
+          if parent_id? and parent_id != session.getRootFolderId()
             getPath(parent_id)
   }
 )


test: removed unused variables from login

--- client/test/lib/login/login.coffee
+++ client/test/lib/login/login.coffee
@@ -1,6 +1,5 @@
 utils    = require '../utils/utils.js'
 helpers  = require '../helpers/helpers.js'
-HUBSPOT  = no

 module.exports =


client compiles and runs

client compiles and runs

--- clients/coffeescript/aeromq.coffee
+++ clients/coffeescript/aeromq.coffee
@@ -2,16 +2,12 @@
 util = require "util"
 assert = require "assert"

-class Client extends EventEmitter
-    constructor: (address, queues) ->
+ZSERVER_ADDRESS = "tcp://0.0.0.0:5556"
+
+class Client extends process.EventEmitter
+    constructor: (@queues, address=ZSERVER_ADDRESS) ->
         @socket = zeromq.createSocket 'req'
         @socket.connect address
-
-        # tell the server what tasks we're interested in
-        @socket.send JSON.stringify {
-            command: 'ready'
-            queues: queues
-        }

         @socket.on 'message', (message) =>
             try
@@ -22,6 +18,13 @@

             @emit job.queue, job.uuid, job.message

+    ready: ->
+        # tell the server what tasks we're interested in
+        @socket.send JSON.stringify {
+            command: 'ready'
+            queues: queues
+        }
+
     done: (uuid) ->
         @socket.send JSON.stringify {
             command: 'done'


fix hourssum

fix hourssum

--- client/client.coffee
+++ client/client.coffee
@@ -175,6 +175,8 @@

 		ny = "#{$scope.currentYear+1}".substring 2
 		$scope.currentYearString = "#{$scope.currentYear}/#{ny}"
+
+		$scope.hoursSum = _.sum allHours, (h) -> h.hours

 	updateHours()


forgot to initialize a variable after copy/paste

--- client/editor.coffee
+++ client/editor.coffee
@@ -324,7 +324,7 @@
     else @cm.execCommand 'goDocEnd'; @cm.execCommand 'newlineAndIndent'; @xline = l + 1
     return
   onbeforeunload: -> # called when the user presses [X] on the OS window
-    if v == @originalText && @breakpoints.join() == @originalBreakpoints
+    if @cm.getValue() == @originalText && @breakpoints.join() == @originalBreakpoints
       @EP(); return
     else if !@dialog
       @dialog = $("
The object \"#{@name}\" has changed.
Do you want to save the changes?
").dialog buttons: [
@@ -336,4 +336,4 @@
       #   NW.js prevents the window from closing.
       #   Browsers ask the user "Are you sure you want to close this window?"
       #   In addition, some browsers display the returned string along with the above question.
-      ''
+      ''


remove Session variable

remove Session variable

--- client/images.coffee
+++ client/images.coffee
@@ -1,4 +1,4 @@
-Session.setDefault "trigger_update", null
+trigger_update = new Deps.Dependency

 my_uploader = null # variable local to this script
 uploader_state_changed = new Deps.Dependency
@@ -224,8 +224,7 @@
       return

   get_n_selected: ->
-    dt = Session.get "trigger_update"
-
+    trigger_update.depend()
     template = Template.instance()
     if !template.firstNode?
       # The DOM hasn't been rendered yet, can't count selected.
@@ -259,7 +258,7 @@
   for image_id in data.current_images
     $('.selectable#'+image_id).addClass('selected')

-  Session.set "trigger_update",Date.now() # force update (how else to do this?)
+  trigger_update.changed() # force update

 Template.LinkExistingImageDialog.helpers
   friendly_item_name: ->


Prevent duplicate files to be imported at the same time.

--- client/import.coffee
+++ client/import.coffee
@@ -1,4 +1,12 @@
 # Local (client-only) collection of importing files
+# Fields:
+#   name: user's file name
+#   readProgress: progress of reading from file, in %
+#   uploadProgress: progress of uploading file, in %
+#   status: current status or error message
+#   finished: true when importing has finished
+#   publicationId: publication ID for the imported file
+#   sha256: SHA256 hash for the file
 ImportingFiles = new Meteor.Collection null

 UPLOAD_CHUNK_SIZE = 128 * 1024 # bytes
@@ -54,6 +62,20 @@
         hash = new Crypto.SHA256()
         hash.update @result
         sha256 = hash.finalize()
+
+        alreadyImporting = ImportingFiles.findOne(sha256: sha256)
+        if alreadyImporting
+          ImportingFiles.update file._id,
+            $set:
+              status: "File is already importing"
+              finished: true
+              # publicationId might not yet be available, but let's try
+              publicationId: alreadyImporting.publicationId
+          return
+
+        ImportingFiles.update file._id,
+          $set:
+            sha256: sha256

         Meteor.call 'createPublication', file.name, sha256, (err, result) ->
           if err


improve error message to include project id

--- salvus/page/project.coffee
+++ salvus/page/project.coffee
@@ -1688,7 +1688,7 @@

                 if err
                     if not @public_access
-                        alert_message(type:"error", message:"Problem reading the directory listing for '#{path}' -- #{misc.trunc(err,100)}; email help@sagemath.com if this persists.")
+                        alert_message(type:"error", message:"Problem reading file listing for '#{path}' -- #{misc.trunc(err,100)}; email help@sagemath.com (include the id #{@project.project_id}).")
                         @current_path = []
                     cb?(err)
                 else


make it stronger with type checking

make it stronger with type checking

--- src/coffee/validators/notblank.coffee
+++ src/coffee/validators/notblank.coffee
@@ -11,9 +11,10 @@
     validator = (name, values, rule) ->
       v = values[name]
       if v is undefined or v is null then return false
-      if v is true or v is false then return true
-      if v and !isNaN(v) then return true
-      if (v and (v.replace /^\s+|\s+$/g, "").length > 0) then true
+      if typeof v == "boolean" and v is true or v is false then return true
+      if typeof v == "number" then return true
+      if typeof v == "string"
+        if (v.replace /^\s+|\s+$/g, "").length > 0 then return true else false
       else false

     return {


fixing indentation bug in event bindings in collection view

--- src/components/collection_view.coffee
+++ src/components/collection_view.coffee
@@ -16,39 +16,45 @@
 #
 collectionView.extends            "Luca.components.Panel"

-collectionView.mixesIn          "LoadMaskable",
-                                "Filterable",
-                                "Paginatable"
-
-collectionView.triggers         "before:refresh",
-                                "after:refresh",
-                                "refresh",
-                                "empty:results"
+collectionView.mixesIn            "LoadMaskable",
+                                  "Filterable",
+                                  "Paginatable"
+
+collectionView.triggers           "before:refresh",
+                                  "after:refresh",
+                                  "refresh",
+                                  "empty:results"
+
+# IDEA:
+#
+# For validation of component configuration,
+# we could define a convention like:
+#
+# collectionView.validatesConfigurationWith
+#   requiresValidCollectionAt: "collection"
+#   requiresPresenceOf:
+#     either: ["itemTemplate", "itemRenderer", "itemProperty"]
+#
+#
+collectionView.publicConfiguration
+  tagName: "ol"
+  bodyClassName: "collection-ui-panel"
+  itemTagName: 'li'
+  itemClassName: 'collection-item'
+  itemTemplate: undefined
+  itemRenderer: undefined
+  itemProperty: undefined

 collectionView.defines
-  tagName: "ol"
-
-  className: "luca-ui-collection-view"
-
-  bodyClassName: "collection-ui-panel"
-
-  # A collection view can pass a model through to a template
-  itemTemplate: undefined
-
-  # A collection view can pass a model through a function which should return a string
-  itemRenderer: undefined
-
-  itemTagName: 'li'
-
-  itemClassName: 'collection-item'
-
-
   initialize: (@options={})->
     _.extend(@, @options)
-
     _.bindAll @, "refresh"

-
+    # IDEA:
+    #
+    # This type of code could be moved into a re-usable concern
+    # which higher order components can mixin to make it easier
+    # to extend them, instantiate them, etc.
     unless @collection? or @options.collection
       console.log "Error on initialize of collection view", @
       throw "Collection Views must specify a collection"
@@ -66,28 +72,23 @@
       console.log "Missing Collection on #{ @name || @cid }", @, @collection
       throw "Collection Views must have a valid backbone collection"

-      @collection.on "before:fetch", ()=>
-        @trigger "enable:loadmask"
-
-      @collection.bind "reset", ()=>
-        @refresh()
-        @trigger "disable:loadmask"
-
-      @collection.bind "remove", ()=>
-        @refresh()
-
-      @collection.bind "add", ()=>
-        @refresh()
-
-      if @observeChanges is true
-        @collection.on "change", @refreshModel, @
+    @collection.on "before:fetch", ()=>
+      @trigger "enable:loadmask"
+
+    @collection.bind "reset", ()=>
+      @refresh()
+      @trigger "disable:loadmask"
+
+    @collection.bind "remove", ()=>
+      @refresh()
+
+    @collection.bind "add", ()=>
+      @refresh()
+
+    if @observeChanges is true
+      @collection.on "change", @refreshModel, @

     Luca.components.Panel::initialize.apply(@, arguments)
-
-    unless @autoRefreshOnModelsPresent is false
-      @defer ()=>
-        @refresh() if @collection.length > 0
-      .until("after:render")

     @on "refresh", @refresh, @

@@ -132,10 +133,10 @@

   # Private: returns the query that is applied to the underlying collection.
   # accepts the same options as Luca.Collection.query's initial query option.
-  getQuery: ()->
+  getQuery: (options={})->
     query = @query ||= {}
     for querySource in _( @querySources || [] ).compact()
-      query = _.extend(query, (querySource()||{}) )
+      query = _.extend(query, (querySource(options)||{}) )
     query

   # Private: returns the query that is applied to the underlying collection.


Add system information as api call

Add system information as api call

--- coffee/server.coffee
+++ coffee/server.coffee
@@ -55,6 +55,12 @@
 app.get '/objekttyper', (req, res, next) ->
   res.json 200, ['turer', 'steder', 'områder', 'grupper', 'aktiviteter', 'bilder']

+app.get '/system', (req, res, next) ->
+  res.json 200,
+    uptime: process.uptime()
+    memory: process.memoryUsage()
+    versions: process.versions()
+
 app.param 'objectid', document.param
 app.all '/:collection/:objectid', (req, res, next) ->
   switch req.method


Add context menu on the tree-view to toggle the Finder.

--- menus/tree-view-finder.cson
+++ menus/tree-view-finder.cson
@@ -1,10 +1,11 @@
 # See https://atom.io/docs/latest/hacking-atom-package-word-count#menus for more details
 'context-menu':
-  'atom-text-editor': [
+  '.tree-view': [
     {
       'label': 'Toggle tree-view-finder'
       'command': 'tree-view-finder:toggle'
     }
+    {'type': 'separator'}
   ]
 'menu': [
   {


That test was more pain than it was worth.

--- spec/side-view-spec.coffee
+++ spec/side-view-spec.coffee
@@ -19,11 +19,6 @@
   it 'applies its position as a CSS class', ->
     expect(view.hasClass 'top').toBe(true)
     expect(view.hasClass 'bottom').toBe(false)
-
-  xit 'positions itself over the banner line', ->
-    refBanner = $(editorView).find('.line:contains("<<<<<<<")')
-    expect(view.offset().top).toEqual(refBanner.offset().top)
-    expect(view.height()).toEqual(refBanner.height())

   it 'knows if its text is unaltered', ->
     expect(ours.isDirty).toBe(false)


Added unit test for remove first item of a collection

--- specs/somewhereSpec.coffee
+++ specs/somewhereSpec.coffee
@@ -143,6 +143,11 @@
       expect(typeof item).to.equal 'object'
       expect(Object.keys(item).length).to.equal 0

+    it "should remove first item from a collection", ->
+      item = db.database.users[0]
+      result = db.remove 'users', item.id
+      expect(result).to.equal true
+
     it "should not remove an item that not exist", ->
       item = db.remove 'users', '12345'
       expect(item).to.equal false


Removed brackets

Removed brackets

--- specs/somewhereSpec.coffee
+++ specs/somewhereSpec.coffee
@@ -4,7 +4,7 @@
 DB = require '../index'

 describe "JSONdb module", ->
-  describe "Persistence and memory tests", ->
+  describe "Memory and disk persistence", ->
     it "should set new database path", ->
       db = new DB './database.json'
       expect(db.databasePath).to.equal './database.json'
@@ -48,7 +48,7 @@
     item = db.save 'users', user

     it "should find one", ->
-      item = db.findOne 'users', { username: 'dreyacosta' }
+      item = db.findOne 'users', username: 'dreyacosta'
       expect(item.name).to.equal 'David'

     it "should find all", ->
@@ -58,24 +58,24 @@
         blog: 'drey.com'
         source: 'twitter'
       item = db.save 'users', user
-      items = db.find 'users', { name: 'David' }
+      items = db.find 'users', name: 'David'
       expect(items.length).to.equal 2

     it "should return an empty object if no match on find one", ->
-      item = db.findOne 'users', { name: 'Paul' }
+      item = db.findOne 'users', name: 'Paul'
       expect(typeof item).to.equal 'object'
       expect(Object.keys(item).length).to.equal 0

     it "should return an empty array if no match on find all", ->
-      items = db.find 'users', { name: 'Paul' }
+      items = db.find 'users', name: 'Paul'
       expect(items.push).to.be.a 'function'
       expect(items.length).to.equal 0

     it "should return a pure object when find one", ->
-      item = db.findOne 'users', { username: 'dreyacosta' }
+      item = db.findOne 'users', username: 'dreyacosta'
       expect(item.name).to.equal 'David'
       item.name = 'Mike'
-      item = db.findOne 'users', { username: 'dreyacosta' }
+      item = db.findOne 'users', username: 'dreyacosta'
       expect(item.name).to.equal 'David'

     it "should return a pure array when find all", ->
@@ -85,33 +85,33 @@
         blog: 'pirish.com'
         source: 'twitter'
       item = db.save 'users', user
-      items = db.find 'users', { source: 'twitter' }
+      items = db.find 'users', source: 'twitter'
       expect(items.length).to.equal 3
       items[0].source = 'facebook'
-      items = db.find 'users', { source: 'twitter' }
+      items = db.find 'users', source: 'twitter'
       expect(items.length).to.equal 3

     it "should return a pure object when update", ->
-      item = db.findOne 'users', { username: 'dreyacosta' }
-      item = db.update 'users', item.id, { name: 'David Rey' }
+      item = db.findOne 'users', username: 'dreyacosta'
+      item = db.update 'users', item.id, name: 'David Rey'
       expect(item.name).to.equal 'David Rey'
       item.name = 'Mike'
-      item = db.findOne 'users', { username: 'dreyacosta' }
+      item = db.findOne 'users', username: 'dreyacosta'
       expect(item.name).to.equal 'David Rey'

     it "should update item", ->
       data =
         country: 'Spain'
-      item = db.findOne 'users', { username: 'drey' }
+      item = db.findOne 'users', username: 'drey'
       item = db.update 'users', item.id, data
       expect(item.country).to.equal 'Spain'

     it "should remove item from a collection", ->
-      item = db.findOne 'users', { username: 'drey' }
+      item = db.findOne 'users', username: 'drey'
       expect(item.username).to.equal 'drey'
       result = db.remove 'users', item.id
       expect(result).to.equal true
-      item = db.findOne 'users', { id: item.id }
+      item = db.findOne 'users', id: item.id
       expect(typeof item).to.equal 'object'
       expect(Object.keys(item).length).to.equal 0


Ensure all graphs loaded from runtime are fbp-graph objects

--- components/RuntimeToProject.coffee
+++ components/RuntimeToProject.coffee
@@ -82,7 +82,12 @@
     # Add components and graphs from library
     fetchFromLibrary project.namespace, data.payload.runtime, (err, sources) ->
       return callback err if err
-      graphs = graphs.concat sources.filter (c) -> c.language is 'json'
+      projectGraphs = sources.filter (c) -> c.language is 'json'
+      for graphDef in projectGraphs
+        noflo.graph.loadJSON graphDef, (err, graph) ->
+          return if err
+          graphs.push graph
+
       components = components.concat sources.filter (c) -> c.language isnt 'json'

       for graph in graphs


Table widget font-size

Table widget font-size

--- widgets/table/table.coffee
+++ widgets/table/table.coffee
@@ -3,5 +3,5 @@
     onData: (data) ->
         console.log 'table widget data: ', data
         console.log 'table widget node: ', $(@node)
-        console.log 'table widget node height: ', $(@node).clientHeight
+        console.log 'table widget node height: ', $(@node).attr("clientHeight")
         #console.log 'table widget parent: ', $(@node).parent()


typofix

typofix

--- lib/action/clickOnAndWaitForElementByCss.coffee
+++ lib/action/clickOnAndWaitForElementByCss.coffee
@@ -1,4 +1,4 @@
-module.exports = class ClickOnAndForElementByCss extends require '../action'
+module.exports = class ClickOnAndWaitForElementByCss extends require '../action'
   clickOnAndWaitForElementByCssAction: (context, clickOn, waitFor, asserter, timeout = 10000) ->
     asserter or= timeout
     timeout = undefined if typeof asserter is 'number'


httpListening hook, for stuff that has to wait until the HTTP server is listening

--- server/AbstractHttp.coffee
+++ server/AbstractHttp.coffee
@@ -1,6 +1,7 @@

 nconf = require 'nconf'
 pkgman = require 'pkgman'
+Promise = require 'bluebird'
 winston = require 'winston'

 middleware = require 'middleware'
@@ -22,7 +23,19 @@
 		middleware.dispatch request, response, (error) =>
 			return fn error if error?

-			@listen fn
+			@listen (error) =>
+				return fn error if error?
+
+				promises = for _, promise of pkgman.invoke(
+					'httpListening', this
+				)
+					promise
+
+
+				Promise.all(promises).then(
+					-> fn()
+					(error) -> fn error
+				)

 	config: -> @_config


add comments

add comments

--- server/lib/manifest.coffee
+++ server/lib/manifest.coffee
@@ -8,6 +8,12 @@
 class exports.Manifest

+    # Attempt to download application NPM manifest from three different
+    # location (location selection is based on manifest information):
+    #
+    # * NPM registry
+    # * Gitlab repository
+    # * Github repository
     download: (app, callback) ->

         if app.package?
@@ -27,6 +33,7 @@
                 callback null, {}

         else if app.git?
+
             providerName = app.git.match /(github\.com|gitlab\.cozycloud\.cc)/
             if not providerName?
                 logger.error "Unknown provider '#{app.git}'"
@@ -35,10 +42,10 @@
             else
                 providerName = providerName[0]

-                # This could be moved to a separate factory class...
                 if providerName is "gitlab.cozycloud.cc"
                     Provider = require('./git_providers').CozyGitlabProvider
-                else # fallback to github
+
+                else
                     Provider = require('./git_providers').GithubProvider

                 provider = new Provider app
@@ -54,6 +61,9 @@
             callback null, {}

+    # Download the manifest from the NPM registry. This manifest has many
+    # information (it includes history). So we extract the lastest version
+    # of the application manifest.
     downloadFromNpm: (packageName, callback) ->
         client = request.createClient "https://registry.npmjs.org/"
         client.get packageName, (err, res, data) ->


add twoLineWrap() function for strings

add twoLineWrap() function for strings

--- shared/code/custard.coffee
+++ shared/code/custard.coffee
@@ -1,4 +1,6 @@
-# Utility functions for the Custard frontend
+# Utility functions for
+# the Custard frontend
+

 showOrAddSSH = (model, type) =>

@@ -46,3 +48,14 @@
   $(document).on 'click', '.modal #add-ssh-key', addSSHKey
   $(document).on 'click', '.modal #add-another-ssh-key', ->
     makeModal JST['modal-add-ssh']()
+
+
+String::twoLineWrap = (characters=20) ->
+  return this if this.length <= characters
+  text = this
+  if this.length > characters*2
+    regexp = new RegExp "(.{1,#{characters*2}})[ ](.*)"
+    text = text.replace regexp, "$1\u2026"
+  regexp = new RegExp "(.{1,#{characters}})[ ](.*)"
+  text = text.replace regexp, '$1<br>$2'
+  return text


Allow test methods to be named test*, not necessarily test_*.

--- coffee/ExerciseController.coffee
+++ coffee/ExerciseController.coffee
@@ -95,7 +95,7 @@
       case_.inputLineNum = 0
       try
         if case_.code
-          match = /^def (test_[a-zA-Z0-9_]*)\n/.exec case_.code
+          match = /^def (test[a-zA-Z0-9_]*)\n/.exec case_.code
           throw "Case doesn't start with def test_" if match == null
           test_name = match[1]
           bytecodes = AstToBytecodeCompiler.compile [


Read form method attribute, not property

--- remote.coffee
+++ remote.coffee
@@ -192,7 +192,7 @@
   settings.context = this

   # Use form method as the AJAX method
-  if type = this.method
+  if type = form.attr 'method'
     settings.type = type

   # Use form action as the AJAX url