add alloy.xml grammar

add alloy.xml grammar

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

--- grammars/alloyxml.cson
+++ grammars/alloyxml.cson
@@ -0,0 +1,507 @@
+'scopeName': 'text.alloyxml'
+'firstLineMatch': '<Alloy'
+'fileTypes': [
+  # 'xml'
+]
+'name': 'ALLOY.XML'
+'patterns': [
+  {
+    'begin': '(<)([a-zA-Z0-9:-]++)(?=[^>]*></\\2>)'
+    'beginCaptures':
+      '1':
+        'name': 'punctuation.definition.tag.html'
+      '2':
+        'name': 'entity.name.tag.html'
+    'end': '(>(\\s*<)/)(\\2)(>)'
+    'endCaptures':
+      '1':
+        'name': 'punctuation.definition.tag.html'
+      '2':
+        'name': 'meta.scope.between-tag-pair.html'
+      '3':
+        'name': 'entity.name.tag.html'
+      '4':
+        'name': 'punctuation.definition.tag.html'
+    'name': 'meta.tag.any.html'
+    'patterns': [
+      {
+        'include': '#tag-stuff'
+      }
+    ]
+  }
+  {
+    'begin': '(<\\?)(xml)'
+    'captures':
+      '1':
+        'name': 'punctuation.definition.tag.html'
+      '2':
+        'name': 'entity.name.tag.xml.html'
+    'end': '(\\?>)'
+    'name': 'meta.tag.preprocessor.xml.html'
+    'patterns': [
+      {
+        'include': '#tag-generic-attribute'
+      }
+      {
+        'include': '#string-double-quoted'
+      }
+      {
+        'include': '#string-single-quoted'
+      }
+    ]
+  }
+  {
+    'begin': '<!--'
+    'captures':
+      '0':
+        'name': 'punctuation.definition.comment.html'
+    'end': '--\\s*>'
+    'name': 'comment.block.html'
+    'patterns': [
+      {
+        'match': '--(?!-*\\s*>)'
+        'name': 'invalid.illegal.bad-comments-or-CDATA.html'
+      }
+      {
+        'include': '#embedded-code'
+      }
+    ]
+  }
+  {
+    'begin': '<!'
+    'captures':
+      '0':
+        'name': 'punctuation.definition.tag.html'
+    'end': '>'
+    'name': 'meta.tag.sgml.html'
+    'patterns': [
+      {
+        'begin': '(?i:DOCTYPE)'
+        'captures':
+          '1':
+            'name': 'entity.name.tag.doctype.html'
+        'end': '(?=>)'
+        'name': 'meta.tag.sgml.doctype.html'
+        'patterns': [
+          {
+            'match': '"[^">]*"'
+            'name': 'string.quoted.double.doctype.identifiers-and-DTDs.html'
+          }
+        ]
+      }
+      {
+        'begin': '\\[CDATA\\['
+        'end': ']](?=>)'
+        'name': 'constant.other.inline-data.html'
+      }
+      {
+        'match': '(\\s*)(?!--|>)\\S(\\s*)'
+        'name': 'invalid.illegal.bad-comments-or-CDATA.html'
+      }
+    ]
+  }
+  {
+    'include': '#embedded-code'
+  }
+  {
+    'begin': '(?:^\\s+)?(<)((?i:style))\\b(?![^>]*/>)'
+    'captures':
+      '1':
+        'name': 'punctuation.definition.tag.html'
+      '2':
+        'name': 'entity.name.tag.style.html'
+      '3':
+        'name': 'punctuation.definition.tag.html'
+    'end': '(</)((?i:style))(>)(?:\\s*\\n)?'
+    'name': 'source.css.embedded.html'
+    'patterns': [
+      {
+        'include': '#tag-stuff'
+      }
+      {
+        'begin': '(>)'
+        'beginCaptures':
+          '1':
+            'name': 'punctuation.definition.tag.html'
+        'end': '(?=</(?i:style))'
+        'patterns': [
+          {
+            'include': '#embedded-code'
+          }
+          {
+            'include': 'source.css'
+          }
+        ]
+      }
+    ]
+  }
+  {
+    'begin': '(?:^\\s+)?(<)((?i:script))\\b(?=[^>]*\\btype\\s*=\\s*[\'"]?text/(x-handlebars|(x-handlebars-)?template|html)[\'"]?)(?![^>]*/>)'
+    'beginCaptures':
+      '1':
+        'name': 'punctuation.definition.tag.html'
+      '2':
+        'name': 'entity.name.tag.script.html'
+    'end': '(?<=</(script|SCRIPT))(>)(?:\\s*\\n)?'
+    'endCaptures':
+      '2':
+        'name': 'punctuation.definition.tag.html'
+    'contentName': 'text.embedded.html'
+    'patterns': [
+      {
+        'include': '#tag-stuff'
+      }
+      {
+        'begin': '(?<!</(?:script|SCRIPT))(>)'
+        'captures':
+          '1':
+            'name': 'punctuation.definition.tag.html'
+          '2':
+            'name': 'entity.name.tag.script.html'
+        'end': '(</)((?i:script))'
+        'patterns': [
+          {
+            'include': 'text.html.basic'
+          }
+        ]
+      }
+    ]
+  }
+  {
+    'begin': '(?:^\\s+)?(<)((?i:script))\\b(?=[^>]*\\btype\\s*=\\s*[\'"]?text/coffeescript[\'"]?)(?![^>]*/>)'
+    'beginCaptures':
+      '1':
+        'name': 'punctuation.definition.tag.html'
+      '2':
+        'name': 'entity.name.tag.script.html'
+    'end': '(?<=</(script|SCRIPT))(>)(?:\\s*\\n)?'
+    'endCaptures':
+      '2':
+        'name': 'punctuation.definition.tag.html'
+    'contentName': 'source.coffee.embedded.html'
+    'patterns': [
+      {
+        'include': '#tag-stuff'
+      }
+      {
+        'begin': '(?<!</(?:script|SCRIPT))(>)'
+        'captures':
+          '1':
+            'name': 'punctuation.definition.tag.html'
+          '2':
+            'name': 'entity.name.tag.script.html'
+        'end': '(</)((?i:script))'
+        'patterns': [
+          {
+            'captures':
+              '1':
+                'name': 'punctuation.definition.comment.coffee'
+            'match': '(#).*?((?=</script)|$\\n?)'
+            'name': 'comment.line.number-sign.coffee'
+          }
+          {
+            'include': 'source.coffee'
+          }
+        ]
+      }
+    ]
+  }
+  {
+    'begin': '(?:^\\s+)?(<)((?i:script))\\b(?![^>]*/>)'
+    'beginCaptures':
+      '1':
+        'name': 'punctuation.definition.tag.html'
+      '2':
+        'name': 'entity.name.tag.script.html'
+    'end': '(?<=</(script|SCRIPT))(>)(?:\\s*\\n)?'
+    'endCaptures':
+      '2':
+        'name': 'punctuation.definition.tag.html'
+    'contentName': 'source.js.embedded.html'
+    'patterns': [
+      {
+        'include': '#tag-stuff'
+      }
+      {
+        'begin': '(?<!</(?:script|SCRIPT))(>)'
+        'captures':
+          '1':
+            'name': 'punctuation.definition.tag.html'
+          '2':
+            'name': 'entity.name.tag.script.html'
+        'end': '(</)((?i:script))'
+        'patterns': [
+          {
+            'captures':
+              '1':
+                'name': 'punctuation.definition.comment.js'
+            'match': '(//).*?((?=</script)|$\\n?)'
+            'name': 'comment.line.double-slash.js'
+          }
+          {
+            'begin': '/\\*'
+            'captures':
+              '0':
+                'name': 'punctuation.definition.comment.js'
+            'end': '\\*/|(?=</script)'
+            'name': 'comment.block.js'
+          }
+          {
+            'include': 'source.js'
+          }
+        ]
+      }
+    ]
+  }
+  {
+    'begin': '(</?)((?i:body|head|html)\\b)'
+    'captures':
+      '1':
+        'name': 'punctuation.definition.tag.html'
+      '2':
+        'name': 'entity.name.tag.structure.any.html'
+    'end': '(>)'
+    'name': 'meta.tag.structure.any.html'
+    'patterns': [
+      {
+        'include': '#tag-stuff'
+      }
+    ]
+  }
+  {
+    'begin': '(</?)((?i:address|blockquote|dd|div|section|article|aside|header|footer|nav|menu|dl|dt|fieldset|form|frame|frameset|h1|h2|h3|h4|h5|h6|iframe|noframes|object|ol|p|ul|applet|center|dir|hr|pre)\\b)'
+    'beginCaptures':
+      '1':
+        'name': 'punctuation.definition.tag.begin.html'
+      '2':
+        'name': 'entity.name.tag.block.any.html'
+    'end': '(>)'
+    'endCaptures':
+      '1':
+        'name': 'punctuation.definition.tag.end.html'
+    'name': 'meta.tag.block.any.html'
+    'patterns': [
+      {
+        'include': '#tag-stuff'
+      }
+    ]
+  }
+  {
+    'begin': '(</?)((?i:a|abbr|acronym|area|b|base|basefont|bdo|big|br|button|caption|cite|code|col|colgroup|del|dfn|em|font|head|html|i|img|input|ins|isindex|kbd|label|legend|li|link|map|meta|noscript|optgroup|option|param|q|s|samp|script|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|title|tr|tt|u|var)\\b)'
+    'beginCaptures':
+      '1':
+        'name': 'punctuation.definition.tag.begin.html'
+      '2':
+        'name': 'entity.name.tag.inline.any.html'
+    'end': '((?: ?/)?>)'
+    'endCaptures':
+      '1':
+        'name': 'punctuation.definition.tag.end.html'
+    'name': 'meta.tag.inline.any.html'
+    'patterns': [
+      {
+        'include': '#tag-stuff'
+      }
+    ]
+  }
+  {
+    'begin': '(</?)([a-zA-Z0-9:-]+)'
+    'beginCaptures':
+      '1':
+        'name': 'punctuation.definition.tag.begin.html'
+      '2':
+        'name': 'entity.name.tag.other.html'
+    'end': '(>)'
+    'endCaptures':
+      '1':
+        'name': 'punctuation.definition.tag.end.html'
+    'name': 'meta.tag.other.html'
+    'patterns': [
+      {
+        'include': '#tag-stuff'
+      }
+    ]
+  }
+  {
+    'include': '#entities'
+  }
+  {
+    'match': '<>'
+    'name': 'invalid.illegal.incomplete.html'
+  }
+]
+'repository':
+  'embedded-code':
+    'patterns': [
+      {
+        'include': '#smarty'
+      }
+      {
+        'include': '#python'
+      }
+    ]
+  'entities':
+    'patterns': [
+      {
+        'captures':
+          '1':
+            'name': 'punctuation.definition.entity.html'
+          '3':
+            'name': 'punctuation.definition.entity.html'
+        'match': '(&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)'
+        'name': 'constant.character.entity.html'
+      }
+      {
+        'match': '&'
+        'name': 'invalid.illegal.bad-ampersand.html'
+      }
+    ]
+  'python':
+    'begin': '(?:^\\s*)<\\?python(?!.*\\?>)'
+    'end': '\\?>(?:\\s*$\\n)?'
+    'name': 'source.python.embedded.html'
+    'patterns': [
+      {
+        'include': 'source.python'
+      }
+    ]
+  'smarty':
+    'patterns': [
+      {
+        'begin': '(\\{(literal)\\})'
+        'captures':
+          '1':
+            'name': 'source.smarty.embedded.html'
+          '2':
+            'name': 'support.function.built-in.smarty'
+        'end': '(\\{/(literal)\\})'
+      }
+      {
+        'begin': '{{|{'
+        'disabled': 1
+        'end': '}}|}'
+        'name': 'source.smarty.embedded.html'
+        'patterns': [
+          {
+            'include': 'source.smarty'
+          }
+        ]
+      }
+    ]
+  'string-double-quoted':
+    'begin': '"'
+    'beginCaptures':
+      '0':
+        'name': 'punctuation.definition.string.begin.html'
+    'end': '"'
+    'endCaptures':
+      '0':
+        'name': 'punctuation.definition.string.end.html'
+    'name': 'string.quoted.double.html'
+    'patterns': [
+      {
+        'include': '#embedded-code'
+      }
+      {
+        'include': '#entities'
+      }
+    ]
+  'string-single-quoted':
+    'begin': '\''
+    'beginCaptures':
+      '0':
+        'name': 'punctuation.definition.string.begin.html'
+    'end': '\''
+    'endCaptures':
+      '0':
+        'name': 'punctuation.definition.string.end.html'
+    'name': 'string.quoted.single.html'
+    'patterns': [
+      {
+        'include': '#embedded-code'
+      }
+      {
+        'include': '#entities'
+      }
+    ]
+  'tag-generic-attribute':
+    'match': '(?<=[^=])\\b([a-zA-Z0-9:-]+)'
+    'name': 'entity.other.attribute-name.html'
+  'tag-id-attribute':
+    'begin': '\\b(id)\\b\\s*(=)'
+    'captures':
+      '1':
+        'name': 'entity.other.attribute-name.id.html'
+      '2':
+        'name': 'punctuation.separator.key-value.html'
+    'end': '(?<=\'|")|(?=\\s|>)'
+    'name': 'meta.attribute-with-value.id.html'
+    'patterns': [
+      {
+        'begin': '"'
+        'beginCaptures':
+          '0':
+            'name': 'punctuation.definition.string.begin.html'
+        'contentName': 'meta.toc-list.id.html'
+        'end': '"'
+        'endCaptures':
+          '0':
+            'name': 'punctuation.definition.string.end.html'
+        'name': 'string.quoted.double.html'
+        'patterns': [
+          {
+            'include': '#embedded-code'
+          }
+          {
+            'include': '#entities'
+          }
+        ]
+      }
+      {
+        'begin': '\''
+        'beginCaptures':
+          '0':
+            'name': 'punctuation.definition.string.begin.html'
+        'contentName': 'meta.toc-list.id.html'
+        'end': '\''
+        'endCaptures':
+          '0':
+            'name': 'punctuation.definition.string.end.html'
+        'name': 'string.quoted.single.html'
+        'patterns': [
+          {
+            'include': '#embedded-code'
+          }
+          {
+            'include': '#entities'
+          }
+        ]
+      }
+      {
+        'include': '#unquoted-attribute'
+      }
+    ]
+  'tag-stuff':
+    'patterns': [
+      {
+        'include': '#tag-id-attribute'
+      }
+      {
+        'include': '#tag-generic-attribute'
+      }
+      {
+        'include': '#string-double-quoted'
+      }
+      {
+        'include': '#string-single-quoted'
+      }
+      {
+        'include': '#embedded-code'
+      }
+      {
+        'include': '#unquoted-attribute'
+      }
+    ]
+  'unquoted-attribute':
+    'match': '(?<==)(?:[^\\s<>/\'"]|/(?!>))+'
+    'name': 'string.unquoted.html'


