add module for various experiments, gists

error: pathspec 'src/experiments/various-pull-streams.coffee' did not match any file(s) known to git

--- src/experiments/various-pull-streams.coffee
+++ src/experiments/various-pull-streams.coffee
@@ -0,0 +1,115 @@
+
+
+############################################################################################################
+CND                       = require 'cnd'
+rpr                       = CND.rpr
+badge                     = 'PIPESTREAMS/EXPERIMENTS/VARIOUS-PULL-STREAMS'
+log                       = CND.get_logger 'plain',     badge
+info                      = CND.get_logger 'info',      badge
+whisper                   = CND.get_logger 'whisper',   badge
+alert                     = CND.get_logger 'alert',     badge
+debug                     = CND.get_logger 'debug',     badge
+warn                      = CND.get_logger 'warn',      badge
+help                      = CND.get_logger 'help',      badge
+urge                      = CND.get_logger 'urge',      badge
+echo                      = CND.echo.bind CND
+#...........................................................................................................
+PS                        = require '../..'
+{ $, $async, }            = PS
+#...........................................................................................................
+after                     = ( dts, f ) -> setTimeout f, dts * 1000
+{ jr }                    = CND
+
+# https://pull-stream.github.io/#pull-through
+# nope https://github.com/dominictarr/pull-flow (https://github.com/pull-stream/pull-stream/issues/4)
+
+# https://github.com/pull-stream/pull-cont
+# https://github.com/pull-stream/pull-defer
+# https://github.com/scrapjs/pull-imux
+
+#-----------------------------------------------------------------------------------------------------------
+demo_merge_1 = ->
+  ### https://github.com/pull-stream/pull-merge ###
+  pull      = require 'pull-stream'
+  merge     = require 'pull-merge'
+  pipeline  = []
+  # pipeline.push merge ( pull.values [ 1, 5, 6, ] ), ( pull.values [ 2, 4, 7, ] )
+  # pipeline.push merge ( pull.values [ 1, 5, 6, ] ), ( pull.values [ 2, 4, 7, 10, 11, 12, ] )
+  # pipeline.push merge ( pull.values [ 1, 5, 6, ] ), ( pull.values [] )
+  # pipeline.push merge ( pull.values [ 1, 5, 6, ] ), ( pull.values [ 1, 5, 6, ] )
+  # pipeline.push merge ( pull.values [ [1], [5], [6], ] ), ( pull.values [ [1], [5], [6], [7], ] )
+  pipeline.push merge ( pull.values [ 1, 5, 6, ] ), ( pull.values [ 1, 5, 6, ] ), ( a, b ) -> -1
+  pipeline.push pull.collect ( error, collector ) ->
+    throw error if error?
+    help collector
+  pull pipeline...
+  return null
+
+#-----------------------------------------------------------------------------------------------------------
+new_async_source = ( name ) ->
+    source    = PS.new_push_source()
+    pipeline  = []
+    pipeline.push source
+    pipeline.push PS.$watch ( d ) -> urge name, jr d
+    R         = PS.pull pipeline...
+    R.push    = ( x ) -> source.push x
+    R.end     = -> source.end()
+    return R
+
+#-----------------------------------------------------------------------------------------------------------
+demo_merge_async_sources = ->
+  ### won't take all inputs from both sources ###
+  merge     = require 'pull-merge'
+  source_1 = new_async_source 's1'
+  source_2 = new_async_source 's2'
+  return new Promise ( resolve ) ->
+    pipeline  = []
+    pipeline.push merge source_2, source_1, ( a, b ) -> -1
+    pipeline.push PS.$watch ( d ) -> help '-->', jr d
+    pipeline.push PS.$drain ->
+      help 'ok'
+      resolve null
+    PS.pull pipeline...
+    after 0.1, -> source_2.push 4
+    after 0.2, -> source_2.push 5
+    after 0.3, -> source_2.push 6
+    after 0.4, -> source_1.push 1
+    after 0.5, -> source_1.push 2
+    after 0.6, -> source_1.push 3
+    # after 1.0, -> source_1.push null
+    # after 1.0, -> source_2.push null
+    return null
+
+#-----------------------------------------------------------------------------------------------------------
+demo_mux_async_sources = ->
+  mux       = require 'pull-mux'
+  source_1  = new_async_source 's1'
+  source_2  = new_async_source 's2'
+  $demux    = -> PS.map ( [ k, v, ] ) -> v
+  # $demux    = $ ( [ k, v, ], send ) -> send v
+  return new Promise ( resolve ) ->
+    pipeline  = []
+    pipeline.push mux { s1: source_1, s2: source_2, }
+    pipeline.push $demux()
+    pipeline.push PS.$collect()
+    pipeline.push PS.$watch ( d ) -> help '-->', jr d
+    pipeline.push PS.$drain ->
+      help 'ok'
+      resolve null
+    PS.pull pipeline...
+    after 0.1, -> source_2.push 4
+    after 0.5, -> source_1.push 2
+    after 0.6, -> source_1.push 3
+    after 0.2, -> source_2.push 5
+    after 0.3, -> source_2.push 6
+    after 0.4, -> source_1.push 1
+    after 1.0, -> source_1.end()
+    after 1.0, -> source_2.end()
+    return null
+
+############################################################################################################
+unless module.parent?
+  # demo_merge_1()
+  # demo_merge_async_sources()
+  demo_mux_async_sources()
+


Use Editor::getVisibleRowRange instead of the rendered row range

The rendered row range is larger than the visible row range to force the
DOM to break up repaints. This is a more accurate method to us.

--- src/react-editor-view.coffee
+++ src/react-editor-view.coffee
@@ -122,9 +122,9 @@
     @component?.getModel()

   getFirstVisibleScreenRow: ->
-    @component.getRenderedRowRange()[0]
+    @editor.getVisibleRowRange()[0]

   getLastVisibleScreenRow: ->
-    @component.getRenderedRowRange()[1]
+    @editor.getVisibleRowRange()[1]

   requestDisplayUpdate: -> # No-op shim for find-and-replace


Fixed issue where label filtering didnt work

Closes #18375

--- app/assets/javascripts/labels_select.js.coffee
+++ app/assets/javascripts/labels_select.js.coffee
@@ -254,7 +254,7 @@
         search:
           fields: ['title']
         selectable: true
-
+        filterable: true
         toggleLabel: (selected, el) ->
           selected_labels = $('.js-label-select').siblings('.dropdown-menu-labels').find('.is-active')


Remove console.log

Remove console.log

--- app/assets/javascripts/labels_select.js.coffee
+++ app/assets/javascripts/labels_select.js.coffee
@@ -316,7 +316,6 @@

         setIndeterminateIds: ->
           if @dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')
-            console.log 'options.setIndeterminateIds'
             @indeterminateIds = _this.getIndeterminateIds()
       )


i am a stupid

i am a stupid

--- app/assets/javascripts/notifications.js.coffee
+++ app/assets/javascripts/notifications.js.coffee
@@ -26,4 +26,4 @@
     if $('li.notification-item').length > 0
       notification_css_id = $('li.notification-item').first().attr('id')
       notification_id = /\d+/.exec(notification_css_id)
-      $.post("notifications/mark_as_viewed?latest_viewed=#{notification_id}")
+      $.post("/notifications/mark_as_viewed?latest_viewed=#{notification_id}")


Fixing ADMIN.PROJECT_VALUES.ERROR_DELETE_ALL translation

--- app/coffee/modules/admin/project-values.coffee
+++ app/coffee/modules/admin/project-values.coffee
@@ -293,7 +293,7 @@
             subtitle = value.name

             if _.keys(choices).length == 0
-                return $confirm.error("ADMIN.PROJECT_VALUES.ERROR_DELETE_ALL")
+                return $confirm.error($translate.instant("ADMIN.PROJECT_VALUES.ERROR_DELETE_ALL"))

             title = $translate.instant("ADMIN.COMMON.TITLE_ACTION_DELETE_VALUE")
             text = $translate.instant("ADMIN.PROJECT_VALUES.REPLACEMENT")


Add a FIXME for this workspaceView bit

Add a FIXME for this workspaceView bit

--- spec/atom-spec.coffee
+++ spec/atom-spec.coffee
@@ -5,9 +5,6 @@
 ThemeManager = require '../src/theme-manager'

 describe "the `atom` global", ->
-  beforeEach ->
-    atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView
-
   describe 'window sizing methods', ->
     describe '::getPosition and ::setPosition', ->
       it 'sets the position of the window, and can retrieve the position just set', ->
@@ -35,6 +32,9 @@

   describe "window:update-available", ->
     it "is triggered when the auto-updater sends the update-downloaded event", ->
+      # FIXME: We need to figure out a way minus workspaceView to handle update-available events.
+      atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView
+
       updateAvailableHandler = jasmine.createSpy("update-available-handler")
       atom.workspaceView.on 'window:update-available', updateAvailableHandler
       autoUpdater = require('remote').require('auto-updater')


prevents linecharts with only one point

prevents linecharts with only one point

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/xaun/impac-angular.git/'


Check that display isn't none for visibility

--- spec/pane-spec.coffee
+++ spec/pane-spec.coffee
@@ -36,7 +36,7 @@
       expect(pane.activeItem).toBe view1
       pane.showItem(view2)
       expect(view1.css('display')).toBe 'none'
-      expect(view2.css('display')).toBe ''
+      expect(view2.css('display')).not.toBe 'none'
       expect(pane.activeItem).toBe view2

     it "triggers 'pane:active-item-changed' if the item isn't already the activeItem", ->
@@ -90,7 +90,7 @@
         it "appends and shows a view to display the item based on its `.getViewClass` method", ->
           pane.showItem(editSession1)
           editor = pane.activeView
-          expect(editor.css('display')).toBe ''
+          expect(editor.css('display')).not.toBe 'none'
           expect(editor.activeEditSession).toBe editSession1

       describe "when a valid view has already been appended for another item", ->
@@ -99,7 +99,7 @@
           pane.showItem(editSession2)
           expect(pane.itemViews.find('.editor').length).toBe 2
           editor = pane.activeView
-          expect(editor.css('display')).toBe ''
+          expect(editor.css('display')).not.toBe 'none'
           expect(editor.activeEditSession).toBe editSession2

         it "creates a new view with the item", ->


reporters folder

reporters folder

error: pathspec 'src/reporters/xml-pmd.coffee' did not match any file(s) known to git

