Initial commit with working JSON queries

--- server.coffee
+++ server.coffee
@@ -0,0 +1,140 @@
+#!/usr/bin/env coffee
+
+MongoClient = require('mongodb').MongoClient
+app = require('express')()
+
+MongoClient.connect 'mongodb://localhost/plv_stats', (err, db) =>
+  if err then throw err
+
+  coll = db.collection 'rtc'
+
+  # stat helper
+
+  add_map_reduce_stat = (name, map, reduce) =>
+    path = '/stats/' + name + '.json'
+
+    page_fun = (req, res) =>
+      get_int = (key, fallback) =>
+        if req.param(key)?
+          return parseInt(req.param(key))
+        else
+          return fallback
+
+      start = get_int('start', 0)
+      end = get_int('end', Number.MAX_VALUE)
+
+      scope = {}
+
+      scope.start = start
+
+      if req.param('steps')
+        scope.steps = JSON.parse(req.param('steps'))
+
+        if not scope.steps instanceof Array
+          res.send({'error': "steps should be a JSON array"})
+          return
+
+      scope.scale = get_int('scale', 0)
+
+      scope.min_time = get_int('min_time', 0)
+      scope.max_time = get_int('max_time', Number.MAX_VALUE)
+
+      scope.min_peak = get_int('min_peak', 0)
+      scope.max_peak = get_int('max_peak', Number.MAX_VALUE)
+
+      scope.adjust_time = (time) =>
+        if scale
+          return time - time % scale
+        else if steps?
+          last = start
+          for step in steps
+            if step <= time
+              return step
+        else
+          return time
+
+      options =
+        out:
+          inline: 1
+        scope: scope
+        query:
+          c_at:
+            $gte: start,
+            $lt: end,
+
+      coll.mapReduce map, reduce, options, (err, result) =>
+        if err
+          res.send({error: err})
+          return
+
+        data = {}
+
+        for item in result
+          data[item._id] = item.value
+
+        res.send data
+
+    app.get path, page_fun
+    app.post path, page_fun
+
+  # stat helpers
+
+  add_objects = (key, values) =>
+      result = {}
+      for item in values
+        for key, value of item
+          if result[key]?
+            result[key] += value
+          else
+            result[key] = value
+      return result
+
+  # actual stat functions
+
+  add_map_reduce_stat 'count_rooms',
+    # map
+    () ->
+      count = 0
+      for peak, amount of @room_peaks
+        if peak >= min_peak and peak < max_peak
+          count += parseInt(amount)
+      emit(adjust_time(@c_at), count)
+    # reduce
+    (key, values) ->
+      return Array.sum(values)
+
+  add_map_reduce_stat 'count_users',
+    # map
+    () ->
+      count = 0
+      for time, amount of @connection_time
+        if time >= min_time and time < max_time
+          count += parseInt(amount)
+      emit(adjust_time(@c_at), count)
+    # reduce
+    (key, values) ->
+      return Array.sum(values)
+
+  add_map_reduce_stat 'user_times',
+    # map
+    () ->
+      times = {}
+      for key, value of @connection_time
+        times[key] = parseInt(value)
+      emit(adjust_time(@c_at), times)
+    # reduce
+    add_objects
+
+  add_map_reduce_stat 'room_peaks',
+    # map
+    () ->
+      peaks = {}
+      for key, value of @room_peaks
+        peaks[key] = parseInt(value)
+      emit(adjust_time(@c_at), peaks)
+    # reduce
+    add_objects
+
+  console.log "Ready for action"
+
+app.listen(3000)


Isolated some logic

Isolated some logic

error: pathspec 'moon-phase/index.coffee' did not match any file(s) known to git

--- moon-phase/index.coffee
+++ moon-phase/index.coffee
@@ -0,0 +1,377 @@
+
+# set locale
+locale =
+  city             : ''
+  region           : ''
+  country          : ''
+
+# set preferences
+option =
+  fontName         : 'Futura'
+  fontSize         : 14        # scales the overall widget size
+  fontColor        : '#FFF'    #
+  fontColorMuted   : '#FFF'    # for RUS label; at 50% opacity
+  iconSet          : 'lit'     # pixels are "lit" or "shadow" side of moon
+  iconColor        : '#FFF'    # pixels
+  iconBackground   : '#FFF'    #
+  iconOpacity      : 0.10      # percentage (0.01-1.00); 0 is transparent
+  widgetBackground : '#FFF'    #
+  widgetOpacity    : 0.02      # percentage (0.01-1.00); 0 is transparent
+  showPhase        : true      # the current moon phase
+  showIcon         : true      #
+  showCity         : true      #
+  showCoords       : true      # latitude and longitude
+  showAge          : true      # age in days
+  showIllum        : true      # percentage illumination
+  showRUS          : true      # w/separator, upcoming times for rise, upper transit, set
+  showClosest      : true      # w/separator, closest phase, either ahead or behind
+  showCloseDay     : true      #  +-> closest phase date, iff showClosest is true
+  showAMPM         : false     # default is military time
+
+refreshFrequency   : '1hr'     # 1hr is best accuracy for moon illumination data
+
+
+# do the heavy lifting; escape spaces
+command: "moon-phase.widget/get-phase.sh \"#{locale.city}\"   \
+                                         \"#{locale.region}\" \
+                                         \"#{locale.country}\""
+
+
+style: """
+  left             : 85px
+  top              : 15px
+  border-radius    : 20px
+  padding          : 10px
+  background       : rgba(#{option.widgetBackground}, #{option.widgetOpacity})
+  display          : inline-block
+  vertical-align   : bottom
+  line-height      : 1.5
+
+  color            : #{option.fontColor}
+  font-family      : #{option.fontName}
+  text-align       : center
+
+  icon-size = #{option.fontSize * 5}px
+
+  .error
+    font-size      : #{option.fontSize}px
+    color          : #FF0000
+    background     : rgba(#000000, 0.5)
+
+  .icon
+    display        : inline-block
+    font-family    : 'Weather'
+    vertical-align : middle
+    font-size      : #{option.fontSize}px
+    vertical-align : middle
+    text-align     : center
+
+    fill           : #{option.iconBackground}
+    width          : icon-size * 3
+    height         : icon-size * 3
+    max-width      : icon-size * 3
+    max-height     : icon-size * 3
+    border-radius  : 50%
+    background     : rgba(#{option.iconBackground}, #{option.iconOpacity})
+
+    img
+      width        : 100%
+
+    @font-face
+      font-family  : 'Weather'
+      src url(weather.widget/moon-icons.svg) format('svg')
+
+  .current
+    position       : relative
+    display        : inline-block
+    white-space    : nowrap
+    text-align     : center
+
+  .current .phase
+    font-size      : #{option.fontSize * 1.7}px
+    font-weight    : bold
+  .current .illum
+    font-size      : #{option.fontSize}px
+  .current .age
+    font-size      : #{option.fontSize}px
+
+  .current .phenomenae
+    display        : flex
+    justify-content: space-between
+  .current .phenomenae div
+    color          : rgba(#{option.fontColorMuted}, 0.5)
+    font-size      : #{option.fontSize * 0.75}px
+    width          : 30%
+
+  .current .phentimes
+    display        : flex
+    justify-content: space-between
+  .current .phentimes div
+    font-size      : #{option.fontSize}px
+    width          : 30%
+
+  .current .location
+    font-size      : #{option.fontSize * 1.5}px
+
+  .current .coords
+    font-size      : #{option.fontSize}px
+
+  .current .separator
+    background     : #666666
+    border-top     : #{option.fontSize / 10}px solid rgba(#{option.fontColor}, 0.5)
+    height         : #{option.fontSize / 10}px
+
+  .closest .clphase
+    font-size      : #{option.fontSize * 0.85}px
+  .closest .cldate
+    font-size      : #{option.fontSize * 0.85}px
+
+"""
+
+
+option : option
+
+
+render: -> """
+

+

+
+

+

+

+

+

+

+
+

+

+

+
+

+

+

+

+

+
+

+"""
+
+
+renderMoonData: (data) ->
+  moonEl = @$domEl.find('.current')
+
+  today = new Date()
+
+  # calculate current phase based on known new moon, modulo 29.53
+  # https://en.wikipedia.org/wiki/Lunar_phase#Calculating_phase
+  synodic_month = 29.530588853
+
+  # the most recent new moon; TODO: log last new moon seen to a file?
+  new_moon = new Date('03/09/2016 01:54 GMT')
+
+  #today = new Date('03/08/2016 18:35 CST')
+  #new_moon = new Date('02/08/2016 14:39 GMT')
+
+  ms_per_day = 1000 * 60 * 60  * 24
+  days_passed = (today.getTime() - new_moon.getTime()) / ms_per_day
+  moon_age = days_passed % synodic_month
+  moon_age = (moon_age).toFixed(1)
+
+  if @option.showPhase
+    # if moon phase isn't modulo 25, curphase is provided
+    if data.curphase?
+      curphase = data.curphase
+    else
+      curphase = data.closestphase.phase
+    moonEl.find('.phase').text "#{curphase}"
+
+# ###FIXME
+  if @option.showIcon
+    #icon = @getIcon(Math.floor(moon_age), @option.iconSet)
+    #console.error icon
+    #console.error 'Moon age:', moon_age
+    #console.error 'Floored :', Math.floor(moon_age)
+    moonEl.find('.icon').html @getIcon(Math.floor(moon_age), @option.iconSet)
+
+  if @option.showCity
+    moonEl.find('.location').text "#{data.city}"
+
+  if @option.showAge
+    moonEl.find('.age').text "#{moon_age} days old"
+
+  if @option.showIllum
+    # handle leading zeroes
+    fracillum = Number(data.illum)
+    moonEl.find('.illum').text "#{fracillum}% illumination"
+
+  if @option.showCoords
+    if data.lat > 0 then latcard = 'N' else latcard = 'S'
+    if data.lon > 0 then loncard = 'E' else loncard = 'W'
+    lat = Math.abs((data.lat).toFixed(2))
+    lon = Math.abs((data.lon).toFixed(2))
+    moonEl.find('.coords').text "#{lat}#{latcard} #{lon}#{loncard}"
+
+  # upcoming phenomenon and times; order based on current time
+  if @option.showRUS
+    count = Object.keys(data.moondata).length
+
+    phen = moonEl.find('.phenomenae')
+    phen.empty()
+    if count < 3
+      phenName = @returnPhenomenae("#{data.prevmoondata[0].phen}")
+      phen.append "
#{phenName}
"
+    for d in data.moondata
+      phenName = @returnPhenomenae("#{d.phen}")
+      phen.append "
#{phenName}
"
+
+    time = moonEl.find('.phentimes')
+    time.empty()
+    if count < 3
+      if @option.showAMPM
+        my_time = @returnAMPM(data.prevmoondata[0].time)
+      else
+        my_time = data.prevmoondata[0].time
+      time.append "
#{my.time}
"
+    for d in data.moondata
+      if @option.showAMPM
+        my_time = @returnAMPM(d.time)
+      else
+        my_time = d.time
+      time.append "
#{my_time}
"
+
+  if @option.showClosest
+    # closest phase looks both backwards and fowards: determine which
+    clday = new Date(data.closestphase.date + " " + data.closestphase.time)
+
+    # compare in milliseconds to avoid string issues
+    if clday.getTime() > today.getTime()
+      clause = 'is'
+    else
+      clause = 'was'
+
+    moonEl.find('.clphase').text "Closest phase #{clause} #{data.closestphase.phase}"
+
+    if @option.showCloseDay
+      # prepare time
+      if @option.showAMPM
+        my_time = @returnAMPM(data.closestphase.time)
+      else
+        my_time = data.closestphase.time
+      moonEl.find('.cldate').text "on #{data.closestphase.date} at #{my_time}"
+
+
+renderError: (data) ->
+  moonEl = @$domEl.find('.moon')
+  moonEl.find('.current').text "moon-phase: #{data.message}"
+  moonEl.append "
moon-phase: #{data.message}
"
+
+
+update: (output, domEl) ->
+  @$domEl = $(domEl)
+
+  data = JSON.parse(output)
+  if data?.error
+    console.error 'moon-phase: ', data.message
+    return @renderError(data)
+  @renderMoonData data
+
+
+returnAMPM: (time) ->
+  my_time = time.split(':')
+  hh = Number(my_time[0])
+  mm = Number(my_time[1])
+  if hh >= 12 then time_suffix = 'PM' else time_suffix = 'AM'
+  if hh > 12 then hh = hh - 12
+  if mm < 10 then mm = '0' + mm
+  my_time = hh + ':' + mm + ' ' + time_suffix
+  return my_time
+
+
+returnPhenomenae: (code) ->
+  if code is "R" then return "Rises"
+  if code is "U" then return "Upper Transit"
+  if code is "S" then return "Sets"
+
+
+getIcon: (code, iconSet) ->
+  if iconSet is 'lit'
+    @getLitIcon(code)
+  else
+    @getShadowIcon(code)
+
+getLitIcon: (code) ->
+  if code < 0 or code > 29
+    return @iconLitMapping['na']
+  else
+    @iconLitMapping[code]
+
+getShadowIcon: (code) ->
+  if code < 0 or code > 29
+    return @iconShadowMapping['na']
+  else
+    @iconShadowMapping[code1]
+
+iconLitMapping:
+  0  : ""
+  1  : ""
+  2  : ""
+  3  : ""
+  4  : ""
+  5  : ""
+  6  : ""
+  7  : ""
+  8  : ""
+  9  : ""
+  10 : ""
+  11 : ""
+  12 : ""
+  13 : ""
+  14 : ""
+  15 : ""
+  16 : ""
+  17 : ""
+  18 : ""
+  19 : ""
+  20 : ""
+  21 : ""
+  22 : ""
+  23 : ""
+  24 : ""
+  25 : ""
+  26 : ""
+  27 : ""
+  28 : ""
+  na : ""
+
+iconShadowMapping:
+  0  : ""
+  1  : ""
+  2  : ""
+  3  : ""
+  4  : ""
+  5  : ""
+  6  : ""
+  7  : ""
+  8  : ""
+  9  : ""
+  10 : ""
+  11 : ""
+  12 : ""
+  13 : ""
+  14 : ""
+  15 : ""
+  16 : ""
+  17 : ""
+  18 : ""
+  19 : ""
+  20 : ""
+  21 : ""
+  22 : ""
+  23 : ""
+  24 : ""
+  25 : ""
+  26 : ""
+  27 : ""
+  28 : ""
+  na : ""
+


