Add DocMap

Add DocMap

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

--- src/DocMap.coffee
+++ src/DocMap.coffee
@@ -0,0 +1,81 @@
+# A map of documents. Useful for caching documents to avoid hitting the collection.
+class DocMap
+
+  constructor: (options) ->
+    @_options = Setter.merge({
+      # Whether to freeze all documents added to the temporary collection/map to ensure
+      # immutability for direct access (faster).
+      freeze: true
+      # Whether to use a plain map instead of a temporary collection. Faster since nothing needs
+      # to be cloned, but is not reactive and selectors cannot be used on the underlying collection.
+      plain: false
+    }, options)
+    @_collection = if @_options.plain then {} else Collections.createTemporary()
+    @_handles = []
+
+  # Adds the given documents to the map.
+  #   * `arg` - A cursor, collection, array or document.
+  #   * `options.beforeInsert` - A function which is passed each document in the given cursor before
+  #         it is inserted into the collection. If false is returned by this function, the
+  #         insert is cancelled. Only used if the first argument is a colleciton or cursor.
+  add: (arg, options) ->
+    if Collections.isCursor(arg) or Collections.isCollection(arg)
+      if @_options.plain
+        return _.map Collections.getItems(arg), (doc) => @_insert(doc)
+      else
+        promise = Collections.copy arg, @_collection,
+          track: true
+          beforeInsert: options?.beforeInsert
+          afterInsert: (id) => @_maybeFreeze @get(id)
+        @_handles.push @_collection.trackHandle
+        return promise
+    else if Types.isArray(arg)
+      return _.map arg, (doc) => @_insert(doc)
+    else if Types.isObjectLiteral(arg)
+      return @_insert(arg)
+    else
+      throw new Error('Unsupported type - must be doc or cursor')
+
+  _insert: (doc) ->
+    if @_options.plain
+      id = doc._id
+      unless id then throw new Error('Inserted doc in plain map must have ID')
+      @_collection[id] = doc
+    else
+      id = @_collection.insert(doc)
+    @_maybeFreeze @get(id)
+    return id
+
+  _maybeFreeze: (doc) -> if @_options.freeze then Object.freeze(doc) else doc
+
+  get: (id) -> if @_options.plain then @_collection[id] else @_collection._collection._docs.get(id)
+
+  getAll: -> _.values @_getMap()
+
+  getMap: -> _.extend {}, @_getMap()
+
+  _getMap: -> if @_options.plain then @_collection else @_collection._collection._docs._map
+
+  forEach: (callback) -> _.each @_getMap(), callback
+
+  has: (id) -> if @_options.plain then @_collection[id]? else @_collection._collection._docs.has(id)
+
+  remove: (selectorOrId) ->
+    if @_options.plain
+      if @has(selectorOrId)
+        delete @_collection[selectorOrId]
+        1
+      else 0
+    else
+      # TODO(aramk) Will still recieve updates from copy() even if document is removed here.
+      @_collection.remove(selectorOrId)
+
+  size: -> if @_options.plain then _.size(@_collection) else @_collection._collection._docs.size()
+
+  getCollection: -> unless @_options.plain then @_collection
+
+  reset: -> _.each @_handles, (handle) -> handle.stop()
+
+  destroy: ->
+    # TODO(aramk) Add any destructive logic here.
+    @reset()


Added Atom keymap

Added Atom keymap

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


Non-admins can save (but not overwrite) file uploads.

--- server/routes/file.coffee
+++ server/routes/file.coffee
@@ -19,7 +19,7 @@
     objectId = mongoose.Types.ObjectId(path)
     query = objectId
   catch e
-    path = path.split('/')
+    path = path.split('/')
     filename = path[path.length-1]
     path = path[...path.length-1].join('/')
     query =
@@ -34,7 +34,7 @@
         res.setHeader('Content-Type', 'text/json')
         res.send(results)
         res.end()
-
+
   else
     Grid.gfs.collection('media').findOne query, (err, filedata) =>
       return errors.notFound(res) if not filedata
@@ -42,7 +42,7 @@
       if req.headers['if-modified-since'] is filedata.uploadDate
         res.status(304)
         return res.end()
-
+
       res.setHeader('Content-Type', filedata.contentType)
       res.setHeader('Last-Modified', filedata.uploadDate)
       res.setHeader('Cache-Control', 'public')
@@ -70,7 +70,7 @@
   required: ['filename', 'mimetype', 'path']

 filePost = (req, res) ->
-  return errors.forbidden(res) unless req.user?.isAdmin()
+  return errors.forbidden(res) unless req.user
   options = req.body
   tv4 = require('tv4').tv4
   valid = tv4.validate(options, postFileSchema)
@@ -83,7 +83,8 @@

 saveURL = (req, res) ->
   options = createPostOptions(req)
-  checkExistence options, res, req.body.force, (err) ->
+  force = req.user.isAdmin() and req.body.force
+  checkExistence options, res, force, (err) ->
     return errors.serverError(res) if err
     writestream = Grid.gfs.createWriteStream(options)
     request(req.body.url).pipe(writestream)
@@ -91,7 +92,8 @@

 saveFile = (req, res) ->
   options = createPostOptions(req)
-  checkExistence options, res, req.body.force, (err) ->
+  force = req.user.isAdmin() and req.body.force
+  checkExistence options, res, force, (err) ->
     return if err
     writestream = Grid.gfs.createWriteStream(options)
     f = req.files[req.body.postName]
@@ -101,7 +103,8 @@

 savePNG = (req, res) ->
   options = createPostOptions(req)
-  checkExistence options, res, req.body.force, (err) ->
+  force = req.user.isAdmin() and req.body.force
+  checkExistence options, res, force, (err) ->
     return errors.serverError(res) if err
     writestream = Grid.gfs.createWriteStream(options)
     img = new Buffer(req.body.b64png, 'base64')
@@ -143,11 +146,11 @@
   unless req.body.name
     name = req.body.filename.split('.')[0]
     req.body.name = _.str.humanize(name)
-
+
   path = req.body.path or ''
   path = path[1...] if path and path[0] is '/'
   path = path[...path.length-2] if path and path[path.length-1] is '/'
-
+
   options =
     mode: 'w'
     filename: req.body.filename
@@ -158,6 +161,6 @@
       name: req.body.name
       path: path
       creator: ''+req.user._id
-  options.metadata.description = req.body.description if req.body.description?
+  options.metadata.description = req.body.description if req.body.description?

   options


import components

import components

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

--- app/assets/javascripts/components.js.coffee
+++ app/assets/javascripts/components.js.coffee
@@ -0,0 +1,5 @@
+React = require('react')
+App = require("./components/app")
+
+$(document).ready ->
+  React.renderComponent(App(null), document.body)


Use joinTo value for sorting

Use joinTo value for sorting

--- src/fs_utils/generate.coffee
+++ src/fs_utils/generate.coffee
@@ -22,11 +22,12 @@
     criteria = [
       config.before ? []
       config.after ? []
+      config.joinToValue ? []
       config.bower ? []
       config.component ? []
       config.vendorConvention ? -> no
     ]
-    anysort.grouped files, criteria, [0, 2, 3, 4, 5, 1]
+    anysort.grouped files, criteria, [0, 2, 3, 4, 5, 6, 1]
   else
     files

@@ -51,11 +52,12 @@
   component = packageInfo.component.order
   {before, after, vendorConvention, bower, component}

-sort = (files, config) ->
+sort = (files, config, joinToValue) ->
   paths = files.map (file) -> file.path
   indexes = Object.create(null)
   files.forEach (file, index) -> indexes[file.path] = file
   order = extractOrder files, config
+  order.joinToValue = joinToValue
   sortByConfig(paths, order).map (path) ->
     indexes[path]

@@ -118,7 +120,8 @@
     'stylesheet'
   optimizers = optimizers.filter((optimizer) -> optimizer.type is type)

-  sorted = sort sourceFiles, config
+  joinToValue = config.files["#{type}s"].joinTo[path[config.paths.public.length+1..]]
+  sorted = sort sourceFiles, config, joinToValue

   {code, map} = concat sorted, path, type, config._normalized.modules.definition, config._normalized.packageInfo['component'].aliases


Sanitize value of input type select. Fixes #303.

--- core/htdocs_source/src/pods/oxisection-form/component.coffee
+++ core/htdocs_source/src/pods/oxisection-form/component.coffee
@@ -9,6 +9,10 @@

         for f in fields
             f.placeholder = "" if typeof f.placeholder is "undefined"
+
+            # needed for Firefox, see #303
+            if f.type is "select" and f.value is null
+                f.value = ""

         clonables = (f for f in fields when f.clonable)
         names = []


Small fix oops

Small fix oops

--- views/double-tabareas.cjsx
+++ views/double-tabareas.cjsx
@@ -56,6 +56,7 @@
       detail:
         visible: true
     window.dispatchEvent event
+    @handleSelectLeft 0
   handleSelectShipView: ->
     event = new CustomEvent 'view.main.visible',
       bubbles: true
@@ -63,6 +64,7 @@
       detail:
         visible: false
     window.dispatchEvent event
+    @handleSelectLeft 0
   handleCtrlOrCmdTabKeyDown: ->
     @handleSelect [(@state.key[0] + 1) % 1, @state.key[1]]
   handleCtrlOrCmdNumberKeyDown: (num) ->


fix admin login jump

fix admin login jump

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


Issue 432: Fixing issue where the noprojects message was appearing out of context.

--- app/assets/javascripts/projects.js.coffee
+++ app/assets/javascripts/projects.js.coffee
@@ -1,5 +1,6 @@
 $ ->
   projects = $('#projects').clone()
+  $('#noprojects').hide()

   languages = []
   $('#languages a').click (e) ->
@@ -39,9 +40,9 @@
       $('#someprojects').show()
     return false

-
   resetLanguage = ->
     $('#languages li').removeClass('disabled')
     $('#projects').html(projects.find('.project'))
     projects = $('#projects').clone()
     $('#projects').css('height', 'auto')
+    resetMoreButton()


made classes for each field type, add aggregation for array, more methods for Counter

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