--- src/reporters/xml-pmd.coffee
+++ src/reporters/xml-pmd.coffee
@@ -0,0 +1,24 @@
+Map = require('./map').Map
+
+exports = (map, options) ->
+
+    result = ""
+    xmlDoc = "<?xml version='1.0' encoding='UTF-8' ?><pmd-cpd>"
+    verbose = options.verbose
+
+    for clone in map.clones
+      do (clone) ->
+        result = result +
+    "\n\t-#{clone.firstFile}:#{clone.firstFileStart}-#{clone.firstFileStart + clone.linesCount}\n\t
+    #{clone.secondFile}:#{clone.secondFileStart}-#{clone.secondFileStart + clone.linesCount}\n\t"
+
+        result = "#{result}\n#{clone.getLines()}" if verbose
+        xmlDoc = "#{xmlDoc}
+    <duplication lines='#{clone.linesCount}' tokens='#{clone.tokensCount}'>
+    <file path='#{clone.firstFile}' line='#{clone.firstFileStart}'/>
+    <file path='#{clone.secondFile}' line='#{clone.secondFileStart}'/>
+    <codefragment>#{htmlspecialchars(clone.getLines())}</codefragment>
+    </duplication>"
+
+    xmlDoc = xmlDoc + "</pmd-cpd>"
+    fs.writeFileSync(options.output, xmlDoc) if options.output


add content for an about component

add content for an about component

error: pathspec 'assets/coffee/components/About.cjsx' did not match any file(s) known to git

--- assets/coffee/components/About.cjsx
+++ assets/coffee/components/About.cjsx
@@ -0,0 +1,100 @@
+React = require 'react'
+
+About = React.createClass
+  displayName: 'About'
+
+  render: ->
+

+
+
About

+
+
You're at a party. You're having an adequate time. And then, it happens:

+
+
"If you were stuck on a desert island for the rest of your life with only one band to listen to, whom would you choose?"

+
+
Ahhh, yes; what a wonderful game for us to play! From the douche who says Jack Johnson (bro!) to the tyrannical majority that cannot understand people who don't pick the Beatles (dude!) right down to the dirty dude who can't stop talking about his Dead collection (come on man!), this perfunctory and scripted conversation should make any thinking person with a shred of human dignity want to vomit blood for about three hours.

+
+
And you know the person who started all of this did so after posting the Top 10 Inspirational People of 2013 on their Facebook page. You just fucking know that...

+
+
Well, we're here to tell you that we've had enough of this. We think the world needs a little bitter despair straight form the Heart of Darkness, and we're here to give it to you.

+
+
In this spirit, we ask a better question:

+
+
If you were marooned on a desert island and you were limited to the music of only ONE band, what band would immediately cause you to choose suicide over survival?

+
+
What catalogue is so hideous and beyond redemption that you'd rather disembowel yourself with a coconut shank? We all have our individual tastes by style and artist, but who cuts across our petty differences to objectively sound the brownest of notes? What is the sum of our fears?

+
+
The process

+
+
Round 1: The Nominating

+
+
You, dear reader, will email us your nominations. You may nominate anyone, though see the FAQ for some conditions. Nomination frequency will be used to seed brackets for Round 2.

+
+
Round 2: The Brackets

+
+
The top 64 nominated acts will be put into NCAA style brackets with four Regions: Cleveland, Detroit, St Louis, Des Moines or maybe Mississippi, Alabama, Arkansas, Missouri On-line voting will take place until a Fatal Four has been chosen. Brackets will be used rather than simply tallying nominations because the latter is boring (you asshole) and we really want to force the voters into some hard decisions. Making a list is one thing. Choosing between Nickelback and Creed, however, will foment the type of existential crisis we're looking for here.

+
+
Round 3: The Foul Four Great Debate & Chautauqua at Doha: Lincoln vs. Bohr vs. Douglas vs. Einstein Part VII: The Reckoning: The Revenge.

+
+
Once the Fatal Four have been settled upon, the winner will be chosen at a live event (data and venue TBA). Here, 4 intrepid souls will each give a short presentation defending one of the Fatal Four, after which the Prophesy will come to pass and a winner will be crowned.

+
+
There will be two "winners" in our little competition.

+
+

+
The "talent", i.e, the Desert Island Suicide Band TM.

+
The voter with the most insight into all that is fetid and herpes-infested in this world, or the person whose bracket is closest to the ‘winning' bracket.

+

+
+
The rules

+
+
1. No one hit wonders.

+
+
To qualify for the competition, any band has to have at least 3 studio albums. As deserved as it might be, the Baha Men winning DISG would be deeply unsatisfying, and this rule is here to prevent that.

+
+
2. No acts that aren't really trying

+
+
This is left to the organizers discretion. "Trying" means that the act is at least attempting to make good music. We will not include acts that are simply corporate entities (e.g., Jonas Brothers) or child molester-assembled singing collectives (e.g., Backstreet Boys), etc. We will be transparent about who is not included and open to appeals, though, so feel free to nominate anyone.

+
+
That said, finding that Menudo is the worst act ever would be the ultimate in sister-kissing, and this rule is here to ensure that this does not happen.

+
+
FAQ

+
+
1. Is it just bands? Can I nominate solo artists?

+
+
Both solo artists and bands are included.

+
+
2. How do I submit my nominations?

+
+
Sign in to the app and submit a band in the form.

+
+
3. Can any style of music qualify?

+
+
Yes! One of the goals of this game is to average across the idiosyncrasies of our individual loathing. Some hate classic rock while others detest prog. All that really matters is that you free the black bile from the inner chasm where your soul should be.

+
+
4. What criteria may I use?

+
+
Ideally, the only criteria should be musical content. For example, every person with human blood hates Kanye West or Ryan Adams, but if you like their music you shouldn't nominate them. Remember, on the Island you will not be hanging out with these people, you will be listening to their catalogue. For a time anyway.

+
+
5. But if I were on a dessert island, I would get sick of any band!

+
+
No, if you were stuck on a dessert island you would have fancy pastries, gourmet cakes and sumptuous pies for the rest of your life.

+
+
6. But if I were on a desert island, I would get sick of any band!

+
+
Please refrain from playing our game.

+
+
7. But if I were on a desert island, I would just shut the music off – I wouldn't kill myself!

+
+
Please refrain from playing our game.

+
+
8. But if I were on a desert island, where would I get the power to play music for life? Surely at some point I would run out of battery power...

+
+
Please refrain from playing our game.

+
+
9. In episode 2F09, when Itchy plays Scratchy's skeleton like a xylophone, he strikes that same rib twice in succession yet he produces two clearly different tones. I mean, what are we, to believe that this is some sort of a, a magic xylophone or something?

+
+
Please refrain from playing our game.

+
+

+
+module.exports = About


[bot] [fix] removing arbitrary timeouts in queue

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/Mikuia/Mikuia.git/'


Add a generic config script for the server

error: pathspec 'server/config.coffee' did not match any file(s) known to git


Copy repository in remaining specs

Copy repository in remaining specs

--- spec/git-spec.coffee
+++ spec/git-spec.coffee
@@ -126,15 +126,12 @@
       expect(-> repo.getShortHead()).toThrow()

   describe ".getPathStatus(path)", ->
-    [filePath, originalPathText] = []
-
-    beforeEach ->
-      repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
-      filePath = require.resolve('./fixtures/git/working-dir/file.txt')
-      originalPathText = fs.readFileSync(filePath, 'utf8')
-
-    afterEach ->
-      fs.writeFileSync(filePath, originalPathText)
+    [filePath] = []
+
+    beforeEach ->
+      workingDirectory = copyRepository()
+      repo = new Git(workingDirectory)
+      filePath = path.join(workingDirectory, 'file.txt')

     it "trigger a status-changed event when the new status differs from the last cached one", ->
       statusHandler = jasmine.createSpy("statusHandler")
@@ -149,16 +146,13 @@
       expect(statusHandler.callCount).toBe 1

   describe ".getDirectoryStatus(path)", ->
-    [directoryPath, filePath, originalPathText] = []
-
-    beforeEach ->
-      repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
-      directoryPath = path.join(__dirname, 'fixtures', 'git', 'working-dir', 'dir')
-      filePath = require.resolve('./fixtures/git/working-dir/dir/b.txt')
-      originalPathText = fs.readFileSync(filePath, 'utf8')
-
-    afterEach ->
-      fs.writeFileSync(filePath, originalPathText)
+    [directoryPath, filePath] = []
+
+    beforeEach ->
+      workingDirectory = copyRepository()
+      repo = new Git(workingDirectory)
+      directoryPath = path.join(workingDirectory, 'dir')
+      filePath = path.join(directoryPath, 'b.txt')

     it "gets the status based on the files inside the directory", ->
       expect(repo.isStatusModified(repo.getDirectoryStatus(directoryPath))).toBe false
@@ -170,17 +164,14 @@
     [newPath, modifiedPath, cleanPath, originalModifiedPathText] = []

     beforeEach ->
-      repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
-      modifiedPath = atom.project.resolve('git/working-dir/file.txt')
-      originalModifiedPathText = fs.readFileSync(modifiedPath, 'utf8')
-      newPath = atom.project.resolve('git/working-dir/untracked.txt')
-      cleanPath = atom.project.resolve('git/working-dir/other.txt')
+      workingDirectory = copyRepository()
+      repo = new Git(workingDirectory)
+      modifiedPath = path.join(workingDirectory, 'file.txt')
+      newPath = path.join(workingDirectory, 'untracked.txt')
+      cleanPath = path.join(workingDirectory, 'other.txt')
+      fs.writeFileSync(cleanPath, 'Full of text')
       fs.writeFileSync(newPath, '')
       newPath = fs.absolute newPath  # specs could be running under symbol path.
-
-    afterEach ->
-      fs.writeFileSync(modifiedPath, originalModifiedPathText)
-      fs.removeSync(newPath) if fs.existsSync(newPath)

     it "returns status information for all new and modified files", ->
       fs.writeFileSync(modifiedPath, 'making this path modified')


client: added an i18n coffeescript module that provides `i18n._()` to the client side templates.

error: pathspec 'src/awraamba/coffee/i18n.coffee' did not match any file(s) known to git

--- src/awraamba/coffee/i18n.coffee
+++ src/awraamba/coffee/i18n.coffee
@@ -0,0 +1,20 @@
+# Use `i18n._()` to translate message strings, if a translated version of the
+# string has been provided using ``i18n.register_strings()``, e.g.:
+#
+#     i18n.register_strings hello: 'bonjour'
+#     i18n._ 'hello'
+#     => 'bonjour'
+#
+define 'i18n', (exports, root) ->
+
+  _msg_strings = {}
+
+  register_strings = (data) ->
+    _msg_strings = _.update(_msg_strings, data)
+
+  translate = (s) ->
+    if s of _msg_strings then _msg_strings[s] else s
+
+  exports.register_strings = register_strings
+  exports._ = exports.translate = translate
+


Fix a typo and some scope issues.

Fix a typo and some scope issues.

--- src/spine.ajax.coffee
+++ src/spine.ajax.coffee
@@ -2,13 +2,12 @@
 $     = Spine.$
 Model = Spine.Model

-getURL = (object) ->
-  object and object.url?() or object.url
-
 Ajax =
   enabled:  true
   pending:  false
   requests: []
+  getURL: (object) ->
+    object and object.url?() or object.url

   disable: (callback) ->
     @enabled = false