add file from last commit

add file from last commit

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

--- client/config.coffee
+++ client/config.coffee
@@ -0,0 +1,15 @@
+on_verify_callback = (error, failures) ->
+  if error?
+    console.error "Failure during remote call:",error
+  if failures.length==0
+    alert("AWS appears configured properly")
+  else
+    alert("AWS not properly configured: "+failures)
+  $('.verify-aws').prop('disabled', false)
+
+Template.config.events
+  "click .verify-aws": (e) ->
+    $('.verify-aws').prop('disabled', true)
+    Meteor.call("verify_AWS_configuration", on_verify_callback)
+    return
+


javscript added

javscript added

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


Add click handler for icon to toggle output panel

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/rafalprzywarski/test-status.git/'


Client: Activity: Deleted unnecessary lines

--- client/activity/lib/flux/getters.coffee
+++ client/activity/lib/flux/getters.coffee
@@ -348,7 +348,6 @@

 channelParticipantsSearchQuery  = ChannelParticipantsSearchQueryStore
-
 # Returns a list of users depending on the current query
 # If query is empty, returns selected channel participants
 # Otherwise, returns users filtered by query


<view> ActuatorProfile - Created

<view> ActuatorProfile - Created

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

--- client/app/views/actuatorProfile.coffee
+++ client/app/views/actuatorProfile.coffee
@@ -0,0 +1,16 @@
+BaseView = require '../lib/base_view'
+
+module.exports = class ActuatorProfile extends BaseView
+    className: 'device-profile'
+    template: require 'templates/actuatorProfile'
+
+    initialize: ->
+        @listenTo @model, 'change', => @render()
+
+    getRenderData: ->
+        out =
+            name: @model.name
+            driverName: @model.driver.name
+			customId: @modeL.customId
+            url: @model.getURL()
+        return out


Add logger to core Bootstrapper.

Add logger to core Bootstrapper.

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


Run: kill all processes with a second pass

Signed-off-by: Cihangir SAVAS <3e363b341565e659960779c80f888b117da0c0d7@koding.com>

--- config/main.dev.coffee
+++ config/main.dev.coffee
@@ -340,7 +340,6 @@
     killlist = ->
       str = "kill -KILL "
       str += "$#{key}pid " for key,val of KONFIG.workers
-      str += " $$" #kill self

       return str