Remove unused parameter

Remove unused parameter

--- src/app/buffer-marker.coffee
+++ src/app/buffer-marker.coffee
@@ -141,7 +141,7 @@
     @suppressObserverNotification = false
     @notifyObservers({oldHeadPosition, newHeadPosition, oldTailPosition, newTailPosition, bufferChanged})

-  invalidate: (preserve) ->
+  invalidate: ->
     delete @buffer.validMarkers[@id]
     @buffer.invalidMarkers[@id] = this


Language mode no longer uses Ace for anything

--- src/app/language-mode.coffee
+++ src/app/language-mode.coffee
@@ -1,4 +1,3 @@
-AceAdaptor = require 'ace-adaptor'
 Range = require 'range'
 TextMateBundle = require 'text-mate-bundle'
 _ = require 'underscore'
@@ -14,11 +13,7 @@
     "'": "'"

   constructor: (@editSession) ->
-    @buffer = @editSession.buffer
-    @aceMode = @requireAceMode()
-
     @grammar = TextMateBundle.grammarForFileName(@editSession.buffer.getBaseName())
-    @aceAdaptor = new AceAdaptor(@editSession)

     _.adviseBefore @editSession, 'insertText', (text) =>
       return true if @editSession.hasMultipleCursors()
@@ -33,19 +28,6 @@
         @editSession.insertText text + pairedCharacter
         @editSession.moveCursorLeft()
         false
-
-  requireAceMode: (fileExtension) ->
-    modeName = switch @editSession.buffer.getExtension()
-      when 'js' then 'javascript'
-      when 'coffee' then 'coffee'
-      when 'rb', 'ru' then 'ruby'
-      when 'c', 'h', 'cpp' then 'c_cpp'
-      when 'html', 'htm' then 'html'
-      when 'css' then 'css'
-      when 'java' then 'java'
-      when 'xml' then 'xml'
-      else 'text'
-    new (require("ace/mode/#{modeName}").Mode)

   isOpenBracket: (string) ->
     @pairedCharacters[string]?


Forgot to add toc

Forgot to add toc

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

--- examples/toc.coffee
+++ examples/toc.coffee
@@ -0,0 +1,73 @@
+glob = require('glob')
+path = require('path')
+fs = require('fs')
+
+makeTree = (files) ->
+	tree = {}
+	for file in files
+		parts = file.split('/')
+		branch = tree
+		for part, idx in parts
+			if idx == parts.length - 1
+				branch[part] = file
+				break
+			if not branch[part]
+				branch[part] = {}
+			branch = branch[part]
+	return tree
+
+printTree = (tree) ->
+	ret = '
\n'
+	for branch, link of tree
+		ret += '
'
+		if typeof link == 'string'
+			ret += "#{branch}"
+		else
+			ret += branch
+			ret += printTree(link)
+		ret += '
\n'
+	ret += '
\n'
+	return ret
+
+exports.getFiles = (callback) ->
+	glob __dirname + '/**/!(index).html', (err, files) ->
+		callback err, files
+
+exports.getFilesSync = ->
+	return glob.sync __dirname+'/**/!(index).html'
+
+exports.getFilePathsSync = ->
+	return glob.sync __dirname + '/**/!(index).html'
+
+exports.run = ->
+	exports.getFiles (err, files) ->
+		if err
+			console.log err
+			return
+		if files.length == 0
+			console.log 'No files'
+			return
+
+		for file, i in files
+			files[i] = path.relative __dirname, file
+
+		tree = makeTree(files)
+		#console.log JSON.stringify(tree, null, '\t')
+
+		content = '''
+
+
+				<title>Examples</title>
+
+
+
Contents

+		'''
+
+		content += printTree(tree)
+
+		content += '''
+
+
+		'''
+
+		fs.writeFileSync path.resolve('examples','index.html'), content


Remove editor class form ReactEditorView, it is on EditorComponent

I couldn’t recreate the problem with activation events mentioned
https://github.com/atom/atom/commit/fa66689c07f3c64cdf338da1c9a034d06ec54f9c

--- src/react-editor-view.coffee
+++ src/react-editor-view.coffee
@@ -5,7 +5,7 @@

 module.exports =
 class ReactEditorView extends View
-  @content: -> @div class: 'editor react-wrapper'
+  @content: -> @div class: 'react-wrapper'

   focusOnAttach: false


fix alignment

fix alignment

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


Remove bomb

Remove bomb

