Convert most trigger() calls to dispatch

--- spec/project-find-view-spec.coffee
+++ spec/project-find-view-spec.coffee
@@ -40,7 +40,7 @@

   describe "when project-find:show is triggered", ->
     it "attaches ProjectFindView to the root view", ->
-      atom.workspaceView.trigger 'project-find:show'
+      atom.commands.dispatch(workspaceElement, 'project-find:show')

       waitsForPromise ->
         activationPromise
@@ -51,13 +51,13 @@
         expect(getAtomPanel()).toBeVisible()
         expect(projectFindView.find('.preview-block')).not.toBeVisible()
         expect(projectFindView.find('.loading')).not.toBeVisible()
-        expect(projectFindView.findEditor.getEditor().getSelectedBufferRange()).toEqual [[0, 0], [0, 5]]
+        expect(projectFindView.findEditor.getModel().getSelectedBufferRange()).toEqual [[0, 0], [0, 5]]

     describe "with an open buffer", ->
       editor = null

       beforeEach ->
-        atom.workspaceView.trigger 'project-find:show'
+        atom.commands.dispatch(workspaceElement, 'project-find:show')

         waitsForPromise ->
           activationPromise
@@ -70,47 +70,47 @@

       it "populates the findEditor with selection when there is a selection", ->
         editor.setSelectedBufferRange([[2, 8], [2, 13]])
-        atom.workspaceView.trigger 'project-find:show'
+        atom.commands.dispatch(workspaceElement, 'project-find:show')
         expect(getAtomPanel()).toBeVisible()
         expect(projectFindView.findEditor.getText()).toBe('items')

         editor.setSelectedBufferRange([[2, 14], [2, 20]])
-        atom.workspaceView.trigger 'project-find:show'
+        atom.commands.dispatch(workspaceElement, 'project-find:show')
         expect(getAtomPanel()).toBeVisible()
         expect(projectFindView.findEditor.getText()).toBe('length')

       it "populates the findEditor with the previous selection when there is no selection", ->
         editor.setSelectedBufferRange([[2, 14], [2, 20]])
-        atom.workspaceView.trigger 'project-find:show'
+        atom.commands.dispatch(workspaceElement, 'project-find:show')
         expect(getAtomPanel()).toBeVisible()
         expect(projectFindView.findEditor.getText()).toBe('length')

         editor.setSelectedBufferRange([[2, 30], [2, 30]])
-        atom.workspaceView.trigger 'project-find:show'
+        atom.commands.dispatch(workspaceElement, 'project-find:show')
         expect(getAtomPanel()).toBeVisible()
         expect(projectFindView.findEditor.getText()).toBe('length')

     describe "when the ProjectFindView is already attached", ->
       beforeEach ->
-        atom.workspaceView.trigger 'project-find:show'
+        atom.commands.dispatch(workspaceElement, 'project-find:show')

         waitsForPromise ->
           activationPromise

         runs ->
           projectFindView.findEditor.setText('items')
-          projectFindView.findEditor.getEditor().setSelectedBufferRange([[0, 0], [0, 0]])
+          projectFindView.findEditor.getModel().setSelectedBufferRange([[0, 0], [0, 0]])

       it "focuses the find editor and selects all the text", ->
-        atom.workspaceView.trigger 'project-find:show'
+        atom.commands.dispatch(workspaceElement, 'project-find:show')
         expect(projectFindView.findEditor).toHaveFocus()
-        expect(projectFindView.findEditor.getEditor().getSelectedText()).toBe "items"
+        expect(projectFindView.findEditor.getModel().getSelectedText()).toBe "items"

     it "honors config settings for find options", ->
       atom.config.set('find-and-replace.useRegex', true)
       atom.config.set('find-and-replace.caseSensitive', true)

-      atom.workspaceView.trigger 'project-find:show'
+      atom.commands.dispatch(workspaceElement, 'project-find:show')

       waitsForPromise ->
         activationPromise
@@ -121,14 +121,14 @@

   describe "when project-find:toggle is triggered", ->
     it "toggles the visibility of the ProjectFindView", ->
-      atom.workspaceView.trigger 'project-find:toggle'
+      atom.commands.dispatch(workspaceElement, 'project-find:toggle')

       waitsForPromise ->
         activationPromise

       runs ->
         expect(getAtomPanel()).toBeVisible()
-        atom.workspaceView.trigger 'project-find:toggle'
+        atom.commands.dispatch(workspaceElement, 'project-find:toggle')
         expect(getAtomPanel()).not.toBeVisible()

   describe "when project-find:show-in-current-directory is triggered", ->
@@ -210,7 +210,7 @@

       runs ->
         editorView = atom.workspaceView.getActiveView()
-        atom.workspaceView.trigger 'project-find:show'
+        atom.commands.dispatch(workspaceElement, 'project-find:show')

       waitsForPromise ->
         activationPromise
@@ -220,13 +220,13 @@
         projectPath = temp.mkdirSync("atom")
         fs.writeFileSync(path.join(projectPath, "tabs.txt"), "\t\n\\\t\n\\\\t")
         atom.project.setPaths([projectPath])
-        atom.workspaceView.trigger 'project-find:show'
+        atom.commands.dispatch(workspaceElement, 'project-find:show')

       describe "when regex seach is enabled", ->
         it "finds a literal tab character", ->
-          projectFindView.trigger 'project-find:toggle-regex-option'
+          atom.commands.dispatch(projectFindView[0], 'project-find:toggle-regex-option')
           projectFindView.findEditor.setText('\\t')
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

           waitsForPromise ->
             searchPromise
@@ -240,7 +240,7 @@
       describe "when regex seach is disabled", ->
         it "finds the escape char", ->
           projectFindView.findEditor.setText('\\t')
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

           waitsForPromise ->
             searchPromise
@@ -253,7 +253,7 @@

         it "finds a backslash", ->
           projectFindView.findEditor.setText('\\')
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

           waitsForPromise ->
             searchPromise
@@ -266,7 +266,7 @@

         it "doesn't insert a escaped char if there are multiple backslashs in front of the char", ->
           projectFindView.findEditor.setText('\\\\t')
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

           waitsForPromise ->
             searchPromise
@@ -279,7 +279,7 @@

     describe "when core:cancel is triggered", ->
       beforeEach ->
-        atom.workspaceView.trigger 'project-find:show'
+        atom.commands.dispatch(workspaceElement, 'project-find:show')
         projectFindView.focus()

       it "detaches from the root view", ->
@@ -295,7 +295,7 @@
         initialPane = atom.workspaceView.getActivePaneView()
         atom.config.set('find-and-replace.openProjectFindResultsInRightPane', true)
         projectFindView.findEditor.setText('items')
-        projectFindView.trigger 'core:confirm'
+        atom.commands.dispatch(projectFindView[0], 'core:confirm')

         waitsForPromise ->
           searchPromise
@@ -307,7 +307,7 @@
       it "does not split when option is false", ->
         initialPane = atom.workspaceView.getActivePaneView()
         projectFindView.findEditor.setText('items')
-        projectFindView.trigger 'core:confirm'
+        atom.commands.dispatch(projectFindView[0], 'core:confirm')

         waitsForPromise ->
           searchPromise
@@ -319,7 +319,7 @@
       it "can be duplicated", ->
         atom.config.set('find-and-replace.openProjectFindResultsInRightPane', true)
         projectFindView.findEditor.setText('items')
-        projectFindView.trigger 'core:confirm'
+        atom.commands.dispatch(projectFindView[0], 'core:confirm')

         waitsForPromise ->
           searchPromise
@@ -370,12 +370,12 @@
     describe "description label", ->
       beforeEach ->
         editorView.trigger 'project-find:show'
-        projectFindView.trigger 'project-find:toggle-regex-option'
+        atom.commands.dispatch(projectFindView[0], 'project-find:toggle-regex-option')
         spyOn(atom.project, 'scan').andCallFake -> Q()

       it "shows an error when the pattern is invalid and clears when no error", ->
         projectFindView.findEditor.setText('[')
-        projectFindView.trigger 'core:confirm'
+        atom.commands.dispatch(projectFindView[0], 'core:confirm')

         waitsForPromise ->
           searchPromise
@@ -385,13 +385,13 @@
           expect(projectFindView.descriptionLabel.text()).toContain('Invalid regular expression')

           projectFindView.findEditor.setText('')
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

           expect(projectFindView.descriptionLabel).not.toHaveClass('text-error')
           expect(projectFindView.descriptionLabel.text()).toContain('Find in Project')

           projectFindView.findEditor.setText('items')
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

         waitsForPromise ->
           searchPromise
@@ -407,7 +407,7 @@
         spyOn(atom.project, 'scan').andCallFake -> Q()

       it "escapes regex patterns by default", ->
-        projectFindView.trigger 'core:confirm'
+        atom.commands.dispatch(projectFindView[0], 'core:confirm')

         waitsForPromise ->
           searchPromise
@@ -416,9 +416,9 @@
           expect(atom.project.scan.argsForCall[0][0]).toEqual /i\(\\w\)ems\+/gi

       it "shows an error when the regex pattern is invalid", ->
-        projectFindView.trigger 'project-find:toggle-regex-option'
+        atom.commands.dispatch(projectFindView[0], 'project-find:toggle-regex-option')
         projectFindView.findEditor.setText('[')
-        projectFindView.trigger 'core:confirm'
+        atom.commands.dispatch(projectFindView[0], 'core:confirm')

         waitsForPromise ->
           searchPromise
@@ -429,18 +429,18 @@
       describe "when search has not been run yet", ->
         it "toggles regex option via an event but does not run the search", ->
           expect(projectFindView.regexOptionButton).not.toHaveClass('selected')
-          projectFindView.trigger 'project-find:toggle-regex-option'
+          atom.commands.dispatch(projectFindView[0], 'project-find:toggle-regex-option')
           expect(projectFindView.regexOptionButton).toHaveClass('selected')
           expect(atom.project.scan).not.toHaveBeenCalled()

       describe "when search has been run", ->
         beforeEach ->
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')
           waitsForPromise -> searchPromise

         it "toggles regex option via an event and finds files matching the pattern", ->
           expect(projectFindView.regexOptionButton).not.toHaveClass('selected')
-          projectFindView.trigger 'project-find:toggle-regex-option'
+          atom.commands.dispatch(projectFindView[0], 'project-find:toggle-regex-option')

           waitsForPromise ->
             searchPromise
@@ -465,7 +465,7 @@
         editorView.trigger 'project-find:show'
         spyOn(atom.project, 'scan').andCallFake -> Q()
         projectFindView.findEditor.setText('ITEMS')
-        projectFindView.trigger 'core:confirm'
+        atom.commands.dispatch(projectFindView[0], 'core:confirm')
         waitsForPromise -> searchPromise

       it "runs a case insensitive search by default", ->
@@ -473,7 +473,7 @@

       it "toggles case sensitive option via an event and finds files matching the pattern", ->
         expect(projectFindView.caseOptionButton).not.toHaveClass('selected')
-        projectFindView.trigger 'project-find:toggle-case-option'
+        atom.commands.dispatch(projectFindView[0], 'project-find:toggle-case-option')

         waitsForPromise ->
           searchPromise
@@ -496,7 +496,7 @@
     describe "when project-find:confirm is triggered", ->
       it "displays the results and no errors", ->
         projectFindView.findEditor.setText('items')
-        projectFindView.trigger 'project-find:confirm'
+        atom.commands.dispatch(projectFindView[0], 'project-find:confirm')

         waitsForPromise ->
           searchPromise
@@ -510,26 +510,26 @@

     describe "when core:confirm is triggered", ->
       beforeEach ->
-        atom.workspaceView.trigger 'project-find:show'
+        atom.commands.dispatch(workspaceElement, 'project-find:show')

       describe "when the there search field is empty", ->
         it "does not run the seach but clears the model", ->
           spyOn(atom.project, 'scan')
           spyOn(projectFindView.model, 'clear')
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')
           expect(atom.project.scan).not.toHaveBeenCalled()
           expect(projectFindView.model.clear).toHaveBeenCalled()

       it "reruns the search when confirmed again after focusing the window", ->
         projectFindView.findEditor.setText('thisdoesnotmatch')
-        projectFindView.trigger 'core:confirm'
+        atom.commands.dispatch(projectFindView[0], 'core:confirm')

         waitsForPromise ->
           searchPromise

         runs ->
           spyOn(atom.project, 'scan')
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

         waitsForPromise ->
           searchPromise
@@ -538,7 +538,7 @@
           expect(atom.project.scan).not.toHaveBeenCalled()
           atom.project.scan.reset()
           $(window).triggerHandler 'focus'
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

         waitsForPromise ->
           searchPromise
@@ -546,7 +546,7 @@
         runs ->
           expect(atom.project.scan).toHaveBeenCalled()
           atom.project.scan.reset()
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

         waitsForPromise ->
           searchPromise
