Starting work.

Starting work.

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

--- scripts/newproject.coffee
+++ scripts/newproject.coffee
@@ -0,0 +1,70 @@
+# Commands:
+#   hubot newproject list - Describe kinds of projects that can be set up
+#   hubot newproject describe <project-type> - show cookiecutter.json for project-type
+#
+
+typecache = null
+timerid = null
+svc = "https://api.lsst.codes/ccutter"
+
+module.exports = (robot) ->
+  pollprojects(robot)
+  rootCas = require('ssl-root-cas/latest').create()
+  require('https').globalAgent.options.ca = rootCas
+  robot.respond /newproject\s+list$/i, (msg) ->
+    repstr = "I know about the following project types:\n"
+    for type of typecache
+      repstr += "  `#{type}`\n"
+    msg.send "#{repstr}"
+    return
+  robot.respond /newproject\s+describe\s+(\S+)$/i, (msg) ->
+    ptype = msg.match[1]
+    if typecache.ptype
+      msg.send "`" + JSON.stringify(typecache.ptype) + "`"
+      return
+    msg.send "I don't know about project type `#{ptype}`"
+    return
+
+repopulate_cache = (robot) ->
+  robot.http("#{svc}/").get() (err, res, body) ->
+    if err
+      return
+    try
+      content = JSON.parse(body)
+      typecache = clone(content)
+
+# https://coffeescript-cookbook.github.io/chapters/classes_and_objects/cloning
+
+clone = (obj) ->
+  if not obj? or typeof obj isnt 'object'
+    return obj
+
+  if obj instanceof Date
+    return new Date(obj.getTime())
+
+  if obj instanceof RegExp
+    flags = ''
+    flags += 'g' if obj.global?
+    flags += 'i' if obj.ignoreCase?
+    flags += 'm' if obj.multiline?
+    flags += 'y' if obj.sticky?
+    return new RegExp(obj.source, flags)
+
+  newInstance = new obj.constructor()
+
+  for key of obj
+    newInstance[key] = clone obj[key]
+
+  return newInstance
+
+pollprojects = (robot) ->
+  if ! timerid?
+    secs = 3600 # Check every hour
+    interval = secs * 1000
+    repopulate_cache(robot)
+    timerid = setInterval ->
+      repopulate_cache(robot)
+    , interval
+
+
+


Filters: Reset now set the first option instead of ""

To allow first option to not be have "" value

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


Test inquiry specs

Test inquiry specs

error: pathspec 'components/inquiry_questionnaire/test/views/test_inquiry.coffee' did not match any file(s) known to git

--- components/inquiry_questionnaire/test/views/test_inquiry.coffee
+++ components/inquiry_questionnaire/test/views/test_inquiry.coffee
@@ -0,0 +1,226 @@
+benv = require 'benv'
+sinon = require 'sinon'
+Backbone = require 'backbone'
+{ fabricate } = require 'antigravity'
+setup = require './setup'
+Inquiry = benv.requireWithJadeify require.resolve('../../views/test_inquiry'), [
+  'template'
+]
+
+describe 'Inquiry', setup ->
+  beforeEach ->
+    sinon.stub Backbone, 'sync'
+
+  afterEach ->
+    Backbone.sync.restore()
+
+  describe '#render', ->
+    describe 'user with email and name', ->
+      beforeEach ->
+        @view = new Inquiry
+          user: @currentUser
+          artwork: @artwork
+          inquiry: @inquiry
+          state: @state
+
+        @view.render()
+
+      it 'renders the template', ->
+        @view.$('h1').text()
+          .should.equal 'Send message to gallery'
+        @view.$('.scontact-description').text()
+          .should.equal 'To: Gagosian Gallery'
+        @view.$('input[type="text"][name="name"]')
+          .should.have.lengthOf 0
+        @view.$('input[type="email"][name="email"]')
+          .should.have.lengthOf 0
+        @view.$('.scontact-from').text()
+          .should.equal 'From: Craig Spaeth (craigspaeth@gmail.com)'
+
+    describe 'user without contact details', ->
+      beforeEach ->
+        @loggedOutUser.unset 'name'
+        @loggedOutUser.unset 'email'
+
+        @view = new Inquiry
+          user: @loggedOutUser
+          artwork: @artwork
+          inquiry: @inquiry
+          state: @state
+
+        @view.render()
+
+      it 'renders the template', ->
+        @view.$('h1').text()
+          .should.equal 'Send message to gallery'
+        @view.$('.scontact-description').text()
+          .should.equal 'To: Gagosian Gallery'
+        @view.$('input[type="text"][name="name"]')
+          .should.have.lengthOf 1
+        @view.$('input[type="email"][name="email"]')
+          .should.have.lengthOf 1
+        @view.$('.scontact-from').text()
+          .should.be.empty()
+
+  describe '#next (with user)', ->
+    beforeEach ->
+      @state.set 'steps', ['inquiry', 'after_inquiry']
+
+      @view = new Inquiry
+        user: @currentUser
+        artwork: @artwork
+        inquiry: @inquiry
+        state: @state
+
+      @view.render()
+
+    it 'sets up the inquiry and ensures the user has contact details', ->
+      @view.$('input[name="name"]').val 'Craig Spaeth'
+      @view.$('input[name="email"]').val 'craigspaeth@gmail.com'
+      @view.$('textarea[name="message"]').val 'I wish to buy the foo bar'
+      @view.$('button').click()
+
+      @view.__serialize__.then =>
+        # Sets up the inquiry
+        @inquiry.get('message').should.equal 'I wish to buy the foo bar'
+        @inquiry.get('contact_gallery').should.be.true()
+        @inquiry.get('artwork').should.equal @artwork.id
+
+        # Sets up the user
+        @currentUser.get('name').should.equal 'Craig Spaeth'
+        @currentUser.get('email').should.equal 'craigspaeth@gmail.com'
+
+        Backbone.sync.callCount.should.equal 3
+
+        Backbone.sync.args[0][1].url()
+          .should.containEql '/api/v1/me/artwork_inquiry_request'
+        Backbone.sync.args[1][1].url()
+          .should.containEql "/api/v1/me"
+        Backbone.sync.args[2][1].url
+          .should.containEql = '/api/v1/user'
+
+        # Next
+        @view.state.current().should.equal 'after_inquiry'
+
+  describe '#next', ->
+    beforeEach ->
+      @state.set 'steps', ['inquiry', 'after_inquiry']
+
+      @loggedOutUser.unset 'name'
+      @loggedOutUser.unset 'email'
+
+      @view = new Inquiry
+        user: @loggedOutUser
+        artwork: @artwork
+        inquiry: @inquiry
+        state: @state
+
+      @view.render()
+
+    it 'sets up the inquiry and ensures the user has contact details', ->
+      @view.$('input[name="name"]').val 'Foo Bar'
+      @view.$('input[name="email"]').val 'foo@bar.com'
+      @view.$('textarea[name="message"]').val 'I wish to buy the foo bar'
+      @view.$('button').click()
+
+      @view.__serialize__.then =>
+        # Sets up the inquiry
+        @inquiry.get('message').should.equal 'I wish to buy the foo bar'
+        @inquiry.get('contact_gallery').should.be.true()
+        @inquiry.get('artwork').should.equal @artwork.id
+
+        # Sets up the user
+        @loggedOutUser.get('name').should.equal 'Foo Bar'
+        @loggedOutUser.get('email').should.equal 'foo@bar.com'
+
+        Backbone.sync.callCount.should.equal 2
+
+        Backbone.sync.args[0][1].url()
+          .should.containEql "/api/v1/me/anonymous_session/#{@loggedOutUser.id}"
+        Backbone.sync.args[1][1].url
+          .should.containEql '/api/v1/user'
+
+        # Next
+        @view.state.current().should.equal 'after_inquiry'
+
+    it 'prevents an initial send (but not subsequent) when submitting the default message', ->
+      sinon.stub Inquiry::, 'nudged'
+        .returns false
+
+      @view.$('textarea[name="message"]').val()
+        .should.containEql 'Hi, I’m interested in purchasing this work. Could you please provide more information about the piece?'
+
+      @view.$('button').click()
+
+      @view.nudged.returns true
+
+      Backbone.sync.callCount.should.equal 0
+
+      @view.$('.alertable-input').data 'alert'
+        .should.equal 'We recommend personalizing your message to get a faster answer from the gallery.'
+
+      @view.$('button').text().should.equal 'Send Anyway?'
+      @view.$('button').click()
+
+      Backbone.sync.callCount.should.equal 2
+
+      @view.nudged.restore()
+
+  describe 'in a fair context', ->
+    beforeEach ->
+      @state.set 'steps', ['inquiry', 'after_inquiry']
+
+      @loggedOutUser.unset 'name'
+      @loggedOutUser.unset 'email'
+
+      @artwork.related().fairs.add fabricate 'fair'
+
+      @view = new Inquiry
+        user: @loggedOutUser
+        artwork: @artwork
+        inquiry: @inquiry
+        state: @state
+
+      @view.render()
+
+    describe '#render', ->
+      it 'renders the attendance checkbox', ->
+        @view.$el.html().should.containEql 'I will attend Armory Show'
+
+    describe '#next', ->
+      it 'saves the user fair action', ->
+        @view.$('input[name="name"]').val 'Foo Bar'
+        @view.$('input[name="email"]').val 'foo@bar.com'
+        @view.$('textarea[name="message"]').val 'I wish to buy the foo bar'
+        @view.$('input[name="attending"]').prop 'checked', true
+        @view.$('button').click()
+
+        @view.__serialize__.then =>
+          Backbone.sync.callCount.should.equal 3
+
+          Backbone.sync.args[2][1].url()
+            .should.containEql '/api/v1/me/user_fair_action'
+
+          @view.state.current().should.equal 'after_inquiry'
+
+      it 'continues on to the next state even when the UserFairAction errors', ->
+        Backbone.sync
+          .onCall 0
+            .returns Promise.resolve()
+          .onCall 1
+            .returns Promise.resolve()
+          .onCall 2
+            .returns Promise.resolve()
+          .onCall 3
+            .returns Promise.reject('Action already taken')
+
+        @view.$('input[name="name"]').val 'Foo Bar'
+        @view.$('input[name="email"]').val 'foo@bar.com'
+        @view.$('textarea[name="message"]').val 'I wish to buy the foo bar'
+        @view.$('input[name="attending"]').prop 'checked', true
+        @view.$('button').click()
+
+        @view.__serialize__.then =>
+          Backbone.sync.callCount.should.equal 3
+
+          @view.state.current().should.equal 'after_inquiry'


Comment flickr store autoload

Comment flickr store autoload

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


added extensions

added extensions

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


payment: remove old broken implementation

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


Components: Common: Link: Return if href is null or undefined


unifying formatTime functions

unifying formatTime functions

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


cobalt -> custard box migration

cobalt -> custard box migration

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

--- migration/migrate_boxes_to_custard.coffee
+++ migration/migrate_boxes_to_custard.coffee
@@ -0,0 +1,48 @@
+#!/usr/bin/env coffee
+fs = require 'fs'
+
+request = require 'request'
+mongoose = require 'mongoose'
+async = require 'async'
+
+cobalt = mongoose.createConnection process.env['COBALT_DB']
+custard = mongoose.createConnection process.env['CU_DB']
+
+User = require 'models/user'
+Box = require 'models/box'
+
+CobaltUser = cobalt.model 'User', User
+CobaltBox = cobalt.model 'Box', Box
+
+CustardUser = custard.model 'User', User
+CustardBox = custard.model 'Box', Box
+
+custard.on 'error', (err, b ) ->
+  console.log err, b
+
+cobalt.on 'error', (err, b ) ->
+  console.log err, b
+
+getUserFromBox = (box, cb) ->
+  cb() unless box?
+  CobaltUser.findOne {_id: box.user}, (err, user) ->
+    console.log err if err?
+    #console.log "#{box?.name} #{user?.shortname}"
+    if box?.name? and user?.shortname
+      CustardUser.findOne {shortName: user.shortname}, (err, cusUser) ->
+        if cusUser?
+          custardBox = new CustardBox
+            name: box.name
+            users: [cusUser.shortName]
+          console.log custardBox
+          return custardBox.save (err) ->
+            console.log "ERROR: #{err}" if err?
+            return cb()
+        else
+          console.log "ERROR: #{user.shortname} not found in custard"
+    return cb()
+
+CobaltBox.find {}, (err, boxes) ->
+  async.forEach boxes, getUserFromBox, (err, res) ->
+    console.log err, res
+    #process.exit 0


Fixes clicking on the plane to send message

--- client/views/app/chatWindowDashboard.coffee
+++ client/views/app/chatWindowDashboard.coffee
@@ -358,7 +358,7 @@
 		ChatMessages.stopEditingLastMessage()

 	'click .message-form .icon-paper-plane': (event) ->
