Include source.ruby to define grammar

Include source.ruby to define grammar

--- grammars/rubymotion.cson
+++ grammars/rubymotion.cson
@@ -2,1640 +2,6 @@
 'firstLineMatch': '^\\s*(class|module)\\s+([.a-zA-Z0-9_:]+\\s*<\\s*)?((NS|UI)[.a-zA-Z0-9_:]+)|([.a-zA-Z0-9_:]*AppDelegate)$'
 'name': 'RubyMotion'
 'patterns': [
-  {
-    'captures':
-      '1':
-        'name': 'keyword.control.class.ruby-motion'
-      '2':
-        'name': 'entity.name.type.class.ruby-motion'
-      '4':
-        'name': 'entity.other.inherited-class.ruby-motion'
-      '5':
-        'name': 'punctuation.separator.inheritance.ruby-motion'
-      '6':
-        'name': 'variable.other.object.ruby-motion'
-      '7':
-        'name': 'punctuation.definition.variable.ruby-motion'
-    'match': '^\\s*(class)\\s+(([.a-zA-Z0-9_:]+(\\s*(<)\\s*[.a-zA-Z0-9_:]+)?)|((<<)\\s*[.a-zA-Z0-9_:]+))'
-    'name': 'meta.class.ruby-motion'
-  }
-  {
-    'captures':
-      '1':
-        'name': 'keyword.control.module.ruby-motion'
-      '2':
-        'name': 'entity.name.type.module.ruby-motion'
-      '3':
-        'name': 'entity.other.inherited-class.module.first.ruby-motion'
-      '4':
-        'name': 'punctuation.separator.inheritance.ruby-motion'
-      '5':
-        'name': 'entity.other.inherited-class.module.second.ruby-motion'
-      '6':
-        'name': 'punctuation.separator.inheritance.ruby-motion'
-      '7':
-        'name': 'entity.other.inherited-class.module.third.ruby-motion'
-      '8':
-        'name': 'punctuation.separator.inheritance.ruby-motion'
-    'match': '^\\s*(module)\\s+(([A-Z]\\w*(::))?([A-Z]\\w*(::))?([A-Z]\\w*(::))*[A-Z]\\w*)'
-    'name': 'meta.module.ruby-motion'
-  }
-  {
-    'comment': 'else if is a common mistake carried over from other languages. it works if you put in a second end, but it’s never what you want.'
-    'match': '(?<!\\.)\\belse(\\s)+if\\b'
-    'name': 'invalid.deprecated.ruby-motion'
-  }
-  {
-    'captures':
-      '1':
-        'name': 'punctuation.definition.constant.ruby-motion'
-    'comment': 'symbols as hash key (1.9 syntax)'
-    'match': '(?>[a-zA-Z_]\\w*(?>[?!])?)(:)(?!:)'
-    'name': 'constant.other.symbol.hashkey.ruby-motion'
-  }
-  {
-    'captures':
-      '1':
-        'name': 'punctuation.definition.constant.ruby-motion'
-    'comment': 'symbols as hash key (1.8 syntax)'
-    'match': '(?<!:)(:)(?>[a-zA-Z_]\\w*(?>[?!])?)(?=\\s*=>)'
-    'name': 'constant.other.symbol.hashkey.ruby-motion'
-  }
-  {
-    'comment': 'everything being a reserved word, not a value and needing a \'end\' is a..'
-    'match': '(?<!\\.)\\b(BEGIN|begin|case|class|else|elsif|END|end|ensure|for|if|in|module|rescue|then|unless|until|when|while)\\b(?![?!])'
-    'name': 'keyword.control.ruby-motion'
-  }
-  {
-    'comment': 'contextual smart pair support for block parameters'
-    'match': '(?<!\\.)\\bdo\\b\\s*'
-    'name': 'keyword.control.start-block.ruby-motion'
-  }
-  {
-    'comment': 'contextual smart pair support'
-    'match': '(?<=\\{)(\\s+)'
-    'name': 'meta.syntax.ruby-motion.start-block'
-  }
-  {
-    'comment': ' as above, just doesn\'t need a \'end\' and does a logic operation'
-    'match': '(?<!\\.)\\b(and|not|or)\\b'
-    'name': 'keyword.operator.logical.ruby-motion'
-  }
-  {
-    'comment': ' just as above but being not a logical operation'
-    'match': '(?<!\\.)\\b(alias|alias_method|break|next|redo|retry|return|super|undef|yield)\\b(?![?!])|\\bdefined\\?|\\bblock_given\\?'
-    'name': 'keyword.control.pseudo-method.ruby-motion'
-  }
-  {
-    'match': '\\bnil\\b(?![?!])'
-    'name': 'constant.language.nil.ruby-motion'
-  }
-  {
-    'match': '\\b(true|false)\\b(?![?!])'
-    'name': 'constant.language.boolean.ruby-motion'
-  }
-  {
-    'match': '\\b(__(FILE|LINE)__|self)\\b(?![?!])'
-    'name': 'variable.language.ruby-motion'
-  }
-  {
-    'comment': ' everything being a method but having a special function is a..'
-    'match': '\\b(initialize|new|loop|include|extend|prepend|raise|attr_reader|attr_writer|attr_accessor|attr|catch|throw|private|module_function|public|protected)\\b(?![?!])'
-    'name': 'keyword.other.special-method.ruby-motion'
-  }
-  {
-    'begin': '\\b(require|require_relative|gem)\\b'
-    'captures':
-      '1':
-        'name': 'keyword.other.special-method.ruby-motion'
-    'end': '$|(?=#|\\})'
-    'name': 'meta.require.ruby-motion'
-    'patterns': [
-      {
-        'include': '$self'
-      }
-    ]
-  }
-  {
-    'captures':
-      '1':
-        'name': 'punctuation.definition.variable.ruby-motion'
-    'match': '(@)[a-zA-Z_]\\w*'
-    'name': 'variable.other.readwrite.instance.ruby-motion'
-  }
-  {
-    'captures':
-      '1':
-        'name': 'punctuation.definition.variable.ruby-motion'
-    'match': '(@@)[a-zA-Z_]\\w*'
-    'name': 'variable.other.readwrite.class.ruby-motion'
-  }
-  {
-    'captures':
-      '1':
-        'name': 'punctuation.definition.variable.ruby-motion'
-    'match': '(\\$)[a-zA-Z_]\\w*'
-    'name': 'variable.other.readwrite.global.ruby-motion'
-  }
-  {
-    'captures':
-      '1':
-        'name': 'punctuation.definition.variable.ruby-motion'
-    'match': '(\\$)(!|@|&|`|\'|\\+|\\d+|~|=|/|\\\\|,|;|\\.|<|>|_|\\*|\\$|\\?|:|"|-[0adFiIlpv])'
-    'name': 'variable.other.readwrite.global.pre-defined.ruby-motion'
-  }
-  {
-    'begin': '\\b(ENV)\\['
-    'beginCaptures':
-      '1':
-        'name': 'variable.other.constant.ruby-motion'
-    'end': '\\]'
-    'name': 'meta.environment-variable.ruby-motion'
-    'patterns': [
-      {
-        'include': '$self'
-      }
-    ]
-  }
-  {
-    'match': '\\b[A-Z]\\w*(?=((\\.|::)[A-Za-z]|\\[))'
-    'name': 'support.class.ruby-motion'
-  }
-  {
-    'match': '\\b[A-Z]\\w*\\b'
-    'name': 'variable.other.constant.ruby-motion'
-  }
-  {
-    'begin': '(?x)\n\t\t\t         (?=def\\b)                                                      # an optimization to help Oniguruma fail fast\n\t\t\t         (?<=^|\\s)(def)\\s+                                              # the def keyword\n\t\t\t         ( (?>[a-zA-Z_]\\w*(?>\\.|::))?                                   # a method name prefix\n\t\t\t           (?>[a-zA-Z_]\\w*(?>[?!]|=(?!>))?                              # the method name\n\t\t\t           |===?|>[>=]?|<=>|<[<=]?|[%&`/\\|]|\\*\\*?|=?~|[-+]@?|\\[\\]=?) )  # …or an operator method\n\t\t\t         \\s*(\\()                                                        # the openning parenthesis for arguments\n\t\t\t        '
-    'beginCaptures':
-      '1':
-        'name': 'keyword.control.def.ruby-motion'
-      '2':
-        'name': 'entity.name.function.ruby-motion'
-      '3':
-        'name': 'punctuation.definition.parameters.ruby-motion'
-    'comment': 'the method pattern comes from the symbol pattern, see there for a explaination'
-    'end': '\\)'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.parameters.ruby-motion'
-    'name': 'meta.function.method.with-arguments.ruby-motion'
-    'patterns': [
-      {
-        'begin': '(?![\\s,)])'
-        'end': '(?=[,)])'
-        'patterns': [
-          {
-            'captures':
-              '1':
-                'name': 'storage.type.variable.ruby-motion'
-              '2':
-                'name': 'variable.parameter.function.ruby-motion'
-            'match': '\\G([&*]?)([_a-zA-Z][_a-zA-Z0-9]*)'
-          }
-          {
-            'include': '$self'
-          }
-        ]
-      }
-    ]
-  }
-  {
-    'begin': '(?x)\n\t\t\t         (?=def\\b)                                                      # an optimization to help Oniguruma fail fast\n\t\t\t         (?<=^|\\s)(def)\\s+                                              # the def keyword\n\t\t\t         ( (?>[a-zA-Z_]\\w*(?>\\.|::))?                                   # a method name prefix\n\t\t\t           (?>[a-zA-Z_]\\w*(?>[?!]|=(?!>))?                              # the method name\n\t\t\t           |===?|>[>=]?|<=>|<[<=]?|[%&`/\\|]|\\*\\*?|=?~|[-+]@?|\\[\\]=?) )  # …or an operator method\n\t\t\t         [ \\t]                                                          # the space separating the arguments\n\t\t\t         (?=[ \\t]*[^\\s#;])                                              # make sure arguments and not a comment follow\n\t\t\t        '
-    'beginCaptures':
-      '1':
-        'name': 'keyword.control.def.ruby-motion'
-      '2':
-        'name': 'entity.name.function.ruby-motion'
-    'comment': 'same as the previous rule, but without parentheses around the arguments'
-    'end': '$'
-    'name': 'meta.function.method.with-arguments.ruby-motion'
-    'patterns': [
-      {
-        'begin': '(?![\\s,])'
-        'end': '(?=,|$)'
-        'patterns': [
-          {
-            'captures':
-              '1':
-                'name': 'punctuation.definition.variable.ruby-motion'
-            'match': '\\G([&*]?)[_a-zA-Z][_a-zA-Z0-9]*'
-            'name': 'variable.parameter.function.ruby-motion'
-          }
-          {
-            'include': '$self'
-          }
-        ]
-      }
-    ]
-  }
-  {
-    'captures':
-      '1':
-        'name': 'keyword.control.def.ruby-motion'
-      '3':
-        'name': 'entity.name.function.ruby-motion'
-    'comment': ' the optional name is just to catch the def also without a method-name'
-    'match': '(?x)\n\t\t\t         (?=def\\b)                                                           # an optimization to help Oniguruma fail fast\n\t\t\t         (?<=^|\\s)(def)\\b                                                    # the def keyword\n\t\t\t         ( \\s+                                                               # an optional group of whitespace followed by…\n\t\t\t           ( (?>[a-zA-Z_]\\w*(?>\\.|::))?                                      # a method name prefix\n\t\t\t             (?>[a-zA-Z_]\\w*(?>[?!]|=(?!>))?                                 # the method name\n\t\t\t             |===?|>[>=]?|<=>|<[<=]?|[%&`/\\|]|\\*\\*?|=?~|[-+]@?|\\[\\]=?) ) )?  # …or an operator method\n\t\t\t        '
-    'name': 'meta.function.method.without-arguments.ruby-motion'
-  }
-  {
-    'match': '\\b(0[xX]\\h(?>_?\\h)*|\\d(?>_?\\d)*(\\.(?![^[:space:][:digit:]])(?>_?\\d)*)?([eE][-+]?\\d(?>_?\\d)*)?|0[bB][01]+)\\b'
-    'name': 'constant.numeric.ruby-motion'
-  }
-  {
-    'begin': ':\''
-    'captures':
-      '0':
-        'name': 'punctuation.definition.constant.ruby-motion'
-    'end': '\''
-    'name': 'constant.other.symbol.single-quoted.ruby-motion'
-    'patterns': [
-      {
-        'match': '\\\\[\'\\\\]'
-        'name': 'constant.character.escape.ruby-motion'
-      }
-    ]
-  }
-  {
-    'begin': ':"'
-    'captures':
-      '0':
-        'name': 'punctuation.definition.constant.ruby-motion'
-    'end': '"'
-    'name': 'constant.other.symbol.double-quoted.ruby-motion'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-    ]
-  }
-  {
-    'comment': 'Needs higher precidence than regular expressions.'
-    'match': '(?<!\\()/='
-    'name': 'keyword.operator.assignment.augmented.ruby-motion'
-  }
-  {
-    'begin': '\''
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'single quoted string (does not allow interpolation)'
-    'end': '\''
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.quoted.single.ruby-motion'
-    'patterns': [
-      {
-        'match': '\\\\\'|\\\\\\\\'
-        'name': 'constant.character.escape.ruby-motion'
-      }
-    ]
-  }
-  {
-    'begin': '"'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'double quoted string (allows for interpolation)'
-    'end': '"'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.quoted.double.ruby-motion'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-    ]
-  }
-  {
-    'begin': '`'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'execute string (allows for interpolation)'
-    'end': '`'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.interpolated.ruby-motion'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-    ]
-  }
-  {
-    'begin': '%x\\{'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'execute string (allow for interpolation)'
-    'end': '\\}'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.interpolated.ruby-motion'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-      {
-        'include': '#nest_curly_i'
-      }
-    ]
-  }
-  {
-    'begin': '%x\\['
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'execute string (allow for interpolation)'
-    'end': '\\]'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.interpolated.ruby-motion'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-      {
-        'include': '#nest_brackets_i'
-      }
-    ]
-  }
-  {
-    'begin': '%x\\<'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'execute string (allow for interpolation)'
-    'end': '\\>'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.interpolated.ruby-motion'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-      {
-        'include': '#nest_ltgt_i'
-      }
-    ]
-  }
-  {
-    'begin': '%x\\('
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'execute string (allow for interpolation)'
-    'end': '\\)'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.interpolated.ruby-motion'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-      {
-        'include': '#nest_parens_i'
-      }
-    ]
-  }
-  {
-    'begin': '%x([^\\w])'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'execute string (allow for interpolation)'
-    'end': '\\1'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.interpolated.ruby-motion'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-    ]
-  }
-  {
-    'begin': '(?x)\n\t\t\t   (?:\n\t\t\t     ^                      # beginning of line\n\t\t\t   | (?<=                   # or look-behind on:\n\t\t\t       [=>~(?:\\[,|&;]\n\t\t\t     | [\\s;]if\\s\t\t\t# keywords\n\t\t\t     | [\\s;]elsif\\s\n\t\t\t     | [\\s;]while\\s\n\t\t\t     | [\\s;]unless\\s\n\t\t\t     | [\\s;]when\\s\n\t\t\t     | [\\s;]assert_match\\s\n\t\t\t     | [\\s;]or\\s\t\t\t# boolean opperators\n\t\t\t     | [\\s;]and\\s\n\t\t\t     | [\\s;]not\\s\n\t\t\t     | [\\s.]index\\s\t\t\t# methods\n\t\t\t     | [\\s.]scan\\s\n\t\t\t     | [\\s.]sub\\s\n\t\t\t     | [\\s.]sub!\\s\n\t\t\t     | [\\s.]gsub\\s\n\t\t\t     | [\\s.]gsub!\\s\n\t\t\t     | [\\s.]match\\s\n\t\t\t     )\n\t\t\t   | (?<=                  # or a look-behind with line anchor:\n\t\t\t        ^when\\s            # duplication necessary due to limits of regex\n\t\t\t      | ^if\\s\n\t\t\t      | ^elsif\\s\n\t\t\t      | ^while\\s\n\t\t\t      | ^unless\\s\n\t\t\t      )\n\t\t\t   )\n\t\t\t   \\s*((/))(?![*+{}?])\n\t\t\t'
-    'captures':
-      '1':
-        'name': 'string.regexp.classic.ruby-motion'
-      '2':
-        'name': 'punctuation.definition.string.ruby-motion'
-    'comment': 'regular expressions (normal)\n\t\t\twe only start a regexp if the character before it (excluding whitespace)\n\t\t\tis what we think is before a regexp\n\t\t\t'
-    'contentName': 'string.regexp.classic.ruby-motion'
-    'end': '((/[eimnosux]*))'
-    'patterns': [
-      {
-        'include': '#regex_sub'
-      }
-    ]
-  }
-  {
-    'begin': '%r\\{'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'regular expressions (literal)'
-    'end': '\\}[eimnosux]*'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.regexp.mod-r.ruby-motion'
-    'patterns': [
-      {
-        'include': '#regex_sub'
-      }
-      {
-        'include': '#nest_curly_r'
-      }
-    ]
-  }
-  {
-    'begin': '%r\\['
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'regular expressions (literal)'
-    'end': '\\][eimnosux]*'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.regexp.mod-r.ruby-motion'
-    'patterns': [
-      {
-        'include': '#regex_sub'
-      }
-      {
-        'include': '#nest_brackets_r'
-      }
-    ]
-  }
-  {
-    'begin': '%r\\('
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'regular expressions (literal)'
-    'end': '\\)[eimnosux]*'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.regexp.mod-r.ruby-motion'
-    'patterns': [
-      {
-        'include': '#regex_sub'
-      }
-      {
-        'include': '#nest_parens_r'
-      }
-    ]
-  }
-  {
-    'begin': '%r\\<'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'regular expressions (literal)'
-    'end': '\\>[eimnosux]*'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.regexp.mod-r.ruby-motion'
-    'patterns': [
-      {
-        'include': '#regex_sub'
-      }
-      {
-        'include': '#nest_ltgt_r'
-      }
-    ]
-  }
-  {
-    'begin': '%r([^\\w])'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'regular expressions (literal)'
-    'end': '\\1[eimnosux]*'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.regexp.mod-r.ruby-motion'
-    'patterns': [
-      {
-        'include': '#regex_sub'
-      }
-    ]
-  }
-  {
-    'begin': '%[QWSR]?\\('
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'literal capable of interpolation ()'
-    'end': '\\)'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.quoted.other.literal.upper.ruby-motion'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-      {
-        'include': '#nest_parens_i'
-      }
-    ]
-  }
-  {
-    'begin': '%[QWSR]?\\['
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'literal capable of interpolation []'
-    'end': '\\]'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.quoted.other.literal.upper.ruby-motion'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-      {
-        'include': '#nest_brackets_i'
-      }
-    ]
-  }
-  {
-    'begin': '%[QWSR]?\\<'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'literal capable of interpolation <>'
-    'end': '\\>'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.quoted.other.literal.upper.ruby-motion'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-      {
-        'include': '#nest_ltgt_i'
-      }
-    ]
-  }
-  {
-    'begin': '%[QWSR]?\\{'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'literal capable of interpolation -- {}'
-    'end': '\\}'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.quoted.double.ruby-motion.mod'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-      {
-        'include': '#nest_curly_i'
-      }
-    ]
-  }
-  {
-    'begin': '%[QWSR]([^\\w])'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'literal capable of interpolation -- wildcard'
-    'end': '\\1'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.quoted.other.literal.upper.ruby-motion'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-    ]
-  }
-  {
-    'begin': '%([^\\w\\s=])'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'literal capable of interpolation -- wildcard'
-    'end': '\\1'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.quoted.other.literal.other.ruby-motion'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-    ]
-  }
-  {
-    'begin': '%[qws]\\('
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'literal incapable of interpolation -- ()'
-    'end': '\\)'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.quoted.other.literal.lower.ruby-motion'
-    'patterns': [
-      {
-        'match': '\\\\\\)|\\\\\\\\'
-        'name': 'constant.character.escape.ruby-motion'
-      }
-      {
-        'include': '#nest_parens'
-      }
-    ]
-  }
-  {
-    'begin': '%[qws]\\<'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'literal incapable of interpolation -- <>'
-    'end': '\\>'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.quoted.other.literal.lower.ruby-motion'
-    'patterns': [
-      {
-        'match': '\\\\\\>|\\\\\\\\'
-        'name': 'constant.character.escape.ruby-motion'
-      }
-      {
-        'include': '#nest_ltgt'
-      }
-    ]
-  }
-  {
-    'begin': '%[qws]\\['
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'literal incapable of interpolation -- []'
-    'end': '\\]'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.quoted.other.literal.lower.ruby-motion'
-    'patterns': [
-      {
-        'match': '\\\\\\]|\\\\\\\\'
-        'name': 'constant.character.escape.ruby-motion'
-      }
-      {
-        'include': '#nest_brackets'
-      }
-    ]
-  }
-  {
-    'begin': '%[qws]\\{'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'literal incapable of interpolation -- {}'
-    'end': '\\}'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.quoted.other.literal.lower.ruby-motion'
-    'patterns': [
-      {
-        'match': '\\\\\\}|\\\\\\\\'
-        'name': 'constant.character.escape.ruby-motion'
-      }
-      {
-        'include': '#nest_curly'
-      }
-    ]
-  }
-  {
-    'begin': '%[qws]([^\\w])'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'literal incapable of interpolation -- wildcard'
-    'end': '\\1'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.quoted.other.literal.lower.ruby-motion'
-    'patterns': [
-      {
-        'comment': 'Cant be named because its not neccesarily an escape.'
-        'match': '\\\\.'
-      }
-    ]
-  }
-  {
-    'captures':
-      '1':
-        'name': 'punctuation.definition.constant.ruby-motion'
-    'comment': 'symbols'
-    'match': '(?<!:)(:)(?>[a-zA-Z_]\\w*(?>[?!]|=(?![>=]))?|===?|>[>=]?|<[<=]?|<=>|[%&`/\\|]|\\*\\*?|=?~|[-+]@?|\\[\\]=?|@@?[a-zA-Z_]\\w*)'
-    'name': 'constant.other.symbol.ruby-motion'
-  }
-  {
-    'begin': '^=begin'
-    'captures':
-      '0':
-        'name': 'punctuation.definition.comment.ruby-motion'
-    'comment': 'multiline comments'
-    'end': '^=end'
-    'name': 'comment.block.documentation.ruby-motion'
-  }
-  {
-    'begin': '(^[ \\t]+)?(?=#)'
-    'beginCaptures':
-      '1':
-        'name': 'punctuation.whitespace.comment.leading.ruby-motion'
-    'end': '(?!\\G)'
-    'patterns': [
-      {
-        'begin': '#'
-        'beginCaptures':
-          '0':
-            'name': 'punctuation.definition.comment.ruby-motion'
-        'end': '\\n'
-        'name': 'comment.line.number-sign.ruby-motion'
-      }
-    ]
-  }
-  {
-    'comment': '\n\t\t\tmatches questionmark-letters.\n\n\t\t\texamples (1st alternation = hex):\n\t\t\t?\\x1     ?\\x61\n\n\t\t\texamples (2nd alternation = octal):\n\t\t\t?\\0      ?\\07     ?\\017\n\n\t\t\texamples (3rd alternation = escaped):\n\t\t\t?\\n      ?\\b\n\n\t\t\texamples (4th alternation = meta-ctrl):\n\t\t\t?\\C-a    ?\\M-a    ?\\C-\\M-\\C-\\M-a\n\n\t\t\texamples (4th alternation = normal):\n\t\t\t?a       ?A       ?0 \n\t\t\t?*       ?"       ?( \n\t\t\t?.       ?#\n\t\t\t\n\t\t\t\n\t\t\tthe negative lookbehind prevents against matching\n\t\t\tp(42.tainted?)\n\t\t\t'
-    'match': '(?<!\\w)\\?(\\\\(x\\h{1,2}(?!\\h)\\b|0[0-7]{0,2}(?![0-7])\\b|[^x0MC])|(\\\\[MC]-)+\\w|[^\\s\\\\])'
-    'name': 'constant.numeric.ruby-motion'
-  }
-  {
-    'begin': '^__END__\\n'
-    'captures':
-      '0':
-        'name': 'string.unquoted.program-block.ruby-motion'
-    'comment': '__END__ marker'
-    'contentName': 'text.plain'
-    'end': '(?=not)impossible'
-    'patterns': [
-      {
-        'begin': '(?=<?xml|<(?i:html\\b)|!DOCTYPE (?i:html\\b))'
-        'end': '(?=not)impossible'
-        'name': 'text.html.embedded.ruby-motion'
-        'patterns': [
-          {
-            'include': 'text.html.basic'
-          }
-        ]
-      }
-    ]
-  }
-  {
-    'begin': '(?=(?><<-("?)((?:[_\\w]+_|)HTML)\\b\\1))'
-    'comment': 'Heredoc with embedded html'
-    'end': '(?!\\G)'
-    'name': 'meta.embedded.block.html'
-    'patterns': [
-      {
-        'begin': '(?><<-("?)((?:[_\\w]+_|)HTML)\\b\\1)'
-        'beginCaptures':
-          '0':
-            'name': 'punctuation.definition.string.begin.ruby-motion'
-        'contentName': 'text.html'
-        'end': '\\s*\\2$\\n?'
-        'endCaptures':
-          '0':
-            'name': 'punctuation.definition.string.end.ruby-motion'
-        'name': 'string.unquoted.heredoc.ruby-motion'
-        'patterns': [
-          {
-            'include': '#heredoc'
-          }
-          {
-            'include': '#interpolated_ruby'
-          }
-          {
-            'include': 'text.html.basic'
-          }
-          {
-            'include': '#escaped_char'
-          }
-        ]
-      }
-    ]
-  }
-  {
-    'begin': '(?=(?><<-("?)((?:[_\\w]+_|)SQL)\\b\\1))'
-    'comment': 'Heredoc with embedded sql'
-    'end': '(?!\\G)'
-    'name': 'meta.embedded.block.sql'
-    'patterns': [
-      {
-        'begin': '(?><<-("?)((?:[_\\w]+_|)SQL)\\b\\1)'
-        'beginCaptures':
-          '0':
-            'name': 'punctuation.definition.string.begin.ruby-motion'
-        'contentName': 'source.sql'
-        'end': '\\s*\\2$\\n?'
-        'endCaptures':
-          '0':
-            'name': 'punctuation.definition.string.end.ruby-motion'
-        'name': 'string.unquoted.heredoc.ruby-motion'
-        'patterns': [
-          {
-            'include': '#heredoc'
-          }
-          {
-            'include': '#interpolated_ruby'
-          }
-          {
-            'include': 'source.sql'
-          }
-          {
-            'include': '#escaped_char'
-          }
-        ]
-      }
-    ]
-  }
-  {
-    'begin': '(?=(?><<-("?)((?:[_\\w]+_|)CSS)\\b\\1))'
-    'comment': 'Heredoc with embedded css'
-    'end': '(?!\\G)'
-    'name': 'meta.embedded.block.css'
-    'patterns': [
-      {
-        'begin': '(?><<-("?)((?:[_\\w]+_|)CSS)\\b\\1)'
-        'beginCaptures':
-          '0':
-            'name': 'punctuation.definition.string.begin.ruby-motion'
-        'contentName': 'source.css'
-        'end': '\\s*\\2$\\n?'
-        'endCaptures':
-          '0':
-            'name': 'punctuation.definition.string.end.ruby-motion'
-        'name': 'string.unquoted.heredoc.ruby-motion'
-        'patterns': [
-          {
-            'include': '#heredoc'
-          }
-          {
-            'include': '#interpolated_ruby'
-          }
-          {
-            'include': 'source.css'
-          }
-          {
-            'include': '#escaped_char'
-          }
-        ]
-      }
-    ]
-  }
-  {
-    'begin': '(?=(?><<-("?)((?:[_\\w]+_|)CPP)\\b\\1))'
-    'comment': 'Heredoc with embedded c++'
-    'end': '(?!\\G)'
-    'name': 'meta.embedded.block.c++'
-    'patterns': [
-      {
-        'begin': '(?><<-("?)((?:[_\\w]+_|)CPP)\\b\\1)'
-        'beginCaptures':
-          '0':
-            'name': 'punctuation.definition.string.begin.ruby-motion'
-        'contentName': 'source.c++'
-        'end': '\\s*\\2$\\n?'
-        'endCaptures':
-          '0':
-            'name': 'punctuation.definition.string.end.ruby-motion'
-        'name': 'string.unquoted.heredoc.ruby-motion'
-        'patterns': [
-          {
-            'include': '#heredoc'
-          }
-          {
-            'include': '#interpolated_ruby'
-          }
-          {
-            'include': 'source.c++'
-          }
-          {
-            'include': '#escaped_char'
-          }
-        ]
-      }
-    ]
-  }
-  {
-    'begin': '(?=(?><<-("?)((?:[_\\w]+_|)C)\\b\\1))'
-    'comment': 'Heredoc with embedded c'
-    'end': '(?!\\G)'
-    'name': 'meta.embedded.block.c'
-    'patterns': [
-      {
-        'begin': '(?><<-("?)((?:[_\\w]+_|)C)\\b\\1)'
-        'beginCaptures':
-          '0':
-            'name': 'punctuation.definition.string.begin.ruby-motion'
-        'contentName': 'source.c'
-        'end': '\\s*\\2$\\n?'
-        'endCaptures':
-          '0':
-            'name': 'punctuation.definition.string.end.ruby-motion'
-        'name': 'string.unquoted.heredoc.ruby-motion'
-        'patterns': [
-          {
-            'include': '#heredoc'
-          }
-          {
-            'include': '#interpolated_ruby'
-          }
-          {
-            'include': 'source.c'
-          }
-          {
-            'include': '#escaped_char'
-          }
-        ]
-      }
-    ]
-  }
-  {
-    'begin': '(?=(?><<-("?)((?:[_\\w]+_|)(?:JS|JAVASCRIPT))\\b\\1))'
-    'comment': 'Heredoc with embedded javascript'
-    'end': '(?!\\G)'
-    'name': 'meta.embedded.block.js'
-    'patterns': [
-      {
-        'begin': '(?><<-("?)((?:[_\\w]+_|)(?:JS|JAVASCRIPT))\\b\\1)'
-        'beginCaptures':
-          '0':
-            'name': 'punctuation.definition.string.begin.ruby-motion'
-        'contentName': 'source.js'
-        'end': '\\s*\\2$\\n?'
-        'endCaptures':
-          '0':
-            'name': 'punctuation.definition.string.end.ruby-motion'
-        'name': 'string.unquoted.heredoc.ruby-motion'
-        'patterns': [
-          {
-            'include': '#heredoc'
-          }
-          {
-            'include': '#interpolated_ruby'
-          }
-          {
-            'include': 'source.js'
-          }
-          {
-            'include': '#escaped_char'
-          }
-        ]
-      }
-    ]
-  }
-  {
-    'begin': '(?=(?><<-("?)((?:[_\\w]+_|)JQUERY)\\b\\1))'
-    'comment': 'Heredoc with embedded jQuery javascript'
-    'end': '(?!\\G)'
-    'name': 'meta.embedded.block.js.jquery'
-    'patterns': [
-      {
-        'begin': '(?><<-("?)((?:[_\\w]+_|)JQUERY)\\b\\1)'
-        'beginCaptures':
-          '0':
-            'name': 'punctuation.definition.string.begin.ruby-motion'
-        'contentName': 'source.js.jquery'
-        'end': '\\s*\\2$\\n?'
-        'endCaptures':
-          '0':
-            'name': 'punctuation.definition.string.end.ruby-motion'
-        'name': 'string.unquoted.heredoc.ruby-motion'
-        'patterns': [
-          {
-            'include': '#heredoc'
-          }
-          {
-            'include': '#interpolated_ruby'
-          }
-          {
-            'include': 'source.js.jquery'
-          }
-          {
-            'include': '#escaped_char'
-          }
-        ]
-      }
-    ]
-  }
-  {
-    'begin': '(?=(?><<-("?)((?:[_\\w]+_|)(?:SH|SHELL))\\b\\1))'
-    'comment': 'Heredoc with embedded shell'
-    'end': '(?!\\G)'
-    'name': 'meta.embedded.block.shell'
-    'patterns': [
-      {
-        'begin': '(?><<-("?)((?:[_\\w]+_|)(?:SH|SHELL))\\b\\1)'
-        'beginCaptures':
-          '0':
-            'name': 'punctuation.definition.string.begin.ruby-motion'
-        'contentName': 'source.shell'
-        'end': '\\s*\\2$\\n?'
-        'endCaptures':
-          '0':
-            'name': 'punctuation.definition.string.end.ruby-motion'
-        'name': 'string.unquoted.heredoc.ruby-motion'
-        'patterns': [
-          {
-            'include': '#heredoc'
-          }
-          {
-            'include': '#interpolated_ruby'
-          }
-          {
-            'include': 'source.shell'
-          }
-          {
-            'include': '#escaped_char'
-          }
-        ]
-      }
-    ]
-  }
-  {
-    'begin': '(?=(?><<-("?)((?:[_\\w]+_|)LUA)\\b\\1))'
-    'comment': 'Heredoc with embedded lua'
-    'end': '(?!\\G)'
-    'name': 'meta.embedded.block.lua'
-    'patterns': [
-      {
-        'begin': '(?><<-("?)((?:[_\\w]+_|)LUA)\\b\\1)'
-        'beginCaptures':
-          '0':
-            'name': 'punctuation.definition.string.begin.ruby-motion'
-        'contentName': 'source.lua'
-        'end': '\\s*\\2$\\n?'
-        'endCaptures':
-          '0':
-            'name': 'punctuation.definition.string.end.ruby-motion'
-        'name': 'string.unquoted.heredoc.ruby-motion'
-        'patterns': [
-          {
-            'include': '#heredoc'
-          }
-          {
-            'include': '#interpolated_ruby'
-          }
-          {
-            'include': 'source.lua'
-          }
-          {
-            'include': '#escaped_char'
-          }
-        ]
-      }
-    ]
-  }
-  {
-    'begin': '(?=(?><<-("?)((?:[_\\w]+_|)RUBY)\\b\\1))'
-    'comment': 'Heredoc with embedded ruby-motion'
-    'end': '(?!\\G)'
-    'name': 'meta.embedded.block.ruby-motion'
-    'patterns': [
-      {
-        'begin': '(?><<-("?)((?:[_\\w]+_|)RUBY)\\b\\1)'
-        'beginCaptures':
-          '0':
-            'name': 'punctuation.definition.string.begin.ruby-motion'
-        'contentName': 'source.ruby-motion'
-        'end': '\\s*\\2$\\n?'
-        'endCaptures':
-          '0':
-            'name': 'punctuation.definition.string.end.ruby-motion'
-        'name': 'string.unquoted.heredoc.ruby-motion'
-        'patterns': [
-          {
-            'include': '#heredoc'
-          }
-          {
-            'include': '#interpolated_ruby'
-          }
-          {
-            'include': 'source.ruby-motion'
-          }
-          {
-            'include': '#escaped_char'
-          }
-        ]
-      }
-    ]
-  }
-  {
-    'begin': '(?>\\=\\s*<<(\\w+))'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'end': '^\\1$'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.unquoted.heredoc.ruby-motion'
-    'patterns': [
-      {
-        'include': '#heredoc'
-      }
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-    ]
-  }
-  {
-    'begin': '(?><<-(\\w+))'
-    'beginCaptures':
-      '0':
-        'name': 'punctuation.definition.string.begin.ruby-motion'
-    'comment': 'heredoc with indented terminator'
-    'end': '\\s*\\1$'
-    'endCaptures':
-      '0':
-        'name': 'punctuation.definition.string.end.ruby-motion'
-    'name': 'string.unquoted.heredoc.ruby-motion'
-    'patterns': [
-      {
-        'include': '#heredoc'
-      }
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-    ]
-  }
-  {
-    'begin': '(?<=\\{|do|\\{\\s|do\\s)(\\|)'
-    'captures':
-      '1':
-        'name': 'punctuation.separator.variable.ruby-motion'
-    'end': '(\\|)'
-    'patterns': [
-      {
-        'match': '[_a-zA-Z][_a-zA-Z0-9]*'
-        'name': 'variable.other.block.ruby-motion'
-      }
-      {
-        'match': ','
-        'name': 'punctuation.separator.variable.ruby-motion'
-      }
-    ]
-  }
-  {
-    'match': '=>'
-    'name': 'punctuation.separator.key-value'
-  }
-  {
-    'match': '<<=|%=|&=|\\*=|\\*\\*=|\\+=|\\-=|\\^=|\\|{1,2}=|<<'
-    'name': 'keyword.operator.assignment.augmented.ruby-motion'
-  }
-  {
-    'match': '<=>|<(?!<|=)|>(?!<|=|>)|<=|>=|===|==|=~|!=|!~|(?<=[ \\t])\\?'
-    'name': 'keyword.operator.comparison.ruby-motion'
-  }
-  {
-    'match': '(?<=[ \\t])!+|\\bnot\\b|&&|\\band\\b|\\|\\||\\bor\\b|\\^'
-    'name': 'keyword.operator.logical.ruby-motion'
-  }
-  {
-    'match': '(%|&|\\*\\*|\\*|\\+|\\-|/)'
-    'name': 'keyword.operator.arithmetic.ruby-motion'
-  }
-  {
-    'match': '='
-    'name': 'keyword.operator.assignment.ruby-motion'
-  }
-  {
-    'match': '\\||~|>>'
-    'name': 'keyword.operator.other.ruby-motion'
-  }
-  {
-    'match': ':'
-    'name': 'punctuation.separator.other.ruby-motion'
-  }
-  {
-    'match': '\\;'
-    'name': 'punctuation.separator.statement.ruby-motion'
-  }
-  {
-    'match': ','
-    'name': 'punctuation.separator.object.ruby-motion'
-  }
-  {
-    'match': '\\.|::'
-    'name': 'punctuation.separator.method.ruby-motion'
-  }
-  {
-    'match': '\\{'
-    'name': 'punctuation.section.scope.begin.ruby-motion'
-  }
-  {
-    'match': '\\}'
-    'name': 'punctuation.section.scope.end.ruby-motion'
-  }
-  {
-    'match': '\\['
-    'name': 'punctuation.section.array.begin.ruby-motion'
-  }
-  {
-    'match': '\\]'
-    'name': 'punctuation.section.array.end.ruby-motion'
-  }
-  {
-    'match': '\\(|\\)'
-    'name': 'punctuation.section.function.ruby-motion'
-  }
+  {'include': 'source.ruby'}
 ]