@@ -559,7 +559,7 @@
           projectFindView.findEditor.setText('items')

         it "displays the results and no errors", ->
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

           waitsForPromise ->
             searchPromise
@@ -576,7 +576,7 @@
         it "only searches paths matching text in the path filter", ->
           spyOn(atom.project, 'scan').andCallFake -> Q()
           projectFindView.pathsEditor.setText('*.js')
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

           waitsForPromise ->
             searchPromise
@@ -585,7 +585,7 @@
             expect(atom.project.scan.argsForCall[0][1]['paths']).toEqual ['*.js']

         it "updates the results list when a buffer changes", ->
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')
           buffer = atom.project.bufferForPathSync('sample.js')

           waitsForPromise ->
@@ -622,7 +622,7 @@
           spyOn(atom.project, 'scan').andCallFake -> Q()

         it "displays no errors and no results", ->
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

           waitsForPromise ->
             searchPromise
@@ -635,7 +635,7 @@

     describe "history", ->
       beforeEach ->
-        atom.workspaceView.trigger 'project-find:show'
+        atom.commands.dispatch(workspaceElement, 'project-find:show')
         spyOn(atom.project, 'scan').andCallFake ->
           promise = Q()
           promise.cancel = ->
@@ -644,63 +644,63 @@
         projectFindView.findEditor.setText('sort')
         projectFindView.replaceEditor.setText('bort')
         projectFindView.pathsEditor.setText('abc')
-        projectFindView.findEditor.trigger 'core:confirm'
+        atom.commands.dispatch(projectFindView.findEditor[0], 'core:confirm')

         projectFindView.findEditor.setText('items')
         projectFindView.replaceEditor.setText('eyetims')
         projectFindView.pathsEditor.setText('def')
-        projectFindView.findEditor.trigger 'core:confirm'
+        atom.commands.dispatch(projectFindView.findEditor[0], 'core:confirm')

       it "can navigate the entire history stack", ->
         expect(projectFindView.findEditor.getText()).toEqual 'items'

-        projectFindView.findEditor.trigger 'core:move-up'
+        atom.commands.dispatch(projectFindView.findEditor[0], 'core:move-up')
         expect(projectFindView.findEditor.getText()).toEqual 'sort'

-        projectFindView.findEditor.trigger 'core:move-down'
+        atom.commands.dispatch(projectFindView.findEditor[0], 'core:move-down')
         expect(projectFindView.findEditor.getText()).toEqual 'items'

-        projectFindView.findEditor.trigger 'core:move-down'
+        atom.commands.dispatch(projectFindView.findEditor[0], 'core:move-down')
         expect(projectFindView.findEditor.getText()).toEqual ''

         expect(projectFindView.pathsEditor.getText()).toEqual 'def'

-        projectFindView.pathsEditor.trigger 'core:move-up'
+        atom.commands.dispatch(projectFindView.pathsEditor[0], 'core:move-up')
         expect(projectFindView.pathsEditor.getText()).toEqual 'abc'

-        projectFindView.pathsEditor.trigger 'core:move-down'
+        atom.commands.dispatch(projectFindView.pathsEditor[0], 'core:move-down')
         expect(projectFindView.pathsEditor.getText()).toEqual 'def'

-        projectFindView.pathsEditor.trigger 'core:move-down'
+        atom.commands.dispatch(projectFindView.pathsEditor[0], 'core:move-down')
         expect(projectFindView.pathsEditor.getText()).toEqual ''

         expect(projectFindView.replaceEditor.getText()).toEqual 'eyetims'

-        projectFindView.replaceEditor.trigger 'core:move-up'
+        atom.commands.dispatch(projectFindView.replaceEditor[0], 'core:move-up')
         expect(projectFindView.replaceEditor.getText()).toEqual 'bort'

-        projectFindView.replaceEditor.trigger 'core:move-down'
+        atom.commands.dispatch(projectFindView.replaceEditor[0], 'core:move-down')
         expect(projectFindView.replaceEditor.getText()).toEqual 'eyetims'

-        projectFindView.replaceEditor.trigger 'core:move-down'
+        atom.commands.dispatch(projectFindView.replaceEditor[0], 'core:move-down')
         expect(projectFindView.replaceEditor.getText()).toEqual ''

     describe "when find-and-replace:set-find-pattern is triggered", ->
       it "places the selected text into the find editor", ->
-        editorView.getEditor().setSelectedBufferRange([[1,6],[1,10]])
+        editorView.getModel().setSelectedBufferRange([[1,6],[1,10]])
         atom.workspaceView.trigger 'find-and-replace:use-selection-as-find-pattern'
         expect(projectFindView.findEditor.getText()).toBe 'sort'

-        editorView.getEditor().setSelectedBufferRange([[1,13],[1,21]])
+        editorView.getModel().setSelectedBufferRange([[1,13],[1,21]])
         atom.workspaceView.trigger 'find-and-replace:use-selection-as-find-pattern'
         expect(projectFindView.findEditor.getText()).toBe 'function'

       it "places the previously selected text into the find editor if no selection", ->
-        editorView.getEditor().setSelectedBufferRange([[1,13],[1,21]])
+        editorView.getModel().setSelectedBufferRange([[1,13],[1,21]])
         atom.workspaceView.trigger 'find-and-replace:use-selection-as-find-pattern'
         expect(projectFindView.findEditor.getText()).toBe 'function'

-        editorView.getEditor().setSelectedBufferRange([[1,30],[1,30]])
+        editorView.getModel().setSelectedBufferRange([[1,30],[1,30]])
         atom.workspaceView.trigger 'find-and-replace:use-selection-as-find-pattern'
         expect(projectFindView.findEditor.getText()).toBe ''

@@ -714,7 +714,7 @@
           called = true
           deferred.promise

-        projectFindView.trigger 'core:confirm'
+        atom.commands.dispatch(projectFindView[0], 'core:confirm')

         waitsFor -> called

@@ -757,7 +757,7 @@

         runs ->
           projectFindView.findEditor.setText('items')
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

         waitsForPromise ->
           searchPromise
@@ -782,11 +782,11 @@
           expect(editorView.find('.highlight.current-result')).toHaveLength 1
           expect(atom.workspaceView).toHaveClass 'find-visible'

-          initialSelectedRange = editorView.getEditor().getSelectedBufferRange()
+          initialSelectedRange = editorView.getModel().getSelectedBufferRange()

           # now we can find next
           editorView.trigger 'find-and-replace:find-next'
-          expect(editorView.getEditor().getSelectedBufferRange()).not.toEqual initialSelectedRange
+          expect(editorView.getModel().getSelectedBufferRange()).not.toEqual initialSelectedRange

   describe "replacing", ->
     [testDir, sampleJs, sampleCoffee, replacePromise] = []
@@ -799,7 +799,7 @@

       fs.writeFileSync(sampleCoffee, fs.readFileSync(require.resolve('./fixtures/sample.coffee')))
       fs.writeFileSync(sampleJs, fs.readFileSync(require.resolve('./fixtures/sample.js')))
-      atom.workspaceView.trigger 'project-find:show'
+      atom.commands.dispatch(workspaceElement, 'project-find:show')

       waitsForPromise ->
         activationPromise
@@ -839,16 +839,16 @@
         filePath = path.join(projectPath, "tabs.txt")
         fs.writeFileSync(filePath, "a\nb\na")
         atom.project.setPaths([projectPath])
-        atom.workspaceView.trigger 'project-find:show'
+        atom.commands.dispatch(workspaceElement, 'project-find:show')

       describe "when the regex option is chosen", ->
         beforeEach ->
-          projectFindView.trigger 'project-find:toggle-regex-option'
+          atom.commands.dispatch(projectFindView[0], 'project-find:toggle-regex-option')

         it "finds the escape char", ->
           projectFindView.findEditor.setText('a')
           projectFindView.replaceEditor.setText('\\t')
-          projectFindView.trigger 'project-find:replace-all'
+          atom.commands.dispatch(projectFindView[0], 'project-find:replace-all')

           waitsForPromise ->
             replacePromise
@@ -860,7 +860,7 @@
         it "doesn't insert a escaped char if there are multiple backslashs in front of the char", ->
           projectFindView.findEditor.setText('a')
           projectFindView.replaceEditor.setText('\\\\t')
-          projectFindView.trigger 'project-find:replace-all'
+          atom.commands.dispatch(projectFindView[0], 'project-find:replace-all')

           waitsForPromise ->
             replacePromise
@@ -874,7 +874,7 @@
         it "finds the escape char", ->
           projectFindView.findEditor.setText('a')
           projectFindView.replaceEditor.setText('\\t')
-          projectFindView.trigger 'project-find:replace-all'
+          atom.commands.dispatch(projectFindView[0], 'project-find:replace-all')

           waitsForPromise ->
             replacePromise
@@ -886,7 +886,7 @@
     describe "when the replace button is pressed", ->
       it "runs the search, and replaces all the matches", ->
         projectFindView.findEditor.setText('items')
-        projectFindView.trigger 'core:confirm'
+        atom.commands.dispatch(projectFindView[0], 'core:confirm')

         waitsForPromise ->
           searchPromise
@@ -913,7 +913,7 @@
       describe "when there are search results after a replace", ->
         it "runs the search after the replace", ->
           projectFindView.findEditor.setText('items')
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

           waitsForPromise ->
             searchPromise
@@ -932,7 +932,7 @@
             expect(projectFindView.descriptionLabel.text()).toContain 'Replaced items with items-123 13 times in 2 files'

             projectFindView.replaceEditor.setText('cats')
-            advanceClock(projectFindView.replaceEditor.getEditor().getBuffer().stoppedChangingDelay)
+            advanceClock(projectFindView.replaceEditor.getModel().getBuffer().stoppedChangingDelay)

             expect(projectFindView.descriptionLabel.text()).not.toContain 'Replaced items'
             expect(projectFindView.descriptionLabel.text()).toContain "13 results found in 2 files for items"
@@ -945,7 +945,7 @@

           spyOn(atom.project, 'scan').andCallThrough()
           spyOn(atom, 'beep')
-          projectFindView.trigger 'project-find:replace-all'
+          atom.commands.dispatch(projectFindView[0], 'project-find:replace-all')

           waitsForPromise ->
             replacePromise
@@ -960,7 +960,7 @@
           projectFindView.findEditor.setText('items')
           projectFindView.replaceEditor.setText('sunshine')

-          projectFindView.trigger 'project-find:replace-all'
+          atom.commands.dispatch(projectFindView[0], 'project-find:replace-all')

           waitsForPromise ->
             replacePromise
@@ -971,7 +971,7 @@
       describe "when the search text has changed since that last search", ->
         beforeEach ->
           projectFindView.findEditor.setText('items')
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

           waitsForPromise ->
             searchPromise
@@ -984,7 +984,7 @@
           projectFindView.replaceEditor.setText('ok')
           expect(projectFindView.resultsView).not.toBeVisible()

-          projectFindView.trigger 'project-find:replace-all'
+          atom.commands.dispatch(projectFindView[0], 'project-find:replace-all')

           waitsForPromise ->
             replacePromise
@@ -997,14 +997,14 @@
       describe "when the text in the search box triggered the results", ->
         beforeEach ->
           projectFindView.findEditor.setText('items')
-          projectFindView.trigger 'core:confirm'
+          atom.commands.dispatch(projectFindView[0], 'core:confirm')

           waitsForPromise ->
             searchPromise

         it "runs the search, and replaces all the matches", ->
           projectFindView.replaceEditor.setText('sunshine')
-          projectFindView.trigger 'project-find:replace-all'
+          atom.commands.dispatch(projectFindView[0], 'project-find:replace-all')
           expect(projectFindView.errorMessages).not.toBeVisible()

           waitsForPromise ->
@@ -1039,7 +1039,7 @@
           called = true
           deferred.promise

-        projectFindView.trigger 'project-find:replace-all'
+        atom.commands.dispatch(projectFindView[0], 'project-find:replace-all')

         waitsFor -> called

@@ -1066,7 +1066,7 @@

   describe "panel focus", ->
     beforeEach ->
-      atom.workspaceView.trigger 'project-find:show'
+      atom.commands.dispatch(workspaceElement, 'project-find:show')
       waitsForPromise -> activationPromise

     it "focuses the find editor when the panel gets focus", ->


Adjusted socket.io to work with cloudflare

--- src/server/server.iced
+++ src/server/server.iced
@@ -17,7 +17,7 @@
 envi          = require "./environment-helper"
 app						= express()
 server        = require("http").Server(app)
-io            = require("socket.io")(server)
+io            = require("socket.io")(server, transports: [ "polling" ])
 ioHandler     = require("./socket-handler")(io)

 # Authentication config


Modify test slightly to also cover switching active files

