added gruntfile

added gruntfile

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

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -0,0 +1,53 @@
+module.exports = (grunt) ->
+
+  grunt.initConfig
+    pkg: grunt.file.readJSON('package.json')
+
+    copy:
+      all:
+        expand: true
+        src: ['server/**', 'node_modules/**', 'test/**', 'public/**', '!**/*.coffee']
+        dest: '_build'
+      node_modules:
+        expand: true
+        src: ['node_modules/**', '!**/*.coffee']
+        dest: '_build'
+      server:
+        expand: true
+        src: ['server/**', '!**/*.coffee']
+        dest: '_build'
+      test:
+        expand: true
+        src: ['server/**', 'test/**', '!**/*.coffee']
+        dest: '_build'
+      pub:
+        expand: true
+        src: ['public/**', '!**/*.coffee']
+        dest: '_build'
+
+    watch:
+      coffee:
+        files: ['server/**/*.coffee', 'node_modules/**/*.coffee', 'test/**/*.coffee', '!node_modules/eco/**/*']
+        tasks: ['coffee:map']
+        options:
+          nospawn: true
+
+    coffee:
+      map:
+        options:
+          sourceMap: true
+        expand: true
+        src: ['server/**/*.coffee', 'node_modules/**/*.coffee', 'test/**/*.coffee', '!node_modules/eco/**/*']
+        dest: '_build'
+        ext: '.js'
+
+  grunt.loadNpmTasks 'grunt-contrib-coffee'
+  grunt.loadNpmTasks 'grunt-contrib-copy'
+  grunt.loadNpmTasks 'grunt-contrib-watch'
+
+  grunt.registerTask 'default', ['copy:all', 'coffee:map', 'watch:coffee']
+
+  # On watch events, inject only the changed files into the config
+  grunt.event.on 'watch', (action, filepath) ->
+    grunt.config(['coffee', 'map', 'src'], [filepath])
+


usage removed, examples added

usage removed, examples 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/AppGyver/supersonic.git/'


remove camera follow

remove camera follow

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


Template paths fixed

Template paths fixed

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


Add a easy way to connect and wait for mongo.

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

--- lib/model/mongo.coffee
+++ lib/model/mongo.coffee
@@ -0,0 +1,23 @@
+#
+# FastChat
+# 2015
+#
+
+Q = require 'q'
+mongoose = require('mongoose-q')()
+log = require '../helpers/log'
+
+module.exports = (config)->
+  deferred = Q.defer()
+  mongoUri = process.env.MONGOLAB_URI or 'mongodb://localhost/dev'
+  log.debug 'Connecting to DB: ', mongoUri
+  mongoose.connect(mongoUri)
+  db = mongoose.connection
+
+  db.on 'error', (err)->
+    deferred.reject(err)
+
+  db.once 'open', ->
+    deferred.resolve(db)
+
+  deferred.promise


Update Comment

Update Comment

--- src/fairy.coffee
+++ src/fairy.coffee
@@ -12,7 +12,7 @@
 #   1. Tasks of group `X` and `Y` are appointed to worker `A`.
 #   2. Worker `A` is processing tasks of group `X` **sequentially**.
 #   3. Tasks of group `Y` are pending, while:
-#   4. Worker `B` is still idling because of 1.
+#   4. Worker `B` is snoozing (because of 1)!
 #
 # **Fairy** will route the task of group `Y` to worker `B` in this scenario.
 #


Refactor source_tasks method

Refactor source_tasks method

--- src/fairy.coffee
+++ src/fairy.coffee
@@ -648,26 +648,34 @@

   # ### Get Source Tasks Asynchronously
   #
-  # Get (up to 10) tasks in the `SOURCE` list. Tasks in the `SOURCE` list
-  # does **NOT** equal to **pending** tasks since there may be tasks in the
-  # `QUEUED` list pending for processing.
-  #
-  # The accept parameters are:
-  #
-  #   1. The callback function. The argument of which follows
-  #   2. *Optional*, the number of skipped tasks. Defaults to 0.
-  #   3. *Optional*, the number of tasks need be taken. Defaults to 10.
-  #
+  # Get tasks in the `SOURCE` list. **NOTE:** Tasks in the `SOURCE` list does
+  # **NOT** equal to **pending** tasks! There may be tasks in the `QUEUED` lists
+  # need be processed before processing tasks in the `SOURCE` list.
+  #
+  # Accepted parameters are:
+  #
+  #   1. `skip`, *optional*, the number of skipped tasks. Defaults to 0.
+  #   2. `take`, *optional*, the number of tasks need be taken. Defaults to 10.
+  #   3. `callback`, the callback function. Arguments of which follows nodejs error
+  #   handling convention: (err, res).
+  #
+  # Possible combinations of arguments are:
+  #
+  #   1. `callback`. (`skip` defaults to 0, `take` defaults to 10).
+  #   2. `skip`, `callback`. (`take` defaults to 10).
+  #   3. `skip`, `take`, `callback`.
   #
   # **Usage:**
   #
-  #     queue.source_tasks (tasks) ->
+  #     queue.source_tasks 20, 5, (err, tasks) ->
   #       console.log tasks
-  #     , 0, 10
-  source_tasks: (callback, skip=0, take=10) ->
+  source_tasks: (args..., callback) ->
+    return if typeof callback isnt 'function'
+    skip = args[0] or 0
+    take = args[1] or 10
     @redis.lrange @key('SOURCE'), skip, skip + take - 1, (err, res) ->
       callback err if err
-      callback res.map (entry) ->
+      callback null, res.map (entry) ->
         entry = JSON.parse(entry)
         id: entry[0]
         params: entry[1..-2]


Update Comment

Update Comment

--- src/fairy.coffee
+++ src/fairy.coffee
@@ -34,7 +34,7 @@
 #
 #   + **[node-uuid]**, generate unique identifiers for tasks, and
 #   + **[redis]** node.js driver, of course!
-#   + **[express]**, only if you need the web-front-end!
+#   + **[express]**, only if you need the http api or web front-end!
 #
 # [node-uuid]: https://github.com/broofa/node-uuid
 # [redis]:     https://github.com/mranney/node_redis


Don't render the image on the server

Don't render the image on the server

Rendering on the server can will mean that the tag is in the DOM before the
loader component mounts on the client, which defeats the purpose of a component
meant to control the load of the image.

--- src/index.coffee
+++ src/index.coffee
@@ -3,7 +3,7 @@
 ReactLoaderMixin = require 'react-loadermixin'

 {PropTypes} = React
-{span, img} = React.DOM
+{span, img, noscript} = React.DOM

 Status =
   PENDING: 'pending'
@@ -18,6 +18,24 @@

 ImageLoaderImg = React.createClass
   displayName: 'ImageLoaderImage'
+  getInitialState: ->
+    # We don't want to render the image on the server, because that will result
+    # in the <img> tag being serialized the DOM causing the browser to start
+    # loading the image before this component mounts on the client. Since the
+    # point of this component is to exert control over the image load, we want
+    # to avoid that.
+    #
+    # However, initially rendering different things on the server and the client
+    # is a big no-no (invariant), so we need to also treat the first render on
+    # the client like we do on the server. Only then, once we know we're in the
+    # client environment, can we safely render with actual <img> tag.
+    #
+    # So, to achieve client-server parity, we track our own `isInitialRender`
+    # state (we can't use `isMounted()`, since that will be true at the time of
+    # initial render on the client, but not the server).
+    isInitialRender: true
+  componentDidMount: ->
+    @setState isInitialRender: false
   handleLoad: (args...) ->
     return unless @isMounted()
     image = @refs.image
@@ -26,12 +44,31 @@
     else @props.onLoad? args...
   handleError: (args...) ->
     @props.onError? args...
-  render: ->
+  renderImg: ->
     (img merge @props,
       ref: 'image'
       onLoad: @handleLoad
       onError: @handleError
     )
+  render: ->
+    if @state.isInitialRender
+      # We will initially render the <img> tag in a <noscript> (see note in
+      # `getInitialState` for reasons). This will increase accessibility in that
+      # rare case when the serialized component is served to a browser with
+      # javascript disabled, but ensure that the image won't start loading
+      # before we're ready. However, there is an issue
+      # (https://github.com/facebook/react/issues/1252) that causes noscript to
+      # cause invariant violations when rendered on the server. So, we render it
+      # as a string and set the inner HTML of a wrapper span.
+      html = React.renderComponentToStaticMarkup (noscript null, @renderImg())
+      (span
+        style:
+          display: 'none'
+        dangerouslySetInnerHTML:
+          __html: html
+      )
+    else
+      @renderImg()

 module.exports = ImageLoader = React.createClass


Rename exported helper method.

Rename exported helper method.

There was previously an issue where the helper method "makeMockAdapter"
was actually being defined in Query.test.coffee and attached to the
`helpers` 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/JoshuaToenyes/stout-core.git/'


Now we are all sons of bitches.

Now we are all sons of bitches.

--- scripts/vote.coffee
+++ scripts/vote.coffee
@@ -13,6 +13,8 @@
 #
 # Author:
 #   sshirokov
+
+Twitter = require '../lib/twitter'

 ## Dat model
 class Vote
@@ -199,6 +201,15 @@
         catch error
           msg.reply error

+      when "tweet"
+        try
+          vote = new Vote robot, msg, "Do we Tweet '#{arg}'", timeout, ->
+            Twitter.tweet arg, (err, tweet, url) ->
+              return msg.reply "It can't be done, #{err}" if err
+              msg.send "I hope you're all proud - #{url}"
+        catch error
+          msg.reply error
+
       # Shut up, loony bin
       else
         msg.reply "That made no sense, and you're probably crazy."


edit by line too. (one at a time). use section id for add by line

--- client/create.coffee
+++ client/create.coffee
@@ -221,23 +221,27 @@
     halfWidth + (Session.get "separation") / 2

 Tracker.autorun ->
+  Session.set 'currentYId', Session.get('story').verticalSections[Session.get('currentY')]._id
+
+Tracker.autorun ->
+  currentContextBlocks = Session.get("story").verticalSections[Session.get("currentY")].contextBlocks
   horizontalContextDiv = $(".horizontal-context")
   horizontalContextDiv.removeClass 'editing'

-  if Session.get("addingContextToCurrentY") or Session.get("editingContext")
+  if Session.get("addingContextToCurrentY") or Session.get("editingContext") in currentContextBlocks
     horizontalContextDiv.addClass 'editing'
   else
     horizontalContextDiv.removeClass 'editing'

 Tracker.autorun ->
-  Session.set "addingContextToCurrentY", Session.get("addingContext") is Session.get("currentY")
+  Session.set "addingContextToCurrentY", Session.get("addingContext") is Session.get 'currentYId'

 Template.add_horizontal.events
   "click section": (d) ->
     if Session.get "addingContextToCurrentY"
       Session.set "addingContext", null
     else
-      Session.set "addingContext", Session.get('currentY')
+      Session.set "addingContext", Session.get('currentYId')
       Session.set "editingContext", null

     # unless Session.get("editingContext")