-'repository':
-  'escaped_char':
-    'match': '\\\\(?:[0-7]{1,3}|x[\\da-fA-F]{1,2}|.)'
-    'name': 'constant.character.escape.ruby-motion'
-  'heredoc':
-    'begin': '^<<-?\\w+'
-    'end': '$'
-    'patterns': [
-      {
-        'include': '$self'
-      }
-    ]
-  'interpolated_ruby':
-    'patterns': [
-      {
-        'begin': '#\\{'
-        'beginCaptures':
-          '0':
-            'name': 'punctuation.section.embedded.begin.ruby-motion'
-        'contentName': 'source.ruby-motion'
-        'end': '(\\})'
-        'endCaptures':
-          '0':
-            'name': 'punctuation.section.embedded.end.ruby-motion'
-          '1':
-            'name': 'source.ruby-motion'
-        'name': 'meta.embedded.line.ruby-motion'
-        'patterns': [
-          {
-            'include': '#nest_curly_and_self'
-          }
-          {
-            'include': '$self'
-          }
-        ]
-      }
-      {
-        'captures':
-          '1':
-            'name': 'punctuation.definition.variable.ruby-motion'
-        'match': '(#@)[a-zA-Z_]\\w*'
-        'name': 'variable.other.readwrite.instance.ruby-motion'
-      }
-      {
-        'captures':
-          '1':
-            'name': 'punctuation.definition.variable.ruby-motion'
-        'match': '(#@@)[a-zA-Z_]\\w*'
-        'name': 'variable.other.readwrite.class.ruby-motion'
-      }
-      {
-        'captures':
-          '1':
-            'name': 'punctuation.definition.variable.ruby-motion'
-        'match': '(#\\$)[a-zA-Z_]\\w*'
-        'name': 'variable.other.readwrite.global.ruby-motion'
-      }
-    ]
-  'nest_brackets':
-    'begin': '\\['
-    'captures':
-      '0':
-        'name': 'punctuation.section.scope.ruby-motion'
-    'end': '\\]'
-    'patterns': [
-      {
-        'include': '#nest_brackets'
-      }
-    ]
-  'nest_brackets_i':
-    'begin': '\\['
-    'captures':
-      '0':
-        'name': 'punctuation.section.scope.ruby-motion'
-    'end': '\\]'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-      {
-        'include': '#nest_brackets_i'
-      }
-    ]
-  'nest_brackets_r':
-    'begin': '\\['
-    'captures':
-      '0':
-        'name': 'punctuation.section.scope.ruby-motion'
-    'end': '\\]'
-    'patterns': [
-      {
-        'include': '#regex_sub'
-      }
-      {
-        'include': '#nest_brackets_r'
-      }
-    ]
-  'nest_curly':
-    'begin': '\\{'
-    'captures':
-      '0':
-        'name': 'punctuation.section.scope.ruby-motion'
-    'end': '\\}'
-    'patterns': [
-      {
-        'include': '#nest_curly'
-      }
-    ]
-  'nest_curly_and_self':
-    'patterns': [
-      {
-        'begin': '\\{'
-        'captures':
-          '0':
-            'name': 'punctuation.section.scope.ruby-motion'
-        'end': '\\}'
-        'patterns': [
-          {
-            'include': '#nest_curly_and_self'
-          }
-        ]
-      }
-      {
-        'include': '$self'
-      }
-    ]
-  'nest_curly_i':
-    'begin': '\\{'
-    'captures':
-      '0':
-        'name': 'punctuation.section.scope.ruby-motion'
-    'end': '\\}'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-      {
-        'include': '#nest_curly_i'
-      }
-    ]
-  'nest_curly_r':
-    'begin': '\\{'
-    'captures':
-      '0':
-        'name': 'punctuation.section.scope.ruby-motion'
-    'end': '\\}'
-    'patterns': [
-      {
-        'include': '#regex_sub'
-      }
-      {
-        'include': '#nest_curly_r'
-      }
-    ]
-  'nest_ltgt':
-    'begin': '\\<'
-    'captures':
-      '0':
-        'name': 'punctuation.section.scope.ruby-motion'
-    'end': '\\>'
-    'patterns': [
-      {
-        'include': '#nest_ltgt'
-      }
-    ]
-  'nest_ltgt_i':
-    'begin': '\\<'
-    'captures':
-      '0':
-        'name': 'punctuation.section.scope.ruby-motion'
-    'end': '\\>'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-      {
-        'include': '#nest_ltgt_i'
-      }
-    ]
-  'nest_ltgt_r':
-    'begin': '\\<'
-    'captures':
-      '0':
-        'name': 'punctuation.section.scope.ruby-motion'
-    'end': '\\>'
-    'patterns': [
-      {
-        'include': '#regex_sub'
-      }
-      {
-        'include': '#nest_ltgt_r'
-      }
-    ]
-  'nest_parens':
-    'begin': '\\('
-    'captures':
-      '0':
-        'name': 'punctuation.section.scope.ruby-motion'
-    'end': '\\)'
-    'patterns': [
-      {
-        'include': '#nest_parens'
-      }
-    ]
-  'nest_parens_i':
-    'begin': '\\('
-    'captures':
-      '0':
-        'name': 'punctuation.section.scope.ruby-motion'
-    'end': '\\)'
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-      {
-        'include': '#nest_parens_i'
-      }
-    ]
-  'nest_parens_r':
-    'begin': '\\('
-    'captures':
-      '0':
-        'name': 'punctuation.section.scope.ruby-motion'
-    'end': '\\)'
-    'patterns': [
-      {
-        'include': '#regex_sub'
-      }
-      {
-        'include': '#nest_parens_r'
-      }
-    ]
-  'regex_sub':
-    'patterns': [
-      {
-        'include': '#interpolated_ruby'
-      }
-      {
-        'include': '#escaped_char'
-      }
-      {
-        'captures':
-          '1':
-            'name': 'punctuation.definition.arbitrary-repitition.ruby-motion'
-          '3':
-            'name': 'punctuation.definition.arbitrary-repitition.ruby-motion'
-        'match': '(\\{)\\d+(,\\d+)?(\\})'
-        'name': 'string.regexp.arbitrary-repitition.ruby-motion'
-      }
-      {
-        'begin': '\\[(?:\\^?\\])?'
-        'captures':
-          '0':
-            'name': 'punctuation.definition.character-class.ruby-motion'
-        'end': '\\]'
-        'name': 'string.regexp.character-class.ruby-motion'
-        'patterns': [
-          {
-            'include': '#escaped_char'
-          }
-        ]
-      }
-      {
-        'begin': '\\(\\?#'
-        'beginCaptures':
-          '0':
-            'name': 'punctuation.definition.comment.begin.ruby-motion'
-        'end': '\\)'
-        'endCaptures':
-          '0':
-            'name': 'punctuation.definition.comment.end.ruby-motion'
-        'name': 'comment.line.number-sign.ruby-motion'
-        'patterns': [
-          {
-            'include': '#escaped_char'
-          }
-        ]
-      }
-      {
-        'begin': '\\('
-        'captures':
-          '0':
-            'name': 'punctuation.definition.group.ruby-motion'
-        'end': '\\)'
-        'name': 'string.regexp.group.ruby-motion'
-        'patterns': [
-          {
-            'include': '#regex_sub'
-          }
-        ]
-      }
-      {
-        'begin': '(?<=^|\\s)(#)\\s(?=[[a-zA-Z0-9,. \\t?!-][^\\x{00}-\\x{7F}]]*$)'
-        'beginCaptures':
-          '1':
-            'name': 'punctuation.definition.comment.ruby-motion'
-        'comment': 'We are restrictive in what we allow to go after the comment character to avoid false positives, since the availability of comments depend on regexp flags.'
-        'end': '$\\n?'
-        'endCaptures':
-          '0':
-            'name': 'punctuation.definition.comment.ruby-motion'
-        'name': 'comment.line.number-sign.ruby-motion'
-      }
-    ]
 'scopeName': 'source.ruby-motion'


