Removed obsolete text from command line help text

--- src/index.coffee
+++ src/index.coffee
@@ -150,14 +150,13 @@
   yargs = require('yargs')
     .usage('''

-Usage: $0 [--host <hostname>] [--port <portnum>] [--env <envvar>] [--method <logintype>] [--retry <count>] [--ssl] [--plaintext]
+Usage: $0 [--host <hostname>] [--port <portnum>] [--env <envvar>] [--method <logintype>]
+          [--retry <count>] [--ssl] [--plaintext]

 Output: a valid authToken, if successful

 Note: If your Meteor server is older than v0.8.2, you will need to use the --plaintext
-option to authenticate. If it is v0.8.2 or newer, but the account was created on an
-an older server, you should re-authenticate once with a Meteor client to transition
-the account to the post v0.8.2 account format. Otherwise, you must use --plaintext.
+option to authenticate.
 ''')
     .example('', '''


Immediately invoke the touchLocalRootFileAndWait functionality

--- src/index.coffee
+++ src/index.coffee
@@ -86,7 +86,7 @@

   _touchLocalRootFileAndWait: =>
-    @_waitingOnRootFileChangeIntervalId = setInterval =>
+    do fn = =>
       if not @_waitingOnRootFileChange
         return

@@ -104,7 +104,8 @@
       gutil.log "#{retries}Waiting for incoming Listen Data.."

       @_waitingOnRootFileChangeRetries++
-    , 500
+
+    @_waitingOnRootFileChangeIntervalId = setInterval fn, 500

   _touchLocalRootFile: ->
@@ -274,7 +275,5 @@
       callback()

-
-
 module.exports = (options) ->
   new WatchNetwork options


Fix login btn label.

Fix login btn label.

--- app/client/js/react/login.coffee
+++ app/client/js/react/login.coffee
@@ -29,4 +29,4 @@
         firebase.loginViaFacebook()

   @MSG_LOGOUT: goog.getMsg 'Log Out'
-  @MSG_LOGIN: goog.getMsg 'Log In'
+  @MSG_LOGIN: goog.getMsg 'Login with Facebook'


Attempt to fix Issue #3119

Attempt to fix Issue #3119

reddit.com and new.reddit.com had special scrolling properties, but not www.reddit.com. This fix should allow users to scroll properly on reddit's redesign on all addresses.

--- content_scripts/scroller.coffee
+++ content_scripts/scroller.coffee
@@ -327,6 +327,7 @@
   'twitter.com': 'div.permalink-container div.permalink[role=main]'
   'reddit.com': '#overlayScrollContainer'
   'new.reddit.com': '#overlayScrollContainer'
+  'www.reddit.com': '#overlayScrollContainer'

 root = exports ? (window.root ?= {})
 root.Scroller = Scroller


Exclude reposts from conversation views

Exclude reposts from conversation views

--- assets/javascripts/models/post.js.coffee
+++ assets/javascripts/models/post.js.coffee
@@ -112,7 +112,7 @@

     params = _.extend({
       limit: TentStatus.config.PER_CONVERSATION_PAGE
-      post_types: TentStatus.config.post_types
+      post_types: [TentStatus.config.POST_TYPES.STATUS]
     }, options.params || {})

     options.client.get "/posts/#{@get('id')}/mentions", params, {


Add dynamic sortable placeholder height

Add dynamic sortable placeholder height

--- backend/app/assets/javascripts/spree/backend/taxonomy.js.coffee
+++ backend/app/assets/javascripts/spree/backend/taxonomy.js.coffee
@@ -17,9 +17,16 @@
 redraw_tree = ->
   get_taxonomy().done(draw_tree)

+resize_placeholder = (ui) ->
+  handleHeight = ui.helper.find('.sortable-handle').outerHeight()
+  ui.placeholder.height(handleHeight)
+
 @setup_taxonomy_tree = (taxonomy_id) ->
   return unless taxonomy_id?
   taxons_template_text = $('#taxons-list-template').text()
   taxons_template = Handlebars.compile(taxons_template_text)
   Handlebars.registerPartial( 'taxons', taxons_template_text )
   redraw_tree()
+  $('#taxonomy_tree').on
+      sortstart: (e, ui) ->
+        resize_placeholder(ui)


house cleaning

house cleaning

--- app/js/controllers/packet.coffee
+++ app/js/controllers/packet.coffee
@@ -33,27 +33,12 @@

   , (err) ->
     Growl.notice "", "Error occured"
-    # if (err.response.data.error.code == 20010)
-    #     $translate('market.tip.insufficient_balances').then (val) ->
-    #         Growl.notice "", val
-

   # check claim statuses
   $scope.$watch ->
     Wallet.current_account
   , ->
-    # $scope.packet
     $scope.frm_data.to_account_name = Wallet.current_account.name
-
-  # highlight my claimed (my means any account in my wallet)
-  # $scope.$watchCollection ->
-  #   Wallet.accounts
-  # , ->
-  #   my_accounts = []
-  #   my_accounts.push acct.id if acct.id > 0 for k, acct of Wallet.accounts
-  #
-  #   for status in $scope.packet.claimers
-  #     status.claimer.is_mine = my_accounts.indexOf(status.account_id) > -1

   $scope.hide = ->


Add spec for subtraction without spaces.

--- spec/compiler.coffee
+++ spec/compiler.coffee
@@ -1040,6 +1040,17 @@
           }

   parse """
+          [left] == 0-1; // negative via additive expression without spaces
+        """
+        ,
+          {
+            selectors: []
+            commands: [
+              ['eq', ['get', '[left]'], ['minus', ['number', 0], ['number', 1]]]
+            ]
+          }
+
+  parse """
           [left] == -1; // negative without additive expression
         """
         ,


chat: disable preview

chat: disable preview

--- src/smc-webapp/editor_chat.cjsx
+++ src/smc-webapp/editor_chat.cjsx
@@ -686,7 +686,7 @@
         input          : ''
         preview        : ''
         preview_button : false
-        is_preview_on  : true
+        is_preview_on  : false     # all devs reports at that preview is **annoying**, e.g., "trying to type with eyes closed chat preview is so annoying."  I didn't realize this would be the case.

     mark_as_read: ->
         @props.redux.getActions('file_use').mark_file(@props.project_id, @props.path, 'read')


simply replay history

simply replay history

--- spec/protocol.coffee
+++ spec/protocol.coffee
@@ -1,9 +1,10 @@
 server = require '../server'
 expect = require('chai').expect
-sinon = require 'sinon'
 io = require 'socket.io-client'
 BeginOfTest = 0
+InBetween = 0
 MatchId = ""
+History = 0

 #   GCP PROTOCOL SPECIFICATION   *StudioLounge Multiplayer Game*
 #                         v0.4                           (draft)
@@ -54,6 +55,7 @@
       @lukas.send "happy again :-)"
       @anyplayer.on 'message', (msg) ->
         expect(msg).to.equal "Lukas:   happy again :-)"
+        History += 1
       @anotherplayer.on 'message', (msg) ->
         expect(msg).to.equal "Lukas:   happy again :-)"
         done()
@@ -68,7 +70,9 @@

-  describe "MATCHING (players with instances of games)", () ->
+  describe "MATCHING (players with games)", () ->
+
+    InBetween = Date.now()

     it "should allow any logged in player to host games", (done) ->
       @anyplayer.emit 'host', { game: "my.game", min: 2, max: 3}
@@ -77,6 +81,7 @@
         expect(match.min).to.equal 2
         expect(match.max).to.equal 3
         MatchId = match.id # server assigned GUID
+        History += 1
       @lukas.on 'host', (match) ->
         expect(match.host).to.equal "Anyname"
         expect(match.min).to.equal 2
@@ -93,56 +98,51 @@
       @anyplayer.on 'join', (msg) =>
         expect(msg.player).to.equal "Ananda"
         expect(msg.id).to.equal MatchId
+        History += 1
         done()

-  describe "HISTORY (catch up)", ->
+  describe "CUSTOM MESSAGING", () ->

-    it "should tell (the diff) what happened in some meanwhile", (done) ->
-      @anyplayer.emit 'history', { since: Date.now }
-      @anyplayer.on 'history', (diffs) ->
-        expect(diffs).to.deep.equal( {
-          players: [],
-          games: [],
-          match: [],
-          chat: []
-          stats: { player_online: 3, games_played: 1}
-        } # not much happened since now :-)
-
-      @anyplayer.emit 'history', { since: BeginOfTest }
-      @anyplayer.on 'history', (diffs) ->
-        expect(diffs).to.deep.equal( {
-          players: [],
-          games: [],
-          match: [ {
-            id: MatchID
-            min: 2
-            max: 3
-            host: "Anyname"
-            players: ["Ananda"]
-            } ],
-          chat: ["Lukas:   happy again :-)"]
-          stats: { player_online: 3, games_played: 1}
-        }
-
-
+    it "should broadcast game messages among players of a match", (done) ->
+      @anotherplayer.emit 'move', { foo: "my", data: 42 }
+      @anyplayer.on 'move', (msg) =>
+        expect(msg).to.deep.equal( { foo: "my", data: 42 }
+        History += 1
+        done()

-  describe "CUSTOM MESSAGING", () ->
-
-    it "should send custom game messages to everyone in the game", (done) ->
-      @anyplayer.emit 'move', {foo: "my", data: 42}
-      @anotherplayer.on 'move', (msg) =>
-        expect(msg).to.deep.equal( {
-          foo: "my"
-          data: 42
-        }

+  describe "HISTORY (catch up)", ->
+
+    replay = History
+
+    it "should tell no diff if nothing happened", (done) ->
+      @anyplayer.emit 'history', { since: Date.now }
+      setTimeout ( () ->
+        expect(History).to.equal replay # still the same
+        ), 333 #ms
+
+    it "should tell the difference if something happened in between", (done) ->
+      History = 0
+      @anyplayer.emit 'history', { since: InBetween }
+      setTimeout ( () ->
+        expect(History).to.equal 3   # [host, join, move] have been replayed
+        ), 55 #ms
+
+    it "should tell the difference of everything that ever happened", (done) ->
+      History = 0
+      @anyplayer.emit 'history', { since: BeginOfTest }
+      setTimeout ( () ->
+        expect(History).to.equal replay
+        ), 55 #ms
+
+


bad regex fix

bad regex fix

Signed-off-by: Arnaud Richard <791baf8974538c563f287130527dd623cb0e836d@webshell.io>

--- lib/db_apps.coffee
+++ lib/db_apps.coffee
@@ -219,7 +219,7 @@
 		return callback null, true if domain.host == config.url.host
 		for vdomain_str in domains
 			vdomain_str = vdomain_str.replace '*', '.'
-			if not vdomain_str.match /^{1,}:\/\//
+			if not vdomain_str.match /^.{1,}:\/\//
 				vdomain_str = '.://' + vdomain_str
 			vdomain = Url.parse vdomain_str
 			continue if vdomain.protocol != '.:' && vdomain.protocol != domain.protocol


Add test for API key refresh.

Add test for API key refresh.

--- spec/settingsController.coffee
+++ spec/settingsController.coffee
@@ -43,6 +43,19 @@
               data:
                 status: 'OK'
                 characters: []
+          deferred.promise
+
+      spyOn Server, 'refreshApiKey'
+        .and.callFake (key) ->
+          sessionInfo = JSON.parse JSON.stringify fixture.load 'session.json'
+          deferred = $q.defer()
+          if throwError
+            deferred.reject 'ERROR! RUN!!!'
+          else
+            deferred.resolve
+              data:
+                status: 'OK'
+                characters: sessionInfo.apiKeys[0].characters
           deferred.promise

       spyOn Server, 'getLoginStatus'
@@ -112,9 +125,7 @@
       vcode: "abcdefg"
       label: "hijklmnop"
     ctrl.addKey()
-    console.log 'Not yet applied.'
     scope.$apply()
-    console.log 'Applied.'
     expect(ctrl.alerts.length).toEqual 1
     ctrl.closeAlert(0)
     expect(ctrl.alerts.length).toEqual 0
@@ -130,3 +141,20 @@
     scope.$apply()
     expect(ctrl.authenticated).toBeFalsy()
     expect(ctrl.apikeys.length).toEqual 0
+
+  it 'should handle API key refresh', () ->
+    scope.$apply()
+    expect(ctrl.apikeys[0].characters.length).toEqual 2
+    ctrl.apikeys[0].characters = []
+    ctrl.refreshKey(ctrl.apikeys[0])
+    scope.$apply()
+    expect(ctrl.apikeys[0].characters.length).toEqual 2
+
+  it 'should handle API key refresh failure', () ->
+    scope.$apply()
+    throwError = true
+    ctrl.refreshKey(ctrl.apikeys[0])
+    scope.$apply()
+    expect(ctrl.alerts.length).toEqual 1
+    ctrl.closeAlert(0)
+    expect(ctrl.alerts.length).toEqual 0


make commands a Promise

make commands a Promise

--- lib/commander.coffee
+++ lib/commander.coffee
@@ -1,4 +1,5 @@
 Core = require './core'
+Promise = require 'bluebird'
 {log, warn, error} = require './logger'
 {OutOfGoalError, EmptyGoalError, QueryCancelledError} = require './error'

@@ -38,7 +39,7 @@
                 @load()
             else
                 if @loaded
-                    @[method](option)
+                    Promise.resolve @[method](option)
                         .catch OutOfGoalError, @textBuffer.warnOutOfGoal
                         .catch EmptyGoalError, @textBuffer.warnEmptyGoal
                         .catch QueryCancelledError, => console.log 'query cancelled'


:art: Throw error if input isn't string

:art: Throw error if input isn't string

--- lib/helpers.coffee
+++ lib/helpers.coffee
@@ -61,6 +61,7 @@
       regex = xcache.get(rawRegex)
     else
       xcache.set(rawRegex, regex = XRegExp(rawRegex))
+    throw new Error("Input must be a string") unless typeof data is 'string'
     for line in data.split(/\r?\n/)
       match = XRegExp.exec(line, regex)
       if match


use 'not x?' so we don't incorrectly match ""

--- lib/echo-util.coffee
+++ lib/echo-util.coffee
@@ -59,7 +59,7 @@
         throw new Error "invalid name in create_identifier" if not x
         type: syntax.Identifier, name: x
 exports.create_string_literal = (x) ->
-        throw new Error "invalid string in create_string_literal" if not x
+        throw new Error "invalid string in create_string_literal" if not x?
         type: syntax.Literal, value: x, raw: "\"#{x}\""
 exports.create_number_literal = (x) ->
         throw new Error "invalid number '#{x}' (#{typeof x}) in create_number_literal" if typeof x isnt "number"


Use more description variable names instead of path

--- lib/file-view.coffee
+++ lib/file-view.coffee
@@ -32,8 +32,8 @@
         @fileName.addClass('text-icon')

     if git?
-      @subscribe git, 'status-changed', (path, status) =>
-        @updateStatus() if path is @getPath()
+      @subscribe git, 'status-changed', (changedPath, status) =>
+        @updateStatus() if changedPath is @getPath()
       @subscribe git, 'statuses-changed', =>
         @updateStatus()

@@ -43,11 +43,11 @@
     @removeClass('ignored modified new')
     return unless git?

-    path = @getPath()
-    if git.isPathIgnored(path)
+    filePath = @getPath()
+    if git.isPathIgnored(filePath)
       @addClass('ignored')
     else
-      status = git.statuses[path]
+      status = git.statuses[filePath]
       if git.isStatusModified(status)
         @addClass('modified')
       else if git.isStatusNew(status)


Always populate the find box with selection

Closes #135

--- lib/find-view.coffee
+++ lib/find-view.coffee
@@ -131,9 +131,8 @@
     atom.workspaceView.command 'find-and-replace:replace-all', @replaceAll

   showFind: =>
-    unless @findEditor.getText()
-      editor = atom.workspaceView.getActivePaneItem()
-      @findEditor.setText(editor.getSelectedText()) if editor?.getSelectedText?
+    editor = atom.workspaceView.getActivePaneItem()
+    @findEditor.setText(editor.getSelectedText()) if editor?.getSelectedText?

     @attach() if not @hasParent()
     @findEditor.focus()


style(options.coffee): Alphabetize CLI options

--- lib/options.coffee
+++ lib/options.coffee
@@ -3,8 +3,19 @@
 ###

 options =
-  server:
-    description: 'Specify API endpoint to use. The RAML-specified baseUri value will be used if not provided'
+  'generate-hooks':
+    description: 'Output hooks generated from template file and exit'
+    type: 'boolean'
+
+  grep:
+    alias: 'g'
+    description: 'Only run tests matching <pattern>'
+    type: 'string'
+
+  header:
+    alias: 'h'
+    description: 'Add header to include in each request. Header must be in KEY:VALUE format ' +
+      '(e.g., "-h Accept:application/json").\nReuse option to add multiple headers'
     type: 'string'

   hookfiles:
@@ -12,10 +23,20 @@
     description: 'Specify pattern to match files with before/after hooks for running tests'
     type: 'string'

-  schemas:
-    alias: 's'
-    description: 'Specify pattern to match schema files to be loaded for use as JSON refs'
-    type: 'string'
+  'hooks-only':
+    alias: 'H'
+    description: 'Run test only if defined either before or after hooks'
+    type: 'boolean'
+
+  invert:
+    alias: 'i'
+    description: 'Invert --grep matches'
+    type: 'boolean'
+
+  names:
+    alias: 'n'
+    description: 'List names of requests and exit'
+    type: 'boolean'

   reporter:
     alias: 'r'
@@ -23,26 +44,18 @@
     type: 'string'
     default: 'spec'

-  header:
-    alias: 'h'
-    description: 'Add header to include in each request. Header must be in KEY:VALUE format ' +
-      '(e.g., "-h Accept:application/json").\nReuse option to add multiple headers'
+  reporters:
+    description: 'Display available reporters and exit'
+    type: 'boolean'
+
+  schemas:
+    alias: 's'
+    description: 'Specify pattern to match schema files to be loaded for use as JSON refs'
     type: 'string'

-  'hooks-only':
-    alias: 'H'
-    description: 'Run test only if defined either before or after hooks'
-    type: 'boolean'
-
-  grep:
-    alias: 'g'
-    description: 'Only run tests matching <pattern>'
+  server:
+    description: 'Specify API endpoint to use. The RAML-specified baseUri value will be used if not provided'
     type: 'string'
-
-  invert:
-    alias: 'i'
-    description: 'Invert --grep matches'
-    type: 'boolean'

   sorted:
     description: 'Sorts requests in a sensible way so that objects are not ' +
@@ -50,29 +63,16 @@
                  'CONNECT, OPTIONS, POST, GET, HEAD, PUT, PATCH, DELETE, TRACE.'
     type: 'boolean'

-  timeout:
-    alias: 't'
-    description: 'Set test-case timeout in milliseconds'
-    type: 'number'
-    default: 2000
-
   template:
     description: 'Specify template file to use for generating hooks'
     type: 'string'
     normalize: true

-  names:
-    alias: 'n'
-    description: 'List names of requests and exit'
-    type: 'boolean'
-
-  'generate-hooks':
-    description: 'Output hooks generated from template file and exit'
-    type: 'boolean'
-
-  reporters:
-    description: 'Display available reporters and exit'
-    type: 'boolean'
+  timeout:
+    alias: 't'
+    description: 'Set test case timeout in milliseconds'
+    type: 'number'
+    default: 2000

 module.exports = options


Make var clearer

Make var clearer

--- lib/project.coffee
+++ lib/project.coffee
@@ -9,7 +9,7 @@

   # Properties that have been set
   # as to not save default values in DB
-  setProps: []
+  propsToSave: []

   db: null
   projectSettings: null
@@ -18,7 +18,7 @@
     @props = @getDefaultProps()
     if props
       for key, value of props
-        @setProps.push(key) unless key in @setProps
+        @propsToSave.push(key) unless key in @propsToSave
         @props[key] = value

   getDefaultProps: ->
@@ -33,12 +33,12 @@

   set: (key, value) =>
     @props[key] = value
-    @setProps.push(key) unless key in @setProps
+    @propsToSave.push(key) unless key in @propsToSave
     @save()

   unset: (key) ->
     unset(@props[key])
-    unset(@setProps[key])
+    unset(@propsToSave[key])
     @save()

   isCurrent: =>
@@ -66,7 +66,7 @@
   save: =>
     @db ?= new DB()
     props = {}
-    for key, value in @setProps
+    for key, value in @propsToSave
       props[key] = @props[key]

     if @props._id


forgot to make use of generate.enum

forgot to make use of generate.enum

--- index_.coffee
+++ index_.coffee
@@ -6,6 +6,8 @@

 module.exports = generate = (schema, method = 'all', depth = 0) ->
   return schema  unless type(schema) is 'object'
+
+  return generate.enum schema, method, depth  if schema.enum

   switch schema.type
     when 'string', 'number', 'integer', 'boolean', 'array', 'object', 'null'


[➦] Merged changes.

[➦] Merged changes.

--- vendor/assets/javascripts/jquery/plugins/shadify/shady.js.coffee
+++ vendor/assets/javascripts/jquery/plugins/shadify/shady.js.coffee
@@ -236,6 +236,8 @@
         14
       else if offsetWidth > 1440
         16
+      else
+        6

     return


Check non-null return from item match

Check non-null return from item match

--- lib/linter/gc.coffee
+++ lib/linter/gc.coffee
@@ -62,7 +62,9 @@
           unless skippingIndented
             violations[violations.length - 1].message += '\n' + item
         else
-          [_, filePath, line, _, col, msg] = item.match(ERROR_PATTERN)
+          matches = item.match(ERROR_PATTERN)
+          continue unless matches
+          [_, filePath, line, _, col, msg] = matches
           filePath = '/' + filePath
           if filePath isnt @filePath
             skippingIndented = true


Update Templating component to public Jade API

--- src/components/Template.coffee
+++ src/components/Template.coffee
@@ -35,7 +35,8 @@

         @outPorts.out.on "connect", =>
             templating = require @engine
-            @outPorts.out.send templating.render @template, @variables
+            fn = templating.compile @template, @variables
+            @outPorts.out.send fn @variables.locals
             @variables = null
             @outPorts.out.disconnect()


Runtime: Remove obsoleted uploadFBP()

Runtime: Remove obsoleted uploadFBP()

--- lib/runtime.coffee
+++ lib/runtime.coffee
@@ -647,13 +647,6 @@
         catch e
             return callback e

-    uploadFBP: (prog, callback) ->
-        try
-            graph = require('fbp').parse(prog)
-        catch e
-            return callback e
-        @uploadGraph graph, callback
-
 module.exports =
     setupRuntime: setupRuntime
     setupWebsocket: setupWebsocket


update schema

update schema

--- lib/schemas.coffee
+++ lib/schemas.coffee
@@ -152,11 +152,11 @@
       "pattern": /(^urn:[a-zA-Z0-9]{1}[a-zA-Z0-9\-.]+:[a-zA-Z0-9_,=@;!'%/#\(\)\+\-\.\$\*\?]+\/?.+$)/
     },
     "convid" : {
-      "type" : "string",
+      "type" : ["string","null"],
       "description": "The ID of the conversation to which the message belongs."
     },
     "ref" : {
-      "type" : "string",
+      "type" : ["string","null"],
       "description": "Refers to another hMessage msgid. Provide a mechanism to do correlation between messages."
     },
     "type" : {
@@ -164,23 +164,23 @@
       "description": "The type of the message payload."
     },
     "priority" : {
-      "type" : "integer",
+      "type" : ["integer","null"],
       "description": "The priority the hMessage."
     },
     "relevance" : {
-      "type" : "integer",
+      "type" : ["integer","null"],
       "description": "Defines the date (timestamp in milliseconds) until which the message is considered as relevant."
     },
     "persistent" : {
-      "type" : "boolean",
+      "type" : ["boolean","null"],
       "description": "Indicates if the message MUST/MUST NOT be persisted by the middleware."
     },
     "location" : {
-      "type" : "object",
+      "type" : ["object","null"],
       "description": "The geographical location to which the message refer."
     },
     "author" : {
-      "type" : "string",
+      "type" : ["string","null"],
       "description": "The URN of the author (the object or device at the origin of the message)."
     },
     "publisher" : {
@@ -189,19 +189,19 @@
       "pattern": /(^urn:[a-zA-Z0-9]{1}[a-zA-Z0-9\-.]+:[a-zA-Z0-9_,=@;!'%/#\(\)\+\-\.\$\*\?]+\/?.+$)/
     },
     "published" : {
-      "type" : "integer",
+      "type" : ["integer","null"],
       "description": "The date (timestamp in milliseconds) at which the message has been published."
     },
     "headers" : {
-      "type" : "object",
+      "type" : ["object","null"],
       "description": "A Headers object attached to this hMessage. It is a key-value pair map."
     },
     "payload" : {
-      "type" : ["object","string","boolean","number","array"],
+      "type" : ["object","string","boolean","number","array","null"],
       "description": "The content of the message. It can be plain text or more structured data (HTML, XML, JSON, etc.)."
     },
     "timeout" : {
-      "type" : "integer",
+      "type" : ["integer","null"],
       "description": "Define the timeout (ms) to get an answer to the hMessage."
     },
     "sent" : {


conn: format fixes

conn: format fixes

--- client/app/MainApp/monitor_status.coffee
+++ client/app/MainApp/monitor_status.coffee
@@ -162,8 +162,7 @@
       item.run()

 class ExternalPing extends KDObject
-  constructor: (@url) ->
-    super
+  constructor: (@url) -> super

   ping: (callback) ->
     @callback = callback
@@ -174,8 +173,7 @@
       dataType: "jsonp"
       error : ->

-  pong: ->
-    @callback()
+  pong: -> @callback()

 do ->
   url = "https://s3.amazonaws.com/koding-ping/ping.json"


app: minor: code styling

app: minor: code styling

--- client/app/lib/applicationmanager.coffee
+++ client/app/lib/applicationmanager.coffee
@@ -1,15 +1,15 @@
-$ = require 'jquery'
-globals = require 'globals'
-getAppOptions = require './util/getAppOptions'
-getAppClass = require './util/getAppClass'
-kd = require 'kd'
+$                    = require 'jquery'
+globals              = require 'globals'
+kd                   = require 'kd'
 KDModalViewWithForms = kd.ModalViewWithForms
-KDNotificationView = kd.NotificationView
-KDObject = kd.Object
-KDOnOffSwitch = kd.OnOffSwitch
-KDSelectBox = kd.SelectBox
-KDView = kd.View
-FSHelper = require './util/fs/fshelper'
+KDNotificationView   = kd.NotificationView
+KDObject             = kd.Object
+KDOnOffSwitch        = kd.OnOffSwitch
+KDSelectBox          = kd.SelectBox
+KDView               = kd.View
+getAppOptions        = require './util/getAppOptions'
+getAppClass          = require './util/getAppClass'
+FSHelper             = require './util/fs/fshelper'
 KodingAppsController = require './kodingappscontroller'


chat: transfer input focus to message pane

--- client/ide/views/chat/messagepane.coffee
+++ client/ide/views/chat/messagepane.coffee
@@ -16,6 +16,8 @@
     @on 'AddedParticipant', (participant) =>
       channel = @getData()
       channel.emit 'AddedToChannel', participant
+
+    @input.input.on 'focus', (event) => @handleFocus yes, event

   createParticipantsView: ->


Handle putting empty registers

Handle putting empty registers

--- lib/operators.coffee
+++ lib/operators.coffee
@@ -274,7 +274,8 @@
   #
   # Returns nothing.
   execute: (count=1) ->
-    {text, type} = @vimState.getRegister(@register)
+    {text, type} = @vimState.getRegister(@register) || {}
+    return unless text

     _.times count, =>
       if type == 'linewise' and @location == 'after'


Split arrays onto new lines

Split arrays onto new lines

Vertical white space is a godsend.

--- src/robot.coffee
+++ src/robot.coffee
@@ -11,9 +11,21 @@

 inspect = require('util').inspect

-HUBOT_DEFAULT_ADAPTERS = [ 'campfire', 'shell' ]
-HUBOT_DOCUMENTATION_SECTIONS = [ 'description', 'dependencies', 'configuration', 'commands', 'notes', 'author', 'examples', 'urls' ]
-
+HUBOT_DEFAULT_ADAPTERS = [
+  'campfire',
+  'shell'
+]
+
+HUBOT_DOCUMENTATION_SECTIONS = [
+  'description',
+  'dependencies',
+  'configuration',
+  'commands',
+  'notes',
+  'author',
+  'examples',
+  'urls'
+]

 class Robot
   # Robots receive messages from a chat source (Campfire, irc, etc), and


Make {hide: true, admin: false} as default option.

--- src/runas.coffee
+++ src/runas.coffee
@@ -1,7 +1,7 @@
 runas = require('bindings')('runas.node')

 module.exports = (command, args=[], options={}) ->
-  options.hide ?= false
-  options.admin ?= true
+  options.hide ?= true
+  options.admin ?= false

   runas.runas(command, args, options)


Allow use with a non-bot api token

Allow use with a non-bot api token

Some bots should talk like people.

--- src/slack.coffee
+++ src/slack.coffee
@@ -20,7 +20,7 @@
       autoMark: true

     return @robot.logger.error "No services token provided to Hubot" unless options.token
-    return @robot.logger.error "v2 services token provided, please follow the upgrade instructions" unless (options.token.substring(0, 5) == 'xoxb-')
+    return @robot.logger.error "v2 services token provided, please follow the upgrade instructions" unless (options.token.substring(0, 5) in ['xoxb-', 'xoxp-'])

     @options = options


Adds https support for url conversion. Ensures encompassing square brackets that don't break links.

--- src/slack.coffee
+++ src/slack.coffee
@@ -75,7 +75,7 @@

       if hubot_msg
         # Convert markup into plain url string.
-        hubot_msg = hubot_msg.replace(/<((\bhttp)[^|]+)(\|(.*))+>/g, '$1')
+        hubot_msg = hubot_msg.replace(/<((\bhttps?)[^|]+)(\|(.*))+>/g, '< $1 >')

         # Unescape
         hubot_msg = hubot_msg.replace(/&/g, '&')


Less checks for the remainder

Less checks for the remainder

--- lib/read-file.coffee
+++ lib/read-file.coffee
@@ -6,16 +6,6 @@
   while i--
     return i if buffer[i] == char
   -1
-
-concat = (str1, str2) ->
-  if str1? and str2?
-    str1 + str2
-  else if not str1? and not str2?
-    ''
-  else if str1?
-    str1
-  else
-    str2

 headerBuffer = new Buffer(256)
 chunkedBuffer = null
@@ -26,7 +16,7 @@
   fd = fs.openSync(path, "r");
   try
     offset = 0
-    remainder = null
+    remainder = ''
     return if isBinaryFile(headerBuffer, fs.readSync(fd, headerBuffer, 0, 256))

     chunkedBuffer ?= new Buffer(chunkSize)
@@ -42,7 +32,7 @@
         lines = null
       else if index > -1 and index == bytesRead - 1
         # the last char is a newline
-        newRemainder = null
+        newRemainder = ''
         str = chunkedBuffer.toString("utf8", 0, bytesRead - 1)
         lines = str.split('\n')
       else
@@ -51,9 +41,9 @@
         lines = str.split('\n')

       if not lines? or lines.length == 0
-        remainder = concat(remainder, newRemainder)
+        remainder = remainder + newRemainder
       else
-        lines[0] = remainder + lines[0] if remainder?
+        lines[0] = remainder + lines[0] if remainder
         callback(lines, line)
         remainder = newRemainder


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/tween.coffee
+++ src/tween.coffee
@@ -16,6 +16,7 @@
     for property, data of I.activeTweens
       if I.age >= data.endTime
         I[property] = data.end
+        I.activeTweens
         delete I.activeTweens[property]
       else
         f = Easing[data.easing](data.start, data.end)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/tween.coffee
+++ src/tween.coffee
@@ -17,4 +17,5 @@
       I[property] = 10

-  tween: (t, properties) ->
+  tween: (duration, properties) ->
+


Remove jquery dependency in search.coffee

--- coffee/cilantro/ui/concept/search.coffee
+++ coffee/cilantro/ui/concept/search.coffee
@@ -1,8 +1,7 @@
 define [
-    'jquery'
     '../core'
     'tpl!templates/views/concept-search.html'
-], ($, c, template) ->
+], (c, template) ->

     class ConceptSearch extends c.Marionette.ItemView
         className: 'concept-search'
@@ -14,7 +13,7 @@

         onRender: ->
             url = c.data.concepts.url()
-            search = $(@ui.input).typeahead
+            search = c.$(@ui.input).typeahead
                 name: 'Concepts'
                 remote: "#{ url }?q=%QUERY"
                 valueKey: 'label'


cleanup

cleanup

--- coffeescripts/jquery.nanoscroller.coffee
+++ coffeescripts/jquery.nanoscroller.coffee
@@ -134,7 +134,7 @@

       content = @content[0]
       if ($.browser.msie and parseInt($.browser.version, 10) is 7)
-        @content.css({ height: @content.height() })
+        @content.css height: @content.height()
       @contentH  = content.scrollHeight + @scrollW
       @paneH     = @pane.outerHeight()
       @sliderH   = @paneH / @contentH * @paneH


Update HTTP.URI::toString() to call ::toStringWithoutSchemePort()

--- assets/javascripts/http.js.coffee
+++ assets/javascripts/http.js.coffee
@@ -86,11 +86,9 @@

       @isURI = true

-    toString: =>
-      (@scheme + @hostname + ':' + @port + @path).replace(/\/$/, '')
-
+    toString: => @toStringWithoutSchemePort()
     toStringWithoutSchemePort: =>
-      if [443, 80].indexOf(@port) != -1
+      if @port in [443, 80]
         port_string = ''
       else
         port_string = ':' + @port


Other components require template component

--- assets/javascripts/luca-ui.coffee
+++ assets/javascripts/luca-ui.coffee
@@ -1,2 +1,3 @@
 #= require ./luca-ui-base
+#= require ./luca-ui/components/template
 #= require_tree ./luca-ui/components


Use application-specific controller, remove..

..unneeded comment

--- app/assets/javascripts/controllers/hello_world_controller.js.coffee
+++ app/assets/javascripts/controllers/hello_world_controller.js.coffee
@@ -1,11 +1,11 @@
 define [
-  'chaplin'
+  'controllers/base/controller'
   'models/hello_world'
   'views/hello_world_view'
-], (Chaplin, HelloWorld, HelloWorldView) ->
+], (Controller, HelloWorld, HelloWorldView) ->
   'use strict'

-  class HelloWorldController extends Chaplin.Controller
+  class HelloWorldController extends Controller

     title: 'Hello World'

@@ -13,6 +13,5 @@
       ''

     show: (params) ->
-      #console.debug 'HelloWorldController#show'
       @model = new HelloWorld()
       @view = new HelloWorldView model: @model


Remove unnecessary local variable

Remove unnecessary local variable

--- app/assets/javascripts/rglossa/controllers/corpus_controller.coffee
+++ app/assets/javascripts/rglossa/controllers/corpus_controller.coffee
@@ -46,6 +46,6 @@
   # depending on the user's preferences or the default variant
   preferredSearchInterfaceVariant: (->
     engine  = @get('searchEngine')
-    variant = @get('userPreferences.interfaces')?[engine] or
-      @defaultSearchInterfaceVariant[engine]
+    @get('userPreferences.interfaces')?[engine] or @defaultSearchInterfaceVariant[engine]
   ).property('searchEngine', 'userPreferences.interfaces')
+


Improved showing panels

Improved showing panels

--- lib/spark-ide.coffee
+++ lib/spark-ide.coffee
@@ -77,12 +77,8 @@

       return unless protocol is 'spark-ide:'

-      if pathname == '/cloud-variables-and-functions'
-        @CloudVariablesAndFunctions ?= require './views/cloud-variables-and-functions-view'
-        @cloudVariablesAndFunctionsView = new @CloudVariablesAndFunctions()
-
-        return @cloudVariablesAndFunctionsView
-
+      @initView pathname.substr(1) + '-view'
+
   deactivate: ->
     @statusView?.destroy()

@@ -100,7 +96,9 @@
       className += _s.capitalize part

     @[className] ?= require './views/' + name
-    @[className.charAt(0).toLowerCase() + className.slice(1)] ?= new @[className]()
+    key = className.charAt(0).toLowerCase() + className.slice(1)
+    @[key] ?= new @[className]()
+    @[key]

   # "Decorator" which runs callback only when user is logged in
   loginRequired: (callback) ->
@@ -140,7 +138,7 @@
         pane = atom.workspaceView.getActivePaneView().splitDown()
       else
         paneViews = atom.workspaceView.getPaneViews()
-        pane = paneViews[paneViews.length]
+        pane = paneViews[paneViews.length - 1]

       pane.activate()
       atom.workspace.open(uri, searchAllPanes: true)


Show a more useful stub when there's no track loaded yet

--- assets/front.coffee
+++ assets/front.coffee
@@ -290,8 +290,8 @@
 				artist = document.getElementById('artist'+tag)
 				if artist
 					artist.innerHTML = ""
-					document.getElementById('length'+tag).innerHTML = ""
-					# document.getElementById('story'+tag).innerHTML = ""
+					document.getElementById('length'+tag).innerHTML = "Loading..."
+					document.getElementById('story'+tag).innerHTML = "We're still loading info for that track, sit tight! :)"
 				else
 					break
 	setTimeout getTrackInfo, 1000


Include full-text searches into analytics

--- src/views.coffee
+++ src/views.coffee
@@ -456,6 +456,8 @@
                 query = $.trim search_el.val()
                 results.search query,
                     success: =>
+                        if _paq?
+                            _paq.push ['trackSiteSearch', query, false, results.models.length]
                         @show_search_results results
                 # For console debugging
                 window.debug_search_results = results


Add autoRetrieve property

Add autoRetrieve property

--- client/lanes/models/Query.coffee
+++ client/lanes/models/Query.coffee
@@ -172,6 +172,7 @@
         idIndex: 'number'
         initialFieldIndex: 'number'
         pageSize: 'number'
+        autoRetrieve: ['bool', true, true]

     derived:
         results:
@@ -194,9 +195,9 @@
             @idIndex = @fields.length
             @fields.add(id: idName)
         @clauses = new Clauses([], query: this )
-        this.listenTo(@clauses, 'change remove reset', ->
+        this.listenTo(@clauses, 'change remove reset', =>
             @results.reset()
-            this.trigger('change', arguments...)
+            @results.ensureLoaded() if this.autoRetrieve
         )
         if @initialFieldIndex
             @initialField = this.fields.at(@initialFieldIndex)
@@ -206,9 +207,6 @@
         this.addNewClause()
         this

-    execute: ->
-        this.trigger('execute')
-
     isValid: ->
         ! @clauses.findWhere( isValid: false )


allow drag onto file

allow drag onto file

--- lib/tree-view.coffee
+++ lib/tree-view.coffee
@@ -1024,12 +1024,11 @@
     @list.classList.contains('multi-select')

   onDragEnter: (e) =>
-    if header = e.target.closest('.entry.directory > .header')
+    if entry = e.target.closest('.entry.directory')
       return if @rootDragAndDrop.isDragging(e)

       e.stopPropagation()

-      entry = header.parentNode
       @dragEventCounts.set(entry, 0) unless @dragEventCounts.get(entry)
       unless @dragEventCounts.get(entry) isnt 0 or entry.classList.contains('selected')
         entry.classList.add('drag-over', 'selected')
@@ -1037,12 +1036,11 @@
       @dragEventCounts.set(entry, @dragEventCounts.get(entry) + 1)

   onDragLeave: (e) =>
-    if header = e.target.closest('.entry.directory > .header')
+    if entry = e.target.closest('.entry.directory')
       return if @rootDragAndDrop.isDragging(e)

       e.stopPropagation()

-      entry = header.parentNode
       @dragEventCounts.set(entry, @dragEventCounts.get(entry) - 1)
       if @dragEventCounts.get(entry) is 0 and entry.classList.contains('drag-over')
         entry.classList.remove('drag-over', 'selected')
@@ -1094,7 +1092,7 @@

   # Handle entry dragover event; reset default dragover actions
   onDragOver: (e) ->
-    if entry = e.target.closest('.entry')
+    if entry = e.target.closest('.entry.directory')
       return if @rootDragAndDrop.isDragging(e)

       e.preventDefault()
@@ -1106,13 +1104,11 @@
   # Handle entry drop event
   onDrop: (e) ->
     @dragEventCounts = new WeakMap
-    if entry = e.target.closest('.entry')
+    if entry = e.target.closest('.entry.directory')
       return if @rootDragAndDrop.isDragging(e)

       e.preventDefault()
       e.stopPropagation()
-
-      return unless entry.classList.contains('directory')

       newDirectoryPath = entry.querySelector('.name')?.dataset.path
       return false unless newDirectoryPath


Added functionality to focus parent folder on deletion

--- lib/tree-view.coffee
+++ lib/tree-view.coffee
@@ -414,6 +414,9 @@
     dialog.attach()

   removeSelectedEntries: ->
+    parents = _.uniq(_.map(@selectedPaths(),  (path) ->
+      return path.substring(0, path.lastIndexOf('/'))
+    ))
     if @hasFocus()
       selectedPaths = @selectedPaths()
     else if activePath = @getActivePath()
@@ -430,9 +433,10 @@
         message: "Are you sure you want to delete the selected #{if selectedPaths.length > 1 then 'items' else 'item'}?"
         detailedMessage: "You are deleting:\n#{selectedPaths.join('\n')}"
         buttons:
-          "Move to Trash": ->
+          "Move to Trash": =>
             for selectedPath in selectedPaths
               shell.moveItemToTrash(selectedPath)
+            @selectEntry(@list.find("[data-path='#{parents[0]}']").parents('li').first()?[0])
           "Cancel": null

   # Public: Copy the path of the selected entry element.


Don't need to intercept Enter key in code blocks because Shift+Enter works?

--- client/views/admin/editor.coffee
+++ client/views/admin/editor.coffee
@@ -16,8 +16,8 @@
       buttons:
         ['bold', 'italic', 'underline', 'anchor', 'pre', 'header1', 'header2', 'orderedlist', 'unorderedlist', 'quote', 'image']
       onShowToolbar: =>
+        # Disable medium toolbar if we are in a code block
         if @inPreformatted()
-          console.log 'preformatted'
           editor.toolbar.hideToolbar()

@@ -69,15 +69,7 @@
         #embeds: {}
     ###

-    editor.subscribe 'editableKeydownEnter', (e, el) =>
-      if e.which is 13 and @inPreformatted()
-        console.log 'in preformatted'
-        e.preventDefault()
-        editor.disableReturn = true
-        document.execCommand 'insertHTML', false, "\n"
-      else
-        editor.disableReturn = false
-
+
     $editable.data 'mediumEditor', editor
     editor

@@ -87,8 +79,8 @@
     @init.apply @, arguments

     # Don't let the medium insert plugin submit the form
-    $('form').on 'click', (event) ->
-      if $(event.target).is '.mediumInsert' then event.preventDefault();
+    #$('form').on 'click', (event) ->
+      #if $(event.target).is '.mediumInsert' then event.preventDefault();

   # Return medium editor's contents
   contents: ->
@@ -133,32 +125,3 @@
       unless current
         break
     false
-
-  # Disable medium toolbar if we are in a code block
-  ###
-  checkSelection: ->
-    if @inPreformatted()
-      return false
-
-    super()
-
-  # Disable "hard" returns if we are in a code block
-  bindParagraphCreation: (index) ->
-    @elements[index].addEventListener 'keyup', (e) =>
-      if e.which is 13 and @inPreformatted()
-        e.preventDefault()
-        @options.disableReturn = true
-      else
-        @options.disableReturn = false
-
-    super index
-
-  # Insert "soft" returns always if we are in a code block
-  bindReturn: (index) ->
-    @elements[index].addEventListener 'keypress', (e) =>
-      if e.which is 13 and @inPreformatted()
-        e.preventDefault()
-        document.execCommand 'insertHTML', false, "\n"
-
-    super index
-  ###


add times()

add times()

--- matrix.coffee
+++ matrix.coffee
@@ -5,3 +5,6 @@
       for el, i in col
         B[j][i] = f(el)
     B
+
+  times: (s, A, B) ->
+    this.map(((x) -> s*x), A, B)


implement first version of the run function

--- src/zuvor.coffee
+++ src/zuvor.coffee
@@ -337,27 +337,57 @@
   ###################################################################################
   # run

-  run = (options) ->
-    options.call =
-    options.graph =
-    options.exclude =
-    options.isStrict =
-    options.ids
-
-  ###################################################################################
-  # module
-
-  zuvor =
-    Graph: Graph
-    Set: Set
-    run: run
-
-  ###################################################################################
-  # nodejs or browser?
-
-  if window?
-    window.zuvor = zuvor
-  else if module?.exports?
-    module.exports = zuvor
-  else
-    throw new Error 'either the `window` global or the `module.exports` global must be present'
+  zuvor.run = (options) ->
+    unless 'function' is typeof options.callback
+      throw new TypeError 'options.callback must be a Function'
+
+    options.done ?= new Set
+    unless options.done instanceof Set
+      throw new TypeError 'options.done must be a Set'
+
+    options.pending ?= new Set
+    unless options.pending instanceof Set
+      throw new TypeError 'options.pending must be a Set'
+
+    if options.graph? and not options.graph instanceof Graph
+      throw new TypeError 'options.graph must be a Graph'
+
+    options.strict ?= false
+    options.reversed ?= false
+
+    if options.debug? and not 'function' is typeof options.debug
+      throw new TypeError 'options.debug must be a Function'
+
+    results = {}
+
+    start = (names) ->
+      valid = new Set(names).delete(options.pending).delete(options.done)
+      options.pending.add valid
+      Promise.all valid.keys().map (id) ->
+        # TODO pass in results of parents
+        promise = Promise.resolve options.callback id
+        promise.then (value) ->
+          options.pending.delete id
+          options.done.add id
+          results[id] = value
+
+          candidates = if options.reversed
+            options.graph.whereAllChildrenIn(options.done.keys())
+          else
+            options.graph.whereAllParentsIn(options.done.keys())
+
+          # start all we can start now that have not been started
+          next = new Set(candidates)
+            .delete(options.pending)
+            .delete(options.done)
+            .keys()
+          start next
+
+    # TODO we can start all those that are not in the graph
+    #
+    # if not strict ignore those in the graph that are not in ids
+
+    start if options.reversed
+      options.graph.childless()
+    else
+      options.graph.parentless()


Tokenizing is getting functional!

Tokenizing is getting functional!

--- server/lib/tokenizer.coffee
+++ server/lib/tokenizer.coffee
@@ -3,8 +3,8 @@

   # change the type of the token before emitting it
   "phoneComLog" if match.type is "word" and token is "appel"
-  "phoneComLog" if match.type is "word" and token is "appelé"
-  "phoneComLog" if match.type is "word" and token is "appelée"
+  "phoneComLog" if match.type is "word" and token is "appele"
+  "phoneComLog" if match.type is "word" and token is "appelee"

 )
 #template
@@ -17,7 +17,7 @@
 t.addRule /^"[^"]*$/, "maybe citation"

 # REFERENCES TO SELF
-t.addRule /^ai-je\s$/i, "moi"
+t.addRule /^je$/i, "moi"
 t.addRule /^m'a$/i, "moi"
 t.addRule /^j'ai$/i, "moi"
 t.addRule /^je$/i, "moi"
@@ -25,29 +25,55 @@
 # Ponctuation

 # REFERENCES TO OTHERS
-t.addRule /^qui\s$/,"contact"
+t.addRule /^qui$/i,"contact"

 # PHONE COMMUNICATIONS
+t.addRule /^appele$/,"phoneComLog"
+t.addRule /^appelee$/,"phoneComLog"
+t.addRule /^appel$/,"phoneComLog"
+
+

 # TEMPORAL OBJECTS
 ## Years
 t.addRule /^\d{4}$/,"year"
-t.addRule /^en(\s)(\d{4})$/,"givenYear"
+t.addRule /^en(\d{4})$/,"givenYear"
 t.addRule /^cette(\s)annee$/,"currentYear"
 t.addRule /^l'annee(\s)derniere$/,"lastYear"
 ## Months
+t.addRule /^janvier$/,"month"
+t.addRule /^fevrier$/,"month"
+t.addRule /^mars$/,"month"
+t.addRule /^avril/,"month"
+t.addRule /^mai$/,"month"
+t.addRule /^juin$/,"month"
+t.addRule /^juillet$/,"month"
+t.addRule /^aout$/,"month"
+t.addRule /^septembre$/,"month"
+t.addRule /^octobre$/,"month"
+t.addRule /^novembre$/,"month"
+t.addRule /^decembre$/,"month"
+
+
 ## Days
 ## Specific date : le 17-03-1997
 t.addRule /^(le(\s)\d{1,2})-(\d{1,2})-(\d{4})$/,"specificDate"

+## BLACKLIST
+t.addRule /^ai$/,"blacklist"
+
+
 # if it's a word and it's not been matched yet it's probably a name
-t.addRule /^\w+$/, "contact"
+# wording for now
+t.addRule /^\w+$/, "word"
 t.addRule /^(\s)+$/, "whitespace"
+t.ignore /^(\s)+$/, "whitespace"
 t.addRule /^[',;.:!?-]$/, "ponctuation"

 unless module.parent
     #t.addRule /^salut$/i, "salut"
     t.on 'token', (tok) -> console.log tok
-    t.write "qui ai-je appele en 2013"
+    #t.write "qui ai-je appele en 2013"
+    t.write "qui ai-je appele en juin 2014"
     t.end()


Fixes based on reviews

Fixes based on reviews

--- components/dia/kddiascene.coffee
+++ components/dia/kddiascene.coffee
@@ -22,7 +22,7 @@

   diaAdded:(container, diaObj)->
     diaObj.on "JointRequestsLine",   @bound "handleLineRequest"
-    diaObj.on "DragInAction",        => @setActiveDia diaObj
+    diaObj.on "DragInAction",        => @highlightLines diaObj
     diaObj.on "RemoveMyConnections", => @disconnect diaObj

   addContainer:(container, pos = {})->
@@ -30,7 +30,7 @@

     container.on "NewDiaObjectAdded", @bound "diaAdded"
     container.on "DragInAction",      @bound "updateScene"
-    container.on "HighlightDia",      @bound "setActiveDia"
+    container.on "HighlightDia",      @bound "highlightLines"

     @containers.push container

@@ -56,7 +56,7 @@

   click:(e)->
     return if e.target isnt e.currentTarget
-    @setActiveDia()
+    @highlightLines()

   mouseMove:(e)->
     return  unless @_trackJoint
@@ -97,10 +97,12 @@
       break  if dia = container.dias[objId]
     return {dia, joint, container}

-  setActiveDia:(dia=[], update=yes)->
+  highlightLines:(dia=[], update=yes)->
     if not Array.isArray dia then dia = [dia]
     @activeDias = dia
-    @deselectAllDias()
+    joint.off 'DeleteRequested'      for joint in @activeJoints
+    container.emit 'UnhighlightDias' for container in @containers
+    @activeJoints = []
     @updateScene()  if update
     return  unless @activeDias.length is 1

@@ -117,11 +119,6 @@
               joint.on 'DeleteRequested', @bound 'disconnectHelper'
               @activeJoints.push joint

-  deselectAllDias:->
-    joint.off 'DeleteRequested'      for joint in @activeJoints
-    container.emit 'UnhighlightDias' for container in @containers
-    @activeJoints = []
-
   handleLineRequest:(joint)->
     @_trackJoint = joint

@@ -140,7 +137,7 @@
         connectionsToDelete.push conn

     @connections = (c for c in @connections when c not in connectionsToDelete)
-    @setActiveDia @activeDias
+    @highlightLines @activeDias

   disconnect:(dia)->

@@ -151,7 +148,7 @@
         newConnections.push connection
     @connections = newConnections

-    @setActiveDia()
+    @highlightLines()

   connect:(source, target)->
     return  unless source and target
@@ -162,7 +159,7 @@
                      to #{target.dia.constructor.name} is not allowed!"""

     @connections.push {source, target}
-    @setActiveDia target.dia
+    @highlightLines target.dia

   allowedToConnect:(source, target)->
     for i in [0..1]
@@ -202,11 +199,11 @@
       [sx, sy, tx, ty] = [0, 0, 0, 0]
       if source.joint in ["top", "bottom"]
         sy = if source.joint is "top" then -cd else cd
-      if source.joint in ["left", "right"]
+      else if source.joint in ["left", "right"]
         sx = if source.joint is "left" then -cd else cd
       if target.joint in ["top", "bottom"]
         ty = if target.joint is "top" then -cd else cd
-      if target.joint in ["left", "right"]
+      else if target.joint in ["left", "right"]
         tx = if target.joint is "left" then -cd else cd

       @realContext.bezierCurveTo(sJoint.x + sx, sJoint.y + sy, \


:wrench: open file on selection (and close last)

--- atom/package.coffee
+++ atom/package.coffee
@@ -4,6 +4,7 @@
 projects = require '../src/observables/projects.coffee'
 vdomTree = require '../src/observables/vdom-tree.coffee'
 rootNode = require '../src/observables/root-node.coffee'
+Path = require 'path'

 module.exports =
   panel: undefined
@@ -69,6 +70,10 @@
     @subscriptions.push bodyHeightBus.debounce(500).onValue (newHeight) ->
       atom.config.set('atom-notational.bodyHeight', newHeight)

+    @subscriptions.push selectedItemBus.onValue (item) ->
+      atom.workspace.getActivePaneItem()?.destroy()
+      atom.workspace.open Path.join(item.projectPath, item.relPath), searchAllPanes: true
+
     terminateProjectsProp = projectsProp.sampledBy(@deactivateBus)
     terminateProjectsProp.onValue (projects) ->
       for { task } in projects


Support optional parameters in custom command autocomplete parsing

--- lib/autocomplete/command.coffee
+++ lib/autocomplete/command.coffee
@@ -109,8 +109,7 @@
           counts: 1
       else
         items[result[1]].counts += 1
-      # Parse custom user-defined commands with fixed number of parameters TODO: optional parameters
-    newCommandReg = /\\(?:re|provide)?(?:new)?command(?:{)?\\(\w+)(?:})?(?:\[([0-9]+)\]{)?/g
+    newCommandReg = /\\(?:re|provide)?(?:new)?command(?:{)?\\(\w+)(?:})?(?:\[([0-9])\]|\[[0-9]\]\[\]{)?/g
     loop
       result = newCommandReg.exec content
       break if !result?


Draw annulus different on IE

Draw annulus different on IE

--- bokehjs/src/coffee/renderer/glyph/annulus.coffee
+++ bokehjs/src/coffee/renderer/glyph/annulus.coffee
@@ -23,18 +23,29 @@
         continue

       # Because this visual has a whole in it, it proved "challenging"
-      # for some browsers to render if drawn naively --- i.e. it did not
-      # work on IE. Instead we render in two parts (upper and lower part),
-      # thus making it unambiguous what part should be filled. The line is
+      # for some browsers to render if drawn in one go --- i.e. it did not
+      # work on IE. If we render in two parts (upper and lower part),
+      # it is unambiguous what part should be filled. The line is
       # better drawn in one go though, otherwise the part where the pieces
       # meet will not be fully closed due to aa.

+      # Detect Microsoft browser. Might need change for newer versions.
+      isie = (navigator.userAgent.indexOf('MSIE') >= 0 ||
+              navigator.userAgent.indexOf('Trident') > 0 ||
+              navigator.userAgent.indexOf('Edge') > 0)
+
       if @visuals.fill.do_fill
         @visuals.fill.set_vectorize(ctx, i)
         ctx.beginPath()
-        for clockwise in [false, true]
-            ctx.arc(sx[i], sy[i], sinner_radius[i], 0, Math.PI, clockwise)
-            ctx.arc(sx[i], sy[i], souter_radius[i], Math.PI, 0, !clockwise)
+        if isie
+            # Draw two halves of the donut. Works on IE, but causes an aa line on Safari.
+            for clockwise in [false, true]
+                ctx.arc(sx[i], sy[i], sinner_radius[i], 0, Math.PI, clockwise)
+                ctx.arc(sx[i], sy[i], souter_radius[i], Math.PI, 0, !clockwise)
+        else
+            # Draw donut in one go. Does not work on iE.
+            ctx.arc(sx[i], sy[i], sinner_radius[i], 0, 2 * Math.PI, true)
+            ctx.arc(sx[i], sy[i], souter_radius[i], 2 * Math.PI, 0, false)
         ctx.fill()

       if @visuals.line.do_stroke


early stage app

early stage app

--- src/bootstrap.coffee
+++ src/bootstrap.coffee
@@ -9,34 +9,60 @@
 csrgen = Promise.promisify require 'csr-gen'
 request = Promise.promisify require 'request'

-module.exports = ->
-	# Load config file
-	userConfig = require('/boot/config.json')
-
-	version = utils.getSupervisorVersion()
-
+registerDevice = (apiKey, userId, applicationId) ->
 	# I'd be nice if the UUID matched the output of a SHA-256 function, but although the length limit of the CN
 	# attribute in a X.509 certificate is 64 chars, a 32 byte UUID (64 chars in hex) doesn't pass the certificate
 	# validation in OpenVPN This either means that the RFC counts a final NULL byte as part of the CN or that the
 	# OpenVPN/OpenSSL implementation has a bug.
 	uuid = crypto.pseudoRandomBytes(31).toString('hex')
+	request(
+		method: 'POST'
+		url: url.resolve(config.apiEndpoint, '/ewa/device?apikey=' + apiKey)
+		json:
+			user: userId
+			application: applicationId
+			uuid: uuid
+			'device_type': 'Raspberry Pi'
+	).spread (response, body) ->
+		if response.statusCode != 201
+			throw new Error('Device registration to resin failed. body: ' + body + '. status code: ' + response.statusCode)
+		else
+			return uuid

-	# Generate SSL certificate
-	keys = csrgen(uuid,
-		company: 'Rulemotion Ltd'
-		csrName: 'client.csr'
-		keyName: 'client.key'
-		outputDir: '/data'
-		email: 'vpn@resin.io'
-		read: true
-		country: ''
-		city: ''
-		state: ''
-		division: ''
-	)
+module.exports = ->
+	# Load config file
+	userConfig = require('/boot/config.json')

-	Promise.all([keys, version])
-	.then ([keys, version]) ->
+	new Promise (resolve, reject) ->
+		if not userConfig.uuid?
+			registerDevice(userConfig.apiKey, userConfig.userId, userConfig.applicationId)
+			.then (uuid) ->
+				userConfig.uuid = uuid
+				resolve(uuid)
+			.catch (err) ->
+				reject(err)
+		else
+			uuid = userConfig.uuid
+			resolve(uuid)
+	.then (uuid) ->
+		version = utils.getSupervisorVersion()
+
+		# Generate SSL certificate
+		keys = csrgen(uuid,
+			company: 'Rulemotion Ltd'
+			csrName: 'client.csr'
+			keyName: 'client.key'
+			outputDir: '/data'
+			email: 'vpn@resin.io'
+			read: true
+			country: ''
+			city: ''
+			state: ''
+			division: ''
+		)
+
+		return [keys, version, uuid]
+	.spread (keys, version, uuid) ->
 		console.log('UUID:', uuid)
 		console.log('User ID:', userConfig.userId)
 		console.log('User:', userConfig.username)
@@ -50,7 +76,7 @@
 		userConfig.version = version
 		return request(
 			method: 'POST'
-			url: url.resolve(config.apiEndpoint, 'associate')
+			url: url.resolve(config.apiEndpoint, 'sign_certificate?apikey=' + userConfig.apiKey)
 			json: userConfig
 		)
 	.spread (response, body) ->
@@ -73,12 +99,11 @@
 			knex('config').truncate()
 			.then ->
 				knex('config').insert([
-					{ key: 'uuid', value: uuid }
+					{ key: 'uuid', value: userConfig.uuid }
 					{ key: 'apiKey', value: userConfig.apiKey }
 					{ key: 'username', value: userConfig.username }
 					{ key: 'userId', value: userConfig.userId }
-					{ key: 'version', value: version }
+					{ key: 'version', value: userConfig.version }
 				])
 			knex('app').truncate()
 		])
-	.return(uuid)


Небольшая оптимизация

Небольшая оптимизация

--- src/chocolate.coffee
+++ src/chocolate.coffee
@@ -2,7 +2,7 @@

 existActions = ['next', 'prev', 'close']

-isHistory    = not not (window.history and history.pushState)
+isHistory = not not (window.history and history.pushState)
 # isFullscreen = document.webkitRequestFullScreen || document.mozRequestFullScreen
 # test = document.getElementById 'choco-overlay'
 # if test.webkitRequestFullScreen
@@ -70,7 +70,7 @@

   getImageFromUri: ->
     hash = window.location.hash
-    if hash then parseInt hash.replace('#image', ''), 10 else 0
+    if hash then toInt hash.replace('#image', '') else 0

   ###
    Добавляем список изображений для работы в галереи
@@ -203,6 +203,7 @@
     else
       after.call @, cid

+
   ###
    Обновление размеров блока с главным изображением
   ###
@@ -211,8 +212,8 @@

     thumbnails = if not @options.thumbnails or @thumbnails.css('display') is 'none' then 0 else @thumbnails.height()

-    horizontal = parseInt(@overlay.css('padding-left'), 10) + parseInt(@overlay.css('padding-right'), 10)
-    vertical   = parseInt(@overlay.css('padding-top'), 10) + parseInt(@overlay.css('padding-bottom'), 10)
+    horizontal = toInt(@overlay.css('padding-left')) + toInt(@overlay.css('padding-right'))
+    vertical   = toInt(@overlay.css('padding-top')) + toInt(@overlay.css('padding-bottom'))

     innerWidth   = window.innerWidth
     windowWidth  = innerWidth - horizontal
@@ -227,20 +228,30 @@
       width  = windowHeight * width / height
       height = windowHeight

-    left = parseInt width / 2, 10
-    top  = parseInt height / 2, 10
-    top += parseInt thumbnails / 2, 10 if thumbnails > 0
+    left = toInt width / 2
+    top  = toInt height / 2
+    top += toInt thumbnails / 2 if thumbnails > 0
     top += 20 if title

-    style = 'width': (innerWidth / 2 - left) + 'px', 'height': innerHeight + 'px'
+    style =
+      'width':  (innerWidth / 2 - left) + 'px'
+      'height': innerHeight + 'px'

     @leftside.css  style
     @rightside.css style

-    style = 'width': width, 'height': height, 'margin-left': '-' + left + 'px', 'margin-top': '-' + top + 'px'
+    style =
+      'width':       width
+      'height':      height
+      'margin-left': '-' + left + 'px'
+      'margin-top':  '-' + top + 'px'

     if title
-      @header.css 'display': 'block', 'width': width, 'margin-left': '-' + left + 'px', 'padding-top': parseInt((height - 100) / 2, 10) + 'px'
+      @header.css
+        'display':     'block'
+        'width':       width
+        'margin-left': '-' + left + 'px'
+        'padding-top': toInt((height - 100) / 2) + 'px'
     else
       @header.css 'display': 'none'

@@ -267,7 +278,7 @@
                          .replace('{{title}}', if image.title then ' title="' + image.title + '"' else '')

     @thumbnails.html(content).find('.choco-thumbnail').click (event) ->
-      _this.updateImage parseInt $(@).attr('data-cid'), 10
+      _this.updateImage toInt $(@).attr('data-cid')

     @overlay.find('.choco-thumbnails-toggle').click (event) ->
       method = if _this.thumbnails.hasClass 'hide' then 'removeClass' else 'addClass'
@@ -278,6 +289,8 @@
       _this.updateDimensions current.width, current.height

     @
+
+toInt = (string) -> parseInt string, 10

 # Экспорт в глобальное пространство
 window.chocolate = Chocolate


Clampable#clampToBounds

Clampable#clampToBounds

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -18,5 +18,5 @@
         max: bounds.width - I.width/2
       y:
         min: bounds.y + I.height/2
-        max:
+        max: bounds.height - I.he


Clampable#clampToBounds

Clampable#clampToBounds

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -13,4 +13,5 @@
     bounds ||= Rectangle x: 0, y: 0, width: App.width, height: App.height

     self.clamp "x",
-      min: bounds.x+      min: bounds.x
+      max:


bug fix

bug fix

Signed-off-by: Manson Li <f2a598d7717cc6757bef28b84a9ab02e5efc6048@matchstick.tv>

--- lib/dial/session/Session.coffee
+++ lib/dial/session/Session.coffee
@@ -19,7 +19,7 @@
 class Session

     constructor: (@sessionManager, @token, @appId) ->
-        if not sessionManager
+        if not @sessionManager
             Log.e "cannot create a ReceiverSession with a null SessionManager!!!"
             throw new Error "cannot create a ReceiverSession with a null SessionManager!!!"


beautify

beautify

--- src/color/rgb.coffee
+++ src/color/rgb.coffee
@@ -71,7 +71,7 @@

 class RgbCS
-  constructor: (@white, @red, @green, @blue, @g) ->
+  constructor: (@red, @green, @blue, @white, @g) ->
     @gInv = 1 / g
     # assume: white.Y = 1
     @fromXYZ = (XYZ, T) ->
@@ -83,7 +83,7 @@
       @toXYZ Rgb, T

   init: ->
-    if not @baseXYZ?
+    if not @base?
       # create xyz base (luminance is unknown => need to multiply each column by a scalar)
       bxyz = M [
             @red.x         ,     @green.x           ,     @blue.x
@@ -103,6 +103,7 @@

       delete @toXYZ
       delete @fromXYZ
+      return

   gamma: (x) ->
     pow(x, @g)
@@ -127,8 +128,8 @@
     T

 # public api
-module.exports = (white) ->
-  new RgbCS(white)
+module.exports = (red, green, blue, white, g) ->
+  new RgbCS(red, green, blue, white, g)

 module.exports.rgb = (r, g, b) ->
   new Rgb(r, g, b)
@@ -138,10 +139,10 @@

 module.exports.space =
   'Adobe-98': new RgbCS(
-    white.D65
     xyY(0.6400, 0.3300)
     xyY(0.2100, 0.7100)
     xyY(0.1500, 0.0600)
+    white.D65
     2.2
   )


change newBlocks default value

change newBlocks default value


CADS-848 : Self employment javascript not correctly show/hide on different paths. Refactor to always set the full stack visibility on pageload or when items are clicked.


remove rm's

remove rm's

--- app/generator.coffee
+++ app/generator.coffee
@@ -134,13 +134,6 @@
         shell.rm '-rf', "scripts"
         shell.rm '-rf', "styles"
         shell.rm "README.txt"
-        shell.rm "basic-page.php"
-        shell.rm "search.php"
-        shell.rm "sitemap.php"
-        shell.rm "home.php"
-        shell.rm "_init.php"
-        shell.rm "_main.php"
-        shell.rm "_func.php"

       # remove alternative ProcessWire site profiles
       at dest('src/'), () =>


Fix authors page title

Fix authors page title

--- app/lib/en_us.coffee
+++ app/lib/en_us.coffee
@@ -398,7 +398,7 @@
     loadMore: 'Load more'

   authors: '''
-
About

+
Authors

The science of Planet Four is made possible by the work of our
     volunteers; those who gave us permission to publish their names are


Refactor: Extract method

Refactor: Extract method

--- lib/toggle-markdown-task.coffee
+++ lib/toggle-markdown-task.coffee
@@ -13,18 +13,20 @@

   toggle: ->
     if editor = atom.workspace.getActiveTextEditor()
-      selection = editor.getLastSelection();
-      rows  = selection.getBufferRowRange()
+      toggleSelection(editor.getLastSelection())

-      for row in [rows[0]..rows[1]]
-        selection.cursor.setBufferPosition([row, 0])
-        selection.selectToEndOfLine()
+toggleSelection = (selection) ->
+  rows = selection.getBufferRowRange()

-        if line = selection.getText()
-          toggledTask = toggleTask(line)
+  for row in [rows[0]..rows[1]]
+    selection.cursor.setBufferPosition([row, 0])
+    selection.selectToEndOfLine()

-          if toggledTask
-            selection.insertText(toggledTask)
+    if line = selection.getText()
+      toggledTask = toggleTask(line)
+
+      if toggledTask
+        selection.insertText(toggledTask)

 toggleTask = (taskText) ->
   if taskText.search(/\- \[ \]/) != -1


Fixed grammar errors. (#4088)

Fixed grammar errors. (#4088)

--- app/locale/el.coffee
+++ app/locale/el.coffee
@@ -219,7 +219,7 @@
     finishing: "Τελειώνει"
     sign_in_with_facebook: "Σύνδεση μέσω Facebook"
     sign_in_with_gplus: "Σύνδεση μέσω G+"
-    signup_switch: "θέλεις να δημιουργήσεις ένα λογαριασμός;"
+    signup_switch: "Δεν έχεις λογαριασμό;" # fixed to fit in web page

   signup:
 #    create_student_header: "Create Student Account"
@@ -242,7 +242,7 @@
 #    connected_facebook_p: "Finish signing up so you can log in with your Facebook account."
 #    facebook_exists: "You already have an account associated with Facebook!"
 #    hey_students: "Students, enter the class code from your teacher."
-#    birthday: "Birthday"
+    birthday: "Γενέθλια"
 #    parent_email_blurb: "We know you can't wait to learn programming — we're excited too! Your parents will receive an email with further instructions on how to create an account for you. Email {{email_link}} if you have any questions."
 #    classroom_not_found: "No classes exist with this Class Code. Check your spelling or ask your teacher for help."
 #    checking: "Checking..."
@@ -252,7 +252,7 @@
 #    name_taken: "Username already taken! Try {{suggestedName}}?"
 #    name_available: "Username available!"
 #    name_is_email: "Username may not be an email"
-#    choose_type: "Choose your account type:"
+    choose_type: "Επιλέξτε τον τύπο του λογαριασμού σας:"
 #    teacher_type_1: "Teach programming using CodeCombat!"
 #    teacher_type_2: "Set up your class"
 #    teacher_type_3: "Access Course Guides"
@@ -380,13 +380,13 @@
     warrior: "Πολεμιστής"
     ranger: "Καταδρομέας"
     wizard: "Μάγος"
-#    first_name: "First Name"
-#    last_name: "Last Name"
+    first_name: "Όνομα"
+    last_name: "Επώνυμο"
 #    last_initial: "Last Initial"
-#    username: "Username"
-#    contact_us: "Contact Us"
+    username: "Όνομα χρήστη"
+    contact_us: "Επικοινωνήστε μαζί μας"
 #    close_window: "Close Window"
-#    learn_more: "Learn More"
+    learn_more: "Μάθε Περισσότερα"

   units:
     second: "δευτερόλεπτο"
@@ -995,8 +995,8 @@
     wrong_password: "Λάθος Κωδικός"
     upload_picture: "Ανέβασμα φωτογραφίας"
     delete_this_account: "Μόνιμη διαγραφή λογαριασμού"
-    reset_progress_tab: "Εκκαθαριση Προοδου"
-    reset_your_progress: "Εκκαθάριση Πρόοδου και Επανεκκίνηση"
+    reset_progress_tab: "Εκκαθάριση Προόδου"
+    reset_your_progress: "Εκκαθάριση Προόδου και Επανεκκίνηση"
     god_mode: "Κατάσταση Θεού!"
     emails_tab: "Emails"
     admin: "Διαχειριστής"
@@ -1004,7 +1004,7 @@
     new_password: "Καινούργιος Κωδικός"
     new_password_verify: " Επαλήθευση  Κωδικού"
     type_in_email: "Γράψτε τη διεύθυνση ηλεκτρονικού ταχυδρομείου σας για να επιβεβαιώσετε τη διαγραφή του λογαριασμού." # {change}
-    type_in_email_progress: "Πληκτρολόγησε το email σου για επιβεβαιώση της εκκαθάρισης πρόοδου."
+    type_in_email_progress: "Πληκτρολόγησε το email σου για επιβεβαίωση της εκκαθάρισης πρόοδου."
     type_in_password: "Επίσης, γράψτε τον κωδικό σας."
     email_subscriptions: "Συνδρομές ηλεκτρονικού ταχυδρομείου"
     email_subscriptions_none: "Δεν υπάρχουν συνδρομές ηλεκτρονικού ταχυδρομείου."
@@ -1021,7 +1021,7 @@
     contribute_prefix: "Αναζητούμε ανθρώπους που θέλουν να  "
     contribute_page: "Σελίδα συνεισφοράς"
     contribute_suffix: " μάθε περισσότερα"
-    email_toggle: "Επέλεξα όλα"
+    email_toggle: "Εναλλαγή Όλων"
     error_saving: "Σφάλμα αποθήκευσης"
     saved: "Οι αλλαγές αποθηκεύτηκαν"
     password_mismatch: "Οι κωδικοί δεν ταιριάζουν"
@@ -1780,9 +1780,9 @@
     join_desc_2: "για να ξεκινήσεις, και πάτα το κουμπί παρακάτω για να μας δείξεις ότι είσαι ένας γενναίος Αρχιμάγος και να παίρνεις τα τελευταία νέα μέσω ηλεκτρονικού ταχυδρομείου. Θέλεις να συζητήσεις για το τι να κάνεις ή πως να εμπλακείς πιο βαθειά "
     join_desc_3: ", ή να μας βρεις στο "
     join_desc_4: "και εμείς θα το πάρουμε από εκεί και μετά!"
-    join_url_email: "Στείλε μας μήνυμα"
-#    join_url_slack: "public Slack channel"
-    archmage_subscribe_desc: "Παίρνε μηνύματα ηλεκτρονικού ταχυδρομείου για νέες ευκαιρείες προγραμματισμού και ανακοινώσεις."
+    join_url_email: "Στείλτε μας μήνυμα"
+    join_url_slack: "Δημόσιο κανάλι Slack"
+    archmage_subscribe_desc: "Πάρτε μηνύματα για νέες ευκαιρίες προγραμματισμού και ανακοινώσεις."
     artisan_introduction_pref: "Πρέπει να δημιουργήσουμε επιπλέον επίπεδα! Οι άνθρωποι φωνάζουν για καινούριο περιεχόμενο, and we can only build so many ourselves. Προς το παρόν ο σταθμός εργασίας σου είναι στο πρώτο επίπεδο. Ο διορθωτής επιπέδων μας καλά καλά δεν μπορεί να χρησιμοποιηθεί ούτε από τους δημιουργούς του, γιαυτό πρόσεχε. Αν οραματίζεσε καμπάνιες που να περιέχουν επαναλήψεις Για μέχρι"
     artisan_introduction_suf: ", τότε αυτή η τάξη ίσως να είναι για σένα."
     artisan_attribute_1: "Οποιαδήποτε εμπειρία στη δημιουργία παρόμοιου περιεχομένου είναι καλή, όπως η γνση των διορθωτώβ επιπέδων της Blizzard. Αλλά δεν είναι απαιτείται!"
@@ -1793,22 +1793,22 @@
     artisan_join_step2: "Δημιούργησε ένα νέο επίπεδο και εξερεύνησε τα ήδη υπάρχοντα."
     artisan_join_step3: "Αν χρειάζεσαι βοήθεια, βρες μας στο δημόσιο μας κανάλι στο Slack."
     artisan_join_step4: "Δημοσίευσε τα επίπεδά σου στο φόρουμ για να δεις πως φαίνονται σε άλλους."
-    artisan_subscribe_desc: "Δέξου μηνύματα ηλεκτρονικού ταχυδρομείου που αφορούν ανακοινώσεις και αναβαθμίσεις του συντάκτη επιπέδων."
+    artisan_subscribe_desc: "Πάρτε μηνύματα που αφορούν ανακοινώσεις και αναβαθμίσεις του συντάκτη επιπέδων."
     adventurer_introduction: "Ας είμαστε ξακάθαροι για το ρόλο σου: είσαι ένα άρμα μάχης. Θα δεχθείς πολλά πυρά και θα έχεις πολλές ζημιές. Χρειαζόμαστε ανθρώπους να δοκιμάζουν νέα επίπεδα και να βοηθούν να αναγνωρίζουμε πυως να κάνουμε τα πράγματα καλύτερα. Ο πόνος θα είναι μεγάλος, η κατασκευή καλών παιχνιδιών είναι μια χρονοβόρα διαδικασία και κανένας δεν τα καταφέρνει σωστά με την πρώτη φορά. Αν νομίζεις ότι μπορεί να αντέξεις, τότε αυτή η τάξη μπορεί να είναι για σένα."
     adventurer_attribute_1: "Δίψα για μάθηση. Εσύ θέλεις να μάθεις να προγραμματίζεις και εμείς θέλούμε να σου μάθουμε να προγραμματίζεις. Αν και μάλλον, στην περίπτωση αυτή, εσύ θα κάνεις το περισσότερο κομμάτι της διδασκαλίας."
     adventurer_attribute_2: "Χαρισματικός. Να είσαι ευγενής αλλά σαφής για το τι χρειάζεται βελτίωση, και κάνε προτάσεις για το πως θα βελτιώσουμε τα πράγματα."
-    adventurer_join_pref: "Συνάντησε έναν Τεχνίτη (ή στρατολόγησε έναν!) και δούλεψε μαζί του, ή κάνε κλικ στο κουμπιί παρακάτω για να λαμβάνεις μηνύματα ηλεκ. ταχυδρομείου όταν υπάρχουν νέα επίπεδα για έλεγχο. Επίσης, θα δημοσιεύουμε επίσης για έλεγχο νέων επίπεδα στα δίκτυά μας όπως"
+    adventurer_join_pref: "Συνάντησε έναν Τεχνίτη (ή στρατολόγησε έναν!) και δούλεψε μαζί του, ή κάνε κλικ στο κουμπιί παρακάτω για να λαμβάνεις μηνύματα όταν υπάρχουν νέα επίπεδα για έλεγχο. Επίσης, θα δημοσιεύουμε επίσης για έλεγχο νέων επίπεδα στα δίκτυά μας όπως"
     adventurer_forum_url: "το φόρουμ μας"
     adventurer_join_suf: "οπότε αν προτιμάς να σε ειδοποιούμε με αυτούς τους τρόπους κάνε εγγραφή!"
-    adventurer_subscribe_desc: "Δέξουε μηνύματα ηλεκτρονικού ταχυδρομείου όταν υπάρχουν νέα επίπεδα που πρέπει να δοκιμαστούν."
+    adventurer_subscribe_desc: "Πάρτε μηνύματα όταν υπάρχουν νέα επίπεδα που πρέπει να δοκιμαστούν."
     scribe_introduction_pref: "Το CodeCombat δε θα είναι απλά ένα μάτσο επίπεδα. Θα περιλαμβάνει επίσης πηγές γνώσης, ένα wiki για θέματα προγραμματισμού, στο οποίο μπορούν να παραπέμπουν τα επίπεδα. Έτσι, αντί κάθε Τεχνίτης να πρέπει να περιγράφει με λεπτομέρεια τι είναι ένας τελεστής σύγκρισης, μπορεί απλά να βάλει ένα σύνδεσμο από το επίπεδό τους στο άρθρο περιγράφοντάς τους ό,τι είναι ήδη γραμμένο με σκοπό την επιμόρφωση του χρήστη. Κάτι παρόμοιο με ό,τι το "
     scribe_introduction_url_mozilla: "Δίκτυο Ανάπτυξης Mozilla (Mozilla Developer Network)"
     scribe_introduction_suf: " έχει φτιάξει. Αν θεωρείς διασκεδαστικό να καταγράφεις με σαφήνεια θέματα προγραμματισμού σε μορφή Markdown, τότε αυτή η τάξη μπορεί να είναι η κατάλληλη για σένα."
     scribe_attribute_1: "Το μόνο που χρειάζεσαι είναι να είσαι καλός με τις λέξεις. Να είσαι καλός όχι μόνο με γραμματική και ορθογραφία, αλλά να είσαι ικανός να μεταφέρεις πολύπλοκες ιδέες σε άλλους."
-    contact_us_url: "Επικοινώνησε μαζί μας" # {change}
+    contact_us_url: "Επικοινωνία"
     scribe_join_description: "πες μας λίγα πράγματα για σένα, την εμπειρία σου με τον προγραμματισμό και για τι είδους πράγματα θα ήθελες να γράφεις. Εμείς θα αναλάβουμε από εκεί και μετά!"
-    scribe_subscribe_desc: "Πάρε μηνύματα ηλεκτρονικού ταχυδρομείου σχετικά με ανακοινώσεις για τη συγγραφή άρθρων."
-    diplomat_introduction_pref: "Λοιπ, αν υπάρχει κάτι που μάθαμε από το  "
+    scribe_subscribe_desc: "Πάρτε μηνύματα σχετικά με ανακοινώσεις για τη συγγραφή άρθρων."
+    diplomat_introduction_pref: "Λοιπόν, αν υπάρχει κάτι που μάθαμε από το "
     diplomat_launch_url: "ξεκίνημά μας το Οκτώβρη"
     diplomat_introduction_suf: "είναι ότι υπάρχει υπολογίσιμο ενδιαφέρον για το CodeCombat σε άλλα κράτη! Φτιάχνουμε μια ομάδα μεταφραστών, που να είναι πρόθυμοι να μεταφράζουν για να κάνουν CodeCombat όσο πιο προσβάσιμο στην υφήλιο γίνεται. Αν θέλεις να ίχνεις κλεφτές ματιές σε μελλοντικό περιεχόμενο και να φέρνεις αυτά τα επίπεδα στους συμπατριώτες όσο το δυνατό γρηγορότερα, τότε αυτή η τάξη ίσως να είναι για σένα."
     diplomat_attribute_1: "Πρέπει να είσαι άριστος στα Αγγλικά και στη γλώσσα στην οποία θέλεις να μεταφράσεις. Όταν μεταφέρεις πολύπλοκες ιδέες, είναι σημαντικό να είσαι πολύ καλός και στις δύο!"
@@ -1818,13 +1818,13 @@
     diplomat_join_pref_github: "Βρες το αρχείο της γλώσσας σου "
     diplomat_github_url: "στο GitHub"
     diplomat_join_suf_github: ", επεξεργάσου του online, και υπόβαλε ένα αίτημα υποβολής (pull request). Επίσης, τσέκαρε το κουμπί παρακάτω για να σε κρατάμε ενήμερο για τις εξελίξεις στη διεθνοποίηση!"
-    diplomat_subscribe_desc: "Δέξουν μηνήματα για τις αλλαγές στο i18n και επίπεδα για μετάφραση."
+    diplomat_subscribe_desc: "Πάρτε μηνήματα για τις εξελίξεις στο i18n και επίπεδα για μετάφραση."
     ambassador_introduction: "Κτίζουμε μια κοινότητα, και εσείς είστε ο συνδετικός κρίκος. Έχουμε φόρα, emails, και κοινωνικά δίκτυα με πολλούς ανθρώπους, με τους οποίους μπορείτε να μιλήσετε και να τους βοηθήσετε να γνωρίσουν το παιχνίδι και να μάθουν από αυτό. Αν θέλεις να βοηθήσεις ανθρώπους να μπουν στο παιχνίδι και να διασκεδάσουν, να αποκτήσεις μια καλή αίσθηση του παλμού του CodeCombat και του που πηγαίνουμε, τότε αυτή η τάξη μπορεί να είναι για σένα."
     ambassador_attribute_1: "Ικανότητες επικοινωνίας. Να μπορείς να αναγνωρίζεις τα προβλήματα των παικτών και να τους βοηθάς να τα λύνουν. Επίσης, να ενημερώνεις κι εμάς για το τι λένε οι παίκτες, τι τους αρέσει και τι όχι και τι άλλο χρειάζονται!"
     ambassador_join_desc: "πες μας λίγο για εσένα, τι έχεις κάνει μέχρι τώρα και τι σε ενδιαφέρει να κάνεις. Εμείς θα το συνεχίσουμε μετά!"
     ambassador_join_note_strong: "Σημείωση"
     ambassador_join_note_desc: "Μια από τις μεγαλύτερες προτεραιότητές μας είναι να φτιάχνουμε παιχνίδια πολλαπλών χρηστών όπου οι παίκτες που δυσκολεύονται στην επίλυση επιπέδων μπορούν να καλούν μάγους ανωτέρων επιπέδων για να τους βοηθήσουν. Αυτή θα είναι ένας φανταστικός τρόπος για τους Πρεσβευτές να λάμψουν. Θα σας ενημερώνουμε!"
-    ambassador_subscribe_desc: "Δεψτείτε μηνύματα ηλεκτρονικού ταχυδρομείου για νέα θέματα υποστήριξης και αναπτυξη παιχνιδιών πολλαπλών παικτών."
+    ambassador_subscribe_desc: "Πάρτε μηνύματα για ενημερώσεις υποστήριξης και τις εξελίξεις στο multiplayer ."
 #    teacher_subscribe_desc: "Get emails on updates and announcements for teachers."
     changes_auto_save: "Οι αλλαγές αποθηκεύονται αυτόματα όταν πατάτε τα κουμπιά επιλογής."
     diligent_scribes: "Οι Ακούραστοι Γραφιάδες μας:"
@@ -1929,7 +1929,7 @@

   account:
     payments: "Πληρωμές"
-    prepaid_codes: "Προπληρωμένοι Κώδικες"
+    prepaid_codes: "Προπληρωμές"
     purchased: "Αγοράστηκαν"
     subscription: "Συνδρομή"
     invoices: "Εντολές Πληρωμής"
@@ -2004,16 +2004,16 @@
 #    login_required: "Login Required"
 #    login_required_desc: "You need to be logged in to access this page."
     unauthorized: "Πρέπει να είσαι συνδεμένος. Μήπως έχεις απεργοποιήσει τα cookies;"
-    forbidden: "Δεν σου επιτρέπεται."
+    forbidden: "Απαγορευμένο"
 #    forbidden_desc: "Oh no, there’s nothing we can show you here! Make sure you’re logged into the correct account, or visit one of the links below to get back to programming!"
-    not_found: "Δε βρέθηκε."
+    not_found: "Δε Βρέθηκε"
 #    not_found_desc: "Hm, there’s nothing here. Visit one of the following links to get back to programming!"
     not_allowed: "Η μέθοδος δεν επιτρέπεται."
-    timeout: "Ο εξυπηρετητής άργησε πολύ να απαντήσει." # {change}
+    timeout: "Ο Εξυπηρετητής Δεν Απάντησε" # {change}
     conflict: "Σύγκρουση πόρων."
     bad_input: "Λάθος δεδομένα εισόδου."
     server_error: "Σφάλμα εξυπηρετητή."
-    unknown: "Άγνωστο σφάλμα." # {change}
+    unknown: "Άγνωστο Σφάλμα" # {change}
     error: "Σφάλμα"
 #    general_desc: "Something went wrong, and it’s probably our fault. Try waiting a bit and then refreshing the page, or visit one of the following links to get back to programming!"

@@ -2177,7 +2177,7 @@
     cc_license_url: "άδεια Αναφορά Δημιουργού 4.0 Διεθνές"
     art_description_suffix: "Κοινό περιεχόμενο είναι ο,τιδήποτε έγινε γενικά διαθέσιμο από το CodeCombat με σκοποό τη δημιουργία Επιπέδων. Αυτό περιλαμβάνει:"
     art_music: "Μουσική"
-    art_sound: "Ήχο"
+    art_sound: "Ήχος"
     art_artwork: "Γραφικά"
     art_sprites: "Εικονίδια Χαρακτήρων (Sprites)"
     art_other: "Οποιαδήποτε άλλη μη προγραμματιστική, δημιουργική εργασία που είναι διαθέσιμη για τη δημιουργία Επιπέδων."