:bug: Fix error raised when minimap is not toggled

Fixes #4

--- lib/minimap-highlight-selected-view.coffee
+++ lib/minimap-highlight-selected-view.coffee
@@ -28,4 +28,5 @@

     handleSelection: ->
       return unless atom.workspace.getActiveTextEditor()?
+      return unless @fakeEditor.getActiveTextEditor()?
       super


Hotfix for previous commit, forgot to uncommit some stuff

--- app/views/play/level/tome/tome_view.coffee
+++ app/views/play/level/tome/tome_view.coffee
@@ -58,9 +58,9 @@

     if programmableThangs.length
       @createSpells programmableThangs  # Do before spellList, thangList, and castButton
-      #@spellList = @insertSubView new SpellListView spells: @spells, supermodel: @supermodel
-      #@thangList = @insertSubView new ThangListView spells: @spells, thangs: @options.thangs, supermodel: @supermodel
-      #@castButton = @insertSubView new CastButtonView spells: @spells
+      @spellList = @insertSubView new SpellListView spells: @spells, supermodel: @supermodel
+      @thangList = @insertSubView new ThangListView spells: @spells, thangs: @options.thangs, supermodel: @supermodel
+      @castButton = @insertSubView new CastButtonView spells: @spells
     else
       @cast()


CreateStore: allowing to change emitter pass any data