Separated id from item parameter in editListItemByTitle.


switchNextProject: switching to the first project even if the current workspace is not on a project

--- i3-project-focus-workflow/switchNextProject.coffee
+++ i3-project-focus-workflow/switchNextProject.coffee
@@ -7,18 +7,22 @@

   focWkName = nf.getFocusedWK(wkList)

+  allProjectNames = nf.getListOfProjects(wkList)
+
+  if allProjectNames.length == 0 || allProjectNames == undefined
+    process.exit()
+
   currentProjName = nf.getProjectFromWKName(focWkName)

-  allProjectNames = nf.getListOfProjects(wkList)
-
-  nextProjIndex = allProjectNames.indexOf(currentProjName)
-
-  if nextProjIndex == -1
-    return undefined
-  if nextProjIndex == (allProjectNames.length-1)
+  if currentProjName == undefined
     nextProjIndex = 0
   else
-    nextProjIndex += 1
+    nextProjIndex = allProjectNames.indexOf(currentProjName)
+
+    if nextProjIndex == (allProjectNames.length-1)
+      nextProjIndex = 0
+    else
+      nextProjIndex += 1

   nxtProjWks = nf.getWKNamesFromProj(wkList, allProjectNames[nextProjIndex])


fix for checkpoint app - not exporting files

