CredentialHelper: fix credential create with simple retry mechanism

I still not sure about the root case but the error I’m getting
intermittently is `not logged in` for new created users. This simply
retries.

--- workers/social/testhelper/models/computeproviders/credentialhelper.coffee
+++ workers/social/testhelper/models/computeproviders/credentialhelper.coffee
@@ -47,10 +47,13 @@
   options.meta     ?= generateMetaData options.provider
   options.title    ?= 'koding'

-  JCredential.create client, options, (err, credential) ->
-    addToRemoveList client, credential.identifier  if credential
-    console.error 'createCredential:', err  if err
-    callback err, { credential }
+  maxTry = 3
+  do create = ->
+    JCredential.create client, options, (err, credential) ->
+      return create()  if err?.description is 'not logged in' and maxTry--
+      addToRemoveList client, credential.identifier  if credential
+      console.error 'createCredential:', err  if err
+      callback err, { credential }

 withConvertedUserAndCredential = (options, callback) ->


adhere to timecop deprecation

adhere to timecop deprecation

--- keymaps/remote-ftp.cson
+++ keymaps/remote-ftp.cson
@@ -1,2 +1,2 @@
-'.workspace':
+'atom-workspace':
   'ctrl-alt-o': 'remote-ftp:toggle'


Call exit on process global

Call exit on process global

--- build/tasks/check-licenses-task.coffee
+++ build/tasks/check-licenses-task.coffee
@@ -1,4 +1,3 @@
-
 module.exports = (grunt) ->
   grunt.registerTask 'check-licenses', 'Report the licenses of all dependencies', ->
     legalEagle = require 'legal-eagle'
@@ -13,7 +12,7 @@
     legalEagle options, (err, summary) ->
       if err?
         console.error(err)
-        exit 1
+        process.exit 1

       for key of summary
         delete summary[key] if key.match /^atom@/


Detect if browser is chrome

Detect if browser is chrome

--- apps/tools/routes.coffee
+++ apps/tools/routes.coffee
@@ -1,3 +1,4 @@
+useragent = require('useragent')
 Authentication = require '../../models/authentication'
 bookmarklet = require '../../lib/bookmarklet'

@@ -15,6 +16,7 @@
     tab: tab
     auth: auth
     bookmarklet: bookmarklet
+    isChrome: useragent.is(req.headers['user-agent']).chrome

 @findFriends = (req, res, next) ->
   tab = res.locals.sd.TAB = 'find-friends'


Fix map

Fix map

--- apps/users/routes.coffee
+++ apps/users/routes.coffee
@@ -15,8 +15,8 @@
       User.findOne {username: username}, (err, user) ->
         next(err) if err?
         if user?
-          badges = user.badges.map ->
-            badge = @toJSON();
+          badges = user.badges.map (badge)->
+            badge = badge.toJSON()
             badge.assertion = "http://#{configuration.get('hostname')}/users/#{user.email_hash}/badges/#{badge.slug}"
             badge
           formatResponse req, res, badges


Remove unused require

Remove unused require

--- src/app/root-view.coffee
+++ src/app/root-view.coffee
@@ -10,7 +10,6 @@
 Pane = require 'pane'
 PaneColumn = require 'pane-column'
 PaneRow = require 'pane-row'
-StatusBar = require 'status-bar'
 TextMateTheme = require 'text-mate-theme'

 module.exports =


Remove unused indent methods from Selection

--- src/app/selection.coffee
+++ src/app/selection.coffee
@@ -481,12 +481,6 @@
     @editSession.createFold(range.start.row, range.end.row)
     @cursor.setBufferPosition([range.end.row + 1, 0])

-  autoIndentText: (text) ->
-    @editSession.autoIndentTextAfterBufferPosition(text, @cursor.getBufferPosition())
-
-  autoOutdent: ->
-    @editSession.autoOutdentBufferRow(@cursor.getBufferRow())
-
   modifySelection: (fn) ->
     @retainSelection = true
     @placeTail()


add core dependency resolution test

add core dependency resolution test

--- test/dependency-resolution-sync.coffee
+++ test/dependency-resolution-sync.coffee
@@ -2,7 +2,11 @@

   deps = (entryFile, opts) ->
     entryFile = path.resolve path.join FIXTURES_DIR, entryFile
-    (Object.keys traverseDependenciesSync entryFile, FIXTURES_DIR, opts).sort()
+    for filename in (Object.keys traverseDependenciesSync entryFile, FIXTURES_DIR, opts).sort()
+      if filename[...FIXTURES_DIR.length] is FIXTURES_DIR
+        "/#{path.relative FIXTURES_DIR, filename}"
+      else
+        path.relative __dirname, filename

   test 'no dependencies', ->
     fixtures '/a.js': ''
@@ -34,6 +38,10 @@
       '/b.js': 'require("./a")'
     arrayEq ['/a.js', '/b.js'], deps '/a.js'

+  test 'core dependencies', ->
+    fixtures '/a.js': 'require("punycode")'
+    arrayEq ['../core/punycode.js', '/a.js'], deps '/a.js'
+
   test 'missing dependencies', ->
     fixtures '/a.js': 'require("./b")'
     throws -> deps '/a.js'


Add license header to testcase

Add license header to testcase

--- test/index.coffee
+++ test/index.coffee
@@ -1,3 +1,26 @@
+###
+The MIT License (MIT)
+
+Copyright (c) 2013 Tim Düsterhus
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+###
+
 should = require 'should'
 validator = require '../validator'


.

Former-commit-id: 7c28e47570b58771dbf269ac8b44893a45e88795 [formerly 8ebc2678d7807a6599fc10cb5e99e00fe7e5ee26] [formerly b5f07128150b8b311baed2104b490260db119d70 [formerly 5ccb653be830430984825bfd19667605aee1fa94]] [formerly 9849ef1a54bfa85b245c6721b83795d9270ba346 [formerly bffbacc16b884cc2f51a65de53434dc7665dd972] [formerly 8998fc545b1c00816f41edf26e0695bd314d04c0 [formerly 8998fc545b1c00816f41edf26e0695bd314d04c0 [formerly dcda24f118b11fe7a905ea55ebf828ab7eebf021]]]]
Former-commit-id: 7380646693e01592c82830696725ebac7448d808 [formerly eeefa3cca14a3a762cb081069f7b974fa5f072d9] [formerly aebca49123f42fa3f49e23de6d72e0db0811ef54 [formerly 956c88e02b78b9f1eacbc3da9c20e8928ce5f56b]]
Former-commit-id: 943c6e84684f68a4f491c625b83722fe8b735acc [formerly 84e3f69bc0fd9dddeacd8130e9064f96e08597f0]
Former-commit-id: 5fb68a58271a5f3de2fe08e78d7edc706427ae2e
Former-commit-id: d5daed9764db5f165623a9269c20ac49d6d91e64

--- @client/customizations.coffee
+++ @client/customizations.coffee
@@ -344,6 +344,11 @@

 ##########################
 # SUBDOMAIN CONFIGURATIONS
+
+
+customizations['us'] =
+  show_proposer_icon: true
+

 ###############
 # Monitorinstitute


Move process.env filter into a separate function.

--- index.coffee
+++ index.coffee
@@ -22,6 +22,15 @@
     return dir.path if activeFilePath.indexOf(dir.path + '/') is 0
   defaultPath

+filterProcessEnv = () ->
+  env = {}
+  for key, value of process.env
+    env[key] = value if key not in [
+      # Filter out environment variables leaked by the Atom process:
+      'NODE_PATH', 'NODE_ENV', 'GOOGLE_API_KEY', 'ATOM_HOME'
+    ]
+  env
+
 open = (filepath) ->
   if not filepath
     dirpath = getRootDir()
@@ -31,11 +40,7 @@
     dirpath = filepath
   return if not dirpath
   command = atom.config.get 'open-terminal-here.command'
-  env = {}
-  for key, value of process.env
-    env[key] = value if key not in ['NODE_PATH', 'NODE_ENV', 'GOOGLE_API_KEY', 'ATOM_HOME']
-  require('child_process').exec command,
-    {cwd: dirpath, env}
+  require('child_process').exec command, cwd: dirpath, env: filterProcessEnv()

 switch require('os').platform()
   when 'darwin'


Removed useless log statement

Removed useless log statement

Signed-off-by: Wyatt Calandro <96804f3875bc364d25340989c9f5960c99a00fd9@arm1stice.com>

--- index.coffee
+++ index.coffee
@@ -20,4 +20,3 @@
     # In this scenario, the api key is already set and the application is set up already, so we just open the main window
     lptConfig = require '../../../config.json' # Import the config
     require './src/index.coffee'
-    console.log 'exists'


clearer if block

clearer if block

--- index.coffee
+++ index.coffee
@@ -177,7 +177,7 @@
     err = (err?.toString() or res?.body.error_description or res?.body.error)

     # Error if we do not have an access token
-    unless err or res?.body.access_token
+    if not err or not res?.body.access_token
       err = "Unable to authenticate you"

     # Success


@getActiveEditor() doesn't exist. Use atom.workspace.getActiveTextEditor(). Fixes #35.

--- index.coffee
+++ index.coffee
@@ -267,7 +267,9 @@
       splitter()

   pipeTerm: (action) ->
-    editor = @getActiveEditor()
+    editor = atom.workspace.getActiveTextEditor()
+    if !editor
+      return
     stream = switch action
       when 'path'
         editor.getBuffer().file.path


Use command registry

Use command registry

--- index.coffee
+++ index.coffee
@@ -29,9 +29,10 @@

 module.exports =
   activate: ->
-    atom.workspaceView.command 'pretty-json:prettify', '.editor', ->
-      editor = atom.workspace.getActiveEditor()
-      prettify(editor)
-    atom.workspaceView.command 'pretty-json:sort-and-prettify', '.editor', ->
-      editor = atom.workspace.getActiveEditor()
-      prettify(editor, true)
+    atom.commands.add 'atom-workspace',
+      'pretty-json:prettify': ->
+        editor = atom.workspace.getActiveEditor()
+        prettify(editor)
+      'pretty-json:sort-and-prettify': ->
+        editor = atom.workspace.getActiveEditor()
+        prettify(editor, true)


Fix validateOne for recipients

Fix validateOne for recipients

--- index.coffee
+++ index.coffee
@@ -114,7 +114,14 @@
 						when "validateAll"
 							# at least one recipient did not match -> return false
 							return false unless toResult
-			return true if foundMyMail
+			if foundMyMail
+				switch config.multipleToHandling
+					when "validateOne"
+						# we would have early aborted by now if any mail was valid
+						return false
+					when "validateAll"
+						# we would have early aborted by now if any mail was invalid
+						return true
 			config.validIfNotFound

 		if result


Looping right through the callbacks in the bag as well

--- index.coffee
+++ index.coffee
@@ -90,7 +90,7 @@
 	###
 	fire: (e) =>
 		_.forEachRight @handlers[e.type], (bag) ->
-			_.each bag, (cbs) -> cbs.modified(e); return true
+			_.forEachRight bag, (cbs) -> cbs.modified(e); return true

 # This operates as a singleton
 module.exports = new WindowEventMediator()


Remove body classes when deactivating package

--- index.coffee
+++ index.coffee
@@ -38,6 +38,10 @@

   deactivate: ->
     @disableSetiIcons false
+    @forceShow false
+    @onChanges false
+    @colour true
+    @tabPaneIcon false
     # console.log 'deactivate'

   serialize: ->


Fix message

Fix message

--- lib/atom-perl6-editor-tools.coffee
+++ lib/atom-perl6-editor-tools.coffee
@@ -26,7 +26,7 @@
       disabled = true if (pkg == "language-perl")

     # Warn only when language-perl is enabled!
-    atom.notifications.addWarning("Please disable language-perl to get a better Perl 6 syntax highlighting") unless disabled
+    atom.notifications.addWarning("Please disable language-perl for a better Perl 6 syntax highlighted code") unless disabled

     # Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
     @subscriptions = new CompositeDisposable


DiaScene: include z-index as in scene attributes

--- lib/components/dia/diascene.coffee
+++ lib/components/dia/diascene.coffee
@@ -339,18 +339,24 @@

   setScale: (scale = 1) ->
+    @scale = scale
     container.setScale scale  for container in @containers
     @updateScene()

-    canvas.setAttributes @getSceneSize()

   cleanup: (canvas) ->
+    canvas.setAttributes @getSceneAttributes()
+

   parentDidResize: ->
     super
     @updateScene()

-  getSceneSize:-> width: @getWidth(), height: @getHeight()
+  getSceneAttributes: -> {
+    width  : @getWidth()
+    height : @getHeight()
+    zIndex : 1
+  }

   dumpScene: -> console.log @containers, @connections


Making profile update show the profile instead of minimizing it

--- app/coffee/context_panel.coffee
+++ app/coffee/context_panel.coffee
@@ -23,7 +23,7 @@

     $('form#update_profile').bind 'ajax:beforeSend', (xhr, settings)=>
       @contextView.showProfile()