@@ -448,16 +447,22 @@
       function ctrl_c () {
         echo "ctrl_c detected. killing all processes..."
         kill_all
+
+        echo "killing hanged processes"
+        # there is race condition, that first kill_all can not kill all process
+        sleep 3
+
+        kill_all
       }

       function kill_all () {
+        # both of them are  required

         ps aux | grep koding | grep -E 'node|go/bin' | awk '{ print $2 }' | xargs kill -9
-        ps | grep koding- | awk '{print $1}' | xargs kill -9
-
-        # do not change the order.
-        # killist comes last - it kills itself thus nothing can run after.
+
         #{killlist()}
+
+        pkill -9 koding-
       }

       function nginxstop () {


atom stuff

atom stuff

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/anhari/dotfiles-local.git/'


copyied file from dotfiles to windows and back again

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


Add shortcut for checking off markdown tasks

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


script/decide.coffee

script/decide.coffee

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

--- scripts/decide.coffee
+++ scripts/decide.coffee
@@ -0,0 +1,19 @@
+# Description:
+#   Allows Hubot to help you decide between multiple options
+#
+# Dependencies:
+#   None
+#
+# Configuration:
+#   None
+#
+# Commands:
+#   hubot decide "<option1>" "<option2>" "<optionx>" - Randomly picks an option
+#
+# Authors:
+#   logikal
+
+module.exports = (robot) ->
+  robot.respond /decide "(.*)"/i, (msg) ->
+    options = msg.match[1].split('" "')
+    msg.reply("Definitely \"#{ msg.random options }\".")


add misawa neta

add misawa neta

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

--- scripts/misawa.coffee
+++ scripts/misawa.coffee
@@ -0,0 +1,18 @@
+# Description:
+#   Jojo Neta
+#
+# Dependencies:
+#   None
+#
+# Configuration:
+#   None
+#
+# Commands:
+#   hubot daga - get daga kotowaru
+#   hubot tururu- get tururu
+
+module.exports = (robot) ->
+  robot.respond /俺の分$/, (msg) ->
+    msg.send "http://imgcc.naver.jp/kaze/mission/USER/20120712/15/1022545/47/329x237x2c75f6b1e78fdf342e6180c2.jpg"
+    msg.send "http://imgcc.naver.jp/kaze/mission/USER/20120712/15/1022545/47/329x237x2c75f6b1e78fdf342e6180c2.jpg"
+


don't use toggle as double clicking the recent wouldn't work

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


Add goodbye script

Add goodbye script

goodbye moves a deceased greyhound to the Rainbow Bridge page

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

--- scripts/goodbye.coffee
+++ scripts/goodbye.coffee
@@ -0,0 +1,45 @@
+# Description:
+#   Move an deceased greyhound to the Rainbow Bridge page
+#
+# Commands:
+#   hubot goodbye <greyhound> [yyyy-mm-dd] - Moves a deceased greyhound to the Rainbow Bridge page
+#
+# Author:
+#   Zach Whaley (zachwhaley) <zachbwhaley@gmail.com>
+
+capitalize = require 'capitalize'
+
+git = require './git'
+
+goodbye = (greyhound, dod, callback) ->
+  git.loadGreyhounds (greyhounds) ->
+    if greyhound not of greyhounds
+      return callback "Sorry, couldn't find #{greyhound} 😕"
+
+    if greyhounds[greyhound].deceased is yes
+      return callback "#{capitalize(greyhound)} has already crossed the Rainbow Bridge 😢"
+
+    greyhounds[greyhound].deceased = yes
+    greyhounds[greyhound].dod = new Date(dod) if dod?
+    git.dumpGreyhounds greyhounds, callback
+
+module.exports = (robot) ->
+  robot.respond /goodbye (\w+)\s?(\d\d\d\d-\d{1,2}-\d{1,2})?/i, (res) ->
+    greyhound = res.match[1]
+    dod = res.match[2]
+    message = "#{capitalize(greyhound)} crossed the Rainbow Bridge 😢"
+    branch = "goodbye-#{greyhound}"
+    user =
+      name: res.message.user?.real_name?,
+      email: res.message.user?.profile?.email?
+
+    res.reply "Moving #{capitalize(greyhound)} to the Rainbow Bridge 😢\n" +
+              "Hang on a sec..."
+    git.pull (repo) ->
+      git.branch repo, branch, (ref) ->
+        goodbye greyhound, dod, (err) ->
+          return res.reply err if err
+          git.commit repo, user, message, (oid) ->
+            git.push repo, ref, ->
+              git.pullrequest message, branch, (pr) ->
+                res.reply "Pull Request ready ➜ #{pr.html_url}"


add helper function to set hidden __source property

error: pathspec 'lib/set-source.coffee' did not match any file(s) known to git

--- lib/set-source.coffee
+++ lib/set-source.coffee
@@ -0,0 +1,7 @@
+module.exports = (object, value) ->
+  Object.defineProperty object, '__source',
+    value: value
+    writable: false
+    enumerable: false
+    configurable: false
+  return


Coffeescript support.

Coffeescript support.

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


Refactor database module.

Refactor database module.

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


added rich core parsing

added rich core parsing

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

--- server/richcore.coffee
+++ server/richcore.coffee
@@ -0,0 +1,54 @@
+
+lazy = require('lazy')
+
+parse_rich_core = (rcorefile, cb) ->
+    console.log "parsing rich core: #{rcorefile.path}"
+
+    lines = new lazy(fs.createReadStream rcorefile.path).lines
+
+    groups = group_lines(lines)
+
+    core = null
+
+    groups.forEach (g) ->
+        if not core?
+            core =
+                cmdline: g.lines[0]
+        else
+            switch g.name
+                when 'date' then core.date = parse_core_date g.lines[0]
+
+    groups.on 'end', () -> cb? core
+
+
+date_regexp = /(\w+)\s(\w+)\s(\d+)\s([0-9:]+)\s([A-Z]+)\s(\d+)/
+parse_core_date = (d) ->
+    match = date_regexp.exec(d)
+    [_, weekday, month, day, time, timezone, year] = match
+    return new Date("#{weekday} #{month} #{day} #{year} #{time} (#{timezone})")
+
+
+group_lines = (lines) ->
+    parser = new lazy()
+
+    group =
+        name: undefined
+        lines: []
+
+    header = /[---rich-core: (.*)---]/
+
+    lines.forEach (x) ->
+        match = header.exec(x)
+        if match?
+            name = match[1]
+            parser.emit('data', group)
+            group =
+                name: name
+                lines: []
+        else
+            group.lines.push(x)
+
+    lines.on 'end', () ->
+        parser.end()
+
+exports.parse_rich_core = parse_rich_core


bump the version so we know what we're serving

--- server.coffee
+++ server.coffee
@@ -5,7 +5,7 @@
 QueryString = require 'querystring'

 port            = parseInt process.env.PORT        || 8081
-version         = "1.2.1"
+version         = "1.4.0"
 shared_key      = process.env.CAMO_KEY             || '0x24FEEDFACEDEADBEEFCAFE'
 max_redirects   = process.env.CAMO_MAX_REDIRECTS   || 4
 camo_hostname   = process.env.CAMO_HOSTNAME        || "unknown"


Create polyfill for jquery placeholder plugin

error: pathspec 'js/libs/placeholder.coffee' did not match any file(s) known to git

--- js/libs/placeholder.coffee
+++ js/libs/placeholder.coffee
@@ -0,0 +1,2 @@
+define [ "outer", "js/vendor/jquery.placeholder" ], () ->
+  $("input, textarea").placeholder()


Adds Org search 404 handling. Closes #16

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


added D.coffee for D selection support

added D.coffee for D selection support

error: pathspec 'lib/grammar-utils/d.coffee' did not match any file(s) known to git

--- lib/grammar-utils/d.coffee
+++ lib/grammar-utils/d.coffee
@@ -0,0 +1,28 @@
+# Require some libs used for creating temporary files
+os = require 'os'
+fs = require 'fs'
+path = require 'path'
+uuid = require 'node-uuid'
+
+# Public: GrammarUtils.D - a module which assist the creation of D temporary files
+module.exports =
+  tempFilesDir: path.join(os.tmpdir(), 'atom_script_tempfiles')
+
+  # Public: Create a temporary file with the provided D code
+  #
+  # * `code`    A {String} containing some D code
+  #
+  # Returns the {String} filepath of the new file
+  createTempFileWithCode: (code) ->
+    try
+      fs.mkdirSync(@tempFilesDir) unless fs.existsSync(@tempFilesDir)
+
+      tempFilePath = @tempFilesDir + path.sep + 'm' + uuid.v1().split('-').join('_')  + '.d'
+
+      file = fs.openSync(tempFilePath, 'w')
+      fs.writeSync(file, code)
+      fs.closeSync(file)
+
+      tempFilePath
+    catch error
+      throw ("Error while creating temporary file (#{error})")


adding 'unless' blocks

adding 'unless' blocks

--- grammar.coffee
+++ grammar.coffee
@@ -488,6 +488,7 @@
   # ambiguity.
   IfStart: [
     o "IF Expression Block",                    -> new IfNode $2, $3
+    o "UNLESS Expression Block",                -> new IfNode $2, $3, null, {invert: true}
     o "IfStart ElsIf",                          -> $1.add_else $2
   ]


Added mesh.coffee module for mesh operations.

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

--- coffee/mesh.coffee
+++ coffee/mesh.coffee
@@ -0,0 +1,21 @@
+
+surfaceUV = (arr) ->
+
+    if !arr instanceof NJ.NDArray
+        throw new error.NumjisException('argument is not a NDArray object')
+
+    if !(arr.ndim == 2 || arr.ndim == 3)
+        throw new error.NumjisException('Array dimensions should be 2 or 3, got: ' + arr.ndim)
+
+    height = arr.shape[0]
+    width = arr.shape[1]
+
+    UV = new NJ.NDArray([height, width, 2], NJ.float32)
+
+    for r in [0...height]
+        for c in [0...width]
+
+            UV.data[UV.flat([r, c, 0])] = r / (height-1)
+            UV.data[UV.flat([r, c, 1])] = c / (width-1)
+
+    return UV


Starting router.

Starting router.

error: pathspec 'js/routers/FrontRouter.coffee' did not match any file(s) known to git

--- js/routers/FrontRouter.coffee
+++ js/routers/FrontRouter.coffee
@@ -0,0 +1,15 @@
+class FrontRouter extends Backbone.Router
+
+  routes:
+    '': 'startApp'
+    'panel/:id': 'goToPanel'
+
+  startApp: ->
+    window.flight = new Flight();
+
+  goToPanel: (id) ->
+    @view = new app.Views.panel2View
+    @view.render(id)
+
+@app = window.app ? {}
+@app.Routers.FrontRouter = FrontRouter


Adding testhelper

Adding testhelper

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

--- test/lib/test_helper.coffee
+++ test/lib/test_helper.coffee
@@ -0,0 +1,7 @@
+global.path = require 'path'
+global.os = require 'os'
+
+global.chai = require 'chai'
+global.assert = chai.assert
+
+chai.should()


Always send a response when asked to start an app

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


When a pane view is removed in anyway, make sure its model is destroyed

--- src/pane.coffee
+++ src/pane.coffee
@@ -206,9 +206,11 @@
   getContainer: ->
     @closest('.panes').view()

+  beforeRemove: ->
+    @model.destroy() unless @model.isDestroyed()
+
   # Private:
   remove: (selector, keepData) ->
     return super if keepData
     @unsubscribe()
-    @model.destroy() unless @model.isDestroyed()
     super


Not to emit JS error even if User's github repos-list is empty

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/ikeda-yuko/jay.git/'


adding missing conf helper

adding missing conf helper

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

--- app/config-helper.coffee
+++ app/config-helper.coffee
@@ -0,0 +1,30 @@
+{ _ }  = require 'underscore'
+config = require '../config'
+
+
+# Grade stuff
+
+exports.fromGradeID = (grade_id) ->
+   return gradeNames[grade_id]
+
+exports.gradeNames = () ->
+    return config.grades.Object.keys()
+
+exports.gradeValue = (grade_name) ->
+    return config.grades[grade_name]
+
+exports.gradeCSS = (grade_id) ->
+    return config.gradeCSSClass[grade_id]
+
+
+
+# Sector stuff
+
+exports.sectors = () ->
+    return config.sectors.Object.keys()
+
+exports.sectorImage = (sector_name) ->
+    return config.sectors[sector_name]
+
+
+


Add view schema

Add view schema

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

--- src/view.coffee
+++ src/view.coffee
@@ -0,0 +1,115 @@
+class IceView
+
+  constructor: (@block) ->
+    @children = [new IcePaper()] # All child blocks, for event delegation.
+
+    # Start and end lines
+    @lineStart = @lineEnd = null
+
+    @lineChildren =
+      'lineno': new IcePaper() # Children on each line, computed in FIRST PASS
+
+    @dimensions =
+      'lineno': new draw.Size 0, 0 # Bounding box on each line, computed in SECOND PASS
+
+    @bounds =
+      'lineno': new draw.NoRectangle() # Bounding boxes on each line, computed in THIRD PASS
+
+  # FIRST PASS: generate @lineChildren and @children
+  computeChildren: (line) -> # (line) is the starting line
+
+    # Record the starting line
+    @lineStart = line
+
+    # Linked-list loop through inner tokens
+    head = @block.start
+    while head isnt @block.end
+      switch head.type
+        when 'blockStart'
+          # Ask this child to compute its children (thus determining its ending line, as well)
+          line = head.indent.view.computeChildren line
+
+          # Append to children array
+          @children.push head.block.view
+
+          # Append to line children array
+          for occupiedLine in [head.indent.view.lineStart..head.indent.view.lineEnd] # (iterate over all lines which this indent occupies)
+            # (initialize empty array if it doesn't already exist
+            @lineChildren[occupiedLine] ?= []
+
+            # Push to the children on this line
+            @lineChildren[occupiedLine].push head.indent.view
+
+          # Skip to the end of this indent
+          head = head.block.end
+
+        when 'indentStart'
+          # Act analagously for indents
+          line = head.indent.view.computeChildren line
+
+          # Append to children array
+          @children.push head.block.view
+
+          # Append to line children array
+          for occupiedLine in [head.indent.view.lineStart..head.indent.view.lineEnd] # (iterate over all lines which this indent occupies)
+            # (initialize empty array if it doesn't already exist
+            @lineChildren[occupiedLine] ?= []
+
+            # Push to the children on this line
+            @lineChildren[occupiedLine].push head.indent.view
+
+          # Skip to the end of this indent
+          head = head.block.end
+
+        when 'text', 'cursor'
+          # Act analagously for text and cursor
+          head.view.computeChildren line
+
+          # (For text and cursor the token itself is also the manifested thing)
+          @children.push head.view
+
+          @lineChildren[line] ?= []; @lineChildren[line].push head.view
+
+        when 'newline'
+          line += 1
+
+      # Advance our head token (linked-loop list)
+      head = head.next
+
+    # Record the last line
+    @lineEnd = line
+
+    return line
+
+  # SECOND PASS: compute dimensions on each line
+  computeDimensions: ->
+    # Event propagate
+    for child in @children then child.computeDimensions()
+
+    for
+
+    return @dimensions
+
+  # THIRD PASS: compute bounding boxes on each line
+  computeBoundingBoxes: ->
+    # Event propagate
+    for child in @children then child.computeBoundingBoxes
+
+    return @bounds
+
+  # FOURTH PASS: join "path bits" into a path
+  computePath: ->
+    # Event propagate
+    for child in @children then child.computePath()
+
+    return @bounds
+
+  # FIFTH PASS: draw
+  draw: (ctx) ->
+    # Event propagate
+    for child in @children then child.draw ctx
+
+  # Convenience function: compute
+  compute: (line = 0) ->
+    @computeChildren line
+    @computeDimensions(); @computeBoundingBoxes(); @computePath()


Add Spellbook.equalHeights Component

Add Spellbook.equalHeights Component

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

--- components/equalHeights.coffee
+++ components/equalHeights.coffee
@@ -0,0 +1,26 @@
+# *************************************
+#
+#   Equal Heights
+#   -> Create equal-height elements
+#
+# *************************************
+
+@Spellbook.equalHeights = (options) ->
+  settings =
+    element: $('.js-equalHeight')
+
+  settings = $.extend(settings, options)
+
+  heights = []
+  settings.element.each -> heights.push $(@).height()
+
+  height = Math.max.apply(Math, heights)
+
+  settings.element.css('height', height)
+
+# -------------------------------------
+#   Usage
+# -------------------------------------
+#
+# Spellbook.equalHeights()
+#


fixes #2

fixes #2

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/Sanjo/meteor-long-running-child-process.git/'


fixed chk ua bug in productive app launcher

--- src/app.coffee
+++ src/app.coffee
@@ -104,18 +104,15 @@
     ua = req.headers['user-agent']
     if /MSIE [1-9]\./i.test ua
       msg = 'This WebApp does not support IE below 10!'
-      false
     else if /opera/i.test ua
       msg = 'This WebApp does not support Opera!'
-      false
     else if /^Mozilla\/4/i.test ua
       msg = 'This WebApp does not support your browser! \nIt seems your browser is out of date.'
-      false
     else
       return true
     # res.writeHead 200, 'Content-Type': 'text/plain'
     res.end msg
-    return
+    return false

   MAX_AGE: 30 * 24 * 60 * 60 * 1000 # 30 days
   MIN_AGE: 60 * 1000 # 1 min


social: clean up dummy admins

social: clean up dummy admins

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -646,9 +646,9 @@
         @update { $set: { 'counts.twitterFollowers': followerCount } }, ->

-  dummyAdmins = [ 'sinan', 'devrim', 'gokmen', 'fatihacet',
-                  'sent-hil', 'cihangirsavas', 'leeolayvar', 'stefanbc',
-                  'szkl', 'nitin', 'usirin', 'kodinglearn', 'rjeczalik', 'caikoding'] # kodinglearn is nitin's impersonation account
+  dummyAdmins = [ 'sinan', 'devrim', 'gokmen',
+                  'sent-hil', 'cihangirsavas', 'leeolayvar',
+                  'szkl', 'usirin', 'rjeczalik', 'caikoding']

   isEmailVerified: (callback) ->


oauth: secure unlinkOauth

oauth: secure unlinkOauth

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -1217,12 +1217,17 @@
       email.save ->

   unlinkOauth: (provider, callback)->
-    @fetchUser (err, user)->
-      return callback err  if err
-
-      query                            = {}
-      query["foreignAuth.#{provider}"] = ""
-      user.update $unset: query, callback
+    {delegate} = client.connection
+    isMine    = this.equals delegate
+    if isMine
+      @fetchUser (err, user)->
+        return callback err  if err
+
+        query                            = {}
+        query["foreignAuth.#{provider}"] = ""
+        user.update $unset: query, callback
+    else
+      callback new KodingError 'Access denied'

   # we are using this in sorting members list..
   updateMetaModifiedAt: (callback)->


social: tweak user not found error in sidebar

--- workers/social/lib/social/models/sidebar.coffee
+++ workers/social/lib/social/models/sidebar.coffee
@@ -29,7 +29,7 @@

       return callback new KodingError err  if err

-      return callback new KodingError {message: "user not found"}  unless user
+      return callback new KodingError {message: "[Sidebar::fetchEnvironment] user not found"}  unless user

       query = 'users.id': user.getId()


lint error fix

lint error fix

--- workers/social/lib/social/render/favicon.coffee
+++ workers/social/lib/social/render/favicon.coffee
@@ -19,4 +19,3 @@
   <meta name="msapplication-config" content="/a/favicon/browserconfig.xml?v=wAvxkwgmmY">
   <meta name="theme-color" content="#d9e0ec">
   """
-


(#352) allow open-ended dates in pandoc csl

error: pathspec 'resource/translators/Pandoc' did not match any file(s) known to git
error: pathspec 'JSON.coffee' did not match any file(s) known to git


Update order-of-crops to match best practices

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/publicmediaplatform/support.pmp.io.git/'


Change the url value

Change the url value

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/Hiroto-K/MP3-Downloader.git/'


clean up

clean up

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


commit

commit

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


_setPasswordAuthHeader method: use fat arrow

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/rremizov/github-notifier.git/'


Added gutter problem support for iPad

Added gutter problem support for iPad

--- app/views/play/level/tome/Problem.coffee
+++ app/views/play/level/tome/Problem.coffee
@@ -10,6 +10,7 @@
     @buildAnnotation()
     @buildAlertView() if withAlert
     @buildMarkerRange() if isCast
+    Backbone.Mediator.publish("problem:problem-created", line:@annotation.row, text: @annotation.text) if application.isIPadApp
     @saveUserCodeProblem() if isCast

   destroy: ->


Fixes compiling order

Fixes compiling order

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -191,7 +191,7 @@
   grunt.registerTask "test", ["coffeelint", "recess"]

   # Build site with `jekyll`
-  grunt.registerTask "build", ["clean", "test", "less:dist", "shell:dist", "useminPrepare", "rev", "usemin", "concurrent:dist", "manifest"]
+  grunt.registerTask "build", ["clean", "test", "less:dist", "shell:dist", "useminPrepare", "concurrent:dist", "rev", "usemin", "manifest"]

   # Archive old version with specific URL prefix, all old versions goes to http://sparanoid.com/lab/version/
   grunt.registerTask "archive", ["build", "shell:archive", "concurrent:dist"]


add clean task on gruntfile

add clean task on 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/kisski/titanium-seed.git/'


Fix grunt task

Fix grunt task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -43,8 +43,7 @@
         noUniversalSelectors: false

       test:
-        files:
-          src: ["<%= core.app %>/assets/less/app.less"]
+        src: ["<%= core.app %>/assets/less/app.less"]

     watch:
       coffee:
@@ -52,7 +51,7 @@
         tasks: ["coffeelint"]

       less:
-        files: ["<%= recess.test.files.src %>"]
+        files: ["<%= recess.test.src %>"]
         tasks: ["less:server", "autoprefixer", "recess"]

     less:
@@ -60,20 +59,18 @@
         options:
           dumpLineNumbers: "all"

+        src: ["<%= recess.test.src %>"]
+        dest: "<%= core.app %>/assets/css/app.css"
+
+      dist:
+        src: ["<%= recess.test.src %>"]
+        dest: "<%= less.server.dest %>"
+
+    autoprefixer:
+      dist:
         files:
-          src: ["<%= recess.test.files.src %>"]
-          dest: "<%= core.app %>/assets/css/app.css"
-
-      dist:
-        files:
-          src: ["<%= recess.test.files.src %>"]
-          dest: "<%= less.server.files.dest %>"
-
-    autoprefixer:
-      dist:
-        files:
-          src: ["<%= less.server.files.dest %>"]
-          dest: "<%= less.server.files.dest %>"
+          src: ["<%= less.server.dest %>"]
+          dest: "<%= less.server.dest %>"

     htmlmin:
       dist:


Add global $stout.scope() function.

Add global $stout.scope() function.

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


teamwork: generate export url using window location

--- client/Teamwork/Views/teamworkexportmodal.coffee
+++ client/Teamwork/Views/teamworkexportmodal.coffee
@@ -85,7 +85,7 @@

   handleExportDone: (shortenUrl) ->
     @destroy()
-    fullUrl      = "https://koding.com/Teamwork?importUrl=#{shortenUrl}"
+    fullUrl      = "#{window.location.origin}/Teamwork?importUrl=#{shortenUrl}"
     inputContent = """

I exported my files here, click this link to see them.

#{fullUrl}


YamlUtils: remove logs

YamlUtils: remove logs

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


Notification controller issues fixed pointed in #7140065591077


Remove extra parens

Remove extra parens

--- index.coffee
+++ index.coffee
@@ -17,9 +17,9 @@
     metadata = grunt.file.readJSON('package.json')

     inputTemplate = grunt.file.read(path.join(__dirname, 'template.nuspec'))
-    nuspecContent = _.template(inputTemplate, metadata))
+    nuspecContent = _.template(inputTemplate, metadata)

