Added new !TeX syntax magic comments

Added new !TeX syntax magic comments

--- grammars/latex.cson
+++ grammars/latex.cson
@@ -39,7 +39,7 @@
   metaPercent: {
     comment: 'This is called when there is a lone percent sign (escaped covered by metaControl).'
     patterns: [
-      { include: '#magicComment' }
+      { include: '#metaMagicComment' }
       { include: '#lineComment' }
     ]
   }
@@ -56,7 +56,7 @@
     match: '~'
   }
   metaAmpersand: {
-    comment: 'The ampersand normally represents alignment (catcode 4). Probably not useful (or legal) outside of align or table environment. However, it must be left this way to let users implement custom environments.'
+    comment: 'The ampersand normally represents alignment (catcode 4). Probably not useful (or legal) outside of align or table environment. However, it should be left this way to let users implement custom syntax.'
     name: 'punctuation.alignment.latex'
     match: '&'
   }
@@ -439,7 +439,7 @@
     name: 'comment.line.percentage.latex'
     begin: '%'
     end: '$'
-    patterns: [{ include: '#magicComment' }]
+    patterns: [{ include: '#metaMagicComment' }]
   }
   escapedCurlyBracket: {
     comment: 'Escaped }. Possible deprecated by escapedCharacter.'
@@ -499,24 +499,76 @@
     patterns: [
       { include: '#doubleBackslash' }
       { include: '#escapedCharacter' }
-      { include: '#magicComment' }
+      { include: '#metaMagicComment' }
       { include: '#lineComment' }
     ]
   }