@@ -44,7 +43,7 @@
 class Collection extends Base
   constructor: (@model) ->
     super
-    @url = getURL(@model)
+    @url = Ajax.getURL(@model)

   findAll: (params) ->
     @send params,
@@ -67,7 +66,7 @@
   constructor: (@record) ->
     super
     @model = @record.constructor
-    @url   = getURL(@record)
+    @url   = Ajax.getURL(@record)

   find: (params) ->
     @send params
@@ -130,7 +129,7 @@
   ajax: -> new Singleton(this)

   url: ->
-    base = Ajax.getUrl(@constructor)
+    base = Ajax.getURL(@constructor)
     base += "/" unless base.charAt(base.length - 1) is "/"
     base += encodeURIComponent(@id)
     base


[added] 'link-to' snippet

[added] 'link-to' snippet

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/AlexKVal/dotfiles.git/'


fix for no user logged

fix for no user logged

--- app/views/docs/components_view.coffee
+++ app/views/docs/components_view.coffee
@@ -34,5 +34,5 @@
     if (me.get('aceConfig')?.language?) is false
       c.language = 'javascript'
     else
-      c.language = JSON.stringify(me.get('aceConfig').language)
+      c.language = me.get('aceConfig').language
     c


bug fix

bug fix

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/bubblegroup/bubblebot.git/'


Fixed the title in the gold view to handle when goldEarned isn't available.

--- app/views/play/level/gold_view.coffee
+++ app/views/play/level/gold_view.coffee
@@ -34,7 +34,13 @@
     @shownOnce = true

   updateTitle: ->
-    @$el.attr 'title', ("Team '#{team}' has #{gold} now of #{@teamGoldEarned[team]} gold earned." for team, gold of @teamGold).join ' '
+    strings = []
+    for team, gold of @teamGold
+      if @teamGoldEarned[team]
+        strings.push "Team '#{team}' has #{gold} now of #{@teamGoldEarned[team]} gold earned."
+      else
+        strings.push "Team '#{team}' has #{gold} gold."
+    @$el.attr 'title', strings.join ' '

   onSetLetterbox: (e) ->
     @$el.toggle not e.on if @shownOnce


Always force '\n' not '\r\n' when getting the value out of CM to make windows happy

--- src/client/cm.coffee
+++ src/client/cm.coffee
@@ -42,7 +42,7 @@
   sharedoc = @
   check = ->
     window.setTimeout ->
-        editorText = editor.getValue()
+        editorText = editor.getValue('\n')
         otText = sharedoc.getText()

         if editorText != otText
@@ -54,7 +54,7 @@
       , 0

   if keepEditorContents
-    @del 0, sharedoc.getText().length
+    @del 0, sharedoc.getText('\n').length
     @insert 0, editor.getValue()
   else
     editor.setValue sharedoc.getText()


scanInRange does not call positionForCharacterIndex for a match until the given iterator visits it.

Optimization to speed up buffer scanning in large files.

--- src/app/buffer.coffee
+++ src/app/buffer.coffee
@@ -162,72 +162,65 @@

     @mode = new (require("ace/mode/#{modeName}").Mode)

-  scanInRange: (regex, range, iterator) ->
+  matchesInCharacterRange: (regex, startIndex, endIndex) ->
+    text = @getText()
+    matches = []
+
+    regex.lastIndex = startIndex
+    while match = regex.exec(text)
+      matchLength = match[0].length
+      matchStartIndex = match.index
+      matchEndIndex = matchStartIndex + matchLength
+
+      if matchEndIndex > endIndex
+        regex.lastIndex = 0
+        if matchStartIndex < endIndex and submatch = regex.exec(text[matchStartIndex...endIndex])
+          submatch.index = matchStartIndex
+          matches.push submatch
+        break
+
+      matchEndIndex++ if matchLength is 0
+      regex.lastIndex = matchEndIndex
+      matches.push match
+
+    matches
+
+  scanInRange: (regex, range, iterator, reverse=false) ->
     range = Range.fromObject(range)
     global = regex.global
     regex = new RegExp(regex.source, 'gm')

-    text = @getText()
     startIndex = @characterIndexForPosition(range.start)
     endIndex = @characterIndexForPosition(range.end)
+
+    matches = @matchesInCharacterRange(regex, startIndex, endIndex)
     lengthDelta = 0

-    while true
-      regex.lastIndex = startIndex
-      return unless match = regex.exec(text)
-
+    keepLooping = null
+    replacementText = null
+    stop = -> keepLooping = false
+    replace = (text) -> replacementText = text
+
+    matches.reverse() if reverse
+    for match in matches
       matchLength = match[0].length
       matchStartIndex = match.index
       matchEndIndex = matchStartIndex + matchLength
-
-      if matchEndIndex > endIndex
-        regex.lastIndex = 0
-        if matchStartIndex < endIndex and match = regex.exec(text[matchStartIndex...endIndex])
-          matchLength = match[0].length
-          matchEndIndex = matchStartIndex + matchLength
-        else
-          return

       startPosition = @positionForCharacterIndex(matchStartIndex + lengthDelta)
       endPosition = @positionForCharacterIndex(matchEndIndex + lengthDelta)
       range = new Range(startPosition, endPosition)
       keepLooping = true
       replacementText = null
-      stop = -> keepLooping = false
-      replace = (text) -> replacementText = text
       iterator(match, range, { stop, replace })

       if replacementText
         @change(range, replacementText)
-        lengthDelta += replacementText.length - matchLength
-
-      if matchLength is 0
-        matchStartIndex++
-        matchEndIndex++
+        lengthDelta += replacementText.length - matchLength unless reverse

       break unless global and keepLooping
-      startIndex = matchEndIndex

   backwardsScanInRange: (regex, range, iterator) ->
-    global = regex.global
-    regex = new RegExp(regex.source, 'gm')
-
-    matches = []
-    @scanInRange regex, range, (match, matchRange) ->
-      matches.push([match, matchRange])
-
-    matches.reverse()
-
-    keepLooping = true
-    stop = -> keepLooping = false
-    replacementText = null
-    replace = (text) -> replacementText = text
-
-    for [match, matchRange] in matches
-      replacementText = null
-      iterator(match, matchRange, { stop, replace })
-      @change(matchRange, replacementText) if replacementText
-      return unless global and keepLooping
-
+    @scanInRange regex, range, iterator, true

 _.extend(Buffer.prototype, EventEmitter)


Update config

Update config

--- src/app/config.coffee
+++ src/app/config.coffee
@@ -88,7 +88,19 @@
     @watchSubscription?.close()
     @watchSubscription = null

-  # Public: Retrieves the setting for the given key.
+  setDefaults: (keyPath, defaults) ->
+    keys = keyPath.split('.')
+    hash = @defaultSettings
+    for key in keys
+      hash[key] ?= {}
+      hash = hash[key]
+
+    _.extend hash, defaults
+    @update()
+
+  ### Public ###
+
+  # Retrieves the setting for the given key.
   #
   # keyPath - The {String} name of the key to retrieve
   #
@@ -98,25 +110,28 @@
     _.valueForKeyPath(@settings, keyPath) ?
       _.valueForKeyPath(@defaultSettings, keyPath)

-  # Public: Retrieves the setting for the given key as an integer number.
+
+  # Retrieves the setting for the given key as an integer.
   #
   # keyPath - The {String} name of the key to retrieve
+  #
   # Returns the value from Atom's default settings, the user's configuration file,
   # or `NaN` if the key doesn't exist in either.
   getInt: (keyPath, defaultValueWhenFalsy) ->
     parseInt(@get(keyPath))

-  # Public: Retrieves the setting for the given key as a positive integer number.
+  # Retrieves the setting for the given key as a positive integer.
   #
   # keyPath - The {String} name of the key to retrieve
   # defaultValue - The integer {Number} to fall back to if the value isn't
   #                positive
+  #
   # Returns the value from Atom's default settings, the user's configuration file,
   # or `defaultValue` if the key value isn't greater than zero.
   getPositiveInt: (keyPath, defaultValue) ->
     Math.max(@getInt(keyPath), 0) or defaultValue
-
-  # Public: Sets the value for a configuration setting.
+
+  # Sets the value for a configuration setting.
   #
   # This value is stored in Atom's internal configuration file.
   #
@@ -129,17 +144,7 @@
     @update()
     value

-  setDefaults: (keyPath, defaults) ->
-    keys = keyPath.split('.')
-    hash = @defaultSettings
-    for key in keys
-      hash[key] ?= {}
-      hash = hash[key]
-
-    _.extend hash, defaults
-    @update()
-
-  # Public: Establishes an event listener for a given key.
+  # Establishes an event listener for a given key.
   #
   # Whenever the value of the key is changed, a callback is fired.
   #
@@ -160,6 +165,18 @@
     callback(value)
     subscription

+  ### Internal ###
+
+  setDefaults: (keyPath, defaults) ->
+    keys = keyPath.split('.')
+    hash = @defaultSettings
+    for key in keys
+      hash[key] ?= {}
+      hash = hash[key]
+
+    _.extend hash, defaults
+    @update()
+
   update: ->
     return if @configFileHasErrors
     @save()


Only update gutter when editor is attached

--- src/app/editor.coffee
+++ src/app/editor.coffee
@@ -406,12 +406,13 @@
   handleRendererChange: (e) ->
     oldScreenRange = e.oldRange
     newScreenRange = e.newRange
-    unless newScreenRange.isSingleLine() and newScreenRange.coversSameRows(oldScreenRange)
-      @gutter.renderLineNumbers(@getFirstVisibleScreenRow(), @getLastVisibleScreenRow())

     @compositeCursor.updateBufferPosition() unless e.bufferChanged

     if @attached
+      unless newScreenRange.isSingleLine() and newScreenRange.coversSameRows(oldScreenRange)
+        @gutter.renderLineNumbers(@getFirstVisibleScreenRow(), @getLastVisibleScreenRow())
+
       lineElements = @buildLineElements(newScreenRange.start.row, newScreenRange.end.row)
       @replaceLineElements(oldScreenRange.start.row, oldScreenRange.end.row, lineElements)
       @verticalScrollbarContent.height(@lineHeight * @screenLineCount())


RootView can no longer be focused.

RootView can no longer be focused.

Allowing root view to be focused was stealing focus away from the
editor whenever a click event made it to the root view. This unnecessary
switching of focus was interfering with the ability to drag tabs.

But if RootView can't be focused, focus ends up being returned to the
document body when there are no focusable elements. This would be fine,
except for the fact that we frequently bind global events on root view,
and so they aren't triggered when events are triggered on the body. We
could just bind all global events on the body, but this would require
us to always attach elements to the DOM during specs, which is a serious
performance killer in specs.

The workaround is in the keymap. When the keymap handles a key event
that was triggered on the body, it triggers the corresponding semantic
event on the root view anyway, so from the event perspective, it's as
if the root view actually had focus. The only place this might fall
down is if someone wants to capture raw key events. But that's the
keymap's job anyway, and we maybe add a hook on the keymap if such a
need ever arises.

