Add initial tests for dependency loader

Add initial tests for dependency loader

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

--- test/dependency.coffee
+++ test/dependency.coffee
@@ -0,0 +1,31 @@
+should = require 'should'
+{join} = require 'path'
+
+# lib stuff
+{load, process, applyPolicy, print, create, print} = require '../lib/main'
+
+# sample stuff
+jargon = require '../sample/app/domain/auth/jargon'
+serviceLocation = join __dirname, '../sample/app/domain/auth/services'
+policy = require '../sample/app/domain/auth/policy'
+
+
+describe 'dependency', ->
+  beforeEach (done) ->
+    @services = create serviceLocation, jargon, policy
+    @sessionId = 'ab23ab23ab23ab23'
+    should.exist @services.doSomething
+    should.exist @services.helpDoSomething
+    done()
+
+  it 'should fail without a dependency load function wired up', (done) ->
+    @services.doSomething {@sessionId}, (err) =>
+      should.exist err
+      err.message.should.equal 'Could not load dependency'
+      done()
+
+  it 'should not fail when the dependency load function is specified', (done) ->
+    # specify loader, then...
+    @services.doSomething {@sessionId}, (err) =>
+      should.not.exist err
+      done()


Update the commitList after (hard)reset

Update the commitList after (hard)reset

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/aki77/atomatigit.git/'


Adds deploy-docs grunt task

Adds deploy-docs grunt task

--- tasks/docs-task.coffee
+++ tasks/docs-task.coffee
@@ -20,3 +20,33 @@
     done = @async()
     args = [commonArgs..., '--noOutput', '--missing', 'src/app/']
     grunt.util.spawn({cmd, args, opts}, done)
+
+  grunt.registerTask 'deploy-docs', 'Publishes latest API docs to atom-docs.githubapp.com', ->
+    done = @async()
+
+    pushHeroku = (error, result, code) ->
+      sha = String(result).trim()
+      cmd = 'git'
+      args = ['--work-tree=../atom-docs/', '--git-dir=../atom-docs/.git/', 'push', 'heroku', 'master']
+      grunt.util.spawn({cmd, args, opts}, done)
+
+    pushOrigin = (error, result, code) ->
+      sha = String(result).trim()
+      cmd = 'git'
+      args = ['--work-tree=../atom-docs/', '--git-dir=../atom-docs/.git/', 'push', 'origin', 'master']
+      grunt.util.spawn({cmd, args, opts}, pushHeroku)
+
+    commitChanges = (error, result, code) ->
+      sha = String(result).trim()
+      cmd = 'git'
+      args = ['--work-tree=../atom-docs/', '--git-dir=../atom-docs/.git/', 'commit', '-a', "-m Update API docs to #{sha}"]
+      grunt.util.spawn({cmd, args, opts}, pushOrigin)
+
+    fetchSha = (error, result, code) ->
+      cmd = 'git'
+      args = ['rev-parse', 'HEAD']
+      grunt.util.spawn({cmd, args}, commitChanges)
+
+    cmd = 'cp'
+    args = ['-r', 'docs/api', '../atom-docs/public/']
+    grunt.util.spawn {cmd, args, opts}, fetchSha


Generate docs from text-buffer instead of telepath

--- tasks/docs-task.coffee
+++ tasks/docs-task.coffee
@@ -9,7 +9,7 @@

   grunt.registerTask 'build-docs', 'Builds the API docs in src/app', ->
     done = @async()
-    args = [commonArgs..., '--title', 'Atom API Documentation', '-o', 'docs/output/api', 'src/', '../telepath/src/range.coffee', '../telepath/src/point.coffee', '../telepath/src/string-marker.coffee']
+    args = [commonArgs..., '--title', 'Atom API Documentation', '-o', 'docs/output/api', 'src/', '../text-buffer/src/range.coffee', '../text-buffer/src/point.coffee', '../text-buffer/src/marker.coffee']
     grunt.util.spawn({cmd, args, opts}, done)

   grunt.registerTask 'lint-docs', 'Generate stats about the doc coverage', ->


Add file

Add file

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