-    targetNuspecPath = path.join(temp.mkdirSync('squirrel-installer-'), "#{metadata.name}.nuspec"))
+    targetNuspecPath = path.join(temp.mkdirSync('squirrel-installer-'), "#{metadata.name}.nuspec")
     grunt.file.write(targetNuspecPath, nuspecContent)

     cmd = path.resolve(__dirname, '..', 'vendor', 'nuget.exe')


Use Last-Modified to store cache

Use Last-Modified to store cache

--- lib/proxy.coffee
+++ lib/proxy.coffee
@@ -92,13 +92,22 @@
               body: reqBody
           # Use cache file
           if cacheFile
-            data = yield fs.readFileAsync cacheFile
-            res.writeHead 200,
-              'Server': 'Apache'
-              'Content-Length': data.length
-              'Cache-Control': 'no-cache'
-              'Content-Type': mime.lookup cacheFile
-            res.end data
+            stats = yield fs.statAsync cacheFile
+            # Cache is new
+            if req.headers['if-modified-since']? && (new Date(req.headers['if-modified-since']) >= stats.mtime)
+              res.writeHead 304,
+                'Server': 'Apache'
+                'Last-Modified': stats.mtime.toGMTString()
+              res.end()
+            # Cache is old
+            else
+              data = yield fs.readFileAsync cacheFile
+              res.writeHead 200,
+                'Server': 'Apache'
+                'Content-Length': data.length
+                'Content-Type': mime.lookup cacheFile
+                'Last-Modified': stats.mtime.toGMTString()
+              res.end data
           # Enable retry for game api
           else if isGameApi
             success = false


fix rootView spec

fix rootView spec

--- spec/root-view-spec.coffee
+++ spec/root-view-spec.coffee
@@ -33,7 +33,7 @@
         editor1 = rootView.getActiveView()
         buffer = editor1.getBuffer()
         editor1.splitRight()
-        expect(rootView.getActiveView()).toBe rootView.getEditors()[1]
+        expect(rootView.getActiveView()).toBe rootView.getEditors()[2]

         refreshRootViewAndProject()


Properly unsubscribe DisplayBuffer from Buffer on destruction

--- src/app/display-buffer.coffee
+++ src/app/display-buffer.coffee
@@ -31,8 +31,8 @@
     @buildLineMap()
     @tokenizedBuffer.on 'grammar-changed', (grammar) => @trigger 'grammar-changed', grammar
     @tokenizedBuffer.on 'changed', @handleTokenizedBufferChange
-    @buffer.on 'markers-updated', @handleMarkersUpdated
-    @buffer.on 'marker-created', @handleMarkerCreated
+    @subscribe @buffer, 'markers-updated', @handleMarkersUpdated
+    @subscribe @buffer, 'marker-created', @handleMarkerCreated

   buildLineMap: ->
     @lineMap = new LineMap
@@ -537,7 +537,7 @@

   destroy: ->
     @tokenizedBuffer.destroy()
-    @buffer.off 'markers-updated', @handleMarkersUpdated
+    @unsubscribe()

   logLines: (start, end) ->
     @lineMap.logLines(start, end)


Fixed ldap address for dev and vagrant in sharedhosting environment

--- config/kite.sharedHosting.vagrant.coffee
+++ config/kite.sharedHosting.vagrant.coffee
@@ -42,7 +42,7 @@
     configFilePath      : '/opt/lsws/conf/httpd_config.xml'
     minRestartInterval  : '10000' # 10 sec
   ldap                  :
-    ldapUrl             : 'ldap://ldap0-prod.in.koding.com'
+    ldapUrl             : 'ldap://ldap0-dev.in.koding.com'
     rootUser            : "uid=KAdmin,ou=Special Users,dc=koding,dc=com"
     rootPass            : 'sOg4:L]iM7!_UV-H'
     groupDN             : 'ou=Beta,ou=Groups,dc=koding,dc=com'


