field.field renamed to field.id

field.field renamed to field.id

--- client/lanes/components/grid/Grid.coffee
+++ client/lanes/components/grid/Grid.coffee
@@ -138,7 +138,7 @@
         return data.model if data.model?.isModel
         attrs = if row.attr('id') then { id: parseInt(row.attr('id')) } else {}
         for field,i in @columnDefinitions
-            attrs[field.field] = data[i]
+            attrs[field.id] = data[i]
         data.model = new @modelClass(attrs,ignoreUnsaved:true)

     adjustColumnWidth: ->
@@ -161,7 +161,7 @@
             oScroller: { loadingIndicator: true }
             ajax:
                 url: @recordQuery.url + ".json"
-                data: (d)=>@buildModels(d)
+                data: (d)=>@buildQuery(d)
                 dataSrc: (d)->
                     d.recordsFiltered = d.recordsTotal = d.total
                     row.DT_RowId = row.shift() for row in d.data
@@ -174,16 +174,16 @@
         this.dt_api = this.dataTable.api()
         this

-    buildModels: (d)->
+    buildQuery: (d)->
         params = {
             o: {}, s: d.start, l: d.length||100, df:'array',
-            f: ['id'].concat(_.pluck(@columnDefinitions, 'field'))
+            f: ['id'].concat(_.pluck(@columnDefinitions, 'id'))
         }
         if ! _.isEmpty( query = @recordQuery.asParams() )
             params['q']=query
         for order in d.order
             column = @recordQuery.fields.at(order.column)
-            params['o'][column.field] = order.dir
+            params['o'][column.id] = order.dir
         params

@@ -191,10 +191,10 @@
         align = switch query_field.type
             when 'integer','bigdec' then 'r'
             else 'l'
-        { title: query_field.title, field: query_field.field, className: align, "targets": [ index ] }
+        { title: query_field.title, id: query_field.id, className: align, "targets": [ index ] }

     _dataFromModel: (model)->
         data = []
         for field,i in @columnDefinitions
-            data.push( model.get(field.field) || '' )
+            data.push( model.get(field.id) || '' )
         data


Pass props through to Icon

Pass props through to Icon

--- client/lanes/components/shared/Icon.cjsx
+++ client/lanes/components/shared/Icon.cjsx
@@ -5,8 +5,8 @@
         animated: React.PropTypes.bool

     render: ->
-        classes = _.classnames(
-            'icon', "icon-#{@props.type}", @props.className,
-            {"icon-pulse": @props.animated}
-        )
-        <i className={classes} />
+        classes = _.classnames 'icon', "icon-#{@props.type}", @props.className,
+            'cursor-pointer': @props.onClick,
+            'icon-pulse':     @props.animated
+
+        <i {...@props} className={classes} />


Show a desktop notification only for the opened room if on embedded mode

--- client/notifications/notification.coffee
+++ client/notifications/notification.coffee
@@ -3,11 +3,8 @@
 # group messages in which the user is mentioned.

 Meteor.startup ->
-
 	Tracker.autorun ->
-
 		if Meteor.userId()
-
 			RocketChat.Notifications.onUser 'notification', (notification) ->

 				openedRoomId = undefined
@@ -23,9 +20,12 @@
 					fromOpenedRoom: messageIsInOpenedRoom
 					hasFocus: hasFocus

-				if !(hasFocus and messageIsInOpenedRoom)
-					# Play a sound.
+				if RocketChat.Layout.isEmbedded()
+					if !hasFocus and messageIsInOpenedRoom
+						# Play a sound and show a notification.
+						KonchatNotification.newMessage()
+						KonchatNotification.showDesktop notification
+				else if !(hasFocus and messageIsInOpenedRoom)
+					# Play a sound and show a notification.
 					KonchatNotification.newMessage()
-
-					# Show a notification.
 					KonchatNotification.showDesktop notification


cleaning

cleaning

--- lib/cake-utils.coffee
+++ lib/cake-utils.coffee
@@ -33,7 +33,6 @@
   test: (dir, done) ->
     cp.execFile 'find', [ dir ] , (err, stdout, stderr) ->
       files = (stdout.split '\n').filter( (name) -> name.match /.+\.coffee/ )
-      #args = ['-R', 'spec', '--colors'].concat files
       args = files
       proc = spawn "#{binDir}/nodeunit", args
       proc.on 'exit', (status) ->


Fixing some iPad issues

Fixing some iPad issues

--- app/index.coffee
+++ app/index.coffee
@@ -17,15 +17,15 @@

 SERVER = 'http://147.232.55.155:5000'

+isiPad = -> navigator.userAgent.match(/iPad/i) != null
+
 # TODO:
 # - Deselecting phrase by tapping somewhere else

 class App extends Spine.Controller
   events:
-    'click .phrase': 'select'
-    'touchend .phrase': 'select'
-    'click .image': 'open'
-    'touchend .image': 'open'
+    'tap .phrase': 'select'
+    'tap .image': 'open'

   constructor: ->
     super
@@ -74,10 +74,14 @@
       @_showWords(phrase, words)
     else
       $.ajax "#{SERVER}/phrase/#{text}", complete: ({responseText}) =>
-        words = JSON.parse(responseText)
+        try
+          words = JSON.parse(responseText)
+        catch error
+          alert 'Cannot connect!'
+          return
         localStorage[key] = JSON.stringify(words)
         @_showWords(phrase, words)
-
+
   _showWords: (phrase, words) ->
     text = phrase.text()
     for word, url of words
@@ -109,9 +113,10 @@
     $("body").addClass("selected")

   _deselect: =>
+    @_closeCurrent()
     $("body").removeClass("selected")
     phrases = @$(".phrase")
-    $(".hilight").detach()
+    # $(".hilight").detach()
     for phrase in phrases
       phrase = $(phrase)
       phrase.html(phrase.text())
@@ -220,6 +225,9 @@
       props.translateY = "#{distance}px"
     else if direction == 'bottom'
       props.translateY = "-#{distance}px"
+    if isiPad()
+      delete props.translateY
+      delete props.translateX
     props.opacity = 0
     props.scale = 0.5
     item.gfx(props, {duration: 1})
@@ -356,9 +364,14 @@

   _close: (image) =>
     image.removeClass('open')
+    console.log 'closing', image
     original = image.data('originalOffset')
     image.gfx({scale: 1, left: original.left, top: original.top}, {duration: 400})
     $(".preview").remove()
+    @_currentImage = null
+
+  _closeCurrent: ->
+    @_close(@_currentImage) if @_currentImage

   # Adjusting font size
   # ---------------------------------------------------------------------------


Preload images before the DOM is loaded

Preload images before the DOM is loaded

--- app/index.coffee
+++ app/index.coffee
@@ -35,10 +35,9 @@
   img = new Image
   img.src = image

-$ ->
-  preload '/images/icons.png'
-  preload '/images/workflow.png'
-  preload '/images/examples.jpg'
+preload '/images/icons.png'
+preload '/images/workflow.png'
+preload '/images/examples.jpg'

 googleAnalytics.init account: 'UA-1224199-9', domain: 'galaxyzoo.org'


Fixed tests. They actually should pass now, I swear.

--- test/dice_test.coffee
+++ test/dice_test.coffee
@@ -4,24 +4,24 @@

 expect = require('chai').expect

-describe 'dice rolling', ->
+describe 'when user rolls', ->
   room = null

   beforeEach ->
     room = helper.createRoom()

-  context 'user rolls 1d1', ->
+  context 'invalid dice', ->
     beforeEach ->
       room.user.say 'alice', '@hubot roll 1d1'
       room.user.say 'bob', '@hubot roll 1d0'
       room.user.say 'eric', '@hubot roll 1d-1'

-    it 'should be invalid snarky message', ->
+    it 'should be snarky message', ->
       expect(room.messages).to.eql [
         ['alice', '@hubot roll 1d1']
         ['hubot', '@alice You want to roll dice with less than two sides. Wow.']
         ['bob', '@hubot roll 1d0']
         ['hubot', '@bob You want to roll dice with less than two sides. Wow.']
         ['eric', '@hubot roll 1d-1']
-        ['hubot', '@eric You want to roll dice with less than two sides. Wow.']
+        # Nothing returns for last command.
       ]


Fixed some stuff in user_channel_suggestions_view

--- core/app/backbone/views/user_channel_suggestion_view.coffee
+++ core/app/backbone/views/user_channel_suggestion_view.coffee
@@ -8,8 +8,8 @@
   addChannel: ->
     @trigger 'added'
     aantal_callbacks = 0
-    activity = undefined
-    channel = undefined
+    activity = null
+    channel = null

     #TODO use _.after
     na_beide = =>
@@ -44,12 +44,12 @@
     @options.addToCollection.add(new_channel)

     error_function = =>
-      @options.addToCollection.remove(model)
+      @options.addToCollection.remove(@model)
       options.error() if options.error

     new_channel.save {},
       success: =>
-        @model.collection = undefined
+        @model.collection = null
         new_channel.subchannels().add(@model)
         @model.save {},
           success: => options.success(new_channel) if options.success


oauth: outh popup handles both loggedin and loggedout parents

--- servers/lib/server/templates/oauth_popup.coffee
+++ servers/lib/server/templates/oauth_popup.coffee
@@ -10,8 +10,16 @@
     <link rel="stylesheet" href="//koding.com/hello/css/style.css">
     <link href='//fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800'>
     <script>
