fix withings konnectors

fix withings konnectors

Withings cert is no more trusted. I removed the strictSSL option to request
querying the withings website API.

--- server/konnectors/withings.coffee
+++ server/konnectors/withings.coffee
@@ -156,18 +156,20 @@
                 sessionid = \
                     res.headers['set-cookie'][1].split(';')[0].split('=')[1]

-                data =
-                    action: 'getuserslist'
-                    appliver: '20140428120105'
-                    appname: 'my2'
-                    apppfm: 'web'
-                    listmask: '5'
-                    recurse_devtype: '1'
-                    recurse_use: '1'
-                    sessionid: sessionid
+                options =
+                    strictSSL: false
+                    form:
+                        action: 'getuserslist'
+                        appliver: '20140428120105'
+                        appname: 'my2'
+                        apppfm: 'web'
+                        listmask: '5'
+                        recurse_devtype: '1'
+                        recurse_use: '1'
+                        sessionid: sessionid

                 # Get user id.
-                request.post accountUrl, form: data, (err, res, body) ->
+                request.post accountUrl, options, (err, res, body) ->
                     return callback err if err

                     body = JSON.parse body
@@ -175,22 +177,24 @@
                     userid = user.id
                     username = "#{user.firstname} #{user.lastname}"

-                    data =
-                        action: 'getmeas'
-                        appliver: '20140428120105'
-                        appname: 'my2'
-                        apppfm: 'web'
-                        category: 1
-                        limit: 2000
-                        offset: 0
-                        meastype: '12,35'
-                        sessionid: sessionid
-                        startdate: 0
-                        enddate: end
-                        userid: userid
+                    options =
+                        strictSSL: false
+                        form:
+                            action: 'getmeas'
+                            appliver: '20140428120105'
+                            appname: 'my2'
+                            apppfm: 'web'
+                            category: 1
+                            limit: 2000
+                            offset: 0
+                            meastype: '12,35'
+                            sessionid: sessionid
+                            startdate: 0
+                            enddate: end
+                            userid: userid

                     # Fetch withings body measures
-                    request.post measureUrl, form: data, (err, res, body) ->
+                    request.post measureUrl, options, (err, res, body) ->
                         return callback err if err

                         measures = JSON.parse body
@@ -204,24 +208,26 @@
                                 .format('YYYY-MM-DD')

                             # Fetch withings activity measures
-                            data =
-                                sessionid: sessionid
-                                userid: userid
-                                range: '1'
-                                meastype: '36,40'
-                                appname: 'my2'
-                                appliver: '20140428120105'
-                                apppfm: 'web'
-                                action: 'getbyuserid'
-                                startdateymd: startDate
-                                enddateymd: moment().format('YYYY-MM-DD')
+                            options =
+                                strictSSL: false
+                                form:
+                                    sessionid: sessionid
+                                    userid: userid
+                                    range: '1'
+                                    meastype: '36,40'
+                                    appname: 'my2'
+                                    appliver: '20140428120105'
+                                    apppfm: 'web'
+                                    action: 'getbyuserid'
+                                    startdateymd: startDate
+                                    enddateymd: moment().format('YYYY-MM-DD')

                             onMeasures = (err, res, body) ->
                                 return callback err if err
                                 measures = JSON.parse body
                                 saveActivityMeasures measures, callback

-                            request.post aggregateUrl, form: data, onMeasures
+                            request.post aggregateUrl, options, onMeasures

 hashMeasuresByDate = (measures) ->


Update news.coffee

Update news.coffee