--- spec/tree-view-package-spec.coffee
+++ spec/tree-view-package-spec.coffee
@@ -4500,24 +4500,29 @@
         expect(atom.project.getPaths()).toEqual [alphaDirPath, thetaDirPath]
         expect(document.querySelector('.placeholder')).not.toExist()

-  describe "when a file is opened", ->
-    describe "if the file is not in a currently opened project", ->
-      it "deselects all entries", ->
-        nonProjectPath = path.join(temp.mkdirSync(), 'new-file.txt')
-        fs.writeFileSync(nonProjectPath, 'test')
-
-        waitForWorkspaceOpenEvent ->
-          sampleJs.dispatchEvent(new MouseEvent('click', {bubbles: true, detail: 1}))
-
-        runs ->
-          expect(sampleJs).toHaveClass 'selected'
-          expect(treeView.getSelectedEntries().length).toBe 1
-
-        waitsForPromise ->
-          atom.workspace.open(nonProjectPath)
-
-        runs ->
-          expect(treeView.getSelectedEntries().length).toBe 0
+  fdescribe "when the active file path does not exist in the project", ->
+    it "deselects all entries", ->
+      nonProjectPath = path.join(temp.mkdirSync(), 'new-file.txt')
+      fs.writeFileSync(nonProjectPath, 'test')
+
+      waitForWorkspaceOpenEvent ->
+        sampleJs.dispatchEvent(new MouseEvent('click', {bubbles: true, detail: 1}))
+
+      runs ->
+        expect(sampleJs).toHaveClass 'selected'
+        expect(treeView.getSelectedEntries().length).toBe 1
+
+      waitsForPromise ->
+        atom.workspace.open(nonProjectPath)
+
+      runs ->
+        expect(treeView.getSelectedEntries().length).toBe 0
+
+      waitsForPromise ->
+        atom.workspace.open(sampleJs.getPath())
+
+      runs ->
+        expect(sampleJs).toHaveClass 'selected'

   describe "when there is a __proto__ entry present", ->
     it "does not break anything", ->


nginx: Add koding-prod-deployment CIDR to allowed internal subnets


Abstract font setters

Abstract font setters

--- src/style_mixin.coffee
+++ src/style_mixin.coffee
@@ -12,32 +12,35 @@
 			mixin = self._.styleMixin
 			mixin.style.font = mixin.sm.cloneResource(mixin.style.font)

+		fontSetter = (self, key, val) ->
+			mixin = self._.styleMixin
+			if mixin.cloned
+				return mixin.style.font[key] = val
+			cloneFont(self)
+			mixin.style.font[key] = val
+			mixin.cloned = true
+			mixin.onUpdate?()
+
+
 		Object.defineProperties proto,
 			"fontName":
 				get: -> @_.styleMixin.style.font.name
 				set: (val)->
-					cloneFont(this)
-					mixin = @_.styleMixin
-					mixin.style.font.name = val
-					mixin.onUpdate?()
+					fontSetter(this, "name", val)
+
 			"fontSize":
 				get: -> @_.styleMixin.style.font.size
 				set: (val)->
-					cloneFont(this)
-					mixin = @_.styleMixin
-					mixin.style.font.size = val
-					mixin.onUpdate?()
+					fontSetter(this, "size", val)
+
 			"fontColor":
 				get: -> @_.styleMixin.style.font.color
 				set: (val)->
-					cloneFont(this)
-					mixin = @_.styleMixin
-					mixin.style.font.color = val
-					mixin.onUpdate?()
+					fontSetter(this, "color", val)

 	@bind: (obj, styleId)->
 		new StyleMixin(obj, styleId)
-
+
 	constructor: (obj, styleId) ->
 		obj._.styleMixin = this
 		@sm = obj.workbook._.sm


Expose all native regex search APIs

Expose all native regex search APIs

--- src/text-buffer.coffee
+++ src/text-buffer.coffee
@@ -1423,21 +1423,54 @@

     replacements

-  # Experimental: Run an async regexp search on the buffer
+  # Experimental: Asynchronously search the buffer for a given regex.
   #
   # * `regex` A {RegExp} to search for.
   #
   # Returns a {Promise} that resolves with the first {Range} of text that
   # matches the given regex.
-  find: (regex) ->
-    @buffer.find(regex)
-
-  # Experimental: Run a regexp search on the buffer
+  find: (regex) -> @buffer.find(regex)
+
+  # Experimental: Asynchronously search a given range of the buffer for a given regex.
+  #
+  # * `regex` A {RegExp} to search for.
+  # * `range` A {Range} to search within.
+  #
+  # Returns a {Promise} that resolves with the first {Range} of text that
+  # matches the given regex.
+  findInRange: (regex) -> @buffer.findInRange(regex)
+
+  # Experimental: Search the buffer for a given regex.
   #
   # * `regex` A {RegExp} to search for.
   #
   # Returns the first {Range} of text that matches the given regex.
   findSync: (regex) -> @buffer.findSync(regex)
+
+  # Experimental: Search a given range of the buffer for a given regex.
+  #
+  # * `regex` A {RegExp} to search for.
+  # * `range` A {Range} to search within.
+  #
+  # Returns the first {Range} of text that matches the given regex.
+  findInRangeSync: (regex) -> @buffer.findInRangeSync(regex)
+
+  # Experimental: Asynchronously search the buffer for a given regex.
+  #
+  # * `regex` A {RegExp} to search for.
+  #
+  # Returns a {Promise} that resolves with an {Array} containing every
+  # {Range} of text that matches the given regex.
+  findAll: (regex) -> @buffer.findAll(regex)
+
+  # Experimental: Asynchronously search a given range of the buffer for a given regex.
+  #
+  # * `regex` A {RegExp} to search for.
+  # * `range` A {Range} to search within.
+  #
+  # Returns a {Promise} that resolves with an {Array} containing every
+  # {Range} of text that matches the given regex.
+  findAllInRange: (regex) -> @buffer.findAllInRange(regex)

   # Experimental: Run an regexp search on the buffer
   #
@@ -1446,6 +1479,15 @@
   # Returns an {Array} containing every {Range} of text that matches the given
   # regex.
   findAllSync: (regex) -> @buffer.findAllSync(regex)
+
+  # Experimental: Search a given range of the buffer for a given regex.
+  #
+  # * `regex` A {RegExp} to search for.
+  # * `range` A {Range} to search within.
+  #
+  # Returns an {Array} containing every {Range} of text that matches the given
+  # regex.
+  findAllInRangeSync: (regex) -> @buffer.findAllInRangeSync(regex)

   # Experimental: Find fuzzy match suggestions in the buffer
   #


Use fdatasync to ensure writes are committed to disk

We shouldn’t proceed to write the main file until we know the backup
is on disk. We shouldn’t delete the backup until we know the main file
has been written.

--- src/text-buffer.coffee
+++ src/text-buffer.coffee
@@ -7,6 +7,7 @@
 Q = require 'q'
 _ = require 'underscore-plus'
 fs = require 'fs-plus'
+path = require 'path'

 Point = require './point'
 Range = require './range'
@@ -1213,14 +1214,19 @@
     @emit 'will-be-saved', this if Grim.includeDeprecatedAPIs
     @setPath(filePath)

-    if options?.backup and @file.existsSync()
-      backupFilePath = filePath + '~'
-      backupFilePath += '~' while fs.existsSync(backupFilePath)
-      fs.writeFileSync(backupFilePath, @file.readSync())
+    if options?.backup
+      backupFilePath = @backupFileContentsBeforeWriting()

     try
-      @file.writeSync(@getText())
-      fs.removeSync(backupFilePath) if backupFilePath?
+      if backupFilePath
+        fd = fs.openSync(filePath, 'w') # We open fd so we can call fdatasync
+        @file.writeSync(@getText()) # File::writeSync does privelege escalation, so we don't use fd here
+        fs.fdatasyncSync(fd) # Ensure file is written to disk before proceeding
+        fs.closeSync(fd)
+        fs.removeSync(backupFilePath)
+      else
+        @file.writeSync(@getText())
+
     catch error
       if backupFilePath?
         fs.writeFileSync(filePath, fs.readFileSync(backupFilePath))
@@ -1258,6 +1264,26 @@
     Q(@file?.read(flushCache) ? "").then (contents) =>
       @cachedDiskContents = contents
       callback?()
+
+  # Creates a backup file for the given path when writing.
+  backupFileContentsBeforeWriting: ->
+    return unless @file.existsSync()
+
+    backupFilePath = @getPath() + '~'
+    backupFilePath += '~' while fs.existsSync(backupFilePath)
+    backupFD = fs.openSync(backupFilePath, 'w')
+    fs.writeSync(backupFD, @file.readSync())
+
+    # ensure backup file contents are really on disk before proceeding
+    fs.fdatasyncSync(backupFD)
+    fs.closeSync(backupFD)
+
+    # ensure backup file directory entry is really on disk before proceeding
+    backupDirectoryFD = fs.openSync(path.dirname(backupFilePath), 'r')
+    fs.fdatasyncSync(backupDirectoryFD)
+    fs.closeSync(backupDirectoryFD)
+
+    backupFilePath

   ###
   Section: Private Utility Methods


Operate on selection objects, not just ranges

--- src/text-editor.coffee
+++ src/text-editor.coffee
@@ -822,26 +822,27 @@
   # coordinates.
   moveLineUp: ->
     newSelectionBufferRanges = []
-    selections = @getSelectedBufferRanges()
-    selections.sort (a, b) -> a.compare(b)
-
-    if selections[0].start.row is 0
+    selections = @getSelectionsOrderedByBufferPosition()
+
+    if selections[0].getBufferRange().start.row is 0
       return

-    if selections[selections.length - 1].start.row is @getLastBufferRow() and @buffer.getLastLine() is ''
+    if selections[selections.length - 1].getBufferRange().start.row is @getLastBufferRow() and @buffer.getLastLine() is ''
       return

     @transact =>
       for selection in selections
+        selectionRange = selection.getBufferRange()
+
         foldedRows = []
-        rows = [selection.start.row..selection.end.row]
-        if selection.start.row isnt selection.end.row and selection.end.column is 0
-          rows.pop() unless @isFoldedAtBufferRow(selection.end.row)
-
-        # Move line around the fold that is directly above the selection
-        precedingScreenRow = @screenRowForBufferRow(selection.start.row) - 1
+        rows = [selectionRange.start.row..selectionRange.end.row]
+        if selectionRange.start.row isnt selectionRange.end.row and selectionRange.end.column is 0
+          rows.pop() unless @isFoldedAtBufferRow(selectionRange.end.row)
+
+        # Move line around the fold that is directly above the selectionRange
+        precedingScreenRow = @screenRowForBufferRow(selectionRange.start.row) - 1
         precedingBufferRow = @bufferRowForScreenRow(precedingScreenRow)
-        insertDelta = selection.start.row - precedingBufferRow
+        insertDelta = selectionRange.start.row - precedingBufferRow

         for row in rows
           if fold = @displayBuffer.largestFoldStartingAtBufferRow(row)
@@ -871,7 +872,7 @@
         for foldedRow in foldedRows when 0 <= foldedRow <= @getLastBufferRow()
           @foldBufferRow(foldedRow)

-        newSelectionBufferRanges.push(selection.translate([-insertDelta]))
+        newSelectionBufferRanges.push(selectionRange.translate([-insertDelta]))

       @setSelectedBufferRanges(newSelectionBufferRanges, preserveFolds: true, autoscroll: true)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/text_screen.coffee
+++ src/text_screen.coffee
@@ -16,6 +16,7 @@
     Draw center aligned text at the given y position.

+
     enemy.follow(player)

     # => The enemy now has it's velocity attribute set in


added length test

added length test

--- test/point.coffee
+++ test/point.coffee
@@ -72,6 +72,10 @@
   test "#magnitude", ->
     equals Point(3, 4).magnitude(), 5

+  test "#length", ->
+    equals Point(0, 0).length(), 0
+    equals Point(-1, 0).length(), 1
+
   test ".fromAngle", ->
     p = Point.fromAngle(Math.TAU / 4)


Rotate weapon origin as well

Rotate weapon origin as well

--- app/scripts/components/utils/flipable.coffee
+++ app/scripts/components/utils/flipable.coffee
@@ -15,6 +15,7 @@

     @_mirrorCollision()
     @_mirrorRotationPoints()
+    @_mirrorWeaponOrigin()
     this

   unflipX: ->
@@ -32,6 +33,7 @@
       console.log e
     @_mirrorCollision()
     @_mirrorRotationPoints()
+    @_mirrorWeaponOrigin()
     this

   _mirrorCollision: ->
@@ -46,3 +48,8 @@
     for c in @_children
       c._origin.x = c.w - c._origin.x if c.origin?
       c.rotation = (360 + (360 - c.rotation)) % 360
+
+  _mirrorWeaponOrigin: ->
+    return unless @weaponOrigin?
+    @weaponOrigin = [@w - @weaponOrigin[0], @weaponOrigin[1]]
+