:pencil: Document Workspace::addViewProvider

--- src/workspace.coffee
+++ src/workspace.coffee
@@ -534,5 +534,48 @@
   # Returns a DOM element.
   getView: (object) ->
     @viewRegistry.getView(object)
+
+  # Essential: Add a provider that will be used to construct views in the
+  # workspace's view layer based on model objects in its model layer.
+  #
+  # If you're adding your own kind of pane item, a good strategy for all but the
+  # simplest items is to separate the model and the view. The model handles
+  # application logic and is the primary point of API interaction. The view
+  # just handles presentation.
+  #
+  # Use view providers to inform the workspace how your model objects should be
+  # presented in the DOM. A view provider must always return a DOM node, which
+  # makes [HTML 5 custom elements](http://www.html5rocks.com/en/tutorials/webcomponents/customelements/)
+  # an ideal tool for implementing views in Atom.
+  #
+  # ## Example
+  #
+  # Text editors are divided into a model and a view layer, so when you interact
+  # with methods like `atom.workspace.getActiveTextEditor()` you're only going
+  # to get the model object. We display text editors on screen by teaching the
+  # workspace what view constructor it should use to represent them:
+  #
+  # ```coffee
+  # atom.workspace.addViewProvider
+  #   modelConstructor: TextEditor
+  #   viewConstructor: TextEditorElement
+  # ```
+  #
+  # * `providerSpec` {Object} containing the following keys:
+  #   * `modelConstructor` Constructor {Function} for your model.
+  #   * `viewConstructor` (Optional) Constructor {Function} for your view. It
+  #     should be a subclass of `HTMLElement` (that is, your view should be a
+  #     DOM node) and   have a `::setModel()` method which will be called
+  #     immediately after construction. If you don't supply this property, you
+  #     must supply the `createView` property with a function that never returns
+  #     `undefined`.
+  #   * `createView` (Optional) Factory {Function} that must return a subclass
+  #     of `HTMLElement` or `undefined`. If this property is not present or the
+  #     function returns `undefined`, the view provider will fall back to the
+  #     `viewConstructor` property. If you don't provide this property, you must
+  #     provider a `viewConstructor` property.
+  #
+  # Returns a {Disposable} on which `.dispose()` can be called to remove the
+  # added provider.
   addViewProvider: (providerSpec) ->
     @viewRegistry.addViewProvider(providerSpec)


adds recent connections collection

adds recent connections collection

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

--- collections/recent_connections.coffee
+++ collections/recent_connections.coffee
@@ -0,0 +1,10 @@
+Base = require './base.coffee'
+Backbone = require 'backbone'
+Backbone.LocalStorage = require 'backbone.localstorage'
+Block = require "../models/block.coffee"
+
+module.exports = class RecentConnections extends Backbone.Collection
+
+  model: Block
+
+  localStorage: new Backbone.LocalStorage "RecentConnections"


Forgot a file

Forgot a file

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

--- controllers/reports_controller.coffee
+++ controllers/reports_controller.coffee
@@ -0,0 +1,17 @@
+reports = require '../lib/reports'
+
+module.exports =
+  index: (req, res) ->
+    report = req.body
+    unless report
+      res.render '404.jade', status: 404
+
+    unless report.secret
+      res.send '401 Unauthorized noob detected', 401
+
+    reports.parse report, (err, game) ->
+      return res.send('500 Could not parse report due to error: ' + err.toString() + '\n', 500) if err
+
+      game.save (err) ->
+        return res.send('Could not save due to error: ' + err.toString() + '\n') if err
+        res.send 'WIN'


Added absolute arguments to forElement methods on Rect and Point.

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


Fixed brain.coffee

Fixed brain.coffee

brain.remove was supposed to return @ for chaining.

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


Frontend queue polling doesn't render HTML until content changes

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


Improve Documentation

Improve Documentation

--- src/fairy.coffee
+++ src/fairy.coffee
@@ -64,19 +64,19 @@

 # ## Class Fairy

-# Class `Fairy` is not exposed outside the commonjs module. To get an object
-# of class `Fairy`, use the `connect` method to connect to the Redis server.
-# **Usage:**
-#
-#     fairy = require('fairy').connect()
-#
 # Object of class `Fairy` keeps a Redis connection and a pool of named queues
 # (objects of class `Queue`) responsible for enqueuing and dispatching tasks,
 # etc.
 class Fairy

   # ### Constructor
-
+  #
+  # Class `Fairy` is not exposed outside the commonjs module. To get an object
+  # of class `Fairy`, use the `connect` method to connect to the Redis server.
+  # **Usage:**
+  #
+  #     fairy = require('fairy').connect()
+
   # The constructor of class `Fairy` stores the passed-in Redis client as an
   # instance property.
   #
@@ -90,12 +90,10 @@
   # include:
   #
   #   + `QUEUES`, Redis set, containing names of all registered queues.
-  #
-  # The method is designed to be invoked internally.
   key: (key) -> "#{prefix}:#{key}"

   # ### Get a Named Queue
-
+
   # If the named queue can be found in the `queue_pool` cache, return the cached
   # queue. Otherwise, create an object of class `Queue` using the Redis client
   # and the name of the queue. Add the queue name into the `QUEUES` set for


Improve Documentation

Improve Documentation

--- src/fairy.coffee
+++ src/fairy.coffee
@@ -914,7 +914,7 @@
       #
       # The equation used to calculate pending tasks is:
       #
-      #       pending = total - finished - processing - failed - blocked
+      #      pending = total - finished - processing - failed - blocked
       result.blocked.groups = multi_res[4].length
       multi2 = @redis.multi()
       multi2.llen "#{@key('QUEUED')}:#{group}" for group in multi_res[4]


skipDuplicates on visibility state changes


