map should be sourcemap

map should be sourcemap

--- tests/integrated.coffee
+++ tests/integrated.coffee
@@ -27,8 +27,8 @@
           fs.readFile,
           "./tests/data/single/source.css.map"
         ).then(
-          (map) ->
-            right.sourcemap = JSON.parse(map.toString "utf-8")
+          (sourcemap) ->
+            right.sourcemap = JSON.parse(sourcemap.toString "utf-8")
             right.sourcemap.sources = right.sourcemap.sources.map(
               (file) -> path.relative(
                 process.cwd(), path.resolve "./tests/data/single", file
@@ -103,13 +103,14 @@
             resultPath = path.join("./tests/results/multiple", file)
             if not right[resultPath]
               right[resultPath] = {}
-            right[resultPath].map = JSON.parse data.toString("utf-8")
-            right[resultPath].map.sources = right[resultPath].map.sources.map(
-              (file) -> path.relative(
-                process.cwd()
-                path.resolve "./tests/data/multiple", file
-              ).replace /\\/g, "/"
-            )
+            right[resultPath].sourcemap = JSON.parse data
+            right[resultPath].sourcemap.sources =
+              right[resultPath].sourcemap.sources.map(
+                (file) -> path.relative(
+                  process.cwd()
+                  path.resolve "./tests/data/multiple", file
+                ).replace /\\/g, "/"
+              )
         )
       q.all(promises).done (-> done()), done

@@ -149,7 +150,9 @@
             )
             promises.push q.nfcall(
               fs.readFile, file + ".map"
-            ).then((data) -> expect(JSON.parse data).eql right[file].map)
+            ).then(
+              (data) -> expect(JSON.parse data).eql right[file].sourcemap
+            )
           q.all(promises).done (-> done()), done
       )
   describe "Glob test case", ->


Referral: separate referral saving function

--- workers/social/lib/social/models/referral/index.coffee
+++ workers/social/lib/social/models/referral/index.coffee
@@ -343,6 +343,25 @@
         return console.error err if err
         console.log "referal saved successfully for #{me.profile.nickname} from #{referrerCode}"

+    persistReferrals = (source, target, callback)->
+      getReferralDiskSizeAmount (err, amount)->
+        return callback err if err
+        referral = new JReferral { type: "disk", unit: "MB", amount}
+        referral.save (err) ->
+          return callback err if err
+          #add referrer as referrer to the referral system
+          source.addReferrer referral, (err)->
+            return callback err if err
+            # add me as referred to the referral system
+            target.addReferred referral, (err)->
+              return callback err if err
+              console.info "referal saved successfully for #{target.profile.nickname} from #{source.profile.nickname}"
+              callback null
+
+              # do this async
+              decreaseLeftSpace amount, (err)->
+                return console.error err if err
+
     JUser.on 'EmailConfirmed', (user)->
       return console.log "User is not defined in event" unless user

@@ -351,20 +370,14 @@
         # if account not fonud then do nothing and return
         return console.error "Account couldnt found" unless me
         referrerUsername = me.referrerUsername
-        return console.log "User doesn't have any referrer" unless referrerUsername
+        return console.info "User doesn't have any referrer" unless referrerUsername
         # get referrer
         JAccount.one {'profile.nickname': referrerUsername }, (err, referrer)->
           # if error occured than do nothing and return
           return console.error "Error while fetching referrer", err if err
           # if referrer not fonud then do nothing and return
           return console.error "Referrer couldnt found" if not referrer
-          referral = new JReferral { type: "disk", unit: "MB", amount: 250 }
-          referral.save (err) ->
+          persistReferrals referrer, me, (err)->
             return console.error err if err
-            #add referrer as referrer to the referral system
-            referrer.addReferrer referral, (err)->
+            persistReferrals me, referrer, (err)->
               return console.error err if err
-              # add me as referred to the referral system
-              me.addReferred referral, (err)->
-                return console.error err if err
-                console.log "referal saved successfully for #{me.profile.nickname} from #{referrerUsername}"


unwanted file

unwanted file

--- flood2.coffee
+++ flood2.coffee
@@ -1,88 +0,0 @@
-globals =
-  gridSize: 12
-  colorCount: 6
-
-game = Snap('#game')
-game.attr(
-  viewBox: "0 0 #{globals.gridSize} #{globals.gridSize}"
-  shapeRendering: "crispEdges"
-)
-
-class GraphicalCell
-  constructor: (color, i, j) ->
-    @rect = game.rect i, j, 1, 1
-    @rect.attr(class: "color-#{color}")
-
-  setInNetwork: () ->
-    @rect.attr(class: "in-network")
-
-class Cell
-  constructor: (@color, @graphicalCell, @inNetwork) ->
-    @graphicalCell.setInNetwork() if @inNetwork
-    @neighbours = []
-
-  addNeighbour: (cell) ->
-    @neighbours.push cell
-
-  explore: (color) ->
-    @navigate(color) if @inNetwork
-
-  expand: (color) ->
-    if @inNetwork || @color != color
-      return
-    @inNetwork = true
-    @graphicalCell.setInNetwork()
-    @navigate(color)
-
-  navigate: (color) ->
-    n.expand(color) for n in @neighbours
-
-class Grid
-  constructor: (@gridSize, @colorCount) ->
-    row = []
-    grid = for i in [0..@gridSize-1]
-      row = @createRow(i, row)
-    @cells = [].concat.apply([], grid)
-    @step = -1
-    @switchColor(@cells[0].color)
-
-  createRow: (i, prevRow) ->
-    for j in [0..@gridSize-1]
-      cell = @createCell i, j, cell, prevRow[j]
-
-  createCell: (i, j, neighbours...) ->
-    color = Math.floor Math.random() * @colorCount
-    graphicalCell = new GraphicalCell(color, i, j)
-    cell = new Cell(color, graphicalCell, i == 0 && j == 0)
-    for neighbour in neighbours when neighbour
-      cell.addNeighbour neighbour
-      neighbour.addNeighbour cell
-    return cell
-
-  switchColor: (color) ->
-    unless 0 <= color < @colorCount
-      alert "Impossible color: #{color}"
-      return
-    return if color == @color
-    @color = color
-    stepText.node.textContent = "Step #{++@step}"
-    game.attr(class: "current-#{color}")
-    cell.explore(color) for cell in @cells
-    if (c for c in @cells when !c.inNetwork).length == 0
-      alert "Youpi !"
-      window.location = window.location
-
-topControls = Snap '#top-controls'
-stepText = topControls.text 2, 5, ""
-
-grid = new Grid(globals.gridSize, globals.colorCount)
-
-
-bottomControls = Snap '#bottom-controls'
-
-makeCircle = (i) ->
-  circle = bottomControls.circle((2 * i + 1) * 100 / (globals.colorCount * 2), 10, 6)
-  circle.attr(class: "color-#{i}")
-  circle.click(() -> grid.switchColor(i))
-
-makeCircle(i) for i in [0..globals.colorCount-1]


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

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

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


Refactor update code, introduce bugs, break shit

--- source/coffee/index.coffee
+++ source/coffee/index.coffee
@@ -33,12 +33,16 @@
     @parseNodes = (data, pin, keyed={}) ->
       root = {}

+      console.log "Keyed: ", keyed
+
       # Index node list by ID, merging/updating if keyed was provided
       for node in data.nodes
+        console.log "Node: ", node
         keyed[node.id] = node

       # Step through IDs
       for id of keyed
+        console.log "Id: ", id
         node = keyed[id]
         pid = node.facts?.parent_id
         if pid? # Has parent ID?
@@ -47,10 +51,12 @@
             pnode.children ?= [] # Initialize if first child
             pnode.children.push node # Add to parent's children
           else # We're an orphan (broken data or from previous merge)
+            console.log "Deleting orphan: ", keyed[id], node
             delete keyed[id] # No mercy for orphans!
         else if node.name is "workspace" # Mebbe root node?
           root = node # Point at it
         else # Invalid root node!
+          console.log "Deleting invalid root: ", id, node
           delete keyed[id] # Pew Pew!

       pin keyed if pin? # Update pin with keyed
@@ -72,24 +78,46 @@
         status: "unknown"
       , {}, ko.mapping.fromJS @node, mapping

-    @updateNodes = (url, keys, pin) =>
+    @updateNodes = (data, pin, keys) =>
+      @mapData @parseNodes(data, null, keys), pin, mapping
+
+    @getNodes = (url, pin, keys) =>
       @getData url, (data) =>
-        @mapData @parseNodes(data, keys), pin, mapping
+        @updateNodes data, pin, keys

     @wsTemp = ko.observableArray()
-    @wsItems = ko.computed =>
-      @wsTemp()?[0]?.children ? []
+    @wsItems = ko.computed(=>
+      @wsTemp()?[0]?.children ? []).extend throttle: 200 # Coalesce node changes

     @wsPlans = ko.observableArray()
     @wsKeys = ko.observable()

     @poll = (url, cb, timeout=@config?.timeout?.long) =>
+      rePoll = (data) =>
+        if data?
+          @sKey = data.transaction.session_key
+          @txID = data.transaction.txid
+          console.log "Updating transaction: ", @sKey, @txID
+        # Restart long-poller for new transaction
+        setTimeout (=> @poll "/roush/nodes/updates/#{@sKey}/#{@txID}?poll", cb, timeout), 1
+
       $.ajax
         url: url
-        success: (data) ->
+        success: (data) =>
           cb data
+          rePoll data
+        error: (jqXHR, textStatus, errorThrown) =>
+          switch jqXHR.status
+            when 410 # Gone, cycle txID
+              @getData "/roush/updates", (data) =>
+                rePoll data
+            when 0 # Timeout
+              console.log "Retrying"
+              rePoll()
+            else # Other errors
+              console.log "Error (#{jqXHR.status}): #{errorThrown}"
+              setTimeout (=> @poll url, cb, timeout), 1000 # Throttle retry
         dataType: "json"
-        complete: (=> @poll url, cb, timeout)
         timeout: timeout ? 30000

     # Get config and grab initial set of nodes
@@ -104,10 +132,10 @@
         # Start long-poller
         @poll "/roush/nodes/updates/#{@sKey}/#{@txID}?poll", (data) =>
           console.log "Got update: ", data
-          @updateNodes "/roush/nodes/", @wsKeys, @wsTemp
+          setTimeout @updateNodes(data, @wsKeys, @wsTemp), 1000

         # Load initial data, and poll every config.interval ms
-        @updateNodes "/roush/nodes/", @wsKeys, @wsTemp
+        @getNodes "/roush/nodes/", @wsKeys, @wsTemp

     @siteActive = ntrapy.selector (data) =>
       null # TODO:


Make request and token setup in tests consistent

--- tests/pine.spec.coffee
+++ tests/pine.spec.coffee
@@ -3,7 +3,6 @@
 Promise = require('bluebird')
 url = require('url')
 tokens = require('./fixtures/tokens.json')
-getToken = require('resin-token')
 getPine = require('../lib/pine')

 IS_BROWSER = window?
@@ -25,7 +24,7 @@
 fetchMock.fetchMock.Promise = Promise
 require('resin-request/build/utils').fetch = fetchMock.fetchMock # Can become just fetchMock after issue above is fixed.

-token = getToken({ dataDirectory })
+token = require('resin-token')({ dataDirectory })
 request = require('resin-request')({ dataDirectory })

 apiVersion = 'v2'