--- server/materials/data/news.coffee
+++ server/materials/data/news.coffee
@@ -3,6 +3,9 @@

 export default allNews = () ->
     return news([
+        newsItem("3 марта занятия в лицее 40 не будет", String.raw"""
+
3 марта занятия в лицее 40 не будет.

+        """),
         newsItem("Летняя компьютерная школа и прочие летние школы", String.raw"""

Добавлена информация про ЛКШ и про летние школы вообще. Обязательно прочитайте информацию про ЛКШ; я настоятельно рекомендую всем школьникам, кто может, туда поехать.

         """),


Add mark commands to README, simple refactoring.

--- content_scripts/marks.coffee
+++ content_scripts/marks.coffee
@@ -31,19 +31,17 @@
         # If <Shift> is depressed, then it's a global mark, otherwise it's a local mark.  This is consistent
         # vim's [A-Z] for global marks, [a-z] for local marks.  However, it also admits other non-Latin
         # characters.
-        if event.shiftKey
-          @exit =>
-            chrome.runtime.sendMessage
-              handler: 'createMark'
-              markName: keyChar
-              scrollX: window.scrollX
-              scrollY: window.scrollY
-            , => @showMessage "Created global mark", keyChar
-        else
-          @exit =>
-            markString = JSON.stringify scrollX: window.scrollX, scrollY: window.scrollY
-            localStorage[@getLocationKey keyChar] = @getMarkString()
-            @showMessage "Created local mark", keyChar
+        @exit =>
+          if event.shiftKey
+              chrome.runtime.sendMessage
+                handler: 'createMark'
+                markName: keyChar
+                scrollX: window.scrollX
+                scrollY: window.scrollY
+              , => @showMessage "Created global mark", keyChar
+          else
+              localStorage[@getLocationKey keyChar] = @getMarkString()
+              @showMessage "Created local mark", keyChar

   activateGotoMode: (registryEntry) ->
     # We pick off the last character of the key sequence used to launch this command. Usually this is just "`".


publish push to buildbot

publish push to buildbot

Signed-off-by: Pierre Tardy <bb5a2a16eebb4a48138fca46fede24b3c8d635fe@intel.com>

--- guanlecoja/config.coffee
+++ guanlecoja/config.coffee
@@ -28,8 +28,8 @@
     exec("git add .")
     exec("git commit -m " + bower_json.version)
     exec("git tag " + bower_json.version)
-    exec("git push origin gh-pages")
-    exec("git push origin " + bower_json.version)
+    exec("git push buildbot gh-pages")
+    exec("git push buildbot " + bower_json.version)
     exec("git checkout master")

 gulp.task "readme", ->


explicitly setting url for a11y extension is no longer needed

--- shared/src/helpers/mathjax.coffee
+++ shared/src/helpers/mathjax.coffee
@@ -64,7 +64,6 @@
     window.MathJax.Hub.Configured()

   if window.MathJax?.Hub
-    window.MathJax.Ajax.config.path["a11y"] = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/#{window.MathJax.version}/extensions/a11y"
     window.MathJax.Hub.Config(MATHJAX_CONFIG)
     # Does not seem to work when passed to Config
     window.MathJax.Hub.processSectionDelay = 0


Fixes #15: correct field access highlighting.

--- tools/syntax_highlighting/atom/language-do/grammars/do.cson
+++ tools/syntax_highlighting/atom/language-do/grammars/do.cson
@@ -31,8 +31,8 @@
 	},
 	{
 		"match": "\\.[A-Za-z_]\\w*",
-		"name": "entity.other.do",
-		"comment": "Access to field."
+		"name": "variable.accessor.structure-field.do",
+		"comment": "Access to structure field."
 	},
 	{
 		"match": "\\bNULL\\b",


removed unused code

removed unused code

--- Framework/Views/Controls/LoadingIndicatorView_Framework.coffee
+++ Framework/Views/Controls/LoadingIndicatorView_Framework.coffee
@@ -1,9 +1,6 @@
 root.LoadingIndicatorView_Framework = class LoadingIndicatorView_Framework extends root.BaseView
   constructor:(options = {}) ->
-    options = root._.extend({
-      title: 'LoadingIndicatorView_Framework_Common'
-    }, options)
-    super(options)
+    super options

     if Ti.Platform.osname == "iphone" || Ti.Platform.osname == "ipad"
       @loadingView = Ti.UI.createView({


rename syncToBoundEditor to original syncToEditor but without argument

--- lib/ui.coffee
+++ lib/ui.coffee
@@ -256,14 +256,15 @@

     @refresh().then =>
       if @provider.needAutoReveal()
-        @syncToEditor(@provider.editor)
-        row = @editor.getCursorBufferPosition().row
-        if @provider.showLineHeader
-          column = @getSelectedItem()._lineHeader.length - 1
-        else
-          column = 0
-        @editor.setCursorBufferPosition([row, column])
-        @preview()
+        if @syncToEditor()
+          row = @editor.getCursorBufferPosition().row
+          if @provider.showLineHeader
+            lineHeader = @getSelectedItem()?._lineHeader
+            column = lineHeader?.length - 1 or 0
+          else
+            column = 0
+          @editor.setCursorBufferPosition([row, column])
+          @preview()

       if @activate
         @preview() if @query and @autoPreview
@@ -552,16 +553,19 @@

     return items[0]

-  syncToBoundEditor: ->
-    @syncToEditor(@provider.editor)
-
-  syncToEditor: (editor) ->
-    return if @preventSyncToEditor
+  # Return success or fail
+  syncToEditor: ->
+    return false if @preventSyncToEditor
+
+    editor = @provider.editor
     if item = @findClosestItemForEditor(editor)
       @selectItem(item)
       {row} = @editor.getCursorBufferPosition()
       @moveToSelectedItem(scrollToColumnZero: true)
       @emitDidMoveToItemArea() if @isPromptRow(row)
+      true
+    else
+      false

   moveToSelectedItem: ({scrollToColumnZero, ignoreCursorMove}={}) ->
     if (row = @getRowForSelectedItem()) >= 0
@@ -753,7 +757,7 @@
     newFilePath = editor.getPath()

     @provider.bindEditor(editor)
-    @syncToBoundEditor()
+    @syncToEditor()

     ignoreColumnChange = @provider.ignoreSideMovementOnSyncToEditor

@@ -761,10 +765,10 @@
       return unless isActiveEditor(editor)
       return if event.textChanged
       return if ignoreColumnChange and (event.oldBufferPosition.row is event.newBufferPosition.row)
-      @syncToBoundEditor()
+      @syncToEditor()

     @syncSubcriptions.add @onDidRefresh =>
-      @syncToBoundEditor()
+      @syncToEditor()

     # Avoid refresh while active, important to update-real-file don't cause auto-refresh.
     refresh = => @refresh(force: true) unless @isActive()


make sure current sound is playing, fix #5

--- src/scripts/directives/playlist.coffee
+++ src/scripts/directives/playlist.coffee
@@ -57,7 +57,10 @@

         playTrack: (index) ->
             if index is @current.index
-                return @seek 0
+                @seek 0
+                if @current.sound.playState is 0
+                    @current.sound.play()
+                return

             @stop()
             @current =


Grunt Test

Grunt Test

--- src/scripts/services/netStorage.coffee
+++ src/scripts/services/netStorage.coffee
@@ -44,5 +44,4 @@
 				storage.nets.splice(0, 1) while storage.nets.length > 0
 				storage.nets.push(getDefaultNet())
 				$state.go "editor", name: storage.nets[0].name
-
 		}


fix so that unsaved edits generate a warning again

--- vue/src/shared/services/rescue_unsaved_edits_service.coffee
+++ vue/src/shared/services/rescue_unsaved_edits_service.coffee
@@ -8,6 +8,7 @@
   okToLeave: (model) ->
     attrs = ['description', 'title', 'body', 'details', 'name', 'reason', 'statement']
     models = ((model && [model]) || @models)
+    models.forEach (m) -> m.beforeSave()
     if some(models, (m) -> intersection(attrs, m.modifiedAttributes()).length > 0)
       # console.log 'some modified', @models.map (m) ->
       #   modifiedAttrs = intersection(attrs, m.modifiedAttributes())


improve memory constrains and get some properties from config

--- hadoop/lib/memory.coffee
+++ hadoop/lib/memory.coffee
@@ -6,7 +6,6 @@
 memory = (ctx) ->
   {yarn, hadoop_conf_dir} = ctx.config.hdp
   yarn_site = yarn
-  # yarn.scheduler.maximum-allocation-mb
   # yarn.nodemanager.log.retain-seconds (cherif mettre la valeur à 10800 au lie de 604800)
   # yarn.log-aggregation.retain-seconds (cherif)

@@ -28,17 +27,27 @@
   # Amount of RAM per container
   # max(MIN_CONTAINER_SIZE, (Total Available RAM) / containers))
   memoryPerContainer = Math.floor Math.max mininumContainerSize, memoryAvailableMb / maxNumberOfcontainers
-  # Virtual memory (physical + paged memory) upper limit for each Map and Reduce task
-  virtualMemoryRatio = 2.1
+  # Get default
+  yarnNodeManagerResourceMemoryMb = ['yarn.nodemanager.resource.memory-mb']
+  YarnNodemanagerVirtualMemoryRatio = yarn_site['yarn.nodemanager.vmem-pmem-ratio']
+  yarnSchedulerMinimumAllocationMb = yarn_site['yarn.scheduler.minimum-allocation-mb']
+  yarnSchedulerMaximumAllocationMb = yarn_site['yarn.scheduler.maximum-allocation-mb']
+  yarnAppMapreduceAmResourceMb = yarn_site['yarn.app.mapreduce.am.resource.mb']
+  yarnAppMapreduceAmCommandOpts = /-Xmx(.*)m/.exec(yarn_site['yarn.app.mapreduce.am.command-opts'])?[1]
   # Compute
-  yarnSchedulerMaximumAllocationMb = maxNumberOfcontainers * memoryPerContainer # containers * RAM-per-container
-  yarnAppMapreduceAmResourceMb = 2 * memoryPerContainer # 2 * RAM-per-container
-  yarnAppMapreduceAmCommmandOpts = Math.floor(.8 * 2 * memoryPerContainer) # 0.8 * 2 * RAM-per-container
+  yarnNodeManagerResourceMemoryMb ?= maxNumberOfcontainers * memoryPerContainer
+  yarnSchedulerMinimumAllocationMb ?= memoryPerContainer
+  yarnSchedulerMaximumAllocationMb ?= maxNumberOfcontainers * memoryPerContainer # containers * RAM-per-container
+  yarnAppMapreduceAmResourceMb ?= 2 * memoryPerContainer # 2 * RAM-per-container
+  yarnAppMapreduceAmCommandOpts ?= Math.floor(.8 * 2 * memoryPerContainer) # 0.8 * 2 * RAM-per-container
+  YarnNodemanagerVirtualMemoryRatio ?= 2.1 # Virtual memory (physical + paged memory) upper limit for each Map and Reduce task
+  mapreduceMapMemoryMb = memoryPerContainer
   mapreduceReduceMemoryMb = 2 * memoryPerContainer # 2 * RAM-per-container
   # Constrain
-  yarnAppMapreduceAmResourceMb = Math.min yarnAppMapreduceAmResourceMb, maxNumberOfcontainers * memoryPerContainer
-  yarnAppMapreduceAmCommmandOpts = Math.min yarnAppMapreduceAmCommmandOpts, maxNumberOfcontainers * memoryPerContainer
-  mapreduceReduceMemoryMb = Math.min yarnSchedulerMaximumAllocationMb, mapreduceReduceMemoryMb # REDUCE capability required is more than the supported max container capability in the cluster. Killing the Job. reduceResourceReqt: 3844 maxContainerCapability:1922
+  yarnAppMapreduceAmResourceMb = Math.min yarnAppMapreduceAmResourceMb, yarnSchedulerMaximumAllocationMb
+  yarnAppMapreduceAmCommandOpts = Math.min yarnAppMapreduceAmCommandOpts, yarnSchedulerMaximumAllocationMb
+  mapreduceMapMemoryMb = Math.min mapreduceMapMemoryMb, yarnSchedulerMaximumAllocationMb # RAM-per-container cannot exceed YARN maximum allocation, example: "Invalid resource request, requested memory < 0, or requested memory > max configured, requestedMemory=1922, maxMemory=1800"
+  mapreduceReduceMemoryMb = Math.min mapreduceReduceMemoryMb, yarnSchedulerMaximumAllocationMb # RAM per reduce task cannot exceed YARN minimum allocation, example: "REDUCE capability required is more than the supported max container capability in the cluster. Killing the Job. reduceResourceReqt: 3844 maxContainerCapability:1922"
   result =
     info:
       'coreNumber': coreNumber
@@ -48,16 +57,15 @@
       'mininumContainerSize': mininumContainerSize
       'maxNumberOfcontainers': maxNumberOfcontainers
       'memoryPerContainer': memoryPerContainer
-      'virtualMemoryRatio': virtualMemoryRatio
     yarn_site:
-      'yarn.nodemanager.resource.memory-mb': "#{maxNumberOfcontainers * memoryPerContainer}" # containers * RAM-per-container
-      'yarn.scheduler.minimum-allocation-mb': "#{memoryPerContainer}" # RAM-per-container
+      'yarn.nodemanager.resource.memory-mb': "#{yarnNodeManagerResourceMemoryMb}" # containers * RAM-per-container
+      'yarn.nodemanager.vmem-pmem-ratio': "#{YarnNodemanagerVirtualMemoryRatio}"
+      'yarn.scheduler.minimum-allocation-mb': "#{yarnSchedulerMinimumAllocationMb}" # RAM-per-container
       'yarn.scheduler.maximum-allocation-mb': "#{yarnSchedulerMaximumAllocationMb}"
       'yarn.app.mapreduce.am.resource.mb': "#{yarnAppMapreduceAmResourceMb}"
-      'yarn.app.mapreduce.am.command-opts': "-Xmx#{yarnAppMapreduceAmCommmandOpts}m"
-      'yarn.nodemanager.vmem-pmem-ratio': "#{virtualMemoryRatio}"
+      'yarn.app.mapreduce.am.command-opts': "-Xmx#{yarnAppMapreduceAmCommandOpts}m"
     mapred_site:
-      'mapreduce.map.memory.mb': "#{memoryPerContainer}" # RAM-per-container
+      'mapreduce.map.memory.mb': "#{mapreduceMapMemoryMb}"
       'mapreduce.reduce.memory.mb': "#{mapreduceReduceMemoryMb}"
       'mapreduce.map.java.opts': "-Xmx#{Math.floor .8 * memoryPerContainer}m" # 0.8 * RAM-per-container
       'mapreduce.reduce.java.opts': "-Xmx#{Math.floor .8 * 2 * memoryPerContainer}m" # 0.8 * 2 * RAM-per-container


Fix event bindings for variable-length keypaths for realsies.

--- src/view/bindings/event_binding.coffee
+++ src/view/bindings/event_binding.coffee
@@ -9,7 +9,10 @@

     callback = =>
       func = @get('filteredValue')
-      target = @view.targetForKeypathBase(@functionPath)
+      target = @view.targetForKeypathBase(@functionPath || @unfilteredKey)
+      if target && @functionPath
+        target = Batman.get(target, @functionPath)
+
       return func?.apply(target, arguments)

     if attacher = Batman.DOM.events[@attributeName]
@@ -18,13 +21,12 @@
       Batman.DOM.events.other(@node, @attributeName, callback, @view)

   _unfilteredValue: (key) ->
+    @unfilteredKey = key
     if not @functionName and (index = key.lastIndexOf('.')) != -1
       @functionPath = key.substr(0, index)
       @functionName = key.substr(index + 1)
-    else
-      @functionPath = key

-    value = super(@functionPath)
+    value = super(@functionPath || key)
     if @functionName
       value?[@functionName]
     else


Added failing build on document parsing failed

--- cli/tasks/build/server/parse/documents.coffee
+++ cli/tasks/build/server/parse/documents.coffee
@@ -21,11 +21,18 @@
 Document.STYLES_PATH = STYLES_DIR
 loadedExtensions = {}

+class DocumentParseError extends Error
+    constructor: (@message, @previousError) ->
+        if @previousError
+            @message += "\n\n#{@previousError.message}"
+
 module.exports = (platform, app, callback) ->
     unless fs.existsSync(IN_DIR)
         return callback null

     logtime = log.time 'Parse documents'
+
+    parsingError = null

     # clear
     fs.removeSync "./#{OUT_DIR}/#{IN_DIR}"
@@ -71,11 +78,8 @@
         try
             Document.parse file
         catch error
-            log.error """
-                View file `#{path}` can't be parsed; \
-                if it's not related to your component scripts, please report this error on GitHub
-                #{error.stack}
-            """
+            msg = "Cannot parse file '#{path}'\n#{error.message}"
+            parsingError = new DocumentParseError msg, parsingError
             return
         file

@@ -106,7 +110,7 @@
         Document.onStyle.disconnect onStyleListener

         log.end logtime
-        callback err
+        callback parsingError
         return

     cliUtils.forEachFileDeep IN_DIR, (path, stat) ->


don't use label in build status badge on dashboard

--- js/inner/build.coffee
+++ js/inner/build.coffee
@@ -121,13 +121,10 @@
           false

     @style =
-      "label-important": @important_style
-      "label-warning": @warning_style
-
-      "label-success": @success_style
-      "label-info": @info_style
-      label: true
-      build_status: true
+      "fail": @important_style
+      "stop": @warning_style
+      "pass": @success_style
+      "busy": @info_style

     @favicon_color = @komp =>
       if @important_style()


Apply the same rule to `off` action.

Apply the same rule to `off` action.

--- client/admin/lib/views/permissionsform.coffee
+++ client/admin/lib/views/permissionsform.coffee
@@ -144,13 +144,19 @@
       delegate     : this
       callback     : ->

+        switches = @parent.subViews.filter (item) -> item instanceof PermissionSwitch
+
         # If the swicth is on now.
         if @getValue()
-          switches = @parent.subViews.filter (item) -> item instanceof PermissionSwitch
           switches = switches.slice 0, switches.indexOf this

           switches.forEach (item) ->
             item.setOn no  unless item.getValue()
+        else
+          switches = switches.slice switches.indexOf this
+
+          switches.forEach (item) ->
+            item.setOff no  if item.getValue()

         @getDelegate().save()
     }


collaboration: add rtm activation methods

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -285,6 +285,46 @@
     @broadcastMessages.push message

+  activateRealtimeManager: (doc) ->
+
+    @rtm.setRealtimeDoc doc
+    @setCollaborativeReferences()
+    @addParticipant whoami()
+    @registerCollaborationSessionId()
+    @bindRealtimeEvents()
+
+    if @amIHost
+    then @activateRealtimeManagerForHost()
+    else @activateRealtimeManagerForParticipant()
+
+    @rtm.isReady = yes
+    @emit 'RTMIsReady'
+
+    unless @myWatchMap.values().length
+      @listChatParticipants (accounts) =>
+        accounts.forEach (account) =>
+          {nickname} = account.profile
+          @myWatchMap.set nickname, nickname
+
+
+  activateRealtimeManagerForHost: ->
+
+    @getView().setClass 'host'
+    @startHeartbeat()
+
+
+  activateRealtimeManagerForParticipant: ->
+
+    @startRealtimePolling()
+    @resurrectSnapshot()
+
+    if @collaborationHost in @myWatchMap.values()
+      @reviveHostSnapshot()
+
+    if @permissions.get(nick()) is 'read'
+      @makeReadOnly()
+
+
   loadCollaborationFile: (fileId) ->

     return  unless fileId


collaboration: auto bind to notification after create

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

     @showChatPane()

+    @bindAutoInviteHandlers()
+
     @transitionViewsToActive()
     @collectButtonShownMetric()
     @bindRealtimeEvents()
@@ -928,6 +930,25 @@
     if openFolders and not @amIHost
       for path in openFolders
         @finderPane.finderController.expandFolder path
+
+
+  bindAutoInviteHandlers: ->
+
+    {actions} = require 'activity/flux'
+
+    kd.singletons.notificationController.on 'notificationFromOtherAccount', (notification) ->
+      switch notification.action
+        when 'COLLABORATION_REQUEST'
+
+          return if notification.id isnt channel.id
+
+          {channelId, senderUserId, senderAccountId, sender} = notification
+
+          actions.channel.addParticipants(channelId, [senderAccountId], [senderUserId]).then ->
+            whoami().pushNotification
+              receiver  : sender
+              channelId : channelId
+              action    : 'COLLABORATION_REQUEST_ACCEPT'

   transitionViewsToActive: ->


Remove logging.

Remove logging.

--- client/templates/items_dial/items_dial.coffee
+++ client/templates/items_dial/items_dial.coffee
@@ -38,7 +38,6 @@
   )
   $(".circular").draggable()
   center_item_id = Template.parentData()._id
-  console.log center_item_id
   $(".circular").on("dragstop", -> dragStop.apply this, [center_item_id])

 Template.items_dial.helpers


only show my own projects

only show my own projects

--- client/views/pages/dashboard/dashboard.coffee
+++ client/views/pages/dashboard/dashboard.coffee
@@ -134,7 +134,10 @@
 		projects = Projects.find {}, sort: name: 1
 		result = []

-		for project, index in projects.fetch()
+		projects = projects.fetch().filter (project) ->
+			Roles.userIsInRole Meteor.userId(), Permissions.member, project._id
+
+		for project, index in projects
 			if index % 2 == 0
 				result.push projects: [ project ]
 			else


Fix capturing groups for empty strings

Fix capturing groups for empty strings

--- grammars/roff.cson
+++ grammars/roff.cson
@@ -79,8 +79,9 @@
 		patterns: [{
 			name: "string.quoted.double.empty.roff",
 			match: '(")(")'
-			beginCaptures: {0: {name: "punctuation.definition.string.begin.roff"}}
-			endCaptures:   {0: {name: "punctuation.definition.string.end.roff"}}
+			captures:
+				1: {name: "punctuation.definition.string.begin.roff"}
+				2: {name: "punctuation.definition.string.end.roff"}
 		},{
 			name: "string.quoted.double.roff",
 			begin: '"(?!")'


make adjustments for different metadata format in new light curves

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -233,12 +233,12 @@
     @dec     = @subject.coords[1]
     ukirtUrl = "http://surveys.roe.ac.uk:8080/wsa/GetImage?ra=" + @ra + "&dec=" + @dec + "&database=wserv4v20101019&frameType=stack&obsType=object&programmeID=10209&mode=show&archive=%20wsa&project=wserv4"
     # console.log 'ukirtUrl: ', ukirtUrl
-    metadata = @Subject.current.metadata.magnitudes
+    metadata = @Subject.current.metadata
     @el.find('#star-id').html( @Subject.current.location['14-1'].split("\/").pop().split(".")[0].concat(" Information") )
     @el.find('#star-type').html(metadata.spec_type)
-    @el.find('#magnitude').html(metadata.kepler)
-    @el.find('#temperature').html metadata.eff_temp.toString().concat("(K)")
-    @el.find('#radius').html metadata.stellar_rad.toString().concat("x Sol")
+    @el.find('#magnitude').html(metadata.magnitudes.kepler)
+    @el.find('#temperature').html metadata.teff.toString().concat("(K)")
+    @el.find('#radius').html metadata.radius.toString().concat("x Sol")
     @el.find('#ukirt-url').attr("href", ukirtUrl)

   onChangeScaleSlider: ->


Add note that this is actually a PoC

Add note that this is actually a PoC

--- app/js/publisher_poc/nu.nl.coffee
+++ app/js/publisher_poc/nu.nl.coffee
@@ -1,3 +1,6 @@
+# Please note: This is a Proof of Concept to be used for user testing.
+# This really needs clean up before we are actually going to use this.
+
 `/*!
   * $script.js Async loader & dependency manager
   * https://github.com/ded/script.js


fix null ptr in loadhistory #787

fix null ptr in loadhistory #787

--- server/methods/loadHistory.coffee
+++ server/methods/loadHistory.coffee
@@ -25,7 +25,7 @@

 		if ls?
 			fistMessage = messages[messages.length - 1]
-			if fistMessage.ts > ls
+			if fistMessage?.ts > ls
 				query.ts.$lt = fistMessage.ts
 				query.ts.$gt = ls
 				delete options.limit


Refactor address form fields js in order to support two and more address sections on a form (for example, on effective_orders gem checkout page, where could be both billing and shipping addresses). Fix bug for cases when country doesn't have subregions, but state code field remains required.

--- app/assets/javascripts/effective_addresses/address_fields.js.coffee
+++ app/assets/javascripts/effective_addresses/address_fields.js.coffee
@@ -1,20 +1,34 @@
-$(document).on 'change', "select[data-effective-address-country]", (event) ->
-  country_code = $(this).val()
-  uuid = $(this).data('effective-address-country')
-  nested_fields = $(this).closest('.nested-fields')
-  form = $(this).closest('form')
+loadSubregions = ($countrySelect) ->
+  $.each $countrySelect, (index, countrySelector) ->
+    $particularCountrySelect = $(countrySelector)
+    countryCode = $particularCountrySelect.val()
+    uuid = $particularCountrySelect.data('effective-address-country')

-  # clear postal_code values on country change
-  (nested_fields || form).find("input[data-effective-address-postal-code='#{uuid}']").val('')
+    $nestedFields = $particularCountrySelect.closest('.nested-fields')
+    $form = $particularCountrySelect.closest('form')

-  # load state options
-  url = "/addresses/subregions/#{country_code}"
-  state_select = (nested_fields || form).find("select[data-effective-address-state='#{uuid}']").first()
+    $container = if $nestedFields.length == 0 then $form else $nestedFields

-  if country_code.length == 0
-    state_select.prop('disabled', true).addClass('disabled').parent('.form-group').addClass('disabled')
-    state_select.html('<option value="">Please choose a country first</option>')
-  else
-    state_select.prop('disabled', false).removeClass('disabled').parent('.form-group').removeClass('disabled')
-    state_select.find('option').first().text('loading...')
-    state_select.load(url)
+    # clear postal_code values on country change
+    $container.find("input[data-effective-address-postal-code='#{uuid}']").val('')
+
+    # load state options
+    url = "/addresses/subregions/#{countryCode}"
+    $stateSelect = $container.find("select[data-effective-address-state='#{uuid}']:first")
+
+    if countryCode.length == 0
+      $stateSelect.prop('disabled', true).addClass('disabled').parent('.form-group').addClass('disabled')
+      $stateSelect.html('<option value="">Please choose a country first</option>')
+    else
+      $stateSelect.prop('disabled', false).removeClass('disabled').parent('.form-group').removeClass('disabled')
+      $stateSelect.find('option').first().text('loading...')
+      $stateSelect.load url, ->
+        stateSelectAvailable = $(@).find('option:last').val().length > 0
+        $(@).prop('required', stateSelectAvailable)
+        $(@).prop('disabled', !stateSelectAvailable)
+
+$(document).on 'change', 'select[data-effective-address-country]', ->
+  loadSubregions($(@))
+
+$ -> loadSubregions($('select[data-effective-address-country]'))
+$(document).on 'page:change', -> loadSubregions($('select[data-effective-address-country]'))


activity: modify single private channel route to exclude postId ops

--- client/activity/lib/routes/singleprivatechannel.coffee
+++ client/activity/lib/routes/singleprivatechannel.coffee
@@ -13,16 +13,18 @@

 NewPrivateChannelRoute = require './newprivatechannel'
 AllPrivateChannelsRoute = require './allprivatechannels'
+SingleMessageRoute = require './singlemessage'

 module.exports = class SinglePrivateMessageRoute

   constructor: ->

-    @path = ':privateChannelId(/:postId)'
+    @path = ':privateChannelId'
     @childRoutes = [
       new NewPrivateChannelRoute
       new AllPrivateChannelsRoute
+      new SingleMessageRoute
     ]

@@ -48,7 +50,7 @@
         privateChannelId = botChannel.id

     if privateChannelId
-      transitionToChannel privateChannelId, postId, done
+      transitionToChannel privateChannelId, done
     else if not thread
       threadActions.changeSelectedThread null
       done()
@@ -62,9 +64,12 @@
     messageActions.changeSelectedMessage null

-transitionToChannel = (channelId, postId, done) ->
+transitionToChannel = (channelId, done) ->

-  successFn = ({ channel }) -> changeToChannel channel, postId, done
+  successFn = ({ channel }) ->
+    threadActions.changeSelectedThread channel.id
+    channelActions.loadParticipants channel.id
+    done()

   channel = kd.singletons.reactor.evaluateToJS ['ChannelsStore', channelId]


StacksCustomViews: fetchGithubRepos: fetch organizations, user repos and so on from remote.api.Github

--- client/admin/lib/views/stacks/stackscustomviews.coffee
+++ client/admin/lib/views/stacks/stackscustomviews.coffee
@@ -106,6 +106,34 @@
     return out.machines

+  fetchGithubRepos = (options, callback) ->
+
+    { oauth_data } = options
+    { Github }     = remote.api
+
+    Github.api method: 'user.getOrgs', (err, orgs) ->
+
+      kd.warn err  if err
+
+      orgs ?= []
+
+      # to make identical users and orgs assigning
+      # username to login field as well
+      oauth_data.login = oauth_data.username
+      users = [oauth_data]
+
+      Github.api
+        method  : 'repos.getFromUser'
+        options :
+          user  : users.first.username
+      , (err, repos) ->
+
+        users.first.err   = err
+        users.first.repos = repos ? []
+
+        callback null, {orgs, users}
+
+
   handleCheckTemplate = (options, callback) ->

     { stackTemplate } = options
@@ -530,7 +558,10 @@
       loader       = @addTo container,
         mainLoader : 'Fetching repositories list...'

-      GitHub.fetchUsersRepos users, (err, response) =>
+      fetchGithubRepos options, (err, repo_data) =>
+
+        showError err
+
         loader.hide()

         views        = @addTo container,
@@ -539,7 +570,9 @@

         {controller, __view: repoList} = views.repoList

-        controller.replaceAllItems response
+        {orgs, users} = repo_data
+        controller.replaceAllItems users.concat orgs
+
         container.forwardEvent repoList, 'RepoSelected'

       return container


Make sure the preloader does not wait for media players with an undefined source

--- framer/Extras/Preloader.coffee
+++ framer/Extras/Preloader.coffee
@@ -52,13 +52,15 @@
 				@_handleProgress()

 	addPlayer: (player) =>
-		if player and player.readyState? and player not in @_media
-			if player.readyState < 3
-				@_media.push(player)
-				# Wait until there is enough data for playback to start playing smoothly
-				Events.wrap(player).addEventListener "canplaythrough", =>
-					@_mediaLoaded.push(player)
-					@_handleProgress()
+		return unless player and player not in @_media
+		return unless player.src? and player.getAttribute('src') isnt "undefined"
+		return unless player.readyState? and player.readyState < 3
+		# … else
+		@_media.push(player)
+		# Wait until there is enough data for playback to start playing
+		Events.wrap(player).addEventListener "canplaythrough", =>
+			@_mediaLoaded.push(player)
+			@_handleProgress()

 	start: =>
 		return if @isLoading


SocialWorker: JLocation: return next err

--- workers/social/lib/social/models/location/index.coffee
+++ workers/social/lib/social/models/location/index.coffee
@@ -63,7 +63,7 @@
       countries = countryCodes.map (countryCode) => (next) =>

         collection.distinct 'stateCode', { countryCode }, (err, stateCodes) =>
-          return callback err  if err
+          return next err  if err

           states = stateCodes.filter(Boolean).map (stateCode) => (nextState) =>

@@ -78,7 +78,7 @@

           async.seris states, -> next()

-      async.series countries, -> callback null
+      async.series countries, callback

   @importAll = secure (client, callback) ->


Accepts jQuery promises

Accepts jQuery promises

--- src/client/datasource.coffee
+++ src/client/datasource.coffee
@@ -92,7 +92,7 @@
       else if _.isFunction(@def)
         ret = @def()
         if ret?.promise
-          dfd = ret
+          return promises.when(ret)
         else
           dfd.resolve ret
       else


[nav] only pull-to-refresh on touch devices

--- app/assets/javascripts/states/main/views/page_layout.js.coffee
+++ app/assets/javascripts/states/main/views/page_layout.js.coffee
@@ -18,7 +18,8 @@
       $(document).off("swipedown")

     after_render: ->
-      # refresh page when pulling down at top
-      $(document).swipedown (e, info) =>
-        if info.deltaY > 100
-          @state.hard_refresh()
+      if Modernizr.touch # needed to avoid mouseclick fallback
+        # refresh page when pulling down at top
+        $(document).swipedown (e, info) =>
+          if info.deltaY > 100
+            @state.hard_refresh()


Don't display an editor window in atom-environment-spec

--- spec/atom-environment-spec.coffee
+++ spec/atom-environment-spec.coffee
@@ -259,6 +259,7 @@
       }
       atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, window, document: fakeDocument})
       spyOn(atomEnvironment.packages, 'getAvailablePackagePaths').andReturn []
+      spyOn(atomEnvironment, 'displayWindow').andReturn Promise.resolve()
       atomEnvironment.startEditorWindow()
       atomEnvironment.unloadEditorWindow()
       atomEnvironment.destroy()


Add next tick call

Add next tick call

--- spec/editor-component-spec.coffee
+++ spec/editor-component-spec.coffee
@@ -1785,6 +1785,7 @@
       editor.on 'screen-lines-changed', -> callingOrder.push 'screen-lines-changed'
       wrapperView.on 'editor:display-updated', -> callingOrder.push 'editor:display-updated'
       editor.insertText("HELLO! HELLO!\n HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! ")
+      nextTick()

       expect(callingOrder).toEqual ['screen-lines-changed', 'editor:display-updated']


:white_check_mark: #119 test first

:white_check_mark: #119 test first

--- spec/operator-general-spec.coffee
+++ spec/operator-general-spec.coffee
@@ -244,6 +244,16 @@
             cursor: [2, 0]
         it "deletes both lines", ->
           ensure 'dk', text: "a\nb\n", cursor: [1, 1]
+
+      # [TODO] write more generic operator test. #119
+      # This is general behavior of all operator.
+      # When it cant move, its target selection should be empty so nothing happen.
+      describe "when it can't move", ->
+        textOriginal = "a\nb\n"
+        cursorOriginal = [0, 0]
+        it "deletes delete nothing", ->
+          set text: textOriginal, cursor: cursorOriginal
+          ensure 'dk', text: textOriginal, cursor: cursorOriginal

     describe "when followed by a G", ->
       beforeEach ->


Fix specs for latest master

Fix specs for latest master

--- spec/provider-manager-spec.coffee
+++ spec/provider-manager-spec.coffee
@@ -44,25 +44,25 @@

     it 'adds providers', ->
       expect(providerManager.isProviderRegistered(testProvider)).toEqual(false)
-      expect(providerManager.subscriptions?.disposables?.indexOf(testProvider)).toBe(-1)
+      expect(hasDisposable(providerManager.subscriptions, testProvider)).toBe false

       providerManager.addProvider(testProvider, '2.0.0')
       expect(providerManager.isProviderRegistered(testProvider)).toEqual(true)
       apiVersion = providerManager.apiVersionForProvider(testProvider)
       expect(apiVersion).toEqual('2.0.0')
-      expect(providerManager.subscriptions?.disposables?.indexOf(testProvider)).not.toBe(-1)
+      expect(hasDisposable(providerManager.subscriptions, testProvider)).toBe true

     it 'removes providers', ->
       expect(providerManager.metadataForProvider(testProvider)).toBeFalsy()
-      expect(providerManager.subscriptions?.disposables?.indexOf(testProvider)).toBe(-1)
+      expect(hasDisposable(providerManager.subscriptions, testProvider)).toBe false

       providerManager.addProvider(testProvider)
       expect(providerManager.metadataForProvider(testProvider)).toBeTruthy()
-      expect(providerManager.subscriptions?.disposables?.indexOf(testProvider)).not.toBe(-1)
+      expect(hasDisposable(providerManager.subscriptions, testProvider)).toBe true

       providerManager.removeProvider(testProvider)
       expect(providerManager.metadataForProvider(testProvider)).toBeFalsy()
-      expect(providerManager.subscriptions?.disposables?.indexOf(testProvider)).toBe(-1)
+      expect(hasDisposable(providerManager.subscriptions, testProvider)).toBe false

     it 'can identify a provider with a missing getSuggestions', ->
       bogusProvider =
@@ -442,3 +442,11 @@
       expect(providers[0]).toEqual provider2
       expect(providers[1]).toEqual provider3
       expect(providers[2]).toEqual provider1
+
+hasDisposable = (compositeDisposable, disposable) ->
+  if compositeDisposable?.disposables?.indexOf?
+    compositeDisposable.disposables.indexOf(disposable) > -1
+  if compositeDisposable?.disposables?.has?
+    compositeDisposable.disposables.has(disposable)
+  else
+    false


Handle zeros properly during templating

Handle zeros properly during templating

--- src/core/modules/html.coffee
+++ src/core/modules/html.coffee
@@ -21,7 +21,7 @@
   closeTag = "</#{name}>"

   if type is '='
-    (content) -> beginTag + (content or '') + closeTag
+    (content) -> beginTag + (if content isnt null and content isnt undefined then content else '') + closeTag
   else if type is '+'
     (content, arg0) -> #TODO add more args as necessary
       tag = replace beginTag, '{0}', arg0


Fixed bug in which too many pages are added to the history when navigating to a page for which there is no backbone route

--- core/app/backbone/contrib/default_click_handler.coffee
+++ core/app/backbone/contrib/default_click_handler.coffee
@@ -22,10 +22,9 @@
       trigger: true
       replace: true
   else
-    oldFragment = Backbone.history.fragment
-    Backbone.history.navigate routeTo, false
-    unless Backbone.history.loadUrl(routeTo)
-      Backbone.history.navigate oldFragment, false
+    if Backbone.history.loadUrl(routeTo) # Try if there is a Backbone route available
+      Backbone.history.navigate routeTo, false
+    else
       window.open routeTo, FactlinkApp.linkTarget
       window.focus()


video: opentok fix docs

video: opentok fix docs

--- client/app/lib/videocollaboration/services/opentok.coffee
+++ client/app/lib/videocollaboration/services/opentok.coffee
@@ -45,7 +45,7 @@
    * Initializes the client library of OpenTok.
    * TODO: It may be wise to include this in our bundle?
    *
-   * @emits OpenTokService#ClientLoaded
+   * @emits OpenTokService~ClientLoaded
   ###
   initOpenTokClient: ->

@@ -58,6 +58,13 @@
       @_loaded = yes

+  ###*
+   * Call given callback if loaded, otherwise register callback to be called
+   * when 'ClientLoaded' event is emitted.
+   *
+   * @param {function} callback
+   * @listens OpenTokService~ClientLoaded
+  ###
   whenReady: (callback) ->

     if @_loaded


detect if the port used is assigned for qunit grunt or for web based qunit

--- tests/coffee/ezBreadcrumbs-test.coffee
+++ tests/coffee/ezBreadcrumbs-test.coffee
@@ -7,7 +7,8 @@
     html          = $ document.documentElement
     body          = $ document.body

-    testElement = ($ '#test-breadcrumb').find '.breadcrumb'
+    testElement = if location.port is '3000' then ($ '#qunit-fixture').find('.breadcrumb') else ($ '#test-breadcrumb').find '.breadcrumb'
+
     children    = testElement.children 'li'

     crumbWidths = children


fix(SFDC): fix bug where opening new file would cause attachments to fail

--- src/flux/models/utils.coffee
+++ src/flux/models/utils.coffee
@@ -585,8 +585,8 @@
     for commaPath in commaPaths
       joinedVals = []
       paths = commaPath.split("+")
-      for path in paths
-        parts = path.split(".")
+      for filePath in paths
+        parts = filePath.split(".")
         curVal = model
         for part in parts
           if _.isFunction(curVal[part])


add another +1

add another +1

--- scripts/seal-of-approval.coffee
+++ scripts/seal-of-approval.coffee
@@ -26,7 +26,8 @@
  "http://i.imgur.com/NJcSZ.gif",
  "http://i.imgur.com/FSHXA.gif",
  "http://i.imgur.com/bpHdq.gif",
- "http://mlkshk.com/r/CYHO.gif"
+ "http://mlkshk.com/r/CYHO.gif",
+ "http://i.imgur.com/uM5NJ.gif"
 ]

 module.exports = (robot) ->


generalised ndp_interactors_page, so we can also use it in old discussion page

--- core/app/backbone/collections/ndp_interactors_page.coffee
+++ core/app/backbone/collections/ndp_interactors_page.coffee
@@ -17,12 +17,11 @@
     @totalPages = Math.floor(response.total / @perPage)
     response.users

-  paginator_ui:
-    perPage: 6
-    firstPage: 1
-    currentPage: 1
-
   initialize: (opts) ->
     @paginator_core =
       dataType: "json"
       url: "/facts/#{opts.fact_id}/#{group_for_type(opts.type)}"
+    @paginator_ui =
+      perPage: opts.perPage || 6
+      firstPage: 1
+      currentPage: 1


make sure we always have a dropdown

make sure we always have a dropdown

--- core/app/backbone/collections/topic_search_results.coffee
+++ core/app/backbone/collections/topic_search_results.coffee
@@ -32,4 +32,5 @@
       @makeEmpty()
     else
       @query = query
+      @reset []
       @fetch()


Use \@options instead of \@defaults

Use \@options instead of \@defaults

--- core/app/backbone/views/wheel/base_fact_wheel_view.coffee
+++ core/app/backbone/views/wheel/base_fact_wheel_view.coffee
@@ -29,7 +29,7 @@
     @opinionTypeRaphaels = {}

   defaultStrokeWidth: ->
-    3/5 * @defaults.radius
+    3/5 * @options.radius

   hoverStrokeWidth: ->
     @defaultStrokeWidth() + 2


evaluator tests: decimals and strings

evaluator tests: decimals and strings

--- test/evaluator.coffee
+++ test/evaluator.coffee
@@ -6,9 +6,24 @@
 describe 'evaluator', ->
   describe '.', ->
     describe 'build', ->
-      it 'builds numbers', ->
+      it 'builds integer', ->
         f = e.build {
           expression: 'integer'
           value: 5
         }
         assert.equal f.value, 5
+
+      it 'builds decimals', ->
+        f = e.build {
+          expression: 'decimal'
+          whole: 3
+          part: 2
+        }
+        assert.equal f.value, 3.2
+
+      it 'builds strings', ->
+        f = e.build {
+          expression: 'string'
+          string: 'foobar'
+        }
+        assert.equal f.value, 'foobar'


log deleted

log deleted

--- test/list.test.coffee
+++ test/list.test.coffee
@@ -45,7 +45,6 @@
       currentList.remove 'id'

     onNodeRemoved = (nodeList) ->
-      console.log nodeList
       nodeList.should.be.an 'array'
       nodeList.length.should.be.equal 0
       done()


pushing changes up from the XLF.Survey model to the settings

--- dkobo/koboform/static/js/xlform/view_xlformbuilder.coffee
+++ dkobo/koboform/static/js/xlform/view_xlformbuilder.coffee
@@ -278,8 +278,9 @@
     @rowViews = new Backbone.Model()

     @survey.rows.on "add", @softReset, @
-    # @survey.rows.on "reset", @reset, @
-    # @survey.on "change", @softReset, @
+
+    @survey.on "change:form_title", (s, val)=> s.settings.set("form_title", val)
+    @survey.on "change:form_id", (s, val)=> s.settings.set("form_id", val)

     @onPublish = options.publish || $.noop
     @onSave = options.save || $.noop


Fix tip plugin's legacy cruft now causing incorrect offset.

--- src/js/jquery.hlf.tip.coffee
+++ src/js/jquery.hlf.tip.coffee
@@ -573,7 +573,7 @@
           offset.top += $trigger.outerHeight()
         if @snap.toYAxis is off
           # Note arbitrary buffer offset.
-          offset.left = baseOffset.left - (@$tip.outerWidth() - 12) / 2
+          offset.left = baseOffset.left - @$tip.outerWidth() / 2
       if @snap.toYAxis is on
         if @isDirection 'right', $trigger
           offset.left += $trigger.outerWidth()


commit tree-view color

commit tree-view color

--- lib/isotope-ui.coffee
+++ lib/isotope-ui.coffee
@@ -27,11 +27,6 @@
         'Light',
         'Regular'
       ]
-    colorTreeSelection:
-      description: 'Make the selected file stand out in tree-view.
-        Looks better off when scrollbars always visible (e.g. on Linux)'
-      type: 'boolean'
-      default: true
     customBackgroundColor:
       description: 'Choose a custom background color.'
       type: 'boolean'


Fold correctly now

Fold correctly now

--- lib/log-filter.coffee
+++ lib/log-filter.coffee
@@ -81,7 +81,14 @@

     # Atom folds the line under the selected row
     # and the first line doesn't really fold
-    @textEditor.setSelectedBufferRange([[start - 1, 0], [end, 0]])
+    actualStartLine = start-1
+    actualStartColumn = 0
+    if actualStartLine <= 0
+      actualStartLine = 0
+      actualStartColumn = 0
+    else
+      actualStartColumn = @textEditor.getBuffer().lineLengthForRow(actualStartLine)
+    @textEditor.setSelectedBufferRange([[actualStartLine, actualStartColumn], [end, @textEditor.getBuffer().lineLengthForRow(end)]])
     @textEditor.getSelections()[0].fold()

   shouldFilterScopes: (tokens, filterScopes) ->


Change torepdo salvo render order

Change torepdo salvo render order

--- lib/simulator2.coffee
+++ lib/simulator2.coffee
@@ -103,10 +103,10 @@
 simulateTorpedo = (fleet, enemyFleet, raigeki) ->
   return unless raigeki?
   attacks = []
+  if raigeki.api_frai?
+    attacks = attacks.concat(simulateTorpedoAttack(fleet, enemyFleet, raigeki.api_fydam, raigeki.api_frai, raigeki.api_fcl))
   if raigeki.api_erai?
     attacks = attacks.concat(simulateTorpedoAttack(enemyFleet, fleet, raigeki.api_eydam, raigeki.api_erai, raigeki.api_ecl))
-  if raigeki.api_frai?
-    attacks = attacks.concat(simulateTorpedoAttack(fleet, enemyFleet, raigeki.api_fydam, raigeki.api_frai, raigeki.api_fcl))
   return new Stage
     type: StageType.Torpedo
     attacks: attacks


Use correct CTA Bar on New Artist Pages

Use correct CTA Bar on New Artist Pages

--- apps/artist_new/client/cta.coffee
+++ apps/artist_new/client/cta.coffee
@@ -12,6 +12,7 @@
   ctaBarView = new CTABarView
     headline: ctaHeadline
     name: name
+    mode: ''
     persist: true
     modalOptions:
       copy: modalCopy


Dock: removed some apps from navigation

Dock: removed some apps from navigation

--- client/Main/maincontroller/dockcontroller.coffee
+++ client/Main/maincontroller/dockcontroller.coffee
@@ -3,11 +3,11 @@
   isRunning = (item) -> item?.state is 'running'

   defaultItems = [
-    { title : 'Activity',  path : '/Activity', order : 10, type :'persistent' }
+    # { title : 'Social',  path : '/Activity', order : 10, type :'persistent' }
     { title : 'IDE',       path : '/IDE',      order : 20, type :'persistent' }
     { title : 'Teamwork',  path : '/Teamwork', order : 30, type :'persistent' }
-    { title : 'Apps',      path : '/Apps',     order : 40, type :'persistent' }
-    { title : 'DevTools',  path : '/DevTools', order : 50, type :'persistent' }
+    # { title : '+',      path : '/Apps',     order : 40, type :'persistent' }
+    # { title : 'DevTools',  path : '/DevTools', order : 50, type :'persistent' }
     # { title : 'Environments',  path : '/Environments', order : 60, type :'persistent' }
   ]


Client: VMSettings: Updated snapshotlistitem ui views and their callbacks

--- client/app/lib/providers/snapshotlistitem.coffee
+++ client/app/lib/providers/snapshotlistitem.coffee
@@ -1,9 +1,6 @@
-kd                        = require 'kd'
-remote                    = require('app/remote').getInstance()
-JView                     = require '../jview'
-nicetime                  = require '../util/nicetime'
-
-
+kd       = require 'kd'
+JView    = require '../jview'
+nicetime = require '../util/nicetime'

 module.exports = class SnapshotListItem extends kd.ListItemView

@@ -43,17 +40,26 @@
   ###
   initViews: ->

+    listView = @getDelegate()
+
     data = @getData()
+
     @editInput = new kd.HitEnterInputView
       type        : 'text'
       placeholder : 'Snapshot Name'
       cssClass    : 'label'
-      callback    : @bound 'renameSnapshot'
+      callback    : =>
+        listView.emit 'ItemAction',
+          action        : 'RenameSnapshot'
+          item          : this

     @editRenameBtn = new kd.ButtonView
       title    : 'rename'
       cssClass : 'solid green small rename'
-      callback : @bound 'renameSnapshot'
+      callback    : =>
+        listView.emit 'ItemAction',
+          action        : 'RenameSnapshot'
+          item          : this

     @editCancelBtn = new kd.View
       partial  : 'cancel'
@@ -76,16 +82,25 @@
     @infoDeleteBtn = new kd.ButtonView
       iconOnly : true
       cssClass : 'delete'
-      callback : @bound 'confirmDeleteSnapshot'
       tooltip  :
         title  : 'Delete Snapshot'
+      callback : =>
+        listView.emit 'ItemAction',
+          action        : 'DeleteSnapshot'
+          item          : this
+          options       :
+            title       : 'Delete snapshot?'
+            description : 'Do you want to remove ?'

     @infoNewVmBtn = new kd.ButtonView
       iconOnly : true
       cssClass : 'new-vm'
-      callback : @bound 'vmFromSnapshot'
       tooltip  :
         title  : 'Create VM from Snapshot'
+      callback : =>
+        listView.emit 'ItemAction',
+          action        : 'VMFromSnapshot'
+          item          : this

     @addSubView @editView = new JView
       cssClass        : 'edit hidden'


test/virtualmachines: check for virtual machine

--- client/test/lib/dashboard/virtualmachines.coffee
+++ client/test/lib/dashboard/virtualmachines.coffee
@@ -30,3 +30,41 @@

     async.series queue, (err, result) ->
       done()  unless err
+
+
+  virtualmachines: (browser) ->
+
+    member = utils.getUser no, 1
+
+    virtualMachineSelector = '.HomeAppView--section.virtual-machines'
+    runningVMSelector = "#{virtualMachineSelector} .MachinesListItem-machineLabel.Running"
+    machineDetailSelector = '.MachinesListItem-machineDetails'
+    vmPowerSelector = "#{machineDetailSelector} .MachineDetails div.GenericToggler:nth-of-type(2)"
+    alwaysOnSelector = "#{machineDetailSelector} .MachineDetails div.GenericToggler:nth-of-type(3)"
+    vmSharingSelector = "#{machineDetailSelector} .MachineDetails div.GenericToggler:nth-of-type(4)"
+    vmPowerToggleSelector = "#{vmPowerSelector} .react-toggle-thumb"
+    alwaysOnToggleSelector = "#{alwaysOnSelector} .react-toggle-thumb"
+    vmSharingToggleSelector = "#{vmSharingSelector} .react-toggle-thumb"
+    machineSharingDetails = '.MachineSharingDetails'
+    inputSelector = "#{machineSharingDetails} input.kdinput.text"
+    memberSelector = "#{machineSharingDetails} .AutocompleteListItem"
+    membersList = "#{machineSharingDetails} .ListView"
+    removeSharedMachineMember = "#{membersList} .remove"
+    memberNicknameToShareMachine = "@#{member.username}"
+
+    addAConnectedMachineButtonSelector = '.kdbutton.GenericButton.HomeAppViewVMSection--addOwnMachineButton'
+    addYourOwnMachineSelector = '.kdmodal.add-managed-vm'
+
+    selectButtonSelector = "#{addYourOwnMachineSelector} .code .select-all"
+    closeAddYourOwnMachineModal = "#{addYourOwnMachineSelector} .close-icon.closeModal"
+    pressCMDCNotificationSelector = '.kdview.kdtooltip.just-text.placement-top.direction-center'
+
+
+    browser
+      .pause 5000
+      .url virtualMachinesUrl
+      .waitForElementVisible virtualMachineSelector, 20000
+      .waitForElementVisible runningVMSelector, 20000
+      .click runningVMSelector
+      .waitForElementVisible machineDetailSelector, 20000
+


Load system feedback template for SectionEdit tests

--- cms/static/coffee/spec/views/section_spec.coffee
+++ cms/static/coffee/spec/views/section_spec.coffee
@@ -26,9 +26,11 @@
 describe "CMS.Views.SectionEdit", ->
     describe "Basic", ->
         tpl = readFixtures('section-name-edit.underscore')
+        feedback_tpl = readFixtures('system-feedback.underscore')

         beforeEach ->
             setFixtures($("<script>", {id: "section-name-edit-tpl", type: "text/template"}).text(tpl))
+            appendSetFixtures($("<script>", {id: "system-feedback-tpl", type: "text/template"}).text(feedback_tpl))
             spyOn(CMS.Views.SectionEdit.prototype, "switchToShowView")
                 .andCallThrough()
             spyOn(CMS.Views.SectionEdit.prototype, "showInvalidMessage")


CollaborativeWorkspace: Show session not active view if host is not there.

--- client/landing/CollaborativeWorkspace/collaborativeworkspace.coffee
+++ client/landing/CollaborativeWorkspace/collaborativeworkspace.coffee
@@ -122,8 +122,14 @@

     @usersRef.child(@getHost()).child("timestamp").on "value", (snapshot) =>
       return if @amIHost() or @connected or snapshot.val() is null
+
+      if Date.now() - snapshot.val() > 20000
+        return @pingHostTimer = KD.utils.wait 10000, =>
+          @showNotActiveView()
+
       @syncWorkspace()
       @connected = yes
+      KD.utils.killWait @pingHostTimer

   requestPingFromHost: ->
     @requestPingRef.set Date.now()


use coffe notation

use coffe notation

--- BackofficeBundle/Resources/public/coffee/orchestraLib.coffee
+++ BackofficeBundle/Resources/public/coffee/orchestraLib.coffee
@@ -31,7 +31,9 @@

 displayMenu = (route, refresh) ->
   selectedPath = "#" + (route || Backbone.history.fragment)
-  refresh = refresh || (typeof route == "undefined")
+  refresh = refresh || route?
+  console refresh
+  console selectedPath
   $.ajax
     url: $("#left-panel nav").data("url")
     type: "GET"


Refactor test to be less massive

Refactor test to be less massive

--- server/test/units/indicator_data.coffee
+++ server/test/units/indicator_data.coffee
@@ -95,23 +95,17 @@
     ]
   )

-  Q.nsend(
-    indicator, 'save'
-  ).then(->
+  saveIndicator = (indicator, cb) ->
+    indicator.save(cb)
+
+  Q.nfcall(
+    async.map, [indicator, indicator2], saveIndicator
+  ).then((indicators)->
     indicatorData.indicator = indicator
-
-    Q.nsend(
-      indicatorData, 'save'
-    )
-  ).then(->
-    Q.nsend(
-      indicator2, 'save'
-    )
-  ).then(->
     indicatorData2.indicator = indicator2

-    Q.nsend(
-      indicatorData2, 'save'
+    Q.nfcall(
+      async.each, [indicatorData, indicatorData2], saveIndicator
     )
   ).then(->
     IndicatorData.dataToSeedJSON()
@@ -122,8 +116,6 @@

       assert.lengthOf seedData, 2,
         "Expected the seed data to have only 1 entry"
-
-      console.log seedData

       indicator1Data = seedData[0]
       assert.strictEqual indicator1Data.indicator, indicator.short_name,


#301 - Refactor night mode timer

#301 - Refactor night mode timer

--- source/scripts/views/night.coffee
+++ source/scripts/views/night.coffee
@@ -4,7 +4,7 @@

 DELAY = 1000 * 60 * 60 * 12 # 12 hours
 MORNING = 7
-NIGHT = MORNING + 12
+EVENING = MORNING + 12

 class NightMode extends Base.View

@@ -18,38 +18,73 @@

     @toggle Pref.night

-  toggle: (value) =>
+
+  ###
+   * (private) Turn
+   *
+   * Set night mode. Default on.
+   *
+   * - [value] (boolean) - turn it off or on
+  ###
+
+  _turn: (value=true) ->
+    @el.toggleClass 'dark', value
+
+
+  ###
+   * (private) Auto Timer
+   *
+   * Starts a recursive timer for the 'auto' mode
+  ###
+
+  _autoTimer: ->
     now = new Date()
     hours = now.getHours()

-    if value is Pref.NIGHT_AUTO
-      nextRun = new Date()
-      nextRun.setMinutes 0
+    nextRun = new Date()
+    nextRun.setMinutes 0
+    nextRun.setSeconds 0

-      # turn it off at 7am tomorrow
-      if hours > NIGHT
-        nextRun.setHours MORNING
-        nextRun.setDate nextRun.getDate()+1
+    # Run it tomorrow morning
+    if hours > EVENING
+      nextRun.setHours MORNING
+      nextRun.setDate nextRun.getDate() + 1

-      # turn it off at 7am today
-      else if hours < MORNING
-        nextRun.setHours MORNING
+    # Run it this morning
+    else if hours < MORNING
+      nextRun.setHours MORNING

-      # turn it off 7pm today
-      else
-        # turn it off 7pm today
-        nextRun.setHours NIGHT
+    # Run it this evening
+    else
+      nextRun.setHours EVENING

-      delay nextRun.getTime() - now.getTime(), =>
-        @el.toggleClass 'dark'
-        delay DELAY, =>
-          @el.toggleClass 'dark'
+    state = (hours > EVENING or hours < MORNING)
+    @_turn state

-    if (value is Pref.NIGHT_DARK) or
-    (value is Pref.NIGHT_AUTO and (hours > NIGHT or hours < MORNING))
-      @el.addClass 'dark'
+    delay nextRun.getTime() - now.getTime(), =>
+      @_turn not state
+      @_autoTimer()

-    else if value is Pref.NIGHT_LIGHT
-      @el.removeClass 'dark'
+
+  ###
+   * Toggle
+   *
+   * Handles light, dark, and auto modes
+   *
+   * - value (int) : value to set to
+  ###
+
+  toggle: (value) =>
+
+    switch value
+
+      when Pref.NIGHT_LIGHT
+        @_turn off
+
+      when Pref.NIGHT_DARK
+        @_turn on
+
+      when Pref.NIGHT_AUTO
+        @_autoTimer()

 module.exports = NightMode


Trigger symmetrical events for working and upstream nodes

When the manager performs an action, the end result may only impact one
of the nodes (usually upstream), however the working node should still be
made aware of the event.

--- src/coffee/cilantro/models/context/manager.coffee
+++ src/coffee/cilantro/models/context/manager.coffee
@@ -97,6 +97,7 @@
             @working.define(attrs, options)

         # Save the model on behalf of a node. Defaults to the upstream node.
+        # TODO debounce this call to prevent successive calls from firing.
         save: (node, options) ->
             node ?= @upstream

@@ -119,47 +120,74 @@
         # the node, nodes in the working tree are never removed.
         remove: (ident, options) ->
             ident = ident.identity?() or ident
-            if (node = @upstream.find(ident))
-                node.destroy()
-                @save(node)
+            if not (n = @find(ident))
+                return
+            if (u = @upstream.find(ident))
+                u.destroy()
+                n.trigger('remove')
+                u.trigger('remove')
+                @save(n)

         # Applies a node in the working tree to upstream. This triggers a
         # validation and only gets applied if deemed valid. On success, this
         # triggers a sync with a server.
         apply: (ident, options) ->
             ident = ident.identity?() or ident
-            attrs = @find(ident).toJSON()
-            node = @upstream.define(ident)
-            node.set(attrs, options)
-            @save(node)
+            if not (n = @find(ident))
+                return
+            # No attributes, which means this is not valid
+            if not (attrs = n.toJSON({strict: true}))
+                return
+            # Define upstream, this is idempotent
+            u = @upstream.define(ident, n.path(), type: n.type)
+            u.set(attrs, options)
+            if u.hasChanged()
+                n.trigger('apply')
+                u.trigger('apply')
+                @save(u)

         # Reverts a working tree node to it's upstream state if one exists.
         revert: (ident, options) ->
             ident = ident.identity?() or ident
-            if not (wn = @find(ident))
-                return
-            if (un = @upstream.find(ident))
-                wn.set(un.toJSON())
+            if not (n = @find(ident))
+                return
+            if (u = @upstream.find(ident))
+                n.set(u.toJSON())
+                if n.hasChanged()
+                    n.trigger('revert')
+                    u.trigger('revert')
             else
-                wn.clear()
+                n.clear()

         # Enables a node in the upstream tree that was previously disabled.
         # Triggers a sync.
         enable: (ident) ->
             ident = ident.identity?() or ident
-            if (node = @upstream.find(ident))
-                node.set(enabled: true)
-                @save(node)
+            if not (n = @find(ident))
+                return
+            if (u = @upstream.find(ident))
+                u.set(enabled: true)
+                if u.hasChanged('enabled')
+                    n.trigger('enable')
+                    u.trigger('enable')
+                    @save(u)

         # Disables a node in the upstream tree. Triggers a sync.
         disable: (ident) ->
             ident = ident.identity?() or ident
-            if (node = @upstream.find(ident))
-                node.set(enabled: false)
-                @save(node)
+            if not (n = @find(ident))
+                return
+            if (u = @upstream.find(ident))
+                u.set(enabled: false)
+                if u.hasChanged('enabled')
+                    n.trigger('disable')
+                    u.trigger('disable')
+                    @save(u)

         clear: ->
             @upstream.clear(reset: true)
+            @upstream.trigger('clear')
+            @working.trigger('clear')
             @save()
             return @


:fire: Spec focus

:fire: Spec focus

--- spec/rich-description-spec.coffee
+++ spec/rich-description-spec.coffee
@@ -1,6 +1,6 @@
 {getSettingDescription} = require '../lib/rich-description'

-fdescribe "Rich descriptions", ->
+describe "Rich descriptions", ->
   beforeEach ->
     config =
       type: 'object'


Update requires

Update requires

--- spec/text-editor-view-spec.coffee
+++ spec/text-editor-view-spec.coffee
@@ -1,5 +1,8 @@
-{_, $, $$, fs, Range, RootView} = require 'atom'
+RootView = require '../src/root-view'
 TextEditorView = require '../src/text-editor-view'
+{$, $$} = require '../src/space-pen-extensions'
+_ = require 'underscore'
+fs = require 'fs-plus'
 path = require 'path'
 temp = require 'temp'


fix reset default value when change field type

--- BackofficeBundle/Resources/public/coffee/ContentTypeFormView.coffee
+++ BackofficeBundle/Resources/public/coffee/ContentTypeFormView.coffee
@@ -31,6 +31,7 @@
     defaultValueId = targetId.replace(/type$/g, 'default_value')
     displayLoader('#' + optionId)
     $('#' + defaultValueId, @$el).closest( ".form-group" ).hide()
+    $('#' + defaultValueId, @$el).val('')

     $('form', @$el).ajaxSubmit
       type: 'PATCH'


Moved callback to the correct place in router, coffee-ised code a bit.

--- src/middleware/router.coffee
+++ src/middleware/router.coffee
@@ -96,7 +96,7 @@
 	method = http

 	if secured
-                method = https
+        method = https

 	routeReq = method.request options, (routeRes) ->
 		responseDst.status = routeRes.statusCode
@@ -114,29 +114,29 @@
 			bufs.push chunk

-                #See https://www.exratione.com/2014/07/nodejs-handling-uncertain-http-response-compression/
+		#See https://www.exratione.com/2014/07/nodejs-handling-uncertain-http-response-compression/
 		routeRes.on "end", ->
 			responseDst.timestamp = new Date()
 			charset = obtainCharset(routeRes.headers)
-			if (routeRes.headers['content-encoding'] == 'gzip')
-				console.log('gzip')
+			if routeRes.headers['content-encoding'] == 'gzip'
 				zlib.gunzip(
-					Buffer.concat(bufs),
-					(gunzipError, buf)->
-						if (gunzipError) then console.log(gunzipError)
-						else responseDst.body=buf.toString(charset)
+					Buffer.concat bufs,
+					(gunzipError, buf) ->
+						if gunzipError then logger.error gunzipError
+						else responseDst.body = buf.toString charset
+						callback()
 				)
-			else if (routeRes.headers['content-encoding'] == 'deflate')
-				console.log('deflate')
+			else if routeRes.headers['content-encoding'] == 'deflate'
 				zlib.inflate(
-					Buffer.concat(bufs),
-					(inflateError, buf)->
-						if (inflateError) then console.log(inflateError)
-						else responseDst.body = buf.toString(charset)
+					Buffer.concat bufs,
+					(inflateError, buf) ->
+						if inflateError then logger.error inflateError
+						else responseDst.body = buf.toString charset
+						callback()
 				)
 			else
-				responseDst.body = Buffer.concat(bufs).toString(charset)
-			callback()
+				responseDst.body = Buffer.concat(bufs).toString charset
+				callback()

 	routeReq.on "error", (err) ->
 		responseDst.status = status.INTERNAL_SERVER_ERROR


ability to edit the proposal cluster quickly

Former-commit-id: fec2d72d2e1fed419a247dbef27dfa7fa2353427 [formerly 87332e9dc5f5d4c2037536d164b181bc1651c9fe] [formerly c5958a085357264d1a784ccf72e81eb2cfb438af [formerly 90afadd7e73bed51ddc0d6939204534df3ed6302]] [formerly 6bcfd77354a75b36b4b39a4e9ec3408f0fe66bb5 [formerly cbd2a7582f1a5185f1b520789a78a7302f9d72e9] [formerly 1639a0d4fb3909213b627b70cf04c9f44d8107d4 [formerly 93c9094b9440bb75a2353d5a448a8e543937849c]]]
Former-commit-id: 278232f8c60c4e352f5515a636c353701f8fd594 [formerly b849509a498035099dde075fda86a0623241788c] [formerly 04519230593c528ebc2af1856292a32f410b148e [formerly f06599096a22319faafae7d5faec38dfc482bc3e]]
Former-commit-id: fb4d1838bace1f93cc509f42f3de1f4bd8d230b4 [formerly 4f29613b0e5610124413f7793ba25f1851e05d0a]
Former-commit-id: 5a133133d1f0cd45a92e8059bb7592b4d3ba6f59
Former-commit-id: d2c47b33154be68444df5c9eab44257f59d1d6ca

--- @client/proposal_navigation.coffee
+++ @client/proposal_navigation.coffee
@@ -93,7 +93,25 @@
           fontStyle: 'italic'
           visibility: if !@proposal.cluster then 'hidden'

-        @proposal.cluster or '-'
+        if permit('update proposal', @proposal)
+          INPUT
+            ref: 'cluster'
+            name: 'cluster'
+            pattern: '^.{3,}'
+            defaultValue: @proposal.cluster
+            style:
+              border: 'none'
+              outline: 'none'
+              fontStyle: 'italic'
+              fontSize: 16
+
+            onBlur: =>
+              @proposal.cluster = @refs.cluster.getDOMNode().value
+              save @proposal
+
+
+        else
+          @proposal.cluster or '-'

   componentDidUpdate : -> @typeset()
@@ -210,6 +228,7 @@

         SPAN null,
           "#{if @proposal.designator && @proposal.category then "#{@proposal.category[0]}-#{@proposal.designator} " else ''}#{@proposal.name}"
+
           I
             className: 'fa fa-caret-down'
             style:


Remove unused: desktop/components/smooth_scroll

--- src/desktop/components/smooth_scroll/index.coffee
+++ src/desktop/components/smooth_scroll/index.coffee
@@ -1,7 +0,0 @@
-module.exports = (el, duration = 200) ->
-  offset = 53 # `main-header-height`
-  top = $(document.body).scrollTop()
-  position = $(el).offset().top - offset
-
-  $('html, body')
-    .animate scrollTop: position, duration


Added _noOwnScoll param for getVisibleBoxCoords

--- js/core/elem/elem.coffee
+++ js/core/elem/elem.coffee
@@ -353,9 +353,9 @@
   ###
   Returns the visible box coordinates of the element as a [ left, top, width, height ]
   ###
-  getVisibleBoxCoords: (_id)->
-    [ x, y ] = @getVisiblePosition( _id )
-    [ w, h ] = @getVisibleSize( _id )
+  getVisibleBoxCoords: (_id, _noOwnScoll)->
+    [ x, y ] = @getVisiblePosition( _id, _noOwnScoll )
+    [ w, h ] = @getVisibleSize( _id, _noOwnScoll )
     [ x, y, w, h ]

   ###


removed reference to easy image

removed reference to easy image

--- services/filestore/test/unit/coffee/FileConverterTests.coffee
+++ services/filestore/test/unit/coffee/FileConverterTests.coffee
@@ -10,13 +10,9 @@

 	beforeEach ->

-		@easyimage =
-			convert:sinon.stub()
-			exec: sinon.stub()
 		@child_process =
 			exec : sinon.stub()
 		@converter = SandboxedModule.require modulePath, requires:
-			"easyimage":@easyimage
 			'child_process': @child_process
 			"logger-sharelatex":
 				log:->
@@ -55,7 +51,7 @@
 				done()

 	describe "thumbnail", ->
-		it "should call easy image resize with args", (done)->
+		it "should call converter resize with args", (done)->
 			@child_process.exec.callsArgWith(2)
 			@converter.thumbnail @sourcePath, (err)=>
 				args = @child_process.exec.args[0][0]
@@ -63,7 +59,7 @@
 				done()

 	describe "preview", ->
-		it "should call easy image resize with args", (done)->
+		it "should call converter resize with args", (done)->
 			@child_process.exec.callsArgWith(2)
 			@converter.preview @sourcePath, (err)=>
 				args = @child_process.exec.args[0][0]


remove a log

remove a log

--- node_modules_koding/bongo-client/src/eventbus.coffee
+++ node_modules_koding/bongo-client/src/eventbus.coffee
@@ -43,7 +43,6 @@
       getGenericStaticRoutingKey, getStaticRoutingKey
       konstructor.name, event, listener
     )
-    console.log this

   staticOff:(konstructor, event, listener)->
     @removeListener(


can call frontend.core.setup_BANG_ as soon as the app.js loads now

--- js/setup-frontend.coffee
+++ js/setup-frontend.coffee
@@ -2,9 +2,4 @@
 stefon doesn't like comments at the end of the previous file
 ###

-old_onload = document.onload
-window.onload = () ->
-  console.log('document onload')
-  frontend.core.setup_BANG_()
-  if old_onload?
-    old_onload()
+frontend.core.setup_BANG_()


Add iframe tag to JS errors

Add iframe tag to JS errors

--- assets/javascripts/app/app.coffee
+++ assets/javascripts/app/app.coffee
@@ -55,6 +55,7 @@
           ignoreErrors: [/dpQuery/, /NPObject/]
           tags:
             mode: if @DOC then 'single' else 'full'
+            iframe: (window.top isnt window).toString()
         .install()
       @previousErrorHandler = onerror
       window.onerror = @onWindowError.bind(@)


Feature: add flash message

Feature: add flash message

Alert the user if he's already contacted me

--- assets/javascripts/contact.coffee
+++ assets/javascripts/contact.coffee
@@ -56,6 +56,16 @@
         input

       autofill input, value.values for input in $ @form.find 'input, textarea'
+
+      $ @flashDiv
+      .removeClass 'alert-warning'
+      .addClass 'alert-warning'
+      $ @flashDiv
+      .find '.message'
+      .text "You've already sent me a message. I'll get back to you."
+      $ @flashDiv
+      .show 'slow'
+
       return true

     $ @form


Fix: set retry request callbacks to failed request callbacks

--- assets/javascripts/http.js.coffee
+++ assets/javascripts/http.js.coffee
@@ -15,7 +15,8 @@

     @retry_arguments = _.inject(arguments, ((memo, i)-> memo.push(i); memo), [])
     @retry = =>
-      new HTTP @retry_arguments...
+      http = new HTTP @retry_arguments...
+      http.callbacks = @callbacks

     @request = new HTTP.Request


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/number_extensions.coffee
+++ src/number_extensions.coffee
@@ -458,7 +458,7 @@

 I.rotation = 0.25.rotations

-1.rotation # => 2 * M
+1.rotation # => 2 * Math.PI
 </pre></code>

 @name turns


Fix number keyboard flash and slow down animation slightly

--- _source/client/templates/components/controls/number-keyboard.coffee
+++ _source/client/templates/components/controls/number-keyboard.coffee
@@ -70,10 +70,12 @@
     return

   insertDOMElement: (parent, node, before) ->
+    height = $(window).height()
     $(node)
       .appendTo(parent)
-      # .velocity("transition.slideUpIn", { duration: 500 })
-      .velocity({translateY: [0, 200], translateZ: 0}, {duration: 250})
+      .css
+        transform: "translateY(#{height}px)"
+      .velocity({translateY: [0, 200], translateZ: 0}, {duration: 300})
     super

   removeDOMElement: (parent, node) ->
@@ -82,7 +84,7 @@
     $(node).velocity({
       translateY: 250, translateZ: 0
     }, {
-      duration: 250
+      duration: 300
       complete: (elements) ->
         $(node).remove()
     })


Minor perfomance improvement in jquery selectors.

--- app/assets/javascripts/ng-services/ng-HighlightedEntrySvc.js.coffee
+++ app/assets/javascripts/ng-services/ng-HighlightedEntrySvc.js.coffee
@@ -15,12 +15,12 @@
     entry_css_selector = "#feed-entries a[data-entry-id=#{entry.id}]"

     # Add CSS class "highlighted-entry" only to currently highlighted entry
+    $('#feed-entries a[data-entry-id].highlighted-entry').removeClass 'highlighted-entry'
     $(entry_css_selector).addClass 'highlighted-entry'
-    $('a[data-entry-id]').not(entry_css_selector).removeClass 'highlighted-entry'

     # Make caret visible only for the currently highlighted entry
+    $('i.current-entry:visible').hide()
     $("#{entry_css_selector} i.current-entry").show()
-    $('i.current-entry').not("#{entry_css_selector} i.current-entry").hide()

   service =


Import zepto

Import zepto

Signed-off-by: Renato Carvalho <3a567acd0cc20231ba7f35c2bad7076ae1d7999b@gmail.com>

--- source/assets/javascripts/vendor.coffee
+++ source/assets/javascripts/vendor.coffee
@@ -1 +1 @@
-
+#= require zepto/zepto


Rename variables.

Rename variables.

--- server/api.coffee
+++ server/api.coffee
@@ -1,32 +1,33 @@
 request = require 'superagent'

-module.exports = (host='localhost', port=5000) ->
+module.exports = (hostname='localhost', port=5000) ->
   # Forward the request to the REST server and handle the
   # response. This is a request end point, i.e. the next
   # middleware is not executed to further process the
   # request.
   #
-  # @param req the HTTP request object
-  # @param res the HTTP response object that Express sends
+  # @param request the HTTP request object
+  # @param response the HTTP response object that Express sends
   # @param next the Express middleware to execute when the
   #   request is received (unused since this function is a
   #   request end point)
-  (req, res, next) ->
+  (request, response, next) ->
     # The REST server URL.
-    path = "#{ host }:#{ port }#{ req.path }"
+    path = "#{ hostname }:#{ port }#{ request.path }"
     # Send the request to the REST server.
     # When a successful REST response is received, then parse
     # the REST response body as a JSON object.
     # If the REST request was unsuccessful, then pass on the
     # REST response error status and a message.
-    request[req.method.toLowerCase()](path)
-      .query(req.query)
+    request[request.method.toLowerCase()](path)
+      .query(request.query)
       .accept('json')
-      .send(req.body)
-      .end (err, restRes) ->
-        if restRes.ok
-          res.json restRes.body
+      .send(request.body)
+      .end (error, restResponse) ->
+        if restResponse.ok
+          restResponse.json restResponse.body
         else
-          res.status(restRes.status)
-            .send("The requested resource #{req.host}:#{port}#{req.path}" +
-                  " was not found: #{ restRes.reason } (#{ restRes.status })")
+          response.status(restResponse.status)
+            .send("The requested resource #{ hostname }:#{ port }" +
+                  "#{ request.path } request was unsuccessful:" +
+                  " #{ restResponse.reason } (#{ restResponse.status })")


require_tree is no longer required

require_tree is no longer required

--- lib/assets/javascripts/oojspec.js.coffee
+++ lib/assets/javascripts/oojspec.js.coffee
@@ -1,5 +1,4 @@
 # =require buster/all
-# =require_tree ./oojspec

 window.oojspec = new class OojspecRunner
   constructor: ->


Filled in remaining component types for build_expression_from_javascript_object

--- javascripts/lib/math/build_expression_from_javascript_object.coffee
+++ javascripts/lib/math/build_expression_from_javascript_object.coffee
@@ -12,6 +12,7 @@
         @expression_builder = @opts.expression_builder || components.expression
         @number_builder = @opts.number_builder || components.number
         @addition_builder = @opts.addition_builder || components.addition
+        @subtraction_builder = @opts.subtraction_builder || components.subtraction
         @division_builder = @opts.division_builder || components.division
         @exponentiation_builder = @opts.exponentiation_builder || components.exponentiation
         @blank_builder = @opts.blank_builder || components.blank
@@ -26,11 +27,27 @@
           switch typeof(object_to_convert)
             when "number" then @number_builder.build(value: object_to_convert)
             when "string"
-              switch object_to_convert
-                when "+" then @addition_builder.build()
-                when "/" then @division_builder.build()
-                when "*" then @multiplication_builder.build()
+              obj = object_to_convert
+              switch
+                when obj == "+" then @addition_builder.build()
+                when obj == "-" then @subtraction_builder.build()
+                when obj == "/" then @division_builder.build()
+                when obj == "*" then @multiplication_builder.build()
+                when @matchesNumberRegexp(obj)
+                  @numberFromString(obj)
+                else throw "STRING NOT IMPLEMENTED"
             when "object" then @convertObject(object_to_convert)
+
+      matchesNumberRegexp: (str)->
+        str.search(/\d+/) != -1
+
+      numberFromString: (str)->
+        if parsed = str.match /(\d+)(\.)(\d+)/
+          @number_builder.build(value: str)
+        else if parsed = str.match /(\d+)(\.)/
+          @number_builder.build(value: parsed[1], future_as_decimal: true)
+        else if parsed = str.match /(\d+)/
+          @number_builder.build(value: parsed[1])

       # privates
       processExpressionParts: (exp, parts)->


Cleaned up code

Cleaned up code

--- public/dreamcatcher/controllers/comment_controller.coffee
+++ public/dreamcatcher/controllers/comment_controller.coffee
@@ -1,15 +1,15 @@
 $.Controller 'Dreamcatcher.Controllers.Comment',

-  #TODO: Could abstract into Comment, with StreamComment, and EntryComment inheriting.
+  #TODO: [Architectual] Could abstract into Abstract class Comment, with StreamComment, and EntryComment inheriting.

   init: ->
     @currentUserId = parseInt $("#current_user_id_1").val()
     @entryView = $("#showEntry").length > 0

-    if @entryView   #single-entry view
+    if @entryView                                 #single entry view
       @entryId = $('#showEntry').data 'id'
       @loadComments $('#showEntry'),@entryId
-    else            #stream view
+    else                                          #stream view
       $(".thumb-1d").each (index,element) =>
         entry = $(element)
         newCount = @getNewCommentCount(entry)
@@ -42,12 +42,13 @@
     commentCountText = $(".comment .count span",entry).text().trim()
     return parseInt commentCountText if commentCountText.length > 0
     return 0
+

   updateCommentCount: (entry) ->
-    totalCount = @getTotalCommentCount(entry)
+    totalCount = @getTotalCommentCount entry

-    $(".showAll span,.count span",entry).text(totalCount)
-    $(".comment",entry).removeClass("new")
+    $(".showAll span,.count span",entry).text totalCount
+    $(".comment",entry).removeClass "new"

     if totalCount > 0
       $(".comment .count span",entry).text(totalCount).removeClass("empty")
@@ -55,7 +56,7 @@
       $(".comment .count span",entry).text("").addClass("empty")

-  loadComments: (entry,entryId) ->
+  loadComments: (entry, entryId) ->
     $(".commentsTarget",entry).addClass("commentsPanel wrapper").html(
       @view 'init',{
         userId: @currentUserId
@@ -65,20 +66,18 @@
     $(".comments",entry).addClass("spinner") if @getTotalCommentCount(entry) > 0
     Dreamcatcher.Models.Comment.findEntryComments entryId,{},@callback('populateComments',entry,entryId)

-  populateComments: (entry,entryId,comments) ->
+  populateComments: (entry, entryId, comments) ->
     totalCount = comments.length
-    newCount = @getNewCommentCount entry
-
-    #show new items, or just 2.
     if @entryView
       numberToShow = totalCount
-      $(".commentHeader span",entry).text(totalCount)
+      $(".commentHeader span",entry).text totalCount
     else
-      numberToShow = if newCount > 0 then newCount else 2
-      numberToShow = Math.min(totalCount,numberToShow) #make sure numberToShow does not exceed total
-      $(entry).addClass("expanded")
+      newCount = @getNewCommentCount entry
+      numberToShow = if newCount > 0 then newCount else 2   #show all 'new' items, or just latest 2
+      numberToShow = Math.min totalCount,numberToShow       #make sure numberToShow does not exceed total
+      $(entry).addClass "expanded"
       if numberToShow < totalCount
-        $(".showAll span",entry).text(totalCount)
+        $(".showAll span",entry).text totalCount
         $(".showAll",entry).show()

     $(".comments",entry).html(
@@ -114,13 +113,13 @@
     entry = @getEntryFromElement el
     entryId = @getEntryId entry

-    if entry.hasClass("expanded") #currently expanded, so collapse
+    if entry.hasClass("expanded")                 #currently expanded -> collapse
       $(".commentsTarget",entry).hide()
       entry.removeClass("expanded")
-    else if $(".commentsPanel",entry).length > 0
+    else if $(".commentsPanel",entry).length > 0  #already been expanded -> re-expand
       $(".commentsTarget",entry).show()
       entry.addClass("expanded")
-    else
+    else                                          #never been expanded -> populate
       @loadComments entry,entryId

   '.showAll click': (el) ->
@@ -135,7 +134,6 @@
     Dreamcatcher.Models.Comment.delete entryId,commentId
     el.closest('.prevCommentWrap').remove()
     @updateCommentCount entry
-

   '.save click': (el) ->
     $(".comment_body,.save",el.parent()).attr("disabled",true).addClass("disabled")


Set check cycles to 2

Set check cycles to 2

--- config.coffee
+++ config.coffee
@@ -7,4 +7,4 @@
     defaultDelay: 3
     defaultDuration: 0.5
     defaultTransition: "none"
-    checkCycles: 20+    checkCycles: 2


brunch config changes, removed unnescarry configurations

--- config.coffee
+++ config.coffee
@@ -13,15 +13,9 @@
       joinTo:
         'js/app.js': /^app/
         'js/vendor.js': /^(bower_components|vendor)/
-
     stylesheets:
       joinTo:
         'css/app.css': /^(app|vendor|bower_components)/
-      order:
-        before: [
-          'app/styles/app.less'
-        ]
-
     templates:
       joinTo:
         'js/dontUseMe' : /^app/ # dirty hack for Jade compiling.


Formatting on multiple line substitution

--- annotran/static/scripts/annotator/plugin/substitution.coffee
+++ annotran/static/scripts/annotator/plugin/substitution.coffee
@@ -67,7 +67,7 @@
   createSubstitutionElement: (originalText, substituteText, ele) ->

     # we don't preserve full formatting but we can at least put some paragraph breaks in
-    originalText = originalText.replace(new RegExp('\n', 'g'), '
')
+    originalText = originalText.replace(new RegExp('\n', 'g'), '

')
     substituteText = substituteText.replace(new RegExp('\n', 'g'), '
')

     newEle = $('')


fat arrows don't really do anything for class methods for LongPoll, also change around some of its logging

--- lib/assets/javascripts/firehose/long_poll.js.coffee
+++ lib/assets/javascripts/firehose/long_poll.js.coffee
@@ -2,10 +2,10 @@
   messageSequenceHeader: 'pragma'

   # CORS is supported in IE 8+
-  @ieSupported: =>
+  @ieSupported: ->
     $.browser.msie and parseInt($.browser.version) > 7 and window.XDomainRequest

-  @supported: =>
+  @supported: ->
     # IE 8+, FF 3.5+, Chrome 4+, Safari 4+, Opera 12+, iOS 3.2+, Android 2.1+
     if xhr = $.ajaxSettings.xhr()
       "withCredentials" of xhr || Firehose.LongPoll.ieSupported()
@@ -27,6 +27,7 @@
     @_stopRequestLoop = false

   connect: (delay = 0) =>
+    console?.log "connect", delay
     unless @_isConnected
       @_isConnected = true
       @config.connected()
@@ -49,17 +50,18 @@
       error:        @_error
       xhr:          hackAroundFirefoxXhrHeadersBug if $.browser is 'mozilla'
       complete:     @_xhrComplete
-    console?.log "_request END"

   _xhrComplete: (jqXhr) =>
     console?.log "XHR complete", arguments
     # Get the last sequence from the server if specified.
     if jqXhr.status == 200
       @_lastMessageSequence = jqXhr.getResponseHeader @messageSequenceHeader
+      console?.log "@_lastMessageSequence => #{@_lastMessageSequence}"
       if @_lastMessageSequence == null
         console?.log 'ERROR: Unable to get last message sequnce from header'

   stop: =>
+    console?.log "stop"
     @_stopRequestLoop = true

   _success: (data, status, jqXhr) =>


make error accept action

make error accept action

--- lib/assets/javascripts/transponder/presenter.coffee
+++ lib/assets/javascripts/transponder/presenter.coffee
@@ -34,7 +34,7 @@
   runAction: (event, response) =>
     @beforeFilter(event, response)
     if @response.errors
-      @errorOut()
+      @errorOut(@response.action)
     else
       @[event.type.split(':').pop()]()
     @afterFilter(event, response)
@@ -48,9 +48,9 @@
   triggerEmptyError: (eventName) ->
     console.log "Error #{eventName} triggered! Override this action in your own presenter"

-  errorOut: ->
+  errorOut: (action) ->
     for key, value of @response.errors
-      @error[key](value)
+      @error[action](value)

   index: ->
     @triggerEmpty('Index')


waterfall: fixed scaling

waterfall: fixed scaling

PJ charts use absolute values, the other ones autoscale

--- app/assets/javascripts/lib/views/waterfall_chart_view.coffee
+++ app/assets/javascripts/lib/views/waterfall_chart_view.coffee
@@ -20,16 +20,20 @@

   results: ->
     scale = @data_scale()
-    series = @model.series.map (serie) ->
+    series = @model.series.map (serie) =>
       present = serie.present_value()
       future = serie.future_value()
       if serie.get('group') == 'value'
         # Take only the present value, as group == value queries only future/present
         # ?! - PZ
-        return present # Metric.scale_value present, scale
+        if @scale_units() then Metric.scale_value(present, scale) else present
       else
-        return future # Metric.scale_value future, scale
+        if @scale_units() then Metric.scale_value(future, scale) else future
     [series]
+
+  scale_units: => @model.get('unit') != 'PJ'
+
+  tick_unit: => if @scale_units() then @parsed_unit() else @model.get('unit')

   render_waterfall: =>
     $.jqplot @model.get("container"), @results(), @chart_opts()
@@ -64,4 +68,4 @@
           rendererOptions:
             forceTickAt0: true # we always want a tick a 0
           tickOptions:
-            formatString: "%.#{@significant_digits()}f #{@model.get('unit')}"
+            formatString: "%.#{@significant_digits()}f #{@tick_unit()}"


OX-299 mouse fixed

OX-299 mouse fixed

--- app/assets/javascripts/oxalis/controller/controller3d.coffee
+++ app/assets/javascripts/oxalis/controller/controller3d.coffee
@@ -76,13 +76,12 @@
   initMouse : ->
     @input.mouse = new Input.Mouse(
       @canvas
-      "x" : (distX) =>
+      leftDownMove : (delta) =>
         @cam.yawDistance(
-          distX * @model.user.configuration.mouseInversionX * @model.user.configuration.mouseRotateValue
-        )
-      "y" : (distY) =>
+          delta.x * @model.user.mouseInversionX * @model.user.mouseRotateValue
+        );
         @cam.pitchDistance(
-          distY * @model.user.configuration.mouseInversionY * @model.user.configuration.mouseRotateValue
+          delta.y * @model.user.mouseInversionY * @model.user.mouseRotateValue
         )
     )


try something

try something

--- config.coffee
+++ config.coffee
@@ -7,7 +7,7 @@
   ROOT: __dirname
   DB:
     REDIS:
-      HOST: process.env.DB_REDIS_HOST or 'redis://rediscloud:password@localhost:'
+      HOST: process.env.DB_REDIS_HOST or 'redis://rediscloud:password@localhost'
       PORT: process.env.DB_REDIS_PORT or 6379
       PREFIX: 'lendme:'
   EXPRESS:


Added correct failure state for report creation test

--- server/test/units/report.coffee
+++ server/test/units/report.coffee
@@ -17,9 +17,11 @@
     Report.findAndCountAll().
       success((count)->
         assert.equal 1, count
-      ).
-      failure( ->
-        throw 'Report saving failed'
+      ).failure( ->
+        throw 'Failed to find Reports'
       )
+  ).
+  failure( ->
+    throw 'Report saving failed'
   )
 )


Nodejs Web Server Tests: add generateRequestParamsEncodeBody helper function

--- servers/testhelper/index.coffee
+++ servers/testhelper/index.coffee
@@ -89,7 +89,6 @@
 generateDefaultRequestParams = (opts = {}) ->

   defaultBodyObject    = generateDefaultBodyObject()
-
   defaultHeadersObject = generateDefaultHeadersObject()

   defaultParams        =
@@ -100,6 +99,17 @@
   defaultParams = deepObjectExtend defaultParams, opts

   return defaultParams
+
+
+generateRequestParamsEncodeBody = (params, opts = {}) ->
+
+  defaultRequestParams  = generateDefaultRequestParams params
+  requestParams         = deepObjectExtend defaultRequestParams, opts
+  # after deep extending object, encodes body param to a query string
+  if requestParams.body
+    requestParams.body = querystring.stringify requestParams.body
+
+  return requestParams

 # _.extend didn't help with deep extend
@@ -144,4 +154,5 @@
   generateRandomUsername
   checkBongoConnectivity
   generateDefaultRequestParams
+  generateRequestParamsEncodeBody
 }


neo4j: fix bug where overview wasn't populating properly

--- server/lib/server/graph/decorators/bucket_activity.coffee
+++ server/lib/server/graph/decorators/bucket_activity.coffee
@@ -16,26 +16,35 @@

   groupByAnchorId:->
     for datum in @data
-      id = @extractId datum
-      if @groups[id]
-        @addFollowerToGroup datum
+      anchorId = @extractId datum
+      if @groups[anchorId]
+        @addActivityToGroup datum, anchorId
       else
         @createNewGroup datum

-  addFollowerToGroup:(datum)->
+  addActivityToGroup:(datum, anchorId)->
+    # TODO: use anchorId
     id = @extractId datum
     @groups[id].snapshot.group.push @decorateGroupActivity datum[@groupByName]
+    @addActvityToOverview datum[@groupByName].first, anchorId
+
+  addActvityToOverview:(datum, anchorId)->
+    for followers in @groups.overview when followers.ids.first is anchorId
+      followers.ids.push datum.id
+      followers.createdAt.push datum.meta.createdAt
+      followers.count++

   createNewGroup:(datum)->
     id = @extractId datum
     @groups[id] = @decorateTargetActivity datum
     @groups[id].snapshot.group = [@decorateGroupActivity datum[@groupByName]]
-    @groups.overview = @decorateOverview datum[@groupByName].first
+    @groups.overview ||= []
+    @groups.overview.push @decorateOverview datum[@groupByName].first, id

-  decorateOverview:(target)->
+  decorateOverview:(target, anchorId)->
     overview =
       createdAt : [@convertToISO(target.meta.createdAt)]
-      ids       : [target.id]
+      ids       : [anchorId]
       type      : @groupName
       count     : 1


Changed api server

Changed api server

--- server.coffee
+++ server.coffee
@@ -6,7 +6,7 @@

 app.get /^\/wp-json.*$/, (req, res) ->
 #  console.log(req.originalUrl)
-  request('http://new.dev.dotby.jp' + req.originalUrl).pipe(res)
+  request('http://dotby.jp' + req.originalUrl).pipe(res)

 app.get /^[\w\-\/]*$/, (req, res) ->
   res.set('Content-Type', 'text/html')


Check the return value from migrations.

Check the return value from migrations.

--- server.coffee
+++ server.coffee
@@ -802,6 +802,7 @@
       migration._updateAll = false

       counts = migration.forward @, new DirectCollection(currentName), currentSchema, newSchema
+      throw new Error "Invalid return value from migration: #{ util.inspect counts }" unless 'migrated' of counts and 'all' of counts

       updateAll = true if counts.migrated and migration._updateAll


stop repeating lines

stop repeating lines

--- server.coffee
+++ server.coffee
@@ -118,9 +118,11 @@
     oldPos = oldSorted.indexOf userId
     Db.shared.modify 'counters', App.userId(), (v) -> v+1
     Db.shared.modify 'total', (v) -> v+1
-    if f is 25 and Db.personal(userId).get('limit') is 0 and Db.personal(userId).get('timelimit') is 0 #last two statements are redundant, but easier to remove time limit later on
-        r = Math.floor(Math.random()*lines.length)
-        Db.personal(userId).set('funnies', lines[r])
+    if f < 25 and Db.personal(userId).get('limit') is 0 #and Db.personal(userId).get('timelimit') is 0 #last two statements are redundant, but easier to remove time limit later on
+        #r = Math.floor(Math.random()*lines.length)
+        #Db.personal(userId).set('funnies', lines[r])
+        fun = getRandomFunny(userId)
+        Db.personal(userId).set('funnies', fun)
         Db.personal(userId).set('limit', 1)
         Db.personal(userId).set('timelimit', 1)
         Db.personal(userId).modify 'odds', (v) -> v*1.2
@@ -132,6 +134,19 @@
                 lowPrio: true
                 text: App.userName(newSorted[i]) + " outclicked you!"

+getRandomFunny = (userId) !->
+    i = rnd = Math.round(Math.random() * lines.length)
+    seen = Db.personal(userId).ref('seenlines')
+    while seen.get i
+        break if i is (rnd - 1)
+        i = i + 1 % lines.length # wrap around if needed
+
+    # i is now the first unseen funny after rnd
+    seen i, true
+    return lines[i]
+    Db.personal(userId).set('seenlines', i, true)
+
+
 exports.client_clearfunnies = !->
     userId = App.userId()
     Db.personal(userId).set('funnies', null)


Fixing tests.

Fixing tests.

--- server.coffee
+++ server.coffee
@@ -41,6 +41,9 @@
             # Mark it as ready only the first time
             publish.ready() unless ready
             ready = true
+            # To return nothing, so that it can be used at the end of the
+            # publish function in CoffeeScript without an error
+            return

           relatedPublish.stop = (relatedChange) ->
             if relatedChange


change app name in americano config

change app name in americano config

--- server.coffee
+++ server.coffee
@@ -2,7 +2,7 @@

 application = module.exports.start = (options, callback) ->
     options ?= {}
-    options.name = 'webmail'
+    options.name = 'emails'
     options.root ?= __dirname
     options.port ?= process.env.PORT or 9125
     options.host ?= process.env.HOST or '0.0.0.0'


More lenient local hostname check

More lenient local hostname check

--- SingularityUI/app/env.coffee
+++ SingularityUI/app/env.coffee
@@ -1,4 +1,4 @@
-if window.location.hostname is 'localhost'
+if window.location.hostname.substr(0, 'local'.length) is 'local'
     env =
         env: 'local'
         SINGULARITY_BASE: 'http://heliograph.iad01.hubspot-networks.net:7005'


test: after parse the csv file clean from not valid invitation

--- servers/lib/server/handlers/invitetoteambycsv.test.coffee
+++ servers/lib/server/handlers/invitetoteambycsv.test.coffee
@@ -1,4 +1,5 @@
 parser = require 'csv-parse'
+helpers = require '../helpers'
 { withConvertedUser } = require '../../../../workers/social/testhelper'

 { async
@@ -53,12 +54,20 @@
     return callback err if err

     JInvitation = require '../../../models/invitation'
-    # 4 is a RANDOM NUMBER OK?.
-    JInvitation.one { email: data[4].email }, (err, invitation) ->
+    data = analyzeInvitations data
+    random = Math.floor(Math.random() * data.length)
+    JInvitation.one { email: data[random].email }, (err, invitation) ->
       return callback err if err
       return callback new Error 'invitation is not found' if not invitation

       return callback null
+
+
+analyzeInvitations = (data, callback) ->
+  params = { data, userEmails: [], pendingEmails: [], myEmail: '' }
+  { data } = helpers.analyzedInvitationResults params
+  return data
+

 brokenFile = '''
   this is not an valid line that contains email
@@ -94,4 +103,4 @@
 #   { email: 'cihangir6@koding.com.cihangir6.savas6.member' }
 # ] }

-lotsOfInvitations = (generateRandomInvitationsWithEmailRole() for i in [1...500]).join('\n')
+lotsOfInvitations = (generateRandomInvitationsWithEmailRole() for i in [1...100]).join('\n')


Make triggers return only my triggers

Make triggers return only my triggers

--- server.coffee
+++ server.coffee
@@ -50,7 +50,7 @@

 app.options '*', cors()

-app.get '/triggers', triggerController.getTriggers
+app.get '/triggers', triggerController.getMyTriggers
 app.get '/mytriggers', triggerController.getMyTriggers

 app.post '/flows/:flowId/triggers/:triggerId', triggerController.trigger