--- fields.coffee
+++ fields.coffee
@@ -0,0 +1,187 @@
+_ = require "underscore"
+
+# Constants
+
+NO_VALUE = ->
+INIT_FIELD = ->
+
+illegalInputException = (input) ->
+  @message = "Attempted input: " + input
+  @name = "IllegalInputException"
+
+notImplementedException = ->
+  @name = "NotImplementedException"
+
+# utilities
+
+# @todo: augment Counter for each subclass of Fields
+# e.g. NumberCounter may have methods such as min, max, mean, medium
+class Counter
+  @merge: (c1, c2) ->
+    ret = new Counter()
+    ret.put(k, c1.get(k)) for k in c1.keys()
+    ret.put(k, c2.get(k)) for k in c2.keys()
+    ret
+  constructor: (initial) ->
+    @dict = {}
+    @put(initial) if initial?
+  get: (key) ->
+    if key of @dict
+      @dict[key]
+    else
+      @put(key, 0)
+  put: (key, val=1) ->
+    if key of @dict
+      @dict[key] += val
+    else
+      @dict[key] = val
+  keys: ->
+    Object.keys(@dict)
+  #below are poorly implemented (for now) utility methods
+  flatten: ->
+    list = []
+    for key, count of @dict
+      list.push(key) while count--
+    list
+  sortByCounts: ->
+    _.sortBy _.pairs(@dict), (tuple) ->
+      -tuple[1]
+  toString: ->
+    "[Object Counter<#{@sortByCounts}>]"
+
+# Fields definitions
+
+class Field
+  @type = NO_VALUE
+  @build = (val, key) ->
+    cnst = resolveCnst val
+    new cnst val, key
+  @aggregate = (f1, f2) ->
+    return f2 if f1 is INIT_FIELD
+    return f1 if f2 is INIT_FIELD
+    if f1.type is f2.type
+      return CNST[f1.type].aggregate(f1, f2)
+    throw notImplementedException()
+  constructor: (val, key, @type) ->
+    throw illegalInputException("type") unless @type in TYPES
+    # @todo: add variable @hint
+    # guess the possible function of the Field based on @type, key, val
+  toSchema: ->
+    # @todo: returns schema description file conforming to application/json+schema
+    throw notImplementedException()
+  toString: ->
+    "[Object Field]"
+
+class NullField extends Field
+  @type = "null"
+  @aggregate: (n1, n2) ->
+    new NullField()
+  constructor: (val, key) ->
+    super val, key, @constructor.type
+
+class BooleanField extends Field
+  @type = "boolean"
+  @aggregate: (b1, b2) ->
+    ret = new BooleanField()
+    ret._counter = Counter.merge(b1._counter, b2._counter)
+    ret
+  constructor: (bool, key) ->
+    super bool, key, @constructor.type
+    @_counter = new Counter(bool)
+
+class NumberField extends Field
+  @type = "number"
+  @aggregate: (n1, n2) ->
+    ret = new NumberField()
+    ret._counter = Counter.merge(n1._counter, n2._counter)
+    ret
+  constructor: (num, key) ->
+    super num, key, @constructor.type
+    @_counter = new Counter(num)
+
+class StringField extends Field
+  @type = "string"
+  @aggregate: (s1, s2) ->
+    ret = new StringField()
+    ret._counter = Counter.merge(s1._counter, s2._counter)
+    ret
+  constructor: (str, key) ->
+    super str, key, @constructor.type
+    @pattern = NO_VALUE
+    @_counter = new Counter(str)
+
+class ArrayField extends Field
+  @type = "array"
+  @aggregate: (a1, a2) ->
+    ret = new ArrayField()
+    ret.items = Field.aggregate(a1.items, a2.items)
+    ret
+  constructor: (ar=[], key) ->
+    super ar, key, @constructor.type
+    items = (Field.build(item) for item in ar)
+    @items = items.reduce(Field.aggregate, INIT_FIELD)
+
+class ObjectField extends Field
+  @type = "object"
+  @aggregate: (o1, o2) ->
+    ret = new ObjectField()
+    ret.required = _.intersection(o1.required, o2.required)
+    ret._pCounter = Counter.merge(o1._pCounter, o2._pCounter)
+    props = _.union(Object.keys(o1.properties),
+                    Object.keys(o2.properties))
+    for prop in props
+      p1 = o1.properties[prop] ? INIT_FIELD
+      p2 = o2.properties[prop] ? INIT_FIELD
+      ret.properties[prop] = Field.aggregate(p1, p2)
+    ret
+  constructor: (obj={}, key) ->
+    super obj, key, @constructor.type
+    @required = []
+    @properties = {}
+    @_pCounter = new Counter()
+    for k, v of obj
+      @_pCounter.put(k)
+      @required.push(k)
+      @properties[k] = Field.build(v, k)
+
+class ComplexField extends Field
+  constructor: ->
+    # @todo: handle fields with heterogenous datatypes
+    throw notImplementedException()
+
+# CONSTANTS
+
+CNST =
+  number: NumberField
+  null: NullField
+  string: StringField
+  array: ArrayField
+  object: ObjectField
+  boolean: BooleanField
+
+TYPES = (v.type for k, v of CNST)
+
+# helpers
+
+resolveCnst = (obj) ->
+  switch typeof obj
+    when "number" then CNST.number
+    when "boolean" then CNST.boolean
+    when "string" then CNST.string
+    when "object"
+      if obj is null
+        return CNST.null
+      if Array.isArray obj
+        return CNST.array
+      CNST.object
+    else throw illegalInputException "type"
+
+module.exports =
+  Counter: Counter
+  Field: Field
+  NumberField: NumberField
+  NullField: NullField
+  BooleanField: BooleanField
+  StringField: StringField
+  ArrayField: ArrayField
+  ObjectField: ObjectField


Added an isObject function

Added an isObject function

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


chat: add extra checks for new user on settings pane

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


Fix beatmapset cover thumbnail url in profile page

--- resources/assets/coffee/react/profile-page/historical.coffee
+++ resources/assets/coffee/react/profile-page/historical.coffee
@@ -41,7 +41,7 @@
       div
         className: 'beatmapset-row__cover'
         style:
-          backgroundImage: "url('#{bmset.coverUrl}')"
+          backgroundImage: "url('#{bmset.covers.list}')"
       div
         className: 'beatmapset-row__detail'
         div


fixes #290

fixes #290

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


Bettered batch setter.

Bettered batch setter.

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


Tests: Added an element into mochaContainer when tests finished.

--- client/testrunner/lib/routehandler.coffee
+++ client/testrunner/lib/routehandler.coffee
@@ -29,6 +29,11 @@
     addToHead 'script', jsOptions, ->
       mocha.ui('bdd')
       mochaTests = require './require-tests'
-      mocha.run()
+      runner = mocha.run()

+      runner.on 'end', ->
+        el           = document.createElement 'div'
+        el.id        = 'tests-completed'
+        el.innerHTML = 'All tests finished'

+        mochaContainer.appendChild el


removed unnecessary coffeescript file

removed unnecessary coffeescript file

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


Need more arrays. Yes. More arrays. More. All your arrays. All your memory. Nomnomnomnomnomnom.

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


initial commit - ability to respond to custom answers - ability to teach something to the bot - ability to say something randomly - ability to forget what learned

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

--- src/scripts/talkative.coffee
+++ src/scripts/talkative.coffee
@@ -0,0 +1,79 @@
+# Respond to custom answers
+# - say something about <topic> - will say something he knows about the subject
+# - when asked <regexp_of_question> answer <response> - teach your bot to answer to <regexp_of_question> with <response>
+# - forget answers - remove every teached answer from bot brain
+
+module.exports = (robot) ->
+
+  basic_knowledge = {
+    1: {regexp: "(what( is|'s))?( your)? favorite( programming)? language", answer: 'CoffeeScript'},
+    2: {regexp: 'favorite (os|operating system|platform)', answer: 'Linux'}
+  }
+
+  respondToAnswer = (item) ->
+    robot.respond new RegExp(item.regexp, 'i'), (msg) ->
+      for key, item of robot.brain.data.knowledge
+        break if msg.match[0].replace(robot.name,'').match new RegExp(item.regexp, 'i')
+      msg.send item.answer if item?.answer?
+
+  knowledgeAbout = (subject) ->
+    for key, item of robot.brain.data.knowledge
+      if subject.replace(robot.name,'').match new RegExp(item.regexp, 'i')
+        found = true ; break
+    if found == true
+      @.key = key ; @.item = item
+      return @
+    else
+      return null
+
+  robot.brain.on 'loaded', =>
+    console.log "Loading knowledge"
+    robot.brain.data.knowledge ?= {}
+
+    robot.brain.data.knowledge = basic_knowledge if Object.keys(robot.brain.data.knowledge).length == 0
+    for key, item of robot.brain.data.knowledge
+      respondToAnswer(item)
+
+  robot.respond /(when )?asked (.*) (reply|answer|return|say) (.*)$/i, (msg) ->
+    question = msg.match[2]
+    answer = msg.match[4]
+
+    result = new knowledgeAbout(question)
+
+    if result.key?
+      if result.item.answer == answer
+        msg.send "I already know that"
+      else
+        msg.send "I thought \"#{result.item.answer}\" but I will now answer \"#{answer}\""
+        robot.brain.data.knowledge[result.key].answer = answer
+    else
+      new_question = {regexp: question, answer: answer}
+      next_id = Object.keys(robot.brain.data.knowledge).length+1
+      robot.brain.data.knowledge[next_id] = new_question
+      respondToAnswer(new_question)
+      msg.send "OK, I will answer \"#{answer}\" when asked \"#{question}\""
+
+  robot.respond /(forget)( all)? (answers|replies|everything)$/i, (msg) ->
+    for key, item of robot.brain.data.knowledge
+      i = 0
+      while i < robot.listeners.length
+        robot.listeners.splice(i,1) if String(item.regexp) in String(robot.listeners[i].regex)
+        i++
+    robot.brain.data.knowledge = {}
+    msg.send "OK, I've forgot all answers"
+
+  robot.respond /((say )?s(ome)?thing|talk( to me)?)( about (.*))?$/i, (msg) ->
+    subject = msg.match[6]
+    knowledge = robot.brain.data.knowledge
+    if JSON.stringify(knowledge) is '{}'
+      msg.send "I don't know anything, teach me something please ..."
+    else
+      if subject is undefined
+        answer = knowledge[msg.random(Object.keys(knowledge))].answer
+        msg.send "I would say #{answer}"
+      else
+        result = new knowledgeAbout(subject)
+        if result.key?
+          msg.send "If you ask #{result.item.regexp}, I would answer #{result.item.answer}"
+        else
+          msg.send "I don't know anything about #{subject}, please teach me something about it"


Split page shell into separate file

Split page shell into separate file

error: pathspec 'src/components/reference-book/page-shell.cjsx' did not match any file(s) known to git

--- src/components/reference-book/page-shell.cjsx
+++ src/components/reference-book/page-shell.cjsx
@@ -0,0 +1,53 @@
+React = require 'react'
+BS = require 'react-bootstrap'
+_  = require 'underscore'
+
+LoadableItem = require '../loadable-item'
+ReferenceBookPage = require './page'
+
+{Invalid} = require '../index'
+{ReferenceBookPageActions, ReferenceBookPageStore} = require '../../flux/reference-book-page'
+
+ReferenceBookPageShell = React.createClass
+
+  propTypes:
+    cnxId: React.PropTypes.string.isRequired
+
+  getDefaultState: ->
+    previousPageProps: null
+
+  componentWillReceiveProps: (nextProps) ->
+    @setState(previousPageProps: @props)
+
+  isAnotherPage: (previousPageProps, currentProps) ->
+    previousPageProps? and previousPageProps.cnxId? and not _.isEqual(previousPageProps, currentProps)
+
+  renderLoading: (previousPageProps, currentProps, refreshButton) ->
+    if @isAnotherPage(previousPageProps, currentProps)
+      loading = <ReferenceBookPage
+        {...previousPageProps}
+        className='page-loading loadable is-loading'>
+        {refreshButton}
+      </ReferenceBookPage>
+    else
+      loading =
Loading... {refreshButton}

+
+    loading
+
+  renderLoaded: ->
+    <ReferenceBookPage {...@props}/>
+
+  render: ->
+    if @props.cnxId?
+      <LoadableItem
+        id={@props.cnxId}
+        store={ReferenceBookPageStore}
+        actions={ReferenceBookPageActions}
+        renderLoading={_.partial(@renderLoading, @state?.previousPageProps, @props)}
+        renderItem={@renderLoaded}
+      />
+    else
+      <Invalid />
+
+
+module.exports = ReferenceBookPageShell


do not throw update errors

do not throw update errors

--- src/supervisor-update.coffee
+++ src/supervisor-update.coffee
@@ -123,4 +123,3 @@
 			startNewSupervisor(currentSupervisor)
 		.catch (err) ->
 			utils.mixpanelTrack('Supervisor update failed', error: err)
-			throw err


Implement 'select all' checkbox

Implement 'select all' checkbox

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


ComputeProvider: MachineList (wip) machine modal to list all machines


sidebar: add connectSidebar HOC

sidebar: add connectSidebar HOC

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

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

--- client/app/lib/sidebar/connectsidebar.coffee
+++ client/app/lib/sidebar/connectsidebar.coffee
@@ -0,0 +1,60 @@
+React = require 'app/react'
+kd = require 'kd'
+
+debug = require('debug')('sidebar:connect')
+
+module.exports = connectSidebar = (config) -> (WrappedComponent) ->
+
+  class ConnectSidebar extends React.Component
+
+    constructor: (props) ->
+
+      super props
+
+      { sidebar } = kd.singletons
+
+      @_mounted = no
+      @_subscription = null
+
+
+    transformSidebarState: (sidebarState) ->
+
+      return  unless @_mounted
+
+      @setState (config.transformState sidebarState, @props) or {}
+
+
+    componentDidMount: ->
+
+      { sidebar } = kd.singletons
+
+      @_mounted = yes
+      @_subscription = sidebar.subscribeChange @bound 'transformSidebarState'
+
+      @setState (sidebar.getState @bound 'transformSidebarState') or {}
+
+
+    componentWillReceiveProps: (nextProps) ->
+
+      { sidebar } = kd.singletons
+
+      @setState (config.transformState sidebar.getState(), nextProps) or {}
+
+
+    componentWillUnmount: ->
+
+      @_subscription?.cancel()
+      @_subscription = null
+      @_mounted = no
+
+
+    render: ->
+      <WrappedComponent {...@state} {...@props} />
+
+
+  name = \
+    WrappedComponent.displayName or WrappedComponent.name or 'Component'
+
+  ConnectSidebar.displayName = "ConnectSidebar(#{name})"
+
+  return ConnectSidebar