cleanup

cleanup

--- content/journal-abbrev.coffee
+++ content/journal-abbrev.coffee
@@ -63,9 +63,11 @@
       try
         debug('JournalAbbrev.get: trying', field)
         journal = if item.getField then item.getField(field, false, true) else item[field]
-        if journal
-          debug('JournalAbbrev.get: found', field, journal)
-          break
+        continue unless journal
+        journal = journal.replace(/<\/?(sup|sub|i|b)>/g, '')
+        continue unless journal
+        debug('JournalAbbrev.get: found', field, journal)
+        break

     return null unless journal


Fix adding of members to work for staff members too

--- app/assets/javascripts/forms.js.coffee
+++ app/assets/javascripts/forms.js.coffee
@@ -100,13 +100,13 @@
     $('.add-member .btn').click () ->
       email = $(@).prev('input').val()
       form = $(@).parents('form.new_member')
-      hallopeds = $(@).parents('.hallopeds')
+      members = $(@).parents('.hallopeds, .staff')
       superagent.post(form.attr 'action').
         type('form-data').
         send(form.serialize()).
         end((response) ->
           findOrCreateNewRow = () ->
-            lastRow = hallopeds.find('.empty-row:last')
+            lastRow = members.find('.empty-row:last')
             if lastRow.find('.member .member-card').length == 0
               lastRow
             else
@@ -114,12 +114,16 @@
               newRow.find('.member-card').remove()
               lastRow.append newRow
               newRow
-          newMemberRow = findOrCreateNewRow()
-          newSlot = newMemberRow.find('.member-card-empty.member')
-          placeHolder = newSlot.html()
-          newSlot.html(response.text).append placeHolder
-          initDraggableCard newMemberRow.find('.member-card')
-          initDroppableSlot newMemberRow.find('.member-card-empty')
+          if members.hasClass 'staff'
+            $(response.text).insertAfter('.staff .member-card:last')
+            alignCards(members)
+          else
+            newMemberRow = findOrCreateNewRow()
+            newSlot = newMemberRow.find('.member-card-empty.member')
+            placeHolder = newSlot.html()
+            newSlot.html(response.text).append placeHolder
+            initDraggableCard newMemberRow.find('.member-card')
+            initDroppableSlot newMemberRow.find('.member-card-empty')
           cached.clear()
         )
       return false


fix #77

fix #77

--- app/assets/javascripts/pager.js.coffee
+++ app/assets/javascripts/pager.js.coffee
@@ -27,8 +27,6 @@
     $(".content_list").append html
     if count > 0
       @offset += count
-    else
-      @disable = true

   initLoadMore: ->
     $(document).unbind('scroll')


Delete unused tv_shows.coffee

Delete unused tv_shows.coffee

--- app/assets/javascripts/tv_shows.coffee
+++ app/assets/javascripts/tv_shows.coffee
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/


[fix] respond with job data object

[fix] respond with job data object

--- src/el-borracho.coffee
+++ src/el-borracho.coffee
@@ -82,7 +82,7 @@
     {id, queue, state} = req.params

     await @store.dataById queue, id, ideally defer results
-    res.json message: results
+    res.json results

   counts: (req, res, next) =>
     ideally = errify next


fix move selected-text

fix move selected-text

--- lib/selection-wrapper.coffee
+++ lib/selection-wrapper.coffee
@@ -1,4 +1,4 @@
-{Range, Point} = require 'atom'
+{Range, Point, Disposable} = require 'atom'
 {
   translatePointAndClip
   getRangeByTranslatePointAndClip
@@ -186,6 +186,19 @@
     @setBufferRange([tail, head], options)
     @setReversedState(head.isLessThan(tail))

+  applyColumnFromProperties: ->
+    selectionProperties = @getProperties()
+    return unless selectionProperties?
+    {head, tail} = selectionProperties
+
+    if @selection.isReversed()
+      [start, end] = [head, tail]
+    else
+      [start, end] = [tail, head]
+    [start.row, end.row] = @selection.getBufferRowRange()
+    @setBufferRange([start, end])
+    @translateSelectionEndAndClip('backward', translate: false)
+
   # set selections bufferRange with default option {autoscroll: false, preserveFolds: true}
   setBufferRange: (range, options={}) ->
     if options.keepGoalColumn ? true
@@ -231,8 +244,7 @@
   normalize: ->
     unless @selection.isEmpty()
       if @hasProperties() and @getProperties().wise is 'linewise'
-        @selectByProperties(@getProperties())
-        @translateSelectionEndAndClip('backward', translate: false)
+        @applyColumnFromProperties()
       else
         @translateSelectionEndAndClip('backward')
     @clearProperties()
@@ -271,4 +283,13 @@
   for selection in editor.getSelections()
     swrap(selection).fixPropertiesForLinewise()

+# Return function to restore
+# Used in vmp-move-selected-text
+swrap.switchToLinewise = (editor) ->
+  swrap.saveProperties(editor)
+  swrap.applyWise(editor, 'linewise')
+  new Disposable ->
+    swrap.normalize(editor)
+    swrap.applyWise(editor, 'characterwise')
+
 module.exports = swrap


Use TextEditor::lineTextForBufferRow

Use TextEditor::lineTextForBufferRow

--- lib/snippet-expansion.coffee
+++ lib/snippet-expansion.coffee
@@ -35,7 +35,7 @@
     @setTabStopIndex(0)

   indentSubsequentLines: (startRow, snippet) ->
-    initialIndent = @editor.lineForBufferRow(startRow).match(/^\s*/)[0]
+    initialIndent = @editor.lineTextForBufferRow(startRow).match(/^\s*/)[0]
     for row in [startRow + 1...startRow + snippet.lineCount]
       @editor.buffer.insert([row, 0], initialIndent)


Improving points visualization

Improving points visualization

--- app/coffee/modules/backlog/main.coffee
+++ app/coffee/modules/backlog/main.coffee
@@ -504,7 +504,7 @@

         $scope.$on "uspoints:select", (ctx, roleId, roleName) ->
             $el.find(".popover").hide()
-            $el.find(".header-points").text(roleName)
+            $el.find(".header-points").text("#{roleName}/Total")

         $scope.$on "uspoints:clear-selection", (ctx, roleId) ->
             $el.find(".popover").hide()
@@ -582,7 +582,7 @@
             else
                 pointId = us.points[roleId]
                 points = $scope.pointsById[pointId]
-                pointsDom.text("#{points.name}/#{us.total_points}")
+                pointsDom.text("#{points.name} / #{us.total_points}")

         calculateTotalPoints = ->
             values = _.map(us.points, (v, k) -> $scope.pointsById[v].value)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -1,3 +1,36 @@
+###*
+The Bounded module is used to provide basic data about the
+location and dimensions of the including object. This module is included
+by default in GameObject.
+
+

+player = Core
+  x: 10
+  y: 50
+  width: 20
+  height: 20
+  other: "stuff"
+  more: "properties"
+
+player.position()
+# => Uncaught TypeError: Object has no method 'position'
+
+player.include(Bounded)
+
+# now player has all the methods provided by this module
+player.position()
+# => {x: 10, y: 50}
+

+
+@see GameObject
+
+Bounded module
+@name Bounded
+@module
+@constructor
+@param {Object} I Instance variables
+@param {Core} self Reference to including object
+###
 TimedEvents = (I={}) ->
   every: (n, fn) ->
     if I.age.mod(n) is 0


levels and default game states

levels and default game states

--- src/title_screen.coffee
+++ src/title_screen.coffee
@@ -5,6 +5,6 @@
     engine.nextLevel() if justPressed.any

   self.bind "overlay", (canvas) ->
-    self. canvas, window.title, "Press any key to start"
+    self.centerText canvas, window.title, "Press any key to start"

   return self


Add a function to unmount component after specs

--- test/components/helpers/component-testing.coffee
+++ test/components/helpers/component-testing.coffee
@@ -11,6 +11,8 @@
 ROUTER = null
 RENDERED = []

+{TransitionAssistant} = require '../../../src/components/unsaved-state-mixin'
+
 # Mock a router for the context
 beforeEach ->
   RENDERED = []
@@ -19,9 +21,6 @@
   ROUTER.transitionTo = sandbox.spy()

 afterEach ->
-  for comp in RENDERED
-    dom = React.findDOMNode(comp)
-    React.unmountComponentAtNode(dom) if dom
   sandbox.restore()

 # A wrapper component to setup the router context
@@ -39,16 +38,20 @@

   renderComponent: (component, options) ->
     options.props ||= {}
-    new Promise (resolve, reject) ->
+    div = document.createElement('div')
+    promise = new Promise( (resolve, reject) ->
       props = _.clone(options.props)
       props._wrapped_component = component
-      wrapper = ReactTestUtils.renderIntoDocument React.createElement(Wrapper, props)
-      RENDERED.push(wrapper)
+      wrapper = React.render( React.createElement(Wrapper, props), div )
       resolve(
         wrapper,
         element: wrapper.refs.element,
         dom: React.findDOMNode(wrapper.refs.element)
       )
+    )
+    # defer adding the then callback so it'll be called after whatever is attached after the return
+    _.defer -> promise.then -> React.unmountComponentAtNode(div)
+    promise

   actions: commonActions


Expressify: comments about queue observer for requests

--- node_modules_koding/bongo/lib/expressify.coffee
+++ node_modules_koding/bongo/lib/expressify.coffee
@@ -73,6 +73,19 @@
       responses[i] = {
         arguments : [{ message: 'Timed out' }]
         callbacks : {}
+        # In the working queue req.callbacks is an object
+        # uses callbackId's as key and currently we only
+        # support one callback per req. with following
+        # we're putting this callbackId as returned method
+        # name. this can be explained like in following example; ~GG
+        #
+        #   callbacks = { "12": Object }
+        #   keys = Object.keys callbacks
+        #   key = keys[0]
+        #   method = +key # which makes it number. equals to Number(key)
+        #
+        #   method will be 12
+        #
         method    : +(Object.keys message.callbacks)[0]
       }

@@ -89,6 +102,13 @@
     observeQueue queueId, calls, responses, callback

     async.parallel workQueue, ->
+      # If a given queue couldn't completed all items in it in 7sec.
+      # it will be returned with already completed results by
+      # observeQueue helper and it will be removed from OBSERVER_QUEUE
+      # In this case if somehow requests in the queue completes the process
+      # and hits async.parallel callback this will cause multiple responses
+      # from here. To prevent we're checking it out it's status in the queue
+      # here. Same case is valid and handled in observeQueue helper as well ~GG
       callback responses  if OBSERVE_QUEUE[queueId]
       OBSERVE_QUEUE[queueId] = null


abstract module name

abstract module name

--- src/virustotal.coffee
+++ src/virustotal.coffee
@@ -19,6 +19,7 @@
 moment = require 'moment'
 virustotal = require 'virustotal.js'

+modulename = 'Virus total'
 maxRequestsPerInterval = 4
 requestWindowMs = 60 * 1000
 defaultwaitms = 1000
@@ -29,7 +30,8 @@
 queueUrlReport = (robot, msg, url) ->
   ms = Date.now()
   if sq.length >= maxRequestsPerInterval
-    msgout = "Max requests per interval (#{maxRequestsPerInterval}) reached. Your request will be serviced as soon as possible.  Window + Queue: #{sq.length}."
+    msgout = "#{modulename}: api max requests per interval reached. Your request will be serviced as soon as possible.  Window `#{sq.length}`."
+    robot.logger.info "#{msgout} [#{msg.envelope.user.name}]"
     robot.send {room: msg.envelope.user.name}, msgout
   sq.push { whenqueued: ms, sent: false, robot: robot, msg: msg, url: url }
   # robot.logger.debug "sq: { whenqueued: #{ms}, url: #{url} }"
@@ -68,7 +70,7 @@
   # robot.logger.info "sq: sending virustotal request for #{url}"
   virustotal.getUrlReport url, (err, res) ->
     if err
-      msgout = "Virus total: error: `#{err.json.verbose_msg}`."
+      msgout = "#{modulename}: error: `#{err.json.verbose_msg}`."
       robot.logger.info "#{msgout} [#{msg.envelope.user.name}]"
       return robot.send {room: msg.envelope.user.name}, msgout

@@ -77,7 +79,7 @@
       r.clean++ unless obj.detected
       r.unclean++ if obj.detected

-    msgout = "Virus total: `#{res.resource.replace('http:\/\/','')}` rated clean by #{r.clean}, unclean by #{r.unclean}.  More info: #{res.permalink}"
+    msgout = "#{modulename}: `#{res.resource.replace('http:\/\/','')}` rated clean by #{r.clean}, unclean by #{r.unclean}.  More info: #{res.permalink}"
     robot.logger.info "#{msgout} [#{msg.envelope.user.name}]"
     return robot.send {room: msg.envelope.user.name}, msgout

@@ -85,7 +87,7 @@
 module.exports = (robot) ->

   unless process.env.HUBOT_VIRUSTOTAL_API?
-    robot.logger.warning 'The HUBOT_VIRUSTOTAL_API environment variable not set'
+    robot.logger.warning "#{modulename}: environment variable HUBOT_VIRUSTOTAL_API not set."
   else
     virustotal.setKey(process.env.HUBOT_VIRUSTOTAL_API)

@@ -106,6 +108,6 @@
   robot.respond /virustotal url (.+)$/i, (msg) ->
     url = msg.match[1]

-    robot.logger.info "Virus total: url report request: #{url} [#{msg.envelope.user.name}]"
+    robot.logger.info "#{modulename}: url report request: #{url} [#{msg.envelope.user.name}]"

     return queueUrlReport robot, msg, url


Fix pronoun ambiguity

Fix pronoun ambiguity

--- src/http_server.coffee
+++ src/http_server.coffee
@@ -117,7 +117,7 @@
       next()

   # If the request object is annotated with an application, pass the
-  # request off to its `handle` method.
+  # request off to the application's `handle` method.
   handleApplicationRequest: (req, res, next) =>
     if application = req.pow?.application
       application.handle req, res, next, req.pow.resume


updated msa url

updated msa url

Former-commit-id: 0db48fcedc5d606653b2c449813d211a0b118296 [formerly 970e22cb28d8a98ca61bb6ee48ed94c24ab8f1a9]
Former-commit-id: 1c96add53ae8f56635aac319058314e22f05928e

--- src/utils/export.coffee
+++ src/utils/export.coffee
@@ -39,7 +39,7 @@

   shareLink: (that, cb) ->
     url = that.g.config.get "importURL"
-    msaURL = "http://biojs-msa.org/app/?seq="
+    msaURL = "http://msa.biojs.net/app/?seq="
     fCB = (link) ->
       fURL = msaURL + link
       if cb


Fix the dependent app test randomly failing b/c of public apps

Change-type: patch
Signed-off-by: Thodoris Greasidis <5791bdc4541e79bd43d586e3c3eff1e39c16665f@balena.io>

--- tests/integration/models/application.spec.coffee
+++ tests/integration/models/application.spec.coffee
@@ -76,6 +76,7 @@
 					balena.pine.get
 						resource: 'application'
 						options:
+							$filter: is_public: false
 							$orderby: id: 'asc'
 				.then ([ parentApplication, childApplication ]) ->
 					m.chai.expect(childApplication.depends_on__application.__id).to.equal(parentApplication.id)


Refactoring ofnSelect2, works with multiple, and with promised data

--- app/assets/javascripts/admin/index_utils/directives/ofn-select2.js.coffee
+++ app/assets/javascripts/admin/index_utils/directives/ofn-select2.js.coffee
@@ -3,21 +3,42 @@
   restrict: 'C'
   scope:
     data: "="
-    minSearch: "@?"
-    text: "@?"
+    minSearch: "@"
+    text: "@"
     blank: "=?"
     filter: "=?"
     onSelecting: "=?"
+    multiple: '@'
   link: (scope, element, attrs, ngModel) ->
     $timeout ->
-      scope.text ||= 'name'
-      scope.filter ||= -> true
+      scope.text ?= 'name'
+      scope.multiple ?= false
+      scope.filter ?= -> true

+      if scope.data.$promise
+        scope.data.$promise.then -> init()
+      else
+        init()
+
+    element.on "select2-opening", scope.onSelecting || angular.noop
+
+    attrs.$observe 'disabled', (value) ->
+      element.select2('enable', !value)
+
+    ngModel.$formatters.push (value) ->
+      element.select2('val', value)
+      value
+
+    ngModel.$parsers.push (value) ->
+      return value.split(",") if scope.multiple
+      value
+
+    init = ->
       scope.data.unshift(scope.blank) if scope.blank? && typeof scope.blank is "object"
-

       item.name = $sanitize(item.name) for item in scope.data
       element.select2
+        multiple: scope.multiple
         minimumResultsForSearch: scope.minSearch || 0
         data: ->
           filtered = $filter('filter')(scope.data,scope.filter)
@@ -26,12 +47,3 @@
           item[scope.text]
         formatResult: (item) ->
           item[scope.text]
-
-      element.on "select2-opening", scope.onSelecting || angular.noop
-
-    attrs.$observe 'disabled', (value) ->
-      element.select2('enable', !value)
-
-    ngModel.$formatters.push (value) ->
-      element.select2('val', value)
-      value


Revert "Fixed issue #986 - Zammad sends reply to itself."

This reverts commit 084ef3f50dd31b6898ef08097b9d6c35ae4e5bb1.

--- app/assets/javascripts/app/controllers/ticket_zoom/article_actions.coffee
+++ app/assets/javascripts/app/controllers/ticket_zoom/article_actions.coffee
@@ -336,7 +336,8 @@
           articleNew.to = ticket.customer.email

       else
-        if article.sender.name is 'Agent'
+        user = App.User.find(article.created_by_id)
+        if article.sender.name is 'Agent' && !article.from.match(user.email)
           articleNew.to = article.to
         else
           if article.reply_to


removing console.log

removing console.log

--- shared/fetcher.coffee
+++ shared/fetcher.coffee
@@ -120,10 +120,6 @@
 getResponseFromStore = (spec, callback) ->
   key = getResponseStoreKey(spec)
   value = responseStore.get key
-  if value?
-    console.log "FETCHER: Cache HIT for key: \"#{key}\"."
-  else
-    console.log "FETCHER: Cache MISS for key: \"#{key}\"."
   callback(null, value)

 storeResponse = (results, fetchSpecs) ->


hide the vocabulary tab for now

hide the vocabulary tab for now

--- client/landing/app/Applications/Groups.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Groups.kdapplication/AppController.coffee
@@ -706,7 +706,7 @@
     @prepareSettingsTab()
     @preparePermissionsTab()
     @prepareMembersTab()
-    @prepareVocabularyTab()
+#    @prepareVocabularyTab()

     if 'private' is group.privacy
       @prepareMembershipPolicyTab()


Add Saturday and Sunday to days array.

Add Saturday and Sunday to days array.

Prevents crash that occurs from trying to access a day object that
doesn't exist.

--- routes/room.coffee
+++ routes/room.coffee
@@ -34,6 +34,18 @@
       dayName: "Friday"
       classes: []
       regex: /F/
+    },
+    "S": {
+      dayOfWeek: 6
+      dayName: "Saturday"
+      classes: []
+      regex: /Saturday/ # should never happen
+    },
+    "Su": {
+      dayOfWeek: 7
+      dayName: "Sunday"
+      classes: []
+      regex: /Sunday/ # should never happen
     }
   }