--- src/app/keymap.coffee
+++ src/app/keymap.coffee
@@ -73,6 +73,7 @@
     return true unless bindingSetsForFirstKeystroke?

     currentNode = $(event.target)
+    currentNode = rootView if currentNode is $('body')[0]
     while currentNode.length
       candidateBindingSets = @bindingSetsForNode(currentNode, bindingSetsForFirstKeystroke)
       for bindingSet in candidateBindingSets


testing conditional display

testing conditional display

error: pathspec 'src/test/services/display.coffee' did not match any file(s) known to git

--- src/test/services/display.coffee
+++ src/test/services/display.coffee
@@ -0,0 +1,92 @@
+##
+## display.coffee
+##
+## Created by Frederic DELBOS - fred.delbos@gmail.com on Dec  9 2013.
+## This file is subject to the terms and conditions defined in
+## file 'LICENSE.txt', which is part of this source code package.
+##
+
+describe 'display tests', ->
+
+  beforeEach(module('CoolFormServices'))
+
+  it 'test show when', inject((eventService, displayService) ->
+    values =
+      field1: "no"
+    events = eventService()
+    condition =
+      field: "field1"
+      values: ["yes", true, 1]
+    display = displayService(events, values)
+    shouldShow = false
+
+    display.showWhen([condition], (val) ->
+      shouldShow = val)
+
+    expect(shouldShow).toEqual false
+
+    values["field1"] = "yes"
+    events.handle("field1", "change", "yes")
+    expect(shouldShow).toEqual true
+
+    values["field1"] = "no"
+    events.handle("field1", "change", "no")
+    expect(shouldShow).toEqual false
+
+    values["field1"] = true
+    events.handle("field1", "change", true)
+    expect(shouldShow).toEqual true
+
+    values["field1"] = false
+    events.handle("field1", "change", false)
+    expect(shouldShow).toEqual false
+
+    values["field1"] = 1
+    events.handle("field1", "change", 1)
+    expect(shouldShow).toEqual true
+
+    values["field1"] = 0
+    events.handle("field1", "change", 0)
+    expect(shouldShow).toEqual false
+  )
+
+  it 'test hide when', inject((eventService, displayService) ->
+    values =
+      field1: "no"
+    events = eventService()
+    condition =
+      field: "field1"
+      values: ["yes", true, 1]
+    display = displayService(events, values)
+
+    shouldShow = true
+
+    display.hideWhen([condition], (val) ->
+      shouldShow = val)
+
+    expect(shouldShow).toEqual true
+
+    values["field1"] = "yes"
+    events.handle("field1", "change", "yes")
+    expect(shouldShow).toEqual false
+
+    values["field1"] = "no"
+    events.handle("field1", "change", "no")
+    expect(shouldShow).toEqual true
+
+    values["field1"] = true
+    events.handle("field1", "change", true)
+    expect(shouldShow).toEqual false
+
+    values["field1"] = false
+    events.handle("field1", "change", false)
+    expect(shouldShow).toEqual true
+
+    values["field1"] = 1
+    events.handle("field1", "change", 1)
+    expect(shouldShow).toEqual false
+
+    values["field1"] = 0
+    events.handle("field1", "change", 0)
+    expect(shouldShow).toEqual true
+  )


Fixed overaggressive record fetching through sparse array

--- packages/emberella/lib/views/list_view.coffee
+++ packages/emberella/lib/views/list_view.coffee
@@ -65,6 +65,19 @@

 Emberella.ListView = Emberella.CollectionView.extend Ember.ScrollHandlerMixin, Ember.ResizeHandler,

+  init: ->
+    ret = @_super()
+    @_renderList()
+    ret
+
+  ###
+    @property isEmberellaListView
+    @type Boolean
+    @default true
+    @final
+  ###
+  isEmberellaListView: true
+
   ###
     Add the class name `emberella-list-view`.

@@ -182,11 +195,6 @@
     @type Integer
   ###
   height: Ember.computed.alias '_height'
-
-  init: ->
-    ret = @_super()
-    @_renderList()
-    ret

   ###
     A computed property that indicates the height of the scrollable content.
@@ -668,7 +676,7 @@
     @param {Boolean} dontFetch
     @return null
   ###
-  _finalizeReuseChildForContentIndex: (childView, contentIndex, dontFetch = false) ->
+  _finalizeReuseChildForContentIndex: (childView, contentIndex, dontFetch) ->
     return if get(childView, 'isDestroyed')

     content = get @, 'content'
@@ -799,3 +807,15 @@
   _visibleItemsDidChange: Ember.observer ->
     @trigger('visibleItemsDidChange', (@numberOfVisibleItems() || 0))
   , 'visibleRows'
+
+  ###
+    @private
+
+    Request list item data if shouldRequestObjects property becomes `true`
+    on content.
+
+    @method _shouldRequestObjectsDidChange
+  ###
+  _shouldRequestObjectsDidChange: Ember.observer ->
+    @_updateChildViews() if get(@, 'content.shouldRequestObjects')
+  , 'content.shouldRequestObjects'


Log RootView::openAsync read progress

Log RootView::openAsync read progress

--- src/root-view.coffee
+++ src/root-view.coffee
@@ -1,3 +1,4 @@
+{fs} = require 'atom'
 ipc = require 'ipc'
 path = require 'path'
 Q = require 'q'
@@ -171,6 +172,7 @@
   #
   # Returns a promise that resolves to the {EditSession} for the file URI.
   openAsync: (filePath, options={}) ->
+    absoluteFilePath = filePath
     filePath = project.relativize(filePath)
     initialLine = options.initialLine
     activePane = @getActivePane()
@@ -178,19 +180,24 @@
     editSession = activePane.itemForUri(filePath) if activePane and filePath
     promise = project.openAsync(filePath, {initialLine}) if not editSession

-    returnedPromise = Q(editSession ? promise)
-    returnedPromise.done (editSession) =>
-      if not activePane
-        activePane = new Pane(editSession)
-        @panes.setRoot(activePane)
-
-      activePane.showItem(editSession)
-      activePane.focus()
-
-    returnedPromise
+    fileSize = 0
+    fileSize = fs.statSync(absoluteFilePath).size if fs.exists(absoluteFilePath)
+
+    Q(editSession ? promise)
+      .then (editSession) =>
+        if not activePane
+          activePane = new Pane(editSession)
+          @panes.setRoot(activePane)
+
+        activePane.showItem(editSession)
+        activePane.focus()
+      .progress (value) =>
+        console.log "#{filepath} read #{100 * (value / fileSize)}"
+

   # Private: DEPRECATED Synchronously Opens a given a filepath in Atom.
   open: (filePath, options = {}) ->
+    console.warn("RootView::open is deprecated")
     changeFocus = options.changeFocus ? true
     initialLine = options.initialLine
     filePath = project.relativize(filePath)


Active all heros on intro

Active all heros on intro

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/GregDesplaces/classe-1914.git/'


Specs for request student id component

Specs for request student id component

error: pathspec 'test/course/request-student-id.spec.coffee' did not match any file(s) known to git

--- test/course/request-student-id.spec.coffee
+++ test/course/request-student-id.spec.coffee
@@ -0,0 +1,34 @@
+{Testing, expect, sinon, _, ReactTestUtils} = require 'openstax-react-components/test/helpers'
+
+Course = require 'course/model'
+RequestStudentId = require 'course/request-student-id'
+
+describe 'RequestStudentId Component', ->
+
+  beforeEach ->
+    @props =
+      onCancel: sinon.spy()
+      onSubmit: sinon.spy()
+      label: 'a test label'
+      saveButtonLabel: 'this is save btn'
+      title: 'this is title'
+      course: new Course(ecosystem_book_uuid: 'test-collection-uuid')
+
+  it 'renders values from props', ->
+    Testing.renderComponent( RequestStudentId, props: @props ).then ({dom}) =>
+      expect(dom.querySelector('h3').textContent).to.equal(@props.title)
+      expect(dom.querySelector('.control-label').textContent).to.equal(@props.label)
+      expect(dom.querySelector('.btn-default').textContent).to.equal(@props.saveButtonLabel)
+
+  it 'calls onSubmit when save button is clicked', ->
+    Testing.renderComponent( RequestStudentId, props: @props ).then ({dom}) =>
+      expect(@props.onSubmit).not.to.have.been.called
+      dom.querySelector('input').value = 'test value'
+      Testing.actions.click(dom.querySelector('.btn-default'))
+      expect(@props.onSubmit).to.have.been.calledWith('test value')
+
+  it 'calls onCancel when cancel button is clicked', ->
+    Testing.renderComponent( RequestStudentId, props: @props ).then ({dom}) =>
+      expect(@props.onCancel).not.to.have.been.called
+      Testing.actions.click(dom.querySelector('.cancel .btn'))
+      expect(@props.onCancel).to.have.been.called