--- tools/taskrunner.coffee
+++ tools/taskrunner.coffee
@@ -437,11 +437,13 @@
         if (ids.indexOf item.id)<0
           ids.push item.id
       # app: { files: { url: ... }, ... }
-      for file in ( app.files ? [] ) when file.url and file.url.length>15
-        if file.url.substring(0,10)=='../../../../' and file.url.substr(-6)=='/bytes'
-          id = decodeURIComponent (file.url.substring 10,(file.url.length-6))
+      for file in ( app.files ? [] ) when file.url
+        if file.url.length>15 and file.url.substring(0,12)=='../../../../' and file.url.substr(-6)=='/bytes'
+          id = decodeURIComponent (file.url.substring 12,(file.url.length-6))
           if (ids.indexOf id)<0
             ids.push id
+        else
+          log "ignore app file #{file.url}"
       # Don't copy: app: { servers: { id: ... }, ... }
       # remove any old files
       if !fs.existsSync path


linting

linting

--- lib/phabricator.coffee
+++ lib/phabricator.coffee
@@ -710,13 +710,14 @@
           'transactions[0][value][0]': "#{@bot_phid}"
         }
         for action, i in results.data
-          query['transactions['+(i+1)+'][type]'] = action.type
-          query['transactions['+(i+1)+'][value]'] = action.value
-        query['transactions['+(i+1)+'][type]'] = 'comment'
-        if comment?
-          query['transactions['+(i+1)+'][value]'] = "#{comment} (#{user.name})"
-        else
-          query['transactions['+(i+1)+'][value]'] = "#{results.messages.join(', ')} (by #{user.name})"
+          query['transactions[' + (i + 1) + '][type]'] = action.type
+          query['transactions[' + (i + 1) + '][value]'] = action.value
+        query['transactions[' + (i + 1) + '][type]'] = 'comment'
+        if comment?
+          query['transactions[' + (i + 1) + '][value]'] = "#{comment} (#{user.name})"
+        else
+          query['transactions[' + (i + 1) + '][value]'] =
+            "#{results.messages.join(', ')} (by #{user.name})"
         # console.log query
         @request(query, 'maniphest.edit')
         .then (body) ->
@@ -743,7 +744,7 @@
               res @parseAction(user, item, next, payload)
             else
               res payload
-          .catch (e) =>
+          .catch (e) ->
             payload.notices.push(e)
             res payload
         when 'not in'
@@ -760,7 +761,7 @@
               res @parseAction(user, item, next, payload)
             else
               res payload
-          .catch (e) =>
+          .catch (e) ->
             payload.notices.push(e)
             res payload
         when 'on'
@@ -773,7 +774,7 @@
               res @parseAction(user, item, next, payload)
             else
               res payload