-      @contextView.contractProfile()
+      #@contextView.contractProfile()

     $('form#update_profile').bind 'ajax:success', (data, xhr, status)->
       $('p.notice').text('Profile has been updated')


expect prisoner counts to update in marking

--- app/coffee/tests/browser.coffee
+++ app/coffee/tests/browser.coffee
@@ -528,6 +528,7 @@
         white: 7
         blackscore: 19*19 - 25 + 1
         whitescore: 0
+      @assertPrisoners test, black: 0, white: 1
     # clicking an empty point does nothing
     casper.thenClick (pointSelector 0, 0), =>
       @assertGeneralPointCounts test,
@@ -547,6 +548,7 @@
         whitescore: 9
         blackdead: 3
         black: 9
+      @assertPrisoners test, black: 3, white: 1

     # we click the white group; the neighbouring dead black stones are restored
     # automatically


updating popover and planning board tests

--- iterationplanningboard/IterationPlanningBoardAppSpec.coffee
+++ iterationplanningboard/IterationPlanningBoardAppSpec.coffee
@@ -144,6 +144,64 @@
     @createApp().then =>
       Assert.arrayContains @app.down('.rallycardboard').cardConfig.fields, 'Parent'

+  it 'should render a maximum of 3 columns', ->
+    @createApp(
+      iterationCount: 5
+    ).then =>
+      columns = @getColumns()
+      expect(columns.length).toEqual 4 #1 extra column for the backlog column
+
+  it 'should render columns ordered by end date', ->
+    iterationCount = 2
+    @createApp(
+      iterationCount: iterationCount
+    ).then =>
+      columns = @getColumns()
+      expect(columns[0].getValue()).toBeNull()
+      for i in [0...iterationCount]
+        expect(@iterationData[i]._ref).toEqual columns[i + 1].getValue()
+
+  it 'should not render iterations not within current project', ->
+    iterationCount = 1
+    iterationData = @createIterationData
+      iterationCount: iterationCount
+
+    now = new Date
+    iterationData.push
+      _ref: "/iteration/2"
+      _refObjectName: "Iteration 2"
+      Name: "Iteration 2"
+      ObjectID: 2,
+      Project:
+        _ref: "/project/12345"
+      StartDate: Rally.util.DateTime.toIsoString(Ext.Date.add(now, Ext.Date.DAY, 5))
+      EndDate: Rally.util.DateTime.toIsoString(Ext.Date.add(now, Ext.Date.DAY, 7))
+
+    @createApp(
+      iterationData: iterationData
+    ).then =>
+      columns = @getColumns()
+      expect(columns.length).toEqual iterationCount + 1 # backlog + 1 iteration
+      expect(columns[1].getValue()).toEqual(iterationData[0]._ref)
+
+  it 'should update the project of a card when dropping in a non-like iteration', ->
+    iterationCount = 1
+    iterationData = @createIterationData
+      iterationCount: iterationCount
+
+    userStory = @createUserStoryRecord
+      Project:
+        _ref: '/project/2'
+
+    @createApp(
+      iterationData: iterationData
+    ).then =>
+      iterationColumn = @getColumns()[1]
+      iterationColumn.fireEvent 'beforecarddroppedsave', iterationColumn,
+        getRecord: -> userStory
+
+      expect(Rally.util.Ref.getRelativeUri(userStory.get('Project'))).toEqual(Rally.util.Ref.getRelativeUri(@app.getContext().getProject()))
+
   it 'should hide only user stories when user story type checkbox is unchecked', ->
     userStoryRecord = @createUserStoryRecord Iteration: null
     @ajax.whenQuerying('userstory').respondWith([userStoryRecord.data])


Better test names.

Better test names.

--- test/test_cyclomatic_complexity.coffee
+++ test/test_cyclomatic_complexity.coffee
@@ -30,7 +30,7 @@

         topic : "x = () -> 2 if $ == true"

-        'has a complexity of two' : (source) ->
+        'increments the complexity' : (source) ->
             complexity = getComplexity(source)
             assert.equal(complexity, 2)

@@ -39,7 +39,7 @@

         topic : 'y = -> if $ then 1 else 3'

-        'has a complexity of two' : (source) ->
+        'increments the complexity' : (source) ->
             complexity = getComplexity(source)
             assert.equal(complexity, 2)


Prompt for a login at 3 and 9 classifications

--- app/controllers/classify.coffee
+++ app/controllers/classify.coffee
@@ -47,7 +47,7 @@
     unless User.current
       @classificationCount += 1

-      if @classificationCount is 3
+      if @classificationCount in [3, 9]
         @loginPrompt = new Dialog
           template: 'views/login_prompt'
           callback: -> @el().remove()


Missing imports

Missing imports

--- src/coffee/utils/handlebarsHelpers.coffee
+++ src/coffee/utils/handlebarsHelpers.coffee
@@ -1,3 +1,4 @@
+_ = require 'underscore'
 moment = require 'moment'

 module.exports = (hb) ->
@@ -52,7 +53,7 @@
       return options.inverse(this)

     if options.data
-      data = Handlebars.createFrame(options.data)
+      data = hb.createFrame(options.data)

     if context and _.isArray context
       found = _.find(context, (o) -> o[key] is value)


Remove logs

Remove logs

--- scripts/controllers/SonogramPlayer.coffee
+++ scripts/controllers/SonogramPlayer.coffee
@@ -96,7 +96,6 @@
 		@sound.pause()

 	seekStart: (e) =>
-		@log 'Player will seek'
 		e.preventDefault()

 		@wasPlaying = @playing
@@ -110,7 +109,6 @@
 	seekMove: (e) =>
 		if not @seeking then return

-		@log 'Player seeking'
 		targetX = e.pageX - @track.offset().left
 		percent = targetX / @track.width()
 		percent = Math.min(Math.max(percent, 0), 1)
@@ -121,27 +119,22 @@
 	seekEnd: =>
 		if not @seeking then return

-		@log 'Player done seeking'
 		@seeking = false
 		@el.removeClass 'seeking'

 		if @wasPlaying then @play()

 	playerLoaded: =>
-		@log 'Player loaded'

 	playerPlayed: =>
-		@log 'Player will play'
 		@playing = true
 		@el.addClass 'playing'

 	playerPaused: =>
-		@log 'Player will pause'
 		@playing = false
 		@el.removeClass 'playing'

 	playerTimeUpdated: =>
-		@log 'Player time updated'
 		percent = (@sound.position / @sound.duration) * 100

 		@seekLine.css 'left', percent + '%'
@@ -149,7 +142,6 @@
 		@thumb.css 'left', percent + '%'

 	playerFinished: =>
-		@log 'Player finished'
 		@playerPaused()

 		delay 250, =>


Fixed an error in the bearer strategy.

Fixed an error in the bearer strategy.

- It wasn't actually checking the user...
- Fixed an indentation error
- Also added a few todos.

--- src/server/common/passportConfig.coffee
+++ src/server/common/passportConfig.coffee
@@ -7,7 +7,7 @@
 messages = require "./messages.js"

 generic = messages.error.generic
-invalid = messages.invalid.credentials
+credentials = messages.invalid.credentials

 passport.serializeUser (user, done) ->
 	return done null, user.id
@@ -19,29 +19,38 @@
 passport.use new LocalStrategy (username, password, done) ->
 	db.users.findByUsername username, (err, user) ->
 		if err then return done err, false, { message: generic }
-		else if !user then return done null, false, { message: invalid }
+		else if !user then return done null, false, { message: credentials }
 		else if user.password isnt password
-			return done null, false, { message: invalid }
+			return done null, false, { message: credentials }
 		else return done null, user

 passport.use new ClientPasswordStrategy (clientID, clientSecret, done) ->
 	db.clients.findByClientID clientID, (err, client) ->
 		if err then return done err, false, { message: generic }
-		else if !client then return done null, false, { message: invalid }
+		else if !client then return done null, false, { message: credentials }
 		else if client.clientSecret isnt clientSecret
-			return done null, false, { message: invalid }
+			return done null, false, { message: credentials }
 		else return done null, client

 passport.use new BearerStrategy (accessToken, done) ->
 	db.accessTokens.find accessToken, (err, token) ->
 		if err then	return done err, false, { message: generic }
-		else if !token then return done null, false, { message: invalid }
-		else
-			db.users.find token.userID, (err, user) ->
+		else if !token then return done null, false, { message: credentials }
+		else db.users.find token.userID, (err, user) ->
 			### TODO
 			To keep this example simple, restricted scopes are not implemented
 			and this is just for illustrative purposes.
 			###
-			info =
-				scope: "*"
-			return done null, user, info
+			### TODO
+			When !user, invalidate this access token. Remember that there were
+			other security tips in the oauth2 specification.
+			###
+			### TODO
+			When a token is sent that's invalid, the oauth2 specification says that
+			there are certain messages that are supposed to be sent back. there are
+			standard steps for this. Look them up. Is passport/oauth2orize doing that
+			already, or do I have to that myself?
+			###
+			if err then return done err, false, { message: generic }
+			else if !user then return done null, false, { message: credentials }
+			else return done null, user, { scope: "*" }


Fixing an issue where some requests are converted from POST to GET

Adding an explicit contentType when converting into JSON as jquery will
convert the POST request into a GET based on some values in the input
data.

--- src/ajax_request.coffee
+++ src/ajax_request.coffee
@@ -7,6 +7,8 @@
 #         be defaulted to application/json. Anything else will be send literally.
 #   headers: An object containing header key/value pairs
 #   cache: A boolean which will turn of jquery caching if using jquery, else ignored
+#   contentType: The content type of the request data. This will be set to "application/json; charset=UTF-8" if data is an
+#                object, which is the default case.
 #   dataType: Passed straight through to jquery ajax if using jquery, else ignored
 #   ajaxDelay: Introduce a fixed delay before resolving the request. Useful for testing async scenarios
 #   maxRetries: The number of times to retry a request that failed due to connectivity issues. Default 5
@@ -24,6 +26,8 @@
   ajaxDelay = options.ajaxDelay
   maxRetries = options.maxRetries ? 5

+  contentType = options.contentType
+
   request = null

   successStatusCodes = [200, 202, 206]
@@ -31,6 +35,7 @@
   if data? && typeof data == "object" && options.skipConversion != true
     headers["Content-Type"] = "application/json"
     data = JSON.stringify(data)
+    contentType = "application/json; charset=UTF-8"

   resolveStatus = (data) ->
     if ajaxDelay?
@@ -48,10 +53,10 @@

   try
     ajaxOptions =
-      url: url
+      data: data
       headers: headers
       type: method
-      data: data
+      url: url

       success: (data) ->
         resolveStatus(data)
@@ -97,15 +102,14 @@

           rejectStatus(error)

-    if options.cache?
-      ajaxOptions.cache = options.cache

     if options.withCredentials == true
       ajaxOptions.xhrFields =
         withCredentials: true

-    if options.dataType?
-      ajaxOptions.dataType = options.dataType
+    ajaxOptions.cache = options.cache if options.cache?
+    ajaxOptions.contentType = contentType if contentType?
+    ajaxOptions.dataType = options.dataType if options.dataType?

     request = $.ajax(ajaxOptions)


forgot to remove old code

forgot to remove old code

--- frontend/frontend.coffee
+++ frontend/frontend.coffee
@@ -19,6 +19,5 @@
 	}

 $(document).ready ->
-	window.BlobBuilder ?= window.WebKitBlobBuilder  # support for Chrome
 	$('#go_button').click (event) ->
 		compile_source $('#source').val()


be more careful when connecting to local hub

--- src/smc-hub/local_hub_connection.coffee
+++ src/smc-hub/local_hub_connection.coffee
@@ -505,6 +505,15 @@
         f = (cb) =>
             if not @address?
                 cb("no address")
+                return
+            if not @address.port?
+                cb("no port")
+                return
+            if not @address.host?
+                cb("no host")
+                return
+            if not @address.secret_token?
+                cb("no secret_token")
                 return
             connect_to_a_local_hub
                 port         : @address.port


ListViewTree

ListViewTree

- Open/Close nodes on the node itself in addition
  to the open / close icon. Do this only if no
  other action is done on the node itself, like
  selecting it.

--- src/elements/ListView/ListViewTree.coffee
+++ src/elements/ListView/ListViewTree.coffee
@@ -101,6 +101,74 @@
 		if do_open
 			@root.open()