--- smsgw/static/src/lib/createStore.coffee
+++ smsgw/static/src/lib/createStore.coffee
@@ -15,8 +15,8 @@

     # shared API cross user stores
     store = assign({}, EventEmitter.prototype,
-        emitChange: ->
-            @emit EVENT_CHANGE
+        emitChange: (data = null) ->
+            @emit EVENT_CHANGE, data

         emitError: (err) ->
             @emit EVENT_ERROR, err


remove xss vector in ComboBox

remove xss vector in ComboBox

test-plan:
 - instantiate a combobox with a script tag in one of the raw option
   values
 - view the combobox
 - script in tag should be visible in dropdown, not executed

Change-Id: I40ea9900257034fa00fce900aacae98570eab6a6
Reviewed-on: https://gerrit.instructure.com/23142
Reviewed-by: Brian Palmer <3cb4e1df5ec4da2c7c4af7c52cec8cf340a55a10@instructure.com>
QA-Review: Jeremy Putnam <b030d6d6f199f844ec424882be473c2ab9adc93b@instructure.com>
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
Product-Review: Jacob Fugal <f862f167b85d41b225785c70d70808bc7337c1fe@instructure.com>

--- app/coffeescripts/widget/ComboBox.coffee
+++ app/coffeescripts/widget/ComboBox.coffee
@@ -122,4 +122,4 @@
     # @api private
     # Convert an option label to the displayed selectmenu item.
     _formatOption: (label) =>
-      "#{label}"
+      "#{htmlEscape label}"


changing symbol used for expandable fields

Former-commit-id: 901804b122610e5aff49302a53e922dde426da1f [formerly ddda5afa193efb90f103b02522e05015cd1060e5] [formerly ff37640a0937036636df4d4bddbb6355b5fc69ff [formerly b6a2125d3af653e609d536fa847595d5772ac816]] [formerly fce63e14a981bb4a7aba43210858e8897dd29c25 [formerly e4357c6e2e09ea781d891d14de42d3bc9465bc6f] [formerly 92ccbb21c0ed932096e75656d88aec0a7fb7133e [formerly 92ccbb21c0ed932096e75656d88aec0a7fb7133e [formerly 75d8c8cab6961ec52e282ed52ea8af9ad441ca36]]]]
Former-commit-id: 8daeb1f0a06957f166f9c3dd059ab2f9ccf1462e [formerly 3b5da4ebc89fe18354cb1c4b99ba9ca1605a7424] [formerly 8f882cf2c0fcacfe0480ecad8381ba7e468a908c [formerly 2dff84ddbebba8d336c6d2b886a2d502449330e1]]
Former-commit-id: 308417832bfc9db240e1438887d17ab13c6bc3a9 [formerly 05b30f4af94bca98fd9a448a0bb7bba4de545d8a]
Former-commit-id: fe548718098ec2e43a8433114df0ffeaf952ac0d
Former-commit-id: 64b5f17739e47e9c82b85ca1ec59c2303e5b3df6

--- @client/franklin.coffee
+++ @client/franklin.coffee
@@ -495,7 +495,7 @@
       @local.description_collapsed = true; save(@local)

   renderDescriptionField : (field) ->
-    symbol = if field.expanded then 'fa-minus-circle' else 'fa-plus-circle'
+    symbol = if field.expanded then 'fa-chevron-down' else 'fa-chevron-right'
     DIV
       className: 'description_field'
       key: field.label
@@ -516,8 +516,10 @@
           style:
             opacity: .7
             position: 'relative'
-            left: -4
+            left: -3
             paddingRight: 6
+            display: 'inline-block'
+            width: 20

         SPAN
           style: {lineHeight: 1.6, fontSize: 18}


changing format_on_save test passing

changing format_on_save test passing

--- spec/format-spec.coffee
+++ spec/format-spec.coffee
@@ -6,7 +6,7 @@
 describe "JSFormat package tests", ->
   beforeEach ->
     atom.workspaceView = new WorkspaceView()
-    atom.workspace = atom.workspaceView.model
+    atom.workspace = atom.workspaceView.getModel()

   # JSFormat tests here

@@ -63,41 +63,54 @@
         expect(atom.workspace.getActiveTextEditor().getText()).not.toMatch(fileText)
         atom.config.set('jsformat.format_on_save', false)

-    it "can subscribe and unsubscribe to events when format_on_save is enabled", ->
+    it "can subscribe and unsubscribe to editors when format_on_save is enabled and editors are opened and closed", ->
       # format_on_save test
-
-      waitsForPromise ->
-        atom.packages.activatePackage('jsformat')

       waitsForPromise ->
         spyOn(format, 'subscribeToEvents').andCallThrough()
         atom.workspace.open('specfiles/index.js')

+      waitsForPromise ->
+        atom.packages.activatePackage('jsformat')
+
       runs ->
-        fileText = atom.workspace.getActiveTextEditor().getText()
         atom.config.set('jsformat.format_on_save', true)
-        atom.workspace.getActiveTextEditor().save()
+        console.log(format.editorSaveSubscriptions)
+        console.log(format.editorCloseSubscriptions)
+        atom.workspace.getActiveTextEditor().destroy()

-        # atom.close()
+        atom.workspace.open('file.js')
+        console.log(format.editorSaveSubscriptions)
+        console.log(format.editorCloseSubscriptions)
+        # atom.workspace.getActiveTextEditor().destroy()
+        # expect(format.editorSaveSubscriptions)
+
+        # expect()
         # TODO add a check here to see that the subscriptions were disposed and deleted from the objects

     it "can subscribe and unsubscribe to events when format_on_save is changed", ->
       # format_on_save test

       waitsForPromise ->
-        atom.packages.activatePackage('jsformat')
-
-      waitsForPromise ->
         spyOn(format, 'subscribeToEvents').andCallThrough()
         atom.workspace.open('specfiles/index.js')

+      waitsForPromise ->
+        atom.packages.activatePackage('jsformat')
+
       runs ->
-        # check that subscribeToEvents has run
-        expect(format.subscribeToEvents.callCount).toEqual(0)
-        atom.config.set('jsformat.format_on_save', true)
+        # check that subscribeToEvents has run after toggling format_on_save
         expect(format.subscribeToEvents.callCount).toEqual(1)
         atom.config.set('jsformat.format_on_save', false)
+
+      # waitsFor ->
         expect(format.subscribeToEvents.callCount).toEqual(2)
+        atom.config.set('jsformat.format_on_save', true)
+      # , "Waiting for subscribeToEvents to run", 250
+
+      # waitsFor ->
+        expect(format.subscribeToEvents.callCount).toEqual(3)
+      # , "Wait for subscribeToEvents to run", 250

     it "displays a notification for unsupported languages", ->
       # NotSupportedNotificationView test


Move pieces to exact position at end of move, to stop rounding error drift.

Solution from; http://stackoverflow.com/questions/24988041/making-an-object3d-snap-to-grid

--- source/changers/MoveExecution.js.coffee
+++ source/changers/MoveExecution.js.coffee
@@ -20,4 +20,9 @@
     object.matrix = rotWorldMatrix
     object.rotation.setFromRotationMatrix(object.matrix)

-  _realign: ->+  _realign: ->
+    p2 = Math.PI / 2
+    for piece in @pieces
+      r = piece.rotation
+      [r.x, r.y, r.z] = [Math.round(r.x / p2) * p2, Math.round(r.y / p2) * p2, Math.round(r.z / p2) * p2]
+


fix(specs): Display which tests are console.logging

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -49,6 +49,46 @@
   set: (title) -> documentTitle = title

 jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of equality for toEqual assertions
+
+# ----------------------------------------------------
+# Custom log reporter to pointpoint console statements
+# ----------------------------------------------------
+
+util = require('util')
+console.inspect = (args...) ->
+  arg = args
+  if (args.length is 1)
+    arg = args[0]
+  console.log(util.inspect(arg))
+
+original_log = console.log
+original_warn = console.warn
+original_error = console.error
+
+class JasmineConsoleReporter
+  reportSpecStarting: (spec) ->
+    withContext = (log) ->
+      return ->
+        if arguments[0] is '.'
+          log(arguments...)
+        else
+          log("[#{spec.getFullName()}] #{arguments[0]}", Array(arguments)[1..-1]...)
+    console.log = withContext(original_log)
+    console.warn = withContext(original_warn)
+    console.error = withContext(original_error)
+
+  reportSpecResults: (result) ->
+    if console.log isnt original_log
+      console.log = original_log
+    if console.warn isnt original_warn
+      console.warn = original_warn
+    if console.error isnt original_error
+      console.error = original_error
+
+jasmine.getEnv().addReporter(new JasmineConsoleReporter())
+
+#
+#

 if process.env.JANKY_SHA1 and process.platform is 'win32'
   jasmine.getEnv().defaultTimeoutInterval = 60000
@@ -226,26 +266,8 @@

   TimeOverride.resetSpyData()

-util = require('util')
-console.inspect = (args...) ->
-  arg = args
-  if (args.length is 1)
-    arg = args[0]
-  console.log(util.inspect(arg))
-
-original_log = console.log
-original_warn = console.warn
-original_error = console.error

 afterEach ->
-
-  if console.log isnt original_log
-    console.log = original_log
-  if console.warn isnt original_warn
-    console.warn = original_warn
-  if console.error isnt original_error
-    console.error = original_error
-
   NylasEnv.packages.deactivatePackages()
   NylasEnv.menu.template = []

@@ -347,6 +369,11 @@
       element = element.get(0) if element.jquery
       @message = -> return "Expected element '#{element}' or its descendants#{notText} to show."
       element.style.display in ['block', 'inline-block', 'static', 'fixed']
+
+
+# -------------------------
+# Stubs for Window methods
+# -------------------------

 window.keyIdentifierForKey = (key) ->
   if key.length > 1 # named key


trololol

trololol

--- spec/test_helper.coffee
+++ spec/test_helper.coffee
@@ -10,9 +10,9 @@
   else
     givenModes

-  for m in modes
-    do (m) ->
-      if process.env.STEROIDS_TEST_RUN_MODE == m
+  for mode in modes
+    do (mode) ->
+      if process.env.STEROIDS_TEST_RUN_MODE == mode
         console.log "Mode is #{mode}, skipping this test"
         process.exit(0)


entrance notifications complete

entrance notifications complete

--- src/entrance.coffee
+++ src/entrance.coffee
@@ -22,7 +22,5 @@
 module.exports = (robot) ->
 	robot.enter (msg)->
 		room = msg.message.room
-		if(room == "trello")
+		if(room == "general" or room == "tests")
 			msg.reply(welcomeMessage)
-
-


move pipe after error handler setup

move pipe after error handler setup

--- services/filestore/app/coffee/LocalFileWriter.coffee
+++ services/filestore/app/coffee/LocalFileWriter.coffee
@@ -14,7 +14,6 @@
 		fsPath = @_getPath(key)
 		logger.log fsPath:fsPath, "writing file locally"
 		writeStream = fs.createWriteStream(fsPath)
-		stream.pipe writeStream
 		writeStream.on "finish", ->
 			timer.done()
 			logger.log fsPath:fsPath, "finished writing file locally"
@@ -25,6 +24,7 @@
 		stream.on "error", (err)->
 			logger.log err:err, fsPath:fsPath, "problem writing file locally, with read stream"
 			callback err
+		stream.pipe writeStream

 	deleteFile: (fsPath, callback)->
 		logger.log fsPath:fsPath, "removing local temp file"


added comment about query memory usage for toArray

--- services/track-changes/app/coffee/PackManager.coffee
+++ services/track-changes/app/coffee/PackManager.coffee
@@ -88,6 +88,10 @@

 		needMore = false  # keep track of whether we need to load more data
 		updates = [] # used to accumulate the set of results
+
+		# FIXME: packs are big so we should accumulate the results
+		# incrementally instead of using .toArray() to avoid reading all
+		# of the changes into memory
 		cursor.toArray (err, result) ->
 			unpackedSet = PackManager._unpackResults(result)
 			updates = PackManager._filterAndLimit(updates, unpackedSet, filterFn, limit)
@@ -141,6 +145,9 @@

 		updates = [] # used to accumulate the set of results

+		# FIXME: packs are big so we should accumulate the results
+		# incrementally instead of using .toArray() to avoid reading all
+		# of the changes into memory
 		cursor.toArray (err, result) ->
 			if err?
 				return callback err, result


Added support for icon_emoji

Added support for icon_emoji

--- src/lib/slack.seed.coffee
+++ src/lib/slack.seed.coffee
@@ -22,6 +22,7 @@
         text: options.text
         username: options.username
         icon_url: options.icon_url || ""
+        icon_emoji: options.icon_emoji || ""
         attachments: options.attachments
     , (err, body, response) ->
       if err or response isnt "ok"


Fix spec

Fix spec

--- spec_app/spec/javascripts/up/fragment_spec.js.coffee
+++ spec_app/spec/javascripts/up/fragment_spec.js.coffee
@@ -1630,7 +1630,7 @@
           target = fixture('.target', text: 'target text')
           origin = fixture('.origin', text: 'origin text')

-          up.change('.target', url: '/path', reveal: '&', origin: origin')
+          up.change('.target', url: '/path', reveal: '&', origin: origin)

           next =>
             @respondWithSelector('.target')


Use KeymapManager::addKeymap

Use KeymapManager::addKeymap

--- spec/keybinding-resolver-view-spec.coffee
+++ spec/keybinding-resolver-view-spec.coffee
@@ -19,9 +19,9 @@

   describe "when a keydown event occurs", ->
     it "displays all commands for the event", ->
-      atom.keymap.bindKeys 'name', '.workspace', 'x': 'match-1'
-      atom.keymap.bindKeys 'name', '.workspace', 'x': 'match-2'
-      atom.keymap.bindKeys 'name', '.never-again', 'x': 'unmatch-2'
+      atom.keymap.addKeymap 'name', '.workspace': 'x': 'match-1'
+      atom.keymap.addKeymap 'name', '.workspace': 'x': 'match-2'
+      atom.keymap.addKeymap 'name', '.never-again': 'x': 'unmatch-2'

       atom.commands.dispatch workspaceElement, 'key-binding-resolver:toggle'
       document.dispatchEvent keydownEvent('x', target: workspaceElement).originalEvent


Minor correction

Minor correction

--- app/js/script-console/task-runner.coffee
+++ app/js/script-console/task-runner.coffee
@@ -28,7 +28,7 @@

     ###
-    # ##TaskRunner.show
+    # ## TaskRunner.show
     # Show the output dialog.
     ###


Update nyala.coffee

Update nyala.coffee

--- app/lib/field-guide-content/nyala.coffee
+++ app/lib/field-guide-content/nyala.coffee
@@ -3,7 +3,7 @@
     Nyala are medium-sized antelopes that exhibit extreme sexual dimorphism, with the two sexes appearing entirely different. Females and young are short-haired, bright rufous-chestnut in color, and have 12 or more vertical white stripes. They also have white spots on their face, throat, lower flanks, and thighs. Male coats are shaggy and turn dark-brown to gray with age. Males have fewer and less conspicuous stripes and spots. Both sexes have a white chevron between their eyes and a bushy tail that is black above and white underneath.
   '''

-  scientificName: '(Tragelaphus angasii)'
+  scientificName: 'Tragelaphus angasii'
   mainImage: 'assets/fieldguide-content/mammals/nyala/nyala-feature.jpg'

   conservationStatus: 'Least Concern' # Options are Least Concern, Near Threatened, Vulnerable, and Endangered; all have their own little icons as well.


remember the folder choice across edit and view mode

--- web/volume/spreadsheet.coffee
+++ web/volume/spreadsheet.coffee
@@ -1398,6 +1398,7 @@
         $scope.setKey = (key) ->
           setKey(key)
           fill()
+          sessionStorage.setItem 'spreadsheetFolder', key
           return

         $scope.state =
@@ -1540,12 +1541,20 @@
       state = storage.getValue('spreadsheet-state')
       state = undefined unless state?.volume == $scope.volume.id
       $scope.state.restore($attrs.key || $location.search().key, state)
-      # show the first tab on angular load
-      $scope.setKey($scope.views[0].id)
+      # show the first tab on angular load or show the tab in the sessionSotrage
+      folderTab = sessionStorage.getItem('spreadsheetFolder')
+      if folderTab
+        $scope.setKey(folderTab)
+      else
+        $scope.setKey($scope.views[0].id)
+      console.log(folderTab)
       $scope.$on 'refreshParent', ->
         $scope.volume.get(records: true).then ((res) ->
           $scope.volume.records = res.records
-          $scope.setKey($scope.views[0].id)
+          if folderTab
+            $scope.setKey(folderTab)
+          else
+            $scope.setKey($scope.views[0].id)
           return
         ), (res) ->
           messages.addError


Filter repositories without last build

Filter repositories without last build

--- app/routes/dashboard/repositories.coffee
+++ app/routes/dashboard/repositories.coffee
@@ -12,7 +12,9 @@
         Authorization: 'token ' + @auth.token()
       }
     }).then (response) ->
-      response.repositories.sortBy('last_build.finished_at').map( (repo) ->
+      response.repositories.sortBy('last_build.finished_at').filter( (repo) ->
+        repo.last_build
+      ).map( (repo) ->
         Ember.Object.create(repo)
       )


<model> Sensor - Correcting small bugs

<model> Sensor - Correcting small bugs

--- server/models/sensor.coffee
+++ server/models/sensor.coffee
@@ -102,16 +102,20 @@
 				if err
 					callback err, null
 				else if sensors.length isnt 0 # Sensor already exists.
-					callback 'Device already added', sensor
+					callback 'Device already added', sensors[0]
 				else
 					superCreate data, (err, sensor) ->
+						if err
+							callback err, null
+							return
+
 						# Let the driver handle the integration of the device to the system:
 						sensorsDrivers[type].add customId, sensor.id, (err) ->
-						if err
-							# Cancelling modif:
-							thisSensor.requestDestroy "all", {key: sensor.id}, (err) ->
-								callback err, null
-						else
-							callback null, sensor
+							if err
+								# Cancelling modif:
+								thisSensor.requestDestroy "all", {key: sensor.id}, (err) ->
+									callback err, null
+							else
+								callback null, sensor
 		else
 			callback 'Device not supported', null


Add another spec to the reference counter

--- spec/ref-counted-token-list-spec.coffee
+++ spec/ref-counted-token-list-spec.coffee
@@ -5,8 +5,8 @@
   beforeEach ->
     list = new RefCountedTokenList

-  describe "when words are added and removed from the list", ->
-    it "maintains the word in the list until there are no more references", ->
+  describe "when tokens are added to and removed from the list", ->
+    it "maintains the token in the list until there are no more references", ->
       expect(list.getTokens()).toEqual []

       list.addToken('abc')
@@ -27,3 +27,28 @@

       list.removeToken('abc')
       expect(list.getTokens()).toEqual []
+
+  describe "when object tokens are added to and removed from the list", ->
+    it "maintains the token in the list until there are no more references", ->
+      expect(list.getTokens()).toEqual []
+
+      abcToken = {text: 'abc'}
+      defToken = {text: 'def'}
+      list.addToken(abcToken, 'text')
+      expect(list.getTokens()).toEqual [abcToken]
+
+      list.addToken(abcToken, 'text')
+      list.addToken(defToken, 'text')
+      expect(list.getTokens()).toEqual [abcToken, defToken]
+
+      list.removeToken(abcToken, 'text')
+      expect(list.getTokens()).toEqual [abcToken, defToken]
+
+      list.removeToken(defToken, 'text')
+      expect(list.getTokens()).toEqual [abcToken]
+
+      list.removeToken(abcToken, 'text')
+      expect(list.getTokens()).toEqual []
+
+      list.removeToken(abcToken, 'text')
+      expect(list.getTokens()).toEqual []


adds geocoding service

adds geocoding service

--- public/js/services.coffee
+++ public/js/services.coffee
@@ -1 +1,22 @@
 services = angular.module 'app.services', []
+
+services.factory 'geocoder', ($q, $rootScope) ->
+  geocoder = new google.maps.Geocoder()
+
+  return {
+  geocode: (address) ->
+    deferred = $q.defer()
+
+    geocoder.geocode
+      address: address
+    , (results, status) ->
+      if status is google.maps.GeocoderStatus.OK
+        location = results[0].geometry.location
+      else
+        location = null
+
+      deferred.resolve(location)
+      $rootScope.$apply()
+
+    return deferred.promise
+  }


need to note use .get to get active state, use attrs dict

--- bokehjs/src/coffee/common/grid_plot.coffee
+++ bokehjs/src/coffee/common/grid_plot.coffee
@@ -22,6 +22,7 @@
       # better grid plot. This just mimics all the events that
       # any of the tool types might expect to get.
       @listenTo(@, 'do', @do)
+      @listenTo(@, 'change:active', @active)
       return null

     do: () ->
@@ -31,7 +32,7 @@

     active: () ->
       for tool in @attributes.tools
-        tool.set('active', @get('active'))
+        tool.set('active', @attributes.active)
       return null

     attrs_and_props: () ->


husl color mix

husl color mix

--- framer/Color.coffee
+++ framer/Color.coffee
@@ -46,8 +46,8 @@
 		else "rgba(#{Utils.round(@_r, 0)}, #{Utils.round(@_g, 0)}, #{Utils.round(@_b, 0)}, #{@_roundA})"

 	toHsl: ->
-		hsl = rgbToHsl(@_r, @_g, @_b)
-		return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: @_a }
+		@_hsl = rgbToHsl(@_r, @_g, @_b) if @_hsl == undefined
+		return { h: @_hsl.h * 360, s: @_hsl.s, l: @_hsl.l, a: @_a }

 	toHslString: ->
 		hsl = rgbToHsl(@_r, @_g, @_b)
@@ -116,7 +116,7 @@
 	##############################################################
 	## Class methods

-	@mix: (colorA, colorB, fraction = .5, limit = false) ->
+	@mix: (colorA, colorB, fraction = .5, limit = false, model = "husl") ->

 		result = null

@@ -136,11 +136,28 @@

 		if colorB instanceof Color

-			result = new Color
-				r: Utils.modulate(fraction, [0, 1], [colorA._r, colorB._r], limit)
-				g: Utils.modulate(fraction, [0, 1], [colorA._g, colorB._g], limit)
-				b: Utils.modulate(fraction, [0, 1], [colorA._b, colorB._b], limit)
-				a: Utils.modulate(fraction, [0, 1], [colorA._a, colorB._a], limit)
+			if model == "husl"
+
+				hslA = colorA.toHsl()
+				hslB = colorB.toHsl()
+
+				if hslA.s == 0
+					hslA.h = hslB.h
+				else if hslB.s == 0
+					hslB.h = hslA.h
+
+				result = new Color
+					h: Utils.modulate(fraction, [0, 1], [hslA.h, hslB.h], limit)
+					s: Utils.modulate(fraction, [0, 1], [hslA.s, hslB.s], limit)
+					l: Utils.modulate(fraction, [0, 1], [hslA.l, hslB.l], limit)
+					a: Utils.modulate(fraction, [0, 1], [hslA.a, hslB.a], limit)
+
+			else
+				result = new Color
+					r: Utils.modulate(fraction, [0, 1], [colorA._r, colorB._r], limit)
+					g: Utils.modulate(fraction, [0, 1], [colorA._g, colorB._g], limit)
+					b: Utils.modulate(fraction, [0, 1], [colorA._b, colorB._b], limit)
+					a: Utils.modulate(fraction, [0, 1], [colorA._a, colorB._a], limit)

 		return result


home: minor fix

home: minor fix

--- client/app/Applications/Activity.kdapplication/AppView.coffee
+++ client/app/Applications/Activity.kdapplication/AppView.coffee
@@ -56,7 +56,7 @@
       else
         @setClass "fixed"
     else
-      @unsetClass "fixed"
+      @unsetClass "fixed" unless KD.isLoggedIn()

   navigateHome:(itemData)->


SidebarOwnMachinesList: Use `getMachines` to pass MoreVMsModal.

--- client/app/lib/activity/sidebar/sidebarownmachineslist.coffee
+++ client/app/lib/activity/sidebar/sidebarownmachineslist.coffee
@@ -16,10 +16,4 @@

     @on 'ListHeaderPlusIconClicked', -> ComputeHelpers.handleNewMachineRequest()

-    @on 'ListHeaderClicked', =>
-
-      machines = []
-
-      machines.push new Machine machine: obj.machine  for obj in data
-
-      new MoreVMsModal {}, machines
+    @on 'ListHeaderClicked', => new MoreVMsModal {}, @getMachines()


EnvironmentsMachineStateModal: update show stacks route

--- client/app/lib/providers/environmentsmachinestatemodal.coffee
+++ client/app/lib/providers/environmentsmachinestatemodal.coffee
@@ -709,9 +709,9 @@

   requestNewMachine: ->

-    route = if isKoding() then '/My-Machines' else '/Stacks'
-
-    kd.singletons.appManager.getFrontApp().quit()
+    route = if isKoding() then '/My-Machines' else '/Home/Stacks'
+
+    kd.singletons.appManager.getFrontApp().quit()  if isKoding()
     kd.singletons.router.handleRoute route


Tweak to saveEditedField validation

Tweak to saveEditedField validation

--- ribs.coffee
+++ ribs.coffee
@@ -681,12 +681,10 @@
                 @options.save.call this, editField, @model
             else
                 value = editField.val()
-                changeSet = {}
+                changeSet = $.extend true, {}, @model.attributes
                 changeSet[@options.field] = value

-                attrs = $.extend true, changeSet, @model.attributes
-                valid = @model._validate(attrs, @model)
-                unless valid
+                unless @model._validate(changeSet, @model)
                     return

                 # do whatever it takes to re-render


Add tests

Add tests

--- api/apps/articles/test/model/save.coffee
+++ api/apps/articles/test/model/save.coffee
@@ -55,6 +55,50 @@
           .equal moment().format('MM DD YYYY')
         done()

+    it 'does not generate published_at if scheduled', (done) ->
+      Save.onPublish { thumbnail_title: 'a title', scheduled_publish_at: '2017-07-26T17:37:03.065Z', published_at: null }, (err, article) =>
+        (article.published_at is null).should.be.true()
+        done()
+
+  describe '#generateSlugs', ->
+
+    it 'generates a slug', (done) ->
+      Save.generateSlugs {
+        thumbnail_title: 'Clockwork'
+        published: true
+        author: name: 'Molly'
+      }, (err, article) =>
+        article.slugs[0].should.equal 'molly-clockwork'
+        done()
+
+    it 'appends a date to the slug if it exists already', (done) ->
+      Save.sanitizeAndSave( =>
+        Save.generateSlugs {
+          thumbnail_title: 'Clockwork'
+          published: true
+          author: name: 'Molly'
+          published_at: '2017-07-26T17:37:03.065Z'
+        }, (err, article) =>
+          article.slugs[0].should.equal 'molly-clockwork-07-26-17'
+          done()
+      )(null, {
+        slugs: ['molly-clockwork']
+      })
+
+    it 'appends unix to the slug if it exists already and it is a draft', ->
+      Save.sanitizeAndSave( =>
+        Save.generateSlugs {
+          thumbnail_title: 'Clockwork'
+          published: false
+          author: name: 'Molly'
+          published_at: '2017-07-26T17:37:03.065Z'
+        }, (err, article) =>
+          article.slugs[0].should.equal 'molly-clockwork-1501090623'
+          done()
+      )(null, {
+        slugs: ['molly-clockwork']
+      })
+
   describe '#onUnpublish', ->

     it 'generates slugs and deletes article from sailthru', (done) ->


update application list

update application list

* remove todos and notes from official applications
* change webdav and databrowser names

--- client/app/collections/application.coffee
+++ client/app/collections/application.coffee
@@ -55,23 +55,23 @@
                 name:"notes"
                 displayName:"Note"
                 slug:"notes"
-                git:"https://github.com/mycozycloud/cozy-notes.git"
-                comment:"official application"
-                description:"Organize and store your notes efficiently."
+                git:"https://github.com/cozy/notes.git"
+                comment:"community contribution"
+                description:"Organize and write your smart notes."
            ,
                 icon:"img/todos-icon.png"
                 name:"todos"
                 displayName:"Todos"
                 slug:"todos"
-                git:"https://github.com/mycozycloud/cozy-todos.git"
-                comment:"official application"
+                git:"https://github.com/cozy/todos.git"
+                comment:"community contribution"
                 description:"Write your tasks, order them and execute them efficiently."
            ,
                 icon: "img/webdav.png"
-                name: "webdav"
-                displayName:"Webdav"
-                slug: "webdav"
-                git: "https://github.com/mycozycloud/cozy-webdav.git"
+                name: "sync"
+                displayName:"Sync"
+                slug: "sync"
+                git: "https://github.com/cozy/cozy-sync.git"
                 comment: "official application"
                 description: "Synchronize your contacts and your agenda with Cozy"
            ,
@@ -105,7 +105,7 @@
                 slug: "pfm"
                 git: "https://github.com/seeker89/cozy-pfm.git"
                 comment: "community contribution"
-                description: "Browse your bank accounts records and get daily reports from them."
+                description: "Suivez vos comptes banquaires sans avoir à vous relogger à chaque fois."
            ,
                 icon: "img/kyou.png"
                 name: "kyou"
@@ -142,7 +142,7 @@
            ,
                 icon: "img/databrowser-icon.png"
                 name: "databrowser"
-                displayName:"Toutes mes données"
+                displayName:"Data Browser"
                 slug: "databrowser"
                 git: "https://github.com/n-a-n/cozy-databrowser.git"
                 comment: "community contribution"


client:seperate lines with blank

client:seperate lines with blank

--- client/app/lib/socialapicontroller.coffee
+++ client/app/lib/socialapicontroller.coffee
@@ -876,6 +876,7 @@
         endPoint : "/api/social/channel/#{id}/delete"
         data     : options
       , callback
+
 # needs to be checked for create..
 # probably create is never used under client
 #~mehmetali
@@ -892,6 +893,7 @@
         type     : 'GET'
         endPoint : "/api/social/channel/search"
       , callback
+
 # client didnt use this endpoint.. check ~mehmetali
     # checkChannelParticipation: (options, callback) ->
     #   doXhrRequest
@@ -914,7 +916,6 @@

-
   channel:
     byId                 : channelRequesterFn
       fnName             : 'byId'


Do not close connection when RTSP 404

Do not close connection when RTSP 404

--- rtsp.coffee
+++ rtsp.coffee
@@ -1199,7 +1199,7 @@
     Not Found
     """.replace /\n/g, "\r\n"
     callback null, res,
-      close: req.headers.connection?.toLowerCase() isnt 'keep-alive'
+      close: (protocol is 'HTTP') and (req.headers.connection?.toLowerCase() isnt 'keep-alive')

   respondWithUnauthorized: (req, protocol, callback) ->
     if not protocol?


minor: use === in autogenerated code for rules

--- rule.coffee
+++ rule.coffee
@@ -99,7 +99,7 @@

 exports.binaryTransitionFunc2GenericCode = (binTf) ->
-  row2condition = (row) -> ("s==#{sum}" for nextValue, sum in row when nextValue).join(" || ")
+  row2condition = (row) -> ("s===#{sum}" for nextValue, sum in row when nextValue).join(" || ")

   conditionBorn = row2condition binTf.table[0]
   conditionStay = row2condition binTf.table[1]
@@ -116,23 +116,23 @@
     //Transition function. Takes current state and sum, returns new state.
     //this.generation stores current generation number
     'next': function(x, s){
-        if (x==1 && (#{conditionStay})) return 1;
-        if (x==0 && (#{conditionBorn})) return 1;
+        if (x===1 && (#{conditionStay})) return 1;
+        if (x===0 && (#{conditionBorn})) return 1;
         return 0;
      }
 }"""]

 exports.dayNightBinaryTransitionFunc2GenericCode = (binTf) ->
-  row2condition = (row) -> ("s==#{sum}" for nextValue, sum in row when nextValue).join(" || ")
-  row2conditionInv = (row) -> ("s==#{binTf.base.numNeighbors-sum}" for nextValue, sum in row when nextValue).join(" || ")
+  row2condition = (row) -> ("s===#{sum}" for nextValue, sum in row when nextValue).join(" || ")
+  row2conditionInv = (row) -> ("s===#{binTf.base.numNeighbors-sum}" for nextValue, sum in row when nextValue).join(" || ")

   conditionBorn = row2condition binTf.base.table[0]
   conditionStay = row2condition binTf.base.table[1]
   conditionBornInv = row2conditionInv binTf.base.table[0]
   conditionStayInv = row2conditionInv binTf.base.table[1]

-  code = ["""//Automatically generated code for binary rule #{binTf}
+  code = ["""//Automatically generated code for population-inverting binary rule #{binTf}
 {
     //number of states
     'states': 2,
@@ -145,13 +145,19 @@
     'next': function(x, s){
         var phase = this.generation & 1;

+        //The original rule #{binTf} inverts state of an empty field
+        //To calculate it efficiently, we instead invert each odd generation, so that population never goes to infinity.
+
+
         if (phase === 0){
-            if (x==1 && (#{conditionStay})) return 0;
-            if (x==0 && (#{conditionBorn})) return 0;
+            //On even generations, invert output
+            if (x===1 && (#{conditionStay})) return 0;
+            if (x===0 && (#{conditionBorn})) return 0;
             return 1
         } else {
-            if (x==0 && (#{conditionStayInv})) return 1;
-            if (x==1 && (#{conditionBornInv})) return 1;
+            //On odd generations, invert input state and nighbors sum
+            if (x===0 && (#{conditionStayInv})) return 1;
+            if (x===1 && (#{conditionBornInv})) return 1;
             return 0;
         }
      }


Rename generated css file

Rename generated css file

--- grunt/stylus.coffee
+++ grunt/stylus.coffee
@@ -9,7 +9,7 @@
   main:
     options:
       banner: '<%= banner %>'
-    files:    [ '<%= buildDir %>/tesserae.css': '<%= srcDir %>/index.styl' ]
+    files:    [ '<%= buildDir %>/kaleidoscope.css': '<%= srcDir %>/index.styl' ]

   docs:
     files:    [ '<%= docsDir %>/assets/css/docs.css': '<%= docsSrcDir %>/assets/stylus/index.styl' ]


Use when with comma

Use when with comma

--- bin/heyu-run.coffee
+++ bin/heyu-run.coffee
@@ -56,9 +56,16 @@
   print """
   Usage: heyu-run [args]

-    --test     Run tests
+    --id appl         Appliance id
+    --switch ON|OFF   Send event to appliance
+    --test            Run tests
+
+  Examples:
+
+    heyu-run --id light1 --switch on
+
   """
-  throw new Error("Done.");
+  quit(1)

 # ---- Check sanity of the environment
 test = () ->
@@ -98,14 +105,14 @@
   file = new File("myfile.txt")
   file.remove() if file.exists
   print 'Tests passed'
+  quit(0)

 # ---- Parse the command line
 parse_opts = (set,args) ->
   if args.length > 0
     args2 =
       switch args[0]
-        when '--help' or '-h'
-          help()
+        when '--help','-h' then help()
         when '--test'
           test()
           set.event = "on"
@@ -124,9 +131,9 @@

 # ---- Main program
 root = this
-appliances = read_json(state_db_fn)
 args = clone(root.arguments)  # don't need to do this, just for fun
 set = parse_opts({test: test},args)
+appliances = read_json(state_db_fn)
 print "# in:",set.event,set.id
 appl = new HeyuAppliance(set.id, states: ['OFF', 'ON'])
 appl.changeState('any',set.event)


Actually added Pistachio

Actually added Pistachio

Actualy added the transform to the calling code. Heh.

--- bin/kdc-plus.coffee
+++ bin/kdc-plus.coffee
@@ -12,6 +12,7 @@
   StdioTransform
 }                 = require '../lib/streams/load'
 maniutils         = require '../lib/maniutils'
+{PistachioThis}   = require '../lib/streams/pistachio'
 {
   installDev
   installProd
@@ -114,6 +115,9 @@
     if opts.coffee
       loader.transform (file, ext) ->
         if ext is '.coffee' then return new CoffeeTransform bare: opts.bare
+
+    if opts.pistachioThis
+      loader.transform -> new PistachioThis()

     if opts.transform?
       # Currently we only support a single user transform, so until we figure
@@ -181,7 +185,7 @@
     'for the previous transform'
   compileCmd.option '-p, --pipe', 'Pipe to STDOUT instead of to a file'
   compileCmd.option '-f, --file <file>', 'Choose the output file'
-  compileCmd.option '--pistachiothis', 'Convert @ to this in your pistachio'
+  compileCmd.option '--pistachio-this', 'Convert @ to this in your pistachio'
   compileCmd.action -> compile arguments..., log

@@ -224,7 +228,7 @@
   legacyOptions =
     coffee        : true
     bare          : true
-    pistachiothis : true
+    pistachioThis : true

   # ### No Options Default, Legacy
   #


add a new function called random_question

--- cf/spell.coffee
+++ cf/spell.coffee
@@ -12,3 +12,7 @@

   startUp = (data) ->
     $("#question, #answer").show()
+    random_question(data)
+
+  random_question = (data) ->
+    console.log data['words'].length


add class alert-danger when spelling attempt failed

--- cf/spell.coffee
+++ cf/spell.coffee
@@ -41,5 +41,6 @@
           update_question(@data)
         else
           @fail += 1
+          $(".alert").addClass("alert-danger")
           $("input#input_answer").val("")
     )


Conditionally set X-CSRF-Token header.

Conditionally set X-CSRF-Token header.

--- src/extras/batman.rails.coffee
+++ src/extras/batman.rails.coffee
@@ -76,7 +76,7 @@

     if token = @constructor.CSRF_TOKEN
       headers = env.options.headers ||= {}
-      headers['X-CSRF-Token'] = token
+      headers['X-CSRF-Token'] ?= token

     next()


allow customizing collection class

allow customizing collection class

--- client/lanes/models/AssociationMap.coffee
+++ client/lanes/models/AssociationMap.coffee
@@ -80,8 +80,9 @@
             new target_class(options.models || [], options)
         else
             options.model = target_class
-            options.association_name=name
-            new Lanes.Models.AssociationCollection(options.models || [], options)
+            options.association_name = name
+            klass = options.collectionClass or Lanes.Models.AssociationCollection
+            new klass(options.models || [], options)

     # returns a collection for the given association.
     collectionFor: (name, model, options = {}) ->


activity feed: comment out unused old member bucket view classes

--- client/app/Applications/Activity.kdapplication/views/newmemberbucket.coffee
+++ client/app/Applications/Activity.kdapplication/views/newmemberbucket.coffee
@@ -9,159 +9,159 @@

     super

-class NewMemberBucketView extends JView
+#class NewMemberBucketView extends JView

-  constructor: (options = {}, data)->
+#  constructor: (options = {}, data)->

-    options.cssClass = "new-member"
+#    options.cssClass = "new-member"

-    super
+#    super

-    @group = new NewMemberLinkGroup (totalCount : @getData().count), @getData().anchors
+#    @group = new NewMemberLinkGroup (totalCount : @getData().count), @getData().anchors

-    @lastFetchedDate      = null
-    @lastFetchedItemCount = 0
-    @isUserViewCreated    = no
-    @listViews            = []
-    @isLoading            = no
+#    @lastFetchedDate      = null
+#    @lastFetchedItemCount = 0
+#    @isUserViewCreated    = no
+#    @listViews            = []
+#    @isLoading            = no

-    @group.on "moreLinkClicked", =>
+#    @group.on "moreLinkClicked", =>

-      return warn "not yet implemented, @facet fix pls!!!"
+#      return warn "not yet implemented, @facet fix pls!!!"

-      return if @isLoading or @getData().count <= @lastFetchedItemCount and @showMore
-      @isLoading = yes
-      @groupLoader = new KDLoaderView
-        cssClass : "new-members-loader"
-        size     :
-          width  : 24
+#      return if @isLoading or @getData().count <= @lastFetchedItemCount and @showMore
+#      @isLoading = yes
+#      @groupLoader = new KDLoaderView
+#        cssClass : "new-members-loader"
+#        size     :
+#          width  : 24

-      @addSubView @groupLoader
-      @groupLoader.show()
-      @showMore?.hide()
+#      @addSubView @groupLoader
+#      @groupLoader.show()
+#      @showMore?.hide()

-      count = 10
+#      count = 10

-      if not @isUserViewCreated
-        @createCloseButton()
-        @isUserViewCreated = yes
+#      if not @isUserViewCreated
+#        @createCloseButton()
+#        @isUserViewCreated = yes

-      selector    =
-        type      : { $in : [options.type or= 'CNewMemberBucketActivity'] }
-        createdAt :
-          $gt     : @lastFetchedDate or @getData().createdAtTimestamps[0]
-          $lt     : @getData().createdAtTimestamps[1]
+#      selector    =
+#        type      : { $in : [options.type or= 'CNewMemberBucketActivity'] }
+#        createdAt :
+#          $gt     : @lastFetchedDate or @getData().createdAtTimestamps[0]
+#          $lt     : @getData().createdAtTimestamps[1]

-      options     =
-        limit     : count
+#      options     =
+#        limit     : count

-      KD.getSingleton("appManager").tell "Activity", "fetch", selector, options, (teasers, activities) =>
-        @getData().anchors = @getData().anchors.concat teasers.map (item)-> item.anchor
-        @group.setData @getData().anchors
+#      KD.getSingleton("appManager").tell "Activity", "fetch", selector, options, (teasers, activities) =>
+#        @getData().anchors = @getData().anchors.concat teasers.map (item)-> item.anchor
+#        @group.setData @getData().anchors

-        items = @getData().anchors.slice @lastFetchedItemCount, @lastFetchedItemCount + count
+#        items = @getData().anchors.slice @lastFetchedItemCount, @lastFetchedItemCount + count

-        newMembersList = new KDListViewController
-          view        : new NewMemberList
-          wrapper     : no
-          scrollView  : no
-        , items: items
+#        newMembersList = new KDListViewController
+#          view        : new NewMemberList
+#          wrapper     : no
+#          scrollView  : no
+#        , items: items

-        @listViews.push newMembersList
-        @addSubView newMembersList.getView()
-        @lastFetchedItemCount = @lastFetchedItemCount + count
-        @showMore.hide() if @getData().count <= @lastFetchedItemCount and @showMore
-        @lastFetchedDate = activities.last.createdAt
-        @groupLoader.destroy()
-        @createShowMore count
-        @isLoading = no
+#        @listViews.push newMembersList
+#        @addSubView newMembersList.getView()
+#        @lastFetchedItemCount = @lastFetchedItemCount + count
+#        @showMore.hide() if @getData().count <= @lastFetchedItemCount and @showMore
+#        @lastFetchedDate = activities.last.createdAt
+#        @groupLoader.destroy()
+#        @createShowMore count
+#        @isLoading = no

-  createCloseButton: ->
-    @addSubView @closeButton = new KDView
-      cssClass : "close-button"
-      partial  : "Close"
-      click    : =>
-        list.getView().destroy() for list in @listViews
-        @closeButton.destroy()
-        @showMore?.destroy()
-        @groupLoader?.destroy()
-        @lastFetchedItemCount = 0
-        @isUserViewCreated    = no
-        @isLoading            = no
-        @lastFetchedDate      = null
-        @listViews            = []
+#  createCloseButton: ->
+#    @addSubView @closeButton = new KDView
+#      cssClass : "close-button"
+#      partial  : "Close"
+#      click    : =>
+#        list.getView().destroy() for list in @listViews
+#        @closeButton.destroy()
+#        @showMore?.destroy()
+#        @groupLoader?.destroy()
+#        @lastFetchedItemCount = 0
+#        @isUserViewCreated    = no
+#        @isLoading            = no
+#        @lastFetchedDate      = null
+#        @listViews            = []

-  createShowMore: (count) ->
-    return if @getData().count < @lastFetchedItemCount
-    @addSubView @showMore = new KDView
-      cssClass : "show-more"
-      partial  : "Show More"
-      click    : =>
-        @group.emit "moreLinkClicked"
-        @showMore.hide() if @getData().count <= @lastFetchedItemCount + count
+#  createShowMore: (count) ->
+#    return if @getData().count < @lastFetchedItemCount
+#    @addSubView @showMore = new KDView
+#      cssClass : "show-more"
+#      partial  : "Show More"
+#      click    : =>
+#        @group.emit "moreLinkClicked"
+#        @showMore.hide() if @getData().count <= @lastFetchedItemCount + count

-  pistachio:->
-    """
-
-
-    {{> @group}}
-    """
+#  pistachio:->
+#    """
+#
+#
+#    {{> @group}}
+#    """

-class NewMemberList extends KDListView
-  constructor: (options = {}, data) ->
-    options.tagName   = "ul"
-    options.cssClass  = "activity-new-members"
-    options.itemClass = NewMemberListItem
+#class NewMemberList extends KDListView
+#  constructor: (options = {}, data) ->
+#    options.tagName   = "ul"
+#    options.cssClass  = "activity-new-members"
+#    options.itemClass = NewMemberListItem

-    super options, data
+#    super options, data

-class NewMemberLinkGroup extends LinkGroup
+#class NewMemberLinkGroup extends LinkGroup

-  constructor:(options = {}, data)->
+#  constructor:(options = {}, data)->

-    options.suffix or= " became a member."
-    super options, data
+#    options.suffix or= " became a member."
+#    super options, data

-  createMoreLink:->
+#  createMoreLink:->

-    @more.destroy() if @more
-    {totalCount, group} = @getOptions()
-    @more = new KDCustomHTMLView
-      tagName     : "a"
-      cssClass    : "more"
-      partial     : "#{totalCount-3} more"
-      attributes  :
-        href      : "#"
-        title     : "Click to view..."
-      click       : (e)=>
-        @emit "moreLinkClicked"
+#    @more.destroy() if @more
+#    {totalCount, group} = @getOptions()
+#    @more = new KDCustomHTMLView
+#      tagName     : "a"
+#      cssClass    : "more"
+#      partial     : "#{totalCount-3} more"
+#      attributes  :
+#        href      : "#"
+#        title     : "Click to view..."
+#      click       : (e)=>
+#        @emit "moreLinkClicked"

-# OLD
+## OLD

-class NewMemberBucketItemView extends KDView
+#class NewMemberBucketItemView extends KDView

-  constructor:(options,data)->
-    options = $.extend options,
-      cssClass : "new-member"
-    super options,data
+#  constructor:(options,data)->
+#    options = $.extend options,
+#      cssClass : "new-member"
+#    super options,data

-    @anchor = new ProfileLinkView origin: data.anchor
+#    @anchor = new ProfileLinkView origin: data.anchor

-  render:->
+#  render:->

-  addCommentBox:->
+#  addCommentBox:->

-  viewAppended:->
-    @setTemplate @pistachio()
-    @template.update()
+#  viewAppended:->
+#    @setTemplate @pistachio()
+#    @template.update()

-  pistachio:->
-    """
-
-    {{> @anchor}}
-    became a member.
-    """
+#  pistachio:->
+#    """
+#
+#    {{> @anchor}}
+#    became a member.
+#    """


added generic error logging

added generic error logging

--- services/web/app/coffee/router.coffee
+++ services/web/app/coffee/router.coffee
@@ -217,6 +217,10 @@
 			require("./models/Project").Project.findOne {}, () ->
 				throw new Error("Test error")

+		app.get '/opps-small', (req, res, next)->
+			logger.err "test error occured"
+			res.send()
+
 		app.post '/error/client', (req, res, next) ->
 			logger.error err: req.body.error, meta: req.body.meta, "client side error"
 			res.send(204)


Make sure values_hash is not nil if it is left blank in the DOM

--- app/assets/javascripts/designs.js.coffee
+++ app/assets/javascripts/designs.js.coffee
@@ -6,7 +6,7 @@
 # This function updates all variables starting with lowest one and progressing up in visibility.
 @updateAllVariables = () ->
   variableContainers = $('[data-object~="variable-container"]')
-  dmsg("Updating #{variableContainers.length} Variables")
+  # dmsg("Updating #{variableContainers.length} Variables")
   # $(variableContainers.get().reverse()).each( (index, variableContainer) ->
   variableContainers.each( (index, variableContainer) ->
     updateVariableContainer(variableContainer)
@@ -18,7 +18,7 @@
 # Show if none of the values evaluate to false [1,1,1,1] or [], but not [1,0,1,1] or [0]
 @updateVariableContainer = (element) ->
   # dmsg("Updating #{$(element).attr('id')}")
-  values_hash = $(element).data('values-hash')
+  values_hash = $(element).data('values-hash') || []
   truth_table = []
   $.each(values_hash, (index, condition_hash) ->
     result = checkCondition(condition_hash)


break responses

break responses

--- app/assets/javascripts/directives.coffee
+++ app/assets/javascripts/directives.coffee
@@ -152,7 +152,7 @@
         if !!node.responses
           text = text + "Responses:\n\n"
           _.each node.responses, (r) ->
-            text = text + r + "\n\n"
+            text = text + break_lines(r[0]) + ", " + r[1] + "\n\n"

         maxLineLength = _.max(text.split('\n'), (l) ->
           l.length
@@ -248,7 +248,7 @@
         root = get_root(source_h, target_h)

         flare = {name: root, children: [_.uniq source_h[root]]}
-        console.log flare
+        # console.log flare
         # _.each _.keys(source_h), (k) ->
         #   _.each _.keys(source_h), (k2) ->
         #     #console.log $.inArray(k, source_h[k2])        console.log root


Adding a yellow underline when editing the topology lines

--- app/assets/javascripts/editors.js.coffee
+++ app/assets/javascripts/editors.js.coffee
@@ -17,6 +17,7 @@

   editor.on 'change', ->
     textarea.text(editor.getSession().getValue())
+    $("a[href='#topology']").addClass("editing");

 $(document).on "page:change", ->
   textarea = $('textarea.topology-graph')


remove old file

remove old file

--- packages/rocketchat-version/plugin/compile-version.coffee
+++ packages/rocketchat-version/plugin/compile-version.coffee
@@ -1,62 +0,0 @@
-exec = Npm.require('child_process').exec
-os = Npm.require('os')
-Future = Npm.require('fibers/future')
-async = Npm.require('async')
-
-Plugin.registerCompiler
-	extensions: ['info']
-, -> new VersionCompiler()
-
-
-class VersionCompiler
-	processFilesForTarget: (files) ->
-		future = new Future
-
-		processFile = (file, cb) ->
-			return cb() if not file.getDisplayPath().match /rocketchat\.info$/
-
-			output = JSON.parse file.getContentsAsString()
-			output.build =
-				date: new Date().toISOString()
-				nodeVersion: process.version
-				arch: process.arch
-				platform: process.platform
-				osRelease: os.release()
-				totalMemory: os.totalmem()
-				freeMemory: os.freemem()
-				cpus: os.cpus().length
-
-			if process.env.TRAVIS_BUILD_NUMBER
-				output.travis =
-					buildNumber: process.env.TRAVIS_BUILD_NUMBER
-					branch: process.env.TRAVIS_BRANCH
-					tag: process.env.TRAVIS_TAG
-
-			exec "git log --pretty=format:'%H%n%ad%n%an%n%s' -n 1", (err, result) ->
-				if not err?
-					result = result.split('\n')
-
-					output.commit =
-						hash: result.shift()
-						date: result.shift()
-						author: result.shift()
-						subject: result.join('\n')
-
-				exec "git describe --abbrev=0 --tags", (err, result) ->
-					if not err?
-						output.commit?.tag = result.replace('\n', '')
-
-					exec "git rev-parse --abbrev-ref HEAD", (err, result) ->
-						if not err?
-							output.commit?.branch = result.replace('\n', '')
-
-						output = """
-							RocketChat.Info = #{JSON.stringify(output, null, 4)};
-						"""
-
-						file.addJavaScript({ data: output, path: file.getPathInPackage() + '.js' })
-						cb()
-
-		async.each files, processFile, future.resolver()
-
-		future.wait()


Fixed datepicker not working after changing report content once

--- app/assets/javascripts/reports.js.coffee
+++ app/assets/javascripts/reports.js.coffee
@@ -6,6 +6,7 @@
   $.get base_url + '/content/' + date.getFullYear() + '/' + (date.getMonth()+1)
   , (data) ->
     $("#report-content").html data
+    ready()
     return

 ready = ->


remove repeated js

remove repeated js

--- app/assets/javascripts/utility.js.coffee
+++ app/assets/javascripts/utility.js.coffee
@@ -16,13 +16,11 @@

   $(window).resize ->
     showFontSizes()
+    showContainerSize()

   $(".container").append(
     ""
   )
-
-  $(window).resize ->
-    showContainerSize()

   $("#light-bg").click (e)->
     v_span = $(this).find(".js-verb")


Angular was broken

Angular was broken

--- server/packages/angular/index.coffee
+++ server/packages/angular/index.coffee
@@ -57,7 +57,7 @@
 			htmlPromise.bind({}).then((html) ->

 				sandboxes.lookupOrCreate(
-					html, cookie, id
+					html, req.headers.cookie, req.session.id

 				# } Augment it.
 				).then (sandbox) -> exports.augmentSandbox sandbox


check for project - fixes #2422

check for project - fixes #2422

--- app/classifier/tasks/generic-editor.cjsx
+++ app/classifier/tasks/generic-editor.cjsx
@@ -57,7 +57,7 @@
         </div>}
       {' '}

-      {if 'hide previous marks' in @props.project.experimental_tools
+      {if @props.project and 'hide previous marks' in @props.project.experimental_tools
         <label className="pill-button">
           <AutoSave resource={@props.workflow}>
             <input type="checkbox" checked={@props.task.enableHidePrevMarks} onChange={@toggleHidePrevMarksEnabled} />{' '}


Don’t use jQuery in theme-manager-spec

Don’t use jQuery in theme-manager-spec

--- spec/theme-manager-spec.coffee
+++ spec/theme-manager-spec.coffee
@@ -1,6 +1,4 @@
 path = require 'path'
-
-{$, $$} = require '../src/space-pen-extensions'
 fs = require 'fs-plus'
 temp = require 'temp'

@@ -26,19 +24,20 @@
     afterEach ->
       jasmine.restoreDeprecationsSnapshot()

-    it 'getLoadedThemes get all the loaded themes', ->
-      themes = themeManager.getLoadedThemes()
-      expect(themes.length).toBeGreaterThan(2)
-
-    it 'getActiveThemes get all the active themes', ->
-      waitsForPromise ->
-        themeManager.activateThemes()
-
-      runs ->
-        names = atom.config.get('core.themes')
-        expect(names.length).toBeGreaterThan(0)
-        themes = themeManager.getActiveThemes()
-        expect(themes).toHaveLength(names.length)
+    describe 'getLoadedThemes', ->
+      it 'gets all the loaded themes', ->
+        themes = themeManager.getLoadedThemes()
+        expect(themes.length).toBeGreaterThan(2)
+
+    describe "getActiveThemes", ->
+      it 'gets all the active themes', ->
+        waitsForPromise -> themeManager.activateThemes()
+
+        runs ->
+          names = atom.config.get('core.themes')
+          expect(names.length).toBeGreaterThan(0)
+          themes = themeManager.getActiveThemes()
+          expect(themes).toHaveLength(names.length)

   describe "when the core.themes config value contains invalid entry", ->
     it "ignores theme", ->
@@ -88,7 +87,7 @@

       runs ->
         didChangeActiveThemesHandler.reset()
-        expect($('style.theme')).toHaveLength 0
+        expect(document.querySelectorAll('style.theme')).toHaveLength 0
         atom.config.set('core.themes', ['atom-dark-ui'])

       waitsFor ->
@@ -96,8 +95,8 @@

       runs ->
         didChangeActiveThemesHandler.reset()
-        expect($('style[priority=1]')).toHaveLength 2
-        expect($('style[priority=1]:eq(0)').attr('source-path')).toMatch /atom-dark-ui/
+        expect(document.querySelectorAll('style[priority="1"]')).toHaveLength 2
+        expect(document.querySelector('style[priority="1"]').getAttribute('source-path')).toMatch /atom-dark-ui/
         atom.config.set('core.themes', ['atom-light-ui', 'atom-dark-ui'])

       waitsFor ->
@@ -105,9 +104,9 @@

       runs ->
         didChangeActiveThemesHandler.reset()
-        expect($('style[priority=1]')).toHaveLength 2
-        expect($('style[priority=1]:eq(0)').attr('source-path')).toMatch /atom-dark-ui/
-        expect($('style[priority=1]:eq(1)').attr('source-path')).toMatch /atom-light-ui/
+        expect(document.querySelectorAll('style[priority="1"]')).toHaveLength 2
+        expect(document.querySelectorAll('style[priority="1"]')[0].getAttribute('source-path')).toMatch /atom-dark-ui/
+        expect(document.querySelectorAll('style[priority="1"]')[1].getAttribute('source-path')).toMatch /atom-light-ui/
         atom.config.set('core.themes', [])

       waitsFor ->
@@ -115,7 +114,7 @@

       runs ->
         didChangeActiveThemesHandler.reset()
-        expect($('style[priority=1]')).toHaveLength 2
+        expect(document.querySelectorAll('style[priority="1"]')).toHaveLength 2
         # atom-dark-ui has an directory path, the syntax one doesn't
         atom.config.set('core.themes', ['theme-with-index-less', 'atom-dark-ui'])

@@ -123,7 +122,7 @@
         didChangeActiveThemesHandler.callCount is 1

       runs ->
-        expect($('style[priority=1]')).toHaveLength 2
+        expect(document.querySelectorAll('style[priority="1"]')).toHaveLength 2
         importPaths = themeManager.getImportPaths()
         expect(importPaths.length).toBe 1
         expect(importPaths[0]).toContain 'atom-dark-ui'
@@ -172,37 +171,38 @@
       themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")

       cssPath = atom.project.getDirectories()[0]?.resolve('css.css')
-      lengthBefore = $('head style').length
+      lengthBefore = document.querySelectorAll('head style').length

       themeManager.requireStylesheet(cssPath)
-      expect($('head style').length).toBe lengthBefore + 1
+      expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1

       expect(styleElementAddedHandler).toHaveBeenCalled()
       expect(stylesheetAddedHandler).toHaveBeenCalled()
       expect(stylesheetsChangedHandler).toHaveBeenCalled()

-      element = $('head style[source-path*="css.css"]')
-      expect(element.attr('source-path')).toBe themeManager.stringToId(cssPath)
-      expect(element.text()).toBe fs.readFileSync(cssPath, 'utf8')
-      expect(element[0].sheet).toBe stylesheetAddedHandler.argsForCall[0][0]
+      element = document.querySelector('head style[source-path*="css.css"]')
+      expect(element.getAttribute('source-path')).toBe themeManager.stringToId(cssPath)
+      expect(element.textContent).toBe fs.readFileSync(cssPath, 'utf8')
+      expect(element.sheet).toBe stylesheetAddedHandler.argsForCall[0][0]

       # doesn't append twice
       styleElementAddedHandler.reset()
       themeManager.requireStylesheet(cssPath)
-      expect($('head style').length).toBe lengthBefore + 1
+      expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1
       expect(styleElementAddedHandler).not.toHaveBeenCalled()

-      $('head style[id*="css.css"]').remove()
+      for styleElement in document.querySelectorAll('head style[id*="css.css"]')
+        styleElement.remove()

     it "synchronously loads and parses less files at the given path and installs a style tag for it in the head", ->
       lessPath = atom.project.getDirectories()[0]?.resolve('sample.less')
-      lengthBefore = $('head style').length
+      lengthBefore = document.querySelectorAll('head style').length
       themeManager.requireStylesheet(lessPath)
-      expect($('head style').length).toBe lengthBefore + 1
-
-      element = $('head style[source-path*="sample.less"]')
-      expect(element.attr('source-path')).toBe themeManager.stringToId(lessPath)
-      expect(element.text()).toBe """
+      expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1
+
+      element = document.querySelector('head style[source-path*="sample.less"]')
+      expect(element.getAttribute('source-path')).toBe themeManager.stringToId(lessPath)
+      expect(element.textContent).toBe """
       #header {
         color: #4d926f;
       }
@@ -214,24 +214,25 @@

       # doesn't append twice
       themeManager.requireStylesheet(lessPath)
-      expect($('head style').length).toBe lengthBefore + 1
-      $('head style[id*="sample.less"]').remove()
+      expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1
+      for styleElement in document.querySelectorAll('head style[id*="sample.less"]')
+        styleElement.remove()

     it "supports requiring css and less stylesheets without an explicit extension", ->
       themeManager.requireStylesheet path.join(__dirname, 'fixtures', 'css')
-      expect($('head style[source-path*="css.css"]').attr('source-path')).toBe themeManager.stringToId(atom.project.getDirectories()[0]?.resolve('css.css'))
+      expect(document.querySelector('head style[source-path*="css.css"]').getAttribute('source-path')).toBe themeManager.stringToId(atom.project.getDirectories()[0]?.resolve('css.css'))
       themeManager.requireStylesheet path.join(__dirname, 'fixtures', 'sample')
-      expect($('head style[source-path*="sample.less"]').attr('source-path')).toBe themeManager.stringToId(atom.project.getDirectories()[0]?.resolve('sample.less'))
-
-      $('head style[id*="css.css"]').remove()
-      $('head style[id*="sample.less"]').remove()
+      expect(document.querySelector('head style[source-path*="sample.less"]').getAttribute('source-path')).toBe themeManager.stringToId(atom.project.getDirectories()[0]?.resolve('sample.less'))
+
+      document.querySelector('head style[source-path*="css.css"]').remove()
+      document.querySelector('head style[source-path*="sample.less"]').remove()

     it "returns a disposable allowing styles applied by the given path to be removed", ->
       cssPath = require.resolve('./fixtures/css.css')

-      expect($(document.body).css('font-weight')).not.toBe("bold")
+      expect(getComputedStyle(document.body).fontWeight).not.toBe("bold")
       disposable = themeManager.requireStylesheet(cssPath)
-      expect($(document.body).css('font-weight')).toBe("bold")
+      expect(getComputedStyle(document.body).fontWeight).toBe("bold")

       atom.styles.onDidRemoveStyleElement styleElementRemovedHandler = jasmine.createSpy("styleElementRemovedHandler")
       themeManager.onDidRemoveStylesheet stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
@@ -239,7 +240,7 @@

       disposable.dispose()

-      expect($(document.body).css('font-weight')).not.toBe("bold")
+      expect(getComputedStyle(document.body).fontWeight).not.toBe("bold")

       expect(styleElementRemovedHandler).toHaveBeenCalled()
       expect(stylesheetRemovedHandler).toHaveBeenCalled()
@@ -271,9 +272,9 @@
         expect(getComputedStyle(workspaceElement)["background-color"]).toBe "rgb(0, 0, 255)"

         # from within the theme itself
-        expect($("atom-text-editor").css("padding-top")).toBe "150px"
-        expect($("atom-text-editor").css("padding-right")).toBe "150px"
-        expect($("atom-text-editor").css("padding-bottom")).toBe "150px"
+        expect(getComputedStyle(document.querySelector("atom-text-editor")).paddingTop).toBe "150px"
+        expect(getComputedStyle(document.querySelector("atom-text-editor")).paddingRight).toBe "150px"
+        expect(getComputedStyle(document.querySelector("atom-text-editor")).paddingBottom).toBe "150px"

     describe "when there is a theme with incomplete variables", ->
       it "loads the correct values from the fallback ui-variables", ->
@@ -288,7 +289,7 @@
           expect(getComputedStyle(workspaceElement)["background-color"]).toBe "rgb(0, 0, 255)"

           # from within the theme itself
-          expect($("atom-text-editor").css("background-color")).toBe "rgb(0, 152, 255)"
+          expect(getComputedStyle(document.querySelector("atom-text-editor")).backgroundColor).toBe "rgb(0, 152, 255)"

   describe "user stylesheet", ->
     userStylesheetPath = null
@@ -320,14 +321,14 @@
           themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
           spyOn(themeManager, 'loadUserStylesheet').andCallThrough()

-          expect($(document.body).css('border-style')).toBe 'dotted'
+          expect(getComputedStyle(document.body).borderStyle).toBe 'dotted'
           fs.writeFileSync(userStylesheetPath, 'body {border-style: dashed}')

         waitsFor ->
           themeManager.loadUserStylesheet.callCount is 1

         runs ->
-          expect($(document.body).css('border-style')).toBe 'dashed'
+          expect(getComputedStyle(document.body).borderStyle).toBe 'dashed'

           expect(styleElementRemovedHandler).toHaveBeenCalled()
           expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain 'dotted'
@@ -354,7 +355,7 @@
           expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain 'dashed'
           expect(stylesheetRemovedHandler).toHaveBeenCalled()
           expect(stylesheetRemovedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dashed'
-          expect($(document.body).css('border-style')).toBe 'none'
+          expect(getComputedStyle(document.body).borderStyle).toBe 'none'
           expect(stylesheetsChangedHandler).toHaveBeenCalled()

     describe "when there is an error reading the stylesheet", ->


Properly work with problems with pdf statement

--- server/testSystems/Codeforces.coffee
+++ server/testSystems/Codeforces.coffee
@@ -170,9 +170,11 @@
         {contest, problem} = data.testSystemData
         if contest.startsWith("gym")
             href = "#{BASE_URL}/#{contest}/problem/#{problem}?csrf_token=#{csrf}"
+            csrfHref = "#{BASE_URL}/#{contest}"
         else
             href = "#{BASE_URL}/problemset/problem/#{contest}/#{problem}?csrf_token=#{csrf}"
-        page = await @download(href)
+            csrfHref = href
+        page = await @download(csrfHref)
         csrf = @_getCsrf(page)
         data = {
                 csrf_token: csrf
@@ -251,7 +253,7 @@

     downloadProblem: (options) ->
         if options.contest.startsWith("gym")
-            href = "#{BASE_URL}/#{options.contest}/problem/#{options.problem}"
+            href = "#{BASE_URL}/#{options.contest}/problem/#{options.problem}?locale=ru"
         else
             href = "#{BASE_URL}/problemset/problem/#{options.contest}/#{options.problem}?locale=ru"
         page = await downloadLimited(href, {timeout: 15 * 1000})
@@ -259,7 +261,10 @@
         data = document.getElementsByClassName("problem-statement")
         if not data or data.length == 0
             logger.warn("Can't find statement for problem " + href)
-            return {"???", "???"}
+            name = options.name || "???"
+            name = "#{options.problem}. #{name}"
+            text = "
#{name}

См. условие на codeforces:
"
+            return {name, text}
         data = data[0]
         nameEl = data.getElementsByClassName("title")[0]
         # Drop leading letter, dot and space


(feature) change opacity of ws editor if not connected or they exist pending ops

--- app/scripts/pages/editor/markdown.coffee
+++ app/scripts/pages/editor/markdown.coffee
@@ -101,6 +101,23 @@
       javascriptEditorErrors "js", prev
     ]

-    shareDocConnection.connect(editor);
+    getStatus = shareDocConnection.connect(editor);
+
+    checkStatus = ->
+      status = getStatus();
+      if status.pending > 0 && status.state != "connected"
+        editor.container.style.opacity=0.1
+        #console.log "not connected and pending changes"
+      else if status.pending > 0
+        editor.container.style.opacity=0.6
+        #console.log "pending changes"
+      else if status.state != "connected"
+        editor.container.style.opacity=0.3
+        #console.log "not connected"
+      else
+        editor.container.style.opacity=1.0
+        #console.log "connected"
+
+    setInterval checkStatus, 5000

   prev.render task.solution()


Helper methods for learning guide

Helper methods for learning guide

--- src/flux/learning-guide.coffee
+++ src/flux/learning-guide.coffee
@@ -35,17 +35,17 @@
 # learning guide data for a student.
 Student = makeSimpleStore extendConfig {
   exports:
-    getSortedSections: (courseId, property = 'current_level') ->
+    getSortedSections: (courseId) ->
       sections = findAllSections(@_get(courseId))
-      _.sortBy(sections, property)
+      _.sortBy(sections, (s) -> s.clue.value)

     getAllSections: (courseId) ->
       findAllSections(@_get(courseId))

-    getPracticePages: (courseId) ->
-      all = @exports.getSortedSections.call(this, courseId)
-      count = Math.min(all.length, 4)
-      _.chain(all).first(count).pluck('page_ids').flatten().uniq().value()
+    # getPracticePages: (courseId) ->
+    #   all = @exports.getSortedSections.call(this, courseId)
+    #   count = Math.min(all.length, 4)
+    #   _.chain(all).first(count).pluck('page_ids').flatten().uniq().value()

 }, new CrudConfig
@@ -100,5 +100,30 @@

 }, new CrudConfig

+Helpers = {

-module.exports = {Student, Teacher, TeacherStudent}
+  filterForecastedSections: (sections) ->
+    _.filter(sections, (s) -> s.clue.sample_size_interpretation isnt 'below')
+
+  weakestSections: (sections, displayCount = 4) ->
+    validSections = @filterForecastedSections(sections)
+    displayCount = Math.min(Math.floor(validSections.length / 2), displayCount)
+
+    # Sort by value and pick 'displayCount' of the weakest
+    _.chain(validSections)
+      .sortBy((s) -> s.clue.value )
+      .first(displayCount)
+      .value()
+
+  canPractice: ({sections, displayCount, minimumSectionCount}) ->
+    displayCount ||= 4
+    minimumSectionCount ||= 2
+    @weakestSections(sections, displayCount).length >= minimumSectionCount
+
+  pagesForSections: (sections) ->
+    _.chain(sections).pluck('page_ids').flatten().uniq().value()
+
+}
+
+
+module.exports = {Student, Teacher, TeacherStudent, Helpers}


Fix spec

Fix spec

--- spec/deprecation-cop-status-bar-view-spec.coffee
+++ spec/deprecation-cop-status-bar-view-spec.coffee
@@ -21,7 +21,7 @@

   it "adds the status bar view when activated", ->
     expect(statusBarView).toExist()
-    expect(statusBarView.textContent).toBe '0'
+    expect(statusBarView.textContent).toBe '0 deprecations!'
     expect(statusBarView).not.toShow()

   it "increments when there are deprecated methods", ->
@@ -31,41 +31,41 @@
     expect(statusBarView).not.toShow()

     deprecatedMethod()
-    expect(statusBarView.textContent).toBe '1'
+    expect(statusBarView.textContent).toBe '1 deprecation!'
     expect(statusBarView).toShow()

     deprecatedMethod()
-    expect(statusBarView.textContent).toBe '2'
+    expect(statusBarView.textContent).toBe '2 deprecations!'
     expect(statusBarView).toShow()

     anotherDeprecatedMethod()
-    expect(statusBarView.textContent).toBe '3'
+    expect(statusBarView.textContent).toBe '3 deprecations!'
     expect(statusBarView).toShow()

   it "increments when there are deprecated selectors", ->
     atom.packages.loadPackage(path.join(__dirname, "..", "spec", "fixtures", "package-with-deprecated-selectors"))

-    expect(statusBarView.textContent).toBe '3'
+    expect(statusBarView.textContent).toBe '3 deprecations!'
     expect(statusBarView).toBeVisible()

     atom.packages.unloadPackage('package-with-deprecated-selectors')

-    expect(statusBarView.textContent).toBe '0'
+    expect(statusBarView.textContent).toBe '0 deprecations!'
     expect(statusBarView).not.toBeVisible()

   it "increments when a theme with deprecated selectors is activated", ->
     atom.packages.loadPackage(path.join(__dirname, "..", "spec", "fixtures", "theme-with-deprecated-selectors"))

     expect(statusBarView).not.toBeVisible()
-    expect(statusBarView.textContent).toBe '0'
+    expect(statusBarView.textContent).toBe '0 deprecations!'

     waitsForPromise ->
       atom.packages.activatePackage(path.join(__dirname, "..", "spec", "fixtures", "theme-with-deprecated-selectors"))

     runs ->
       expect(statusBarView).toBeVisible()
-      expect(statusBarView.textContent).toBe '1'
-
+      expect(statusBarView.textContent).toBe '1 deprecation!'
+
       atom.packages.deactivatePackage("theme-with-deprecated-selectors")
       atom.packages.unloadPackage("theme-with-deprecated-selectors")


check dirty resources

check dirty resources

--- firefox/lib/lixian.coffee
+++ firefox/lib/lixian.coffee
@@ -393,7 +393,9 @@
 				commit_url = "/interface/bt_task_commit?callback=#{jsonp}"
 				@post commit_url, form, ({text}) =>
 					result = @parse_jsonp_response text, jsonp
-					if result?.progress? and result.progress not in [-12, -11]
+					if result?.msg # "progress":2,"rtcode":"75","msg":"..."
+						callback ok: false, reason: result.msg, response: text
+					else if result?.progress? and result.progress not in [-12, -11]
 						callback ok: true, reason: 'BT task created', info_hash: info_hash
 					else if result?.progress in [-12, -11]
 						if @require_verification_code


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/function_extensions.coffee
+++ src/function_extensions.coffee
@@ -4,7 +4,7 @@

   return ->
     return memo if ran
-
+    ran = tr

   _.once = function(func) {


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/function_extensions.coffee
+++ src/function_extensions.coffee
@@ -1,4 +1,4 @@
-Function
+Function::once

 Function::withBefore = (interception) ->
   method = this


Add hubot prefix to command docs in beerme.coffee

--- src/scripts/beerme.coffee
+++ src/scripts/beerme.coffee
@@ -8,7 +8,7 @@
 #   None
 #
 # Commands:
-#   beer me - Grab me a beer
+#   hubot beer me - Grab me a beer
 #
 # Author:
 #  houndbee


Check if Room is defined

Check if Room is defined

--- src/scripts/deploy.coffee
+++ src/scripts/deploy.coffee
@@ -40,7 +40,7 @@
     message += " version " + version if version

     robot.send(user, message)
-    if robot.adapter.bot?
+    if robot.adapter.bot?.Room?
       robot.adapter.bot.Room(user.room).sound "trombone", (err, data) =>
         console.log "campfire error: #{err}" if err


Allow links to avoid triggering Backbone's route function

--- src/scripts/loader.coffee
+++ src/scripts/loader.coffee
@@ -20,7 +20,8 @@

     # Catch internal application links and let Backbone handle the routing
     $(document).on 'click', 'a:not([data-bypass])', (e) ->
-      href = $(this).attr('href')
+      $this = $(this)
+      href = $this.attr('href')

       # Only handle links intended to be processed by Backbone
       if e.isDefaultPrevented() or href.charAt(0) is '#' or /^mailto:.+/.test(href) then return
@@ -40,7 +41,8 @@
       else if resources.test(href)
         window.open(href, '_blank')
       else
-        router.navigate(href, {trigger: true})
+        if $this.data('trigger') is false then trigger = false else trigger = true
+        router.navigate(href, {trigger: trigger})

     Backbone.history.start
       pushState: true


changed points.coffee to use robot.brain rather than redis directly

--- src/scripts/points.coffee
+++ src/scripts/points.coffee
@@ -2,11 +2,10 @@
 #   Give, Take and List User Points
 #
 # Dependencies:
-#   "redis": "0.7.2"
+#   None
 #
 # Configuration:
-#   HUBOT_REDIS_HOST
-#   HUBOT_REDIS_PORT
+#   None
 #
 # Commands:
 #   hubot give <number> points to <username> - award <number> points to <username>
@@ -18,64 +17,51 @@
 # Author:
 #   brettlangdon
 #
-redis = require 'redis'

-client = null
-host = if process.env.HUBOT_REDIS_HOST then process.env.HUBOT_REDIS_HOST else 'localhost'
-port = if process.env.HUBOT_REDIS_PORT then parseInt(process.env.HUBOT_REDIS_PORT) else 6379
-
+points = {}

 award_points = (msg, username, pts) ->
-    client.get('hubot.points.'+username, (err,value)->
-        if err
-            msg.logger.err err
-            value = 0
+    points[username] ?= 0
+    points[username] += parseInt(pts)
+    msg.send pts + ' Awarded To ' + username

-        value = parseInt(value) + parseInt(pts)
-        client.set('hubot.points.'+username, value)
-        msg.send pts + ' Awarded To ' + username
-    )
-
-
+save = (robot) ->
+    robot.brain.data.points = points

 module.exports = (robot) ->
+    robot.brain.on 'loaded', ->
+        points = robot.brain.data.points
+
     robot.respond /give (\d+) points to (.*?)\s?$/i, (msg) ->
         award_points(msg, msg.match[2], msg.match[1])
+        save(robot)
+
     robot.respond /give (.*?) (\d+) points/i, (msg) ->
         award_points(msg, msg.match[1], msg.match[2])
+        save(robot)

     robot.respond /take all points from (.*?)\s?$/i, (msg) ->
         username = msg.match[1]
-        client.set('hubot.points.'+username, 0)
+        points[username] = 0
         msg.send username + ' WHAT DID YOU DO?!'
-
+        save(robot)

     robot.respond /take (\d+) points from (.*?)\s?$/i, (msg) ->
          pts = msg.match[1]
          username = msg.match[2]
-         client.get('hubot.points.'+username, (err,value)->
-             if err
-                 msg.logger.err err
-                 value = 0
-             value = parseInt(value) - parseInt(pts)
-             if value < 0
-                 value = 0
-             client.set('hubot.points.'+username, value)
-             msg.send pts + ' Taken Away From ' + username
-         )
+         points[username] ?= 0
+
+         if points[username] is 0
+             msg.send username + ' Does Not Have Any Points To Take Away'
+         else
+             points[username] -= parseInt(pts)
+             msg.send pts + ' Points Taken Away From ' + username
+
+         save(robot)

     robot.respond /how many points does (.*?) have\??/i, (msg) ->
         username = msg.match[1]
-
-        client.get('hubot.points.'+username, (err,value) ->
-            if err
-                msg.logger.err err
-                value = 0
-            msg.send username + ' Has ' + value + ' Points'
-        )
-
-    client = redis.createClient(port,host)
-    client.on 'error', (err) ->
-        robot.logger.error err
-    client.on 'connect', ->
-        robot.logger.debug 'Connected to Redis'+        points[username] ?= 0
+
+        msg.send username + ' Has ' + points[username] + ' Points'
+


Decoded path replaces encoded path in history

Really fixed this time.

--- src/scripts/router.coffee
+++ src/scripts/router.coffee
@@ -10,7 +10,7 @@
     initialize: (args...) ->
       decodedPathname = decodeURIComponent(window.location.pathname)
       if (decodedPathname != window.location.pathname)
-        Backbone.history.navigate(decodedPathname)
+        window.location.replace(decodeURIComponent(window.location))
       @appView = new AppView()

       # Default Route


Fixed table view row width after refactor

--- src/directives/table_view.coffee
+++ src/directives/table_view.coffee
@@ -21,6 +21,7 @@
 ## - mac-table-has-total-footer:  Boolean determining if footer with total should be shown         (default false)
 ## - mac-table-has-footer:        A boolean value to determine if footer should be shown           (default false)
 ## - mac-table-width:             The width of the whole table                                     (default 800)
+## - mac-table-fluid-width:
 ## - mac-table-column-width:      The minimum width of a column                                    (default 140)
 ## - mac-table-row-height:        The height of each row in the table                              (default 20)
 ## - mac-table-num-display-rows:  The total number of rows to display                              (default 10)
@@ -67,6 +68,7 @@
         allowReorder:          true
         objectPrefix:          ""
         calculateTotalLocally: false
+        fluidWidth:            false

       transcludedBlock = $(".table-transclude", element)
@@ -90,10 +92,13 @@
       totalRows       = opts.numDisplayRows
       totalRows      += opts.hasFooter + opts.hasTotalFooter

-      # Update the width and height of the whole table
-      element.css
-        height: cellOuterHeight * totalRows
-        width:  opts.width - 2 * opts.borderWidth
+      (->
+        # Update the width and height of the whole table
+        width = if false then "100%" else (opts.width - 2 * opts.borderWidth)
+        element.css
+          height: cellOuterHeight * totalRows
+          width:  width
+      )()

       ($scope, element, attrs) ->
         # Make sure columns are defined


Fix a little issue with resizing...

Fix a little issue with resizing...

--- salvus/page/editor.coffee
+++ salvus/page/editor.coffee
@@ -858,6 +858,8 @@
         @output.width(@element.width())

     update: (cb) =>
+        @output.height(@element.height())
+        @output.width(@element.width())
         @spinner.show().spin(true)
         tmp_dir @editor.project_id, @path, (err, tmp) =>
             if err


onNextSlide callback

onNextSlide callback

--- typist.coffee
+++ typist.coffee
@@ -4,6 +4,9 @@

   _addEvent: (element, event, fn, useCapture = false) ->
     element.addEventListener event, fn, useCapture
+
+  _fireEvent: (event, options) =>
+    @options[event].call @, options if @options[event]

   _forEach: (array, fn, bind) ->
     i = 0
@@ -85,6 +88,7 @@

     @_delay =>
       @typeText @variations[@offsets.current.index]
+      @_fireEvent "onNextSlide"
     , @options.letterInterval * @offsets.current.text.length

     # loop index


Fixed editing documents. Oops

Fixed editing documents. Oops

--- src/server/session.coffee
+++ src/server/session.coffee
@@ -126,12 +126,11 @@
       #stream.emit 'error', error
       return callback error

-    collection = req.c
-
     # The agent can specify null as the docName to get a random doc name.
     if req.a in ['qfetch', 'qsub', 'qunsub']
       # Query based query.
       qid = req.id
+      collection = req.c
       qopts = {}
       if req.o
         autoFetch = req.o.f
@@ -154,6 +153,7 @@
         req.doc = lastReceivedDoc

       doc = req.doc
+      collection = req.c

     switch req.a


Tests: Helpers: IDEHelpers: Added toggleInvisibleFiles helper.

--- client/test/lib/helpers/idehelpers.coffee
+++ client/test/lib/helpers/idehelpers.coffee
@@ -133,3 +133,21 @@
       .waitForElementVisible  contextMenuSelector, 20000
       .click                  openFileSelector
       .waitForElementVisible  fileTabSelector, 20000
+
+
+  toggleInvisibleFiles: (browser, user) ->
+
+    pathSelector = "span[title='/home/#{user.username}/.bashrc']"
+
+    helpers.clickVMHeaderButton(browser)
+
+    browser
+      .click                   '.context-list-wrapper .refresh'
+      .waitForElementVisible    pathSelector, 20000 # Assertion
+
+    helpers.clickVMHeaderButton(browser)
+
+    browser
+      .click                    '.context-list-wrapper .toggle-invisible-files'
+      .pause 2000
+      .waitForElementNotPresent pathSelector, 20000 # Assertion


fix compass files path when enabling sass or scss

--- app/templates/grunt/contrib-watch.coffee
+++ app/templates/grunt/contrib-watch.coffee
@@ -13,8 +13,8 @@
         spawn: false
     <% } %><% if (precompilerSass || precompilerScss) { %>compass:
       files: [<% if (precompilerSass) { %>
-        '<%%= compass.dev.options.sassDir %>/**/*.sass'<% } %><% if (precompilerScss) { %>
-        '<%%= compass.dev.options.sassDir %>/**/*.scss'
+        '<%%= compass.devSASS.options.sassDir %>/**/*.sass'<% } %><% if (precompilerScss) { %>
+        '<%%= compass.devSCSS.options.sassDir %>/**/*.scss'
       <% } %>]
       tasks: [
         <% if (precompilerSass) { %>


style tree

style tree

--- app/graphite.coffee
+++ app/graphite.coffee
@@ -177,17 +177,21 @@
           parts = child.path.split '.'
           name = parts[parts.length - 1]
           TreeNodeComponent {cache: @props.cache, tree_state: @props.tree_state, node: child, open: @props.open, close: @props.close, load: @props.load, name: name}
-      else if state == 'opening'
-        child = React.DOM.span null, 'loading...'
       else
         child = null
       if @props.node.is_leaf
         toggle = ''
       else if state == 'open'
-        toggle = '- '
-      else
-        toggle = '+ '
-      React.DOM.li null, React.DOM.span({onClick: @handle_click}, "#{toggle}#{@props.name}"), child
+        toggle = 'fa fa-fw fa-caret-down'
+      else if state == 'opening'
+        toggle = 'fa fa-fw fa-spinner fa-spin'
+      else
+        toggle = 'fa fa-fw fa-caret-right'
+      React.DOM.li null,
+        React.DOM.span({onClick: @handle_click},
+          React.DOM.i {className: toggle}
+          "#{@props.name}")
+          child
     handle_click: ->
       path = @props.node.path
       state = @props.tree_state[path]


Fix app initialization on old browsers

Fix app initialization on old browsers

--- assets/javascripts/application.js.coffee
+++ assets/javascripts/application.js.coffee
@@ -19,7 +19,7 @@
 #= require_tree ./templates

 init = ->
-  document.removeEventListener 'DOMContentLoaded', init
+  document.removeEventListener 'DOMContentLoaded', init, false
   app.init()

 document.addEventListener 'DOMContentLoaded', init, false


Remove unused injected variable

Remove unused injected variable

--- src/app/text-mate-grammar.coffee
+++ src/app/text-mate-grammar.coffee
@@ -212,11 +212,9 @@
   getScanner: (baseGrammar, position, firstLine) ->
     return scanner if scanner = @scannersByBaseGrammarName[baseGrammar.name]

-    injected = false
     patterns = @getIncludedPatterns(baseGrammar)
     scanner = @createScanner(patterns, firstLine, position)
-    unless scanner.anchored or injected
-      @scannersByBaseGrammarName[baseGrammar.name] = scanner
+    @scannersByBaseGrammarName[baseGrammar.name] = scanner unless scanner.anchored
     scanner

   scanInjections: (ruleStack, line, position, firstLine) ->


Lil typo

Lil typo

--- examples/basic/main.coffee
+++ examples/basic/main.coffee
@@ -1,2 +1,2 @@
-#Usese the Items collection object previously defined in testdata.coffee
-@Pages = new Meteor.Pagination Items+#Uses the Items collection object previously defined in testdata.coffee
+@Pages = new Meteor.Pagination Items


Keymap to move caret to the end/start of the current line

To simply move the caret to the end/start of the current line instead of
using the `end` and `pos` keys a new mapping should be added for Linux
based OS.

- Move to the end of the current line: `Ctrl` (super) + `alt` + `→`
- Move to the start of the current line: `Ctrl` (super) + `alt` + `←`

The default mappings `⌘` + `⌥` + `←` / `→` for macOS are already
provided by default.

Closes GH-167

--- snowblocks/atom/keymap.cson
+++ snowblocks/atom/keymap.cson
@@ -15,5 +15,8 @@
   # Simple and fast project management workflow.
   "ctrl-alt-p": "project-folder:add"

-"atom-text-editor":
+".platform-linux atom-text-editor":
   "ctrl-alt-c": "color-picker:open"
+  # Easy mappings to move the caret to the end/start of the current line instead of using "end" and "pos" keys.
+  "cmd-alt-right": "editor:move-to-end-of-screen-line"
+  "cmd-alt-left": "editor:move-to-first-character-of-line"


support rate parameter

support rate parameter

--- src/opentsdb.coffee
+++ src/opentsdb.coffee
@@ -11,8 +11,9 @@
     to_metric_string: (time_series) ->
       if _.isString time_series
         time_series = metric_name: time_series
-      {aggregation, metric_name, downsample, tags} = time_series
+      {aggregation, metric_name, downsample, tags, rate} = time_series
       parts = [aggregation ? 'sum']
+      parts.push 'rate' if rate
       parts.push "#{downsample.period}-#{downsample.aggregation}" if downsample
       parts.push metric_name + '{' + _.map(tags, (tagv, tagk) -> "#{tagk}=#{tagv}").join(',') + '}'
       parts.join ':'


Optimize homepage API calls

Optimize homepage API calls

Cuts the request count down from 12 to 1

--- app/pages/home.cjsx
+++ app/pages/home.cjsx
@@ -42,17 +42,27 @@
 FeaturedProjects = React.createClass
   displayName: "FeaturedProjects"

+  imagePromise: (project) ->
+    src = if project.avatar_src
+      "//#{ project.avatar_src }"
+    else
+      '/assets/simple-avatar.jpg'
+    Promise.resolve src
+
   render: ->

-      <PromiseRenderer promise={apiClient.type('projects').get(FEATURED_PRODUCT_IDS)}>{(projects) =>
+      <PromiseRenderer promise={apiClient.type('projects').get(id: FEATURED_PRODUCT_IDS, cards: true)}>{(projects) =>
         if projects?

           {for project in projects
             [owner, name] = project.slug.split('/')
-
-            avatarSrc = project.get('avatar').then (avatar) ->
-              avatar.src
-            <OwnedCard key={project.id} resource={project} linkTo="/projects/#{owner}/#{name}" translationObjectName="projectsPage" imagePromise={avatarSrc} />
+            <OwnedCard
+              key={project.id}
+              resource={project}
+              linkTo="/projects/#{owner}/#{name}"
+              translationObjectName="projectsPage"
+              imagePromise={@imagePromise(project)}
+              skipOwner={true} />
           }

       }</PromiseRenderer>


dynamically adds or removes handles if model changes

--- src/coffeescript/multirange-slider.coffee
+++ src/coffeescript/multirange-slider.coffee
@@ -54,37 +54,48 @@
           left: x + "%"
           top: "-" + handle.prop("clientHeight")/2 + "px"

-    for mv,i in scope.model
-      do (mv, i)->
-        return if i == scope.model.length-1
-        handle = angular.element('

')
-        handle.css("position", "absolute")
-        handles.push(handle)
-        element.append(handle)
+    renderHandles = (model) ->
+      for mv,i in model
+        do (mv, i)->
+          return if i == model.length-1
+          handle = angular.element('

')
+          handle.css("position", "absolute")
+          handles.push(handle)
+          element.append(handle)

-        startX = 0
-        startPleft = startPright = 0
-        handle.on "mousedown", (event) ->
-          mousemove = (event) => scope.$apply ()->
-            dp = (event.screenX - startX) / element.prop("clientWidth") * pTotal
-            return if dp < -startPleft or dp > startPright
-            setP(i, startPleft+dp)
-            setP(i+1, startPright-dp)
-            updatePositions()
+          startX = 0
+          startPleft = startPright = 0
+          handle.on "mousedown", (event) ->
+            mousemove = (event) => scope.$apply ()->
+              dp = (event.screenX - startX) / element.prop("clientWidth") * pTotal
+              return if dp < -startPleft or dp > startPright
+              setP(i, startPleft+dp)
+              setP(i+1, startPright-dp)
+              updatePositions()

-          mouseup = ->
-            $document.unbind "mousemove", mousemove
-            $document.unbind "mouseup", mouseup
+            mouseup = ->
+              $document.unbind "mousemove", mousemove
+              $document.unbind "mouseup", mouseup

-          # Prevent default dragging of selected content
-          event.preventDefault()
-          startX = event.screenX
-          startPleft = getP(i)
-          startPright = getP(i+1)
-          $document.on "mousemove", mousemove
-          $document.on "mouseup", mouseup
+            # Prevent default dragging of selected content
+            event.preventDefault()
+            startX = event.screenX
+            startPleft = getP(i)
+            startPright = getP(i+1)
+            $document.on "mousemove", mousemove
+            $document.on "mouseup", mouseup

-    scope.$watch "model", updatePositions, true
+    onModelChange = (changedModel, model) ->
+      if changedModel.length != model.length
+        handles = []
+        element.children().remove()
+        renderHandles(changedModel)
+
+      updatePositions()
+
+
+    renderHandles scope.model
+    scope.$watch "model", onModelChange, true
 )

 angular.module("multirangeSlider").controller("Ctrl", ($scope)->


fix broken spec

fix broken spec

--- spec/stdlib/onig-reg-exp-spec.coffee
+++ spec/stdlib/onig-reg-exp-spec.coffee
@@ -12,7 +12,7 @@
       result = regex.search("--------")
       expect(result).toBeNull()

-  describe ".getCaptureTree(string, index)", ->
+  describe ".getCaptureIndices(string, index)", ->
     it "returns match with nested capture groups organized into a tree", ->
       regex = new OnigRegExp("a((bc)d)e(f(g)(h))(?=ij)")
       tree = regex.getCaptureIndices("abcdefghij")
@@ -28,5 +28,5 @@

     it "returns undefined if there was no match", ->
       regex = new OnigRegExp('x')
-      expect(regex.getCaptureTree('y')).toBeNull()
+      expect(regex.getCaptureIndices('y')).toBeNull()


In TextEditorElement spec, style scrollbar within shadow root

--- spec/text-editor-element-spec.coffee
+++ spec/text-editor-element-spec.coffee
@@ -133,16 +133,16 @@
     it "re-renders the scrollbar", ->
       jasmineContent.appendChild(element)

-      atom.styles.addStyleSheet """
+      atom.styles.addStyleSheet("""
         ::-webkit-scrollbar {
           width: 8px;
         }
-      """
+      """, context: 'atom-text-editor')

       initialThemeLoadComplete = true
       themeReloadCallback()

-      verticalScrollbarNode = element.querySelector(".vertical-scrollbar")
+      verticalScrollbarNode = element.shadowRoot.querySelector(".vertical-scrollbar")
       scrollbarWidth = verticalScrollbarNode.offsetWidth - verticalScrollbarNode.clientWidth
       expect(scrollbarWidth).toEqual(8)


Replace jquery deprecated .live with .on

--- app/assets/javascripts/commits.js.coffee
+++ app/assets/javascripts/commits.js.coffee
@@ -12,7 +12,7 @@
     $('.loading').hide()

   @init: (ref, limit) ->
-    $(".day-commits-table li.commit").live 'click', (event) ->
+    $("body").on "click", ".day-commits-table li.commit", (event) ->
       if event.target.nodeName != "A"
         location.href = $(this).attr("url")
         e.stopPropagation()


Adds other methods and adds ajax request for adding a new contact

--- app/assets/javascripts/contact.js.coffee
+++ app/assets/javascripts/contact.js.coffee
@@ -4,7 +4,7 @@
     @UPDATE_CONTACT = ""
     @DELETE_CONTACT = ""
     @LOAD_SETTINGS = ""
-    @SEARCH_FILE = ""
+    @SEARCH = ""

     @search_start('')
     @run()
@@ -21,27 +21,27 @@
       $("#sortable").disableSelection()

       # Triggered when the user stopped sorting and the DOM position has changed
-      $('#sortable').sortable().bind 'sortupdate', () ->
-        update_list()
+      $('#sortable').sortable().bind 'sortupdate', () =>
+        @update_list()

       # Add new POST
-      $('.answers_box_addnew').keypress (e) ->
+      $('.answers_box_addnew').keypress (e) =>
         if e.keyCode == 13
-          add_new_contact()
+          @add_new_contact()

       # Click function
-      $(@).click (e) ->
+      $(@).click (e) =>
         # if click outside the <input> and if <input> exists
         if ($(e.target).parent().attr('class') != 'contact_name' & $('#contact_input').length)
-          close_settings()
+          @close_settings()

       # Key press functions
-      $(@).keydown( (e) ->
+      $(@).keydown( (e) =>
         # Contact name
         if ($(e.target).parent().attr('class') == 'contact_name')
           if (e.keyCode == 13)
-            close_settings()
+            @close_settings()
           else if (e.keyCode == 27)
             # Return old value
             $(e.target).parent().html(contact_text)
@@ -59,16 +59,114 @@
       )

     # Button actions
-    $('#add_new_button').click () ->
-      add_new_contact()
+    $('#add_new_button').click () =>
+      @add_new_contact()

     # Sort by name
-    $('.contacts_title_name').click () ->
-      sort_by_name()
+    $('.contacts_title_name').click () =>
+      @sort_by_name()

     # Sort by last contact
-    $('.contacts_title_last_contact').click () ->
-      sort_by_last_contact();
+    $('.contacts_title_last_contact').click () =>
+      @sort_by_last_contact();
+
+
+  search_start: (search_term) ->
+    # Enable and disable (if you use search) the jQuery sortable UI
+    if (search_term != '')
+      $('#sortable').sortable({ disabled: true })
+    else
+      $('#sortable').sortable({ disabled: false })
+
+    # Display contacts
+    $.post(SEARCH, {
+      search_term: search_term,
+      order:'position'
+    }, (data) =>
+      @draw_contacts(data)
+    )
+
+
+  sort_by_name: ->
+    $.post(@SEARCH, {
+      search_term: '',
+      order: 'name'
+    }, (data) =>
+      @draw_contacts(data)
+    )
+
+
+  sort_by_last_contact: ->
+    $.post(@SEARCH, {
+      search_term: '',
+      order: 'last_date'
+    }, (data) =>
+      @draw_contacts(data)
+    )
+
+
+  add_new_contact: ->
+    new_contact = $('.answers_box_addnew').attr('value')
+    if (new_contact == '')
+      return false
+
+    # Find last position
+    position = $('.contact_name').length
+    $.post(gon.addnew_path, {
+      new_contact: new_contact,
+      position:position
+    }, (data) =>
+      @search_start('')
+      $('.answers_box_addnew').attr('value','')
+    )
+
+
+  delete_contact: (contact_id) ->
+    $.post(@DELETE_CONTACT, {
+      contact_id: contact_id
+    }, () =>
+      @search_start('')
+    )
+
+
+  update_list: ->
+    # Forming the variables for ajax request
+    $('.contact_name').each( (i,name) =>
+      id = $(this).attr('id')
+      name = $(name).text()
+      $.post(@UPDATE_LIST, {
+        id: id,
+        name: name,
+        position: i
+      })
+    )
+
+
+  update_colors: (id, red) ->
+    $.post(@UPDATE_COLOR, {
+      id: id,
+      red: red
+    }, (data) ->
+      $('#contact_container_'+id).attr('class',data)
+    )
+
+
+  close_settings: () ->
+    # Find active settings
+    object = $('#contact_input').parent()
+    # Update colors
+    contact_red = object.find('#red_set').attr('value')
+
+    if (contact_red == '')
+      contact_red = 0
+
+    update_colors(object.attr('id'), contact_red)
+    # Close <input> and save new values
+    contact_text = object.find('#contact_input').attr('value')
+    object.html(contact_text)
+
+    # Update list
+    @update_list()

   search_start: (search_term) ->
@@ -77,7 +175,7 @@
     else
       $('#sortable').sortable({ disabled: false; })

-    $.post(@SEARCH_FILE,
+    $.post(@SEARCH,
       {
         search_term: search_term,
         order: 'position'
@@ -109,7 +207,7 @@

     enable = 0

-    $('.contact_edit').click (event) ->
+    $('.contact_edit').click (e) ->
       if enable == 0
         enable = 1

@@ -136,15 +234,15 @@

     #
-    $('.contact_delete').click( (event) ->
+    $('.contact_delete').click( (e) ->
       contact_id = $(@).parent().find('.contact_name').attr('id')
       if (confirm('Delete this field?'))
-        delete_contact(contact_id)
-    )
-
-    $('.contact_update').click( (event) ->
+        @delete_contact(contact_id)
+    )
+
+    $('.contact_update').click( (e) ->
       contact_obj = $(@).parent().parent().find('.contact_name')
-      $.post(UPDATE_DATE_FILE, {
+      $.post(@UPDATE_DATE, {
         id: $(contact_obj).attr('id')
       }, (data) =>
         @search_start('');