Remove it.only

Remove it.only

--- test/lib/publishConfig-spec.coffee
+++ test/lib/publishConfig-spec.coffee
@@ -172,5 +172,5 @@
         subscriber.subscribe 'config', 'uuid-subscriber', =>
           @sut.publish done

-      it.only 'should call onMessage', ->
+      it 'should call onMessage', ->
         expect(@onMessage).to.have.been.calledOnce


ComputeProvider: reviveClient, helper to get JGroup from context.group and JUser from connection.delegate.account from given client object

--- workers/social/lib/social/models/computeproviders/computeprovider.coffee
+++ workers/social/lib/social/models/computeproviders/computeprovider.coffee
@@ -24,6 +24,29 @@
       callback new KodingError "Credential failed.", "AccessDenied"
     else
       callback null, credential
+
+reviveClient = (client, callback, revive = yes)->
+
+  return callback null  unless revive
+
+  { connection: { delegate:account }, context: { group } } = client
+
+  JGroup = require '../group'
+  JGroup.one { slug: group }, (err, groupObj)=>
+
+    return callback err  if err
+    return callback new Error "Group not found"  unless groupObj
+
+    res = { group: groupObj }
+
+    account.fetchUser (err, user)=>
+
+      return callback err  if err
+      return callback new Error "User not found"  unless user
+
+      res.user = user
+
+      callback null, res

 module.exports = class ComputeProvider extends Base


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/animated.coffee
+++ test/animated.coffee
@@ -355,7 +355,7 @@
          "complete":"Idle1",
          "interruptible":false,
          "speed":"110",
-         "transition":["Matrix.HORIZONTAL_FLIP"],
+         "transition":[{hflip: true, vflip: true}],
          "triggers": {
            "0":["whiteParticles"],
            "4":["blueParticles","greenParticles"],
@@ -491,14 +491,5 @@

   ok chompSoundFired, "Chomp sound effect fired"

-test "should set transform if one is present", ->
-  animation = GameObject
-    data: animationData
-    includedModules: ["Animated"]
-
-  animation.update()
-
-  equals animation.I.transform, Matrix.HORIZONTAL_FLIP
-
 module()


namespaced unbind

namespaced unbind

--- test/bindable.coffee
+++ test/bindable.coffee
@@ -49,7 +49,7 @@

   o.trigger "test"

-  o.unbind "TestNamespace.", ->
+  o.unbind ".TestNamespace", ->
   o.trigger "test"

 test "#unbind namespaced", 1, ->


bind => on

bind => on

--- test/bindable.coffee
+++ test/bindable.coffee
@@ -28,7 +28,7 @@
   o.trigger "test", param1, param2

 test "#unbind", ->
-  o = Object.extend({}, Bindable())
+  o = Core().include("Bindable")

   callback = ->
     ok false
@@ -44,7 +44,7 @@
   o.trigger "test"

 test "#trigger namespace", 1, ->
-  o = Object.extend({}, Bindable())
+  o = Core().include("Bindable")
   o.bind "test.TestNamespace", ->
     ok true


fix French translation of pane:close

fix French translation of pane:close

The original translation meant "close tab," not "close pane," which was misleading since `pane:close` closes all the tabs in the selected pane, not just the visible tab (which is what `tab:close-tab` does).

--- def/fr/context.cson
+++ def/fr/context.cson
@@ -16,13 +16,13 @@
     "pane:split-down-and-copy-active-item": "Dédoubler en bas"
     "pane:split-left-and-copy-active-item": "Dédoubler à gauche"
     "pane:split-right-and-copy-active-item": "Dédoubler à droite"
-    "pane:close": "Fermer l'onglet"
+    "pane:close": "Fermer le panneau"
   "atom-pane":
     "pane:split-up-and-copy-active-item": "Dédoubler en haut"
     "pane:split-down-and-copy-active-item": "Dédoubler en bas"
     "pane:split-left-and-copy-active-item": "Dédoubler à gauche"
     "pane:split-right-and-copy-active-item": "Dédoubler à droite"
-    "pane:close": "Fermer l'onglet"
+    "pane:close": "Fermer le panneau"
   "atom-text-editor:not([mini])":
     "encoding-selector:show": "Changer l'encodage"
     "spell-check:correct-misspelling": "Corriger l'orthographe"


payment: pass additional subscription through workflow and callbacks

--- client/Main/payment/paymentcontroller.coffee
+++ client/Main/payment/paymentcontroller.coffee
@@ -134,9 +134,9 @@

     workflow
       .on 'DataCollected', (data) =>
-        @transitionSubscription data, (err, subscription) ->
+        @transitionSubscription data, (err, subscription, rest...) ->
           return  if KD.showError err
-          workflow.emit 'Finished', data, subscription
+          workflow.emit 'Finished', data, subscription, rest...
       .enter()

     workflow
@@ -173,7 +173,7 @@
       planCode: plan.planCode
     }

-    planApi.subscribe options, (err, subscription) =>
+    planApi.subscribe options, (err, subscription, rest...) =>
       if err?.short is 'existing_subscription'
         { existingSubscription } = err

@@ -195,7 +195,7 @@
           return callback err  if err

           JUser.logout (err) ->
-            callback err, subscription
+            callback err, subscription, rest...
       else
         callback err, subscription


client/kite: disable debug by default on command buffer

--- client/app/lib/kite/kitecommandbuffer.coffee
+++ client/app/lib/kite/kitecommandbuffer.coffee
@@ -11,6 +11,10 @@

   constructor: (options = {}) ->

+    # activating this will start logging to console.
+    # use `commandBuffer.setOption('debug', yes)` to activate it on runtime.
+    options.debug ?= no
+
     super options

     { kite } = options
@@ -19,6 +23,9 @@
     @storage = kd.utils.dict()

     @bindKiteEvents()
+
+
+  debug: (args...) -> @getOption('debug') and debug args...

   bindKiteEvents: ->
@@ -36,16 +43,20 @@

   onTellSuccess: (id, method, result) ->

-    debug 'log', "~~~~~ SUCCESS (#{@kite.options.name}) ~~~~~"
+    @debug 'log', "~~~~~ SUCCESS (#{@kite.options.name}) ~~~~~"
+
     @storage[id] = _.assign {}, @storage[id], { result }
     @emit 'change'
-    debug 'log', @storage[id]
+
+    @debug 'log', @storage[id]

   onTellFail: (id, method, error) ->

-    debug 'error', '~~~~~ ERROR ~~~~~'
+    @debug 'error', '~~~~~ ERROR ~~~~~'
+
     @storage[id] = _.assign {}, @storage[id], { error }
     @emit 'change'
-    debug 'error', error

+    @debug 'error', error
+


KDFormViewWithFields: Check for buttons before attempting create buttons

--- components/forms/KDFormViewWithFields.coffee
+++ components/forms/KDFormViewWithFields.coffee
@@ -12,10 +12,10 @@
     {fields,buttons} = @getOptions()

     @createFields @utils.objectToArray fields  if fields
-
-    @createButtons buttons  if buttons

-    { @buttons } = @buttonField
+    if buttons
+      @createButtons buttons
+      { @buttons } = @buttonField

   createFields:(fields)->
     @addSubView @createField fieldData for fieldData in fields


Add failing test for resetting replaced modules.

--- test/src/replace/index-test.coffee
+++ test/src/replace/index-test.coffee
@@ -186,3 +186,7 @@
       describe 'and classes on objects on funcs', ->
         When -> td.when(@lights.brights.prototype.beBright(1)).thenReturn('yow')
         Then -> (new @car.lights.brights).beBright(1) == 'yow'
+
+    describe 'post-reset usage', ->
+      Given -> td.reset()
+      Then -> @car.honk.toString() == "throw 'honk'"


Update reload commands

Update reload commands

--- extension/packages/commands.coffee
+++ extension/packages/commands.coffee
@@ -70,27 +70,23 @@
 command_yank = (vim) ->
   utils.writeToClipboard(vim.window.location.href)

-# Reload the page, possibly from cache
+# Reload the current tab, possibly from cache
 command_reload = (vim) ->
-  vim.window.location.reload(false)
-
-# Reload the page from the server
+  vim.rootWindow.BrowserReload()
+
+# Reload the current tab, skipping cache
 command_reload_force = (vim) ->
-  vim.window.location.reload(true)
-
-# Reload the page, possibly from cache
+  vim.rootWindow.BrowserReloadSkipCache()
+
+# Reload all tabs, possibly from cache
 command_reload_all = (vim) ->
-  if tabs = vim.rootWindow.gBrowser.tabContainer
-    for i in [0...tabs.itemCount]
-      window = tabs.getItemAtIndex(i).linkedBrowser.contentWindow
-      window.location.reload(false)
-
-# Reload the page from the server
+  vim.rootWindow.gBrowser.reloadAllTabs()
+
+# Reload all tabs, skipping cache
 command_reload_all_force = (vim) ->
-  if tabs = vim.rootWindow.gBrowser.tabContainer
-    for i in [0...tabs.itemCount]
-      window = tabs.getItemAtIndex(i).linkedBrowser.contentWindow
-      window.location.reload(true)
+  for tab in vim.rootWindow.gBrowser.visibleTabs
+    window = tab.linkedBrowser.contentWindow
+    window.location.reload(true)

 command_stop = (vim) ->
   vim.window.stop()


Add tooltip with title and description

Add tooltip with title and description

--- app/assets/javascripts/custom.coffee
+++ app/assets/javascripts/custom.coffee
@@ -18,18 +18,18 @@
     timeFormat: 'H:mm',
     displayEventEnd: 'true',
     eventRender: (event, element) ->
-      if event.description
-        element.qtip
-          content: {
-            text: event.description
-          },
-          position: {
-            my: 'center center',
-            at: 'top center'
-          },
-          style: {
-            classes: 'qtip-green qtip-shadow qtip-rounded'
-          }
+      element.qtip
+        content: {
+          title: { text: event.title },
+          text: event.description
+        },
+        position: {
+          my: 'center center',
+          at: 'top center'
+        },
+        style: {
+          classes: 'qtip-green qtip-shadow qtip-rounded'
+        }

       return


Do not render map when container is missing.

--- app/assets/javascripts/map.js.coffee
+++ app/assets/javascripts/map.js.coffee
@@ -11,44 +11,44 @@
     marker.setLatLng e.latlng
     return

-
-  lat = $("#leaflet").data("lat")
-  lon = $("#leaflet").data("lon")
-  map = L.map("leaflet").setView([
-    lat
-    lon
-  ], 16)
-  tiles = L.tileLayer("http://{s}.tiles.mapbox.com/v3/sozialhelden.map-iqt6py1k/{z}/{x}/{y}.png64",
-    attribution: "Map data © OpenStreetMap contributors, ODbL, Tiles © Mapbox"
-    maxZoom: 18
-  ).addTo(map)
-  circle = L.circle([
-    lat
-    lon
-  ], 150,
-    color: "organge"
-    fillColor: "#FE7101"
-    fillOpacity: 0.4
-  ).addTo(map)
-  markerIcon = L.icon(
-    iconUrl: "http://api.tiles.mapbox.com/v3/marker/pin-l-star+a22.png"
-    iconRetinaUrl: "http://api.tiles.mapbox.com/v3/marker/pin-l-star+a22@2x.png"
-    iconSize: [
-      36
-      90
-    ]
-    popupAnchor: [
-      -3
-      -76
-    ]
-  )
-  marker = L.marker([
-    lat
-    lon
-  ],
-    icon: markerIcon
-    draggable: true
-  ).addTo(map)
-  map.attributionControl.setPrefix ""
-  map.on "click", onMapClick
-  marker.on "dragend", onMarkerDrag+  if (el = $('#leaflet')).length > 0
+    lat = $("#leaflet").data("lat")
+    lon = $("#leaflet").data("lon")
+    map = L.map("leaflet").setView([
+      lat
+      lon
+    ], 16)
+    tiles = L.tileLayer("http://{s}.tiles.mapbox.com/v3/sozialhelden.map-iqt6py1k/{z}/{x}/{y}.png64",
+      attribution: "Map data © OpenStreetMap contributors, ODbL, Tiles © Mapbox"
+      maxZoom: 18
+    ).addTo(map)
+    circle = L.circle([
+      lat
+      lon
+    ], 150,
+      color: "organge"
+      fillColor: "#FE7101"
+      fillOpacity: 0.4
+    ).addTo(map)
+    markerIcon = L.icon(
+      iconUrl: "http://api.tiles.mapbox.com/v3/marker/pin-l-star+a22.png"
+      iconRetinaUrl: "http://api.tiles.mapbox.com/v3/marker/pin-l-star+a22@2x.png"
+      iconSize: [
+        36
+        90
+      ]
+      popupAnchor: [
+        -3
+        -76
+      ]
+    )
+    marker = L.marker([
+      lat
+      lon
+    ],
+      icon: markerIcon
+      draggable: true
+    ).addTo(map)
+    map.attributionControl.setPrefix ""
+    map.on "click", onMapClick
+    marker.on "dragend", onMarkerDrag