-          .catch (e) =>
+          .catch (e) ->
             payload.notices.push(e)
             res payload
         when 'to'
@@ -782,7 +783,7 @@
           else
             cols = Promise.map item.projectPHIDs, (phid) =>
               @getProject(phid)
-              .then (projectData) =>
+              .then (projectData) ->
                 for i in Object.keys(projectData.data.columns)
                   if (new RegExp(r[2])).test i
                     return { colname: i, colphid: projectData.data.columns[i] }


Configuration cleanup

Configuration cleanup

--- atom/config.cson
+++ atom/config.cson
@@ -1,7 +1,5 @@
 'exception-reporting':
   'userId': 'ee24cf00-f793-9081-be2a-2cdae5536b7f'
-'release-notes':
-  'viewedVersion': '0.95.0'
 'welcome':
   'showOnStartup': false
 'metrics':
@@ -48,12 +46,10 @@
 'tree-view':
   'hideIgnoredNames': true
   'hideVcsIgnoredFiles': true
-'autosave': {}
 'remember-window':
   'storeOutsideMainConfig': true
 'tabs-to-spaces':
   'onSave': 'untabify'
-'git-diff': {}
 'autocomplete':
   'includeCompletionsFromAllBuffers': true
 'fancy-new-file':
@@ -97,10 +93,6 @@
 'atom-color-highlight':
   'hideMarkersInComments': true
   'hideMarkersInStrings': true
-'break':
-  'microBreakIntervalInSeconds': 900
-  'microBreakLengthInSeconds': 30
-  'macroBreakIntervalInMicroAmount': 4
 'package-generator':
   'createInDevMode': true
 'atom-lint':


atom: fix whitespace settings and show all files in tree-view

--- atom/config.cson
+++ atom/config.cson
@@ -53,7 +53,6 @@
     disabledPackages: [
       "php-debug"
       "linter-phpcs"
-      "whitespace"
       "linter-scss-lint"
     ]
     followSymlinks: false
@@ -167,13 +166,12 @@
   "trailing-spaces":
     enableForIndentation: true
   "tree-view":
-    hideVcsIgnoredFiles: true
     squashDirectoryNames: true
   welcome:
     showOnStartup: false
-  whitespace:
-    ensureSingleTrailingNewline: false
-    removeTrailingWhitespace: false
 ".source.yaml":
   editor:
     tabLength: 2
+"text.html.php":
+  whitespace:
+    removeTrailingWhitespace: false


Atom - fuzzy-finder disable default keybindings, search all panes

--- atom/config.cson
+++ atom/config.cson
@@ -12,6 +12,7 @@
     ]
     packagesWithKeymapsDisabled: [
       "bracket-matcher"
+      "fuzzy-finder"
     ]
     telemetryConsent: "limited"
     themes: [
@@ -22,6 +23,8 @@
     tabLength: 4
   "exception-reporting":
     userId: "82a26126-5c31-4531-b32c-a1877d4677e0"
+  "fuzzy-finder":
+    searchAllPanes: true
   "linter-flake8": {}
   "linter-ui-default":
     panelHeight: 163


Sync Atom packages on Atom init

Sync Atom packages on Atom init

--- atom/init.coffee
+++ atom/init.coffee
@@ -20,7 +20,13 @@
         console.log("Activated virtualenv at #{virtualenv}")
     )

+# Sync Atom packages via package-sync package
+syncPackages = ->
+  activeEditor = atom.views.getView(atom.workspace.getActiveTextEditor())
+  atom.commands.dispatch(activeEditor, 'package-sync:sync')
+
 # Explicitly define PATH and detect project virtualenvs
 process.env.PATH = '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin'
 if process.env.VIRTUAL_ENV_NAME
   activateVirtualenv()
+syncPackages()


Disable editor-centric commands in non-editor views

For all Atom commands that are intended to operate on editor views, make
it so that those commands are only available inside an editor view. For
example, we don't want editor specific commands to show up in the
command palette when we're working in the tree view.

--- atom/init.coffee
+++ atom/init.coffee
@@ -42,75 +42,71 @@
   atom.workspace.getPanes().forEach (pane) ->
     pane.destroyItems()

-# Approximate Vim's "H" motion: Move the cursor to the topmost line that is
-# currently visible.
-atom.workspaceView.command 'dot-atom:move-to-top-visible-line', '.editor', ->
-  view = atom.workspaceView.getActiveView()
-  topRow = view.getFirstVisibleScreenRow()
-  topRow = topRow + 1 unless topRow == 0
-  view.getEditor().setCursorBufferPosition [topRow, 0], autoscroll: false
+# Define commands that should only be available in an editor view (and should
+# not be available in a tree view, for example).
+atom.workspaceView.eachEditorView (editorView) ->

-# Approximate Vim's "M" motion: Move the cursor to the middle line that is
-# currently visible.
-atom.workspaceView.command 'dot-atom:move-to-middle-visible-line', '.editor', ->
-  view = atom.workspaceView.getActiveView()
-  topRow = view.getFirstVisibleScreenRow()
-  bottomRow = view.getLastVisibleScreenRow()
-  middleRow = Math.floor((bottomRow - topRow) / 2) + topRow
-  view.getEditor().setCursorBufferPosition [middleRow, 0]
+  # Approximate Vim's "H" motion: Move the cursor to the topmost line that is
+  # currently visible.
+  editorView.command 'dot-atom:move-to-top-visible-line', ->
+    topRow = editorView.getFirstVisibleScreenRow()
+    topRow = topRow + 1 unless topRow == 0
+    editorView.getEditor().setCursorBufferPosition [topRow, 0], autoscroll: false

-# Approximate Vim's "L" motion: Move the cursor to the bottommost line that
-# is currently visible.
-atom.workspaceView.command 'dot-atom:move-to-bottom-visible-line', '.editor', ->
-  view = atom.workspaceView.getActiveView()
-  editor = view.getEditor()
-  bottomRow = view.getLastVisibleScreenRow()
-  bottomRow = bottomRow - 1 unless bottomRow == editor.getLastScreenRow()
-  editor.setCursorBufferPosition [bottomRow, 0], autoscroll: false
+  # Approximate Vim's "M" motion: Move the cursor to the middle line that is
+  # currently visible.
+  editorView.command 'dot-atom:move-to-middle-visible-line', ->
+    topRow = editorView.getFirstVisibleScreenRow()
+    bottomRow = editorView.getLastVisibleScreenRow()
+    middleRow = Math.floor((bottomRow - topRow) / 2) + topRow
+    editorView.getEditor().setCursorBufferPosition [middleRow, 0]

-# Approximate Vim's "zt" motion: Scroll the view such that the line containing
-# the cursor is at the top of the view.
-atom.workspaceView.command 'dot-atom:scroll-cursor-to-top', '.editor', ->
-  view = atom.workspaceView.getActiveView()
-  editor = view.getEditor()
-  pixelPositionForCursorPosition =
-    view.pixelPositionForScreenPosition(editor.getCursorScreenPosition())
-  view.scrollTop pixelPositionForCursorPosition.top
+  # Approximate Vim's "L" motion: Move the cursor to the bottommost line that
+  # is currently visible.
+  editorView.command 'dot-atom:move-to-bottom-visible-line', ->
+    editor = editorView.getEditor()
+    bottomRow = editorView.getLastVisibleScreenRow()
+    bottomRow = bottomRow - 1 unless bottomRow == editor.getLastScreenRow()
+    editor.setCursorBufferPosition [bottomRow, 0], autoscroll: false

-# Approximate Vim's "zz" motion: Scroll the view such that the line containing
-# the cursor is vertically centered in the view.
-atom.workspaceView.command 'dot-atom:scroll-cursor-to-center', '.editor', ->
-  view = atom.workspaceView.getActiveView()
-  editor = view.getEditor()
-  # TODO Why can't we implement this command using: `view.scrollToScreenPosition view.getCursorScreenPosition(), center: true`
-  #      This line seems to be the culprit: https://github.com/atom/atom/blob/9fce6a2f1cea680d69bc3181774bc98c541f00b7/src/editor-view.coffee#L1133
-  #      Because of that line, if the cursor is currently visible, no
-  #      scrolling occurs.
-  pixelPositionForCursorPosition =
-    view.pixelPositionForScreenPosition(editor.getCursorScreenPosition())
-  halfScreenHeight = view.scrollView.height() / 2
-  view.scrollTop(pixelPositionForCursorPosition.top - halfScreenHeight)
+  # Approximate Vim's "zt" motion: Scroll the view such that the line containing
+  # the cursor is at the top of the view.
+  editorView.command 'dot-atom:scroll-cursor-to-top', ->
+    editor = editorView.getEditor()
+    pixelPositionForCursorPosition =
+      editorView.pixelPositionForScreenPosition(editor.getCursorScreenPosition())
+    editorView.scrollTop pixelPositionForCursorPosition.top

-# Approximate Vim's "zb" motion: Scroll the view such that the line containing
-# the cursor is at the bottom of the view.
-atom.workspaceView.command 'dot-atom:scroll-cursor-to-bottom', '.editor', ->
-  view = atom.workspaceView.getActiveView()
-  cursorPosition = view.getEditor().getCursorScreenPosition()
-  scrollBottomPosition = [cursorPosition.row + 1, cursorPosition.column]
-  pixelPositionForScrollBottomPosition =
-    view.pixelPositionForScreenPosition(scrollBottomPosition)
-  view.scrollBottom pixelPositionForScrollBottomPosition.top
+  # Approximate Vim's "zz" motion: Scroll the view such that the line containing
+  # the cursor is vertically centered in the view.
+  editorView.command 'dot-atom:scroll-cursor-to-center', ->
+    editor = editorView.getEditor()
+    # TODO Why can't we implement this command using: `editorView.scrollToScreenPosition editorView.getCursorScreenPosition(), center: true`
+    #      This line seems to be the culprit: https://github.com/atom/atom/blob/9fce6a2f1cea680d69bc3181774bc98c541f00b7/src/editor-view.coffee#L1133
+    #      Because of that line, if the cursor is currently visible, no
+    #      scrolling occurs.
+    pixelPositionForCursorPosition =
+      editorView.pixelPositionForScreenPosition(editor.getCursorScreenPosition())
+    halfScreenHeight = editorView.scrollView.height() / 2
+    editorView.scrollTop(pixelPositionForCursorPosition.top - halfScreenHeight)

-# Move the cursor to the next diff in the editor, and then scroll the view such
-# that the line containing the cursor is vertically centered in the view.
-atom.workspaceView.command 'dot-atom:center-next-diff', ->
-  view = atom.workspaceView.getActiveView()
-  view.trigger('git-diff:move-to-next-diff')
-  view.trigger('dot-atom:scroll-cursor-to-center')
+  # Approximate Vim's "zb" motion: Scroll the view such that the line containing
+  # the cursor is at the bottom of the view.
+  editorView.command 'dot-atom:scroll-cursor-to-bottom', ->
+    cursorPosition = editorView.getEditor().getCursorScreenPosition()
+    scrollBottomPosition = [cursorPosition.row + 1, cursorPosition.column]
+    pixelPositionForScrollBottomPosition =
+      editorView.pixelPositionForScreenPosition(scrollBottomPosition)
+    editorView.scrollBottom pixelPositionForScrollBottomPosition.top

-# Move the cursor to the previous diff in the editor, and then scroll the view
-# such that the line containing the cursor is vertically centered in the view.
-atom.workspaceView.command 'dot-atom:center-previous-diff', ->
-  view = atom.workspaceView.getActiveView()
-  view.trigger('git-diff:move-to-previous-diff')
-  view.trigger('dot-atom:scroll-cursor-to-center')
+  # Move the cursor to the next diff in the editor, and then scroll the view
+  # such that the line containing the cursor is vertically centered in the view.
+  editorView.command 'dot-atom:center-next-diff', ->
+    editorView.trigger('git-diff:move-to-next-diff')
+    editorView.trigger('dot-atom:scroll-cursor-to-center')
+
+  # Move the cursor to the previous diff in the editor, and then scroll the view
+  # such that the line containing the cursor is vertically centered in the view.
+  editorView.command 'dot-atom:center-previous-diff', ->
+    view.trigger('git-diff:move-to-previous-diff')
+    view.trigger('dot-atom:scroll-cursor-to-center')


:new: Fix bugs introduced by last commit


Making compile async

Making compile async

--- src/server.coffee
+++ src/server.coffee
@@ -83,20 +83,23 @@
   for fullPath in options.args
     compilePath fullPath, options

+  return
+
 # compilePath
 # ------------------------------------------------------------------------------
 # Compile any file or directory path

-compilePath = (fullPath, options = {}) ->
+compilePath = (fullPath, options = {}, cb = ->) ->
   if isDirectory fullPath