Resolves: [#106305264]

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


Shows pencil icon for tab written in by buddy

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


Bugfix - NormalizeUrl was overriding alternate hosts for api endpoints

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/sbruno81/rets-client.git/'


upgrade boyt_publish to swig template

upgrade boyt_publish to swig template

 On branch master

	modified:   nodejs_server/bestofyourtown/publish.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/'


`or` is `||`, not `&&`

`or` is `||`, not `&&`

Whoops. ba2ba938

--- resources/assets/coffee/react/beatmap-discussions/nominations.coffee
+++ resources/assets/coffee/react/beatmap-discussions/nominations.coffee
@@ -61,7 +61,7 @@
     mapCanBeNominated = (@props.beatmapset.status == 'pending')
     mapIsQualified = (@props.beatmapset.status == 'qualified')

-    return null unless mapCanBeNominated && mapIsQualified
+    return null unless mapCanBeNominated || mapIsQualified

     if mapIsQualified
       rankingETA = @props.beatmapset.nominations.ranking_eta


add experiment to create derivatie library with altered configuration

error: pathspec 'src/experiments/changed-configuration-with-library-derivative.coffee' did not match any file(s) known to git


whitespace cleanup

whitespace cleanup

--- src/sdk.coffee
+++ src/sdk.coffee
@@ -174,11 +174,11 @@

   prepareRequestURI: (path, query={}) ->
     uri = new SC.URI(path, {"decodeQuery": true})
-
+
     # shallow merge of queries
     for own k,v of query
       uri.query[k] = v
-
+
     # add scheme & host if relative
     if uri.isRelative()
       uri.host = this.hostname("api")
@@ -190,7 +190,7 @@
       uri.scheme = "https"
     else
       uri.query.client_id    = this.options.client_id
-
+
     uri

 ##################################
@@ -300,12 +300,12 @@
       callbacks: {}
       randomCallbackName: ->
         "CB" + parseInt Math.random() * 999999, 10
-
+
       get: (uri, callback) ->
         callbackName        = this.randomCallbackName()
         uri.query.format = "js"
         uri.query.callback = "SC.Helper.JSONP.callbacks." + callbackName
         SC.Helper.JSONP.callbacks[callbackName] = callback
-
+
         SC.Helper.loadJavascript uri.toString(), ->
           document.body.removeChild(this)


Started finger tree implementation.

Started finger tree implementation.

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

--- lib/finger_tree.coffee
+++ lib/finger_tree.coffee
@@ -0,0 +1,96 @@
+# --------------------------------------------------------------------
+# A finger tree implementation.
+#
+# Copyright (c) 2011 Olaf Delgado-Friedrichs (odf@github.com)
+# --------------------------------------------------------------------
+
+
+reducel: (op) -> (z, x) -> x.reducel(z, op)
+reducer: (op) -> (x, z) -> x.reducer(op, z)
+
+
+# A node.
+class Node2
+  constructor: -> [@a, @b] = arguments
+  reducel: (z, op) -> op(op(z, @a), @b)
+  reducer: (op, z) -> op(@a, op(@b, z))
+
+class Node3
+  constructor: -> [@a, @b, @c] = arguments
+  reducel: (z, op) -> op(op(op(z, @a), @b), @c)
+  reducer: (op, z) -> op(@a, op(@b, op(@c, z)))
+
+make_node = (args...) ->
+  type = switch args.length
+    when 2 then Digit2
+    when 3 then Digit3
+    else
+      raise new Error "Illegal number of arguments: #{args.length}"
+
+  new type args...
+
+
+# A digit in a finger tree.
+class Digit1
+  constructor: -> [@a] = arguments
+  reducel: (z, op) -> op(z, @a)
+  reducer: (op, z) -> op(@a, z)
+
+class Digit2
+  constructor: -> [@a, @b] = arguments
+  reducel: (z, op) -> op(op(z, @a), @b)
+  reducer: (op, z) -> op(@a, op(@b, z))
+
+class Digit3
+  constructor: -> [@a, @b, @c] = arguments
+  reducel: (z, op) -> op(op(op(z, @a), @b), @c)
+  reducer: (op, z) -> op(@a, op(@b, op(@c, z)))
+
+class Digit4
+  constructor: -> [@a, @b, @c, @d] = arguments
+  reducel: (z, op) -> op(op(op(op(z, @a), @b), @c), @d)
+  reducer: (op, z) -> op(@a, op(@b, op(@c, op(@d, z))))
+
+make_digit = (args...) ->
+  type = switch args.length
+    when 1 then Digit1
+    when 2 then Digit2
+    when 3 then Digit3
+    when 4 then Digit4
+    else
+      raise new Error "Illegal number of arguments: #{args.length}"
+
+  new type args...
+
+
+# An empty finger tree.
+Empty = {
+  reducel: (z, op) -> z
+  reducer: (op, z) -> z
+}
+
+
+# A finger tree with a single element.
+class Single
+  constructor: (a) -> @a = a
+
+  reducel: (z, op) -> op z, @a
+  reducer: (op, z) -> op @a, z
+
+
+# A deep finger tree.
+class Deep
+  constructor: (left, middle, right) ->
+    @l = left
+    @m = middle
+    @r = right
+
+  reducel: (z, op0) ->
+    op1 = reducel op0
+    op2 = reducel op1
+    op1(op2(op1(z, @l), @m), @r)
+
+  reducer: (op0, z) ->
+    op1 = reducer op0
+    op2 = reducer op1
+    op1(@l, op2(@m, op1(@r, z)))


Remove loop to get motion level

Remove loop to get motion level

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


Fix navigation after a deletion, ref #504

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


client/shortcuts: make sure bindings exist first

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


first commit with updated device names and backwards compatibility

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

--- DevicePixelRatio.coffee
+++ DevicePixelRatio.coffee
@@ -0,0 +1,108 @@
+##############################################################################
+# Created on 23 DEC 2015 by Jordan Dobson / @jordandobson / jordan@brothe.rs
+# Updated on 12 APR 2016 by Jordan Dobson with thanks to Nikolay Berezovskiy!
+##############################################################################
+#
+# Use to measure pixels at 1x and have it adjust for the Pixel Ratio
+#
+# To Get Started...
+#
+#  1. Place this file in Framer Studio modules directory
+#
+#  2. In your project include:
+#
+#     {dpr} = require 'DevicePixelRatio'
+#
+#  3. When you create a layer do so @ 1x and add the dpr function to the value
+#
+#     rect = new Layer
+#       width:  dpr(300)
+#       height: dpr 50
+#       x:      (dpr 16)
+#
+#  4. Use it for more than layer size. Here's advanced usage for multi devices:
+#
+#			# Add a list row w/ the height & text sizing/layout using dpr()
+#
+#     listRow = new Layer
+#       width: Screen.width
+#       height: dpr 44
+#       html: "List Item"
+#       backgroundColor: "#fff"
+#       color: "#000"
+#       style:
+#         font: "400 #{dpr 14}px/#{dpr 42}px -apple-system, Helvetica Neue"
+#         textIndent: "#{dpr 15}px"
+#
+# 		# Add a chevron with the size, right margin & shadow stroke using dpr()
+#
+#     listChevron = new Layer
+#     	superLayer: listRow
+#     	width:  dpr 9
+#     	height: dpr 9
+#     	maxX: listRow.width - dpr 15
+#     	y:    listRow.height / 2
+#     	originX: 1
+#     	originY: 0
+#     	rotation: 45
+#     	backgroundColor: ""
+#     	style:
+#     		boxShadow: "inset -#{dpr 2}px #{dpr 2}px 0 #BCBCC1"
+#
+##############################################################################
+
+class exports.DevicePixelRatio
+
+	#############################################################################
+	# Private Methods ###########################################################
+
+	log = (v) ->
+		console.log "DevicePixelRatio set as:", v
+		return v
+
+	dpr = () ->
+		initialValue = 1
+		value = initialValue
+		# Check if in Studio or Desktop to figure out what the scaling should be
+		if Utils.isFramerStudio() or Utils.isDesktop()
+
+			# Check for 2x devices
+			for device_2x in ['apple-', 'google-nexus-', 'iphone-6-', 'iphone-5', 'ipad-air', 'nexus-9', 'applewatch']
+				value = 2 if _.startsWith(Framer.Device.deviceType, device_2x)
+
+			# Check for 3x devices
+			for device_3x in ['apple-iphone-6s-plus', 'google-nexus-5', 'htc-one-', 'microsoft-lumia-', 'samsung-galaxy-note-', 'iphone-6plus', 'nexus-5']
+				value = 3 if _.startsWith(Framer.Device.deviceType, device_3x)
+
+			# Check for 3.5x devices
+			for device_3p5x in ['google-nexus-6']
+				value = 3.5 if _.startsWith(Framer.Device.deviceType, device_3p5x)
+
+		# Return if the value changed... otherwise continue
+		return log value unless value is initialValue
+
+		# Set Units based on Device Pixel Ratio Except for Desktop
+		unless Utils.isDesktop()
+			devicePixelRatio = Utils.devicePixelRatio()
+			# if it's greater than 1 then update it!
+			value = devicePixelRatio if devicePixelRatio > initialValue
+
+		# return the value even if it hasn't changed and log it everytime its set
+		return log value
+
+	#############################################################################
+	# Constant ##################################################################
+
+	VALUE = dpr()
+
+	#############################################################################
+	# Public Methods ############################################################
+
+	@.calc  = (v) -> return v * VALUE
+
+	@.value = VALUE
+
+################################################################################
+# Create a shorthand to get directly to the calc statement
+
+exports.dpr = exports.DevicePixelRatio.calc


use reactive vars inside the phone instance in order to correctly drive the template

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/VoiSmart/Rocket.Chat.git/'


Initial commit of sdt.coffee

Initial commit of sdt.coffee

--- sdt.coffee
+++ sdt.coffee
@@ -0,0 +1,65 @@
+#
+# sdt-js CoffeeScript library for the Signal Detection Theory (SDT)
+#
+# Copyright (c) 2012 William Högman <me@whn.se>
+# Licensed under the MIT License, see LICENSE.TXT
+
+
+
+# I ported this from some code I wrote earlier in R so it might look
+# strange to someone who doesn't know R.
+
+normal = jStat.normal
+
+# Lets use the names from R
+qnorm = normal.inv
+dnorm = normal.pdf
+
+dprime = (hr,far) -> qnorm(hr,0,1) - qnorm(far,0,1)
+criteria = (hr,far) -> dnorm(qnorm(hr,0,1),0,1) / dnorm(qnorm(1-far,0,1),0,1)
+
+# we are gonna export sdt
+sdt = {}
+
+
+from_rate = (hr,far) ->
+        dprime: dprime(hr,far),
+        criteria: criteria(hr,far),
+        hr: hr,
+        mr: 1 - hr,
+        far: far,
+        cr: 1 - far,
+        yes: (hr + far) / 2
+        no: ((1 - far) + (1 - hr)) / 2
+
+fn = (obj) ->
+        $.extend(obj,
+                noise:  (x) -> dnorm(x,0,1),
+                signal: (x) -> dnorm(x,obj.dprime,1),
+                )
+
+
+
+plot = (canvas,obj) ->
+        space = jStat.seq(-3,5,100)
+        $.plot($(canvas),
+        [
+                {
+                        label: "Noise",
+                        data: space.map((x) -> [x, obj.noise(x)])
+                },
+                {
+                        label: "Signal+Noise"
+                        data: space.map((x) -> [x, obj.signal(x)]),
+                },
+                {
+                        label: "Criteria",
+                        data: space.map((x) -> [qnorm(1-obj.far,0,1),x])
+                }
+
+        ],
+        xaxis: (min: -3, max:6),
+        yaxis: (min: 0, max: 0.4)
+        )
+
+@sdt = from_rate: from_rate, fn: fn, plot: plot


Include error message in logging

Include error message in logging

--- lib/load-paths-handler.coffee
+++ lib/load-paths-handler.coffee
@@ -61,7 +61,7 @@
     try
       ignoredNames.push(new Minimatch(ignore, matchBase: true, dot: true))
     catch error
-      console.warn "Invalid ignore pattern: #{ignore}"
+      console.warn "Error parsing ignore pattern (#{ignore}): #{error.message}"

   callback = @async()
   repo = Git.open(rootPath, refreshOnWindowFocus: false) if ignoreVcsIgnores


Update

Update

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


Updates the Regex to match for a JSON string

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


remap cmd+s to "save all" in atom

remap cmd+s to "save all" in atom

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

--- atom/keymap.cson
+++ atom/keymap.cson
@@ -0,0 +1,30 @@
+# Your keymap
+#
+# Atom keymaps work similarly to style sheets. Just as style sheets use
+# selectors to apply styles to elements, Atom keymaps use selectors to associate
+# keystrokes with events in specific contexts. Unlike style sheets however,
+# each selector can only be declared once.
+#
+# You can create a new keybinding in this file by typing "key" and then hitting
+# tab.
+#
+# Here's an example taken from Atom's built-in keymap:
+#
+# 'atom-text-editor':
+#   'enter': 'editor:newline'
+#
+# 'atom-workspace':
+#   'ctrl-shift-p': 'core:move-up'
+#   'ctrl-p': 'core:move-down'
+#
+# You can find more information about keymaps in these guides:
+# * https://atom.io/docs/latest/using-atom-basic-customization#customizing-key-bindings
+# * https://atom.io/docs/latest/behind-atom-keymaps-in-depth
+#
+# This file uses CoffeeScript Object Notation (CSON).
+# If you are unfamiliar with CSON, you can read more about it in the
+# Atom Flight Manual:
+# https://atom.io/docs/latest/using-atom-basic-customization#cson
+
+'atom-text-editor':
+  'cmd-s': 'window:save-all'


Client: Activity: Added renderAllParticipantsMenu to show all participants with context menu

--- client/activity/lib/components/channelparticipantavatars/index.coffee
+++ client/activity/lib/components/channelparticipantavatars/index.coffee
@@ -92,6 +92,21 @@

+  renderAllParticipantsMenu: ->
+
+    return null  unless @state.showAllParticipants
+    return null  unless @props.participants
+
+    { participants } = @props
+
+

+

+
Other participants

+        {@renderAvatars(participants, yes)}
+

+

+
+
   getAddNewParticipantButtonClassNames: -> classnames
     'ChannelParticipantAvatars-newParticipantBox': yes
     'cross': @state.addNewParticipantMode
@@ -122,5 +137,6 @@
       {@renderMoreCount()}
       {@renderNewParticipantButton()}
       {@renderAddNewParticipantInput()}
+      {@renderAllParticipantsMenu()}


environment/flux: only save group level templates to team templates


accounts directive

accounts directive

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

--- app/assets/javascripts/directives/projects/accounts.coffee
+++ app/assets/javascripts/directives/projects/accounts.coffee
@@ -0,0 +1,7 @@
+angular.module("coledger").directive "projectsAccounts", ['Resources', 'flash', (Resources, flash) ->
+  restrict: 'E'
+  templateUrl: 'projects/accounts.html'
+  scope: true
+  link: (scope, element, attrs) ->
+    scope.accounts = Resources.Account.query { project_id: $routeParams.id }
+]


[codegen] Ditch ditchable parts of the codegen

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


config: export redis connection

config: export redis connection

--- config/generateKonfig.coffee
+++ config/generateKonfig.coffee
@@ -210,6 +210,7 @@
     clientUploadS3BucketName      : options.clientUploadS3BucketName

     kiteHome                      : credentials.kiteHome
+    redis                         : credentials.redis
     mongo                         : credentials.mongo
     postgres                      : credentials.postgres
     mq                            : credentials.rabbitmq


Closes #2141; Show that server is running on logs

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

--- server/startup/serverRunning.coffee
+++ server/startup/serverRunning.coffee
@@ -0,0 +1,10 @@
+Meteor.startup ->
+	Meteor.setTimeout ->
+		msg = [
+			"     Version: #{RocketChat.Info.version}"
+			"Process Port: #{process.env.PORT}"
+			"    Site URL: #{RocketChat.settings.get('Site_Url')}"
+		].join('\n')
+
+		SystemLogger.successBox msg, 'SERVER RUNNING'
+	, 100


Limit included Foundation .js files

Limit included Foundation .js files

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/paulgroves/spree-foundation-theme.git/'


Make sure logStream exists

Make sure logStream exists

--- spec/jasmine-helper.coffee
+++ spec/jasmine-helper.coffee
@@ -25,7 +25,7 @@
         timeReporter.logLongestSuites 10, (line) -> process.stdout.write("#{line}\n")
         process.stdout.write('\n')
         timeReporter.logLongestSpecs 10, (line) -> process.stdout.write("#{line}\n")
-        fs.closeSync(logStream)
+        fs.closeSync(logStream) if logStream?
         atom.exit(runner.results().failedCount > 0 ? 1 : 0)
   else
     AtomReporter = require './atom-reporter'


Add http modules and cronJob's time

Add http modules and cronJob's time

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


Fix bday update in google.

Fix bday update in google.

--- server/models/contact.coffee
+++ server/models/contact.coffee
@@ -236,7 +236,7 @@
     name.gd$nameSuffix = $t: suffix if suffix? and suffix isnt ''
     gContact.gd$name = name

-    gContact.gContact$birthday = when: @bday if @birthday?
+    gContact.gContact$birthday = when: @bday if @bday?
     gContact.gContact$nickname = $t: @nickname if @nickname?
     gContact.content = $t: @note if @note?


Update datetimepicker.coffee

Update datetimepicker.coffee

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


Cleanup

Cleanup

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


Working

Working

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/cpcrowley/vis-hist.git/'


more robust existence checking

more robust existence checking

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/companytools/ember-cli-dunlop.git/'


Add lib/keyboard.coffee

Add lib/keyboard.coffee

error: pathspec 'site/top/lib/keyboard.coffee' did not match any file(s) known to git

--- site/top/lib/keyboard.coffee
+++ site/top/lib/keyboard.coffee
@@ -0,0 +1,241 @@
+###
+
+The Keyboard class provides a rendering of
+a piano keyboard that can color notes as they
+are played.  Example:
+
+await loadscript '/lib/keyboard.coffee', defer()
+k = new Keyboard
+k.play "[CEG]"
+
+The function "play" uses the same ABC notation
+that is used with the built in Pencil Code play
+function.  Google for "ABC notation" on the web.
+
+Here is a an example that with tempo, beats,
+a rest, a semitone, an octave, and a chord:
+
+k.play {tempo: 150}, "c G/2 G/2 A G z B [_B,CEGc]"
+
+Implementation notes: currently keyboard drawing is
+slower than it should be.  It should be sped up.
+
+A specific key can be highlighted by just saying
+something like this:
+
+k.draw(64, blue)
+
+The number used is the midi number for the key,
+where 60 is middle C.
+
+###
+
+class Keyboard
+  constructor: (options = {}) ->
+    defwidth = if options.kh? then (options.kh / 5) else 10
+    @kw = options.kw ? defwidth
+    @kh = options.kh ? @kw * 5
+    @bkw = options.bkw ? @kw * 3 / 5
+    @bkh = options.bkh ? @kh * 3 / 5
+    @lowest = options.lowest ? 21
+    @highest = options.highest ? 108
+    @x = options.x ? 0
+    @y = options.y ? 0
+    @center = floor((@lowest + @highest) / 2)
+    @kt = new Turtle
+    @kt.ht()
+    @kt.speed Infinity
+    @pt = new Turtle
+    @pt.ht()
+    do @drawall
+
+  # white-key position: gives a number
+  # that increases by 1 for every white
+  # key, or that is the next lower white
+  # key number for every black key.
+  @wcp: (n) ->
+    floor((n + 7) / 12 * 7) - 4
+
+  # A code for the shape of the key number.
+  @keyshape: (n) ->
+    [1,8,2,9,3,4,10,5,11,6,12,7][n % 12]
+
+  # A colorful color to use for the key number.
+  @keycolor: (n) ->
+    hsl(n / 12 * 360, 1, 0.5)
+
+  play: ->
+    args = Array.prototype.slice.call(
+      arguments, 0)
+    if (args.length <= 0 or
+        not $.isPlainObject(args[0]))
+      args.unshift({})
+    args[0].callback = @makecallback()
+    @pt.play.apply(@pt, args)
+
+  draw: (n, fillcolor) ->
+    if not (@lowest <= n <= @highest)
+      return
+    if not fillcolor?
+      if Keyboard.keyshape(n) >= 8
+        fillcolor = black
+      else
+        fillcolor = white
+    @kt.pen path
+    @keyoutline(@kt, n)
+    @kt.fill fillcolor
+    @kt.pen black
+    @keyoutline(@kt, n)
+
+  drawall: ->
+    for n in [@lowest..@highest]
+      @draw(n)
+
+  makecallback: ->
+    pressed = []
+    convertfreq = (f) ->
+      round(69 + ln(f / 440) * 12 / ln(2))
+    callback = (d) =>
+      for p in pressed
+        @draw(p)
+      pressed.length = 0
+      if not d?.frequency then return
+      for f in d.frequency
+        midikey = convertfreq f
+        pressed.push midikey
+        @draw midikey, Keyboard.keycolor midikey
+    return callback
+
+  keyoutline: (kt, n) ->
+    # TODO: replace this with high-performance
+    # canvas drawing code.
+    startx = @kw *
+      (Keyboard.wcp(n) - Keyboard.wcp(@center))
+    starty = -@kh / 2
+    # top width of the c key
+    ckw = (3 * @kw - 2 * @bkw) / 3
+    # top width of the f key
+    fkw = (4 * @kw - 3 * @bkw) / 4
+    ks = Keyboard.keyshape(n)
+    # key shapes are modified for the lowest
+    # and highest keys on the piano.
+    ll = n is @lowest
+    hh = n is @highest
+    if ks >= 8
+      starty += @kh - @bkh
+    switch ks
+      when 8
+        startx += ckw
+      when 9
+        startx += 2 * ckw + @bkw - @kw
+      when 10
+        startx += fkw
+      when 11
+        startx += 2 * fkw + @bkw - @kw
+      when 12
+        startx += 3 * fkw + 2 * @bkw - 2 * @kw
+    kt.jumpto startx, starty
+    switch ks
+      when 1
+        kt.fd @kh
+        kt.slide ckw
+        if hh
+          kt.slide @kw - ckw
+          kt.bk @kh
+        else
+          kt.bk @bkh
+          kt.slide @kw - ckw
+          kt.bk @kh - @bkh
+        kt.slide -@kw
+      when 2
+        if ll
+          kt.fd @kh
+          kt.slide (@kw - ckw) / 2
+        else
+          kt.fd @kh - @bkh
+          kt.slide (@kw - ckw) / 2
+          kt.fd @bkh
+        kt.slide ckw
+        if hh
+          kt.slide (@kw  - ckw) / 2
+          kt.bk @kh
+        else
+          kt.bk @bkh
+          kt.slide (@kw - ckw) / 2
+          kt.bk @kh - @bkh
+        kt.slide -@kw
+      when 3
+        if ll
+          kt.fd @kh
+          kt.slide @kw - ckw
+        else
+          kt.fd @kh - @bkh
+          kt.slide @kw - ckw
+          kt.fd @bkh
+        kt.slide ckw
+        kt.bk @kh
+        kt.slide -@kw
+      when 4
+        kt.fd @kh
+        kt.slide fkw
+        if hh
+          kt.slide @kw - fkw
+          kt.bk @kh
+        else
+          kt.bk @bkh
+          kt.slide @kw - fkw
+          kt.bk @kh - @bkh
+        kt.slide -@kw
+      when 5
+        if ll
+          kt.fd @kh
+          kt.slide fkw + @bkw - @kw
+        else
+          kt.fd @kh - @bkh
+          kt.slide fkw + @bkw - @kw
+          kt.fd @bkh
+        kt.slide fkw
+        if hh
+          kt.slide 2 * @kw - 2 * fkw - @bkw
+          kt.bk @kh
+        else
+          kt.bk @bkh
+          kt.slide 2 * @kw - 2 * fkw - @bkw
+          kt.bk @kh - @bkh
+        kt.slide -@kw
+      when 6
+        if ll
+          kt.fd @kh
+          kt.slide 2 * @kw - 2 * fkw - @bkw
+        else
+          kt.fd @kh - @bkh
+          kt.slide 2 * @kw - 2 * fkw - @bkw
+          kt.fd @bkh
+        kt.slide fkw
+        if hh
+          kt.slide fkw + @bkw - @kw
+          kt.bk @kh
+        else
+          kt.bk @bkh
+          kt.slide fkw + @bkw - @kw
+          kt.bk @kh - @bkh
+        kt.slide -@kw
+      when 7
+        if ll
+          kt.fd @kh
+          kt.slide @kw - fkw
+        else
+          kt.fd @kh - @bkh
+          kt.slide @kw - fkw
+          kt.fd @bkh
+        kt.slide fkw
+        kt.bk @kh
+        kt.slide -@kw
+      when 8, 9, 10, 11, 12
+        kt.fd @bkh
+        kt.slide @bkw
+        kt.bk @bkh
+        kt.slide -@bkw
+
+window.Keyboard = Keyboard
+


refine closures for assigning case

refine closures for assigning case

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


refactored functions for error handling, removed neccesity for domain.r package

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


Make sure nothing happens while saving

Make sure nothing happens while saving

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/douggr/atom-project-manager.git/'


Use full size table for tracklist

Use full size table for tracklist

--- resources/assets/coffee/react/_components/tracklist.coffee
+++ resources/assets/coffee/react/_components/tracklist.coffee
@@ -30,7 +30,7 @@
         track: track,

     div className: 'tracklist',
-      table className: 'tracklist__table tracklist__table--smaller',
+      table className: 'tracklist__table',
         thead {},
             tr className: 'tracklist__row--header',
                 th className: 'tracklist__col tracklist__col--preview', ''


add snapshot.test.coffee file

add snapshot.test.coffee file

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

--- workers/social/lib/social/models/computeproviders/snapshot.test.coffee
+++ workers/social/lib/social/models/computeproviders/snapshot.test.coffee
@@ -0,0 +1,124 @@
+JSnapshot = require './snapshot'
+
+{ daisy
+  expect
+  withDummyClient
+  withConvertedUser
+  expectAccessDenied
+  generateRandomString
+  checkBongoConnectivity }    = require '../../../../testhelper'
+{ withConvertedUserAndSnapshot } = require '../../../../testhelper/models/computeproviders/snapshothelper'
+
+
+# this function will be called once before running any test
+beforeTests = -> before (done) ->
+
+  checkBongoConnectivity done
+
+
+# here we have actual tests
+runTests = -> describe 'workers.social.models.computeproviders.snapshot', ->
+
+  describe '#verifySnapshot()', ->
+
+    it 'should fail to verify if snapshotId is not specified', (done) ->
+
+      withConvertedUser ({ client }) ->
+        JSnapshot.verifySnapshot client, { snapshotId : null }, (err) ->
+          expect(err?.message).to.be.equal 'snapshotId is not provided'
+          done()
+
+
+    it 'should fail to verify if storage is no sufficient', (done) ->
+
+      withConvertedUserAndSnapshot ({ client, snapshot }) ->
+        options = { storage : 0, snapshotId : snapshot.snapshotId }
+        JSnapshot.verifySnapshot client, options, (err) ->
+          expect(err?.message).to.be.equal 'Storage size is not enough for this snapshot'
+          done()
+
+
+    it 'should be able to verify snapshot when correct data provided', (done) ->
+
+      withConvertedUserAndSnapshot ({ client, snapshot }) ->
+        options = { snapshotId : snapshot.snapshotId }
+        JSnapshot.verifySnapshot client, options, (err, snapshot_) ->
+          expect(err).to.not.exist
+          expect(snapshot_).to.exist
+          expect(snapshot.label).to.be.equal snapshot_.label
+          done()
+
+
+  describe '#one$()', ->
+
+    it 'should fail to fetch snapshot data if user doesnt have permission', (done) ->
+
+      expectAccessDenied done, JSnapshot, 'one$', snapshotId = null
+
+
+    it 'should be able to fetch the snapshot data', (done) ->
+
+      withConvertedUserAndSnapshot ({ client, snapshot }) ->
+        JSnapshot.one$ client, snapshot.snapshotId, (err, snapshot_) ->
+          expect(err).to.not.exist
+          expect(snapshot).exist
+          expect(snapshot.label).to.be.equal snapshot_.label
+          expect(snapshot.originId).to.be.deep.equal snapshot_.originId
+          expect(snapshot.machineId).to.be.deep.equal snapshot_.machineId
+          done()
+
+
+  describe '#some$()', ->
+
+    it 'should fail to fetch snapshot data if user doesnt have permission', (done) ->
+
+      expectAccessDenied done, JSnapshot, 'some$', selector = {}, options = {}
+
+
+    it 'should be able to fetch snapshot data', (done) ->
+
+      withConvertedUserAndSnapshot ({ client, snapshot }) ->
+        selector = { snapshotId : snapshot.snapshotId }
+        JSnapshot.some$ client, selector, {}, (err, snapshots) ->
+          expect(err).to.not.exist
+          expect(snapshots).to.be.an 'array'
+          expect(snapshots[0].label).to.be.equal snapshot.label
+          expect(snapshots[0].originId).to.be.deep.equal snapshot.originId
+          expect(snapshots[0].machineId).to.be.deep.equal snapshot.machineId
+          done()
+
+
+  describe 'rename()', ->
+
+    it 'should fail to rename snapshot if user doesnt have permission', (done) ->
+
+      withConvertedUserAndSnapshot ({ snapshot }) ->
+        expectAccessDenied done, snapshot, 'rename', label = 'someLabel'
+
+
+    it 'should fail to rename snapshot if label is empty', (done) ->
+
+      withConvertedUserAndSnapshot ({ client, snapshot }) ->
+        label    = snapshot.label
+        selector = { snapshotId : snapshot.snapshotId }
+        snapshot.rename client, '', (err) ->
+          expect(err?.message).to.be.equal 'JSnapshot.rename: label is empty'
+          done()
+
+    it 'should fetch the snapshot data', (done) ->
+
+      withConvertedUserAndSnapshot ({ client, snapshot }) ->
+        label    = snapshot.label
+        selector = { snapshotId : snapshot.snapshotId }
+        snapshot.rename client, 'newLabel', (err) ->
+          expect(err).to.not.exist
+          expect(snapshot.label).not.to.be.equal label
+          expect(snapshot.label).to.be.equal 'newLabel'
+          done()
+
+
+
+beforeTests()
+
+runTests()
+


Added show controller

Added show controller

error: pathspec 'public/dreamcatcher/controllers/entries/show_controller.coffee' did not match any file(s) known to git

--- public/dreamcatcher/controllers/entries/show_controller.coffee
+++ public/dreamcatcher/controllers/entries/show_controller.coffee
@@ -0,0 +1,23 @@
+$.Controller.extend 'Dreamcatcher.Controllers.Entries.Show',
+
+  'a.spine-nav click': (el) ->
+    @historyAdd
+      controller: 'book'
+      action: 'show'
+      id: el.data 'id'
+
+  '.stream click': ->
+    @historyAdd {
+      controller: 'entry'
+      action: 'field'
+    }
+
+  '.prev, .next click': (el) ->
+    @historyAdd {
+      controller: 'entry'
+      action: 'show'
+      id: el.data 'id'
+    }
+
+
+


Add geocoder service

Add geocoder service

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

--- app/assets/javascripts/darkswarm/services/geocoder.js.coffee
+++ app/assets/javascripts/darkswarm/services/geocoder.js.coffee
@@ -0,0 +1,14 @@
+# Usage:
+# Geocoder.geocode address, (results, status) ->
+#   if status == Geocoder.OK
+#     console.log results[0].geometry.location
+#   else
+#     console.log "Error: #{status}"
+
+Darkswarm.service "Geocoder", ->
+  new class Geocoder
+    OK: google.maps.GeocoderStatus.OK
+
+    geocode: (address, callback) ->
+      geocoder = new google.maps.Geocoder()
+      geocoder.geocode {'address': address}, callback


[skip] Extracted helper from houston-core (1m)

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

--- app/assets/javascripts/houston/kanban/handlebars_helpers.coffee
+++ app/assets/javascripts/houston/kanban/handlebars_helpers.coffee
@@ -0,0 +1,13 @@
+Handlebars.registerHelper 'classForAge', (seconds)->
+  if seconds < (6 * Duration.HOUR)
+    'infant'
+  else if seconds < (2 * Duration.DAY)
+    'child'
+  else if seconds < (7 * Duration.DAY)
+    'adult'
+  else if seconds < (4 * Duration.WEEK)
+    'senior'
+  else if seconds < (26 * Duration.WEEK)
+    'old'
+  else
+    'ancient'


add: #1 dist two version of files, the source file and minified file

--- nofile.coffee
+++ nofile.coffee
@@ -6,7 +6,7 @@
 	task 'default build', ['doc', 'code']

 	task 'doc', ['code'], 'build doc', ->
-		size = kit.statSync('dist/yaku.js').size / 1024
+		size = kit.statSync('dist/yaku.min.js').size / 1024
 		kit.warp 'src/yaku.coffee'
 		.load kit.drives.comment2md {
 			tpl: 'docs/readme.jst.md'
@@ -20,6 +20,9 @@
 		kit.warp 'src/**/*.coffee'
 		.load kit.drives.auto 'lint'
 		.load kit.drives.auto 'compile'
+		.load (f) ->
+			f.dest.name = 'yaku.min'
+			kit.outputFile 'dist/yaku.js', f.contents
 		.load kit.drives.auto 'compress'
 		.load (f) ->
 			# Add license.


added commander require

added commander require

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


first attempt

first attempt

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

--- src/app.coffee
+++ src/app.coffee
@@ -0,0 +1,271 @@
+require [ "jquery", "backbone", "bootstrap" ], ->
+  htmlEncode = (value) ->
+    $("<div/>").text(value).html()
+  $.fn.serializeObject = ->
+    o = {}
+    a = @serializeArray()
+    $.each a, ->
+      if o[@name] isnt `undefined`
+        o[@name] = [ o[@name] ]  unless o[@name].push
+        o[@name].push @value or ""
+      else
+        o[@name] = @value or ""
+
+    o
+
+  $.ajaxPrefilter (options, originalOptions, jqXHR) ->
+    options.url = "/researchdb/html/liverpool/api" + options.url
+
+  class Person extends Backbone.Model
+    urlRoot: "/people"
+  class People extends Backbone.Collection
+
+    url: "/people"
+    model: Person
+
+  class Relationship extends Backbone.Model
+    urlRoot: "/relationships"
+
+  class Country extends Backbone.Model
+    urlRoot: "/country"
+
+  class Countries extends Backbone.Collection
+    parse: (response) ->
+      console.log response
+      super(response)
+    url: "/countries"
+    model: Country
+
+  class Relationships extends Backbone.Collection
+    model: Relationship
+    url: "/relationships/" + @id
+    parse: (response) ->
+      console.log response
+      response
+
+
+  people = new People() # create a global collection of all people
+
+  class PeopleListView extends Backbone.View
+    el: "#homepage"
+    initialize: ->
+      @$el.html $("#view-loading").html()
+      that = @
+      people.fetch
+        dataType: "jsonp"
+        type: "GET"
+        success: (result,b,c) ->
+          console.log result,b,c
+          require [ "text!../templates/list.html.tpl" ], (template) ->
+            that.render _.template(template,
+              persons: people.models
+            )
+        error: (a,b,c) ->
+          console.log a,b,c
+
+
+
+    render: (template) ->
+      that = @
+      breadcrumb_template = _.template($("#breadcrumb-template").html(),
+        breadcrumbs: []
+      )
+      $("#breadcrumb").html breadcrumb_template
+      $("#page").empty()
+      if people.length is 0
+        @$el.html $("#view-loading").html()
+      else
+        if template
+          require [ "jquery.datatables", "jquery.datatables_bootstrap_3" ], ->
+            that.$el.html template
+            resultsTable = $("#persons-table").dataTable(
+              sDom: "<'row'<'col-sm-6'<'form-group'l>><'col-sm-6'fi>r>t<'row'<'col-sm-12'>><'row'<'col-sm-12'p>>"
+              sPaginationType: "bootstrap"
+              stateSave: true
+              bFilter: false
+              aoColumnDefs: [
+                bSortable: false #disable sortables on these columns (starts at 0)
+                aTargets: [ 3 ]
+               ]
+              oLanguage:
+                sLengthMenu: "_MENU_ people per page"
+            )
+
+          @$el.show()
+        else
+          @$el.show()
+
+  class SearchFormView extends Backbone.View
+    el: "#page"
+    render: (options) ->
+      that = @
+      templated = _.template($("#breadcrumb-template").html(),
+        breadcrumbs: [
+          title: "Search"
+          url: "/search"
+         ]
+      )
+      $("#breadcrumb").html templated
+
+      require [ "text!../templates/search.html.tpl" ], (template) ->
+        that.$el.html _.template(template)
+
+      countries = new Countries()
+      console.log "fetch countries"
+      #fetch the countries collection with an ajax call
+      countries.fetch
+        dataType: "jsonp"
+        data: []
+        success: (countries) ->
+          console.log "countries: ", countries
+        error: (response) ->
+          console.log response
+        reset: true
+
+    events:
+      "click div[id^=search-] label.btn": "visualDateUpdate"
+      "change input[id$=-start], input[id$=-end]": "valueDateUpdate"
+      "submit #search-form": "searchResults"
+
+    searchResults: ->
+      alert "not quite ready yet"
+      false
+
+    visualDateUpdate: (event) ->
+      optionHit = $(event.currentTarget)[0].firstElementChild
+      set = $(optionHit)[0].name.split("-")[0]
+      value = parseInt($(optionHit)[0].value)
+      switch value
+        when 0
+          $("#" + set + "-end, #" + set + "-and").hide()
+          $("#" + set + "-start").show()
+        when 1
+          $("#" + set + "-start, #" + set + "-and").hide()
+          $("#" + set + "-end").show()
+        when 2
+          $("#" + set + "-end, #" + set + "-and").hide()
+          $("#" + set + "-start").show()
+        when 3
+          $("#" + set + "-end, #" + set + "-and, #" + set + "-start").show()
+        else
+      @valueDateUpdate event
+      console.log "visual"
+
+    valueDateUpdate: (event) ->
+      console.log event.type
+      set = event.currentTarget.id.split("-")[0]
+      optionSelected = parseInt(event.currentTarget.id.split("-")[2])  if event.type is "click"
+      optionSelected = parseInt($("input[name=" + set + "-range]:checked").val())  if event.type is "change"
+      switch optionSelected
+        when 0 #precice
+          $("#" + set + "-start").val ""  if $("#" + set + "-start").val() is "0000"
+          $("#" + set + "-end").val $("#" + set + "-start").val()
+        when 1 #before
+          $("#" + set + "-start").val "0000"
+          $("#" + set + "-end").val ""  if $("#" + set + "-end").val() is "9999"
+        when 2 #after
+          $("#" + set + "-end").val "9999"
+          $("#" + set + "-start").val ""  if $("#" + set + "-start").val() is "0000"
+        when 3 #between
+          console.log "evaluating: ", $("#" + set + "-start").val(), $("#" + set + "-end").val()
+          $("#" + set + "-start").val ""  if $("#" + set + "-start").val() is "0000"
+          $("#" + set + "-end").val ""  if $("#" + set + "-end").val() is "9999"
+        else
+      console.log "data"
+    @
+
+  class PersonSingleView extends Backbone.View
+    el: "#page"
+    fuzzyDateRenderer: (type, date1, date2) ->
+
+      #takes the HL way of representing fuzzy dates, and returns a formatted string.
+      switch type
+        when "exactly"
+          return date1
+        when "between"
+          return "between " + ((if isset(date1) then date1 else "unknown")) + " and " + ((if isset(date2) then date2 else "unknown"))
+        when "unknown", null
+          "unknown"
+
+    render: (options) ->
+      that = this
+      require [ "text!../templates/view.html.tpl" ], (template) ->
+        that.$el.html _.template(template)
+
+      person = new Person(id: options.id)
+      person.fetch
+        dataType: "jsonp"
+        success: (person) ->
+
+          # use some render helpers to add to the model some text to format fuzzy date types
+          person.set
+            birthdate: that.fuzzyDateRenderer(person.get("birthtype"), person.get("birthdate1"), person.get("birthdate2"))
+            deathdate: that.fuzzyDateRenderer(person.get("deathtype"), person.get("deathdate1"), person.get("deathdate2"))
+
+
+          # render the person partial
+          require [ "text!../templates/view_details.html.tpl" ], (template) ->
+            $("#person-details").html _.template(template,
+              person: person
+            )
+
+
+          # now we have a name, add this to the breadcrumb
+          template = _.template($("#breadcrumb-template").html(),
+            breadcrumbs: [
+              url: "#view/" + person.id
+              title: person.get("forenames") + " " + person.get("surname")
+             ]
+          )
+          $("#breadcrumb").html template
+
+
+      #create a new relationships collection for this person
+      relationships = new Relationships(id: options.id)
+
+      #fetch the relationships collection with an ajax call
+      relationships.fetch
+        dataType: "jsonp"
+        success: (relationships) ->
+          template = undefined
+
+          #evaluate whether this person has any relationships in the collection to display
+          if relationships.models.length > 0
+            require [ "text!../templates/view_relationships.html.tpl" ], (template) ->
+              $("#relationships").html _.template(template,
+                relationships: relationships.models
+              )
+
+          else
+
+            # cant name the person because it is loaded syncronously.
+            template = "No relationships were found."
+            $("#relationships").html template
+
+
+  class Router extends Backbone.Router
+    routes:
+      "": "home"
+      "view/:id": "viewPerson"
+      new: "editPerson"
+      list: "home"
+      search: "searchForm"
+
+  router = new Router
+
+  #because peopleListView is special, we need to have this outside of the init router, otherwise it doesn't work when we call a subpage directly etc.
+  router.on "route:home", ->
+    peopleListView = new PeopleListView()
+    peopleListView.render()
+
+  router.on "route:searchForm", ->
+    searchFormView = new SearchFormView()
+    $("#homepage").hide()
+    searchFormView.render()
+
+  router.on "route:viewPerson", (id) ->
+    personSingleView = new PersonSingleView()
+    $("#homepage").hide()
+    personSingleView.render id: id
+
+  Backbone.history.start()


resize things *after* rendering things. fixes #6

I could not reliably duplicate the issue, so the fix is not verified.

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


:boom: still working on it

:boom: still working on it

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

--- src/aui.coffee
+++ src/aui.coffee
@@ -0,0 +1,28 @@
+optional = require
+React = window.React or optional 'react'
+$ = window.jQuery or optional 'jquery'
+
+
+Aui = React.createClass
+  render: ->
+    recursivelyClassifyProps @props.children
+Aui.Aui = Aui
+Aui.modules = $.site?.settings?.modules or []
+
+classifyProps = Aui.classifyProps = (element, props = {}) ->
+  classNames = {}
+  for name in "#{element.props?.className or ''} #{props.className or ''}".split /\s+/g
+    classNames[name] = yes if name
+  for own name, include of element.props
+    if include is yes or name in Aui.modules
+      classNames[name] = yes
+  props.className = classNames.join ' ' if classNames.length
+  React.cloneElement element, props
+
+recursivelyClassifyProps = Aui.recursivelyClassifyProps = (element, props = {}) ->
+  children = React.Children.map if props.children or element.props?.children or null, (child) ->
+    recursivelyClassifyProps child
+  props.children = children if children.length
+  classifyProps element, props
+
+if module and require then module.exports = Aui else window.Aui = Aui


user agent detection

user agent detection

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

--- src/coffee/user_agent.coffee
+++ src/coffee/user_agent.coffee
@@ -0,0 +1,16 @@
+class UserAgent
+  detect: () ->
+    userAgent = (window.navigator && navigator.userAgent) || ""
+
+    for own ua, regex of UAs
+      if regex.test(userAgent)
+        return ua
+
+UAs =
+  android: /android/i
+  ios: /(ipad|iphone|ipod)/i
+  linux: /linux/i
+  osx: /macintosh/i
+  windowsPhone: /windows phone/i
+
+module.exports = UserAgent


Configure default listeners

Configure default listeners

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

--- src/default-listeners.coffee
+++ src/default-listeners.coffee
@@ -0,0 +1,87 @@
+# Listeners for the default models, which learn forward and reverse word chains
+# from a catchAll block and respond to "hubot markov" and "hubot remarkov".
+# If configured to do so, randomly respond to arbitrary messages with a
+# markov string generated from a word from that message.
+
+preprocessor = require './preprocessor'
+
+module.exports = (robot, config) ->
+  activeModelNames = []
+
+  if config.defaultModel
+    robot.markov.createModel 'default_forward', {}
+    activeModelNames.push 'default_forward'
+
+    robot.markov.generateForward = (seed, callback) ->
+      robot.markov.modelNamed 'default_forward', (model) ->
+        model.generate seed, config.generateMax, callback
+
+    # Generate markov chains on demand, optionally seeded by some initial state.
+    robot.respond /markov(\s+(.+))?$/i, (msg) ->
+      robot.markov.generateForward msg.match[2] or '', (text) -> msg.send text
+
+  if config.reverseModel
+    reverseWords = (input) -> preprocessor.reverse(preprocessor.words(input))
+
+    robot.markov.createModel 'default_reverse', {}, (model) ->
+      model.preprocessWith reverseWords
+
+    activeModelNames.push 'default_reverse'
+
+    robot.markov.generateReverse = (seed, callback) ->
+      robot.markov.modelNamed 'default_reverse', (model) ->
+        model.generate seed, config.generateMax, callback
+
+    # Generate reverse markov chains on demand, optionally seeded by some end state
+    robot.respond /remarkov(\s+(.+))?$/i, (msg) ->
+      robot.markov.generateReverse msg.match[2] or '', (text) -> msg.send text
+
+  if config.defaultModel and config.reverseModel
+
+    robot.markov.generateMiddle = (seed, callback) ->
+      generateRight = (cb) ->
+        robot.markov.modelNamed 'default_forward', (model) ->
+          model.generate seed, config.generateMax, cb
+
+      generateRest = (right, cb) ->
+        words = preprocessor.words(right)
+        rightSeed = words.shift() or ''
+        rest = words.join ' '
+
+        robot.markov.modelNamed 'default_reverse', (model) ->
+          model.generate rightSeed, config.generateMax, (left) ->
+            cb([left, rest].join ' ')
+
+      generateRight (right) ->
+        generateRest right, callback
+
+    # Generate markov chains with the seed in the middle
+    robot.respond /mmarkov(\s+(.+))?$/i, (msg) ->
+      robot.markov.generateMiddle msg.match[2] or '', (text) -> msg.send text
+
+  if activeModelNames.length isnt 0
+
+    # The robot hears ALL. You cannot run.
+    robot.catchAll (msg) ->
+      # Ignore empty messages
+      return if !msg.message.text
+
+      # Return if message containers a URL
+      return if !config.includeUrls and msg.message.text.match /https?:\/\//
+
+      # Disregard ignored usernames.
+      return if msg.message.user.name in settings.ignoreList
+
+      # Pass the message to each active model.
+      for name in activeModelNames
+        robot.markov.modelNamed name, (model) -> model.learn msg.message.text
+
+    if config.respondChance > 0
+      robot.catchAll (msg) ->
+        if Math.random() < config.respondChance
+          randomWord = msg.random(preprocessor.words(msg.message.text)) or ''
+
+          if config.reverseModel
+            robot.markov.generateMiddle randomWord, (text) -> msg.send text
+          else
+            robot.markov.generateForward randomWord, (text) -> msg.send text


Client: Activity: Tests: Added proptypes and renamed class


Add dummy src file

Add dummy src file

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

--- src/jquery.turbolinks.coffee
+++ src/jquery.turbolinks.coffee
@@ -0,0 +1,11 @@
+###
+  jquery.turbolinks.js ~ v0.1.0 ~ https://github.com/kossnocorp/jquery.turbolinks
+
+  jQuery plugin for rebind events problem caused by Tubrolinks
+
+  The MIT License
+
+  Copyright (c) 2012 Sasha Koss
+###
+
+$ = require?('jquery') || window.jQuery


Client: Activity: Updated ChannelList renderChildren method to update list item type by given itemComponent prop


Delete SampleCode.coffee

Delete SampleCode.coffee

--- src/sample/SampleCode.coffee
+++ src/sample/SampleCode.coffee
@@ -1,8 +0,0 @@
-module.exports = ()->
-
-  class SampleCode
-
-    constructor:(props)->
-
-    test:->
-      "The test worked"


Added prevent scroll propagation for sidebar

error: pathspec 'core/app/assets/javascripts/frontend/left-column.coffee' did not match any file(s) known to git

--- core/app/assets/javascripts/frontend/left-column.coffee
+++ core/app/assets/javascripts/frontend/left-column.coffee
@@ -0,0 +1 @@
+$('#left-column').preventScrollPropagation();


return one of many alternative trollfaces when trolling is mentioned

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

--- src/scripts/trolololo.coffee
+++ src/scripts/trolololo.coffee
@@ -0,0 +1,42 @@
+# Description:
+#   None
+#
+# Dependencies:
+#   None
+#
+# Configuration:
+#   HUBOT_IMGUR_CLIENT_ID
+#
+# Commands:
+#   trol.* - returns one of many alternative trollfaces when trolling is
+#   mentioned (troll, trolling, trolololololo...)
+#
+# Author:
+#   ajacksified
+
+
+https = require('https')
+
+options =
+  hostname: 'api.imgur.com'
+  path: '/3/album/pTXm0'
+  headers:
+    'Authorization': "Client-ID #{process.env.HUBOT_IMGUR_CLIENT_ID}"
+
+module.exports = (robot) ->
+  robot.hear /\btrol\w+?\b/i, (msg) ->
+    data = []
+
+    https.get(options, (res) ->
+      if res.statusCode == 200
+        res.on 'data', (chunk) ->
+          data.push(chunk)
+
+        res.on 'end', () ->
+          parsedData = JSON.parse(data.join(''))
+          images = parsedData.data.images
+          image = images[parseInt(Math.random() * images.length)]
+
+          msg.send(image.link)
+    )
+


Client: Activity: Tests: Created TabView component for BrowsePublicChannelsModalView


Add a simple launcher that helps to play with scriptscript

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

--- run.coffee
+++ run.coffee
@@ -0,0 +1,29 @@
+# # TODO figure out better name & place & API for such script
+# # TODO add shebang & make executable
+require 'fy'
+if !process.argv[2]?
+  perr "Usage: iced run.coffee [input]"
+  process.exit 1
+## -v 0
+# me = require "."
+# await me.go process.argv[2], {}, defer err, res
+# throw err if err
+# p res
+
+## -v 2
+p "Input:", process.argv[2] # just to make sure that we are given the right string
+{tokenize} = require './tokenizer'
+{parse   } = require './grammar'
+{translate} = require './translator'
+await tokenize  process.argv[2], {}, defer err, tok_res
+throw err if err
+p "Token list:"
+pp tok_res
+await parse     tok_res, {}, defer err, ast
+throw err if err
+p "AST:"
+p ast
+await translate ast[0],  {}, defer err, res
+throw err if err
+p "Output: ", res
+


update pointers to libs on stack_intro

update pointers to libs on stack_intro

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


Added when-scrolled directive

Added when-scrolled directive

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

--- app/assets/javascripts/sprangular/directives/whenScrolled.coffee
+++ app/assets/javascripts/sprangular/directives/whenScrolled.coffee
@@ -0,0 +1,10 @@
+Sprangular.directive 'whenScrolled', ->
+  link: (scope, elm, attr) ->
+    $window = $(window)
+    $document = $(document)
+
+    TRIGGER_OFFSET = 100
+
+    $window.bind 'scroll', ->
+      if $window.scrollTop() + window.innerHeight > $document.height() - TRIGGER_OFFSET
+        scope.$apply(attr.whenScrolled)


up and down arrows

up and down arrows

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


Add pattern handler for chip elements (incomplete yet)

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

--- src/pattern/default/chip.coffee
+++ src/pattern/default/chip.coffee
@@ -0,0 +1,44 @@
+sprintf = require('sprintf-js').sprintf
+calculator = require './common/calculator'
+dual = require './common/dual'
+
+abbrs =
+  CAPC: ['capacitor']
+  RESC: ['resistor']
+  RESDFN: ['resistor', 'no-lead']
+  RESMELF: ['resistor', 'melf']
+  RESM: ['resistor', 'molded']
+  RESSC: ['resistor', 'concave']
+
+getName = (element) ->
+  name = 'U'
+  unless element.keywords? then return name
+  keywords = element.keywords.replace(/\s+/g, '').split(',')
+  abbrWeight = 0
+  for abbr, classes of abbrs
+    weight = keywords.filter((a) => classes.indexOf(a) isnt -1).length
+    if weight > abbrWeight
+      abbrWeight = weight
+      name = abbr
+  name
+
+module.exports = (pattern, element) ->
+  housing = element.housing
+  height = housing.height.max ? housing.height
+  pattern.name ?= sprintf "%s%dX%dX%d",
+    getName(element),
+    [housing.length.nom*100
+    housing.width.nom*100
+    height*100]
+    .map((a) => Math.round a)...
+
+  settings = pattern.settings
+
+  # Calculate pad dimensions according to IPC-7351
+  housing.bodyWidth ?= housing.width
+  housing.bodyLength ?= housing.length
+  housing.leadWidth ?= housing.bodyWidth
+  housing.leadSpan ?= housing.bodyLength
+  padParams = calculator.sop pattern, housing
+
+  console.log padParams


rolling

rolling

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

--- scripts/rolling.coffee
+++ scripts/rolling.coffee
@@ -0,0 +1,10 @@
+# Description
+#   They see me rolling.
+#
+#  Author:
+#   ivey
+
+
+module.exports = (robot) ->
+  robot.hear /let's roll|see me rollin/i, (msg) ->
+    msg.send "http://mlkshk.com/r/PWID.gif"


Now, with re-tweets

Now, with re-tweets

This adds .rt <tweet> as a command to RT the tweet ID or URL to our
account.

Because it's useful or something.

--- scripts/twitter.coffee
+++ scripts/twitter.coffee
@@ -1,6 +1,19 @@
 t = require '../lib/twitter'

 module.exports = (robot) ->
+  robot.respond /(?:retweet|rt|retwat)\s+(.+$)/i, (msg) ->
+    tid = msg.match[1].trim()
+    tid = if tid.match(/^\d+$/)
+        tid
+      else if (info = tid.match /twitter.com\/\w+\/status+\/(\d+)/)
+        info[1]
+
+    return msg.reply "That's not a fucking tweet, moron" if not tid
+    t.client.post "statuses/retweet/#{tid}", {}, (err, tweet, response) ->
+      return msg.reply "No, because #{err}" if err
+      msg.reply "Fine, did it."
+
+
   robot.respond /tweet(\s+(me)?)?\s+(.{3,})$/i, (msg) ->
     who = msg.message.user.name or "Some-Idiot"
     what = msg.match[3].trim()


added first passivetotal command

added first passivetotal command

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

--- src/scripts/passivetotal.coffee
+++ src/scripts/passivetotal.coffee
@@ -0,0 +1,59 @@
+# Description:
+#   PassiveTotal
+#
+# Dependencies:
+#   None
+#
+# Configuration:
+#   PASSIVETOTAL_KEY - Sign up at https://investigate.opendns.com
+#
+# Commands:
+#   hubot ptotal <value> - Gets PassiveTotal Information for a given IP or domain
+#
+# Author:
+#   Scott J Roberts - @sroberts
+
+PASSIVETOTAL_KEY = process.env.PASSIVETOTAL_KEY
+
+PASSIVETOTAL_API = "https://www.passivetotal.org"
+PT_PASSIVE_URL =  PASSIVETOTAL_API + "/api/passive"
+
+
+module.exports = (robot) ->
+  robot.respond /ptotal (.*)/i, (msg) ->
+
+    if PASSIVETOTAL_KEY?
+      value = msg.match[1].toLowerCase()
+      data = "apikey=#{encodeURIComponent PASSIVETOTAL_KEY}&value=#{encodeURIComponent value}"
+
+      robot.http(PT_PASSIVE_URL)
+        .post(data) (err, res, body) ->
+          if res.statusCode is 200
+            pt_json = JSON.parse(body)
+
+            pt = pt_json.results
+
+            response = "I checked out #{pt.type} #{pt.value}. Here's what I found:\n"
+            response += "- Seen from #{pt.firstSeen} to #{pt.lastSeen}\n" if pt.firstSeen != "N/A" and pt.lastSeen != "N/A"
+            response += "- It's in ASN #{pt.asn}\n" if +pt.asn > 0
+            response += "- The ISP is #{pt.isp}\n" if pt.isp
+
+            resolution = ""
+            resolution += "  - #{res.resolve} #{res.tags}\n" for res in pt.resolutions
+
+            response += "- Resolutions: \n" if resolution
+            response += resolution
+
+            response += "- Wow... that was a lot of resolutions!\n" if pt.resolutions > 10
+            response += "- Users tagged this as #{pt.userTags}\n" if pt.userTags.length > 0
+            response += "- #{res.value} is classifed as #{pt.classified}\n" if pt.classified
+            response += "- Pretty sure it's a sinkhole though...\n" if pt.sinkhole is true
+            response += "\nFor full results see https://www.passivetotal.org/passive/#{pt.value}"
+
+            response = "No joy sparky, PassiveTotal didn't find any resolutions but feel free to check https://www.passivetotal.org/passive/#{pt.value}.\n" if pt.resolutions.length == 0
+
+            msg.send response
+          else
+            msg.send "Doh! #{res.statusCode}: Which means that didn't work."
+    else
+      msg.send "PassiveTotal API key not configured."


highlight the jekyll front matter in html files

error: pathspec 'grammars/jekyll-html.cson' did not match any file(s) known to git

--- grammars/jekyll-html.cson
+++ grammars/jekyll-html.cson
@@ -0,0 +1,20 @@
+'scopeName': 'text.hmtl.jekyll'
+'name': 'Jekyll (HTML)'
+'fileTypes': [
+  'html'
+]
+'firstLineMatch': '^---$'
+'patterns': [
+  {
+    'include': 'text.html.basic'
+  }
+  {
+    'begin': '---'
+    'end': '---'
+    'patterns': [
+      {
+        'include': 'source.yaml'
+      }
+    ]
+  }
+]


made select tool work again re-added box selection overlay had to move bind_bokeh_events out of delegateEvents - now it is only called after build_views

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

--- static/coffee/overlays/boxselectionoverlay.coffee
+++ static/coffee/overlays/boxselectionoverlay.coffee
@@ -0,0 +1,80 @@
+base = require("../base")
+PlotWidget = require("../common/plot_widget").PlotWidget
+HasParent = base.HasParent
+
+class BoxSelectionOverlayView extends PlotWidget
+
+  initialize : (options) ->
+    @selecting = false
+    @xrange = [null, null]
+    @yrange = [null, null]
+    super(options)
+    @plot_view.$el.find('.bokeh_canvas_wrapper').append(@$el)
+
+  boxselect : (xrange, yrange) ->
+    @xrange = xrange
+    @yrange = yrange
+    @request_render()
+    console.log('valchange')
+
+  startselect : () ->
+    @selecting = true
+    @xrange = [null, null]
+    @yrange = [null, null]
+    @request_render()
+    console.log('selecting')
+
+  stopselect : () ->
+    @selecting = false
+    @xrange = [null, null]
+    @yrange = [null, null]
+    @request_render()
+    console.log('not selecting')
+
+  bind_bokeh_events : (options) ->
+    @toolview = @plot_view.tools[@mget('tool').id]
+    @listenTo(@toolview, 'boxselect', @boxselect)
+    @listenTo(@toolview, 'startselect', @startselect)
+    @listenTo(@toolview, 'stopselect', @stopselect)
+
+  render : () ->
+    if not @selecting
+      @$el.removeClass('shading')
+      return
+    xrange = @xrange
+    yrange = @yrange
+    if _.any(_.map(xrange, _.isNullOrUndefined)) or
+      _.any(_.map(yrange, _.isNullOrUndefined))
+        @$el.removeClass('shading')
+        return
+    style_string = ""
+    xpos = @plot_view.view_state.device_to_sx(Math.min(xrange[0], xrange[1]))
+    if xrange
+      width = Math.abs(xrange[1] - xrange[0])
+    else
+      width = @plot_view.view_state.get('width')
+    style_string += "; left:#{xpos}px; width:#{width}px; "
+    ypos = @plot_view.view_state.device_to_sy(Math.max(yrange[0], yrange[1]))
+    if yrange
+      height = yrange[1] - yrange[0]
+    else
+      height = @plot_view.view_state.get('height')
+    @$el.addClass('shading')
+    style_string += "top:#{ypos}px; height:#{height}px"
+    @$el.attr('style', style_string)
+
+class BoxSelectionOverlay extends HasParent
+  type : 'BoxSelectionOverlay'
+  default_view : BoxSelectionOverlayView
+_.extend(BoxSelectionOverlay::defaults
+  ,
+    tool : null
+    level : 'overlay'
+)
+
+class BoxSelectionOverlays extends Backbone.Collection
+  model : BoxSelectionOverlay
+
+exports.boxselectionoverlays = new BoxSelectionOverlays
+exports.BoxSelectionOverlayView = BoxSelectionOverlayView
+exports.BoxSelectionOverlay = BoxSelectionOverlay


Test student identifier component

Test student identifier component

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

--- test/course/update-student-identifier.spec.coffee
+++ test/course/update-student-identifier.spec.coffee
@@ -0,0 +1,29 @@
+{Testing, expect, sinon, _, ReactTestUtils} = require 'openstax-react-components/test/helpers'
+
+Course = require 'course/model'
+
+UpdateStudentIdentifier = require 'course/update-student-identifier'
+
+describe 'UpdateStudentIdentifier Component', ->
+
+  beforeEach ->
+    @props =
+      course: new Course(ecosystem_book_uuid: 'test-collection-uuid')
+
+  it 'submits a request when form is filled out', ->
+    sinon.stub(@props.course, 'updateStudent')
+    Testing.renderComponent( UpdateStudentIdentifier, props: @props ).then ({dom}) =>
+      dom.querySelector('input').value = 'test value'
+      Testing.actions.click(dom.querySelector('.btn-default'))
+      expect(@props.course.updateStudent).to.have.been.calledWith(student_identifier: 'test value')
+
+  it 'updates when a successful response is recieved',  (done) ->
+    sinon.stub(@props.course, 'updateStudent', (id) ->
+      @_onStudentUpdated({data: {student_identifier: id}})
+    )
+    Testing.renderComponent( UpdateStudentIdentifier, props: @props ).then ({element, dom}) ->
+      dom.querySelector('input').value = 'new id'
+      Testing.actions.click(dom.querySelector('.btn-default'))
+      _.defer ->
+        expect(element.getDOMNode().textContent).to.match(/You have successfully updated your student identifier/)
+        done()


Fixed typo.

Fixed typo.

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


remove unnecessary console.log

remove unnecessary console.log

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


fix audio

fix audio

--- views/app.cjsx
+++ views/app.cjsx
@@ -87,7 +87,7 @@
           @handleSetAlwaysOnTop()
       catch e
         false
-    , 100
+    , 1000
   render: ->
     <div>
       <OverlayTrigger placement='left' overlay={<Tooltip>开发人员工具</Tooltip>}>


remove dingling , in front

remove dingling , in front

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/8DTechnologies/jobot-storage-util.git/'


Provide HOST_IP and HOST_NAME to all script template

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


Added sns message verification logic

Added sns message verification logic

error: pathspec 'src/sns-message-verify.coffee' did not match any file(s) known to git

--- src/sns-message-verify.coffee
+++ src/sns-message-verify.coffee
@@ -0,0 +1,46 @@
+https = require('https')
+crypto = require('crypto')
+# url = require('url')
+
+certificateCache = { }
+
+downloadCertificate = (url, cb) ->
+  if url in certificateCache
+    cb certificateCache[url]
+
+  https.get(url) (err, res, body) ->
+    chunks = []
+
+    res.on 'data', (chunk) -> chunks.push(chunk)
+    res.on 'end', () ->
+      certificateCache[url] = chunks.join('')
+      cb certificateCache[url]
+
+signatureStringOrder =
+  'Notification': [ 'Message', 'MessageId', 'Subject', 'Timestamp', 'TopicArn', 'Type'],
+  'SubscriptionConfirmation': [ 'Message', 'MessageId', 'SubscribeURL', 'Timestamp', 'Token', 'TopicArn', 'Type' ],
+  'UnsubscribeConfirmation': [ 'Message', 'MessageId', 'SubscribeURL', 'Timestamp', 'Token', 'TopicArn', 'Type' ]
+
+createSignatureString = (msg) ->
+  chunks = []
+  for field in signatureStringOrder[msg.Type]
+    if field in msg
+      chunks.push field
+      chunks.push msg[field]
+  return chunks.join('\n') + '\n'
+
+verifySignature = (msg, success, failure) ->
+  if msg.SignatureVersion isnt 1
+    return failure()
+
+  downloadCertificate msg.SigningCertURL, (pem) ->
+    signatureString = createSignatureString(msg);
+
+    verifier = crypto.createVerify('RSA-SHA1');
+    verifier.update(signatureString, 'utf8');
+    if verifier.verify(pem, msg.Signature, 'base64')
+      return success()
+    else
+      return failure()
+
+module.exports = { verifySignature: verifySignature }


rename to .js.coffee

rename to .js.coffee

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

--- graph.js.coffee
+++ graph.js.coffee
@@ -0,0 +1,27 @@
+# graph.coffee
+# Library for graph theory functions
+# J. Hassler Thurston
+# Adapted from Mathematica code written in 2010-2011
+# January 24, 2014
+
+
+
+# graphs:
+# represented by an object, which has vertex and edge attributes
+# the vertices are represented by an array of vertex names
+# the edges are represented by a ragged array, where the ith array contains other vertices connected to the ith vertex
+# e.g. the graph with edges 1->2, 0->3, 4->1, 1->0 would be represented by the object
+# {
+# 	vertices: [1,2,0,3,4],
+# 	edges: [[2,0],[],[3],[],[1]]
+# }
+
+# creates a graph with the given edges
+class Graph
+	constructor: (@edges) ->
+		vertices = (edge[0] for edge in edges if edge[0] not in vertices)
+
+
+
+
+


extract SC.Helper.responseHandler

extract SC.Helper.responseHandler

--- src/sdk.coffee
+++ src/sdk.coffee
@@ -142,18 +142,8 @@
       uri.query = {}

     handleResponse = (responseText, xhr) ->
-      json = SC.Helper.JSON.parse(responseText)
-      error = null
-
-      if !json
-        if xhr
-          error = {message: "HTTP Error: " + xhr.status}
-        else
-          error = {message: "Unknown error"}
-      else if json.errors
-        error = { message: json.errors && json.errors[0].error_message }
-
-      callback(json, error)
+      response = SC.Helper.responseHandler(responseText, xhr)
+      callback(response.json, response.error)

     if SC.options.flashXHR
       this.whenRecordingReady ->
@@ -273,6 +263,21 @@
       query["_status_code_map[500]"] = 200
       query["_status_code_map[503]"] = 200
       query["_status_code_map[504]"] = 200
+
+    responseHandler: (responseText, xhr) ->
+      json = SC.Helper.JSON.parse(responseText)
+      error = null
+
+      if !json
+        if xhr
+          error = {message: "HTTP Error: " + xhr.status}
+        else
+          error = {message: "Unknown error"}
+      else if json.errors
+        error = { message: json.errors && json.errors[0].error_message }
+
+      {"json": json, "error": error}
+
     FakeStorage: ->
       return {
         _store: {}


comment out lcd

comment out lcd

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


display init fix

display init fix


hardwareFixes toneFeedback relayFixes

hardwareFixes toneFeedback relayFixes


chore (drawer tests) disable tests until steroids with drawers enable/disable is merged


activity: add ParticipantHeads view

activity: add ParticipantHeads view

error: pathspec 'client/activity/lib/views/privatemessage/participantheads.coffee' did not match any file(s) known to git

--- client/activity/lib/views/privatemessage/participantheads.coffee
+++ client/activity/lib/views/privatemessage/participantheads.coffee
@@ -0,0 +1,136 @@
+kd                     = require 'kd'
+AvatarView             = require 'app/commonviews/avatarviews/avatarview'
+MoreParticipantsButton = require './moreparticipantsbutton'
+
+###*
+ * A view to list participants of a SocialChannel. Especially for
+ * PrivateMessages and Collaboration Channels. It has 3 containers:
+ *
+ *     - `previewContainer` - contains the avatar list.
+ *     - `extrasContainer` - contains views for showing extra people
+ *     - `newButtonContainer` - contains views for adding people.
+ *
+ * Biggest difference of this view, it works stateless. There is no saved
+ * avatars, participants or anything. This class basically takes participants,
+ * and renders them, you can pass an object to follow the same semantics of
+ * result of the `ChannelParticipants::getList` method to
+ * `ParticipantHeads::updateParticipants` method, it will destroy everything and
+ * re-render with given participants. See `ParticipantHeads::updateParticipants
+ * for detailed info.
+ *
+ * @class
+###
+module.exports = class ParticipantHeads extends kd.CustomHTMLView
+
+  constructor: (options = {}, data) ->
+
+    options.cssClass = 'ParticipantHeads clearfix'
+
+    super options, data
+
+    @moreListView = null
+
+    @previewContainer   = k 'div', 'ParticipantHeads-previewContainer clearfix'
+    @extrasContainer    = k 'div', 'ParticipantHeads-extrasContainer clearfix'
+    @newButtonContainer = k 'div', 'ParticipantHeads-newButtonContainer clearfix'
+
+    @newButtonContainer.addSubView @newParticipantButton = new kd.ButtonView
+      cssClass : 'ParticipantHeads-button ParticipantHeads-button--new'
+      iconOnly : yes
+      callback : @bound 'onNewParticipantClick'
+
+    @addSubView @previewContainer
+    @addSubView @extrasContainer
+    @addSubView @newButtonContainer
+
+
+  ###*
+   * Click handler for new participant button.
+  ###
+  onNewParticipantClick: ->
+
+    @newParticipantButton.toggleClass 'active'
+    @emit 'NewParticipantButtonClicked'
+
+
+  ###*
+   * Resets new participant button's state.
+  ###
+  resetNewButtonState: ->
+
+    @newParticipantButton.unsetClass 'active'
+
+
+  ###*
+   * Whenever a change happens this method needs to be triggered with
+   * participant map that follows the signature of
+   * `ChannelParticipants::getLists` method, which is an object with 3
+   * properties:
+   *
+   *     - `preview` - participants for preview container.
+   *     - `hidden` - participants for extras container.
+   *     - `all` - all participants for this channel.
+   *
+   * Those object's properties are all instances of `immutable.OrderedMap`
+   *
+   * @param {object} participantsMap
+   * @param {Immutable.OrderedMap} participantsMap.preview
+   * @param {Immutable.OrderedMap} participantsMap.hidden
+  ###
+  updateParticipants: (participantsMap) ->
+
+    @updatePreviewAvatars participantsMap.preview
+    @updateExtras participantsMap.hidden
+
+
+  ###*
+   * Destroy all avatars, then re-add avatars for given participant map.
+   *
+   * @param {Immutable.OrderedMap} participants
+  ###
+  updatePreviewAvatars: (participants) ->
+
+    avatars = participants.toJS().map (participant) ->
+      options = { size: { width: 25, height: 25 } }
+      new AvatarView options, participant
+
+    @previewContainer.destroySubViews()
+    @previewContainer.addSubView avatar  for avatar in avatars
+
+
+  ###*
+   * Destroy all subviews of extras container, and re-add the views back for
+   * given participant map.
+   *
+   * @param {Immutable.OrderedMap} participants
+  ###
+  updateExtras: (participants) ->
+
+    return  @extrasContainer.hide()  unless count = participants.size
+
+    moreButton = new MoreParticipantsButton { participantList: participants }
+
+    @extrasContainer.destroySubViews()
+    @extrasContainer.addSubView moreButton
+    @extrasContainer.show()
+
+
+###*
+ * Create a KDView with given tag, css class, and subviews.
+ *
+ * @param {string} tagName
+ * @param {string} cssClass
+ * @param {Array.<(KDView|string)>} subviews
+###
+k = (tagName, cssClass, subviews = []) ->
+
+  view = new kd.CustomHTMLView { tagName, cssClass }
+
+  for subview in subviews
+    if 'string' is typeof subview
+    then view.setPartial subview
+    else view.addSubView subview
+
+  return view
+
+


Remove ssh.coffee since it's not necessary anymore


added tests

added tests

error: pathspec 'client/apps/edit/components/layout/components/yoast/test/index.coffee' did not match any file(s) known to git

--- client/apps/edit/components/layout/components/yoast/test/index.coffee
+++ client/apps/edit/components/layout/components/yoast/test/index.coffee
@@ -0,0 +1,35 @@
+_ = require 'underscore'
+benv = require 'benv'
+sinon = require 'sinon'
+rewire = require 'rewire'
+Backbone = require 'backbone'
+fixtures = require '../../../../../../../../test/helpers/fixtures'
+{ resolve } = require 'path'
+
+describe 'YoastView', ->
+
+  beforeEach (done) ->
+    benv.setup =>
+      benv.expose $: benv.require('jquery')
+      tmpl = $('

')
+      Backbone.$ = $
+      sinon.stub Backbone, 'sync'
+      @YoastView = rewire '../index.coffee'
+      @YoastView.__set__ 'Modal', sinon.stub()
+      @YoastView.__set__ 'yoastSnippetPreview', -> { changedInput: -> }
+      @YoastView.__set__ 'yoastApp', -> { refresh: -> }
+
+      @view = new @YoastView
+        el: tmpl
+        contentField: 'Testing This Content Field'
+        title: 'Test Title'
+        slug: 'test-slug'
+      done()
+
+  afterEach ->
+    benv.teardown()
+    Backbone.sync.restore()
+
+  describe '#initialize', ->
+
+    xit 'adds yoast html to #yoast-container', ->