--- app/assets/javascripts/plush/plush.coffee
+++ app/assets/javascripts/plush/plush.coffee
@@ -0,0 +1,373 @@
+class @Plush
+  constructor: (@element, @options={}) ->
+    # Hide original and wrap with container
+    @element.hide()
+    @element.wrap('

')
+    @container = @element.parent()
+    @container.append $.handlebar('plush_input', {placeholder: @element.attr('placeholder')})
+
+    @list = $('.plush-option-list', @container)
+    @inputContainer = $('.plush-input-wrapper', @container)
+    @placeholder = $('.plush-placeholder', @inputContainer)
+    @input = $('input', @inputContainer)
+    @options.multiple = @options.multiple? || @element.attr('multiple')?
+    @searchWithAjax = @element.data('query')?
+
+    # Option setting
+    @setQueryDataOptions()
+    @queryData = {} unless @queryData?
+    @queryDefault = 'q'
+
+    defaults =
+      noResults:           'No results found for: '
+      labelMethod:         'label'
+      listItemTemplate:    'plush_list_item'
+      optgroupTemplate:    'plush_optgroup_item'
+      multiSelectTemplate: 'plush_multi_select_item'
+      position:            'bottom'
+      url:                 null
+
+    for key, value of defaults
+      @setDefaultOption key, value
+
+    @list.addClass @options.listItemTemplate.replace(/\_/g, '-')
+    @container.addClass "position-#{@options.position}"
+    @container.addClass "plush-multiple" if @options.multiple?
+
+    @element.attr 'tabindex', -1
+
+    if $('option[selected]', @element).length > 0 && !@options.multiple
+      @placeholder.html $('option[selected]', @element).html()
+      @input.val $('option[selected]', @element).html()
+
+    # See if is <option> based or needs to get some JSON data
+    if @options.url?
+      @createListFromSource(true)
+    unless @options.url?
+      if $('optgroup', @element).length > 0
+        @createListFromGroupedOptions()
+      else
+        @createListFromOptions()
+
+    if @options.multiple
+      selectedOptions = $('option[selected]', @element)
+      @element.html('')
+
+      for option in selectedOptions
+        $option = $(option)
+        @addMultiSelectItem $option.html(), $option.val()
+
+    # Add placeholder to select if data attribute
+    unless @options.multiple
+      if @element.attr('placeholder')?
+        @element.prop('selectedIndex', -1)
+      else
+        @setOptionFor $('li:first-child', @list)
+
+    @inputContainer.on 'click', '.plush-placeholder, .plush-caret', (event) =>
+      event.preventDefault()
+      @show()
+    .on 'click', '.plush-remove', (event) =>
+      event.preventDefault()
+      optionContainer = $(event.currentTarget).parents('.plush-multi-select-item').first()
+      @removeOption optionContainer.data('value')
+      optionContainer.remove()
+
+    # User event behaviour
+    @container.on 'blur', 'input, a', =>
+      setTimeout @bind(@hide), 100
+
+    @input.on 'focus', =>
+      @show() unless @inputContainer.hasClass 'opened'
+    .on 'keyup', (event) =>
+      event.stopPropagation()
+      @handleInputKeyPress(event)
+
+    @list.on 'mousedown', 'a', (event) =>
+      event.preventDefault()
+      event.stopPropagation()
+      $item = $(event.currentTarget).parents('li').first()
+      if @options.multiple
+        @addOptionFor $item
+      else
+        @setOptionFor $item
+        @hide(true)
+    .on 'click', 'a', (event) =>
+      event.preventDefault()
+    .on 'keydown', 'a', (event) =>
+      event.preventDefault()
+      event.stopPropagation()
+    .on 'keyup', 'a', (event) =>
+      event.preventDefault()
+      event.stopPropagation()
+      @handleListKeyPress(event)
+    .on 'blur', 'a', (event) ->
+      $(this).removeClass 'focused'
+
+    @element.trigger 'initialized'
+    return @
+
+  handleInputKeyPress: (event) ->
+    if event.which == 38 || event.which == 40
+      event.preventDefault()
+      @focusAnchor($('li:not(.hidden):last a', @list))  if event.which == 38
+      @focusAnchor($('li:not(.hidden):first a', @list)) if event.which == 40
+    else
+      if @searchWithAjax
+        @delayedSearch()
+      else
+        @search @input.val()
+
+  handleListKeyPress: (event) ->
+    $anchor = $(event.currentTarget)
+
+    # Up / Down key
+    if event.which == 38 || event.which == 40
+      $link = @prevAnchor($anchor) if event.which == 38
+      $link = @nextAnchor($anchor) if event.which == 40
+      if !$link.length > 0 then @input.focus() else @focusAnchor($link)
+
+    # Escape key
+    if event.which == 27
+      @input.focus()
+
+    # Enter key
+    if event.which == 13
+      $anchor = $(event.currentTarget)
+      $item = $anchor.parents('li').first()
+      if @options.multiple? && @options.multiple
+        @addOptionFor $item
+      else
+        @setOptionFor $item
+        @blurAnchor($anchor)
+
+  setDefaultOption: (key, value) ->
+    unless @options[key]?
+      dataAttrName = key.replace /([A-Z])/g, ($1) -> "-" + $1.toLowerCase()
+      @options[key] = @element.data(dataAttrName) || value
+
+  setQueryDataOptions: ->
+    @queryData = @getQueryDataFromElement(@element.get(0))
+
+  setOptionFor: (listItem) ->
+    @placeholder.html listItem.data('label')
+    @element.val listItem.data('value')
+    @element.trigger 'change'
+
+  addOptionFor: (listItem) ->
+    value = listItem.data('value')
+
+    if $("option[value='#{value}']", @element).length == 0
+      @addMultiSelectItem listItem.data('label'), value
+
+  addMultiSelectItem: (label, value) ->
+    $item = $.handlebar @options.multiSelectTemplate, {label: label, value: value}
+    if $('.plush-multi-select-item', @inputContainer).length > 0
+        $('.plush-multi-select-item', @inputContainer).last().after $item
+      else
+        @inputContainer.prepend $item
+
+      @element.append "<option value=#{value} selected>#{label}</option>"
+      @element.trigger 'change'
+
+  removeOption: (value) ->
+    $("option[value=#{value}]", @element).removeAttr('selected')
+
+    if @options.multiple
+      $("option[value=#{value}]", @element).remove()
+
+    @element.trigger 'change'
+
+  focusAnchor: (anchor) ->
+    anchor.focus()
+    anchor.addClass 'focused'
+
+  blurAnchor: (anchor) ->
+    anchor.blur()
+    anchor.removeClass 'focused'
+
+  nextAnchor: (anchor) ->
+    $li = anchor.parents('li').first()
+    next = $('a', $li.next())
+    if next && !next.parents('li').first().hasClass('hidden') then next else @nextAnchor(next)
+
+  prevAnchor: (anchor) ->
+    $li = anchor.parents('li').first()
+    prev = $('a', $li.prev())
+    if prev && !prev.parents('li').first().hasClass('hidden') then prev else @prevAnchor(prev)
+
+
+  # --------------------------------------
+  # <option> based building
+  # --------------------------------------
+
+  createListFromOptions: ->
+    $('option', @element).each (index, item) =>
+      @list.append @createListItemFromOption(item)
+
+  createListFromGroupedOptions: ->
+    $('optgroup', @element).each (index, optGroup) =>
+      $optGroup = $(optGroup)
+      $group = $.handlebar 'plush_optgroup_item', {label: $optGroup.attr('label')}
+
+      $('option', $optGroup).each (index, item) =>
+        $('.plush-optgroup-list', $group).append(@createListItemFromOption(item))
+
+      @list.append $group
+
+  createListItemFromOption: (optionItem) ->
+    $option = $(optionItem)
+    options = @getDataFromElement(optionItem)
+    options.value = $option.val()
+    options.label = $option.html()
+    $.handlebar(@options.listItemTemplate, options)
+
+
+  # --------------------------------------
+  # JSON based building
+  # --------------------------------------
+
+  createListFromSource: (initial = false)->
+    @inputContainer.addClass 'loading'
+
+    ajaxOptions =
+      url: @options.url
+      type: "get"
+      dataType: "json"
+
+    dataOptions = $.extend {}, @queryData
+    dataOptions[@queryDefault] = @input.val() if @searchWithAjax
+    ajaxOptions.data = dataOptions
+
+    $.ajax(ajaxOptions).done (result, status, xhr) =>
+      @createListFromJSON(result, initial)
+
+    .always =>
+      @inputContainer.removeClass 'loading'
+      @checkResults()
+
+  hasFocus: () ->
+    $('*:focus', @container).length > 0
+
+  createListFromJSON: (result = [], initial = false) ->
+    @list.empty()
+    if result? && !$.isEmptyObject(result)
+      # Check if result are grouped
+      if $.inArray('value', Object.keys(result[0])) >= 0
+        for item in result
+          @checkItemLabel(item)
+          @list.append @createListItemFromJson(item)
+          @element.append "<option value=#{item.value}>#{item.label}</option>"
+      else
+        for groupObject in result
+          groupName = Object.keys(groupObject)[0]
+          $group = $.handlebar(@options.optgroupTemplate, {label: groupName})
+
+          for item in groupObject[groupName]
+            @checkItemLabel(item)
+            $('ul', $group).append @createListItemFromJson(item)
+
+          @list.append $group
+
+      @input.focus() unless initial
+      @checkResults()
+
+  checkItemLabel: (item) ->
+    item['label'] = item[@options.labelMethod] unless item['label']?
+
+  createListItemFromJson: (item) ->
+    $.handlebar(@options.listItemTemplate, item)
+
+
+  # --------------------------------------
+  # Search methods
+  # --------------------------------------
+
+  delayedSearch: ->
+    clearTimeout(@timer) if @timer?
+    @timer = setTimeout @bind(@createListFromSource), 500
+
+  search: (query) ->
+    matcher = new RegExp(query, 'i')
+    $('.plush-list-item a', @container).each ->
+      $listElement = $(this).parents('.plush-list-item').first()
+
+      if matcher.test($(this).html())
+        $listElement.removeClass('hidden') unless $listElement.hasClass('disabled')
+      else
+        $listElement.addClass('hidden')
+
+    $('.plush-optgroup', @container).each ->
+      $element = $(this)
+      if $('.plush-list-item:not(.hidden)', $element).length == 0
+        $element.hide()
+      else
+        $element.show()
+
+    @resizeList()
+    @checkResults()
+
+  checkResults: ->
+    if $('li:not(.hidden)', @list).length == 0
+      @showNoResults()
+    else
+      @hideNoResults()
+
+  # No results message
+  showNoResults: ->
+    msg = @options.noResults + @input.val()
+
+    if $('.plush-no-results', @list).length == 0
+      @list.append $("
#{msg}
")
+    else
+      $('.plush-no-results', @list).html(msg)
+      $('.plush-no-results', @list).show()
+
+  hideNoResults: ->
+    $('.plush-no-results', @list).hide()
+
+  # Dynamic dimensions
+  resizeInput: ->
+
+  resizeList: ->
+    if @options.position == 'top'
+      @list.css 'top', "-#{@list.outerHeight(true)}px"
+
+  # Input togglers for autocompletion behaviour
+  show: ->
+    @placeholder.hide()
+    @input.css 'display', 'block'
+    @inputContainer.addClass 'opened'
+    @list.show()
+    @input.focus() unless @input.is(":focus")
+
+  hide: (force = false) ->
+    if !@hasFocus() || force
+      unless @options.multiple
+        @placeholder.show()
+        @input.hide()
+
+      @inputContainer.removeClass 'opened'
+      @list.hide()
+
+  # Utilities
+  getAttributesFromElement: (element, attr_regexp) ->
+    options = {}
+    for attr in element.attributes
+      options[attr.nodeName.replace(attr_regexp, '')]= attr.nodeValue if attr.nodeName.match(attr_regexp)
+    options
+
+  getDataFromElement: (element) ->
+    @getAttributesFromElement element, /^data-/
+
+  getQueryDataFromElement: (element) ->
+    @getAttributesFromElement element, /^data-query-/
+
+  bind: ( Method ) ->
+    () =>
+      Method.apply( @, arguments )
+
+$ ->
+  $("[data-toggle='plush']").plush()
+
+


Simplify dirty line tracking

Simplify dirty line tracking

--- app/assets/javascripts/terminal.js.coffee
+++ app/assets/javascripts/terminal.js.coffee
@@ -8,7 +8,7 @@
     @normalBuffer = []
     @alternateBuffer = []
     @lineData = @normalBuffer
-    @dirtyLines = []
+    @dirtyLines = {}
     @fg = @bg = undefined
     @underline = false

@@ -65,29 +65,17 @@
     @element.find(".line:eq(" + n + ")").html html.join("")

   render: ->
-    updated = []
-
-    i = 0
-    while i < @dirtyLines.length
-      n = @dirtyLines[i]
-      if updated.indexOf(n) is -1
-        @renderLine n
-        updated.push n
-      i++
-
-    @dirtyLines = []
+    for _, n of @dirtyLines
+      @renderLine n
+
+    @dirtyLines = {}

   updateLine: (n) ->
     n = (if typeof n isnt "undefined" then n else @cursorY)
-    @dirtyLines.push n
+    @dirtyLines[n] = n

   updateScreen: ->
-    @dirtyLines = []
-
-    l = 0
-    while l < @lines
-      @dirtyLines.push l
-      l++
+    @dirtyLines[n] = n for n in [0...@lines]

   showCursor: (show) ->
     if show


add a node-based client for easier testing (so don't have to use browser except for GUI stuff)

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

--- salvus/node_client.coffee
+++ salvus/node_client.coffee
@@ -0,0 +1,28 @@
+message = require("salvus_message")
+
+sjsc = require("sockjs-client-ws")  #  https://github.com/steerapi/sockjs-client-node
+
+#client = sjsc.create("https://localhost/node")  # doesn't work -- don't know why
+client = sjsc.create("http://localhost:5000/node")
+
+walltime = -> (new Date()).getTime()
+tm = 0
+n = 0
+
+client.on('connection', ->
+    console.log("connection established")
+    tm = walltime()
+    client.write(JSON.stringify(message.execute_code(0,'2+2')))
+    )
+
+client.on('data', (msg) ->
+    t = walltime() - tm
+    n = n + 1
+    console.log("#{n}: #{Math.floor(n/t*1000)} tps, #{t} ms -- received some data #{msg}")
+    console.log("sending 2+2...")
+    client.write(JSON.stringify(message.execute_code(n,'2+2')))
+)
+
+client.on('error', (e) -> console.log("something went wrong #{e}"))
+
+


updated redis host

updated redis host

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/crystal/crystal-web.git/'


Activity: fetching popular topics wired

Activity: fetching popular topics wired

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/andrewjcasal/koding.git/'


teams: routing for available and unavailable groups


fix (Paths) Provide empty argv if not present in globals

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/steroids.git/'


Simple pure-Rebuild strategy

Simple pure-Rebuild strategy

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

--- strategies/Rebuild.coffee
+++ strategies/Rebuild.coffee
@@ -0,0 +1,11 @@
+{
+  name: 'Rebuild'
+  requires: ['Rebuild']
+  gainPriority: (state, my) -> [
+    "Province"
+    "Rebuild" if my.countInDeck("Rebuild") < 2 or if state.countInSupply("Duchy") == 0
+    "Duchy"
+    "Silver"
+    "Estate" if state.countInSupply("Duchy") == 0 and my.countInDeck("Estate") > 0
+  ]
+}


Add projects/index controller

Add projects/index controller

[#96757124]

error: pathspec 'review_front/app/controllers/projects/index.coffee' did not match any file(s) known to git

--- review_front/app/controllers/projects/index.coffee
+++ review_front/app/controllers/projects/index.coffee
@@ -0,0 +1,12 @@
+`import Ember from 'ember'`
+
+ProjectsIndexController = Ember.Controller.extend
+
+  queryParams: ['page', 'perPage', 'pageNumber']
+  pageBinding: 'content.page'
+  perPageBinding: 'content.perPage'
+
+  page: 1
+  perPage: 25
+
+`export default ProjectsIndexController`


updated drawer gestures

updated drawer gestures

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/kitchensink.git/'


SocialWorker: revert appstorage schema changes


fixed context connection settings

fixed context connection settings

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/disintegrator/antz.git/'


home/payment history: don't show unpaid invoices

Signed-off-by: Umut Sirin <4055abbc0e40a1254e715b952ccd414607e0b365@gmail.com>


home: show invoice item parts in better order

Signed-off-by: Umut Sirin <4055abbc0e40a1254e715b952ccd414607e0b365@gmail.com>


Fix typos.

Fix typos.

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/bmedx/modulestore.git/'


Dumb onClick placeholder for EventEntry

Dumb onClick placeholder for EventEntry

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/'


Client: VMSettings: Updated options and deleted unnecessary initList method


Update Comment

Update Comment

--- src/fairy.coffee
+++ src/fairy.coffee
@@ -82,7 +82,7 @@
   constructor: (@redis) ->
     @queue_pool = {}

-  # ### Function to Get Key Name
+  # ### Function to Resolve Key Name

   # Method to generate prefixed keys. Keys used by objects of class `Fairy` include:
   #


Improve Documentation

Improve Documentation

--- src/fairy.coffee
+++ src/fairy.coffee
@@ -514,7 +514,9 @@
   #
   # Statistics of a queue include:
   #
-  #   + `total_tasks`, total tasks placed
+  #   + `total`
+  #     - `tasks`, total tasks placed
+  #     - `groups`, total groups placed
   #   + `finished_tasks`, total tasks finished
   #   + `average_pending_time`, average time spent on waiting for processing the
   #   finished tasks in milliseconds


:new: Add default keymap

:new: Add default keymap

error: pathspec 'keymaps/linter.cson' did not match any file(s) known to git

--- keymaps/linter.cson
+++ keymaps/linter.cson
@@ -0,0 +1,2 @@
+'atom-text-editor:not(.mini)':
+  'alt': 'linter:set-bubble-transparent'


Added coffeescript implementation

Added coffeescript implementation

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

--- Ackermann.coffee
+++ Ackermann.coffee
@@ -0,0 +1,13 @@
+ack = (m, n) ->
+  if m == 0 then return n + 1
+  else if m > 0 then return ack(m - 1, 1)
+  else if m > 0 and n > 0 then return ack(m - 1, ack(m, n - 1))
+
+i = 0
+
+while i > -1
+  j = i
+  while j > -1
+    ack(i,j)
+    j--
+  i++


Fix title bar tests on non-macOS systems

--- spec/workspace-spec.coffee
+++ spec/workspace-spec.coffee
@@ -887,7 +887,7 @@
   describe "document.title", ->
     describe "when there is no item open", ->
       it "sets the title to 'untitled'", ->
-        expect(document.title).toEqual "untitled"
+        expect(document.title).toMatch ///^untitled///

     describe "when the active pane item's path is not inside a project path", ->
       beforeEach ->
@@ -951,7 +951,7 @@
         it "updates the title to be untitled", ->
           atom.workspace.getActivePane().destroy()
           expect(atom.workspace.getActivePaneItem()).toBeUndefined()
-          expect(document.title).toEqual "untitled"
+          expect(document.title).toMatch ///^untitled///

       describe "when an inactive pane's item changes", ->
         it "does not update the title", ->


Fix following profile on fair and shows feed for logged out users

--- desktop/components/partner_buttons/show_buttons.coffee
+++ desktop/components/partner_buttons/show_buttons.coffee
@@ -9,8 +9,9 @@

   initialize: (options) ->
     _.extend @, options
-    @following = new Following(null, kind: 'profile')
-    @following.syncFollows [@model.get('partner')?.default_profile_id]
+
+    user = CurrentUser.orNull()
+    @following = new Following(null, kind: 'profile') if user
     new FollowButton
       el: @$('.plus-follow-button')
       modelName: 'profile'
@@ -18,6 +19,8 @@
       following: @following
       context_module: 'Partner show module'

+    @following.syncFollows [@model.get('partner')?.default_profile_id] if user
+
   events:
     'click .partner-buttons-contact': 'contactGallery'


Warn user if enter camera private local ip

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/'


Remove unnecessary braces.

Remove unnecessary braces.

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/dhabersack/respaintive.git/'


Proxy server port bugfix

Proxy server port bugfix

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/keboola/kbc-ui-manage-apps.git/'


remove debug line

remove debug line

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/NextEpisode/NextEpisode.git/'


header

header

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/Bit-Bahia/bitbahia-rails.git/'


Fixed textarea auto-expand, added 2 functions

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/Brandon-Stoyles/generator-basilisk.git/'


fresh model

fresh model

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/generator-steroids.git/'


log improvement

log improvement

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/'


Add ability to turn off combination of media-queries for legacy code

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/NewSpring/norma-sass.git/'


Print error when mkdir failed

Print error when mkdir failed

--- spec/modules-spec.coffee
+++ spec/modules-spec.coffee
@@ -22,7 +22,7 @@
     it 'emits file events correctly', (done) ->
       pathwatcher = require 'pathwatcher'
       temp.mkdir 'dir', (err, dir) ->
-        assert err == null
+        assert err == null, String(err)
         file = path.join dir, 'file'
         fs.writeFileSync file, 'content'
         watcher = pathwatcher.watch file, (event) ->


Add spec for being up to date

Add spec for being up to date

--- spec/upgrade-spec.coffee
+++ spec/upgrade-spec.coffee
@@ -77,3 +77,16 @@
     runs ->
       expect(console.log).toHaveBeenCalled()
       expect(console.log.argsForCall[1][0]).toContain 'multi-module 0.1.0 -> 0.3.0'
+
+  it "does not display updates for packages already up to date", ->
+    fs.writeFileSync(path.join(packagesDir, 'multi-module', 'package.json'), JSON.stringify({name: 'multi-module', version: '0.3.0'}))
+
+    callback = jasmine.createSpy('callback')
+    apm.run(['upgrade', '--list', '--no-color'], callback)
+
+    waitsFor 'waiting for upgrade to complete', 600000, ->
+      callback.callCount > 0
+
+    runs ->
+      expect(console.log).toHaveBeenCalled()
+      expect(console.log.argsForCall[1][0]).toContain 'empty'


StackEditor: Editor: add session dump/restore functionality

--- client/new-stack-editor/lib/views/editorview.coffee
+++ client/new-stack-editor/lib/views/editorview.coffee
@@ -58,5 +58,42 @@
     @aceView?._windowDidResize()
     @once 'transitionend', =>
       kd.utils.defer => @aceView?._windowDidResize()
+
+
+  # restore/dump functionality referenced from following example ~ GG
+  # http://stackoverflow.com/questions/28257566/ace-editor-save-send-session-on-server-via-post
+
+  filterHistory = (deltas) ->
+    deltas.filter (d) -> d.group isnt 'fold'
+
+
   _getSession: -> @aceView.ace.editor.getSession()

+
+  _dump: ->
+
+    session   = @_getSession()
+    selection : session.selection.toJSON()
+    value     : session.getValue()
+    history   :
+      undo    : session.$undoManager.$undoStack.map filterHistory
+      redo    : session.$undoManager.$redoStack.map filterHistory
+    scrollTop : session.getScrollTop()
+    scrollLeft: session.getScrollLeft()
+    options   : session.getOptions()
+
+
+  _restore: (dump) ->
+
+    session = (require 'brace').createEditSession dump.value
+
+    session.$undoManager.$doc = session # workaround for a bug in ace
+    session.setOptions dump.options
+    session.$undoManager.$undoStack = dump.history.undo
+    session.$undoManager.$redoStack = dump.history.redo
+    session.selection.fromJSON dump.selection
+    session.setScrollTop dump.scrollTop
+    session.setScrollLeft dump.scrollLeft
+
+    @aceView.ace.editor.setSession session
+


Refs #130; Added option event handlers to the histogram.

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/kidaa/epoch.git/'


simplify set

simplify set

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/showell/CoffeeCoffee.git/'


Uh, whoops.

Uh, whoops.

--- resources/assets/coffee/react/beatmap-discussions/nominations.coffee
+++ resources/assets/coffee/react/beatmap-discussions/nominations.coffee
@@ -27,7 +27,7 @@
     @doAjax 'nominate'

   disqualify: ->
-    reason = osu.trans('beatmaps.nominations.disqualification-prompt')
+    reason = prompt osu.trans('beatmaps.nominations.disqualification-prompt')
     return unless reason

     @doAjax 'disqualify', reason


Fixed deltas in the version history modal.

--- app/views/editor/delta.coffee
+++ app/views/editor/delta.coffee
@@ -31,6 +31,9 @@

     for modelName in ['model', 'headModel', 'comparisonModel']
       @[modelName] = options[modelName]
+      continue unless @[modelName]
+      if not @[modelName].isLoaded
+        @[modelName] = @supermodel.loadModel(@[modelName], 'document').model

     @buildDeltas() if @supermodel.finished()


Adjust deploy branch

Adjust deploy branch


remove debug logging

remove debug logging

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/'


add types! woo.

add types! woo.

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/damianb/crimson.git/'


set args

set args


use real prototypes for classes

use real prototypes for classes


[DONE] prompt file rename on file creation

--- client/app/MainApp/filetree/controllers/findertreecontroller.coffee
+++ client/app/MainApp/filetree/controllers/findertreecontroller.coffee
@@ -289,8 +289,10 @@
     FSItem.create path, type, (err, file)=>
       @notify null, null, err if err
       @refreshFolder @nodes[parentPath], =>
-        @selectNode @nodes[file.path]
         @notify "#{type} created!", "success"
+        node = @nodes[file.path]
+        @selectNode node
+        @showRenameDialog node

   moveFiles:(nodesToBeMoved, targetNodeView, callback)->


finder: conflict has been fixed

finder: conflict has been fixed

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/andrewjcasal/koding.git/'


reverted last improvement on pulsing logo

--- client/landing/app/MainApp/maincontroller/mainviews/mainview.coffee
+++ client/landing/app/MainApp/maincontroller/mainviews/mainview.coffee
@@ -8,13 +8,9 @@
         KD.utils.wait 750, ->
           el.parentElement.removeChild el

-  attachListener = (instance, view)->
-    instance.getView().once 'viewAppended', removePulsing
-    KD.getSingleton('appManager').off 'AppManagerWantsToShowAnApp', attachListener
-
   viewAppended:->

-    KD.getSingleton('appManager').on 'AppManagerWantsToShowAnApp', attachListener
+    KD.utils.wait 1000, removePulsing

     @bindTransitionEnd()
     # @addServerStack()


Speed up token html generation. 20ms -> 6ms

Character replace was most of it. Removing regex creation, array
creation and joins seems to reduce the GC pressure. Calling 500 times,
GC spent 100ms less time.

--- src/token.coffee
+++ src/token.coffee
@@ -2,6 +2,8 @@
 textUtils = require './text-utils'

 whitespaceRegexesByTabLength = {}
+LEADING_WHITESPACE_REGEX = /^[ ]+/
+TRAILING_WHITESPACE_REGEX = /[ ]+$/

 # Private: Represents a single unit of text as selected by a grammar.
 module.exports =
@@ -125,11 +127,9 @@
     html = @value

     if @isHardTab
-      classes = []
-      classes.push('indent-guide') if hasIndentGuide
-      classes.push('invisible-character') if invisibles.tab
-      classes.push('hard-tab')
-      classes = classes.join(' ')
+      classes = 'hard-tab'
+      classes += ' indent-guide' if hasIndentGuide
+      classes += ' invisible-character' if invisibles.tab
       html = html.replace /^./, (match) =>
         match = invisibles.tab ? match
         "#{@wrapCharacters(match)}"
@@ -140,24 +140,20 @@
       leadingHtml = ''
       trailingHtml = ''

-      if hasLeadingWhitespace and match = /^[ ]+/.exec(html)
-        classes = []
-        classes.push('indent-guide') if hasIndentGuide
-        classes.push('invisible-character') if invisibles.space
-        classes.push('leading-whitespace')
-        classes = classes.join(' ')
+      if hasLeadingWhitespace and match = LEADING_WHITESPACE_REGEX.exec(html)
+        classes = 'leading-whitespace'
+        classes += ' indent-guide' if hasIndentGuide
+        classes += ' invisible-character' if invisibles.space

         match[0] = match[0].replace(/./g, invisibles.space) if invisibles.space
         leadingHtml = "#{@wrapCharacters(match[0])}"

         startIndex = match[0].length

-      if hasTrailingWhitespace and match = /[ ]+$/.exec(html)
-        classes = []
-        classes.push('indent-guide') if hasIndentGuide and not hasLeadingWhitespace
-        classes.push('invisible-character') if invisibles.space
-        classes.push('trailing-whitespace')
-        classes = classes.join(' ')
+      if hasTrailingWhitespace and match = TRAILING_WHITESPACE_REGEX.exec(html)
+        classes = 'trailing-whitespace'
+        classes += ' indent-guide' if hasIndentGuide and not hasLeadingWhitespace
+        classes += ' invisible-character' if invisibles.space

         match[0] = match[0].replace(/./g, invisibles.space) if invisibles.space
         trailingHtml = "#{@wrapCharacters(match[0])}"
@@ -175,13 +171,14 @@
     ret = ''

     for i in [startIndex...endIndex]
-      character = str[i]
-        .replace('&', '&')
-        .replace('"', '"')
-        .replace("'", ''')
-        .replace('<', '<')
-        .replace('>', '>')
+      character = switch str[i]
+        when '&' then '&'
+        when '"' then '"'
+        when "'" then '''
+        when '<' then '<'
+        when '>' then '>'
+        else str[i]
+
       ret += "#{character}"

     ret
-


json reporter

json reporter

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

--- src/reporters/json.coffee
+++ src/reporters/json.coffee
@@ -0,0 +1,26 @@
+_ = require 'underscore'
+
+module.exports = (map, options) ->
+
+    log = ''
+    xmlDoc = "<?xml version='1.0' encoding='UTF-8' ?><pmd-cpd>"
+    verbose = options.verbose
+
+    for clone in map.clones
+        do (clone) ->
+            log = "{#{log}
+                \n\t-#{clone.firstFile}:#{clone.firstFileStart}-#{clone.firstFileStart + clone.linesCount}\n\t
+                #{clone.secondFile}:#{clone.secondFileStart}-#{clone.secondFileStart + clone.linesCount}\n\t"
+
+            log = "#{log}\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>#{_.escape(clone.getLines())}</codefragment>
+            </duplication>"
+
+    xmlDoc = xmlDoc + "</pmd-cpd>"
+
+    [xmlDoc, log]


Remove sort from commits controller

Remove sort from commits controller

[#97184318]

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/review.git/'


Add logging

Add logging

--- Email/EmailNotifier.coffee
+++ Email/EmailNotifier.coffee
@@ -37,6 +37,7 @@

                 for email in emails
                     do (email) =>
+                        console.log "Emailing #{email}"
                         # Send the email
                         nodemailer.send_mail {
                             to : email


add more routes to gravity redirect

add more routes to gravity redirect

--- lib/middleware/proxy_to_gravity.coffee
+++ lib/middleware/proxy_to_gravity.coffee
@@ -11,6 +11,6 @@

 app = module.exports = express()

-for route in ['/post', '/oauth2*', '/api/*', '/robots.txt', '/humans.txt', '/sitemap*']
+for route in ['/post', '/oauth2*', '/api/*', '/robots.txt', '/humans.txt', '/sitemap*', "/user/delete", "/user/edit", "/profile/edit"]
   app.all route, (req, res) ->
-    proxy.web req, res, { target: ARTSY_URL }+    proxy.web req, res, { target: ARTSY_URL }


Switch back to one experiment variation for Artist Insights A/B test

--- src/desktop/components/split_test/running_tests.coffee
+++ src/desktop/components/split_test/running_tests.coffee
@@ -50,10 +50,9 @@
     key: 'artist_insights'
     outcomes: [
       'v1'
-      'v2_before_bio'
-      'v2_after_bio'
+      'v2'
     ]
     control_group: 'v1'
-    edge: 'v2_before_bio'
+    edge: 'v2'
     weighting: 'equal'
 }


Benchmark suite :lipstick:

Benchmark suite :lipstick:

--- benchmark/benchmark-suite.coffee
+++ benchmark/benchmark-suite.coffee
@@ -10,8 +10,12 @@

   beforeEach ->
     window.rootViewParentSelector = '#jasmine-content'
-    window.attachRootView()
-    rootView.project.setPath(require.resolve('benchmark/fixtures'))
+    window.attachRootView(require.resolve('benchmark/fixtures'))
+
+    rootView.width(1024)
+    rootView.height(768)
+    require fs.join(atom.configDirPath, "default-config")
+    rootView.open() # open blank editor
     editor = rootView.getActiveEditor()

   afterEach ->
@@ -30,7 +34,7 @@

   describe "300-line-file.", ->
     beforeEach ->
-      editor.edit rootView.project.buildEditSessionForPath('medium.coffee')
+      rootView.open('medium.coffee')

     describe "at-begining.", ->
       benchmark "insert-delete", ->
@@ -51,11 +55,11 @@

   describe "9000-line-file.", ->
     benchmark "opening.", 5, ->
-      editor.edit rootView.project.buildEditSessionForPath('huge.js')
+      rootView.open('huge.js')

     describe "after-opening.", ->
       beforeEach ->
-        editor.edit rootView.project.buildEditSessionForPath('huge.js')
+        rootView.open('huge.js')

       benchmark "moving-to-eof.", 1, ->
         editor.moveCursorToBottom()


Change automatic update check to every 5 mins instead of 15.

--- src/app.coffee
+++ src/app.coffee
@@ -50,5 +50,5 @@
 		console.log('Starting periodic check for updates..')
 		setInterval(->
 			application.update()
-		, 15 * 60 * 1000) # Every 15 mins
+		, 5 * 60 * 1000) # Every 5 mins
 		application.update()


[Marketing Modals] fixes delayDuration statement

--- desktop/components/marketing_signup_modal/index.coffee
+++ desktop/components/marketing_signup_modal/index.coffee
@@ -67,7 +67,7 @@
     @inner.on 'close', => @modal.close()

     loggedOut = not sd.CURRENT_USER?
-    delayDuration = modalData.duration || 2000
+    delayDuration = if modalData.duration then modalData.duration else 2000

     setTimeout @open, delayDuration if loggedOut and modalData?


dont try to show file preview on upload if unknown file type closes 6922 closes 6917

--- packages/rocketchat-ui/client/lib/fileUpload.coffee
+++ packages/rocketchat-ui/client/lib/fileUpload.coffee
@@ -8,6 +8,8 @@
 getUploadPreview = (file, callback) ->
 	# If greater then 10MB don't try and show a preview
 	if file.file.size > 10 * 1000000
+		callback(file, null)
+	else if file.file.type is undefined
 		callback(file, null)
 	else
 		if file.file.type.indexOf('audio') > -1 or file.file.type.indexOf('video') > -1 or file.file.type.indexOf('image') > -1


publish only cards in play

publish only cards in play

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/limratana/superset.git/'


clio-21019 selector fix

clio-21019 selector 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/seanhealy/lib-themisui.git/'


fix #13

fix #13

error: pathspec 'keymaps/sublime-tabs.cson' did not match any file(s) known to git

--- keymaps/sublime-tabs.cson
+++ keymaps/sublime-tabs.cson
@@ -0,0 +1,46 @@
+'.platform-darwin':
+  'cmd-\\': 'tree-view:toggle'
+  'cmd-k cmd-b': 'tree-view:toggle'
+  'cmd-|': 'tree-view:reveal-active-file'
+  'ctrl-0': 'tree-view:toggle-focus'
+
+'.platform-win32, .platform-linux':
+  'ctrl-\\': 'tree-view:toggle'
+  'ctrl-k ctrl-b': 'tree-view:toggle'
+  'ctrl-|': 'tree-view:reveal-active-file'
+  'ctrl-0': 'tree-view:toggle-focus'
+
+'.platform-darwin .tree-view':
+  'cmd-c': 'tree-view:copy'
+  'cmd-x': 'tree-view:cut'
+  'cmd-v': 'tree-view:paste'
+
+'.platform-win32 .tree-view, .platform-linux .tree-view':
+  'ctrl-c': 'tree-view:copy'
+  'ctrl-x': 'tree-view:cut'
+  'ctrl-v': 'tree-view:paste'
+
+'.tree-view':
+  'right': 'tree-view:expand-directory'
+  'ctrl-]': 'tree-view:expand-directory'
+  'l': 'tree-view:expand-directory'
+  'ctrl-f': 'tree-view:expand-directory'
+  'left': 'tree-view:collapse-directory'
+  'ctrl-[': 'tree-view:collapse-directory'
+  'h': 'tree-view:collapse-directory'
+  'ctrl-b': 'tree-view:collapse-directory'
+  'enter': 'tree-view:open-selected-entry'
+  'ctrl-C': 'tree-view:copy-full-path'
+  'm': 'tree-view:move'
+  'f2': 'tree-view:move'
+  'a': 'tree-view:add-file'
+  'shift-a': 'tree-view:add-folder'
+  'd': 'tree-view:duplicate'
+  'delete': 'tree-view:remove'
+  'backspace': 'tree-view:remove'
+  'k': 'core:move-up'
+  'j': 'core:move-down'
+
+'.tree-view-dialog .mini.editor':
+  'enter': 'core:confirm'
+  'escape': 'core:cancel'


Not full string in form BUGFIX

Not full string in form BUGFIX

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/RobertsGroza/kakimasu.git/'


server: scripts: currentGroup typo

server: scripts: currentGroup typo


Removing console.log from BadgeService

Removing console.log from BadgeService

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/UM-USElab/gradecraft-development.git/'


prevent status update after file cancelled

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/prognostikos/uploadcare-widget.git/'


A11y: Screen Readers now read the file name in the checkbox label

Fixes CNVS-18828

Test plan:
- Using a screen reader, visit New Files.
- Read the checkboxes in the grid.
- Notice that they now say the name of the file as part of the label of the
  checkbox.

Change-Id: Ieed13ee4fab2ee608cf09b8df446cffca8d9d30c
Reviewed-on: https://gerrit.instructure.com/49385
Reviewed-by: Clay Diffrient <9dff2e5c98626d20d2848250c411e8009465bb87@instructure.com>
Tested-by: Jenkins
QA-Review: Jahnavi Yetukuri <ed2b2672ccc2e59e56c0615df7f01b579202e014@instructure.com>
Product-Review: Clay Diffrient <9dff2e5c98626d20d2848250c411e8009465bb87@instructure.com>

--- app/coffeescripts/react_files/components/FolderChild.coffee
+++ app/coffeescripts/react_files/components/FolderChild.coffee
@@ -111,6 +111,8 @@

     render: withReactDOM ->

+      selectCheckboxLabel = I18n.t('Select %{itemName}', itemName: @props.model.displayName())
+
       keyboardCheckboxClass = classSet({
         'screenreader-only': @state.hideKeyboardCheck
         'multiselectable-toggler': true
@@ -124,6 +126,7 @@
         label className: keyboardCheckboxClass, role: 'gridcell',
           input {
             type: 'checkbox'
+            'aria-label': selectCheckboxLabel
             onFocus: => @setState({hideKeyboardCheck: false})
             onBlur: => @setState({hideKeyboardCheck: true})
             className: keyboardCheckboxClass
@@ -131,7 +134,7 @@
             onChange: -> #noop, will be caught by 'click' on root node
           }
           span {className: keyboardLabelClass},
-            I18n.t('labels.select', 'Select This Item')
+            selectCheckboxLabel

         div className:'ef-name-col ellipsis', role: 'rowheader',
           if @state.editing


group: delete subscription first in the destroy func

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -1610,6 +1610,17 @@
     queue = [

       (next) ->
+        return next()  unless client
+
+        url = '/api/social/payment/subscription/delete'
+        { deleteReq } = require '../socialapi/requests'
+        { sessionToken } = client
+
+        deleteReq url, { sessionToken }, (err, body) ->
+          err = null  if err?.description is 'not found'
+          kallback 'Subscription', next, err?.error
+
+      (next) ->
         JApiToken = require '../apitoken'
         JApiToken.remove { group: slug }, (err) ->
           kallback 'JApiToken', next, err
@@ -1643,19 +1654,6 @@

       (next) =>
         Relationship.remove { sourceId : @getId() }, next
-
-      (next) ->
-        return next()  unless client
-
-        url = '/api/social/payment/subscription/delete'
-        { deleteReq } = require '../socialapi/requests'
-        { sessionToken } = client
-
-        deleteReq url, { sessionToken }, (err, body) ->
-          if err?.description is 'not admin of the group'
-            console.log "[GROUP_DESTROY_FAILED] for #{slug} please notify Admins"
-          err = null  if err?.description is 'not found'
-          kallback 'Subscription', next, err?.error

       (next) =>
         @remove (err) -> kallback 'JGroup', next, err


Don't pass custom spinner options

Don't pass custom spinner options


Workspace: Css class changes for buttons.

--- client/landing/app/CommonViews/workspace/panel/panel.coffee
+++ client/landing/app/CommonViews/workspace/panel/panel.coffee
@@ -10,30 +10,31 @@
     @panes         = []

     @createHeader()
-    @createHeaderHint()     if options.hint
     @createHeaderButtons()  if options.buttons?.length
+    # @createHeaderHint()     if options.hint

     @createLayout()

     @createPanes()

   createHeader: ->
-    @header     = new KDHeaderView
-      cssClass: "editor-header"
-      partial   : @getOptions().title
-
-  createHeaderHint: ->
-    @header.addSubView new KDCustomHTMLView
-      partial   : "?"
-      cssClasss : "hint"
-      tooltip   :
-        title   : @getOptions().hint
+    @header     = new KDView
+      cssClass  : "inner-header"
+      partial   : """#{@getOptions().title}"""

   createHeaderButtons: ->
     for buttonOptions in @getOptions().buttons
       buttonView = new KDButtonView buttonOptions
       @headerButtons[buttonOptions.title] = buttonView
       @header.addSubView buttonView
+
+  createHeaderHint: ->
+    @header.addSubView new KDButtonView
+      cssClass  : "hint"
+      iconOnly  : yes
+      iconClass : "exclamation"
+      tooltip   :
+        title   : @getOptions().hint

   createLayout: ->
     @container = new KDView


CLIO-23420: Clean up specs

CLIO-23420: Clean up specs


Usage version uses steroidsCli version

Usage version uses steroidsCli version

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/steroids.git/'


Add bad word filter to settings UI

Add bad word filter to settings UI

--- packages/rocketchat-lib/server/startup/settings.coffee
+++ packages/rocketchat-lib/server/startup/settings.coffee
@@ -155,6 +155,8 @@
 	@add 'Message_AlwaysSearchRegExp', false, { type: 'boolean' }
 	@add 'Message_ShowEditedStatus', true, { type: 'boolean', public: true }
 	@add 'Message_ShowDeletedStatus', false, { type: 'boolean', public: true }
+	@add 'Message_AllowBadWordsFilter', false, { type: 'boolean', public: true}
+	@add 'Message_BadWordsFilterList', '', {type: 'string', public: true}
 	@add 'Message_KeepHistory', false, { type: 'boolean', public: true }
 	@add 'Message_MaxAll', 0, { type: 'int', public: true }
 	@add 'Message_MaxAllowedSize', 5000, { type: 'int', public: true }


Removed Duplicates

Removed Duplicates

--- app/lib/world/names.coffee
+++ app/lib/world/names.coffee
@@ -87,30 +87,6 @@
     'Lawrence'
     'Leopold'
     'Louis'
-    'Alistair'
-    'Augustus'
-    'Barron'
-    'Bill'
-    'Bond'
-    'Cecil'
-    'Cid'
-    'Dax'
-    'Duke'
-    'Ezra'
-    'Felix'
-    'Ferb'
-    'Gatsby'
-    'Gordon'
-    'Halle'
-    'Harry'
-    'Hirium'
-    'Huburt'
-    'Hugo'
-    'Jax'
-    'Jonah'
-    'Kirin'
-    'Kumar'
-    'Leopold'
     'Lucas'
     'Lucian'
     'Malcolm'
@@ -136,14 +112,6 @@
     'Ralph'
     'Randy'
     'Raymond'
-    'Max'
-    'Maxwell'
-    'Miles'
-    'Mischa'
-    'Orion'
-    'Philippian'
-    'Phineas'
-    'Pierce'
     'Remy'
     'Ricardo'
     'Richard'
@@ -179,16 +147,6 @@
     'Wayne'
     'William'
     'Willie'
-    'Ryan'
-    'Sage'
-    'Samson'
-    'Silas'
-    'Sterling'
-    'Stormy'
-    'Thelonious'
-    'Theo'
-    'Tyrone'
-    'William'
   ]
   'Soldier F': [
     'Alana'
@@ -202,7 +160,6 @@
     'Ann'
     'Anna'
     'Anne'
-    'Annie'
     'Annie'
     'Aphrodite'
     'Ashley'
@@ -248,7 +205,6 @@
     'Jean'
     'Jennifer'
     'Jessica'
-    'Joan'
     'Joan'
     'Joyce'
     'Judith'
@@ -299,7 +255,6 @@
     'Sandra'
     'Sara'
     'Sarah'
-    'Sarah'
     'Scarlett'
     'Shannon'
     'Sharon'
@@ -313,26 +268,6 @@
     'Trinity'
     'Virginia'
     'Wanda'
-    'Allankrita'
-    'Annie'
-    'Aphrodite'
-    'Buffy'
-    'Coco'
-    'Gabrielle'
-    'Gorgin'
-    'Helga'
-    'Holly'
-    'Imani'
-    'Joan'
-    'Kay'
-    'Lana'
-    'Lukaz'
-    'Natasha'
-    'Nikita'
-    'Sarah'
-    'Scarlett'
-    'Shannon'
-    'Trinity'
   ]
   'Peasant M': [
     'Azgot'


Add acceptance tests for dependencies.

Add acceptance tests for dependencies.

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/jamesotron/ember-enumerology.git/'


added recaptcha service

added recaptcha service

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/Bogdan-p/bookingbug-angular.git/'


limit

limit

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/sagish/compound-angular-todo.git/'


Delete converted file

Delete converted file

--- packages/rocketchat-ui/client/lib/fileUpload.coffee
+++ packages/rocketchat-ui/client/lib/fileUpload.coffee
@@ -1,187 +0,0 @@
-readAsDataURL = (file, callback) ->
-	reader = new FileReader()
-	reader.onload = (ev) ->
-		callback ev.target.result, file
-
-	reader.readAsDataURL file
-
-getUploadPreview = (file, callback) ->
-	# If greater then 10MB don't try and show a preview
-	if file.file.size > 10 * 1000000
-		callback(file, null)
-	else
-		if file.file.type.indexOf('audio') > -1 or file.file.type.indexOf('video') > -1 or file.file.type.indexOf('image') > -1
-			file.type = file.file.type.split('/')[0]
-
-			readAsDataURL file.file, (content) ->
-				callback(file, content)
-		else
-			callback(file, null)
-
-formatBytes = (bytes, decimals) ->
-	if bytes == 0
-		return '0 Bytes'
-
-	k = 1000
-	dm = decimals + 1 or 3
-
-	sizes = [
-		'Bytes'
-		'KB'
-		'MB'
-		'GB'
-		'TB'
-		'PB'
-	]
-
-	i = Math.floor(Math.log(bytes) / Math.log(k))
-
-	parseFloat((bytes / k ** i).toFixed(dm)) + ' ' + sizes[i]
-
-readAsArrayBuffer = (file, callback) ->
-	reader = new FileReader()
-	reader.onload = (ev) ->
-		callback ev.target.result, file
-
-	reader.readAsArrayBuffer file
-
-
-@fileUpload = (files) ->
-	roomId = Session.get('openedRoom')
-	files = [].concat files
-
-	consume = ->
-		file = files.pop()
-		if not file?
-			swal.close()
-			return
-
-		if not RocketChat.fileUploadIsValidContentType file.file.type
-			swal
-				title: t('FileUpload_MediaType_NotAccepted')
-				text: file.file.type || "*.#{s.strRightBack(file.file.name, '.')}"
-				type: 'error'
-				timer: 3000
-			return
-
-		if file.file.size is 0
-			swal
-				title: t('FileUpload_File_Empty')
-				type: 'error'
-				timer: 1000
-			return
-
-		getUploadPreview file, (file, preview) ->
-			text = ''
-
-			if file.type is 'audio'
-				text = """
-

-						<audio  style="width: 100%;" controls="controls">
-							<source src="#{preview}" type="audio/wav">
-							Your browser does not support the audio element.
-						</audio>
-

-

-						<input id='file-name' style='display: inherit;' value='#{Handlebars._escape(file.name)}' placeholder='#{t("Upload_file_name")}'>
-						<input id='file-description' style='display: inherit;' value='' placeholder='#{t("Upload_file_description")}'>
-

-				"""
-			else if file.type is 'video'
-				text = """
-

-						<video  style="width: 100%;" controls="controls">
-							<source src="#{preview}" type="video/webm">
-							Your browser does not support the video element.
-						</video>
-

-

-						<input id='file-name' style='display: inherit;' value='#{Handlebars._escape(file.name)}' placeholder='#{t("Upload_file_name")}'>
-						<input id='file-description' style='display: inherit;' value='' placeholder='#{t("Upload_file_description")}'>
-

-				"""
-			else if file.type is 'image'
-				text = """
-

-

-

-

-						<input id='file-name' style='display: inherit;' value='#{Handlebars._escape(file.name)}' placeholder='#{t("Upload_file_name")}'>
-						<input id='file-description' style='display: inherit;' value='' placeholder='#{t("Upload_file_description")}'>
-

-				"""
-			else
-				fileSize = formatBytes(file.file.size)
-
-				text = """
-

-
#{Handlebars._escape(file.name)} - #{fileSize}

-

-

-						<input id='file-name' style='display: inherit;' value='#{Handlebars._escape(file.name)}' placeholder='#{t("Upload_file_name")}'>
-						<input id='file-description' style='display: inherit;' value='' placeholder='#{t("Upload_file_description")}'>
-

-				"""
-
-			swal
-				title: t('Upload_file_question')
-				text: text
-				showCancelButton: true
-				closeOnConfirm: false
-				closeOnCancel: false
-				confirmButtonText: t('Send')
-				cancelButtonText: t('Cancel')
-				html: true
-			, (isConfirm) ->
-				consume()
-				if isConfirm isnt true
-					return
-
-				record =
-					name: document.getElementById('file-name').value or file.name or file.file.name
-					size: file.file.size
-					type: file.file.type
-					rid: roomId
-					description: document.getElementById('file-description').value
-
-				upload = fileUploadHandler record, file.file
-
-				uploading = Session.get('uploading') or []
-				uploading.push
-					id: upload.id
-					name: upload.getFileName()
-					percentage: 0
-
-				Session.set 'uploading', uploading
-
-				upload.onProgress = (progress) ->
-					uploading = Session.get('uploading')
-
-					item = _.findWhere(uploading, {id: upload.id})
-					if item?
-						item.percentage = Math.round(progress * 100) or 0
-						Session.set 'uploading', uploading
-
-				upload.start()
-
-				Tracker.autorun (c) ->
-					cancel = Session.get "uploading-cancel-#{upload.id}"
-					if cancel
-						upload.stop()
-						c.stop()
-
-						uploading = Session.get 'uploading'
-						if uploading?
-							item = _.findWhere(uploading, {id: upload.id})
-							if item?
-								item.percentage = 0
-							Session.set 'uploading', uploading
-
-						Meteor.setTimeout ->
-							uploading = Session.get 'uploading'
-							if uploading?
-								item = _.findWhere(uploading, {id: upload.id})
-								Session.set 'uploading', _.without(uploading, item)
-						, 1000
-
-	consume()


Protect from appending undefined variable

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/lonelyplanet/rizzo.git/'


Force JSON return type in CORS

Force JSON return type in CORS


[CActivity] minor

[CActivity] minor

--- workers/social/lib/social/models/activity/index.coffee
+++ workers/social/lib/social/models/activity/index.coffee
@@ -339,13 +339,13 @@
       to = Math.floor(to/1000)  # unix vs js timestamp diff.

       requestOptions =
-        client    : client
-        startDate : to
-        withExempt: options.withExempt
-        group     :
-          groupName : group.slug
-          groupId   : group._id
-          facets    : options.facets
+        client       : client
+        startDate    : to
+        withExempt   : options.withExempt
+        group        :
+          groupName  : group.slug
+          groupId    : group._id
+          facets     : options.facets

       FetchAllActivityParallel = require './../graph/fetch'
       fetch = new FetchAllActivityParallel requestOptions


Working on handling the viewport better, scrolling between timelines.


Hide all profile sections except description

--- resources/assets/coffee/react/profile-page/main.coffee
+++ resources/assets/coffee/react/profile-page/main.coffee
@@ -62,6 +62,9 @@
       recentlyReceivedKudosu: @props.recentlyReceivedKudosu
       showMorePagination: {}

+    if @props.user.isBot
+      @state.profileOrder = ['me']
+
     for own elem, perPage of @props.perPage
       @state.showMorePagination[elem] ?= {}
       @state.showMorePagination[elem].hasMore = @state[elem].length > perPage


Add configuration file loading and parsing.

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/RobotSnacks/stout-server.git/'


rearrange tabs according to usage

rearrange tabs according to usage

--- app/assets/javascripts/uploadcare/settings.js.coffee
+++ app/assets/javascripts/uploadcare/settings.js.coffee
@@ -24,7 +24,7 @@
     'multiple-max': 0
     'multiple-min': 1
     'path-value': false
-    'tabs': 'file url facebook instagram flickr dropbox gdrive evernote box skydrive'
+    'tabs': 'file url facebook gdrive dropbox instagram evernote flickr skydrive box'
     'preferred-types': ''
     'input-accept-types': ''  # '' means default, null means "disable accept"
     # upload settings
@@ -39,7 +39,7 @@

   presets =
     'tabs':
-      all: 'file url facebook dropbox gdrive instagram flickr vk evernote box skydrive'
+      all: 'file url facebook gdrive dropbox instagram evernote flickr skydrive box'
       default: defaults.tabs


Social: check for existnce before returning error

--- workers/social/lib/social/models/socialapi/requests.coffee
+++ workers/social/lib/social/models/socialapi/requests.coffee
@@ -9,7 +9,7 @@
       return callback null, body

 createAccount = (id, callback)->
-  return callback {message:"Accont id is not valid"}
+  return callback {message:"Accont id is not valid"} unless id
   url = "#{SOCIAL_API_URL}/account"
   post url, {oldId: id}, callback


Doh. Forgot new file

Doh. Forgot new file

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

--- src/layout/behavior.coffee
+++ src/layout/behavior.coffee
@@ -0,0 +1,50 @@
+#
+# behavior.coffee
+#
+# A Behavior is a dictionary of Words and Actions
+# Actions can be either a list of words (array)
+# or a sentence (string)
+#
+# Role: create and display program objects
+#
+# Responsibility:
+# * populate behavior pane of sprite inspector
+# * display the current behavior and command
+# * apply command events to the selected program
+# * send next commmand on step events
+
+{my} = require '../my'
+{make} = require '../render/make'
+# {processor} = require './processor'
+{programs} = require './programs'
+
+#
+# TODO: Editing Issues
+# * add new programs
+# * rename events
+# * select the target program
+# * reorder commmands within and between programs
+# * drag commands from above into a program
+# * drag programs into the commands view!
+#
+# TODO: Behavior Issues
+# * step through a program
+# * send next command to sprite
+# * detect and handle interruptions
+#   * hitting boundaries
+#   * collisions
+#   * finishing levels
+#
+
+exports.behavior = (sprite) ->
+  rows = make.rows 'behavior', programs(sprite)
+  default_program = rows._CHILDREN[0]
+  my.assert default_program, "no default_program"
+
+  initial_label = default_program._LABEL
+  my.extend rows, # processor(initial_label, sprite),
+    {
+#      _EXPORTS: ['step']
+      y: (world) -> world.index * my.row.spacing
+      class: 'program'
+    }


proc: Adding new files processor

proc: Adding new files processor

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

--- src/processors/files.coffee
+++ src/processors/files.coffee
@@ -0,0 +1,28 @@
+# iterates through files in the repository
+
+recursive = require 'recursive-readdir'
+async = require 'async'
+
+logger = require '../logger'
+
+module.exports = files = (pathRe, callback) ->
+  return (repo, finished) ->
+    repoLoc = repo.workdir()
+    recursive repoLoc, ["#{repoLoc}/.git/**"], (err, files) ->
+      async.eachSeries files, ((filePath, done) ->
+        relativePath = filePath.replace repoLoc, ''
+
+        # Remove the leading '/' if present
+        if relativePath.substring(0, 1) == '/'
+          relativePath = relativePath.substring 1
+
+        re = new RegExp pathRe
+        if re.test relativePath
+          logger.info "On file #{logger.highlight relativePath}"
+          callback filePath, done
+        else
+          done()
+      ),
+      ((err) ->
+        finished err
+      )


Added birthday.coffee (delegate your birthday greetings to Hubot).

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

--- src/scripts/birthday.coffee
+++ src/scripts/birthday.coffee
@@ -0,0 +1,90 @@
+# Description:
+#   Delegate your birthday greetings, celebrations and quotes to Hubot.
+#
+# Dependencies:
+#   None
+#
+# Configuration:
+#   None
+#
+# Commands:
+#   hubot birthday quote for <user> -- congratulate <user> with a random birthday quote
+#   hubot celebrate me <user> -- congratulate <user> with an inspirational greeting
+#   hubot happy birthday me <user> -- congratulate <user> with a humorous greeting
+#
+# Author:
+#   sopel
+
+module.exports = (robot) ->
+
+  robot.respond /(birthday quote)( for )?(.*)/i, (msg)->
+    name = msg.match[3].trim()
+    if name.length == 0
+      msg.send(quote())
+    else
+      msg.send(name + " - here's a quote for you: ")
+      msg.send(quote(name))
+
+  robot.respond /(happy birthday)( me )?(.*)/i, (msg)->
+    name = msg.match[3].trim()
+    if name.length == 0
+      msg.send(quote())
+    else
+      msg.send(greeting(name))
+
+  robot.respond /(celebrate)( me )?(.*)/i, (msg)->
+    name = msg.match[3].trim()
+    if name.length == 0
+      msg.send("You must be kidding.")
+    else
+      msg.send(celebrate(name))
+
+celebrate = (name) ->
+  celebrates[(Math.random() * celebrates.length) >> 0].replace(/{name}/, name);
+
+celebrates = [
+  "{name} - Hoping that your day will be as special as you are.",
+  "{name} - Count your life by smiles, not tears. Count your age by friends, not years.",
+  "May the years continue to be good to you. Happy Birthday {name}!",
+  "{name} - You're not getting older, you're getting better.",
+  "{name} - May this year bring with it all the success and fulfillment your heart desires.",
+  "{name} - Wishing you all the great things in life, hope this day will bring you an extra share of all that makes you happiest.",
+  "Happy Birthday {name}, and may all the wishes and dreams you dream today turn to reality.",
+  "May this day bring to you all things that make you smile. Happy Birthday {name}!",
+  "{name} - Your best years are still ahead of you.",
+  "{name} - Birthdays are filled with yesterday's memories, today's joys, and tomorrow's dreams.",
+  "{name} - Hoping that your day will be as special as you are.",
+  "{name} - You'll always be forever young."
+]
+greeting = (name) ->
+  greetings[(Math.random() * greetings.length) >> 0].replace(/{name}/, name);
+
+greetings = [
+  "Happy Birthday {name}, you're not getting older, you're just a little closer to death.",
+  "Birthdays are good for you {name}. Statistics show that people who have the most live the longest!",
+  "{name} - I'm so glad you were born, because you brighten my life and fill it with joy.",
+  "{name} - Always remember: growing old is mandatory, growing up is optional.",
+  "{name} - Better to be over the hill than burried under it.",
+  "You always have such fun birthdays {name}, you should have one every year.",
+  "Happy birthday to {name}, a person who is smart, good looking, and funny and reminds me a lot of myself.",
+  "{name} - We know we're getting old when the only thing we want for our birthday is not to be reminded of it.",
+  "Happy Birthday on your very special day {name}, I hope that you don't die before you eat your cake."
+]
+
+quote = () ->
+  quotes[(Math.random() * quotes.length) >> 0];
+
+quotes = [
+  "Our birthdays are feathers in the broad wing of time. - Jean Paul Richter",
+  "Inside every older person is a younger person wondering what happened. - Jennifer Yane",
+  "Wisdom doesn't necessarily come with age. Sometimes age just shows up all by itself. - Tom Wilson",
+  "May you stay forever young. - Bob Dylan",
+  "The old believe everything; the middle-aged suspect everything; the young know everything. - Oscar Wilde",
+  "Old age is like everything else. To make a success of it, you've got to start young. - Fred Astaire",
+  "Age is a number and mine is unlisted. - Unknown",
+  "When I was younger, I could remember anything, whether it happened or not.- Mark Twain",
+  "Whatever with the past has gone, The best is always yet to come. - Lucy Larcom",
+  "It takes a long time to grow young. - Pablo Picasso",
+  "Few women admit their age. Few men act theirs. - Unkown",
+  "The best way to remember your wife's birthday is to forget it once. - H. V. Prochnow"
+]


added the coffee file

added the coffee file

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

--- sketch.coffee
+++ sketch.coffee
@@ -0,0 +1,73 @@
+canvas = document.querySelector("#whiteboard")
+r = 4
+g = 10
+b = 20
+r2 = 50
+g2 = 150
+b2 = 220
+t_r = 4
+t_g = 10
+t_b = 20
+ctx = canvas.getContext("2d")
+sketch = document.querySelector("#container")
+sketch_style = getComputedStyle(sketch)
+canvas.width = parseInt(sketch_style.getPropertyValue("width"))
+canvas.height = parseInt(sketch_style.getPropertyValue("height"))
+mouse =
+  x: 0
+  y: 0
+
+last_mouse =
+  x: 0
+  y: 0
+
+ctx.lineWidth = 5 #to get it from zaid
+ctx.lineJoin = "round"
+ctx.lineCap = "round"
+
+canvas.addEventListener "mousemove", ((e) ->
+  last_mouse.x = mouse.x
+  last_mouse.y = mouse.y
+  mouse.x = e.clientX
+  mouse.y = e.clientY
+), false
+
+canvas.addEventListener "mousedown", ((e) ->
+  canvas.addEventListener "mousemove", onPaint, false
+), false
+
+canvas.addEventListener "mouseup", (->
+  t_r = r
+  t_g = g
+  t_b = b
+  canvas.removeEventListener "mousemove", onPaint, false
+), false
+
+canvas.addEventListener "touchmove", ((e) ->
+  last_mouse.x = mouse.x
+  last_mouse.y = mouse.y
+  mouse.x = e.touches[0].pageX
+  mouse.y = e.touches[0].pageY
+), false
+
+canvas.addEventListener "touchstart", ((e) ->
+  canvas.addEventListener "touchmove", onPaint, false
+), false
+
+canvas.addEventListener "touchend", (->
+  canvas.removeEventListener "touchmove", onPaint, false
+), false
+
+onPaint = ->
+  get_color()
+  ctx.strokeStyle = "rgb(#{Math.floor(t_r + 0.49)}, #{Math.floor(t_g + 0.49)}, #{Math.floor(t_b + 0.49)})"
+  ctx.beginPath()
+  ctx.moveTo last_mouse.x, last_mouse.y
+  ctx.lineTo mouse.x, mouse.y
+  ctx.closePath()
+  ctx.stroke()
+
+get_color = ->
+  t_r = t_r + (r2 - t_r) * 0.01
+  t_g = t_g + (g2 - t_g) * 0.01
+  t_b = t_b + (b2 - t_b) * 0.01


servers: add teams/invite-by-csv-analyze enpoint to analyze csv

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/andrewjcasal/koding.git/'


pass user when logging to external

pass user when logging to external

--- client/Main/rollbar.coffee
+++ client/Main/rollbar.coffee
@@ -3,19 +3,22 @@
   return  unless KD.config.logToExternal and _rollbar
   return  if KD.isGuest()

+  {nickname} = KD.whoami().profile
+
   if args?
-    args.msg = msg
+    args.msg  = msg
+    args.user = nickname
+
     _rollbar.push args
   else
-    _rollbar.push msg
+    _rollbar.push msg:msg, user:nickname

 # log ping times so we know if failure was due to user's slow
 # internet or our internals timing out
 KD.logToExternalWithTime = (name, options)->
   KD.troubleshoot (times)->
-    KD.logToExternal {
+    KD.logToExternal "#{name} timed out", {
       options
-      msg      : "#{name} timed out"
       pings    : times
       protocol : KD.remote.mq.ws.protocol
     }


Update simple_form_extension.coffee

Update simple_form_extension.coffee

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/zenati/simple_form_extension.git/'


Wait for MP to load before setting

Wait for MP to load before setting

--- components/split_test/split_test.coffee
+++ components/split_test/split_test.coffee
@@ -1,7 +1,7 @@
 _ = require 'underscore'
 Backbone = require 'backbone'
 { CURRENT_USER, NODE_ENV } = require('sharify').data
-{ getProperty, setProperty, unsetProperty, setDimension } = require '../../lib/analytics.coffee'
+{ load, getProperty, setProperty, unsetProperty, setDimension } = require '../../lib/analytics.coffee'
 IS_TEST_ENV = not _.contains(['production', 'staging', 'development'], NODE_ENV)

 module.exports = class SplitTest
@@ -19,9 +19,18 @@

   set: (outcome) ->
     @cookies().set @_key(), outcome
+
+    # Set for Mixpanel
     unsetProperty @_key() # Force unset
-    setProperty _.tap({}, (hsh) => hsh[@_key()] = outcome)
+    property = _.tap({}, (hsh) => hsh[@_key()] = outcome)
+    if IS_TEST_ENV
+      setProperty property
+    else
+      load -> setProperty property
+
+    # Set for Google Analytics
     setDimension @dimension, outcome if @dimension?
+
     outcome

   get: ->


add fact facts

add fact facts

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

--- scripts/fact.coffee
+++ scripts/fact.coffee
@@ -0,0 +1,18 @@
+# Description:
+#   Fact facts
+# Commands:
+#   hubot fact - Retuns a fact fact
+# Facts from http://en.wikipedia.org/wiki/Fact
+module.exports = (robot) ->
+  robot.respond /fact/i, (msg) ->
+    quotes = [
+      'The word fact derives from the Latin factum, and was first used in English with the same meaning: "a thing done or performed", a use that is now obsolete.[1] The common usage of "something that has really occurred or is the case" dates from the middle of the sixteenth century.',
+      'Fact is sometimes used synonymously with truth, as distinct from opinions, falsehoods, or matters of taste. This use is found in such phrases as, It is a fact that the cup is blue or Matter of fact, and "... not history, nor fact, but imagination." Filmmaker Werner Herzog distinguishes clearly between the two, claiming that "fact creates norms, and truth illumination".'
+      'Fact also indicates a matter under discussion deemed to be true or correct, such as to emphasize a point or prove a disputed issue; (e.g., "... the fact of the matter is ...").',
+      'Alternatively, fact may also indicate an allegation or stipulation of something that may or may not be a "true fact", (e.g., "the author\'s facts are not trustworthy"). This alternate usage, although contested by some, has a long history in standard English.',
+      'Fact may also indicate findings derived through a process of evaluation, including review of testimony, direct observation, or otherwise; as distinguishable from matters of inference or speculation. This use is reflected in the terms "fact-find" and "fact-finder" (e.g., "set up a fact-finding commission").',
+      'Facts may be checked by reason, experiment, personal experience, or may be argued from authority. Roger Bacon wrote "If in other sciences we should arrive at certainty without doubt and truth without error, it behooves us to place the foundations of knowledge in mathematics."'
+      'In philosophy, the concept fact is considered in epistemology and ontology. Questions of objectivity and truth are closely associated with questions of fact. A "fact" can be defined as something which is the case, that is, a state of affairs.',
+      'Facts may be understood as that which makes a true sentence true. Facts may also be understood as those things to which a true sentence refers. The statement "Jupiter is the largest planet in the solar system" is about the fact Jupiter is the largest planet in the solar system.'
+    ]
+    msg.send msg.random quotes


list hot entries on Hatena bookmarks

list hot entries on Hatena bookmarks

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

--- scripts/news.coffee
+++ scripts/news.coffee
@@ -0,0 +1,34 @@
+# Description:
+#   Get your favorite news
+#
+# Dependencies:
+#   "cheerio": "0.17.0"
+#
+# Commands:
+#   hubot news hatebu <category> -- List hot entries on Hatena bookmarks
+#
+# Author:
+#   yulii
+
+cheerio = require('cheerio')
+
+module.exports = (robot) ->
+  robot.respond /news\s+hatebu(\s+\w+)?/i, (msg) ->
+    type = (msg.match[1] || "").trim()
+    url  = "http://b.hatena.ne.jp/hotentry/#{type}"
+    viewList msg, url
+
+viewList = (msg, url) ->
+  msg.send "GET #{url}", "Please wait a few seconds."
+  msg.http("#{url}.rss")
+    .get() (err, res, body) ->
+      if res.statusCode isnt 200
+        msg.send "Request didn't come back HTTP 200 :("
+        return
+
+      $ = cheerio.load(body, normalizeWhitespace: true, xmlMode: true)
+      $('item').each (i, e) ->
+        title = $(this).find('title').text()
+        link  = $(this).find('link').text()
+        msg.send "#{title}\n#{link}"
+


Ross Tracker 5000

Ross Tracker 5000

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

--- scripts/ross.coffee
+++ scripts/ross.coffee
@@ -0,0 +1,25 @@
+# Description:
+#   Finds Ross.
+#
+
+BASE_URL = 'http://odyssey.rosspaffett.com'
+POLL_INTERVAL_MINS = 10
+ROOM = 'pm-with:ari@scvngr.com'
+
+cheerio = require 'cheerio'
+sys = require 'sys'
+
+module.exports = (robot) ->
+  callback = ->
+    robot.http(BASE_URL + '/posts').get() (err, res, body) ->
+      $ = cheerio.load(body)
+      location = $('.post-header strong').eq(1).text()
+      link = BASE_URL + $('a.post-link').first().attr('href')
+      picture = $('a.post-link img').first().attr('src')
+
+      if robot.brain.data.rosslink isnt link
+        robot.brain.data.rosslink = link
+        robot.send {room: ROOM}, "Ross has arrived in #{location} #{link} #{picture}"
+
+  callback()
+  setInterval callback, POLL_INTERVAL_MINS * 60 * 1000


remove parallax for small devices

remove parallax for small devices

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/tkraak/elm.git/'


Display default gravatar for users who don't have one

[#93521276]

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/'


drag'n'drop events fix (always call delayedDragState)

--- app/assets/javascripts/uploadcare/widget/dragdrop.js.coffee
+++ app/assets/javascripts/uploadcare/widget/dragdrop.js.coffee
@@ -19,7 +19,7 @@
         .on 'drop', (e) ->
           e.stopPropagation() # Prevent redirect
           e.preventDefault()
-          dragState off
+          delayedDragState off, 0
           $(this).trigger('uploadcare.drop')
           dt = e.originalEvent.dataTransfer
           if dt.files.length
@@ -45,11 +45,11 @@
         clearTimeout delayedDragState.timeout
         delayedDragState.timeout = null
       if delay > 0
-        delayedDragState.timeout = setTimeout (-> dragState newActive), delay
+        delayedDragState.timeout = setTimeout (-> _dragState newActive), delay
       else
-        dragState newActive
+        _dragState newActive

-    dragState = (newActive) ->
+    _dragState = (newActive) ->
       if active != newActive
         active = newActive
         $('@uploadcare-drop-area').trigger('uploadcare.dragstatechange', active)


sandbox: update `newkontrol` configuration

--- config/main.sandbox.coffee
+++ config/main.sandbox.coffee
@@ -185,7 +185,7 @@
       github    :
         clientId: "f733c52d991ae9642365"
       newkontrol:
-        url         : 'https://stage-kontrol.koding.com/kite'
+        url         : 'http://sandbox.koding.com:8888/kite'
       fileFetchTimeout: 15 * 1000 # seconds
       externalProfiles  :
         github          :
@@ -286,12 +286,12 @@
     cleanupCron     : '*/10 * * * * *'
   pidFile       : '/tmp/koding.server.pid'
   newkites      :
-    useTLS          : yes
+    useTLS          : no
     certFile        : "/etc/ssl/koding/wildcard.sj.koding.com.crt"
     keyFile         : "/etc/ssl/koding/wildcard.sj.koding.com.key"
   newkontrol      :
-    port            : 443
-    useTLS          : yes
+    port            : 8888
+    useTLS          : no
     certFile        : "/opt/koding/certs/koding_com_cert.pem"
     keyFile         : "/opt/koding/certs/koding_com_key.pem"
     publicKeyFile   : "/opt/koding/certs/test_kontrol_rsa_public.pem"


Adds turbase-spec test cases

Adds turbase-spec test cases

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

--- test/turbase-spec.coffee
+++ test/turbase-spec.coffee
@@ -0,0 +1,10 @@
+turbase = require './../coffee/turbase'
+
+describe '#get()', ->
+  it 'should get without errors', (done) ->
+    req =
+      params:
+        object: 'turer'
+        id: abc
+    turbase.get
+    done()


fix testApp gruntfile

fix testApp gruntfile

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/'


fix(test): add unit test for set-value pollution

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

--- test/prototype-pollution.coffee
+++ test/prototype-pollution.coffee
@@ -0,0 +1,12 @@
+chai        = require "chai"
+objectUtils = require "../lib/utils.js"
+
+describe( "Prototype pollution", () ->
+    describe( "#setValue()", () ->
+        it( "Should not pollute value", () ->
+            objectUtils.setValue( '__proto__.polluted', {}, true )
+
+            chai.expect( global.polluted ).to.eql( undefined )
+        )
+    )
+)


Hotfix for hotfix.

Hotfix for hotfix.

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/'


removes unsure button (ORA-254)

removes unsure button (ORA-254)

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/bmedx/modulestore.git/'


Client: Activity: Using toList in renderChildren method instead of render


activity: waypoint marker logic fix

activity: waypoint marker logic fix


Client: Activity: Updated ChatList to add ConsequentMessageItem if next message is created by same user

--- client/activity/lib/components/chatlist/index.coffee
+++ client/activity/lib/components/chatlist/index.coffee
@@ -1,7 +1,8 @@
-kd           = require 'kd'
-React        = require 'kd-react'
-immutable    = require 'immutable'
-ChatListItem = require 'activity/components/chatlistitem'
+kd                    = require 'kd'
+React                 = require 'kd-react'
+immutable             = require 'immutable'
+ChatListItem          = require 'activity/components/chatlistitem'
+ConsequentMessageItem = require 'activity/components/chatlistitem/consequentmessageitem'

 module.exports = class ChatList extends React.Component

@@ -9,8 +10,15 @@
     messages: immutable.List()

   renderChildren: ->
-    @props.messages.map (message) ->
-      <ChatListItem key={message.get 'id'} message={message} />
+
+    lastMessageId = undefined
+
+    @props.messages.map (message, i) ->
+      if lastMessageId and lastMessageId == message.get 'accountId'
+        return <ConsequentMessageItem key={message.get 'id'} message={message} />
+      else
+        lastMessageId = message.get 'accountId'
+        return <ChatListItem key={message.get 'id'} message={message} />

   render: ->


Client: Activity: Updated  setPaddedClassName method to set channelInfoContainer position to bottom with chalets


Activity: refactor getting channel type by name util

--- client/activity/lib/util/getChannelTypeByName.coffee
+++ client/activity/lib/util/getChannelTypeByName.coffee
@@ -1,10 +1,5 @@
-getGroup = require 'app/util/getGroup'
-
 module.exports = getChannelTypeByName = (name) ->

-  type = switch name
-    when 'public'                     then 'group'
-    when 'changelog', getGroup().slug then 'announcement'
-    else 'topic'
+  if name is 'public' then 'group' else 'topic'


landing: change the way we parse errors

landing: change the way we parse errors

Signed-off-by: Umut Sirin <4055abbc0e40a1254e715b952ccd414607e0b365@gmail.com>

--- client/landing/site.landing/coffee/core/utils.coffee
+++ client/landing/site.landing/coffee/core/utils.coffee
@@ -522,7 +522,7 @@
       data: JSON.stringify { source: { token }, email }
       success: resolve
       error: (err) ->
-        reject JSON.parse err.responseText
+        reject JSON.parse err.responseJSON?.description

     $.ajax options


SidebarWorkspaceItem: Handle collaboration urls.

--- client/app/lib/activity/sidebar/sidebarworkspaceitem.coffee
+++ client/app/lib/activity/sidebar/sidebarworkspaceitem.coffee
@@ -20,9 +20,15 @@
     {machine} = options
     workspace = data # to make it more sense in the following lines.
     path      = "/IDE/#{machine.slug or machine.label}/#{workspace.slug}"
-    href      = groupifyLink path
     title     = workspace.name

+    unless machine.isMine()
+      if machine.isPermanent()
+        kd.log 'update shared ws url here'
+      else
+        path = "/IDE/#{workspace.channelId}"
+
+    href   = groupifyLink path
     @title = new CustomLinkView { href, title }

     @unreadCount = new KDCustomHTMLView


PrivateMessage: Call initPrivateMessage from PrivateMessageModal


login: add redirectTo functionality to register route


changing api endpoints for realmeye api

changing api endpoints for realmeye api

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/'


added misc.coffee

added misc.coffee

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

--- dev/coffee/misc.coffee
+++ dev/coffee/misc.coffee
@@ -0,0 +1,9 @@
+get_random = (min, max) ->
+  min = min or 0
+  max = max or 0
+
+  if typeof(min) is 'number' and typeof(max) is 'number'
+    random = Math.floor(Math.random() * (max - min + 1) + min)
+  else
+    random = false
+  random


Added ability to add elements to a ReactiveTaxonomy tree via autosuggest

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/UMNLibraries/ikidowinan.git/'


Clean up comments_index

Clean up comments_index

--- app/assets/javascripts/backbone/views/comments/comments_index.js.coffee
+++ app/assets/javascripts/backbone/views/comments/comments_index.js.coffee
@@ -6,20 +6,16 @@
     @collection.on('reset', @addAll, this)
     @collection.on('add', @addOne, this)

-    $('#new-comment').submit (event)=>
+    $('#new-comment').submit (event) =>
       @createComment(event)

   addAll: ->
     @collection.each (comment) =>
       @addOne(comment)

-    this
-
   addOne:(comment) ->
     view = new AsciiIo.Views.CommentEntry({ model: comment, collection: @collection})
     $(this.el).append view.render().el
-
-    this

   createComment: (event) ->
     event.preventDefault()


change create clal back in select

change create clal back in select

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/pervino/solidus_designs.git/'


model/group: add deleting api tokens

model/group: add deleting api tokens

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -1558,7 +1558,7 @@
     unless account or password
       return callback 'Error occured while deleting team'

-    account.fetchUser (err, user) =>
+    account.fetchUser (err, user) ->
       unless err
         unless user.checkPassword password
           return callback 'Your password didn\'t match with our records'
@@ -1573,61 +1573,70 @@
     ]
     success  : (client, password, callback) ->

-      JName = require '../name'
       account = client?.connection?.delegate

-      removeHelper = (model, err, next) ->
-        return next err  if err
-        return next()  unless model
       @checkUserPassword account, password, (err) =>

-        model.remove (err) -> next err
         return callback new KodingError err  if err

-      removeHelperMany = (klass, models, err, next) ->
-        return next err  if err
-        return next()    if not models or models.length < 1
-
-        ids = (model._id for model in models)
-        klass.remove ({ _id: { $in: ids } }), (err) -> next err
-
-      async.series [
-
-        (next) =>
-          JName.one { name: @slug }, (err, name) ->
-            removeHelper name, err, next
-
-        (next) =>
-          @fetchPermissionSet (err, permSet) ->
-            removeHelper permSet, err, next
-
-        (next) =>
-          @fetchDefaultPermissionSet (err, permSet) ->
-            removeHelper permSet, err, next
-
-        (next) =>
-          JInvitation = require '../invitation'
-          JInvitation.remove { groupName: @slug }, (err) ->
-            next err
-
-        (next) =>
-          ComputeProvider = require '../computeproviders/computeprovider'
-          ComputeProvider.destroyGroupResources this, -> next()
-
-        (next) =>
-          JSession = require '../session'
-          @sendNotification 'GroupDestroyed', @slug, =>
-            JSession.remove { groupName: @slug }, (err) ->
+        slug = @getAt 'slug'
+        JName = require '../name'
+
+        removeHelper = (model, err, next) ->
+          return next err  if err
+          return next()  unless model
+
+          model.remove (err) -> next err
+
+        removeHelperMany = (klass, models, err, next) ->
+          return next err  if err
+          return next()    if not models or models.length < 1
+
+          ids = (model._id for model in models)
+          klass.remove ({ _id: { $in: ids } }), (err) -> next err
+
+        async.series [
+
+          (next) ->
+            JName.one { name: slug }, (err, name) ->
+              removeHelper name, err, next
+
+          (next) =>
+            @fetchPermissionSet (err, permSet) ->
+              removeHelper permSet, err, next
+
+          (next) =>
+            @fetchDefaultPermissionSet (err, permSet) ->
+              removeHelper permSet, err, next
+
+          (next) ->
+            JInvitation = require '../invitation'
+            JInvitation.remove { groupName: slug }, (err) ->
               next err

-        (next) =>
-          @constructor.emit 'GroupDestroyed', this
-          next()
-
-        (next) =>
-          @remove (err) -> next err
-
-      ], callback
+          (next) =>
+            ComputeProvider = require '../computeproviders/computeprovider'
+            ComputeProvider.destroyGroupResources this, -> next()
+
+          (next) =>
+            JSession = require '../session'
+            @sendNotification 'GroupDestroyed', slug, ->
+              JSession.remove { groupName: slug }, (err) ->
+                next err
+
+          (next) ->
+            JApiToken = require '../apitoken'
+            JApiToken.remove { group: slug }, (err) ->
+              next err
+
+          (next) =>
+            @constructor.emit 'GroupDestroyed', this
+            next()
+
+          (next) =>
+            @remove (err) -> next err
+
+        ], callback

   sendNotificationToAdmins: (event, contents) ->


DownloadLink: Fixed user join date.

DownloadLink: Fixed user join date.

--- client/landing/app/Applications/StartTab.kdapplication/AppView.coffee
+++ client/landing/app/Applications/StartTab.kdapplication/AppView.coffee
@@ -54,7 +54,7 @@
       cssClass : 'file-container'

     @downloadFilesLink = new KDCustomHTMLView
-    userJoinDate       = KD.whoami().meta.createdAt
+    userJoinDate       = new Date(KD.whoami().meta.createdAt).getTime()
     oldKodingDownDate  = 1374267600000

     if userJoinDate < oldKodingDownDate


Optimization for not rebuilding LevelSession defaults once a second to set playtime.

--- app/lib/LevelBus.coffee
+++ app/lib/LevelBus.coffee
@@ -46,7 +46,7 @@
   incrementSessionPlaytime: =>
     if @playerIsIdle then return
     @changedSessionProperties.playtime = true
-    @session.set('playtime', @session.get('playtime', true) + 1)
+    @session.set('playtime', (@session.get('playtime') ? 0) + 1)

   onPoint: ->
     return true unless @session?.get('multiplayer')