-    return compileDir fullPath, options
+    return compileDir fullPath, options, cb
   includeDir = path.dirname fullPath
-  compileFile fullPath, includeDir, options
+  compileFile fullPath, includeDir, options, cb
+  return

 # compileDir
 # ------------------------------------------------------------------------------

-compileDir = (dirPath, options = {}) ->
+compileDir = (dirPath, options = {}, cb = ->) ->
   # Handle recursion and gather files to watch and compile
   lsWatch dirPath, options, (err, files, dirs) ->

@@ -105,15 +108,21 @@
       for d in dirs
         watchDir d, dirPath, options

+    # Call cb when it has been called length times
+    _cb = _.after files.length, cb
+
     for f in files

       # Compile and watch all pages
       if isOJPage f
-        compileFile f, dirPath, options
+        compileFile f, dirPath, options, _cb

       # Watch files that aren't pages
       else if options.watch
         watchFile f, dirPath, options
+        _cb()
+    return
+  return

 # nodeModulePaths: Determine node_module paths from a given path
 # Implementation is from node.js' Module._nodeModulePaths
@@ -165,7 +174,7 @@

 # compileFile
 # ------------------------------------------------------------------------------
-compileFile = (filePath, includeDir, options = {}) ->
+compileFile = (filePath, includeDir, options = {}, cb = ->) ->
   # Time this method
   startTime = process.hrtime()

@@ -301,19 +310,24 @@
   if mkdirp.sync dirOut
     verbose 3, "mkdir #{dirOut}"

-  # Write file
-  fs.writeFileSync fileOut, html
+  # Record
+  deltaTime = process.hrtime(startTime)
+  timeStamp = " (#{deltaTime[0] + Math.round(10000*deltaTime[1]/1000000000)/10000} sec)"

   # Clear caches
   cache = null
   hookCache = null
   hookOriginalCache = null

-  # Record
-  deltaTime = process.hrtime(startTime)
-  timeStamp = " (#{deltaTime[0] + Math.round(10000*deltaTime[1]/1000000000)/10000} sec)"
-  verbose 1, "compiled #{fileOut}#{timeStamp}", 'cyan'
-  return
+  # Write file
+  fs.writeFile fileOut, html, (err) ->
+
+    if err
+      error "file writing error #{filePath}: #{err}"
+      return
+
+    verbose 1, "compiled #{fileOut}#{timeStamp}", 'cyan'
+    return

 # Keep track of which files are watched
 watchCache = {}


utils: more elegant checks

utils: more elegant checks

--- app/_src/utils.coffee
+++ app/_src/utils.coffee
@@ -27,9 +27,8 @@
 		Simple checks if we are dealing with localhost
 	###
 	@isLocalhost: () ->
-			(document.location.hostname is 'localhost') or
-			(document.location.hostname is '0.0.0.0') or
-			(document.location.hostname is '127.0.0.1')
+		hosts = ['localhost', '0.0.0.0', '127.0.0.1']
+		hosts.indexOf(document.location.hostname) isnt -1

 	###
 		Returns a random number


Set manual error message for 500 responses

--- app/api/client.coffee
+++ app/api/client.coffee
@@ -21,6 +21,10 @@
         ("#{key} #{error}" for key, error of message).join '\n'
     errorMessage = errorMessage.join '\n'

+  # Manually set a reasonable error when we get HTML back (currently 500s will do this).
+  if request.responseText?.indexOf('<!DOCTYPE') isnt -1
+    errorMessage ?= "There was a problem on the server. #{request.responseURL} → #{request.status}"
+
   errorMessage ?= request.responseText?.trim() || "#{request.status} #{request.statusText}"
   throw new Error errorMessage


eliminate needless logs

eliminate needless logs

--- js/src/http/ObjectApi.coffee
+++ js/src/http/ObjectApi.coffee
@@ -47,7 +47,6 @@
       })))
       .then (response) ->
         objectIds = response.data.data
-        log.info('objectIds', objectIds)
         return objectIds

     # load a kryptnosticObject in encrypted form


fixing issue where empty responses were undefined instead of strings

--- jsapp/xlform_model_view/mv.skipLogicHelpers.coffee
+++ jsapp/xlform_model_view/mv.skipLogicHelpers.coffee
@@ -143,7 +143,7 @@
       question = @model._get_question()
       if (question && question._isSelectQuestion())
         response_value = _.find(question.getList().options.models, (option) ->
-          option.get('name') == response_value).cid
+          option.get('name') == response_value)?.cid
       @view.response_value_view.val response_value
       @view.attach_to destination

@@ -221,8 +221,8 @@
       presenter = @build_criterion_logic operator_model, operator_picker_view, response_value_view
       presenter.model.change_question question.cid

-      response_value = if question._isSelectQuestion() then _.find(question.getList().options.models, (option) => return option.get('name') == @criterion.response_value).cid else @criterion.response_value
-      presenter.model.change_response response_value
+      response_value = if question._isSelectQuestion() then _.find(question.getList().options.models, (option) => return option.get('name') == @criterion.response_value)?.cid else @criterion.response_value
+      presenter.model.change_response response_value || ''
       response_value_view.model = presenter.model.get 'response_value'
       response_value_view.val(response_value)


Trying this again.

Trying this again.

--- scripts/watched.coffee
+++ scripts/watched.coffee
@@ -80,19 +80,16 @@
         if robot.auth.hasRole(msg.envelope.user, ['admin', 'moderator'])
             hourcount = msg.match[1]
             savedhours = robot.brain.get 'topwatchers'
+            tophours = Object.keys(savedhours).sort(topScore(savedhours))
+            topFive = tophours.map(displayScore(savedhours)).slice(0, hourcount).join(', ')

-            # Using "for in" is for iterating over an array.
-            # Using "for of" is for iterating over properties of an object.
-            # watchedscores = [timename + " (" + hours[timename] / 100 + " hours)"] for timename of savedhours
-            tophours = (items) ->
-                ([k, v] for k, v of items).sort (a, b) ->
-                    b[1] - a[1]
-                .slice(0, hourcount).map (n) -> n[0]
+            topScore = (list) ->
+              (a, b) ->
+                list[b] - list[a]

-            hourscore = tophours savedhours
+            displayScore = (list) ->
+              (user, index) ->
+                index + 1 + '. ' + user + ' (' + list[user] + ')'

             # msg.send "The top #{hourcount} users with the most hours are: #{hourscore}"
-            msg.send "Saved hours: " + hourscore
-
-            # Inspect the object savedhours
-            # msg.send "Inspection: #{Util.inspect(savedhours)}"
+            msg.send "The top " + hourcount + " people for hours watched: " + hourscore


extraneous return

extraneous return

--- lib/assets/javascripts/turbograft/turbohead.coffee
+++ lib/assets/javascripts/turbograft/turbohead.coffee
@@ -26,7 +26,7 @@
   )

 extractTrackedAssets = (doc) ->
-  return [].slice.call(doc.querySelectorAll('[data-turbolinks-track]'))
+  [].slice.call(doc.querySelectorAll('[data-turbolinks-track]'))

 filterForNodeType = (nodeType) ->
   (node) -> node.nodeName == nodeType


Update CC enrollment; include enrollment_code param

--- tutor/src/components/course-settings/cc-enrollment-code.cjsx
+++ tutor/src/components/course-settings/cc-enrollment-code.cjsx
@@ -29,7 +29,7 @@
   getInstructions: (code) ->
     {bookUrl, bookName} = @props
     # appends :3 to skip book intro
-    url = bookUrl + ':3'
+    url = "#{bookUrl}:3?enrollment_code=#{code}"
     section =
       <CourseGroupingLabel lowercase courseId={@props.courseId} />

@@ -38,21 +38,30 @@

       To register for Concept Coach:

-      1. Paste this link in your web browser to visit the class textbook:
-      #{url}
+      1. Click or paste this link in your web browser to visit the class textbook:
+        #{url}

-      You can also find your Concept Coach book by visiting cc.openstax.org and clicking “Student Portal.”
+      The link has your enrollment code for this Concept Coach course embedded. Course Enrollment Code: #{code}

-      1. In the browser, click the orange “Jump to Concept Coach” button to jump to to the Concept Coach widget at the end of the section. Click “Launch Concept Coach” to open your Concept Coach log-in window.
+      2. Click "Jump to Concept Coach"

-      2. If you’re new to Concept Coach, click “Sign up for Concept Coach” and follow the prompts to create your free account. If you’ve used Concept Coach before, click “Sign In” to sign in.
+      In the browser, click the orange “Jump to Concept Coach” button to jump to the Concept Coach widget at the end of the section.

-      3. After signing in, enter your enrollment code for this course. Your enrollment code is:
-      #{code}
+      3. Click “Enroll in This Course”

-      4. On the enrollment confirmation screen, input your school-issued ID number so your instructor can identify you.
+      Click the orange “Enroll in This Course” button to open your Concept Coach log-in window.

-      5. Continue to your Concept Coach questions!
+      4. Click Sign Up and Enroll (or Login and Enroll if you already have an account).
+
+      If you’re new to Concept Coach, you’ll be prompted to create a free account. If you’ve used Concept Coach before, log in using your existing OpenStax Concept Coach account.
+
+      5. Enter your school-issued ID
+
+      On the enrollment confirmation screen, input your school-issued ID number used for grading so your instructor can identify you.
+
+      6. Continue to your Concept Coach questions!
+
+      You can also find your Concept Coach book by visiting cc.openstax.org and clicking “Student Portal.” If you get to your book this way, and have not already enrolled, you may be asked to enter your enrollment code:  Course Enrollment Code: #{code}
     """
     <div>


cleanp vs

cleanp vs

--- src/application.coffee
+++ src/application.coffee
@@ -54,7 +54,6 @@

   createObject: (name, options = {}) ->

-
     if type(name) is "function"
       clazz = name
     else
@@ -63,7 +62,6 @@
       unless clazz
         throw new Error "class '#{name}' doesn't exist"

-
     return new clazz _.extend(options, { application: @ })


minor fix in Sprite.removeAll

minor fix in Sprite.removeAll

--- src/sprite.coffee
+++ src/sprite.coffee
@@ -32,6 +32,9 @@
             _list.splice i, 1
             return
     @removeAll = (excep...) ->
+        for sp in _list when sp not in excep
+            sp.stop() if sp.isRunning()
+
         _list = []
         for sp in excep
             _list.push sp


Address feedback changes for auctions on desktop

--- src/desktop/apps/artwork/components/auction/view.coffee
+++ src/desktop/apps/artwork/components/auction/view.coffee
@@ -9,8 +9,8 @@
 acquire = require '../../lib/acquire.coffee'
 helpers = require './helpers.coffee'
 metaphysics = require '../../../../../lib/metaphysics.coffee'
-Serializer = require '../../../../components/form/serializer.coffee'
 CurrentUser = require '../../../../models/current_user.coffee'
+{ createOrder } = require '../../../../../lib/components/create_order'
 template = -> require('./templates/index.jade') arguments...

 LOT_STANDING_MAX_POLLS = 10
@@ -64,26 +64,22 @@
   acquire: (e) ->
     e.preventDefault()

+    $target = $(e.currentTarget)
+    $target.attr 'data-state', 'loading'
+
     # Show the new buy now flow if you have the lab feature enabled
     loggedInUser = CurrentUser.orNull()
     if loggedInUser?.hasLabFeature('New Buy Now Flow')
-      serializer = new Serializer @$('.js-artwork-auction-buy-now-form')
-      data = serializer.data()
-
       createOrder
-        artworkId: @data.artwork.get('_id')
-        editionSetId: data.edition_set_id
+        artworkId: AUCTION.artwork_id
         quantity: 1
         user: loggedInUser
       .then (data) ->
         order = data?.createOrderWithArtwork?.orderOrError?.order
         location.assign("/order2/#{order.id}/shipping")

-    # Legacy purchase flow flow
+    # Legacy purchase flow
     else
-      $target = $(e.currentTarget)
-      $target.attr 'data-state', 'loading'
-
       acquire AUCTION.artwork_id
         .catch ->
           $target.attr 'data-state', 'error'


Allow chaining until() calls

Allow chaining until() calls

--- src/stdlib.coffee
+++ src/stdlib.coffee
@@ -131,7 +131,9 @@
     @time = 0 # Initialize to 0 so any callers using getTime() can correctly
               # perform offset math.

-  getTime: -> @time
+  getTime: ->
+    @time
+
   setTime: (time) ->
     # Time only advances
     if time > @time || time == 0
@@ -219,10 +221,13 @@
   until: (delay, callback) ->
     newScope = @createUntilScope(delay)
     callback.apply(newScope)
+    # Chain untils() to run sequentially
+    {
+      then: (_delay, _callback) => @after(delay, (=> @until(_delay, _callback)))
+    }

   #
   # Internal API:
-
   withExpiration: (id) ->
     setTimeout((=> clearInterval(id)), @expiration - TinyRave.timer.getTime())


kite: removed timeout

kite: removed timeout

--- node_modules_koding/koding-kite/worker.coffee
+++ node_modules_koding/koding-kite/worker.coffee
@@ -166,7 +166,7 @@
           return clientCallback err, null if err

           if callback
-            callback request, runWithTimeout(worker, 2, clientCallback)
+            callback request, clientCallback

 module.exports.RequestFilter  = RequestFilter
 module.exports.RequestFilters = RequestFilters


AppDetailsView: Simplfy the app details view, add reviewView back

--- client/Social/Apps/Views/appdetailsview.coffee
+++ client/Social/Apps/Views/appdetailsview.coffee
@@ -7,7 +7,7 @@
     app = @getData()
     {icns, identifier, version, authorNick} = app.manifest

-    @listenWindowResize()
+    # @listenWindowResize()

     @slideShow = new KDCustomHTMLView
       tagName   : "ul"
@@ -18,28 +18,17 @@
           tmpl += "

"
         return tmpl

-    # @reviewView = new ReviewView {}, app
+    @reviewView = new ReviewView {}, app

   viewAppended:->

     @setTemplate @pistachio()
     @template.update()

-    @_windowDidResize()
-
-  _windowDidResize:->
-    @setHeight @parent.getHeight() - @parent.$('.kdview.profilearea').outerHeight(no) - @parent.$('>h2').outerHeight(no)
-
-  click:(event)->
-
-    if $(event.target).is('header a, header a span')
-      log "right"
-
-  scroll:(event)->
-    if @getScrollTop() > 20
-      @parent.$('.profilearea').addClass "cast-shadow"
-    else
-      @parent.$('.profilearea').removeClass "cast-shadow"
+  # Do we need this? ~ GG
+  #   @_windowDidResize()
+  # _windowDidResize:->
+  #   @setHeight @parent.getHeight() - @parent.$('.kdview.profilearea').outerHeight(no) - @parent.$('>h2').outerHeight(no)

   pistachio:->
     if @getData().manifest.screenshots?.length
@@ -54,5 +43,5 @@
     #{screenshots or ""}

     Reviews
+
{{> @reviewView}}

     """
