Update spell-check package for new telepath-based marker API

--- lib/misspelling-view.coffee
+++ lib/misspelling-view.coffee
@@ -14,13 +14,13 @@
     @endPosition = range.end
     @misspellingValid = true

-    @marker = @editSession.markScreenRange(range, invalidationStrategy: 'between')
-    @marker.on 'changed', ({newHeadScreenPosition, newTailScreenPosition, valid}) =>
+    @marker = @editSession.markScreenRange(range, invalidation: 'inside')
+    @marker.on 'changed', ({newHeadScreenPosition, newTailScreenPosition, isValid}) =>
       @startPosition = newTailScreenPosition
       @endPosition = newHeadScreenPosition
-      @updateDisplayPosition = valid
-      @misspellingValid = valid
-      @hide() unless valid
+      @updateDisplayPosition = isValid
+      @misspellingValid = isValid
+      @hide() unless isValid

     @subscribe @editor, 'editor:display-updated', =>
       @updatePosition() if @updateDisplayPosition


make cd commands work everywhere

make cd commands work everywhere

--- lib/package/commands.coffee
+++ lib/package/commands.coffee
@@ -46,13 +46,11 @@
       'julia-client:set-working-module': -> modules.chooseModule()
       'julia-client:reset-working-module': -> modules.resetModule()

-
     @subs.add atom.commands.add 'atom-workspace',
       'julia:open-startup-file': -> atom.workspace.open paths.home '.juliarc.jl'
       'julia:open-julia-home': -> shell.openItem paths.juliaHome()
       'julia:open-package-in-new-window': -> paths.openPackage()

-    @subs.add atom.commands.add '.item-views > atom-text-editor',
       'julia-client:work-in-file-folder': ->
         client.require -> evaluation.cdHere()
       'julia-client:work-in-project-folder': ->


fix toc bug when front matter hides

fix toc bug when front matter hides

--- lib/md.coffee
+++ lib/md.coffee
@@ -601,7 +601,9 @@
         content = yamlStr + inputString.slice(end+4)
         return {content, table: ''}
       else # hide
-        return {content: inputString.slice(end+4), table: ''}
+        yamlStr = inputString.slice(0, end+4)
+        content = '\n'.repeat(yamlStr.match(/\n/g)?.length or 0) + inputString.slice(end+4)
+        return {content, table: ''}

   {content: inputString, table: ''}


use correct path when on windows

use correct path when on windows

--- lib/connection/client.coffee
+++ lib/connection/client.coffee
@@ -66,7 +66,9 @@
       path = ed.getPath()
       ind = path.indexOf(@remoteConfig.host)
       if ind > -1
-        return path.slice(ind + @remoteConfig.host.length, path.length)
+        path = path.slice(ind + @remoteConfig.host.length, path.length)
+        path = path.replace(/\\/g, '/')
+        return path
       else
         return path


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/core_object.coffee
+++ src/core_object.coffee
@@ -148,7 +148,7 @@
           Module = Module.constantize()
         else

-        self.extend Module(I, self)
+        self.extend Module(I, self) unless I.incl

       return self


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/core_object.coffee
+++ src/core_object.coffee
@@ -139,7 +139,7 @@

     @name include
     @methodOf Core#
-    @param {St} Module the module to include. A module is a constructor that takes two parameters, I and self, and returns an object containing the public methods to extend the including object with.
+    @param {String} Module the module to include. A module is a constructor that takes two parameters, I and self, and returns an object containing the public methods to extend the including object with.
     ###
     include: (modules...) ->
       for Module in modules


Sigfigs on completion rate, humanize played counts over 1k, change background to black

--- app/views/play/CampaignView.coffee
+++ app/views/play/CampaignView.coffee
@@ -304,8 +304,8 @@
               ratio = 0
             else
               ratio = finished / started