add test for the issue

add test for the issue

--- spec/operators-spec.coffee
+++ spec/operators-spec.coffee
@@ -917,6 +917,15 @@
         it "inserts the contents", ->
           expect(editor.getText()).toBe "034512\n"
           expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+
+      describe "at the end of a line", ->
+        beforeEach ->
+          editor.setCursorScreenPosition [0, 2]
+          keydown('p')
+
+        it "positions cursor correctly", ->
+          expect(editor.getText()).toBe "012345\n"
+          expect(editor.getCursorScreenPosition()).toEqual [0, 5]

       describe "when useClipboardAsDefaultRegister enabled", ->
         it "inserts contents from clipboard", ->


fix failing test

fix failing test

--- apps/fair_info/test/routes.coffee
+++ apps/fair_info/test/routes.coffee
@@ -1,11 +1,14 @@
 routes = require '../routes'
+Backbone = require 'backbone'
 sinon = require 'sinon'
 { fabricate } = require 'antigravity'
 Profile = require '../../../models/profile'
+Fair = require '../../../models/fair'

 describe 'FairInfo routes', ->
   beforeEach ->
+    sinon.stub Backbone, 'sync'
     @req = {
       params: {
         id: "artissma-2014"
@@ -15,11 +18,16 @@
     @res = {
       locals: {
         profile: new Profile fabricate 'profile', owner: fabricate 'fair'
+        fair: new Fair fabricate 'fair'
       }
     }

     @next = sinon.stub()

+
+  afterEach ->
+    Backbone.sync.restore()
+
   describe '#assignFair', ->
     it 'assigns a fair model to locals', ->
       routes.assignFair(@req, @res, @next)


Creates WatchedApp.List model

Creates WatchedApp.List model

--- app/assets/javascripts/backbone/apps/watched/list/list_model.js.coffee
+++ app/assets/javascripts/backbone/apps/watched/list/list_model.js.coffee
@@ -0,0 +1,7 @@
+@VideoTracker.module "WatchedApp.List", (List, App, Backbone, Marionette, $, _) ->
+
+  class List.WatchedMovie extends Backbone.Model
+
+
+  class List.WatchedMovies extends Backbone.Collection
+    model: List.WatchedMovie


#413 Set direction according to last two centroids

--- app/assets/javascripts/oxalis/model/volumetracing/volumetracing.coffee
+++ app/assets/javascripts/oxalis/model/volumetracing/volumetracing.coffee
@@ -18,6 +18,7 @@
     @activeCell   = null
     @currentLayer = null        # Layer currently edited
     @idCount      = @contentData.nextCell || 1
+    @lastCentroid = null

     @stateLogger  = new VolumeTracingStateLogger(
       @flycam, tracing.version, tracing.id, tracing.typ,
@@ -67,6 +68,7 @@
     @currentLayer.addContour(pos)
     @trigger("updateLayer", @currentLayer.getSmoothedContourList())

+
   finishLayer : ->

     unless @currentLayer?
@@ -79,9 +81,21 @@
     @binary.cube.labelVoxels(iterator, labelValue)
     console.log "Labeling time:", ((new Date()).getTime() - start)

+    @updateDirection(@currentLayer.getCentroid())
     @currentLayer = null

     @trigger "volumeAnnotated"
+
+
+  updateDirection : (centroid) ->
+    console.log @lastCentroid, centroid
+    if @lastCentroid?
+      @flycam.setDirection([
+        centroid[0] - @lastCentroid[0]
+        centroid[1] - @lastCentroid[1]
+        centroid[2] - @lastCentroid[2]
+      ])
+    @lastCentroid = centroid

   getActiveCellId : ->


uploadimageview : blocking modal.

uploadimageview : blocking modal.

--- client/Main/CommonViews/uploadimagemodalview.coffee
+++ client/Main/CommonViews/uploadimagemodalview.coffee
@@ -5,6 +5,7 @@
     options.uploaderTitle ?= "Drag & drop image here!"
     options.overlay       ?= yes
     options.preview       ?= options.image
+    options.overlayClick  ?= no
     options.buttons       ?=
       uploadButton     :
         title          : "Upload"


Use proper grammar.

Use proper grammar.

--- client/landing/app/MainApp/paymentcontroller.coffee
+++ client/landing/app/MainApp/paymentcontroller.coffee
@@ -329,7 +329,7 @@
         content += "
You have $#{formatMoney balance} credited to your account.
"

       if chargeAmount > 0
-        content += "
You will be charged for $#{formatMoney chargeAmount}.
"
+        content += "
You will be charged $#{formatMoney chargeAmount}.
"
       else
         content += "
You won't be charged for this VM.
"


Wait for termination to complete before removing frame.

- Show errors if any.
- Close frame on second close attempt if errors.

--- community/browser/app/scripts/services/Frame.coffee
+++ community/browser/app/scripts/services/Frame.coffee
@@ -62,6 +62,7 @@
             @hasErrors = no
             @isLoading = yes
             @isTerminating = no
+            @closeAttempts = 0
             @response  = null
             @templateUrl = intr.templateUrl
             timer = Timer.start()
@@ -69,10 +70,21 @@
             intrPromise = intrFn(query, $q.defer())
             @terminate = =>
               @resetError()
+              q = $q.defer()
+              if not intrPromise or not intrPromise.transaction
+                q.resolve({})
+                return q.promise
               @isTerminating = yes
-              intrPromise?.transaction?.rollback()?.then( =>
-                @isTerminating = no
+              intrPromise.transaction.rollback().then(
+                (r) =>
+                  @isTerminating = no
+                  q.resolve r
+                ,
+                (r) =>
+                  @isTerminating = no
+                  q.reject r
               )
+              return q.promise

             $q.when(intrPromise).then(
               (result) =>
@@ -140,8 +152,16 @@
             frame or rv

           close: (frame) ->
-            @remove(frame)
-            frame.terminate()
+            pr = frame.terminate()
+            pr.then(
+              =>
+                @remove frame
+              ,
+              (r) =>
+                return @remove frame unless frame.closeAttempts < 1
+                frame.setError r
+                frame.closeAttempts++
+            )

           createOne: (data = {}) ->
             last = @last()


dont delay first call for update

dont delay first call for update

--- desktop/apps/artwork/components/auction/view.coffee
+++ desktop/apps/artwork/components/auction/view.coffee
@@ -26,7 +26,7 @@
     'change .js-artwork-auction-max-bid': 'setMaxBid'

   initialize: ({ @data }) -> #
-    @delayedUpdateBidLabel LOT_STANDING_MAX_POLLS
+    @updateBidLabel LOT_STANDING_MAX_POLLS

   openBuyersPremium: (e) ->
     e.preventDefault()


added "basic" support for inserting symbols into existing import statements

--- lib/typescript-import.coffee
+++ lib/typescript-import.coffee
@@ -54,28 +54,57 @@
       atom.commands.dispatch(document.querySelector('atom-text-editor'), 'typescript:go-to-declaration')

-  addImportStatement: (importStatement) ->
+  addImportStatement: (importedSymbol, relativePath, isDefaultImport) ->
       editor = atom.workspace.getActiveTextEditor()
       currentText = editor.getText()

-      if currentText.indexOf(importStatement)>=0
-        atom.notifications.addWarning('Import already defined.');
+      reImports = /import(.|\r|\n)+?from(.*)$/gm;
+      isDefined = false
+      hasImportStatements = false;
+      lastMatchIndex = 0
+      while(!isDefined && importMatch = reImports.exec(currentText))
+        if !@isInComment(importMatch.index, lastMatchIndex, currentText)
+          lastMatchIndex = importMatch.index
+          hasImportStatements = true
+          #TODO check for comments using lastImport
+          lastImport = importMatch[0]
+          if @containsSymbol(importMatch, importedSymbol)
+            isDefined = true
+          #TODO handle insertion of default imports (currently: create a new import statement if default import)
+          else if !isDefaultImport && @isImportFromFile(importMatch, relativePath)
+            newStatement = @insertIntoStatement(importMatch, importedSymbol, isDefaultImport)
+            existingImportStatement = {match: importMatch, statement: newStatement}
+        else
+            lastMatchIndex = importMatch.index
+
+      if isDefined
+        atom.notifications.addWarning('Import '+importedSymbol+' is already defined.');
       else
         currentPosition = editor.getCursorBufferPosition()
-        importMatches = currentText.match(/import\s*(\{\s*)?\w*\s*(\}\s*)?from.*\n/g)
-        referencesMatches= currentText.match(/\/\/\/\s*<reference\s*path.*\/>\n/g)
-        useStrictMatche = currentText.match(/.*[\'\"]use strict[\'\"].*/)
-        if importMatches
-          lastImport = importMatches.pop();
-          currentText = currentText.replace(lastImport, lastImport + importStatement);
-        else if referencesMatches
-          lastReference = referencesMatches.pop();
-          currentText = currentText.replace(lastReference, lastReference + '\n' + importStatement);
-        else if useStrictMatche
-          useStrict = useStrictMatche.pop();
-          currentText = currentText.replace(useStrict, useStrict + '\n' + importStatement);
-        else
-          currentText = importStatement + currentText;
+        if hasImportStatements
+          if existingImportStatement
+            newStatement = existingImportStatement.statement
+            importMatch = existingImportStatement.match
+            prefixEnd = importMatch.index
+            suffixStart = prefixEnd + importMatch[0].length
+            currentText = currentText.substring(0, prefixEnd) + newStatement + currentText.substring(suffixStart)
+          else
+            importStatement = @createNewImportStatement(importedSymbol, relativePath, isDefaultImport)
+            currentText = currentText.replace(lastImport, lastImport + importStatement);
+        else
+          importStatement = @createNewImportStatement(importedSymbol, relativePath, isDefaultImport)
+          referencesMatches= currentText.match(/\/\/\/\s*<reference\s*path.*\/>\s*$/gm)
+          nl = @getNewLineChar()
+          if referencesMatches
+            lastReference = referencesMatches.pop();
+            currentText = currentText.replace(lastReference, lastReference + importStatement + nl);
+          else
+            useStrictMatche = currentText.match(/.*[\'\"]use strict[\'\"].*/)
+            if useStrictMatche
+              useStrict = useStrictMatche.pop();
+              currentText = currentText.replace(useStrict, useStrict + importStatement + nl);
+            else
+              currentText = importStatement + currentText;
         editor.setText(currentText);
         currentPosition.row++;
         editor.setCursorBufferPosition(currentPosition)
@@ -104,14 +133,125 @@
         if(!/^\./.test(relative))
           relative = './' + relative;

-        if(defaultImport)
-          importClause = "import #{selection} from '#{relative}';\n"
-        else
-          importClause = "import {#{selection}} from '#{relative}';\n"
-        @addImportStatement(importClause)
-#        editor.insertText(selection + "\nimport #{selection} from './#{relative}'")
+        @addImportStatement(selection, relative, defaultImport)
       else
         atom.notifications.addError('Symbol '+selection+' not found.');
+
+  createNewImportStatement: (importedSymbol, relativePath, isDefaultImport) ->
+    nl = @getNewLineChar()
+
+    if(isDefaultImport)
+      importStatement = "#{nl}import #{importedSymbol} from '#{relativePath}';"
+    else
+      importStatement = "#{nl}import { #{importedSymbol} } from '#{relativePath}';"
+
+
+  getNewLineChar: ->
+    switch atom.config.get('line-ending-selector.defaultLineEnding')
+      when 'CRLF' then return '\r\n'
+      when 'LF' then return '\n'
+      # when 'OS Default' then
+      else
+        os = require('os')
+        if os.platform() == 'win32'
+          return '\r\n'
+        else
+          return '\n'
+
+
+  isInComment: (startIndex, previousIndex, text) ->
+    if @isInMultiLineComment(startIndex, previousIndex, text)
+      return true
+    else
+      return @isInLineComment(startIndex, previousIndex, text)
+
+  isInLineComment: (startIndex, previousIndex, text) ->
+    reLineComment = /\/\//g
+    reLineComment.lastIndex = previousIndex
+
+    #find last line-comment before startIndex
+    while (match = reLineComment.exec(text)) && match.index < startIndex
+      lastComment = match
+
+    #check if last line-comment is in same line as startIndex
+    if lastComment
+      reNewLine = /\r|\n/g
+      reNewLine.lastIndex = lastComment.index
+      if match = reNewLine.exec(text)
+        #if match.index > startIndex#DEGUB
+        #  console.warn('import is within line-comment')
+        return match.index > startIndex # if the next NL comes after the import statement -> import statement is within the line-comment
+
+    return false
+
+  isInMultiLineComment: (startIndex, previousIndex, text) ->
+    reComment = /\/\*\*?/g
+    reClosing = /\*\//
+    reComment.lastIndex = previousIndex
+    isOpen = false
+    #check if last multi-line comment is open for startIndex
+    while (commentMatch = reComment.exec(text)) && commentMatch.index < startIndex
+      reClosing.lastIndex = commentMatch.index
+      if closingMatch = reClosing.exec() && closingMatch.index < startIndex
+        isOpen = false
+      else
+        isOpen = true
+
+    #if isOpen#DEBUG
+    #  console.warn('import in within multi-line-comment')
+
+    return isOpen
+
+  isImportFromFile: (regexImportStatement, symbolPath) ->
+      importPathRaw = regexImportStatement[2]#regarding index-access [2]: see RegExp definition for matchImports in addImportStatement()
+      importPathMatch = /'([^']+)'|"([^"]+)"/gm.exec(importPathRaw);
+      if importPathMatch
+        if importPathMatch[1]
+          importPath = importPathMatch[1]
+        else
+          importPath = importPathMatch[2]
+      if !importPath
+        console.log('could not extract file path from import statement', regexImportStatement)
+        return false
+      start = 0
+      end = importPath.length
+      if /^\.\/\.\./.test(importPath)
+        start = 2
+      #TODO normalize paths properly
+      importPath = importPath.substring(start, end)
+      return (importPath == symbolPath)
+
+  extractSymbolStringFrom: (regexImportStatement) ->
+    importStatement = regexImportStatement[0];
+    if /\{/gm.test(importStatement)
+      strSymbols = /.*\{([^}]+)\}/g.exec(importStatement)
+    else
+      strSymbols = /.*?import((.|\r|\n)+?)from/g.exec(importStatement)
+
+  containsSymbol: (regexImportStatement, newSymbol) ->
+    symbolStrList = @extractSymbolStringFrom(regexImportStatement)
+    reTest = new RegExp('\\s*' + newSymbol + '\\s*(,|$)', 'gm')
+    i = 0
+    size = symbolStrList.length
+    while i < size
+      if reTest.test(symbolStrList[i])
+        return true
+      ++i
+    return false
+
+  insertIntoStatement: (regexImportStatement, newSymbol, isDefaultImport) ->
+    #TODO handle default import?: "import {...} form ..." -> "import newSymbol, {...} form ..."
+    importStatement = regexImportStatement[0];
+    sb = [', ', newSymbol, ' '];
+    if /\{/gm.test(importStatement)
+      insertIndex = importStatement.lastIndexOf('}');
+    else
+      insertIndex = /from(.*)$/gm.exec(importStatement).index;#ASSERT there is at least on match, due to RegExp definition in addImportStatement()
+      sb[0] = '{ '
+      sb.push('}')
+    sb.unshift(importStatement.substring(0, insertIndex))
+    sb.push(importStatement.substring(insertIndex, importStatement.length))
+    return sb.join('')

   buildIndex: ->
     index = @index;


Fix the logging in the watch

Fix the logging in the watch

--- library/gearing/watch.coffee
+++ library/gearing/watch.coffee
@@ -181,8 +181,9 @@
         notExists = "Dir %s does not exist, not watching"
         exists = fs.existsSync directory.toString()
         throw new Error(notString) unless _.isString directory
-        logger.warn notExists.grey, directory unless exists
         relative = paths.relative process.cwd(), directory
+        formats = [notExists.grey, relative.underline]
+        return logger.warn formats... unless exists
         watching = "Watching %s directory for modules"
         logger.info watching.blue, relative.underline
         watcher = chokidar.watch directory.toString()


Implement directory tracking in the watcher

--- library/nucleus/watch.coffee
+++ library/nucleus/watch.coffee
@@ -175,6 +175,22 @@
         services = _.filter services, isFinal
         _.unique services

+    # Directory tracking routine keeps inventory of all directories
+    # that have been added to the watcher. Besides that it is called
+    # upon an addition of a new directory to ensure that the directory
+    # does not intersect with any directories that already present.
+    directoryTracking: (directory) ->
+        tracked = @tracked ?= []
+        pattern = /^(?:\.{2}\/?)+$/
+        resolved = paths.resolve directory
+        return undefined if resolved in tracked
+        relA = (p) -> paths.relative(p, resolved)
+        relB = (p) -> paths.relative(resolved, p)
+        matches = (f) -> (p) -> pattern.test f(p)
+        return no if _.any tracked, matches(relA)
+        return no if _.any tracked, matches(relB)
+        tracked.push resolved.toString()
+
     # Watch the specified directory for addition and changing of
     # the files, looking for modules with services there and then
     # loading them and reloading and doing all other routines for
@@ -186,6 +202,7 @@
         exists = fs.existsSync directory.toString()
         relative = paths.relative process.cwd(), directory
         formats = [notExists.grey, relative.underline]
+        return unless @directoryTracking directory
         return logger.warn formats... unless exists
         watching = "Watching %s directory for modules"
         logger.info watching.blue, relative.underline


Docs: minor

Docs: minor

--- docs/src/views/contentview.coffee
+++ docs/src/views/contentview.coffee
@@ -98,17 +98,17 @@

KD Framework Guidelines

-          Welcome to the Ember.js guides! This documentation will take you from
-          total beginner to Ember expert. It is designed to start from the basics,
+          Welcome to the KD guides! This documentation will take you from
+          total beginner to KD expert. It is designed to start from the basics,
           and slowly increase to more sophisticated concepts until you know
           everything there is to know about building awesome web applications.

           To help you get started, we've also made a 30-minute screencast that
-          will guide you through building a full-featured Ember.js
-          application:Welcome to the Ember.js guides! This documentation will
-          take you from total beginner to Ember expert. It is designed to start
+          will guide you through building a full-featured KD
+          application:Welcome to the KD guides! This documentation will
+          take you from total beginner to KD expert. It is designed to start
           from the basics, and slowly increase to more sophisticated concepts
           until you know everything there is to know about building awesome web
           applications.
@@ -123,8 +123,8 @@

So how should I, how could I. Would I?

-          Welcome to the Ember.js guides! This documentation will take you from
-          total beginner to Ember expert. It is designed to start from the
+          Welcome to the KD guides! This documentation will take you from
+          total beginner to KD expert. It is designed to start from the
           basics, and slowly increase to applications.

@@ -134,8 +134,8 @@

So how should I, how could I. Would I?

-          Welcome to the Ember.js guides! This documentation will take you from
-          total beginner to Ember expert. It is designed to start from the
+          Welcome to the KD guides! This documentation will take you from
+          total beginner to KD expert. It is designed to start from the
           basics, and slowly increase to applications.


Unnecessary fat arrow

Unnecessary fat arrow

--- src/lib/Network.coffee
+++ src/lib/Network.coffee
@@ -385,7 +385,7 @@
       @bufferedEmit 'process-error', event
     return unless source?.component?.isLegacy()
     # Handle activation for legacy components via connects/disconnects
-    socket.on 'connect', =>
+    socket.on 'connect', ->
       source.component.__openConnections = 0 unless source.component.__openConnections
       source.component.__openConnections++
     socket.on 'disconnect', =>


Removed obsolete App class

Removed obsolete App class

--- src/modules/App.coffee
+++ src/modules/App.coffee
@@ -1,119 +0,0 @@
-###
-Copyright 2015 Jan Svager & Michael Muller
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-###
-
-THREE = require("three")
-Stats = require("stats-js")
-Controls = require("./Controls")
-Objects = require("./Objects")
-helpers = require("./helpers")
-
-class App
-
-  # Main DOM container for canvas
-  container: document.getElementById("app")
-
-  # Window width & height
-  width: -> window.innerWidth
-  height: -> window.innerHeight
-
-  # Window aspect ratio
-  aspect: -> @width() / @height()
-
-  # FPS debugging
-  stats: new Stats
-
-  loading: true
-
-  constructor: (opts)->
-    @scene = new THREE.Scene
-    @camera = new THREE.PerspectiveCamera 45, @aspect(), 1, 10000
-    @renderer = new THREE.WebGLRenderer
-      devicePixelRatio: opts.pixelRatio
-      antialias: opts.antialias
-
-  ### Handle window resizing ###
-  handleWindowResize: =>
-    @camera.aspect = @aspect()
-    @camera.updateProjectionMatrix()
-    @renderer.setSize(@width(), @height())
-
-  ### Init all stuff here before rendering ###
-  init: =>
-    # Init events
-    window.addEventListener('resize', @handleWindowResize)
-
-    # Init renderer
-    @renderer.setSize(@width(), @height())
-    @renderer.setClearColor(0xFFFFFF)
-    @renderer.shadowMapEnabled = true
-    @container.appendChild(@renderer.domElement)
-
-    # Init stats
-    @stats.domElement.style.position = 'absolute'
-    @stats.domElement.style.top = '0px'
-    @container.appendChild(@stats.domElement)
-
-    # Init controls & camera
-    @controls = new Controls(@camera)
-    @controlsCamera = @controls.getCamera()
-
-    # Init scene objects
-    @redCube = new Objects.ColorCube(10, 10, 10, "red")
-    @greenCube = new Objects.ColorCube(10, 10, 10, "green")
-
-    @skyBox = new Objects.SkyBox 8000, 8000, 8000, [
-      'front.jpg', 'back.jpg', 'up.jpg', 'down.jpg', 'right.jpg', 'left.jpg'
-    ]
-
-    @heightMapTexture = new THREE.ImageUtils.loadTexture "textures/height_map_1.png", null, (texture) =>
-      @heightMapImage = helpers.getImageData(texture.image)
-      @loading = false
-    @heightMap = new Objects.HeightMap(@heightMapTexture)
-
-    # Init objects position
-    @redCube.position.set(10, 50, -30)
-    @greenCube.position.set(-10, 50, -30)
-    @heightMap.rotation.x -= Math.PI / 2
-
-    # Add objects to scene
-    @scene.add(@controlsCamera)
-    @scene.add(@redCube)
-    @scene.add(@greenCube)
-    @scene.add(@skyBox)
-    @scene.add(@heightMap)
-
-  ### Render single frame ###
-  render: =>
-    height = helpers.getPixel(@heightMapImage,
-      Math.round(@controlsCamera.position.x) + @heightMapImage.width / 2,
-      Math.round(@controlsCamera.position.z) + @heightMapImage.height / 2
-    ).r
-    @controls.render(height)
-    @renderer.render(@scene, @camera)
-
-  ### Animate all frames ###
-  animate: =>
-    @stats.begin()
-    @render() if not @loading
-    @stats.end();
-    requestAnimationFrame @animate
-
-  ### Run application ###
-  run: =>
-    @init()
-    @animate()
-
-module.exports = App


Typo in client comment

Typo in client comment

--- src/nack/client.coffee
+++ src/nack/client.coffee
@@ -278,7 +278,7 @@
       else if data.length > 0
         @emit 'data', data

-      # Empty string mean EOF
+      # Empty string means EOF
       else
         @emit 'end'


console.debug: logs via console.log iff the global DEBUG flag is true; DEBUG defaults to true when run in the browser

--- salvus/misc.coffee
+++ salvus/misc.coffee
@@ -18,9 +18,6 @@
 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 ###############################################################################
-
-DEBUG = true
-

 ##########################################################################
 #
@@ -52,6 +49,20 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ###############################################################################
+
+
+# global flag RUNNING_IN_NODE: true when running in node, false in the browser
+global.RUNNING_IN_NODE = typeof process is 'object' and process + '' is '[object process]'
+
+# Set DEBUG to false when run in node, but true when in the browser
+# prefix `global.` to set it globally, which is `window` in the browser client.
+# Access it via `global.DEBUG` or just `DEBUG` (which looks it up).
+global.DEBUG = not global.RUNNING_IN_NODE
+
+# console.debug only logs if DEBUG is true
+global.console.debug = (msg) ->
+    if global.DEBUG
+        console.log(msg)

 # startswith(s, x) is true if s starts with the string x or any of the strings in x.
@@ -147,7 +158,7 @@
     error  = () ->
         try
             s = "(obj1=#{exports.trunc(exports.to_json(obj1),1024)}, obj2=#{exports.trunc(exports.to_json(obj2),1024)})"
-            console.log(s)
+            console.debug(s)
             return s
         catch error
             return ""
@@ -155,7 +166,7 @@
         # We put explicit traces before the errors in this function,
         # since otherwise they can be very hard to debug.
         err = "misc.defaults -- TypeError: function takes inputs as an object #{error()}"
-        console.log(err)
+        console.debug(err)
         console.trace()
         if DEBUG
             throw err
@@ -166,7 +177,7 @@
         if obj1.hasOwnProperty(prop) and obj1[prop]?
             if obj2[prop] == exports.defaults.required and not obj1[prop]?
                 err = "misc.defaults -- TypeError: property '#{prop}' must be specified: #{error()}"
-                console.log(err)
+                console.debug(err)
                 console.trace()
                 if DEBUG
                     throw err
@@ -174,7 +185,7 @@
         else if obj2[prop]?  # only record not undefined properties
             if obj2[prop] == exports.defaults.required
                 err = "misc.defaults -- TypeError: property '#{prop}' must be specified: #{error()}"
-                console.log(err)
+                console.debug(err)
                 console.trace()
                 if DEBUG
                     throw err
@@ -184,7 +195,7 @@
         for prop, val of obj1
             if not obj2.hasOwnProperty(prop)
                 err = "misc.defaults -- TypeError: got an unexpected argument '#{prop}' #{error()}"
-                console.log(err)
+                console.debug(err)
                 console.trace()
                 if DEBUG
                     throw err
@@ -264,7 +275,7 @@
     try
         JSON.parse(x)
     catch err
-        console.log("from_json: error parsing #{x} (=#{exports.to_json(x)}) from JSON")
+        console.debug("from_json: error parsing #{x} (=#{exports.to_json(x)}) from JSON")
         throw err

 # convert to JSON even if there are circular references
@@ -572,7 +583,7 @@

     call: (cb, retry_delay) =>
         if @opts.logname?
-            console.log("#{@opts.logname}(... #{retry_delay})")
+            console.debug("#{@opts.logname}(... #{retry_delay})")

         if not @_cb_stack?
             @_cb_stack = []
@@ -585,7 +596,7 @@
             @attempts = 0

         if @opts.logname?
-            console.log("actually calling -- #{@opts.logname}(... #{retry_delay})")
+            console.debug("actually calling -- #{@opts.logname}(... #{retry_delay})")

         g = () =>
             if @opts.min_interval?
@@ -595,7 +606,7 @@
                 @_calling = false
                 if err
                     if @opts.verbose
-                        console.log("#{@opts.logname}: error=#{err}")
+                        console.debug("#{@opts.logname}: error=#{err}")
                     if @opts.max_tries? and @attempts >= @opts.max_tries
                         while @_cb_stack.length > 0
                             @_cb_stack.pop()(err)
@@ -707,9 +718,9 @@
     while j >= 0 and j >= s.length-n and s[j] == '\n'
         j -= 1
     # Now either j = -1 or s[j] is not a newline (and it is the first character not a newline from the right).
-    console.log(j)
+    console.debug(j)
     k = n - (s.length - (j + 1))
-    console.log(k)
+    console.debug(k)
     if k == 0
         return s
     else
@@ -757,15 +768,6 @@
         hash |= 0 # convert to 32-bit integer
         i++
     return hash
-
-
-
-
-
-
-
-
-

@@ -994,9 +996,9 @@
             @notifications[path] = a = {}
         a.timestamp = event.timestamp
         a.id = event.id
-        #console.log("process_event", event, path)
-        #console.log(event.seen_by?.indexOf(@account_id))
-        #console.log(event.read_by?.indexOf(@account_id))
+        #console.debug("process_event", event, path)
+        #console.debug(event.seen_by?.indexOf(@account_id))
+        #console.debug(event.read_by?.indexOf(@account_id))
         if event.seen_by? and event.seen_by.indexOf(@account_id) != -1
             a.seen = event.timestamp
         if event.read_by? and event.read_by.indexOf(@account_id) != -1


Removing whitespaces

Removing whitespaces

--- app/scripts/controllers/domains.coffee
+++ app/scripts/controllers/domains.coffee
@@ -19,7 +19,7 @@

   _fillDomainsDetails: (domains) =>
     @domains = domains
-
+
   _fillViolations: (mostCommonViolations) =>
     @mostFrequentViolations = mostCommonViolations.slice(0, 10)
     @leastFrequentViolations = mostCommonViolations.slice(10)


#266 - Form now saving skip logic

#266 - Form now saving skip logic

--- dkobo/koboform/static/js/xlform/model_xlform.coffee
+++ dkobo/koboform/static/js/xlform/model_xlform.coffee
@@ -332,8 +332,11 @@

   attributesArray: ()->
     arr = ([k, v] for k, v of @attributes)
-    if(@skipLogicClause)
-      arr.push(['relevant', @skipLogicClause.serialize()])
+    if(@skipLogicClause && @skipLogicClause.get('questionName'))
+      for item in arr
+        if item[0] == 'relevant'
+          item[1].set('value', @skipLogicClause.serialize())
+          break

     arr.sort (a,b)-> if a[1]._order < b[1]._order then -1 else 1
     arr


fix http path

fix http path

--- coffee/app.coffee
+++ coffee/app.coffee
@@ -106,7 +106,7 @@
                 unless $rootScope.serial then return false
                 unless $rootScope.serial.npid then return false
                 query =
-                    url: "../topojson/#{$rootScope.serial.npid}.topojson"
+                    url: "./topojson/#{$rootScope.serial.npid}.topojson"
                     method: 'GET'
                 $http(query).success (json) ->
                     $rootScope.geojson = (topojson.feature json, json.objects[$rootScope.serial.npid]) #TopoJSON -> GeoJSON


fix spec for sample

fix spec for sample

--- spec/BaconSpec.coffee
+++ spec/BaconSpec.coffee
@@ -410,8 +410,8 @@
     expectStreamEvents(
       ->
         prop = repeat(20, [1, error(), 2]).take(2).toProperty()
-        prop.sample(30).take(2)
-      [1, error(), 2])
+        prop.sample(50).take(2)
+      [error(), 1, 2])

 describe "Bacon.latestValue(property)()", ->
   it "returns current value of property", ->


Remove buffer tests since we're removing the feature

--- spec/Component.coffee
+++ spec/Component.coffee
@@ -1386,191 +1386,6 @@
         for item in sample
           sin2.post new noflo.IP 'data', item.bar
           sin1.post new noflo.IP 'data', item.foo
-
-    describe 'using buffers', ->
-      it 'should get from buffer using a name', (done) ->
-        c = new noflo.Component
-          inPorts:
-            in:
-              datatype: 'string'
-          outPorts:
-            out:
-              datatype: 'string'
-          process: (input, output) ->
-            return unless input.has 'in', (ip) -> ip.type is 'data'
-            buf = input.buffer.get 'in', (ip) -> ip.type is 'data'
-
-            chai.expect(buf[0].data).to.eql 'foo'
-            chai.expect(buf).to.eql input.ports.in.buffer
-            done()
-
-        c.inPorts.in.attach sin1
-        sin1.post new noflo.IP 'data', 'foo'
-
-      it 'should filter everything from the buffer using no name', (done) ->
-        c = new noflo.Component
-          inPorts:
-            in:
-              datatype: 'string'
-          outPorts:
-            out:
-              datatype: 'string'
-            error:
-              datatype: 'object'
-          process: (input, output) ->
-            return unless input.has 'in', (ip) -> ip.type is 'data'
-            originalBuffer = input.buffer.get()
-            input.buffer.filter (ip) -> false
-            buffer = input.buffer.get()
-
-            chai.expect(originalBuffer.length).to.eql 1
-            chai.expect(buffer).to.eql []
-            done()
-
-        c.inPorts.in.attach sin1
-        sin1.post new noflo.IP 'data', 'foo'
-
-      it 'should filter everything from the scoped buffer using no name', (done) ->
-        c = new noflo.Component
-          inPorts:
-            in:
-              datatype: 'string'
-          outPorts:
-            out:
-              datatype: 'string'
-            error:
-              datatype: 'object'
-          process: (input, output) ->
-            return unless input.has 'in', (ip) -> ip.type is 'data'
-            originalBuffer = input.buffer.get()
-            input.buffer.filter (ip) -> false
-            buffer = input.buffer.get()
-
-            chai.expect(originalBuffer.length).to.eql 1
-            chai.expect(buffer).to.eql []
-            done()
-
-        c.inPorts.in.attach sin1
-        ip = new noflo.IP 'data', 'foo'
-        ip.scope = 'eh'
-        sin1.post ip
-
-      it 'should find from the buffer using a name', (done) ->
-        c = new noflo.Component
-          inPorts:
-            in:
-              datatype: 'string'
-          outPorts:
-            out:
-              datatype: 'string'
-            error:
-              datatype: 'object'
-          process: (input, output) ->
-            return unless input.has 'in', (ip) -> ip.type is 'data'
-            bufferedData = input.buffer.find 'in', (ip) -> return if ip.data? then true else false
-
-            chai.expect(bufferedData[0].data).to.eql 'foo'
-            done()
-
-        c.inPorts.in.attach sin1
-        sin1.post new noflo.IP 'data', 'foo'
-
-      it 'should get scoped buffer using a name ', (done) ->
-        c = new noflo.Component
-          inPorts:
-            in:
-              datatype: 'string'
-          outPorts:
-            out:
-              datatype: 'string'
-          process: (input, output) ->
-            return unless input.has 'in', (ip) -> ip.type is 'data'
-            buf = input.buffer.get 'in'
-            chai.expect(buf).to.eql input.ports.in.scopedBuffer.eh
-            done()
-
-        c.inPorts.in.attach sin1
-        ip = new noflo.IP 'data', 'foo'
-        ip.scope = 'eh'
-        sin1.post ip
-
-      it 'should set a buffer using a name', (done) ->
-        c = new noflo.Component
-          inPorts:
-            in:
-              datatype: 'string'
-          outPorts:
-            out:
-              datatype: 'string'
-          process: (input, output) ->
-            return unless input.has 'in', (ip) -> ip.type is 'data'
-            input.buffer.set 'in', []
-            bufferedData = input.buffer.get 'in'
-
-            chai.expect(bufferedData).to.eql []
-            done()
-
-        c.inPorts.in.attach sin1
-        sin1.post new noflo.IP 'data', 'foo'
-
-      it 'should set a buffer without a name', (done) ->
-        c = new noflo.Component
-          inPorts:
-            in:
-              datatype: 'string'
-          outPorts:
-            out:
-              datatype: 'string'
-          process: (input, output) ->
-            return unless input.has 'in', (ip) -> ip.type is 'data'
-            input.buffer.set []
-            bufferedData = input.buffer.get()
-
-            chai.expect(bufferedData).to.eql []
-            done()
-
-        c.inPorts.in.attach sin1
-        sin1.post new noflo.IP 'data', 'foo'
-
-      it 'should set a scoped buffer using a name', (done) ->
-        c = new noflo.Component
-          inPorts:
-            in:
-              datatype: 'string'
-          outPorts:
-            out:
-              datatype: 'string'
-          process: (input, output) ->
-            return unless input.has 'in', (ip) -> ip.type is 'data'
-            input.buffer.set 'in', []
-            bufferedData = input.buffer.get 'in'
-            chai.expect(bufferedData).to.eql []
-            done()
-
-        c.inPorts.in.attach sin1
-        ip = new noflo.IP 'data', 'foo'
-        ip.scope = 'eh'
-        sin1.post ip
-
-      it 'should set a scoped buffer without a name', (done) ->
-        c = new noflo.Component
-          inPorts:
-            in:
-              datatype: 'string'
-          outPorts:
-            out:
-              datatype: 'string'
-          process: (input, output) ->
-            return unless input.has 'in', (ip) -> ip.type is 'data'
-            input.buffer.set []
-            bufferedData = input.buffer.get()
-            chai.expect(bufferedData).to.eql []
-            done()
-
-        c.inPorts.in.attach sin1
-        ip = new noflo.IP 'data', 'foo'
-        ip.scope = 'eh'
-        sin1.post ip

     describe 'using streams', ->
       it 'should not trigger without a full stream without getting the whole stream', (done) ->


enable client tests

enable client tests

--- spec/juno-spec.coffee
+++ spec/juno-spec.coffee
@@ -20,5 +20,5 @@
         deprecationWarnings: false
         precompiled: true

-  # require './client'
+  require './client'
   require './eval'


Update documentation.

Update documentation.

--- spec/preparser.coffee
+++ spec/preparser.coffee
@@ -42,7 +42,7 @@
 # @param message [String] This should be provided when a rule exists to catch
 # invalid syntax, and omitted when an error is expected to be thrown by the PEG
 # parser.
-# @param [Boolean] Whether the spec should be treated as pending.
+# @param pending [Boolean] Whether the spec should be treated as pending.
 #
 expectError = (source, message, pending) ->
   itFn = if pending then xit else it


FindBy spec passing

FindBy spec passing

--- spec/adaptorMethods/findBySpec.coffee
+++ spec/adaptorMethods/findBySpec.coffee
@@ -1,13 +1,72 @@
 findBy = require '../../src/adaptorMethods/findBy'
+create = require '../../src/adaptorMethods/create'
 Promise = require 'promise'
 _ = require 'lodash'
+redis = require 'redis'

 describe 'oomphRedisAdaptor#findBy', ->
+
+  beforeAll (done) ->
+    @redis = redis.createClient(1111, 'localhost')
+    done()
+
+  beforeEach ->
+    @parentObject =
+      className: 'TestFindByClass'
+      redis: @redis
+      create: create
+      classAttributes:
+        name:
+          dataType: 'string'
+        url:
+          dataType: 'string'
+          url: true
+          urlBaseAttribute: 'name'
+        one:
+          dataType: 'integer'
+          sortable: true
+        two:
+          dataType: 'integer'
+          sortable: true
+        three:
+          dataType: 'integer'
+          sortable: true
+        integer:
+          dataType: 'integer'
+        identifier:
+          dataType: 'string'
+          identifiable: true
+        reference:
+          dataType: 'reference'
+          referenceModelName: 'Reference'
+        manyReferences:
+          dataType: 'reference'
+          many: true
+          referenceModelName: 'Reference'
+        sortableString:
+          dataType: 'string'
+          sortable: true
+        sortableInteger:
+          dataType: 'integer'
+          sortable: true
+        searchableText:
+          dataType: 'text'
+          searchable: true
+        searchableString:
+          dataType: 'string'
+          searchable: true
+        boolean:
+          dataType: 'boolean'
+    @findBy = findBy.bind(@parentObject)
+
+  afterEach (done) ->
+    @redis.flushdb()
+    done()

-  beforeAll ->
-    parentObject =
-      classAttributes: {}
-    @findBy = findBy.bind(parentObject)
+  afterAll (done) ->
+    @redis.flushdb()
+    @redis.end()
+    done()

   it 'should return a promise', ->
     testObject = @findBy(id: 'test1')
@@ -15,7 +74,7 @@

   it "should resolve to a valid instance of the module's class when given an id", (done) ->
     testProps = { url: 'uniqueValue', one: 1, two: 2, three: 3 }
-    @create(testProps).then (createdObject) =>
+    @parentObject.create(testProps).then (createdObject) =>
       findByPromise = @findBy(id: createdObject.id)
       findByPromise.done (returnValue) ->
         expect(returnValue).toEqual createdObject
@@ -23,7 +82,7 @@

   it "should resolve to a valid instance of the module's class when given a url", (done) ->
     testProps = { url: 'uniqueValue', one: 1, two: 2, three: 3 }
-    @create(testProps).then (createdObject) =>
+    @parentObject.create(testProps).then (createdObject) =>
       findByPromise = @findBy(url: 'uniqueValue')
       findByPromise.done (returnValue) ->
         expect(returnValue).toEqual createdObject


:green_heart: Fix broken tests since change of styles for outline markers

--- spec/color-marker-element-spec.coffee
+++ spec/color-marker-element-spec.coffee
@@ -125,7 +125,7 @@

     it 'sets the drop shadow color of the region with the color css value', ->
       for region in regions
-        expect(region.style.backgroundColor).toEqual('rgb(255, 0, 0)')
+        expect(region.style.borderColor).toEqual('rgb(255, 0, 0)')

     describe 'when the marker is modified', ->
       beforeEach ->


Deactivate the root whew instead of deactivating the tree view

--- spec/extensions/tree-view-spec.coffee
+++ spec/extensions/tree-view-spec.coffee
@@ -22,8 +22,7 @@
     expect(treeView.root.directory.subscriptionCount()).toBeGreaterThan 0

   afterEach ->
-    treeView.deactivate()
-    rootView.remove()
+    rootView.deactivate()

   describe ".initialize(project)", ->
     it "renders the root of the project and its contents alphabetically with subdirectories first in a collapsed state", ->
@@ -49,7 +48,7 @@

     describe "when the project has no path", ->
       beforeEach ->
-        treeView.deactivate()
+        rootView.deactivate()

         rootView = new RootView
         rootView.activateExtension(TreeView)
@@ -73,10 +72,11 @@
         expect(oldRoot.hasParent()).toBeFalsy()

   describe "serialization", ->
-    newTreeView = null
+    [newRootView, newTreeView] = []

     afterEach ->
-      newTreeView.deactivate()
+      newRootView.deactivate()
+
   describe "when the prototypes deactivate method is called", ->
     it "calls the deactivate on tree view instance", ->
       spyOn(treeView, "deactivate").andCallThrough()
@@ -87,6 +87,8 @@
       treeView.find('.directory:contains(zed)').click()
       sampleJs.click()
       newRootView = RootView.deserialize(rootView.serialize())
+      rootView.deactivate() # Deactivates previous TreeView
+
       newRootView.activateExtension(TreeView)

       newTreeView = newRootView.find(".tree-view").view()
@@ -94,7 +96,6 @@
       expect(newTreeView).toExist()
       expect(newTreeView.selectedEntry()).toMatchSelector(".file:contains(sample.js)")
       expect(newTreeView.find(".directory:contains(zed)")).toHaveClass("expanded")
-      newRootView.remove()

     it "restores the focus state of the tree view", ->
       rootView.attachToDom()
@@ -102,13 +103,13 @@
       expect(treeView).toMatchSelector ':focus'

       newRootView = RootView.deserialize(rootView.serialize())
-      rootView.remove()
+      rootView.deactivate() # Deactivates previous TreeView
+
       newRootView.attachToDom()
       newRootView.activateExtension(TreeView)

       newTreeView = newRootView.find(".tree-view").view()
       expect(newTreeView).toMatchSelector ':focus'
-      newRootView.remove()

   describe "when tree-view:toggle is triggered on the root view", ->
     beforeEach ->
@@ -440,7 +441,7 @@
     [dirView, fileView, rootDirPath, dirPath, filePath] = []

     beforeEach ->
-      treeView.deactivate()
+      rootView.deactivate()

       rootDirPath = "/tmp/atom-tests"
       fs.remove(rootDirPath) if fs.exists(rootDirPath)
@@ -453,8 +454,8 @@

       rootView = new RootView(rootDirPath)
       project = rootView.project
-      treeView = new TreeView(rootView)
-      treeView.root = treeView.root
+      rootView.activateExtension(TreeView)
+      treeView = rootView.find(".tree-view").view()
       dirView = treeView.root.entries.find('.directory:contains(test-dir)').view()
       dirView.expand()
       fileView = treeView.find('.file:contains(test-file.txt)').view()
@@ -598,15 +599,14 @@
         describe "when the path is changed and confirmed", ->
           describe "when all the directories along the new path exist", ->
             it "moves the file, updates the tree view, and closes the dialog", ->
-              runs ->
-                newPath = fs.join(rootDirPath, 'renamed-test-file.txt')
-                moveDialog.miniEditor.setText(newPath)
-
-                moveDialog.trigger 'tree-view:confirm'
-
-                expect(fs.exists(newPath)).toBeTruthy()
-                expect(fs.exists(filePath)).toBeFalsy()
-                expect(moveDialog.parent()).not.toExist()
+              newPath = fs.join(rootDirPath, 'renamed-test-file.txt')
+              moveDialog.miniEditor.setText(newPath)
+
+              moveDialog.trigger 'tree-view:confirm'
+
+              expect(fs.exists(newPath)).toBeTruthy()
+              expect(fs.exists(filePath)).toBeFalsy()
+              expect(moveDialog.parent()).not.toExist()

               waitsFor "tree view to update", ->
                 treeView.root.find('> .entries > .file:contains(renamed-test-file.txt)').length > 0


Fix typo

Fix typo

--- scripts/net.coffee
+++ scripts/net.coffee
@@ -42,7 +42,7 @@
           for domain, i in result.domains?
             title = "Domain"
             title += "#{i+1}" if result.domains?.length > 1
-            attachments.fields.push {
+            attachment.fields.push {
               title: title
               value: domain
               short: false


Comments.

Comments.

--- js/flight.coffee
+++ js/flight.coffee
@@ -22,9 +22,11 @@
         @speed = options.speed
       if options.useScroller?
         @useScroller = options.useScroller
-
+
+    # see what device we're using
     @detectUserAgent()
-
+
+    # don't bother using transition animation on older android devices as they look terrible
     if @os.android and @os.version <= "2.1" then @transitionAnimation = false

     if @hideUrlBar is true then @hideUrlBar()


Go for it.

Go for it.

--- apps/gallery_partnerships/index.coffee
+++ apps/gallery_partnerships/index.coffee
@@ -9,8 +9,8 @@
 app.set 'views', __dirname + '/templates'
 app.set 'view engine', 'jade'

-app.get '/gallery-partnerships', routes.adminOnly, routes.index
-app.get /^\/gallery-partnerships\/((?!edit$).)+$/, routes.adminOnly, routes.index # Scroll routes
+app.get '/gallery-partnerships', routes.index
+app.get /^\/gallery-partnerships\/((?!edit$).)+$/, routes.index # Scroll routes

 # Safely init upload routes for missing S3 env vars (like in test)
 try


Fix duplicate pages

Fix duplicate pages

--- apps/notifications/client/index.coffee
+++ apps/notifications/client/index.coffee
@@ -30,7 +30,6 @@
     @setupJumpView()

     @setup =>
-      @attachScrollHandler()
       @notifications.getFirstPage()?.then @checkIfEmpty

   attachScrollHandler: ->


Removed urlify(). Using existing getUrl(), instead

getUrl() works, whereas urlify() did not work for cases where model.url was a function.

--- backbone.dualstorage.coffee
+++ backbone.dualstorage.coffee
@@ -142,12 +142,9 @@
   # Make the request.
   $.ajax params

-urlify = (model) ->
-  if _.isFunction(model.url) then model.url() else model.url
-
 dualsync = (method, model, options) ->
   console.log 'dualsync', method, model, options
-  store = new Store urlify(model)
+  store = new Store getUrl(model)

   switch method
     when 'read'


Only reverse tasks for active

Only reverse tasks for active

--- SingularityUI/app/views/tasks.coffee
+++ SingularityUI/app/views/tasks.coffee
@@ -9,6 +9,10 @@
     render: (tasksFilter) =>
         @collection = app.collections.tasksActive
         template = @templateTasksActive
+        tasks = _.pluck(@collection.sort().models, 'attributes')
+
+        if tasksFilter is 'active'
+            tasks = tasks.reverse()

         if tasksFilter is 'scheduled'
             @collection = app.collections.tasksScheduled
@@ -19,7 +23,7 @@
             template = @templateTasksCleaning

         context =
-            tasks: _.pluck(@collection.sort().models, 'attributes').reverse()
+            tasks: tasks

         @$el.html template context


Only allow 1 message on AQMP per participant

Needs a proper API, for instance options object on
Client / transport.getClient

--- src/participant.coffee
+++ src/participant.coffee
@@ -19,6 +19,8 @@

   start: (callback) ->
     @messaging.connect (err) =>
+      @messaging.channel?.prefetch 1 # FIXME: move out to consumer
+
       debug 'connected', err
       return callback err if err
       @setupPorts (err) =>


Client: Activity: Feed: Added handleRoute method. It changes route by out parameter and channelName

--- client/activity/lib/components/publicfeedpane/feedpanetabcontainer.coffee
+++ client/activity/lib/components/publicfeedpane/feedpanetabcontainer.coffee
@@ -28,6 +28,15 @@

     @handleRoute '/'

+
+  handleRoute: (route) ->
+
+    channelName = @props.thread.getIn ['channel', 'name']
+    route       = "/Channels/#{channelName}/#{route}"
+
+    kd.singletons.router.handleRoute route
+
+
   render: ->

     return null  unless @props.thread


Client: Activity: Feed: Added onChange method to set query state

--- client/activity/lib/components/publicfeedpane/feedpanetabcontainer.coffee
+++ client/activity/lib/components/publicfeedpane/feedpanetabcontainer.coffee
@@ -57,6 +57,12 @@
     'active'       : @props.thread.getIn(['flags', 'resultListState']) is ResultState.LIKED

+  onChange: (event) ->
+
+    query = event.target.value
+    @setState { query }
+
+
   onEsc: (event) -> @redirectToChannel()


display fix for loader (will not load when there is no actual embed request sent to embed.ly)

--- client/app/Applications/Activity.kdapplication/views/embedboxviews.coffee
+++ client/app/Applications/Activity.kdapplication/views/embedboxviews.coffee
@@ -30,6 +30,7 @@
     @makeActive()

     # KDListView -> EmbedBoxLinksView -> EmbedBox .embedUrl
+    @getDelegate().getDelegate().getDelegate().embedLoader.hide()
     @getDelegate().getDelegate().getDelegate().embedUrl @linkUrl, {}, (embedData)=>
       if embedData.favicon_url? then @setFavicon embedData.favicon_url


Grammar

Grammar

--- client/landing/app/Applications/Groups.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Groups.kdapplication/AppController.coffee
@@ -108,7 +108,7 @@

   onboardingText =
     everything : """
-
Koding groups is a simple way to connect and interact with people who share
+
Koding groups are a simple way to connect and interact with people who share
       your interests.

When you join a group such as your univeristy or your company, you can share virtual


fixed "see all groups" in group switcher popup

--- client/landing/app/MainApp/avatararea/avatarareagroupswitcherpopup.coffee
+++ client/landing/app/MainApp/avatararea/avatarareagroupswitcherpopup.coffee
@@ -58,7 +58,7 @@
       cssClass : "split sublink"
       partial  : "See all groups..."
       click    : =>
-        KD.getSingleton("appManager").open "Groups"
+        KD.getSingleton('router').handleRoute '/Groups'
         @hide()

     backToKodingView = new KDView


Rename _is_reserved_word() to is_reserved_method_name().

--- src/TinyMockJS.coffee
+++ src/TinyMockJS.coffee
@@ -74,13 +74,10 @@

   _check_expects_usage = (object, method_name) ->
     _throw_expects_usage() unless method_name?
-    _throw_reserved_word(method_name) if _is_reserved_word(method_name)
+    _throw_reserved_word(method_name) if is_reserved_method_name(method_name)
     _throw_pre_existing_property(method_name) if is_property_of_object(object, method_name)
+    _throw_not_an_existing_method(method_name) if not is_mock_object(object) and is_class(object) and not is_method_in_prototype(object, method_name)
     _throw_not_an_existing_method(method_name) if not is_mock_object(object) and not is_class(object) and not is_method_of_object(object, method_name)
-    _throw_not_an_existing_method(method_name) if not is_mock_object(object) and is_class(object) and not is_method_in_prototype(object, method_name)
-
-  _is_reserved_word = (word) ->
-    word in [ "expects", "args", "returns", "check" ]

   _create_expectation = (object, method_name) ->
     new Expectation(object, method_name)
@@ -307,3 +304,6 @@

 is_mock_object = (object) ->
   object.constructor.name == 'MockObject'
+
+is_reserved_method_name = (word) ->
+  word in [ "expects", "args", "returns", "check" ]


Additional frame timing tweaks (increased delta time smoothing)

--- source/Main.coffee
+++ source/Main.coffee
@@ -120,7 +120,7 @@
 		elapsed = 0.0
 	lastTime = timeNow

-	deltaTime = elapsed * 0.5 + deltaTime * 0.5
+	deltaTime = elapsed * 0.1 + deltaTime * 0.9

 updateMouse = ->
 	if not mouseIsDown then return


Updated worker script for POST transactions

--- src/api/worker.coffee
+++ src/api/worker.coffee
@@ -62,9 +62,11 @@
               port: 7786
               path: transaction.request.path
               method: transaction.request.method
-              headers:
+              headers: transaction.request.headers
                 clientID: transaction.clientID
                 parentID: transaction._id
+
+              console.log(options)

             if transaction.request.querystring
               options.path += "?"+transaction.request.querystring
@@ -81,6 +83,9 @@
               console.log "problem with request: " + e.message

             # write data to request body
+
+            if transaction.request.method == "POST" || transaction.request.method == "PUT"
+              req.write transaction.request.body
             req.end()

             ################################################################


fix formula

fix formula

--- komodo/play.coffee
+++ komodo/play.coffee
@@ -25,8 +25,8 @@
                 value = if _.isNumber(question.value) then question.value else 1000
                 timeScale = 1
                 if _.isNumber(question.time)
-                    timeScale = question.time - timer + 1
-                modifier.$inc["players.#{i}.score"] = value / timeScale
+                    timeScale = timer / question.time
+                modifier.$inc["players.#{i}.score"] = Math.floor(value * timeScale)
         LiveGames.update gameid, modifier

 if Meteor.isClient


:lipstick:

:lipstick:

--- src/app/window.coffee
+++ src/app/window.coffee
@@ -21,8 +21,8 @@
     $(document).on 'keydown', @_handleKeyEvent

   startup: (path) ->
+    @loadUserConfiguration()
     @attachRootView(path)
-    @loadUserConfiguration()
     $(window).on 'close', => @close()
     $(window).on 'beforeunload', =>
       @shutdown()
@@ -53,7 +53,7 @@
     try
       require atom.userConfigurationPath if fs.exists(atom.userConfigurationPath)
     catch error
-      console.error "Failed to load `#{atom.userConfigurationPath}`", error
+      console.error "Failed to load `#{atom.userConfigurationPath}`", error.message, error
       @showConsole()

   requireStylesheet: (path) ->


cleanup

cleanup

--- lib/Model.coffee
+++ lib/Model.coffee
@@ -21,6 +21,7 @@
     wrap item for item in data
   else
     wrap data
+

 wrapAsync = require './wrapAsync'

@@ -130,15 +131,14 @@
         query.run cb
       else query

+
     @all: (cb) ->
       query = new Query @, @r()
       query.collection = yes
       if cb? then query.run cb else query

-    @getAll: (args...) ->
-
-
+    @getAll: (id, cb) ->
       query = new Query @, @r().getAll(id)
       query.collection = yes
       if cb? then query.run cb else query


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/game_object.coffee
+++ test/game_object.coffee
@@ -40,14 +40,13 @@

   equals p.x, o.I.x

-test "[event] create", 2, ->
+test "[event] create", 1, ->
   o = GameObject()
   o.bind "create", ->
       ok true, "created event is fired on create"

   o.create()
-
-  o.create()
+  o.create() # Make sure only fired once

 test "[event] update", 1, ->
   gameObject = GameObject()


hub/healthcheck: always configure endpoint, i.e. also for proxy

--- src/smc-hub/hub.coffee
+++ src/smc-hub/hub.coffee
@@ -542,8 +542,6 @@
             # This must happen *AFTER* update_schema above.
             init_smc_version(database, cb)
         (cb) ->
-            if not program.port
-                cb(); return
             # setting port must come before the hub_http_server.init_express_http_server below
             if program.agent_port
                 healthchecks.set_agent_endpoint(program.agent_port, program.host)


act like nothing happened

act like nothing happened

--- test/server/cart.coffee
+++ test/server/cart.coffee
@@ -4,7 +4,7 @@
   new Promise (resolve, reject) ->
     setTimeout resolve, delay

-describe 'Api.cart', ->
+describe.only 'Api.cart', ->
   fixture = null
   car = null


syntax styling and small fixes

syntax styling and small fixes

--- lib/index.coffee
+++ lib/index.coffee
@@ -9,7 +9,7 @@

     constructor: (@roots) ->
       @roots.config.locals ||= {}
-      @__records = {}
+      @__records ||= {}

     compile_hooks: =>

@@ -18,46 +18,43 @@
         if !roots.records?
           roots.records ||= []
           for key, obj of opts
-            roots.records.push(_get.call(@, key, obj))
+            roots.records.push(get.call(@, key, obj))
         W.all(roots.records)

       before_pass: (ctx) =>
-        roots   = ctx.file.roots
-        config  = roots.config
-        locals  = config.locals
-        locals.records = @__records
+        return if @roots.config.locals.records?
+        @roots.config.locals.records = @__records

-    _get = (key, obj) ->
+    get = (key, obj) ->
       if obj.url?
-        return _url.call(@, key, obj)
+        return url.call(@, key, obj)
       else if obj.file?
-        return _file.call(@, key, obj)
+        return file.call(@, key, obj)
       else if obj.data?
-        return _data.call(@, key, obj)
+        return data.call(@, key, obj)
       else
         throw new Error "A valid key is required"

-    _url = (key, obj) ->
+    url = (key, obj) ->
       nodefn.call(request, obj.url)
         .tap (response) =>
-          _respond.call(@, key, obj, JSON.parse(response[0].body))
+          respond.call(@, key, obj, JSON.parse(response[0].body))

-    _file = (key, obj) ->
+    file = (key, obj) ->
       W ->
         f = fs.readFileSync obj.file, 'utf8'
-        _respond.call(@, key, obj, JSON.parse(f))
+        respond.call(@, key, obj, JSON.parse(f))

-    _data = (key, obj) ->
+    data = (key, obj) ->
       W ->
-        _respond.call(@, key, obj, obj.data)
+        respond.call(@, key, obj, obj.data)

-    _respond = (key, obj, json) ->
-      @__records[key] = _to(json, obj.path)
+    respond = (key, obj, json) ->
+      @__records[key] = to(json, obj.path)

-    _to = (json, path) ->
-      return json if !path?
-      keys = path.split "/"
-      pos = json
-      for key in keys
-        pos = pos[key] unless !pos[key]?
+    to = (json, path) ->
+      if not path then return json
+      keys  = path.split "/"
+      pos   = json
+      pos   = pos[key] for key in keys when pos[key]?
       return pos


pass options in singleCommand mode

pass options in singleCommand mode

--- lib/index.coffee
+++ lib/index.coffee
@@ -25,7 +25,7 @@
     isSingleCommand = typeof args.command is 'string'

     unless args.cb
-      return execSync args.command if isSingleCommand
+      return execSync args.command args.options if isSingleCommand
       child = []
       child.push @exec command for command in args.command
       return child