-    #
{{> @reviewView}}


AccountTwoFactor: Lowercase code

AccountTwoFactor: Lowercase code

--- client/account/lib/accounttwofactorauth.coffee
+++ client/account/lib/accounttwofactorauth.coffee
@@ -208,7 +208,7 @@

Open the Authenticator app on your phone.

Tap the “+" or “..." icon and then choose “Scan barcode" to add Koding.
-
Scan the Code shown below using your phone's camera.
+
Scan the code shown below using your phone's camera.

Enter the 6-digit verification code generated by the app in the space
         below and click the “Enable” button.


environment/flux: return a promise for reiniting the stack

--- client/app/lib/flux/environment/actions.coffee
+++ client/app/lib/flux/environment/actions.coffee
@@ -385,9 +385,12 @@

   { computeController } = kd.singletons

-  computeController.reinitStack if stack
-  then remote.revive stack.toJS()
-  else computeController.getGroupStack()
+  new Promise (resolve, reject) ->
+
+    stack = if stack then stack.toJS() else computeController.getGroupStack()
+
+    computeController.reinitStack stack, (err) ->
+      if err then reject(err) else resolve()

 createWorkspace = (machine, workspace) ->


ComputeStorage: query: support full data path on key if possible

--- client/app/lib/providers/computestorage.coffee
+++ client/app/lib/providers/computestorage.coffee
@@ -56,7 +56,7 @@
       if typeof key is 'string'
         res = items
           .map (item) ->
-            return item  if item and item[key] is value
+            return item  if item and (item.getAt?(key) ? item[key]) is value
           .filter Boolean

     res ?= []


copy pasta fail

copy pasta fail

--- src/atom/editor.coffee
+++ src/atom/editor.coffee
@@ -93,19 +93,6 @@

     true

-  edit: (code) ->
-    @session = new EditSession code
-    @session.setValue code
-    @session.setUseSoftTabs @settings.softTabs
-    @session.setTabSize if @settings.softTabs then @settings.tabSize else 8
-    @session.setUndoManager new UndoManager
-    @session.on 'change', => @dirty = true
-    @pane.ace.setSession @session
-
-    @pane.ace.setTheme require "ace/theme/#{@settings.theme}"
-    @pane.ace.setShowInvisibles @settings.showInvisibles
-    @pane.ace.setPrintMarginColumn @settings.marginColumn
-
   close: ->
     if @dirty
       detailedMessage = if @url


code quality/cleanup

code quality/cleanup

--- client/landing/app/MainApp/kodingrouter.coffee
+++ client/landing/app/MainApp/kodingrouter.coffee
@@ -120,22 +120,24 @@
         else
           @loadContent name, section, topicSlug, route

-  collectionToMap =(acc, sec)->
-    acc[sec[0]] = sec[1]
-    acc
-
   getRoutes =->
+    # Abbreviations used below:
+    # "acc" is short for "accumulator"
+    # "kv" is short for "key-value pair"
+    # "sec" is short for "section"
     mainController = KD.getSingleton 'mainController'
+
+    kv =(acc, sec)-> acc[sec[0]] = sec[1]; acc

     goToContent = 'Activity Apps Groups Members Topics'
       .split(' ')
       .map((sec)=> [sec, @createContentDisplayHandler sec])
-      .reduce collectionToMap, {}
+      .reduce kv, {}

     goToSection = 'Account Activity Apps Groups Members StartTab Topics'
       .split(' ')
       .map((sec)-> [sec, ({params:{name}, query})-> @go sec, name, query])
-      .reduce collectionToMap, {}
+      .reduce kv, {}

     routes =

@@ -237,7 +239,7 @@
             when 'JGroup'   then goToContent.Groups  routeInfo, model
             when 'JTopic'   then goToContent.Topics  routeInfo, model
             else status_404()
-        handler =(routeInfo, state, route)->
+        nameHandler =(routeInfo, state, route)->
           {params} = routeInfo
           status_404 = @handleNotFound.bind this, params.name
           if state?


Common

Common

- add index method

--- src/base/Common.coffee
+++ src/base/Common.coffee
@@ -405,6 +405,9 @@
 	else
 		0

+index = (node) ->
+	Array.prototype.indexOf.call(node.parentNode.children, node)
+
 # pushes value onto array, if not exists
 # returns index of the pushed value
 pushOntoArray = (value, arr, compFunc) ->


router to redirect loggedout users to home app

--- client/landing/app/MainApp/kodingrouter.coffee
+++ client/landing/app/MainApp/kodingrouter.coffee
@@ -98,7 +98,7 @@
       if err or not target? then status_404()
       else status_301 target

-  getDefaultRoute:-> '/Activity'
+  getDefaultRoute:-> if KD.isLoggedIn() then '/Activity' else '/Home'

   setPageTitle:(title="Koding")-> document.title = Encoder.htmlDecode title


remove console.log

remove console.log

--- client/src/common/services/trello-utils.coffee
+++ client/src/common/services/trello-utils.coffee
@@ -73,7 +73,6 @@
         name: card.idShort
         data: _.map labels, (label) ->
           if label.name in _.map card.labels, 'name'
-            console.log label.name, label.color, getColorCode(label.color)
             color: getColorCode(label.color)
             y: points
             name: card.idShort


About: fixed vm count

About: fixed vm count

--- client/About/AppView.coffee
+++ client/About/AppView.coffee
@@ -62,7 +62,7 @@

VMs spinned up

-              1,000,000,000+
+              1,000,000+

           photo by - Isaak Dury


payment: remove includes of unnecessary classes.

--- client/Main/includes.coffee
+++ client/Main/includes.coffee
@@ -187,18 +187,22 @@
   # PAYMENT
   # controller
   "payment/paymentcontroller.coffee",
-  # views
-  "payment/paymentmethodview.coffee",
-  "payment/subscriptionview.coffee",
-  "payment/paymentmethodentryform.coffee",
-  "payment/paymentchoiceform.coffee",
-  "payment/paymentformmodal.coffee",
-  "payment/paymentworkflow.coffee",
-  "payment/paymentconfirmform.coffee",
-  "payment/genericplanview.coffee",
-  "payment/planupgradeconfirmform.coffee",
-  "payment/planproductlist.coffee",
-  "payment/existingaccountworkflow.coffee",
+  # # views
+  # "payment/paymentmethodview.coffee",
+  # "payment/subscriptionview.coffee",
+  # "payment/paymentmethodentryform.coffee",
+  # "payment/paymentchoiceform.coffee",
+  # "payment/paymentformmodal.coffee",
+  # "payment/paymentworkflow.coffee",
+  # "payment/paymentconfirmform.coffee",
+  # "payment/genericplanview.coffee",
+  # "payment/planupgradeconfirmform.coffee",
+  # "payment/planproductlist.coffee",
+  # "payment/existingaccountworkflow.coffee",
+
+  "payment/workflow.coffee",
+  "payment/form.coffee",
+  "payment/modal.coffee",

   # global notifications


mixpanel: send email, username along with every event

--- client/Main/mixpanel.coffee
+++ client/Main/mixpanel.coffee
@@ -24,7 +24,17 @@
 # Access control wrapper around mixpanel object.
 KD.mixpanel = (args...)->
   return  unless mixpanel and KD.config.logToExternal
-  mixpanel.track args...
+  if args.length < 2
+    args.push {}
+
+  me = KD.whoami()
+  me.fetchEmail (err, email)->
+    console.log err  if err
+
+    args[1]["username"] = me.profile.nickname
+    args[1]["email"] = email
+
+    mixpanel.track args...

 KD.mixpanel.alias = (args...)->
   return  unless mixpanel and KD.config.logToExternal


appcontroller: improve createPaneFromChange method

extract create pane methods for specific pane types.

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -1145,40 +1145,50 @@
     @changeActiveTabView paneType

     switch paneType
-      when 'terminal'
-        terminalOptions =
-          machine       : @mountedMachine
-          session       : context.session
-          hash          : paneHash
-          joinUser      : @collaborationHost or nick()
-          fitToWindow   : not @isInSession
-
-        @createNewTerminal terminalOptions
-
-      when 'editor'
-        { file }      = context
-        { path }      = file
-        options       = { path, machine : @mountedMachine }
-        file          = FSHelper.createFileInstance options
-        file.paneHash = paneHash
-
-        if @rtm?.realtimeDoc
-          content = @rtm.getFromModel(path)?.getText() or ''
-          @openFile file, content, noop, no
-        else if file.isDummyFile()
-          @openFile file, context.file.content, noop, no
-        else
-          file.fetchContents (err, contents = '') =>
-            return showError err  if err
-            @changeActiveTabView paneType
-            @openFile file, contents, noop, no
-
-      when 'drawing'
-        @createNewDrawing paneHash
-
-    if @mySnapshot
-      unless @mySnapshot.get paneHash
-        @mySnapshot.set paneHash, change
+      when 'terminal' then @createTerminalPaneFromChange change, paneHash
+      when 'editor'   then @createEditorPaneFromChange change, paneHash
+      when 'drawing'  then @createDrawingPaneFromChange change, paneHash
+
+    if @mySnapshot and not @mySnapshot.get paneHash
+      @mySnapshot.set paneHash, change
+
+
+  createTerminalPaneFromChange: (change, hash) ->
+
+    @createNewTerminal
+      machine       : @mountedMachine
+      session       : change.context.session
+      hash          : hash
+      joinUser      : @collaborationHost or nick()
+      fitToWindow   : not @isInSession
+
+
+  createEditorPaneFromChange: (change, hash) ->
+
+    { context }   = change
+    { file }      = context
+    { path }      = file
+    options       = { path, machine : @mountedMachine }
+    file          = FSHelper.createFileInstance options
+    file.paneHash = hash
+
+    if @rtm?.realtimeDoc
+      content = @rtm.getFromModel(path)?.getText() or ''
+      @openFile file, content, noop, no
+
+    else if file.isDummyFile()
+      @openFile file, file.content, noop, no
+
+    else
+      file.fetchContents (err, contents = '') =>
+        return showError err  if err
+        @changeActiveTabView paneType
+        @openFile file, contents, noop, no
+
+
+  createDrawingPaneFromChange: (change, hash) ->
+
+    @createNewDrawing hash

   showModal: (modalOptions = {}, callback = noop) ->


Nicer coffeescript syntax

Nicer coffeescript syntax

--- app/models/pot.coffee
+++ app/models/pot.coffee
@@ -5,11 +5,11 @@

   constructor: (amount) ->
     throw "We're not in the credit business here" if amount < 0