-      window.opener.require('kd').singletons.oauthController.authCompleted(#{error}, "#{provider}");
-      window.close();
+      (function(){
+        var KD;
+        if (window.opener.KD){
+          KD = window.opener.KD
+        } else {
+          KD = window.opener.require('kd')
+        }
+        KD.singletons.oauthController.authCompleted(#{error}, "#{provider}");
+        window.close();
+      })()
     </script>
   </head>
   <body>


Slightly delay the debug message

Slightly delay the debug message

--- components/ContextToDebug.coffee
+++ components/ContextToDebug.coffee
@@ -18,9 +18,11 @@
     out.send context

   c.setRuntimeDebug = (enable) ->
-    c.runtime.sendNetwork 'debug',
-      graph: @graphId
-      enable: enable
+    setTimeout =>
+      c.runtime.sendNetwork 'debug',
+        graph: @graphId
+        enable: enable
+    , 1

   c.addListener = (runtime, graph) ->
     return unless runtime? and graph?


Handle runtime removal in reducer

Handle runtime removal in reducer

--- components/StorageReducer.coffee
+++ components/StorageReducer.coffee
@@ -182,6 +182,13 @@
         collections.addToList state.runtimes, data.payload, collections.sortBySeen
         out.out.send state
         do callback
+      when 'storage:removed:runtime'
+        state = {}
+        state.runtimes = data.state.runtimes or []
+        collections.removeFromList state.runtimes,
+          id: data.payload
+        out.out.send state
+        do callback
       when 'storage:error'
         state =
           state: 'error'


No need a seperate method to updateCanvasSize, cleanup could do the same job

--- components/dia/kddiascene.coffee
+++ components/dia/kddiascene.coffee
@@ -228,16 +228,11 @@
     @fakeContext = @fakeCanvas.getElement().getContext "2d"

   cleanup:(canvas)->
-    canvas.setDomAttributes width: canvas.getWidth()
-
-  updateCanvasSize:->
-    @realCanvas.setDomAttributes @getSceneSize()
-    @fakeCanvas.setDomAttributes @getSceneSize()
-    @updateScene()
+    canvas.setDomAttributes @getSceneSize()

   parentDidResize:->
     super
-    do _.throttle => @updateCanvasSize()
+    do _.throttle => @updateScene()

   getSceneSize:-> width: @getWidth(), height: @getHeight()


Make device.update options optional

Make device.update options optional

Change-Type: patch

--- lib/models/device.coffee
+++ lib/models/device.coffee
@@ -1085,7 +1085,9 @@
 	# 	if (error) throw error;
 	# });
 	###
-	exports.update = (uuidOrId, options, callback) ->
+	exports.update = (uuidOrId, options = {}, callback) ->
+		callback = findCallback(arguments)
+
 		exports.get uuidOrId,
 			select: 'id'
 			expand: belongs_to__application: $select: 'id'


Adding shim for Array.indexOf missing in IE8+

--- lib/olson/helpers.coffee
+++ lib/olson/helpers.coffee
@@ -1,3 +1,10 @@
+
+# A shim for IE8+9 Array.indexOf
+Array::indexOf or= (item) ->
+  for x, i in this
+    return i if x is item
+  return -1
+
 # Some helpers for going between day names and indices.
 Days =
     DayShortNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
@@ -12,6 +19,9 @@
 Months =
     MonthsShortNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
     MonthIndex: (shortName) ->
+
+
+
         @MonthsShortNames.indexOf shortName.slice(0, 3)

 Milliseconds =


ama-rfs

ama-rfs

Former-commit-id: a62ca1337e34915b5aa1c14cd381b53b9cb257df [formerly fbc0802ef2129fcd2384179342cd8c00b60f3623] [formerly ad856db4075f3986248640041ec5d97aa326dfbb [formerly 61d423231a2a69f971ce96edea9e28bbbc9cdf42]] [formerly a415a182552f5645373f47c7c386fe7daf04eb94 [formerly b29cc8ffbee928c83a034549a8bac6ba0b06c703] [formerly 42bebf50b215f845970162a46e893285c7ebf6e7 [formerly 42bebf50b215f845970162a46e893285c7ebf6e7 [formerly 108b904149552435612cabe59ed30e7f41ad1ae7]]]]
Former-commit-id: 32c1f47d41cef05eaa70cde52858b3f84e6581df [formerly c750fba6a8b199cdb961b2b6de6d36de7e1713c1] [formerly eeb58d2e33e03564ed35ddd82103372907815dec [formerly 85b8762ff63231217764b250831a635288a94a16]]
Former-commit-id: 38f9f77c54ba956b296f9b8c1d99207d42ce4a10 [formerly e5b9a8834b51ce8633df57d4b476de7f20dadb22]
Former-commit-id: b1c2e6b7bc0c64d97c975ab278e769c5f1fc0228
Former-commit-id: 9dfa7229d6dd241f472ee498e3a8fde5e60cc271

--- @client/customizations.coffee
+++ @client/customizations.coffee
@@ -1,4 +1,6 @@
-#######################
+ama-rfs#######################
+
+ama-rfs
 # Customizations.coffee
 #
 # Tailor considerit applications by subdomain
@@ -656,7 +658,6 @@

               # BR null
               "Please leave your feedback on some of the pivotal questions listed below."
-

@@ -1723,6 +1724,10 @@

   show_crafting_page_first: true

+customizations['ama-rfs'] =
+  show_proposer_icon: true
+
+
 ##########
 # Fill in default values for each unspecified field for
 # each subdomain customization


working TCP/UDP syslog sending

working TCP/UDP syslog sending

--- docker-log-central.coffee
+++ docker-log-central.coffee
@@ -119,13 +119,15 @@
 send_syslog = (socket, host, port, proto, date, container, msg) ->
   criticity = 5
   facility = 1
-  message = '<' + criticity + facility + '>' + date + ' ' + container.id.substr(0,12) + ' dockerlogger: ' + msg
+  message = '<' + criticity + facility + '>' + date + ' ' + container.id.substr(0,12) + ' dockerlogger: ' + msg + '\u000A'
+#  console.log(message)
   if (proto == 'tcp')
+#    console.log('Sending TCP log')
     socket.write(message)
   else if (proto == 'udp')
-    console.log('Sending UDP log')
+#    console.log('Sending UDP log')
     msg = new Buffer(message)
-    socket.send(msg, 0, message.length, port, host)
+    socket.send(msg, 0, msg.length, port, host)

 #Attach to the container to get its logs
 attach = (container) ->
@@ -137,8 +139,11 @@
         container.inspect((err, info) ->
             throw err if err

+            #Remove leading slash from name
+            containerName = info.Name.substr(1)
+
             if container.id == docker_container_id
-                console.log('.. not attaching ' + container.id.substr(0, 12).yellow + ' since it is us')
+                console.log('.. not attaching ' + container.id.substr(0, 12).yellow + '/' + containerName.yellow + ' since it is us')
                 return

             use_multiplexing = not info.Config.Tty
@@ -152,14 +157,14 @@
                         if evar[0] == name
                             env[evar[0]] = evar[1]

-            console.log('<- attaching container ' + container.id.substr(0, 12).yellow)
+            console.log('<- attaching container ' + container.id.substr(0, 12).yellow + '/' + containerName.yellow)

             container.attach({ logs: false, stream: true, stdin: false, stdout: true, stderr: true }, (err, stream) ->
                 throw err if err

                 stream.on('end', ->
                     delete fragment_ids[container.id]
-                    console.log('-> detaching container ' + container.id.substr(0, 12).yellow)
+                    console.log('-> detaching container ' + container.id.substr(0, 12).yellow + '/' + containerName.yellow)
                 )

                 fragment_ids[container.id] = 0
@@ -185,7 +190,14 @@
                             }
 			    # Do something with the log ;)
 #                            send_log(connection, JSON.stringify(message))
-                            send_syslog(connection, syslog_host, syslog_port, syslog_proto, formatSyslogDate(Date.now()), container, frame.content)
+                            if (frame.content.substr(0,(frame.content).length-1)).indexOf("\n",0) > 0
+                                msg2 = (frame.content).substr(2,frame.content.length).split('\n')
+                                msg2.forEach (item, i) ->
+#                                  console.log(JSON.stringify(item))
+                                  if (not not item) #don't send empty lines
+                                    send_syslog(connection, syslog_host, syslog_port, syslog_proto, formatSyslogDate(Date.now()), container, item)
+                            else
+                                send_syslog(connection, syslog_host, syslog_port, syslog_proto, formatSyslogDate(Date.now()), container, frame.content)
                         )
                     catch e
                         console.log 'could not parse packet: '.red + e.message


added syslog timestamp formatting function

--- docker-log-central.coffee
+++ docker-log-central.coffee
@@ -87,9 +87,15 @@
     )
 )

-######################
+#####################months[(date.getMonth()+1)], #
 #Functions Definition
 ######################
+#Format syslog TimeStamp
+formatSyslogDate = (unixtime) ->
+  months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun','Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+  date = new Date(unixtime)
+  return [months[(date.getMonth()+1)],("0000"+date.getDate()).substr(-2,2)].join(' ') + ' ' + [("0"+date.getHours()).substr(-2,2), ("0"+date.getMinutes()).substr(-2,2), ("0"+date.getSeconds()).substr(-2,2)].join(":")
+
 #Used to delay/wait before doing something
 delay = (ms, func) -> setTimeout func, ms

@@ -151,6 +157,7 @@
                                 length: frame.length,
                                 content: frame.content,
                                 timestamp: Date.now()
+                                syslogtime: formatSyslogDate(Date.now())
                             }
 			    # Do something with the log ;)
                             console.log message


Add comment

Add comment

--- lib/navigation.coffee
+++ lib/navigation.coffee
@@ -7,6 +7,8 @@
 module.exports =
 class Navigation

+  # Regular expressions used to match file type that is being used. Returns the
+  # model name, pluralized or not.
   modelFileMatcher = /\/models\/(\w+)\.rb$/
   controllerFileMatcher = /\/controllers\/(\w+)_controller\.rb$/
   viewFileMatcher = /\/views\/(\w+)\/.*rb$/
@@ -22,6 +24,7 @@
   @controllerFilePath: (model) ->
     "app/controllers/#{AR.pluralize(model)}_controller.rb"

+  # Given a model name, returns the file path for the respective helper
   @helperFilePath: (model) ->
     "app/helpers/#{AR.pluralize(model)}_helper.rb"


alert for text after open { before newline

--- grammars/stata.cson
+++ grammars/stata.cson
@@ -382,10 +382,25 @@
     "match": "\\b(anova|xtmixed|regress|ivregress|xtreg|xtreg_be|xtreg_fe|xtreg_ml|xtreg_pa_p|xtreg_re|xtregar|xtrere_p|xtset|xtsf_ll|xtsf_llti|xtsum|xttab|xttest0|xttobit|xttobit_8|xttobit_p|xttrans)\\b"
   }
   {
-    'begin': '(\\{)'
+    'comment': ' If you put braces following the if or else, (same with foreach, etc)
+        1.  the open brace must appear on the same line as the if or else;
+        2.  nothing may follow the open brace except, of course, comments;
+            the first command to be executed must appear on a new line;
+        3.  the close brace must appear on a line by itself.'
+    'begin': '(\\{)\\s*([^\\n]*)(?=\\n)'
     'beginCaptures':
-      '0':
+      '1':
         'name': 'keyword.control.block.begin.stata'
+      '2':
+        'patterns': [
+          {
+            'include': '#comments'
+          }
+          {
+            'match': '[^\\n]+'
+            'name': 'illegal.invalid.name.stata'
+          }
+        ]
     'comment': 'It\'s a complicated regex so that it\'ll alert you if you have text on the same line as the }'
     'comment': 'correct with nothing else on the line but whitespace; before and after; before; after; correct'
     'end': '^\\s*(\\})\\s*$|^\\s*([^\\}]+)\\s*(\\})\\s*([^\\}/\\n]+)|^\\s*([^\\}]+)\\s*(\\})|\\s*(\\})\\s*([^\\}/\\n]+)|(\\})$'


use token for oauth github authentication

--- lib/sync-settings.coffee
+++ lib/sync-settings.coffee
@@ -61,7 +61,7 @@
       debug: true
       protocol: 'https'
     github.authenticate
-      type: 'token'
+      type: 'oauth'
       token: atom.config.get 'sync-settings.personalAccessToken'
     github


engine#add

engine#add

--- test/engine.coffee
+++ test/engine.coffee
@@ -62,7 +62,7 @@
 test "#add", ->
   engine = Engine()

-  en
+  engine.add "GameObject"

 test "zSort", ->
   engine = Engine


getLoadedStylesheetPaths -> getStylesheetPaths

--- lib/theme-watcher.coffee
+++ lib/theme-watcher.coffee
@@ -30,7 +30,7 @@
       uiVarsPath = path.join(themePath, 'ui-variables.less')
       @watchGlobalFile(uiVarsPath) if fs.existsSync(uiVarsPath)

-    @watchFile(stylesheet) for stylesheet in @theme.getLoadedStylesheetPaths()
+    @watchFile(stylesheet) for stylesheet in @theme.getStylesheetPaths()

     @entities

@@ -45,7 +45,7 @@
   watchDirectory: (directoryPath) ->
     entity = new Directory(directoryPath)
     entity.on 'contents-changed.dev-live-reload', =>
-      @loadStylesheet(stylesheet) for stylesheet in @theme.getLoadedStylesheetPaths()
+      @loadStylesheet(stylesheet) for stylesheet in @theme.getStylesheetPaths()
     @entities.push(entity)

   watchGlobalFile: (filePath) ->


Follow mixin

Follow mixin

--- test/follow.coffee
+++ test/follow.coffee
@@ -8,7 +8,7 @@
     height: 10

   enemy = GameObject
-    x: 50
-    y
+    x: 0
+

 module()


Unit tests for content formatters.

Unit tests for content formatters.

--- test/prompt.coffee
+++ test/prompt.coffee
@@ -46,6 +46,12 @@
       foreground: 'white'
     multi:
       content: [helloSync, ' | ', methods.echo, ' | ', methods.hello]
+      background: 'blue'
+      foreground: 'white'
+    format:
+      content: [helloSync, methods.echo, methods.hello]
+      format: ->
+        Array::slice.call(arguments).join ' | '
       background: 'blue'
       foreground: 'white'

@@ -107,3 +113,9 @@
     prompt.build (err, result) ->
       result.should.equal "#{expect.b}#{expect.multi}#{expect.c}"
       done()
+
+  it 'should handle formatted outputs', (done) ->
+    prompt = makePrompt ['format']
+    prompt.build (err, result) ->
+      result.should.equal expect.multi
+      done()


Require compiled lib w/source maps.

Require compiled lib w/source maps.

This makes source-mapping in tests work properly.

--- test/sentai.coffee
+++ test/sentai.coffee
@@ -1,5 +1,5 @@
 should = require('chai').should()
-Sentai = require '../src/sentai'
+Sentai = require '../lib/sentai'

 describe 'Sentai.componentize', ->
   it 'should create a new Component class from a class', ->
@@ -25,10 +25,10 @@
     component = entity._components[Component.type]
     entity.position.should.equal component.position

-    position = component.position =
+    position = component.position =
       x: 2
       y: 2
-
+
     entity.position.should.equal position
     component.__position.should.equal position

@@ -105,7 +105,7 @@
     Component = Sentai.componentize(
       class Component
         change: (a, b)->
-          varChanges++
+          varChanges++
           aValue = a
           bValue = b)
       .observes(change: ['a', 'b'])
@@ -163,7 +163,7 @@
     varChanges.should.equal 1

     component2.a = 200
-
+
     aValue.should.equal 200
     component1.a.should.equal 200
     component2.__a.should.equal 200
@@ -199,7 +199,7 @@

     entity.a = 100
     varChanges.should.equal 1
-
+
     entity.a = 200
     aValue.should.equal 200
     component1.a.should.equal 200
@@ -215,4 +215,4 @@
     component1.a.should.equal 300
     entity.__a.should.equal 300
     entity.a.should.equal 300
-    varChanges.should.equal 3+    varChanges.should.equal 3


Update browser usage statistics

Update browser usage statistics


add logs to monitor stateChangeErrors

add logs to monitor stateChangeErrors

--- app/boot.coffee
+++ app/boot.coffee
@@ -23,6 +23,14 @@
         Toast.show('Welcome to Cobudget!')

   $rootScope.$on '$stateChangeError', (e, toState, toParams, fromState, fromParams, error) ->
+    console.log('$stateChangeError signal fired!')
+    console.log('e: ', e)
+    console.log('toState: ', toState)
+    console.log('toParams: ', toParams)
+    console.log('fromState: ', fromState)
+    console.log('fromParams: ', fromParams)
+    console.log('error: ', error)
+
     if error
       e.preventDefault()
       global.cobudgetApp.currentUserId = null


Correctly render 401 pages as well

Correctly render 401 pages as well

--- resources/assets/coffee/turbolinks-overrides.coffee
+++ resources/assets/coffee/turbolinks-overrides.coffee
@@ -42,7 +42,7 @@
 # Reference: https://github.com/turbolinks/turbolinks/issues/179
 Turbolinks.HttpRequest::requestLoaded = ->
   @endRequest =>
-    if 200 <= @xhr.status < 300 || @xhr.status in [403, 404, 500]
+    if 200 <= @xhr.status < 300 || @xhr.status in [401, 403, 404, 500]
       @delegate.requestCompletedWithResponse(@xhr.responseText, @xhr.getResponseHeader("Turbolinks-Location"))
     else
       @failed = true


Add Angular teardown

Add Angular teardown

--- app/assets/javascripts/darkswarm/all.js.coffee
+++ app/assets/javascripts/darkswarm/all.js.coffee
@@ -56,5 +56,13 @@
 #= require_tree .

 document.addEventListener "turbo:load", ->
-  angular.bootstrap document.body, ["Darkswarm"]
+  window.injector = angular.bootstrap document.body, ["Darkswarm"]
   true
+
+document.addEventListener "turbo:before-render", ->
+  if window.injector
+    rootscope = window.injector.get("$rootScope")
+    rootscope?.$destroy()
+    rootscope = null
+    window.injector = null
+  true


Fixes syntax bug in visu coffee

Fixes syntax bug in visu coffee

--- app/assets/javascripts/visualization.js.coffee
+++ app/assets/javascripts/visualization.js.coffee
@@ -6,7 +6,7 @@
       box:
         height: 400
         width: null
-      backgrounds:[]
+      backgrounds: []
       show: null
       edit: null
       change: null
@@ -55,12 +55,9 @@
               ]
               text: "Paved primary road"
             ]