pitts

pitts

--- app/assets/javascripts/school.coffee
+++ app/assets/javascripts/school.coffee
@@ -177,24 +177,26 @@

 class window.PittsState extends School
   school_name: 'pitts_state',
-  fighting: 'left'
+  fighting: 'right'
   imageFaces: 'left'
   imageOffset: {
-    'head': {x: 25, y: 60},
-
-    'left-arm-fighting': {x: -180, y: 90},
-    'left-arm-fighting-reversed': {x: 82, y: 90},
-    'left-arm': {x: -126, y: -20},
-    'left-arm-reversed': {x: 110, y: -20},
-
-    'body': {x: 10, y: 150},
+    'head': {x: 10, y: 60},
+    'head-reversed': {x: 25, y: 60},
+
+    'left-arm': {x: -86, y: 150},
+    'left-arm-reversed': {x: 100, y: 150},
+
+    'body': {x: 0, y: 150},
     'body-reversed': {x: 10, y: 150},

-    'right-arm': {x: 100, y: 150},
-    'right-arm-reversed': {x: -60, y: 150},
-
-    'legs': {x: 45, y: 260},
-    'legs-reversed': {x: -25, y: 260},
+    'right-arm': {x: 90, y: -20},
+    'right-arm-reversed': {x: -120, y: -20},
+    'right-arm-fighting': {x: 70, y: 90},
+    'right-arm-fighting-reversed': {x: -182, y: 90},
+
+
+    'legs': {x: -35, y: 260},
+    'legs-reversed': {x: 50, y: 260},
   }

 class window.Stritch extends School


fix spelling

fix spelling

--- app/assets/javascripts/search.coffee
+++ app/assets/javascripts/search.coffee
@@ -4,9 +4,9 @@

   search: (c) =>
     if c.keyCode == 13
-      jsRoutes.controllers.Rdio.search(@$in.val()).ajax({success: this.populateResutls})
+      jsRoutes.controllers.Rdio.search(@$in.val()).ajax({success: this.populateResults})

-  populateResutls: (resp) =>
+  populateResults: (resp) =>
     divs = resp.result.results.map this.renderResult
     @$res.empty().append(divs)


fixed audio only bug

fixed audio only bug

--- app/assets/javascripts/webrtc.coffee
+++ app/assets/javascripts/webrtc.coffee
@@ -288,6 +288,9 @@
       desc = new RTCSessionDescription(remote_description,{
         "optional": [{"DtlsSrtpKeyAgreement": true}]
       })
+      desc = new RTCSessionDescription(remote_description)
+
+
       console.log("Description Object: ", desc)

       peer.setRemoteDescription(desc, =>
@@ -364,7 +367,8 @@
       if( callback )
         callback()
         return
-    constraints = {"audio": true, "video": {"mandatory": {}, "optional": []}};
+    #constraints = {"audio": true, "video": {"mandatory": {}, "optional": []}};
+    constraints = {"audio": true, "video": true};
     try
       console.log("Requested access to local media with mediaConstraints:\n \"" + JSON.stringify(constraints) + "\"");
       getUserMedia(constraints, (stream) =>


Removing turbolinks.

Removing turbolinks.

--- app/assets/javascripts/weight.coffee
+++ app/assets/javascripts/weight.coffee
@@ -76,8 +76,7 @@
     $('#change_tax').val(window.localStorage.change_tax) if window.localStorage.change_tax

-$(document).on 'turbolinks:load', ->
-
+start_f = ->
   if typeof Storage != 'undefined'
     $('#database_status').html('Database OK')
     can_save = true
@@ -102,3 +101,10 @@
   $('#change_tax').keyup ->
     save_data()
     compute_weight()
+
+
+$(document).on 'turbolinks:load', ->
+  start_f()
+
+$(window).load ->
+  start_f()


Further improve defaulting in record completer

Fixes #3527, #3511

--- app/assets/volume/spreadsheet.coffee
+++ app/assets/volume/spreadsheet.coffee
@@ -950,24 +950,25 @@
             inputl = (input ? '').toLowerCase()
             set = (r) -> (cell) ->
               setRecord(cell, info, r)
-            for r in editScope.records
-              add("Use " + info.category.name + ' ' + r.d, set(r.r), r.v == inputl) if r.v.startsWith(inputl)
-            v = if info.metric.options
+            rs = (r for r in editScope.records when r.v.startsWith(inputl))
+            for r in rs
+              add("Use " + info.category.name + ' ' + r.d, set(r.r), input && rs.length == 1 || r.v == inputl)
+            os = if info.metric.options
                 (x for x in info.metric.options when x.toLowerCase().startsWith(inputl))
               else
                 []
-            if input && !v.length
-              v = [input]
-            v.forEach (i) ->
+            if input && !os.length
+              os = [input]
+            os.forEach (i) ->
               if info.r
                 add("Change all " + info.record.displayName + " " + info.metric.name + " to '" + i + "'",
                   (cell) -> saveMeasure(cell, info.record, info.metric, i),
-                  i == input)
+                  input && !rs.length && os.length == 1 || i == input)
               add("Create new " + info.category.name + " with " + info.metric.name + " '" + i + "'",
                 (cell) -> setRecord(cell, info).then((r) ->
                   saveMeasure(cell, r, info.metric, i) if r
                   return),
-                i == input)
+                input && !rs.length && os.length == 1 || i == input)
           if o.length then o else input

         optionCompletions = (input) ->


HUB-166 : Bug fix: update channel properties in unit test

--- test/hAdapter.coffee
+++ test/hAdapter.coffee
@@ -79,25 +79,29 @@
           listenOn: "tcp://127.0.0.1:1221",
           broadcastOn: "tcp://127.0.0.1:2998",
           db:{
-            dbName: "test",
-            dbCollection: config.logins[1].urn
-          }
+            host: "localhost",
+            port: 27017,
+            name: "test"
+          },
+          collection: config.logins[1].urn
         }
       }
       hActor = actorModuleChannel.newActor(topology)
       hActor.h_onMessageInternal(hActor.buildSignal(hActor.actor, "start", {}))

       topology = {
-        actor: config.logins[1].urn,
+        actor: config.logins[3].urn,
         type: "hchannel",
         properties: {
           subscribers:[config.logins[1].urn, config.logins[2].urn],
           listenOn: "tcp://127.0.0.1:2112",
           broadcastOn: "tcp://127.0.0.1:2998",
           db:{
-            dbName: "test",
-            dbCollection: config.logins[1].urn
-          }
+            host: "localhost",
+            port: 27017,
+            name: "test"
+          },
+          collection: config.logins[3].urn
         }
       }
       hActor2 = actorModuleChannel.newActor(topology)


Fixing typo

Fixing typo

--- source/core/class/atom.coffee
+++ source/core/class/atom.coffee
@@ -13,7 +13,7 @@
   @include Atoms.Core.EventEmitter
   @include Atoms.Core.Output

-  @events = do @evts...
+  @events = (@evts...) -> @

   constructor: (@attributes) ->
     super


updates all.js to test

updates all.js to test