-            rateDisplay = (ratio * 100).toFixed(2) + '%'
-            $("div[data-level-slug=#{level.slug}] .level-kind").html(started + "
" + rateDisplay)
+            rateDisplay = (ratio * 100).toFixed(1) + '%'
+            $("div[data-level-slug=#{level.slug}] .level-kind").html((if started < 1000 then started else (started / 1000).toFixed(1) + "k") + "
" + rateDisplay)
             if ratio <= 0.5
               color = "rgb(255, 0, 0)"
             else if ratio > 0.5 and ratio <= 0.85
@@ -317,6 +317,8 @@
             else
               color = "rgb(0, 256, 0)"
             $("div[data-level-slug=#{level.slug}] .level-kind").css({"color":color, "width":256+"px", "transform":"translateX(-50%) translateX(15px)"})
+            $(".gradient").remove()
+            $("#campaign-view").css("background-color", "black")
             $("div[data-level-slug=#{level.slug}]").css("background-color", color)
         }, 0
         request.load()


Use the last focused window instead of the last opened window.

--- src/browser/atom-application.coffee
+++ src/browser/atom-application.coffee
@@ -367,7 +367,7 @@
       darwin: 22
       win32: 26

-    dimensions = @windows[@windows.length - 1]?.getDimensions()
+    dimensions = (@focusedWindow() ? @lastFocusedWindow)?.getDimensions()
     offset = offsetByPlatform[process.platform]
     if dimensions? and offset?
       dimensions.x += offset


Cleanup SignalListView

Cleanup SignalListView

--- lib/signal-list-view.coffee
+++ lib/signal-list-view.coffee
@@ -10,38 +10,25 @@
         super

         @basicCommands = [
-            {
-                name: 'Interrupt'
-                value: 'interrupt-kernel'
-                language: null
-            },
-            {
-                name: 'Restart'
-                value: 'restart-kernel'
-                language: null
-            },
-            {
-                name: 'Shut Down'
-                value: 'shutdown-kernel'
-                language: null
-            },
+            name: 'Interrupt'
+            value: 'interrupt-kernel'
+        ,
+            name: 'Restart'
+            value: 'restart-kernel'
+        ,
+            name: 'Shut Down'
+            value: 'shutdown-kernel'
         ]

         @wsKernelCommands = [
-            {
-                name: 'Rename'
-                value: 'rename-kernel'
-                language: null
-            },
-            {
-                name: 'Disconnect from'
-                value: 'disconnect-kernel'
-                language: null
-            }
+            name: 'Rename session for'
+            value: 'rename-kernel'
+        ,
+            name: 'Disconnect from'
+            value: 'disconnect-kernel'
         ]

         @onConfirmed = null
-        @addClass('kernel-signal-selector')
         @list.addClass('mark-active')
         @setItems([])

@@ -67,24 +54,20 @@
             return @setItems []

         # add basic commands for the current grammar language
-        basicCommands = @basicCommands.map (command) ->
-            name =
-                command.name + ' ' + kernel.kernelSpec.display_name + ' kernel'
+        basicCommands = @basicCommands.map (command) =>
             return {
-                name: name
-                value: command.value
+                name: @_getCommandName command.name, kernel.kernelSpec
+                command: command.value
                 grammar: grammar
                 language: language
                 kernel: kernel
             }

         if kernel instanceof WSKernel
-            wsKernelCommands = @wsKernelCommands.map (command) ->
-                name =
-                    command.name + ' ' + kernel.kernelSpec.display_name + ' kernel'
+            wsKernelCommands = @wsKernelCommands.map (command) =>
                 return {
-                    name: name
-                    value: command.value
+                    name: @_getCommandName command.name, kernel.kernelSpec
+                    command: command.value
                     grammar: grammar
                     language: language
                     kernel: kernel
@@ -94,21 +77,25 @@
             # add commands to switch to other kernels
             @kernelManager.getAllKernelSpecsFor language, (kernelSpecs) =>
                 _.pull kernelSpecs, kernel.kernelSpec
-                switchCommands = kernelSpecs.map (spec) ->
+
+                switchCommands = kernelSpecs.map (kernelSpec) =>
                     return {
-                        name: 'Switch to ' + spec.display_name
-                        value: 'switch-kernel'
+                        name: @_getCommandName 'Switch to', kernelSpec
+                        command: 'switch-kernel'
                         grammar: grammar
                         language: language
-                        kernelSpec: spec
+                        kernelSpec: kernelSpec
                     }

                 @setItems _.union basicCommands, switchCommands

+    _getCommandName: (name, kernelSpec) ->
+        return name + ' ' + kernelSpec.display_name + ' kernel'
+
+
     confirmed: (item) ->
         console.log 'Selected command:', item
-        item.command = item.value
         @onConfirmed?(item)
         @cancel()


Adds initials method

Adds initials method

--- models/user.coffee
+++ models/user.coffee
@@ -49,3 +49,7 @@
     @__related__ =
       customer: new Customer
       policy: new Policy
+
+  initials: ->
+    @get('initials') or
+    _.first(@get('username').split(' ').map((name) => name[0]), 4).join('')


always return a promise

always return a promise

Otherwise it can cause cannot call `.then` on undefined

--- shared/src/api/index.coffee
+++ shared/src/api/index.coffee
@@ -150,7 +150,7 @@

   # send can now be used separately without initializing routes
   send: (requestConfig, routeOptions, args...) ->
-    return if @records.isPending(requestConfig)
+    return Promise.reject('already-in-progress') if @records.isPending(requestConfig)

     requestInfo = pick(routeOptions, 'subject', 'topic', 'action')
     requestInfo = guessInfoFromConfig(requestConfig) if isEmpty(requestInfo)


handle version and dryrun cli options

handle version and dryrun cli options

--- bin/command.coffee
+++ bin/command.coffee
@@ -1,7 +1,15 @@
 module.exports = (options) ->

-  # read cli options and options file and produce an `op`
-  op = require('./op') options?.create
+  # ouptput the version from the package.json file
+  if '-v' in process.argv or '--version' in process.argv
+    pkg = require '../package.json'
+    console.log "bonce v#{pkg.version}"

-  # get `bonce` function and run it with `op`
-  require('../lib') op, options?.bonce
+  else
+    # read cli options and options file and produce an `op`
+    op = require('./op') options?.create
+
+    # if `dryrun` is set then dont do the rest.
+    unless op.dryrun
+      # get `bonce` function and run it with `op`
+      require('../lib') op, options?.bonce


Fixing dialog api parameter parsing

Fixing dialog api parameter parsing

--- atom/browser/api/lib/dialog.coffee
+++ atom/browser/api/lib/dialog.coffee
@@ -51,7 +51,7 @@
                            window,
                            wrappedCallback

-  showSaveDialog: (window, options, callback) ->
+  showSaveDialog: (args...) ->
     [window, options, callback] = parseArgs args...

     options ?= title: 'Save'
@@ -71,7 +71,7 @@
                            window,
                            wrappedCallback

-  showMessageBox: (window, options, callback) ->
+  showMessageBox: (args...) ->
     [window, options, callback] = parseArgs args...

     options ?= type: 'none'


bugif: manualBackgroundSize

bugif: manualBackgroundSize

--- lib/editor-background.coffee
+++ lib/editor-background.coffee
@@ -198,7 +198,7 @@
     range=conf.boxRange
     range2=range // 3
     bgSize=conf.backgroundSize
-    if bgSize=='manual' then bgSize=manualBackgroundSize
+    if bgSize=='manual' then bgSize=conf.manualBackgroundSize
     if bgSize=='original' then bgSize='auto'
     body = qr 'body'
     x=body.style.width - @mouseX


we need to resolve some bugs

we need to resolve some bugs

--- lib/editor-background.coffee
+++ lib/editor-background.coffee
@@ -712,8 +712,9 @@
   initialize: ->
     @elements.body = qr 'body'
     @elements.workspace = atom.views.getView(atom.workspace)
-    activeEditor = workspace.getActiveTextEditor()
-    @elements.editor = atom.views.getView(activeEditor)
+    if @elements.workspace?
+      activeEditor = atom.workspace.getActiveTextEditor()
+      @elements.editor = atom.views.getView(activeEditor)
     @elements.treeView = qr '.tree-view'
     @elements.left = qr '.left'
     @elements.leftPanel = qr '.panel-left'
@@ -887,8 +888,11 @@
         inline @elements.bg,"background-image: url('#{imageData}') !important"

   applyBackground: ->
-    atom.views.getView(atom.workspace).addClass 'editor-background'
     if @packagesLoaded
+      workspaceView = atom.views.getView(atom.workspace)
+      console.log 'workspaceView',workspaceView
+      if workspaceView?
+        workspaceView.addClass 'editor-background'
       conf = atom.config.get 'editor-background'
       opacity = 100 - conf.opacity
       alpha=(opacity / 100).toFixed(2)


Change keymap

Change keymap

--- keymap.cson
+++ keymap.cson
@@ -27,8 +27,8 @@
 # https://atom.io/docs/latest/using-atom-basic-customization#cson

 'atom-text-editor':
-  'ctrl-shift-tab': 'window:focus-pane-on-left'
-  'alt-"'         : 'window:focus-pane-on-right'
   'alt-d'         : 'find-and-replace:select-all'
   'ctrl-t'        : 'terminal-plus:toggle'
-  'ctrl-shift-X'  : 'snippets:next-tab-stop'
+
+  'ctrl-shift-up ctrl-shift-right'  : 'window:focus-pane-on-right'
+  'ctrl-shift-up ctrl-shift-left'   : 'window:focus-pane-on-left'


shorten custom Intercom variable labels, and start recording date of most recently created table extract dataset

--- client/code/router/main.coffee
+++ client/code/router/main.coffee
@@ -75,24 +75,26 @@
           datahub_id: effective.shortName
           datahub_name: effective.displayName
           datasets: datasets.length
-          table_xtract_datasets: 0
-          table_xtract_downloads: 0
-          twitter_search_datasets: 0
-          code_in_browser_datasets: 0
-          most_recent_dataset_created_at: null
+          dataset_created_at: null
+          tx_datasets: 0
+          tx_downloads: 0
+          tx_created_at: null
+          ts_datasets: 0
+          cb_datasets: 0

         _.each datasets, (dataset) ->
           date = Date.parse(dataset.createdDate) / 1000
-          settings.most_recent_dataset_created_at = Math.max date, settings.most_recent_dataset_created_at
+          settings.dataset_created_at = Math.max date, settings.dataset_created_at
           if dataset.tool == 'table-xtract'
-            settings.table_xtract_datasets += 1
+            settings.tx_created_at = Math.max date, settings.tx_created_at
+            settings.tx_datasets += 1
             _.each dataset.views, (view) ->
               if view.tool == 'spreadsheet-download'
-                settings.table_xtract_downloads += 1
+                settings.tx_downloads += 1
           else if dataset.tool == 'twitter-search'
-            settings.twitter_search_datasets += 1
+            settings.ts_datasets += 1
           else if dataset.tool == 'code-scraper-in-browser'
-            settings.code_in_browser_datasets += 1
+            settings.cb_datasets += 1

         cb settings


dashboard: missing include files

dashboard: missing include files

--- client/landing/includes.coffee
+++ client/landing/includes.coffee
@@ -641,8 +641,8 @@

   # GROUP DASHBOARD

-  # "app/Applications/Dashboard.kdapplication/AppController.coffee",
-  # "app/Applications/Dashboard.kdapplication/AppView.coffee",
+  "app/Applications/Dashboard.kdapplication/AppController.coffee",
+  "app/Applications/Dashboard.kdapplication/AppView.coffee",

   # CONTENT DISPLAY VIEWS


if this.isMessageTooLong(input) return Errors.throw t('Error_message_too_long')

--- client/lib/chatMessages.coffee
+++ client/lib/chatMessages.coffee
@@ -66,8 +66,9 @@
 			this.editing.saved = this.input.value

 	send: (rid, input) ->
-		if _.trim(input.value) isnt '' and not this.isMessageTooLong(input)
-			console.error 'sending', input.value
+		if _.trim(input.value) isnt ''
+			if this.isMessageTooLong(input)
+				return Errors.throw t('Error_message_too_long')
 			KonchatNotification.removeRoomNotification(rid)
 			msg = input.value
 			input.value = ''
@@ -187,6 +188,6 @@
 		# ctrl (command) + shift + k -> clear room messages
 		else if k is 75 and ((navigator?.platform?.indexOf('Mac') isnt -1 and event.metaKey and event.shiftKey) or (navigator?.platform?.indexOf('Mac') is -1 and event.ctrlKey and event.shiftKey))
 			RoomHistoryManager.clear rid
-
+
 	isMessageTooLong: (input) ->
-		input?.value.length > this.messageMaxSize+		input?.value.length > this.messageMaxSize


Uses site name from settings.

Uses site name from settings.

--- client/lib/notification.coffee
+++ client/lib/notification.coffee
@@ -10,7 +10,7 @@
 	# notificacoes HTML5
 	showDesktop: (room, msg) ->
 		unless Session.equals('user_' + Meteor.userId() + '_status', 'busy')
-			roomName = room.name + ' - Rocket.Chat'
+			roomName = room.name + ' - ' + RocketChat.settings.get 'Site_Name'
 			if window.Notification && Notification.permission == "granted"
 				n = new Notification roomName,
 					icon: '/images/rocket-chat-logo-square.png'


formatting

formatting

removed unnecessary space

--- lib/project-find-view.coffee
+++ lib/project-find-view.coffee
@@ -52,7 +52,6 @@
         @div class: 'input-block-item', =>
           @div class: 'btn-group btn-group-find', =>
             @button outlet: 'findAllButton', class: 'btn', 'Find'
-
           @div class: 'btn-group btn-toggle btn-group-options', =>
             @button outlet: 'regexOptionButton', class: 'btn option-regex', =>
               @raw '<svg class="icon"><use xlink:href="#find-and-replace-icon-regex" /></svg>'


Add APNS debug message

Add APNS debug message

--- lib/pushservices/apns.coffee
+++ lib/pushservices/apns.coffee
@@ -16,6 +16,7 @@
         @feedback = new apns.Feedback(conf)
         # Handle Apple Feedbacks
         @feedback.on 'feedback', (feedbackData) =>
+            @logger?.debug("APNS feedback returned #{feedbackData.length} devices")
             feedbackData.forEach (item) =>
                 tokenResolver 'apns', item.device.toString(), (subscriber) =>
                     subscriber?.get (info) ->


removed unnecessarily line breaks

removed unnecessarily line breaks

--- lib/project-find-view.coffee
+++ lib/project-find-view.coffee
@@ -52,8 +52,6 @@
         @div class: 'input-block-item', =>
           @div class: 'btn-group btn-group-find', =>
             @button outlet: 'findAllButton', class: 'btn', 'Find'
-
-

         @div class: 'input-block-item', =>
           @div class: 'btn-group btn-toggle btn-group-options', =>


添加调试代码

添加调试代码

--- lib/pushservices/apns.coffee
+++ lib/pushservices/apns.coffee
@@ -50,9 +50,9 @@
             if note_bytesize > 265
                 difference = note_bytesize - 265
             alert_bytesize =  oldAlert_bytesize - difference - 3
-            logger.verbos oldAlert_bytesize
-            logger.verbos difference
-            logger.verbos alert
+            logger.verbose oldAlert_bytesize
+            logger.verbose difference
+            logger.verbose alert
             alertNew = ''
             i = 0
             while i <= alert.length


--- lib/utils/retsParsing.coffee
+++ lib/utils/retsParsing.coffee
@@ -110,6 +110,9 @@
           writeOutput('metadataStart', attrs)
           result.rowsReceived = 0
         when 'COUNT'
+          ### Ignore count write when stream ended due to NO_RECORDS_FOUND (20201) error. ###
+          if !retsStream.writable && parseInt(attrs.Records) == 0
+            return false
           writeOutput('count', parseInt(attrs.Records))
         when 'MAXROWS'
           result.maxRowsExceeded = true


Add tooltips explaining timings

Add tooltips explaining timings

--- lib/window-panel-view.coffee
+++ lib/window-panel-view.coffee
@@ -20,6 +20,12 @@
         @div class: 'timing', outlet: 'projectTiming', =>
           @span class: 'inline-block', 'Project load time'
           @span class: 'inline-block', outlet: 'projectLoadTime'
+
+  initialize: ->
+    @windowTiming.children().setTooltip('The time taken to load this window')
+    @shellTiming.children().setTooltip('The time taken to launch the app')
+    @workspaceTiming.children().setTooltip('The time taken to rebuild the prevoiusly opened editors')
+    @projectTiming.children().setTooltip('The time taken to rebuild the previously opened buffers')

   updateWindowLoadTime: ->
     time = atom.getWindowLoadTime()


andnow

andnow

--- models/deploy.coffee
+++ models/deploy.coffee
@@ -29,8 +29,8 @@
   @team (err, team) ->
     console.log "TEAM IP IS: #{team.ip}"
     next(false) if err
-    # next(team.ip is v)
-    next(true)
+    next(team.ip is v)
+    # next(true)
 , 'not recognized'

 DeploySchema.path('remoteAddress').validate (v, next) ->


plan.getSubscriptions()

plan.getSubscriptions()

--- workers/social/lib/social/models/recurly/index.coffee
+++ workers/social/lib/social/models/recurly/index.coffee
@@ -27,7 +27,7 @@
       ]
       instance     : [
         'getToken', 'subscribe',
-        'getType'
+        'getType', 'getSubscriptions'
       ]
     schema         :
       code         : String
@@ -335,11 +335,20 @@

     @getAccountBalance userCode, callback

-  getType:(callback)->
+  getType: (callback)->
     if @feeInterval is 1
       callback 'recurring'
     else
       callback 'single'
+
+  getSubscriptions: (callback)->
+    JRecurlySubscription.all
+      planCode: @code
+      $or      : [
+        {status: 'active'}
+        {status: 'canceled'}
+      ]
+    , callback

 do ->
   # Koding Recurly Products


Share shared machine user add method

Share shared machine user add method

--- workers/social/lib/social/models/sharedmachine.coffee
+++ workers/social/lib/social/models/sharedmachine.coffee
@@ -8,6 +8,11 @@
 module.exports = class SharedMachine extends bongo.Base

   @share()
+
+  @set
+    sharedMethods  :
+      static       :
+        add        : (signature String, Object, Function)

   @add = secure (client, uid, target, callback) ->


Improved error logging if a plugin fails to load.

--- app-loader/app-loader.coffee
+++ app-loader/app-loader.coffee
@@ -50,8 +50,8 @@
             else
                 resolve()

-        fail = () ->
-            console.error("error loading", pluginPath)
+        fail = (a, errorStr, e) ->
+            console.error("error loading", pluginPath, e)

         $.getJSON(pluginPath).then(success, fail)


Remvoe terms checkbox from javascript on credit card engine and small refactors

--- lib/gems/catarse_credit_card_net/app/assets/javascripts/catarse_credit_card_net/credit_card.js.coffee
+++ lib/gems/catarse_credit_card_net/app/assets/javascripts/catarse_credit_card_net/credit_card.js.coffee
@@ -6,12 +6,12 @@
     this.$el.foundation()

     this.$button = this.$('input[type=submit]')
+    this.$form = this.$('form#credit-card-form')

     this.$('#billing_first_name, #billing_last_name, #card_number, #card_code').focusout =>
       this.validate()

-    this.$('#terms').change this.validate
-    this.$('form#credit-card-form').bind('submit', this.submit)
+    this.$form.bind('submit', this.submit)

     this.showAuthorizeNetSeal()

@@ -27,15 +27,14 @@
       billing_first_name: this.$('#billing_first_name').val()
       billing_last_name: this.$('#billing_last_name').val()

-    $.post(this.$('form#credit-card-form').prop('action'), data, (response) =>
+    $.post(this.$form.prop('action'), data, (response) =>
       console.log response
       if response.process_status is 'ok'
-        thank_you_path = $('.create-backer-page').data('thank-you-path')
-        location.href = thank_you_path
+        location.href = $('.create-backer-page').data('thank-you-path')
       else
         this.$('.check-error p.error-name').text response.message
         this.$('.check-error').fadeIn 300
-        $.rails.enableFormElements($('form#credit-card-form'))
+        $.rails.enableFormElements(this.$form)
     , 'json').error ->
       this.$('.check-error p.error-name').text 'The back already confirmed, if you can do another back please refresh the page or go back to project page :)'
       this.$('.check-error').fadeIn 300
@@ -46,7 +45,6 @@
     valid = false unless this.validateField this.$('#billing_last_name')
     valid = false unless this.validateField this.$('#card_number')
     valid = false unless this.validateField this.$('#card_code')
-    valid = false unless this.aceptedTerms()

     return valid

@@ -69,14 +67,6 @@
     $field.removeClass 'error'
     $field.parent().find('span.error').remove()

-  aceptedTerms: ->
-    unless this.$('#terms').is(':checked')
-      this.$('#terms').parents('.terms').addClass('error')
-      return false
-    else
-      this.$('#terms').parents('.terms').removeClass('error')
-      return true
-
   replaceAll: (string, token, newtoken) ->
     return string unless string && string.length > 0
     string = string.replace(token, newtoken) until string.indexOf(token) is -1


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/controllable.coffee
+++ src/controllable.coffee
@@ -16,7 +16,7 @@
   # update the player
   player.update()

-  # the player is moved
+  # the player is moved left
   player.I.x
   # => 2.5 # half the player's width


fixed potential regex error

fixed potential regex error

--- builder.coffee
+++ builder.coffee
@@ -112,7 +112,7 @@
 			version: @core.version.content.match(/version.*?\'([^\']+)\'/)[1]
 			date: @core.version.content.match(/date.*?\'([^\']+)\'/)[1]

-		res = res.replace(/{{{version}}}/, version.version)
+		res = res.replace('{{{version}}}', version.version)
 		res = [
 			"/**"
 			"  * Angular Light " + version.version + ", (c) 2016 Oleg Nechaev"
@@ -131,7 +131,7 @@
 			date: @core.version.content.match(/date.*?\'([^\']+)\'/)[1]

 		callback = (res) =>
-			res = res.replace(/{{{version}}}/, version.version)
+			res = res.replace('{{{version}}}', version.version)
 			res = "// Angular Light " + version.version + " (c) 2016 Oleg Nechaev, MIT License. " + version.date + ", http://angularlight.org/, custom build: " + document.location.href + "\n" + res
 			@download.compressed.content = res
 			@download.compressed.fileSize = res.length


Add documentation

Add documentation

--- lib/motions.coffee
+++ lib/motions.coffee
@@ -100,6 +100,13 @@
       @editor.selectToScreenPosition(screenPosition)
       true

+  # Private: Finds the end of the current word and stops on the last character
+  #
+  # exclusive - If true will stop on the last character of the word rather than
+  #             the next character after the word.
+  #
+  # The reason this is implemented here is that Atom always stops on the
+  # character after the word which is only sometimes what vim means.
   nextBufferPosition: ({exclusive}={})->
     cursor = @editor.getCursor()
     current = cursor.getBufferPosition()


Tweaked error handling to raise alert

Tweaked error handling to raise alert

--- src/core/javascripts/controllers/client_details.js.coffee
+++ src/core/javascripts/controllers/client_details.js.coffee
@@ -61,8 +61,9 @@
       $scope.decideNextPage(route)
     , (err) ->
       if err.data.error == "Please Login"
-        $scope.existing_member = true
-      $scope.setLoadedAndShowError($scope, err, 'Sorry, something went wrong')
+        $scope.existing_member = true
+        AlertService.danger({msg: "You have already registered with this email address. Please login or reset your password using the Forgot Password link below."})
+      $scope.setLoaded $scope

   $scope.clientLogin = () =>
     $scope.login_error = false


removed stupid error handling

removed stupid error handling

--- lib/orpheus.coffee
+++ lib/orpheus.coffee
@@ -344,18 +344,24 @@
 						hmget.push key
 					else
 						hash_parts_are_private = true
+
 				when 'list'
 					if not_private()
 						@_commands.push ['lrange', @get_key(key), 0, -1]
-						schema.push key
+
 				when 'set'
 					if not_private()
 						@_commands.push ['smembers', @get_key(key)]
-						schema.push key
+
 				when 'zset'
 					if not_private()
 						@_commands.push ['zrange', @get_key(key), 0, -1, 'withscores']
-						schema.push key
+
+				when 'hash'
+					if not_private()
+						@_commands.push ['hgetall', @get_key(key)]
+
+			schema.push key unless type is 'str' or type is 'num'

 		if hash_parts_are_private
 			if hmget.length


JReferralCampaign: add campaignMaxAmount, make name a required field

--- workers/social/lib/social/models/referral/campaign.coffee
+++ workers/social/lib/social/models/referral/campaign.coffee
@@ -24,7 +24,9 @@
       name                   : 'unique'

     schema                   :
-      name                   : String
+      name                   :
+        type                 : String
+        required             : yes
       slug                   : String
       isActive               : Boolean
       campaignType           :
@@ -34,6 +36,8 @@
         type                 : String
         default              : "MB"
       campaignInitialAmount  :
+        type                 : Number
+      campaignMaxAmount      :
         type                 : Number
       campaignPerEventAmount :
         type                 : Number
@@ -76,8 +80,9 @@

       campaign = new JReferralCampaign data
       campaign.save (err)->
-        return callback err  if err
-        callback null, campaign
+
+        if err then callback err
+        else callback null, campaign

   update$: permit 'manage campaign',
@@ -107,7 +112,7 @@
       callback null, campaign

-  @isCampaignValid = isCampaignValid = (campaignName, callback)->
+  isCampaignValid = (campaignName, callback)->

     unless callback
       [campaignName, callback] = [DEFAULT_CAMPAIGN, campaignName]
@@ -117,8 +122,10 @@
       return callback err  if err
       return callback null, isValid: no  unless campaign

-      { campaignGivenAmount,
-        campaignInitialAmount
+      { campaignMaxAmount,
+        campaignGivenAmount,
+        campaignInitialAmount,
+        campaignPerEventAmount,
         endDate, startDate } = campaign

       if Date.now() < startDate.getTime()
@@ -135,11 +142,17 @@
       if campaignInitialAmount is 0
         return callback null, { isValid: yes, campaign }

-      # if campaign has more disk space
-      if campaignGivenAmount > campaignInitialAmount
+      # if campaign hit the limits
+      if campaignGivenAmount + campaignPerEventAmount > campaignMaxAmount
+        console.info "hit the max amount for #{campaignName} campaign"
         return callback null, isValid: no

       return callback null, { isValid: yes, campaign }
+
+
+  @isCampaignValid = (campaignName, callback)->
+    isCampaignValid campaignName, callback
+

   increaseGivenAmountSpace:(size, callback)->
@@ -147,6 +160,4 @@
     unless callback
       [size, callback] = [@campaignPerEventAmount, size]

-    size = size * 4
-
     @update $inc: campaignGivenAmount: size , callback


Update twitter-oauth.coffee

Update twitter-oauth.coffee

--- scripts/twitter-oauth.coffee
+++ scripts/twitter-oauth.coffee
@@ -148,7 +148,7 @@
     sign = @signature(@extend_list([],post_data, oauth_headers), TwitterOAuth.URL.POST, "POST", false)
     oauth_data = @authorization(oauth_headers, sign)
     @post TwitterOAuth.URL.BASE, TwitterOAuth.URL.POST+'?'+@join_options(post_data, '&', false), oauth_data,  null, (chunk) =>
-      #@log chunk+""
+      @log chunk+""
       msg = JSON.parse(chunk+"")
       link = "https://twitter.com/#{msg['user']['screen_name'].toLowerCase()}/status/#{msg['id_str']}"
       if link?


Call getSelectedText() on Editor

Call getSelectedText() on Editor

--- src/editor-view.coffee
+++ src/editor-view.coffee
@@ -411,7 +411,7 @@

     selectedText = null
     @hiddenInput.on 'compositionstart', =>
-      selectedText = @getSelectedText()
+      selectedText = @editor.getSelectedText()
       @hiddenInput.css('width', '100%')
     @hiddenInput.on 'compositionupdate', (e) =>
       @editor.insertText(e.originalEvent.data, {select: true, undo: 'skip'})


Eliminate options object for suppressAutoscroll

It's a single option used only internally. Let's not allocate an object
for it.

--- src/editor-view.coffee
+++ src/editor-view.coffee
@@ -940,7 +940,7 @@
     @setSoftWrap(@editor.getSoftWrap())
     @newCursors = @editor.getCursors()
     @newSelections = @editor.getSelections()
-    @updateDisplay(suppressAutoScroll: true)
+    @updateDisplay(suppressAutoscroll: true)

   requestDisplayUpdate: ->
     return if @pendingDisplayUpdate
@@ -950,7 +950,7 @@
       @updateDisplay()
       @pendingDisplayUpdate = false

-  updateDisplay: (options={}) ->
+  updateDisplay: (options) ->
     return unless @attached and @editor
     return if @editor.isDestroyed()
     unless @isOnDom() and @isVisible()
@@ -962,7 +962,7 @@
     @highlightCursorLine()
     @updateCursorViews()
     @updateSelectionViews()
-    @autoscroll(options)
+    @autoscroll(options?.suppressAutoscroll ? false)
     @trigger 'editor:display-updated'

   updateCursorViews: ->
@@ -1005,14 +1005,14 @@
   syncCursorAnimations: ->
     cursorView.resetBlinking() for cursorView in @getCursorViews()

-  autoscroll: (options={}) ->
+  autoscroll: (suppressAutoscroll) ->
     for cursorView in @getCursorViews()
-      if !options.suppressAutoScroll and cursorView.needsAutoscroll()
+      if !suppressAutoscroll and cursorView.needsAutoscroll()
         @scrollToPixelPosition(cursorView.getPixelPosition())
       cursorView.clearAutoscroll()

     for selectionView in @getSelectionViews()
-      if !options.suppressAutoScroll and selectionView.needsAutoscroll()
+      if !suppressAutoscroll and selectionView.needsAutoscroll()
         @scrollToPixelPosition(selectionView.getCenterPixelPosition(), center: true)
         selectionView.highlight()
       selectionView.clearAutoscroll()


copy change

copy change

--- client/landing/app/Applications/Account.kdapplication/account/accSettingsPersEmailNotifications.coffee
+++ client/landing/app/Applications/Account.kdapplication/account/accSettingsPersEmailNotifications.coffee
@@ -10,15 +10,15 @@
       global         :
         title        : 'Email notifications'
       daily          :
-        title        : 'Daily digest'
+        title        : 'Send me a daily email about everything below'
       privateMessage :
-        title        : 'When someone send me a private message'
+        title        : 'Someone sends me a private message'
       followActions  :
-        title        : 'When someone followed me'
+        title        : 'Someone follows me'
       comment        :
-        title        : 'When a comment related with me'
+        title        : 'My post receives a comment'
       likeActivities :
-        title        : 'When someone liked my activities'
+        title        : 'When I receive likes'

     for flag, field of fields
       @addSubView field.formView = new KDFormView


execute success callback when filesystem copyfile completed

--- services/filestore/app/coffee/FSPersistorManager.coffee
+++ services/filestore/app/coffee/FSPersistorManager.coffee
@@ -53,6 +53,8 @@
     targetStream.on 'error', (err) ->
       logger.err err:err, location:location, key:filteredToName, "Error writing to file"
       callback err
+    targetStream.on 'finish', () ->
+      callback null
     sourceStream.pipe targetStream

   deleteFile: (location, name, callback)->


note that acks are for our own ops

note that acks are for our own ops

--- services/web/public/coffee/ide/editor/ShareJsDoc.coffee
+++ services/web/public/coffee/ide/editor/ShareJsDoc.coffee
@@ -46,7 +46,7 @@
 			@_doc.on "change", () =>
 				@trigger "change"
 			@_doc.on "acknowledge", () =>
-				@lastAcked = new Date() # note time of last ack from server
+				@lastAcked = new Date() # note time of last ack from server for an op we sent
 				@trigger "acknowledge"
 			@_doc.on "remoteop", () =>
 				# As soon as we're working with a collaborator, start sending


Fix JStackTemplate.one$ tests

Fix JStackTemplate.one$ tests

--- workers/social/lib/social/models/computeproviders/stacktemplate.test.coffee
+++ workers/social/lib/social/models/computeproviders/stacktemplate.test.coffee
@@ -129,10 +129,11 @@

             ->
               selector = { '_id' : stackTemplate._id }
-              StackTemplate.one$ client, selector, null, (err, templates) ->
+              StackTemplate.one$ client, selector, null, (err, template) ->
                 expect(err?.message).to.not.exist
-                expect(templates[0].title).to.be.equal stackTemplateData.title
-                expect(templates[0].template.content).to.be.deep.equal stackTemplateData.template
+                expect(template).to.exist
+                expect(template.title).to.be.equal stackTemplateData.title
+                expect(template.template.content).to.be.deep.equal stackTemplateData.template
                 queue.next()

             -> done()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/game_object.coffee
+++ src/game_object.coffee
@@ -146,7 +146,7 @@
       I.active = false
   }

-  GameObject.defaultModules.each (Module) ->
+  GameObject.defaultModules.each (moduleName) ->
     self.include Module

   self


Removed redundant code

Removed redundant code

--- memory_backbone_sync.coffee
+++ memory_backbone_sync.coffee
@@ -46,7 +46,6 @@
   cursor: (query={}) -> return new MemoryCursor(query, {model_type: @model_type})

   destroy: (query, callback) ->
-    [query, callback] = [{}, query] if arguments.length is 1
     if (keys = _.keys(query)).length
       for id, model_json of @store
         delete @store[id] if _.isEqual(_.pick(model_json, keys), query)


Fix: ロシア語の翻訳抜け

Fix: ロシア語の翻訳抜け

--- src/gui/js/repo.coffee
+++ src/gui/js/repo.coffee
@@ -200,14 +200,17 @@
           switch lang
             when "ja" then return "適用中..."
             when "en" then return "Applying..."
+            when "ru" then return "Применение..."
         when "done"
           switch lang
             when "ja" then return "適用完了"
             when "en" then return "Applied Successfully"
+            when "ru" then return "Применено успешно"
         when "failed"
           switch lang
             when "ja" then return "適用失敗"
             when "en" then return "Failed to Apply"
+            when "ru" then return "Не удалось применить"
 )
 p = new Vue(
   el: "#progress"
@@ -263,21 +266,25 @@
             switch lang
               when "ja" then p.addLog("#{mod.name} - 適用完了")
               when "en" then p.addLog("#{mod.name} - Applied Successfully")
+              when "ru" then p.addLog("#{mod.name} - Применено успешно")
           when "delete"
             $checkbox.removeClass("applied")
             switch lang
               when "ja" then p.addLog("#{mod.name} - 解除完了")
               when "en" then p.addLog("#{mod.name} - Removed Successfully")
+              when "ru" then p.addLog("#{mod.name} - Удалено успешно")
       else
         switch type
           when "add"
             switch lang
               when "ja" then p.addLog("#{mod.name} - 適用失敗(#{err})")
               when "en" then p.addLog("#{mod.name} - Failed to Apply(#{err})")
+              when "ru" then p.addLog("#{mod.name} - Не удалось применить(#{err})")
           when "delete"
             switch lang
               when "ja" then p.addLog("#{mod.name} - 解除失敗(#{err})")
               when "en" then p.addLog("#{mod.name} - Failed to Remove(#{err})")
+              when "ru" then p.addLog("#{mod.name} - Не удалось удалить(#{err})")
       return
     ).then( ->
       p.changePhase("done")


adding innerclass comments, fixes #148

adding innerclass comments, fixes #148

note that this isn't required for passing disasm tests, because we
ignore comments

--- src/disassembler.coffee
+++ src/disassembler.coffee
@@ -12,6 +12,7 @@
   (zeroes + value).slice(-padding)

 root.disassemble = (class_file) ->
+  pool = class_file.constant_pool
   access_string = (access_flags) ->
     ordered_flags = [ 'public', 'protected', 'private', 'static', 'final' ]
     ordered_flags.push 'abstract' unless access_flags.interface
@@ -40,10 +41,14 @@
     for cls in icls.classes
       flags = util.parse_flags cls.inner_access_flags
       access = ((f+' ' if flags[f]) for f in [ 'public', 'protected', 'private', 'abstract' ]).join ''
+      cls_type = util.descriptor2typestr pool.get(cls.inner_info_index).deref()
       if cls.outer_info_index <= 0  # it's an anonymous class
-        rv += "   #{access}##{cls.inner_info_index};\n"
+        rv += "   #{access}##{cls.inner_info_index}; //class #{cls_type}\n"
       else  # it's a named inner class
-        rv += "   #{access}##{cls.inner_name_index}= ##{cls.inner_info_index} of ##{cls.outer_info_index};\n"
+        rv += "   #{access}##{cls.inner_name_index}= ##{cls.inner_info_index} of ##{cls.outer_info_index};"
+        name = pool.get(cls.inner_name_index).value
+        outer_cls_type = util.descriptor2typestr pool.get(cls.outer_info_index).deref()
+        rv += " //#{name}=class #{cls_type} of class #{outer_cls_type}\n"
   rv += "  minor version: #{class_file.minor_version}\n"
   rv += "  major version: #{class_file.major_version}\n"
   rv += "  Constant pool:\n"
@@ -82,7 +87,6 @@
       when 'long' then val + "l"
       else util.escape_whitespace ((if entry.deref? then "#" else "") + val)

-  pool = class_file.constant_pool
   pool.each (idx, entry) ->
     rv += "const ##{idx} = #{entry.type}\t#{format entry};"
     rv += "#{util.format_extra_info entry}\n"


findSimilarImage should always return an array, and test the repoTag[0]

--- src/docker-utils.coffee
+++ src/docker-utils.coffee
@@ -39,10 +39,10 @@
 				return repoTag

 		# Otherwise return the most specific supervisor tag (commit hash)
-		for repoTag in repoTags when /resin\/.*-supervisor.*:[0-9a-f]{6}/.test(repoTag)
+		for repoTag in repoTags when /resin\/.*-supervisor.*:[0-9a-f]{6}/.test(repoTag[0])
 			return repoTag

-		return config.supervisorImage
+		return [ config.supervisorImage ]

 exports.rsyncImageWithProgress = (imgDest, onProgress) ->
 	findSimilarImage(imgDest)


destroy the feed if it isnt visble

destroy the feed if it isnt visble

--- components/feed/client/feed.coffee
+++ components/feed/client/feed.coffee
@@ -192,11 +192,18 @@
     return if @feedItems.doneFetching or @waiting
     return unless @lastItem?.length

+
     top = if @lastItem.offset() then @lastItem.offset().top else 0
     if @scrollTop + 1500 > top
-      @fetchMoreItems()
+      if @$el.is(':visible')
+        @fetchMoreItems()
+      else
+        # Destroy the feed if it isn't visible
+        # - helps with filtering
+        @destroy()

     @trackScroll()
+

   scrollPositionsTracked: {}
   scrollInterval: 3000


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_mouse.coffee
+++ src/engine_mouse.coffee
@@ -9,7 +9,7 @@
 ###
 Engine.Mouse = (I, self) ->
   self.bind "beforeUpdate", ->
-    # TODO: Make a Gamepad/Keyboard input module that has web and XNA
+    # TODO: Make a Gamepad/Keyboard/ input module that has web and XNA
     # implementations
     updateMouse?()


wrong folder

wrong folder

--- src/remote/gateway.coffee
+++ src/remote/gateway.coffee
@@ -6,7 +6,7 @@
 RemoteConfigStore   = require '../flux/stores/RemoteConfigStore'
 RemoteHeaderStore   = require '../flux/stores/RemoteHeaderStore'
 RemoteHeaderActions = require '../flux/actions/RemoteHeaderActions'
-QSEncoder           = require '../../utils/query-string-encoder'
+QSEncoder           = require '../utils/query-string-encoder'

 # require 'whatwg-fetch' #Polyfill for Global -> Not ready from primetime
 superagent          = require 'superagent'


Dismiss modals by clicking elsewhere on the body

--- sources/tuktuk.modal.coffee
+++ sources/tuktuk.modal.coffee
@@ -54,6 +54,9 @@
         </div>
       </div>
       """
+    tk.dom("[data-tuktuk=lock]").on "click", (e) ->
+      TukTuk.Modal.hide() unless e.target is modal
+
     lock = tk.dom("[data-tuktuk=lock]").first()
   )()


Replace for shipping selector

Replace for shipping selector

--- app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee
+++ app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee
@@ -1,5 +1,6 @@
 Darkswarm.directive "shippingTypeSelector", (FilterSelectorsService)->
   restrict: 'E'
+  replace: true
   templateUrl: 'shipping_type_selector.html'
   link: (scope, elem, attr)->
     scope.shippingTypes =


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_delay.coffee
+++ src/engine_delay.coffee
@@ -12,7 +12,7 @@

   self.bind 'afterUpdate', (elapsedTime) ->
     [delayedEvents, firingEvents] = delayedEvents.partition (event) ->
-      (event.delay -= 1) >= 0
+      (event.delay -= elapsedTime) >= 0

     firingEvents.each (event) ->
       event.callback()


Added new Circle power visualization. (Still in BETA)

--- src/documents/live/index.js.coffee
+++ src/documents/live/index.js.coffee
@@ -114,6 +114,20 @@
         0)
     return temp

+class LIVE.PowerCircle
+  constructor: (opts) ->
+    if opts?
+      {name, radius, segments, color} = opts
+    name ?= 'circle'
+    radius ?= 5
+    segments ?= 32
+    color ?= 0xff8800
+
+    material = new THREE.MeshBasicMaterial({color: color, side: THREE.DoubleSide});
+    circleGeometry = new THREE.CircleGeometry( radius, segments );
+    @object = new THREE.Mesh( circleGeometry, material);
+    @object.name = name
+
 # Get the range of safe FT values from the GUI textboxes (currently hidden because they're ugly,
 # so you are stuck with the default values).
 extractLimits = (el) ->
@@ -146,6 +160,11 @@
   stats.domElement.style.position = 'relative'
   stats.domElement.style.cssFloat = 'right'
   LIVE.stats = stats
+
+LIVE.setCircleVisibility = (val) ->
+  for joint in LIVE.hubo.joints.asArray()
+    if joint.circle?
+      joint.circle.object.visible = val

 #
 # MAIN
@@ -220,6 +239,64 @@
     # # Looks like the wrists need some rotation too.
     # hubo.ft.HUBO_FT_R_HAND.axis.rotation.y = -Math.PI/2
     # hubo.ft.HUBO_FT_L_HAND.axis.rotation.y = -Math.PI/2
+
+    # Test of new power consumption circles.
+    # TODO: Do we have to place all of these by hand?
+    power_circle_data =
+      REB:
+        py: -0.08
+        rx: 90*Math.PI/180
+      RSP:
+        py: -0.15
+        rx: 90*Math.PI/180
+      RSR:
+        px: 0.05
+        ry: 90*Math.PI/180
+      RSY:
+        pz: -0.05
+        r: 0.07
+      RWY:
+        pz: 0.05
+        r: 0.07
+      RWP:
+        py: -0.07
+        rx: 90*Math.PI/180
+      RHP:
+        py: -0.03
+        rx: 90*Math.PI/180
+      RHR:
+        px: 0.05
+        ry: 90*Math.PI/180
+      RHY:
+        pz: -0.015
+        r: 0.08
+      RKN:
+        py: -0.07
+        rx: 90*Math.PI/180
+      RAR:
+        px: 0.04
+        ry: 90*Math.PI/180
+      RAP:
+        py: -0.04
+        rx: 90*Math.PI/180
+    for k, v of power_circle_data
+      r = v.r ? 0.05
+      circle = new LIVE.PowerCircle(name: 'circle', radius: r)
+      o = circle.object
+      if (v.px?)
+        o.position.x = v.px
+      if (v.py?)
+        o.position.y = v.py
+      if (v.pz?)
+        o.position.z = v.pz
+      if (v.rx?)
+        o.rotation.x = v.rx
+      if (v.ry?)
+        o.rotation.y = v.ry
+      if (hubo.joints[k]?)
+        hubo.joints[k].circle = circle
+        hubo.joints[k].child.add(o)
+    LIVE.setCircleVisibility(false)

     updateModel = (serial_state) ->
       if (not serial_state? or serial_state == "")
@@ -314,13 +391,13 @@
         hubo.joints["LWY"].child.color.setRGB(0.866667+100*state.cur[ 8]*state.cur[ 8],0.866667+50*state.cur[ 8]*state.cur[ 8],0.866667)
       # hubo.joints["LWR"].child.color.setRGB(0.866667+100*state.cur[ 9]*state.cur[ 9],0.866667+50*state.cur[ 9]*state.cur[ 9],0.866667)
         hubo.joints["LWP"].child.color.setRGB(0.866667+100*state.cur[10]*state.cur[10],0.866667+50*state.cur[10]*state.cur[10],0.866667)
-        hubo.joints["RSP"].child.color.setRGB(0.866667+100*state.cur[11]*state.cur[11],0.866667+50*state.cur[11]*state.cur[11],0.866667)
-        hubo.joints["RSR"].child.color.setRGB(0.866667+100*state.cur[12]*state.cur[12],0.866667+50*state.cur[12]*state.cur[12],0.866667)
-        hubo.joints["RSY"].child.color.setRGB(0.866667+100*state.cur[13]*state.cur[13],0.866667+50*state.cur[13]*state.cur[13],0.866667)
-        hubo.joints["REB"].child.color.setRGB(0.866667+100*state.cur[14]*state.cur[14],0.866667+50*state.cur[14]*state.cur[14],0.866667)
-        hubo.joints["RWY"].child.color.setRGB(0.866667+100*state.cur[15]*state.cur[15],0.866667+50*state.cur[15]*state.cur[15],0.866667)
+        # hubo.joints["RSP"].child.color.setRGB(0.866667+100*state.cur[11]*state.cur[11],0.866667+50*state.cur[11]*state.cur[11],0.866667)
+        # hubo.joints["RSR"].child.color.setRGB(0.866667+100*state.cur[12]*state.cur[12],0.866667+50*state.cur[12]*state.cur[12],0.866667)
+        # hubo.joints["RSY"].child.color.setRGB(0.866667+100*state.cur[13]*state.cur[13],0.866667+50*state.cur[13]*state.cur[13],0.866667)
+        # hubo.joints["REB"].child.color.setRGB(0.866667+100*state.cur[14]*state.cur[14],0.866667+50*state.cur[14]*state.cur[14],0.866667)
+        # hubo.joints["RWY"].child.color.setRGB(0.866667+100*state.cur[15]*state.cur[15],0.866667+50*state.cur[15]*state.cur[15],0.866667)
       # hubo.joints["RWR"].child.color.setRGB(0.866667+100*state.cur[16]*state.cur[16],0.866667+50*state.cur[16]*state.cur[16],0.866667)
-        hubo.joints["RWP"].child.color.setRGB(0.866667+100*state.cur[17]*state.cur[17],0.866667+50*state.cur[17]*state.cur[17],0.866667)
+        # hubo.joints["RWP"].child.color.setRGB(0.866667+100*state.cur[17]*state.cur[17],0.866667+50*state.cur[17]*state.cur[17],0.866667)
         # mind the gap
         hubo.joints["LHY"].child.color.setRGB(0.866667+100*state.cur[19]*state.cur[19],0.866667+50*state.cur[19]*state.cur[19],0.866667)
         hubo.joints["LHR"].child.color.setRGB(0.866667+100*state.cur[20]*state.cur[20],0.866667+50*state.cur[20]*state.cur[20],0.866667)
@@ -329,22 +406,56 @@
         hubo.joints["LAP"].child.color.setRGB(0.866667+100*state.cur[23]*state.cur[23],0.866667+50*state.cur[23]*state.cur[23],0.866667)
         hubo.joints["LAR"].child.color.setRGB(0.866667+100*state.cur[24]*state.cur[24],0.866667+50*state.cur[24]*state.cur[24],0.866667)
         # mind the gap
-        hubo.joints["RHY"].child.color.setRGB(0.866667+100*state.cur[26]*state.cur[26],0.866667+50*state.cur[26]*state.cur[26],0.866667)
-        hubo.joints["RHR"].child.color.setRGB(0.866667+100*state.cur[27]*state.cur[27],0.866667+50*state.cur[27]*state.cur[27],0.866667)
-        hubo.joints["RHP"].child.color.setRGB(0.866667+100*state.cur[28]*state.cur[28],0.866667+50*state.cur[28]*state.cur[28],0.866667)
-        hubo.joints["RKN"].child.color.setRGB(0.866667+100*state.cur[29]*state.cur[29],0.866667+50*state.cur[29]*state.cur[29],0.866667)
-        hubo.joints["RAP"].child.color.setRGB(0.866667+100*state.cur[30]*state.cur[30],0.866667+50*state.cur[30]*state.cur[30],0.866667)
-        hubo.joints["RAR"].child.color.setRGB(0.866667+100*state.cur[31]*state.cur[31],0.866667+50*state.cur[31]*state.cur[31],0.866667)
-        # hubo.joints["RF1"].child.color.setRGB(0.866667+100*state.cur[32]*state.cur[32],0.866667+state.cur[32]*5,0.866667)
-        # hubo.joints["RF2"].child.color.setRGB(0.866667+100*state.cur[33]*state.cur[33],0.866667+state.cur[33]*5,0.866667)
-        # hubo.joints["RF3"].child.color.setRGB(0.866667+100*state.cur[34]*state.cur[34],0.866667+state.cur[34]*5,0.866667)
-        # hubo.joints["RF4"].child.color.setRGB(0.866667+100*state.cur[35]*state.cur[35],0.866667+state.cur[35]*5,0.866667)
-        # hubo.joints["RF5"].child.color.setRGB(0.866667+100*state.cur[36]*state.cur[36],0.866667+state.cur[36]*5,0.866667)
-        # hubo.joints["LF1"].child.color.setRGB(0.866667+100*state.cur[37]*state.cur[37],0.866667+state.cur[37]*5,0.866667)
-        # hubo.joints["LF2"].child.color.setRGB(0.866667+100*state.cur[38]*state.cur[38],0.866667+state.cur[38]*5,0.866667)
-        # hubo.joints["LF3"].child.color.setRGB(0.866667+100*state.cur[39]*state.cur[39],0.866667+state.cur[39]*5,0.866667)
-        # hubo.joints["LF4"].child.color.setRGB(0.866667+100*state.cur[40]*state.cur[40],0.866667+state.cur[40]*5,0.866667)
-        # hubo.joints["LF5"].child.color.setRGB(0.866667+100*state.cur[41]*state.cur[41],0.866667+state.cur[41]*5,0.866667)
+        # hubo.joints["RHY"].child.color.setRGB(0.866667+100*state.cur[26]*state.cur[26],0.866667+50*state.cur[26]*state.cur[26],0.866667)
+        # hubo.joints["RHR"].child.color.setRGB(0.866667+100*state.cur[27]*state.cur[27],0.866667+50*state.cur[27]*state.cur[27],0.866667)
+        # hubo.joints["RHP"].child.color.setRGB(0.866667+100*state.cur[28]*state.cur[28],0.866667+50*state.cur[28]*state.cur[28],0.866667)
+        # hubo.joints["RKN"].child.color.setRGB(0.866667+100*state.cur[29]*state.cur[29],0.866667+50*state.cur[29]*state.cur[29],0.866667)
+        # hubo.joints["RAP"].child.color.setRGB(0.866667+100*state.cur[30]*state.cur[30],0.866667+50*state.cur[30]*state.cur[30],0.866667)
+        # hubo.joints["RAR"].child.color.setRGB(0.866667+100*state.cur[31]*state.cur[31],0.866667+50*state.cur[31]*state.cur[31],0.866667)
+
+        # New power visualization
+        # hubo.joints["WST"].circle.object.material.color.setRGB(0.866667+100*state.cur[ 0]*state.cur[ 0],0.866667+50*state.cur[ 0]*state.cur[ 0],0.866667)
+        # hubo.joints["NKY"].circle.object.material.color.setRGB(0.866667+100*state.cur[ 1]*state.cur[ 1],0.866667+50*state.cur[ 1]*state.cur[ 1],0.866667)
+      # hubo.joints["NK1"].circle.object.material.color.setRGB(0.866667+100*state.cur[ 2]*state.cur[ 2],0.866667+50*state.cur[ 2]*state.cur[ 2],0.866667)
+      # hubo.joints["NK2"].circle.object.material.color.setRGB(0.866667+100*state.cur[ 3]*state.cur[ 3],0.866667+50*state.cur[ 3]*state.cur[ 3],0.866667)
+        # hubo.joints["LSP"].circle.object.material.color.setRGB(0.866667+100*state.cur[ 4]*state.cur[ 4],0.866667+50*state.cur[ 4]*state.cur[ 4],0.866667)
+        # hubo.joints["LSR"].circle.object.material.color.setRGB(0.866667+100*state.cur[ 5]*state.cur[ 5],0.866667+50*state.cur[ 5]*state.cur[ 5],0.866667)
+        # hubo.joints["LSY"].circle.object.material.color.setRGB(0.866667+100*state.cur[ 6]*state.cur[ 6],0.866667+50*state.cur[ 6]*state.cur[ 6],0.866667)
+        # hubo.joints["LEB"].circle.object.material.color.setRGB(0.866667+100*state.cur[ 7]*state.cur[ 7],0.866667+50*state.cur[ 7]*state.cur[ 7],0.866667)
+        # hubo.joints["LWY"].circle.object.material.color.setRGB(0.866667+100*state.cur[ 8]*state.cur[ 8],0.866667+50*state.cur[ 8]*state.cur[ 8],0.866667)
+      # hubo.joints["LWR"].circle.object.material.color.setRGB(0.866667+100*state.cur[ 9]*state.cur[ 9],0.866667+50*state.cur[ 9]*state.cur[ 9],0.866667)
+        # hubo.joints["LWP"].circle.object.material.color.setRGB(0.866667+100*state.cur[10]*state.cur[10],0.866667+50*state.cur[10]*state.cur[10],0.866667)
+        hubo.joints["RSP"].circle.object.material.color.setRGB(100*state.cur[11]*state.cur[11],50*state.cur[11]*state.cur[11],0)
+        hubo.joints["RSR"].circle.object.material.color.setRGB(100*state.cur[12]*state.cur[12],50*state.cur[12]*state.cur[12],0)
+        hubo.joints["RSY"].circle.object.material.color.setRGB(100*state.cur[13]*state.cur[13],50*state.cur[13]*state.cur[13],0)
+        hubo.joints["REB"].circle.object.material.color.setRGB(100*state.cur[14]*state.cur[14],50*state.cur[14]*state.cur[14],0)
+        hubo.joints["RWY"].circle.object.material.color.setRGB(100*state.cur[15]*state.cur[15],50*state.cur[15]*state.cur[15],0)
+      # hubo.joints["RWR"].circle.object.material.color.setRGB(100*state.cur[16]*state.cur[16],50*state.cur[16]*state.cur[16],0)
+        hubo.joints["RWP"].circle.object.material.color.setRGB(100*state.cur[17]*state.cur[17],50*state.cur[17]*state.cur[17],0)
+        # mind the gap
+        # hubo.joints["LHY"].circle.object.material.color.setRGB(100*state.cur[19]*state.cur[19],50*state.cur[19]*state.cur[19],0)
+        # hubo.joints["LHR"].circle.object.material.color.setRGB(100*state.cur[20]*state.cur[20],50*state.cur[20]*state.cur[20],0)
+        # hubo.joints["LHP"].circle.object.material.color.setRGB(100*state.cur[21]*state.cur[21],50*state.cur[21]*state.cur[21],0)
+        # hubo.joints["LKN"].circle.object.material.color.setRGB(100*state.cur[22]*state.cur[22],50*state.cur[22]*state.cur[22],0)
+        # hubo.joints["LAP"].circle.object.material.color.setRGB(100*state.cur[23]*state.cur[23],50*state.cur[23]*state.cur[23],0)
+        # hubo.joints["LAR"].circle.object.material.color.setRGB(100*state.cur[24]*state.cur[24],50*state.cur[24]*state.cur[24],0)
+        # mind the gap
+        hubo.joints["RHY"].circle.object.material.color.setRGB(100*state.cur[26]*state.cur[26],50*state.cur[26]*state.cur[26],0)
+        hubo.joints["RHR"].circle.object.material.color.setRGB(100*state.cur[27]*state.cur[27],50*state.cur[27]*state.cur[27],0)
+        hubo.joints["RHP"].circle.object.material.color.setRGB(100*state.cur[28]*state.cur[28],50*state.cur[28]*state.cur[28],0)
+        hubo.joints["RKN"].circle.object.material.color.setRGB(100*state.cur[29]*state.cur[29],50*state.cur[29]*state.cur[29],0)
+        hubo.joints["RAP"].circle.object.material.color.setRGB(100*state.cur[30]*state.cur[30],50*state.cur[30]*state.cur[30],0)
+        hubo.joints["RAR"].circle.object.material.color.setRGB(100*state.cur[31]*state.cur[31],50*state.cur[31]*state.cur[31],0)
+        # hubo.joints["RF1"].circle.object.material.color.setRGB(0.866667+100*state.cur[32]*state.cur[32],0.866667+state.cur[32]*5,0.866667)
+        # hubo.joints["RF2"].circle.object.material.color.setRGB(0.866667+100*state.cur[33]*state.cur[33],0.866667+state.cur[33]*5,0.866667)
+        # hubo.joints["RF3"].circle.object.material.color.setRGB(0.866667+100*state.cur[34]*state.cur[34],0.866667+state.cur[34]*5,0.866667)
+        # hubo.joints["RF4"].circle.object.material.color.setRGB(0.866667+100*state.cur[35]*state.cur[35],0.866667+state.cur[35]*5,0.866667)
+        # hubo.joints["RF5"].circle.object.material.color.setRGB(0.866667+100*state.cur[36]*state.cur[36],0.866667+state.cur[36]*5,0.866667)
+        # hubo.joints["LF1"].circle.object.material.color.setRGB(0.866667+100*state.cur[37]*state.cur[37],0.866667+state.cur[37]*5,0.866667)
+        # hubo.joints["LF2"].circle.object.material.color.setRGB(0.866667+100*state.cur[38]*state.cur[38],0.866667+state.cur[38]*5,0.866667)
+        # hubo.joints["LF3"].circle.object.material.color.setRGB(0.866667+100*state.cur[39]*state.cur[39],0.866667+state.cur[39]*5,0.866667)
+        # hubo.joints["LF4"].circle.object.material.color.setRGB(0.866667+100*state.cur[40]*state.cur[40],0.866667+state.cur[40]*5,0.866667)
+        # hubo.joints["LF5"].circle.object.material.color.setRGB(0.866667+100*state.cur[41]*state.cur[41],0.866667+state.cur[41]*5,0.866667)

       hubo.canvas.render()

@@ -370,6 +481,12 @@
       # current visualization off, but doesn't hurt.
       for link in hubo.links.asArray()
         link.unhighlight()
+      if @value == 'on'
+        LIVE.setCircleVisibility(true)
+        hubo.canvas.render()
+      else if @value == 'off'
+        LIVE.setCircleVisibility(false)
+        hubo.canvas.render()

     $('#fullscreen-button').on 'click', () ->
       if (document.webkitFullscreenEnabled)


Fix stop game time

Fix stop game time

--- pages/games.coffee
+++ pages/games.coffee
@@ -88,9 +88,9 @@
       .then (words) ->
         players = uniquePlayers(words)
         first_time = words[0].time
-        last_time = words[words.length - 1].time
         for word in words
           word.time = word.time - first_time + 1000
+        last_time = words[words.length - 1].time
         res.set {
           'Content-Type': 'text/yaml'
         }
@@ -98,6 +98,6 @@
           layout: false
           players: players
           words: words
-          end_time: last_time + 1000
+          end_time: last_time + 300
       .catch (error) ->
         console.error(error)


RootView.initialize no longer assigns window.rootView or calls open

--- spec/go-to-line-spec.coffee
+++ spec/go-to-line-spec.coffee
@@ -5,14 +5,12 @@
   [goToLine, editor] = []

   beforeEach ->
-    new RootView(require.resolve('fixtures/sample.js'))
+    window.rootView = new RootView
+    rootView.open('sample.js')
     rootView.enableKeymap()
     editor = rootView.getActiveEditor()
     goToLine = GoToLineView.activate()
     editor.setCursorBufferPosition([1,0])
-
-  afterEach ->
-    rootView.remove()

   describe "when editor:go-to-line is triggered", ->
     it "attaches to the root view", ->


Add GitHub Enterprise support to github-issue-link

--- src/scripts/github-issue-link.coffee
+++ src/scripts/github-issue-link.coffee
@@ -8,9 +8,13 @@
 # Configuration:
 #   HUBOT_GITHUB_REPO
 #   HUBOT_GITHUB_TOKEN
+#   HUBOT_GITHUB_API
 #
 # Commands:
 #   Listens for #nnn and links to the issue for your default repo on github
+#
+# Notes:
+#   HUBOT_GITHUB_API allows you to set a custom URL path (for Github enterprise users)
 #
 # Author:
 #   tenfef
@@ -24,6 +28,11 @@

     bot_github_repo = github.qualified_repo process.env.HUBOT_GITHUB_REPO
     issue_title = ""
-    github.get "https://api.github.com/repos/#{bot_github_repo}/issues/" + issue_number, (issue_obj) ->
+    base_url = process.env.HUBOT_GITHUB_API || 'https://api.github.com'
+    github.get "#{base_url}/repos/#{bot_github_repo}/issues/" + issue_number, (issue_obj) ->
       issue_title = issue_obj.title
-      msg.send "Issue " + issue_number + ": " + issue_title  + "  https://github.com/" + bot_github_repo + '/issues/' + issue_number
+      unless process.env.HUBOT_GITHUB_API
+        url = "https://github.com/"
+      else
+        url = base_url.replace /api\/v3/, ''
+      msg.send "Issue " + issue_number + ": " + issue_title  + "  #{url}" + bot_github_repo + '/issues/' + issue_number


Use atom-api for requires

Use atom-api for requires

--- spec/whitespace-spec.coffee
+++ spec/whitespace-spec.coffee
@@ -1,21 +1,21 @@
-fsUtils = require 'fs-utils'
+{fs} = require 'atom-api'

 describe "Whitespace", ->
   [editor, buffer, path] = []

   beforeEach ->
     path = "/tmp/atom-whitespace.txt"
-    fsUtils.writeSync(path, "")
+    fs.writeSync(path, "")
     editor = project.open(path)
     buffer = editor.getBuffer()

     atom.activatePackage('whitespace')

   afterEach ->
-    fsUtils.remove(path) if fsUtils.exists(path)
+    fs.remove(path) if fs.exists(path)

   it "strips trailing whitespace before an editor saves a buffer", ->
-    spyOn(fsUtils, 'write')
+    spyOn(fs, 'write')

     config.set("whitespace.ensureSingleTrailingNewline", false)

@@ -34,7 +34,7 @@

   describe "when the edit session is destroyed", ->
     beforeEach ->
-      spyOn(fsUtils, 'write')
+      spyOn(fs, 'write')
       config.set("whitespace.ensureSingleTrailingNewline", false)

       buffer.retain()


Added unit test for new DOM method

Added unit test for new DOM method

--- specs/micro.dom.spec.coffee
+++ specs/micro.dom.spec.coffee
@@ -1,6 +1,6 @@
 'use strict'

-el = document.write '
Fixture
'
+el = document.write '
Fixture
<input type="text" name="username" value="dreyacosta" />'

 describe "DOM manipulation methods", ->

@@ -11,6 +11,10 @@
   it "should get fixture div innerHTML", ->
     div = u('#fixture')
     expect(do div.html).toEqual 'Fixture'
+
+  it "should get fixture input value", ->
+    inputEl = u('input[name=username]')
+    expect(do inputEl.value).toEqual "dreyacosta"

   it "should modify fixture div content", ->
     div = u('#fixture').html 'Hello World'


Add project navigation tracking

Add project navigation tracking

--- src/smc-webapp/project/file-tab.cjsx
+++ src/smc-webapp/project/file-tab.cjsx
@@ -11,6 +11,8 @@
 {NavItem} = require('react-bootstrap')

 {COLORS, HiddenXS, Icon, Tip} = require('../r_misc')
+
+{analytics_event} = require("../tracker")

 exports.DEFAULT_FILE_TAB_STYLES =
     width        : 250
@@ -60,11 +62,13 @@
     click: (e) ->
         actions = @actions(project_id: @props.project_id)
         if @props.file_tab and (e.ctrlKey or e.shiftKey or e.metaKey)
+            analytics_event('project_navigation', 'opened_a_file')
             # shift/ctrl/option clicking on *file* tab opens in a new popout window.
             actions.open_file
                 path               : misc.tab_to_path(@props.name)
                 new_browser_window : true
         else
+            analytics_event('project_navigation', 'opened_' + @props.name)
             actions.set_active_tab(@props.name)

     # middle mouse click closes


get rid of tooltips fixing a bug with labels for proj buttons; also get rid of ..., since it wastes space

--- src/smc-webapp/project/file-tab.cjsx
+++ src/smc-webapp/project/file-tab.cjsx
@@ -10,7 +10,7 @@

 {NavItem} = require('react-bootstrap')

-{COLORS, Icon, Tip} = require('../r_misc')
+{COLORS, Icon} = require('../r_misc')

 exports.DEFAULT_FILE_TAB_STYLES =
     width        : 250
@@ -89,7 +89,7 @@
         label_styles =
             whiteSpace   : 'nowrap'
             overflow     : 'hidden'
-            textOverflow : 'ellipsis'
+            # textOverflow : 'ellipsis'   # removed, since it ends up wasting precious space!

         x_button_styles =
             float      : 'right'
@@ -117,9 +117,7 @@
                     /> if @props.file_tab}
                 </div>
                 <div style={label_styles}>
-                    <Tip title={@props.tooltip} stable={true} placement='bottom' size='small'>
-                        <Icon style={icon_style} name={@props.icon} /> {@props.label if not @props.shrink}
-                    </Tip>
+                    <Icon style={icon_style} name={@props.icon} /> {@props.label if not @props.shrink}
                 </div>
             </div>
         </NavItem>


webapp/md viewer: quick idea how to fix margins

--- src/smc-webapp/public/editor_md.cjsx
+++ src/smc-webapp/public/editor_md.cjsx
@@ -45,8 +45,12 @@
         else if not @props.content?
             <Loading />
         else
-

-                <Markdown project_id={@props.project_id} file_path={@props.file_path} value={@props.content} />
+

+                <Markdown
+                    project_id  = {@props.project_id}
+                    file_path   = {@props.file_path}
+                    style       = {marginLeft: "2em", marginRight: "2em"}
+                    value       = {@props.content} />

 class MDActions extends Actions


updating label text

updating label text

--- src/components/task-plan/homework/exercise-summary.cjsx
+++ src/components/task-plan/homework/exercise-summary.cjsx
@@ -76,7 +76,7 @@
         <BS.Row>
           <BS.Col sm={6} md={2} className="total">

{total}

-            Problems Selected
+            Total Problems
           </BS.Col>
           <BS.Col sm={6} md={2} className="num-selected">

{numSelected}


Ignore string package data

Ignore string package data

It indicates an unmet dependency

--- src/legal-eagle.coffee
+++ src/legal-eagle.coffee
@@ -16,6 +16,9 @@
       cb(err)

 findLicenses = (licenseSummary, packageData, path) ->
+  # Unmet dependencies are left as strings
+  return if typeof packageData is 'string'
+
   {name, version, dependencies, engines} = packageData
   id = "#{name}@#{version}"


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/level_state.coffee
+++ src/level_state.coffee
@@ -1,6 +1,6 @@
 LevelState = (I={}) ->
   Object.reverseMerge I,
-    duration: 1
+    duration: 10
     level: 'level1'

   self = GameState(I)
@@ -8,7 +8,7 @@
   self.bind "enter", ->
     # TODO: Adjustable Fade In
     engine.fadeIn
-      duration: 10
+      duration: I.duration

     engine.loadMap I.level, ->
       engine.I.transitioning = false


Updated bbServices to filter out event groups unless requested not to

--- src/core/javascripts/controllers/service_list.js.coffee
+++ src/core/javascripts/controllers/service_list.js.coffee
@@ -64,6 +64,10 @@
           # if we've selected a category for the current item - limit the list
           # of services to ones that are relevant
           items = items.filter (x) -> x.$has('category') && x.$href('category') is $scope.booking_item.category.self
+
+      # filter out event groups unless explicity requested
+      if !$scope.options.show_event_groups
+        items = items.filter (x) -> !x.is_event_group

       if (items.length is 1 && !$scope.allowSinglePick)
         if !$scope.selectItem(items[0], $scope.nextRoute )


Update test instance to AMI v6

Update test instance to AMI v6

--- scripts/test-instance/instance-ami.coffee
+++ scripts/test-instance/instance-ami.coffee
@@ -1,5 +1,5 @@
 module.exports  =
-  current: 'ami-cc7842a4'
+  current: 'ami-10465678'

   # Ordered by creation date
   list: [
@@ -8,4 +8,5 @@
     'ami-e06c2488'
     'ami-c4c397ac'
     'ami-cc7842a4'
+    'ami-10465678'
   ]


Allow login from custom oAuth in accounts meld

--- server/configuration/accounts_meld.coffee
+++ server/configuration/accounts_meld.coffee
@@ -1,6 +1,6 @@
 orig_updateOrCreateUserFromExternalService = Accounts.updateOrCreateUserFromExternalService
 Accounts.updateOrCreateUserFromExternalService = (serviceName, serviceData, options) ->
-	if serviceName not in ['facebook', 'github', 'gitlab', 'google', 'meteor-developer', 'linkedin', 'twitter']
+	if serviceName not in ['facebook', 'github', 'google', 'meteor-developer', 'linkedin', 'twitter'] and serviceData._oAuthCustom isnt true
 		return

 	if serviceName is 'meteor-developer'


dumb workaround for $ escape issue in sagews...

--- src/smc-webapp/sagews/sagews.coffee
+++ src/smc-webapp/sagews/sagews.coffee
@@ -1534,7 +1534,9 @@

         if mesg.md?
             # markdown
-            html = markdown.markdown_to_html(mesg.md)
+            # we replace all backslashes by double backslashes since bizarely the markdown-it processes replaces \$ with $, which
+            # breaks later use of mathjax :-(.  This will get deleted soon.
+            html = markdown.markdown_to_html(misc.replace_all(mesg.md,'\\$', '\\\\$'))
             t = $('<div class="sagews-output-md">')
             if @editor.opts.allow_javascript_eval
                 t.html(html)


Update - json formatting to coffeescript style.

--- src/spec/product-import.spec.coffee
+++ src/spec/product-import.spec.coffee
@@ -1,80 +1,76 @@
 _ = require 'underscore'
-_.mixin require('underscore-mixins')
+_.mixin require 'underscore-mixins'
 {ProductImport} = require '../coffee'
-Config = require('../../config')
+Config = require '../../config'
 Promise = require 'bluebird'

 sampleProducts = [
-  {
-    masterVariant: { sku: 'a' }
+    masterVariant:
+      sku: 'a'
     variants: [
-      { id: 2, sku: 'b' },
-      { id: 3 },
-      { id: 4, sku: 'c' },
+      id: 2
+      sku: 'b'
+    ,
+      id: 3
+    ,
+      id: 4
+      sku: 'c'
     ]
-  },
-  {
+  ,
     masterVariant: {}
     variants: [
-      { id: 2, sku: 'b' },
-      { id: 3, sku: 'd' },
+      id: 2
+      sku: 'b'
+    ,
+      id: 3
+      sku: 'd'
     ]
-  },
-  {
-    masterVariant: { sku: 'e' }
+  ,
+    masterVariant:
+      sku: 'e'
     variants: []
-  }
 ]

-sampleNewProduct = {
-
-  productType: { id: 'product_type_name' }
-
-  taxCategory: { id: 'tax_category_name' }
-
+sampleNewProduct =
+  productType:
+    id: 'product_type_name'
+  taxCategory:
+    id: 'tax_category_name'
   categories: [
-    { id: 'category_external_id1' },
-    { id: 'category_external_id2' }
-  ]
-}
-
-sampleMasterVariant = {
-  sku: '12345',
-  id: 1,
+    id: 'category_external_id1'
+  ,
+    id: 'category_external_id2'
+  ]
+
+sampleMasterVariant =
+  sku: '12345'
+  id: 1
   attributes: [
-    {
-      name: 'attribute1',
-      value: 'attribute1_value1'
-    }
-  ],
+     name: 'attribute1'
+     value: 'attribute1_value1'
+  ]
   images: []
-}
-
-sampleVariant1 = {
-  id: '2',
-  sku: '12345_2',
+
+sampleVariant1 =
+  id: '2'
+  sku: '12345_2'
   attributes: [
-    {
-      name: 'attribute1',
-      value: 'attribute1_value2'
-    },
-    images: []
-  ]
-}
-
-sampleVariant2 = {
-  id: '7',
-  sku: '12345_7',
+    name: 'attribute1'
+    value: 'attribute1_value2'
+  ]
+  images: []
+
+
+sampleVariant2 =
+  id: '7'
+  sku: '12345_7'
   attributes: [
-    {
-      name: 'attribute1',
-      value: 'attribute1_value3'
-    },
-    images: []
-  ]
-}
-
-sampleNewPreparedProduct = {
+    name: 'attribute1'
+    value: 'attribute1_value3'
+  ]
+  images: []
+
+sampleNewPreparedProduct =
   productType:
     id: 'product_type_internal_id'
     typeId: 'product-type'
@@ -84,83 +80,66 @@
     typeId: 'tax-category'

   categories: [
-    {
-      id: 'category_internal_id1'
-      typeId: 'category'
-    },
-    {
-      id: 'category_internal_id1'
-      typeId: 'category'
-    }
-  ]
-
-}
+    id: 'category_internal_id1'
+    typeId: 'category'
+  ,
+    id: 'category_internal_id1'
+    typeId: 'category'
+  ]

 sampleProductProjectionResponse = [
-  {
-    masterVariant : { sku: 'e'},
-    variants: []
-  }
+  masterVariant :
+    sku: 'e'
+  variants: []
 ]

 sampleProductTypeResponse =
   body:
     results: [
-      {
-        id: 'product_type_internal_id',
-        version: 1,
-        name: 'AGS',
-        description: 'Gütesiegel',
-        classifier: 'Complex',
-        attributes: [ ],
-        createdAt: '2015-04-15T15:11:07.175Z',
-        lastModifiedAt: '2015-04-15T15:11:07.175Z'
-      }
+      id: 'product_type_internal_id'
+      version: 1
+      name: 'AGS'
+      description: 'Gütesiegel'
+      classifier: 'Complex'
+      attributes: [ ]
+      createdAt: '2015-04-15T15:11:07.175Z'
+      lastModifiedAt: '2015-04-15T15:11:07.175Z'
     ]

 sampleTaxCategoryResponse =
   body:
     results: [
-      {
-        id: 'tax_category_internal_id',
-        version: 5,
-        name: 'defaultTax_AT',
-        description: 'Steuer Österreich',
-        rates: [
-          {
-            name: '20% MwSt',
-            amount: 0.2,
-            includedInPrice: true,
-            country: 'AT',
-            id: '2CV8kXRE'
-          }
-        ],
-        createdAt: '2015-03-03T10:12:22.136Z',
-        lastModifiedAt: '2015-04-16T07:36:36.123Z'
-      }
+      id: 'tax_category_internal_id'
+      version: 5
+      name: 'defaultTax_AT'
+      description: 'Steuer Österreich'
+      rates: [
+        name: '20% MwSt'
+        amount: 0.2
+        includedInPrice: true
+        country: 'AT'
+        id: '2CV8kXRE'
+      ]
+      createdAt: '2015-03-03T10:12:22.136Z'
+      lastModifiedAt: '2015-04-16T07:36:36.123Z'
     ]

 sampleCategoriesResponse =
   body:
     results: [
-      {
-        id: 'category_internal_id1'
-        version: 2
-        name:
-          de: 'obst-gemuse1'
-        ancestors: []
-        externalId: 'category_external_id1'
-      }
+      id: 'category_internal_id1'
+      version: 2
+      name:
+        de: 'obst-gemuse1'
+      ancestors: []
+      externalId: 'category_external_id1'
     ]

 sampleReferenceCats =
   [
-    {
-      id: 'category_external_id1'
-    },
-    {
-      id: 'category_external_id2'
-    }
+    id: 'category_external_id1'
+  ,
+    id: 'category_external_id2'
   ]

 describe 'ProductImport', ->
@@ -388,24 +367,16 @@

       existingProducts = [existingProduct1,existingProduct2]

-      expectedUpdateActions = {
+      expectedUpdateActions =
         actions: [
-          {
-            action: 'addVariant',
-            sku: '9876_2_3',
-            attributes: [
-              {
-                name: 'attribute1',
-                value: 'attribute1_value3'
-              },
-              {
-                images: []
-              }
-            ]
-          }
+          action: 'addVariant'
+          sku: '9876_2_3'
+          attributes: [
+            name: 'attribute1'
+            value: 'attribute1_value3'
+          ]
         ],
         version: 1
-      }

       spyOn(@import, "_prepareNewProduct").andCallFake (prepareProduct) => Promise.resolve(prepareProduct)
       spyOn(@import.client._rest, 'POST').andCallFake (endpoint, payload, callback) ->


unbind click event on flag

unbind click event on flag

--- app/assets/javascripts/api/define_behavior.js.coffee
+++ app/assets/javascripts/api/define_behavior.js.coffee
@@ -102,14 +102,16 @@
   $("flagcomment:not(.juvia-installed-behavior)").each ->
     $this = $(this)
     unless $this.hasClass("flagged")
-      $this.addClass "juvia-installed-behavior"
-      $this.bind "click", (event) ->
-        if confirm("Are you sure you wish to flag this comment?")
-          $(this).removeClass "juvia-installed-behavior"
-          $this.unbind "click"
-          self.reportComment event, this
-        else
-          false
+      $flag_span = $($this.find("span"))
+      unless $flag_span.html() == " Flagged"
+        $this.addClass "juvia-installed-behavior"
+        $this.bind "click", (event) ->
+          if confirm("Are you sure you wish to flag this comment?")
+            $(this).removeClass "juvia-installed-behavior"
+            $this.unbind "click"
+            self.reportComment event, this
+          else
+            false

   $(".juvia-comment-function").each ->


reverse articles

reverse articles

--- app/assets/javascripts/components/articles.js.coffee
+++ app/assets/javascripts/components/articles.js.coffee
@@ -6,9 +6,6 @@
 	addArticle: (article) ->
 		articles = @state.articles.slice()
 		articles.push article
-		@setState articles: articles
-	reverseArticles: ->
-		articles = articles.reverse()
 		@setState articles: articles
 	render: ->
 		React.DOM.div
@@ -21,7 +18,7 @@
 				className: 'table table-bordered'
 				React.DOM.thead null
 					React.DOM.th null, "Article URL"
-						onClick: @reverseArticles
+						onClick: @state.articles.reverse()
 					React.DOM.th null, "Status"
 					React.DOM.th null, "Mood Music URL"
 				React.DOM.tbody null,


move version offset to default argument

move version offset to default argument

--- source/infrastructure/commit_store.coffee
+++ source/infrastructure/commit_store.coffee
@@ -65,9 +65,7 @@
       throw new Error "Expected entity <#{sourceId}> to be at version
                       #{expectedVersion} but was on #{currentVersion}"

-  getEvents: (sourceId, versionOffset) ->
-
-    versionOffset ?= 1
+  getEvents: (sourceId, versionOffset=1) ->
     events = []
     withVersionOffset = {
       sourceId: sourceId.toString()


CookieCnil :: Remove unnecessary fallbacks property

--- app/assets/javascripts/plugins/cookie_cnil.js.coffee
+++ app/assets/javascripts/plugins/cookie_cnil.js.coffee
@@ -1,5 +1,4 @@
 $(document).on 'ready page:load page:restore', ->
-  I18n.fallbacks = true
   if Cookies.get('cookiebar_cnil') is undefined and !gon.disable_cookie_message
     $('body').append(
       "<div class='cookie_cnil' id='cookie_cnil'>


fix performance problem in specs

fix performance problem in specs

when loading several maps with deps the memorized callbacks should only
be fired once otherwise we create thousands of instances.

--- app/scripts/services/angular_template_service.coffee
+++ app/scripts/services/angular_template_service.coffee
@@ -35,7 +35,7 @@
     if dependency
       cb = yepnopeQueue[dependency]
       unless cb
-        cb = $.Callbacks()
+        cb = $.Callbacks('once memory')
         yepnopeQueue[dependency] = cb
       cb.add(callback)


Improve fixCorruptContainerBounds editor command (#715)

--- app/views/editor/thang/ThangTypeEditView.ozar.coffee
+++ app/views/editor/thang/ThangTypeEditView.ozar.coffee
@@ -647,10 +647,31 @@
   #  no big ones.
   #  When dryRun is true, no mutation takes place. Instead all containers with bounds
   #  larger than the maxBounds are logged letting you find them.
-  fixCorruptContainerBounds: (boundsWidthToFix=400, dryRun=true) ->
+  fixCorruptContainerBounds: (boundsWidthToFix=400, dryRun=true, backupBounds=undefined) ->
+    console.log("""
+      Running fixCorruptContainerBounds.
+        First argument is size of bounds to fix.
+        Second argument is whether or not to fix the container.
+
+      To find the numbers of large bounds, run the script:
+        `currentView.fixCorruptContainerBounds()`
+      To run a test run without making changes to bounds of size 700 run:
+        `currentView.fixCorruptContainerBounds(700, true)`
+      And to make changes:
+        `currentView.fixCorruptContainerBounds(700, false)`
+      You can always revert the changes from the editor if the animation is broken.
+
+      Finally if there are no shape bounds present you can pass in your own with the format of [x, y, width, height]
+      i.e.
+        `currentView.fixCorruptContainerBounds(700, false, [0, 0, 50, 100])`
+      This will cut out a 50px wide and 100px tall container around the sprite.
+      Incorrect settings of custom bounds will cut the artwork.
+    """)
     # Fix all the messed up bounds
     data = @thangType.attributes
     fixCount = 0
+    failCount = 0
+    backupBoundsCount = 0
     for [key, container] in Object.entries(data.raw.containers)
       if dryRun
         if container.b?[2] >= boundsWidthToFix
@@ -660,10 +681,16 @@
           reference = container.c[0]
           if data.raw.shapes[reference]
             shape = data.raw.shapes[reference]
-            container.b = [shape.bounds[0] + shape.t[0] - 5, shape.bounds[1] + shape.t[1] - 5, shape.bounds[2] + 10, shape.bounds[3] + 10]
-            fixCount += 1
+            if shape.bounds is undefined and Array.isArray(backupBounds)
+              backupBoundsCount += 1
+              shape.bounds ?= backupBounds # Lets user pass in backup bounds with options: [x, y, width, height]
+            try
+              container.b = [shape.bounds[0] + shape.t[0] - 5, shape.bounds[1] + shape.t[1] - 5, shape.bounds[2] + 10, shape.bounds[3] + 10]
+              fixCount += 1
+            catch e
+              failCount += 1
             console.log('.')
-    console.log('Fixed:', fixCount)
+    console.log('Fixed:', fixCount, 'Failed:', failCount, 'Used backup bounds:', backupBoundsCount)


Correct typo in spec

Correct typo in spec

--- src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee
+++ src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee
@@ -19,7 +19,7 @@
   describe "file-finder behavior", ->
     describe "toggling", ->
       describe "when the root view's project has a path", ->
-        it "shows the FuzzyFinder or hides it nad returns focus to the active editor if it already showing", ->
+        it "shows the FuzzyFinder or hides it and returns focus to the active editor if it already showing", ->
           rootView.attachToDom()
           expect(rootView.find('.fuzzy-finder')).not.toExist()
           rootView.find('.editor').trigger 'editor:split-right'


use delete

use delete

--- src/model/model.coffee
+++ src/model/model.coffee
@@ -121,7 +121,7 @@
       record._withoutDirtyTracking -> @set 'id', id
       @_pending[id] = record
     record.loadWithOptions options, =>
-      @_pending[id] = null
+      delete @_pending[id]
       callback.apply(@, arguments)
     return record


fixed coffeelint errors on workers/social/lib/social/models/computeproviders/credential.coffee

--- workers/social/lib/social/models/computeproviders/credential.coffee
+++ workers/social/lib/social/models/computeproviders/credential.coffee
@@ -1,4 +1,5 @@
-
+# due to a bug in coffeelint 1.10.1
+# coffeelint: disable=no_implicit_braces
 jraphical      = require 'jraphical'

 module.exports = class JCredential extends jraphical.Module
@@ -11,10 +12,10 @@

   KodingError        = require '../../error'

-  {secure, ObjectId, signature, daisy} = require 'bongo'
-  {Relationship}     = jraphical
-  {permit}           = require '../group/permissionset'
-  Validators         = require '../group/validators'
+  { secure, ObjectId, signature, daisy } = require 'bongo'
+  { Relationship }     = jraphical
+  { permit }           = require '../group/permissionset'
+  Validators           = require '../group/validators'

   @trait __dirname, '../../traits/protected'

@@ -90,12 +91,12 @@
     relationships     :

       data            :
-        targetType    : "JCredentialData"
-        as            : "data"
+        targetType    : 'JCredentialData'
+        as            : 'data'

   @getName = -> 'JCredential'

-  failed = (err, callback, rest...)->
+  failed = (err, callback, rest...) ->
     return false  unless err

     if rest
@@ -107,10 +108,10 @@

   @create = permit 'create credential',

-    success: (client, data, callback)->
-
-      {delegate} = client.connection
-      {provider, title, meta} = data
+    success: (client, data, callback) ->
+
+      { delegate } = client.connection
+      { provider, title, meta } = data
       originId = delegate.getId()

       if not PROVIDERS[provider]?
@@ -118,53 +119,54 @@
         return

       credData = new JCredentialData { meta, originId }
-      credData.save (err)->
+      credData.save (err) ->
         return  if failed err, callback

         { identifier } = credData
         credential = new JCredential { provider, title, identifier, originId }

-        credential.save (err)->
+        credential.save (err) ->
           return  if failed err, callback, credData

-          delegate.addCredential credential, as: "owner", (err)->
+          delegate.addCredential credential, { as: 'owner' }, (err) ->
             return  if failed err, callback, credential, credData

-            credential.addData credData, (err)->
+            credential.addData credData, (err) ->
               return  if failed err, callback, credential, credData
               callback null, credential

-  @fetchByIdentifier = (client, identifier, callback)->
+  @fetchByIdentifier = (client, identifier, callback) ->

     options =
       limit         : 1
-      targetOptions : selector : { identifier }
-
-    {delegate} = client.connection
-    delegate.fetchCredential { }, options, (err, res)->
+      targetOptions :
+        selector    : { identifier }
+
+    { delegate } = client.connection
+    delegate.fetchCredential {}, options, (err, res) ->

       return callback err        if err?
       return callback null, res  if res?

       { group } = client.context
-      JGroup.one slug: group, (err, group)->
+      JGroup.one { slug: group }, (err, group) ->
         return callback err  if err?

-        group.fetchCredential { }, options, (err, res)->
+        group.fetchCredential {}, options, (err, res) ->
           callback err, res

   @one$ = permit 'list credentials',

-    success: (client, identifier, callback)->
+    success: (client, identifier, callback) ->

       @fetchByIdentifier client, identifier, callback

   @some$ = permit 'list credentials',

-    success: (client, selector, options, callback)->
+    success: (client, selector, options, callback) ->

       [options, callback] = [callback, options]  unless callback
       options ?= {}
@@ -180,21 +182,21 @@
         relSelector.as = selector.as
         delete selector.as

-      Relationship.someData relSelector, { targetId:1, as:1 }, (err, cursor)=>
+      Relationship.someData relSelector, { targetId:1, as:1 }, (err, cursor) =>

         return callback err  if err?

-        cursor.toArray (err, arr)=>
-
-          map = arr.reduce (memo, doc)=>
+        cursor.toArray (err, arr) =>
+
+          map = arr.reduce (memo, doc) ->
             memo[doc.targetId] = doc.as
             memo
           , {}

           selector    ?= {}
-          selector._id = $in: (t.targetId for t in arr)
-
-          @some selector, options, (err, items)->
+          selector._id = { $in: (t.targetId for t in arr) }
+
+          @some selector, options, (err, items) ->
             return callback err  if err?

             for item in items
@@ -209,15 +211,15 @@
       { permission: 'update credential', validateWith: Validators.own }
     ]

-    success: (client, callback)->
+    success: (client, callback) ->

       Relationship.someData targetId : @getId(), {
         as:1, sourceId:1, sourceName:1
-      }, (err, cursor)->
+      }, (err, cursor) ->

         return callback err  if err?

-        cursor.toArray (err, arr)->
+        cursor.toArray (err, arr) ->
           return callback err  if err?

           if arr.length > 0
@@ -230,21 +232,21 @@
             callback null, []

-  setPermissionFor: (target, {user, owner}, callback)->
+  setPermissionFor: (target, { user, owner }, callback) ->

     Relationship.remove
       targetId : @getId()
       sourceId : target.getId()
-    , (err)=>
+    , (err) =>

       if user
         as = if owner then 'owner' else 'user'
-        target.addCredential this, { as }, (err)-> callback err
+        target.addCredential this, { as }, (err) -> callback err
       else
         callback err

-  shareWith: (client, options, callback)->
+  shareWith: (client, options, callback) ->

     { delegate } = client.connection
     { target, user, owner } = options
@@ -255,25 +257,25 @@
     if delegate.profile.nickname is target
       return callback null

-    JName.fetchModels target, (err, result)=>
+    JName.fetchModels target, (err, result) =>

       if err or not result
-        return callback new KodingError "Target not found."
+        return callback new KodingError 'Target not found.'

       { models } = result
       [ target ] = models

       if target instanceof JUser
-        target.fetchOwnAccount (err, account)=>
+        target.fetchOwnAccount (err, account) =>
           if err or not account
-            return callback new KodingError "Failed to fetch account."
-          @setPermissionFor account, {user, owner}, callback
+            return callback new KodingError 'Failed to fetch account.'
+          @setPermissionFor account, { user, owner }, callback

       else if target instanceof JGroup
-        @setPermissionFor target, {user, owner}, callback
+        @setPermissionFor target, { user, owner }, callback

       else
-        callback new KodingError "Target does not support credentials."
+        callback new KodingError 'Target does not support credentials.'

   # .share can be used like this:
@@ -292,14 +294,14 @@

   delete: permit 'delete credential',

-    success: (client, callback)->
+    success: (client, callback) ->

       { delegate } = client.connection

       Relationship.one {
         targetId : @getId()
         sourceId : delegate.getId()
-      }, (err, rel)=>
+      }, (err, rel) =>

         return callback err   if err?
         return callback null  unless rel?
@@ -326,7 +328,7 @@

     sensitiveKeys = PROVIDERS[@provider]?.sensitiveKeys or []

-    Relationship.one {sourceId: @getId(), as: 'data'}, (err, rel) ->
+    Relationship.one { sourceId: @getId(), as: 'data' }, (err, rel) ->

       return callback err  if err
       return callback new KodingError 'No data found'  unless rel
@@ -347,7 +349,7 @@
       { permission: 'update credential', validateWith: Validators.own }
     ]

-    success: (client, callback)->
+    success: (client, callback) ->

       @fetchData callback

@@ -358,21 +360,21 @@
       { permission: 'update credential', validateWith: Validators.own }
     ]

-    success: (client, options, callback)->
+    success: (client, options, callback) ->

       { title, meta } = options

       unless title or meta
-        return callback new KodingError "Nothing to update"
+        return callback new KodingError 'Nothing to update'

       title ?= @title

-      @update $set : { title }, (err)=>
+      @update $set : { title }, (err) =>
         return callback err  if err?

         if meta?

-          @fetchData (err, credData)=>
+          @fetchData (err, credData) ->
             return callback err  if err?
             credData.update $set : { meta }, callback

@@ -405,3 +407,5 @@
           verifiedCount++  if data['meta']?[key]?

         callback null, bootstrapKeys.length is verifiedCount
+
+


Ease constructor. Simpler naming.

Ease constructor. Simpler naming.

--- src/coffee/apiclient.coffee
+++ src/coffee/apiclient.coffee
@@ -6,10 +6,9 @@

 class ApiClient

-  constructor: (@logger, options = {}) ->
-    if options.config # for unit testing
-      # @sync = new CategorySync # TODO: enable as soon as new sdk released
-      @client = new SphereClient options
+  constructor: (@logger, options) ->
+    # @sync = new CategorySync # TODO: enable as soon as new sdk released
+    @client = new SphereClient options

     @continueOnProblems = false
     @updatesOnly = false
@@ -95,7 +94,7 @@
             reject "[#{context.sourceInfo}] Error on creating new category:\n#{_.prettify err}"
         .done()

-  deleteCategory: (category, context) ->
+  delete: (category, context) ->
     new Promise (resolve, reject) =>
       @client.categories.byId(category.id).delete(category.version)
       .then ->


[background] fixed bug where sources linked to communities/events weren't shown

--- src/coffee/data/data.coffee
+++ src/coffee/data/data.coffee
@@ -368,9 +368,7 @@
                         key: source.getTag()
                     }]

-            result.reduce (res, elem) ->
-                res.concat elem
-            ,
+            result.flatten()

         find: (pattern) ->
             if @topLevel


Fetch all products for now.

Fetch all products for now.

--- src/coffee/pricesync.coffee
+++ src/coffee/pricesync.coffee
@@ -83,12 +83,13 @@

     deferred.promise

-  getPublishedProducts: (client) ->
-    # TODO: get only modified products
-    # date = new Date()
-    # date.setDate(date.getDate - 1)
-    # client.productProjections.where("modifiedAt > \"#{date.toISOString()}\"").fetch()
-    client.productProjections.fetch()
+  getPublishedProducts: (client, offsetInDays) ->
+    #date = new Date()
+    #offsetInDays = 2 if offsetInDays is undefined
+    #date.setDate(date.getDate() - offsetInDays)
+    #d = "#{date.toISOString().substring(0,10)}T00:00:00.000Z"
+    #client.productProjections.where("lastModifiedAt > \"#{d}\"").perPage(0).fetch()
+    client.productProjections.perPage(0).fetch()

   getCustomerGroup: (client, name) ->
     client.customerGroups.where("name=\"#{name}\"").fetch()


Add TODO.

Add TODO.

--- src/coffee/validator.coffee
+++ src/coffee/validator.coffee
@@ -72,7 +72,9 @@
     errors

   isVariant: (row) ->
-    row[@h2i[CONS.HEADER_PRODUCT_TYPE]] is '' and row[@h2i[CONS.HEADER_NAME]] is '' and row[@h2i[CONS.HEADER_VARIANT_ID]] isnt undefined
+    row[@h2i[CONS.HEADER_PRODUCT_TYPE]] is '' and
+    row[@h2i[CONS.HEADER_NAME]] is '' and
+    row[@h2i[CONS.HEADER_VARIANT_ID]] isnt undefined # TODO: Check for numbers > 1

   isProduct: (row) ->
     not @isVariant row


Just use the hostname

Just use the hostname

--- src/microservice.coffee
+++ src/microservice.coffee
@@ -265,17 +265,12 @@

     hostname = os.hostname()

-    if process.env.DOCKERCLOUD_CONTAINER_FQDN?
-      id = "#{process.env.DOCKERCLOUD_CONTAINER_FQDN}/#{hostname}"
-    else
-      id = hostname
-
     options =
       url: hook
       headers:
         "Content-Type": "application/json"
       json:
-        text: "#{id} #{message}"
+        text: "#{hostname} #{message}"
         username: @getName()
         icon_emoji: icon


Fix submit block for dormant users

Fix submit block for dormant users

--- server/api/setupApi.coffee
+++ server/api/setupApi.coffee
@@ -161,7 +161,7 @@
             return
         if user.dormant
             res.json({dormant: true})
-            return0
+            return
         try
             await createSubmit(req.params.problemId, req.user.userKey(), user.userList, req.body.language, req.body.code, req.body.draft)
         catch e


chore fix typo on API method name

chore fix typo on API method name

(cherry picked from commit 2cc78dbd7e25d3b6456fcb81f5a8ad18d2bd1730)

--- src/models/Modal.coffee
+++ src/models/Modal.coffee
@@ -25,7 +25,7 @@
     switch view.constructor.name
       when "MediaGalleryView"
         steroids.nativeBridge.nativeCall
-          method: "showMediaGalery"
+          method: "showMediaGallery"
           parameters:
             files: view.getNativeFilePath()
           successCallbacks: [callbacks.onSuccess]


Fix component name to match behaviour

Fix component name to match behaviour

--- src/components/tags/lo.cjsx
+++ src/components/tags/lo.cjsx
@@ -72,7 +72,7 @@
       </span>
     </div>

-ExIdTags = React.createClass
+LoTags = React.createClass

   propTypes:
     exerciseId: React.PropTypes.string.isRequired
@@ -87,4 +87,4 @@
         <Input key={tag} {...@props} tag={tag} />}
     </Wrapper>

-module.exports = ExIdTags
+module.exports = LoTags


Express server creating in 2.x.x fixed

Express server creating in 2.x.x fixed

--- servers/embed/index.coffee
+++ servers/embed/index.coffee
@@ -7,7 +7,7 @@
 nconf = require("nconf")
 request = require("request")

-module.exports = app = express()
+module.exports = app = express.createServer()

 apiUrl = nconf.get("url:api")


participant: Remove deprecated connectGraphEdges/File

Should use msgflo.setup instead

--- src/participant.coffee
+++ src/participant.coffee
@@ -140,39 +140,6 @@
       debug 'registered', err
       return callback err

-  # Sets up queues to match those defined in graph
-  connectGraphEdges: (graph) ->
-    console.log 'WARN: msgflo.Participant::connectGraphEdges() is deprecated. Use msgflo.setup.setupBindings() instead'
-    processName = @definition.role
-
-    # If there are outbound connections
-    # Set the output queue to equal to the input queue of the target
-    for conn in graph.connections
-      if conn.src?.process == processName
-        # WARN: assumes the queue naming convention,
-        # as we don't have access to the definition of target participant
-        # altenative would be to instantiate whole network,
-        # and in worker case only run one participant?
-        # using exchanges for the outports and binding to inports might also solve it
-        tgtQueue = "#{conn.tgt.process}.#{conn.tgt.port.toUpperCase()}"
-        ports = @definition.outports.filter (p) -> return p.id == conn.src.port
-        ports[0].queue = tgtQueue
-
-  connectGraphEdgesFile: (filepath, callback) ->
-    console.log 'WARN: msgflo.Participant::connectGraphEdgesFile() is deprecated. Use msgflo.setup.setupBindings() instead'
-    ext = path.extname filepath
-    fs.readFile filepath, { encoding: 'utf-8' }, (err, contents) =>
-      return callback err if err
-      try
-        if ext == '.fbp'
-          graph = fbp.parse contents
-        else
-          graph = JSON.parse contents
-        @connectGraphEdges graph
-      catch e
-        return callback e
-      return callback null
-
 # TODO: consider making component api a bit more like NoFlo.WirePattern
 #
 # inputs = { portA: { data: dataA1, groups: ['A', '1'] }, portB: { data: B1 } }