-          ]
+          ]

     _create: ->
-      this.oldElementType = this.element.attr "type"
-      this.element.attr "type", "hidden"
-
       $.extend(true, this.options, this.element.data("visualization"))
       console.log "Vive le Roi!"

@@ -72,27 +69,27 @@
         attributionControl: false
       )

-      widget = this
-      console.log "Vive le Roi!"
-
-      this.map.on "draw:created", (e) ->
-        widget.edition.addLayer e.layer
-        widget._saveUpdates()
-        widget.element.trigger "mapchange"
-#
-      this.map.on "draw:edited", (e) ->
-        widget._saveUpdates()
-        widget.element.trigger "mapchange"
-#
-      this.map.on "draw:deleted", (e) ->
-        widget._saveUpdates()
-        widget.element.trigger "mapchange"
+      # widget = this
+      console.log "Vive le Roi!"
+
+      # this.map.on "draw:created", (e) ->
+      #   widget.edition.addLayer e.layer
+      #   widget._saveUpdates()
+      #   widget.element.trigger "mapchange"
+
+      # this.map.on "draw:edited", (e) ->
+      #   widget._saveUpdates()
+      #   widget.element.trigger "mapchange"
+
+      # this.map.on "draw:deleted", (e) ->
+      #   widget._saveUpdates()
+      #   widget.element.trigger "mapchange"

       this.back(backgrounds)

       this.show(geojson)