-    @size = amount || 0
+    @size = amount ? 0

   validate: ->
     "We're card sharks, not loan sharks!" unless @size >= 0
-
+
   credit: (amount) ->
     throw "Can only credit positive amounts. Got: #{amount}" if amount < 0
     @size += amount
@@ -20,5 +20,5 @@
     throw "You can't debit #{amount}, there's only #{@size} in the pot" if amount > @size
     @size -= amount
     @save()
-
+
 module.exports = Pot


register the default task to an empty array.  Leaving it undefined has unintended consequences when running `lineman grunt` without a task.

--- config/grunt.coffee
+++ config/grunt.coffee
@@ -2,6 +2,7 @@

 module.exports =
   run: (grunt) ->
+    grunt.registerTask('default', []);
     grunt.initConfig(userConfig())
     grunt.loadTasks("#{__dirname}/../tasks") #Lineman-defined tasks/
     grunt.loadTasks("tasks") #User-defined tasks/


Switches to ntb_test for updater script

Switches to ntb_test for updater script

--- coffee/tools/updater.coffee
+++ coffee/tools/updater.coffee
@@ -9,7 +9,7 @@
 mongodb = require 'mongodb'
 database = require './../database.coffee'

-database.connect 'ntb_07', (err, db) ->
+database.connect 'ntb_test', (err, db) ->
   return console.log err if err

   console.log 'Database connection is open'


snippets added

snippets added


KDContentEditableView: remove obsolete control structure

--- components/inputs/KDContentEditableView.coffee
+++ components/inputs/KDContentEditableView.coffee
@@ -86,7 +86,6 @@
     @emit "ValueChanged", event

   keyDown: (event) =>
-    return  unless event.target is @getElement()
     {tabNavigation, multiline, validate} = @getOptions()

     switch event.which


Comment out test

Comment out test

--- components/main_layout/header/test/view.coffee
+++ components/main_layout/header/test/view.coffee
@@ -36,18 +36,18 @@
       @view.$welcomeHeader.hide.called.should.be.ok
       @view.$window.off.called.should.be.ok

-  describe '#login', ->
-    it 'triggers the mediator', ->
-      spy = sinon.spy mediator, 'trigger'
-      @view.$('.mlh-login').click()
-      spy.args[0][0].should.equal 'open:auth'
-      spy.args[0][1].mode.should.equal 'login'
-      mediator.trigger.restore()
+  # describe '#login', ->
+  #   it 'triggers the mediator', ->
+  #     spy = sinon.spy mediator, 'trigger'
+  #     @view.$('.mlh-login').click()
+  #     spy.args[0][0].should.equal 'open:auth'
+  #     spy.args[0][1].mode.should.equal 'login'
+  #     mediator.trigger.restore()

-  describe '#signup', ->
-    it 'triggers the mediator', ->
-      spy = sinon.spy mediator, 'trigger'
-      @view.$('.mlh-signup').click()
-      spy.args[0][0].should.equal 'open:auth'
-      spy.args[0][1].mode.should.equal 'signup'
-      mediator.trigger.restore()
+  # describe '#signup', ->
+  #   it 'triggers the mediator', ->
+  #     spy = sinon.spy mediator, 'trigger'
+  #     @view.$('.mlh-signup').click()
+  #     spy.args[0][0].should.equal 'open:auth'
+  #     spy.args[0][1].mode.should.equal 'signup'
+  #     mediator.trigger.restore()


WebtermMessagePane: while in busy state, ignore all clicks

--- client/Terminal/webtermmessagepane.coffee
+++ client/Terminal/webtermmessagepane.coffee
@@ -9,6 +9,8 @@
     super options, data

   busy: ->
+
+    @off 'click'

     @loader.updatePartial 'Connecting'


amend gruntfile

amend gruntfile

--- gruntfile.coffee
+++ gruntfile.coffee
@@ -26,12 +26,14 @@
         options:
           sassDir: "sass/"
           cssDir: "build/css/"
-          environment: 'production'
+          imageDir: 'img/'
+          environment: 'development'
       dist:
         options:
           sassDir: "sass/"
           cssDir: "build/css/"
-          environment: 'development'
+          imageDir: 'img/'
+          environment: 'production'
     coffee:
       compile:
         options:
@@ -78,19 +80,19 @@
     watch:
       css:
         files: 'sass/**'
-        tasks: ['compass:dev']
+        tasks: ['compass:compile']
         options:
           spawn: false
           livereload: 35729
       jade:
         files: 'jade/**'
-        tasks: ['jade']
+        tasks: ['jade:compile']
         options:
           spawn: false
           livereload: 35729
       coffee:
         files: 'coffee/**'
-        tasks: ['coffee']
+        tasks: ['coffee:compile']
         options:
           spawn: false
           livereload: 35729
@@ -110,7 +112,6 @@
       '*.log'
     ]

-
   grunt.loadNpmTasks 'grunt-contrib-jade'
   grunt.loadNpmTasks 'grunt-contrib-compass'
   grunt.loadNpmTasks 'grunt-contrib-coffee'
@@ -118,7 +119,6 @@
   grunt.loadNpmTasks 'grunt-contrib-connect'
   grunt.loadNpmTasks 'grunt-contrib-watch'
   grunt.loadNpmTasks 'grunt-contrib-copy'
-  grunt.loadNpmTasks 'grunt-contrib-clean'

   grunt.registerTask 'remake', ['bower:install', 'coffee:compile', 'jade:compile', 'compass:compile', 'copy:dev']
   grunt.registerTask 'make', ['coffee:compile', 'jade:compile', 'compass:compile']


payment: subscription: bring back cancel/resume/terminate

...with new implementations

--- workers/social/lib/social/models/payment/subscription.coffee
+++ workers/social/lib/social/models/payment/subscription.coffee
@@ -141,15 +141,37 @@

   #     update_ sub, callback

-  # cancel: (callback)->
-  #   payment.cancelSubscription @userCode, {@uuid}, (err, sub)=>
-  #     return callback err  if err
-  #     update_ sub, callback
-
-  # resume: (callback)->
-  #   payment.reactivateUserSubscription @userCode, {@uuid}, (err, sub)=>
-  #     return callback err  if err
-  #     update_ sub, callback
+  updateStatus: (status, callback) ->
+    @update $set: { status }, callback
+
+  invokeMethod: (method, options, callback) ->
+    [callback, options] = [options, callback]  unless callback
+    options ?= { @uuid }
+    payment[method] options, (err, sub) =>
+      return callback err  if err
+
+      @updateStatus sub.status, (err) ->
+        return callback err  if err
+
+        callback null
+
+  cancel: (callback) ->
+    @invokeMethod 'cancelSubscription', callback
+
+  terminate: (callback) ->
+    @invokeMethod 'terminateSubscription', (err) ->
+      return callback err  if err
+
+      callback null  # dunno why we're calling bacjk early C.T.
+
+      @calculateRefund (err, percent)=>
+        unless err
+          @refund percent, (err) ->
+            console.error err  if err
+            console.log "Refunding #{percent}% of subscription #{@uuid}."
+
+  resume: (callback) ->
+    @invokeMethod 'reactivateSubscription', callback

   checkUsage: (product, callback) ->
     JPaymentPlan = require './plan'


payment: improve error handling of subscription lock procedure

--- workers/social/lib/social/models/payment/subscription.coffee
+++ workers/social/lib/social/models/payment/subscription.coffee
@@ -215,14 +215,18 @@
   debit: ({ pack, multiplyFactor, shouldCreateNonce }, callback) ->
     return callback new KodingError "Your subscription is currently locked"  if @transactionLock

+    multiplyFactor    ?= 1
+    shouldCreateNonce ?= no
+
     @update $set: transactionLock: yes, (err) =>
       return callback err  if err

-      multiplyFactor    ?= 1
-      shouldCreateNonce ?= no
-
       @checkUsage pack, multiplyFactor, (err, usage) =>
-        return callback err  if err
+        if err
+          callback err  if err
+          @update $set: transactionLock: no, (err) ->
+            console.warn "Transaction lock reset failed"  if err
+          return

         { quantities } = pack

@@ -236,7 +240,11 @@
         op.$set.transactionLock = no

         @update op, (err) =>
-          return callback err  if err
+          if err
+            callback err  if err
+            @update $set: transactionLock: no, (err) ->
+              console.warn "Transaction lock reset failed"  if err
+            return

           if shouldCreateNonce
             @createFulfillmentNonce pack, (multiplyFactor > 0), callback


Pass clientId to doReset to make login after password recovery work.

--- client/app/MainApp/login/loginview.coffee
+++ client/app/MainApp/login/loginview.coffee
@@ -114,7 +114,9 @@

     @resetForm = new ResetInlineForm
       cssClass : "login-form"
-      callback : (formData)=> @doReset formData
+      callback : (formData)=>
+        formData.clientId = $.cookie('clientId')
+        @doReset formData

     @requestForm = new RequestInlineForm
       cssClass : "login-form"
@@ -217,12 +219,12 @@
     {{> @backToHomeLink}}
     """

-  doReset:({recoveryToken, password})->
+  doReset:({recoveryToken, password, clientId})->
     KD.remote.api.JPasswordRecovery.resetPassword recoveryToken, password, (err, username)=>
       @resetForm.button.hideLoader()
       @resetForm.reset()
       @animateToForm 'login'
-      @doLogin {username, password}
+      @doLogin {username, password, clientId}

   doRecover:(formData)->
     KD.remote.api.JPasswordRecovery.recoverPassword formData['username-or-email'], (err)=>


removed tunnel-identifier

removed tunnel-identifier

--- test/e2e/protractor.conf.coffee
+++ test/e2e/protractor.conf.coffee
@@ -25,7 +25,6 @@
   config.sauceUser = process.env.SAUCE_USERNAME
   config.sauceKey = process.env.SAUCE_ACCESS_KEY
   config.capabilities =
-    'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
     build: process.env.TRAVIS_BUILD_NUMBER
     name: "Radian build #{process.env.TRAVIS_BUILD_NUMBER}"


dashboard: fetchRoot is added to endpoint

--- client/app/lib/socialapicontroller.coffee
+++ client/app/lib/socialapicontroller.coffee
@@ -205,7 +205,7 @@

   mapChannel = (channel) ->
     { socialapi } = kd.singletons
-
+
     data  = channel.channel

     # hold state of cache hit
@@ -213,7 +213,7 @@

     # item is initially our data
     item = data
-
+
     # if we find the channel in cache, replace item with it
     if cacheItem = socialapi.retrieveCachedItem item.typeConstant, item.id
       cacheFound = yes
@@ -221,7 +221,7 @@

     item._id                 = data.id
     item.isParticipant       = channel.isParticipant
-    # we only allow name, purpose and payload to be updated
+    # we only allow name, purpose and payload to be updated
     item.payload             = data.payload
     item.name                = data.name
     item.purpose             = data.purpose
@@ -229,10 +229,10 @@
     item.participantsPreview = mapAccounts channel.participantsPreview
     item.unreadCount         = channel.unreadCount
     item.lastMessage         = mapActivity channel.lastMessage  if channel.lastMessage
-
-    unless cacheFound
+
+    unless cacheFound
       channelInstance = new remote.api.SocialChannel item
-    else
+    else
       channelInstance = item

     kd.singletons.socialapi.cacheItem channelInstance
@@ -698,11 +698,6 @@
       validateOptionsWith: ["channelId"]
       successFn          : removeChannel

-    create               : channelRequesterFn
-      fnName             : 'create'
-      validateOptionsWith: ["name"]
-      mapperFn           : mapChannel
-
     revive               : mapChannel

   moderation:
@@ -727,6 +722,14 @@
         return callback err if err
         return callback null, mapChannels result

+    fetchRoot   : (options, callback) ->
+      doXhrRequest {
+        endPoint : "/api/social/moderation/channel/#{options.leafId}/root?#{serialize(options)}"
+        type     : 'GET'
+      }, (err, result)->
+        return callback err if err
+        return callback null, mapChannel result
+
     blacklist: (options, callback) ->
       doXhrRequest {
         endPoint : "/api/social/moderation/channel/blacklist"


Rename Treeview to Tree View in View menu

Synchronizes it to the same label used in the Packages menu.

--- menus/tree-view.cson
+++ menus/tree-view.cson
@@ -2,7 +2,7 @@
   {
     'label': 'View'
     'submenu': [
-      'label': 'Toggle Treeview'
+      'label': 'Toggle Tree View'
       'command': 'tree-view:toggle'
     ]
   }


expose the mongo model

expose the mongo model

--- models/models.coffee
+++ models/models.coffee
@@ -289,6 +289,7 @@
 nko.Vote = Vote

 Mongo.blessAll nko
+nko.Mongo = Mongo

 Team::toParam = -> @slug
 Team.fromParam = (id, options, fn) ->