+		prep_target = (ev, info, handle) =>
+			if ev.getType() == "click"
+				CUI.DOM.setStyleOne(handle, "opacity", 0.5)
+				return true
+			if info.mousemoveEvent._done
+				# CUI.debug "event is done, not doing anything"
+				return false
+			if info.mousemoveEvent._counter % 2 == 0
+				CUI.DOM.setStyleOne(handle, "opacity", "")
+			else
+				CUI.DOM.setStyleOne(handle, "opacity", "0.5")
+			# CUI.debug "ev.mousemoveEvent._counter #{ev.mousemoveEvent._counter} #{ev.mousemoveEvent._done}"
+			info.mousemoveEvent._counter > 4
+
+		run_trigger = (ev, info, action, node) =>
+			if ev.ctrlKey() and ev.getType() == "click"
+				action_on_node(ev, info, action+"Recursively", node)
+			else
+				action_on_node(ev, info, action, node)
+			return
+
+		action_on_node = (ev, info, action, node) =>
+			console.time("#{@__uniqueId}: action on node #{action}")
+			info.mousemoveEvent?._done = true
+
+			hide_spinner = null
+			spinner_timeout = CUI.setTimeout
+				ms: 500
+				call: =>
+					node.showSpinner()
+					spinner_timeout = null
+					hide_spinner = true
+
+			@stopLayout()
+
+			ret = node[action]()
+			ret.done =>
+				switch action
+					when "open"
+						@_onOpen?(ev, node: node)
+					when "close"
+						@_onClose?(ev, node: node)
+
+			ret.always =>
+				if spinner_timeout
+					CUI.clearTimeout(spinner_timeout)
+
+				if hide_spinner
+					node.hideSpinner()
+
+				@startLayout()
+
+			return ret
+			# console.timeEnd("#{@__uniqueId}: action on node #{action}")
+
+
+		action_on_handle = (ev, info, row, node) =>
+			handle = CUI.DOM.matchSelector(row, ".cui-tree-node-handle")[0]
+			if handle.hasClass("cui-tree-node-is-closed") # and not $target.hasClass("no-children")
+				if prep_target(ev, info, handle)
+					run_trigger(ev, info, "open", node)
+					return
+			else if handle.hasClass("cui-tree-node-is-open")
+				if prep_target(ev, info, handle)
+					run_trigger(ev, info, "close", node)
+					return
+			return
+
 		# this uses the capture phase, don't interfer with the
 		# click, if we have nothing to do
 		Events.listen
@@ -112,83 +180,22 @@
 				# console.warn "ListViewTree", ev.getType(), @DOM
 				# dragover fires multiple times, so we need to prevent
 				# this node from open multiple times
-				$target = $(ev.getTarget())
-
-
-				_row = $target.closest(".cui-list-view-grid-row")
-				# _row = $target.closest(".#{@__lvClass}-row")
-				_handle = $target.closest(".cui-tree-node-handle")
-				node = DOM.data(_row, "listViewRow")
+				target = ev.getTarget()
+
+				row = CUI.DOM.closest(target, ".cui-list-view-grid-row")
+				node = DOM.data(row, "listViewRow")

 				# console.error "tree event", ev, _row, _handle, node

 				if not node or node.isLoading?()
 					return

-				prep_target = =>
-					if ev.getType() == "click"
-						_handle.css(opacity: 0.5)
-						return true
-					if info.mousemoveEvent._done
-						# CUI.debug "event is done, not doing anything"
-						return false
-					if info.mousemoveEvent._counter % 2 == 0
-						_handle.css(opacity: "")
-					else
-						_handle.css(opacity: 0.5)
-					# CUI.debug "ev.mousemoveEvent._counter #{ev.mousemoveEvent._counter} #{ev.mousemoveEvent._done}"
-					info.mousemoveEvent._counter > 4
-
-				run_trigger = (action) =>
-					if ev.ctrlKey() and ev.getType() == "click"
-						action_on_node(action+"Recursively", node)
-					else
-						action_on_node(action, node)
-					return
-
-				action_on_node = (action, _node) =>
-					console.time("#{@__uniqueId}: action on node #{action}")
-					info.mousemoveEvent?._done = true
+				if CUI.DOM.closest(target, ".cui-tree-node-handle")
 					ev.stopPropagation()
-
-					hide_spinner = null
-					spinner_timeout = CUI.setTimeout
-						ms: 500
-						call: =>
-							node.showSpinner()
-							spinner_timeout = null
-							hide_spinner = true
-
-					@stopLayout()
-
-					ret = _node[action]()
-					ret.done =>
-						switch action
-							when "open"
-								@_onOpen?(ev, node: node)
-							when "close"
-								@_onClose?(ev, node: node)
-
-					ret.always =>
-						if spinner_timeout
-							CUI.clearTimeout(spinner_timeout)
-
-						if hide_spinner
-							node.hideSpinner()
-
-						@startLayout()
-
-					return ret
-					# console.timeEnd("#{@__uniqueId}: action on node #{action}")
-
-				if _handle.hasClass("cui-tree-node-is-closed") # and not $target.hasClass("no-children")
-					if prep_target()
-						run_trigger("open")
-						return
-				else if _handle.hasClass("cui-tree-node-is-open")
-					if prep_target()
-						run_trigger("close")
-						return
+					action_on_handle(ev, info, row, node)
+
+				return
+

 		# this is the bubble phase, note that the click
 		# is stopped here by "select" and "deselect" below
@@ -199,10 +206,9 @@
 				if ev.hasModifierKey(true)
 					return

-				$target = $(ev.getTarget())
-				_row = $target.closest(".cui-list-view-grid-row")
-				# _row = $target.closest(".#{@__lvClass}-row")
-				node = DOM.data(_row, "listViewRow")
+				target = ev.getTarget()
+				row = CUI.DOM.closest(target, ".cui-list-view-grid-row")
+				node = DOM.data(row, "listViewRow")

 				if not node or node.isLoading?()
 					return
@@ -210,11 +216,21 @@
 				# FIXME: This code needs to go away and use the select/deselect mechanism
 				# of ListView
 				#
-
 				if node.isSelected?()
-					node.deselect?(ev)
+					action = "deselect"
 				else
-					node.select?(ev)
+					action = "select"
+
+				ret = node[action]?(ev)
+
+				# console.error "node action", action, ret
+
+				if isPromise(ret)
+					ret.fail =>
+						# if the node did not select, we try the handle
+						ev.stopPropagation()
+						action_on_handle(ev, info, row, node)
+
 				return

 		if @_no_hierarchy


Support older style instagram embeds.

Support older style instagram embeds.

--- app/assets/javascripts/_site.js.coffee
+++ app/assets/javascripts/_site.js.coffee
@@ -371,7 +371,7 @@
         url = urlFinder(item)
         if feedbin.embeds["#{url}"]
           item.replaceWith(feedbin.embeds["#{url}"])
-        else
+        else if url
           id = feedbin.randomNumber()
           item.attr("id", id)
           $.get(embed_url, {url: url, dom_id: id}).fail ->
@@ -392,7 +392,7 @@
     items = $('blockquote.instagram-media')

     urlFinder = (item) ->
-      item.data("instgrmPermalink")
+      item.data("instgrmPermalink") || $("a", item).last().attr("href")

     feedbin.embed(items, feedbin.data.instagram_embed_path, urlFinder)


Enable back button on mobile.

Enable back button on mobile.

--- app/assets/javascripts/_site.js.coffee
+++ app/assets/javascripts/_site.js.coffee
@@ -4,6 +4,7 @@

   messageTimeout: null
   swipe: false
+  panel: 1

   drawBarCharts: ->
     $('[data-behavior~=line_graph]').each ()->
@@ -21,17 +22,30 @@
   showFeedList: ->
     $('[data-behavior~=feeds_target]').addClass('in')

+  mobileView: ->
+    if $(window).width() <= 550
+      true
+    else
+      false
+
   showPanel: (panel, state = true) ->
+    feedbin.panel = panel
     if panel == 1
+      if feedbin.mobileView()
+        window.history.replaceState({panel: 1}, document.title, "/");
       $('body').addClass('nothing-selected').removeClass('feed-selected entry-selected')
       if feedbin.swipe
         $('.app-wrap').animate({scrollLeft: 0}, {duration: 250})
     else if panel == 2
+      if state && feedbin.mobileView()
+        window.history.pushState({panel: 2}, document.title, "/");
       $('body').addClass('feed-selected').removeClass('nothing-selected entry-selected')
       if feedbin.swipe
         offset = $('.entries-column')[0].offsetLeft
         $('.app-wrap').animate({scrollLeft: offset}, {duration: 250})
     else if panel == 3
+      if state && feedbin.mobileView()
+        window.history.pushState({panel: 3}, document.title, "/");
       $('body').addClass('entry-selected').removeClass('nothing-selected feed-selected')
       if feedbin.swipe
         offset = $('.entry-column')[0].offsetLeft
@@ -812,11 +826,9 @@

     state: ->
       $(window).on 'popstate', (event) ->
-        original = event.originalEvent
-        if original.state?
-          feedbin.showPanel(original.state.panel, false)
-        else
-          feedbin.showPanel(1)
+        if feedbin.panel > 1
+          newPanel = feedbin.panel - 1
+          feedbin.showPanel(newPanel, false)

     renameFeed: ->
       $(document).on 'dblclick', '[data-behavior~=renamable]', (event) ->


Bug fix

Bug fix

--- app/assets/javascripts/nodes.js.coffee
+++ app/assets/javascripts/nodes.js.coffee
@@ -28,7 +28,6 @@
       constructor: ->
         @characters = characters
         @construct_list()