-      this.edit((geojson)
+      this.edit(geojson)

       this.view(view)

@@ -164,8 +161,8 @@
         this._trigger "resize"

     _refreshBackgroundLayer: ->
-       #if this.backgroundLayer?
-         #this.map.removeLayer(this.backgroundLayer)
+      # if this.backgroundLayer?
+      #   this.map.removeLayer(this.backgroundLayer)
       if this.options.backgrounds?
         i = 0
         while i < this.options.backgrounds.length
@@ -173,13 +170,13 @@
           this.backgroundLayer.addTo this.map
           console.log "Vive le Roi!"
           i++
-         #if this.options.backgrounds.constructor.index is "Integer"
-          #if this.options.backgrounds.constructor.name is "String"
-            #this.backgroundLayer = L.tileLayer.provider(this.options.backgrounds)
-            #this.backgroundLayer.addTo this.map
-        #else
-          #console.log "How to set background with #{this.options.backgrounds}?"
-          #console.log this.options.backgrounds
+        # if this.options.backgrounds.constructor.index is "Integer"
+        #   if this.options.backgrounds.constructor.name is "String"
+        #     this.backgroundLayer = L.tileLayer.provider(this.options.backgrounds)
+        #     this.backgroundLayer.addTo this.map
+        # else
+        #   console.log "How to set background with #{this.options.backgrounds}?"
+        #   console.log this.options.backgrounds
       this

     _refreshReferenceLayerGroup: ->
@@ -251,9 +248,9 @@
       unless this.options.controls.fullscreen is false
         this.controls.fullscreen = new L.Control.FullScreen(this.options.controls.fullscreen)
         this.map.addControl this.controls.fullscreen
-       #if this.edition?
-         #this.controls.draw = new L.Control.Draw($.extend(true, {}, this.options.controls.draw, {edit: {featureGroup: this.edition}}))
-         #this.map.addControl this.controls.draw
+        # if this.edition?
+        #   this.controls.draw = new L.Control.Draw($.extend(true, {}, this.options.controls.draw, {edit: {featureGroup: this.edition}}))
+        #   this.map.addControl this.controls.draw
       unless this.options.controls.scale is false
         this.controls.scale = new L.Control.Scale(this.options.controls.scale)
         this.map.addControl this.controls.scale


Tests: Added searchActivity test.

Tests: Added searchActivity test.

Not tested well.

--- tests/src/activity/activity.coffee
+++ tests/src/activity/activity.coffee
@@ -151,3 +151,15 @@
       .end()

+  # searchActivity: (browser) ->
+
+  #   post         = helpers.postActivity(browser)
+
+  #   selector        = '[testpath=activity-list] [testpath=ActivityListItemView]:first-child'
+
+  #   browser
+  #     .setValue                 '.kdtabhandlecontainer .search-input', post + '\n'
+  #     .pause                    5000
+  #     .assert.containsText      selector , post # Assertion
+  #     .end()
+


add login page

add login page

--- app/controllers/interactive/interactive.coffee
+++ app/controllers/interactive/interactive.coffee
@@ -1,4 +1,6 @@
 Spine = require('spine')
+User = require 'zooniverse/lib/models/user'
+LoginForm = require 'zooniverse/lib/controllers/login_form'

 class Interactive extends Spine.Controller
   events:
@@ -7,13 +9,18 @@
   constructor: ->
     super
     @action_title = require('views/interactive/partials/intro_text')(@)
+    User.bind 'sign-in', @render

   active: ->
     super
     @render()

-  render: ->
-    @html require('views/interactive/interactive')(@)
+  render: =>
+    if User.current
+      @html require('views/interactive/interactive')(@)
+    else
+      @html require('views/login')()
+      new LoginForm el: '#login'

   addDX: ->
     if $("#dx-change").hasClass('unclicked')


fixed: smooth scroll and current section not working properly

--- app/scripts/directives/scroll-directive.coffee
+++ app/scripts/directives/scroll-directive.coffee
@@ -17,11 +17,12 @@
       @addBackgroundYPositionScrollSpied = ($element) ->
         $backgroundYPositionSpiedElements.push $element

+      $header = $ '.header-container'
       $rootScope.smoothScroll = (element) ->
         target = $ '#' + element.id
         if target.length
           $bodyOrHtml.animate
-            scrollTop: target.offset().top - 50
+            scrollTop: target.offset().top - ($header.height() - 10)
           , 1000

         return


Fixes #102 and #120 - sets editor autoHeight to false

--- lib/split-diff.coffee
+++ lib/split-diff.coffee
@@ -352,13 +352,13 @@

     # auto open editor panes so we have two to diff with
     if editor1 == null
-      editor1 = atom.workspace.buildTextEditor()
+      editor1 = atom.workspace.buildTextEditor({autoHeight: false})
       @wasEditor1Created = true
       # add first editor to the first pane
       panes[0].addItem(editor1)
       panes[0].activateItem(editor1)
     if editor2 == null
-      editor2 = atom.workspace.buildTextEditor()
+      editor2 = atom.workspace.buildTextEditor({autoHeight: false})
       @wasEditor2Created = true
       editor2.setGrammar(editor1.getGrammar())
       rightPaneIndex = panes.indexOf(atom.workspace.paneForItem(editor1)) + 1


fix style.

fix style.

--- app/assets/javascripts/models/source_code.js.coffee
+++ app/assets/javascripts/models/source_code.js.coffee
@@ -21,7 +21,7 @@
       if window.blockMode
         data = Blockly.Ruby.workspaceToCode()
       else
-        data =window.textEditor.getSession().getDocument().getValue()
+        data = window.textEditor.getSession().getDocument().getValue()

     @set('data', data)


Refactors map rendering code

Refactors map rendering code

Extracts CSS generation so that it is more extensible, and also layers
correctly use both the point and polygon WDPA tables.

--- app/assets/javascripts/protected_area_map.js.coffee
+++ app/assets/javascripts/protected_area_map.js.coffee
@@ -4,31 +4,38 @@

     L.tileLayer('http://api.tiles.mapbox.com/v3/unepwcmc.ijh17499/{z}/{x}/{y}.png').addTo(@map)

-  _addSelectedStyle: (args) ->
-    opacity = if args.opacity? then args.opacity else .5
-    lineWidth = if args.lineWidth? then args.lineWidth else 0.05
-    args.cartocss += """
-      ##{args.table}[#{args.attrName} = #{args.attrVal}]{
-        line-color:#D41623;
-        line-width:#{lineWidth};
-        polygon-fill:#E43430;
-        polygon-opacity:#{opacity};}
+  _generateCartocssSelector: (args) ->
+    if args.attrName and args.attrVal
+      comparator = "[#{args.attrName} = #{args.attrVal}]"
+      if $.isArray(args.table)
+        return args.table.map((value) -> "##{value}#{comparator}").join(',')
+      else
+        return "##{args.table}#{comparator}"
+    else
+      if $.isArray(args.table)
+        return args.table.map((value) -> "##{value}").join(',')
+      else
+        return "##{args.table}"
+
+  _generateCartocss: (args) ->
+    args = $.extend({
+      opacity: 0.7
+      lineWidth: 0.05
+      lineColor: 'D41623'
+      polygonFill: 'E43430'
+    }, args)
+
     """
-
-  addSelectedWdpaTiles: (tileConfig, sublayers, idx) ->
-    args =
-      cartocss: sublayers[idx].cartocss
-      table: 'wdpapoly_july2014_0'
-      attrName: 'wdpaid'
-      attrVal: tileConfig.wdpaId
-    cartocss = @_addSelectedStyle args
-
-    sublayers[idx].cartocss = cartocss
-    sublayers
+      #{@_generateCartocssSelector(args)} {
+        line-color:##{args.lineColor};
+        line-width:#{args.lineWidth};
+        polygon-fill:##{args.polygonFill};
+        polygon-opacity:#{args.opacity};
+      }
+    """

   addCountryTiles: (tileConfig, sublayers) ->
     args =
-      cartocss: ''
       table: 'countries_geometries'
       attrName: 'iso_3'
       attrVal: "'#{tileConfig.iso3}'"
@@ -36,13 +43,12 @@
       lineWidth: 0

     sublayers.push
-      sql: "select * from #{args.table} where iso_3 = '#{tileConfig.iso3}'"
-      cartocss: @_addSelectedStyle args
+      sql: "SELECT * FROM #{args.table} WHERE iso_3 = '#{tileConfig.iso3}'"
+      cartocss: @_generateCartocss(args)
     sublayers

   addRegionTiles: (tileConfig, sublayers) ->
     args =
-      cartocss: ''
       table: 'continents'
       attrName: 'continent'
       attrVal: "'#{tileConfig.regionName}'"
@@ -50,38 +56,46 @@
       lineWidth: 0

     sublayers.push
-      sql: "select * from #{args.table} where continent = '#{tileConfig.regionName}'"
-      cartocss: @_addSelectedStyle args
+      sql: "SELECT * FROM #{args.table} WHERE continent = '#{tileConfig.regionName}'"
+      cartocss: @_generateCartocss(args)
+    sublayers
+
+  addWdpaTiles: (tileConfig, sublayers) ->
+    cartocss = [
+      @_generateCartocss(
+        table: ['wdpa_poly', 'wdpa_point']
+        lineColor: '40541b'
+        polygonFill: '83ad35'
+      )
+    ]
+
+    if tileConfig.wdpaId?
+      cartocss.push @_generateCartocss(
+        table: ['wdpa_poly', 'wdpa_point']
+        attrName: 'wdpaid'
+        attrVal: tileConfig.wdpaId
+      )
+
+    sublayers.push
+      sql: "SELECT the_geom FROM wdpa_point UNION ALL SELECT the_geom FROM wdpa_poly"
+      cartocss: cartocss.join("\n")
     sublayers

   addCartodbTiles: (tileConfig) ->
-    # Always show the wdpa layer:
-    cartocss = """
-      #wdpa_point, #wdpa_poly {
-        line-color:#40541b;
-        line-width:0.05;
-        polygon-fill:#83ad35;
-        polygon-opacity:0.7;}
-    """
+    sublayers = []

-    sublayers = [
-      sql: """
-        SELECT the_geom FROM wdpa_point
-          UNION ALL
-        SELECT the_geom FROM wdpa_poly
-      """
-      cartocss: cartocss
-    ]
-    if tileConfig.wdpaId?
-      sublayers = @addSelectedWdpaTiles tileConfig, sublayers, 0
+    @addWdpaTiles(tileConfig, sublayers)
+
     if tileConfig.iso3?
       sublayers = @addCountryTiles tileConfig, sublayers
     if tileConfig.regionName?
       sublayers = @addRegionTiles tileConfig, sublayers
+
     carto_tiles = new cartodb.Tiles(
       sublayers: sublayers
       user_name: "carbon-tool"
     )
+
     carto_tiles.getTiles( (o) =>
       L.tileLayer(o.tiles[0]).addTo @map
     )
@@ -90,7 +104,7 @@
     x1 = bounds[0][1]
     x2 = bounds[1][1]
     if x1 < 0 and x2 >= 0
-      return Math.abs(bounds[0][1]) + Math.abs(bounds[1][1])
+      return Math.abs(x1) + Math.abs(x2)
     else
       max = Math.max(Math.abs(x1), Math.abs(x2))
       min = Math.min(Math.abs(x1), Math.abs(x2))


Fix syntax error on coffeescript ... what was I thinking ...

--- app/assets/javascripts/rubyception/lib/jenny.coffee
+++ app/assets/javascripts/rubyception/lib/jenny.coffee
@@ -107,7 +107,7 @@
   template: (path,data)->
     template = null
     eval "template = Template.#{path.replace(/\//g,'.')}"
-    new throw "template is undefined: Template.#{path.replace(/\//g,'.')}" if template is undefined
+    throw "template is undefined: Template.#{path.replace(/\//g,'.')}" if template is undefined
     Milk.render template, data

   # collect


Fixed: use the right host to request notification center

--- lib/alarm_manager.coffee
+++ lib/alarm_manager.coffee
@@ -8,7 +8,7 @@

     constructor: (@timezone, @Alarm) ->

-        @client = new Client "http://192.168.33.10:9103/"
+        @client = new Client "http://localhost:9103/"

         # We load the existing alarms
         @Alarm.all (err, alarms) =>


use getLoadedThemes()

use getLoadedThemes()

--- lib/ui-watcher.coffee
+++ lib/ui-watcher.coffee
@@ -5,7 +5,7 @@
 class UIWatcher
   constructor: ({@themeManager}) ->
     @baseTheme = new BaseThemeWatcher()
-    for theme in @themeManager.getThemes()
+    for theme in @themeManager.getLoadedThemes()
       @createThemeWatcher(theme)
     @themeManager.on 'theme-loaded', (theme) =>
       @createThemeWatcher(theme)


新增判断标识

新增判断标识

--- lib/utils/util.coffee
+++ lib/utils/util.coffee
@@ -59,15 +59,17 @@
     regEx1 = /[\`\~\!\@\#\$\%\^\&\*\(\)\+\=\|\{\}\'\:\;\,\·\\\[\]\<\>\/\?\~\！\@\#\￥\%\…\…\&\*\（\）\—\—\+\|\{\}\【\】\‘\；\：\”\“\’\。\，\、\？]/g
     regEx2 = /[^\x00-\xff]/g
     regEx3 = /\d/
+    firstchar = str[0]
     flag1 = regEx1.test str
     flag2 = regEx2.test str
-    flag3 = regEx3.test str[0]
+    flag3 = regEx3.test firstchar
+    flag4 = firstchar is "-"
     # strcheck = str.replace(/[^\x00-\xff]/g,"")
     # strcheck = strcheck.replace(regEx,"")
     # strcheck = strcheck.replace(/-+/g, '-')
     # # 特殊处理
     # strcheck = '...' if strcheck is '.' or strcheck is '..'
-    return !(flag1 or flag2 or flag3)
+    return !(flag1 or flag2 or flag3 or flag4)

   getRepo: (appPath,repoUri, cb) ->
     options =


Remove need for buffer in `ensureSingleTrailingNewline`

--- lib/whitespace.coffee
+++ lib/whitespace.coffee
@@ -33,11 +33,13 @@
         replace('')

   ensureSingleTrailingNewline: (editor) ->
-    buffer = editor.getBuffer()
-    if buffer.getLastLine() is ''
-      row = buffer.getLastRow() - 1
-      buffer.deleteRow(row--) while row and buffer.lineForRow(row) is ''
+    lastRow = editor.getLastBufferRow()
+    lastLine = editor.lineForBufferRow(lastRow)
+    if lastLine is ''
+      row = lastRow - 1
+      while row and editor.lineForBufferRow(row) is ''
+        editor.deleteBufferRow(row--)
     else
       selectedBufferRanges = editor.getSelectedBufferRanges()
-      buffer.append('\n')
+      editor.appendText('\n')
       editor.setSelectedBufferRanges(selectedBufferRanges)


exec: print err message after close

exec: print err message after close

--- lib/commands/exec.coffee
+++ lib/commands/exec.coffee
@@ -26,8 +26,11 @@
         write "\n"
         callback()
     n.next (err) ->
-      n.ssh.close()
-      next err
+      # n.ssh.close()
+      # next err
+      n.ssh.close header: 'SSH Close' #unless params.command is 'prepare' # params.end and
+      n.next ->
+        process.stdout.write err.message if err
   .next (err) ->
     process.stdout.write err.message if err
     # Done


Read the offset from the EditorView directly.

--- lib/covering-view.coffee
+++ lib/covering-view.coffee
@@ -31,7 +31,7 @@

   reposition: ->
     marker = @cover()
-    anchor = @adapter.linesElement().offset()
+    anchor = @editorView.offset()
     ref = @offsetForMarker marker

     @offset top: ref.top + anchor.top


add test case for update

add test case for update

--- test/src/mysql.coffee
+++ test/src/mysql.coffee
@@ -125,6 +125,22 @@

       mysql_users._fetch_all fetched, [ { _login: 'joe' } ]

+    it 'should allow to update existing user', ( done ) ->
+      input._update [ [
+        joe
+
+        {
+          email: 'joe@toubkal.rocks'
+          login: 'joe'
+        }
+      ] ]
+
+      mysql_users._fetch_all ( _users ) ->
+        check done, () ->
+          expect( _users.length ).to.be.eql 1
+          joe = users._fetch_all()[ 0 ]
+          expect( _users ).to.be.eql [ joe ]
+
     it 'should allow to remove previously added user', ( done ) ->
       input._remove [ joe ]


Default to no summary if blank

Default to no summary if blank

--- scripts/views/workspace/content/edit-summary.coffee
+++ scripts/views/workspace/content/edit-summary.coffee
@@ -9,5 +9,5 @@
   return AlohaEditView.extend
     # **NOTE:** This template is not wrapped in an element
      template: (serializedModel) ->
-       return "#{serializedModel.summary or 'Enter a summary here'}"
+       return "#{serializedModel.summary or ''}"
      modelKey: 'summary'


Remove sinon from buttonviewwithmenu

Remove sinon from buttonviewwithmenu

--- test/components/buttons/buttonviewwithmenu.coffee
+++ test/components/buttons/buttonviewwithmenu.coffee
@@ -7,7 +7,6 @@

 describe 'KDButtonViewWithMenu', ->
   beforeEach ->
-    @sinon = sinon.sandbox.create()
     @view = new KDButtonViewWithMenu
       title : 'Settings'
       iconClass : 'settings'
@@ -16,9 +15,6 @@
         'Add Into' : { callback: => (->) }
         'Edit' : { callback: => (->) }
         'Delete' : { callback: => (->) }
-
-  afterEach ->
-    @sinon.restore()

   describe 'constructor', ->
     it 'should instantiate without any errors', ->
@@ -57,6 +53,6 @@

   describe 'contextMenu', ->
     it 'should create context menu', ->
-      @view.createContextMenu = @sinon.stub()
+      @view.createContextMenu = sinon.spy (->)
       @view.contextMenu();
       @view.createContextMenu.should.be.calledOnce


Fix writing file sync

Fix writing file sync

--- JakeFile.coffee
+++ JakeFile.coffee
@@ -12,14 +12,15 @@
         complete()

 desc('Generate mammouth parser');
-task 'generateParser', () ->
-	parser = require './lib/grammar'
-	fs.writeFile './lib/parser.js', parser.generate()
-	fs.unlinkSync './lib/grammar.js'
-	console.log 'Generating: mammouth parser has successfully been generated :)'
+task 'generateParser', {async: on}, () ->
+    parser = require './lib/grammar'
+    fs.writeFileSync './lib/parser.js', parser.generate(), 'utf8'
+    fs.unlinkSync './lib/grammar.js'
+    console.log 'Generating: mammouth parser has successfully been generated :)'
+    complete()

 desc('Generate mammouth for browser');
-task 'generateBrowser', () ->
+task 'generateBrowser', {async: on}, () ->
     code = ''
     # add parser.js
     code += 'require["./parser"] = (function() {'
@@ -98,6 +99,7 @@
             else
                 console.log "Generating: browser minifed file has successfully been generated :)"
                 addHeader()
+            complete()
     )

 desc 'Build the project.'


Don't show trashed Google Drive files

Don't show trashed Google Drive files

[#129178817]

--- src/code/providers/google-drive-provider.coffee
+++ src/code/providers/google-drive-provider.coffee
@@ -127,9 +127,9 @@

   list: (metadata, callback) ->
     @_loadedGAPI =>
-      mimeTypesQuery = ("(mimeType = '#{mimeType}')" for mimeType in @readableMimetypes).join " or "
+      mimeTypesQuery = ("mimeType = '#{mimeType}'" for mimeType in @readableMimetypes).join " or "
       request = gapi.client.drive.files.list
-        q: query = "(#{mimeTypesQuery} or (mimeType = 'application/vnd.google-apps.folder')) and '#{if metadata then metadata.providerData.id else 'root'}' in parents"
+        q: query = "trashed = false and (#{mimeTypesQuery} or mimeType = 'application/vnd.google-apps.folder') and '#{if metadata then metadata.providerData.id else 'root'}' in parents"
       request.execute (result) =>
         return callback('Unable to list files') if not result
         list = []


remove vendor specific fullscreen code in thyme

--- app/assets/javascripts/thyme.coffee
+++ app/assets/javascripts/thyme.coffee
@@ -552,44 +552,15 @@
     return

   # Event listener for the full-screen button
-  # unfortunately, lots of brwoser specific code
   fullScreenButton.addEventListener 'click', ->
     if fullScreenButton.dataset.status == 'true'
-      if document.exitFullscreen
-        document.exitFullscreen()
-      else if document.mozCancelFullScreen
-        document.mozCancelFullScreen()
-      else if document.webkitExitFullscreen
-        document.webkitExitFullscreen()
+      document.exitFullscreen() if document.exitFullscreen
     else
-      if thymeContainer.requestFullscreen
-        thymeContainer.requestFullscreen()
-      else if thymeContainer.mozRequestFullScreen
-        thymeContainer.mozRequestFullScreen()
-      else if thymeContainer.webkitRequestFullscreen
-        thymeContainer.webkitRequestFullscreen()
+      thymeContainer.requestFullscreen() if thymeContainer.requestFullscreen
     return

   document.onfullscreenchange = ->
-    if document.FullscreenElement != null
-      fullScreenButton.innerHTML = 'fullscreen_exit'
-      fullScreenButton.dataset.status = 'true'
-    else
-      fullScreenButton.innerHTML = 'fullscreen'
-      fullScreenButton.dataset.status = 'false'
-    return
-
-  document.onwebkitfullscreenchange = ->
-    if document.webkitFullscreenElement != null
-      fullScreenButton.innerHTML = 'fullscreen_exit'
-      fullScreenButton.dataset.status = 'true'
-    else
-      fullScreenButton.innerHTML = 'fullscreen'
-      fullScreenButton.dataset.status = 'false'
-    return
-
-  document.onmozfullscreenchange = ->
-    if document.mozFullScreenElement != null
+    if document.fullscreenElement != null
       fullScreenButton.innerHTML = 'fullscreen_exit'
       fullScreenButton.dataset.status = 'true'
     else


Fix Bug #229: Error when create issues in firefox with attachments

--- app/coffee/services/resource.coffee
+++ app/coffee/services/resource.coffee
@@ -598,7 +598,11 @@
         uploadComplete = (evt) =>
             @rootScope.$apply ->
                 file.status = "done"
-                data = JSON.parse(evt.target.responseText)
+                try
+                    data = JSON.parse(evt.target.responseText)
+                catch
+                    # NOTE: HACK: In firefox evt.target.responseText is HTML instead json text Why? Why?
+                    data = {}
                 defered.resolve(data)

         uploadFailed = (evt) =>
@@ -644,7 +648,11 @@
         uploadComplete = (evt) =>
             @rootScope.$apply ->
                 file.status = "done"
-                data = JSON.parse(evt.target.responseText)
+                try
+                    data = JSON.parse(evt.target.responseText)
+                catch
+                    # NOTE: HACK: In firefox evt.target.responseText is HTML instead json text Why? Why?
+                    data = {}
                 defered.resolve(data)

         uploadFailed = (evt) =>
@@ -690,7 +698,11 @@
         uploadComplete = (evt) =>
             @rootScope.$apply ->
                 file.status = "done"
-                data = JSON.parse(evt.target.responseText)
+                try
+                    data = JSON.parse(evt.target.responseText)
+                catch
+                    # NOTE: HACK: In firefox evt.target.responseText is HTML instead json text Why? Why?
+                    data = {}
                 defered.resolve(data)

         uploadFailed = (evt) =>
@@ -737,7 +749,11 @@
         uploadComplete = (evt) =>
             @rootScope.$apply ->
                 file.status = "done"
-                data = JSON.parse(evt.target.responseText)
+                try
+                    data = JSON.parse(evt.target.responseText)
+                catch
+                    # NOTE: HACK: In firefox evt.target.responseText is HTML instead json text Why? Why?
+                    data = {}
                 defered.resolve(data)

         uploadFailed = (evt) =>


Add comment

Add comment

--- lib/linter-csound.coffee
+++ lib/linter-csound.coffee
@@ -9,7 +9,7 @@
 module.exports =
 LinterCsound =
   provideLinter: ->
-
+    # Populate a symbol table with Csound’s built-in opcodes.
     Csound = csound.Create()
     opcodeList = []
     csound.NewOpcodeList Csound, opcodeList


limit articles in artist feed to editorial feed

--- src/desktop/apps/artist/queries/articles.coffee
+++ src/desktop/apps/artist/queries/articles.coffee
@@ -2,7 +2,7 @@
   """
   query artist($artist_id: String!) {
     artist(id: $artist_id) {
-      articles (limit: 99, sort: PUBLISHED_AT_DESC) {
+      articles (limit: 99, in_editorial_feed: true, sort: PUBLISHED_AT_DESC) {
         href
         thumbnail_title
         thumbnail_teaser


Bug fix for find in many

Bug fix for find in many

--- lib/memory_cursor.coffee
+++ lib/memory_cursor.coffee
@@ -183,32 +183,39 @@
     key_components = key_path.split('.')
     model_type = @model_type

-    next = (err, model_json) =>
+    next = (err, models_json) =>
       return callback(err) if err
       key = key_components.shift()

       # done conditions
       unless key_components.length
         was_handled = false
-        model_value = model_json[key]
-        find_value = @_find[key]
-
-        # an object might specify $lt, $lte, $gt, $gte, $ne
-        if _.isObject(find_value)
-          for operator in IS_MATCH_OPERATORS when find_value.hasOwnProperty(operator)
-            # console.log "Testing operator: #{operator}, model_value: #{util.inspect(model_value)}, test_value: #{util.inspect(find_value[operator])} result: #{IS_MATCH_FNS[operator](model_value, find_value[operator])}"
-            was_handled = true
-            break if not is_match = IS_MATCH_FNS[operator](model_value, find_value[operator])
-
-        return callback(null, is_match) if was_handled
-        return callback(null, _.isEqual(model_value, find_value))
-
-      # console.log "Next model (#{key_path}): #{key} model_json: #{util.inspect(model_json)}"
-
-      # still looking for actual model
-      if relation = model_type.relation(key)
-        relation.cursor(model_json, key).toJSON(next)
-      else
-        next(null, model_json[key])
+        find_value = @_find[key_path]
+
+        models_json = [models_json] unless _.isArray(models_json)
+        for model_json in models_json
+          model_value = model_json[key]
+          # console.log "\nChecking value (#{key_path}): #{key}, find_value: #{util.inspect(find_value)}, model_value: #{util.inspect(model_value)}, model_json: #{util.inspect(model_json)}"
+
+          # an object might specify $lt, $lte, $gt, $gte, $ne
+          if _.isObject(find_value)
+            for operator in IS_MATCH_OPERATORS when find_value.hasOwnProperty(operator)
+              # console.log "Testing operator: #{operator}, model_value: #{util.inspect(model_value)}, test_value: #{util.inspect(find_value[operator])} result: #{IS_MATCH_FNS[operator](model_value, find_value[operator])}"
+              was_handled = true
+              break if not is_match = IS_MATCH_FNS[operator](model_value, find_value[operator])
+
+          if was_handled
+            return callback(null, is_match) if is_match
+          else if is_match = _.isEqual(model_value, find_value)
+            return callback(null, is_match)
+
+        # checked all models and none were a match
+        return callback(null, false)
+
+      # console.log "\nNext model (#{key_path}): #{key} model_json: #{util.inspect(model_json)}"
+
+      # fetch relation
+      return relation.cursor(model_json, key).toJSON(next) if (relation = model_type.relation(key)) and not relation.embed
+      next(null, model_json[key])

     next(null, model_json) # start checking


dumbTypos -= 1

dumbTypos -= 1

--- lib/message-views.coffee
+++ lib/message-views.coffee
@@ -47,5 +47,5 @@

 module.exports =
   SuccessView: SuccessView,
-  MaybeLayerView: MaybeLaterView,
+  MaybeLaterView: MaybeLaterView,
   NothingToMergeView: NothingToMergeView


Support for dash array

Support for dash array

PDF reference 1.7 pages 218-219

--- lib/mixins/vector.coffee
+++ lib/mixins/vector.coffee
@@ -46,11 +46,14 @@

   dash: (length, options = {}) ->
     return this unless length?
-
-    space = options.space ? length
-    phase = options.phase or 0
-
-    @addContent "[#{length} #{space}] #{phase} d"
+    if Array.isArray length
+      length = length.join ' '
+      phase = options.phase or 0
+      @addContent "[#{length}] #{phase} d"
+    else
+      space = options.space ? length
+      phase = options.phase or 0
+      @addContent "[#{length} #{space}] #{phase} d"

   undash: ->
     @addContent "[] 0 d"


mail screen needs to fetch all to sync long-running screens (not just new)

--- app/js/services/mail_service.coffee
+++ app/js/services/mail_service.coffee
@@ -163,7 +163,7 @@
                        deferred.resolve()
                        @refreshing = off
         else
-            @MailAPI.check_new_messages(fetch_old = false).then =>
+            @MailAPI.check_new_messages(fetch_old = true).then =>
                 check_all().then =>
                     deferred.resolve()
                     @refreshing = off


Remove extraneous comment

Remove extraneous comment

--- app/schemas/models/user.coco.coffee
+++ app/schemas/models/user.coco.coffee
@@ -157,7 +157,6 @@
     value: {description: 'The experiment value/group that this user is assigned to', additionalProperties: true}  # Data type is flexible depending on experiment needs
     probability: c.pct {description: 'Probability of being assigned to this experiment value'}
     startDate: c.date {description: 'When this user first started the experiment'}
-    # TODO: add to Ozaria user
   mailChimp: {type: 'object'}
   hourOfCode: {type: 'boolean'}
   hourOfCode2019: {type: 'boolean'} # adding for hoc 2019, TODO refactor into a reusable property if needed


Updated selector to use :not

Updated selector to use :not

--- lib/services/goto.coffee
+++ lib/services/goto.coffee
@@ -113,7 +113,7 @@

         if $(selector).parent().hasClass('function argument') ||
            $(selector).prev().hasClass('namespace') && $(selector).hasClass('class') ||
-           $(selector).next().hasClass('class') && $(selector).next().hasClass('operator') == false
-            return $(selector).parent().children('.namespace, .class')
+           $(selector).next().hasClass('class')
+            return $(selector).parent().children('.namespace, .class:not(.operator):not(.constant)')

         return selector


Add heading in updates panel

Add heading in updates panel

--- lib/updates-panel.coffee
+++ lib/updates-panel.coffee
@@ -7,7 +7,7 @@
     @div =>
       @section class: 'section packages', =>
         @div class: 'section-container updates-container', =>
-          @div class: 'section-heading clearfix', =>
+          @h1 class: 'section-heading icon icon-cloud-download', 'Available Updates', =>
             @button outlet: 'updateAllButton', class: 'pull-right update-all-button btn btn-primary', 'Update All'

           @div outlet: 'updateErrors'


Fix circular reference caused by Object.defineProperty

--- atom/renderer/api/lib/remote.coffee
+++ atom/renderer/api/lib/remote.coffee
@@ -75,18 +75,7 @@
         if member.type is 'function'
           ret[member.name] = createRemoteMemberFunction meta.id, member.name
         else
-          do (member) ->
-            Object.defineProperty ret, member.name,
-              enumerable: true,
-              configurable: false,
-              set: (value) ->
-                # Set member data.
-                ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_SET', meta.id, member.name, value
-                value
-              get: ->
-                # Get member data.
-                val = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_GET', meta.id, member.name
-                metaToValue val
+          Object.defineProperty ret, member.name, createRemoteMemberProperty(meta.id, member.name)

       # Track delegate object's life time, and tell the browser to clean up
       # when the object is GCed.
@@ -120,6 +109,20 @@
         # Call member function.
         ret = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_CALL', metaId, name, wrapArgs(arguments)
         return metaToValue ret
+
+# Create configuration for defineProperty.
+# This function's content should not be inlined into metaToValue, otherwise V8
+# may consider it circular reference.
+createRemoteMemberProperty = (metaId, name) ->
+  enumerable: true,
+  configurable: false,
+  set: (value) ->
+    # Set member data.
+    ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_SET', metaId, name, value
+    value
+  get: ->
+    # Get member data.
+    metaToValue ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_GET', metaId, name)

 # Browser calls a callback in renderer.
 ipcRenderer.on 'ATOM_RENDERER_CALLBACK', (event, id, args) ->


turning on select_every_mousemove

turning on select_every_mousemove

--- bokehjs/src/coffee/tool/box_select_tool.coffee
+++ bokehjs/src/coffee/tool/box_select_tool.coffee
@@ -146,7 +146,7 @@
         renderers: []
         select_x: true
         select_y: true
-        select_every_mousemove: false
+        select_every_mousemove: true
         data_source_options: {} #backbone options for save on datasource
       })


only cache webpack when cache ENV is set

--- configs/webpack/base.coffee
+++ configs/webpack/base.coffee
@@ -168,7 +168,7 @@
     new ProgressBarPlugin(),
   ]

-  plugins.push(new HardSourceWebpackPlugin()) unless process.env.SOFT
+  plugins.push(new HardSourceWebpackPlugin()) if process.env.CACHE

   developmentBase =
     context: path.resolve(__dirname, '../../', projectConfig.basePath)


remove whitespace

remove whitespace

--- modules/plot/main/coffee/Sparkline.coffee
+++ modules/plot/main/coffee/Sparkline.coffee
@@ -1,7 +1,5 @@

 class Sparkline
-
-

   constructor: (selector, options) ->
     opts = hx.merge.defined({


Fix bare newlines when sending message

Fix bare newlines when sending message

When sending a message, some IMAP servers'll complain about _bare newlines_ when
the message is saved to the `sent` folder after smtp submission. This can be due
to RFC enforcements that forbid bare newlines after headers.

Our editor always starts with a `\n` character, and it may produces the bare
newlines warning from IMAP server as it follows directly the message header.

This commit trim the content of the message to remove this useless newline
first-char and try to fix the warning.

--- server/controllers/messages.coffee
+++ server/controllers/messages.coffee
@@ -193,6 +193,9 @@
     isDraft = req.body.isDraft
     delete req.body.isDraft

+    message = req.body
+    message.html = message.html.trim() if message.composeInHTML
+
     proc = new SaveOrSendMessage
         account: ramStore.getAccount req.body.accountID
         previousState: req.message # can be null


ensure the server doesnt break because a timeLog isnt found when stopping a time log

--- server/controllers/timeLogs.coffee
+++ server/controllers/timeLogs.coffee
@@ -44,8 +44,9 @@
     .exec (err, timeLogs) ->
       return next err if err
       timeLog = timeLogs[0]
-      timeLog.stopTime = req.body.stopTime
-      timeLog.save (err, timeLog) ->
-        res.status(200).json timeLog
+      if timeLog
+        timeLog.stopTime = req.body.stopTime
+        timeLog.save (err, timeLog) ->
+          res.status(200).json timeLog

 module.exports = router


Update config.cson

Update config.cson

--- Atom/config.cson
+++ Atom/config.cson
@@ -9,6 +9,9 @@
     fontSize: 16
     showIndentGuide: true
     scrollPastEnd: true
+    undoGroupingInterval: 100
+  "advanced-open-file":
+    createFileInstantly: true
   "atom-beautify":
     _analyticsUserId: ...
     html_end_with_newline: true
@@ -20,19 +23,17 @@
     js_keep_function_indentation: true
     js_space_after_anon_function: true
     js_end_with_newline: true
-    language_js_beautify_on_save: true
-    language_json_beautify_on_save: true
-    language_markdown_beautify_on_save: true
-  "pigments":
-    markerType: "dot"
-  "open-recent":
-    maxRecentFiles: 6
-    maxRecentDirectories: 10
-  "file-icons":
-    onChanges: true
+    language_js_beautify_on_save: false
+    language_json_beautify_on_save: false
+    language_markdown_beautify_on_save: false
   "clipboard-plus":
     minimumTextLength: 1
     maximumTextLength: 5000
     maximumLinesNumber: 6
-  "advanced-open-file":
-    createFileInstantly: true
+  "file-icons":
+    onChanges: true
+  "open-recent":
+    maxRecentFiles: 6
+    maxRecentDirectories: 10
+  "pigments":
+    markerType: "dot"


Refactors async rename() error handling

Refactors async rename() error handling

--- src/pathname.coffee
+++ src/pathname.coffee
@@ -98,16 +98,12 @@

     if cb?
       core.fs.rename @path, path.toString(), (err) =>
-        if err?
-          cb(err, null)
-        else
-          cb(null, new @constructor(path.toString()))
+        cb(err, new @constructor(path.toString()))
     else
       core.fs.renameSync(@path, path.toString())
       new @constructor(path.toString())

   # TODO
-  # rename
   # truncate
   # chmod
   # lstat


Protocol: Use debug() instead of console.log

--- src/protocol.coffee
+++ src/protocol.coffee
@@ -2,10 +2,11 @@
 # Implementation of the FBP protocol
 # http://noflojs.org/documentation/protocol

+debug = require('debug')('msgflo:fbp')
 EventEmitter = require('events').EventEmitter

 handleMessage = (proto, sub, cmd, payload, ctx) ->
-  console.log 'FBP RECV:', sub, cmd, payload
+  debug 'RECV:', sub, cmd, payload

   defaultGraph = 'default/main'

@@ -34,7 +35,7 @@
         out.push m
       return out

-    console.log 'Protocol, attempting to list componenents'
+    debug 'attempting to list componenents'

     classes = []
     for name, part of proto.coordinator.participants
@@ -50,7 +51,7 @@
       proto.transport.send 'component', 'component', component, ctx

   else if sub == 'component' and cmd == 'getsource'
-    return console.log 'ERROR: cannot get source for #{payload.name}' if payload.name != defaultGraph
+    return debug 'ERROR: cannot get source for #{payload.name}' if payload.name != defaultGraph

     sendSource = () ->
       graph = proto.coordinator.serializeGraph 'main'
@@ -67,14 +68,14 @@
     handleGraphMessage proto, cmd, payload, ctx

   else
-    console.log 'Unhandled FBP protocol message: ', sub, cmd
+    debug 'Unhandled FBP protocol message: ', sub, cmd

 handleGraphMessage = (proto, cmd, payload, ctx) ->
   graph = payload.graph

   if cmd == 'addedge'
-    console.log 'add', payload
+    debug 'addedge', payload
     p = payload
     proto.coordinator.connect p.src.node, p.src.port, p.tgt.node, p.tgt.port
     proto.transport.sendAll 'graph', 'addedge', payload
@@ -89,7 +90,7 @@
     proto.coordinator.removeInitial payload.tgt.node, payload.tgt.port
     proto.transport.sendAll 'graph', 'removeinitial', payload
   else
-    console.log 'Unhandled FBP protocol message: ', 'graph', cmd
+    debug 'Unhandled FBP protocol message: ', 'graph', cmd

 class Protocol
   constructor: (@transport, @coordinator) ->
@@ -99,7 +100,7 @@
       handleMessage @, protocol, command, payload, ctx

     @coordinator.on 'data', (from, fromPort, to, toPort, data) =>
-      console.log 'Proocol on data', from, fromPort, data
+      debug 'on data', from, fromPort, data

       id = "#{from}() #{fromPort.toUpperCase()} -> #{toPort.toUpperCase()} #{to}()"
       msg =


correcting brazilian turn right sign

correcting brazilian turn right sign

--- dev/br.cson
+++ dev/br.cson
@@ -621,7 +621,7 @@
   elements: [
     { type: 'square-rounded', color: 'black', transform: '{square_to_diamond}' }
     { type: 'square-rounded', color: 'yellow', transform: 'scale(.95) {square_to_diamond}' }
-    { type: 'turn-l-curve', color: 'black', transform: '{fit_diamond}' }
+    { type: 'turn-l-curve', color: 'black', transform: 'scale(-1,1) {fit_diamond}' }
   ]

 'turn-left':


Fix bug that caused file to revert to undefined after running with 'browse to task sandbox' checked

--- SingularityUI/app/models/Request.coffee
+++ SingularityUI/app/models/Request.coffee
@@ -487,7 +487,7 @@
                         return false

                     else
-                        localStorage.setItem('taskRunRedirectFilename', fileName) if filename?
+                        localStorage.setItem('taskRunRedirectFilename', fileName) if fileName?
                         localStorage.setItem('taskRunAfterStart', @data.afterStart)
                         @data.id = @get 'id'


activity: remove old embedly data argument

--- client/Social/Activity/views/inputwidget.coffee
+++ client/Social/Activity/views/inputwidget.coffee
@@ -176,10 +176,6 @@
     #     else if data.$suggest and data.$suggest not in suggestedTags
     #       suggestedTags.push data.$suggest

-    # fixme embedbox
-
-    # data.link_url   = @embedBox.url or ""
-    # data.link_embed = @embedBox.getDataForSubmit() or {}

     @lockSubmit()


util: modify findscrollableparent

util: modify findscrollableparent

--- client/app/lib/util/findScrollableParent.coffee
+++ client/app/lib/util/findScrollableParent.coffee
@@ -7,9 +7,9 @@
  *  styling. If no parent found, `global` (global: window for browser), the
  *  `window` object is returned.
 ###
-module.exports = findScrollableParent = (element) ->
+module.exports = findScrollableParent = (element, checkForKdScrollView = no) ->

-  while element.parentNode
+  while element?.parentNode
     element = element.parentNode

     # document don't have computed style.
@@ -17,6 +17,9 @@
       continue

     if element.dataset.isScroller
+      return element
+
+    if element.classList.contains('kdscrollview') and checkForKdScrollView
       return element

     style = global.getComputedStyle element


Toggle players

Toggle players

--- source/javascripts/games.js.coffee
+++ source/javascripts/games.js.coffee
@@ -23,7 +23,7 @@
 updateVisibility = ->
   $('.tournaments-by-year').show()
   $('#games-chart .tournament').show()
-  $('#games-chart .game').hide()
+  $('#games-chart .game').hide().css('opacity', '')

   $('.tournament-types .toggleable').addClass('inactive')
   $.each config.activeTypes, ->
@@ -43,7 +43,8 @@
     $.each config.activeOpponents, ->
       cls = playerToClass this
       $(".opponents .#{cls}").removeClass('inactive')
-      $("#games-chart .#{cls}").show()
+      $("#games-chart .tournament.#{cls} .game").show().css('opacity', '0.15')
+      $("#games-chart .tournament.#{cls} .game.#{cls}").css('opacity', '')

   $('#games-chart .tournament').each ->
     if $('.game', this).filter(':visible').length > 0
@@ -59,7 +60,7 @@

 T.def 'tournament-types', (tournamentTypes) ->
   [ '.tournament-types'
-    [ 'div.toggleable.all'
+    [ '.toggleable.all'
       click: ->
         if config.allTypes()
           config.activeTypes = []
@@ -75,7 +76,7 @@

 T.def 'tournament-type', (type) ->
   [
-    "div.toggleable.tournament-type.#{type}"
+    ".toggleable.tournament-type.#{type}"
     click: ->
       if config.activeTypes.indexOf(type) >= 0
         config.activeTypes.splice(config.activeTypes.indexOf(type), 1)
@@ -88,9 +89,9 @@
   ]

 T.def 'opponents', (opponents) ->
-  [ 'div.opponents'
+  [ '.opponents'
     'Opponents: '
-    [ 'div.toggleable.all'
+    [ '.toggleable.all'
       click: ->
         if config.activeOpponents.indexOf('all') >= 0
           config.activeOpponents = []
@@ -107,7 +108,7 @@
 T.def 'opponent', (opponent) ->
   cls = playerToClass opponent
   [
-    "div.toggleable.opponent.#{cls}"
+    ".toggleable.opponent.#{cls}"
     click: ->
       if config.activeOpponents is 'all'
         config.activeOpponents = hotOpponents.slice(0)
@@ -152,26 +153,26 @@
   else if tournament.type is 'atp1000'
     name = name.replace /ATP World Tour Masters 1000|ATP Masters Series /, ''

-  [ 'div.tournament'
+  [ '.tournament'
     class: tournament.type
     for game in tournament.games
       class: playerToClass game.opponent

-    [ 'div.tournament-info',
+    [ '.tournament-info',
       ['span.type', translateType(tournament.type)]
       ['br']
       ['span.name', name]
     ]
-    [ 'div.games'
+    [ '.games'
       T.each_with_index('game', tournament.games)
     ]
   ]

 T.def 'game', (game, index, tournament) ->
   if game.rank is 0
-    return ['div.game', 'BYE']
-
-  [ 'div.game'
+    return ['.game', 'BYE']
+
+  [ '.game'
     class: playerToClass game.opponent

     if game.round is 'S'
@@ -184,14 +185,22 @@
     else if game.result is 'L'
       class: 'lose'

+    click: ->
+      if config.activeOpponents.length is 1 and config.activeOpponents[0] is game.opponent
+        config.activeOpponents = 'all'
+      else
+        config.activeOpponents = [game.opponent]
+
+      updateVisibility()
+
     game.opponent
     " (#{game.rank})"
   ]

 T.def 'tournaments-by-year', (year, tournaments) ->
   if not tournaments then return
-  [ 'div.tournaments-by-year'
-    ['div.year', year]
+  [ '.tournaments-by-year'
+    ['.year', year]
     T.each('tournament', tournaments)
   ]


keyboard localization

keyboard localization

--- atom/config.cson
+++ atom/config.cson
@@ -23,3 +23,5 @@
   "atom-ternjs": {}
   "atom-beautify":
     _analyticsUserId: "83429072-4046-4dd1-85f5-5a216dc56d2a"
+  "keyboard-localization":
+    useKeyboardLayout: "fr_CH"


updated atom config

updated atom config

--- atom/config.cson
+++ atom/config.cson
@@ -1,6 +1,10 @@
 "*":
   core:
+    disabledPackages: [
+      "background-tips"
+    ]
     telemetryConsent: "limited"
+    warnOnLargeFileLimit: 10
   editor:
     showIndentGuide: true
     softWrap: true


scope some language things

scope some language things

--- atom/config.cson
+++ atom/config.cson
@@ -1,21 +1,15 @@
 "*":
-  editor:
-    invisibles: {}
-    fontFamily: "Source Code Pro Semibold"
-    fontSize: 15
-    showIndentGuide: true
-    tabLength: 4
+  amdbutler: {}
+  "atom-htmltidy":
+    enableLinter: false
+    formatOnSave: false
+    tidyExecPath: "/usr/local/bin/tidy"
+  "atom-typescript": {}
   core:
-    themes: [
-      "seti-ui"
-      "seti-syntax"
-    ]
     audioBeep: false
-    autoHideMenuBar: true
     disabledPackages: [
       "metrics"
-      "script"
-      "merge-conflicts"
+      "atom-htmltidy"
     ]
     ignoredNames: [
       ".eggs"
@@ -25,24 +19,84 @@
       ".git"
       ".tox"
     ]
+    telemetryConsent: "no"
+    themes: [
+      "slack-ui"
+      "one-light-syntax"
+    ]
+  editor:
+    fontFamily: "FiraCode-Retina"
+    invisibles:
+      cr: ""
+      eol: "¬"
+      tab: "⇥"
+    normalizeIndentOnPaste: false
+    scrollPastEnd: true
+    scrollSensitivity: 80
+    showIndentGuide: true
+    showInvisibles: true
+    tabLength: 4
+    tabType: "soft"
+  emmet: {}
   "exception-reporting":
-    userId: "**redacted**"
+    userId: "515ef670-19dc-8052-fceb-9ece67822ec5"
+  linter:
+    lintDebug: true
+    showInfoMessages: true
+    statusBar: "Show all errors"
+  "linter-eslint":
+    globalNodePath: "/usr/local"
+    useGlobalEslint: true
+  "linter-flake8":
+    executablePath: "/usr/local/bin/flake8"
+    flakeErrors: true
+    hangClosing: true
+  "linter-python-pep8":
+    pep8DirToExecutable: "C:/Python27/ArcGISx6410.3/Scripts/pep8.exe"
+  "linter-scss-lint":
+    disableWhenNoConfigFileInPath: true
+    executablePath: "/Users/sgourley/.rvm/bin/atom_scss-lint"
+  "linter-stylint":
+    onlyRunWhenConfig: true
+  "markdown-preview":
+    breakOnSingleNewline: true
+  "merge-conflicts": {}
+  "omnisharp-atom":
+    enhancedHighlighting19: true
+  "python-yapf":
+    checkOnSave: true
+    yapfPath: "/usr/local/bin/yapf"
+  "tree-view":
+    autoReveal: true
+    hideIgnoredNames: true
+    showOnRightSide: true
+    squashDirectoryNames: true
+  "vim-mode":
+    useClipboardAsDefaultRegister: false
   welcome:
     showOnStartup: false
-  linter:
-    lintOnEditorFocus: false
-    showHighlighting: true
-    lintOnChangeInterval: 1000
-    lintDebug: false
-  "vim-mode":
-    useClipboardAsDefaultRegister: false
-  "linter-jshint": {}
-  emmet: {}
-  "linter-jscs": {}
-  "jscs-fixer": {}
   whitespace:
     ignoreWhitespaceOnCurrentLine: false
-  "linter-pep8":
-    maxLineLength: 160
-  "tree-view":
-    hideIgnoredNames: true
+  "xml-formatter":
+    xmlUtf8Header: false
+".basic.html.text":
+  editor:
+    normalizeIndentOnPaste: "false"
+    softWrap: true
+    tabLength: 2
+".console.python.text":
+  editor:
+    normalizeIndentOnPaste: "false"
+    tabLength: 4
+".js.source":
+  editor:
+    normalizeIndentOnPaste: "false"
+    tabLength: 4
+".json.source":
+  editor:
+    normalizeIndentOnPaste: "false"
+    tabLength: 2
+".python.source":
+  editor:
+    normalizeIndentOnPaste: "false"
+    tabLength: 4


Exclude Word documents from Fuzzy Finder

--- atom/config.cson
+++ atom/config.cson
@@ -37,6 +37,7 @@
       "*.png"
       "*.jpg"
       "*.out"
+      "*.docx"
     ]
     followSymlinks: false
   editor:


moved fullscreen button and markdown helper to the KDInputViewWithPreview

--- components/inputs/KDInputViewWithPreview.coffee
+++ components/inputs/KDInputViewWithPreview.coffee
@@ -7,6 +7,8 @@
     options.preview.language      or= "markdown"
     options.preview.showInitially ?= yes
     options.preview.mirrorScroll  ?= yes
+    options.allowMaximized        ?= yes
+    options.showHelperModal       ?= yes

     options.keyup ?= (event)=>
       if @options.preview.autoUpdate
@@ -25,8 +27,10 @@
     @showPreview = options.preview.showInitially or no

     @previewOnOffLabel = new KDLabelView
-      cssClass : "preview_switch_label"
-      title: "Preview"
+      cssClass      : "preview_switch_label"
+      title         : "Preview"
+      tooltip       :
+        title       : "Show/hide the Text Preview Box"
     @previewOnOffSwitch = new KDOnOffSwitch
       label         : @previewOnOffLabel
       size          : "tiny"
@@ -48,6 +52,103 @@
     @previewOnOffContainer = new KDView
       cssClass : "preview_switch"

+    if @options.showHelperModal
+
+      @markdownLink = new KDCustomHTMLView
+        tagName     : 'a'
+        name        : "markdownLink"
+        value       : "markdown is enabled"
+        attributes  :
+          href      : '#'
+          value     : "markdown syntax is enabled"
+        cssClass    : 'markdown-link'
+        partial     : "What is Markdown?"
+        tooltip     :
+          title     : "Show available Markdown formatting syntax"
+        click       : (event)=>
+          if $(event.target).is 'span'
+            link.hide()
+          else
+            markdownText = new KDMarkdownModalText
+            modal = new KDModalView
+              title       : "How to use the Markdown syntax."
+              cssClass    : "what-you-should-know-modal markdown-cheatsheet"
+              height      : "auto"
+              width       : 500
+              content     : markdownText.markdownText()
+              buttons     :
+                Close     :
+                  title   : 'Close'
+                  style   : 'modal-clean-gray'
+                  callback: -> modal.destroy()
+
+      @previewOnOffContainer.addSubView @markdownLink
+
+    if @options.allowMaximized
+      @fullScreenBtn = new KDButtonView
+        style           : "clean-gray small"
+        cssClass        : "fullscreen-button"
+        title           : "Fullscreen Edit"
+        icon            : no
+        tooltip         :
+          title         : "Open a Fullscreen Editor"
+        callback: =>
+          @textContainer = new KDView
+            cssClass:"modal-fullscreen-text"
+
+          @text = new KDInputViewWithPreview
+            type : "textarea"
+            cssClass : "fullscreen-data kdinput text"
+            allowMaximized : no
+            defaultValue : @getValue()
+
+          @textContainer.addSubView @text
+
+          modal = new KDModalView
+            title       : "Please enter your content here."
+            cssClass    : "modal-fullscreen"
+            width       : $(window).width()-110
+            height      : $(window).height()-120
+            view        : @textContainer
+            position:
+              top       : 55
+              left      : 55
+            overlay     : yes
+            buttons     :
+              Cancel    :
+                title   : "Discard changes"
+                style   : "modal-clean-gray"
+                callback:=>
+                  modal.destroy()
+              Apply     :
+                title   : "Apply changes"
+                style   : "modal-clean-gray"
+                callback:=>
+                  @setValue @text.getValue()
+                  @generatePreview()
+                  modal.destroy()
+
+          modal.$(".kdmodal-content").height modal.$(".kdmodal-inner").height()-modal.$(".kdmodal-buttons").height()-modal.$(".kdmodal-title").height() # minus the margin, border pixels too..
+          modal.$(".fullscreen-data").height modal.$(".kdmodal-content").height()-30-23+10
+          modal.$(".input_preview").height   modal.$(".kdmodal-content").height()-0-21+10
+          modal.$(".input_preview").css maxHeight:  modal.$(".kdmodal-content").height()-0-21+10
+          modal.$(".input_preview div.preview_content").css maxHeight:  modal.$(".kdmodal-content").height()-0-21
+          contentWidth = modal.$(".kdmodal-content").width()-40
+          halfWidth  = contentWidth / 2
+
+          @text.on "PreviewHidden", =>
+            modal.$(".fullscreen-data").width contentWidth #-(modal.$("div.preview_switch").width()+20)-10
+            # modal.$(".input_preview").width (modal.$("div.preview_switch").width()+20)
+
+          @text.on "PreviewShown", =>
+            modal.$(".fullscreen-data").width contentWidth-halfWidth-5
+            # modal.$(".input_preview").width halfWidth-5
+
+          modal.$(".fullscreen-data").width contentWidth-halfWidth-5
+          modal.$(".input_preview").width halfWidth-5
+
+      @previewOnOffContainer.addSubView @fullScreenBtn
+
     @previewOnOffContainer.addSubView @previewOnOffLabel
     @previewOnOffContainer.addSubView @previewOnOffSwitch


no message

no message

--- scripts/test_ushio.coffee
+++ scripts/test_ushio.coffee
@@ -1,9 +1,9 @@
 # Description:
 #   AAを表示するbot
 # Author:
-#   raoka0000
+#   munonasalu

 module.exports = (robot) ->
   robot.respond /(hiroto)/i, (msg) ->
-    text = "こんばんわんこそば"
+    text = "Welcome to ようこそ ジャパリパーク！"
     msg.send text


teams: pass error back to callback

teams: pass error back to callback

--- workers/social/lib/social/models/teamtoken.coffee
+++ workers/social/lib/social/models/teamtoken.coffee
@@ -115,7 +115,7 @@
       emails.forEach (email) =>
         queue.push =>
           @create client, { email }, (err, invitation) ->
-            return queue.fin()  if err
+            return queue.fin err  if err

             properties =
               inviter  : inviter


Tests: environments: paidaccount: fixed makeAlwaysOnForNotPaidUser test.

--- client/test/lib/environments/paidaccount.coffee
+++ client/test/lib/environments/paidaccount.coffee
@@ -26,9 +26,8 @@

   makeAlwaysOnForNotPaidUser: (browser) ->

-    buttonSelector    = '.machine-settings-modal .alwayson .koding-on-off a'
-    vmSelector        = 'a[href="/IDE/koding-vm-1"]'
-    freeModalSelector = '.computeplan-modal.env-modal.free-plan'
+    toggleSelector = '.machine-settings-modal .alwayson'
+    vmSelector     = 'a[href="/IDE/koding-vm-1"]'

     helpers.beginTest(browser)

@@ -40,11 +39,10 @@
         environmentHelpers.openVmSettingsModal(browser)

         browser
-          .waitForElementVisible  buttonSelector, 20000
-          .click                  buttonSelector
+          .waitForElementVisible  toggleSelector, 20000
+          .click                  toggleSelector + ' .koding-on-off a.knob'
           .pause                  2000
-          .waitForElementVisible  freeModalSelector, 20000 # Assertion
-          .assert.containsText    freeModalSelector, 'Please upgrade to enable this feature.' # Assertion
+          .waitForElementVisible  '.kdmodal-content a.custom-link-view', 20000 # Assertion
           .end()


sponsor tweak

sponsor tweak

--- models/sponsor.coffee
+++ models/sponsor.coffee
@@ -25,7 +25,7 @@
   descriptionStyle: "padding-top:15px"
   description:
     '''
-    Kadira is a performance monitoring platform for Meteor. They'll also add support for monitoring GraphQL apps soon.
+    [Kadira](https://kadira.io) is a performance monitoring service for Meteor and GraphQL, a technology poised to become the future of APIs. Kadira will award an additional $1000 for the best team using GraphQL. So, start learning GraphQL here: <https://learngraphql.com/>
     '''
 ,
   name:  'Joyent'


KDProgressBarView: added data parameter to constructor

--- components/progressbar/KDProgressBarView.coffee
+++ components/progressbar/KDProgressBarView.coffee
@@ -1,5 +1,5 @@
 class KDProgressBarView extends KDCustomHTMLView
-  constructor:(options = {})->
+  constructor:(options = {}, data)->

     options.cssClass = KD.utils.curry "progressbar-container", options.cssClass

@@ -7,7 +7,7 @@
     options.initial      ?= no
     options.title        ?= ""

-    super options
+    super options, data

   viewAppended:->
     {initial, title} = @getOptions()


Added WikiHistoricalController tests

Added WikiHistoricalController tests

--- test/unit/controllers/wikiControllerSpec.coffee
+++ test/unit/controllers/wikiControllerSpec.coffee
@@ -238,3 +238,72 @@
             ctrl.scope.attachments = [$model.make_model('wiki/attachments', {"id": "test", "content": "test"})]
             ctrl.deleteNewAttachment(ctrl.scope.attachments[0])
             expect(ctrl.scope.newAttachments).to.be.deep.equal([])
+
+    describe "WikiHistoricalController", ->
+        httpBackend = null
+        scope = null
+        ctrl = null
+
+        beforeEach(inject(($rootScope, $controller, $httpBackend, $routeParams) ->
+            scope = $rootScope.$new()
+            $routeParams.slug = "test"
+            $routeParams.pslug = "ptest"
+            ctrl = $controller("WikiHistoricalController", {
+                $scope: scope
+            })
+            httpBackend = $httpBackend
+            httpBackend.whenGET("http://localhost:8000/api/v1/sites").respond(200, {test: "test"})
+            httpBackend.whenGET("http://localhost:8000/api/v1/resolver?project=ptest").respond(200, {project: 1})
+            httpBackend.whenGET("http://localhost:8000/api/v1/projects/1?").respond(200, {id: 1, ref: "2", points: []})
+            httpBackend.whenGET("http://localhost:8000/api/v1/wiki?project=1&slug=test").respond(200, [{id: "test", content: "test-content"}])
+            httpBackend.whenGET("http://localhost:8000/api/v1/wiki-attachments?object_id=test&project=1").respond(200, [])
+            httpBackend.whenGET("http://localhost:8000/api/v1/wiki/test/historical?page=1").respond(200, [{"test1": "test1"}])
+            httpBackend.whenGET("http://localhost:8000/api/v1/users?project=1").respond(200, [])
+            httpBackend.whenGET("http://localhost:8000/api/v1/roles?project=1").respond(200, [])
+            httpBackend.flush()
+        ))
+
+        afterEach ->
+            httpBackend.verifyNoOutstandingExpectation()
+            httpBackend.verifyNoOutstandingRequest()
+
+        it "should have section login", ->
+            expect(ctrl.section).to.be.equal("wiki")
+
+        it "should have a title", ->
+            expect(ctrl.getTitle).to.be.ok
+
+        it "should reload the page after a restore", inject ($model) ->
+            ctrl.scope.content = "other-content"
+            ctrl.scope.page = $model.make_model('wiki', {"id": "other", "content": "other"})
+            httpBackend.expectGET("http://localhost:8000/api/v1/wiki?project=1&slug=test").respond(200, [{id: "test", content: "test-content"}])
+            httpBackend.expectGET("http://localhost:8000/api/v1/wiki/test/historical?page=1").respond(200, [])
+            ctrl.scope.$emit("wiki:restored")
+            httpBackend.flush()
+            expect(ctrl.scope.page.getAttrs()).to.be.deep.equal({id: "test", content: "test-content"})
+            expect(ctrl.scope.content).to.be.equal("test-content")
+
+        it "should allow to load more historical", inject ($model) ->
+            httpBackend.expectGET(
+                "http://localhost:8000/api/v1/wiki/test/historical?page=1"
+            ).respond(200, [{"test1": "test1"}, {"test2": "test2"}])
+            promise = ctrl.loadHistorical()
+            httpBackend.flush()
+            promise.then ->
+                expect(ctrl.scope.historical.models.length).to.be.equal(1)
+
+            httpBackend.expectGET(
+                "http://localhost:8000/api/v1/wiki/test/historical?page=2"
+            ).respond(200, [{"test3": "test3"}])
+            promise = ctrl.loadMoreHistorical()
+            httpBackend.flush()
+            promise.then ->
+                expect(ctrl.scope.historical.models.length).to.be.equal(2)
+
+        it "should load the first page historical on loadMorehistorical when no historical", inject ($model) ->
+            ctrl.scope.historical = null
+            httpBackend.expectGET(
+                "http://localhost:8000/api/v1/wiki/test/historical?page=1"
+            ).respond(200, [{"test1": "test1"}, {"test2": "test2"}])
+            promise = ctrl.loadMoreHistorical()
+            httpBackend.flush()


Revert default timeout to 30sec.

Revert default timeout to 30sec.

--- client/Main/providers/computecontroller.coffee
+++ client/Main/providers/computecontroller.coffee
@@ -2,7 +2,7 @@

   @providers = KD.config.providers

-  @timeout = 15000
+  @timeout = 30000

   constructor:->


Don't listen key down events for enter anymore.

--- client/account/lib/accounttwofactorauth.coffee
+++ client/account/lib/accounttwofactorauth.coffee
@@ -79,9 +79,6 @@
           name             : 'password'
           type             : 'password'
           label            : 'Password'
-          keydown          : (e) =>
-            @handleKeyDown e, @bound 'handleDisableFormButton'
-
         button             :
           label            : ' '
           cssClass         : 'Formline--half'
@@ -127,15 +124,11 @@
           name             : 'password'
           type             : 'password'
           label            : 'Password'
-          keydown          : (e) =>
-            @handleKeyDown e, @bound 'handleEnableFormButton'
         tfcode             :
           cssClass         : 'Formline--half'
           placeholder      : 'Enter the verification code'
           name             : 'tfcode'
           label            : 'Verification Code'
-          keydown          : (e) =>
-            @handleKeyDown e, @bound 'handleEnableFormButton'

     @addSubView new kd.ButtonView
       title            : 'Enable 2-Factor Auth'
@@ -226,8 +219,3 @@

       """

-
-  handleKeyDown: (e, method = kd.noop) ->
-
-    method.call()  if (e.which or e.keyCode) is 13
-


Fix newAppModal create logic

Fix newAppModal create logic

--- client/app/MainApp/kodingappscontroller.coffee
+++ client/app/MainApp/kodingappscontroller.coffee
@@ -562,17 +562,18 @@
                   appPath     = getAppPath manifest

                   FSItem.doesExist appPath, (err, exists)=>
-                    newAppModal.modalTabs.forms.form.buttons.Create.hideLoader()
                     if exists
+                      newAppModal.modalTabs.forms.form.buttons.Create.hideLoader()
                       new KDNotificationView
                         type      : "mini"
                         cssClass  : "error"
                         title     : "App folder with that name is already exists, please choose a new name."
                         duration  : 3000
                     else
-                      @prepareApplication {isBlank : type is "blank", name}, (err, response)->
+                      @prepareApplication {isBlank : type is "blank", name}, (err, response)=>
                         callback? err
-                      newAppModal.destroy()
+                        newAppModal.modalTabs.forms.form.buttons.Create.hideLoader()
+                        newAppModal.destroy()
             fields                :
               type                :
                 label             : "Type"


maintabs: hiddenhandle missing option added

--- client/app/MainApp/maintabs/maintabview.coffee
+++ client/app/MainApp/maintabs/maintabview.coffee
@@ -117,10 +117,11 @@
     # this is a temporary hack
     # for reviving the main tabs
     # a better solution tbdl - SY
-    o.domId    = "maintabpane-#{@utils.slugify options.name}"
-    o.domId   += "-#{@utils.getRandomNumber()}" if document.getElementById o.domId
-    o.name     = options.name
-    o.behavior = options.behavior
+    o.domId         = "maintabpane-#{@utils.slugify options.name}"
+    o.domId        += "-#{@utils.getRandomNumber()}" if document.getElementById o.domId
+    o.name          = options.name
+    o.behavior      = options.behavior
+    o.hiddenHandle  = options.hiddenHandle

     paneInstance = new MainTabPane o


flux/payment: add action types to load group invoices

--- client/app/lib/flux/payment/actiontypes.coffee
+++ client/app/lib/flux/payment/actiontypes.coffee
@@ -6,6 +6,10 @@
   'CREATE_STRIPE_TOKEN_BEGIN'
   'CREATE_STRIPE_TOKEN_SUCCESS'
   'CREATE_STRIPE_TOKEN_FAIL'
+
+  'LOAD_GROUP_INVOICES_BEGIN'
+  'LOAD_GROUP_INVOICES_SUCCESS'
+  'LOAD_GROUP_INVOICES_FAIL'

   'LOAD_GROUP_PLAN_BEGIN'
   'LOAD_GROUP_PLAN_SUCCESS'


Add addtional specs for test cases

Add addtional specs for test cases

--- specs/coffee/ValidatorSpecs.coffee
+++ specs/coffee/ValidatorSpecs.coffee
@@ -65,6 +65,12 @@
     it 'should return true when an email contains a space', ->
       expect(BackboneValidate.validators.email('someemail@google.com Name Surname')).toBe(true)

+    it 'should return true when an email ends with a period', ->
+      expect(BackboneValidate.validators.email('someemail@google.com.')).toBe(true)
+
+    it 'should return true when an email is in the format name (email)', ->
+      expect(BackboneValidate.validators.email('Name Surname (email@gmail.com)')).toBe(true)
+
   describe 'the "maxLength" validator', ->
     it 'should be exposed', ->
       expect(BackboneValidate.validators.maxLength).toBeDefined()