-  magicComment: {
-    comment: 'Can be improved to change color depending if the command matches a known string'
-    name: 'comment.line.percentage.latex'
-    captures: 0: name: 'keyword.control.magic.latex'
-    match: '''(?x)   # Allow comments like this. More of an educational thing, really, for anyone reading this.
-     ((        # Capture groups 1 & 2
-       (%)     # Capture percent sign
-       (\\ !(?>TEX|BIB)\\ )  # See https://github.com/kkos/oniguruma/blob/771535fce64f225f9fa2f965dbb55277e18fbde9/doc/RE#L252 for ?>
-       (\\S+)    # A word (this is required as far as I know)
-       )       # End capture group 2
-       (\\ = \\ )  # Match = with space (required)
-     )         # End capture group 1
-     .*$       # To end; some options have spaces
-   '''
+  metaMagicComment: {
+    patterns: [
+      {
+        comment: 'Simplify syntax highlighting until the next magic syntax comment'
+        begin: '% !(?>T[eE]X) syntax = plain'
+        beginCaptures: 0: name: 'keyword.control.magic.syntax.plain.latex'
+        end: '(?=% !T[eE]X syntax)'
+        contentName: 'meta.syntax.plain.latex'
+        patterns: [{ include: '#syntaxPlain'}]
+      }
+      {
+        comment: 'Forces mathmode until the next magic syntax comment'
+        begin: '% !(?>T[eE]X) syntax = math'
+        beginCaptures: 0: name: 'keyword.control.magic.syntax.math.latex'
+        end: '(?=% !T[eE]X syntax)'
+        contentName: 'string.other.math.latex'
+        patterns: [{ include: '$self' }]
+      }
+      {
+        comment: 'Forces out of mathmode. Actually implemented in the mathMode patterns, as I dont know how to force an exit indirectly.'
+        match: '% !(?>T[eE]X) syntax = text'
+        captures: 0: name: 'keyword.control.magic.syntax.text.latex'
+      }
+      {
+        begin: '% !(?>T[eE]X) syntax = verbatim'
+        beginCaptures: 0: name: 'keyword.control.magic.syntax.verbatim.latex'
+        end: '(?=% !T[eE]X syntax)'
+        contentName: 'markup.raw.verbatim.latex'
+      }
+      {
+        begin: '% !(?>T[eE]X) syntax = none'
+        beginCaptures: 0: name: 'keyword.control.magic.syntax.verbatim.latex'
+        end: '(?=% !T[eE]X syntax)'
+        contentName: 'meta.syntax.none.latex'
+      }
+      {
+        comment: 'Can be improved to change color depending if the command matches a known string'
+        name: 'comment.line.percentage.latex'
+        captures: 0: name: 'keyword.control.magic.latex'
+        match: '''(?x)   # Allow comments like this. More of an educational thing, really, for anyone reading this.
+         ((        # Capture groups 1 & 2
+           (%)     # Capture percent sign
+           (\\ !(?>T[eE]X|BIB)\\ )  # See https://github.com/kkos/oniguruma/blob/771535fce64f225f9fa2f965dbb55277e18fbde9/doc/RE#L252 for ?>
+           (\\S+)    # A word (this is required as far as I know)
+           )       # End capture group 2
+           (\\ = \\ )  # Match = with space (required)
+         )         # End capture group 1
+         .*$       # To end; some options have spaces
+       '''
+      }
+    ]
+  }
+  syntaxPlain: {
+    comment: 'This is bare minimum that should work in most cases. It does not attempt to match pairs of anything, or specific constructions; just control sequences'
+    patterns: [
+      { include: '#controlSymbol' }
+      { include: '#controlWord' }
+      { include: '#lineComment' }
+      {
+        comment: 'Does not look for matching, just shows it is there'
+        match: '(\\$\\$)|(\\$)'
+        captures:
+          1: name: 'string.other.math.display.latex'
+          2: name: 'string.other.math.inline.latex'
+      }
+    ]
   }
   documentclass: {
     comment: 'Documentclass finder.'
@@ -619,7 +671,7 @@
     beginCaptures:
       0: name: 'string.other.math.display.begin.latex'
       1: name: 'invalid.deprecated.latex'
-    end: '(\\$\\$)|(\\\\\\])|(?=\\})'
+    end: '(\\$\\$)|(\\\\\\])|(?=\\})|((?=% !T[eE]X syntax))'
     endCaptures:
       0: name: 'string.other.math.display.end.latex'
       1: name: 'invalid.deprecated.latex'


general changes + removed `hypersetup`

general changes + removed `hypersetup`

--- grammars/latex.cson
+++ grammars/latex.cson
@@ -8,7 +8,7 @@
 # Rules to be implemented. Please add to repository and link to a 'meta' to include.
 # The following rules correspond to the ten special latex characters. They are applied at the outmost level, but can be called inside patterns by using `$base`
 patterns: [
-  { include: '#metaControl' }
+  { include: '#metaControl' } # must go first to catch escaped sequences
   { include: '#metaPercent' }
   { include: '#metaDollar' }
   { include: '#metaTilde' }
@@ -20,10 +20,8 @@
   { include: '#metaHashtag' }
 ]

-# List of available rules. Must 'include' a rule to patterns for it to be implemented.
-# Thinking of moving pure TeX commands to a separate file and linking it in here (like the preexisting package).
 repository:
-# Meta Commands
+# Main meta groups; directly referenced in `patterns`
   metaControl: {
     comment: 'All these commands begin with a backslash.'
     patterns: [
@@ -37,6 +35,82 @@
       { include: '#controlWord' }
     ]
   }
+  metaPercent: {
+    comment: 'This is called when there is a lone percent sign (escaped covered by metaControl).'
+    patterns: [
+      { include: '#magicComment' }
+      { include: '#lineComment' }
+    ]
+  }
+  metaDollar: {
+    comment: 'Called when $ sign found. Posiibly deprecated by \( and \) (which is called in metaControl), but here for completeness. The previous statement did not make its meaning very clear.'
+    patterns: [
+      { include: '#displayMathMode' }
+      { include: '#inlineMathMode' }
+    ]
+  }
+  metaTilde: {
+    comment: 'This is only an unbreaking space (when alone).'
+    name: 'punctuation.space.latex'
+    match: '~'
+  }
+  metaAmpersand: {
+    comment: 'The ampersand normally represents alignment (catcode 4). Probably not useful (or legal) outside of align or table environment. However, it must be left this way to let users implement custom environments.'
+    name: 'punctuation.alignment.latex'
+    match: '&'
+  }
+  metaOpenBrace: {
+    contentName: 'meta.group.braces.latex'
+    begin: '{'
+    beginCaptures:
+      0:
+        name: 'punctuation.definition.group.latex'
+    end: '}'
+    endCaptures:
+      0:
+        name: 'punctuation.definition.group.latex'
+    patterns: [
+      comment: 'Optimisation good to implement here. Rework metaComment to be a more general check for escaped characters and comments'
+      {
+        include: '#escapedCharacter' # for an escaped %. Possible deprecated by $base match
+      }
+      { include: '#lineComment' }
+      { include: '$base' }
+    ]
+  }
+  metaCloseBrace: {
+    comment: 'To reach this means unbalanced brackets: THIS IS AN ERROR. I dont care if youre doing fancy file mish-mashing; DONT DO IT.'
+    name: 'invalid.illegal.latex'
+    match: '}'
+  }
+  metaUnderscore: {
+    comment: 'Underscore means subscript. It will take an argument in brackets if possible. If not, just the single next character. Only valid when within mathmode. Will address this later.'
+    patterns: [
+      { include: '#underscoreWithArgument' }
+      { include: '#underscoreNoArgument' }
+    ]
+  }
+  metaCaret: {
+    comment: 'Like underscore, but superscript'
+    patterns: [
+      { include: '#doubleCaret' }
+      { include: '#caretWithArgument' }
+      { include: '#caretNoArgument' }
+    ]
+  }
+  metaHashtag: {
+    comment: 'I dont like calling this the pound symbol. Catcode says it is a parameter identifier.'
+    match: '(\\#{3,}[0-9]+)|(\\#{2}[0-9]+)|(\\#[0-9]+)'
+    captures:
+      1:
+        name: 'variable.parameter.hashtag.3.latex'
+      2:
+        name: 'variable.parameter.hashtag.2.latex'
+      3:
+        name: 'variable.parameter.hashtag.1.latex'
+  }
+
+# Other meta groups
   metaCommonControlSequences: {
     comment: 'This is a collection of control sequences that are given specific rules. The ones here should be common to all users.'
     patterns: [
@@ -60,80 +134,6 @@
       { include: '#envGeneric' }
     ]
   }
-  metaPercent: {
-    comment: 'This is called when there is a lone percent sign (escaped covered by metaControl).'
-    patterns: [
-      { include: '#magicComment' }
-      { include: '#lineComment' }
-    ]
-  }
-  metaDollar: {
-    comment: 'Called when $ sign found. Posiibly deprecated by \( and \) (which is called in metaControl), but here for completeness. The previous statement did not make its meaning very clear.'
-    patterns: [
-      { include: '#displayMathMode' }
-      { include: '#inlineMathMode' }
-    ]
-  }
-  metaTilde: {
-    comment: 'This is only an unbreaking space (when alone).'
-    name: 'punctuation.space.latex'
-    match: '~'
-  }
-  metaAmpersand: {
-    comment: 'The ampersand normally represents alignment (catcode 4). Probably not useful (or legal) outside of align or table environment. However, it must be left this way to let users implement custom environments.'
-    name: 'punctuation.alignment.latex'
-    match: '&'
-  }
-  metaOpenBrace: {
-    contentName: 'meta.group.braces.latex'
-    begin: '{'
-    beginCaptures:
-      0:
-        name: 'punctuation.definition.group.latex'
-    end: '}'
-    endCaptures:
-      0:
-        name: 'punctuation.definition.group.latex'
-    patterns: [
-      comment: 'Optimisation good to implement here. Rework metaComment to be a more general check for escaped characters and comments'
-      {
-        include: '#escapedCharacter' # for an escaped %. Possible deprecated by $base match
-      }
-      { include: '#lineComment' }
-      { include: '$base' }
-    ]
-  }
-  metaCloseBrace: {
-    comment: 'To reach this means unbalanced brackets: THIS IS AN ERROR. I dont care if youre doing fancy file mish-mashing; DONT DO IT.'
-    name: 'invalid.illegal.latex'
-    match: '}'
-  }
-  metaUnderscore: {
-    comment: 'Underscore means subscript. It will take an argument in brackets if possible. If not, just the single next character. Only valid when within mathmode. Will address this later.'
-    patterns: [
-      { include: '#underscoreWithArgument' }
-      { include: '#underscoreNoArgument' }
-    ]
-  }
-  metaCaret: {
-    comment: 'Like underscore, but superscript'
-    patterns: [
-      { include: '#doubleCaret' }
-      { include: '#caretWithArgument' }
-      { include: '#caretNoArgument' }
-    ]
-  }
-  metaHashtag: {
-    comment: 'I dont like calling this the pound symbol. Catcode says it is a parameter identifier.'
-    match: '(\\#{3,}[0-9]+)|(\\#{2}[0-9]+)|(\\#[0-9]+)'
-    captures:
-      1:
-        name: 'variable.parameter.hashtag.3.latex'
-      2:
-        name: 'variable.parameter.hashtag.2.latex'
-      3:
-        name: 'variable.parameter.hashtag.1.latex'
-  }
   metaPrimitives: {
     comment: 'Allows organisation of various primitive sources'
     patterns: [
@@ -158,25 +158,15 @@
     name: 'support.function.general.latex'
     match: '\\\\[a-zA-Z]+'
   }
+  controlWordWithAt: {
+    comment: 'To be used when @ is a letter'
+    name: 'support.function.general.latex'
+    match: '\\\\[a-zA-Z@]+'
+  }
   accents: {
     comment: 'For standard latex accent macros such as \^ or \`. Not used for now, at least until better rules are developed.'
     name: 'constant.character.accent.latex'
     match: '''\\\\([\\`\\'\\^\\"\\~\\=\\.]\\s*(\\w|\\{\\w?\\})|[Hcklbdruv]\\{\\w?\\})'''
-  }
-  hypersetup: {
-    comment: 'Recongnises hypersetup environment. Can be extended to be a general key-option scoper, but this (potentially) allows custom colours for known keys.'
-    name: 'meta.preamble.latex'
-    begin: '\\\\hypersetup(?=[^a-zA-Z@])'
-    beginCaptures:
-      0:
-        name: 'keyword.control.preamble.hypersetup.latex'
-    end: '(?<=\\})|(^\\s*$)'
-    endCaptures:
-      1:
-        name: 'invalid.illegal.latex'
-    patterns: [
-      { include: '#argumentScope' }
-    ]
   }
   lineComment: {
     comment: 'Line comment. This will find an available % sign and match it to just before another % (where it looks for a magic comment) or the end.'
@@ -551,7 +541,7 @@
   }
   makeAtSomething: {
     comment: 'Matches the makeat(letter|other) commands so that they get custom highlighting (because @ is now a character)'
-    contentName: 'markup.raw.verbatim.latex'
+    contentName: 'markup.raw.verbatim.latex' # To make user aware of its effect
     begin: '(\\\\)makeatletter\\b'
     beginCaptures:
       0:
@@ -561,7 +551,8 @@
       0:
         name: 'support.function.makeat.latex'
     patterns: [
-      { include: '#commentMeta' }
+      { include: '#controlWordWithAt' }
+      { include: '$base'}
     ]
   }
   inputFile: {
@@ -671,7 +662,6 @@
     name: 'constant.numeric.latex'
     match: '\\b((\\+|\\-)\\s*)?((\\d+(\\.|\\,)?)|(\\d*((\\.|\\,)\\d*)))\\s*(true\\s*)?(pt|pc|in|bp|cm|mm|dd|cc|sp|em|ex)\\b'
   }
-
   keywords: {
     comment: '''Taken from the TeXBook. Not sorted.
       at, bp, by, cc, cm, dd, depth, em, ex, fil, height, in, l, minus, mm, mu, pc, plus, pt, scaled, sp, spread, to, true, width


Clean up comments

Clean up comments

--- app/javascript/src/classes/note.coffee
+++ app/javascript/src/classes/note.coffee
@@ -108,9 +108,7 @@
       notesManager.noteShowingBody.bodyHide()
     notesManager.noteShowingBody = this
     if notesManager.zindex >= 9
-
-      ### don't use more than 10 layers (+1 for the body, which will always be above all notes) ###
-
+      # don't use more than 10 layers (+1 for the body, which will always be above all notes)
       notesManager.zindex = 0
       i = 0
       while i < notesManager.all.length
@@ -135,9 +133,7 @@
       w = @elements.body.offsetWidth
       h = @elements.body.offsetHeight
       if w / h < 1.6180339887
-
-        ### for tall notes (lots of text), find more pleasant proportions ###
-
+        # for tall notes (lots of text), find more pleasant proportions
         lo = 140
         hi = 400
         loop
@@ -153,9 +149,7 @@
           unless lo < hi and w > last
             break
       else if @elements.body.scrollWidth <= @elements.body.clientWidth
-
-        ### for short notes (often a single line), make the box no wider than necessary ###
-
+        # for short notes (often a single line), make the box no wider than necessary
         # scroll test necessary for Firefox
         lo = 20
         hi = w


Fix translations for WidgetAccountsExpenseWeightCtrl

--- src/components/widgets/accounts-expense-weight/accounts-expense-weight.directive.js.coffee
+++ src/components/widgets/accounts-expense-weight/accounts-expense-weight.directive.js.coffee
@@ -1,6 +1,6 @@
 module = angular.module('impac.components.widgets.accounts-expense-weight',[])

-module.controller('WidgetAccountsExpenseWeightCtrl', ($scope, $q, ChartFormatterSvc, $filter) ->
+module.controller('WidgetAccountsExpenseWeightCtrl', ($scope, $q, ChartFormatterSvc, $filter, $translate) ->

   w = $scope.widget

@@ -38,9 +38,9 @@
   $scope.getComparator = ->
     switch w.metadata.comparator
       when 'turnover'
-        $translate("impac.widget.account_expense_weight.comparator.turnover").then((comparator)-> return comparator)
+        $translate.instant("impac.widget.account_expense_weight.comparator.turnover")
       else
-        $translate("impac.widget.account_expense_weight.comparator.total_exp").then((comparator)-> return comparator)
+        $translate.instant("impac.widget.account_expense_weight.comparator.total_exp")

   # Chart formating function


Sort package settings after core and editor

--- lib/general-panel.coffee
+++ lib/general-panel.coffee
@@ -12,7 +12,14 @@

   initialize: ->
     @loadingElement.remove()
-    @appendSettings(name, settings) for name, settings of atom.config.getSettings()
+
+    settings = atom.config.getSettings()
+    @appendSettings('core', settings.core)
+    delete settings.core
+    @appendSettings('editor', settings.editor)
+    delete settings.editor
+    @appendSettings(name, settings[name]) for name in _.keys(settings).sort()
+
     @bindFormFields()
     @bindEditors()


Comments on email address.

Comments on email address.

--- library/EmailAddress.coffee
+++ library/EmailAddress.coffee
@@ -1,5 +1,4 @@
-EmailAddressPattern = /[-0-9A-Z.+_]+@[-0-9A-Z.+_]+\.[A-Z]{2,20}/i
-
-# miniLock only accepts standards compliant email addresses.
 exports.isAcceptable = (emailAddress) ->
   EmailAddressPattern.test(emailAddress)
+
+EmailAddressPattern = /[-0-9A-Z.+_]+@[-0-9A-Z.+_]+\.[A-Z]{2,20}/i


Remove unused file

Remove unused file


Reordered linters.

Reordered linters.

--- lib/linter-pylama.coffee
+++ lib/linter-pylama.coffee
@@ -118,11 +118,11 @@
         if @skipFiles
           @cmd = "#{@cmd} #{@skipFiles}"
         linters = [
+          @usePyFlakes
           @useMcCabe
           @usePEP8
+          @usePyLint
           @usePEP257
-          @usePyFlakes
-          @usePyLint
         ].join()
         linters = linters.replace /(,+)/g, ','
         linters = linters.replace /(^,+)|(,+$)/g, ''


Fix issue #3.

Fix issue #3.

--- lib/linter-pylama.coffee
+++ lib/linter-pylama.coffee
@@ -9,6 +9,7 @@

 class LinterPylama extends Linter
   @enable: false
+  @pylamaVersion: ''
   @syntax: 'source.python'
   @cmd: ''
   @cfg: null
@@ -31,7 +32,12 @@
   executionCheckHandler: (error, stdout, stderr) =>
     if not @enabled
       versionRegEx = /pylama ([\d\.]+)/
-      if not (versionRegEx.test(stderr) or versionRegEx.test(stdout))
+      if versionRegEx.test(stderr)
+        @pylamaVersion = versionRegEx.exec(stderr)[1]
+      else
+        if versionRegEx.test(stdout)
+          @pylamaVersion = versionRegEx.exec(stdout)[1]
+      if not @pylamaVersion
         result = if error? then '#' + error.code + ': ' else ''
         result += 'stdout: ' + stdout if stdout.length > 0
         result += 'stderr: ' + stderr if stderr.length > 0
@@ -41,7 +47,7 @@
         Please, check executable path in the linter settings."
         return
     @enabled = true
-    log "Linter-Pylama: found pylama " + versionRegEx.exec(stderr)[1]
+    log "Linter-Pylama: found pylama " + @pylamaVersion
     do @initPythonPath
     do @initCmd


removing loop index

removing loop index

--- src/base.iced
+++ src/base.iced
@@ -148,15 +148,12 @@
         await a_json_parse body, esc defer body_json
         await @aget body_json, 'fees', esc defer fees
         currentClearanceMins = 10000
-        idx = 0
         await @aassert Array.isArray(fees), esc defer()
-        while idx < fees.length and currentClearanceMins >= maxClearanceMins
-          fee = fees[idx]
+        for fee in fees when currentClearanceMins >= maxClearanceMins
           await @aget fee, 'maxMinutes', esc defer currentClearanceMins
           await @aget fee, 'maxFee', esc defer currentFee
           await @aassert Number.isFinite(currentClearanceMins), esc defer()
           await @aassert Number.isFinite(currentFee), esc defer()
-          idx++
         cb null, currentFee
       else if resp.statusCode == 429
         cb new Error("API limit has been reached"), 0


Options

Options

- Improved code readability.

--- src/elements/Options/Options.coffee
+++ src/elements/Options/Options.coffee
@@ -419,10 +419,11 @@
 					else
 						el = cb.DOM

-					if cb.isActive() and @_activatable
-						@append(el, "active")
-					else if @_activatable
-						@append(el, "inactive")
+					if @_activatable
+						if cb.isActive()
+							@append(el, "active")
+						else
+							@append(el, "inactive")
 					else
 						@append(el, "center")


JS: Actually call $pager.empty()

JS: Actually call $pager.empty()

--- evesrp/static/js/requestList.coffee
+++ evesrp/static/js/requestList.coffee
@@ -63,7 +63,7 @@
 renderPager = (data, filters) ->
     $pager = jQuery 'ul.pagination'
     numPages = (Math.ceil (data.request_count / pageSize - 1)) + 1
-    $pager.empty
+    $pager.empty()
     if numPages > 1
         $pager.removeClass 'hidden'
         # Prev arrow


Switch from custom timeOffset to more reliable 'moment' library.

--- lib/notifications.coffee
+++ lib/notifications.coffee
@@ -23,19 +23,6 @@
     unit: 'second'
   #OR: 'instant' has no delays, but 'settled' also applies

-@timeOffset = (date, amount, unit) ->
-  date = new Date date  ## copy to avoid in-place modification
-  switch unit
-    when 'second'
-      date.setUTCSeconds amount + date.getUTCSeconds()
-    when 'minute'
-      date.setUTCMinutes amount + date.getUTCMinutes()
-    when 'hour'
-      date.setUTCHours amount + date.getUTCHours()
-    when 'day'
-      date.setUTCDay amount + date.getUTCDay()
-  date
-
 @defaultNotificationsOn = true

 @notificationsDefault = ->
@@ -53,8 +40,8 @@
   delays = user.profile?.notifications?[notification.level] ?
            defaultNotificationDelays[notification.level]
   #xxx batched
-  settleTime = timeOffset dateMax(notification.dates...), delays.settle, delays.unit
-  maximumTime = timeOffset dateMin(notification.dates...), delays.maximum, delays.unit
+  settleTime = moment(dateMax(notification.dates...)).add(delays.settle, delays.unit).toDate()
+  maximumTime = moment(dateMin(notification.dates...)).add(delays.maximum, delays.unit).toDate()
   dateMin settleTime, maximumTime

 ## Notification consists of


Added logger to downloadtrack

Added logger to downloadtrack

--- source/Downloader.coffee
+++ source/Downloader.coffee
@@ -24,6 +24,7 @@
 # Download the given file name from
 # the given url.
 downloadTrack = (name, url) ->
+  winston.info('Called download track.')
   URI =
     url: url
     headers:


Added log on request callback

Added log on request callback

--- source/Downloader.coffee
+++ source/Downloader.coffee
@@ -60,3 +60,4 @@
 scrape = (source) ->
   winston.info('Start scrape for source: ' + source)
   request source, (error, response, html) ->
+    winston('Received answer from server.')


Added calculation of destination path

Added calculation of destination path

--- source/Downloader.coffee
+++ source/Downloader.coffee
@@ -32,3 +32,5 @@
       'Referer': 'http://www.123savemp3.net'
       'User-agent': 'Mozilla/5.0 (Macintosh)'
   winston.info('Created download headers.')
+  destination = './' + name + '.mp3'
+  winston.info('Calculated destination.')


Scene: Add world material loading options to load() and load_objects()

--- engine/scene.coffee
+++ engine/scene.coffee
@@ -306,7 +306,7 @@
         if visible or all
             promise = Promise.all([
                 promise
-                @world_material?.load() or Promise.resolve()
+                @world_material?.load(options) or Promise.resolve()
             ])
         return promise.then(=>this)

@@ -321,13 +321,14 @@
     # @return [Promise]
     load_objects: (list, options={})->
         if not list?.length?
-            throw Error "Invalid arguments, expects (list, options). Did you
+            throw  Error "Invalid arguments, expects (list, options). Did you
                         mean 'load_all_objects()'?"
         # TODO: This may not work the second time is not called.
         # Meshes should always return data's promises
+
         return Promise.all([
             fetch_objects(list, options)
-            @world_material?.load() or Promise.resolve()
+            @world_material?.load(options) or Promise.resolve()
         ]).then(=>@)

     unload_invisible_objects: (options) ->


fixes bug with toggling select/create account when converting lead

--- app/assets/javascripts/crm.js.coffee
+++ app/assets/javascripts/crm.js.coffee
@@ -111,6 +111,7 @@
       $("#account_disabled_title").hide()
       $("#account_create_title").hide()
       $("#account_select_title").show()
+      $("#account_id").show()
       $("#account_name").hide()
       $("#account_name").prop('disabled', true)
       $("#account_id").prop('disabled', false)
@@ -123,6 +124,7 @@
       crm.makeAjaxChosen()
       $("#account_create_title").hide()
       $("#account_select_title").hide()
+      $("#account_id").hide()
       $("#account_disabled_title").show()
       $("#account_name").hide()
       $("#account_name").prop('disabled', true)


Prefer double quotes

Prefer double quotes

--- app/assets/javascripts/global.coffee
+++ app/assets/javascripts/global.coffee
@@ -1,10 +1,9 @@
-
 @fadeAndRemove = (element) ->
   $(element).fadeOut(500, -> $(element).remove())

 @setFocusToField = (element_id) ->
   val = $(element_id).val()
-  $(element_id).focus().val('').val(val)
+  $(element_id).focus().val("").val(val)

 @componentsReady = ->
   themesReady()
@@ -19,7 +18,7 @@
   window.$isDirty = false
   componentsReady()
   extensionsReady()
-  $('[data-object~="form-load"]').submit()
+  $("[data-object~=form-load]").submit()

 # These functions get called on initial page visit and on turbolink page changes
 @turbolinksReady = ->
@@ -52,33 +51,29 @@
 $(window).onbeforeunload = -> return "You haven't saved your changes." if window.$isDirty
 $(document).ready(initialLoadReady)
 $(document)
-  .on('turbolinks:load', turbolinksReady)
-  .on('turbolinks:before-visit', (event) ->
+  .on("turbolinks:load", turbolinksReady)
+  .on("turbolinks:before-visit", (event) ->
     event.preventDefault() if window.$isDirty and !confirm("You haven't saved your changes.")
   )
-  .on('click', '[data-object~="suppress-click"]', -> false)
-  .on('click', '[data-object~="remove-self"]', ->
-    $(this).remove()
+  .on("click", "[data-object~=suppress-click]", -> false)
+  .on("click", "[data-object~=remove-closest]", ->
+    $(this).closest($(this).data("target")).remove()
     false
   )
-  .on('click', '[data-object~="remove-closest"]', ->
-    $(this).closest($(this).data('target')).remove()
+  .on("click", "[data-object~=remove]", ->
+    $($(this).data("target")).remove()
     false
   )
-  .on('click', '[data-object~="remove"]', ->
-    $($(this).data('target')).remove()
+  .on("click", "[data-object~=modal-show]", ->
+    $($(this).data("target")).modal({ dynamic: true })
     false
   )
-  .on('click', '[data-object~="modal-show"]', ->
-    $($(this).data('target')).modal({ dynamic: true })
+  .on("click", "[data-object~=modal-hide]", ->
+    $($(this).data("target")).modal("hide")
     false
   )
-  .on('click', '[data-object~="modal-hide"]', ->
-    $($(this).data('target')).modal('hide')
-    false
-  )
-  .on('click', '[data-object~="submit"]', ->
-    $($(this).data('target')).submit()
+  .on("click", "[data-object~=submit]", ->
+    $($(this).data("target")).submit()
     false
   )
   .on("click", "[data-object~=submit-and-disable]", ->
@@ -86,43 +81,43 @@
     $($(this).data("target")).submit()
     false
   )
-  .on('mouseenter', '[data-object~="hover-show"]', ->
+  .on("mouseenter", "[data-object~=hover-show]", ->
     return false unless document.documentElement.ontouchstart == undefined
-    $('[data-object~="hover-show"]').each( (index, element) ->
-      $($(element).data('target')).hide()
+    $("[data-object~=hover-show]").each( (index, element) ->
+      $($(element).data("target")).hide()
     )
-    $($(this).data('target')).show()
+    $($(this).data("target")).show()
   )
-  .on('mouseleave', '[data-object~="hover-show"]', ->
-    $($(this).data('target')).hide()
+  .on("mouseleave", "[data-object~=hover-show]", ->
+    $($(this).data("target")).hide()
   )
   .keydown( (e) ->
-    if $("#interactive_design_modal").is(':visible')
+    if $("#interactive_design_modal").is(":visible")
       hideInteractiveDesignModal()     if e.which == 27
     if e.which == 77 and not $("input, textarea, select, a").is(":focus")
-      if $('#preview-mode').length == 1 and $('#edit-mode').length == 1 and $('#edit-mode').parent().hasClass('active')
-        $('#preview-mode').click()
+      if $("#preview-mode").length == 1 and $("#edit-mode").length == 1 and $("#edit-mode").parent().hasClass("active")
+        $("#preview-mode").click()
       else
-        $('#edit-mode').click()
+        $("#edit-mode").click()
       e.preventDefault()
       return
   )
-  .on('click', '[data-object~="settings-save"]', ->
+  .on("click", "[data-object~=settings-save]", ->
     window.$isDirty = false
-    $($(this).data('target')).submit()
+    $($(this).data("target")).submit()
     false
   )
-  .on('click', '[data-object~="toggle-visibility"]', ->
-    $($(this).data('target')).toggle()
+  .on("click", "[data-object~=toggle-visibility]", ->
+    $($(this).data("target")).toggle()
     false
   )
-  .on('change', ':input', ->
-    if $("#isdirty").val() == '1'
+  .on("change", ":input", ->
+    if $("#isdirty").val() == "1"
       window.$isDirty = true
   )
-  .on('click', '[data-object~="toggle-delete-buttons"]', ->
-    $($(this).data('target-show')).show()
-    $($(this).data('target-hide')).hide()
+  .on("click", "[data-object~=toggle-delete-buttons]", ->
+    $($(this).data("target-show")).show()
+    $($(this).data("target-hide")).hide()
     false
   )
   .on("wheel", "input[type=number]", ->


Add test to cover #217

Add test to cover #217

--- tests/batman/model/associations/has_many_test.coffee
+++ tests/batman/model/associations/has_many_test.coffee
@@ -216,6 +216,18 @@
       equal products2.length, 1
       QUnit.start()

+asyncTest "hasMany loads after an instance of the related model is saved locally", 2, ->
+  product = new @Product
+    name: "Local product"
+    store_id: 1
+
+  product.save (err, savedProduct) =>
+    @Store.find 1, (err, store) ->
+      products = store.get('products')
+      ok products.has(savedProduct)
+      equal products.length, 4
+      QUnit.start()
+
 QUnit.module "Batman.Model hasMany Associations with inverse of"
   setup: ->
     namespace = {}


permissions fix for deposit lookup

permissions fix for deposit lookup

--- noddy/service/v2/permissions.coffee
+++ noddy/service/v2/permissions.coffee
@@ -78,7 +78,7 @@
         API.log 'Permissions check found in Ricks cache for ' + meta.doi
     if not perms.ricks?
       ru = 'https://api.greenoait.org/permissions/doi/' + meta.doi
-      if uid and uc = API.service.deposit.config(uid)
+      if uid and uc = API.service.oab.deposit.config(uid)
         ru += '?affiliation=' + uc.ROR_ID if uc.ROR_ID
       API.log 'Permissions check connecting to Ricks for ' + ru
       try


Fix included fonts.

Fix included fonts.

--- _assets/javascripts/fonts.coffee
+++ _assets/javascripts/fonts.coffee
@@ -3,8 +3,8 @@
 WebFont.load
   google:
     families: [
+      'Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800:latin,latin-ext'
+      'Roboto:400,100,100italic,300,300italic,400italic,500,500italic,700,700italic,900,900italic'
+      'Inconsolata:400,700:latin,latin-ext'
       'Exo+2:700,400:latin,cyrillic' # for Remodal
-      'Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic,800italic,800:latin,latin-ext'
-      'Inconsolata:400,700:latin,latin-ext'
-      'Roboto:400,300,300italic,500,400italic,500italic,700,700italic:latin'
     ]


line breaks.

line breaks.

--- public/views/product_detail_view.coffee
+++ public/views/product_detail_view.coffee
@@ -57,7 +57,9 @@
       .epages-shop-overlay {
         color: #444;
       }
-      .epages-shop-overlay h1, .epages-shop-overlay h2, .epages-shop-overlay h3 {
+      .epages-shop-overlay h1,
+      .epages-shop-overlay h2,
+      .epages-shop-overlay h3 {
         color: #333;
       }
       .epages-shop-overlay h3 {
@@ -87,10 +89,12 @@
       .epages-shop-overlay-table {
         width: 100%;
       }
-      .epages-shop-overlay-buy-button[disabled=disabled], .epages-shop-overlay-buy-button:disabled {
+      .epages-shop-overlay-buy-button[disabled=disabled],
+      .epages-shop-overlay-buy-button:disabled {
         color: #ddd;
       }
-      .epages-shop-overlay-table th, .epages-shop-overlay-table td {
+      .epages-shop-overlay-table th,
+      .epages-shop-overlay-table td {
         vertical-align: baseline;
         padding: 2px;
       }


Change e to event for clarity

Change e to event for clarity

--- app/assets/javascripts/orders.coffee
+++ app/assets/javascripts/orders.coffee
@@ -61,9 +61,9 @@
   populateCategories category
   $("#new-order-table tbody").append newRow

-$(document).on "click", ".add-item", (e) ->
-  e.preventDefault()
-  e.stopPropagation()
+$(document).on "click", ".add-item", (event) ->
+  event.preventDefault()
+  event.stopPropagation()
   $("#add_inventory_modal").modal("show")

 $(document).on "click", "#add-item-row", (event) ->


make sure to return the right thing in ensureVisible

--- lib/runtime/plots.coffee
+++ lib/runtime/plots.coffee
@@ -19,8 +19,9 @@

   ensureVisible: ->
     p = atom.workspace.getActivePane()
-    @open()
-    p.activate()
+    prom = @open()
+    prom.then(() => p.activate())
+    prom

   show: (view) ->
     @ensureVisible()


default stack change flow is confusing

default stack change flow is confusing

  # this is at best a notification, we shouldn't put this on
  # top of the sidebar as a forcing function. if we do, there should be "hide this" option
  # i'd argue that we should remove this completely for now.
  # users should go to stack catalogue, select whatever stack they like.
  # on top of that, we say "go re-init your default stack", re-init means
  # re-init the current one, this action changes the current with the new
  # default thereby it's very confusing.

cc @sinan

--- client/app/lib/components/sidebarstacksection/sidebardifferentstackresources.coffee
+++ client/app/lib/components/sidebarstacksection/sidebardifferentstackresources.coffee
@@ -11,17 +11,23 @@
   @defaultProps =
     className   : 'SidebarStackWidgets --DifferentStackResources'

-
+  # this is at best a notification, we shouldn't put this on
+  # top of the sidebar as a forcing function. if we do, there should be "hide this" option
+  # i'd argue that we should remove this completely for now.
+  # users should go to stack catalogue, select whatever stack they like.
+  # on top of that, we say "go re-init your default stack", re-init means
+  # re-init the current one, this action changes the current with the new
+  # default thereby it's very confusing.
   render: ->

-          You have different resources in your stacks.
-          Please re-initialize your stacks.
+          Team admin has changed the default stack.
+          Please save your changes and go to Stack Catalog, and reinitialize.

         <Link href='/Stacks'>
-          Show Stacks
+          Stack Catalog
         </Link>


Fix error messages

Fix error messages

--- app/assets/javascripts/upload.coffee
+++ app/assets/javascripts/upload.coffee
@@ -51,7 +51,6 @@
     '/videos/upload'
     "#video-uploadButton-button-actual"
     (data)->
-      console.log data
       data = JSON.parse data.response
       $('#video-wait').hide()
       if data.metadata.mime_type in ['video/mp4']
@@ -75,6 +74,7 @@
       else
         # display error message if  detects wrong mime type
         alert('Falscher MIME-Typ:' + data.metadata.mime_type)
+        $("#video-uploadButton-button-actual").text "Falscher MIME-Typ:" + data.metadata.mime_type
       return
     null
     'upload-video-hidden'
@@ -125,9 +125,11 @@
       else if data.metadata.mime_type != 'application/pdf'
         # display error message if  detects wrong mime type
         alert('Falscher MIME-Typ:' + data.metadata.mime_type, 'error', 5000)
+        $("#manuscript-uploadButton-button-actual").text "Falscher MIME-Typ:" + data.metadata.mime_type
       else
         # display error message if  detects some other problem
         alert('Die Datei ist beschädigt.', 'error', 5000)
+        $("#manuscript-uploadButton-button-actual").text "Datei beschädigt."
       return
     null
     hiddenInput
@@ -173,6 +175,7 @@
         $('#medium-basics-warning').show()
       else if data.metadata.mime_type != 'application/zip'
         alert('Falscher MIME-Typ:' + data.metadata.mime_type, 'error', 5000)
+        $("#geogebra-uploadButton-button-actual").text "Falscher MIME-Typ:" + data.metadata.mime_type
       else
         alert('Die Datei ist beschädigt.', 'error', 5000)
       return
@@ -232,6 +235,8 @@
         $('#image-none').hide()
       else
         alert('Falscher MIME-Typ:' + data.metadata.mime_type)
+        $("#image-uploadButton-button-actual").text "Falscher MIME-Typ:" + data.metadata.mime_type
+
     null
     'upload-image-hidden'
     true
@@ -376,11 +381,11 @@
               uploadedFiles2 = uploadedFiles
               if single
                 uploadedFiles2 = uploadedFiles[0]
-              if successCallback != undefined
-                successCallback(xhr)
               $(progressBarElement).text(
                 $(progressBarElement).data 'tr-success'
               )
+              if successCallback != undefined
+                successCallback(xhr)
               hiddenInput.value = JSON.stringify uploadedFiles2
               fileInput.value = null
               $(progressBarElement)


Fix spreadsheet when no rows

Fix spreadsheet when no rows

Awful stupid terrible coffescript

--- app/assets/volume/spreadsheet.coffee
+++ app/assets/volume/spreadsheet.coffee
@@ -124,7 +124,7 @@
         slots = (container for containerId, container of volume.containers when top != !container.top) # [Row] = Slot
         ### jshint ignore:end ###

-        order = [0..slots.length-1] # Permutation Array of Row in display order
+        order = if slots.length then [0..slots.length-1] else [] # Permutation Array of Row in display order

         records = {}                # [Category_id][Metric_id][Count] :: Data
         counts = new Array(slots.length) # [Row][Category_id] :: Count


Make S3 Key/Secret pair optional.

Make S3 Key/Secret pair optional.

When using Instance Role in AWS, the credentials are unneeded. So
make them optional to use.

--- app/coffee/S3PersistorManager.coffee
+++ app/coffee/S3PersistorManager.coffee
@@ -16,8 +16,8 @@
 buildDefaultOptions = (bucketName, method, key)->
 	return {
 			aws:
-				key: settings.filestore.s3.key
-				secret: settings.filestore.s3.secret
+				key: settings.filestore.s3?.key
+				secret: settings.filestore.s3?.secret
 				bucket: bucketName
 			method: method
 			timeout: thirtySeconds
@@ -28,10 +28,10 @@

 	sendFile: (bucketName, key, fsPath, callback)->
 		s3Client = knox.createClient
-			key: settings.filestore.s3.key
-			secret: settings.filestore.s3.secret
+			key: settings.filestore.s3?.key
+			secret: settings.filestore.s3?.secret
 			bucket: bucketName
-		putEventEmiter = s3Client.putFile fsPath, key, (err, res)->
+		putEventEmitter = s3Client.putFile fsPath, key, (err, res)->
 			if err?
 				logger.err err:err,  bucketName:bucketName, key:key, fsPath:fsPath,"something went wrong uploading file to s3"
 				return callback(err)
@@ -44,8 +44,8 @@
 			LocalFileWriter.deleteFile fsPath, (err)->
 				logger.log res:res,  bucketName:bucketName, key:key, fsPath:fsPath,"file uploaded to s3"
 				callback(err)
-		putEventEmiter.on "error", (err)->
-			logger.err err:err,  bucketName:bucketName, key:key, fsPath:fsPath, "error emmited on put of file"
+		putEventEmitter.on "error", (err)->
+			logger.err err:err,  bucketName:bucketName, key:key, fsPath:fsPath, "error received uploading file to s3"
 			callback err

 	sendStream: (bucketName, key, readStream, callback)->
@@ -62,8 +62,8 @@
 		callback = _.once callback
 		logger.log bucketName:bucketName, key:key, "getting file from s3"
 		s3Client = knox.createClient
-			key: settings.filestore.s3.key
-			secret: settings.filestore.s3.secret
+			key: settings.filestore.s3?.key
+			secret: settings.filestore.s3?.secret
 			bucket: bucketName
 		s3Stream = s3Client.get(key)
 		s3Stream.end()
@@ -76,12 +76,12 @@
 	copyFile: (bucketName, sourceKey, destKey, callback)->
 		logger.log bucketName:bucketName, sourceKey:sourceKey, destKey:destKey, "copying file in s3"
 		s3Client = knox.createClient
-			key: settings.filestore.s3.key
-			secret: settings.filestore.s3.secret
+			key: settings.filestore.s3?.key
+			secret: settings.filestore.s3?.secret
 			bucket: bucketName
 		s3Client.copyFile sourceKey, destKey, (err)->
 			if err?
-				logger.err err:err, bucketName:bucketName, sourceKey:sourceKey, destKey:destKey, "something went wrong copying file in aws"
+				logger.err err:err, bucketName:bucketName, sourceKey:sourceKey, destKey:destKey, "something went wrong copying file in s3"
 			callback(err)

 	deleteFile: (bucketName, key, callback)->
@@ -89,7 +89,7 @@
 		options = buildDefaultOptions(bucketName, "delete", key)
 		request options, (err, res)->
 			if err?
-				logger.err err:err, res:res, bucketName:bucketName, key:key, "something went wrong deleting file in aws"
+				logger.err err:err, res:res, bucketName:bucketName, key:key, "something went wrong deleting file in s3"
 			callback(err)

 	deleteDirectory: (bucketName, key, _callback)->
@@ -100,12 +100,12 @@

 		logger.log key: key, bucketName: bucketName, "deleting directory"
 		s3Client = knox.createClient
-			key: settings.filestore.s3.key
-			secret: settings.filestore.s3.secret
+			key: settings.filestore.s3?.key
+			secret: settings.filestore.s3?.secret
 			bucket: bucketName
 		s3Client.list prefix:key, (err, data)->
 			if err?
-				logger.err err:err, bucketName:bucketName, key:key, "something went wrong listing prefix in aws"
+				logger.err err:err, bucketName:bucketName, key:key, "something went wrong listing prefix in s3"
 				return callback(err)
 			keys = _.map data.Contents, (entry)->
 				return entry.Key
@@ -116,13 +116,13 @@
 		options = buildDefaultOptions(bucketName, "head", key)
 		request options, (err, res)->
 			if err?
-				logger.err err:err, res:res, bucketName:bucketName, key:key, "something went wrong checking file in aws"
+				logger.err err:err, res:res, bucketName:bucketName, key:key, "something went wrong checking file in s3"
 				return callback(err)
 			if !res?
 				logger.err err:err, res:res, bucketName:bucketName, key:key, "no response object returned when checking if file exists"
 				err = new Error("no response from s3 #{bucketName} #{key}")
 				return callback(err)
 			exists = res.statusCode == 200
-			logger.log bucketName:bucketName, key:key, exists:exists, "checked if file exsists in s3"
+			logger.log bucketName:bucketName, key:key, exists:exists, "checked if file exists in s3"
 			callback(err, exists)


completion for string value on tss(style), not perfect

--- lib/styleProvider.coffee
+++ lib/styleProvider.coffee
@@ -13,7 +13,7 @@

 module.exports =
   selector: '.source.css.tss'
-  disableForSelector: '.source.css.tss .comment, .source.css.tss .string'
+  # disableForSelector: '.source.css.tss .comment, .source.css.tss .string'

   # Tell autocomplete to fuzzy filter the results of getSuggestions(). We are
   # still filtering by the first character of the prefix in this provider for
@@ -21,11 +21,14 @@
   filterSuggestions: true

   getSuggestions: (request) ->
+    console.log '=-=====request'
+    console.log request
     completions = null
     scopes = request.scopeDescriptor.getScopesArray()

     # for key & value
     if @isCompletingValue(request)
+      console.log '---value'
       completions = @getPropertyValueCompletions(request)
     # # else if @isCompletingPseudoSelector(request)
     # #   comfpletions = @getPseudoSelectorCompletions(request)
@@ -55,7 +58,7 @@
       sourceEditor = util.getFileEditor related.getTargetPath('xml')
       if(!sourceEditor.isEmpty())
         sourceEditor.scan /id="(.*?)"/g, (item) ->
-          console.log item.match[1]
+          # console.log item.match[1]
           completions.push({
             type: '#'
             text: item.match[1]
@@ -68,6 +71,7 @@
         completions ?= []
         completions = completions.concat(tagCompletions)

+    # console.log completions
     completions

   onDidInsertSuggestion: ({editor, suggestion}) ->
@@ -101,6 +105,7 @@
     previousScopes = editor.scopeDescriptorForBufferPosition(previousBufferPosition)
     previousScopesArray = previousScopes.getScopesArray()

+    console.log (hasScope(scopes, 'meta.property-value.css.tss') and not hasScope(scopes, 'punctuation.terminator.rule.css.tss'))
     (hasScope(scopes, 'meta.property-value.css.tss') and not hasScope(scopes, 'punctuation.terminator.rule.css.tss'))

   isCompletingName: ({scopeDescriptor, bufferPosition, prefix, editor}) ->
@@ -198,7 +203,8 @@
       row--
     return

-  getPropertyValueCompletions: ({bufferPosition, editor, prefix, scopeDescriptor}) ->
+  getPropertyValueCompletions: (request) ->
+    {bufferPosition, editor, prefix, scopeDescriptor} = request
     property = @getPreviousPropertyName(bufferPosition, editor)
     values = @properties[property]?.values
     return null unless values?
@@ -207,11 +213,14 @@

     completions = []
     if @isPropertyValuePrefix(prefix)
-      for value in values when firstCharsEqual(value, prefix)
-        completions.push(@buildPropertyValueCompletion(value, property, scopes))
+      for value in values when firstCharsEqual(value.replace(/\"/g,''), prefix.replace(/\"/g,''))
+        if firstCharsEqual(value, prefix)
+          completions.push(@buildPropertyValueCompletion(value, property, scopes, request))
+        else
+          completions.push(@buildPropertyValueCompletionWidthQuotation(value, property, scopes, request))
     else
       for value in values
-        completions.push(@buildPropertyValueCompletion(value, property, scopes))
+        completions.push(@buildPropertyValueCompletion(value, property, scopes, request))

     # if importantPrefix = @getImportantPrefix(editor, bufferPosition)
     #   # attention: règle dangereux
@@ -225,24 +234,39 @@

     completions

-  buildPropertyValueCompletion: (value, propertyName, scopes) ->
-    text = value
-    text += ','
-
+  buildPropertyValueCompletion: (value, propertyName, scopes, {scopeDescriptor, bufferPosition, prefix, editor}) ->
+    text = "#{value},"
+
     {
       type: 'value'
       text: text
       displayText: value
       description: "#{value} value for the #{propertyName} property"
+    }
+
+  buildPropertyValueCompletionWidthQuotation: (value, propertyName, scopes, {scopeDescriptor, bufferPosition, prefix, editor}) ->
+    text = "#{value}"
+
+    {
+      type: 'value'
+      text: text
+      # snippet: "",
+      displayText: value
+      description: "#{value} value for the #{propertyName} property"
+      replacementPrefix : "\"#{prefix}"
       # leftLabel: 'leftLabel'
       # rightLabel: 'right'
       # descriptionMoreURL: "#{cssDocsURL}/#{propertyName}#Values"
     }
-
+    # completion.replacementPrefix = "#{prefix}" if /^".+?"$/.test(value)
+
+    # if /^".+?"$/.test(value)
+      # completion.replacementPrefix = "\"#{prefix}"
+
   getPropertyNamePrefix: (bufferPosition, editor) ->
     line = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition])
     propertyNamePrefixPattern.exec(line)?[0]
-
+
   getPropertyNameCompletions: ({bufferPosition, editor, scopeDescriptor, activatedManually}) ->
     # Don't autocomplete property names in SASS on root level
     scopes = scopeDescriptor.getScopesArray()


Fix test expectation

Fix test expectation

--- spec/GetHistogram.coffee
+++ spec/GetHistogram.coffee
@@ -41,7 +41,7 @@
       out.once 'endgroup', (group) ->
         groups.pop()
       out.once 'data', (res) ->
-        chai.expect(groups).to.be.eql groupId
+        chai.expect(groups).to.be.eql ['histogram-values']
         chai.expect(res).to.be.deep.equal
         chai.expect(res).to.be.an 'object'
         hists = 'rgbayhslc'


throw unhandled exceptions

throw unhandled exceptions

--- zechat/static/app.coffee
+++ zechat/static/app.coffee
@@ -13,7 +13,7 @@
   app.reqres.setHandler 'root_el', -> $(options.el)

   setup_identity = zc.setup_identity(app)
-  setup_identity.then (fingerprint) ->
+  setup_identity.done (fingerprint) ->
     app.vent.trigger('start')
     app.commands.execute('open-conversation', fingerprint)


cleaning up mkdirp bit.

cleaning up mkdirp bit.

--- src/command.coffee
+++ src/command.coffee
@@ -285,9 +285,7 @@
         if err
           printLine "Could not write source map: #{err.message}"
   exists jsDir, (itExists) ->
-    if itExists then compile() else mkdirp jsDir, (err) =>
-      if err then printLine "Error while creating dir #{jsDir}: #{err}"; exec "mkdir -p #{jsDir}"
-      compile()
+    if itExists then compile() else mkdirp jsDir, compile

 # Convenience for cleaner setTimeouts.
 wait = (milliseconds, func) -> setTimeout func, milliseconds


use childNodes over children

use childNodes over children

--- src/compile.coffee
+++ src/compile.coffee
@@ -204,7 +204,7 @@
       div.innerHTML = element
       aggregate.push(child) for child in div.children
     else if element.nodeName is "#document-fragment"
-      aggregate.push(child) for child in element.children
+      aggregate.push(child) for child in element.childNodes
     else
       aggregate.push(element)
     aggregate


:art: fix spec description

:art: fix spec description

--- spec/grammar-spec.coffee
+++ spec/grammar-spec.coffee
@@ -859,7 +859,7 @@
         registry.decodeTokens(line, tags)

     describe "Thrift", ->
-      it "doesn't loop on this evil example", ->
+      it "doesn't loop infinitely when the same rule is pushed or popped based on a zero-width match", ->
         loadGrammarSync("thrift.cson")
         grammar = registry.grammarForScopeName("source.thrift")


:art: tests

:art: tests

--- spec/grammar-spec.coffee
+++ spec/grammar-spec.coffee
@@ -801,19 +801,18 @@
           expect(tokens[6].scopes).toEqual ["source.json", "meta.structure.dictionary.json", "meta.structure.dictionary.value.json", "constant.numeric.json"]

       describe "when the line contains emoji characters", ->
-
         it "correctly terminates quotes & parses tokens starting after them", ->
           grammar = registry.grammarForScopeName('source.js')

-          withoutEmoji = grammar.tokenizeLine "var emoji = 'http://a'; var after;"
+          withoutEmoji = grammar.tokenizeLine "var emoji = 'xx http://a'; var after;"
           withoutEmojiTokens = registry.decodeTokens(withoutEmoji.line, withoutEmoji.tags)

           withEmoji = grammar.tokenizeLine "var emoji = '💻 http://a'; var after;"
           withEmojiTokens = registry.decodeTokens(withEmoji.line, withEmoji.tags)

           # ignoring this value (the string containing the emoji), they should be identical
-          withoutEmojiTokens[5].value = 'ABC'
-          withEmojiTokens[5].value = 'ABC'
+          delete withoutEmojiTokens[5].value
+          delete withEmojiTokens[5].value

           expect(withEmojiTokens).toEqual(withoutEmojiTokens)


Add specs coverage for new params

Add specs coverage for new params

--- spec/metrics-spec.coffee
+++ spec/metrics-spec.coffee
@@ -62,6 +62,53 @@
     runs ->
       [url] = Reporter.request.mostRecentCall.args
       expect(url).toContain('&aip=1&')
+
+  it "specifies screen resolution", ->
+    waitsForPromise ->
+      atom.packages.activatePackage('metrics')
+
+    waitsFor ->
+      Reporter.request.callCount > 0
+
+    runs ->
+      [url] = Reporter.request.mostRecentCall.args
+      expect(url).toContain("&sr=#{screen.width}x#{screen.height}&")
+
+  it "specifies window resolution", ->
+    waitsForPromise ->
+      atom.packages.activatePackage('metrics')
+
+    waitsFor ->
+      Reporter.request.callCount > 0
+
+    runs ->
+      [url] = Reporter.request.mostRecentCall.args
+      expect(url).toContain("&vp=#{innerWidth}x#{innerHeight}&")
+
+  it "specifies heap usage in MB and %", ->
+    spyOn(process, 'memoryUsage').andReturn {heapTotal: 234567890, heapUsed: 123456789}
+
+    waitsForPromise ->
+      atom.packages.activatePackage('metrics')
+
+    waitsFor ->
+      Reporter.request.callCount > 0
+
+    runs ->
+      [url] = Reporter.request.mostRecentCall.args
+      expect(url).toContain("&cm1=117&")
+      expect(url).toContain("&cm2=53&")
+
+  it "specifies language locale", ->
+    waitsForPromise ->
+      atom.packages.activatePackage('metrics')
+
+    waitsFor ->
+      Reporter.request.callCount > 0
+
+    runs ->
+      [url] = Reporter.request.mostRecentCall.args
+      expect(url).toContain("&ul=en-US&")

   describe "reporting release channel", ->
     beforeEach ->


After 10 seconds timeout show failed to fetch DB list message and provide a link for retry

--- client/landing/app/Applications/Account.kdapplication/account/accSettingsDevDatabases.coffee
+++ client/landing/app/Applications/Account.kdapplication/account/accSettingsDevDatabases.coffee
@@ -64,16 +64,29 @@

   loadItems:(callback)->

-    @_loaderCount = 2
+    dbTypes = ['mysql', 'mongo']
+    @_loaderCount = dbTypes.length
     @showLazyLoader no

     hideLoaderWhenFinished = =>
       @_loaderCount--
       @hideLazyLoader() if @_loaderCount is 0

-    for dbtype in ['mysql', 'mongo']
+    setTimeout =>
+      for i in dbTypes
+        hideLoaderWhenFinished()
+      @scrollView.addSubView timeout = new KDCustomHTMLView
+        cssClass : "lazy-loader"
+        partial  : "Fetching database list failed. Retry"
+        click    : (ins, event)=>
+          if $(event.target).is "a"
+            @loadItems()
+            timeout.destroy()
+    , 10000
+
+    for dbtype in dbTypes
       @talkToKite
-        method      : @commands[dbtype].fetch
+        method    : @commands[dbtype].fetch
         withArgs  :
           dbUser  : KD.whoami().profile.nickname
       , (err, response)=>
@@ -412,9 +425,6 @@
   #   @modal.destroy()

-
-
-
 class AccountDatabaseListItem extends KDListItemView
   constructor:(options = {},data)->


update cart functions

update cart functions

--- assets/coffeescript/pupil_store.coffee
+++ assets/coffeescript/pupil_store.coffee
@@ -47,6 +47,7 @@
       @postalCodeValidator()
       @divisionValidator()
       @eventLoadCart()
+      @eventToggleQuoteType()

   eventStorePageInit: ->
     if $(@storePage).length > 0
@@ -56,7 +57,7 @@
         title_store = get_world_cam_data()[world_id]['title_store']
         klass = if world_id is "w120" then "StoreConfig-world StoreConfig--state-active" else "StoreConfig-world"
         html = "

-                 <button class='#{ klass }' id='#{ world_id }'>#{title_store}</button>
+                 <button class='#{ klass }' id='#{ world_id }'>#{title_store}</button>

"
         $("ul[class='Grid Grid--justifyCenter ConfigOptions--world']").append(html)

@@ -65,10 +66,10 @@
         title_store = get_eye_cam_data()[eye_id]['title_store']
         klass = if eye_id is "e200" then "StoreConfig-eye StoreConfig--state-active" else "StoreConfig-eye"
         html = "

-                 <button class='#{ klass }' id='#{ eye_id }' href='#{}'>#{title_store}</button>
+                 <button class='#{ klass }' id='#{ eye_id }' href='#{}'>#{title_store}</button>

"
         $("ul[class~='ConfigOptions--eye']").append(html)
-
+

       # create vr/ar products
       for vr_ar_id in get_vr_ar_product_ids()
@@ -85,7 +86,7 @@

                     <button id='#{ vr_ar_id }' class='AddToCart Button-store' href='#' data-product='product'>€ #{product.cost}</button>
-
+

"
         $("div[class~='VR-AR-products']").append(html)
@@ -105,7 +106,7 @@

             <button id='#{ p_id }' class='AddToCart Button-store' href='#' data-product='product'>€ #{product.cost}</button>
-
+

"

@@ -133,7 +134,7 @@
                 product_id = ['pupil',worldId,eyeId,licenseId].join("_")
               else
                 product_id = ['pupil',worldId,eyeId].join("_")
-            else
+            else
               product_id = $(addToCartBtn).attr('id')

             # check if the order already exists in the cart
@@ -155,8 +156,8 @@
                 "qty"   : 1
               }
               LocalStorage.set(key, JSON.stringify(item))
-
-            # update the nav counter
+
+            # update the nav counter
             @eventUpdateCartNavCounter()
           else
             return false
@@ -165,15 +166,15 @@
     @clearCartButton.click (event)=>
       event.preventDefault()
       LocalStorage.clear()
-      $(".Cart-container").hide 800, ->
-        $("#Cart-empty").fadeIn(1000)
+      $(".Cart-container").hide 250, ->
+        $("#Cart-empty").fadeIn(300)
       @eventUpdateCartNavCounter()

   eventLoadCart: ->
     if $("#Cart").length > 0
       qty = [v.qty for k,v of LocalStorage.dict()]
       if qty[0].length <= 0
-        $("#Cart-empty").fadeIn(1000)
+        $("#Cart-empty").fadeIn(300)

   eventUpdateCartNavCounter: ->
@@ -198,7 +199,7 @@
         $("#e120b").removeClass("StoreConfig--state-inactive")
         $("#e200b").removeClass("StoreConfig--state-inactive")
         $("#enone").removeClass("StoreConfig--state-inactive")
-        $("#wnone").removeClass("StoreConfig--state-inactive")
+        $("#wnone").removeClass("StoreConfig--state-inactive")

         if $(@worldConfigActiveClass).attr('id') is "wnone"
           $("#specs-world").fadeTo(800,0).prop('disabled',true).css('cursor','default')
@@ -206,7 +207,7 @@
         else
           $("#specs-world").fadeTo(800,100).prop('disabled',false).css('cursor','pointer')
         if $(@eyeConfigActiveClass).attr('id') is "enone"
-          $("#specs-eye").fadeTo(800,0).prop('disabled',true).css('cursor','default')
+          $("#specs-eye").fadeTo(800,0).prop('disabled',true).css('cursor','default')
           $("#wnone").addClass("StoreConfig--state-inactive")
         else
           $("#specs-eye").fadeTo(800,100).prop('disabled',false).css('cursor','pointer')
@@ -247,8 +248,7 @@
           if title_product is "Pupil Headset"
             sub_products = db[v.product]['sub_products']
             for sub_product_key,sub_product_data of sub_products
-              cart_spec_html += "
#{ sub_product_data['title_cart'] }

-
#{ sub_product_data['description_cart'] }
"
+              cart_spec_html += "
#{ sub_product_data['title_cart'] }
"
           else
             cart_spec_html += "
#{ db[v.product]['description_cart'] }
"

@@ -257,28 +257,22 @@

-
"
+
"

           specTxtHtml = "

-
#{ db[v.product]['title_product'] }

+

+
#{ db[v.product]['title_product'] }

+
+

                           #{ cart_spec_html }
+
unit cost: € #{ Number(db[v.product]['cost']) }

"

           costFormulaHtml = "

-

-
€ #{ Number(db[v.product]['cost']) }

-

-

-

-
x

-

-

-
#{ v.qty }

-

@@ -294,16 +288,8 @@
           costSumHtml = "

-

-
=

-

-

€ #{ Number(db[v.product]['cost'] * v.qty) }

-

-
-

-
(remove)

@@ -317,13 +303,16 @@
                           "
" +
                             costFormulaHtml +
                             costSumHtml +
-                          "
" +
-                        "
" +
-
-                      "
" +
-                    "
"
-
-          $("#Cart-table").after(newRow)
+                          "

+

+                        <btn class='Cart-removeItem Grid-cell u-textRight' style='align-self:start;'>
+                          close
+                        </btn>
+

+
"
+
+          $("#Cart-table").append(newRow)
+          # $("#Cart-table").after(newRow)
         [totalPrice,label] = if LocalStorage.length() > 0 then [Number(get_product_database()[v.product].cost * v.qty) for k,v of LocalStorage.dict(),"Subtotal"] else ["",""]
         totalPrice = if totalPrice.length > 0 then "€ " + totalPrice.reduce (a,b) -> a + b
         $("h3[id='CartSum--label']").text("#{ label }")
@@ -334,15 +323,15 @@

   eventRemoveCartItem: ->
     if $(@cartPage).length > 0
-      $("div[class~='Cart-removeItem']").click (event)=>
+      $("btn[class~='Cart-removeItem']").click (event)=>
         event.preventDefault()
         item = $(event.currentTarget)
         row = $(item).closest('.Cart-row')
         container = $(row).closest('.Cart-rowContainer')
         LocalStorage.expire($(row).attr('id'))
-
+
         # remove the row
-        $(container).slideUp 400, ->
+        $(container).slideUp 250, ->
           $(container).remove()

         # update total
@@ -356,8 +345,8 @@
         @eventUpdateCartNavCounter()
         if LocalStorage.length() < 1
           # remove empty cart text
-          $(".Cart-container").hide 600, ->
-            $("#Cart-empty").fadeIn(1000)
+          $(".Cart-container").fadeOut 250, ->
+            $("#Cart-empty").fadeIn(300)

   eventUpdateCartQuantity: ->
     if $(@cartPage).length > 0
@@ -372,7 +361,7 @@

         # get object from local storage
         item = JSON.parse(LocalStorage.get(key))
-        # update quantity
+        # update quantity
         item.qty = if sign is 'plus' then item.qty += 1 else if item.qty > 1 then item.qty -= 1 else 1

         # write quantity back to storage
@@ -384,7 +373,7 @@
         # update row sum
         $(row).find("p[class='Cart--sumRow Cart-costCalc--subTotal']").text("€ " + "#{ Number(get_product_database()[item.product].cost * item.qty) }")

-        # update cart subtotal
+        # update cart subtotal
         totalPrice = if LocalStorage.length() > 0 then (Number(get_product_database()[v.product].cost * v.qty) for k,v of LocalStorage.dict()) else ""
         totalPrice = if totalPrice.length > 0 then "€ " + totalPrice.reduce (a,b) -> a + b
         $("#CartSum--total").text("#{ totalPrice }")
@@ -404,15 +393,15 @@
       $("a[class='TechSpecs']").click (event)=>
         event.preventDefault()
         button = $(event.target)
-
+
         if not $(button).prop('disabled')
           # eye or world from 'id'
-          type = $(button).attr('id').split('-').pop()
+          type = $(button).attr('id').split('-').pop()

           selection = "button[class='StoreConfig-#{type} #{ @storeConfigActiveClass }']"
           id = $(selection).attr('id')
-          # make append active class to container
-          element = "div[class='Grid-cell TechSpecs--#{ type }']"
+          # make append active class to container
+          element = "div[class='Grid-cell TechSpecs--#{ type }']"

           if $(button).hasClass("TechSpecs--active")
             $(element).fadeOut(400)
@@ -426,21 +415,26 @@

   eventShowOrderForm: ->
     if $(@cartPage).length > 0
+      orderFormContainer = "Cart-orderForm-container"
+      $('#OrderType-order').addClass("Button--state-active")
+      $("."+orderFormContainer).css("display","block")
+      $('label[for="form-submit"]').text('Submit Order')
+
       $("input[class='Form-input--radio Form-checkout']").click (event)=>
         event.preventDefault()
         button = $(event.target)
         id = $(button).attr('id')
         submitTxt = if id is "order" then "Submit Order" else "Request Quote"
         labelId = '#OrderType-'+id
-        orderFormContainer = "Cart-orderForm-container"
-        orderFormActive = "Cart-orderForm--state-active"
+
+        orderFormActive = "Cart-orderForm--state-active"
         if not $(labelId).hasClass("Button--state-active")
-          $("label[class^='Button-radio--lg Form-input--radioLabel--lg']").removeClass('Button--state-active')
+          $("label[class^='Button-radio--lg Form-input--radioLabel--lg']").removeClass('Button--state-active')
           $(labelId).addClass("Button--state-active")
           if not $(orderFormContainer).hasClass(orderFormActive)
             $("."+orderFormContainer).slideDown()
             $("."+orderFormContainer).addClass(orderFormActive)
-          $('label[for="form-submit"]').text(submitTxt)
+          $('label[for="form-submit"]').text(submitTxt)

   eventUpdateFormValues: ->
     if $(@cartPage).length > 0
@@ -465,42 +459,62 @@

   eventToggleShippingInfo: ->
     if $(@cartPage).length > 0
-      $("input[id^='s-toggle-']").click (event)=>
+      $("#s-checkbox").click (event)=>
         event.preventDefault()
         button = $(event.target)
-        buttonId = $(button).attr('id')
-        type = buttonId.split("-").pop()
-        if type is "alt"
-          # clear all the values of the inputs
-          $("label[for='#{ buttonId }']").addClass('Button--state-active')
-          $("label[for='s-toggle-copy']").removeClass('Button--state-active')
+
+        if $(button).hasClass('checkmark--active')
+          $(button).toggleClass('checkmark--active')
+          $(".Form-shipping-container").fadeOut(250)
+        else
+          $(button).toggleClass('checkmark--active')
           $("input[id='postalCode_s']")
           .attr("data-parsley-postalcodevalidator","#{$("input[id='postalCode_b']").data('parsley-postalcodevalidator')}")
-          $(".Form-shipping-container").fadeIn()
+          $(".Form-shipping-container").fadeIn(250)
+
+  eventToggleQuoteType: ->
+    $("#q-checkbox").click (event)=>
+      event.preventDefault()
+      button = $(event.target)
+      input = $('#o_type')
+      p_transfer = $("div[for='p-banktransfer']")
+
+      if $(input).val() == 'order'
+        $(button).toggleClass('checkmark--active')
+        $(input).val('quote')
+
+        if $(p_transfer).hasClass('Button--state-active')
+          $(p_transfer).val('purchaseorder')
         else
-          $("label[for='#{ buttonId }']").addClass('Button--state-active')
-          $("label[for='s-toggle-alt']").removeClass('Button--state-active')
-          $(".Form-shipping-container").fadeOut()
+          $(p_transfer).val('banktransfer')
+        # console.log($(p_transfer).val())
+
+      else
+        $(button).toggleClass('checkmark--active')
+        $(input).val('order')

   eventTogglePaymentType: ->
     if $(@cartPage).length > 0
-      radios = "input[name='p-type']:radio"
-      inputPaymentClass = "input[class='Form-input--radio Form-payment-type']"
-      $(inputPaymentClass).click (event)=>
+      paymentButton = $("div[for^='p-']")
+
+      $(paymentButton).click (event)=>
         event.preventDefault()
         button = $(event.target)
-        buttonId = $(button).attr('id')
-        label = "label[for='#{ buttonId }']"
-        $("label[for^='p-']").not($(buttonId)).removeClass('Button--state-active')
-        $(label).toggleClass("Button--state-active")
-
-        $(button).prop("checked",true)
-        # the checked state is not saved for form submission why?
-
-  resetActivePaymentRadio: ->
-    activeId = "#"+$("label[class='Button-radio--sm Form-input--radioLabel Button--state-active'][for^='p-']").attr('for')
-    $(activeId).prop('checked',true)
-
+        buttonId = $(button).attr('for')
+        inputSelector = "input[id='#{ buttonId }']"
+        input_transfer = $('#p-banktransfer')
+        o_input = $('#o_type')
+
+        if !$(button).hasClass('Button--state-active')
+          $(paymentButton).toggleClass('Button--state-active')
+          $(inputSelector).prop("checked",true)
+
+          if $(o_input).val() == 'order'
+            $(input_transfer).val('banktransfer')
+            console.log($(input_transfer).val())
+          else
+            $(input_transfer).val('purchaseorder')
+            console.log($(input_transfer).val())

   eventSubmitForm: ->
     if $(@cartPage).length > 0
@@ -510,21 +524,19 @@
         form = $(event.target)

         if $(form).parsley().isValid()
-          $('label[for="form-submit"]').addClass("Button--state-inactive")
-          $('label[for="form-submit"]').text("Submitting Request")
-          $('label[for="form-submit"]').attr('disabled',true)
+          $('label[for="form-submit"]').addClass("Button--state-inactive")
+          $('label[for="form-submit"]').text("Submitting Request")
+          $('label[for="form-submit"]').attr('disabled',true)
           # add loading animation
-          $('label[for="form-submit"]').addClass("loading")
+          $('label[for="form-submit"]').addClass("loading")

           # disable the submit button to prevent double submits
           $("#form-submit").attr('disabled',true)
-          @resetActivePaymentRadio()
-          @_setOrderType()

           # add countryIso to form data
           $("input[id='countryIso_b']").val(countryList[$("input[id='country_b']").val()].countryISO)
           $("input[id='countryIso_s']").val(countryList[$("input[id='country_s']").val()].countryISO)
-
+
           # add order object to a hidden form text area
           products = []
           keys = [k for k,v in LocalStorage.dict()]
@@ -544,6 +556,8 @@

           formData_formatted_JSON = JSON.stringify(formData_formatted)
           url = "https://p-u-p-i-l.com/order/form_handler"
+
+          console.log(formData_formatted_JSON)

           xhr = new XMLHttpRequest()

@@ -622,7 +636,7 @@
         requirements = requirement.toString().split(',')
         tests = []
         # ideally this should be a function (but can not call/return from fn within this fn)
-        for r in requirements
+        for r in requirements
           exp = '^('
           for c in r.trim().split("")
             fragment = switch
@@ -640,7 +654,7 @@
       )).addMessage 'en', 'postalcodevalidator', 'Postal code should follow the pattern: %s'

   eventGenerateOrderLink: ->
-    if $(@cartPage).length > 0
+    if $(@cartPage).length > 0
       $("#Nav-cart").click (event)=>
         event.preventDefault()
         link = $(event.target)
@@ -658,7 +672,7 @@
       j = 0
       for p,i in pairs by 2
         product_id = decodeURIComponent(decodeURIComponent(pairs.shift().split("=").pop())).split(',')
-
+
         try
           pid = product_id[0]
         catch e
@@ -670,7 +684,7 @@
           if pid.length is 0
             LocalStorage.clear()
             return false
-
+
         # product_id = updateLegacyProductIds_(product_id)
         qty = parseInt(pairs.shift().split("=").pop())
         item = {
@@ -680,7 +694,7 @@
         LocalStorage.set(j, JSON.stringify(item))
         j += 1
       @eventUpdateCartNavCounter()
-
+
   eventOrderLinkSuccessPage: =>
     if $("#Success").length > 0
       data = @_getOrderPermalink()
@@ -689,9 +703,9 @@
       html = "
You can always revisit your order with this #{link}.
"
       $(".Site-content-container.Background-img-caption-container.u-textCenter").append(html)
       # very important - clear LocalStorage after setting the link
-      LocalStorage.clear()
+      LocalStorage.clear()
       @eventUpdateCartNavCounter()
-
+

   _getOrderPermalink: ->
     data = []
@@ -706,7 +720,7 @@

   _setOrderType: ->
     activeId = $("label[id^='OrderType-'][class~='Button--state-active']").attr('id').split('-').pop()
-    $("input[id='o_type']").val(activeId.toLowerCase())
+    $("input[id='o_type']").val('order')

   _setActiveState: (links)->
     for link in links
@@ -725,11 +739,11 @@
     infoTxt = ""
     videoLink = ""

-    for k,v of product.tech_specs
+    for k,v of product.tech_specs
       tableRows += "
#{ k }	#{ v }
"

     if typeof(product.link_video) isnt 'undefined'
-      link = "#{ product.title_video }"
+      link = "#{ product.title_video }"
       videoLink = "
sample video(s)	#{ link }
"

     selector = "div[class='Grid-cell TechSpecs--#{ type }']"
@@ -762,15 +776,15 @@
     product_id = if $("#license").hasClass(@licenseConfigActive) then ['pupil',activeWorldId,activeEyeId,"edu"].join("_") else ['pupil',activeWorldId,activeEyeId].join("_")

     if activeWorldId is "wnone" and activeEyeId is "enone"
-      subTotal = "Not for sale"
+      subTotal = "Not for sale"
       weight = ""
     else if activeWorldId is "w30" and activeEyeId is "e120b"
-      subTotal = "Not for sale"
+      subTotal = "Not for sale"
       weight = ""
     else
       db = get_product_database()
       product = db[product_id]
-      sub_products = product.sub_products
+      sub_products = product.sub_products

       subTotal = "€ " + db[product_id]['cost']
       weight = "weight: " + Number(sub_products['world_camera'].weight + sub_products['eye_camera'].weight) + " grams"
@@ -788,7 +802,7 @@
   _get_key_from_product_id: (id)->
     if LocalStorage.length() > 0
       key = (k for k,v of LocalStorage.dict() when id is v.product)
-      return parseInt(key)
+      return parseInt(key)

 $(document).ready ->
   s = new PupilStore


bug fixes

bug fixes

--- assets/coffeescript/pupil_store.coffee
+++ assets/coffeescript/pupil_store.coffee
@@ -81,8 +81,9 @@
           "quantity": 1
         }
         # save to local storage & update the nav counter
-        @saveToCart(key, item)
+        @saveToCart(JSON.stringify(key), item)
         @eventUpdateCartNavCounter()
+        console.log LocalStorage.raw()

   eventClearCart: ->
     @clearCartButton.click (event)=>
@@ -91,7 +92,8 @@
       @eventUpdateCartNavCounter()

   eventUpdateCartNavCounter: ->
-    $(@cartNavCounter).text("#{ LocalStorage.length() }")
+    counter = if LocalStorage.length() > 0 then LocalStorage.length() else ""
+    $(@cartNavCounter).text("#{ counter }")

   eventUpdateConfig: ->
     if $("#Store").length > 0
@@ -125,12 +127,12 @@
         # product, id, specs, price, quantity
         newRow = "

#{ v['product'] }

#{ v['specs'] }
	#{ v['quantity'] }	#{ v['price'] }	X
"
         $("#Cart-items tbody").append(newRow).addClass("Cart-orderItem")
-      total = if LocalStorage.length() > 0 then @_sumAll((v['price'] for v in LocalStorage.values())) else 0
-      $("td[id='CartSum--total'").text("#{ total }")
+      total = if LocalStorage.length() > 0 then @_sumAll((v['price'] for v in LocalStorage.values())) else ""
+      $("td[id='CartSum--total']").text("#{ total }")

   eventRemoveCartItem: ->
     if $(@cartPage).length > 0
-      $("td[class='Cart-removeItem'").click (event)=>
+      $("td[class='Cart-removeItem']").click (event)=>
         event.preventDefault()
         item = $(event.target)
         tr = $(item).closest('tr')
@@ -141,8 +143,8 @@
           $(tr).remove()

         # update total
-        total = if LocalStorage.length() > 0 then @_sumAll((v['price'] for v in LocalStorage.values())) else 0
-        $("td[id='CartSum--total'").text("#{ total }")
+        total = if LocalStorage.length() > 0 then @_sumAll((v['price'] for v in LocalStorage.values())) else ""
+        $("td[id='CartSum--total']").text("#{ total }")

         # update header
         @eventUpdateCartNavCounter()


Use unless instead of if not

Use unless instead of if not

--- src/db.coffee
+++ src/db.coffee
@@ -12,7 +12,7 @@
   # Returns the connection to the Redis server.
   client: ->
     # If the client object isn't cached, create a new connection.
-    if not @_client
+    unless @_client
       @_client = redis.createClient DB.REDIS_PORT

       # If the client throws an error, attempt to spawn the Redis server.
@@ -31,8 +31,7 @@
     # if it isn't already running.
     #
     # If we don't have a cached client, attempt to connect.
-    if not @_client
-      @_client = redis.createClient DB.REDIS_PORT
+    @_client = redis.createClient DB.REDIS_PORT unless @_client

     # Remove the error handler that will spawn the server.
     @_client.removeListener 'error', @_spawnServerFromError


Switch build status image URL to SVG.

Switch build status image URL to SVG.

--- assets/scripts/app/helpers/urls.coffee
+++ assets/scripts/app/helpers/urls.coffee
@@ -21,7 +21,7 @@
     "https://github.com/#{slug}/settings/hooks#travis_minibucket"

   statusImage: (slug, branch) ->
-    "#{location.protocol}//#{location.host}/#{slug}.png" + if branch then "?branch=#{branch}" else ''
+    "#{location.protocol}//#{location.host}/#{slug}.svg" + if branch then "?branch=#{branch}" else ''

   email: (email) ->
     "mailto:#{email}"


payment: add a quantities field for tracking products-per-plan

--- workers/social/lib/social/models/payment/plan.coffee
+++ workers/social/lib/social/models/payment/plan.coffee
@@ -64,6 +64,9 @@
       group         :
         type        : String
         required    : yes
+      quantities    :
+        type        : Object
+        default     : -> {}

   # * It seems like we're stuffing some JSON into the description field
   #   on recurly.  I think that's a really bad idea, so let's store any


minor grammar fix

minor grammar fix

--- workers/social/lib/social/models/welcomeemail.coffee
+++ workers/social/lib/social/models/welcomeemail.coffee
@@ -11,7 +11,7 @@

   Whether you are starting to learn something or looking to tinker with a new project, we hope that Koding will be able to help you achieve your goals.

-  We have prepared a lot of introductory material over at http://learn.koding.com . There you will find videos and how-to's as well as extensive guides from how to configure servers to installing Drupal, Wordpress, MySQL, MongoDB, etc on your Koding VM.
+  We have prepared a lot of introductory material over at http://learn.koding.com . There you will find videos and how-to's on Koding as well as extensive guides on installing and configuring software packages like Wordpress, MySQL, MongoDB, Joomla, etc.

   Last, but not least, we're improving Koding every day so if you encounter any quirks, just drop us a line at support@koding.com.


fix blank glitch messages again

fix blank glitch messages again

--- scripts/gitter-activity-notifier.coffee
+++ scripts/gitter-activity-notifier.coffee
@@ -101,8 +101,10 @@
                 }
                 if action == "opened"
                     glitchpy.checkPrAssignee(repo, prNum)
+                flag = false
                 if repo in noCheck
                     debouncedMessages.push(message)
+                    flag = true
             else
                 flag = false


observe API embed setting and apply immediatly - fixes #1989

--- packages/rocketchat-oembed/server/server.coffee
+++ packages/rocketchat-oembed/server/server.coffee
@@ -196,5 +196,8 @@

 	return message

-if RocketChat.settings.get 'API_Embed'
-	RocketChat.callbacks.add 'afterSaveMessage', OEmbed.RocketUrlParser, RocketChat.callbacks.priority.LOW
+RocketChat.settings.get 'API_Embed', (key, value) ->
+	if value
+		RocketChat.callbacks.add 'afterSaveMessage', OEmbed.RocketUrlParser, RocketChat.callbacks.priority.LOW, 'API_Embed'
+	else
+		RocketChat.callbacks.remove 'afterSaveMessage', 'API_Embed'


Refactor scheduler tests to use describeFoo pattern

--- specsrc/scheduler.coffee
+++ specsrc/scheduler.coffee
@@ -4,192 +4,202 @@
 {scheduler} = require 'backburner-scheduler'
 {Task} = require 'backburner'

-describe 'a Scheduler instance', ->
-    beforeEach ->
-        scheduler.autostart true
-    describe 'provides exec', ->
+describeScheduler = (schedulerFactory, name) ->
+    scheduler = schedulerFactory()
+    name ?= scheduler.constructor.name
+    if name isnt ''
+        name += ' '
+    describe name + 'implements Scheduler', ->
         beforeEach ->
-            scheduler.killAll()
-
-        it 'should execute passed Tasks when runnable', ->
-            fn1 = trackCalls()
-            task1 = new Task fn1, runnable: true
-            fn2 = trackCalls()
-            task2 = new Task fn2
-
-            runs ->
+            scheduler.autostart true
+        describe 'and provides exec', ->
+            beforeEach ->
+                scheduler.killAll()
+
+            it 'should execute passed Tasks when runnable', ->
+                fn1 = trackCalls()
+                task1 = new Task fn1, runnable: true
+                fn2 = trackCalls()
+                task2 = new Task fn2
+
+                runs ->
+                    scheduler.exec task1
+                    scheduler.exec task2
+                waits 2 * scheduler.period()
+                runs ->
+                    expect(fn1.called).toBe true
+                runs ->
+                    task2.start()
+                waits 2 * scheduler.period()
+                runs ->
+                    expect(fn2.called).toBe true
+
+            it 'should not execute passed Tasks when not runnable', ->
+                fn1 = trackCalls()
+                task1 = new Task fn1, runnable: true
+                fn2 = trackCalls()
+                task2 = new Task fn2
+
+                runs ->
+                    scheduler.exec task1
+                    scheduler.exec task2
+                waits 2 * scheduler.period()
+                runs ->
+                    expect(fn2.called).not.toBe true
+                runs ->
+                    delete fn1.called
+                    task1.stop()
+                waits 2 * scheduler.period()
+                runs ->
+                    expect(fn1.called).not.toBe true
+
+            it 'should start the scheduler when a task is added if autostart is true', ->
+                fn = trackCalls()
+                task = new Task fn, runnable: true
+
+                scheduler.stop()
+                scheduler.autostart true
+                scheduler.exec task
+                expect(scheduler.isRunning()).toBe true
+
+            it 'should not start the scheduler when a task is added if autostart is false', ->
+                fn = trackCalls()
+                task = new Task fn, runnable: true
+
+                scheduler.stop()
+                scheduler.autostart false
+                scheduler.exec task
+                expect(scheduler.isRunning()).not.toBe true
+
+        describe 'and provides kill', ->
+            beforeEach ->
+                scheduler.killAll()
+
+            it 'should kill any tasks passed to it', ->
+                fn1 = trackCalls()
+                task1 = new Task fn1, runnable: true
+                fn2 = trackCalls()
+                task2 = new Task fn2, runnable: true
+
+                runs ->
+                    scheduler.exec task1
+                    scheduler.exec task2
+                waits 2 * scheduler.period()
+                runs ->
+                    scheduler.kill task1, task2
+                    delete fn1.called
+                    delete fn2.called
+                waits 2 * scheduler.period()
+                runs ->
+                    expect(fn1.called).not.toBe true
+                    expect(fn2.called).not.toBe true
+
+            it 'should not kill any tasks not passed to it', ->
+                fn1 = trackCalls()
+                task1 = new Task fn1, runnable: true
+                fn2 = trackCalls()
+                task2 = new Task fn2, runnable: true
+
+                runs ->
+                    scheduler.exec task1
+                    scheduler.exec task2
+                waits 2 * scheduler.period()
+                runs ->
+                    delete fn1.called
+                    delete fn2.called
+                    scheduler.kill task1
+                waits 4 * scheduler.period()
+                runs ->
+                    expect(fn2.called).toBe true
+
+            it 'should reject any killed tasks', ->
+                fn1 = trackCalls()
+                task1 = new Task fn1, runnable: true
+                fn2 = trackCalls()
+                task2 = new Task fn2, runnable: true
+
                 scheduler.exec task1
                 scheduler.exec task2
-            waits 2 * scheduler.period()
-            runs ->
-                expect(fn1.called).toBe true
-            runs ->
-                task2.start()
-            waits 2 * scheduler.period()
-            runs ->
-                expect(fn2.called).toBe true
-
-        it 'should not execute passed Tasks when not runnable', ->
-            fn1 = trackCalls()
-            task1 = new Task fn1, runnable: true
-            fn2 = trackCalls()
-            task2 = new Task fn2
-
-            runs ->
+                scheduler.kill task1, task2
+                waitsFor (-> task1.isRejected() and task2.isRejected()),
+                    'both tasks to be rejected',
+                    WAIT_TIME
+
+            it 'should not reject any unkilled tasks', ->
+                fn1 = trackCalls()
+                task1 = new Task fn1, runnable: true
+                fn2 = trackCalls()
+                task2 = new Task fn2, runnable: true
+
                 scheduler.exec task1
                 scheduler.exec task2
-            waits 2 * scheduler.period()
-            runs ->
-                expect(fn2.called).not.toBe true
-            runs ->
-                delete fn1.called
-                task1.stop()
-            waits 2 * scheduler.period()
-            runs ->
-                expect(fn1.called).not.toBe true
-
-        it 'should start the scheduler when a task is added if autostart is true', ->
-            fn = trackCalls()
-            task = new Task fn, runnable: true
-
-            scheduler.stop()
-            scheduler.autostart true
-            scheduler.exec task
-            expect(scheduler.isRunning()).toBe true
-
-        it 'should not start the scheduler when a task is added if autostart is false', ->
-            fn = trackCalls()
-            task = new Task fn, runnable: true
-
-            scheduler.stop()
-            scheduler.autostart false
-            scheduler.exec task
-            expect(scheduler.isRunning()).not.toBe true
-
-    describe 'provides kill', ->
-        beforeEach ->
-            scheduler.killAll()
-
-        it 'should kill any tasks passed to it', ->
-            fn1 = trackCalls()
-            task1 = new Task fn1, runnable: true
-            fn2 = trackCalls()
-            task2 = new Task fn2, runnable: true
-
-            runs ->
-                scheduler.exec task1
-                scheduler.exec task2
-            waits 2 * scheduler.period()
-            runs ->
-                scheduler.kill task1, task2
-                delete fn1.called
-                delete fn2.called
-            waits 2 * scheduler.period()
-            runs ->
-                expect(fn1.called).not.toBe true
-                expect(fn2.called).not.toBe true
-
-        it 'should not kill any tasks not passed to it', ->
-            fn1 = trackCalls()
-            task1 = new Task fn1, runnable: true
-            fn2 = trackCalls()
-            task2 = new Task fn2, runnable: true
-
-            runs ->
-                scheduler.exec task1
-                scheduler.exec task2
-            waits 2 * scheduler.period()
-            runs ->
-                delete fn1.called
-                delete fn2.called
                 scheduler.kill task1
-            waits 4 * scheduler.period()
-            runs ->
-                expect(fn2.called).toBe true
-
-        it 'should reject any killed tasks', ->
-            fn1 = trackCalls()
-            task1 = new Task fn1, runnable: true
-            fn2 = trackCalls()
-            task2 = new Task fn2, runnable: true
-
-            scheduler.exec task1
-            scheduler.exec task2
-            scheduler.kill task1, task2
-            waitsFor (-> task1.isRejected() and task2.isRejected()),
-                'both tasks to be rejected',
-                WAIT_TIME
-
-        it 'should not reject any unkilled tasks', ->
-            fn1 = trackCalls()
-            task1 = new Task fn1, runnable: true
-            fn2 = trackCalls()
-            task2 = new Task fn2, runnable: true
-
-            scheduler.exec task1
-            scheduler.exec task2
-            scheduler.kill task1
-            waitsFor (-> task1.isRejected()), 'the first task to be rejected', WAIT_TIME
-            expect(task2.isRejected()).toBe false
-
-    describe 'provides killAll', ->
-        beforeEach ->
-            scheduler.killAll()
-
-        it 'should kill all tasks', ->
-            fn1 = trackCalls()
-            task1 = new Task fn1, runnable: true
-            fn2 = trackCalls()
-            task2 = new Task fn2, runnable: true
-
-            runs ->
-                scheduler.exec task1
-                scheduler.exec task2
-            waits 2 * scheduler.period()
-            runs ->
-                scheduler.killAll()
-                delete fn1.called
-                delete fn2.called
-            waits 2 * scheduler.period()
-            runs ->
-                expect(fn1.called).not.toBe true
-                expect(fn2.called).not.toBe true
-
-        it 'should stop the scheduler if autostart is true', ->
-            scheduler.start()
-            scheduler.killAll()
-            expect(scheduler.isRunning()).not.toBe true
-
-        it 'should not stop the scheduler if autostart is false', ->
-            scheduler.autostart(false)
-            scheduler.start()
-            scheduler.killAll()
-            expect(scheduler.isRunning()).toBe true
-
-    describe 'provides start', ->
-        beforeEach ->
-            scheduler.killAll()
-
-        it 'should start the scheduler', ->
-            scheduler.start()
-            expect(scheduler.isRunning()).toBe true
-
-    describe 'provides stop', ->
-        beforeEach ->
-            scheduler.killAll()
-
-        it 'should stop the scheduler', ->
-            scheduler.stop()
-            expect(scheduler.isRunning()).toBe false
-
-    describe 'provides isRunning', ->
-        beforeEach ->
-            scheduler.killAll()
-
-        it 'should return true if the scheduler is running', ->
-            scheduler.start()
-            expect(scheduler.isRunning()).toBe true
-
-        it 'should return false if the scheduler is not running', ->
-            scheduler.stop()
-            expect(scheduler.isRunning()).toBe false
+                waitsFor (-> task1.isRejected()), 'the first task to be rejected', WAIT_TIME
+                expect(task2.isRejected()).toBe false
+
+        describe 'and provides killAll', ->
+            beforeEach ->
+                scheduler.killAll()
+
+            it 'should kill all tasks', ->
+                fn1 = trackCalls()
+                task1 = new Task fn1, runnable: true
+                fn2 = trackCalls()
+                task2 = new Task fn2, runnable: true
+
+                runs ->
+                    scheduler.exec task1
+                    scheduler.exec task2
+                waits 2 * scheduler.period()
+                runs ->
+                    scheduler.killAll()
+                    delete fn1.called
+                    delete fn2.called
+                waits 2 * scheduler.period()
+                runs ->
+                    expect(fn1.called).not.toBe true
+                    expect(fn2.called).not.toBe true
+
+            it 'should stop the scheduler if autostart is true', ->
+                scheduler.start()
+                scheduler.killAll()
+                expect(scheduler.isRunning()).not.toBe true
+
+            it 'should not stop the scheduler if autostart is false', ->
+                scheduler.autostart(false)
+                scheduler.start()
+                scheduler.killAll()
+                expect(scheduler.isRunning()).toBe true
+
+        describe 'and provides start', ->
+            beforeEach ->
+                scheduler.killAll()
+
+            it 'should start the scheduler', ->
+                scheduler.start()
+                expect(scheduler.isRunning()).toBe true
+
+        describe 'and provides stop', ->
+            beforeEach ->
+                scheduler.killAll()
+
+            it 'should stop the scheduler', ->
+                scheduler.stop()
+                expect(scheduler.isRunning()).toBe false
+
+        describe 'and provides isRunning', ->
+            beforeEach ->
+                scheduler.killAll()
+
+            it 'should return true if the scheduler is running', ->
+                scheduler.start()
+                expect(scheduler.isRunning()).toBe true
+
+            it 'should return false if the scheduler is not running', ->
+                scheduler.stop()
+                expect(scheduler.isRunning()).toBe false
+exports.describeScheduler = describeScheduler
+
+describeScheduler ->
+        return scheduler
+    , 'backburner.scheduler'


Issue #66: correct a code style of snippets in the Atom plugin


--- vendor/assets/javascripts/jquery.socialShareButtons.js.coffee
+++ vendor/assets/javascripts/jquery.socialShareButtons.js.coffee
@@ -14,7 +14,7 @@
           ok: '.js-ok'
         containerSelector: '.socials-share-buttons-container'
         url: location.href
-        title: document.title
+        title: $("meta[property='og:title']").attr("content") or document.title
         image: $("meta[property='og:image']").attr("content")
         description: $("meta[name='description']").attr("content")
         isInitScroller: false


Do not fetch sessions for course instances that do not have classrooms

--- app/views/courses/CoursesView.coffee
+++ app/views/courses/CoursesView.coffee
@@ -72,6 +72,7 @@

   onCourseInstancesLoaded: ->
     for courseInstance in @courseInstances.models
+      continue if not courseInstance.get('classroomID')
       courseID = courseInstance.get('courseID')
       courseInstance.sessions = new CocoCollection([], {
         url: courseInstance.url() + '/my-course-level-sessions',


added support for up key

added support for up key

--- app/assets/javascripts/handle_aria_event.js.coffee
+++ app/assets/javascripts/handle_aria_event.js.coffee
@@ -76,18 +76,21 @@

       prev_cell =  $curCell.closest('.row').prev()
       if prev_cell.length
-        $newCell = prev_cell.find(".thumbnails li#row_#{row_number-1}_col_#{col_number}")
+        $newCell = prev_cell.find(".thumbnails li#row_#{parseInt(row_number)-1}_col_#{col_number}")
         if $newCell.length == 0
           $newCell = prev_cell.find(".thumbnails li.span3").last()
         $newCell.attr("tabindex", "0").focus()
         $curCell.removeAttr("tabindex")
       else
         next_cell = $curCell.closest('.row').next()
-        console.log next_cell
+        console.debug next_cell
         if next_cell.length
-          $newCell = prev_cell.find(".thumbnails li#row_#{row_number+1}_col_#{col_number}")
+          $newCell = next_cell.find(".thumbnails li#row_#{parseInt(row_number)+1}_col_#{col_number}")
+          console.log $newCell
+
           if $newCell.length == 0
-            $newCell = prev_cell.find(".thumbnails li.span3").last()
+            $newCell = next_cell.find(".thumbnails li.span3").last()
+
           $newCell.attr("tabindex", "0").focus()
           $curCell.removeAttr("tabindex")
       e.stopPropagation
@@ -116,7 +119,7 @@
       e.stopPropagation
       break

-    when 90 #down
+    when 40 #down

       e.stopPropagation
       break


should only define the js callback if its missing

--- app/assets/javascripts/type_station/init.js.coffee
+++ app/assets/javascripts/type_station/init.js.coffee
@@ -1,14 +1,14 @@
 window.TS.models = new window.TS.Store
 window.TS.editors = new window.TS.Store

-window.TS.onSave = -> null
-window.TS.onSaved = -> null
+window.TS.onSave = -> null unless window.TS['onSave']
+window.TS.onSaved = -> null unless window.TS['onSaved']

-window.TS.onEnable = -> null
-window.TS.onEnabled = -> null
+window.TS.onEnable = -> null unless window.TS['onEnable']
+window.TS.onEnabled = -> null unless window.TS['onEnabled']

-window.TS.onDisable = -> null
-window.TS.onDisabled = -> null
+window.TS.onDisable = -> null unless window.TS['onDisable']
+window.TS.onDisabled = -> null unless window.TS['onDisabled']

 window.TS.getModel = (url) ->
   model = @models.get url


Update ground level for helicopters

Update ground level for helicopters

--- app/scripts/lazerscripts/stage1/heli_attack.coffee
+++ app/scripts/lazerscripts/stage1/heli_attack.coffee
@@ -7,7 +7,7 @@

   spawn: (options) ->
     @dir = options.from ? 'top'
-    @ground = options.ground ? 700
+    @ground = options.ground ? 660
     @corpseKeep = options.corpseKeep ? 10000

     p = Crafty.e('Helicopter').attr(


Don't show higher AI difficulty achievements in victory modal

--- app/views/play/level/modal/HeroVictoryModal.coffee
+++ app/views/play/level/modal/HeroVictoryModal.coffee
@@ -105,6 +105,7 @@
     @showStars()

   onAchievementsLoaded: ->
+    @achievements.models = _.filter @achievements.models, (m) -> not m.get('query')?.ladderAchievementDifficulty  # Don't show higher AI difficulty achievements
     @$el.toggleClass 'full-achievements', @achievements.models.length is 3
     thangTypeOriginals = []
     achievementIDs = []


Make the temporary wesabe.isString et al shortcuts work in Node.js.

--- application/chrome/content/wesabe/lang/type.coffee
+++ application/chrome/content/wesabe/lang/type.coffee
@@ -54,6 +54,7 @@
     object?.constructor is type

 # make all these available as shortcuts on the wesabe object
+wesabe ?= require '../../wesabe'
 for own name, fn of type
   wesabe[name] = logger.wrapDeprecated "wesabe.#{name}", "type.#{name}", fn, type


Fixed port range

Fixed port range

--- server/serversystem/manager.coffee
+++ server/serversystem/manager.coffee
@@ -21,7 +21,7 @@
 launchServer = (serv, lobby)->
   id = idCounter
   idCounter+=1
-  port = Math.floor(Math.random()*27100)+27000
+  port = Math.floor(Math.random()*10000)+27000
   serv.activeLobbies.push
     id: id
     port: port


updated wording

updated wording

--- src/helpers.coffee
+++ src/helpers.coffee
@@ -13,12 +13,12 @@
   sys.pump read, write, ->
     callback()

-# walk through tree and creates directories and copy files
+# walk through tree, creates directories and copy files
 exports.walkTreeAndCopyFiles = (source, destination, callback) ->
   fs.readdir source, (err, files) ->
     return callback err if err

-    # iterates over directory
+    # iterates over current directory
     async.forEach files, (file, next) ->
       return next() if file.match /^\./

@@ -54,7 +54,7 @@
       callback err, paths.sort()

-## copied source from watch_dir, because it did not work as package
+# copied source from watch_dir, because it did not work as package
 exports.watchDirectory = (_opts, callback) ->
   opts = _.extend(
     { path: '.', persistent: true, interval: 500, callOnAdd: false },


remove post page load check for authorization

--- app/client/helpers/router.coffee
+++ app/client/helpers/router.coffee
@@ -192,7 +192,7 @@
 Router.before setTags, except: []

 # this hook will run on almost all routes
-Router.after googleDriveAuthorize, except: []
+#Router.after googleDriveAuthorize, except: []

 Router.after addPageTag, except: ['home']