Use window.location.protocol to choose between ws:// and wss:// shcheme.

--- lib/assets/javascripts/websocket_rails/websocket_connection.js.coffee
+++ lib/assets/javascripts/websocket_rails/websocket_connection.js.coffee
@@ -4,7 +4,11 @@
 class WebSocketRails.WebSocketConnection

   constructor: (@url,@dispatcher) ->
-    @url             = "ws://#{@url}" unless @url.match(/^wss?:\/\//)
+    if window.location.protocol == 'http:'
+        @url             = "ws://#{@url}"
+    else
+        @url             = "wss://#{@url}"
+
     @message_queue   = []
     @_conn           = new WebSocket(@url)
     @_conn.onmessage = @on_message


Fix AUTH state transition

Fix AUTH state transition

--- src/nsqdconnection.coffee
+++ src/nsqdconnection.coffee
@@ -324,6 +324,7 @@
       Enter: ->
         return @goto @afterIdentify() unless @conn.config.authSecret
         @conn.write wire.auth @conn.config.authSecret
+        return @goto 'AUTH_RESPONSE'

     AUTH_RESPONSE:
       response: (data) ->


firefox fails with scale (0,0)

firefox fails with scale (0,0)

--- graphics.coffee
+++ graphics.coffee
@@ -287,9 +287,10 @@
       y: @record_dims.y + .5 * @block + .5
       scale: 0
       render: =>
-        @ctx.scale(sprite.scale, sprite.scale)
-        @ctx.strokeStyle = 'white'
-        @renderArrow(dir.theta, @block)
+        if sprite.scale > 0
+          @ctx.scale(sprite.scale, sprite.scale)
+          @ctx.strokeStyle = 'white'
+          @renderArrow(dir.theta, @block)
     sprite.animations = @animatePopIn(1, {x:sprite.x, y:sprite.y})

     @advanceNextRecordSprite(1)


Autoplay recording on click hour

Autoplay recording on click hour

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


Use skinny arrow for event handler

Use skinny arrow for event handler

--- lib/find.coffee
+++ lib/find.coffee
@@ -54,7 +54,7 @@

     atom.workspaceView.eachEditorView (editorView) ->
       selectNext = new SelectNext(editorView.editor)
-      editorView.command 'find-and-replace:select-next', =>
+      editorView.command 'find-and-replace:select-next', ->
         selectNext.findAndSelectNext()

   createProjectFindView: ->


Don't use Saucelabs by default

Don't use Saucelabs by default

--- lib/fran.coffee
+++ lib/fran.coffee
@@ -3,12 +3,12 @@
 Factory = require('./factory')

 module.exports = (options = {}) ->
-  if process.env['FRAN_SAUCE'] == '0'
-    options.sauce = false
-  else
-    options.sauce =
+  options.sauce =
+    if process.env['FRAN_SAUCE'] == '1'
       username: process.env['SAUCE_USERNAME']
       apiKey: process.env['SAUCE_API_KEY']
+    else
+      {}

   options.ports =
     if franPorts = process.env['FRAN_PORT']


Updated map directive to support range limit to limit results to particular range - useful for showing local stores [BBB-75]

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


Added hi-pri back to email

Added hi-pri back to email

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


Logging

Logging

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


Social: added small note

Social: added small note

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -726,7 +726,7 @@

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

   userIsExempt: (callback)->
     # console.log @isExempt, this


Calculate the total score from the rubric.

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


Added test cases for AsyncIterator

Added test cases for AsyncIterator

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

--- test/t8-AsyncIterator.coffee
+++ test/t8-AsyncIterator.coffee
@@ -0,0 +1,117 @@
+
+{ expect, assert } = require('chai')
+
+baselib = require './../index.coffee'
+
+{ AsyncIterator } = baselib
+
+describe 'AsyncIterator', ->
+
+  it 'Existence', ->
+
+    expect(baselib)
+    .to.have.property('AsyncIterator')
+    .which.is.a('function')
+
+  it 'General Use Case', (done)->
+
+    testString = ''
+
+    array = [ 'A', 'B', 'C', 'D' ]
+
+    it = new AsyncIterator
+
+    it.generateWith (expectedIndex)->
+      if expectedIndex < array.length then [ expectedIndex, array[expectedIndex] ] else null
+
+    it.forEach (next, index, item)->
+      testString += item
+      next()
+
+    it.finally ->
+      expect(testString).to.equal('ABCD')
+      done()
+
+  it 'General Use Case With Zero Iterations', (done)->
+
+    testString = ''
+
+    array = [ 'A', 'B', 'C', 'D' ]
+
+    it = new AsyncIterator
+
+    it.generateWith (expectedIndex)->
+      null
+
+    it.forEach (next, index, item)->
+      testString += item
+      next()
+
+    it.finally ->
+      expect(testString).to.equal('')
+      done()
+
+  it 'Shimming Array Iteration', (done)->
+
+    testString = ''
+
+    array = [ 'A', 'B', 'C', 'D' ]
+
+    it = new AsyncIterator
+
+    it.generateWith (expectedIndex)->
+      if expectedIndex < array.length then [ expectedIndex, array[expectedIndex] ] else null
+
+    it.forEach (next, index, item)->
+      testString += item
+      next()
+
+    it.finally ->
+      expect(testString).to.equal('ABCD')
+      done()
+
+  it 'Shimming key/value pair of Object Iteration', (done)->
+
+    testString = ''
+
+    obj =
+      a: 'A'
+      b: 'B'
+      c: 'C'
+
+    it = new AsyncIterator
+
+    array = Object.keys obj
+    it.generateWith (expectedIndex)->
+      if expectedIndex < array.length then [ array[expectedIndex], obj[array[expectedIndex]] ] else null
+
+    it.forEach (next, key, value)->
+      testString += key + value
+      next()
+
+    it.finally ->
+      expect(testString).to.equal('aAbBcC')
+      done()
+
+  it 'Shimming while behavior', (done)->
+
+    testString = ''
+
+    it = new AsyncIterator
+
+    i = 0
+    it.generateWith (expectedIndex)->
+      if i < 5
+        i += 1
+        return []
+      else
+        null
+
+    it.forEach (next)->
+      testString += 'A'
+      next()
+
+    it.finally ->
+      expect(testString).to.equal('AAAAA')
+      done()
+


Main application controller for mobile app

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

--- js/mobile/application.coffee
+++ js/mobile/application.coffee
@@ -0,0 +1,106 @@
+# Main application router for Splash.  All route handlers only do enough to
+# hydrate the application state if necessary and then display the relevant view.
+class Splash.Routers.Router extends Backbone.Router
+  routes:
+    '':                  'index'
+    'place/:id':         'place'
+    'search':            'search'
+    'search/:query':     'search'
+    'search/:query/map': 'map'
+    'about':             'about'
+    ':frag':             'error'
+
+
+  # Links to a Backbone.View object linked to the current view being displayed.
+  # This is used to determine the direction of slide the required to show the
+  # new view.
+  currentView: null
+
+  # Track a new pageview and other events to Google Analytics.
+  _trackPageview: ->
+    return
+
+  # Updates the contents of the application container and the status of the
+  # header bar.  It also determines the direction of the sliding action.
+  _updateContent: (newView) =>
+    Debug 'Splash.Routers.Router._updateContent'
+
+    return if newView == @currentView
+
+    if @currentView?
+      # If there is a current view we need to determine the direction in which
+      # we should slide off the current view and which direction to slide in the
+      # new view.
+      if @currentView._ident == 'about'
+        dir = 'ltr'
+      else if @currentView._ident == 'search' and newView._ident == 'index'
+        dir = 'ltr'
+      else if @currentView._ident == 'search' and newView._ident == 'detail'
+        dir = 'rtl'
+      else if @currentView._ident == 'detail' and newView._ident == 'search'
+        dir = 'ltr'
+      else
+        dir = 'rtl'
+    else if newView._ident == 'about'
+      dir = 'ltr' # Some weird animation bug here
+      # TODO: find out why this screen doesn't work properly
+    else
+      dir = 'rtl'
+
+    # Delete if the current view if necessary and load the new one
+    @currentView.destruct dir if @currentView?
+    state = newView.getHeaderState()
+    @header.update state.headline, dir, state.buttons
+    newView.construct ($ '#content'), dir
+    @currentView = newView
+
+    return
+
+  initialize: ->
+    @bind 'all', @_trackPageview
+    # Bind to the header element that already exists in the DOM and attach a
+    # Backbone View to it.
+    @header = new Splash.Views.HeaderView
+      el: '#header'
+
+  # Route handlers
+  index: ->
+    view = new Splash.Views.Index
+    view.render()
+    @_updateContent view
+    return
+
+  about: ->
+    view = new Splash.Views.AboutView
+    view.render()
+    @_updateContent view
+
+  # The this route will not be triggered by a search but allows an easy way to
+  # represent the results of a particular query.
+  # *query* {String} - User provided query string
+  search: (query) ->
+    view = new Splash.Views.SearchView
+      q: query
+    view.render()
+    @_updateContent view
+
+  # Displays the details screen for a particular place in the database.
+  place: (id) ->
+    view = new Splash.Views.DetailView
+      place: id
+    view.render()
+    @_updateContent view
+
+  # Handles a route that is not matched against a defined route handler.
+  # *frag* {String} - URL fragment that didn't match a route handler
+  error: (frag) ->
+    Debug 'Splash.Routers.Router.error'
+    Debug 'Route Not Found: ' + frag
+    return
+
+
+
+$ ->
+  window.__DEBUG__ = true
+  Splash.Data.Router = new Splash.Routers.Router
+  Backbone.history.start()


Fixed: path.join doesn't take 'null' as argument

--- server/lib/icon.coffee
+++ server/lib/icon.coffee
@@ -13,12 +13,15 @@
 ###
 icons.getPath = (root, appli) ->

+    iconPath = null
+
     # try to retrieve icon path from manifest, if developer set it.
-    iconPath = path.join root, appli.iconPath
+    if appli.iconPath? and fs.existsSync(path.join root, appli.iconPath)
+        iconPath = path.join root, appli.iconPath

     # if it has not been set, or if it doesn't exist, try to guess the icon path
     # first check for svg icon, then for png.
-    if not appli.iconPath? or not fs.existsSync(iconPath)
+    else
         basePath = path.join root, "client", "app", "assets", "icons"
         svgPath = path.join basePath, "main_icon.svg"
         pngPath = path.join basePath, "main_icon.png"


start testing sudo-mode

start testing sudo-mode

error: pathspec 'services/web/test/UnitTests/coffee/SudoMode/SudoModeHandlerTests.coffee' did not match any file(s) known to git

--- services/web/test/UnitTests/coffee/SudoMode/SudoModeHandlerTests.coffee
+++ services/web/test/UnitTests/coffee/SudoMode/SudoModeHandlerTests.coffee
@@ -0,0 +1,110 @@
+SandboxedModule = require('sandboxed-module')
+assert = require('assert')
+require('chai').should()
+expect = require('chai').expect
+sinon = require('sinon')
+modulePath = require('path').join __dirname, '../../../../app/js/Features/SudoMode/SudoModeHandler'
+
+
+describe 'SudoModeHandler', ->
+	beforeEach ->
+		@userId = 'some_user_id'
+		@rclient = {get: sinon.stub(), set: sinon.stub(), del: sinon.stub()}
+		@RedisWrapper =
+			client: () => @rclient
+		@SudoModeHandler = SandboxedModule.require modulePath, requires:
+			'../../infrastructure/RedisWrapper': @RedisWrapper
+			'logger-sharelatex': @logger = {log: sinon.stub(), err: sinon.stub()}
+
+	describe '_buildKey', ->
+
+		it 'should build a properly formed key', ->
+			expect(@SudoModeHandler._buildKey('123')).to.equal 'SudoMode:{123}'
+
+	describe 'activateSudoMode', ->
+		beforeEach ->
+			@call = (cb) =>
+				@SudoModeHandler.activateSudoMode @userId, cb
+
+		describe 'when all goes well', ->
+			beforeEach ->
+				@rclient.set = sinon.stub().callsArgWith(4, null)
+
+			it 'should not produce an error', (done) ->
+				@call (err) =>
+					expect(err).to.equal null
+					done()
+
+			it 'should set a value in redis', (done) ->
+				@call (err) =>
+					expect(@rclient.set.callCount).to.equal 1
+					expect(@rclient.set.calledWith(
+						'SudoMode:{some_user_id}', '1', 'EX', 60*60
+					)).to.equal true
+					done()
+
+		describe 'when rclient.set produces an error', ->
+			beforeEach ->
+				@rclient.set = sinon.stub().callsArgWith(4, new Error('woops'))
+
+			it 'should produce an error', (done) ->
+				@call (err) =>
+					expect(err).to.not.equal null
+					expect(err).to.be.instanceof Error
+					done()
+
+	describe 'isSudoModeActive', ->
+		beforeEach ->
+			@call = (cb) =>
+				@SudoModeHandler.isSudoModeActive @userId, cb
+
+		describe 'when sudo-mode is active for that user', ->
+			beforeEach ->
+				@rclient.get = sinon.stub().callsArgWith(1, null, '1')
+
+			it 'should not produce an error', (done) ->
+				@call (err, isActive) =>
+					expect(err).to.equal null
+					done()
+
+			it 'should get the value from redis', (done) ->
+				@call (err, isActive) =>
+					expect(@rclient.get.callCount).to.equal 1
+					expect(@rclient.get.calledWith('SudoMode:{some_user_id}')).to.equal true
+					done()
+
+			it 'should produce a true result', (done) ->
+				@call (err, isActive) =>
+					expect(isActive).to.equal true
+					done()
+
+		describe 'when sudo-mode is not active for that user', ->
+			beforeEach ->
+				@rclient.get = sinon.stub().callsArgWith(1, null, null)
+
+			it 'should not produce an error', (done) ->
+				@call (err, isActive) =>
+					expect(err).to.equal null
+					done()
+
+			it 'should get the value from redis', (done) ->
+				@call (err, isActive) =>
+					expect(@rclient.get.callCount).to.equal 1
+					expect(@rclient.get.calledWith('SudoMode:{some_user_id}')).to.equal true
+					done()
+
+			it 'should produce a false result', (done) ->
+				@call (err, isActive) =>
+					expect(isActive).to.equal false
+					done()
+
+		describe 'when rclient.get produces an error', ->
+			beforeEach ->
+				@rclient.get = sinon.stub().callsArgWith(1, new Error('woops'))
+
+			it 'should produce an error', (done) ->
+				@call (err, isActive) =>
+					expect(err).to.not.equal null
+					expect(err).to.be.instanceof Error
+					expect(isActive).to.be.oneOf [null, undefined]
+					done()


Make child_process.execFileSync support asar

--- atom/common/lib/asar.coffee
+++ atom/common/lib/asar.coffee
@@ -355,3 +355,4 @@
   overrideAPISync process, 'dlopen', 1
   overrideAPISync require('module')._extensions, '.node', 1
   overrideAPISync fs, 'openSync'
+  overrideAPISync child_process, 'execFileSync'


Push new note when adding word

Push new note when adding word

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


Overwrite up-arrow history mechanism with per-room history

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

--- app/assets/javascripts/per-room-history.coffee
+++ app/assets/javascripts/per-room-history.coffee
@@ -0,0 +1,71 @@
+existingMessageHistory = localStorage.getItem("per_room_history")
+if existingMessageHistory?
+  try
+    history = JSON.parse(existingMessageHistory)
+    TS.model.per_room_input_history = history
+  catch e
+    console.log "Failed to parse existing history. Moving on with life."
+
+TS.chat_history.initializeChannelHistory = (cid) ->
+  TS.model.per_room_input_history ||= {}
+  history = TS.model.per_room_input_history[TS.model.active_cid]
+  if !history?
+    history = {}
+    history.index = -1
+    history.entries = []
+    TS.model.per_room_input_history[TS.model.active_cid] = history
+
+  return history
+
+TS.chat_history.add = (txt) ->
+  unless TS.model.prefs?.arrow_history
+    return
+  if txt is ""
+    return
+
+  history = TS.chat_history.initializeChannelHistory(TS.model.active_cid)
+
+  entries = history.entries
+
+  index = entries.indexOf(txt)
+  if index != -1
+    entries.splice(index, 1)
+  entries.unshift(txt)
+  entries.splice(30)
+  localStorage.setItem("per_room_history", JSON.stringify(TS.model.per_room_input_history))
+
+TS.chat_history.resetPosition = (why) ->
+  history = TS.chat_history.initializeChannelHistory(TS.model.active_cid)
+  history.index = -1
+
+TS.chat_history.onArrowKey = (e, input) ->
+  unless TS.model.prefs?.arrow_history
+    return
+  history = TS.chat_history.initializeChannelHistory(TS.model.active_cid)
+  return unless history.entries.length
+
+  txt = input.val()
+  hist_text = ""
+  if history.index < 0
+    history.current = txt
+
+  if e.which == TS.utility.keymap.up
+    history.index += 1
+    if history.index >= history.entries.length
+      history.index = history.entries.length - 1
+      return
+  else if e.which == TS.utility.keymap.down
+    history.index -= 1
+    if history.index < 0
+      history.index = -1
+      hist_text = history.current
+  else
+    return
+
+  hist_text ||= history.entries[history.index]
+  e.preventDefault()
+  TS.utility.populateInput(TS.client.ui.$msg_input, hist_text)
+  if e.which == TS.utility.keymap.up
+    input.setCursorPosition 0
+  else
+    input.setCursorPosition(input.val().length)


remove for sale modifier if no works are for sale

--- apps/artwork/client/setup_artwork_rails.coffee
+++ apps/artwork/client/setup_artwork_rails.coffee
@@ -60,7 +60,9 @@
         if model.get('sold')  or not model.get('forsale')
           firstRail = _.first(_.keys(rails))
           artworks = new Artworks rails[firstRail]
-          { title } = railwayMap(artwork, ' For Sale')[firstRail]
+          anyForSale = artworks.any (model) -> model.get('forsale')
+          modifier = if anyForSale then ' For Sale' else ''
+          { title } = railwayMap(artwork, modifier)[firstRail]

           view = new ArtworkRailView
             collection: artworks


Fix scheduable field bug in edit mode

Fix scheduable field bug in edit mode

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/ICTU/self-healer.git/'


jquery UI dependency delete pivottable

jquery UI dependency delete pivottable

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/gurujowa/rails-simple-crm.git/'


Add test file and several unit tests for ConfigProvider.

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


Remove Transaction tests "only" scope.

Remove Transaction tests "only" scope.


No () in method names

No () in method names

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


Sync up campaign and world selector level counts

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


Fix $.hasChild and $.closestLink when el becomes null

--- assets/javascripts/lib/util.coffee
+++ assets/javascripts/lib/util.coffee
@@ -12,15 +12,14 @@
   document.getElementById(id)

 $.hasChild = (parent, el) ->
-  return unless parent and el
-  loop
+  return unless parent
+  while el
     return true if el is parent
     return if el is document.body
     el = el.parentElement

 $.closestLink = (el, parent = document.body) ->
-  return unless el and parent
-  loop
+  while el
     return el if el.tagName is 'A'
     return if el is parent
     el = el.parentElement


client/redux: add dispatchInitialActions util

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

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

--- client/app/lib/redux/dispatchInitialActions.coffee
+++ client/app/lib/redux/dispatchInitialActions.coffee
@@ -0,0 +1,77 @@
+globals = require 'globals'
+isAdmin = require 'app/util/isAdmin'
+
+{ LOAD: BONGO_LOAD } = bongo = require 'app/redux/modules/bongo'
+customer = require 'app/redux/modules/payment/customer'
+
+{
+  load: loadCustomer
+  create: createCustomer } = require 'app/redux/modules/payment/customer'
+
+{
+  load: loadSubscription
+  create: createSubscription } = require 'app/redux/modules/payment/subscription'
+
+loadAccount = ({ dispatch, getState }) ->
+  dispatch {
+    types: [BONGO_LOAD.BEGIN, BONGO_LOAD.SUCCESS, BONGO_LOAD.FAIL]
+    bongo: (remote) -> Promise.resolve(remote.revive globals.userAccount)
+  }
+
+loadGroup = ({ dispatch, getState }) -> ->
+  dispatch {
+    types: [BONGO_LOAD.BEGIN, BONGO_LOAD.SUCCESS, BONGO_LOAD.FAIL]
+    bongo: (remote) -> Promise.resolve(remote.revive globals.currentGroup)
+  }
+
+loadUserDetails = ({ dispatch, getState }) -> ->
+  dispatch {
+    types: [BONGO_LOAD.BEGIN, BONGO_LOAD.SUCCESS, BONGO_LOAD.FAIL]
+    bongo: (remote) -> remote.api.JUser.fetchUser()
+  }
+
+# TODO(umut):
+# right now there is no default customer coming from backend.
+# if there is no payment information for that group, just create one
+ensureCustomer = ({ dispatch, getState }) -> ->
+
+  { _id } = globals.currentGroup
+
+  group = bongo.byId('JGroup', _id)(getState())
+
+  if group.payment
+  then dispatch(loadCustomer())
+  else dispatch(createCustomer())
+
+
+ensureSubscription = ({ dispatch, getState }) -> ->
+
+  { _id } = globals.currentGroup
+
+  state = getState()
+
+  group = bongo.byId('JGroup', _id)(state)
+
+  if group.payment?.subscription
+  then dispatch(loadSubscription())
+  else dispatch(createSubscription(state.customer.id, 'p_up_to_10'))
+
+
+module.exports = dispatchInitialActions = (store) ->
+
+  { getState, dispatch } = store
+
+  console.log 'dispatching initial actions', store
+
+  promise = loadAccount(store)
+    .then(loadGroup(store))
+    .then(loadUserDetails(store))
+
+  if isAdmin()
+    promise = promise
+      .then(ensureCustomer(store))
+      .then(ensureSubscription(store))
+
+  promise.then(console.log.bind(console, 'finished dispactching initial actions'))
+
+


fixes #307

fixes #307

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


goodnight

goodnight

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

--- scripts/goodnight.coffee
+++ scripts/goodnight.coffee
@@ -0,0 +1,3 @@
+module.exports = (robot) ->
+  robot.hear /goodnight/i, (msg) ->
+    msg.send "http://mlkshk.com/r/QOH8.gif"


app.Firebase stub.

app.Firebase stub.

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

--- app/client/js/firebase.coffee
+++ app/client/js/firebase.coffee
@@ -0,0 +1,41 @@
+goog.provide 'app.Firebase'
+
+class app.Firebase
+
+  ###*
+    @constructor
+  ###
+  constructor: ->
+    # TODO(steida): Use server data, make it isomorphic.
+    if window.Firebase
+      @root = new window.Firebase 'https://shining-fire-6810.firebaseio.com/'
+      @authenticated = @root.child '.info/authenticated'
+
+  ###*
+    @param {Function} callback
+  ###
+  initSimpleLogin: (callback) ->
+    if window.FirebaseSimpleLogin
+      @authClient = new window.FirebaseSimpleLogin @root, callback
+
+# userRef = new Firebase 'https://shining-fire-6810.firebaseio.com/users/1/newSong'
+# userRef.on 'value', (snapshot) =>
+#   json = snapshot.val()
+#   return if !json
+#   newSong = @songsStore.instanceFromJson app.songs.Song, json
+#   @songsStore.newSong = newSong
+#   @notify()
+# @myFirebaseRef = new Firebase 'https://shining-fire-6810.firebaseio.com/'
+# @myFirebaseRef
+#   .child 'songs'
+#   .on 'value', (snapshot) =>
+#     @setState 'songs': snapshot.val()
+
+# @songsStore.listen 'change', (e) =>
+#   @notify()
+
+# firebase.authenticated.on 'value', (snap) =>
+#   console.log 'firebase.authenticated.on'
+#   setTimeout =>
+#     @notify()
+#   , 10


Syntax typo

Syntax typo


bug fix in file uploading

bug fix in file uploading

 On branch master

	modified:   nodejs_server/middleware/file_upload.coffee

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


Incluse JavaScript specs when loading suite

Closes #1615

--- spec/spec-suite.coffee
+++ spec/spec-suite.coffee
@@ -5,7 +5,7 @@
 require './spec-helper'

 requireSpecs = (specDirectory, specType) ->
-  for specFilePath in fs.listTreeSync(specDirectory) when /-spec\.coffee$/.test specFilePath
+  for specFilePath in fs.listTreeSync(specDirectory) when /-spec\.(coffee|js)$/.test specFilePath
     require specFilePath

     # Set spec directory on spec for setting up the project in spec-helper


Create xmind.coffee

Create xmind.coffee

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

--- data/points/xmind.coffee
+++ data/points/xmind.coffee
@@ -0,0 +1,5 @@
+id: "xmind"
+title: "XMind"
+homepage: "http://www.xmind.net/"
+function: [ "mind-mapping" ]
+desc: "专业的思维导图工具，即使免费版本功能也够用。"


remove spurious test

remove spurious test


Change selector to any image with async-load

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


Color by service

Color by service

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


remove message on uncheck amend

remove message on uncheck amend

--- lib/commit-dialog.coffee
+++ lib/commit-dialog.coffee
@@ -64,8 +64,13 @@
     return

   amendChange: ->
-    if @amend.prop("checked") and @message.val() is ''
-      @message.val(@lastCommit)
+    if @amend.prop("checked")
+      if @message.val() is ''
+        @message.val(@lastCommit)
+    else
+      if @message.val() is @lastCommit
+        @message.val('')
+    # TODO: maybe check @msgChanged instead of testing @msg.val()?
     return

   show: ->


Do not submit form when checking checkboxes or selecting options

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


use wss replace ws

use wss replace ws

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


Add JS for mp3 player

Add JS for mp3 player

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/jbox-web/media-server.git/'


Per project settings that ADD to the existing global settings.

Supports multiple projects in single window.

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/jerone/flex-toolbar.git/'


..and the new EventManager itself

..and the new EventManager itself

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

--- js/foundation/eventmanager/eventmanager.coffee
+++ js/foundation/eventmanager/eventmanager.coffee
@@ -0,0 +1,1120 @@
+# Copyright 2012 Juha-Jarmo Heinonen
+#
+# The EventManager is a proxy between the DOM-level
+# events and the higher-lever GUI API's.
+EventManagerApp = HApplication.extend
+  #
+  # Warning wrapper, only active in development mode
+  warn: ->
+    console.warn.apply( console, arguments ) unless @isProduction
+  #
+  # The default options array, each flag corresponds to events received.
+  _defaultEventOptions:
+    #
+    # The recipient's #mouseMove(x,y) method gets called,
+    # whether it has focus or not
+    mouseMove: false
+    #
+    # The recipient's #mouseDown(x,y,button) method gets called,
+    # if focused.
+    mouseDown: false
+    #
+    # The recipient's #click(x,y,button) method gets called,
+    # if focused.
+    click: false
+    #
+    # The recipient's #mouseUp(x,y,button) method gets called,
+    # if focused.
+    mouseUp: false
+    #
+    # The recipient's #startDrag( x, y ), #drag( x, y ) and
+    # #endDrag( x, y ) methods get called, if focused and
+    # a draging operation is done with the pointing device.
+    draggable: false
+    #
+    # The recipient's #startHover( dragObj ), #hover( dragObj ) and
+    # #endHover( dragObj ) methods get called, when a dragged object
+    # is hovered over it. See the rectHover option to set the topmost
+    # vs any mode.
+    droppable: false
+    #
+    # The drop modes define how the hover area responds to dragged objects
+    #  false: point; the [x,y] point of the pointer
+    #  true: area; the [l,t,r,b] contains rectangle of the dragged object
+    #  'contains': for areas; same as true
+    #  'intersects': for areas; intersection instead of containment
+    rectHover: false
+    #
+    # Allows multiple (other than the non-topmost drop target).
+    # Set on both the draggable as well as the drop target object.
+    multiDrop: false
+    #
+    # The recipient's #keyDown( keyCode ) method gets called,
+    # if active and a keyboard key is pressed.
+    keyDown: false
+    #
+    # The recipient's #keyUp( keyCode ) method gets called,
+    # if active and a keyboard key is released.
+    keyUp: false
+    #
+    # The recipient's #mouseWheel( delta) method gets called,
+    # if active and a scroll device is used.
+    mouseWheel: false
+    #
+    # The recipient's #resize() method gets called, when the
+    # browser's window or a HWindow (and similar components) are
+    # resized, this event is triggered on all recipients.
+    resize: false
+    #
+    # The recipient's #textEnter() method gets called, when a keyboard key
+    # has been pressed and released, whether it has focus or not.
+    textEnter: false
+    #
+    # The recipient's #doubleClick(x,y) method gets called, when
+    # the pointing device is double-clicked, if focused.
+    doubleClick: false
+    #
+    # The recipient's #contextMenu() method gets called, when the
+    # pointing device's or keyboard's context button (usually the
+    # right mouse button) has been pressed, if focused.
+    contextMenu: false
+  #
+  # The status object has a list of the most recent HID events by id and name.
+  # Each id and name and states are booleans.
+  #   button1      =>  The state of the left mouse button.
+  #   button2      =>  The state of the right mouse button.
+  #   crsrX        =>  The X-coordinate of the mouse cursor (or last point of touch).
+  #   crsrY        =>  The Y-coordinate of the mouse cursor (or last point of touch).
+  #   keysDown     =>  An Array of the key codes of keys being held down.
+  #   altKeyDown   =>  The state of the Alt key (or equivalent, like Option).
+  #   ctrlKeyDown  =>  The state of the Ctrl key.
+  #   shiftKeyDown => The state of the Shift key.
+  #   metaKeyDown  =>  The state of the Meta key.
+  #   cmdKeyDown   =>  The state of the Command key (or equivalent, like the Windows key).
+  # Note: Will be deprecated in favor of an hash with keys instead of numeric indexes.
+  status:
+    0: false
+    button1: false
+    setButton1: (f)->
+      @button1 = f
+      @[0] = f
+    1: false
+    button2: false
+    setButton2: (f)->
+      @button2 = f
+      @[1] = f
+    2: -1
+    crsrX: -1
+    setCrsrX: (x)->
+      @crsr[0] = x
+      @crsrX = x
+      @[2] = x
+    3: -1
+    crsrY: -1
+    crsr: [ -1, -1 ]
+    setCrsrY: (y)->
+      @crsr[1] = y
+      @crsrY = y
+      @[3] = y
+    setCrsr: (x,y)->
+      @setCrsrX(x)
+      @setCrsrY(y)
+    4: []
+    keysDown: []
+    hasKeyDown: (k)->
+      @keysDown.indexOf(k) != -1
+    addKeyDown: (k)->
+      if !@hasKeyDown(k)
+        @keysDown.push( k )
+        @[4] = @keysDown
+    delKeyDown: (k)->
+      i = @keysDown.indexOf(k)
+      if i != -1
+        @keysDown.splice( i, 1 )
+        @[4] = @keysDown
+    resetKeysDown: ->
+      @keysDown = []
+      @[4] = @keysDown
+    5: false
+    altKeyDown: false
+    setAltKey: (f)->
+      @altKeyDown = f
+      @[5] = f
+    6: false
+    ctrlKeyDown: false
+    setCtrlKey: (f)->
+      @ctrlKeyDown = f
+      @[6] = f
+    7: false
+    shiftKeyDown: false
+    setShiftKey: (f)->
+      @shiftKeyDown = f
+      @[7] = f
+    8: false
+    metaKeyDown: false
+    setMetaKey: (f)->
+      @metaKeyDown = f
+      @[8] = f
+    9: false
+    cmdKeyDown: false
+    setCmdKey: (f)->
+      @cmdKeyDown = f
+      @[9] = f
+    length: 10
+  button1: 0
+  button2: 1
+  crsrX: 2
+  crsrY: 3
+  keysDown: 4
+  altKeyDown: 5
+  ctrlKeyDown: 6
+  shiftKeyDown: 7
+  metaKeyDown: 8
+  cmdKeyDown: 9
+  #
+  # Cleans up events that would be lost, when the browser window is blurred.
+  _domWindowBlur: ->
+    @status.resetKeysDown()
+    @status.setAltKey(false)
+    @status.setCtrlKey(false)
+    @status.setShiftKey(false)
+    @status.setMetaKey(false)
+    @status.setCmdKey(false)
+    @_origDroppableChecks = @enableDroppableChecks
+    @enableDroppableChecks = false
+    if HSystem.defaultInterval != HSystem._blurredInterval
+      @_sysDefaultInterval = HSystem.defaultInterval
+      COMM.Queue.push( (->
+        HSystem.defaultInterval = HSystem._blurredInterval
+      ) )
+  #
+  # Restores system poll frequency
+  _domWindowFocus: ->
+    @enableDroppableChecks = @_origDroppableChecks
+    if HSystem.defaultInterval == HSystem._blurredInterval and @_sysDefaultInterval
+      _this = @
+      COMM.Queue.push( (->
+        HSystem.defaultInterval = _this._sysDefaultInterval
+      ) )
+  #
+  # List of used event methods for global purposes:
+  _eventMethods: [
+    'mouseMove', 'mouseUp', 'mouseDown', 'click', 'keyUp', 'keyDown',
+    'contextMenu', 'resize', 'mouseWheel', 'doubleClick'
+  ]
+  #
+  # This structure keeps track of registered elem/event/object/method; see #observe and #stopObserving
+  _observerMethods: {}
+  #
+  # Observe event, cache anon function; eventName => elem => anonFn
+  observe: (_elem, _eventName, _targetMethodName, _targetObj, _capture)->
+    _targetObj = @ unless _targetObj?
+    _capture = false unless _capture?
+    _anonFn = (e)->
+      _targetObj[_targetMethodName](e)
+    unless @_observerMethods[_eventName]?
+      @_observerMethods[_eventName] = {
+        elems:   []
+        fns:     []
+        capture: []
+      }
+    _cache = @_observerMethods[_eventName]
+    _elemIdx = _cache.elems.indexOf( _elem )
+    if _elemIdx != -1
+      _prevFn = _cache.fns[_elemIdx]
+      _prevCapture = _cache.capture[_elemIdx]
+      Event.stopObserving( _elem, _eventName, _prevFn, _prevCapture )
+      _cache.elems.splice( _elemIdx, 1 )
+      _cache.fns.splice( _elemIdx, 1 )
+      _cache.capture.splice( _elemIdx, 1 )
+    Event.observe( _elem, _eventName, _anonFn, _capture )
+    _cache.elems.unshift( _elem )
+    _cache.fns.unshift( _anonFn )
+    _cache.capture.unshift( _capture )
+    true
+  #
+  # Stop observing event
+  stopObserving: (_elem, _eventName)->
+    return false unless @_observerMethods[_eventName]?
+    if @_observerMethods[_eventName].elems.length == 0
+      delete @_observerMethods[_eventName]
+      return false
+    _cache = @_observerMethods[_eventName]
+    _elemIdx = _cache.elems.indexOf(_elem)
+    return false if _elemIdx == -1
+    _prevFn = _cache.fns[_elemIdx]
+    _prevCapture = _cache.capture[_elemIdx]
+    Event.stopObserving( _elem, _eventName, _prevFn, _prevCapture )
+    _cache.elems.splice( _elemIdx, 1 )
+    _cache.fns.splice( _elemIdx, 1 )
+    _cache.capture.splice( _elemIdx, 1 )
+    return true
+  #
+  # This structure keeps track of view-event bindings:
+  _listeners: {
+    byId: {} # viewId => [ eventName, eventName, .. ]
+    _rectHoverIntersectMode: []
+    byEvent: # event names by viewId
+      mouseMove:    [] # viewIds
+      mouseDown:    [] # viewIds
+      mouseUp:      [] # viewIds
+      draggable:    [] # viewIds
+      droppable:    [] # viewIds
+      rectHover:    [] # viewIds
+      multiDrop:    [] # viewIds
+      keyDown:      [] # viewIds
+      keyUp:        [] # viewIds
+      mouseWheel:   [] # viewIds
+      textEnter:    [] # viewIds
+      click:        [] # viewIds
+      resize:       [] # viewIds
+      doubleClick:  [] # viewIds
+      contextMenu:  [] # viewIds
+    focused:  [] # viewIds
+    enabled:  [] # viewIds
+    dragged:  [] # viewIds
+    selected: [] # viewIds
+    hovered:  [] # viewIds
+    active:   [] # viewIds
+  }
+  #
+  # Returns the global target element based on browser type
+  _getGlobalTargetElem: ->
+    if BROWSER_TYPE.ie and !BROWSER_TYPE.ie9
+      return window.document
+    else
+      return window
+  #
+  # Starts EventManager
+  start: ->
+    @_views = HSystem.views # shortcut to system views
+    _targetElem = @_getGlobalTargetElem()
+    _methods = @_eventMethods
+    _methods.push( 'keyPress' ) unless BROWSER_TYPE.safari or BROWSER_TYPE.ie
+    for _methodName in _methods
+      if _methodName == 'doubleClick'
+        _eventName = 'dblclick'
+      else
+        _eventName = _methodName.toLowerCase()
+      @observe( _targetElem, _eventName, _methodName )
+    if window.addEventListener?
+      @observe( window, 'DOMMouseScroll', 'mouseWheel' )
+      @observe( window, 'resize', 'resize' )
+    @observe( window, 'blur', '_domWindowBlur' )
+    @observe( window, 'focus', '_domWindowFocus' )
+    @_legacyStart()
+  #
+  # Stops EventManager
+  stop: ->
+    delete @_views
+    _targetElem = @_getGlobalTargetElem()
+    _methods = @_eventMethods
+    _methods.push( 'keyPress' ) unless BROWSER_TYPE.safari or BROWSER_TYPE.ie
+    for _methodName in _methods
+      if _methodName == 'doubleClick'
+        _eventName = 'dblclick'
+      else
+        _eventName = _methodName.toLowerCase()
+      @stopObserving( _targetElem, _eventName, _methodName )
+    if window.addEventListener?
+      @stopObserving( window, 'DOMMouseScroll', 'mouseWheel' )
+      @stopObserving( window, 'resize', 'resize' )
+    @stopObserving( window, 'blur', '_domWindowBlur' )
+    @stopObserving( window, 'focus', '_domWindowFocus' )
+  #
+  ## LEGACY; to be removed
+  #
+  # Set to false, if your app don't need drop events.
+  # Setting this to false, when not needed, improves over-all performance,
+  # because the drop events need constant calculation of where the mouse
+  # curser (or last touch) was against all possible drop targets.
+  enableDroppableChecks: true
+  #
+  # Initializes the members used by the drop-related events.
+  # This method is called from within the EventMangaer and is never called,
+  # if @enableDroppableChecks is false
+  startDroppable: ->
+    @warn "EventManager#startDroppable is deprecated"
+    @hovered = [] # Drop-eligible items under the mouse cursor
+    @hoverInterval = 200 # Milliseconds between checks
+    @hoverTimer = new Date().getTime() # Time since last check was triggered
+  #
+  # Legacy startup, semi-compatible
+  _legacyStart: ->
+    @warn "EventManager#"+'_'+"legacyStart is deprecated"
+    @listeners = [] # NOT SUPPORTED
+    @focused = @_listeners.focused # DEPRECATED
+    @resizeListeners = @_listeners.byEvent.resize # DEPRECATED
+    @eventOptions = @_listeners.byId # DEPRECATED
+    @dragItems = @_listeners.dragged # DEPRECATED
+    @topmostDroppable = null # NOT SUPPORTED
+    @textEnterCtrls = @_listeners.byEvent.textEnter # DEPRECATED
+    @_coordCache = [] # NOT SUPPORTED
+    @_coordCacheFlag = true # NOT SUPPORTED
+    @_lastCoordFlushTimeout = null # NOT SUPPORTED
+    @activeControl = null # NOT SUPPORTED
+    @_lastKeyDown = null # NOT SUPPORTED
+    @_origDroppableChecks = @enableDroppablechecks # DEPRECATED
+    @startDroppable() if @enableDroppableChecks # DEPRECATED
+  #
+  # Flushes the position cache by elemId. If no elemId is specified,
+  # everything is flushed.
+  coordCacheFlush: (_elemId)->
+    @warn "EventManager#coordCacheFlush is deprecated"
+    if _elemId
+      @_coordCache[_elemId] = null
+    else
+      @_coordCache = []
+  #
+  # Flushed mouseMove timers, actually did more or less all the mouseMove work:
+  flushMouseMove: (x,y)->
+    @warn( "EventManager#flushMouseMove => Unsupported call, don't call it!", _ctrl )
+    return false
+  ## /LEGACY
+  #
+  # Ensures the type of the object is a HControl
+  _ensureValidControl: (_ctrl,_warnMethodName)->
+    _warnMethodName = '[unknown]' unless _warnMethodName
+    unless _ctrl.hasAncestor?
+      @warn( "EventManager##{_warnMethodName} => Not a HClass: ", _ctrl )
+      return false
+    unless _ctrl.hasAncestor( HView ) and _ctrl.isCtrl
+      @warn( "EventManager##{_warnMethodName} => Not a HControl: ", _ctrl )
+      return false
+    return true
+  #
+  # Ensure valid eventOptions
+  _ensureValidEventOptions: (_eventOptions,_warnMethodName)->
+    _warnMethodName = '[unknown]' unless _warnMethodName
+    if !( typeof _eventOptions == 'object' )
+      @warn( "EventManager##{_warnMethodName} => Invalid eventOptions: ", _eventOptions )
+      return false
+    return true
+  #
+  # Converts eventOptions into a list of enabled event names
+  _setEventOptions: (_ctrl,_eventOptions,_warnMethodName)->
+    _warnMethodName = '[unknown]' unless _warnMethodName
+    _viewId = _ctrl.viewId
+    _eventsOn = []
+    for _key of @_defaultEventOptions
+      continue if _key == 'base' or _key == 'constructor'
+      if @_listeners.byEvent[_key]? and _eventOptions[_key]?
+        _value = _eventOptions[_key]
+        if _value
+          _eventsOn.push( _key )
+          @_listeners.byEvent[_key].unshift( _viewId ) if @_listeners.byEvent[_key].indexOf(_viewId) == -1
+          if _key == 'rectHover' and _value == 'intersects' and @_listeners._rectHoverIntersectMode.indexOf( _viewId ) == -1
+            @_listeners._rectHoverIntersectMode.unshift( _viewId )
+        else
+          _idx = @_listeners.byEvent[_key].indexOf(_viewId)
+          if _idx != -1
+            @_listeners.byEvent[_key].splice( _idx, 1 )
+      else
+        @warn( "EventManager##{_warnMethodName} => Invalid event type: #{_key}" )
+    _this = @
+    @_listeners.byId[_viewId] = _eventsOn
+    if _ctrl.enabled
+      @_listeners.enabled.unshift( _viewId ) if @_listeners.enabled.indexOf(_viewId) == -1
+      _elem = ELEM.get( _ctrl.elemId )
+      @observe( _elem, 'mouseover', '_mouseOver' )
+  #
+  # Releases bindings done by #_setEventOptions
+  _unsetEventOptions: (_ctrl,_warnMethodName)->
+    _warnMethodName = '[unknown]' unless _warnMethodName
+    _viewId = _ctrl.viewId
+    if @_listeners.byId[_viewId]?
+      delete @_listeners.byId[_viewId]
+    else
+      @warn( "EventManager##{_warnMethodName} => viewId not registered: #{_viewId}" )
+      console.log(@_listeners.byId[_viewId],_viewId,_ctrl)
+    for _key, _value of @_listeners.byEvent
+      _viewIdx = _value.indexOf(_viewId)
+      if _viewIdx != -1
+        _value.splice(_viewIdx,1)
+      if _key == 'rectHover'
+        _intersectHoverIdx = @_listeners._rectHoverIntersectMode.indexOf( _viewId )
+        if _intersectHoverIdx != -1
+          @_listeners._rectHoverIntersectMode.splice( _intersectHoverIdx, 1 )
+    _wasFocused = false
+    _elem = ELEM.get( _ctrl.elemId )
+    for _statusItem in [ 'dragged', 'selected', 'hovered', 'active', 'focused', 'enabled' ]
+      _viewIdx = @_listeners[_statusItem].indexOf(_viewId)
+      if _viewIdx != -1
+        if _statusItem == 'dragged'
+          _ctrl.endDrag( @status.crsrX, @status.crsrY )
+        else if _statusItem == 'selected'
+          _ctrl.deSelect()
+        else if _statusItem == 'hovered'
+          _ctrl.endHover( null )
+        else if _statusItem == 'active'
+          _ctrl._lostActiveStatus( null )
+        else if _statusItem == 'focused'
+          # _ctrl._mouseOut()
+          @stopObserving( _elem, 'mouseout', '_mouseOut' )
+          _wasFocused = true
+        else if _statusItem == 'enabled'
+          unless _wasFocused
+            @stopObserving( _elem, 'mouseover', '_mouseOver' )
+          _ctrl.setEnabled( false ) if _ctrl.enabled
+        @_listeners[_statusItem].splice(_viewIdx,1)
+  #
+  # Registers the HControl -derived object _ctrl by event listener flags
+  # in _eventOptions.
+  reg: (_ctrl, _eventOptions)->
+    return false unless @_ensureValidControl( _ctrl, 'reg' )
+    return false unless @_ensureValidEventOptions( _eventOptions, 'reg' )
+    @_setEventOptions( _ctrl, _eventOptions, 'reg' )
+    return true
+  #
+  # Returns status of registration
+  _isreg: (_ctrl)->
+    return @_listeners.byId[_ctrl.viewId]?
+  #
+  # Unregisters the HControl -derived object from all its bindings
+  unreg: (_ctrl)->
+    return false unless @_ensureValidControl( _ctrl, 'unreg' )
+    return false unless @_isreg( _ctrl )
+    @_unsetEventOptions(_ctrl,'unreg')
+  #
+  #
+  ## Event responders; mid-level handlers.
+  ## These all receive the global events and check where to delegate them.
+  #
+  # Handle event modifiers
+  _modifiers: (e)->
+    [ _x, _y ] = ELEM.getScrollPosition(0)
+    [ x, y ] = [ Event.pointerX(e) - _x, Event.pointerY(e) - _y ]
+    unless isNaN(x) or isNaN(y)
+      @status.setCrsr( x, y )
+    @status.setAltKey( e.altKey )
+    @status.setCtrlKey( e.ctrlKey )
+    @status.setShiftKey( e.shiftKey )
+    @status.setMetaKey( e.metaKey )
+  #
+  # Resize is an event triggered by resizing the browser window
+  # (as well as the HWindow component, as a special case)
+  #
+  # The HSystem._updateFlexibleRects call may not be neccessary to call
+  # both before and after in all circumstances, but better be safe than sure.
+  resize: (e)->
+    HSystem._updateFlexibleRects()
+    for _viewId in @_listeners.byEvent.resize
+      _ctrl = @_views[_viewId]
+      _ctrl.resize() if _ctrl.resize?
+      ## Deprecate this:
+      if _ctrl.onResize?
+        @warn( "EventManager#resize => The 'onResize' event responder is deprecated. Please rename it to 'resize'." )
+        _ctrl.onResize()
+      ## /Deprecate
+    HSystem._updateFlexibleRects()
+  #
+  # Finds the next elem with a view_id attribute
+  _findViewId: (_elem)->
+    until _elem.view_id? or _elem == document.body
+      _elem = _elem.parentNode
+    return _elem
+  #
+  # Finds the ctrl based on the element by getting the view_id attribute
+  _findEventControl: (e,_warnMethodName,_stop)->
+    _warnMethodName = '[unknown]' unless _warnMethodName
+    _elem = Event.element(e)
+    _ctrl = null
+    until _ctrl
+      _elem = @_findViewId( _elem )
+      return false if _elem == document.body
+      unless _elem.view_id?
+        @warn( "EventManager##{_warnMethodName} => The element doesn't have an 'view_id' attribute.")
+        return false
+      _viewId = _elem.view_id
+      unless @_views[_viewId]?
+        @warn( "EventManager##{_warnMethodName} => The viewId:#{_viewId} doesn't have a view.")
+        return false
+      _ctrl = @_views[_viewId]
+      unless _ctrl.isCtrl #@_ensureValidControl(_ctrl,_warnMethodName)
+        _ctrl = null
+        _elem = _elem.parentNode
+    Event.stop(e) if _stop
+    return _ctrl
+  #
+  # Enables focused state of enabled HControls by listening to the
+  # view-element-specific mouseover event.
+  _mouseOver: (e)->
+    _ctrl = @_findEventControl(e, '_'+'mouseOver')
+    @focus(_ctrl) if _ctrl
+  #
+  # Disables focused state of enabled HControls by listening to the
+  # view-element-specific mouseout event.
+  _mouseOut: (e)->
+    _ctrl = @_findEventControl(e, '_'+'mouseOut')
+    @blur(_ctrl) if _ctrl
+  #
+  # Focuses a control, triggered based on the view-element-specific
+  # mouseover event.
+  focus: (_ctrl)->
+    _viewId = _ctrl.viewId
+    if @_listeners.focused.indexOf(_viewId) == -1
+      _elem = ELEM.get( _ctrl.elemId )
+      @observe( _elem, 'mouseout', '_mouseOut' )
+      @stopObserving( _elem, 'mouseover', '_mouseOver' )
+      @_listeners.focused.unshift(_viewId)
+      unless _ctrl.focus?
+        @warn( "EventManager#focus => The viewId:#{_viewId} doesn't have a 'focus' method.")
+        return false
+      _ctrl.focus()
+  #
+  # Blurs a control, triggered based on the view-element-specific
+  # mouseout event.
+  blur: (_ctrl)->
+    _viewId = _ctrl.viewId
+    _viewIdx = @_listeners.focused.indexOf(_viewId)
+    if _viewIdx != -1
+      _elem = ELEM.get( _ctrl.elemId )
+      @observe( _elem, 'mouseover', '_mouseOver' )
+      @stopObserving( _elem, 'mouseout', '_mouseOut' )
+      @_listeners.focused.splice(_viewIdx,1)
+      unless _ctrl.blur?
+        @warn( "EventManager#blur => The viewId:#{_viewId} doesn't have a 'blur' method.")
+        return false
+      ## Should probably perform additional de-registration on active events
+      ## dependant on focus here.
+      ##
+      ##
+      _ctrl.blur()
+  #
+  # Mouse movement manager. Triggered by the global mousemove event.
+  # Delegates the following event responder methods to focused HControl instances:
+  # - drag
+  # - mouseMove
+  # - endHover
+  # - startHover
+  mouseMove: (e)->
+    @_modifiers(e) # fetch event modifiers
+    [ x, y ] = @status.crsr
+    Event.stop(e) if @_handleMouseMove( x, y )
+  #
+  # Just split to gain namespace:
+  _handleMouseMove: ( x, y )->
+    @_delegateMouseMove(x,y)
+    _currentlyDragging = @_delegateDrag(x,y)
+    return _currentlyDragging
+  #
+  # Handle items being dragged, sending #drag(x,y) calls to them
+  _delegateDrag: (x, y)->
+    _dragItems = @_listeners.dragged
+    return false if _dragItems.length == 0
+    for _viewId in _dragItems
+      _ctrl = @_views[_viewId]
+      _ctrl.drag(x,y)
+      @_delegateHover( _ctrl, x, y )
+    return true
+  #
+  # Handle items wanting #mouseMove(x,y) calls
+  _delegateMouseMove: (x,y)->
+    _mouseMoveItems = @_listeners.byEvent.mouseMove
+    return false if _mouseMoveItems.length == 0
+    for _viewId in _mouseMoveItems
+      _ctrl = @_views[_viewId]
+      _ctrl.mouseMove(x,y)
+    return true
+  #
+  # Handle items wanting #startHover( _dragObj ),
+  # #hover( _dragObj ) and #endHover( _dragObj ) calls
+  _delegateHover: (_ctrl, x, y)->
+    _byEvent = @_listeners.byEvent
+    _findPoint     = _byEvent.rectHover.indexOf( _ctrl.viewId ) == -1
+    _findTopmost   = _byEvent.multiDrop.indexOf( _ctrl.viewId ) == -1
+    _findIntersect = true
+    if _findPoint
+      _area = HPoint.new( x, y )
+      _matchMethod = 'contains'
+    else
+      _rect = _ctrl.rect
+      _area = HRect.new( x, y, _rect.width, _rect.height )
+      if @_listeners._rectHoverIntersectMode.indexOf( _viewId ) == -1
+        _matchMethod = 'intersects'
+      else
+        _matchMethod = 'contains'
+    if _findTopmost
+      _hoverItems = @_findTopmostDroppable(_area,_matchMethod,_ctrl.viewId)
+    else
+      _hoverItems = @_findAllDroppable(_area,_matchMethod,_ctrl.viewid)
+    _endHover = []
+    for _hoverId in @_listeners.hovered
+      if _hoverItems.indexOf( _hoverId ) == -1
+        _endHover.push( _hoverId )
+    _startHover = []
+    for _hoverId in _hoverItems
+      if @_listeners.hovered.indexOf( _hoverId ) == -1
+        _startHover.push( _hoverId )
+    for _viewId in _startHover
+      @_views[_viewId].startHover(_ctrl)
+    for _viewId in _endHover
+      @_views[_viewId].endHover(_ctrl)
+    for _viewId in _hoverItems
+      @_views[_viewId].hover(_ctrl)
+    @_listeners.hovered = _hoverItems
+  #
+  # Finds the topmost drop/hover target within the area specified by rectHover
+  _findTopmostDroppable: (_area,_matchMethod,_selfId)->
+    _views = @_views
+    _droppable = @_listeners.byEvent.droppable
+    _search = (_parentIds)->
+      for _viewId in _parentIds
+        continue if _viewId == _selfId
+        _view = _views[_viewId]
+        if _view.hasAncestor? and _view.hasAncestor( HView ) and _view.rect[_matchMethod](_area)
+          if _droppable.indexOf( _viewId ) != -1
+            _dropId = _search( _view.viewsZOrder.slice().reverse() )
+            return _dropId if _dropId
+            return _viewId
+      return false
+    _dropId = _search( HSystem.viewsZOrder.slice().reverse() )
+    return [ _dropId ] if _dropId
+    return []
+  #
+  # Finds all drop/hover targets within the area specified by rectHover
+  _findAllDroppable: (_area,_matchMethod,_selfId)->
+    _views = @_views
+    _droppable = @_listeners.byEvent.droppable
+    _found = []
+    _search = (_parentIds)->
+      for _viewId in _parentIds
+        continue if _viewId == _selfId
+        _view = _views[_viewId]
+        if _view.hasAncestor? and _view.hasAncestor( HView ) and _view.rect[_matchMethod](_area)
+          _found.push( _viewId ) if _droppable.indexOf( _viewId ) != -1
+          _search( _view.viewsZOrder.slice().reverse() )
+    _search( HSystem.viewsZOrder.slice().reverse() )
+    return _found
+  #
+  # Sets the active control
+  ###
+  changeActiveControl: (_ctrl)->
+    _isCtrl = (_ctrl != null) and @_ensureValidControl( _ctrl )
+    _ctrl = null unless _isCtrl
+    _active = @_listeners.active
+    _focused = @_listeners.focused
+    return if _ctrl != null and _active[0] == _ctrl.viewId
+    _prevActive = _active.slice()
+    if _isCtrl and _prevActive.indexOf( _ctrl.viewId ) != -1
+      _idx = _prevActive.indexOf( _ctrl.viewId )
+      _prevActive.splice( _idx, 1 )
+    _deactivated = []
+    # lose activity in previous controls first:
+    for _viewId in _active
+      continue if _isCtrl and _viewId == _ctrl.viewId
+      _target = @_views[_viewId]
+      _allowLose = _target._lostActiveStatus( _ctrl )
+      if _allowLose
+        @blur( _target.viewId ) if _focused.indexOf(_target.viewId) != -1
+        _target.active = false
+        _deactivated.push( _viewId )
+    for _viewId in _deactivated
+      _idx = _active.indexOf( _viewId )
+      _active.splice( _idx, 1 )
+      _idx = _prevActive.indexOf( _viewId )
+      _prevActive.splice( _idx, 1 )
+    if _isCtrl
+      _active.unshift(_ctrl.viewId)
+      @focus(_ctrl.viewId) if _focused.indexOf(_ctrl.viewId) == -1
+      _ctrl.active = true
+      for _viewId in _prevActive
+        _ctrl._gainedActiveStatus( @_views[_viewId] )
+  ###
+  delActiveControl: (_newActive)->
+    _active = @_listeners.active
+    _focused = @_listeners.focused
+    return null if _active.length == 0
+    if _active.length == 1
+      _prevActive = @_views[_active[0]]
+    else
+      @warn "Danger, too many active items: #{JSON.stringify(_active)}"
+    for _viewId in _active.slice()
+      continue if _newActive != null and _viewId == _newActive.viewId
+      _ctrl = @_views[_viewId]
+      _ctrl.active = false
+      _idx = _active.indexOf( _viewId )
+      _active.splice( _idx, 1 )
+      @blur(_ctrl) if _focused.indexOf(_viewId) != -1
+      _ctrl.lostActiveStatus(_newActive)
+    _prevActive
+  addActiveControl: (_ctrl,_prevActive)->
+    _active = @_listeners.active
+    _focused = @_listeners.focused
+    _idx = _active.indexOf( _ctrl.viewId )
+    if _idx == -1
+      _active.unshift(_ctrl.viewId)
+      @focus(_ctrl) if _focused.indexOf(_ctrl.viewId) == -1
+      _ctrl.active = true
+      _ctrl.gainedActiveStatus(_prevActive)
+  changeActiveControl: (_ctrl)->
+    # @idle()
+    _prevActive = @delActiveControl(_ctrl)
+    # @idle()
+    @addActiveControl(_ctrl, _prevActive) if _ctrl != null
+    # @idle()
+  #
+  # Method to be called, when you want to make an item draggable from outside of the EventManager
+  startDragging: (_ctrl)->
+    return if !_ctrl.enabled
+    _viewId = _ctrl.viewId
+    @focus( _viewId )
+    @changeActiveControl(_ctrl)
+    @_listeners.dragged.unshift( _viewId ) if @_listeners.dragged.indexOf( _viewId ) == -1
+    _ctrl.startDrag( @status.crsrX, @status.crsrY, @status.button2 )
+  #
+  # Cancels text selections, which happen by
+  _cancelTextSelection: ->
+    # Remove possible selections.
+    ELEM.get(0).focus()
+  #
+  # Mouse button press manager. Triggered by the global mouseDown event.
+  # Delegates the following event responder methods to active HControl instances:
+  # - mouseDown
+  # - startDrag
+  mouseDown: (e)->
+    @_modifiers(e)
+    _leftClick = Event.isLeftClick(e)
+    if _leftClick
+      @status.setButton1( true )
+    else
+      @status.setButton2( true )
+    _focused = @_listeners.focused
+    _active  = @_listeners.active
+    _dragged = @_listeners.dragged
+    _mouseDownable = @_listeners.byEvent.mouseDown
+    _draggable = @_listeners.byEvent.draggable
+    _newActive = []
+    _mouseDownIds = []
+    _startDragIds = []
+    _stop = false
+    for _viewId in _focused
+      _newActive.push( _viewId ) if _active.indexOf(_viewId) == -1
+      _eventOptions = @_listeners.byId[_viewId]
+      if _mouseDownable.indexOf( _viewId ) != -1
+        _mouseDownIds.push( _viewId )
+      if _draggable.indexOf( _viewId ) != -1 and _dragged.indexOf( _viewId ) == -1
+        _startDragIds.push( _viewId )
+    for _viewId in _newActive
+      _ctrl = @_views[_viewId]
+      @changeActiveControl( _ctrl )
+    [ x, y ] = @status.crsr
+    for _viewId in _mouseDownIds
+      _ctrl = @_views[_viewId]
+      _stop = true if _ctrl.mouseDown( x, y, _leftClick )
+    for _viewId in _startDragIds
+      if _dragged.indexOf( _viewId ) == -1
+        _ctrl = @_views[_viewId]
+        _dragged.unshift( _viewId )
+        _stop = true if _ctrl.startDrag( x, y, _leftClick )
+    @_handleMouseMove(x,y)
+    @_cancelTextSelection() unless _startDragIds.length == 0 and _mouseDownIds.length == 0
+    Event.stop(e) if _stop
+  #
+  # Mouse button press manager. Triggered by the global mouseDown event.
+  # Delegates the following event responder methods to active HControl instances:
+  # - mouseUp
+  # - endDrag
+  # - endHover
+  # - drop
+  mouseUp: (e)->
+    @_modifiers(e)
+    _leftClick = Event.isLeftClick(e)
+    @status.setButton1( false )
+    @status.setButton2( false )
+    return false unless _leftClick
+    _focused = @_listeners.focused
+    _active  = @_listeners.active
+    _dragged = @_listeners.dragged
+    _hovered = @_listeners.hovered
+    _mouseUppable = @_listeners.byEvent.mouseUp
+    _draggable = @_listeners.byEvent.draggable
+    _newActive = []
+    _mouseUpIds = []
+    _endDragIds = []
+    _stop = false
+    for _viewId in _focused
+      _newActive.push( _viewId ) if _active.indexOf(_viewId) == -1
+      _eventOptions = @_listeners.byId[_viewId]
+      if _mouseUppable.indexOf( _viewId ) != -1
+        _mouseUpIds.push( _viewId )
+      if _draggable.indexOf( _viewId ) != -1 and _dragged.indexOf( _viewId ) != -1
+        _endDragIds.push( _viewId )
+    for _viewId in _newActive
+      _ctrl = @_views[_viewId]
+      @changeActiveControl( _ctrl )
+    [ x, y ] = @status.crsr
+    for _viewId in _mouseUpIds
+      _ctrl = @_views[_viewId]
+      _stop = true if _ctrl.mouseUp( x, y, _leftClick )
+    for _viewId in _endDragIds
+      _dragIdx = _dragged.indexOf( _viewId )
+      unless _dragIdx == -1
+        _ctrl = @_views[_viewId]
+        _dragged.splice( _dragIdx, 1 )
+        for _dropViewId in _hovered
+          _dropCtrl = @_views[_dropViewId]
+          _dropCtrl.endHover(_ctrl) if _dropCtrl.endHover?
+          _dropCtrl.drop(_ctrl) if _dropCtrl.drop?
+        _stop = true if _ctrl.endDrag( x, y, _leftClick )
+    @_listeners.hovered = []
+    @_listeners.dragged = []
+    @_handleMouseMove(x,y)
+    @_cancelTextSelection() unless _endDragIds.length == 0 and _mouseUpIds.length == 0
+    Event.stop(e) if _stop
+    ## /jatka
+  #
+  # Handles mouse button clicks
+  # It's different from mouseUp/mouseDown, because it's a different event,
+  # and is supported by touch screen devices
+  click: (e)->
+    @_modifiers(e)
+    _leftClick = Event.isLeftClick(e)
+    if _leftClick
+      @status.setButton1( false )
+    else
+      # there is a separate event for context menu, and only
+      # Firefox fires click separately
+      return true
+    _focused = @_listeners.focused
+    _active  = @_listeners.active
+    _clickable = @_listeners.byEvent.click
+    _newActive = []
+    _clickIds = []
+    _stop = false
+    for _viewId in _focused
+      _newActive.push( _viewId ) if _active.indexOf(_viewId) == -1
+      if _clickable.indexOf(_viewId) != -1
+        _clickIds.push( _viewId )
+    for _viewId in _newActive
+      _ctrl = @_views[_viewId]
+      @changeActiveControl( _ctrl )
+    [ x, y ] = @status.crsr
+    for _viewId in _clickIds
+      _ctrl = @_views[_viewId]
+      unless _ctrl.click? and typeof _ctrl.click == 'function'
+        @warn( 'no click:', _ctrl, _ctrl.click?, typeof _ctrl.click )
+        continue
+      _stop = true if _ctrl.click( x, y, _leftClick )
+    @_handleMouseMove(x,y)
+    Event.stop(e) if _stop
+  #
+  # Handles doubleClick events
+  doubleClick: (e)->
+    @_modifiers(e)
+    _leftClick = Event.isLeftClick(e)
+    @status.setButton1( false )
+    @status.setButton2( false )
+    [ x, y ] = @status.crsr
+    @_handleMouseMove(x,y)
+    _focused = @_listeners.focused
+    _doubleClicks = []
+    _doubleClickable = @_listeners.byEvent.doubleClick
+    _stop = false
+    for _viewId in _focused
+      if _doubleClickable.indexOf(_viewId) != -1
+        _doubleClicks.push( _viewId )
+    for _viewId in _doubleClickable
+      _ctrl = @_views[_viewId]
+      if _ctrl.doubleClick?
+        _stop = true if _ctrl.doubleClick(x,y,true)
+    Event.stop(e) if _stop
+  #
+  # Handles mouseWheel events (any HID scroll event)
+  mouseWheel: (e)->
+    e = window.event unless e
+    @_modifiers(e)
+    if e.wheelDelta
+      _delta = 0-(e.wheelDelta/120)
+    else if e.detail
+      _delta = 0-(e.detail/3)
+    if BROWSER_TYPE.opera or BROWSER_TYPE.safari or BROWSER_TYPE.ie
+      _delta = 0-_delta
+    _focused = @_listeners.focused
+    _mouseWheels = []
+    _mouseWheelable = @_listeners.byEvent.mouseWheel
+    _stop = false
+    for _viewId in _focused
+      if _mouseWheelable.indexOf(_viewId) != -1
+        _mouseWheels.push( _viewId )
+    for _viewId in _mouseWheels
+      _ctrl = @_views[_viewId]
+      if _ctrl.mouseWheel?
+        _stop = true if _ctrl.mouseWheel( _delta )
+    Event.stop(e) if _stop
+  #
+  # Handles the contextMenu event
+  contextMenu: (e)->
+    @_modifiers(e)
+    _stop = true
+    @status.setButton1( false )
+    @status.setButton2( false )
+    _focused = @_listeners.focused
+    _contextMenuable = @_listeners.byEvent.contextMenu
+    for _viewId in _focused
+      if _contextMenuable.indexOf(_viewId) != -1
+        _ctrl = @_views[_viewId]
+        _stop = false if _ctrl.contextMenu? and _ctrl.contextMenu()
+    Event.stop(e) if _stop
+  #
+  # Keycode translation tables
+  _keyTrans:
+    opera:
+      # Symbol keys:
+      59: 186 # [;:]
+      61: 187 # [=+]
+      44: 188 # [,<]
+      45: 189 # [-_]
+      46: 190 # [.>]
+      47: 191 # [/?]
+      96: 192 # [`~]
+      91: 219 # [[{]
+      92: 220 # [\|]
+      93: 221 # []}]
+      39: 222 # ['"]
+
+      # Numeric keypad keys can't be mapped on Opera, because Opera
+      # doesn't differentiate between the keys on the numeric keypad
+      # versus the functionally same keys elsewhere on the keyboard.
+
+      # Branded keys:
+      # Apple Command keys are same as ctrl, but ctrl is 0; Can't be re-mapped reliably.
+      # The Windows Menu key also return 0, so it can't be re-mapped either.
+      219: 91 # Left Windows key (Start)
+      220: 92 # Right Windows key (Start)
+    mozilla:
+      # Symbol keys:
+      59: 186  # [;:]
+      61: 187  # [=+]
+      109: 189 # [-_]
+
+      # Branded keys:
+      224: 91 # Apple Command key to left windows key mapping
+  #
+  # Translates keyCodes to the normalized pseudo-ascii used by IE and WebKit browsers.
+  # Opera and Mozilla browsers use different codes, so they'll need translations.
+  translateKeyCodes: (_keyCode)->
+    # We use the WebKit and IE browsers as the normalization base, because
+    # there is no variance between in these. Returns the keyCode as-is for
+    # browsers in this category.
+    if BROWSER_TYPE.safari or BROWSER_TYPE.ie
+      return _keyCode
+    # Opera has its own keyCodes, which are different from all others.
+    else if BROWSER_TYPE.opera
+      _transCode = @_keyTrans.opera[_keyCode]
+    # The assumption is that the other browsers do what mozille does.
+    else
+      _transCode = @_keyTrans.mozilla[_keyCode]
+    # No translation needed:
+    return _keyCode if not _transCode? or _transCode == null
+    # Return translated:
+    return _transCode
+  #
+  # List of keycodes considered command keys
+  _cmdKeys: [
+    17, # Ctrl
+    91, # Others (Left Start Key or Left Command Key)
+    92, # Others (Right Start Key)
+    93  # Others (Menu Key or Right Command Key)
+  ]
+  _detectCmdKey: ( _keyCode )->
+    # On Opera, return true on any of the keycodes
+    if BROWSER_TYPE.opera
+      return @_cmdKeys.indexOf(_keyCode) != -1
+    # Any mac browser (except opera, above) uses left or right windows key
+    # equivalent as the Command key.
+    else if BROWSER_TYPE.mac
+      return _keyCode == 91 or _keyCode == 93
+    # Other platforms use CTRL as the command key.
+    return _keyCode == 17
+  #
+  # Handles the keyDown event
+  keyDown: (e)->
+    @_modifiers(e)
+    _keyCode = @translateKeyCodes( e.keyCode )
+    _stop = false
+    if !@status.cmdKeyDown and @_detectCmdKey( _keyCode )
+      @status.setCmdKey( true )
+      _stop = true
+    _active = @_listeners.active
+    _keyDowners = @_listeners.byEvent.keyDown
+    _keyDowns = []
+    unless @status.hasKeyDown( _keyCode ) and @_lastKeyDown != _keyCode
+      for _viewId in _active
+        _keyDowns.push( _viewId ) if _keyDowners.indexOf( _viewId ) != -1
+      @status.addKeyDown( _keyCode )
+    # repeat not implemented yet
+    for _viewId in _keyDowns
+      _ctrl = @_views[_viewId]
+      if _ctrl.keyDown?
+        _stop = true if _ctrl.keyDown(_keyCode)
+    @_lastKeyDown = _keyCode
+    Event.stop(e) if _stop
+  keyUp: (e)->
+    @_modifiers(e)
+    _keyCode = @translateKeyCodes( e.keyCode )
+    _stop = false
+    if @status.cmdKeyDown and @_detectCmdKey( _keyCode )
+      @status.setCmdKey( false )
+      _stop = true
+    _active = @_listeners.active
+    _keyUppers = @_listeners.byEvent.keyUp
+    _keyUps = []
+    _textEnterers = @_listeners.byEvent.textEnter
+    _textEnters = []
+    if @status.hasKeyDown( _keyCode )
+      for _viewId in _active
+        _keyUps.push( _viewId ) if _keyUppers.indexOf( _viewId ) != -1
+        _textEnters.push( _viewId ) if _textEnterers.indexOf( _viewId ) != -1
+      @status.delKeyDown( _keyCode )
+    for _viewId in _keyUppers
+      _ctrl = @_views[_viewId]
+      if _ctrl.keyUp?
+        _stop = true if _ctrl.keyUp( _keyCode )
+    for _viewId in _textEnters
+      _ctrl = @_views[_viewId]
+      if _ctrl.textEnter?
+        _stop = true if _ctrl.textEnter( _keyCode )
+    Event.stop(e) if _stop
+  keyPress: (e)->
+    @warn('EventManager#keyPress not implemented')
+  isKeyDown: (_keyCode)->
+    @warn('EventManager#isKeyDown() is deprecated, use #status.hasKeyDown() instead')
+    @status.hasKeyDown( _keyCode )
+  isKeyUp: (_keyCode)->
+    @warn('EventManager#isKeyUp() is deprecated, use !#status.hasKeyDown() instead')
+    (not @status.hasKeyDown( _keyCode ))
+  isAltKeyDown: ->
+    @warn('EventManager#isAltKeyDown is deprecated, use #status.altKeyDown instead')
+    @status.altKeyDown
+  isCtrlKeyDown: ->
+    @warn('EventManager#isCtrlKeyDown is deprecated, use #status.ctrlKeyDown instead')
+    @status.ctrlKeyDown
+  isShiftKeyDown: ->
+    @warn('EventManager#isShiftKeyDown is deprecated, use #status.shiftKeyDown instead')
+    @status.shiftKeyDown
+  isMetaKeyDown: ->
+    @warn('EventManager#isMetaKeyDown is deprecated, use #status.metaKeyDown instead')
+    @status.metaKeyDown
+  isCmdKeyDown: ->
+    @warn('EventManager#isCmdKeyDown is deprecated, use #status.cmdKeyDown instead')
+    @status.altKeyDown
+  #
+  # Debug output
+  # idle: ->
+  #   console.log( 'focused: ',
+  #     JSON.stringify(@_listeners.focused),'active:',
+  #     JSON.stringify(@_listeners.active),'dragged:',
+  #     JSON.stringify(@_listeners.dragged),'hovered:',
+  #     JSON.stringify(@_listeners.hovered) )
+  #
+  # Cleans up structures
+  die: ->
+    @stop()
+    @base()
+LOAD( ->
+  window.EventManager = EventManagerApp.new( 500, 'EventManager' )
+  # Alias:
+  window.EVENT = EventManager
+  EventManager.start()
+)