--- source/javascripts/all.coffee
+++ source/javascripts/all.coffee
@@ -27,19 +27,19 @@
   dependencies: [
     {
       # src: "/javascripts/reveal.js/plugin/markdown/marked.js"
-      src: "/tiykiosk/javascripts/reveal.js/plugin/markdown/marked.js"
+      src: "javascripts/reveal.js/plugin/markdown/marked.js"
       condition: ->
         !!document.querySelector("[data-markdown]")
     }
     {
       # src: "/javascripts/reveal.js/plugin/markdown/markdown.js"
-      src: "/tiykiosk/javascripts/reveal.js/plugin/markdown/markdown.js"
+      src: "javascripts/reveal.js/plugin/markdown/markdown.js"
       condition: ->
         !!document.querySelector("[data-markdown]")
     }
     {
       # src: '/javascripts/reveal.js/plugin/highlight/highlight.js'
-      src: '/tiykiosk/javascripts/reveal.js/plugin/highlight/highlight.js'
+      src: 'javascripts/reveal.js/plugin/highlight/highlight.js'
       async: true
       callback: ->
         hljs.initHighlightingOnLoad()


no longer highlight neighborhood name in sidebar

--- source/javascripts/all.coffee
+++ source/javascripts/all.coffee
@@ -7,8 +7,8 @@
 neighborhoods = null

 intensity   = d3.scale.quantile()
-projection  = d3.geo.albers().rotate([120])
-path        = d3.geo.path().projection(projection)
+projection  = d3.geo.albers().rotate [120]
+path        = d3.geo.path().projection projection

 tip = d3.tip().attr('class', 'tip').offset([-3, 0]).html (d) ->
   format = d3.format ','
@@ -103,8 +103,6 @@
     .on('mouseover', (d) ->
       name = d.properties.NAME
       place = places.filter((p) -> p.key == name)[0]
-      container = d3.select('.js-info').html(' ')
-      container.append('h2').text(name)
       tip.show name: name, subject: subject, data: place.value[subject])
     .on 'mouseout', tip.hide

@@ -155,9 +153,9 @@
       out[years[index]] = data
       callback(out) if index == 1

-# Should we exclude a neighoborhood from being highlighted
+# Should we exclude a neighoborhood from being highlighted.
 # Sometimes we want to draw a neighborhood, but not highlight it with others.
 # For example, Portland has a lot of MC Unclaimed areas and overlapping
-# neighborhoods
+# neighborhood boundaries.
 shouldExcludeNeighborhood = (name) ->
   name.toLowerCase().indexOf('unclaimed') != -1


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/tweening.coffee
+++ test/tweening.coffee
@@ -8,7 +8,7 @@
     x: 10

   10.times ->
-    o.
+    o.update()

   # Test for equality of two objects
   equals one, 1


Social: get social api url from config

Social: get social api url from config

--- workers/social/lib/social/models/socialapi/requests.coffee
+++ workers/social/lib/social/models/socialapi/requests.coffee
@@ -1,4 +1,7 @@
-SOCIAL_API_URL = "http://localhost:7000"
+{argv}   = require 'optimist'
+KONFIG = require('koding-config-manager').load("main.#{argv.c}")
+
+SOCIAL_API_URL = KONFIG.socialApiUrl
 request        = require 'request'

 wrapCallback = (callback)->


Fix tests (moment instance expected instead of Date) (#425)

--- tests/helpers.coffee
+++ tests/helpers.coffee
@@ -61,7 +61,6 @@
             callback()

 helpers.getDate = (date) ->
-    date = moment(new Date date).toDate()
+    date = new Date date
     date.setUTCHours 0, 0, 0, 0
-    return date
-
+    return moment date


Footer: Removed unused components

Footer: Removed unused components

Ref: 18671092d6

--- app/scripts/directives/footer.coffee
+++ app/scripts/directives/footer.coffee
@@ -5,7 +5,7 @@
     replace: true
     templateUrl: 'views/footer.html'
     restrict: 'E'
-    controller: ($scope, $rootScope, $location, $cookies, APIVersionFcty, packageJson, WebSocketFcty, AuthSrvc) ->
+    controller: ($scope, APIVersionFcty, packageJson, AuthSrvc) ->

       APIVersionFcty.getAPIVersion().then( (version) ->
         $scope.apiVersion = version


Updated command fetching logic

Updated command fetching logic

The command store now always checks if there are any new commands on
the server, and stores them locally if that is the case.

--- app/scripts/lib/command-store.coffee
+++ app/scripts/lib/command-store.coffee
@@ -8,8 +8,10 @@
   Config
 ) ->
   class CommandStore
-    commands: null
+    commands: []
+    lastSync: null
     fileEntry: null
+
     constructor: ->
       _.extend this, Backbone.Events
       @requestFileSystem(
@@ -32,15 +34,32 @@
       reader.readAsText file
       self = this
       reader.onloadend = ->
-        self.commands = JSON.parse(@result) if @result
+        self.parseFile @result
         self.trigger "initialised"
+
+    parseFile: (content) ->
+      return unless content
+
+      try
+        json = JSON.parse content
+      catch e
+        console.log "Error parsing file"
+        return
+
+      @commands = json.commands
+      @lastSync = json.lastSync

     storeCommands: ->
       @fileEntry.createWriter ((fileWriter) =>
-        blob = new Blob [JSON.stringify @commands], type: "application/json"
+        json = JSON.stringify {
+          commands: @commands
+          lastSync: @lastSync
+        }
+        blob = new Blob [json], type: "application/json"

         fileWriter.write blob
-        fileWriter.onwriteend = console.log.bind console, "Successfully wrote file"
+        fileWriter.onwriteend = \
+          console.log.bind console, "Successfully wrote file"
         fileWriter.onerror = console.log.bind console, "Error writing file"
       ), console.log.bind(console, "Error creating writer")

@@ -49,15 +68,23 @@
       @fs.root.getFile "commands.json", { create: true }, ((fileEntry) =>
         @fileEntry = fileEntry
         fileEntry.file @readFile.bind(this), @onLoadError.bind(this)
-      ), console.log.bind(console, "error loading file")
+      ), console.log.bind(console, "Error loading file")

     sync: ->
-      return _.defer @trigger.bind(this, "synced") if @commands
+      params = {}
+      params["updatedSince"] = @lastSync if @lastSync

-      $.getJSON "#{Config.API_URL}/commands", (response) =>
-        @commands = response
-        @trigger "synced"
-        @storeCommands()
+      $.getJSON("#{Config.API_URL}/commands", params)
+        .success((response) =>
+          if response.length
+            @commands = response.concat @commands
+            @lastSync = _.last(response).updatedAt # Response is sorted by
+                                                   # ascending updatedAt
+            @storeCommands()
+
+          @trigger "synced"
+        )
+        .error(console.log.bind(console, "Error fetching commands"))

     requestFileSystem: (
       window.requestFileSystem ||


Nuke more old fold specs

Nuke more old fold specs

--- spec/app/renderer-spec.coffee
+++ spec/app/renderer-spec.coffee
@@ -402,11 +402,6 @@
         expect(renderer.clipScreenPosition([3, 58])).toEqual [3, 50]
         expect(renderer.clipScreenPosition([3, 1000])).toEqual [3, 50]

-      describe "if there is a fold placeholder at the very end of the screen line", ->
-        it "clips positions at the end of the screen line to the position preceding the placeholder", ->
-          renderer.createFold([[3, 47], [3, 51]])
-          expect(renderer.clipScreenPosition([3, 50])).toEqual [3, 47]
-
     describe "when wrapAtSoftNewlines is true", ->
       it "wraps positions at the end of soft-wrapped lines to the next screen line", ->
         expect(renderer.clipScreenPosition([3, 50], wrapAtSoftNewlines: true)).toEqual [3, 50]
@@ -415,12 +410,6 @@
         expect(renderer.clipScreenPosition([3, 1000], wrapAtSoftNewlines: true)).toEqual [4, 0]

     describe "when skipAtomicTokens is false (the default)", ->
-      it "clips screen positions in the middle of fold placeholders to the to the beginning of fold placeholders", ->
-        renderer.createFold([[3, 55], [3, 59]])
-        expect(renderer.clipScreenPosition([4, 5])).toEqual [4, 4]
-        expect(renderer.clipScreenPosition([4, 6])).toEqual [4, 4]
-        expect(renderer.clipScreenPosition([4, 7])).toEqual [4, 7]
-
       it "clips screen positions in the middle of atomic tab characters to the beginning of the character", ->
         buffer.insert([0, 0], '\t')
         expect(renderer.clipScreenPosition([0, 0])).toEqual [0, 0]
@@ -428,13 +417,7 @@
         expect(renderer.clipScreenPosition([0, tabText.length])).toEqual [0, tabText.length]

     describe "when skipAtomicTokens is true", ->
-      it "wraps the screen positions in the middle of fold placeholders to the end of the placeholder", ->
-        renderer.createFold([[3, 55], [3, 59]])
-        expect(renderer.clipScreenPosition([4, 4], skipAtomicTokens: true)).toEqual [4, 4]
-        expect(renderer.clipScreenPosition([4, 5], skipAtomicTokens: true)).toEqual [4, 7]
-        expect(renderer.clipScreenPosition([4, 6], skipAtomicTokens: true)).toEqual [4, 7]
-
-      it "clips screen positions in the middle of atomic tab characters to the beginning of the character", ->
+      it "clips screen positions in the middle of atomic tab characters to the end of the character", ->
         buffer.insert([0, 0], '\t')
         expect(renderer.clipScreenPosition([0, 0], skipAtomicTokens: true)).toEqual [0, 0]
         expect(renderer.clipScreenPosition([0, 1], skipAtomicTokens: true)).toEqual [0, tabText.length]


Simplify.

Simplify.

--- spec/fuzzy-finder-spec.coffee
+++ spec/fuzzy-finder-spec.coffee
@@ -942,14 +942,7 @@
           fs.writeFileSync(newPath, '')

         waitsForPromise ->
-          gitRepository.refreshStatusForPath(originalPath)
-
-        runs ->
-          newPath = atom.project.getDirectories()[1].resolve('newsample.js')
-          fs.writeFileSync(newPath, '')
-
-        waitsForPromise ->
-          gitRepository.refreshStatusForPath(newPath)
+          gitRepository.refreshStatus()

       it "displays all new and modified paths", ->
         expect(atom.workspace.panelForItem(gitStatusView)).toBeNull()
@@ -959,8 +952,6 @@
         waitForPathsToDisplay gitStatusView

         runs ->
-          console.log(projectPath)
-          console.log(_.keys(atom.project.getRepositories()[1].async.getCachedPathStatuses()))
           expect(gitStatusView.find('.status.status-modified').length).toBe 1
           expect(gitStatusView.find('.status.status-added').length).toBe 3


Fix: Hint marker rotation was broken

Fix: Hint marker rotation was broken

--- extension/packages/mode-hints/hints.coffee
+++ extension/packages/mode-hints/hints.coffee
@@ -189,7 +189,7 @@
   markers = originalMarkers[..]

   # (#1)
-  stacks = (@getStackFor(markers.pop(), markers) while markers.length > 0)
+  stacks = (getStackFor(markers.pop(), markers) while markers.length > 0)

   # (#2)
   # Stacks of length 1 don't participate in any overlapping, and can therefore be skipped.
@@ -228,7 +228,7 @@
     if overlapsVertically and overlapsHorizontally
       # Also get all markers overlapping this one
       markers.splice(index, 1)
-      stack = stack.concat(@getStackFor(nextMarker, markers))
+      stack = stack.concat(getStackFor(nextMarker, markers))
     else
       # Continue the search
       index++


Check for some paths.

Check for some paths.

--- spec/path-scanner-spec.coffee
+++ spec/path-scanner-spec.coffee
@@ -22,3 +22,5 @@

       runs ->
         expect(scanner.paths.length).toBe 13
+        expect(scanner.paths).toContain path.join(rootPath, 'file1.txt')
+        expect(scanner.paths).toContain path.join(rootPath, 'dir', 'file7_ignorable.rb')


Add test to ensure calls dont stack

Add test to ensure calls dont stack

--- spec/python-tools-spec.coffee
+++ spec/python-tools-spec.coffee
@@ -10,6 +10,27 @@
       atom.packages.activatePackage('language-python')
     runs ->
       pythonTools = atom.packages.getActivePackage('python-tools').mainModule
+
+  describe "when running jedi commands", ->
+    editor = null
+    beforeEach ->
+      waitsForPromise ->
+        atom.workspace.open('test.py')
+
+      runs ->
+        editor = atom.workspace.getActiveTextEditor()
+        editor.setText("""
+        import json
+        """)
+
+    it "does not send too many commands over time", ->
+      editor.setCursorBufferPosition(new Point(0, 9))
+      spyOn(pythonTools, 'handleJediToolsResponse')
+      waitsForPromise ->
+        pythonTools.jediToolsRequest('gotoDef')
+      waitsForPromise ->
+        pythonTools.jediToolsRequest('gotoDef').then ->
+          expect(pythonTools.handleJediToolsResponse.calls.length).toEqual(2)

   describe "when running the goto definitions command", ->
     editor = null


cosmetic

cosmetic

--- spec/range-marker-spec.coffee
+++ spec/range-marker-spec.coffee
@@ -34,7 +34,6 @@
       atom.keymaps.add "test",
         'atom-text-editor.vim-mode-plus:not(.insert-mode)':
           'g m': 'vim-mode-plus:mark-range'
-
       set
         text: """
         ooo xxx ooo
@@ -69,6 +68,7 @@
           ooo xxx ooo
           xxx ooo xxx\n
           """
+
     describe "select-all-in-range-marker", ->
       it "select all instance of cursor word only within marked range", ->
         keystroke('gmip}}j.') # Mark 2 inner-word and 1 inner-paragraph


Fix clean-reboot

Fix clean-reboot

--- jobs/vm-clean-reboot/job.coffee
+++ jobs/vm-clean-reboot/job.coffee
@@ -24,7 +24,7 @@
           callback null, {metadata, data}
           return

-        xapi.call('VM.clean_reboot', vmref[0], false, false).then((response) =>
+        xapi.call('VM.clean_reboot', vmref[0]).then((response) =>

           message = "Performed clean reboot on VM " + name
           status = "ok"


Test added

Test added

--- spec/symbol-store-spec.coffee
+++ spec/symbol-store-spec.coffee
@@ -100,6 +100,29 @@
       expect(occurrences[0].symbol.text).toBe 'abc'
       expect(occurrences[0].symbol.type).toBe 'newtype'

+    it "dont override description of built-in function", ->
+      config =
+        function:
+          selectors: Selector.create('.function')
+          typePriority: 1
+        builtins:
+          suggestions: [
+            {
+              'type': 'function'
+              'rightLabel': 'global function'
+              'text': 'ValueFromFile'
+              'description': 'Test description.'
+            }]
+
+      editor.moveToBottom()
+      editor.insertText('ValueFromFile()')
+
+      occurrences = store.symbolsForConfig(config, [editor.getBuffer()], 'value')
+      expect(occurrences.length).toBe 1
+      expect(occurrences[0].symbol.text).toBe 'ValueFromFile'
+      expect(occurrences[0].symbol.description).toBe 'Test description.'
+      expect(occurrences[0].symbol.rightLabel).toBe 'global function'
+
   describe "when there are multiple files with tokens in the store", ->
     [config, editor1, editor2] = []
     beforeEach ->


Simplify loading collection tracking

Simplify loading collection tracking

- no need to check for collection == this since that's always the case
 - no need to specify context since we've got =>

--- core/app/backbone/factlink/collection.coffee
+++ core/app/backbone/factlink/collection.coffee
@@ -3,18 +3,8 @@
   constructor: (args...) ->
     super args...
     @_loading = false
-    @on 'request', @_onRequest, @
-    @on 'sync', @_onSync, @
-
-  _onRequest: (collection) ->
-    return unless collection == this
-
-    @_loading = true
-
-  _onSync: (collection) ->
-    return unless collection == this
-
-    @_loading = false
+    @on 'request', => @_started_loading_once = @_loading = true
+    @on 'sync', => @_loading = false

   loading: -> @_loading


default parentHtmlElement

default parentHtmlElement

--- src/art/engine/core/canvas_element.coffee
+++ src/art/engine/core/canvas_element.coffee
@@ -88,7 +88,8 @@
     canvas || document.getElementById(canvasId) || @_createCanvasElement parentHtmlElement

   _createCanvasElement: (parentHtmlElement) ->
-    parentHtmlElement?.appendChild @_createdHtmlCanvasElement = HtmlCanvas
+    parentHtmlElement ||= document.getElementById("artDomConsoleArea") || document.body
+    parentHtmlElement.appendChild @_createdHtmlCanvasElement = HtmlCanvas
       style: merge @pendingStyle,
         position: "absolute"
         outline: "none"


adding in question number, not sure how it got removed

--- src/components/question/index.cjsx
+++ src/components/question/index.cjsx
@@ -11,6 +11,7 @@
   propTypes:
     html: React.PropTypes.string
     type: React.PropTypes.string
+    questionNumber: React.PropTypes.number
   getDefaultProps: ->
     html: ''
     type: ''
@@ -28,6 +29,7 @@
       className="question-#{type}"
       block={true}
       html={html}
+      data-question-number={@props.questionNumber}
     />

 Question = React.createClass
@@ -83,7 +85,7 @@
     <div className={classes} data-question-number={questionNumber}>
       <QuestionHtml type='context' html={context} />
       <QuestionHtml type='stimulus' html={stimulus_html} />
-      <QuestionHtml type='stem' html={stem_html} />
+      <QuestionHtml type='stem' html={stem_html} questionNumber={questionNumber} />
       {@props.children}
       <AnswersTable {...@props} hasCorrectAnswer={hasCorrectAnswer}/>
       {<FormatsListing formats={formats} /> if @props.displayFormats}


windows shortcuts

windows shortcuts

--- keymaps/julia-client.cson
+++ keymaps/julia-client.cson
@@ -32,3 +32,6 @@
  .platform-linux atom-workspace':
   'ctrl-i ctrl-r': 'julia-client:open-a-repl'
   'ctrl-alt-i ctrl-alt-r': 'julia-client:start-repl-client'
+  'ctrl-i ctrl-s': 'julia-client:start-julia'
+  'ctrl-`': 'julia-client:toggle-console'
+  'ctrl-i ctrl-c': 'julia-client:clear-console'


define database on criscomodel instance

define database on criscomodel instance

--- src/core/models/criscomodel.coffee
+++ src/core/models/criscomodel.coffee
@@ -38,4 +38,7 @@
   targets: () ->
     console.log "Populating Crisco Targets"

+  @::__defineGetter__ "database", () ->
+    return @__database
+
 module.exports = CriscoModel


Fix bug that allowed to dismiss the loading modals

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

     lock = tk.dom("[data-tuktuk=lock]").first()
   )()


Test serializing

Test serializing

--- spec/lanes/models/AssociationMapSpec.coffee
+++ spec/lanes/models/AssociationMapSpec.coffee
@@ -1,4 +1,8 @@
+#=require lanes/access/User
+#=require lanes/access/Roles
+
 describe "Lanes.Models.AssociationMap", ->
+
     class Color
         constructor: -> super
         api_path: -> 'test'
@@ -49,3 +53,24 @@
         expect(model.color).toEqual(jasmine.any(Color))

         expect(model.color.rgb).toEqual('red')
+
+
+    it "serializes associations", ->
+        modelData = {
+            id: 123, title: 'Colors', color: { rgb: 'red' },
+            colors: [
+                { id: 1, rgb: '123' }
+                { id: 2, rgb: '1234' }
+                { id: 3, rgb: '12345' }
+            ]
+        }
+        model = LT.makeModel({
+            props: { id: 'integer', title: 'string' }
+            associations:
+                color:{ model: Color }
+                colors: { collection: Color, fk: 'model_fk_id' }
+        }, modelData)
+
+        expect(model.serialize()).toEqual(
+            _.extend({}, modelData, created_by: {role_names: []}, updated_by: {role_names:[]})
+        )


Fix automatic application of country coupons (#6048)

* Fix automatic application of coupons

* Document brazil edge case

--- app/views/core/SubscribeModal.coffee
+++ app/views/core/SubscribeModal.coffee
@@ -40,6 +40,14 @@
     else
       @products = new Products()
       data = {}
+
+      # Attempt to get the coupon associated with the user's country.
+      # If coupon doesn't exist nothing is returned.
+      @couponID ?= me?.get('country')
+      if @couponID is 'brazil'
+        # Edge case due to misconfigured brazil coupon in stripe that is immutable
+        @couponID = 'brazil-annual'
+
       if @couponID
         data.coupon = @couponID
       @supermodel.trackRequest @products.fetch {data}


Remove focus that snuck in there

Remove focus that snuck in there

--- spec/powershell-spec.coffee
+++ spec/powershell-spec.coffee
@@ -194,7 +194,7 @@
           expect(tokens[36].value).toEqual "finally"
           expect(tokens[36]).toHaveScopes ["source.powershell", "keyword.control.powershell"]

-    fdescribe "Logical operator keywords", ->
+    describe "Logical operator keywords", ->
       logicalOperators = [ "-and", "-or", "-xor", "-not", "-eq", "-lt", "-gt", "-le", "-ge", "-ne" ]

       it "tokenizes logical operators", ->


Don't use jQuery

Don't use jQuery

--- spec/wrap-guide-spec.coffee
+++ spec/wrap-guide-spec.coffee
@@ -1,7 +1,8 @@
-{$} = require 'atom'
-
 describe "WrapGuide", ->
   [editor, wrapGuide, workspaceElement] = []
+
+  getLeftPosition = (el) ->
+    parseInt(el.style.left)

   beforeEach ->
     workspaceElement = atom.views.getView(atom.workspace)
@@ -34,42 +35,42 @@
     it "positions the guide at the configured column", ->
       width = editor.getDefaultCharWidth() * wrapGuide.getDefaultColumn()
       expect(width).toBeGreaterThan(0)
-      expect($(wrapGuide).position().left).toBe(width)
+      expect(getLeftPosition(wrapGuide)).toBe(width)
       expect(wrapGuide).toBeVisible()

   describe "when the font size changes", ->
     it "updates the wrap guide position", ->
-      initial = $(wrapGuide).position().left
+      initial = getLeftPosition(wrapGuide)
       expect(initial).toBeGreaterThan(0)
       fontSize = atom.config.get("editor.fontSize")
       atom.config.set("editor.fontSize", fontSize + 10)

       advanceClock(1)
-      expect($(wrapGuide).position().left).toBeGreaterThan(initial)
+      expect(getLeftPosition(wrapGuide)).toBeGreaterThan(initial)
       expect(wrapGuide).toBeVisible()

   describe "when the column config changes", ->
     it "updates the wrap guide position", ->
-      initial = $(wrapGuide).position().left
+      initial = getLeftPosition(wrapGuide)
       expect(initial).toBeGreaterThan(0)
       column = atom.config.get("editor.preferredLineLength")
       atom.config.set("editor.preferredLineLength", column + 10)
-      expect($(wrapGuide).position().left).toBeGreaterThan(initial)
+      expect(getLeftPosition(wrapGuide)).toBeGreaterThan(initial)
       expect(wrapGuide).toBeVisible()

       atom.config.set("wrap-guide.columns", [{pattern: ".*", column: column - 10}])
-      expect($(wrapGuide).position().left).toBeLessThan(initial)
+      expect(getLeftPosition(wrapGuide)).toBeLessThan(initial)
       expect(wrapGuide).toBeVisible()

   describe "when the editor's grammar changes", ->
     it "updates the wrap guide position", ->
       atom.config.set('wrap-guide.columns', [{scope: 'source.js', column: 20}])
-      initial = $(wrapGuide).position().left
+      initial = getLeftPosition(wrapGuide)
       expect(initial).toBeGreaterThan(0)
       expect(wrapGuide).toBeVisible()

       editor.setGrammar(atom.syntax.grammarForScopeName('text.plain.null-grammar'))
-      expect($(wrapGuide).position().left).toBeGreaterThan(initial)
+      expect(getLeftPosition(wrapGuide)).toBeGreaterThan(initial)
       expect(wrapGuide).toBeVisible()

   describe "using a custom config column", ->
@@ -78,14 +79,14 @@
       wrapGuide.updateGuide()
       width = editor.getDefaultCharWidth() * 20
       expect(width).toBeGreaterThan(0)
-      expect($(wrapGuide).position().left).toBe(width)
+      expect(getLeftPosition(wrapGuide)).toBe(width)

     it "uses the default column when no custom column matches the path", ->
       atom.config.set('wrap-guide.columns', [{pattern: '\.jsp$', column: '100'}])
       wrapGuide.updateGuide()
       width = editor.getDefaultCharWidth() * wrapGuide.getDefaultColumn()
       expect(width).toBeGreaterThan(0)
-      expect($(wrapGuide).position().left).toBe(width)
+      expect(getLeftPosition(wrapGuide)).toBe(width)

     it "hides the guide when the config column is less than 1", ->
       atom.config.set('wrap-guide.columns', [{pattern: 'sample\.js$', column: -1}])
@@ -101,14 +102,14 @@
       wrapGuide.updateGuide()
       width = editor.getDefaultCharWidth() * 20
       expect(width).toBeGreaterThan(0)
-      expect($(wrapGuide).position().left).toBe(width)
+      expect(getLeftPosition(wrapGuide)).toBe(width)

     it "uses the default column when no scope name matches", ->
       atom.config.set('wrap-guide.columns', [{scope: 'source.gfm', column: '100'}])
       wrapGuide.updateGuide()
       width = editor.getDefaultCharWidth() * wrapGuide.getDefaultColumn()
       expect(width).toBeGreaterThan(0)
-      expect($(wrapGuide).position().left).toBe(width)
+      expect(getLeftPosition(wrapGuide)).toBe(width)

     it "favors the first matching rule", ->
       atom.config.set('wrap-guide.columns', [{pattern: '\.js$', column: 20},
@@ -116,4 +117,4 @@
       wrapGuide.updateGuide()
       width = editor.getDefaultCharWidth() * 20
       expect(width).toBeGreaterThan(0)
-      expect($(wrapGuide).position().left).toBe(width)
+      expect(getLeftPosition(wrapGuide)).toBe(width)


Add HintCorrdinator stub.

Add HintCorrdinator stub.

This adds a shim between launching a link-hints mode and creating the
LinkHintsMode object.  The shim is responsibly for for finding the
clickable elements.  This is preparatory to implementing global hints.

--- content_scripts/link_hints.coffee
+++ content_scripts/link_hints.coffee
@@ -46,17 +46,25 @@
   indicator: "Download link URL."
   clickModifiers: altKey: true, ctrlKey: false, metaKey: false

+HintCoordinator =
+  availableModes: [OPEN_IN_CURRENT_TAB, OPEN_IN_NEW_BG_TAB, OPEN_IN_NEW_FG_TAB, OPEN_WITH_QUEUE,
+                   COPY_LINK_URL, OPEN_INCOGNITO, DOWNLOAD_LINK_URL]
+
+  activateMode: (activateModeCallback) ->
+    activateModeCallback ClickableElements.getVisibleClickableElements()
+
 LinkHints =
   activateMode: (count = 1, mode = OPEN_IN_CURRENT_TAB) ->
     if 0 < count
-      new LinkHintsMode mode, (event = null) ->
-        # This is called which LinkHintsMode exits.  Escape and Backspace are the two ways in which hints mode
-        # can exit following which we do not restart hints mode.
-        return if event?.type == "keydown" and KeyboardUtils.isEscape event
-        return if event?.type == "keydown" and event.keyCode in [ keyCodes.backspace, keyCodes.deleteKey ]
-        # Wait for the next tick to allow the previous mode to exit.  It might yet generate a click event,
-        # which would cause our new mode to exit immediately.
-        Utils.nextTick -> LinkHints.activateMode count-1, mode
+      HintCoordinator.activateMode (elements) ->
+        new LinkHintsMode mode, elements, (event = null) ->
+          # This is called which LinkHintsMode exits.  Escape and Backspace are the two ways in which hints mode
+          # can exit following which we do not restart hints mode.
+          return if event?.type == "keydown" and KeyboardUtils.isEscape event
+          return if event?.type == "keydown" and event.keyCode in [ keyCodes.backspace, keyCodes.deleteKey ]
+          # Wait for the next tick to allow the previous mode to exit.  It might yet generate a click event,
+          # which would cause our new mode to exit immediately.
+          Utils.nextTick -> LinkHints.activateMode count-1, mode

   activateModeToOpenInNewTab: (count) -> @activateMode count, OPEN_IN_NEW_BG_TAB
   activateModeToOpenInNewForegroundTab: (count) -> @activateMode count, OPEN_IN_NEW_FG_TAB
@@ -76,11 +84,10 @@
   # A count of the number of Tab presses since the last non-Tab keyboard event.
   tabCount: 0

-  constructor: (mode = OPEN_IN_CURRENT_TAB, onExit = (->)) ->
+  constructor: (mode = OPEN_IN_CURRENT_TAB, elements, onExit = (->)) ->
     # we need documentElement to be ready in order to append links
     return unless document.documentElement

-    elements = ClickableElements.getVisibleClickableElements()
     # For these modes, we filter out those elements which don't have an HREF (since there's nothing we can do
     # with them).
     elements = (el for el in elements when el.element.href?) if mode in [ COPY_LINK_URL, OPEN_INCOGNITO ]


change constructor method signature to default

--- client/Dashboard/views/permissionview.coffee
+++ client/Dashboard/views/permissionview.coffee
@@ -1,6 +1,7 @@
 class GroupPermissionsView extends JView

   constructor:->
+  constructor: (options={}, data)->

     super


ActivityController: Added methods for getting and clearing new activity counter.

--- client/app/MainApp/activitycontroller.coffee
+++ client/app/MainApp/activitycontroller.coffee
@@ -15,7 +15,8 @@
       groupChannel.on 'feed-new', (activities) =>
         @emit 'ActivitiesArrived',
           (KD.remote.revive activity for activity in activities)
-
+          isOnActivityPage = KD.getSingleton("router").getCurrentPath() is "/Activity"
+          ++@newItemsCount  unless isOnActivityPage

     @on "ActivityItemBlockUserClicked",         @bound "openBlockUserModal"
     @on "ActivityItemMarkUserAsTrollClicked",   @bound "markUserAsTroll"
@@ -23,6 +24,8 @@

     @setPageTitleForActivities()

+    KD.getSingleton("appManager").on "AppManagerWantsToShowAnApp", (appController, appView, appOptions) =>
+      @clearNewItemsCount()  if appOptions.name is "Activity"

   blockUser:(accountId, duration, callback)->
     KD.whoami().blockUser accountId, duration, callback
@@ -200,3 +203,12 @@
     @oldTitle      = document.title if document.title.indexOf("Activity") is -1
     document.title = "(#{itemCount}) Activity" if itemCount > 0

+  getNewItemsCount: ->
+    return @newItemsCount
+
+  clearNewItemsCount: ->
+    isOnActivityPage = KD.getSingleton("router").getCurrentPath() is "/Activity"
+    return no if @flags.liveUpdates and not isOnActivityPage
+
+    @newItemsCount = 0
+    @emit "NewItemsCounterCleared"


Fixed: use new spinner instead of old one

--- client/app/views/popover_screens/main.coffee
+++ client/app/views/popover_screens/main.coffee
@@ -88,7 +88,7 @@
     afterRender: ->
         # Cache jQuery selectors.
         @$container   = @$ '.popover-content-wrapper'
-        @addButton    = @$ '.btn.add'
+        @$addButton    = @$ '.btn.add'
         @removeButton = @$ '.remove'
         @spinner = @$ '.remove-spinner'
         @duplicateButton = @$ '.duplicate'
@@ -169,9 +169,9 @@
             @onSetStart()
             @onSetEnd()

-            @addButton.click()
-        else
-            @addButton.removeClass 'disabled'
+            @$addButton.click()
+        else
+            @$addButton.removeClass 'disabled'

     toggleAllDay: ->
@@ -274,14 +274,14 @@

     onAddClicked: ->
         return if @$('.btn.add').hasClass 'disabled'
-        @addButton.html '       '
-        @addButton.spin 'small'
+        spinner = '<img src="img/spinner.svg" alt="spinner" />'
+        @$addButton.empty()
+        @$addButton.append spinner
+
         errors = @model.validate @model.attributes
         if errors
-            @addButton.html @getButtonText()
-            @addButton.children().show()
-
-            @addButton.spin()
+            @$addButton.html @getButtonText()
+
             @$('.alert').remove()
             @$('input').css 'border-color', ''
             @handleError err for err in errors
@@ -295,9 +295,7 @@
                 error: ->
                     alert 'server error occured'
                 complete: =>
-                    @addButton.spin false
-                    @addButton.html @getButtonText()
-                    @addButton.children().show()
+                    @$addButton.html @getButtonText()
                     @popover.selfclose(false)

     handleError: (error) ->


little refactor improving output messages

--- lib/Bumped.plugins.coffee
+++ lib/Bumped.plugins.coffee
@@ -24,14 +24,13 @@

     async.forEachOfSeries type, (settings, name, next) =>
       plugin = @cache[settings.plugin] ?= forceRequire settings.plugin
-      console.log()
-      @bumped.logger.plugin "#{settings.plugin}: #{name}\n"
+      @bumped.logger.plugin "#{settings.plugin}: #{name}"
       plugin @bumped, settings, (err, message) => @print err, message, next
     , cb

-  print: (err, message, cb) ->
+  print: (err, message = '', cb) ->
     return cb err if err
-    message = message.replace(/\n$/, '') # deletes last line break
+    message = message.replace /\n$/, '' # deletes last line break
     @bumped.logger.output message
     cb()


Only create single host view instance

Only create single host view instance

--- src/packages/collaboration/lib/collaboration.coffee
+++ src/packages/collaboration/lib/collaboration.coffee
@@ -5,6 +5,8 @@

 module.exports =
   activate: ->
+    hostView = null
+
     if atom.getLoadSettings().sessionId
       new GuestView(atom.guestSession)
     else
@@ -15,7 +17,7 @@
         pasteboard.write(sessionId) if sessionId

       rootView.command 'collaboration:start-session', ->
-        new HostView(hostSession)
+        hostView ?= new HostView(hostSession)
         if sessionId = hostSession.start()
           pasteboard.write(sessionId)


Allow 'format' function to return an array to make a flat structure

--- lib/ObjectTemplate.coffee
+++ lib/ObjectTemplate.coffee
@@ -109,7 +109,10 @@
   updateContext: (context, node, value, key) =>
     # format key and value
     formatted = @config.applyFormatting node, value, key
-    @aggregateValue context, formatted.key, formatted.value
+    if sysmo.isArray(formatted)
+      @aggregateValue context, item.key, item.value for item in formatted
+    else if formatted?
+      @aggregateValue context, formatted.key, formatted.value

   aggregateValue: (context, key, value) =>
     return context unless value?


Bugfix.

Bugfix.

--- client/publication.coffee
+++ client/publication.coffee
@@ -347,8 +347,7 @@
   # Fields needed when displaying (rendering) the publication: those which are needed for PDF URL to be available
   @DISPLAY_FIELDS: ->
     fields:
-      foreignId: 1
-      source: 1
+      cachedId: 1

 Deps.autorun ->
   if Session.get 'currentPublicationId'


Always generate a table so new items can be added more easily.

--- client/views-table.coffee
+++ client/views-table.coffee
@@ -20,10 +20,10 @@
       (th().text desc)

 record_table = ->
-  return list_empty() if not records.length
-  table().append (thead().append tr().append (th() if root.record_selector isnt do_nothing),
-                                             list_headers()),
-                 tbody().append render_list()
+  [(list_empty() if not records.length),
+   table().append (thead().append tr().append (th() if root.record_selector isnt do_nothing),
+                                              list_headers()),
+                  tbody().append render_list()]

 heading = ->
   (h1().text desc)


matt: added transfer 'type' support, and optional dir create

--- tasks/ftpscript.coffee
+++ tasks/ftpscript.coffee
@@ -6,10 +6,12 @@
       host: 'localhost'
       port: 21
       passive: no
+      type: 'ascii'
       dryrun: no
       ftpCommand: 'ftp'
       encoding: 'utf-8'
       ftpEncoding: 'utf-8'
+      mkdirs: no

     auth = grunt.file.readJSON('.ftppass')?[opts.authKey ? opts.host]

@@ -20,7 +22,7 @@
     cmds = [
       "open #{ opts.host } #{ opts.port }"
       "user #{ auth.username } #{ auth.password }"
-      'type binary'
+      "type #{opts.type}"
       'prompt'
     ]
     cmds.push 'passive' if opts.passive
@@ -30,9 +32,11 @@

     generateUpload dirs, files, f for f in @files

-
-    dirs = for i of dirs
-      "mkdir \"#{ i }\""
+    if opts.mkdirs
+      dirs = for i of dirs
+        "mkdir \"#{ i }\""
+    else
+      dirs = []

     for arg in args
       switch arg
@@ -50,6 +54,8 @@
     if opts.dryrun
       grunt.log.subhead 'Dry-run mode, start display ftp script.'
       grunt.log.writeln cmds
+      grunt.log.writeln 'mkdirs', dirs
+      grunt.log.writeln 'put files', files
       grunt.log.subhead 'End display ftp script.'
     else
       grunt.verbose.subhead 'Start display ftp script.'


update script

update script

--- scripts/unlinked_artists.coffee
+++ scripts/unlinked_artists.coffee
@@ -13,7 +13,7 @@
 _s = require 'underscore.string'
 debug = require('debug') 'scripts'

-db.articles.find({ published: true }).sort(updated_at: -1).toArray (err, articles) ->
+db.articles.find (err, articles) ->
   return exit err if err
   debug "Found #{articles?.length} articles, extracting html..."
   articlesHtmls = articles.map getHtmlFrom
@@ -51,4 +51,4 @@

 exit = (err) ->
   console.error "ERROR", err
-  proces.exit 1
+  process.exit 1


XY: Reorganize abilities, add todos.

XY: Reorganize abilities, add todos.

--- server/xy/data/abilities.coffee
+++ server/xy/data/abilities.coffee
@@ -42,12 +42,48 @@

 # New unique abilities

+# TODO: Aroma Veil
+
 # Implemented in makeAuraAbility
 makeAbility "Aura Break"

 makeAbility 'Bulletproof', ->
   this::isImmune = (type, move) ->
     return true  if move?.hasFlag('bullet')
+
+# TODO: Cheek Pouch
+
+# TODO: Competitive
+
+# TODO: Flower Veil
+
+# TODO: Fur Coat
+
+makeAbility 'Gale Wings', ->
+  this::editPriority = (priority, move) ->
+    # TODO: Test if Gale Wings works with Hidden Power Flying.
+    return priority + 1  if move.type == 'Flying'
+    return priority
+
+# TODO: Gooey
+
+# TODO: Grass Pelt
+
+# TODO: Magician
+
+# TODO: Mega Launcher
+
+makeAbility 'Parental Bond', ->
+  this::calculateNumberOfHits = (move, targets) ->
+    # Do nothing if this move is a multi-hit move or has multiple targets.
+    return  if move.minHits != 1 || targets.length > 1
+    return 2
+
+  this::modifyDamage = (move, target, hitNumber) ->
+    return 0x800  if hitNumber == 2 && move.maxHits == 1
+    return 0x1000
+
+# TODO: Protean

 makeAbility 'Stance Change', ->
   this::beforeMove = (move, user, targets) ->
@@ -63,21 +99,13 @@
   this::switchOut = ->
     @pokemon.changeForme("default")  if !@pokemon.isInForme("default")

-makeAbility 'Gale Wings', ->
-  this::editPriority = (priority, move) ->
-    # TODO: Test if Gale Wings works with Hidden Power Flying.
-    return priority + 1  if move.type == 'Flying'
-    return priority
+# TODO: Strong Jaw

-makeAbility 'Parental Bond', ->
-  this::calculateNumberOfHits = (move, targets) ->
-    # Do nothing if this move is a multi-hit move or has multiple targets.
-    return  if move.minHits != 1 || targets.length > 1
-    return 2
+# TODO: Sweet Veil

-  this::modifyDamage = (move, target, hitNumber) ->
-    return 0x800  if hitNumber == 2 && move.maxHits == 1
-    return 0x1000
+# TODO: Symbiosis
+
+# TODO: Tough Claws

 # Retcons


Started adding color highlighting within the chat messages

--- lib/atox-toxWorker.coffee
+++ lib/atox-toxWorker.coffee
@@ -75,8 +75,8 @@

     @TOX.start()
     @inf "Started TOX"
-    @inf "Name:  #{atom.config.get 'aTox.userName'}"
-    @inf "My ID: #{@TOX.getAddressHexSync()}"
+    @inf "Name:  #{atom.config.get 'aTox.userName'}"
+    @inf "My ID: #{@TOX.getAddressHexSync()}"

     @friendOnline = []

@@ -95,7 +95,7 @@

   reqAvatar: ->
     for i in @TOX.getFriendListSync()
-      @inf "Request Avatar (Friend ID: #{i})"
+      @inf "Requesting Avatar (Friend ID: #{i})"
       @TOX.requestAvatarData( i )

   friendRequestCB: (e) ->
@@ -115,7 +115,7 @@
       tid:    fNum
       pubKey: e.publicKey()
     }
-    @inf "Added Friend #{fNum}"
+    @inf "Added Friend #{fNum}" #TODO: Move this into the contacts, add the randomized color to this string within the contact

     @friendOnline[fNum] = -1

@@ -128,7 +128,7 @@
     try
       ret = @TOX.addGroupchatSync()
     catch e
-      return @err "Faild to add a group chats"
+      return @err "Failed to add group chat"

     @inf "Added group chat #{ret}"

@@ -140,7 +140,7 @@
     }

   groupInviteCB: (e) ->
-    @inf "Recieved group invite from #{e.friend()}"
+    @inf "Received group invite from #{e.friend()}"

     try
       ret = @TOX.joinGroupchatSync e.friend(), e.data()
@@ -224,8 +224,19 @@
       content: "You are now #{e.d}"
       img:      atom.config.get 'aTox.userAvatar'
     }
-
-    @event.emit  'Terminal', {cid: -2, msg: "You are now #{e.d}"} #TODO: Send this to all chat windows
+    color = @getColorByStatus(e.d)
+    @event.emit  'Terminal', {cid: -2, msg: "You are now #{e.d}"} #TODO: Send this to all chat windows
+
+  getColorByStatus: (status) ->
+    console.log status
+    if status is "online"
+      return "rgba(50, 255, 50, 1)"
+    else if status is "offline"
+      return "rgba(80, 80, 80, 1)"
+    else if status is "busy"
+      return "rgba(255, 50, 50, 1)"
+    else if status is "away"
+      return "rgba(255, 255, 50, 1)"

   friendAutoremove: (params) ->
     return @friendOnline[params.fid] = 0 if params.online is true


Removed nonsense

Removed nonsense

--- lib/confirm-dialog.coffee
+++ lib/confirm-dialog.coffee
@@ -128,14 +128,6 @@
     resolve = =>
       @editor = @editorForId(editorId)

-      if @editor?
-        @emitter.emit 'did-change-title' if @editor?
-        #@handleEvents()
-      else
-        # The editor this preview was created for has been closed so close
-        # this preview since a preview cannot be rendered without an editor
-        @parents('.pane').view()?.destroyItem(this)
-
     if atom.workspace?
       resolve()
     else