Hide video save option for safari browser. (#2061)

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


Allow multiple spaces on start of continuation lines

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


Fix bug when no arguments

Fix bug when no arguments

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


fix: Updating hide/show required for optinal fields

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/impact100/common-grant-application.git/'


quick fix

quick fix

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


Wrapping existence tests on functions.

Wrapping existence tests on functions.

--- src/nodes.coffee
+++ src/nodes.coffee
@@ -442,8 +442,8 @@
     o.chainRoot = this unless o.chainRoot
     if @exist
       [@first, @meth] = @variable.compileReference o, precompile: yes
-      @first = "typeof #{@first} === \"function\" ? "
-      @last  = " : null"
+      @first = "(typeof #{@first} === \"function\" ? "
+      @last  = " : null)"
     else if @variable then @meth = @variable.compile o
     for arg in @args when arg instanceof SplatNode
       compilation = @compileSplat(o)


修复群消息的几个问题，增加了api的绑定

修复群消息的几个问题，增加了api的绑定

--- src/qqbot.coffee
+++ src/qqbot.coffee
@@ -1,17 +1,25 @@
+api = require './qqapi'
+api.defaults_read()

 log = console.log
+jsons = JSON.stringify

 class QQBot
-    constructor: (@name) ->
+    constructor: (@name ,@auth) ->
         @buddy_info = {}
         @group_info = {}
         @groupmember_info = {}
+

     # @format PROTOCOL `用户分组信息格式`
     save_buddy_info: (@buddy_info)->

     # @format PROTOCOL `群分组信息格式`
     save_group_info: (@group_info) ->
+
+    # @format PROTOCOL `群用户信息`
+    save_group_member: (group,info)->
+        @groupmember_info[group.gid] = info

     # 获取用户信息
     # @return {nick,uin,flag,face}
@@ -19,6 +27,13 @@
         # TODO:加速查询
         users = @buddy_info.info.filter (item)-> item.uin == uin
         users.pop()
+
+    # 获取群用户信息
+    get_user_ingroup: (uin, gid)->
+        info = @groupmember_info[gid]
+        users = info.minfo.filter (item)-> item.uin == uin
+        users.pop()
+

     # 获取群信息，只支持群 ，支持多关键词搜索
     # @options {key:value}
@@ -28,7 +43,16 @@
             for key ,value of options
                 return item[key] == value
         groups.pop()
-
+
+    # @options {key:value}
+    # @callback (true/false , error)
+    update_group_member: (options, callback)->
+        group = @get_group(options)
+        api.get_group_member group.code , @auth , (ret,e)=>
+            if ret.retcode == 0
+                @save_group_member(group,ret.result)
+            callback(ret.retcode == 0 , e) if callback
+
     handle_poll_responce: (resp)->
         code = resp.retcode
         return if code != 0
@@ -59,9 +83,10 @@

         if msg.type == 'group'
             msg.from_gid = msg.from_uin
-            msg.from_uin = value.send_uin # 这才是用户
-            msg.from_group = @get_group({gid:msg.from_gid} )
-            msg.from_user  = @get_user( msg.from_uin )
+            msg.group_code = value.group_code
+            msg.from_uin = value.send_uin # 这才是用户,group消息中 from_uin 是gid
+            msg.from_group = @get_group( {gid:msg.from_gid} )
+            msg.from_user  = @get_user_ingroup( msg.from_uin ,msg.from_gid )
         else if msg.type == 'buddy'
             msg.from_user = @get_user( msg.from_uin )
         msg


Add SendRequest test file

Add SendRequest test file

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

--- spec/SendRequest.coffee
+++ spec/SendRequest.coffee
@@ -0,0 +1,26 @@
+noflo = require 'noflo'
+chai = require 'chai' unless chai
+SendRequest = require '../components/SendRequest.coffee'
+
+describe 'SendRequest component', ->
+  c = null
+  url = null
+  start = null
+
+  beforeEach ->
+    c = SendRequest.getComponent()
+    url = noflo.internalSocket.createSocket()
+    start = noflo.internalSocket.createSocket()
+    request = noflo.internalSocket.createSocket()
+
+    c.inPorts.url.attach url
+    c.inPorts.start.attach start
+    c.outPorts.request.attach request
+
+  describe 'when instantiated', ->
+    it 'should have a "url" inport', ->
+      chai.expect(c.inPorts.url).to.be.an 'object'
+    it 'should have a "start" outport', ->
+      chai.expect(c.inPorts.start).to.be.an 'object'
+    it 'should have a "request" outport', ->
+      chai.expect(c.outPorts.request).to.be.an 'object'


Reformat.

Reformat.

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/urbanetic/meteor-atlas-util.git/'


Add Stypi example

Add Stypi example

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

--- examples/stypi.coffee
+++ examples/stypi.coffee
@@ -0,0 +1,18 @@
+feature "Collaborative editing", (context, browser, $) ->
+  alice = context.newContext()
+  bob = context.newContext()
+
+  before (done) ->
+    alice.browser.visit 'https://www.stypi.com/', ->
+      bob.browser.visit alice.browser.url, done
+
+  after ->
+    console.log "\tCheck for yourself: #{alice.browser.url}"
+
+  it "shows other user's text", (done) ->
+    oldText = alice.$('#editor').text
+    alice.$('#editor').click()
+    alice.$('#editor').type 'hello Bob'
+    wait.until (-> bob.$('#editor').text != oldText), ->
+      #bob.browser.page.render 'bob.png'
+      done()


add a comment explaining the binary field

The field is set on the Bank Operation model.

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


add clientIdToSiteId to session's document

--- src/packages/collaboration/lib/session.coffee
+++ src/packages/collaboration/lib/session.coffee
@@ -52,16 +52,23 @@
       @mediaConnection = @createMediaConnection()
       @mediaConnection.start()

+      @getClientIdToSiteIdMap().set(@clientId, @site.id)
+
       @connectDocument()
       @channel.one 'channel:subscribed', (participantStates) =>
         @setParticipantStates(participantStates)
         @listening = true
         @trigger 'started', @getParticipants()

-      @on 'participant-entered', =>
+      @on 'participant-entered', (participant) =>
+        # inject siteId; TODO: should be moved to somewhere less sketch
+        guestSiteId = @nextGuestSiteId++
+        clientIdToSiteId = @getClientIdToSiteIdMap()
+        clientIdToSiteId.set(participant.clientId, guestSiteId)
+
         @snapshotRepository (repoSnapshot) =>
           welcomePackage =
-            siteId: @nextGuestSiteId++
+            siteId: guestSiteId
             doc: @doc.serialize()
             repoSnapshot: repoSnapshot
           @channel.send 'welcome', welcomePackage
@@ -95,6 +102,7 @@
       collaborationState:
         guest: {description: '', candidate: '', ready: false}
         host: {description: '', candidate: ''}
+        clientIdToSiteId: {}
         repositoryState:
           url: project.getRepo().getConfigValue('remote.origin.url')
           branch: project.getRepo().getShortHead()
@@ -125,6 +133,8 @@

   setParticipantStates: (participantStates) ->
     @participants = participantStates.map (state) -> new Participant(state)
+
+  getClientIdToSiteIdMap: -> @doc.get('collaborationState.clientIdToSiteId')

   subscribe: (name) ->
     token = keytar.getPassword('github.com', 'github')


Revert "Moved requestAnimationFrame to browserlib"

This reverts commit 4151b78a76dde9e09b31234db9bc8cf353c3ee90.

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

--- src/request_animation_frame.coffee
+++ src/request_animation_frame.coffee
@@ -0,0 +1,10 @@
+window.requestAnimationFrame ||=
+  window.webkitRequestAnimationFrame ||
+  window.mozRequestAnimationFrame    ||
+  window.oRequestAnimationFrame      ||
+  window.msRequestAnimationFrame     ||
+  (callback, element) ->
+    window.setTimeout( ->
+      callback(+new Date())
+    , 1000 / 60)
+


:new: Import linter-registry from ng

:new: Import linter-registry from ng

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

--- lib/linter-registry.coffee
+++ lib/linter-registry.coffee
@@ -0,0 +1,65 @@
+{Emitter} = require('atom')
+validate = require('./validate')
+helpers = require('./helpers')
+
+class LinterRegistry
+  constructor: ->
+    @linters = []
+    @locks =
+      Regular: new WeakSet
+      Fly: new WeakSet
+    @emitter = new Emitter
+
+  hasLinter: (linter) ->
+    @linters.indexOf(linter) isnt -1
+
+  addLinter: (linter) ->
+    try
+      validate.linter(linter)
+      @linters.push(linter)
+    catch e then helpers.error(e)
+
+  deleteLinter: (linter) ->
+    @linters.splice(@linters.indexOf(linter), 1)
+
+  lint: ({onChange, editorLinter}) ->
+    editor = editorLinter.editor
+    lockKey = if onChange then 'Fly' else 'Regular'
+    return if onChange and not atom.config.get('linter.lintOnFly')
+    return unless editorLinter.status
+    return unless editor is atom.workspace.getActiveTextEditor()
+    return unless editor.getPath()
+    return if @locks[lockKey].has(editorLinter)
+
+    @locks[lockKey].add(editorLinter)
+    scopes = editor.scopeDescriptorForBufferPosition(editor.getCursorBufferPosition()).scopes
+    scopes.push('*') # To allow global linters
+
+    # Confusing code ahead, proceed with caution :P
+    return @linters.reduce((promise, linter) =>
+      if helpers.shouldTriggerLinter(linter, true, onChange, scopes)
+        return promise.then(-> linter.lint(editor)).then((vals) =>
+          if vals then @emitter.emit('did-update-messages', {linter, messages: vals, editor})
+        ).catch (e) -> helpers.error(e)
+      else return promise
+    , Promise.resolve()).then( =>
+      Promises = []
+      @linters.forEach (linter) =>
+        return unless helpers.shouldTriggerLinter(linter, false, onChange, scopes)
+        try result = linter.lint(editor) catch e then return helpers.error(e)
+        unless result instanceof Promise
+          result = Promise.resolve(result)
+        result.then (vals) =>
+          if vals then @emitter.emit('did-update-messages', {linter, messages: vals, editor})
+      return Promise.all(Promises)
+    ).then =>
+      @locks[lockKey].delete(editorLinter)
+
+  onDidUpdateMessages: (callback) ->
+    return @emitter.on('did-update-messages', callback)
+
+  deactivate: ->
+    @emitter.dispose()
+    @linters = []
+
+module.exports = LinterRegistry


Don't show errors on xhr aborts due to page refreshes

--- SingularityUI/app/application.coffee
+++ SingularityUI/app/application.coffee
@@ -41,8 +41,14 @@
         Object.freeze? @

     setupGlobalErrorHandling: ->
+        unloading = false
+
+        $(window).on 'beforeunload', ->
+            unloading = true
+            return
+
         $(document).on 'ajaxError', (event, jqxhr, settings) ->
-            if not settings.suppressErrors and jqxhr.statusText isnt 'abort'
+            if not settings.suppressErrors and jqxhr.statusText isnt 'abort' and not unloading
                 vex.dialog.alert "
A #{ jqxhr.statusText } error occurred when trying to access:

#{ settings.url }

The request had status code #{ jqxhr.status }.

Here's the full jqxhr object:

#{ utils.htmlEncode utils.stringJSON jqxhr }
"

     show: (view) ->


added support for old versions of defineLift usage

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


Do not use WebView and drawers.update

Do not use WebView and drawers.update

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


- browserStore save and load via UI is mostly functionnal (but potentially buggy)  * added _dispatchEvent wrapper around backbone.marionette's vent system, so any pubsub system can be used  * now correctly passing the main appvent instance to browserStore at creation time in coffeescad.app  * pubsub events are now dispatched correctly from browserStore via the _dispatchEvent method (with gracefull failure in case no pubsub system was specified)  * save and load thus seem to work correctly, but as the browserView is very messy right now , will need some checks

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

--- dropBoxStore2.coffee
+++ dropBoxStore2.coffee
@@ -0,0 +1,407 @@
+define (require)->
+  #base64 = require 'base64'
+  buildProperties = require 'core/utils/buildProperties'
+  backbone_dropbox = require './backbone.dropbox'
+  vent = require 'core/messaging/appVent'
+  reqRes = require 'core/messaging/appReqRes'
+
+  Project = require 'core/projects/project'
+
+  class DropBoxLibrary extends Backbone.Collection
+    """
+    a library contains multiple projects, stored on dropbox
+    """
+    #model: Project
+    #sync: backbone_dropbox.sync
+    path: ""
+    defaults:
+      recentProjects: []
+
+    constructor:(options)->
+      super options
+      #@bind("reset", @onReset)
+
+    comparator: (project)->
+      date = new Date(project.get('lastModificationDate'))
+      return date.getTime()
+
+    onReset:()->
+      console.log "DropBoxLibrary reset"
+      console.log @
+      console.log "_____________"
+
+  class DropBoxStore extends Backbone.Model
+    attributeNames: ['name','loggedIn','isDataDumpAllowed']
+    buildProperties @
+
+    idAttribute: 'name'
+    defaults:
+      name: "DropboxStore"
+      storeType: "Dropbox"
+      tooltip:"Store to the Dropbox Cloud based storage: requires login"
+      loggedIn:false
+      isDataDumpAllowed:false
+
+    constructor:(options)->
+      super options
+      @debug = true
+
+      @store = new backbone_dropbox()
+      @isLogginRequired = true
+      @vent = vent
+
+      @vent.on("DropboxStore:login", @login)
+      @vent.on("DropboxStore:logout", @logout)
+
+      #experimental
+      @lib = new DropBoxLibrary
+        sync: @store.sync
+      @lib.sync = @store.sync
+
+      #should this be here ?
+      @projectsList = []
+      @cachedProjects = {}
+      #handler for project/file data fetch requests
+      reqRes.addHandler("getdropboxFileOrProjectCode",@_sourceFetchHandler)
+
+    login:=>
+      try
+        onLoginSucceeded=()=>
+          localStorage.setItem("dropboxCon-auth",true)
+          @loggedIn = true
+          @vent.trigger("DropboxStore:loggedIn")
+          console.lo
+
+        onLoginFailed=(error)=>
+          throw error
+
+        loginPromise = @store.authentificate()
+        $.when(loginPromise).done(onLoginSucceeded)
+                            .fail(onLoginFailed)
+      catch error
+        @vent.trigger("DropboxStore:loginFailed")
+
+    logout:=>
+      try
+        onLogoutSucceeded=()=>
+          localStorage.removeItem("dropboxCon-auth")
+          @loggedIn = false
+          @vent.trigger("DropboxStore:loggedOut")
+        onLoginFailed=(error)=>
+          throw error
+
+        logoutPromise = @store.signOut()
+        $.when(logoutPromise).done(onLogoutSucceeded)
+                            .fail(onLogoutFailed)
+
+      catch error
+        @vent.trigger("DropboxStore:logoutFailed")
+
+    authCheck:()->
+      getURLParameter=(paramName)->
+        searchString = window.location.search.substring(1)
+        i = undefined
+        val = undefined
+        params = searchString.split("&")
+        i = 0
+        while i < params.length
+          val = params[i].split("=")
+          return unescape(val[1])  if val[0] is paramName
+          i++
+        null
+      urlAuthOk = getURLParameter("_dropboxjs_scope")
+      #console.log "dropboxStore got redirect param #{urlAuthOk}"
+
+      authOk = localStorage.getItem("dropboxCon-auth")
+      #console.log "dropboxStore got localstorage Param #{authOk}"
+
+
+      if urlAuthOk?
+        @login()
+        appBaseUrl = window.location.protocol + '//' + window.location.host + window.location.pathname
+        window.history.replaceState('', '', appBaseUrl)
+      else
+        if authOk?
+          @login()
+
+    getProjectsName:(callback)=>
+      #hack
+      if @store.client?
+        @store.client.readdir "/", (error, entries) =>
+          if error
+            console.log ("error")
+          else
+            @projectsList = entries
+            if callback?
+              callback(entries)
+
+    getProject:(projectName)=>
+      #console.log "locating #{projectName} in @projectsList"
+      #console.log @projectsList
+      if projectName in @projectsList
+        return @loadProject(projectName,true)
+      else
+        return null
+
+    getProjectFiles:(projectName)=>
+      #returns all files in a project
+      d = $.Deferred()
+      if @store.client?
+        @store.client.readdir "/#{projectName}/", (error, entries) =>
+          if error
+            d.reject(error)
+          else
+            d.resolve(entries)
+       else
+        d.reject(error)
+      return d
+
+    getProjectFiles2:(projectName)=>
+      return @store.client.readdir "/#{projectName}/"
+
+    getProjectFile:(projectName, fileName)=>
+
+
+    getThumbNail:(projectName)=>
+      myDeferred = $.Deferred()
+      deferred = @store._readFile( "/#{projectName}/.thumbnail.png",{arrayBuffer:true})
+
+      parseBase64Png=( rawData)->
+        #convert binary png to base64
+        bytes = new Uint8Array(rawData)
+        data = ''
+        for i in [0...bytes.length]
+          data += String.fromCharCode(bytes[i])
+        data =   btoa(data)
+        #crashes
+        #data = btoa(String.fromCharCode.apply(null, ))
+        base64src='data:image/png;base64,'+data
+        myDeferred.resolve(base64src)
+
+      deferred.done(parseBase64Png)
+      return myDeferred
+
+    checkProjectExists:(projectName)=>
+      return @store._readDir "/#{projectName}/"
+
+    createProject:(fileName)=>
+      #project = @lib.create(options)
+      project = new Project
+        name: fileName
+      project.rootFolder.sync = @store.sync
+      project.rootFolder.path = project.get("name")
+
+      project.createFile
+        name: fileName
+      project.createFile
+        name: "config"
+
+      #FIXME: have one event for both create & load, as in effect , they do the same thing ? (reset views, replace current)
+      #@vent.trigger("project:created",project)
+      @vent.trigger("project:loaded",project)
+
+
+    saveProject:(project, newName)=>
+      console.log "saving projectto dropbox"
+      project.collection = null
+      @lib.add(project)
+      if newName?
+        project.name = newName
+      project.dataStore = @
+
+      filesList = []
+      for index, file of project.rootFolder.models
+        #actual saving of file, not json INSIDE the file
+        projectName = project.name
+        name = file.name
+        content =file.content
+        filePath = "#{projectName}/#{name}"
+        filesList.push(file.name)
+        ext = name.split('.').pop()
+        if ext == "png"
+          #save thumbnail
+          dataURIComponents = content.split(',')
+          mimeString = dataURIComponents[0].split(':')[1].split(';')[0]
+          if(dataURIComponents[0].indexOf('base64') != -1)
+            console.log "base64 v1"
+            data =  atob(dataURIComponents[1])
+            array = []
+            for i in [0...data.length]
+              array.push(data.charCodeAt(i))
+            content = new Blob([new Uint8Array(array)], {type: 'image/png'})
+          else
+            console.log "other v2"
+            byteString = unescape(dataURIComponents[1])
+            length = byteString.length
+            ab = new ArrayBuffer(length)
+            ua = new Uint8Array(ab)
+            for i in [0...length]
+              ua[i] = byteString.charCodeAt(i)
+        file.trigger("save")
+        console.log "saving file to #{filePath}"
+        @store.writeFile(filePath, content)
+
+      #fetch old list of files, for diff, delete old file if not present anymore
+      ###
+      oldFiles = @projectsList
+      added = _.difference(filesList,oldFiles)
+      removed = _.difference(oldFiles,filesList)
+      console.log "added",added
+      console.log "removed", removed
+      @_removeFile(projectName, fileName) for fileName in removed
+      ###
+
+      @vent.trigger("project:saved")
+
+    saveProject_:(project,newName)=>
+      console.log "saving projectto dropbox"
+      project.collection = null
+      @lib.add(project)
+      if newName?
+        project.name = newName
+      project.sync = @store.sync
+      project.rootFolder.sync = project.sync
+      project.rootFolder.path = project.name
+      #project.rootFolder.changeStorage("dropboxDataStore",{path:project.name})
+      project.save()
+      ###
+      for index, file of project.rootFolder.models
+        #file.pathRoot= project.get("name")
+        #file.save()
+
+        #actual saving of file, not json hack
+        projectName = project.name
+        name = file.name
+        content =file.content
+        filePath = "#{projectName}/#{name}"
+        ext = name.split('.').pop()
+        if ext == "png"
+          #save thumbnail
+          dataURIComponents = content.split(',')
+          console.log "dataURIComponents"
+          console.log dataURIComponents
+          mimeString = dataURIComponents[0].split(':')[1].split(';')[0]
+          if(dataURIComponents[0].indexOf('base64') != -1)
+            data =  atob(dataURIComponents[1])
+            array = []
+            for i in [0...data.length]
+              array.push(data.charCodeAt(i))
+            content = new Blob([new Uint8Array(array)], {type: 'image/jpeg'})
+          else
+            byteString = unescape(dataURIComponents[1])
+            length = byteString.length
+            ab = new ArrayBuffer(length)
+            ua = new Uint8Array(ab)
+            for i in [0...length]
+              ua[i] = byteString.charCodeAt(i)
+          file.trigger("save")
+        console.log "saving file to #{filePath}"
+        @store.writeFile(filePath, content)
+        ###
+      @vent.trigger("project:saved")
+
+    loadProject:(projectName,silent=false)=>
+      d = $.Deferred()
+      if projectName in @projectsList
+        console.log "dropbox loading project #{projectName}"
+        @lib.add(project)
+
+        project = new Project()
+        project.name = projectName
+
+        onProjectLoaded=()=>
+          thumbNailFile = project.rootFolder.get(".thumbnail.png")
+          project.rootFolder.remove(thumbNailFile)
+          project._clearFlags()
+          if not silent
+            @vent.trigger("project:loaded",project)
+          d.resolve(project)
+
+        project.dataStore = @
+        project.rootFolder.rawData = true
+        project.rootFolder.sync = @store.sync
+        project.rootFolder.path = projectName
+
+        project.rootFolder.fetch().done(onProjectLoaded)
+      else
+        @checkProjectExists(projectName)
+        .fail(()=>d.fail(new Error("Project #{projectName} not found")))
+        .done ()=>
+          @projectsList.push(projectName)
+          @loadProject(projectName)
+
+      return d
+
+    deleteProject:(projectName)=>
+      index = @projectsList.indexOf(projectName)
+      @projectsList.splice(index, 1)
+      return @store.remove("/#{projectName}")
+
+    destroyFile:(projectName, fileName)=>
+      return @store.remove("#{projectName}/#{fileName}")
+
+    renameProject:(oldName, newName)=>
+      #move /rename project and its main file
+      index = @projectsList.indexOf(oldName)
+      @projectsList.splice(index, 1)
+      @projectsList.push(newName)
+      return @store.move(oldName,newName).done(@store.move("/#{newName}/#{oldName}.coffee","/#{newName}/#{newName}.coffee"))
+
+    _removeFile:(projectName, fileName)=>
+      return @store.remove("#{projectName}/#{fileName}")
+
+    _sourceFetchHandler:([store, projectName, path, deferred])=>
+      #This method handles project/file content requests and returns appropriate data
+      if store != "dropbox"
+        return null
+      console.log "handler recieved #{store}/#{projectName}/#{path}"
+      result = ""
+      if not projectName? and path?
+        shortName = path
+        #console.log "proj"
+        #console.log @project
+        file = @project.rootFolder.get(shortName)
+        result = file.content
+        result = "\n#{result}\n"
+      else if projectName? and not path?
+        console.log "will fetch project #{projectName}'s namespace"
+        project = @getProject(projectName)
+        console.log project
+        namespaced = {}
+        for index, file of project.rootFolder.models
+          namespaced[file.name]=file.content
+
+        namespaced = "#{projectName}={"
+        for index, file of project.rootFolder.models
+          namespaced += "#{file.name}:'#{file.content}'"
+        namespaced+= "}"
+        #namespaced = "#{projectName}="+JSON.stringify(namespaced)
+        #namespaced = """#{projectName}=#{namespaced}"""
+        result = namespaced
+
+      else if projectName? and path?
+        console.log "will fetch #{path} from #{projectName}"
+        getContent=(project) =>
+          #cache for faster access: TODO: clear cache
+          @cachedProjects[projectName]=project
+          file = project.rootFolder.get(path)
+
+          #now we replace all "local" (internal to the project includes) with full path includes
+          result = file.content
+          result = result.replace /(?!\s*?#)(?:\s*?include\s*?)(?:\(?\"([\w\//:'%~+#-.*]+)\"\)?)/g, (match,matchInner) =>
+            includeFull = matchInner.toString()
+            return """\ninclude("dropbox:#{projectName}/#{includeFull}")\n"""
+
+          result = "\n#{result}\n"
+          deferred.resolve(result)
+
+        if not (projectName of @cachedProjects)
+          @loadProject(projectName,true).done(getContent)
+        else
+          getContent(@cachedProjects[projectName])
+
+
+
+      return result
+
+  return DropBoxStore


add est

add est

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

--- data/points/est.coffee
+++ data/points/est.coffee
@@ -0,0 +1,12 @@
+id: "est"
+title: "est 基于LESS的样式工具库"
+language: [ "css" ]
+function: [ "layout-framework" ]
+relevance: [ "less", "archer" ]
+homepage: "http://ecomfe.github.io/est/"
+github: "https://github.com/ecomfe/est"
+desc: """
+est 是一个基于 LESS 的样式工具库，帮助您更轻松地书写 LESS 代码。
+
+est 提供了一系列方便快捷的 mixin，只在调用时才输出代码。est 不希望提供直接给 HTML 调用的类名，用「样式类」污染 HTML 代码的语义。当然您也可以根据自己的项目需求基于 est 搭建样式类库，提供类名接口来进行快速开发。
+"""


remove reset style on paragraph during reply

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


Tests: Added activity post test.

Tests: Added activity post test.

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


More specs for Brush

More specs for Brush

--- spec/javascripts/player/brush_spec.js.coffee
+++ spec/javascripts/player/brush_spec.js.coffee
@@ -8,19 +8,65 @@
       AsciiIo.Brush.clearCache()
       expect(_(AsciiIo.Brush.cache).keys().length).toEqual(0)

+  describe '.hash', ->
+
+    it 'returns string with all brush properties', ->
+      attrs =
+        fg       : 1
+        bg       : 2
+        blink    : false
+        bright   : true
+        italic   : false
+        underline: true
+
+      hash = AsciiIo.Brush.hash attrs
+      expect(hash).toEqual '1_2_false_true_false_true'
+
   describe '.create', ->

     beforeEach ->
       AsciiIo.Brush.clearCache()

     it 'returns new brush instance if not cached', ->
-      brush = AsciiIo.Brush.create({ fg: 1})
+      brush = AsciiIo.Brush.create({ fg: 1 })
       expect(brush instanceof AsciiIo.Brush).toBeTruthy()

     it 'returns existing brush instance if cached', ->
-      brush = AsciiIo.Brush.create({ fg: 1})
+      brush = AsciiIo.Brush.create({ fg: 1 })
       otherBrush = AsciiIo.Brush.create({ fg: 1, bg: 100 })
-      anotherBrush = AsciiIo.Brush.create({ fg: 1})
+      anotherBrush = AsciiIo.Brush.create({ fg: 1 })

       expect(_(AsciiIo.Brush.cache).keys().length).toEqual(2)
       expect(brush is anotherBrush).toBeTruthy()
+
+  describe '#fgColor', ->
+
+    it 'returns 7 if fg is undefined', ->
+      brush = new AsciiIo.Brush fg: undefined
+      expect(brush.fgColor()).toEqual 7
+
+    it 'returns fg+8 if bright is on', ->
+      brush = new AsciiIo.Brush fg: 3, bright: true
+      expect(brush.fgColor()).toEqual 11
+
+  describe '#bgColor', ->
+
+    it 'returns 0 if bg is undefined', ->
+      brush = new AsciiIo.Brush bg: undefined
+      expect(brush.bgColor()).toEqual 0
+
+    it 'returns bg+8 if blink is on', ->
+      brush = new AsciiIo.Brush bg: 4, blink: true
+      expect(brush.bgColor()).toEqual 12
+
+  describe '#attributes', ->
+
+    it 'includes fg, bg, blink, bright, italic, underline', ->
+      brush = new AsciiIo.Brush
+      attrs = brush.attributes()
+      expectedAttrs = ['fg', 'bg', 'blink', 'bright', 'italic', 'underline']
+
+      expect(_(attrs).keys().length).toEqual _(expectedAttrs).keys().length
+
+      for attr in expectedAttrs
+        expect(_(attrs).has(attr)).toBeTruthy()


Update static/vendors/morrisjs/spec/lib/label_series_spec.coffee

Signed-off-by: Bernard Ojengwa <fccb4cc00c1ba7e51bf5c2b5f77130b9fe8d917e@gmail.com>

error: pathspec 'static/vendors/morrisjs/spec/lib/label_series_spec.coffee' did not match any file(s) known to git


fix(index): disabled select profile if user is null

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


Tidied up and documented (properly this time)

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


Helpscout: move user information to top [completes #80326092]


Add benchmarks for text rendering

Add benchmarks for text rendering

--- benchmark/benchmark-suite.coffee
+++ benchmark/benchmark-suite.coffee
@@ -9,7 +9,6 @@
     window.rootViewParentSelector = '#jasmine-content'
     window.rootView = new RootView
     window.rootView.attachToDom()
-

     rootView.width(1024)
     rootView.height(768)
@@ -60,6 +59,24 @@
         editor.insertText('"')
         editor.backspace()

+    describe "text-rendering.", ->
+      beforeEach ->
+        editor.scrollTop(200)
+
+      benchmark "resetDisplay", 20, ->
+        editor.resetDisplay()
+
+      benchmark "htmlForScreenRows", 50, ->
+        lastRow = editor.getLastScreenRow()
+        editor.htmlForScreenRows(0, lastRow)
+
+      benchmark "htmlForScreenRows.htmlParsing", 20, ->
+        lastRow = editor.getLastScreenRow()
+        html = editor.htmlForScreenRows(0, lastRow)
+
+        div = document.createElement('div')
+        div.innerHTML = html
+
   describe "9000-line-file.", ->
     benchmark "opening.", 5, ->
       rootView.open('huge.js')


Systems now autosave too in the level editor.

--- app/views/editor/level/systems_tab_view.coffee
+++ app/views/editor/level/systems_tab_view.coffee
@@ -30,6 +30,7 @@
     for system in @buildDefaultSystems()
       url = "/db/level.system/#{system.original}/version/#{system.majorVersion}"
       ls = new LevelSystem()
+      ls.saveBackups = true
       do (url) -> ls.url = -> url
       continue if @supermodel.getModelByURL ls.url
       ls.fetch()


Add specialized participant heads for IDE chat


Start using new elixir formatter instead of credo

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


revert last changes

revert last changes

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


Add backbone notification model

Add backbone notification model

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

--- app/assets/javascripts/admin/models/notification.js.coffee
+++ app/assets/javascripts/admin/models/notification.js.coffee
@@ -0,0 +1,8 @@
+Augury.Models.Notification = Backbone.Model.extend(
+  initialize: ->
+    @urlRoot = "/stores/#{Augury.store_id}/notifications"
+
+  toJSON: ->
+    @attributes = _.omit(@attributes, ['id'])
+    return notification: _(@attributes).clone()
+)


Show dates for income/expenses.

Show dates for income/expenses.

[Delivers #52051297]

--- client/helpers/payments.coffee
+++ client/helpers/payments.coffee
@@ -70,7 +70,7 @@
     ea = accounting.formatMoney expense.amount
     {
       optionValue: expense._id
-      optionText: "#{expense.description} (#{ear} of #{ea} remaining)"
+      optionText: "#{expense.dueDate} — #{expense.description} (#{ear} of #{ea} remaining)"
       selected: if expense._id is @expenseId then true else false
     }

@@ -87,7 +87,7 @@
     ia = accounting.formatMoney income.amount
     {
       optionValue: income._id
-      optionText: "#{income.description} (#{iar} of #{ia} remaining)"
+      optionText: "#{income.receiptDate} — #{income.description} (#{iar} of #{ia} remaining)"
       selected: if income._id is @incomeId then true else false
     }


Make Payment entry with keyboard faster.

[Delivers #54962584.]

--- client/helpers/payments.coffee
+++ client/helpers/payments.coffee
@@ -142,6 +142,21 @@
       if not error
         clearFormFields $context
         showNavSuccess "New payment added."
+
+        # Set up the form for the next payment to be created, if applicable
+        $expense = elementByName('expenseId', $context)
+        newPayment = Payments.findOne result
+        paymentExpense = Expenses.findOne newPayment.expenseId
+        console.log "Expense: #{paymentExpense}. Remaining: #{paymentExpense.amountRemaining}"
+        if paymentExpense
+          if (Math.abs(accounting.formatMoney paymentExpense.amountRemaining)) isnt 0.00
+            $expense.val(paymentExpense._id)
+            # Focus on income since we'll be wanting to add a payment with a different income
+            (elementByName 'incomeId', $context).focus()
+            return;
+
+        # Focus on expense if we haven't early-returned
+        $expense.focus()
       else
         showNavError "There was a problem adding the new payment. Please try again. If the problem persists, contact us."
         console.log error
@@ -178,6 +193,13 @@
     event.preventDefault();
     Session.set 'editingPayment', null

+  'change [name="expenseId"]': (event) ->
+    $context = $(event.target).parents('.add-record-form')
+    expenseId = valByName('expenseId', $context)
+    incomeId = valByName('incomeId', $context)
+    # Jump to income dropdown if not chosen yet
+    if expenseId and not incomeId then (elementByName 'incomeId', $context).focus()
+
   'change [name="incomeId"], change [name="expenseId"]': (event) ->
     $context = $(event.target).parents('.add-record-form')
     expenseId = valByName('expenseId', $context)


Adding G U Y S ?

Adding G U Y S ?

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

--- scripts/guys.coffee
+++ scripts/guys.coffee
@@ -0,0 +1,3 @@
+module.exports = (robot) ->
+  robot.hear /guys/i, (res) ->
+    res.send "G U Y S ?"


Add GitHub search example

Add GitHub search example

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

--- examples/github.coffee
+++ examples/github.coffee
@@ -0,0 +1,15 @@
+feature "GitHub search", (context, browser, $) ->
+  before (done) -> browser.visit 'https://github.com/search', done
+
+  it "finds WebSpecter", (done) ->
+    $('input[name=q]').fill 'webspecter'
+    $(button: 'Search').click ->
+      $(link: "jgonera / webspecter").present.should.be.true
+      done()
+
+  it "looks only for users when asked to", (done) ->
+    $('input[name=q]').fill 'webspecter'
+    $(field: 'Search for').select 'Users'
+    $(button: 'Search').click ->
+      $(link: "jgonera / webspecter").present.should.be.false
+      done()


Teams: Dashboard: AdminAppView create panes based on the NAV_ITEMS data in opts.

--- client/admin/lib/adminappview.coffee
+++ client/admin/lib/adminappview.coffee
@@ -29,7 +29,7 @@
     @setListeners()

-  setListeners:->
+  setListeners: ->

     @on 'groupSettingsUpdated', (group)->
       @setData group
@@ -54,20 +54,34 @@

   createTabs: ->

-    data = @getData()
+    data         = @getData()
+    {tabData}    = @getOptions()
+    currentGroup = kd.singletons.groupsController.getCurrentGroup()

-    kd.singletons.appManager.tell 'Admin', 'fetchTabData', (tabData) =>
+    items = []

-      for {name, hiddenHandle, viewOptions, kodingOnly}, i in tabData
+    for own sectionKey, section of tabData

-        viewOptions.data    = data
-        viewOptions.options = delegate : this  if name is 'Settings'
-        hiddenHandle        = hiddenHandle? and data.privacy is 'public'
-        pane                = new KDTabPaneView {name, viewOptions}
+      if sectionKey is 'koding' and currentGroup.slug isnt 'koding'
+        continue

-        @tabs.addPane pane, i is 0
+      items = items.concat section.items

-      @emit 'ready'
+
+    items.forEach (item, i) =>
+
+      { viewClass, slug, title } = item
+
+      pane = new KDTabPaneView name: slug
+      pane.addSubView new viewClass
+        cssClass : slug
+        delegate : this
+      , data
+
+      @tabs.addPane pane, i is 0
+
+    @emit 'ready'
+

   search: (searchValue)->


Debug operators

Debug operators

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/Morgan9195/language-script.git/'


client: home: added billing initial

client: home: added billing initial

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

--- client/home/lib/billing/index.coffee
+++ client/home/lib/billing/index.coffee
@@ -0,0 +1,31 @@
+kd                   = require 'kd'
+
+
+# SECTIONS =
+#   'Invite Using Slack' : HomeTeamConnectSlack
+#   'Send Invites'       : HomeTeamSendInvites
+#   Teammates            : HomeTeamTeammates
+
+# section = (name, options, data) ->
+#   new (SECTIONS[name] or kd.View) options or {
+#     tagName  : 'section'
+#     cssClass : "HomeAppView--section #{kd.utils.slugify name}"
+#   }, data
+
+
+module.exports = class HomeTeamBilling extends kd.View
+
+  constructor: (options = {}, data) ->
+
+    super options, data
+
+    { groupsController } = kd.singletons
+
+    @addSubView scrollView = new kd.CustomScrollView
+      cssClass : 'HomeAppView--scroller'
+
+    { wrapper } = scrollView
+
+    # wrapper.addSubView section 'Invite Using Slack'
+    # wrapper.addSubView section 'Send Invites'
+    # wrapper.addSubView section 'Teammates', null, team


Use theme.reload event to reload the theme stylesheets

--- src/app/atom.coffee
+++ src/app/atom.coffee
@@ -57,6 +57,9 @@

   loadPackages: ->
     @loadPackage(name) for name in @getAvailablePackageNames() when not @isPackageDisabled(name)
+    @themes.on 'reload', =>
+      pack.reloadStylesheets?() for name, pack of @loadedPackages
+      null

   loadPackage: (name, options) ->
     if @isPackageDisabled(name)


Working JS dashboard data fetcher

Working JS dashboard data fetcher

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

--- dashboard_spec.coffee
+++ dashboard_spec.coffee
@@ -0,0 +1,27 @@
+#= require dashboard
+#= require mock-ajax
+
+describe "Dashboard - getData()", ->
+  beforeEach ->
+    @dashboard = Dashboard
+    jasmine.Ajax.useMock()
+
+  describe "when the report is ready on the first iteration", ->
+    it "should return the dashboard data", ->
+      that = this
+
+      @dashboard.getData 'lesson_leaders', {}, (data) ->
+        that.data = data
+
+      request = mostRecentAjaxRequest()
+      expect(request.url).toBe('/dashboard/queries')
+      expect(request.method).toBe('POST')
+      request.response { status: 200, responseText: '{"id": "REPORT_ID" }' }
+
+      waits(1000)
+
+      runs ->
+        request = mostRecentAjaxRequest()
+        request.response { status: 200, responseText: '{"is_ready": true, "data":"DATA" }' }
+
+        expect(that.data).toEqual 'DATA'


Destroy repo in an afterEach in Git specs

--- spec/app/git-spec.coffee
+++ spec/app/git-spec.coffee
@@ -2,9 +2,13 @@
 fs = require 'fs'

 describe "Git", ->
+  repo = null

   beforeEach ->
     fs.remove('/tmp/.git') if fs.isDirectory('/tmp/.git')
+
+  afterEach ->
+    repo.destroy() if repo?.repo?

   describe "@open(path)", ->
     it "returns null when no repository is found", ->
@@ -71,7 +75,7 @@
         expect(repo.isPathModified(newPath)).toBeFalsy()

   describe ".isPathNew(path)", ->
-    [repo, path, newPath] = []
+    [path, newPath] = []

     beforeEach ->
       repo = new Git(require.resolve('fixtures/git/working-dir'))
@@ -90,7 +94,7 @@
         expect(repo.isPathNew(path)).toBeFalsy()

   describe ".checkoutHead(path)", ->
-    [repo, path1, path2, originalPath1Text, originalPath2Text] = []
+    [path1, path2, originalPath1Text, originalPath2Text] = []

     beforeEach ->
       repo = new Git(require.resolve('fixtures/git/working-dir'))
@@ -129,7 +133,7 @@
       expect(-> repo.getHead()).toThrow()

   describe ".getDiffStats(path)", ->
-    [repo, path, originalPathText] = []
+    [path, originalPathText] = []

     beforeEach ->
       repo = new Git(require.resolve('fixtures/git/working-dir'))


Stop watchers in an afterEach block

Stop watchers in an afterEach block

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


multiple -> allowMultiple

multiple -> allowMultiple

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


faster install

faster install

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


Implements Subscriptions collection

Implements Subscriptions collection

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

--- collections/subscriptions.coffee
+++ collections/subscriptions.coffee
@@ -0,0 +1,5 @@
+{ API_URL } = require('sharify').data
+Collection = require './base.coffee'
+
+module.exports = class Subscriptions extends Collection
+  url: "#{API_URL}/account/customer/subscriptions"


Fix crash

Fix crash

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


removed app.format

removed app.format

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/0xenvision/negotiator-inator.git/'


Add MathML test

Add MathML test

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

--- spec/mathml-spec.coffee
+++ spec/mathml-spec.coffee
@@ -0,0 +1,20 @@
+Mathematical = require('../lib/mathematical')
+
+describe "MathML", ->
+  mathematical = null
+
+  it "returns mathml", ->
+    string = """
+    $$
+\\begin{pmatrix}
+     1 & a_1 & a_1^2 & \\cdots & a_1^n \\\\
+     1 & a_2 & a_2^2 & \\cdots & a_2^n \\\\
+     \\vdots  & \\vdots& \\vdots & \\ddots & \\vdots \\\\
+     1 & a_m & a_m^2 & \\cdots & a_m^n
+     \\end{pmatrix}
+$$
+"""
+
+    mathematical = new Mathematical(format: "mathml")
+    mathml = mathematical.render(string)["mathml"]
+    expect(mathml).toMatch("<math xmlns='http:\/\/www.w3.org\/1998\/Math\/MathML' display='block'><semantics><mrow><mrow><mo>\(")


Load package relative to the package's spec directory

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -35,7 +35,15 @@
 jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of equality for toEqual assertions
 jasmine.getEnv().defaultTimeoutInterval = 5000

-specDirectory = atom.getLoadSettings().specDirectory ? __dirname
+specPackageName = null
+specPackagePath = null
+
+if specDirectory = atom.getLoadSettings().specDirectory
+  specPackagePath = path.resolve(specDirectory, '..')
+  try
+    specPackageName = fs.readObjectSync(path.join(specPackagePath, 'package.json'))?.name
+else
+  specDirectory = __dirname
 specProjectPath = path.join(specDirectory, 'fixtures')

 beforeEach ->
@@ -48,6 +56,14 @@
   spyOn(atom, 'saveWindowState')
   atom.syntax.clearGrammarOverrides()
   atom.syntax.clearProperties()
+
+  if specPackageName
+    spy = spyOn(atom.packages, 'resolvePackagePath').andCallFake (packageName) ->
+      if packageName is specPackageName
+        resolvePackagePath(specPackagePath)
+      else
+        resolvePackagePath(packageName)
+    resolvePackagePath = _.bind(spy.originalValue, atom.packages)

   # used to reset keymap after each spec
   bindingSetsToRestore = _.clone(keymap.bindingSets)


Add Set::isEqual method in specs

Add Set::isEqual method in specs

This allows us to use the .toEqual matcher to compare Set
objects.

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -48,6 +48,25 @@
 Object.defineProperty document, 'title',
   get: -> documentTitle
   set: (title) -> documentTitle = title
+
+Set.prototype.jasmineToString = ->
+  result = "Set {"
+  first = true
+  @forEach (element) ->
+    result += ", " unless first
+    result += element.toString()
+  first = false
+  result + "}"
+
+Set.prototype.isEqual = (other) ->
+  if other instanceof Set
+    return false if @size isnt other.size
+    values = @values()
+    until (next = values.next()).done
+      return false unless other.has(next.value)
+    true
+  else
+    false

 jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of equality for toEqual assertions


Update enableKeymap spec helper

Update enableKeymap spec helper

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -303,7 +303,11 @@
   event.result

 $.fn.enableKeymap = ->
-  @on 'keydown', (e) -> atom.keymaps.handleKeyboardEvent(e.originalEvent)
+  @on 'keydown', (e) ->
+    originalEvent = e.originalEvent ? e
+    Object.defineProperty(originalEvent, 'target', get: -> e.target) unless originalEvent.target?
+    atom.keymaps.handleKeyboardEvent(originalEvent)
+    not e.originalEvent.defaultPrevented

 $.fn.attachToDom = ->
   @appendTo($('#jasmine-content'))


Created invitation class for invitation related methods

error: pathspec 'workers/social/lib/social/models/graph/invitation.coffee' did not match any file(s) known to git

--- workers/social/lib/social/models/graph/invitation.coffee
+++ workers/social/lib/social/models/graph/invitation.coffee
@@ -0,0 +1,75 @@
+{Graph} = require './index'
+QueryRegistry = require './queryregistry'
+
+module.exports = class Invitation extends Graph
+
+  @fetchInvitations = (options, callback)->
+    {groupId, status, timestamp, requestLimit, search} = options
+
+    queryOptions =
+      groupId    : groupId
+      limitCount : requestLimit or 10
+
+    regexSearch    = ""
+    timeStampQuery = ""
+
+    if search
+      # search = search.replace(/[^\w\s@.+-]/).replace(/([+.]+)/g, "\\$1").trim()
+      search = search.replace(/[^\w\s@.+-]/).trim()
+      regexSearch = "AND groupOwnedNodes.email =~ \".*#{search}.*\""
+
+    if timestamp?
+      timeStampQuery = "AND groupOwnedNodes.requestedAt > \"#{timestamp}\""
+
+    if typeof status is "string" then status = [status]
+
+    # convert status array into string representation
+    status   = "[\"" + status.join("\",\"") + "\"]"
+
+    query = QueryRegistry.invitation.list status, timeStampQuery, regexSearch
+
+    @fetch query, queryOptions, (err, results)=>
+      console.log "arguments"
+      console.log arguments
+      if err then return callback err
+      if results.length < 1 then return callback null, []
+      @generateInvitations [], results, (err, data)=>
+        console.log "err.data"
+        console.log err, data
+        if err then callback err
+        @revive data, (revived)->
+          console.log "revived"
+          console.log revived
+          callback null, revived
+
+#      JInvitationRequest = require '../invitationrequest'
+#      tempRes = []
+#      collectContents = race (i, res, fin)=>
+#        objId = res.groupOwnedNodes.data.id
+#        JInvitationRequest.one  { _id : objId }, (err, invitationRequest)=>
+#          if err
+#            callback err
+#            fin()
+#          else
+#            tempRes[i] = invitationRequest
+#            fin()
+#      , ->
+#        callback null, tempRes
+#
+#      for res in results
+#        collectContents res
+
+  @generateInvitations:(resultData, results, callback)=>
+    console.log "generate inviations arguments"
+    console.log arguments
+    if results? and results.length < 1 then return callback null, resultData
+    result = results.shift()
+    console.log "result"
+    console.log result
+    @objectify result.groupOwnedNodes.data, (objected)=>
+      console.log "objected"
+      console.log objected
+      resultData.push objected
+      @generateInvitations resultData, results, callback
+
+


add daisy-chained aliases (fixes #17)

add daisy-chained aliases (fixes #17)

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


Adding pagerduty_points plugin.

Adding pagerduty_points plugin.

This plugin overloads the pgareduty script to track and display
how many minutes different users have scheduled overrides.

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

--- src/scripts/pagerduty_points.coffee
+++ src/scripts/pagerduty_points.coffee
@@ -0,0 +1,59 @@
+# Description:
+#   Overloads pagerduty plugin commands to record and display
+#   override points for different users.
+#
+# Dependencies:
+#   None
+#
+# Configuration:
+#   None
+#
+# Commands:
+#   hubot pager me <number> - award <number> points to the user
+#   hubot pager me points - should current points
+#
+# Notes:
+#
+# Author:
+#   nstielau
+#
+#
+# Thanks for brettlangdon and monde for their points plugin:
+# https://github.com/github/hubot-scripts/blob/master/src/scripts/points.coffee
+
+pager_points = {}
+
+award_points = (msg, username, pts) ->
+    pager_points[username] ?= 0
+    pager_points[username] += parseInt(pts)
+
+save = (robot) ->
+    robot.brain.data.pager_points = pager_points
+
+module.exports = (robot) ->
+    robot.brain.on 'loaded', ->
+        points = robot.brain.data.pager_points or {}
+
+    # Catch override requests, and award points
+    robot.respond /pager( me)? (\d+)/i, (msg) ->
+        email = msg.message.user.pagerdutyEmail
+        minutes = parseInt msg.match[2]
+        award_points(msg, email, minutes)
+        save(robot)
+
+    # Show current point scoreboard
+    robot.respond /pager( me)? points/i, (msg) ->
+        for username, user_points of pager_points
+            if username and user_points:
+                msg.send username + ' has ' + user_points + ' override minutes clocked'
+
+    # DEBUG: helper for testing without the pagerduty plugin
+    robot.respond /pager(?: me)? as (.*) for points/i, (msg) ->
+      email = msg.match[1]
+      unless msg.message.user.pagerdutyEmail
+        msg.message.user.pagerdutyEmail = email
+
+    # DEBUG: Clear points
+    robot.respond /pager( me)? clear points/i, (msg) ->
+        pager_points = {}
+        save(robot)


DOM query helpers with closest implmentation

Walks up the tree until it finds an element that matches the selector

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

--- src/helpers/dom.coffee
+++ src/helpers/dom.coffee
@@ -0,0 +1,13 @@
+module.exports = {
+
+  matches: (el, selector) ->
+    method = el.matches or el.mozMatchesSelector or el.msMatchesSelector or el.oMatchesSelector or el.webkitMatchesSelector
+    method?.call(el, selector)
+
+
+  closest: (el, selector) ->
+    return null unless el
+    if @matches(el, selector) then el else (el.querySelector(selector) or @closest(el.parentNode, selector))
+
+
+}


Fix query for bid_history...

Fix query for bid_history...

--- apps/user/components/bid_history/query.coffee
+++ apps/user/components/bid_history/query.coffee
@@ -3,15 +3,15 @@
     me {
       bidder_positions(current: false) {
         id
-        highest_bid {
-          display_amount_dollars
-        }
         is_winning
         sale_artwork {
           id
           lot_number
           bidder_positions_count
           sale_id
+          highest_bid {
+            amount_cents
+          }
           artwork {
             href
             title
@@ -25,5 +25,5 @@
         }
       }
     }
-}
+  }
 """


Add temporary stringscore shim to exports

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

--- exports/stringscore.coffee
+++ exports/stringscore.coffee
@@ -0,0 +1 @@
+module.exports = require '../vendor/stringscore'


upd: test

upd: test

--- test/lab.coffee
+++ test/lab.coffee
@@ -1,7 +1,11 @@
 Promise = require '../src/yaku'
 utils = require '../src/utils'

-utils.async 2, ->
-	new Promise (r) ->
-		console.log 'tick'
-		setTimeout r, 1000
+list = [
+    -> utils.sleep 10, 1
+    -> throw 10
+    -> utils.sleep 10, 3
+]
+
+utils.async 2, list
+.catch (err) -> err


:memo: Update CSON documentation link in snippets.cson

--- dot-atom/snippets.cson
+++ dot-atom/snippets.cson
@@ -18,4 +18,4 @@
 # This file uses CoffeeScript Object Notation (CSON).
 # If you are unfamiliar with CSON, you can read more about it in the
 # Atom Flight Manual:
-# https://atom.io/docs/latest/using-atom-basic-customization#cson
+# http://flight-manual.atom.io/using-atom/sections/basic-customization/#_cson


Protect against failure to load MathJax

Protect against failure to load MathJax

- e.g. if on a train and don't have access to S3 or the rest of the web

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


Fixed: Maximum call stack size exceeded error during patch of big calendars on low memory device. Refs #312

--- server/models/event.coffee
+++ server/models/event.coffee
@@ -153,7 +153,8 @@
             callback()
         else
             async.eachLimit events, 10, (event, done) ->
-                event.migrateDoctype -> event.patchTag done
+                event.migrateDoctype -> event.patchTag ->
+                    setImmediate done
             , callback

 Event.bulkCalendarRename = (oldName, newName, callback) ->


Get model provider instance from app provider set.

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


fix [github] overlay for files that are moved+changed

--- src/coffee/github.coffee
+++ src/coffee/github.coffee
@@ -130,6 +130,7 @@
         # find covered file
         fp = self.file or file.find('.file-info>span[title]').attr('title')
         if fp
+          fp = fp.split('→')[1].trim() if '→' in fp
           file_data = report.files[fp]

           # assure button group


Clean log

Clean log

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


Return early when no candidates exist

Return early when no candidates exist

--- src/module-cache.coffee
+++ src/module-cache.coffee
@@ -121,6 +121,9 @@
   return if relativePath[0] is '.'
   return if isAbsolute(relativePath)

+  candidates = cache.dependencies[relativePath]
+  return unless candidates?
+
   folderPath = path.dirname(parentModule.filename)

   range = cache.folders[folderPath]?[relativePath]
@@ -130,9 +133,6 @@
     else
       return

-  candidates = cache.dependencies[relativePath]
-  return unless candidates?
-
   for version, resolvedPath of candidates
     if Module._cache.hasOwnProperty(resolvedPath) or isCorePath(resolvedPath)
       return resolvedPath if satisfies(version, range)


add setting for 'ally (xml)' comment, resolve #19

error: pathspec 'settings/language-alloy.cson' did not match any file(s) known to git


Generate ASAR archives by default

Generate ASAR archives by default

--- build/Gruntfile.coffee
+++ build/Gruntfile.coffee
@@ -209,12 +209,12 @@

   ciTasks = ['output-disk-space', 'build-atom-shell', 'bower:install', 'build', 'generate-license']
   ciTasks.push('dump-symbols') if process.platform isnt 'win32'
-  ciTasks.push('set-version', 'check-licenses', 'lint')
+  ciTasks.push('set-version', 'check-licenses', 'lint', 'generate-asar')
   ciTasks.push('mkdeb') if process.platform is 'linux'
   ciTasks.push('create-windows-installer') if process.platform is 'win32'
   ciTasks.push('test') if process.platform is 'darwin'
   ciTasks.push('codesign')
   grunt.registerTask('ci', ciTasks)

-  defaultTasks = ['build-atom-shell', 'bower:install', 'build', 'set-version']
+  defaultTasks = ['build-atom-shell', 'bower:install', 'build', 'set-version', 'generate-asar']
   grunt.registerTask('default', defaultTasks)


console.log again

console.log again


add github.cson

add github.cson

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


Remove unused package require

Remove unused package require

--- src/theme-manager.coffee
+++ src/theme-manager.coffee
@@ -7,7 +7,6 @@
 {$} = require './space-pen-extensions'
 AtomPackage = require './atom-package'
 File = require './file'
-Package = require './package'

 # Private: Handles discovering and loading available themes.
 #


Sort user list by admin first, then by username

--- app/assets/javascripts/backbone/plugins/user_list.js.coffee
+++ app/assets/javascripts/backbone/plugins/user_list.js.coffee
@@ -15,7 +15,9 @@
     $users = $("

")
     $el.next().hide();

-    for user in Kandan.Data.ActiveUsers.all()
+    users = _(Kandan.Data.ActiveUsers.all()).chain().sortBy("username").reverse().sortBy("is_admin").reverse().value();
+
+    for user in users
       displayName   = null
       displayName   = user.username # Defaults to username
       displayName ||= user.email # Revert to user email address if that's all we have


message particularity for folder and media files + improvements

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/tracersoft/mediadrawer-rails.git/'


tests: add tests for common functions for sort options

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

--- test/common/sort.coffee
+++ test/common/sort.coffee
@@ -0,0 +1,38 @@
+require 'should'
+common = require '../../lib/common'
+
+describe 'Test helper functions for sort options', () ->
+
+  it 'determine ascending option values', () ->
+    true.should.equal common.isAscVal 1
+    true.should.equal common.isAscVal '1'
+    true.should.equal common.isAscVal 'asc'
+    true.should.equal common.isAscVal 'ascending'
+    false.should.equal common.isAscVal null
+    false.should.equal common.isAscVal 0
+    false.should.equal common.isAscVal 'desc'
+
+  it 'determine descending option values', () ->
+    true.should.equal common.isDescVal -1
+    true.should.equal common.isDescVal '-1'
+    true.should.equal common.isDescVal 'desc'
+    true.should.equal common.isDescVal 'descending'
+    false.should.equal common.isDescVal null
+    false.should.equal common.isDescVal 0
+    false.should.equal common.isDescVal '1'
+
+  ASC = 'a'
+  DESC = 'b'
+
+  it 'format sort values as specified', () ->
+    formatter = common.makeSortValueFormatter ASC, DESC
+    ASC.should.equal formatter 1
+    ASC.should.equal formatter 'ASC'
+    DESC.should.equal formatter 'descending'
+    DESC.should.equal formatter 'deSCEndINg'
+
+  it 'throw error for invalid sort values', () ->
+    formatter = common.makeSortValueFormatter ASC, DESC
+    formatter.bind(null, 0).should.throw()
+    formatter.bind(null, null).should.throw()
+    formatter.bind(null, 'banana').should.throw()


brb - natural availability tracking

brb - natural availability tracking

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

--- src/scripts/brb.coffee
+++ src/scripts/brb.coffee
@@ -0,0 +1,34 @@
+# Description:
+#   Natural availability tracking.
+#
+# Dependencies:
+#   None
+#
+# Configuration:
+#   None
+#
+# Commands:
+#   brb
+#
+# Author:
+#   jmhobbs
+
+module.exports = (robot) ->
+
+	users_away = {}
+
+	robot.hear( /./i, (msg) ->
+		if users_away[msg.message.user.name] and msg.message.text != 'brb'
+			msg.send "Welcome back " + msg.message.user.name + "!"
+			delete users_away[msg.message.user.name]
+		else
+			for user, state of users_away
+				substr = msg.message.text.substring(0, user.length+1)
+				if substr == user + ':'
+					msg.send user + " is currently away."
+					break
+		)
+
+	robot.hear /brb/i, (msg) ->
+		users_away[msg.message.user.name] = true
+


Add atom prefix to project

Add atom prefix to project

--- spec/editor-view-spec.coffee
+++ spec/editor-view-spec.coffee
@@ -277,7 +277,7 @@
     it "emits event when editor view view receives a new buffer", ->
       eventHandler = jasmine.createSpy('eventHandler')
       editorView.on 'editor:path-changed', eventHandler
-      editorView.edit(project.openSync(filePath))
+      editorView.edit(atom.project.openSync(filePath))
       expect(eventHandler).toHaveBeenCalled()

     it "stops listening to events on previously set buffers", ->
@@ -285,7 +285,7 @@
       oldBuffer = editorView.getBuffer()
       editorView.on 'editor:path-changed', eventHandler

-      editorView.edit(project.openSync(filePath))
+      editorView.edit(atom.project.openSync(filePath))
       expect(eventHandler).toHaveBeenCalled()

       eventHandler.reset()
@@ -1481,7 +1481,7 @@

     describe "when autoscrolling at the end of the document", ->
       it "renders lines properly", ->
-        editorView.edit(project.openSync('two-hundred.txt'))
+        editorView.edit(atom.project.openSync('two-hundred.txt'))
         editorView.attachToDom(heightInLines: 5.5)

         expect(editorView.renderedLines.find('.line').length).toBe 8
@@ -2236,7 +2236,7 @@
     beforeEach ->
       filePath = atom.project.resolve('git/working-dir/file.txt')
       originalPathText = fs.readFileSync(filePath, 'utf8')
-      editorView.edit(project.openSync(filePath))
+      editorView.edit(atom.project.openSync(filePath))

     afterEach ->
       fs.writeFileSync(filePath, originalPathText)
@@ -2369,7 +2369,7 @@
       fs.removeSync(filePath) if fs.existsSync(filePath)

     it "updates all the rendered lines when the grammar changes", ->
-      editorView.edit(project.openSync(filePath))
+      editorView.edit(atom.project.openSync(filePath))
       expect(editorView.getGrammar().name).toBe 'Plain Text'
       atom.syntax.setGrammarOverrideForPath(filePath, 'source.js')
       editorView.reloadGrammar()
@@ -2389,7 +2389,7 @@
       expect(editorView.getGrammar().name).toBe 'JavaScript'

     it "emits an editor:grammar-changed event when updated", ->
-      editorView.edit(project.openSync(filePath))
+      editorView.edit(atom.project.openSync(filePath))

       eventHandler = jasmine.createSpy('eventHandler')
       editorView.on('editor:grammar-changed', eventHandler)


Append to last commit

Append to last 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/CO-OPEN/Mangos.git/'


jenkins script function for starting a jenkins shell script.   creates event listener for use elsewhere

error: pathspec 'hubot-scripts/jenkins-script.coffee' did not match any file(s) known to git

--- hubot-scripts/jenkins-script.coffee
+++ hubot-scripts/jenkins-script.coffee
@@ -0,0 +1,55 @@
+# Description:
+#   creates event handler to start jenkins scripts
+#
+# Dependencies:
+#   "querystring"
+#   "http-status"
+#
+# Configuration:
+#   HUBOT_JENKINS_URL - url to your jenkins server
+#   HUBOT_JENKINS_AUTH - set to "user:pass" for your jenkins server
+#
+# Commands:
+#
+# Notes:
+#
+# Author:
+#   rexroof
+
+_qs = require 'querystring'
+_hs = require 'http-status'
+
+jenkinsScript = ( script, params, msg ) ->
+  if process.env.HUBOT_JENKINS_URL
+    url = process.env.HUBOT_JENKINS_URL
+  else
+    msg.reply "HUBOT_JENKINS_URL is not set"
+    return
+  url += "/job/jenkins-script/buildWithParameters?"
+  params.SK_CHANNEL = msg.message.room
+  params.SK_REPLY = msg.message.user.name
+  query_params =
+    JENK_SCRIPT: script
+    JSON_OPTIONS: new Buffer(JSON.stringify(params)).toString('base64')
+  url += ("#{_qs.escape k}=#{_qs.escape v}" for k,v of query_params).join('&')
+
+  request = msg.http(url)
+  if process.env.HUBOT_JENKINS_AUTH
+    auth = new Buffer(process.env.HUBOT_JENKINS_AUTH).toString('base64')
+    request.headers Authorization: "Basic #{auth}"
+  request.header('Content-Length', 0)
+  request.post() (err,res,body) ->
+    if err
+      msg.reply "Jenkins error: #{err}"
+    else
+      msg.repy "reqest for jenkins-script:#{script} sent to jenkins (status #{res.statusCode} #{_hs[res.statusCode]})"
+
+
+module.exports = (robot) ->
+  # you can use this in other scripts with
+  #   robot.emit "jenkins-script", "scriptname.sh", parameters, msg
+  #   note if 'robot' is out of scope you can also use msg.robot.emit
+  robot.on "jenkins-script", (_script, _params, _msg) ->
+    jenkinsScript(_script, _params, _msg)
+
+


Added filters test

Added filters test

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

--- test/filters.coffee
+++ test/filters.coffee
@@ -0,0 +1,69 @@
+describe "Filters", ->
+  it "should provide :coffeescript", ->
+    template = makeTemplate """
+      :coffeescript
+        a = "jawsome"
+      %div(type=a)
+    """
+
+    behave template(), ->
+      assert.equal Q("div").getAttribute("type"), "jawsome"
+
+  it "should provide :javascript", ->
+    template = makeTemplate """
+      :javascript
+        a = "jawsome";
+      %div(type=a)
+    """
+
+    behave template(), ->
+      assert.equal Q("div").getAttribute("type"), "jawsome"
+
+  describe ":verbatim", ->
+    it "should keep text verbatim", ->
+      template = makeTemplate """
+        %textarea
+          :verbatim
+            <I> am <verbatim> </text>
+      """
+
+      behave template(), ->
+        assert.equal Q("textarea").value, "<I> am <verbatim> </text>"
+
+    it "should work with indentation", ->
+      template = makeTemplate """
+        :verbatim
+          Hey
+            It's
+              Indented
+
+      """
+
+      behave template(), ->
+        # TODO: This probably shouldn't have a trailing \n
+        assert.equal Q("body").textContent, "Hey\n  It's\n    Indented\n"
+
+    it "should work with indentation without extra trailing whitespace"
+    # TODO
+    ->
+      template = makeTemplate """
+        :verbatim
+          Hey
+            It's
+              Indented
+      """
+
+      behave template(), ->
+        assert.equal Q("body").textContent, "Hey\n  It's\n    Indented"
+
+    it "should work with \"\"\"", ->
+      template = makeTemplate """
+        :verbatim
+          sample = \"\"\"
+            Hey
+          \"\"\"
+
+      """
+
+      behave template(), ->
+        assert.equal Q("body").textContent, "sample = \"\"\"\n  Hey\n\"\"\"\n"


Add nickname to ember person model

Add nickname to ember person model

[#101668990]

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


very basic testing

very basic testing

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

--- spec/juno-spec.coffee
+++ spec/juno-spec.coffee
@@ -0,0 +1,18 @@
+juno = require '../lib/julia-client'
+
+# Testing-specific settings
+juno.connection.process.jlpath = -> "julia"
+juno.connection.process.workingDir = -> process.env.HOME || process.env.USERPROFILE
+
+describe "package activation", ->
+  it "activates without errors", ->
+    waitsForPromise ->
+      atom.packages.activatePackage 'ink'
+    waitsForPromise ->
+      atom.packages.activatePackage 'julia-client'
+
+describe "basic client interaction", ->
+  it "boots a julia client", ->
+    waitsForPromise ->
+      juno.connection.boot().then (pong) ->
+        expect(pong).toBe 'pong'


added test for auto-format

added test for auto-format

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


Code cleanup WIP.

Code cleanup WIP.

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/OnCircle/gbox-video-player.git/'


widget must stop loading before format/chart draw

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


Using req.get '...' instead of req.headers['...'] to prevent problems with case.

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


Disable Atom-LaTeX and LaTeXTools keymaps

They were conflicting with the default "Select Line" keybinding.

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


Add peatix command

Add peatix command

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

--- scripts/peatix.coffee
+++ scripts/peatix.coffee
@@ -0,0 +1,99 @@
+# Description:
+#   Peatix の情報を peatix-crawler へ問い合わせる
+#
+# Commands:
+#   hubot イベント情報 - 対話モードでイベントの一覧や情報を呼び出す
+#
+# Configuration:
+#   PEATIX_CRAWLER_URL - peatix-crawler の URL
+#   PEATIX_CRAWLER_API_TOKEN - peatix-crawler の API キー
+
+request = require 'request'
+moment = require 'moment'
+_ = require "underscore"
+numeral = require "numeral"
+Path = require "path"
+Dialog = require Path.join __dirname, "..", "src", "dialog"
+
+module.exports = (robot) ->
+
+  return unless process.env.PEATIX_CRAWLER_API_TOKEN and
+     process.env.PEATIX_CRAWLER_URL
+
+  class PeatixEvent
+    constructor: (data) ->
+      @data = data
+
+    past: ->
+      moment(@data.datetime).isBefore moment()
+
+    pastString: ->
+      if @past
+        "終了"
+      else
+        "未開催"
+
+    income: ->
+      income_total = 0
+      _.each(@data.tickets, (t) =>
+        income_total += @parse_income(t.subtotal_display)
+      )
+      income_total
+
+    parse_income: (income_display) ->
+      parseInt(income_display.replace(/¥|,/gi, ""), 10)
+
+    incomeToString: ()->
+      "¥" + numeral(@income()).format '0,0'
+
+    toString: (short=false)->
+      if short
+        buffer =  "*#{@data.name}* "
+        buffer += "（#{@pastString()}） "
+        buffer += "#{@data.dashboard_uri}"
+      else
+        buffer =  "*#{@data.name}*\n"
+        buffer += "開催日：#{@data.datetime} （#{@pastString()}）\n"
+        buffer += "チケット：#{@data.seats_sold} / #{@data.seats_total} \n"
+        buffer += "売り上げ：#{@incomeToString()}\n"
+        buffer += "管理画面：#{@data.dashboard_uri}\n"
+        buffer += "#{@data.banner_thumbnail}"
+      buffer
+
+  eventsToString = (events) ->
+    (_.map events, (event, i) ->
+      "#{i+1} : #{event.toString true}"
+    ).join "\n"
+
+  robot.respond /イベント情報/i, (msg) ->
+
+    msg.send "イベント情報を問い合せ中です。。。"
+    peatix_crawler_url = process.env.PEATIX_CRAWLER_URL
+    peatix_crawler_token = process.env.PEATIX_CRAWLER_API_TOKEN
+    url = "#{peatix_crawler_url}/api/events" +
+      "?token=#{peatix_crawler_token}"
+    request url, (err, res, body) =>
+      if !err and res.statusCode is 200
+        events = JSON.parse body
+        events = _.map(events, (e) ->
+          new PeatixEvent e
+        )
+        msg.send "#{events.length}件のイベントが見つかりました。\n" +
+          eventsToString(events) + "\n" +
+          "何番のイベントの詳細を見ますか？[番号/見ない]"
+        dialog = new Dialog msg, (msg) ->
+          text = msg.envelope.message.text
+          if /(\d+)/i.test text
+            index = parseInt(RegExp.$1, 10)-1
+            if events[index]
+              event = events[index]
+              msg.send event.toString()
+            msg.send "他には？\n" +
+              eventsToString(events) + "\n" +
+              "何番のイベントの詳細を見ますか？[番号/見ない]"
+          else if /^((見)?ない|(終|お)わり|おしまい)$/i.test text
+            msg.send "またご利用ください。"
+            @end
+        Dialog.listen robot
+      else
+        msg.send "失敗しました。"