-        @nodes_by_id = nodes_by_id
         @updated_at = characters_updated_at
         setInterval( =>
           @update_from_server()
@@ -45,8 +44,9 @@
           url: "/nodes"
           dataType: "json"
           success: (data) =>
-            @update(data.characters, data.nodes_by_id, data.characters_updated_at)
-      update: (characters, nodes_by_id, characters_updated_at)->
+            nodes_by_id = data.nodes_by_id
+            @update(data.characters, data.characters_updated_at)
+      update: (characters, characters_updated_at)->
         console.log('updated : ', @characters, characters)
         @characters = characters
         if characters_updated_at != @updated_at
@@ -83,7 +83,7 @@
         @update_nodes()
         @destroy_node_obj()
         @create_node_obj()
-        alert("character #{ch.id} updated")
+        console.log("character #{ch.id} updated")
       update_nodes: ->
         @nodes = []
         for node_id in @character.node_ids


cleanup

cleanup

--- client/components/layout/client.coffee
+++ client/components/layout/client.coffee
@@ -11,7 +11,6 @@
 sd = require('sharify').data
 Modal = require 'simple-modal'
 imagesLoaded = require 'imagesloaded'
-{ openErrorModal } = require '../error/client.coffee'

 # Add jquery plugins
 require 'jquery-autosize'


Fix view reize based on keyboard

Fix view reize based on keyboard

--- client/lib/cordova/keyboard-fix.coffee
+++ client/lib/cordova/keyboard-fix.coffee
@@ -1,5 +1,5 @@
 if Meteor.isCordova
-	window.addEventListener 'deviceready', ->
+	document.addEventListener 'deviceready', ->
 		cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
 		cordova.plugins.Keyboard.disableScroll(true);


Tests: Test helper fixes for hubspot changes.

--- client/test/lib/helpers/helpers.coffee
+++ client/test/lib/helpers/helpers.coffee
@@ -3,6 +3,7 @@
 register = require '../register/register.js'
 faker    = require 'faker'
 assert   = require 'assert'
+HUBSPOT  = yes

 activitySelector = '[testpath=activity-list] section:nth-of-type(1) [testpath=ActivityListItemView]:first-child'
@@ -11,7 +12,11 @@

   beginTest: (browser, user) ->

-    url   = @getUrl()
+    url = @getUrl()
+
+    if HUBSPOT
+       url = "#{url}/Login"
+
     user ?= utils.getUser()

     browser.url url
@@ -29,6 +34,10 @@
   assertNotLoggedIn: (browser, user) ->

     url = @getUrl()
+
+    if HUBSPOT
+       url = "#{url}/Login"
+
     browser.url(url)
     browser.maximizeWindow()

@@ -44,9 +53,12 @@

   attemptLogin: (browser, user) ->

-    browser
-      .waitForElementVisible  '[testpath=main-header]', 50000
-      .click                  'nav:not(.mobile-menu) [testpath=login-link]'
+    unless HUBSPOT
+      browser
+        .waitForElementVisible  '[testpath=main-header]', 50000
+        .click                  'nav:not(.mobile-menu) [testpath=login-link]'
+
+    browser
       .waitForElementVisible  '[testpath=login-container]', 50000
       .setValue               '[testpath=login-form-username]', user.username
       .setValue               '[testpath=login-form-password]', user.password
@@ -78,26 +90,38 @@

   attemptEnterEmailAndPasswordOnRegister: (browser, user) ->

-    browser
-      .url                    @getUrl()
-      .waitForElementVisible  '[testpath=main-header]', 30000
-      .setValue               '[testpath=register-form-email]', user.email
-      .setValue               'input[name=password]', user.password
-      .click                  '[testpath=signup-button]'
+    url = @getUrl()
+
+    if HUBSPOT
+      url = "#{url}/Register"
+
+    browser.url url
+
+    unless HUBSPOT
+      browser.waitForElementVisible  '[testpath=main-header]', 30000
+
+    browser.setValue    '[testpath=register-form-email]', user.email
+
+    if HUBSPOT
+      browser.setValue  '.login-form .password input[name=password]', user.password
+    else
+      browser.setValue  'input[name=password]', user.password
+
+    browser.click       '[testpath=signup-button]'

   attemptEnterUsernameOnRegister: (browser, user) ->

     modalSelector  = '.extra-info.password'
-    buttonSelector = 'button[type=submit]'
+    buttonSelector = "#{modalSelector} button[type=submit]"

     browser.waitForElementVisible modalSelector, 30000

     if user.gravatar
       browser
-        .assert.valueContains 'input[name=username]',  'kodingqa'
-        .assert.valueContains 'input[name=firstName]', 'Koding'
-        .assert.valueContains 'input[name=lastName]',  'Testuser'
+        .assert.valueContains "#{modalSelector} input[name=username]",  'kodingqa'
+        .assert.valueContains "#{modalSelector} input[name=firstName]", 'Koding'
+        .assert.valueContains "#{modalSelector} input[name=lastName]",  'Testuser'
     else
       browser
         .setValue '[testpath=register-form-username]', user.username
@@ -115,7 +139,10 @@
     @attemptEnterEmailAndPasswordOnRegister(browser, user)
     @attemptEnterUsernameOnRegister(browser, user)

-    browser.waitForElementVisible '[testpath=AvatarAreaIconLink]', 50000 # Assertion
+    unless HUBSPOT
+      browser.waitForElementVisible '[testpath=main-header]', 50000 # Assertion
+    else
+      browser.waitForElementVisible '[testpath=AvatarAreaIconLink]', 50000 # Assertion

   postActivity: (browser, shouldBeginTest = yes) ->


Do not save if already saving

Do not save if already saving

--- components/add_block/client/view.coffee
+++ components/add_block/client/view.coffee
@@ -12,6 +12,9 @@
     'keypress': 'onKeypress'
     'click .js-choose': 'choose'
     'click .js-button': 'save'
+
+  initialize: ->
+    @state = new Backbone.Model saving: false

   onInput: (e) ->
     @checkInput()
@@ -58,10 +61,13 @@
     false

   save: ->
+    return false if @state.get('saving')
+
     val = @dom.input.val().trim()

     return if val is ''

+    @state.set saving: true
     @dom.button.text 'Adding'

     attrs = if isURL val
@@ -77,11 +83,13 @@
         @dom.button.text 'Added'
         @dom.input.val ''
         @dom.input.focus()
+        @state.set saving: false
         @checkInput()
         setTimeout (=> @dom.button.text 'Add block'), 2000

       error: (_m, e) =>
         console.error e
+        @state.set saving: false
         @dom.button.text 'Error'
         setTimeout (=> @dom.button.text 'Add block'), 2000


Fix obsolete ObserveJS call

Fix obsolete ObserveJS call

--- lib/ecrire/app/assets/javascripts/admin/posts/header.coffee
+++ lib/ecrire/app/assets/javascripts/admin/posts/header.coffee
@@ -63,7 +63,7 @@
     @hide(@template('div.status.uploading'))
     @show(@template('div.error.status'))
     ul = @template('div.error.status').querySelector('ul')
-    @on 'click', @template('div.error.status').querySelector('button'), @clear
+    @on 'click', @element().querySelector('div.error.status button'), @clear
     for error in errors
       ul.insertAdjacentHTML('beforeend', "<li>#{error}</li>")


vms: minor typo fix

vms: minor typo fix

--- client/landing/app/Applications/Account.kdapplication/account/accSettingsPaymentMethods.coffee
+++ client/landing/app/Applications/Account.kdapplication/account/accSettingsPaymentMethods.coffee
@@ -169,7 +169,7 @@
           fields                :
             "intro"             :
               itemClass         : KDCustomHTMLView
-              partial           : "
You can use pre-filled credit card informationbelow to buy VM's during beta.
"
+              partial           : "
You can use pre-filled credit card information below to buy VM's during beta.
"
             cardFirstName       :
               label             : "Name"
               name              : "cardFirstName"


Center using outerHeight rather than height

--- components/zig_zag_banner/index.coffee
+++ components/zig_zag_banner/index.coffee
@@ -43,7 +43,7 @@

   verticallyCenter: ->
     existingMargin  = parseInt(@$el.css 'marginTop')
-    offset          = @$target.height() / 2
+    offset          = @$target.outerHeight() / 2
     newMargin       = offset + existingMargin

     @$el.css marginTop: newMargin


Visual/edit modes: fix bug entering visual mode from edit mode.

--- content_scripts/mode_visual_edit.coffee
+++ content_scripts/mode_visual_edit.coffee
@@ -393,14 +393,15 @@
       exitOnEscape: true
     super extend defaults, options

-    if @options.parentMode and @selection.type == "Caret"
-      # We're being called from edit mode, so establish an intial visible selection.
-      @extendByOneCharacter(forward) or @extendByOneCharacter backward
-    else if @selection.type in [ "None", "Caret" ]
-      unless @options.oneMovementOnly or options.immediateMovement
-        HUD.showForDuration "No selection, entering caret mode first..", 2500
-        @changeMode CaretMode
-        return
+    unless @options.oneMovementOnly or options.immediateMovement
+      if @options.parentMode and @selection.type == "Caret"
+        # We're being called from edit mode, so establish an intial visible selection.
+        @extendByOneCharacter(forward) or @extendByOneCharacter backward
+      else if @selection.type in [ "None", "Caret" ]
+        unless @options.oneMovementOnly or options.immediateMovement
+          HUD.showForDuration "No selection, entering caret mode first..", 2500
+          @changeMode CaretMode
+          return

     # Yank on <Enter>.
     @push


Assign the whole metadata

Assign the whole metadata

--- src/videojs.chromecast-component.coffee
+++ src/videojs.chromecast-component.coffee
@@ -34,15 +34,12 @@

     vjs.log "Cast APIs are available"

-    # Initialize the SessionRequest with the given App ID and the apiConfig.
-    sessionRequest = if @settings.appId
-      new chrome.cast.SessionRequest(@settings.appId)
-    else
-      new chrome.cast.SessionRequest(chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID)
+    appId = @settings.appId or chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID
+    sessionRequest = new chrome.cast.SessionRequest(appId)
+
     apiConfig = new chrome.cast.ApiConfig(sessionRequest, @sessionJoinedListener, @receiverListener.bind(this))

-    # Initialize Chromecast
-    chrome.cast.initialize(apiConfig, @onInitSuccess.bind(this), @castError)
+    chrome.cast.initialize apiConfig, @onInitSuccess.bind(this), @castError

   sessionJoinedListener: (session) ->
     console.log "Session joined"
@@ -69,12 +66,13 @@
     @apiSession = session
     @addClass "connected"

-    mediaInfo = new chrome.cast.media.MediaInfo(@player_.currentSrc(), @player_.currentType());
+    mediaInfo = new chrome.cast.media.MediaInfo @player_.currentSrc(), @player_.currentType()

     if @settings.metadata
-      mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
-      mediaInfo.metadata.title = @settings.metadata.title if @settings.metadata.title
-      mediaInfo.metadata.subtitle = @settings.metadata.subtitle if @settings.metadata.subtitle
+      mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata()
+
+      for key, value of @settings.metadata
+        mediaInfo.metadata[key] = value

       if @player_.options_.poster
         image = new chrome.cast.Image(@player_.options_.poster)


Refine stss

Refine stss

--- mp4.coffee
+++ mp4.coffee
@@ -840,7 +840,8 @@
     obj.entries = @entries
     return obj

-# stss
+# stss: random access points
+# If stss is not present, every sample is a random access point.
 class SyncSampleBox extends Box
   read: (buf) ->
     bits = new Bits buf
@@ -848,8 +849,13 @@

     @entryCount = bits.read_uint32()
     @sampleNumbers = []
+    lastSampleNumber = -1
     for i in [0...@entryCount]
-      @sampleNumbers.push bits.read_uint32()
+      sampleNumber = bits.read_uint32()
+      if sampleNumber < lastSampleNumber
+        throw new Error "stss: sample number must be in increasing order: #{sampleNumber} < #{lastSampleNumber}"
+      lastSampleNumber = sampleNumber
+      @sampleNumbers.push sampleNumber
     return

   getDetails: (detailLevel) ->


Handle backslashes at the end of heredocs

--- lexer.coffee
+++ lexer.coffee
@@ -190,13 +190,13 @@
       when "'"
         return 0 unless match = SIMPLESTR.exec @chunk
         string = match[0]
-        @token 'STRING', @removeNewlines(string), 0, string.length
+        @token 'STRING', @escapeLines(string), 0, string.length
       when '"'
         return 0 unless string = @balancedString @chunk, '"'
         if 0 < string.indexOf '#{', 1
           @interpolateString string[1...-1], strOffset: 1, lexedLength: string.length
         else
-          @token 'STRING', @removeNewlines(string), 0, string.length
+          @token 'STRING', @escapeLines(string), 0, string.length
       else
         return 0
     if octalEsc = /^(?:\\.|[^\\])*\\(?:0[0-7]|[1-7])/.test string
@@ -209,7 +209,9 @@
     return 0 unless match = HEREDOC.exec @chunk
     heredoc = match[0]
     quote = heredoc.charAt 0
-    doc = @sanitizeHeredoc match[2], quote: quote, indent: null
+    # Trim last newline if it's not escaped
+    trimmed = match[2].replace /(([^\\]|\\\\)\s*)\n[^\n\S]*$/, '$1'
+    doc = @sanitizeHeredoc trimmed, quote: quote, indent: null
     if quote is '"' and 0 <= doc.indexOf '#{'
       @interpolateString doc, heredoc: yes, strOffset: 3, lexedLength: heredoc.length
     else
@@ -684,11 +686,6 @@
     @tag() in ['\\', '.', '?.', '?::', 'UNARY', 'MATH', '+', '-', 'SHIFT', 'RELATION'
                'COMPARE', 'LOGIC', 'THROW', 'EXTENDS']

-  # Remove newlines from beginning and end of string literals.
-  # `str` includes quotes.
-  removeNewlines: (str) ->
-    @escapeLines str.replace(/^(.)\s*\n\s*/, '$1').replace(/\s*\n\s*(.)$/, '$1')
-
   # Converts newlines for string literals.
   escapeLines: (str, heredoc) ->
     # Ignore escaped backslashes and remove escaped newlines
@@ -697,7 +694,10 @@
     if heredoc
       str.replace MULTILINER, '\\n'
     else
-      str.replace /\s*\n\s*/g, ' '
+      # Trim leading and trailing whitespace, string includes quotes
+      str.replace(/^(.)\s*\n\s*/, '$1')
+         .replace(/\s*\n\s*(.)$/, '$1')
+         .replace(/\s*\n\s*/g, ' ')

   # Constructs a string token by escaping quotes and newlines.
   makeString: (body, quote, heredoc) ->
@@ -779,7 +779,7 @@
   ^ \d*\.?\d+ (?:e[+-]?\d+)?  # decimal
 ///i

-HEREDOC    = /// ^ ("""|''') ([\s\S]*?) (?:\n[^\n\S]*)? \1 ///
+HEREDOC    = /// ^ ("""|''') (( [\s\S]*? ([^\\]|\\\\) )?) \1 ///

 OPERATOR   = /// ^ (
   ?: [-=]>             # function
@@ -793,7 +793,7 @@

 WHITESPACE = /^[^\n\S]+/

-COMMENT    = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)$)|^(?:\s*#(?!##[^#]).*)+/
+COMMENT    = /^###([^#][\s\S]*?)(?:###[^\n\S]*|###$)|^(?:\s*#(?!##[^#]).*)+/

 CODE       = /^[-=]>/


Removed dead code

Removed dead code

--- core/app/backbone/models/channel.coffee
+++ core/app/backbone/models/channel.coffee
@@ -34,16 +34,6 @@
       channel: this

   topicUrl: -> "/t/#{@get('slug_title')}"
-
-  getOwnContainingChannels: (eventAggregator) ->
-    containing_channel_ids = @get("containing_channel_ids") ? []
-
-    col = new OwnChannelCollection currentUser.channels.channelArrayForIds(containing_channel_ids)
-
-    eventAggregator.listenTo currentUser.channels, 'add remove reset', ->
-      col.reset currentUser.channels.channelArrayForIds(containing_channel_ids)
-
-    col

   url: ->
     if @collection


Search mixing when searching for helpers.

--- lib.coffee
+++ lib.coffee
@@ -39,10 +39,23 @@
     templateInstance.get 'component'

   # Component.
-  if component and name of component
-    return _.bind component[name], component
+  if component
+    if name of component
+      return wrapHelper component, component[name]
+
+    # We manually go over _mixins instead of using getMixin because we want to
+    # distinguish between attribute existing on a mixin with the undefined value,
+    # and no attribute existing with a given name at all on any mixin.
+    for mixin in component._mixins when name of mixin
+      return wrapHelper component, mixin[name]

   null
+
+wrapHelper = (component, helper) ->
+  if _.isFunction helper
+    _.bind helper, component
+  else
+    helper

 viewToTemplateInstance = (view) ->
   # We skip contentBlock views which are injected by Meteor when using
@@ -224,6 +237,14 @@
         return mixin[attributeName]

     # TODO: Should we throw an error here? Something like calling a function which does not exist?
+    return
+
+  getFirstMixin: (attributeName) ->
+    assert @_mixins
+
+    for mixin in @_mixins when attributeName of mixin
+      return mixin[attributeName]
+
     return

   # Calls all mixins in order and gives initial arguments to the first, and then results of that


delegate action attr for fs-form-for

delegate action attr for fs-form-for

--- src/fs/fsFormFor.coffee
+++ src/fs/fsFormFor.coffee
@@ -24,6 +24,7 @@
   restrict: 'AE'
   template: (el, attrs) ->
     modelName = el.attr("model")
+    action = el.attr("action")

     inputReplacer = () ->
       input = $(this)
@@ -81,7 +82,7 @@

     """
-    <form name='form' class='form-horizontal' novalidate>
+    <form name='form' class='form-horizontal' action='#{action}' novalidate>
       #{html}
     </form>
     """


HR size for new VM new disks

HR size for new VM new disks

--- app/modules/new-vm/index.coffee
+++ app/modules/new-vm/index.coffee
@@ -187,6 +187,7 @@
       for VDI in VDIs
         VDI.id = VDI_id++
         VDI.SR or= default_SR
+        VDI.size = bytesToSizeFilter VDI.size
       # if the template is labeled CoreOS
       # we'll use config drive setup
       if template.name_label == 'CoreOS'


Size unit fix.

Size unit fix.

--- app/modules/new-vm/index.coffee
+++ app/modules/new-vm/index.coffee
@@ -199,7 +199,7 @@
     $scope.memory = null
     $scope.memoryValue = null
     $scope.units = ['MiB', 'GiB', 'TiB']
-    $scope.memoryUnit = $scope.units[0]
+    $scope.memoryUnit = $scope.units[1]
     $scope.name_description = 'Created by XO'
     $scope.name_label = ''
     $scope.template = ''


Fix classification creation

Fix classification creation

--- app/pages/project/classify.cjsx
+++ app/pages/project/classify.cjsx
@@ -74,7 +74,7 @@

   createNewClassification: (project, workflowID) ->
     workflow = @getWorkflow project, workflowID
-    subject = workflow.then =>
+    subject = workflow.then (workflow) =>
       @getNextSubject project, workflow

     Promise.all([workflow, subject]).then ([workflow, subject]) ->
@@ -111,7 +111,7 @@

     # Take the next subject in the list, if there are any.
     unless upcomingSubjects.forWorkflow[workflow.id].length is 0
-      subject = upcomingSubjects.forWorkflow[workflow.id].shift()
+      subject = Promise.resolve upcomingSubjects.forWorkflow[workflow.id].shift()

     # If there aren't any left (or there weren't any to begin with), refill the list.
     if upcomingSubjects.forWorkflow[workflow.id].length is 0


Fixed the build files combining order.

Fixed the build files combining order.

--- build/build_utils.coffee
+++ build/build_utils.coffee
@@ -57,10 +57,9 @@
       for file, index in files then do (file, index) ->
         fs.readFile "./src/#{file}", 'utf8', (err, fileContent) ->
           self.error_handler err
-          content[content.length] = fileContent
+          content[index] = fileContent
           contentAdded++

-          if contentAdded is files.length
-            callback content
+          callback(content) if contentAdded is files.length

 global.BuildUtils = BuildUtils


Turn off atom-beautify analytics

Turn off atom-beautify analytics

--- atom/.atom/config.cson
+++ atom/.atom/config.cson
@@ -1,6 +1,6 @@
 "*":
   "atom-beautify":
-    _analyticsUserId: "019c06e6-ef8e-4260-823a-90f039b27d0e"
+    analytics: false
   "autocomplete-plus":
     autoActivationDelay: 150
   core:


CSVData.parse: Only accept quotechar at the beginning of a column, ignore space outside quotes.

--- src/base/CSVData.coffee
+++ src/base/CSVData.coffee
@@ -142,6 +142,7 @@

 		lines = 0

+		space_chars = [' ']
 		auto_quotechars = ['"',"'"]
 		auto_delimiters = [",",";","\t"]
 		# space_chars = [" "]
@@ -182,6 +183,10 @@
 				char = text.charAt(idx)
 				# console.debug "char:", idx, char, text.charCodeAt(idx)

+				if not in_quotes and char in space_chars
+					idx = idx + 1
+					continue
+
 				if quotechar == null and char in auto_quotechars
 					quotechar = char
 					# console.info("CSVData.parse: detected quotechar:", quotechar)
@@ -190,7 +195,7 @@
 					delimiter = char
 					# console.info("CSVData.parse: detected delimiter:", delimiter)

-				if char == quotechar
+				if char == quotechar and (column_chars.length == 0 or in_quotes)
 					if in_quotes
 						if text[idx+1] == quotechar
 							column_chars.push(char)


more forgiving for geoip

more forgiving for geoip

--- src/torconsensus.iced
+++ src/torconsensus.iced
@@ -31,7 +31,10 @@
     @origDateString = components[4] + ' ' + components[5]
     @IP = components[6]
     @geo = geoip.lookup(@IP)
-    @geoString = @geo.city + ", " + @geo.country
+    if @geo?
+        @geoString = @geo.city + ', ' + @geo.country
+    else
+        @geoString = ''
     @onionPort = components[7]
     @directoryPort = components[8]


Begin refactoring

Begin refactoring

--- src/translator.coffee
+++ src/translator.coffee
@@ -65,20 +65,21 @@
 # ###################################################################################################

 do ()->
+  literally_translated_bin_op_list = "+ - * / % += -= *= /= %= = == != < <= > >=".split ' '
   holder = new bin_op_translator_holder
-  for v in bin_op_list = "+ - * / ** // % %%".split ' '
+  for v in literally_translated_bin_op_list
     holder.op_list[v]  = new bin_op_translator_framework "($1$op$2)"
-    v = v+"="
-    holder.op_list[v]  = new bin_op_translator_framework "($1$op$2)"
-
-  for v in bin_op_list = "= == != < <= > >=".split ' '
-    holder.op_list[v]  = new bin_op_translator_framework "($1$op$2)"
+  #   v = v+"="
+  #   holder.op_list[v]  = new bin_op_translator_framework "($1$op$2)"
+
+  # for v in bin_op_list = "= == != < <= > >=".split ' '
+  #   holder.op_list[v]  = new bin_op_translator_framework "($1$op$2)"
   trans.translator_hash['bin_op'] = translate:(ctx, node)->
     op = node.value_array[1].value_view
     # PORTING BUG gram2
     node.value_array[1].value = node.value_array[1].value_view

-    if op in "** // %% and or | **= //= %%= and= or=".split " "
+    if op not in literally_translated_bin_op_list
       [a,_skip,b] = node.value_array
       a_tr = ctx.translate a
       b_tr = ctx.translate b


not using zone time function

not using zone time function

--- src/helpers/time.coffee
+++ src/helpers/time.coffee
@@ -70,10 +70,4 @@
     courseTimezone = CourseStore.getTimezone(courseId)
     TimeHelper.getLocalTimezone().indexOf(courseTimezone) > -1

-  zoneTwix: (twix, zoneName) ->
-    twix.start.tz(zoneName)
-    twix.end.tz(zoneName)
-
-    twix
-
 module.exports = TimeHelper


Add missing rootAtomFolder var

Add missing rootAtomFolder var

--- src/browser/main.coffee
+++ src/browser/main.coffee
@@ -84,6 +84,7 @@
     if SquirrelUpdate.existsSync()
       atomPath = path.join(process.env.LOCALAPPDATA, 'atom').toLowerCase()
       if __dirname.toLowerCase().indexOf(atomPath) isnt 0
+        rootAtomFolder = path.resolve(process.execPath, '..', '..')
         process.env.ATOM_HOME = path.join(rootAtomFolder, '.atom')
         return


Reinstate vomnibar from within help dialog.

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -119,12 +119,12 @@
         You have asked Vimium to perform #{count} repetitions of the command: #{registryEntry.description}.\n
         Are you sure you want to continue?"""

-    if registryEntry.topFrame and window.isVimiumUIComponent? and window.isVimiumUIComponent
-      # We cannot use "topFrame" commands, most notably the Vomnibar, from within a UI component.
-      HUD.showForDuration "#{registryEntry.command} cannot be used here.", 2000
-    else if registryEntry.topFrame
+    if registryEntry.topFrame
+      # The Vomnibar (a top-frame command) cannot coexist with the help dialog (it causes focus issues).
+      sourceFrameId = if HelpDialog.isShowing() and window.isVimiumUIComponent then 0 else frameId
+      HelpDialog.toggle() if HelpDialog.isShowing()
       chrome.runtime.sendMessage
-        handler: "sendMessageToFrames", message: {name: "runInTopFrame", sourceFrameId: frameId, registryEntry}
+        handler: "sendMessageToFrames", message: {name: "runInTopFrame", sourceFrameId, registryEntry}
     else if registryEntry.background
       chrome.runtime.sendMessage {handler: "runBackgroundCommand", registryEntry, count}
     else


close the panel

close the panel

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -26,6 +26,8 @@
     invisibles: {}
     showIndentGuide: true
     softWrapAtPreferredLineLength: true
+  "go-plus":
+    panelDisplayMode: "closed"
   "linter-eslint":
     useGlobalEslint: true
   "release-notes":


update atom

update atom

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -16,10 +16,6 @@
       "vendor"
     ]
     telemetryConsent: "no"
-    themes: [
-      "unity-ui"
-      "glacier-syntax"
-    ]
   editor:
     fontFamily: "Menlo"
     fontSize: 15
@@ -41,3 +37,6 @@
     ]
   welcome:
     showOnStartup: false
+".js.jsx.react.source":
+  editor:
+    autoIndent: true


[LOCALE] Throw error on line not found

[LOCALE] Throw error on line not found

--- src/coffee/locale.coffee
+++ src/coffee/locale.coffee
@@ -23,4 +23,8 @@
     # split lineID in format "mkX_dY_ZZ" into "mkX/dY/ZZ" the key path to access the dictionary value
     # (or _tY_ for a text file content)
     [missionID, textNo, lineNo] = lineID.split '_'
-    @dialogueLines[missionID][textNo][lineNo]
+    line = @dialogueLines[missionID][textNo][lineNo]
+    if not line?
+      throw new Error "Locale for lineID #{lineID} not found"
+    line
+


added coffeelint

added coffeelint

--- app/templates/_gruntfile.coffee
+++ app/templates/_gruntfile.coffee
@@ -12,7 +12,7 @@

   # package options
   packageJson = grunt.file.readJSON('package.json')
-
+
   # configurable paths
   yeomanConfig =
     appName: "<%= appName %>"
@@ -96,6 +96,7 @@
         ]

+    # lint coffee script
     coffeelint:
       app: ['<%%= yeoman.app %>/scripts/{,*/}*.coffee', 'gruntfile.coffee']
       options:
@@ -107,7 +108,7 @@
           level: 'error'
         space_operators:
           level: 'error'
-
+

     jshint:
       options:
@@ -304,7 +305,7 @@
     cssmin:
       options:
         report: 'gzip'
-        banner: '/*! Build <%%= pkg.name %> - v<%%= pkg.version %> - <%%= grunt.template.today("yyyy-mm-dd") %> */'
+        banner: '/*! Build <%%= pkg.name %> - v<%%= pkg.version %> - <%%= grunt.template.today("yyyy-mm-dd") %> */'

       dist:
         files:
@@ -387,6 +388,7 @@
   # $ grunt server
   grunt.registerTask "server", [
     "clean:dist"
+    "coffeelint"
     "concurrent:server"
     "concat:server"
     "autoprefixer:server"
@@ -399,6 +401,7 @@
   # $ grunt build
   grunt.registerTask "build", [
     "clean:dist"
+    "coffeelint"
     "concurrent:dist"
     "uglify:dist"
     "autoprefixer:dist"


AceView: add tabView check since we allow to use AceViews without a tabView

--- client/ace/lib/aceview.coffee
+++ client/ace/lib/aceview.coffee
@@ -71,6 +71,8 @@

   forEachPaneByFile: (path, callback) ->
+
+    return  unless @getDelegate().tabView

     { handles, panes } = @getDelegate().tabView


Closes #774; Disable TimeSync logs

Closes #774; Disable TimeSync logs

--- client/startup/startup.coffee
+++ client/startup/startup.coffee
@@ -1,4 +1,6 @@
 Meteor.startup ->
+	TimeSync.loggingEnabled = false
+
 	UserPresence.awayTime = 300000
 	UserPresence.start()
 	Meteor.subscribe("activeUsers")


improved atom confgi

improved atom confgi

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -5,8 +5,10 @@
     fontSize: 15
     showIndentGuide: true
     showInvisibles: true
+    scrollPastEnd: true
   core:
     hideGitIgnoredFiles: true
+    autoHideMenuBar: true
   "exception-reporting":
     userId: "eb68b94c-a76b-64f4-46e7-bd087cf1c98f"
   welcome:


fucking atom

fucking atom

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,11 +1,12 @@
 "*":
-  editor:
-    showIndentGuide: true
-    fontFamily: "Menlo"
-    invisibles: {}
-    fontSize: 15
-    softWrapAtPreferredLineLength: true
   core:
+    disabledPackages: [
+      "background-tips"
+      "exception-reporting"
+      "metrics"
+    ]
+    followSymlinks: false
+    hideGitIgnoredFiles: true
     ignoredNames: [
       ".bundle"
       ".git"
@@ -18,13 +19,15 @@
       "unity-ui"
       "glacier-syntax"
     ]
-    hideGitIgnoredFiles: true
-    disabledPackages: [
-      "background-tips"
-      "exception-reporting"
-      "metrics"
-    ]
-    followSymlinks: false
+  editor:
+    fontFamily: "Menlo"
+    invisibles: {}
+    showIndentGuide: true
+    softWrapAtPreferredLineLength: true
+  "go-plus":
+    goPath: "/Users/holman/Code/go"
+  "release-notes":
+    viewedVersion: "0.89.0"
   "spell-check":
     grammars: [
       "text.plain"
@@ -33,7 +36,3 @@
     ]
   welcome:
     showOnStartup: false
-  "release-notes":
-    viewedVersion: "0.89.0"
-  "go-plus":
-    goPath: "/Users/holman/Code/go"


Fix path to my more typical username - aross

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -25,7 +25,7 @@
     showIndentGuide: true
     softWrapAtPreferredLineLength: true
   "go-plus":
-    goPath: "/Users/holman/Code/go"
+    goPath: "/Users/aross/Projects/go"
   "release-notes":
     viewedVersion: "0.89.0"
   "spell-check":


Bump the config stuff

Bump the config stuff

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,35 +1,36 @@
-'global':
-  'editor':
-    'showIndentGuide': true
-    'fontFamily': 'Menlo'
-    'fontSize': 15
-    'invisibles': {}
-  'core':
-    'ignoredNames': [
-      '.bundle'
-      '.git'
-      'log'
-      'repositories'
-      'tmp'
-      'vendor'
+"*":
+  editor:
+    showIndentGuide: true
+    fontFamily: "Menlo"
+    invisibles: {}
+    fontSize: 15
+    softWrapAtPreferredLineLength: true
+  core:
+    ignoredNames: [
+      ".bundle"
+      ".git"
+      "log"
+      "repositories"
+      "tmp"
+      "vendor"
     ]
-    'themes': [
-      'unity-ui'
-      'glacier-syntax'
+    themes: [
+      "unity-ui"
+      "glacier-syntax"
     ]
-    'hideGitIgnoredFiles': true
-    'disabledPackages': [
-      'background-tips'
-      'exception-reporting'
-      'metrics'
+    hideGitIgnoredFiles: true
+    disabledPackages: [
+      "background-tips"
+      "exception-reporting"
+      "metrics"
     ]
-  'spell-check':
-    'grammars': [
-      'text.plain'
-      'source.gfm'
-      'text.git-commit'
+  "spell-check":
+    grammars: [
+      "text.plain"
+      "source.gfm"
+      "text.git-commit"
     ]
-  'welcome':
-    'showOnStartup': false
-  'release-notes':
-    'viewedVersion': '0.89.0'
+  welcome:
+    showOnStartup: false
+  "release-notes":
+    viewedVersion: "0.89.0"


VM changes

VM changes

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,35 +1,41 @@
-'editor':
-  'showIndentGuide': true
-  'fontFamily': 'Menlo'
-  'fontSize': 15
-'core':
-  'excludeVcsIgnoredPaths': true
-  'ignoredNames': [
-    '.bundle'
-    '.git'
-    'log'
-    'repositories'
-    'tmp'
-    'vendor'
-  ]
-  'themes': [
-    'unity-ui'
-    'glacier-syntax'
-  ]
-  'hideGitIgnoredFiles': true
-  'disabledPackages': [
-    'background-tips'
-    'exception-reporting'
-    'metrics'
-  ]
-'spell-check':
-  'grammars': [
-    'text.plain'
-    'source.gfm'
-    'text.git-commit'
-  ]
-'welcome':
-  'showOnStartup': false
-'release-notes':
-  'viewedVersion': '0.89.0'
-'tree-view': {}
+"*":
+  editor:
+    showIndentGuide: true
+    invisibles: {}
+    fontFamily: "Roboto Mono"
+    showInvisibles: true
+  core:
+    excludeVcsIgnoredPaths: false
+    ignoredNames: [
+      ".bundle"
+      ".git"
+      "log"
+      "repositories"
+      "tmp"
+      "vendor"
+    ]
+    themes: [
+      "atom-material-ui"
+      "atom-material-syntax"
+    ]
+    hideGitIgnoredFiles: true
+    disabledPackages: [
+      "background-tips"
+      "exception-reporting"
+      "metrics"
+    ]
+    projectHome: "/home/mbaxa/git"
+  "spell-check":
+    grammars: [
+      "text.plain"
+      "source.gfm"
+      "text.git-commit"
+    ]
+  welcome:
+    showOnStartup: false
+  "release-notes":
+    viewedVersion: "0.89.0"
+  "tree-view": {}
+  "atom-material-ui":
+    useRoboto: true
+    compactTreeView: true


Updates in atom

Updates in atom

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -18,8 +18,8 @@
       "vendor"
     ]
     themes: [
-      "unity-ui"
-      "glacier-syntax"
+      "atom-dark-ui"
+      "atom-dark-syntax"
     ]
     hideGitIgnoredFiles: true
     disabledPackages: [
@@ -37,3 +37,4 @@
     showOnStartup: false
   "release-notes":
     viewedVersion: "0.89.0"
+  emmet: {}


add comments and fix anonymous user

add comments and fix anonymous user

--- client/views/blog/blog.coffee
+++ client/views/blog/blog.coffee
@@ -9,17 +9,24 @@
     if settings.useSideComments
       SideComments = require 'side-comments'

-      # cehck if config allows anonymous commenters (default is null)
+      # check if config allows anonymous commenters (default is null)
       if settings.allowAnonymous and !Meteor.user()
         commentUser =
           name: 'Anonymous'
           avatarUrl: 'http://f.cl.ly/items/0s1a0q1y2Z2k2I193k1y/default-user.png'
-          id: Meteor.userId()
-      else
+          id: 0
+      else if Meteor.user()
         commentUser =
           name: Meteor.user().username
           avatarUrl: 'http://f.cl.ly/items/0s1a0q1y2Z2k2I193k1y/default-user.png'
           id: Meteor.userId()
+      else
+        commentUser =
+          name: 'Login to Comment'
+          avatarUrl: 'http://f.cl.ly/items/0s1a0q1y2Z2k2I193k1y/default-user.png'
+          id: 0
+
+      # load existing comments
       existingComments = []
       @data.comments.forEach((section)->
         existingComments.push(
@@ -27,7 +34,11 @@
           comments: section.comments
         )
       )
+
+      # add side comments
       sideComments = new SideComments '#commentable-area', commentUser, existingComments
+
+      # side comments events
       sideComments.on 'commentPosted', (comment) ->
         attrs =
           authorAvatarUrl: comment.authorAvatarUrl


Fix error message

Fix error message

--- src/util/world.coffee
+++ src/util/world.coffee
@@ -24,7 +24,7 @@
     cache_rx = rx or @up.get_raw(RX)
     assert cache_rx, "cache_rx"
     @doc = cache_rx.map()
-    assert _.isString(label), "label is string"
+    assert _.isString(label), "label not a string: #{label}"
     @doc.put LABEL, label
     @doc.put CHILDREN, cache_rx.array()
     @doc.put(RX, rx) if rx?


oauth: implement google flow, JReferrableEmail class

--- client/landing/app/Applications/Members.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Members.kdapplication/AppController.coffee
@@ -19,6 +19,8 @@
     facebook        :
       nicename      : 'Facebook'
       urlLocation   : 'link'
+    google          :
+      nicename      : 'Google'
     # twitter         :
     #   nicename      : 'Twitter'
     # linkedin        :


fix syntax errors caused by a botched merge

--- client/landing/app/Applications/WebTerm.kdapplication/AppController.coffee
+++ client/landing/app/Applications/WebTerm.kdapplication/AppController.coffee
@@ -7,51 +7,33 @@
     hiddenHandle : no
     behavior     : "application"

-      data.on 'ViewClosed', =>
-        @propagateEvent
-          KDEventType : 'ApplicationWantsToClose'
-          globalEvent : yes
-        ,
-          data : data
+  # TODO: the below was pasted in here during a merge.  fixme C.T.
+  # bringToFront: ->
+  #   appStorage = new AppStorage 'WebTerm', '1.0'
+  #   appStorage.fetchStorage =>
+  #     data = new WebTermView appStorage
+  #     data.on "WebTerm.terminated", =>
+  #       @propagateEvent
+  #         KDEventType : "ApplicationWantsToClose"
+  #         globalEvent : yes
+  #       , data: data

-      options =
-        name         : "Terminal"
-        hiddenHandle : no
-        type         : "application"
-        cssClass     : "webterm"
+  #     data.on 'ViewClosed', =>
+  #       @propagateEvent
+  #         KDEventType : 'ApplicationWantsToClose'
+  #         globalEvent : yes
+  #       ,
+  #         data : data

-      @propagateEvent
-        KDEventType  : "ApplicationWantsToBeShown"
-        globalEvent  : yes
-      , {options, data}
+  #     options =
+  #       name         : "Terminal"
+  #       hiddenHandle : no
+  #       type         : "application"
+  #       cssClass     : "webterm"

-  # TODO: the below was pasted in here during a merge.  fixme C.T.
-  bringToFront: ->
-    appStorage = new AppStorage 'WebTerm', '1.0'
-    appStorage.fetchStorage =>
-      data = new WebTermView appStorage
-      data.on "WebTerm.terminated", =>
-        @propagateEvent
-          KDEventType : "ApplicationWantsToClose"
-          globalEvent : yes
-        , data: data
-
-      data.on 'ViewClosed', =>
-        @propagateEvent
-          KDEventType : 'ApplicationWantsToClose'
-          globalEvent : yes
-        ,
-          data : data
-
-      options =
-        name         : "Terminal"
-        hiddenHandle : no
-        type         : "application"
-        cssClass     : "webterm"
-
-      @propagateEvent
-        KDEventType  : "ApplicationWantsToBeShown"
-        globalEvent  : yes
-      , {options, data}
+  #     @propagateEvent
+  #       KDEventType  : "ApplicationWantsToBeShown"
+  #       globalEvent  : yes
+  #     , {options, data}

 WebTerm = {}


WebTerm: Minor changes for code quality and performance.

--- client/landing/app/Applications/WebTerm.kdapplication/AppController.coffee
+++ client/landing/app/Applications/WebTerm.kdapplication/AppController.coffee
@@ -42,8 +42,12 @@
         , cb

   constructor:(options = {}, data)->
-    vmName          = options.params?.vmName or (KD.getSingleton 'vmController').defaultVmName
-    options.view    = new WebTermAppView {vmName, joinUser: options.params?.joinUser, session: options.params?.session}
+    params          = options.params or {}
+    vmName          = params.vmName  or KD.getSingleton("vmController").defaultVmName
+    options.view    = new WebTermAppView
+      vmName        : vmName
+      joinUser      : params.joinUser
+      session       : params.session
     options.appInfo =
       title         : "Terminal on #{vmName}"
       cssClass      : "webterm"


Remove oldfindercontroller

Remove oldfindercontroller

--- client/landing/app/MainApp/filetree/controllers/oldfindercontroller.coffee
+++ client/landing/app/MainApp/filetree/controllers/oldfindercontroller.coffee
@@ -1,174 +0,0 @@
-## DEPRECATED DONT FORGET TO REMOVE IT
-## NOT USED
-
-class NFinderControllerOld extends KDViewController
-
-  constructor:(options = {}, data)->
-
-    {nickname}  = KD.whoami().profile
-
-    options.view = new KDView cssClass : "nfinder file-container"
-    treeOptions  = {}
-    treeOptions.treeItemClass     = options.treeItemClass     or= NFinderItem
-    treeOptions.nodeIdPath        = options.nodeIdPath        or= "path"
-    treeOptions.nodeParentIdPath  = options.nodeParentIdPath  or= "parentPath"
-    treeOptions.dragdrop          = options.dragdrop           ?= yes
-    treeOptions.foldersOnly       = options.foldersOnly        ?= no
-    treeOptions.multipleSelection = options.multipleSelection  ?= yes
-    treeOptions.addOrphansToRoot  = options.addOrphansToRoot   ?= no
-    treeOptions.putDepthInfo      = options.putDepthInfo       ?= yes
-    treeOptions.contextMenu       = options.contextMenu        ?= yes
-    treeOptions.maxRecentFolders  = options.maxRecentFolders  or= 10
-    treeOptions.initDelay         = options.initDelay         or= 0
-    treeOptions.useStorage        = options.useStorage         ?= no
-    treeOptions.delegate          = @
-
-    super options, data
-
-    @kiteController = KD.getSingleton('kiteController')
-    @appStorage     = KD.getSingleton('mainController').getAppStorageSingleton 'Finder', '1.0'
-
-    @treeController = new NFinderTreeController treeOptions, []
-    @treeController.on "file.opened", (file)=> @setRecentFile file.path
-    @treeController.on "folder.expanded", (folder)=> @setRecentFolder folder.path
-    @treeController.on "folder.collapsed", (folder)=> @unsetRecentFolder folder.path
-
-  loadView:(mainView)->
-
-    mainView.addSubView @treeController.getView()
-    @reset()
-    @viewLoaded = yes
-    @utils.killWait @loadDefaultStructureTimer
-
-    # temp hack, if page opens in develop section.
-    @utils.wait 2500, =>
-      KD.getSingleton("mainView").sidebar._windowDidResize()
-
-  expandInitialPath:(path)->
-    pathArray = []
-    path      = path.split "/"
-    temp      = ''
-
-    pathArray = (temp += "/#{chunk}" for chunk in path when chunk)
-
-    pathArray.splice 0, 1 # getting rid of /home folder
-
-    return pathArray
-
-  resetInitialPath:->
-    {nickname}  = KD.whoami().profile
-    initialPath   = "/home/#{nickname}/Sites/#{nickname}.koding.com/website"
-    @initialPath  = @expandInitialPath initialPath
-
-  reset:->
-
-    @appStorage = KD.getSingleton('mainController').getAppStorageSingleton 'Finder', '1.0'
-    @appStorage.once "storageFetched", =>
-      {nickname}    = KD.whoami().profile
-      @mount        = FSHelper.createFile
-        name        : nickname.toLowerCase()
-        path        : "/home/#{nickname}"
-        type        : "mount"
-
-      @defaultStructureLoaded = no
-      @treeController.initTree [@mount]
-
-      if @treeController.getOptions().useStorage
-        unless @viewLoaded
-          @loadDefaultStructureTimer = @utils.wait @treeController.getOptions().initDelay, =>
-            @loadDefaultStructure()
-        else
-          @loadDefaultStructure()
-
-  loadDefaultStructure:->
-
-    return if @defaultStructureLoaded
-    @defaultStructureLoaded = yes
-    @utils.killWait @loadDefaultStructureTimer
-
-    return unless KD.isLoggedIn()
-    {nickname}     = KD.whoami().profile
-    kiteController = KD.getSingleton('kiteController')
-    @appStorage.fetchValue 'recentFolders', (recentFolders)=>
-
-      unless Array.isArray recentFolders
-        @resetInitialPath()  unless @initialPath
-        recentFolders = @initialPath
-
-      timer = Date.now()
-
-      @mount.emit "fs.fetchContents.started"
-
-      @utils.killWait kiteFailureTimer if kiteFailureTimer
-
-      kiteFailureTimer = @utils.wait 5000, =>
-        @treeController.notify "Couldn't fetch files! Click to retry", 'clickable', "Sorry, a problem occured while communicating with servers, please try again later.", yes
-        @mount.emit "fs.fetchContents.finished"
-
-        @treeController.once 'fs.retry.scheduled', =>
-          @defaultStructureLoaded = no
-          @loadDefaultStructure()
-
-      if recentFolders.length is 0
-        return log "recentFolders", recentFolders.length
-
-      @multipleLs recentFolders, (err, response)=>
-        if response
-          files = FSHelper.parseLsOutput recentFolders, response
-          @utils.killWait kiteFailureTimer
-          @treeController.addNodes files
-          @treeController.emit 'fs.retry.success'
-          @treeController.hideNotification()
-
-
-        log "#{(Date.now()-timer)/1000}sec !"
-        # temp fix this doesn't fire in kitecontroller
-        kiteController.emit "UserEnvironmentIsCreated"
-        @mount.emit "fs.fetchContents.finished"
-
-  multipleLs:(pathArray, callback)->
-
-    KD.getSingleton('kiteController').run
-      withArgs  :
-        command : "ls \"#{pathArray.join("\" \"")}\" -Llpva --group-directories-first --time-style=full-iso"
-    , callback
-
-  setRecentFile:(filePath, callback)->
-
-    recentFiles = @appStorage.getValue('recentFiles')
-    recentFiles = [] unless Array.isArray recentFiles
-
-    unless filePath in recentFiles
-      recentFiles.pop() if recentFiles.length is @treeController.getOptions().maxRecentFiles
-      recentFiles.unshift filePath
-
-    @appStorage.setValue 'recentFiles', recentFiles.slice(0,10), =>
-      @emit 'recentfiles.updated', recentFiles
-
-  setRecentFolder:(folderPath, callback)->
-
-    recentFolders = @appStorage.getValue('recentFolders')
-    recentFolders = [] unless Array.isArray recentFolders
-
-    unless folderPath in recentFolders
-      recentFolders.push folderPath
-
-    recentFolders.sort (path)-> if path is folderPath then -1 else 0
-
-    @appStorage.setValue 'recentFolders', recentFolders, callback
-
-  unsetRecentFolder:(folderPath, callback)->
-
-    recentFolders = @appStorage.getValue('recentFolders')
-    recentFolders = [] unless Array.isArray recentFolders
-
-    splicer = ->
-      recentFolders.forEach (recentFolderPath)->
-        if recentFolderPath.search(folderPath) > -1
-          recentFolders.splice recentFolders.indexOf(recentFolderPath), 1
-          splicer()
-          return
-    splicer()
-
-    recentFolders.sort (path)-> if path is folderPath then -1 else 0
-    @appStorage.setValue 'recentFolders', recentFolders, callback


Fixed donate team view error

Fixed donate team view error

--- static/src/scripts/app/AppRouter.coffee
+++ static/src/scripts/app/AppRouter.coffee
@@ -68,7 +68,7 @@
             teamId: team.get 'id'
             name: team.get 'names'
             iphoneRedirect: @_isIphoneRedirect()
-          @_showView DonationFormView
+          @_showView donateView

     login: ->
       loginView = new LoginView


Update usage

Update usage

--- apps/artist/client/index.coffee
+++ apps/artist/client/index.coffee
@@ -14,7 +14,7 @@
 RelatedAuctionResultsView = require '../../../components/related_auction_results/view.coffee'
 { Following, FollowButton } = require '../../../components/follow_button/index.coffee'
 RelatedShowsView = require '../../../components/related_shows/view.coffee'
-# ArtworkFilterView = require '../../../components/artwork_filter/view.coffee'
+# ArtworkFilter = require '../../../components/artwork_filter/index.coffee'

 artistSort = -> require('../templates/sort.jade') arguments...

@@ -84,7 +84,7 @@
       @$('.artist-header-empty').remove() if collection.length

   setupArtworks: ->
-    # @artworkFilterView = new ArtworkFilterView el: @$('#artwork-section'), model: @model
+    # ArtworkFilter.init el: @$('#artwork-section'), model: @model
     @setupArtworksOld()

   setupArtworksOld: ->


Fix serious issue with TableView.

Fix serious issue with TableView.

--- lib/ST/TableView.coffee
+++ lib/ST/TableView.coffee
@@ -103,7 +103,7 @@
     if @_loaded
       tbody = $('tbody', @_tableElement)
       for index in @_mapping
-        tbody.append $('tr.item' + index)
+        tbody.append $('tr.item' + index, @_tableElement)

   @method 'render', ->
     @renderTable()


Fix logs display

Fix logs display

--- lib/actions/logs.coffee
+++ lib/actions/logs.coffee
@@ -47,5 +47,9 @@
 			tail: options.tail
 		}, (error, message) ->
 			return done(error) if error?
-			_.each(message, console.log)
+			if _.isArray(message)
+				_.each message, (line) ->
+					console.log(line)
+			else
+				console.log(message)
 			return done()


fixes

fixes

--- lib/browser-plus.coffee
+++ lib/browser-plus.coffee
@@ -28,6 +28,7 @@
     @Selectorjs = fs.readFileSync "#{resources}selector.js",'utf-8'

     atom.workspace.addOpener (uri,opt)=>
+      path = require 'path'
       if ( path.extname(uri) is '.htmlp' or
           uri.indexOf('http:') is 0 or uri.indexOf('https:') is 0 or
           uri.indexOf('localhost') is 0 or uri.indexOf('file:') is 0 or


Remove the gutter from the text-editor.

Remove the gutter from the text-editor.

--- lib/changes-view.coffee
+++ lib/changes-view.coffee
@@ -22,7 +22,7 @@

Commit message

-      <atom-text-editor class="commit-description" data-placeholder="Enter the commit message describing your changes." style="height: 120px"></atom-text-editor>
+      <atom-text-editor class="commit-description" gutter-hidden data-placeholder="Enter the commit message describing your changes." style="height: 120px"></atom-text-editor>
 <button class="btn btn-commit">Commit</button>


last commit for now, just made sure the server isn't crashing but console-logging the caught exception

--- lib/coffeeRunner.coffee
+++ lib/coffeeRunner.coffee
@@ -10,8 +10,13 @@
 recommender = new Recommender(storage)
 server = new Server(recommender)

-process.on 'exit', -> storage.persist(STORAGE_FILE_PATH)
+process.on 'exit', ->
+  console.log 'Process exits'
+  storage.persist(STORAGE_FILE_PATH)

+process.on 'uncaughtException', (exception) ->
+  console.log "Still running, but caught an exception: \n #{exception}"
+
 # pattern for cron jobs can be found at
 # http://help.sap.com/saphelp_xmii120/helpdata/en/44/89a17188cc6fb5e10000000a155369/content.htm
 new CronJob '0 0 */6 * * *',


Fixed syntax detection

Fixed syntax detection

--- lib/editor-proxy.coffee
+++ lib/editor-proxy.coffee
@@ -205,7 +205,9 @@

   # Returns the editor's syntax mode.
   getSyntax: ->
-    syntax = @getGrammar()
+    syntax = @getGrammar().split(' ')[0]
+    unless resources.hasSyntax syntax
+        syntax = "html"

     if /\b(javascript|jsx)\b/.test(syntax)
       syntax = if @getCurrentScope().some((scope) -> /\bstring\b/.test scope) then 'html' else 'jsx'


Add support for sending code in comments to the REPL

--- lib/editor-utils.coffee
+++ lib/editor-utils.coffee
@@ -153,7 +153,7 @@
   # braces) or next to one returns the text of that block. Also works with
   # Markdown blocks of code starting with  ```clojure  and ending with ```.
   getCursorInBlockRange: (editor, {topLevel} = {topLevel: false})->
-    if topLevel and range = @getCursorInClojureTopBlockRange(editor)
+    if topLevel and range = @getCursorInClojureTopBlockRange(editor,{lookInComments: true})
       range
     else if range = @getCursorInClojureBlockRange(editor)
       range
@@ -161,29 +161,41 @@
       @getCursorInMarkdownBlockRange(editor)

   # Constructs a list of `Range`s, one for each top level form.
-  getTopLevelRanges:  (editor) ->
+  getTopLevelRanges:  (editor, {lookInComments}={lookInComments: false}) ->
     ranges = []
     braceOpened = 0
-    editor.scan /[\{\}\[\]\(\)]/g, (result) =>
+    inTopLevelComment = false
+    if lookInComments
+      rex = /(\(comment\s|[\{\}\[\]\(\)])/g
+    else
+      rex = /[\{\}\[\]\(\)]/g
+    editor.scan rex, (result) =>
       if !(@isIgnorableBrace(editor, result.range.start))
+        matchesComment = result.matchText.match(/^\(comment\s/)
+        if matchesComment and braceOpened == 0
+          inTopLevelComment = true
         c = ""+result.match[0]
-        if ["(","{","["].indexOf(c) >= 0
-          if braceOpened == 0
+        if ["(","{","["].indexOf(c) >= 0 or matchesComment
+          if (braceOpened == 1 and inTopLevelComment == true) or
+             (braceOpened == 0 and inTopLevelComment == false)
             ranges.push([result.range.start])
           braceOpened++
         else if [")","}","]"].indexOf(c) >= 0
           braceOpened--
-          if braceOpened == 0
+          if (braceOpened == 1 and inTopLevelComment == true) or
+             (braceOpened == 0 and inTopLevelComment == false)
             ranges[ranges.length - 1].push(result.range.end)
+          if braceOpened == 0 and inTopLevelComment == true
+            inTopLevelComment = false
     ranges
       .filter((range) -> range.length == 2)
       .map((range) -> Range.fromObject(range))

   # Returns the `Range` that corresponds to the top level form that contains the current cursor position.
   # Doesn't work in Markdown blocks of code.
-  getCursorInClojureTopBlockRange: (editor)->
-    pos = editor.getCursorBufferPosition()
-    topLevelRanges = @getTopLevelRanges(editor)
+  getCursorInClojureTopBlockRange: (editor,options={})->
+    pos = editor.getCursorBufferPosition()
+    topLevelRanges = @getTopLevelRanges(editor,options)
     topLevelRanges.find (range) -> range.containsPoint(pos)

   # Searches all open text editors for the given string. Returns a tuple of the


Minor refactor

Minor refactor

--- lib/flash-loader.coffee
+++ lib/flash-loader.coffee
@@ -78,13 +78,13 @@
     when 'win32' then ''  # TODO

 class FlashPlayerVersions
+  constructor: (builtInFlashPath, chromeFlashPath, systemFlashPath) ->
+    @builtin = getFlashVersion builtInFlashPath
+    @chrome = getFlashVersion chromeFlashPath
+    @system = getFlashVersion systemFlashPath

 getAllVersions = ->
-  out = new FlashPlayerVersions
-  out.chrome = getFlashVersion findChromeFlashPath()
-  out.system = getFlashVersion findSystemFlashPath()
-  out.builtin = getFlashVersion builtInPath
-  out
+  new FlashPlayerVersions builtInPath, findChromeFlashPath(), findSystemFlashPath()

 parseCLIArg = (arg) ->
   # --flash=useChrome


Return early when popped stack is empty

Return early when popped stack is empty

--- lib/go-back-view.coffee
+++ lib/go-back-view.coffee
@@ -2,9 +2,9 @@

 module.exports =
 class GoBackView extends SymbolsView
-  toggle: =>
-    return if @stack.length is 0
+  toggle: ->
+    previousTag = @stack.pop()
+    return unless previousTag?

-    top = @stack.pop()
-    atom.workspaceView.open(top.file).done =>
-      @moveToPosition(top.position, false) if top.position
+    atom.workspaceView.open(previousTag.file).done =>
+      @moveToPosition(previousTag.position, false) if previousTag.position


Fix text for Harpoon Missiles.

Fix text for Harpoon Missiles.

fixes #505

--- coffeescripts/cards-en.coffee
+++ coffeescripts/cards-en.coffee
@@ -1030,7 +1030,7 @@
         'Ion Dischargers':
             text: '''After you receive an ion token, you may choose an enemy ship at Range 1.  If you do, remove that ion token. Then that ship may choose to receive 1 ion token. If it does, discard this card.'''
         'Harpoon Missiles':
-            text: '''Attack (target lock): Discard this card to perform this attack.%LINEBREAK%If this attack hits, assign the "Harpooned!" Condition to the defender.'''
+            text: '''Attack (target lock): Discard this card to perform this attack.%LINEBREAK%If this attack hits, after the attack resolves, assign the "Harpooned!" Condition to the defender.'''
         'Ordnance Silos':
             text: '''B/SF-17 Bomber only.%LINEBREAK%When you equip this card, place 3 ordnance tokens on each other equipped %BOMB% Upgrade card. When you are instructed to discard an Upgrade card, you may discard 1 ordnance token on that card instead.'''
         'Trajectory Simulator':


GameObject: Fix planar probes.

GameObject: Fix planar probes.

--- engine/gameobject.coffee
+++ engine/gameobject.coffee
@@ -404,7 +404,7 @@
         delete @context.objects[@name]

     instance_probes: ->
-        if @probe_cube?
+        if @probe_cube? or @probe_planar?
             return
         {probe_options} = @properties
         if probe_options?


Catch file I/O errors, don't crash

Catch file I/O errors, don't crash

--- lib/linter-clang.coffee
+++ lib/linter-clang.coffee
@@ -88,10 +88,18 @@

     # this function searches a directory for include path files
     searchDirectory = (base) ->
-      list = fs.readdirSync base
+      try
+        list = fs.readdirSync base
+      catch err
+        return
+
       for filename in list
         filenameResolved = path.resolve(base, filename)
-        stat = fs.statSync filenameResolved
+        try
+          stat = fs.statSync filenameResolved
+        catch err
+          continue
+
         if stat.isDirectory()
           searchDirectory filenameResolved
         if stat.isFile() and filename is '.linter-clang-includes'


:fire: [linter-views] Remove a redundant argument

--- lib/linter-views.coffee
+++ lib/linter-views.coffee
@@ -24,7 +24,7 @@
     @subscriptions.add atom.config.observe('linter.showErrorInline', (showBubble) =>
       @showBubble = showBubble
     )
-    @subscriptions.add atom.workspace.onDidChangeActivePaneItem (paneItem) =>
+    @subscriptions.add atom.workspace.onDidChangeActivePaneItem =>
       @render({added: [], removed: [], messages: @linter.messages.publicMessages})
       @panel.refresh(@state.scope)
     @subscriptions.add @bottomContainer.onDidChangeTab =>


Fixes bad delegation target in MinimapView

--- lib/minimap-view.coffee
+++ lib/minimap-view.coffee
@@ -13,7 +13,7 @@
   Delegato.includeInto(this)
   Emitter.includeInto(this)

-  @delegatesMethods 'getLineHeight', 'getLinesCount', 'getMinimapHeight', 'getMinimapScreenHeight', 'getMinimapHeightInLines', 'getFirstVisibleScreenRow', 'getLastVisibleScreenRow', 'addLineClass', 'removeLineClass', 'removeAllLineClasses', toProperty: 'miniVisibleArea'
+  @delegatesMethods 'getLineHeight', 'getLinesCount', 'getMinimapHeight', 'getMinimapScreenHeight', 'getMinimapHeightInLines', 'getFirstVisibleScreenRow', 'getLastVisibleScreenRow', 'addLineClass', 'removeLineClass', 'removeAllLineClasses', toProperty: 'miniEditorView'

   @content: ->
     @div class: 'minimap', =>


Draw big buttons

Draw big buttons

--- src/config/layout.coffee
+++ src/config/layout.coffee
@@ -11,10 +11,24 @@
       j: (world) -> world.get('split')
       width: (world) -> world.get('size')
       height: 96
-      fill: "#cccccc"
+      margin: 8
+      fill: "#888888"
       stroke: "black"
       path: (world, args) -> world.get('rect_path')
+      _AUTHORITY: {
+        fill: "#cccccc"
+        scale: 96
+        transform: (world, args) ->
+          scale = world.get('scale')
+          margin = world.get('margin')
+          x = world.get("_INDEX") * scale + margin
+          y = margin
+          "translate(#{x},#{y})"
+        height: (world) -> world.get('scale') - 2 * world.get('margin')
+        width: (world) -> world.get('height')
+      }
       _CHILDREN: [
+        "play"
       ]
     }
   ]


Allow send empty message

Allow send empty message

--- packages/rocketchat-lib/server/functions/sendMessage.coffee
+++ packages/rocketchat-lib/server/functions/sendMessage.coffee
@@ -6,6 +6,9 @@
 		message.ts = new Date()

 	message.u = _.pick user, ['_id','username']
+
+	if not Match.test(message.msg, String)
+		message.msg = ''

 	message.rid = room._id


See #69. Remove unnecessary console.log

See #69. Remove unnecessary console.log

--- lib/options-view.coffee
+++ lib/options-view.coffee
@@ -39,5 +39,5 @@
     @detach()

   selectRenderer: =>
-    console.log 'Select Renderer!'
+    # console.log 'Select Renderer!'
     @previewView.selectRenderer()


Added PersonalClient code and documentation

--- lib/personal-app.coffee
+++ lib/personal-app.coffee
@@ -153,18 +153,55 @@

 class PersonalClient
     ###
-    Client
-    ###
-
-    constructor: (access_options) ->
+    Client for making calls to personal api
+
+    ###
+
+    constructor: (@access_options) ->
         ###
         PersonalClient constructor

             access_options:
-                access_token:
-                refresh_token:
-                expiration:
-        ###
+                access_token: string - access token from oauth
+                refresh_token: string - refresh token from oauth
+                expiration: date - time at which access token expires
+                sandbox: boolean - Whether to use api-sandbox (default: false)
+        ###
+
+    refresh: (callback) ->
+        ###
+        Performs a refresh on the access token.  Generally PersonalClient will take care of this for you, but this is provided in case manual refresh is desired
+
+            callback: function - form of function(error){}, called when refresh is complete.  error is undefined on success (optional)
+
+            returns a promise object
+        ###
+        deferred = q.defer()
+        #TODO: perform refresh POST
+        return deferred.promise
+
+    request: (options, callback) ->
+        ###
+        GET from the Personal API
+
+            options:
+                path: string - everything after "/api/v1" in the path (required)
+                method: string - "GET" "PUT" "POST" or "DELETE" (required)
+                data: object - javascript object to send (optional)
+            callback: function(err, data){} (optional)
+
+            return a promise containing the parsed object returned from the server
+        ###
+        deferred = q.defer()
+        do_request = (options) ->
+            #TODO: perform request
+        if @access_options.expiration < Date.now()
+            refresh().then ()->
+                do_request(options)
+            , (err) -> deferred.reject(err)
+        else
+            do_request options
+        return deferred.promise

 class PersonalScope
     ###
@@ -342,10 +379,47 @@
     connect_opts.set(key,val) for key,val of options

 PersonalHelpers = (app) ->
+    ###
+    Provides helpers for Express views
+
+    To use:
+
+        express = require("express");
+        personal = require("personal");
+        app = express();
+        personal.Helpers(app);
+
+    Helpers:
+
+        auth_req_url() - provides the authorization request URL for starting the OAuth flow
+    ###
     app.locals
         auth_req_url: -> return connect_curr_req_url.get()

 PersonalMiddleware = (req, res, next) ->
+    ###
+    Connect middleware for using the Personal API
+
+    To use (connect):
+
+        example
+
+    To use (express):
+
+        express = require("express");
+        personal = require("node-personal");
+        personal.Options({<see PersonalConnectOptions>});
+        app = express()
+        app.configure(function(){
+            //various configuration
+            express.use(express.session(<config>));
+            express.use(personal.Middleware);
+        })
+
+    req.session.personal.req_url will now have the appropriate URL for sending users to the authorization page
+
+    Once users return from the authorization page, req.personal.client will be a working PersonalClient
+    ###
     #put logout fn in the request
     req.personal =
         logout: () ->


Fix reading default flags

Fix reading default flags

--- lib/linter-clang.coffee
+++ lib/linter-clang.coffee
@@ -58,7 +58,7 @@
         when 'C'             then atom.config.get 'linter-clang.clangDefaultCFlags'
         when 'Objective-C'   then atom.config.get 'linter-clang.clangDefaultObjCFlags'

-    args.push defaultFlags
+    args.push dflag for dflag in defaultFlags

     args.push "-ferror-limit=#{atom.config.get 'linter-clang.clangErrorLimit'}"
     args.push '-w' if atom.config.get 'linter-clang.clangSuppressWarnings'
@@ -118,7 +118,6 @@
           ###
           # only use line which contain stuff
           contentLines = (line for line in content.split "\n" when line)
-          console.log "TYPEOF #{typeof contentLines}"
           # Glue them together using quotes
           content = "\"" + (contentLines.join "\" \"") + "\""
           contentSplit = splitSpaceString content


Update linter-flint.coffee

Update linter-flint.coffee

--- lib/linter-flint.coffee
+++ lib/linter-flint.coffee
@@ -26,17 +26,7 @@
       default: false

   activate: ->
-    # Show the user an error if they do not have an appropriate linter based
-    #   package installed from Atom Package Manager. This will not be an issue
-    #   after a base linter package is integrated into Atom, in the coming
-    #   months.
-    # TODO: Remove when Linter Base is integrated into Atom.
-    atom.notifications.addError(
-      'Linter package not found.',
-      {
-        detail: 'Please install the `linter` package in your Settings view'
-      }
-    ) unless atom.packages.getLoadedPackages 'linter'
+    require('atom-package-deps').install 'linter-flint'

   provideLinter: ->
     LinterProvider = require('./provider')


Deleted generated view

Deleted generated view

--- lib/redmine-view.coffee
+++ lib/redmine-view.coffee
@@ -1,22 +0,0 @@
-module.exports =
-class RedmineView
-  constructor: (serializedState) ->
-    # Create root element
-    @element = document.createElement('div')
-    @element.classList.add('redmine')
-
-    # Create message element
-    message = document.createElement('div')
-    message.textContent = "The Redmine package is Alive! It's ALIVE!"
-    message.classList.add('message')
-    @element.appendChild(message)
-
-  # Returns an object that can be retrieved when package is activated
-  serialize: ->
-
-  # Tear down any state and detach
-  destroy: ->
-    @element.remove()
-
-  getElement: ->
-    @element