removed key and value position (doesn't make sense to have for non-index-based things like maps)

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/genericdave/speedr.js.git/'


:penguin: Add menu.

:penguin: Add menu.

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

--- menus/linux.cson
+++ menus/linux.cson
@@ -0,0 +1,156 @@
+'menu': [
+  {
+    label: '&File'
+    submenu: [
+      { label: 'New &Window', command: 'application:new-window' }
+      { label: '&New File', command: 'application:new-file' }
+      { label: '&Open...', command: 'application:open' }
+      { label: 'Reopen Last &Item', command: 'pane:reopen-closed-item' }
+      { type: 'separator' }
+      { label: '&Preferences...', command: 'application:show-settings' }
+      { type: 'separator' }
+      { label: '&Save', command: 'core:save' }
+      { label: 'Save &As...', command: 'core:save-as' }
+      { label: 'Save A&ll', command: 'window:save-all' }
+      { type: 'separator' }
+      { label: '&Close Buffer', command: 'core:close' }
+      { label: 'Close All &Buffers', command: 'pane:close' }
+      { label: 'Clos&e Window', command: 'window:close' }
+      { type: 'separator' }
+      { label: 'E&xit', command: 'application:quit' }
+    ]
+  }
+
+  {
+    label: '&Edit'
+    submenu: [
+      { label: '&Undo', command: 'core:undo' }
+      { label: '&Redo', command: 'core:redo' }
+      { type: 'separator' }
+      { label: '&Cut', command: 'core:cut' }
+      { label: 'C&opy', command: 'core:copy' }
+      { label: 'Copy Pat&h', command: 'editor:copy-path' }
+      { label: '&Paste', command: 'core:paste' }
+      { label: 'Select &All', command: 'core:select-all' }
+      { type: 'separator' }
+      { label: '&Toggle Comments', command: 'editor:toggle-line-comments' }
+      {
+        label: 'Lines',
+        submenu: [
+          { label: '&Indent', command: 'editor:indent-selected-rows' }
+          { label: '&Outdent', command: 'editor:outdent-selected-rows' }
+          { label: '&Auto Indent', command: 'editor:auto-indent' }
+          { type: 'separator' }
+          { label: 'Move Line &Up', command: 'editor:move-line-up' }
+          { label: 'Move Line &Down', command: 'editor:move-line-down' }
+          { label: 'Du&plicate Lines', command: 'editor:duplicate-lines' }
+          { label: 'D&elete Line', command: 'editor:delete-line' }
+          { label: '&Join Lines', command: 'editor:join-lines' }
+        ]
+      }
+      {
+        label: 'Text',
+        submenu: [
+          { label: '&Upper Case', command: 'editor:upper-case' }
+          { label: '&Lower Case', command: 'editor:lower-case' }
+          { type: 'separator' }
+          { label: 'Delete to End of &Word', command: 'editor:delete-to-end-of-word' }
+          { label: '&Delete Line', command: 'editor:delete-line' }
+          { type: 'separator' }
+          { label: '&Transpose', command: 'editor:transpose' }
+        ]
+      }
+      {
+        label: 'Folding',
+        submenu: [
+          { label: '&Fold', command: 'editor:fold-current-row' }
+          { label: '&Unfold', command: 'editor:unfold-current-row' }
+          { label: 'Unfold &All', command: 'editor:unfold-all' }
+          { type: 'separator' }
+          { label: 'Fol&d All', command: 'editor:fold-all' }
+          { label: 'Fold Level 1', command: 'editor:fold-at-indent-level-1' }
+          { label: 'Fold Level 2', command: 'editor:fold-at-indent-level-2' }
+          { label: 'Fold Level 3', command: 'editor:fold-at-indent-level-3' }
+          { label: 'Fold Level 4', command: 'editor:fold-at-indent-level-4' }
+          { label: 'Fold Level 5', command: 'editor:fold-at-indent-level-5' }
+          { label: 'Fold Level 6', command: 'editor:fold-at-indent-level-6' }
+          { label: 'Fold Level 7', command: 'editor:fold-at-indent-level-7' }
+          { label: 'Fold Level 8', command: 'editor:fold-at-indent-level-8' }
+          { label: 'Fold Level 9', command: 'editor:fold-at-indent-level-9' }
+        ]
+      }
+    ]
+  }
+
+  {
+    label: '&View'
+    submenu: [
+      { label: '&Reload', command: 'window:reload' }
+      { label: 'Toggle &Full Screen', command: 'window:toggle-full-screen' }
+      {
+        label: 'Developer'
+        submenu: [
+          { label: 'Open In &Dev Mode...', command: 'application:open-dev' }
+          { label: 'Run &Atom Specs', command: 'application:run-all-specs' }
+          { label: 'Run Package &Specs', command: 'window:run-package-specs' }
+          { label: 'Toggle Developer &Tools', command: 'window:toggle-dev-tools' }
+        ]
+      }
+      { type: 'separator' }
+      { label: 'Toggle Soft &Wrap', command: 'editor:toggle-soft-wrap' }
+    ]
+  }
+
+  {
+    label: '&Selection'
+    submenu: [
+      { label: 'Add Selection &Above', command: 'editor:add-selection-above' }
+      { label: 'Add Selection &Below', command: 'editor:add-selection-below' }
+      { label: 'S&plit into Lines', command: 'editor:split-selections-into-lines'}
+      { type: 'separator' }
+      { label: 'Select to &Top', command: 'core:select-to-top' }
+      { label: 'Select to Botto&m', command: 'core:select-to-bottom' }
+      { type: 'separator' }
+      { label: 'Select &Line', command: 'editor:select-line' }
+      { label: 'Select &Word', command: 'editor:select-word' }
+      { label: 'Select to Beginning of W&ord', command: 'editor:select-to-beginning-of-word' }
+      { label: 'Select to Beginning of L&ine', command: 'editor:select-to-beginning-of-line' }
+      { label: 'Select to First &Character of Line', command: 'editor:select-to-first-character-of-line' }
+      { label: 'Select to End of Wor&d', command: 'editor:select-to-end-of-word' }
+      { label: 'Select to End of Lin&e', command: 'editor:select-to-end-of-line' }
+    ]
+  }
+
+  {
+    label: 'F&ind'
+    submenu: []
+  }
+
+  {
+    label: '&Packages'
+    submenu: []
+  }
+
+  {
+    label: '&Window'
+    submenu: [
+      { label: 'Mi&nimize', command: 'application:minimize' }
+      { label: 'Ma&ximize', command: 'application:zoom' }
+      { type: 'separator' }
+      { label: 'Bring &All to Front', command: 'application:bring-all-windows-to-front' }
+    ]
+  }
+
+  {
+    label: '&Help'
+    submenu: [
+      { label: '&About Atom...', command: 'application:about' }
+      { label: 'View &License', command: 'application:open-license' }
+      { label: "VERSION", enabled: false }
+      { label: "Install &update", command: 'application:install-update', visible: false }
+      { type: 'separator' }
+      { label: '&Documentation', command: 'application:open-documentation' }
+      { type: 'separator' }
+    ]
+  }
+]


commit

commit


Check for failed packages first

Check for failed packages first

--- build/tasks/spec-task.coffee
+++ build/tasks/spec-task.coffee
@@ -158,4 +158,4 @@
       if process.platform is 'win32' and process.env.JANKY_SHA1
         done()
       else
-        done(not coreSpecFailed and failedPackages.length is 0)
+        done(not coreSpecFailed and failedPackages?.length is 0)


Fix node filters

Fix node filters

--- app/scripts/alchemy/core/filters.coffee
+++ app/scripts/alchemy/core/filters.coffee
@@ -126,9 +126,8 @@
     checkboxes = $("[type='checkbox']")
     relationshipTypeList = $('#filter-relationships :checked')
     graphElements = {
-        "node" : vis.selectAll('circle'),
+        "node" : vis.selectAll('g'),
         "edge" : vis.selectAll('line'),
-        "caption" : vis.selectAll('text')
     }
     # if tagList.children().length + nodeTypeList.length + relationshipTypeList.length > 0
     #     active = true
@@ -156,7 +155,7 @@
         d3.select("#li-#{box.name}")
             .classed({'active-label': box.checked, 'inactive-label': !box.checked})

-        ["node", "edge", "caption"].forEach (t)->
+        ["node", "edge"].forEach (t)->
             graphElements[t].filter(".#{box.name}")
              .attr("class", "#{t} #{box.name} #{state}")


Remove "only" scope from validator tests.

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


OAuth: check gitlab config from active team and fetch applicationId for.

--- workers/social/lib/social/models/oauth.coffee
+++ workers/social/lib/social/models/oauth.coffee
@@ -15,6 +15,20 @@
       static        :
         getUrl      : (signature Object, Function)

+
+  checkGroupGitLabSettings = (slug, callback) ->
+
+    JGroup = require './group'
+    JGroup.one { slug }, (err, group) ->
+      if not err and group and group.config?.gitlab?.enabled
+        group.fetchDataAt 'gitlab', (err, data) ->
+          return callback err  if err or not data
+          callback null, {
+            url: data.url
+            applicationId: group.config.gitlab.applicationId
+          }
+      else
+        callback null

   getUrlFor = (options, urlOptions, callback) ->
@@ -43,9 +57,15 @@
         port = if port then ":#{port}" else ''
         host = urlOptions.host ? host
         redirectUri = "#{redirectUri}?returnUrl=#{returnUrl}"  if returnUrl
-        url = "#{protocol}#{host}#{port}/oauth/authorize?client_id=#{applicationId}&redirect_uri=#{redirectUri}&response_type=code"

-        callback null, url
+        checkGroupGitLabSettings client.context.group, (err, data) ->
+
+          url = "#{protocol}#{host}#{port}"
+
+          if not err and data
+            { url, applicationId } = data
+
+          callback null, "#{url}/oauth/authorize?client_id=#{applicationId}&response_type=code&redirect_uri=#{redirectUri}"

       facebook: ->


Don't set lastDragValue when the cursor coordinate is 0 (Chrome bug)

Fixes #265.

--- assets/javascripts/views/layout/resizer.coffee
+++ assets/javascripts/views/layout/resizer.coffee
@@ -40,6 +40,7 @@

   onDrag: (event) =>
     value = event.pageX
+    return unless value > 0
     @lastDragValue = value
     return if @lastDrag and @lastDrag > Date.now() - 50
     @lastDrag = Date.now()


spec for dropdown view

spec for dropdown view

error: pathspec 'components/filter2/dropdown/test/view.coffee' did not match any file(s) known to git

--- components/filter2/dropdown/test/view.coffee
+++ components/filter2/dropdown/test/view.coffee
@@ -0,0 +1,40 @@
+_ = require 'underscore'
+benv = require 'benv'
+sinon = require 'sinon'
+Backbone = require 'backbone'
+{ resolve } = require 'path'
+{ fabricate2 } = require 'antigravity'
+FilterArtworks = require '../../../../collections/filter_artworks.coffee'
+
+describe 'Filter / Dropdown', ->
+
+  beforeEach (done) ->
+    benv.setup =>
+      benv.expose
+        $: benv.require 'jquery'
+        _s: require('underscore.string')
+        sd:
+          FILTER_ROOT: '/browse'
+      Backbone.$ = $
+      DropdownView = benv.requireWithJadeify resolve(__dirname, '../view'), ['template']
+      @view = new DropdownView
+        el: $ "

"
+        params: new Backbone.Model
+        collection: new FilterArtworks fabricate2('filter_artworks'), parse: true
+        facets: ['price_range', 'dimension_range', 'medium']
+        facet: 'price_range'
+
+      done()
+
+  afterEach ->
+    benv.teardown()
+
+  it 'renders properly', ->
+    @view.renderCounts @view.collection
+
+    @view.$('.filter-nav-main-text').text().should.equal 'Price'
+    @view.$('.filter-nav-active-text').text().should.equal ''
+    @view.$('.filter-dropdown-nav > a').first().text().should.equal 'All Prices'
+    @view.$('.filter-dropdown-nav > a:nth-child(2) .filter-dropdown-text').text().should.equal 'for Sale'
+    @view.$('.filter-dropdown-nav > a:nth-child(2) .filter-dropdown-count').text().should.equal '(5,647)'
+


Add some debugging statements to the test server

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/fuzzy-ai/microservice-client.git/'


video: cleanup publisher and stream after stopped

--- client/app/lib/videocollaboration/model.coffee
+++ client/app/lib/videocollaboration/model.coffee
@@ -233,6 +233,15 @@

   ###*
+   * Unregister publisher and stream.
+  ###
+  unregisterPublisher: ->
+
+    @publisher = null
+    @stream = null
+
+
+  ###*
    * Action to trigger activation of video collaboration.
    * If given publisher is `null` it means that the video collaboration started
    * without the user publishing his/her video. It's not a concern of neither
@@ -370,6 +379,7 @@
   ###
   handleStopSuccess: ->

+    @unregisterPublisher()
     @setState { publishing: off }
     @setEnded()


User:Profile: destructed token from query

--- client/Account/views/username.coffee
+++ client/Account/views/username.coffee
@@ -94,8 +94,8 @@
         return  notify "Passwords did not match" if password isnt confirmPassword
         # if password is empty than discard operation
         if password is ""
-          query = KD.utils.parseQuery()
-          if query.token
+          {token} = KD.utils.parseQuery()
+          if token
             profileUpdated = no
             notify "You should set your password"
           return queue.next()
@@ -114,8 +114,8 @@

   viewAppended:->
     {JPasswordRecovery, JUser} = KD.remote.api
-    query = KD.utils.parseQuery()
-    if token = query.token
+    {token} = KD.utils.parseQuery()
+    if token
       JPasswordRecovery.validate token, (err, isValid)=>
         if err
           notify err.message
@@ -141,9 +141,9 @@
     @emailForm.inputs.firstName.setDefaultValue firstName
     @emailForm.inputs.lastName.setDefaultValue lastName

-    query = KD.utils.parseQuery()
-    if query.focus
-      @emailForm.inputs[query.focus].setFocus()
+    {focus} = KD.utils.parseQuery()
+    if focus
+      @emailForm.inputs[focus].setFocus()

     if @user.status is "unconfirmed"
       o =


Pass in resizer functions to search results template

--- apps/fair/routes.coffee
+++ apps/fair/routes.coffee
@@ -5,6 +5,7 @@
 cache = require '../../lib/cache'
 client = cache.client
 kinds = require '../favorites_follows/kinds'
+{ crop, fill } = require '../../components/resizer'

 @overview = (req, res, next) ->
   return next() unless res.locals.sd.FAIR
@@ -41,7 +42,12 @@
   search = new Search
   success = _.after 2, ->
     res.locals.sd.SECTION = 'search'
-    res.render 'index', { term: term, fairResults: fairSearch.models, results: search.models }
+    res.render 'index',
+      term: term
+      fairResults: fairSearch.models
+      results: search.models
+      crop: crop
+      fill: fill

   fairSearch.fetch
     data:


sidebar/ctrl: don't use existance to determine visibility

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

--- client/app/lib/sidebarcontroller.coffee
+++ client/app/lib/sidebarcontroller.coffee
@@ -149,11 +149,11 @@

     { FilterType } = SidebarController

-    isVisible = if visibility = @visibility[type]?[id]?
-    then visibility is SidebarController.FilterType
+    isVisible = if visibility = @visibility[type]?[id]
+    then visibility is SidebarController.FilterType.Visible
     else yes

-    debug 'is visible', isVisible
+    debug 'is visible', { isVisible, visibility }

     return isVisible


adds accelerometer tests to testSpecApp

adds accelerometer tests to testSpecApp

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


Add jshint task

Add jshint task

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

--- grunt/jshint.coffee
+++ grunt/jshint.coffee
@@ -0,0 +1,3 @@
+module.exports = (grunt) ->
+  files: ['src/**/*.js'],
+  options: grunt.file.readJSON('.jshintrc')


Improve error handling

Improve error handling

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


client: remove troubleshoot util

client: remove troubleshoot util

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


skip related for now

skip related for now

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/davepwsmith/zotero-better-bibtex.git/'


Fix append

Fix append

--- src/daemon/app/util.coffee
+++ src/daemon/app/util.coffee
@@ -10,4 +10,4 @@
     console.log chalk.red("app   #{path?.split('/').pop()}"), str

   append: (path, data) ->
-    fs.appendFileSync path, data+    fs.appendFileSync path, "#{data}\n"


New namespace for gestures

New namespace for gestures

error: pathspec 'source/quo.gestures.coffee' did not match any file(s) known to git

--- source/quo.gestures.coffee
+++ source/quo.gestures.coffee
@@ -0,0 +1,208 @@
+###
+Basic Quo Module
+
+@namespace Quo
+@class Gestures
+
+@author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
+###
+"use strict"
+
+do ($$ = Quo) ->
+
+  TAPS = null
+  EVENT = undefined
+  GESTURE = {}
+  FIRST_TOUCH = []
+  CURRENT_TOUCH = []
+  TOUCH_TIMEOUT = undefined
+  HOLD_DELAY = 650
+  GESTURES = ["touch",
+              "tap", "singleTap", "doubleTap", "hold",
+              "swipe", "swiping", "swipeLeft", "swipeRight", "swipeUp", "swipeDown",
+              "rotate", "rotating", "rotateLeft", "rotateRight",
+              "pinch", "pinching", "pinchIn", "pinchOut",
+              "drag", "dragLeft", "dragRight", "dragUp", "dragDown"]
+
+  GESTURES.forEach (event) ->
+    $$.fn[event] = (callback) ->
+      event_name = if event is "touch" then "touchend" else event
+      $$(document.body).delegate @selector, event_name, callback
+    @
+
+  $$(document).ready -> _listenTouches()
+
+  # ---------------------------------------------------------------------------
+  # Private Methods
+  # ---------------------------------------------------------------------------
+  _listenTouches = ->
+    environment = $$ document.body
+    environment.bind "touchstart", _onTouchStart
+    environment.bind "touchmove", _onTouchMove
+    environment.bind "touchend", _onTouchEnd
+    environment.bind "touchcancel", _cleanGesture
+
+  _onTouchStart = (event) ->
+    EVENT = event
+    now = Date.now()
+    delta = now - (GESTURE.last or now)
+
+    TOUCH_TIMEOUT and clearTimeout(TOUCH_TIMEOUT)
+    touches = _getTouches(event)
+    fingers = touches.length
+    FIRST_TOUCH = _fingersPosition(touches, fingers)
+    GESTURE.el = $$(_parentIfText(touches[0].target))
+    GESTURE.fingers = fingers
+    GESTURE.last = now
+
+    unless GESTURE.taps then GESTURE.taps = 0
+    GESTURE.taps++
+
+    if fingers is 1
+      if fingers >= 1
+        GESTURE.gap = (delta > 0 and delta <= 250)
+      setTimeout _hold, HOLD_DELAY
+    else if fingers is 2
+      GESTURE.initial_angle = parseInt(_angle(FIRST_TOUCH), 10)
+      GESTURE.initial_distance = parseInt(_distance(FIRST_TOUCH), 10)
+      GESTURE.angle_difference = 0
+      GESTURE.distance_difference = 0
+
+  _onTouchMove = (event) ->
+    EVENT = event
+    if GESTURE.el
+      touches = _getTouches(event)
+      fingers = touches.length
+      if fingers == GESTURE.fingers
+        CURRENT_TOUCH = _fingersPosition(touches, fingers)
+        is_swipe = _isSwipe(event)
+        if is_swipe then GESTURE.prevSwipe = true
+        _trigger "swiping" if (is_swipe or GESTURE.prevSwipe is true)
+        if fingers == 2
+          _captureRotation()
+          _capturePinch()
+          event.preventDefault()
+      else
+        _cleanGesture()
+    true
+
+  _isSwipe = (event) ->
+    it_is = false
+    if CURRENT_TOUCH[0]
+      move_horizontal = Math.abs(FIRST_TOUCH[0].x - CURRENT_TOUCH[0].x) > 30
+      move_vertical = Math.abs(FIRST_TOUCH[0].y - CURRENT_TOUCH[0].y) > 30
+      it_is = GESTURE.el and (move_horizontal or move_vertical)
+    it_is
+
+  _onTouchEnd = (event) ->
+    EVENT = event
+    _trigger "touch"
+
+    if GESTURE.fingers is 1
+      if GESTURE.taps is 2 and GESTURE.gap
+        _trigger "doubleTap"
+        _cleanGesture()
+      else if _isSwipe() or GESTURE.prevSwipe
+        _trigger "swipe"
+        swipe_direction = _swipeDirection(FIRST_TOUCH[0].x, CURRENT_TOUCH[0].x, FIRST_TOUCH[0].y, CURRENT_TOUCH[0].y)
+        _trigger "swipe" + swipe_direction
+        _cleanGesture()
+      else
+        _trigger "tap"
+        if GESTURE.taps is 1
+          TOUCH_TIMEOUT = setTimeout((->
+            _trigger "singleTap"
+            _cleanGesture()
+          ), 100)
+    else
+      anyevent = false
+      if GESTURE.angle_difference
+        _trigger "rotate", angle: GESTURE.angle_difference
+        rotation_direction = if GESTURE.angle_difference > 0 then "rotateRight" else "rotateLeft"
+        _trigger rotation_direction, angle: GESTURE.angle_difference
+        anyevent = true
+      if GESTURE.distance_difference
+        _trigger "pinch", angle: GESTURE.distance_difference
+        pinch_direction = if GESTURE.distance_difference > 0 then "pinchOut" else "pinchIn"
+        _trigger pinch_direction, distance: GESTURE.distance_difference
+        anyevent = true
+      if not anyevent and CURRENT_TOUCH[0]
+        if Math.abs(FIRST_TOUCH[0].x - CURRENT_TOUCH[0].x) > 10 or Math.abs(FIRST_TOUCH[0].y - CURRENT_TOUCH[0].y) > 10
+            _trigger "drag"
+            drag_direction = _swipeDirection(FIRST_TOUCH[0].x, CURRENT_TOUCH[0].x, FIRST_TOUCH[0].y, CURRENT_TOUCH[0].y)
+            _trigger "drag" + drag_direction
+            anyevent = true
+      _cleanGesture()
+    EVENT = undefined
+
+  _fingersPosition = (touches, fingers) ->
+    result = []
+    i = 0
+    touches = if touches[0].targetTouches then touches[0].targetTouches else touches
+    while i < fingers
+      result.push
+        x: touches[i].pageX
+        y: touches[i].pageY
+      i++
+    result
+
+  _captureRotation = () ->
+    angle = parseInt(_angle(CURRENT_TOUCH), 10)
+    diff = parseInt(GESTURE.initial_angle - angle, 10)
+    if Math.abs(diff) > 20 or GESTURE.angle_difference isnt 0
+      i = 0
+      symbol = if GESTURE.angle_difference < 0 then -1 else 1
+      diff += 180 * symbol while Math.abs(diff - GESTURE.angle_difference) > 90 and i++ < 10
+      GESTURE.angle_difference = parseInt(diff, 10)
+      _trigger "rotating", angle: GESTURE.angle_difference
+
+  _capturePinch = () ->
+    distance = parseInt(_distance(CURRENT_TOUCH), 10)
+    diff = GESTURE.initial_distance - distance
+    if Math.abs(diff) > 10
+      GESTURE.distance_difference = diff
+      _trigger "pinching", distance: diff
+
+  _trigger = (type, params) ->
+    if GESTURE.el
+      params = params or {}
+      if CURRENT_TOUCH[0]
+        params.iniTouch = (if GESTURE.fingers > 1 then FIRST_TOUCH else FIRST_TOUCH[0])
+        params.currentTouch = (if GESTURE.fingers > 1 then CURRENT_TOUCH else CURRENT_TOUCH[0])
+      GESTURE.el.trigger type, params, EVENT
+
+  _cleanGesture = (event) ->
+    FIRST_TOUCH = []
+    CURRENT_TOUCH = []
+    GESTURE = {}
+    clearTimeout TOUCH_TIMEOUT
+
+  _angle = (touches_data) ->
+    A = touches_data[0]
+    B = touches_data[1]
+    angle = Math.atan((B.y-A.y)*-1/(B.x-A.x))*(180/Math.PI)
+    if angle < 0 then (angle + 180) else angle
+
+  _distance = (touches_data) ->
+    A = touches_data[0]
+    B = touches_data[1]
+    Math.sqrt((B.x-A.x)*(B.x-A.x)+(B.y-A.y)*(B.y-A.y))*-1
+
+  _getTouches = (event) ->
+    if $$.isMobile() then event.touches else [event]
+
+  _parentIfText = (node) ->
+    if "tagName" of node then node else node.parentNode
+
+  _swipeDirection = (x1, x2, y1, y2) ->
+    xDelta = Math.abs(x1 - x2)
+    yDelta = Math.abs(y1 - y2)
+    if xDelta >= yDelta
+      if x1-x2 > 0 then "Left" else "Right"
+    else
+      if y1-y2 > 0 then "Up" else "Down"
+
+  _hold = ->
+    if GESTURE.last and (Date.now() - GESTURE.last >= HOLD_DELAY)
+      if not _isSwipe then _trigger "hold"
+      GESTURE.taps = 0


Attach to DOM for focus specs

Attach to DOM for focus specs

--- spec/root-view-spec.coffee
+++ spec/root-view-spec.coffee
@@ -92,6 +92,9 @@
         expect(rootView.getEditors().length).toBe 0

   describe "focus", ->
+    beforeEach ->
+      rootView.attachToDom()
+
     describe "when there is an active view", ->
       it "hands off focus to the active view", ->
         editor = rootView.getActiveView()


Remove unnecessary < chars. wtf

Remove unnecessary < chars. wtf

--- spec/workspace-spec.coffee
+++ spec/workspace-spec.coffee
@@ -283,7 +283,7 @@
             expect(notificationSpy).toHaveBeenCalled()
             notification = notificationSpy.mostRecentCall.args[0]
             expect(notification.getType()).toBe 'warning'
-            expect(notification.getMessage()).toContain < '2MB'
+            expect(notification.getMessage()).toContain '< 2MB'

       describe "when a file does not exist", ->
         it "creates a notification", ->
@@ -294,8 +294,8 @@
             expect(notificationSpy).toHaveBeenCalled()
             notification = notificationSpy.mostRecentCall.args[0]
             expect(notification.getType()).toBe 'warning'
-            expect(notification.getMessage()).toContain < 'No such file'
-            expect(notification.getMessage()).toContain < 'not-a-file.md'
+            expect(notification.getMessage()).toContain 'No such file'
+            expect(notification.getMessage()).toContain 'not-a-file.md'

   describe "::reopenItem()", ->
     it "opens the uri associated with the last closed pane that isn't currently open", ->


add logouthandlerhelper.coffee

add logouthandlerhelper.coffee

error: pathspec 'servers/testhelper/logouthandlerhelper.coffee' did not match any file(s) known to git

--- servers/testhelper/logouthandlerhelper.coffee
+++ servers/testhelper/logouthandlerhelper.coffee
@@ -0,0 +1,39 @@
+querystring = require 'querystring'
+
+{ generateUrl
+  deepObjectExtend
+  generateRandomString
+  generateDefaultRequestParams } = require './index.coffee'
+
+generateLogoutRequestBody = (opts = {}) ->
+
+  defaultBodyObject =
+    name : generateRandomString()
+
+  deepObjectExtend defaultBodyObject, opts
+
+  return defaultBodyObject
+
+
+generateLogoutRequestParams = (opts = {}) ->
+
+  name = opts?.body?.name or generateRandomString()
+
+  url  = generateUrl
+    route : "#{encodeURIComponent name}/Logout"
+
+  body = generateLogoutRequestBody()
+
+  params               = { url, body }
+  defaultRequestParams = generateDefaultRequestParams params
+  requestParams        = deepObjectExtend defaultRequestParams, opts
+  # after deep extending object, encodes body param to a query string
+  requestParams.body   = querystring.stringify requestParams.body
+
+  return requestParams
+
+
+module.exports = {
+  generateLogoutRequestBody
+  generateLogoutRequestParams
+}


Don't blink the cursor if it should not be visible

Also, when stopping blinking, set the cursor's visibility to whatever it is on the underlying model. This fixes issues where the cursor would blink when there was a selection.

--- src/app/cursor-view.coffee
+++ src/app/cursor-view.coffee
@@ -67,16 +67,16 @@
         @css('visibility', 'hidden')

   toggleVisible: ->
-    @setVisible(not @visible) if @cursor.isVisible
+    @setVisible(not @visible)

   stopBlinking: ->
     clearInterval(@blinkInterval) if @blinkInterval
     @blinkInterval = null
-    @setVisible(true) if @cursor.isVisible
+    @setVisible(@cursor.isVisible())

   startBlinking: ->
     return if @blinkInterval?
-    blink = => @toggleVisible()
+    blink = => @toggleVisible() if @cursor.isVisible()
     @blinkInterval = setInterval(blink, @blinkPeriod / 2)

   resetBlinking: ->


Translate angular code for editing media into jquery post calls.

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/lmjohns3/thorax-media.git/'


Fix bug in op-undo.

Fix bug in op-undo.


view can be started with a default id

view can be started with a default id


fixed require and added a test counter

fixed require and added a test counter


minor rename

minor rename

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/MicrosmartSA/ubiquity-ui.git/'


Add default task

Add default task

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/BYODKM/legacy-gradient.styl.git/'


Emotioneric.com + slack

Emotioneric.com + slack

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

--- scripts/ericme.coffee
+++ scripts/ericme.coffee
@@ -0,0 +1,210 @@
+# Description:
+#   Eric displays emotions is the most important thing in life
+#
+# Dependencies:
+#   None
+#
+# Configuration:
+#   None
+#
+# Commands:
+#   [hubot-name] eric me - Receive an eric picture
+#   [hubot-name] eric bomb N - get N pugs
+
+urls = [
+	"http://emotioneric.com/happy.jpg",
+	"http://emotioneric.com/sad.jpg",
+	"http://emotioneric.com/anger.jpg",
+	"http://emotioneric.com/fear.jpg",
+	"http://emotioneric.com/annoyed.jpg",
+	"http://emotioneric.com/complacent.jpg",
+	"http://emotioneric.com/shy.jpg",
+	"http://emotioneric.com/unctuous.jpg",
+	"http://emotioneric.com/stressed.jpg",
+	"http://emotioneric.com/perturbed.jpg",
+	"http://emotioneric.com/panic.jpg",
+	"http://emotioneric.com/suave.jpg",
+	"http://emotioneric.com/pity.jpg",
+	"http://emotioneric.com/horror.jpg",
+	"http://emotioneric.com/bemusedr.jpg",
+	"http://emotioneric.com/love.jpg",
+	"http://emotioneric.com/kill.jpg",
+	"http://emotioneric.com/reserved.jpg",
+	"http://emotioneric.com/flirtatious.jpg",
+	"http://emotioneric.com/consternation.jpg",
+	"http://emotioneric.com/indifference.jpg",
+	"http://emotioneric.com/exhaustion.jpg",
+	"http://emotioneric.com/horny.jpg",
+	"http://emotioneric.com/sour.jpg",
+	"http://emotioneric.com/kill2.jpg",
+	"http://emotioneric.com/holiness.jpg",
+	"http://emotioneric.com/motherlylove.jpg",
+	"http://emotioneric.com/scramps.jpg",
+	"http://emotioneric.com/homealone.jpg",
+	"http://emotioneric.com/satanic.jpg",
+	"http://emotioneric.com/drunk.jpg",
+	"http://emotioneric.com/oven.jpg",
+	"http://emotioneric.com/senile.jpg",
+	"http://emotioneric.com/sneeze.jpg",
+	"http://emotioneric.com/invisibility.jpg",
+	"http://emotioneric.com/meditative.jpg",
+	"http://emotioneric.com/nocams.jpg",
+	"http://emotioneric.com/sarcresp.jpg",
+	"http://emotioneric.com/fabric.jpg",
+	"http://emotioneric.com/sassy.jpg",
+	"http://emotioneric.com/dumbf.jpg",
+	"http://emotioneric.com/stairs.jpg",
+	"http://emotioneric.com/fsurprise.jpg",
+	"http://emotioneric.com/nauseate.jpg",
+	"http://emotioneric.com/psychotic.jpg",
+	"http://emotioneric.com/thoughtful.jpg",
+	"http://emotioneric.com/surprised-g.jpg",
+	"http://emotioneric.com/surprise-b.jpg",
+	"http://emotioneric.com/migraine.jpg",
+	"http://emotioneric.com/intrigue.jpg",
+	"http://emotioneric.com/mornaftr.jpg",
+	"http://emotioneric.com/techsupport.jpg",
+	"http://emotioneric.com/footfire.jpg",
+	"http://emotioneric.com/oops.jpg",
+	"http://emotioneric.com/realeric.jpg",
+	"http://emotioneric.com/pixelated.jpg",
+	"http://emotioneric.com/b4seizure.jpg",
+	"http://emotioneric.com/stupidsite.jpg",
+	"http://emotioneric.com/papercut.jpg",
+	"http://emotioneric.com/turndownloan.jpg",
+	"http://emotioneric.com/razorbad.jpg",
+	"http://emotioneric.com/grinch.jpg",
+	"http://emotioneric.com/a-ok.jpg",
+	"http://emotioneric.com/newshoes.jpg",
+	"http://emotioneric.com/halffull.jpg",
+	"http://emotioneric.com/superior.jpg",
+	"http://emotioneric.com/restart.jpg",
+	"http://emotioneric.com/exxcellent.jpg",
+	"http://emotioneric.com/caughtpicking.jpg",
+	"http://emotioneric.com/catchgf.jpg",
+	"http://emotioneric.com/swell.jpg",
+	"http://emotioneric.com/2cool4u.jpg",
+	"http://emotioneric.com/karaoke.jpg",
+	"http://emotioneric.com/finalsdone.jpg",
+	"http://emotioneric.com/misanthropy.jpg",
+	"http://emotioneric.com/fly2.jpg",
+	"http://emotioneric.com/turnjapa.jpg",
+	"http://emotioneric.com/born.jpg",
+	"http://emotioneric.com/multiplicity.jpg",
+	"http://emotioneric.com/quayledad.jpg",
+	"http://emotioneric.com/hamsterpants.jpg",
+	"http://emotioneric.com/nipple3.jpg",
+	"http://emotioneric.com/infectnip.jpg",
+	"http://emotioneric.com/remorse.jpg",
+	"http://emotioneric.com/procrastination.jpg",
+	"http://emotioneric.com/bigears.jpg",
+	"http://emotioneric.com/hardcore.jpg",
+	"http://emotioneric.com/ericsperm.jpg",
+	"http://emotioneric.com/hypnotized.jpg",
+	"http://emotioneric.com/eatendoritos.jpg",
+	"http://emotioneric.com/emotioninfinity.jpg",
+	"http://emotioneric.com/cameron.jpg",
+	"http://emotioneric.com/procrastination2.jpg",
+	"http://emotioneric.com/soylentgreen.jpg",
+	"http://emotioneric.com/grad.jpg",
+	"http://emotioneric.com/masterkilled.jpg",
+	"http://emotioneric.com/brotha.jpg",
+	"http://emotioneric.com/firstsnowboard.jpg",
+	"http://emotioneric.com/day1.jpg",
+	"http://emotioneric.com/day2.jpg",
+	"http://emotioneric.com/intensepsx.jpg",
+	"http://emotioneric.com/ukfame.jpg",
+	"http://emotioneric.com/peopleseyebrow.jpg",
+	"http://emotioneric.com/wristexercise.jpg",
+	"http://emotioneric.com/domo.jpg",
+	"http://emotioneric.com/badhairday.jpg",
+	"http://emotioneric.com/shadowboxing.jpg",
+	"http://emotioneric.com/cantsleep.jpg",
+	"http://emotioneric.com/whassup.jpg",
+	"http://emotioneric.com/unibrow.jpg",
+	"http://emotioneric.com/candystore.jpg",
+	"http://emotioneric.com/houseout.jpg",
+	"http://emotioneric.com/goodbyecruelworld.jpg",
+	"http://emotioneric.com/firsttime.jpg",
+	"http://emotioneric.com/jilted.jpg",
+	"http://emotioneric.com/haironfire.jpg",
+	"http://emotioneric.com/constipated.jpg",
+	"http://emotioneric.com/kickasstakenames.jpg",
+	"http://emotioneric.com/mathiseasy.jpg",
+	"http://emotioneric.com/aspirin.jpg",
+	"http://emotioneric.com/sumoeric.jpg",
+	"http://emotioneric.com/absent.jpg",
+	"http://emotioneric.com/lockjaw.jpg",
+	"http://emotioneric.com/chocolatey.jpg",
+	"http://emotioneric.com/afroeric.jpg",
+	"http://emotioneric.com/killedbymyhands.jpg",
+	"http://emotioneric.com/broccoliteeth.jpg",
+	"http://emotioneric.com/sonofarnie.jpg",
+	"http://emotioneric.com/roadrage.jpg",
+	"http://emotioneric.com/subwaylick.jpg",
+	"http://emotioneric.com/slimfastdiet.jpg",
+	"http://emotioneric.com/notwearingpants.jpg",
+	"http://emotioneric.com/postingbills.jpg",
+	"http://emotioneric.com/doesthismakemelookfat.jpg",
+	"http://emotioneric.com/icecreamheadache.jpg",
+	"http://emotioneric.com/doh.jpg",
+	"http://emotioneric.com/runningwithscissors.jpg",
+	"http://emotioneric.com/caughtpornatwork.jpg",
+	"http://emotioneric.com/whosyourdaddy.jpg",
+	"http://emotioneric.com/itsnottoothpaste.jpg",
+	"http://emotioneric.com/whatsthatsmell.jpg",
+	"http://emotioneric.com/disgust.jpg",
+	"http://emotioneric.com/narcoleptic.jpg",
+	"http://emotioneric.com/erectiledysfunction.jpg",
+	"http://emotioneric.com/lockedkeysincar.jpg",
+	"http://emotioneric.com/toosexyformyshirt.jpg",
+	"http://emotioneric.com/itsnotbutter.jpg",
+	"http://emotioneric.com/illogical.jpg",
+	"http://emotioneric.com/smarmy.jpg",
+	"http://emotioneric.com/meetalterego.jpg",
+	"http://emotioneric.com/patriotic.jpg",
+	"http://emotioneric.com/youwannafight.jpg",
+	"http://emotioneric.com/caffeinated.jpg",
+	"http://emotioneric.com/outofbody.jpg",
+	"http://emotioneric.com/puppydogface.jpg",
+	"http://emotioneric.com/justslammedfingers.jpg",
+	"http://emotioneric.com/outsidelookingin.jpg",
+	"http://emotioneric.com/imontv.jpg",
+	"http://emotioneric.com/kill3.jpg",
+	"http://emotioneric.com/bodyintrunk.jpg",
+	"http://emotioneric.com/taxday.jpg",
+	"http://emotioneric.com/thinkingoutsidethebox.jpg",
+	"http://emotioneric.com/toomanysnooze.jpg",
+	"http://emotioneric.com/elevatorfart.jpg",
+	"http://emotioneric.com/stoned.jpg",
+	"http://emotioneric.com/trappedunderheavy.jpg",
+	"http://emotioneric.com/preventsars.jpg",
+	"http://emotioneric.com/lucypullsfb.jpg",
+	"http://emotioneric.com/givegfpurse.jpg",
+	"http://emotioneric.com/computeratepaper.jpg",
+	"http://emotioneric.com/pensive.jpg",
+	"http://emotioneric.com/deerinheadlights.jpg",
+	"http://emotioneric.com/morningwood.jpg",
+	"http://emotioneric.com/nerderic.jpg",
+	"http://emotioneric.com/killingmesoftlywithhissong.jpg",
+	"http://emotioneric.com/innerchild.jpg",
+	"http://emotioneric.com/mmmdonut.jpg",
+	"http://emotioneric.com/maytheforcebewithyou.jpg",
+	"http://emotioneric.com/narcissistic.jpg",
+	"http://emotioneric.com/discombobulated.jpg",
+	"http://emotioneric.com/greatideafalldoom.jpg",
+	"http://emotioneric.com/condescendingsmile.jpg",
+	"http://emotioneric.com/mauledbyadog.jpg",
+	"http://emotioneric.com/wherearetheupdates.jpg",
+	"http://emotioneric.com/takingcandyfromababy.jpg",
+	"http://emotioneric.com/chickmagnet.jpg"
+]
+
+module.exports = (robot) ->
+
+  robot.respond /eric me/i, (msg) ->
+    msg.send msg.random urls
+
+  robot.respond /eric bomb( (\d+))?/i, (msg) ->
+    count = msg.match[2] || 5
+    msg.send msg.random urls for i in [0 .. count]


changed time_span values to negative values

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


Temporary removal of member management information.

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


Implement deferred based timer

Implement deferred based timer

Helps mitigate callback chaos

error: pathspec 'app/js/jail_iframe/classes/timer.coffee' did not match any file(s) known to git

--- app/js/jail_iframe/classes/timer.coffee
+++ app/js/jail_iframe/classes/timer.coffee
@@ -0,0 +1,4 @@
+FactlinkJailRoot.Timer = (delay) ->
+  deferred = $.Deferred()
+  setTimeout( (-> deferred.resolve()), delay)
+  deferred.promise()


:lipstick: Initialize ivars in constructor

--- src/package-manager.coffee
+++ src/package-manager.coffee
@@ -7,9 +7,11 @@
 module.exports =
 class PackageManager
   _.extend @prototype, EventEmitter
-  loadedPackages: {}
-  activePackages: {}
-  packageStates: {}
+
+  constructor: ->
+    @loadedPackages = {}
+    @activePackages = {}
+    @packageStates = {}

   getPackageState: (name) ->
     @packageStates[name]


Fix test case

Fix test case

--- test/lib/models/device-spec.coffee
+++ test/lib/models/device-spec.coffee
@@ -390,11 +390,6 @@
         it 'should yield an error', ->
           expect(@error).to.be.an.instanceOf Error

-          if process.env.USE_MONGO?.toLocaleLowerCase() == 'true'
-            expect(@error.message).to.deep.equal 'Unknown modifier: $breed'
-          else
-            expect(@error.message).to.deep.equal 'Unknown modifier $breed'
-
   describe '->validate', ->
     describe 'when created with a different uuid', ->
       beforeEach ->


BF-213 added json_socket.coffee

BF-213 added json_socket.coffee

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

--- app/assets/javascripts/libs/json_socket.coffee
+++ app/assets/javascripts/libs/json_socket.coffee
@@ -0,0 +1,159 @@
+### define
+libs/request : Request
+libs/event_mixin : EventMixin
+###
+
+
+class JsonSocket
+
+  senderPointer : 0
+  senders : []
+
+  constructor : (options) ->
+
+    _.extend(this, options)
+    _.extend(this, new EventMixin())
+
+    senderDataCallback = (args...) =>
+      @trigger( "data", args... )
+
+    for sender in @senders
+      sender.on "data", senderDataCallback
+
+    @sender = @senders[0]
+    @sender.open()
+
+
+  switchToNextSender : ->
+
+    if @senderPointer + 1 < @senders.length
+      @senderPointer++
+      @sender.close()
+      @sender = @senders[@senderPointer]
+      @sender.open(this)
+
+
+  send : (data, retryCount = 0) ->
+
+    currentSenderPointer = @senderPointer
+    @sender.send(data).pipe(
+      null
+      =>
+        if currentSenderPointer != @senderPointer
+          @send(data, retryCount + 1)
+        else if retryCount < @senders.length
+          @switchToNextSender()
+          @send(data, retryCount + 1)
+        else
+          null
+    )
+
+
+class JsonSocket.WebSocket
+
+  OPEN_TIMEOUT : 500
+
+  openDeferred : null
+
+  constructor : (@url) ->
+
+    _.extend(this, new EventMixin())
+
+
+  open : ->
+
+    unless @socket and @openDeferred
+
+      socket = @socket = new @WebSocketImpl(@url)
+      openDeferred = @openDeferred = $.Deferred()
+
+      socket.onopen = -> openDeferred.resolve()
+
+      socket.onerror = (err) ->
+        console.error("socket error", err)
+
+      socket.addEventListener(
+        "close"
+        (code, reason) =>
+
+          @socket = null
+          console?.error("socket closed", "#{code}: #{reason}")
+
+        false
+      )
+
+      socket.addEventListener(
+        "message"
+        (event) =>
+          data = null
+          try
+            data = JSON.parse(event.data)
+          catch error
+            console.error("JsonSocket.WebSocket: #{error}")
+
+          @trigger("data", data) if data?
+        false
+      )
+
+      setTimeout(
+        =>
+          if not @socket or @socket.readyState != @WebSocketImpl.OPEN
+            openDeferred.reject("timeout")
+        @OPEN_TIMEOUT
+      )
+
+    @openDeferred.promise()
+
+
+  close : ->
+
+    if @socket
+      @socket.close()
+      @socket = null
+
+
+  send : (data) ->
+
+    @open().pipe =>
+
+      @socket.send(JSON.stringify(data))
+      return
+
+
+  _window = window ? self
+  @prototype.WebSocketImpl = if _window.MozWebSocket then _window.MozWebSocket else _window.WebSocket
+
+
+class JsonSocket.Comet
+
+  iframeElement : null
+  globalCallbackName : ""
+
+  constructor : (@url) ->
+
+    _.extend(this, new EventMixin())
+    @globalCallbackName = "callback_#{Math.round(Math.random() * 10000)}"
+
+
+  open : ->
+
+    window[@globalCallbackName] = (data) =>
+      @trigger("data", data)
+
+    @iframeElement = $("<iframe>", src : "#{@url}&callback=#{@globalCallbackName}").hide()
+    $("body").append(@iframeElement)
+
+
+  send : (data) ->
+
+    Request.send({ data, @url, type : "POST" })
+
+
+  close : ->
+
+    @iframeElement.remove()
+    @iframeElement = null
+    delete window[@globalCallbackName]
+
+
+JsonSocket


chore(tests): add spec for ProductProvider

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

--- server/test/product_provider_spec.coffee
+++ server/test/product_provider_spec.coffee
@@ -0,0 +1,99 @@
+expect = require("chai").expect
+ProductProvider = require("../lib/product_provider")
+
+describe "ProductProvider", ->
+  productProvider = null
+  beforeEach ->
+    products = [
+      { name: "one" }
+      { name: "two" }
+    ]
+    productProvider = new ProductProvider(products)
+
+  describe "a new instance", ->
+
+    it "saves a prducts", ->
+      expect(productProvider.products.length).to.equal 2
+
+    describe "saved products", ->
+
+      it "generates ids", ->
+        products = productProvider.products
+        expect(products[0].id).to.equal 1
+        expect(products[1].id).to.equal 2
+
+      it "assings createdAt date", ->
+        products = productProvider.products
+        expect(products[0].createdAt).to.not.be.undefined
+        expect(products[1].createdAt).to.not.be.undefined
+
+  describe "#findAll()", ->
+
+    it "finds all products", (done) ->
+
+      productProvider.findAll (error, products) ->
+        expect(products.length).to.equal 2
+        done()
+
+  describe "#findById()", ->
+
+    context "when the product can be found", ->
+
+      it "returns the product", (done) ->
+
+        productProvider.findById 1, (error, product) ->
+          expect(product).not.to.be.undefined
+          expect(product.id).to.equal 1
+          expect(product.name).to.equal "one"
+          done()
+
+    context "when the product cannot be found", ->
+
+      it "returns undefined", (done) ->
+
+        productProvider.findById 3, (error, product) ->
+          expect(product).to.be.undefined
+          done()
+
+  describe "#save()", ->
+
+    context "when the single product is given", ->
+      product = null
+      beforeEach (done) ->
+        productProvider.save name: "third", (error, _newProducts_) ->
+          product = _newProducts_[0]
+          done()
+
+      it "saves a product", ->
+          expect(product).not.to.be.undefined
+          expect(product.name).to.equal "third"
+
+      describe "new record", ->
+
+        it "generates an id for the product", ->
+            expect(product.id).to.equal 3
+
+        it "assigns createdAt date", ->
+            expect(product.createdAt).to.not.be.undefined
+
+    context "when the array of products is given", ->
+      products = null
+      beforeEach (done) ->
+        productProvider.save [{ name: "third" }, { name: "forth" }], (error, _newProducts_) ->
+          products = _newProducts_
+          done()
+
+      it "saves the products", ->
+          expect(products.length).to.equal 2
+          expect(products[0].name).to.equal "third"
+          expect(products[1].name).to.equal "forth"
+
+      describe "new records", ->
+
+        it "generates ids for all new records", ->
+            expect(products[0].id).to.equal 3
+            expect(products[1].id).to.equal 4
+
+        it "assigns createdAt date for all new records", ->
+            expect(products[0].createdAt).to.not.be.undefined
+            expect(products[1].createdAt).to.not.be.undefined


Log GitHub response body.

Log GitHub response body.

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


Fix detection of sigils for tuples and closures

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/pyfisch/atom-language-rust.git/'


Add or handlebar helper

Add or handlebar helper

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

--- src/scripts/helpers/handlebars/or.coffee
+++ src/scripts/helpers/handlebars/or.coffee
@@ -0,0 +1,5 @@
+define (require) ->
+  Handlebars = require('Handlebars')
+
+  Handlebars.registerHelper 'or', (testA, testB, options) ->
+    if testA or testB then options.fn(@) else options.inverse(@)


:boar: Add karma task

:boar: Add karma task

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

--- grunt/karma.coffee
+++ grunt/karma.coffee
@@ -0,0 +1,3 @@
+module.exports =
+  unit:
+    configFile: 'karma.conf.js'


Adjust comments

Adjust comments

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


Add Range.getRows

Add Range.getRows

--- src/app/range.coffee
+++ src/app/range.coffee
@@ -204,6 +204,12 @@
   getRowCount: ->
     @end.row - @start.row + 1

+  # Returns an array of all rows in a `Range`
+  #
+  # Returns an {Array}
+  getRows: ->
+    [@start.row..@end.row]
+
   ### Internal ###

   inspect: ->


removing stale entries from db

removing stale entries from db

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