Pass users to filters [#84276770]

Pass users to filters [#84276770]

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/netguru/people.git/'


added jQuery.validate method

added jQuery.validate method

Change-Id: I5f5e95009eec4febdfb733bbaea51ab8adf81ed9
Reviewed-on: https://gerrit.instructure.com/12941
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
Reviewed-by: Cameron Matheson <1d572acbfa68c7c6e541c7b840d6b622e5c0dc91@instructure.com>

error: pathspec 'app/coffeescripts/jquery/validate.coffee' did not match any file(s) known to git

--- app/coffeescripts/jquery/validate.coffee
+++ app/coffeescripts/jquery/validate.coffee
@@ -0,0 +1,41 @@
+##
+# Validates a form, returns true or false, stores errors on element data.
+#
+# Markup supported:
+#
+# - Required
+#   <input type="text" name="whatev" required>
+#
+# ex:
+#   if $form.validates()
+#     doStuff()
+#   else
+#     errors = $form.data 'errors'
+define [
+  'jquery'
+  'underscore'
+  'i18n!validate'
+], ($, _, I18n) ->
+
+  $.fn.validate = ->
+    errors = {}
+
+    this.find('[required]').each ->
+      $input = $ this
+      name = $input.attr 'name'
+      value = $input.val()
+      if value is ''
+        (errors[name] ?= []).push
+          name: name
+          type: 'required'
+          message: I18n.t 'is_required', 'This field is required'
+
+    hasErrors = _.size(errors) > 0
+
+    if hasErrors
+      this.data 'errors', errors
+      false
+    else
+      this.data 'errors', undefined
+      true
+


Bulletproof view-helper test

Bulletproof view-helper test

Due to how timezones and local times affect moment, we use a date string as
normalization rather than a time offset (which can differ in results based
off your location).

--- test/lib/view-helper-test.coffee
+++ test/lib/view-helper-test.coffee
@@ -60,7 +60,7 @@
           expect($ @icon.string).to.have.attr 'title', 'My Title'

     it 'formats date correctly', ->
-      timeStamp = Handlebars.helpers.dateFormat 2048, 'l'
+      timeStamp = Handlebars.helpers.dateFormat '1969-12-31', 'l'
       expect(timeStamp).to.equal '12/31/1969'

     describe 'mail helper', ->


Fixed the natural width console error on sharing email layout. (#2314)

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/evercam/evercam-dashboard.git/'


There is no spoon

There is no spoon

error: pathspec 'scripts/spoon.coffee' did not match any file(s) known to git

--- scripts/spoon.coffee
+++ scripts/spoon.coffee
@@ -0,0 +1,3 @@
+module.exports = (robot) ->
+  robot.respond /spoon$/i, (msg) ->
+    msg.send "Spoon? Echhh... http://youtu.be/pWs9aNmLnwg"


server: added test case for isTeamPage

server: added test case for isTeamPage

error: pathspec 'servers/lib/server/helpers.test.coffee' did not match any file(s) known to git

--- servers/lib/server/helpers.test.coffee
+++ servers/lib/server/helpers.test.coffee
@@ -0,0 +1,26 @@
+{ expect } = require '../../testhelper'
+{ isTeamPage } = require './helpers'
+describe 'helpers::isTeamPage', ->
+  generateReq = (name) ->
+    req = {}
+    req.headers = {}
+    req.headers['x-host'] = name
+    return req
+
+  cases = [
+      { host: '',                          expected: no }
+      { host: 'koding.com',                expected: no }
+      { host: 'latest.koding.com',         expected: no }
+      { host: 'sandbox.koding.com',        expected: no }
+      { host: 'dev.koding.com:8090',       expected: no }
+      { host: 'dev.koding.com',            expected: no }
+      { host: 'hawaii.dev.koding.com',     expected: yes }
+      { host: 'hawaii.koding.com',         expected: yes }
+      { host: 'hawaii.latest.koding.com',  expected: yes }
+      { host: 'hawaii.sandbox.koding.com', expected: yes }
+  ]
+
+  it 'cases should complete successfully', (done) ->
+    for i, req of cases
+      expect(isTeamPage(generateReq(req.host))).to.be.equal req.expected
+    done()


Trigger attach before verifying confirm/cancel events

--- src/packages/jump-to-line/spec/jump-to-line-spec.coffee
+++ src/packages/jump-to-line/spec/jump-to-line-spec.coffee
@@ -36,12 +36,16 @@

     describe "when no line number has been entered", ->
       it "closes the view and does not update the cursor position", ->
+        editor.trigger 'editor:jump-to-line'
+        expect(jumpToLine.hasParent()).toBeTruthy()
         jumpToLine.miniEditor.trigger 'core:confirm'
         expect(jumpToLine.hasParent()).toBeFalsy()
         expect(editor.getCursorBufferPosition()).toEqual [1, 0]

   describe "when core:cancel is triggered", ->
     it "closes the view and does not update the cursor position", ->
+      editor.trigger 'editor:jump-to-line'
+      expect(jumpToLine.hasParent()).toBeTruthy()
       jumpToLine.miniEditor.trigger 'core:cancel'
       expect(jumpToLine.hasParent()).toBeFalsy()
       expect(editor.getCursorBufferPosition()).toEqual [1, 0]


Add functions for periodically fetching events

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/ESWAT/ottawa.git/'


Fix Travis build

Fix Travis build

Change import to be match the case of the file.

--- test/backofftimer_test.coffee
+++ test/backofftimer_test.coffee
@@ -1,6 +1,6 @@
 should = require('chai').should()
 decimal = require 'bignumber.js'
-BackoffTimer = require '../lib/BackoffTimer'
+BackoffTimer = require '../lib/backofftimer'

 describe 'backofftimer', ->
   timer = null


Add Trello script

Add Trello script

error: pathspec 'src/scripts/trello.coffee' did not match any file(s) known to git

--- src/scripts/trello.coffee
+++ src/scripts/trello.coffee
@@ -0,0 +1,40 @@
+# Description:
+#   Create new cards in Trello
+#
+# Dependencies:
+#   "node-trello": "latest"
+#
+# Configuration:
+#   HUBOT_TRELLO_KEY
+#   HUBOT_TRELLO_TOKEN
+#   HUBOT_TRELLO_LIST
+#
+# Commands:
+#   hubot trello card <name> - Create a new Trello card
+#
+# Notes:
+#   To get your key, go to: https://trello.com/1/appKey/generate
+#   To get your token, go to: https://trello.com/1/authorize?key=<<your key>>&name=Hubot+Trello&expiration=never&response_type=token&scope=read,write
+#   To get your list ID, go to: https://trello.com/1/members/my/cards?key=<<your key>>&token=<<your token>> and find a card on the list you'd like to use. The ID is the idList attribute
+#
+# Author:
+#   carmstrong
+
+module.exports = (robot) ->
+  robot.respond /trello card (.*)/i, (msg) ->
+    cardName = msg.match[1]
+    if not cardName.length
+      msg.send "You must give the card a name"
+      return
+    if not (process.env.HUBOT_TRELLO_KEY and process.env.HUBOT_TRELLO_TOKEN and process.env.HUBOT_TRELLO_LIST)
+      msg.send "Please sepcify your Trello key, token, and list as environment variables"
+      return
+    createCard msg, cardName
+
+createCard = (msg, cardName) ->
+  Trello = require("node-trello")
+  t = new Trello(process.env.HUBOT_TRELLO_KEY, process.env.HUBOT_TRELLO_TOKEN)
+  t.post "/1/cards", {name: cardName, idList: process.env.HUBOT_TRELLO_LIST}, (err, data) ->
+    if err
+      msg.send "There was an error creating the card"
+    msg.send data.url


tvshow listener

tvshow listener

Usage
tvshow spongebob squarepants
tvshow american horror story

Output
SpongeBob SquarePants is a Returning Series which started airing Jul/17/1999. The next show, titled "Walking the Plankton" is scheduled for 2011-11-07 at 17:00 on Nickelodeon http://www.tvrage.com/SpongeBob_SquarePants/episodes/1065098509

American Horror Story is a New Series which started airing Oct/05/2011. The next show, titled "Piggy, Piggy" is scheduled for 2011-11-09 at 22:00 on FX http://www.tvrage.com/shows/id-28776/episodes/1065105129

error: pathspec 'src/scripts/tvshow.coffee' did not match any file(s) known to git

--- src/scripts/tvshow.coffee
+++ src/scripts/tvshow.coffee
@@ -0,0 +1,60 @@
+xml2js = require "xml2js"
+module.exports = (robot) ->
+  robot.respond /tvshow(?: me)? (.*)/i, (msg) ->
+    query = encodeURIComponent(msg.match[1])
+    msg.http("http://services.tvrage.com/feeds/full_search.php?show=#{query}")
+      .get() (err, res, body) ->
+        if res.statusCode is 200 and !err?
+          parser = new xml2js.Parser()
+          parser.parseString body, (err, result) ->
+            if result.show?
+              if result.show.length?
+                show = result.show[0]
+              else
+                show = result.show
+              if show.status == "Canceled/Ended"
+                response = "#{show.name} aired for #{show.seasons} season"
+                response += "s" if show.seasons > 1
+                response += " from #{show.started} till #{show.ended}"
+                response += " on #{show.network['#']}" if show.network? and show.network['#']
+                response += " #{show.link}"
+                msg.reply response
+              else
+                # get more info
+                msg.http("http://services.tvrage.com/feeds/episode_list.php?sid=#{show.showid}")
+                  .get() (err, res, details) ->
+                    if res.statusCode is 200 and !err?
+                      parser = new xml2js.Parser()
+                      parser.parseString details, (err, showdetails) ->
+                        now = new Date();
+                        ecb = (season_arr) ->
+                          for episode in season_arr.episode
+                            edate = new Date()
+                            edate.setTime(Date.parse(episode.airdate+' '+show.airtime))
+                            if edate.getTime() > now.getTime()
+                              return episode
+                        if showdetails.Episodelist.Season.length?
+                          unaired = ecb season for season in showdetails.Episodelist.Season
+                        else
+                          unaired = ecb showdetails.Episodelist.Season
+                        if unaired
+                          response = "#{show.name} is a #{show.status} which started airing #{show.started}. The next show, titled \"#{unaired.title}\" is scheduled for #{unaired.airdate}"
+                          response += " #{show.day}" if show.day?
+                          response += " at #{show.airtime}" if show.airtime?
+                          response += " on #{show.network['#']}" if show.network? and show.network['#']
+                          response += " #{unaired.link}"
+                          msg.reply response
+                        else
+                          response = "#{show.name} is a #{show.status} with #{show.seasons} (or more) season"
+                          response += "s" if show.seasons > 1
+                          response += " beginning #{show.started}"
+                          response += " at #{show.airtime}" if show.airtime?
+                          response += " on #{show.network['#']}" if show.network? and show.network['#']
+                          response += " #{show.link}"
+                          msg.reply response
+                    else
+                      msg.reply "Sorry, there was an error looking up your show"
+            else
+              msg.reply "I couldn't find TV show " + msg.match[1]
+        else
+            msg.reply "Sorry, there was an error looking up your show"


Print PATH in Phantomjs class

Print PATH in Phantomjs class

--- src/Phantomjs.coffee
+++ src/Phantomjs.coffee
@@ -5,6 +5,7 @@
 phantomjs = require 'phantomjs'
 process.env.PATH = path.dirname(phantomjs.path) + ':' + process.env.PATH
 _ = require "underscore"
+log.debug "PATH="+process.env.PATH

 class Phantomjs extends EventEmitter


bug fix

bug fix


adding rebuild command

adding rebuild command


nicer name for servers

nicer name for servers


:lipstick:

:lipstick:

--- spec/fs-plus-spec.coffee
+++ spec/fs-plus-spec.coffee
@@ -213,4 +213,3 @@
       it "copies the file and folder", ->
         expect(fs.isFileSync(path.join(destination, 'a.txt'))).toBeTruthy()
         expect(fs.isDirectorySync(path.join(destination, 'b'))).toBeTruthy()
-


Uncomment specs.

Uncomment specs.

--- spec/grammar-spec.coffee
+++ spec/grammar-spec.coffee
@@ -9,16 +9,16 @@
       atom.packages.activatePackage(LB)

   # babel-sublime test files
-  # grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/flow.js')
-  # grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/js-class.js')
-  # grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/js-functions.js')
-  # grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/js-symbols.js')
-  # grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/js-template-strings.js')
-  # grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/jsx-attributes.jsx')
-  # grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/jsx-es6.jsx')
-  # grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/jsx-features.jsx')
-  # grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/jsx-full-react-class.jsx')
-  # grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/jsx-text.jsx')
+  grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/flow.js')
+  grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/js-class.js')
+  grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/js-functions.js')
+  grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/js-symbols.js')
+  grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/js-template-strings.js')
+  grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/jsx-attributes.jsx')
+  grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/jsx-es6.jsx')
+  grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/jsx-features.jsx')
+  grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/jsx-full-react-class.jsx')
+  grammarTest path.join(__dirname, 'fixtures/grammar/babel-sublime/jsx-text.jsx')

   # grammar test large files
   grammarTest path.join(__dirname, 'fixtures/grammar/large files/browser-polyfill.js')


cache featured calls

cache featured calls

--- lib/atom-io-client.coffee
+++ lib/atom-io-client.coffee
@@ -49,9 +49,17 @@
         @getFeatured(true, callback)

   getFeatured: (loadThemes, callback) ->
-    # apm already does this, might as well use it instead of request i guess?
+    # apm already does this, might as well use it instead of request i guess? The
+    # downside is that I need to repeat caching logic here.
     @packageManager.getFeatured(loadThemes)
       .then (packages) =>
+        # copypasta from below
+        key = if loadThemes then 'themes/featured' else 'packages/featured'
+        cached =
+          data: packages
+          createdOn: Date.now()
+        localStorage.setItem(@cacheKeyForPath(key), JSON.stringify(cached))
+        # end copypasta
         callback(null, packages)
       .catch (error) =>
         callback(error, null)


<feat>(source): add xiami music support

<feat>(source): add xiami music support

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/VenDream/MoePlayer.git/'


Added reusable heap data structure

Added reusable heap data structure

error: pathspec 'src/data/heap.coffee' did not match any file(s) known to git

--- src/data/heap.coffee
+++ src/data/heap.coffee
@@ -0,0 +1,209 @@
+{floor, min} = Math
+
+###
+Default comparison function to be used
+###
+defaultCmp = (x, y) ->
+  return -1 if x < y
+  return 1 if x > y
+  0
+
+###
+Insert item x in list a, and keep it sorted assuming a is sorted.
+
+If x is already in a, insert it to the right of the rightmost x.
+
+Optional args lo (default 0) and hi (default a.length) bound the slice
+of a to be searched.
+###
+insort = (a, x, lo=0, hi, cmp=defaultCmp) ->
+  throw new Error('lo must be non-negative') if lo < 0
+  hi ?= a.length
+  while lo < hi
+    mid = floor((lo + hi) / 2)
+    if cmp(x, a[mid]) < 0
+      hi = mid
+    else
+      lo = mid + 1
+  a[lo...lo] = x
+
+###
+Push item onto heap, maintaining the heap invariant.
+###
+heappush = (array, item, cmp=defaultCmp) ->
+  array.push(item)
+  _siftdown(array, 0, array.length - 1, cmp)
+
+###
+Pop the smallest item off the heap, maintaining the heap invariant.
+###
+heappop = (array, cmp=defaultCmp) ->
+  lastelt = array.pop()
+  if array.length
+    returnitem = array[0]
+    array[0] = lastelt
+    _siftup(array, 0, cmp)
+  else
+    returnitem = lastelt
+  returnitem
+
+###
+Pop and return the current smallest value, and add the new item.
+
+This is more efficient than heappop() followed by heappush(), and can be
+more appropriate when using a fixed size heap. Note that the value
+returned may be larger than item! That constrains reasonable use of
+this routine unless written as part of a conditional replacement:
+    if item > array[0]
+      item = heapreplace(array, item)
+###
+heapreplace = (array, item, cmp=defaultCmp) ->
+  returnitem = array[0]
+  array[0] = item
+  _siftup(array, 0, cmp)
+  returnitem
+
+###
+Fast version of a heappush followed by a heappop.
+###
+heappushpop = (array, item, cmp=defaultCmp) ->
+  if array.length and cmp(array[0], item) < 0
+    [item, array[0]] = [array[0], item]
+    _siftup(array, 0, cmp)
+  item
+
+###
+Transform list into a heap, in-place, in O(array.length) time.
+###
+heapify = (array, cmp=defaultCmp) ->
+  for i in [0...floor(array.length / 2)].reverse()
+    _siftup(array, i, cmp)
+
+###
+Update the position of the given item in the heap.
+This function should be called every time the item is being modified.
+###
+updateItem = (array, item, cmp=defaultCmp) ->
+  pos = array.indexOf(item)
+  return if pos is -1
+  _siftdown(array, 0, pos, cmp)
+  _siftup(array, pos, cmp)
+
+###
+Find the n largest elements in a dataset.
+###
+nlargest = (array, n, cmp=defaultCmp) ->
+  result = array[0...n]
+  return result unless result.length
+  heapify(result, cmp)
+  heappushpop(result, elem, cmp) for elem in array[n..]
+  result.sort(cmp).reverse()
+
+###
+Find the n smallest elements in a dataset.
+###
+nsmallest = (array, n, cmp=defaultCmp) ->
+  if n * 10 <= array.length
+    result = array[0...n].sort(cmp)
+    return result unless result.length
+    los = result[result.length - 1]
+    for elem in array[n..]
+      if cmp(elem, los) < 0
+        insort(result, elem, 0, null, cmp)
+        result.pop()
+        los = result[result.length - 1]
+    return result
+
+  heapify(array, cmp)
+  (heappop(array, cmp) for i in [0...min(n, array.length)])
+
+_siftdown = (array, startpos, pos, cmp=defaultCmp) ->
+  newitem = array[pos]
+  while pos > startpos
+    parentpos = (pos - 1) >> 1
+    parent = array[parentpos]
+    if cmp(newitem, parent) < 0
+      array[pos] = parent
+      pos = parentpos
+      continue
+    break
+  array[pos] = newitem
+
+_siftup = (array, pos, cmp=defaultCmp) ->
+  endpos = array.length
+  startpos = pos
+  newitem = array[pos]
+  childpos = 2 * pos + 1
+  while childpos < endpos
+    rightpos = childpos + 1
+    if rightpos < endpos and not (cmp(array[childpos], array[rightpos]) < 0)
+      childpos = rightpos
+    array[pos] = array[childpos]
+    pos = childpos
+    childpos = 2 * pos + 1
+  array[pos] = newitem
+  _siftdown(array, startpos, pos, cmp)
+
+class Heap
+  @push: heappush
+  @pop: heappop
+  @replace: heapreplace
+  @pushpop: heappushpop
+  @heapify: heapify
+  @nlargest: nlargest
+  @nsmallest: nsmallest
+
+  constructor: (@cmp=defaultCmp) ->
+    return new Heap(@cmp) unless this instanceof Heap
+    @nodes = []
+
+  push: (x) ->
+    heappush(@nodes, x, @cmp)
+
+  pop: ->
+    heappop(@nodes, @cmp)
+
+  peek: ->
+    @nodes[0]
+
+  contains: (x) ->
+    @nodes.indexOf(x) isnt -1
+
+  replace: (x) ->
+    heapreplace(@nodes, x, @cmp)
+
+  pushpop: (x) ->
+    heappushpop(@nodes, x, @cmp)
+
+  heapify: ->
+    heapify(@nodes, @cmp)
+
+  updateItem: (x) ->
+    updateItem(@nodes, x, @cmp)
+
+  clear: ->
+    @nodes = []
+
+  empty: ->
+    @nodes.length is 0
+
+  size: ->
+    @nodes.length
+
+  clone: ->
+    heap = new Heap()
+    heap.nodes = @nodes.slice(0)
+    heap
+
+  toArray: ->
+    @nodes.slice(0)
+
+  # aliases
+  insert: @::push
+  top:    @::peek
+  front:  @::peek
+  has:    @::contains
+  copy:   @::clone
+
+# exports to library
+d3plus.data.heap = Heap


Fixed touch symbol start bug.

Fixed touch symbol start bug.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/UCSFMemoryAndAging/tabcat.git/'


Adds Posts collection; includes default parse critera from RelatedPosts component

error: pathspec 'collections/posts.coffee' did not match any file(s) known to git

--- collections/posts.coffee
+++ collections/posts.coffee
@@ -0,0 +1,11 @@
+_ = require 'underscore'
+Backbone = require 'backbone'
+Post = require('../models/post.coffee')
+
+module.exports = class Posts extends Backbone.Collection
+  model: Post
+
+  parse: (response) ->
+    _.filter response, (obj) ->
+      post = new Post obj
+      post.defaultImage()?.imageUrlForMaxSize?()


:fire: File extension

:fire: File extension

--- build/Gruntfile.coffee
+++ build/Gruntfile.coffee
@@ -3,7 +3,7 @@
 os = require 'os'
 glob = require 'glob'
 usesBabel = require './lib/uses-babel'
-babelOptions = require('../static/babelrc.json')
+babelOptions = require '../static/babelrc'

 # Add support for obselete APIs of vm module so we can make some third-party
 # modules work under node v0.11.x.


removing symbols from search

removing symbols from search

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/Mikuia/Mikuia.git/'


moved min/max index to the buffer object

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/zagushka/ui-scroll.git/'


share camera fix

share camera fix


added new todo view

added new todo view

error: pathspec 'app/assets/javascripts/dashit/views/todos/new.js.coffee' did not match any file(s) known to git

--- app/assets/javascripts/dashit/views/todos/new.js.coffee
+++ app/assets/javascripts/dashit/views/todos/new.js.coffee
@@ -0,0 +1,35 @@
+DashIt.NewTodoView = Ember.View.extend
+  tagName: "form"
+  templateName: "dashit/templates/todos/edit"
+
+  init: ->
+    @_super()
+    @set "todo", DashIt.Todo.create()
+
+  didInsertElement: ->
+    @_super()
+    @$("input:first").focus()
+
+  cancelForm: ->
+    @get("parentView").hideNewTodo()
+
+  submit: (event) ->
+    self = @
+
+    # Fetch todo and project
+    todo = @get("todo")
+    project = @get("parentView").get("parentView").get("project")
+
+    # Build todo object
+    todo.status = "todo"
+    todo.project_id = project.id
+    todo.resourceUrl = project.todos._resourceUrl()
+
+    # Save todo
+    event.preventDefault()
+    todo.saveResource().fail((e) ->
+      console.log e
+    ).done ->
+      project.todos.pushObject todo
+      self.get("parentView").hideNewTodo()
+


getFullClassName - Fixed minor syntax error.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/Adirelle/atom-autocomplete-php.git/'


addUseClass - Skip comments when scanning lines.


Remove :not(...) selector for binding default events (IE 11 fix).

The :not(...) selector does not work in IE 11 for orphan nodes. This
fix is less than optimal, as it requires a JS iteration of nodes
to determine if the default listeners should be attached. For the time
being, it will work.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/JoshuaToenyes/stout-client.git/'


client: add modal helper

client: add modal helper

error: pathspec 'client/app/lib/modal.coffee' did not match any file(s) known to git

--- client/app/lib/modal.coffee
+++ client/app/lib/modal.coffee
@@ -0,0 +1,54 @@
+BaseView = require '../lib/base_view'
+
+module.exports = class ModalView extends BaseView
+
+    id: "dialog-modal"
+    className: "modal fade"
+    attributes:
+        'tab-index': -1
+    template: require './templates/modal'
+    value: 0
+
+    events: ->
+        "click #modal-dialog-no"  : "onNo"
+        "click #modal-dialog-yes" : "onYes"
+
+    constructor: (@title, @msg, @yes, @no, @cb, @hideOnYes) ->
+        super()
+        @hideOnYes = true unless @hideOnYes?
+
+    initialize: ->
+        @$el.on 'hidden.bs.modal', => @close()
+
+        @render()
+        @show()
+
+    onYes: ->
+        @cb true if @cb
+        @hide()
+
+    onNo: ->
+        @cb false if @cb
+        @hide() if @hideOnYes
+
+    onShow: ->
+
+    close: ->
+        setTimeout (() => @destroy()), 500
+
+    show: ->
+        @$el.modal 'show'
+        @$el.trigger 'show'
+
+    hide: ->
+        @$el.modal 'hide'
+        @$el.trigger 'hide'
+
+    render: ->
+        @$el.append @template(title: @title, msg: @msg, yes: @yes, no: @no)
+        $("body").append @$el
+        @afterRender()
+        @
+
+module.exports.error = (code, cb) ->
+    new ModalView t("modal error"), code, t("modal ok"), false, cb


bug:Fix level session inventory check race condition

Moving session loaded event to after session.set heroConfig in level
loader.

Closes #4473

--- app/lib/LevelLoader.coffee
+++ app/lib/LevelLoader.coffee
@@ -208,7 +208,6 @@
       team = @team ? @session.get('team')
       Backbone.Mediator.publish 'level:loaded', level: @level, team: team
       @publishedLevelLoaded = true
-      Backbone.Mediator.publish 'level:session-loaded', level: @level, session: @session
       @consolidateFlagHistory() if @opponentSession?.loaded
     else if session is @opponentSession
       @consolidateFlagHistory() if @session.loaded
@@ -221,36 +220,40 @@
         @worldNecessities.push heroResource
       @sessionDependenciesRegistered[session.id] = true
     unless @level.isType('hero', 'hero-ladder', 'hero-coop')
+      if session is @session
+        Backbone.Mediator.publish 'level:session-loaded', level: @level, session: @session
       # Return before loading heroConfig ThangTypes. Finish if all world necessities were completed by the time the session loaded.
       if @checkAllWorldNecessitiesRegisteredAndLoaded()
         @onWorldNecessitiesLoaded()
-      return
-    # Load the ThangTypes needed for the session's heroConfig for these types of levels
-    heroConfig = session.get('heroConfig')
-    heroConfig ?= me.get('heroConfig') if session is @session and not @headless
-    heroConfig ?= {}
-    heroConfig.inventory ?= feet: '53e237bf53457600003e3f05'  # If all else fails, assign simple boots.
-    heroConfig.thangType ?= '529ffbf1cf1818f2be000001'  # If all else fails, assign Tharin as the hero.
-    session.set 'heroConfig', heroConfig unless _.isEqual heroConfig, session.get('heroConfig')
-    url = "/db/thang.type/#{heroConfig.thangType}/version"
-    if heroResource = @maybeLoadURL(url, ThangType, 'thang')
-      @worldNecessities.push heroResource
     else
-      heroThangType = @supermodel.getModel url
-      @loadDefaultComponentsForThangType heroThangType
-      @loadThangsRequiredByThangType heroThangType
-
-    for itemThangType in _.values(heroConfig.inventory)
-      url = "/db/thang.type/#{itemThangType}/version?project=name,components,original,rasterIcon,kind"
-      if itemResource = @maybeLoadURL(url, ThangType, 'thang')
-        @worldNecessities.push itemResource
+      # Load the ThangTypes needed for the session's heroConfig for these types of levels
+      heroConfig = session.get('heroConfig')
+      heroConfig ?= me.get('heroConfig') if session is @session and not @headless
+      heroConfig ?= {}
+      heroConfig.inventory ?= feet: '53e237bf53457600003e3f05'  # If all else fails, assign simple boots.
+      heroConfig.thangType ?= '529ffbf1cf1818f2be000001'  # If all else fails, assign Tharin as the hero.
+      session.set 'heroConfig', heroConfig unless _.isEqual heroConfig, session.get('heroConfig')
+      if session is @session
+        Backbone.Mediator.publish 'level:session-loaded', level: @level, session: @session
+      url = "/db/thang.type/#{heroConfig.thangType}/version"
+      if heroResource = @maybeLoadURL(url, ThangType, 'thang')
+        @worldNecessities.push heroResource
       else
-        itemThangType = @supermodel.getModel url
-        @loadDefaultComponentsForThangType itemThangType
-        @loadThangsRequiredByThangType itemThangType
-    @sessionDependenciesRegistered[session.id] = true
-    if _.size(@sessionDependenciesRegistered) is 2 and @checkAllWorldNecessitiesRegisteredAndLoaded()
-      @onWorldNecessitiesLoaded()
+        heroThangType = @supermodel.getModel url
+        @loadDefaultComponentsForThangType heroThangType
+        @loadThangsRequiredByThangType heroThangType
+
+      for itemThangType in _.values(heroConfig.inventory)
+        url = "/db/thang.type/#{itemThangType}/version?project=name,components,original,rasterIcon,kind"
+        if itemResource = @maybeLoadURL(url, ThangType, 'thang')
+          @worldNecessities.push itemResource
+        else
+          itemThangType = @supermodel.getModel url
+          @loadDefaultComponentsForThangType itemThangType
+          @loadThangsRequiredByThangType itemThangType
+      @sessionDependenciesRegistered[session.id] = true
+      if _.size(@sessionDependenciesRegistered) is 2 and @checkAllWorldNecessitiesRegisteredAndLoaded()
+        @onWorldNecessitiesLoaded()

   loadCodeLanguagesForSession: (session) ->
     codeLanguages = _.uniq _.filter [session.get('codeLanguage') or 'python', session.get('submittedCodeLanguage')]


Check for Updates Periodically.

Check for Updates Periodically.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/jhbruhn/keybase-gui.git/'


Remove unused deps

Remove unused deps

--- models/mixins/relations/sale.coffee
+++ models/mixins/relations/sale.coffee
@@ -1,6 +1,3 @@
-_ = require 'underscore'
-Backbone = require 'backbone'
-
 module.exports =
   related: ->
     return @__related__ if @__related__?


Don't clear the selection if it's empty

Don't clear the selection if it's empty

This avoids emitting selection change events when they aren't really needed. This extra event was causing the highlighted line to be updated when it didn't need to be.

--- src/app/selection.coffee
+++ src/app/selection.coffee
@@ -87,7 +87,8 @@
     @editSession.buffer.getTextInRange(@getBufferRange())

   clear: ->
-    @anchor?.destroy()
+    return unless @anchor
+    @anchor.destroy()
     @anchor = null
     @screenRangeChanged()


fix fs module

fix fs module

--- src/fs.coffee
+++ src/fs.coffee
@@ -1,5 +1,7 @@
 # commonjs fs module
 # http://ringojs.org/api/v0.8/fs/
+
+_ = require 'underscore'

 module.exports =
   # Make the given path absolute by resolving it against the
@@ -35,7 +37,7 @@
   # Returns an array with all the names of files contained
   # in the directory path.
   list: (path, recursive) ->
-    path = File.absolute path
+    path = @absolute path
     fm = OSX.NSFileManager.defaultManager
     if recursive
       paths = fm.subpathsAtPath path


Added getter and setter for attribute id. Added callback for id change.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/AppGyver/supersonic.git/'


Reverted change to ShowIf.

Reverted change to ShowIf.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/cganas/picoCTF-web.git/'


Fix function name.

Fix function name.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/philbooth/GitHubReminder.git/'


editing published pages -listening for change on currentPage.canPublish instead of canPublish

--- src/scripts/modules/media/header/header.coffee
+++ src/scripts/modules/media/header/header.coffee
@@ -39,7 +39,9 @@

     isEditable: () ->
       if @model.asPage()?.get('loaded') and @model.isDraft()
+        console.log @model.asPage().get('canPublish')
         edit = @model.asPage()?.get('canPublish')
+        console.log edit
         if edit isnt undefined and edit.toString().indexOf(session.get('id')) >= 0 and not @model.asPage()?.isDraft()
           return true

@@ -69,7 +71,7 @@
       @listenTo(@model, 'change:downloads change:buyLink change:title change:active', @render)
       @listenTo(@model, 'change:currentPage change:currentPage.active change:currentPage.loaded', @render)
       @listenTo(session, 'change', @render)
-      @listenTo(@model, 'change:currentPage.editable change:canPublish', @render)
+      @listenTo(@model, 'change:currentPage.editable change:currentPage.canPublish', @render)

     onRender: () ->
       if not @model.asPage()?.get('active') then return


Add initial help to look up a company's business address

error: pathspec 'src/address.coffee' did not match any file(s) known to git

--- src/address.coffee
+++ src/address.coffee
@@ -0,0 +1,19 @@
+{DOMParser} = require 'xmldom'
+xpath = require 'xpath'
+request = require 'request'
+
+module.exports =
+  getAddress: (company, callback) ->
+    url = "http://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&output=atom&start=0&count=1&CIK=#{company}"
+
+    request url, (error, response, body) ->
+      if error?
+        callback(error)
+      else
+        dom = new DOMParser().parseFromString(body)
+        [address] = xpath.select('/feed/company-info/addresses/address[@type=\'business\']', dom)
+        street1 = xpath.select('street1/text()', address).toString()
+        city = xpath.select('city/text()', address).toString()
+        state = xpath.select('state/text()', address).toString()
+        zip = xpath.select('zip/text()', address).toString()
+        callback(null, {street1, city, state, zip})


(feature): coffescript + adds animated.coffee file

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/bawt/animated.git/'


adds money helper

adds money helper

error: pathspec 'app/assets/javascripts/spree_checkout/helpers/money.js.coffee' did not match any file(s) known to git

--- app/assets/javascripts/spree_checkout/helpers/money.js.coffee
+++ app/assets/javascripts/spree_checkout/helpers/money.js.coffee
@@ -0,0 +1,5 @@
+Ember.Handlebars.helper 'money', (value, options) ->
+  if Ember.isEmpty(value)
+    return new Ember.Handlebars.SafeString("#{Spree.current_order_currency_symbol} 0")
+  formatted = parseFloat(value, 10).toFixed(2)
+  return new Ember.Handlebars.SafeString("#{Spree.current_order_currency_symbol} #{formatted}")


Fixed #2914: no disabling spaces for Clojure and other advanced/experimental languages.

--- app/views/play/level/tome/SpellView.coffee
+++ app/views/play/level/tome/SpellView.coffee
@@ -223,6 +223,7 @@
         disableSpaces = @options.level.get('disableSpaces') or false
         aceConfig = me.get('aceConfig') ? {}
         disableSpaces = false if aceConfig.keyBindings and aceConfig.keyBindings isnt 'default'  # Not in vim/emacs mode
+        disableSpaces = false if @spell.language in ['clojure', 'lua', 'coffeescript', 'io']  # Don't disable for more advanced/experimental languages
         if not disableSpaces or (_.isNumber(disableSpaces) and disableSpaces < me.level())
           return @ace.execCommand 'insertstring', ' '
         line = @aceDoc.getLine @ace.getCursorPosition().row


add validation

add validation

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/tokopedia/nodame.git/'


Barchart scaling is no longer obscured by label.

--- app/scripts/directives/compare-bar-chart.coffee
+++ app/scripts/directives/compare-bar-chart.coffee
@@ -34,7 +34,7 @@
           .attr('height', 30) # arbitrary

         x = d3.scale.linear()
-          .domain([-x0, x0])
+          .domain([-(x0+ (lwidth/2)), (x0+ (lwidth/2))])
           .range([0 , width])
           .nice()

@@ -53,11 +53,16 @@
             .duration(1000)
             .attr("width", (d, i) ->
               if i is 0
-                Math.abs(parseInt(x(d)) - parseInt(x(0) - (lwidth/2)))
-              else Math.abs(parseInt(x(d)) - parseInt(x(0) + (lwidth/2)))
+                return x(0) - x(d)
+              else
+                return x(d) - x(0)
             ).attr("x", (d, i) ->
-              if i is 0 then  x(Math.min(parseInt(x(0) - (lwidth/2)), d))
-              else x(0) + (lwidth/2))
+              if i is 0
+                return x(d) - (lwidth/2)
+              else
+                return x(0) + (lwidth/2)
+
+            )

         svg.selectAll('text')
           .data(this_data)


fixing path for windows

fixing path for windows

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/davidpaulrosser/atom-maya.git/'


fix: a babeljs issue

fix: a babeljs issue

--- src/yaku.coffee
+++ src/yaku.coffee
@@ -1,6 +1,6 @@

-do (root = this) -> class Yaku
+do (root = this or global) -> class Yaku

 	###*
 	 * This class follows the [Promises/A+](https://promisesaplus.com) and


Session

Session


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

error: pathspec 'test/distance.coffee' did not match any file(s) known to git

--- test/distance.coffee
+++ test/distance.coffee
@@ -0,0 +1,5 @@
+module "Distance"
+
+test 'it s'
+
+module()


add the test methods with spy

add the test methods with spy

error: pathspec 'test/spy-test.coffee' did not match any file(s) known to git

--- test/spy-test.coffee
+++ test/spy-test.coffee
@@ -0,0 +1,23 @@
+sample = require('../sample')
+assert = require('assert')
+sinon = require('sinon')
+
+describe "calculator", ->
+  before ->
+    this.calculator = sinon.spy sample, 'calculator'
+    this.multiple = sinon.spy sample, 'multiple'
+    this.addition = sinon.spy sample, 'addition'
+    this.minus = sinon.spy sample, 'minus'
+    this.divide = sinon.spy sample, 'divide'
+
+  it "should throw an error if no method is matched", ->
+    try
+      sample.calculator('non-exist-method', 1, 2)
+    catch e
+      sinon.assert.threw(this.calculator)
+
+  it "should call the given method when parameter is valid", ->
+    methods = ['multiple', 'addition', 'minus', 'divide']
+    for method in methods
+      sample.calculator(method, 1, 2)
+      sinon.assert.calledOnce(this[method])


Client: Activity: Test: Created ChannelParticipantsInputWidget view tests

error: pathspec 'client/activity/lib/components/channelparticipantsinputwidget/test/view.coffee' did not match any file(s) known to git

--- client/activity/lib/components/channelparticipantsinputwidget/test/view.coffee
+++ client/activity/lib/components/channelparticipantsinputwidget/test/view.coffee
@@ -0,0 +1,130 @@
+kd              = require 'kd'
+React           = require 'kd-react'
+ReactDOM        = require 'react-dom'
+expect          = require 'expect'
+InputWidgetView = require '../view'
+InputWidget     = require '../index'
+immutable       = require 'immutable'
+TestUtils       = require 'react-addons-test-utils'
+keyboardKeys    = require 'app/constants/keyboardKeys'
+
+describe 'ChannelParticipantsInputWidgetView', ->
+
+  { Simulate, renderIntoDocument, isCompositeComponent } = TestUtils
+  { ENTER, UP_ARROW, DOWN_ARROW, TAB } = keyboardKeys
+
+
+  beforeEach ->
+
+    @props =
+      onChange              : kd.noop
+      onKeyDown             : kd.noop
+      query                 : 'koding-dummy-query'
+      value                 : 'koding-dummy-query'
+      placeholder           : 'koding-dummy-placeholder'
+      visible               : yes
+      addNewParticipantMode : no
+      selectedItem          : null
+      selectedIndex         : 1
+      items                 : immutable.List()
+
+
+  afterEach  -> expect.restoreSpies()
+
+
+  describe '::render', ->
+
+    it 'should render ChannelParticipantsInputWidgetView with correct props', ->
+
+      view = renderIntoDocument(<InputWidgetView {...@props}/>)
+
+      expect(view.props.value).toBeA 'string'
+      expect(view.props.query).toBeA 'string'
+      expect(view.props.visible).toBeTruthy()
+      expect(view.props.items).toBeA(immutable.List)
+      expect(view.props.selectedIndex).toEqual 1
+      expect(view.props.addNewParticipantMode).toBeFalsy()
+      expect(isCompositeComponent(view.refs.dropdown)).toBeTruthy()
+      expect(view.props.placeholder).toEqual 'koding-dummy-placeholder'
+
+
+    it 'should render ChannelParticipantsDropdown DOM node', ->
+
+      view = renderIntoDocument(<InputWidgetView {...@props}/>)
+      node = ReactDOM.findDOMNode(view.refs.dropdown)
+
+      expect(node).toExist()
+
+
+  describe '::onChange', ->
+
+    it 'should call passed handler on input change', ->
+
+      onChangeSpy = expect.createSpy()
+
+      view  = renderIntoDocument(<InputWidgetView {...@props} onChange={onChangeSpy}/>)
+      input = ReactDOM.findDOMNode(view.refs.textInput)
+
+      Simulate.change input
+
+      expect(onChangeSpy).toHaveBeenCalled()
+
+
+  describe '::onKeyDown', ->
+
+    it 'should call passed handler on input key down', ->
+
+      onKeyDownSpy = expect.createSpy()
+
+      view  = renderIntoDocument(<InputWidgetView {...@props} onKeyDown={onKeyDownSpy}/>)
+      input = ReactDOM.findDOMNode(view.refs.textInput)
+
+      Simulate.keyDown input
+
+      expect(onKeyDownSpy).toHaveBeenCalled()
+
+
+    it 'should call onEnter handler when input on enter key down', ->
+
+      container  = renderIntoDocument(<InputWidget.Container {...@props}/>)
+      onEnterSpy = expect.spyOn container, 'onEnter'
+      input      = ReactDOM.findDOMNode(container.refs.view.refs.textInput)
+
+      Simulate.keyDown input, { key: 'Enter', keyCode: ENTER, which: ENTER }
+
+      expect(onEnterSpy).toHaveBeenCalled()
+
+
+    it 'should call onPrevPosition handler when input on up-arrow key down', ->
+
+      container         = renderIntoDocument(<InputWidget.Container {...@props}/>)
+      onPrevPositionSpy = expect.spyOn container, 'onPrevPosition'
+      input             = ReactDOM.findDOMNode(container.refs.view.refs.textInput)
+
+      Simulate.keyDown input, { key: 'upArrow', keyCode: UP_ARROW, which: UP_ARROW }
+
+      expect(onPrevPositionSpy).toHaveBeenCalled()
+
+
+    it 'should call onNextPosition handler when input on down-arrow key down', ->
+
+      container         = renderIntoDocument(<InputWidget.Container {...@props}/>)
+      onNextPositionSpy = expect.spyOn container, 'onNextPosition'
+      input             = ReactDOM.findDOMNode(container.refs.view.refs.textInput)
+
+      Simulate.keyDown input, { key: 'downArrow', keyCode: DOWN_ARROW, which: DOWN_ARROW }
+
+      expect(onNextPositionSpy).toHaveBeenCalled()
+
+
+    it 'should call onNextPosition handler when input on tab key down', ->
+
+      container         = renderIntoDocument(<InputWidget.Container {...@props}/>)
+      onNextPositionSpy = expect.spyOn container, 'onNextPosition'
+      input             = ReactDOM.findDOMNode(container.refs.view.refs.textInput)
+
+      Simulate.keyDown input, { key: 'tab', keyCode: TAB, which: TAB }
+
+      expect(onNextPositionSpy).toHaveBeenCalled()
+
+


fix market update after installation

fix market update after installation

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/clochix/cozy-home.git/'


Fixed a bug with the deltas library identifying conflicts between patches.

--- app/lib/deltas.coffee
+++ app/lib/deltas.coffee
@@ -103,10 +103,8 @@
   pendingPathMap = groupDeltasByAffectingPaths(pendingDeltas)
   paths = _.keys(headPathMap).concat(_.keys(pendingPathMap))

-  # Here's my thinking:
-  # A) Conflicts happen when one delta path is a substring of another delta path
-  # B) A delta from one self-consistent group cannot conflict with another
-  # So, sort the paths, which will naturally make conflicts adjacent,
+  # Here's my thinking: conflicts happen when one delta path is a substring of another delta path
+  # So, sort paths from both deltas together, which will naturally make conflicts adjacent,
   # and if one is identified, one path is from the headDeltas, the other is from pendingDeltas
   # This is all to avoid an O(nm) brute force search.

@@ -141,7 +139,27 @@
         delta: delta
         path: (item.toString() for item in path).join('/')
       }
-  _.groupBy metaDeltas, 'path'
+
+  map = _.groupBy metaDeltas, 'path'
+
+  # Turns out there are cases where a single delta can include paths
+  # that 'conflict' with each other, ie one is a substring of the other
+  # because of moved indices. To handle this case, go through and prune
+  # out all deeper paths that conflict with more shallow paths, so
+  # getConflicts path checking works properly.
+
+  paths = _.keys(map)
+  return map unless paths.length
+  paths.sort()
+  prunedMap = {}
+  previousPath = paths[0]
+  for path, i in paths
+    continue if i is 0
+    continue if path.startsWith previousPath
+    prunedMap[path] = map[path]
+    previousPath = path
+
+  prunedMap

 module.exports.pruneConflictsFromDelta = (delta, conflicts) ->
   # the jsondiffpatch delta mustn't include any dangling nodes,