-		input = $(event.currentTarget).siblings("input")
+		input = $(event.currentTarget).siblings("textarea")
 		ChatMessages.send(this._id, input.get(0))

 	'click .add-user': (event) ->


prettying help

prettying help

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


omitted /g flag

omitted /g flag


fix improper hsl calculation when lightness is less than 50

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


Better? history timing and clone state on changing

--- resources/assets/coffee/react/beatmaps/main.coffee
+++ resources/assets/coffee/react/beatmaps/main.coffee
@@ -118,10 +118,10 @@
     if @state.loading || @state.paging.loading || !@state.paging.more
       return

-    paging_state = @state.paging
-    paging_state.loading = true
-
-    @setState paging: paging_state
+    pagingState = _.extend {}, @state.paging
+    pagingState.loading = true
+
+    @setState paging: pagingState

     $.ajax @state.paging.url,
       method: 'get'
@@ -129,15 +129,17 @@
       data: _.extend @buildSearchQuery(), page: @state.paging.page + 1
     .done (data) =>
       more = data.length > 10
-      newState =
-        beatmaps: @state.beatmaps.concat(data)
+
+      @setState newState
+        beatmaps: [].concat(@state.beatmaps, data)
         paging:
           page: @state.paging.page + (if more then 1 else 0)
           url: @state.paging.url
           more: more
         loading: false
-
-      @setState newState
+        =>
+          # copied from https://github.com/turbolinks/turbolinks/pull/61
+          Turbolinks.controller.pushHistoryWithLocationAndRestorationIdentifier newUrl, Turbolinks.uuid()

   saveState: =>
@@ -152,9 +154,6 @@
     newUrl = laroute.route 'beatmapsets.index', params

     return if "#{location.pathname}#{location.search}" == newUrl
-
-    # copied from https://github.com/turbolinks/turbolinks/pull/61
-    Turbolinks.controller.pushHistoryWithLocationAndRestorationIdentifier newUrl, Turbolinks.uuid()

     @showLoader()
     @xhr.search = $.ajax @state.paging.url,


Stripped trailing whitespace

Stripped trailing whitespace

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


- removed node-sass

- removed node-sass

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


Added titles and descriptions for schema

--- server/levels/sessions/level_session_schema.coffee
+++ server/levels/sessions/level_session_schema.coffee
@@ -143,29 +143,43 @@

   matches:
     type: 'array'
+    title: 'Matches'
+    description: 'All of the matches a submitted session has played in its current state.'
     items:
       type: 'object'
       properties:
         date: c.date
-          title: 'Time'
+          title: 'Date computed'
+          description: 'The date a match was computed.'
         metrics:
           type: 'object'
+          title: 'Metrics'
+          description: 'Various information about the outcome of a match.'
           properties:
             rank:
+              title: 'Rank'
+              description: 'A 0-indexed ranking representing the player\'s standing in the outcome of a match'
               type: 'number'
         opponents:
           type: 'array'
+          title: 'Opponents'
+          description: 'An array containing information about the opponents\' sessions in a given match.'
           items:
             type: 'object'
             properties:
               id:
+                title: 'Opponent Session ID'
+                description: 'The session ID of an opponent.'
                 type: ['object', 'string']
               codeSubmitDate: c.date
                 title: 'Submitted'
+                description: 'The date which the opponent submitted their session (used to check if the match can be replayed)'
               metrics:
                 type: 'object'
                 properties:
                   rank:
+                    title: 'Opponent Rank'
+                    description: 'The opponent\'s ranking in a given match'
                     type: 'number'


Attempt to fix failing spec on CI.

Attempt to fix failing spec on CI.

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


Adds google analytics workaround for rails 4

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

--- app/assets/javascripts/analytics.js.coffee
+++ app/assets/javascripts/analytics.js.coffee
@@ -0,0 +1,5 @@
+$(document).on 'page:change', ->
+  if window._gaq?
+    _gaq.push ['_trackPageview']
+  else if window.pageTracker?
+    pageTracker._trackPageview()


nacl driver

nacl driver

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

--- src/js_nacl_driver.coffee
+++ src/js_nacl_driver.coffee
@@ -0,0 +1,62 @@
+# Copyright (c) 2015 Vault12, Inc.
+# MIT License https://opensource.org/licenses/MIT
+Utils = require 'utils'
+
+# Nacl driver for the js-nacl emscripten implementation
+class JsNaclDriver
+
+  # heap size for js-nacl emscripten implementation
+  @HEAP_SIZE: 2 ** 23 # 8,388,608
+  # unload timeout for js-nacl emscripten implementation
+  @UNLOAD_TIMEOUT: 15 * 1000
+
+  @API = [
+    crypto_secretbox_random_nonce
+    crypto_secretbox
+    crypto_secretbox_open
+    crypto_box
+    crypto_box_open
+    crypto_box_random_nonce
+    crypto_box_keypair
+    crypto_box_keypair_from_raw_sk
+    crypto_box_keypair_from_seed
+    crypto_hash_sha256
+    random_bytes
+    encode_utf8
+    decode_utf8
+    to_hex
+    from_hex
+  ]
+
+  @_instance:     null
+  @_unloadTimer:  null
+
+  constructor: ->
+    # If we are running in the browser, then nacl_factory will be defined by
+    # including the nacl_factory.js lib before including glow. If we are on node,
+    # then require 'js-nacl' will include nacl_factory appropriately
+    # https://github.com/tonyg/js-nacl
+    @js_nacl = nacl_factory? or require 'js-nacl'
+
+    @API.forEach (f)=>
+      @[f] = =>
+        inst = @use()
+        Utils.resolve(inst[f].apply(inst, arguments))
+
+  # whenever we call use, we're accessing the js-nacl lib for a function call
+  # if we haven't used any js-nacl lib function calls in 15 seconds, then it
+  # unloads via the unload call
+  @use: ->
+    # timer unloads 8mb heap 15 sec after last use
+    clearTimeout @_unloadTimer if @_unloadTimer
+    @_unloadTimer = setTimeout((-> Nacl.unload()), @UNLOAD_TIMEOUT)
+
+    unless window.__naclInstance   # Global instance to avoid duplicating heap
+      window.__naclInstance = js_nacl.instantiate(@HEAP_SIZE) # 8mb heap
+    window.__naclInstance
+
+  @unload: ->
+    # Nacl hasn't been used in 15 seconds, unload it and free the heap
+    @_unloadTimer = null
+    window.__naclInstance = null
+    delete window.__naclInstance


remove declaracions.coffee

remove declaracions.coffee

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


feat(grunt): add ignore patterns for cache busting

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -272,6 +272,9 @@
           "link[rel*=icon]": ->
             @attribs.href
         }
+        ignorePatterns: [
+          "no-cache-bust"
+        ]
         algorithm: "md5"
         length: 8
         deleteOriginals: true


Change the artifact target directory to dist instead of lib.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -12,25 +12,25 @@
     coffee:
       all:
         files:
-          'lib/rivets.js': 'src/rivets.coffee'
+          'dist/rivets.js': 'src/rivets.coffee'

     concat:
       all:
         options:
           banner: '<%= meta.banner %>'
         files:
-          'lib/rivets.js': 'lib/rivets.js'
+          'dist/rivets.js': 'dist/rivets.js'

     uglify:
       all:
         options:
           banner: '<%= meta.banner %>'
         files:
-          'lib/rivets.min.js': 'lib/rivets.js'
+          'dist/rivets.min.js': 'dist/rivets.js'

     jasmine:
       all:
-        src: 'lib/rivets.js'
+        src: 'dist/rivets.js'
         options:
           specs: 'spec/rivets/**/*.js'
           helpers: 'spec/lib/**/*.js'


welcomeModal/destory: remove unneccesary route check


Amend: tests for populating S3 settings from environment variable

error: pathspec 'services/filestore/test/unit/coffee/SettingsTests.coffee' did not match any file(s) known to git

--- services/filestore/test/unit/coffee/SettingsTests.coffee
+++ services/filestore/test/unit/coffee/SettingsTests.coffee
@@ -0,0 +1,22 @@
+assert = require("chai").assert
+sinon = require('sinon')
+chai = require('chai')
+should = chai.should()
+expect = chai.expect
+modulePath = "../../../app/js/BucketController.js"
+SandboxedModule = require('sandboxed-module')
+
+describe "Settings", ->
+	describe "s3", ->
+		it "should use JSONified env var if present", (done)->
+			s3_settings =
+				key: 'default_key'
+				secret: 'default_secret'
+				bucket1:
+					auth_key: 'bucket1_key'
+					auth_secret: 'bucket1_secret'
+			process.env['S3_CREDENTIALS'] = JSON.stringify s3_settings
+
+			settings =require('settings-sharelatex')
+			expect(settings.filestore.s3).to.deep.equal s3_settings
+			done()


disable dragging from doom-line

disable dragging from doom-line

--- app/coffee/modules/backlog/sortable.coffee
+++ app/coffee/modules/backlog/sortable.coffee
@@ -54,6 +54,7 @@
                 $tgConfirm.notify("error", "You can't drop on backlog when filters are open") #TODO: i18n

             $el.sortable({
+                items: ".us-item-row",
                 connectWith: ".sprint"
                 containment: ".wrapper"
                 dropOnEmpty: true


text changes and icon highlights, form one

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


fixes comment

fixes comment

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


propriétés de scope

propriétés de scope

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


unit test for binary truncated bug

unit test for binary truncated bug

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

--- test/integration/binary-insert-test.coffee
+++ test/integration/binary-insert-test.coffee
@@ -0,0 +1,57 @@
+async = require('async')
+Connection = require('../../src/connection')
+Request = require('../../src/request')
+fs = require('fs')
+TYPES = require('../../src/data-type').typeByName
+
+debug = false
+
+config = JSON.parse(fs.readFileSync(process.env.HOME + '/.tedious/test-connection.json', 'utf8')).config
+config.options.textsize = 8 * 1024
+
+if (debug)
+  config.options.debug =
+    packet: true
+    data: true
+    payload: true
+    token: true
+    log: true
+else
+  config.options.debug = {}
+
+exports.insertBinary = (test) ->
+  sample = new Buffer [0x12, 0x34, 0x00, 0xce]
+  stmts = [
+    ["create table binaryInsertTest (data binary(4))"],
+    ["insert into binaryInsertTest (data) values (@p1)", [['p1', TYPES.Binary, sample]]],
+    ["select data from binaryInsertTest", [], [[sample]]],
+    ["drop table binaryInsertTest"]]
+  test.expect 7
+  testSqls test, stmts
+
+testSqls = (test, stmts) ->
+  connection = new Connection config
+  connection.on 'connect', (err) ->
+    test.ifError err
+    testOne = () ->
+      stmt = stmts.shift()
+      if stmt
+        request = new Request stmt[0], (err) ->
+          test.ifError err
+          testOne()
+        request.addParameter.apply(request, p) for p in (stmt[1] or [])
+        connection.execSql request
+        request.on 'row', (columns) ->
+          row = stmt[2].shift()
+          if Buffer.isBuffer row[0]
+            test.strictEqual columns[0].value.toString('hex'), row[0].toString('hex')
+          else
+            test.strictEqual columns[0].value, row[0]
+      else
+        test.strictEqual stmts.length, 0
+        connection.close()
+    testOne()
+
+  connection.on 'end', (info) ->
+    test.done()
+


Refresh button spec

Refresh button spec

error: pathspec 'test/components/buttons/refresh-button.spec.coffee' did not match any file(s) known to git

--- test/components/buttons/refresh-button.spec.coffee
+++ test/components/buttons/refresh-button.spec.coffee
@@ -0,0 +1,15 @@
+{Testing, expect, sinon, _} = require 'test/helpers'
+
+Button = require 'components/buttons/refresh-button'
+
+describe 'Refresh Button Component', ->
+
+  beforeEach ->
+    @props =
+      beforeText: 'before '
+      buttonText: 'Refresh'
+      afterText: ' after'
+
+  it 'can use custom text', ->
+    Testing.renderComponent( Button, props: @props ).then ({dom}) ->
+      expect(dom.textContent).equal('before Refresh after')


development kernel

development kernel

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


Fixed: stack apps versions were never displayed.

--- client/app/views/config_applications.coffee
+++ client/app/views/config_applications.coffee
@@ -38,8 +38,7 @@
         @deviceList = new ConfigDeviceList @devices
         @$el.find('.title-app').after @applicationList.$el
         @applications = new Application()
-        @stackApplications = new StackApplication()
-        @stackApps.fetch()
+        @stackApps.fetch reset: true
         @displayDevices()

     openUpdatePopover: (slug) ->


Update nl.coffee (#4034)

Update nl.coffee (#4034)

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


Updated uk.coffee.

Updated uk.coffee.

--- app/locale/uk.coffee
+++ app/locale/uk.coffee
@@ -136,10 +136,10 @@
     change_hero: "Змінити героя" # Go back from choose inventory to choose hero
     buy_gems: "Придбати самоцвіти"
     subscription_required: "Потрібен абонемет"
-#    subscribers_only: "Subscribers Only!"
-#    subscribe_unlock: "Subscribe to Unlock!"
+    subscribers_only: "Тільки для підписників!"
+    subscribe_unlock: "Придбайте підписку для розблокування!"
 #    subscriber_heroes: "Subscribe today to immediately unlock Amara, Hushbaum, and Hattori!"
-#    subscriber_gems: "Subscribe today to purchase this hero with gems!"
+    subscriber_gems: "Підпишіться сьогодні, щоб придбати цього героя за самоцвіти!"
     anonymous: "Гравець-анонім"
     level_difficulty: "Складність: "
     play_classroom_version: "Грати в версію для класу" # Choose a level in campaign version that you also can play in one of your courses
@@ -150,7 +150,7 @@
     adjust_volume: "Підлаштувати гучність"
     campaign_multiplayer: "Арени для мультиплеєра"
     campaign_multiplayer_description: "... в яких Ви програмуєте віч-на-віч із іншими гравцями."
-#    brain_pop_done: "You’ve defeated the Ogres with code! You win!"
+    brain_pop_done: "Ви перемогли Оґрів за допомогою коду! Ви перемогли!"

   code:
     if: "якщо" # Keywords--these translations show up on hover, so please translate them all, even if it's kind of long. (In the code editor, they will still be in English.)
@@ -610,9 +610,9 @@
     prompt_button: "Увійти до крамниці"
     recovered: "Попередні покупки самоцвітів відновлені. Будь ласка, поновіть сторінку."
     price: "x{{gems}} / міс"
-#    buy_premium: "Buy Premium"
-#    purchase: "Purchase"
-#    purchased: "Purchased"
+    buy_premium: "Придбати Преміум"
+    purchase: "Купити"
+    purchased: "Куплено"

   subscribe:
     subscribe_modal_title: "CodeCombat Преміум"
@@ -686,27 +686,27 @@
     support_part2: "support@codecombat.com"
     support_part3: "якщо у вас є які-небудь питання."

-#  premium_features:
-#    get_premium: "Get
CodeCombat
Premium" # Fit into the banner on the /features page
-#    master_coder: "Become a Master Coder by subscribing today!"
-#    subscribe_now: "Subscribe Now"
+  premium_features:
+    get_premium: "Отримайте
CodeCombat
Преміум" # Fit into the banner on the /features page
+    master_coder: "Станьте майстром програмування придбавши підписку вже сьогодні!"
+    subscribe_now: "Підписатися зараз"
 #    hero_blurb_1: "Get access to __premiumHeroesCount__ super-charged subscriber-only heroes! Harness the unstoppable power of Okar Stompfoot, the deadly precision of Naria of the Leaf, or summon \"adorable\" skeletons with Nalfar Cryptor."
 #    hero_blurb_2: "Premium Warriors unlock stunning martial skills like Warcry, Stomp, and Hurl Enemy. Or, play as a Ranger, using stealth and bows, throwing knives, traps! Try your skill as a true coding Wizard, and unleash a powerful array of Primordial, Necromantic or Elemental magic!"
-#    hero_caption: "Exciting new heroes!"
+    hero_caption: "Нові вражаючі герої!"
 #    pet_blurb_1: "Pets aren't just adorable companions, they also provide unique functionality and methods. The Baby Griffin can fly over obstacles while helping the hero, the Wolf Pup can fetch potions, and the Cougar can speak!"
 #    pet_blurb_2: "Collect all the pets to discover their unique abilities!"
 #    pet_caption: "Adopt pets to accompany your hero!"
 #    game_dev_blurb: "Learn game scripting and build new levels to share with your friends! Place the items you want, write code for unit logic and behavior, and see if your friends can beat the level!"
-#    game_dev_caption: "Design your own games to challenge your friends!"
-#    everything_in_premium: "Everything you get in CodeCombat Premium:"
-#    list_gems: "Receive bonus gems every month to buy gear, pets, and heroes"
-#    list_levels: "Gain access to __premiumLevelsCount__ more levels"
-#    list_heroes: "Unlock exclusive heroes, include Ranger and Wizard classes"
-#    list_game_dev: "Make and share games with friends"
-#    list_web_dev: "Build websites and interactive apps"
+    game_dev_caption: "Проектуйте власні ігри, щоб кинути виклик своїм друзям!"
+    everything_in_premium: "Все, що ви отримаєте в Преміум CodeCombat:"
+    list_gems: "Отримуйте бонусні самоцвіти щомісяця для придбання спорядження, компаньйонів та героїв"
+    list_levels: "Отримайте доступ до __premiumLevelsCount__ додаткових рівнів"
+    list_heroes: "Розблокуйте екслюзивних героїв, в тому числі класи рейнджера та чаклуна"
+    list_game_dev: "Створюйте та діліться іграми з друзями"
+    list_web_dev: "Створюйте веб-сайти та інтерактивні програми"
 #    list_items: "Equip Premium-only items like pets"
-#    list_support: "Get Premium support to help you debug tricky code"
-#    list_clans: "Create private clans to invite your friends and compete on a group leaderboard"
+    list_support: "Отримайте преміум підтримку для допомоги з відладкою заплутаного коду"
+    list_clans: "Створюйте приватні клани, щоб запросити ваших друзів та змагатися в груповому лідерстві"

   choose_hero:
     choose_hero: "Оберіть героя"
@@ -1045,7 +1045,7 @@
     saved: "Зміни збережено"
     password_mismatch: "Паролі не збігаються."
     password_repeat: "Будь ласка, повторіть пароль."
-#    file_size_limit: "(max file size: 1MB)"
+    file_size_limit: "(максимальний розмір файлу: 1МБ)"

   keyboard_shortcuts:
     keyboard_shortcuts: "Клавіатурні скорочення"


Add install cli commands for apm and atom

--- src/workspace-view.coffee
+++ src/workspace-view.coffee
@@ -6,6 +6,7 @@
 {$, $$, View} = require './space-pen-extensions'
 fs = require 'fs-plus'
 Workspace = require './workspace'
+CommandInstaller = require './command-installer'
 EditorView = require './editor-view'
 PaneView = require './pane-view'
 PaneColumnView = require './pane-column-view'
@@ -108,6 +109,12 @@
     @command 'application:open-your-keymap', -> ipc.sendChannel('command', 'application:open-your-keymap')
     @command 'application:open-your-stylesheet', -> ipc.sendChannel('command', 'application:open-your-stylesheet')

+    @command 'window:install-atom-cli', =>
+      CommandInstaller.installApmCommand (error) => @commandInstalationDialog(error, 'atom')
+
+    @command 'window:install-apm-cli', =>
+      CommandInstaller.installApmCommand (error) => @commandInstalationDialog(error, 'apm')
+
     @command 'window:run-package-specs', => ipc.sendChannel('run-package-specs', path.join(atom.project.getPath(), 'spec'))
     @command 'window:increase-font-size', =>
       atom.config.set("editor.fontSize", atom.config.get("editor.fontSize") + 1)
@@ -130,6 +137,17 @@
     @command 'core:close', => if @getActivePaneItem()? then @destroyActivePaneItem() else @destroyActivePane()
     @command 'core:save', => @saveActivePaneItem()
     @command 'core:save-as', => @saveActivePaneItemAs()
+
+  commandInstalationDialog: (error, commandName) ->
+    if error?
+      installDirectory = CommandInstaller.getInstallDirectory()
+      atom.confirm
+        message: error.message
+        detailedMessage: "Make sure #{CommandInstaller.getInstallDirectory()} is writable. Run 'sudo chmod o+w #{installDirectory}' to fix this problem."
+    else
+      atom.confirm
+        message: "Command installed."
+        detailedMessage: "You can now use `#{commandName}` from the terminal."

   # Private:
   handleFocus: (e) ->


Fixed mark sprite scaling some more.

Fixed mark sprite scaling some more.

--- app/lib/surface/Mark.coffee
+++ app/lib/surface/Mark.coffee
@@ -234,7 +234,7 @@
     if @name is 'debug' or (@name is 'shadow' and @sprite.thang?.shape in ["rectangle", "box"])
       @mark.rotation = @sprite.thang.rotation * 180 / Math.PI

-  updateScale: ->
+  updateScale: (log) ->
     if @name is 'bounds' and (@sprite.thang.width isnt @lastWidth or @sprite.thang.height isnt @lastHeight)
       oldMark = @mark
       @buildBounds()
@@ -243,6 +243,7 @@
       oldMark.parent.removeChild oldMark

     if @markSprite?
+      @markSprite.scaleFactor = 1.2
       @markSprite.updateScale()
     return unless @name in ["selection", "target", "repair", "highlight"]
     if @sprite?.imageObject


Fix edge key

Fix edge key

--- components/split_test/running_tests.coffee
+++ components/split_test/running_tests.coffee
@@ -31,7 +31,7 @@

   show_metaphysics:
     key: 'show_page_metaphysics'
-    edge: true
+    edge: 'true'
     outcomes:
       true: 0.5
       false: 0.5


Use new runas API for grunt install on Windows.

--- build/tasks/install-task.coffee
+++ build/tasks/install-task.coffee
@@ -1,24 +1,20 @@
 path = require 'path'
+runas = null

 module.exports = (grunt) ->
-  {cp, mkdir, rm, spawn} = require('./task-helpers')(grunt)
+  {cp, mkdir, rm} = require('./task-helpers')(grunt)

   grunt.registerTask 'install', 'Install the built application', ->
     installDir = grunt.config.get('atom.installDir')
     shellAppDir = grunt.config.get('atom.shellAppDir')
     if process.platform is 'win32'
-      done = @async()
-
-      runas = require 'runas'
+      runas ?= require 'runas'
       copyFolder = path.resolve 'script', 'copy-folder.cmd'
-      # cmd /c ""script" "source" "destination""
-      arg = "/c \"\"#{copyFolder}\" \"#{shellAppDir}\" \"#{installDir}\"\""
-      if runas('cmd', [arg], hide: true) isnt 0
-        done("Failed to copy #{shellAppDir} to #{installDir}")
+      if runas('cmd', ['/c', copyFolder, shellAppDir, installDir], admin: true) isnt 0
+        grunt.log.error("Failed to copy #{shellAppDir} to #{installDir}")

       createShortcut = path.resolve 'script', 'create-shortcut.cmd'
-      args = ['/c', createShortcut, path.join(installDir, 'atom.exe'), 'Atom']
-      spawn {cmd: 'cmd', args}, done
+      runas('cmd', ['/c', createShortcut, path.join(installDir, 'atom.exe'), 'Atom'])
     else
       rm installDir
       mkdir path.dirname(installDir)


RemoteApi: verify session and use group information from session

--- workers/social/lib/social/remoteapi.coffee
+++ workers/social/lib/social/remoteapi.coffee
@@ -79,6 +79,18 @@
   return { model, id, method, sessionToken }

+verifySession = (Models, sessionToken, callback) ->
+
+  Models.JSession.one { clientId: sessionToken }, (err, session) ->
+
+    if err or not session
+      return callback apiErrors.unauthorizedRequest
+
+    { groupName: group } = session
+
+    callback null, { userArea: { group }, sessionToken }
+
+
 sendSignatureErr = (signatures, method, res) ->

   # Make signatures human readable ~ GG
@@ -117,52 +129,58 @@

     { model, id, method, sessionToken } = parsedRequest

-    constructorName = getConstructorName model, Models
+    verifySession Models, sessionToken, (err, context) ->

-    unless constructorName
-      sendApiError res, apiErrors.invalidInput
-      return
+      if err
+        sendApiError res, err
+        return

-    body = if req.body then clone req.body else null
-    req.body ?= {}
-    req.body  = { userArea: {}, sessionToken }
+      constructorName = getConstructorName model, Models

-    args = if Array.isArray body
-    then body
-    else if (Object.keys body).length
-    then [body]
-    else []
+      unless constructorName
+        sendApiError res, apiErrors.invalidInput
+        return

-    args.push (->)
+      body = if req.body then clone req.body else null
+      req.body ?= {}
+      req.body  = context

-    callbacks = { 1: [args.length - 1] }
+      args = if Array.isArray body
+      then body
+      else if (Object.keys body).length
+      then [body]
+      else []

-    type = if id then 'instance' else 'static'
+      args.push (->)

-    unless Models[constructorName].getSignature type, method
-      sendApiError res, { ok: false, error: 'No such method' }
-      return
+      callbacks = { 1: [args.length - 1] }

-    [validCall, signatures] = Models[constructorName].testSignature type, method, args
+      type = if id then 'instance' else 'static'

-    unless validCall
-      sendSignatureErr signatures, "#{constructorName}.#{method}", res
-      return
+      unless Models[constructorName].getSignature type, method
+        sendApiError res, { ok: false, error: 'No such method' }
+        return

-    bongoRequest = {
-      arguments: args
-      callbacks
-      method: {
-        constructorName
-        method
-        type
+      [validCall, signatures] = Models[constructorName].testSignature type, method, args
+
+      unless validCall
+        sendSignatureErr signatures, "#{constructorName}.#{method}", res
+        return
+
+      bongoRequest = {
+        arguments: args
+        callbacks
+        method: {
+          constructorName
+          method
+          type
+        }
       }
-    }

-    bongoRequest.method.id = id  if id
-    req.body.queue = [ bongoRequest ]
+      bongoRequest.method.id = id  if id
+      req.body.queue = [ bongoRequest ]

-    (koding.expressify {
-      rateLimitOptions: KONFIG.nodejsRateLimiter
-      processPayload
-    }) req, res
+      (koding.expressify {
+        rateLimitOptions: KONFIG.nodejsRateLimiter
+        processPayload
+      }) req, res


add js snippet : addEventListener('',function...

error: pathspec 'snippets/language-javascript.cson' did not match any file(s) known to git

--- snippets/language-javascript.cson
+++ snippets/language-javascript.cson
@@ -0,0 +1,4 @@
+'.source.js':
+  'Ti: addEventListener':
+    'prefix': 'aelf'
+    'body': 'addEventListener(\'${1:eventName}\', function(e) {\n\t$2\n});'


Add TextEditor::onDidChangeEncoding spec

--- spec/text-editor-spec.coffee
+++ spec/text-editor-spec.coffee
@@ -156,6 +156,19 @@
       buffer.setPath(undefined)

       expect(observed).toEqual [__filename, undefined]
+
+  describe "encoding", ->
+    it "notifies ::onDidChangeEncoding observers when the editor encoding changes", ->
+      observed = []
+      editor.onDidChangeEncoding (encoding) -> observed.push(encoding)
+
+      editor.setEncoding('utf16le')
+      editor.setEncoding('utf16le')
+      editor.setEncoding('utf16be')
+      editor.setEncoding()
+      editor.setEncoding()
+
+      expect(observed).toEqual ['utf16le', 'utf16be', 'utf8']

   describe "cursor", ->
     describe ".getLastCursor()", ->


context fix

context fix

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


Clear project paths after creating view

Clear project paths after creating view

--- lib/main.coffee
+++ lib/main.coffee
@@ -50,6 +50,7 @@
     unless @projectView?
       ProjectView  = require './project-view'
       @projectView = new ProjectView(@projectPaths)
+      @projectPaths = null
     @projectView

   createGitStatusView:  ->


Create edit_idea_via_ajax feature branch

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


Fix error adding product in cart by image click.

The product was being added twice in the cart when the product image
was clicked. Removed duplicate event handle for click.

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


Fixed bug when using Azure Cosmos DB

Fixed bug when using Azure Cosmos DB

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


On delete sprint reload the user stories

--- app/coffee/modules/backlog/main.coffee
+++ app/coffee/modules/backlog/main.coffee
@@ -65,6 +65,7 @@
         @scope.$on("sprintform:create:success", @.loadProjectStats)
         @scope.$on("sprintform:remove:success", @.loadSprints)
         @scope.$on("sprintform:remove:success", @.loadProjectStats)
+        @scope.$on("sprintform:remove:success", @.loadUserstories)
         @scope.$on("usform:new:success", @.loadUserstories)
         @scope.$on("usform:edit:success", @.loadUserstories)
         @scope.$on("sprint:us:move", @.moveUs)


Remove TokenizedLine::copy

Remove TokenizedLine::copy

--- src/tokenized-line.coffee
+++ src/tokenized-line.coffee
@@ -79,25 +79,6 @@
       tokens.push(new Token(properties))

     tokens
-
-  copy: ->
-    copy = new TokenizedLine
-    copy.tokenIterator = @tokenIterator
-    copy.openScopes = @openScopes
-    copy.text = @text
-    copy.tags = @tags
-    copy.specialTokens = @specialTokens
-    copy.startBufferColumn = @startBufferColumn
-    copy.bufferDelta = @bufferDelta
-    copy.ruleStack = @ruleStack
-    copy.lineEnding = @lineEnding
-    copy.invisibles = @invisibles
-    copy.endOfLineInvisibles = @endOfLineInvisibles
-    copy.tabLength = @tabLength
-    copy.firstNonWhitespaceIndex = @firstNonWhitespaceIndex
-    copy.firstTrailingWhitespaceIndex = @firstTrailingWhitespaceIndex
-    copy.fold = @fold
-    copy

   # This clips a given screen column to a valid column that's within the line
   # and not in the middle of any atomic tokens.


Kloud: use supportedProviders list instead

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


added white interpolation in hsv test case

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


Revert tests changes

Revert tests changes

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


destroy var for safety

destroy var for safety

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


remove watch mode in development environment

--- config/environments/development.coffee
+++ config/environments/development.coffee
@@ -4,6 +4,6 @@
     app.configure 'development', ->
         app.enable 'log actions'
         app.enable 'env info'
-        app.enable 'watch'
+        app.disable 'watch'
         app.use express.errorHandler
             dumpExceptions: true, showStack: true


Quick fix #112

Quick fix #112

Might need an improved fix

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


Relative path seems to work.

Relative path seems to work.

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


integrated dashboard

integrated dashboard

error: pathspec '@client/dashboard/dashboard.coffee' did not match any file(s) known to git

--- @client/dashboard/dashboard.coffee
+++ @client/dashboard/dashboard.coffee
@@ -0,0 +1,177 @@
+require './admin'
+require './notifications'
+require './roles'
+require './tags'
+require './translations'
+
+
+window.styles += """
+  #DASHBOARD-flex-container {
+    display: flex;
+    flex-wrap: no-wrap;
+    border-top: 1px solid #EEEEEE;
+  }
+  #DASHBOARD-menu {
+    width: 265px;
+    background: rgb(246,246,246);
+    background: linear-gradient(180deg, rgba(246,246,246,1) 88%, rgba(255,255,255,1) 100%);
+    padding-bottom: 70px;
+  }
+  #DASHBOARD-menu a {
+    text-decoration: none;
+    opacity: .35;
+    color: black;
+    padding: 22px 24px 0 24px;
+    display: block;
+    font-weight: 600;
+  } #DASHBOARD-menu a:hover, #DASHBOARD-menu a.active {
+    opacity: 1;
+  }
+  #DASHBOARD-menu a .label {
+    vertical-align: middle;
+  }
+  #DASHBOARD-menu a .icon {
+    vertical-align: middle;
+    padding-right: 18px;
+    width: 45px;
+    display: inline-block;
+  }
+  #DASHBOARD-menu div {
+    text-transform: uppercase;
+    padding: 56px 24px 0 24px;
+    font-weight: 600;
+    opacity: .35;
+    font-size: 12px;
+  }
+  #DASHBOARD-main {
+    flex: 1;
+    padding: 30px 56px;
+  }
+  #DASHBOARD-title {
+    font-weight: 400;
+    font-size: 36px;
+    color: #898989;
+  }
+
+"""
+
+window.Dashboard = ReactiveComponent
+  displayName: 'Dashboard'
+  render: ->
+
+
+    current_user = fetch '/current_user'
+    is_admin = current_user.is_admin
+    is_moderator = current_user.is_moderator
+    is_super = current_user.is_super_admin
+
+    loc = fetch 'location'
+
+    switch loc.url
+      when '/dashboard/email_notifications'
+        title = 'Notifications'
+        Widget = Notifications
+      when '/dashboard/data_import_export'
+        title = 'Data Import & Export'
+        Widget = DataDash
+      when '/dashboard/moderate'
+        title = 'Moderate Content'
+        Widget = ModerationDash
+      when '/dashboard/application'
+        title = 'Forum Settings'
+        Widget = AppSettingsDash
+      when '/dashboard/customizations'
+        title = 'Customizations'
+        Widget = CustomizationsDash
+      when '/dashboard/roles'
+        title = 'Permissions & Roles'
+        Widget = SubdomainRoles
+      when '/dashboard/tags'
+        title = 'User Tags'
+        Widget = UserTags
+      when '/dashboard/translations'
+        title = 'Language Translation'
+        Widget = TranslationsDash
+      else
+        title = "No Dashboard at #{loc.url}"
+
+
+
+    draw_menu_option = (opts) ->
+
+      A
+        className: if opts.href == loc.url then 'active'
+        href: opts.href
+
+        if opts.icon
+          SPAN
+            className: 'icon'
+            dangerouslySetInnerHTML: __html: icons[opts.icon]
+
+        SPAN
+          className: 'label'
+          translator "user_menu.option.#{opts.label}", opts.label
+
+    draw_menu_separator = (title) ->
+      DIV null,
+        title
+
+    DIV
+      id: "DASHBOARD-flex-container"
+
+      DIV
+        id: "DASHBOARD-menu"
+
+        draw_menu_separator 'settings'
+
+        draw_menu_option {href: '/edit_profile', label: 'Edit Profile', icon: 'avatar'}
+        draw_menu_option {href: '/dashboard/email_notifications', label: 'Email Settings', icon: 'bell'}
+
+        if is_admin
+          [
+            draw_menu_separator "forum setup"
+            draw_menu_option {href: '/dashboard/application', label: 'Forum Settings', icon: 'forum'}
+            draw_menu_option {href: '/dashboard/roles', label: 'Permissions & Roles', icon: 'lock'}
+          ]
+
+        if is_super
+          draw_menu_option {href: '/dashboard/customizations', label: 'Customizations', icon: 'coding'}
+
+        if is_admin
+          [
+            draw_menu_separator "administration"
+            draw_menu_option {href: '/dashboard/moderate', label: 'Moderate', icon: 'moderation'}
+            draw_menu_option {href: '/dashboard/data_import_export', label: 'Import / Export Data', icon: 'upload'}
+          ]
+
+        if is_super
+          draw_menu_option {href: '/dashboard/tags', label: 'User Tags', icon: 'user_data'}
+
+        draw_menu_separator 'other'
+        draw_menu_option {href: '/dashboard/translations', label: 'Language Translation', icon: 'translate'}
+
+
+      DIV
+        id: "DASHBOARD-main"
+
+
+        H1
+          id: "DASHBOARD-title"
+          TRANSLATE "dashboard.#{title}.header",  title
+
+        Widget? key: "/page#{loc.url}"
+
+
+icons =
+  avatar:     '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="23 25 53 50" enable-background="new 0 0 100 100" xml:space="preserve"><path d="M25.7,75.2c0,0,0.1,0,0.1,0c1.1-0.1,1.9-1,1.8-2.1c-0.2-2.3,0-6.2,3.1-6.9c10.7-2.7,14.4-6.3,15.6-8.6  c1,0.3,2.1,0.4,3.2,0.4c0,0,0.1,0,0.1,0h0.2c0,0,0.1,0,0.1,0c1.3,0,2.5-0.2,3.7-0.5c1.3,2.4,4.9,6.1,15.6,8.8  c3.1,0.8,3.3,4.7,3.1,6.9c-0.1,1.1,0.7,2,1.8,2.1c0,0,0.1,0,0.1,0c1,0,1.8-0.8,1.9-1.8c0.4-5.9-1.8-9.9-6-11  c-9.6-2.4-12.3-5.4-13-6.7c0.7-0.5,1.3-1,1.9-1.7c4.9-5.5,4.1-14.9,4-15.9c-0.5-9.9-7.3-13.4-13-13.4c-0.1,0-0.2,0-0.3,0  c-0.1,0-0.2,0-0.3,0c-5.7,0-12.5,3.5-13,13.4c-0.1,0.9-0.9,10.4,4,15.9c0.7,0.8,1.4,1.4,2.2,1.9c-0.2,0.3-0.5,0.6-0.9,1  c-1.5,1.5-4.8,3.6-12.1,5.4c-4.2,1.1-6.4,5.1-6,10.9C23.9,74.4,24.7,75.2,25.7,75.2z M40.4,38.5c0,0,0-0.1,0-0.1  c0.4-9.1,7.1-9.8,9.1-9.8c0.1,0,0.2,0,0.2,0c0.1,0,0.1,0,0.2,0c0,0,0.1,0,0.2,0c2,0,8.7,0.7,9.1,9.8c0,0,0,0.1,0,0.1  c0.3,2.4,0.2,9.3-3.1,13c-1.5,1.7-3.6,2.6-6.3,2.6c0,0,0,0-0.1,0c0,0,0,0-0.1,0c-2.7,0-4.8-0.9-6.3-2.6  C39.5,47.1,40.4,38.6,40.4,38.5z"/></svg>'
+  upload:     '<svg xmlns="http://www.w3.org/2000/svg" viewBox="2 4 28 22" x="0px" y="0px"><g data-name="upload cloud"><path d="M30,17.9375a4.3632,4.3632,0,0,0-5.0087-4.327c.0011-.0578.0087-.1151.0087-.173A8.875,8.875,0,0,0,7.8149,10.3218,5.9967,5.9967,0,0,0,8,22.3125h3a1,1,0,0,0,0-2H8a4,4,0,0,1,0-8,4.0947,4.0947,0,0,1,.4268.0225.9464.9464,0,0,0,.118-.0113.9685.9685,0,0,0,.1976-.0188.9517.9517,0,0,0,.1826-.0614.8625.8625,0,0,0,.3111-.214.95.95,0,0,0,.1154-.1378.975.975,0,0,0,.0923-.182.9173.9173,0,0,0,.0523-.1033A6.8771,6.8771,0,0,1,22.86,14.8232a.9958.9958,0,0,0,.1459.7529l.0025.0069a1.0034,1.0034,0,0,0,1.376.3291,2.375,2.375,0,1,1,1.24,4.4h-4.5a1,1,0,0,0,0,2h4.9375a.9931.9931,0,0,0,.3983-.0845A4.38,4.38,0,0,0,30,17.9375Z"/><path d="M20.6,16.6377l-4-3a.996.996,0,0,0-1.1992,0l-4,3a1,1,0,0,0,1.1992,1.6l2.4-1.8v10a1,1,0,0,0,2,0v-10l2.4,1.8a1,1,0,0,0,1.1992-1.6Z"/></g></svg>'
+  translate:  '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="10 10 60 60" style="enable-background:new 0 0 80 80;" xml:space="preserve"><g><path d="M40,16c0-2.21-1.79-4-4-4H16c-2.21,0-4,1.79-4,4v20c0,2.21,1.79,4,4,4h20c2.21,0,4-1.79,4-4V16z M38,36c0,1.1-0.9,2-2,2H16   c-1.1,0-2-0.9-2-2V16c0-1.1,0.9-2,2-2h20c1.1,0,2,0.9,2,2V36z"/><path d="M64,40H44c-2.21,0-4,1.79-4,4v20c0,2.21,1.79,4,4,4h20c2.21,0,4-1.79,4-4V44C68,41.79,66.21,40,64,40z M59.32,59.05   c0.52,0.18,0.8,0.74,0.63,1.27C59.81,60.74,59.42,61,59,61c-0.1,0-0.21-0.02-0.32-0.05c-1.97-0.66-3.5-1.5-4.68-2.4301   c-1.18,0.9301-2.71,1.77-4.68,2.4301C49.21,60.98,49.1,61,49,61c-0.42,0-0.81-0.26-0.95-0.68c-0.17-0.53,0.11-1.09,0.63-1.27   c1.61-0.53,2.87-1.2,3.85-1.93c-2.02-2.27-2.46-4.72-2.54-6.12H49c-0.55,0-1-0.45-1-1s0.45-1,1-1h4v-1c0-0.55,0.45-1,1-1   s1,0.45,1,1v1h4c0.55,0,1,0.45,1,1s-0.45,1-1,1h-0.99c-0.08,1.4-0.52,3.85-2.54,6.12C56.45,57.85,57.71,58.51,59.32,59.05z"/><path d="M54,55.79c1.6-1.82,1.96-3.72,2.02-4.79h-4.05C52.02,52.07,52.38,53.98,54,55.79z"/><path d="M26.9229,19.6152C26.7676,19.2432,26.4033,19,26,19s-0.7676,0.2432-0.9229,0.6152l-2.7814,6.6755   C22.1133,26.4718,22,26.7224,22,27c0,0.0001,0.0001,0.0001,0.0001,0.0002l-1.9229,4.615   c-0.2129,0.5098,0.0283,1.0957,0.5381,1.3076c0.5098,0.2129,1.0947-0.0273,1.3076-0.5381L23.7498,28h4.5004l1.827,4.3848   C30.2373,32.7686,30.6084,33,31,33c0.1289,0,0.2588-0.0244,0.3848-0.0771c0.5098-0.2119,0.751-0.7979,0.5381-1.3076   L26.9229,19.6152z M24.5832,26L26,22.5996L27.4168,26H24.5832z"/><path d="M43.1663,27.5197c0.0552,0.0881,0.1168,0.1675,0.1959,0.2344c0.0154,0.0131,0.0219,0.0335,0.0382,0.0457l4,3   C47.5801,30.9346,47.79,31,47.999,31c0.3047,0,0.6045-0.1377,0.8008-0.4004c0.332-0.4414,0.2422-1.0684-0.2002-1.3994L46.9999,28   H50c0.2861,0,7,0.0908,7,8c0,0.5527,0.4473,1,1,1s1-0.4473,1-1c0-9.8857-8.9102-10-9-10h-3.0001l1.5997-1.2002   c0.4424-0.3311,0.5322-0.958,0.2002-1.3994c-0.3311-0.4434-0.958-0.5322-1.3994-0.2002l-4,3   c-0.0163,0.0122-0.0228,0.0326-0.0382,0.0457c-0.0791,0.0669-0.1408,0.1464-0.196,0.2346   c-0.0216,0.0345-0.0496,0.0624-0.0668,0.0992C43.0391,26.7084,43,26.8484,43,27s0.0391,0.2916,0.0994,0.4203   C43.1166,27.4572,43.1447,27.4851,43.1663,27.5197z"/><path d="M36.834,52.4807c-0.0552-0.0883-0.1171-0.1678-0.1962-0.2347c-0.0154-0.0131-0.0219-0.0335-0.0381-0.0457l-4-3   c-0.4404-0.3301-1.0674-0.2422-1.3994,0.2002c-0.332,0.4414-0.2422,1.0684,0.2002,1.3994L33.0001,52H30c-0.2861,0-7-0.0908-7-8   c0-0.5527-0.4473-1-1-1s-1,0.4473-1,1c0,9.8857,8.9102,10,9,10h3.0001l-1.5997,1.2002c-0.4424,0.3311-0.5322,0.958-0.2002,1.3994   C31.3965,56.8623,31.6963,57,32.001,57c0.209,0,0.4189-0.0654,0.5986-0.2002l4-3c0.0164-0.0122,0.0228-0.0326,0.0382-0.0457   c0.0791-0.0669,0.1409-0.1464,0.196-0.2346c0.0215-0.0345,0.0496-0.0623,0.0668-0.0991C36.9609,53.2917,37,53.1517,37,53   s-0.0391-0.2918-0.0994-0.4205C36.8835,52.5428,36.8555,52.5151,36.834,52.4807z"/></g></svg>'
+  bell:       '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="20 15 60 70" version="1.1" x="0px" y="0px"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g fill-rule="nonzero" fill="#000000"><path d="M58.9863458,71.5 C58.726905,76.2379945 54.8027842,80 50,80 C45.1972158,80 41.273095,76.2379945 41.0136542,71.5 L27.0025482,71.5 C25.3425883,71.5 24,70.1608104 24,68.5029699 L24,65.5 C24,62.189348 26.688664,59.5 30.0020869,59.5 C29.9981947,59.5 30,47.4992494 30,47.4992494 C30,39.0465921 35.2858464,31.6357065 43,28.7587819 L43,28.4952534 C43,24.6330455 46.138457,21.5 50,21.5 C53.8656855,21.5 57,24.6311601 57,28.4952534 L57,28.7589486 C64.7139633,31.6362562 70,39.0483724 70,47.4992494 L70,59.4982567 C73.3063923,59.5 76,62.1883045 76,65.5 L76,68.5029699 C76,70.1542433 74.6530016,71.5 72.9974518,71.5 L58.9863458,71.5 Z M54.9753124,71.5 L45.0246876,71.5 C45.2755498,74.0266613 47.4073259,76 50,76 C52.5926741,76 54.7244502,74.0266613 54.9753124,71.5 Z M72,67.5 L72,65.5 C72,64.3992101 71.099016,63.5 69.9979131,63.5 C67.7877428,63.5 66,61.7131252 66,59.4982567 L66,47.4992494 C66,40.3240131 61.2358497,34.083713 54.4456568,32.1249199 L53,31.7078857 L53,28.4952534 C53,26.8412012 51.6574476,25.5 50,25.5 C48.3460522,25.5 47,26.8437313 47,28.4952534 L47,31.7078537 L45.5542654,32.1248469 C38.7637896,34.083424 34,40.3222636 34,47.4992494 L34,59.4982567 C34,61.7067825 32.2078843,63.5 30.0020869,63.5 C28.8980308,63.5 28,64.3982593 28,65.5 L28,67.5 L72,67.5 Z"/></g></g></svg>'
+  forum:      '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="6 17 88 65" enable-background="new 0 0 100 100" xml:space="preserve"><g><path d="M84.412,19.068H43.588c-3.916,0-7.177,2.833-7.857,6.557H15.588c-4.408,0-7.994,3.586-7.994,7.993v27.164   c0,4.408,3.586,7.994,7.994,7.994h19.456l12.867,11.518c0.468,0.42,1.065,0.638,1.668,0.638c0.368,0,0.738-0.081,1.083-0.247   c0.912-0.438,1.469-1.383,1.413-2.393l-0.532-9.516h4.868c3.593,0,6.639-2.384,7.642-5.653l11.858,10.614   c0.468,0.42,1.065,0.638,1.668,0.638c0.007,0,0.014-0.001,0.02,0c1.381,0,2.5-1.119,2.5-2.5c0-0.156-0.014-0.309-0.042-0.457   l-0.514-9.198h4.868c4.408,0,7.994-3.586,7.994-7.993V27.063C92.405,22.654,88.819,19.068,84.412,19.068z M56.412,63.776H48.9   c-0.687,0-1.344,0.283-1.816,0.782s-0.718,1.171-0.68,1.857l0.342,6.124l-9.079-8.126c-0.458-0.411-1.052-0.638-1.667-0.638H15.588   c-1.651,0-2.994-1.343-2.994-2.994V33.618c0-1.65,1.343-2.993,2.994-2.993h20.006v23.602c0,4.407,3.586,7.993,7.994,7.993h15.433   C58.511,63.143,57.539,63.776,56.412,63.776z M87.405,54.227c0,1.65-1.343,2.993-2.994,2.993H76.9   c-0.687,0-1.344,0.283-1.816,0.782s-0.718,1.171-0.68,1.857l0.342,6.124l-9.079-8.126C65.209,57.446,64.615,57.22,64,57.22H43.588   c-1.651,0-2.994-1.343-2.994-2.993V28.13c0-0.002,0-0.003,0-0.005s0-0.003,0-0.005v-1.058c0-1.651,1.343-2.994,2.994-2.994h40.823   c1.651,0,2.994,1.343,2.994,2.994V54.227z"/></g></svg>'
+  lock:       '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 40 40" version="1.1" x="0px" y="0px"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><rect x="0" y="0" width="40" height="40"/><path d="M20,20 C20.8817862,20 21.5484529,20 22,20 C30.836556,20 38,27.163444 38,36 L38,37 L36,37 L36,36 C36,28.2680135 29.7319865,22 22,22 C21.5473049,22 20.8806382,22 20,22 L20,22 C20,21.4477153 19.5522847,21 19,21 L19,20 L20,20 Z" fill="#000000" fill-rule="nonzero"/><path d="M22,16 C25.3137085,16 28,13.3137085 28,10 C28,6.6862915 25.3137085,4 22,4 C18.6862915,4 16,6.6862915 16,10 C16,13.3137085 18.6862915,16 22,16 Z M22,18 C17.581722,18 14,14.418278 14,10 C14,5.581722 17.581722,2 22,2 C26.418278,2 30,5.581722 30,10 C30,14.418278 26.418278,18 22,18 Z" fill="#000000" fill-rule="nonzero"/><path d="M11,32 C11,32.5522847 10.5522847,33 10,33 C9.44771525,33 9,32.5522847 9,32 L9,30.9146471 C8.41740381,30.7087289 8,30.1531094 8,29.5 C8,28.6715729 8.67157288,28 9.5,28 L10.5,28 C11.3284271,28 12,28.6715729 12,29.5 C12,30.1531094 11.5825962,30.7087289 11,30.9146471 L11,32 Z M4,23 L4,20 C4,16.6862915 6.6862915,14 10,14 C13.3137085,14 16,16.6862915 16,20 L16,23 L18,23 L18,38 L2,38 L2,23 L4,23 Z M4,25 L4,36 L16,36 L16,25 L4,25 Z M6,23 L14,23 L14,20 C14,17.790861 12.209139,16 10,16 C7.790861,16 6,17.790861 6,20 L6,23 Z" fill="#000000" fill-rule="nonzero"/></g></svg>'
+  coding:     '<svg xmlns="http://www.w3.org/2000/svg" viewBox="5 5 37 37" x="0px" y="0px"><g data-name="Layer 2"><path d="M41,6H7A1,1,0,0,0,6,7V41a1,1,0,0,0,1,1H41a1,1,0,0,0,1-1V7A1,1,0,0,0,41,6ZM20,11a1,1,0,1,1-1-1A1,1,0,0,1,20,11Zm-4,0a1,1,0,1,1-1-1A1,1,0,0,1,16,11Zm-5-1a1,1,0,1,1-1,1A1,1,0,0,1,11,10ZM40,40H8V16H21a1,1,0,0,0,.71-.29L25.41,12H40Z"/><path d="M17.29,22.29a1,1,0,0,0-1.41,0l-4,4a1,1,0,0,0,0,1.42l4,4a1,1,0,1,0,1.41-1.42L14,27l3.29-3.29A1,1,0,0,0,17.29,22.29Z"/><path d="M30.88,31.71a1,1,0,0,0,1.41,0l4-4a1,1,0,0,0,0-1.42l-4-4a1,1,0,0,0-1.41,0,1,1,0,0,0,0,1.42L34.17,27l-3.29,3.29A1,1,0,0,0,30.88,31.71Z"/><path d="M25.11,22.55l-4,8a1,1,0,0,0,.44,1.34A.93.93,0,0,0,22,32a1,1,0,0,0,.89-.55l4-8a1,1,0,1,0-1.78-.9Z"/></g></svg>'
+  moderation: '<svg xmlns:x="http://ns.adobe.com/Extensibility/1.0/" xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/" xmlns:graph="http://ns.adobe.com/Graphs/1.0/" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="3 3 95 95" style="enable-background:new 0 0 100 100;" xml:space="preserve"><switch><foreignObject requiredExtensions="http://ns.adobe.com/AdobeIllustrator/10.0/" x="0" y="0" width="1" height="1"/><g i:extraneous="self"><g><path d="M95.1,84.8L74,65.7c4.9-6.6,7.9-14.7,7.9-23.6C81.8,20.3,64,2.5,42.2,2.5S2.5,20.3,2.5,42.2s17.8,39.7,39.7,39.7     c8.8,0,17-2.9,23.6-7.9l19.1,21.1c0.2,0.2,0.3,0.4,0.5,0.5c3,2.7,7.6,2.5,10.3-0.5C98.3,92.1,98.1,87.5,95.1,84.8z M11.1,42.2     C11.1,25,25,11.1,42.2,11.1S73.2,25,73.2,42.2S59.3,73.2,42.2,73.2S11.1,59.3,11.1,42.2z"/><path d="M52.6,30.8L38.1,46.5l-6.4-6.9c-1.6-1.7-4.3-1.8-6.1-0.2c-1.7,1.6-1.8,4.3-0.2,6.1l9.5,10.3c0.8,0.9,2,1.4,3.2,1.4     s2.3-0.5,3.2-1.4l17.7-19.1c1.6-1.7,1.5-4.5-0.2-6.1C57,29,54.2,29.1,52.6,30.8z"/></g></g></switch></svg>'
+  user_data:  '<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" stroke-width="0.501" stroke-linejoin="bevel" fill-rule="evenodd" version="1.1" overflow="visible" viewBox="10 20 80 55" x="0px" y="0px"><g fill="none" stroke="black" transform="scale(1 -1)"><g transform="translate(0 -96)"><g><path d="M 8.625,23.701 L 8.625,72.3 C 8.625,73.334 9.465,74.175 10.5,74.175 L 85.501,74.175 C 86.535,74.175 87.376,73.334 87.376,72.3 L 87.376,23.701 C 87.376,22.666 86.535,21.826 85.501,21.826 L 10.5,21.826 C 9.465,21.826 8.625,22.666 8.625,23.701 Z M 83.626,25.576 L 83.626,70.425 L 12.375,70.425 L 12.375,25.576 L 83.626,25.576 Z M 17.778,33.112 L 17.778,34.987 C 17.778,38.826 19.254,41.73 21.775,43.611 C 24.216,45.432 27.432,46.147 30.721,46.147 C 34.008,46.147 37.224,45.432 39.665,43.611 C 42.187,41.728 43.662,38.829 43.662,34.987 L 43.662,33.112 L 17.778,33.112 Z M 37.422,40.605 C 35.856,41.774 33.539,42.397 30.721,42.397 C 27.901,42.397 25.583,41.774 24.017,40.605 C 22.904,39.774 22.06,38.586 21.707,36.869 L 39.733,36.869 C 39.379,38.587 38.536,39.773 37.422,40.605 Z M 49.433,42.366 C 49.433,43.4 50.273,44.241 51.308,44.241 L 67.636,44.241 C 68.67,44.241 69.511,43.4 69.511,42.366 C 69.511,41.331 68.67,40.491 67.636,40.491 L 51.308,40.491 C 50.273,40.491 49.433,41.331 49.433,42.366 Z M 23.246,55.433 C 23.246,59.558 26.593,62.906 30.719,62.906 C 34.844,62.906 38.192,59.558 38.192,55.433 C 38.192,51.307 34.844,47.96 30.719,47.96 C 26.593,47.96 23.246,51.307 23.246,55.433 Z M 49.433,49.866 C 49.433,50.9 50.273,51.741 51.308,51.741 L 75.886,51.741 C 76.92,51.741 77.761,50.9 77.761,49.866 C 77.761,48.831 76.92,47.991 75.886,47.991 L 51.308,47.991 C 50.273,47.991 49.433,48.831 49.433,49.866 Z M 34.442,55.433 C 34.442,57.487 32.773,59.156 30.719,59.156 C 28.664,59.156 26.996,57.487 26.996,55.433 C 26.996,53.378 28.664,51.71 30.719,51.71 C 32.773,51.71 34.442,53.378 34.442,55.433 Z M 49.433,57.366 C 49.433,58.4 50.273,59.241 51.308,59.241 L 75.886,59.241 C 76.92,59.241 77.761,58.4 77.761,57.366 C 77.761,56.331 76.92,55.491 75.886,55.491 L 51.308,55.491 C 50.273,55.491 49.433,56.331 49.433,57.366 Z" stroke="none" fill="#000000" fill-rule="evenodd" stroke-width="0.5" marker-start="none" marker-end="none" stroke-miterlimit="79.8403193612775"/></g></g></g></svg>'
+
+
+


team export (WIP)

team export (WIP)

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

--- scripts/team-export.coffee
+++ scripts/team-export.coffee
@@ -0,0 +1,19 @@
+require 'colors'
+env = require '../config/env'
+mongoose = require('../models')(env.mongo_url)
+
+Team = mongoose.model 'Team'
+Person = mongoose.model 'Person'
+
+console.log "name\temail\tteam_id"
+Team.find {}, (err, team) ->
+  throw err if err
+
+  Person.find { role: 'contestant', email: /@/, }
+  i = people.length
+  people.forEach (person) ->
+    person.team (err, team) ->
+      throw err if err
+      if team?
+        console.log "#{person.name ? ""}\t#{person.email.replace(/\.nodeknockout\.com$/, '')}\t#{team}"
+      mongoose.connection.close() if --i is 0


Do not do finds within the event method. Decreases likelihood of hitting bug in older versions of Chrome. https://edx.lighthouseapp.com/projects/102637/tickets/153


Add menu

Add menu


First tests in Coffee - sweet

First tests in Coffee - sweet

error: pathspec 'test/integration/controllers/v1/ApiController.test.coffee' did not match any file(s) known to git

--- test/integration/controllers/v1/ApiController.test.coffee
+++ test/integration/controllers/v1/ApiController.test.coffee
@@ -0,0 +1,19 @@
+###*
+# ApiController.test.js
+###
+
+request = require('supertest')
+should = require('should')
+
+###*
+# Test API "ping" endpoint.
+###
+describe 'Requests to the root (/api) path', ->
+  it 'GET: Returns a 200 status code', (done) ->
+    request(sails.hooks.http.app).get('/api').expect 200, done
+    return
+  return
+  it 'GET: Returns JSON format', (done) ->
+    request(sails.hooks.http.app).get('/api').expect 'content-type', /json/, done
+    return
+  return


update file

update file

error: pathspec 'snippets/scaffold.NLF.cson' did not match any file(s) known to git

--- snippets/scaffold.NLF.cson
+++ snippets/scaffold.NLF.cson
@@ -0,0 +1,586 @@
+'.source.nlf':
+  'English NLF':
+    'prefix': 'scaffold-English'
+    'body': """
+      # Header, don't edit
+      NLF v6
+      # Start editing here
+      # Language ID
+      ${1:1033}
+      # Font and size - dash (-) means default
+      ${2:-}
+      ${3:-}
+      # Codepage - dash (-) means ANSI code page
+      ${4:-}
+      # RTL - anything else than RTL means LTR
+      ${5:-}
+      # Translation by ${6:<your name>}
+      # ^Branding
+      ${7:Nullsoft Install System %s}
+      # ^SetupCaption
+      ${8:\$(^Name) Setup}
+      # ^UninstallCaption
+      ${9:\$(^Name) Uninstall}
+      # ^LicenseSubCaption
+      : ${10:License Agreement}
+      # ^ComponentsSubCaption
+      : ${11:Installation Options}
+      # ^DirSubCaption
+      : ${12:Installation Folder}
+      # ^InstallingSubCaption
+      : ${13:Installing}
+      # ^CompletedSubCaption
+      : ${14:Completed}
+      # ^UnComponentsSubCaption
+      : ${15:Uninstallation Options}
+      # ^UnDirSubCaption
+      : ${16:Uninstallation Folder}
+      # ^ConfirmSubCaption
+      : ${17:Confirmation}
+      # ^UninstallingSubCaption
+      : ${18:Uninstalling}
+      # ^UnCompletedSubCaption
+      : ${19:Completed}
+      # ^BackBtn
+      ${20:< &Back}
+      # ^NextBtn
+      ${21:&Next >}
+      # ^AgreeBtn
+      ${22:I &Agree}
+      # ^AcceptBtn
+      ${23:I &accept the terms of the License Agreement}
+      # ^DontAcceptBtn
+      ${24:I &do not accept the terms of the License Agreement}
+      # ^InstallBtn
+      ${25:&Install}
+      # ^UninstallBtn
+      ${26:&Uninstall}
+      # ^CancelBtn
+      ${27:Cancel}
+      # ^CloseBtn
+      ${28:&Close}
+      # ^BrowseBtn
+      ${29:B&rowse...}
+      # ^ShowDetailsBtn
+      ${30:Show &details}
+      # ^ClickNext
+      ${31:Click Next to continue.}
+      # ^ClickInstall
+      ${32:Click Install to start the installation.}
+      # ^ClickUninstall
+      ${33:Click Uninstall to start the uninstallation.}
+      # ^Name
+      ${34:Name}
+      # ^Completed
+      ${35:Completed}
+      # ^LicenseText
+      ${36:Please review the license agreement before installing \$(^NameDA). If you accept all terms of the agreement, click I Agree.}
+      # ^LicenseTextCB
+      ${37:Please review the license agreement before installing \$(^NameDA). If you accept all terms of the agreement, click the check box below. \$_CLICK}
+      # ^LicenseTextRB
+      ${38:Please review the license agreement before installing \$(^NameDA). If you accept all terms of the agreement, select the first option below. \$_CLICK}
+      # ^UnLicenseText
+      ${39:Please review the license agreement before uninstalling \$(^NameDA). If you accept all terms of the agreement, click I Agree.}
+      # ^UnLicenseTextCB
+      ${40:Please review the license agreement before uninstalling \$(^NameDA). If you accept all terms of the agreement, click the check box below. \$_CLICK}
+      # ^UnLicenseTextRB
+      ${41:Please review the license agreement before uninstalling \$(^NameDA). If you accept all terms of the agreement, select the first option below. \$_CLICK}
+      # ^Custom
+      ${42:Custom}
+      # ^ComponentsText
+      ${43:Check the components you want to install and uncheck the components you don't want to install. \$_CLICK}
+      # ^ComponentsSubText1
+      ${44:Select the type of install}:
+      # ^ComponentsSubText2_NoInstTypes
+      ${45:Select components to install}:
+      # ^ComponentsSubText2
+      ${46:Or, select the optional components you wish to install}:
+      # ^UnComponentsText
+      ${47:Check the components you want to uninstall and uncheck the components you don't want to uninstall. \$_CLICK}
+      # ^UnComponentsSubText1
+      ${48:Select the type of uninstall}:
+      # ^UnComponentsSubText2_NoInstTypes
+      ${49:Select components to uninstall}:
+      # ^UnComponentsSubText2
+      ${50:Or, select the optional components you wish to uninstall}:
+      # ^DirText
+      ${51:Setup will install \$(^NameDA) in the following folder. To install in a different folder, click Browse and select another folder. \$_CLICK}
+      # ^DirSubText
+      ${52:Destination Folder}
+      # ^DirBrowseText
+      ${53:Select the folder to install \$(^NameDA) in}:
+      # ^UnDirText
+      ${54:Setup will uninstall \$(^NameDA) from the following folder. To uninstall from a different folder, click Browse and select another folder. \$_CLICK}
+      # ^UnDirSubText
+      "${55}:"
+      # ^UnDirBrowseText
+      ${56:Select the folder to uninstall \$(^NameDA) from}:
+      # ^SpaceAvailable
+      "${57:Space available}: "
+      # ^SpaceRequired
+      "${58:Space required}: "
+      # ^UninstallingText
+      ${59:\$(^NameDA) will be uninstalled from the following folder. \$_CLICK}
+      # ^UninstallingSubText
+      ${60:Uninstalling from}:
+      # ^FileError
+      ${61:Error opening file for writing: \r\n\r\n\"$0"\r\n\r\nClick Abort to stop the installation,\r\nRetry to try again, or\r\nIgnore to skip this file.}
+      # ^FileError_NoIgnore
+      ${62:Error opening file for writing: \r\n\r\n\"$0"\r\n\r\nClick Retry to try again, or\r\nCancel to stop the installation.}
+      # ^CantWrite
+      "${63:Can't write}: "
+      # ^CopyFailed
+      ${64:Copy failed}
+      # ^CopyTo
+      "${65:Copy to }"
+      # ^Registering
+      "${66:Registering}: "
+      # ^Unregistering
+      "${67:Unregistering}: "
+      # ^SymbolNotFound
+      "${68:Could not find symbol}: "
+      # ^CouldNotLoad
+      "${69:Could not load}: "
+      # ^CreateFolder
+      "${70:Create folder}: "
+      # ^CreateShortcut
+      "${71:Create shortcut}: "
+      # ^CreatedUninstaller
+      "${72:Created uninstaller}: "
+      # ^Delete
+      "${73:Delete file}: "
+      # ^DeleteOnReboot
+      "${74:Delete on reboot}: "
+      # ^ErrorCreatingShortcut
+      "${75:Error creating shortcut}: "
+      # ^ErrorCreating
+      "${76:Error creating}: "
+      # ^ErrorDecompressing
+      ${77:Error decompressing data! Corrupted installer?}
+      # ^ErrorRegistering
+      ${78:Error registering DLL}
+      # ^ExecShell
+      "${79:ExecShell}: "
+      # ^Exec
+      "${80:Execute}: "
+      # ^Extract
+      "${81:Extract}: "
+      # ^ErrorWriting
+      "${82:Extract: error writing to file }"
+      # ^InvalidOpcode
+      ${83:Installer corrupted: invalid opcode}
+      # ^NoOLE
+      "${84:No OLE for}: "
+      # ^OutputFolder
+      "${85:Output folder}: "
+      # ^RemoveFolder
+      "${86:Remove folder}: "
+      # ^RenameOnReboot
+      "${87:Rename on reboot}: "
+      # ^Rename
+      "${88:Rename}: "
+      # ^Skipped
+      "${89:Skipped}: "
+      # ^CopyDetails
+      ${90:Copy Details To Clipboard}
+      # ^LogInstall
+      ${91:Log install process}
+      # ^Byte
+      ${92:B}
+      # ^Kilo
+      ${93:K}
+      # ^Mega
+      ${94:M}
+      # ^Giga
+      ${95:G}
+    """
+  'French NLF':
+    'prefix': 'scaffold-French'
+    'body': """
+      # Header, don't edit
+      NLF v6
+      # Start editing here
+      # Language ID
+      ${1:1036}
+      # Font and size - dash (-) means default
+      ${2:-}
+      ${3:-}
+      # Codepage - dash (-) means ANSI code page
+      ${4:-}
+      # RTL - anything else than RTL means LTR
+      ${5:-}
+      # Translation by ${6:<your name>}
+      # ^Branding
+      ${7:Nullsoft Install System %s}
+      # ^SetupCaption
+      ${8:Installation de \$(^Name)}
+      # ^UninstallCaption
+      ${9:Désinstallation de \$(^Name)}
+      # ^LicenseSubCaption
+      : ${10: Licence}
+      # ^ComponentsSubCaption
+      : ${11: Options d'installation}
+      # ^DirSubCaption
+      : ${12: Dossier d'installation}
+      # ^InstallingSubCaption
+      : ${13: Installation des fichiers}
+      # ^CompletedSubCaption
+      : ${14: Terminé}
+      # ^UnComponentsSubCaption
+      : ${15: Options de désinstallation}
+      # ^UnDirSubCaption
+      : ${16: Dossier de désinstallation}
+      # ^ConfirmSubCaption
+      : ${17: Confirmation}
+      # ^UninstallingSubCaption
+      : ${18: Désinstallation des fichiers}
+      # ^UnCompletedSubCaption
+      : ${19: Terminé}
+      # ^BackBtn
+      ${20:< &Précédent}
+      # ^NextBtn
+      ${21:&Suivant >}
+      # ^AgreeBtn
+      ${22:J'a&ccepte}
+      # ^AcceptBtn
+      ${23:J'a&ccepte les termes de la licence}
+      # ^DontAcceptBtn
+      ${24:Je &n'accepte pas les termes de la licence}
+      # ^InstallBtn
+      ${25:&Installer}
+      # ^UninstallBtn
+      ${26:&Désinstaller}
+      # ^CancelBtn
+      ${27:Annuler}
+      # ^CloseBtn
+      ${28:&Fermer}
+      # ^BrowseBtn
+      ${29:P&arcourir...}
+      # ^ShowDetailsBtn
+      ${30:P&lus d'infos}
+      # ^ClickNext
+      ${31:Cliquez sur Suivant pour continuer.}
+      # ^ClickInstall
+      ${32:Cliquez sur Installer pour démarrer l'installation.}
+      # ^ClickUninstall
+      ${33:Cliquez sur Désinstaller pour démarrer la désinstallation.}
+      # ^Name
+      ${34:Nom}
+      # ^Completed
+      ${35:Terminé}
+      # ^LicenseText
+      ${36:Veuillez examiner le contrat de licence avant d'installer \$(^NameDA). Si vous acceptez tous les termes du contrat, cliquez sur J'accepte.}
+      # ^LicenseTextCB
+      ${37:Veuillez examiner le contrat de licence avant d'installer \$(^NameDA). Si vous acceptez tous les termes du contrat, cochez la boîte de contrôle ci-dessous. \$_CLICK}
+      # ^LicenseTextRB
+      ${38:Veuillez examiner le contrat de licence avant d'installer \$(^NameDA). Si vous acceptez tous les termes du contrat, sélectionnez la première option ci-dessous. \$_CLICK}
+      # ^UnLicenseText
+      ${39:Veuillez examiner le contrat de licence avant de désinstaller \$(^NameDA). Si vous acceptez tous les termes du contrat, cliquez sur J'accepte.}
+      # ^UnLicenseTextCB
+      ${40:Veuillez examiner le contrat de licence avant de désinstaller \$(^NameDA). Si vous acceptez tous les termes du contrat, cochez la boîte de contrôle ci-dessous. \$_CLICK}
+      # ^UnLicenseTextRB
+      ${41:Veuillez examiner le contrat de licence avant de désinstaller \$(^NameDA). Si vous acceptez tous les termes du contrat, sélectionnez la première option ci-dessous. \$_CLICK}
+      # ^Custom
+      ${42:Personnalisée}
+      # ^ComponentsText
+      ${43:Cochez les composants que vous désirez installer et décochez ceux que vous ne désirez pas installer. \$_CLICK}
+      # ^ComponentsSubText1
+      ${44:Type d'installation}:
+      # ^ComponentsSubText2_NoInstTypes
+      ${45:Sélectionnez les composants à installer}:
+      # ^ComponentsSubText2
+      ${46:Ou, sélectionnez les composants optionnels que vous voulez installer}:
+      # ^UnComponentsText
+      ${47:Cochez les composants que vous désirez désinstaller et décochez ceux que vous ne désirez pas désinstaller. \$_CLICK}
+      # ^UnComponentsSubText1
+      ${48:Sélectionnez le type de désinstallation}:
+      # ^UnComponentsSubText2_NoInstTypes
+      ${49:Sélectionnez les composants à désinstaller}:
+      # ^UnComponentsSubText2
+      ${50:Ou, sélectionnez les composants optionnels que vous voulez désinstaller}:
+      # ^DirText
+      ${51:Ceci installera \$(^NameDA) dans le dossier suivant. Pour installer dans un autre dossier, cliquez sur Parcourir et choisissez un autre dossier. \$_CLICK}
+      # ^DirSubText
+      ${52:Dossier d'installation}
+      # ^DirBrowseText
+      ${53:Sélectionnez le dossier d'installation pour \$(^NameDA)}:
+      # ^UnDirText
+      ${54:Ceci désinstallera \$(^NameDA) du dossier suivant. Pour désinstaller d'un autre dossier, cliquez sur Parcourir et choisissez un autre dossier. \$_CLICK}
+      # ^UnDirSubText
+      "${55}:"
+      # ^UnDirBrowseText
+      ${56:Sélectionnez le dossier de désinstallation pour \$(^NameDA)}:
+      # ^SpaceAvailable
+      "${57:Espace disponible} : "
+      # ^SpaceRequired
+      "${58:Espace requis} : "
+      # ^UninstallingText
+      ${59:Ce programme désinstallera \$(^NameDA) de votre ordinateur. \$_CLICK}
+      # ^UninstallingSubText
+      ${60:Désinstallation à partir de}:
+      # ^FileError
+      ${61:Erreur lors de l'ouverture du fichier en écriture: \r\n\t"\$0"\r\nAppuyez sur Abandonner pour annuler l'installation,\r\nRéessayer pour réessayer l'écriture du fichier, ou\r\nIgnorer pour passer ce fichier}
+      # ^FileError_NoIgnore
+      ${62:Erreur lors de l'ouverture du fichier en écriture: \r\n\t"\$0"\r\nAppuyez sur Réessayez pour re-écrire le fichier, ou\r\nAnnuler pour abandonner l'installation}
+      # ^CantWrite
+      "${63:Impossible d'écrire} : "
+      # ^CopyFailed
+      ${64:Échec de la copie}
+      # ^CopyTo
+      "${65:Copier vers} "
+      # ^Registering
+      "${66:Enregistrement} : "
+      # ^Unregistering
+      "${67:Suppression de l'enregistrement} : "
+      # ^SymbolNotFound
+      "${68:Impossible de trouver un symbole} : "
+      # ^CouldNotLoad
+      "${69:Impossible de charger} : "
+      # ^CreateFolder
+      "${70:Création du dossier} : "
+      # ^CreateShortcut
+      "${71:Création du raccourci} : "
+      # ^CreatedUninstaller
+      "${72:Création de la désinstallation} : "
+      # ^Delete
+      "${73:Suppression} : "
+      # ^DeleteOnReboot
+      "${74:Suppression au redémarrage} : "
+      # ^ErrorCreatingShortcut
+      "${75:Erreur lors de la création du raccourci} : "
+      # ^ErrorCreating
+      "${76:Erreur de la création} : "
+      # ^ErrorDecompressing
+      ${77:Erreur lors de la décompression des données ! Installation corrompue ?}
+      # ^ErrorRegistering
+      ${78:Erreur lors de l'enregistrement de la DLL}
+      # ^ExecShell
+      "${79:ExecShell} : "
+      # ^Exec
+      "${80:Exécution} : "
+      # ^Extract
+      "${81:Extraction} : "
+      # ^ErrorWriting
+      "${82:Extraction: erreur d'écriture du fichier} "
+      # ^InvalidOpcode
+      ${83:Installation corrompue: opcode incorrect}
+      # ^NoOLE
+      "${84:Pas de OLE pour} : "
+      # ^OutputFolder
+      "${85:Destination} : "
+      # ^RemoveFolder
+      "${86:Suppression du dossier} : "
+      # ^RenameOnReboot
+      "${87:Renommer au redémarrage} : "
+      # ^Rename
+      "${88:Renommer} : "
+      # ^Skipped
+      "${89:Passé} : "
+      # ^CopyDetails
+      ${90:Copier les Détails dans le Presse-papier}
+      # ^LogInstall
+      ${91:Enregistrer le déroulement de l'installation}
+      # ^Byte
+      ${92:o}
+      # ^Kilo
+      ${93:K}
+      # ^Mega
+      ${94:M}
+      # ^Giga
+      ${95:G}
+    """
+  'Spanish NLF':
+    'prefix': 'scaffold-Spanish'
+    'body': """
+      # Header, don't edit
+      NLF v6
+      # Start editing here
+      # Language ID
+      ${1:1034}
+      # Font and size - dash (-) means default
+      ${2:-}
+      ${3:-}
+      # Codepage - dash (-) means ANSI code page
+      ${4:1252}
+      # RTL - anything else than RTL means LTR
+      ${5:-}
+      # Translation by ${6:<your name>}
+      # ^Branding
+      ${7:Nullsoft Install System %s}
+      # ^SetupCaption
+      ${8:Instalación de \$(^Name)}
+      # ^UninstallCaption
+      ${9:Desinstalación de \$(^Name)}
+      # ^LicenseSubCaption
+      : ${10: Acuerdo de Licencia}
+      # ^ComponentsSubCaption
+      : ${11: Opciones de Instalación}
+      # ^DirSubCaption
+      : ${12: Directorio de Instalación}
+      # ^InstallingSubCaption
+      : ${13: Instalando}
+      # ^CompletedSubCaption
+      : ${14: Completado}
+      # ^UnComponentsSubCaption
+      : ${15: Opciones de Desinstalación}
+      # ^UnDirSubCaption
+      : ${16: Directorio de Desinstalación}
+      # ^ConfirmSubCaption
+      : ${17: Confirmación}
+      # ^UninstallingSubCaption
+      : ${18: Désinstallation des fichiers}
+      # ^UnCompletedSubCaption
+      : ${19: Completado}
+      # ^BackBtn
+      ${20:< &Atrás}
+      # ^NextBtn
+      ${21:&Siguiente >}
+      # ^AgreeBtn
+      ${22:A&cepto}
+      # ^AcceptBtn
+      ${23:A&cepto los términos de la licencia}
+      # ^DontAcceptBtn
+      ${24:&No acepto los términos de la licencia}
+      # &Instalar
+      ${25:&Installer}
+      # ^UninstallBtn
+      ${26:&Desinstalar}
+      # ^CancelBtn
+      ${27:Cancelar}
+      # ^CloseBtn
+      ${28:&Cerrar}
+      # ^BrowseBtn
+      ${29:Examinar...}
+      # ^ShowDetailsBtn
+      ${30:Ver &detalles}
+      # ^ClickNext
+      ${31:Presione Siguiente para continuar.}
+      # ^ClickInstall
+      ${32:Presione Instalar para comenzar la instalación.}
+      # ^ClickUninstall
+      ${33:Presione Desinstalar para comenzar la desinstalación.}
+      # ^Name
+      ${34:Nombre}
+      # Completado
+      ${35:Terminé}
+      # ^LicenseText
+      ${36:Por favor, revise el acuerdo de licencia antes de instalar \$(^NameDA). Si acepta todos los términos del acuerdo, presione Acepto.}
+      # ^LicenseTextCB
+      ${37:Por favor, revise el acuerdo de licencia antes de instalar \$(^NameDA). Si acepta todos los términos del acuerdo, marque abajo la casilla. \$_CLICK}
+      # ^LicenseTextRB
+      ${38:Por favor, revise el acuerdo de licencia antes de instalar \$(^NameDA). Si acepta todos los términos del acuerdo, seleccione abajo la primera opción. \$_CLICK}
+      # ^UnLicenseText
+      ${39:Por favor, revise el acuerdo de licencia antes de desinstalar \$(^NameDA). Si acepta todos los términos del acuerdo, presione Acepto.}
+      # ^UnLicenseTextCB
+      ${40:Por favor, revise el acuerdo de licencia antes de desinstalar \$(^NameDA). Si acepta todos los términos del acuerdo, marque abajo la casilla. \$_CLICK.}
+      # ^UnLicenseTextRB
+      ${41:Por favor, revise el acuerdo de licencia antes de desinstalar \$(^NameDA). Si acepta todos los términos del acuerdo, seleccione abajo la primera opción. \$_CLICK}
+      # ^Custom
+      ${42:Personalizada}
+      # ^ComponentsText
+      ${43:Marque los componentes que desee instalar y desmarque los componentes que no desee instalar. \$_CLICK}
+      # ^ComponentsSubText1
+      ${44:Tipos de instalación}:
+      # ^ComponentsSubText2_NoInstTypes
+      ${45:Seleccione los componentes a instalar}:
+      # ^ComponentsSubText2
+      ${46:O seleccione los componentes opcionales que desee instalar}:
+      # ^UnComponentsText
+      ${47:Marque los componentes que desee desinstalar y desmarque los componentes que no desee desinstalar. \$_CLICK}
+      # ^UnComponentsSubText1
+      ${48:Tipos de desinstalación}:
+      # ^UnComponentsSubText2_NoInstTypes
+      ${49:Seleccione los componentes a desinstalar}:
+      # ^UnComponentsSubText2
+      ${50:O seleccione los componentes opcionales que desee desinstalar}:
+      # ^DirText
+      ${51:El programa de instalación instalará \$(^NameDA) en el siguiente directorio. Para instalar en un directorio diferente, presione Examinar y seleccione otro directorio. \$_CLICK}
+      # ^DirSubText
+      ${52:Directorio de Destino}
+      # ^DirBrowseText
+      ${53:Seleccione el directorio en el que instalará \$(^NameDA)}:
+      # ^UnDirText
+      ${54:El programa de instalación desinstalará \$(^NameDA) del siguiente directorio. Para desinstalar de un directorio diferente, presione Examinar y seleccione otro directorio. \$_CLICK}
+      # ^UnDirSubText
+      "${55}:"
+      # ^UnDirBrowseText
+      ${56:Seleccione el directorio desde el cual desinstalará \$(^NameDA)}:
+      # ^SpaceAvailable
+      "${57:Espacio disponible}: "
+      # ^SpaceRequired
+      "${58:Espacio requerido}: "
+      # ^UninstallingText
+      ${59:\$(^NameDA) será desinstalado del siguiente directorio. \$_CLICK}
+      # ^UninstallingSubText
+      ${60:Desinstalando desde}:
+      # ^FileError
+      ${61:Error abriendo archivo para escritura: \r\n\t"\$0"\r\nPresione abortar para anular la instalación,\r\nreintentar para volver a intentar escribir el archivo, u\r\nomitir para ignorar este archivo}
+      # ^FileError_NoIgnore
+      ${62:Error abriendo archivo para escritura: \r\n\t"\$0"\r\nPresione reintentar para volver a intentar escribir el archivo, o\r\ncancelar para anular la instalación l'installation}
+      # ^CantWrite
+      "${63:No pudo escribirse}: "
+      # ^CopyFailed
+      ${64:Falló la copia}
+      # ^CopyTo
+      "${65:Copiar a }"
+      # ^Registering
+      "${66:Registrando}: "
+      # ^Unregistering
+      "${67:Eliminando registro}: "
+      # ^SymbolNotFound
+      "${68:No pudo encontrarse símbolo}: "
+      # ^CouldNotLoad
+      "${69:No pudo cargarse}: "
+      # ^CreateFolder
+      "${70:Crear directorio}: "
+      # ^CreateShortcut
+      "${71:Crear acceso directo}: "
+      # ^CreatedUninstaller
+      "${72:Crear desinstalador}: "
+      # ^Delete
+      "${73:Borrar archivo}: "
+      # ^DeleteOnReboot
+      "${74:Borrar al reinicio}: "
+      # ^ErrorCreatingShortcut
+      "${75:Error creando acceso directo}: "
+      # ^ErrorCreating
+      "${76:Error creando}: "
+      # ^ErrorDecompressing
+      ${77:¡Error descomprimiendo datos! ¿Instalador corrupto?}
+      # ^ErrorRegistering
+      ${78:Error registrando DLL}
+      # ^ExecShell
+      "${79:Ejecutar comando}: "
+      # ^Exec
+      "${80:Ejecutar}: "
+      # ^Extract
+      "${81:Extraer}: "
+      # ^ErrorWriting
+      "${82:Extraer: error escribiendo al archivo }"
+      # ^InvalidOpcode
+      ${83:Instalador corrupto: código de operación no válido}
+      # ^NoOLE
+      "${84:Sin OLE para}: "
+      # ^OutputFolder
+      "${85:Directorio de salida}: "
+      # ^RemoveFolder
+      "${86:Eliminar directorio}: "
+      # ^RenameOnReboot
+      "${87:Renombrar al reinicio}: "
+      # ^Rename
+      "${88:Renombrar}: "
+      # ^Skipped
+      "${89:Omitido}: "
+      # ^CopyDetails
+      ${90:Copiar Detalles al Portapapeles}
+      # ^LogInstall
+      ${91:Registrar proceso de instalación }
+      # ^Byte
+      ${92:B}
+      # ^Kilo
+      ${93:K}
+      # ^Mega
+      ${94:M}
+      # ^Giga
+      ${95:G}
+    """


Update pt-PT.coffee

Update pt-PT.coffee

--- app/locale/pt-PT.coffee
+++ app/locale/pt-PT.coffee
@@ -14,16 +14,16 @@
     for_developers: "Para Programadores" # Not currently shown on home page.
     or_ipad: "Ou descarrega para iPad"

-#  new_home:
-#    slogan: "The most engaging game for learning programming."
-#    classroom_edition: "Classroom Edition:"
-#    learn_to_code: "Learn to code:"
-#    teacher: "Teacher"
-#    student: "Student"
-#    play_now: "Play Now"
-#    im_a_teacher: "I'm a Teacher"
-#    im_a_student: "I'm a Student"
-#    learn_more: "Learn more"
+  new_home:
+    slogan: "O jogo mais cativante para aprender programação."
+    classroom_edition: "Edição de Turma:"
+    learn_to_code: "Aprender a programar:"
+    teacher: "Professor"
+    student: "Estudante"
+    play_now: "Jogar Agora"
+    im_a_teacher: "Sou um Professor"
+    im_a_student: "Sou um Estudante"
+    learn_more: "Aprender mais"
 #    classroom_in_a_box: "A classroom in-a-box for teaching computer science."
 #    codecombat_is: "CodeCombat is a platform for students to learn computer science while playing through a real game."
 #    our_courses: "Our courses have been specifically playtested to excel in the classroom, even by teachers with little to no prior programming experience."
@@ -507,14 +507,14 @@

   subscribe:
     comparison_blurb: "Aperfeiçoa as tuas habilidades com uma subscrição do CodeCombat!"
-    feature1: "110+ níveis básicos dispersos por 4 mundos" # {change}
+    feature1: "125+ níveis básicos dispersos por 4 mundos"
     feature2: "10 heróis novos e poderosos com habilidades únicas!"
-    feature3: "80+ níveis de bónus" # {change}
+    feature3: "85+ níveis de bónus"
     feature4: "{{gems}} gemas de bónus por mês!"
     feature5: "Tutoriais em vídeo"
     feature6: "Apoio por e-mail prioritário"
     feature7: "Clãs Privados"
-#    feature8: "No ads!"
+    feature8: "Sem anúncios!"
     free: "Grátis"
     month: "mês"
     must_be_logged: "Primeiro tens de ter sessão iniciada. Por favor, cria uma conta ou inicia sessão a partir do menu acima."
@@ -877,7 +877,7 @@
     social_facebook: "Gosta do CodeCombat no Facebook"
     social_twitter: "Segue o CodeCombat no Twitter"
     social_gplus: "Junta-te ao CodeCombat no Google+"
-#    social_slack: "Chat with us in the public CodeCombat Slack channel"
+    social_slack: "Fala connosco no canal público do CodeCombat no Slack"
     contribute_to_the_project: "Contribui para o projeto"

   clans:
@@ -931,10 +931,10 @@
     track_concepts2b: "aprendidos por cada membro"
     track_concepts3a: "Acompanhe os níveis completados por cada estudante"
     track_concepts3b: "Acompanhe os níveis completados por cada membro"
-    track_concepts4a: "Veja, dos seus alunos, as"
+    track_concepts4a: "Veja, dos seus estudantes, as"
     track_concepts4b: "Veja, dos seus membros, as"
     track_concepts5: "soluções"
-    track_concepts6a: "Ordene os alunos por nome ou progresso"
+    track_concepts6a: "Ordene os estudantes por nome ou progresso"
     track_concepts6b: "Ordene os membros por nome ou progresso"
     track_concepts7: "É necessário um convite"
     track_concepts8: "para se juntar"
@@ -1303,7 +1303,7 @@
     join_desc_3: " ou encontra-nos na nossa "
     join_desc_4: "e começamos a partir daí!"
     join_url_email: "Contacta-nos"
-#    join_url_slack: "public Slack channel"
+    join_url_slack: "canal público no Slack"
     archmage_subscribe_desc: "Receber e-mails relativos a novas oportunidades de programação e anúncios."
     artisan_introduction_pref: "Temos de construir mais níveis! As pessoas estão a pedir mais conteúdo, e nós mesmos só podemos construir estes tantos. Neste momento, a tua estação de trabalho é o nível um; o nosso editor de nível é pouco utilizável, até mesmo pelos seus criadores, por isso fica atento. Se tens visões de campanhas que abranjam 'for-loops' para o"
     artisan_introduction_suf: ", então esta classe pode ser para ti."