only calling "parse" after initalize

only calling "parse" after initalize

--- dkobo/koboform/static/js/xlform/model_xlform.coffee
+++ dkobo/koboform/static/js/xlform/model_xlform.coffee
@@ -398,9 +398,11 @@
       vals2set.value = valOrObj
     @set(vals2set)
     @_order = XLF.columnOrder(@key)
+    @postInitialize()

   getSurvey: ()-> @parentRow.getSurvey()

+  postInitialize: ()->
   initialize: ()->
     if @get("_hideUnlessChanged")
       @hidden = true
@@ -409,8 +411,6 @@
         @hidden = @get("value") is @_oValue

     @on "change:value", (rd, val, ctxt)=>
-      # why did i add this?
-      # @parse()
       @parentRow.trigger "change", @key, val, ctxt
     if @key is "type"
       @on "change:list", (rd, val, ctxt)=>
@@ -491,18 +491,17 @@
   getValue: ()->
     @serialize()

+  postInitialize: ()->
+    @skipLogicCollection = new XLF.SkipLogicCollection([], rowDetail: @)
+    @parse()
+
   serialize: ()->
     # @hidden = false
     # note: reimplement "hidden" if response is invalid
     @skipLogicCollection.serialize()

   parse: ()->
-    ###
-    Ideally this could go somewhere else that's called after initialize
-    ###
-    unless @skipLogicCollection
-      @skipLogicCollection = new XLF.SkipLogicCollection([], rowDetail: @)
-      @skipLogicCollection.importString(@get('value') || '')
+    @skipLogicCollection.importString(@get('value') || '')

 @XLF.RowDetailMixins =
   relevant: SkipLogicDetailMixin


Add case of disk warning for no status

Add case of disk warning for no status

--- src/smc-webapp/project_page.cjsx
+++ src/smc-webapp/project_page.cjsx
@@ -271,10 +271,10 @@
         if not quotas?.disk_quota? or not project_status?
             return null
         else
-            disk = project_status.get('disk_MB')
+            disk = project_status.get('disk_MB') ? 0
             if disk?
                 disk = Math.ceil(disk)
-        if not disk or quotas.disk_quota - 5 > disk
+        if quotas.disk_quota - 5 > disk
             return null

         styles =


fix the loading of multiple templates thumbnail

--- MediaAdminBundle/Resources/public/coffee/GalleryCollectionView.coffee
+++ MediaAdminBundle/Resources/public/coffee/GalleryCollectionView.coffee
@@ -18,7 +18,9 @@
     ])
     @loadTemplates [
       "OpenOrchestraMediaAdminBundle:BackOffice:Underscore/galleryCollectionView",
-      "OpenOrchestraMediaAdminBundle:BackOffice:Underscore/galleryView"
+      "OpenOrchestraMediaAdminBundle:BackOffice:Underscore/galleryView",
+      'OpenOrchestraMediaAdminBundle:BackOffice:Underscore/TinyMce/media',
+      'OpenOrchestraMediaAdminBundle:BackOffice:Underscore/TinyMce/audio'
     ]
     return


Remove titles from discussion previews

Remove titles from discussion previews

- Small piece of #1426

--- app/talk/latest-comment-link.cjsx
+++ app/talk/latest-comment-link.cjsx
@@ -42,7 +42,7 @@
           </Link>
         }</PromiseRenderer>{' '}

-        {if discussion.title
+        {if discussion.title and @props.title
           <span>
             <Link
               to="#{@projectPrefix()}talk-discussion"


Test for clear() call

Test for clear() call

--- spec/project-find-view-spec.coffee
+++ spec/project-find-view-spec.coffee
@@ -271,10 +271,12 @@
         atom.workspaceView.trigger 'project-find:show'

       describe "when the there search field is empty", ->
-        it "does not run the seach", ->
+        it "does not run the seach but clears the model", ->
           spyOn(atom.project, 'scan')
+          spyOn(projectFindView.model, 'clear')
           projectFindView.trigger 'core:confirm'
           expect(atom.project.scan).not.toHaveBeenCalled()
+          expect(projectFindView.model.clear).toHaveBeenCalled()

       describe "when results exist", ->
         beforeEach ->


Fixed #9 - Updating help text in REPL

Fixed #9 - Updating help text in REPL

--- lib/repl-text-editor.coffee
+++ lib/repl-text-editor.coffee
@@ -11,17 +11,20 @@
 ;; REPL Execution Keybindings\n
 ;; Note: These keybindings can be executed from any file and the results will be
 displayed in this REPL.\n
+;; The keybindings are almost all of the form ctrl + comma, release, and then another key.\n
 ;; See the settings for more keybindings.\n
 \n
-;; cmd+alt+b - execute block. Finds the block of Clojure code your cursor is in
+;; ctrl-, then b - execute block. Finds the block of Clojure code your cursor is in
 and executes that.\n
 \n
-;; Try it now. Put your cursor inside this block and press cmd+alt+b\n
+;; Try it now. Put your cursor inside this block and press ctrl and comma together, \n
+;; release, then press b.\n
 (+ 2 3)\n
 \n
-;; cmd+alt+s - Executes the selection. Sends the selected text to the REPL.\n
+;; ctrl-, s - Executes the selection. Sends the selected text to the REPL.\n
 \n
-;; Try it now. Select these three lines and hit cmd + alt + s.\n
+;; Try it now. Select these three lines and press ctrl and comma together, \n
+;; release, then press s.\n
 (println \"hello 1\")\n
 (println \"hello 2\")\n
 (println \"hello 3\")\n


add test

add test

--- spec/tree-view-package-spec.coffee
+++ spec/tree-view-package-spec.coffee
@@ -3847,6 +3847,18 @@
     files = Array.from(element.querySelectorAll('.entries .file'))
     files.find((file) -> file.fileName.textContent is text)

+describe "Service provider", ->
+  [provideTreeView] = []
+  beforeEach ->
+    waitForPackageActivation()
+
+    runs ->
+      provideTreeView = atom.packages.getActivePackage('tree-view').mainModule.provideTreeView()
+
+  it "should provide selected paths", ->
+    console.log()
+    expect(provideTreeView.getSelectedPaths()).toEqual([atom.project.getPaths()[0]])
+
 describe 'Icon class handling', ->
   it 'allows multiple classes to be passed', ->
     rootDirPath = fs.absolute(temp.mkdirSync('tree-view-root1'))


:pencil: Remove string-based event docs

:pencil: Remove string-based event docs

--- src/directory.coffee
+++ src/directory.coffee
@@ -10,13 +10,6 @@
 PathWatcher = require './main'

 # Public: Represents a directory on disk that can be watched for changes.
-#
-# ## Events
-#
-# ### contents-changed
-#
-# Public: Fired when the contents of the directory has changed.
-#
 module.exports =
 class Directory
   EmitterMixin.includeInto(this)


Update to node v0.10.15.

Update to node v0.10.15.

--- src/config.coffee
+++ src/config.coffee
@@ -14,7 +14,7 @@
     process.env.ATOM_PACKAGES_URL ? 'http://atom.iriscouch.com/registry/_design/apm/_view/atom_packages'

   getNodeVersion: ->
-    process.env.ATOM_NODE_VERSION ? '0.10.12'
+    process.env.ATOM_NODE_VERSION ? '0.10.15'

   getUserConfigPath: ->
     path.resolve(__dirname, '..', '.apmrc')


Not use throw

Not use throw

--- src/config.coffee
+++ src/config.coffee
@@ -15,9 +15,7 @@
     else if fs.existsSync "#{process.env['HOME']}/#{fileName}"
       "#{process.env['HOME']}/#{fileName}"
     else
-      throw(new Error "There's no config file. Try `pending-pr init`.")
+      logger.error "There's no config file. Try `pending-pr init`."
+      process.exit 1

     path
-
-  foo: ->
-    throw(new Error 'Oh no')


Rework defaults and user loading to notify per path

--- src/config.coffee
+++ src/config.coffee
@@ -401,14 +401,8 @@
       catch e
         return false

-    if @get(keyPath) isnt value
-      defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
-      value = undefined if _.isEqual(defaultValue, value)
-
-      oldValue = _.clone(@get(keyPath))
-      _.setValueForKeyPath(@settings, keyPath, value)
-      newValue = @get(keyPath)
-      @update({oldValue, newValue, keyPath}) unless _.isEqual(oldValue, newValue)
+    @setRawValue(keyPath, value)
+    @save() unless @configFileHasErrors
     true

   # Extended: Restore the key path to its default value.
@@ -539,10 +533,8 @@

     try
       userConfig = CSON.readFileSync(@configFilePath)
-      @setAllRecursive(userConfig)
+      @setRecursive(null, userConfig)
       @configFileHasErrors = false
-      @emit 'updated'
-      @emitter.emit 'did-change'
     catch error
       @configFileHasErrors = true
       console.error "Failed to load user config '#{@configFilePath}'", error.message
@@ -560,49 +552,52 @@
     @watchSubscription?.close()
     @watchSubscription = null

-  update: (event) ->
-    return if @configFileHasErrors
-    @save()
-    @emit 'updated'
-    @emitter.emit 'did-change', event
-
   save: ->
     CSON.writeFileSync(@configFilePath, @settings)

-  setAllRecursive: (value) ->
-    @setRecursive(key, childValue) for key, childValue of value
-    return
+  setRawValue: (keyPath, value) ->
+    if @get(keyPath) isnt value
+      defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
+      value = undefined if _.isEqual(defaultValue, value)
+
+      oldValue = _.clone(@get(keyPath))
+      _.setValueForKeyPath(@settings, keyPath, value)
+      newValue = @get(keyPath)
+      @emitter.emit 'did-change', {oldValue, newValue, keyPath}
+
+  setRawDefault: (keyPath, value) ->
+    oldValue = _.clone(@get(keyPath))
+    _.setValueForKeyPath(@defaultSettings, keyPath, value)
+    newValue = @get(keyPath)
+    @emitter.emit 'did-change', {oldValue, newValue, keyPath} if newValue isnt oldValue

   setRecursive: (keyPath, value) ->
     if value? and isPlainObject(value)
-      keys = keyPath.split('.')
+      keys = if keyPath? then keyPath.split('.') else []
       for key, childValue of value
         continue unless value.hasOwnProperty(key)
         @setRecursive(keys.concat([key]).join('.'), childValue)
     else
       try
         value = @makeValueConformToSchema(keyPath, value)
-        defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
-        value = undefined if _.isEqual(defaultValue, value)
-        _.setValueForKeyPath(@settings, keyPath, value)
+        @setRawValue(keyPath, value)
       catch e
         console.warn("'#{keyPath}' could not be set. Attempted value: #{JSON.stringify(value)}; Schema: #{JSON.stringify(@getSchema(keyPath))}")

     return

   setDefaults: (keyPath, defaults) ->
-    unless isPlainObject(defaults)
-      return _.setValueForKeyPath(@defaultSettings, keyPath, defaults)
-
-    hash = @defaultSettings
-    if keyPath
-      for key in keyPath.split('.')
-        hash[key] ?= {}
-        hash = hash[key]
-
-    _.extend hash, defaults
-    @emit 'updated'
-    @emitter.emit 'did-change'
+    if defaults? and isPlainObject(defaults)
+      keys = if keyPath? then keyPath.split('.') else []
+      for key, childValue of defaults
+        continue unless defaults.hasOwnProperty(key)
+        @setDefaults(keys.concat([key]).join('.'), childValue)
+    else
+      try
+        defaults = @makeValueConformToSchema(keyPath, defaults)
+        @setRawDefault(keyPath, defaults)
+      catch e
+        console.warn("'#{keyPath}' could not set the default. Attempted default: #{JSON.stringify(defaults)}; Schema: #{JSON.stringify(@getSchema(keyPath))}")

   setSchema: (keyPath, schema) ->
     unless isPlainObject(schema)


Fix up the linter error

Fix up the linter error

--- src/config.coffee
+++ src/config.coffee
@@ -1041,9 +1041,9 @@
         settings = withoutEmptyObjects(@makeValueConformToSchema(null, settings))
         validatedSettings[scopeSelector] = settings
       catch e
-        ;
-
-      @scopedSettingsStore.addProperties(source, validatedSettings, {priority}) if validatedSettings[scopeSelector]
+        validatedSettings[scopeSelector] = null
+
+      @scopedSettingsStore.addProperties(source, validatedSettings, {priority}) if validatedSettings[scopeSelector]?

     @emitChangeEvent()


remove a sky file

remove a sky file


Separte JS / CSS build.

Separte JS / CSS build.

--- source/graphite.coffee
+++ source/graphite.coffee
@@ -1,5 +1,3 @@
-Components = require './components'
-
 module.exports.stores =
   redis: require './stores/redis'
   memory: require './stores/memory'
@@ -36,16 +34,23 @@
     FS.unlink './tmp.js'
     callback result.code

-# Builds a browser bundle
-#
-# @param [Store] store The store from which to build
-# @param [String] tagname The name of the component to build
-module.exports.build = (store,tagname,callback)->
+module.exports.buildCSS = (store,tagname,callback)->

+  Autoprefixer = require 'autoprefixer'
+  CleanCSS     = require 'clean-css'
+  Components = require './components'
   Components.store = store

-  CleanCSS     = require 'clean-css'
-  Autoprefixer = require 'autoprefixer'
+  Components.css tagname, (code)->
+    css = Autoprefixer.compile(code)
+    css = new CleanCSS().minify(code)
+    callback css
+
+module.exports.buildJS = (store,tagname,callback)->
+
+  Components = require './components'
+  Components.store = store
+
   browserify   = require 'browserify'
   coffeeify    = require 'coffeeify'
   UglifyJS     = require 'uglify-js'
@@ -72,7 +77,6 @@
       document.body.appendChild(element)
     })
     """
-
     FS.writeFileSync("#{__dirname}/tmp.js", code, 'utf-8' )

     console.log "Creating browser bundle..."
@@ -84,9 +88,4 @@
       result = UglifyJS.minify(src, {fromString: true})
       FS.unlink "#{__dirname}/tmp.js"

-      console.log "Creating css..."
-      Components.css tagname, (code)->
-        css = Autoprefixer.compile(code)
-        css = new CleanCSS().minify(code)
-        callback {js: result.code, css: css}
-        console.log "Done!"
+      callback result.code


background user creation.

background user creation.

--- client/app/MainApp/filetree/controllers/findercontroller.coffee
+++ client/app/MainApp/filetree/controllers/findercontroller.coffee
@@ -35,15 +35,11 @@

     mainView.addSubView @treeController.getView()
     @reset()
+
     if @treeController.getOptions().useStorage
-      @defaultStructureLoaded = no
-
       appManager.on "AppManagerOpensAnApplication", (appInst)=>
         if appInst instanceof StartTab12345 and not @defaultStructureLoaded
           @loadDefaultStructure()
-
-      @loadDefaultStructureTimer = @utils.wait @treeController.getOptions().initDelay, =>
-        @loadDefaultStructure()

   reset:->

@@ -64,6 +60,10 @@
         type        : "mount"
     @defaultStructureLoaded = no
     @treeController.initTree [mount]
+    if @treeController.getOptions().useStorage
+      @defaultStructureLoaded = no
+      @loadDefaultStructureTimer = @utils.wait @treeController.getOptions().initDelay, =>
+        @loadDefaultStructure()

   loadDefaultStructure:->


home/myteam: change to multiline JSX

home/myteam: change to multiline JSX

--- client/home/lib/myteam/components/hometeamteammates/view.coffee
+++ client/home/lib/myteam/components/hometeamteammates/view.coffee
@@ -21,7 +21,11 @@

     member = @props.members.toList().get(rowIndex)
     key = member?.get '_id'
-    <Member key={key} member={member} handleInvitation={@props.handleInvitation} handleRoleChange={@props.handleRoleChange}/>  if member
+    <Member
+      key={key}
+      member={member}
+      handleInvitation={@props.handleInvitation}
+      handleRoleChange={@props.handleRoleChange}/>  if member

   renderEmptySectionAtIndex: -> <div> No data found</div>


Fixed #1140 added ascii emoji to autocomplete and sorted them

--- client/views/app/messagePopupConfig.coffee
+++ client/views/app/messagePopupConfig.coffee
@@ -116,12 +116,14 @@
 				getInput: self.getInput
 				getFilter: (collection, filter) ->
 					results = []
+					key = ':' + filter

 					# show common used emojis, when use input a single ':'
 					if filter == ''
 						commonEmojis = [
 					            ':laughing:',
 					            ':smiley:',
+					            ':stuck_out_tongue:',
 					            ':sunglasses:',
 					            ':wink:',
 					            ':innocent:',
@@ -137,18 +139,29 @@
 								data: collection[shortname]
 						return results;

+					# use ascii
+					for shortname, value of RocketChat.emoji.asciiList
+						if results.length > 10
+							break
+
+						if shortname.startsWith(key)
+							results.push
+								_id: shortname
+								data: [value]
+
+					# use shortnames
 					for shortname, data of collection
-						if shortname.indexOf(filter) > -1
+						if results.length > 10
+							break
+
+						if shortname.startsWith(key)
 							results.push
 								_id: shortname
 								data: data

-						if results.length > 10
-							break
-
-					if filter.length >= 3
-						results.sort (a, b) ->
-							a.length > b.length
+					#if filter.length >= 3
+					results.sort (a, b) ->
+						a._id.length - b._id.length

 					return results

@@ -167,4 +180,3 @@

 	@autorun ->
 		template.channelSubscription = template.subscribe 'channelAutocomplete', template.channelFilter.get()
-


удален отладочный лог для плагинов

удален отладочный лог для плагинов

--- lib/nbuild/builder.coffee
+++ lib/nbuild/builder.coffee
@@ -330,7 +330,6 @@
         for file in fs.readdirSync(path)
           if /.*\.plugin\.(coffee|js)$/i.test(file)
             fullpath = join(path,file)
-            console.log 'load plugin'.magenta, fullpath
             try
               require(fullpath).initialize(this)
               @plugins.push(fullpath)


Item movement: bug fixed and behaviour enhanced

Buf fix: solved issue leny/atom-pane-manager#3
Behaviour enhancement: made the item movement behave more like in Sublime Text, the item will be re-activated after the movement.

--- lib/pane-utilities.coffee
+++ lib/pane-utilities.coffee
@@ -49,9 +49,16 @@
     @moveItemTo = ( iTargetPaneIndex ) ->
         oTargetPane = _getPaneAt iTargetPaneIndex
         iItemsLength = oTargetPane.getItems().length
+        oCurrentPane = atom.workspace.getActivePane()
+        oActiveItem = oCurrentPane.getActiveItem()

-        ( oCurrentPane = atom.workspace.getActivePane() )
-            .moveItemToPane oCurrentPane.getActiveItem(), oTargetPane, iItemsLength
+        # Check if the action can be performed
+        if oActiveItem?
+            # Move active item
+            oCurrentPane.moveItemToPane oActiveItem, oTargetPane, iItemsLength
+            # Re-activate the item moved (SublimeText-like behaviour)
+            oTargetPane.activate()
+            oTargetPane.activateItem oActiveItem

         return PaneUtilities


[pylprof] Remove chdir from launch comamnd

--- lib/pylprof/runner.coffee
+++ lib/pylprof/runner.coffee
@@ -45,6 +45,8 @@
         curAttempt += 1
     ), 1000

+    child.stderr.on 'data', ->
+
     child.stdout.on 'data', (data) ->
       if data.toString().indexOf(dialtoneKey) isnt -1
         clearInterval dialtoneInterval
@@ -55,9 +57,7 @@
   profile: (cmd) ->
     deferred = Q.defer()

-    child = spawn '/usr/bin/vagrant', ["ssh", "-c", "source ./dogweb/python/bin/activate; cd ./workspace/dogweb; paster shell development.ini"], {
-      cwd : '/home/ivan/local/personal-chef'
-    }
+    child = spawn '/usr/bin/ssh', ["-p", "2222", "vagrant@127.0.0.1", "-i", "/home/ivan/.vagrant.d/insecure_private_key", "-t", "source ./dogweb/python/bin/activate; cd ./workspace/dogweb; paster shell development.ini"]

     cmd = [cmd, @dumpStatsCmd].join('\n')

@@ -69,7 +69,6 @@
       child.stdout.on 'data', (data) ->
         # inefficient but will do for now
         content += data.toString()
-        # console.log(data.toString())
       child.on 'exit', (code) =>
         m = (content.match '@@@STATSDUMPSTART@@@(.*)@@@STATSDUMPEND@@@')[1]
         m = m.replace('/home/vagrant/workspace', '/home/ivan/local/vm')


Save, rather than set, key on change.

Save, rather than set, key on change.

--- app/views/settings/key.coffee
+++ app/views/settings/key.coffee
@@ -23,6 +23,6 @@

   #Events
   onSelectKey: (e) =>
-    @model.set 'selected_keys', [@$(e.currentTarget).val()]
+    @model.save 'selected_keys', [@$(e.currentTarget).val()]

 module.exports = KeySettings


kontrolworker: create uuid just once, instead of a new one every time.

Create Uuid only once and store it in a file. If the worker restarts get the uuid from the file next time instead of creating one.

--- node_modules_koding/koding-worker/main.coffee
+++ node_modules_koding/koding-worker/main.coffee
@@ -53,7 +53,7 @@
       message   :
         command : options.command
         option  : options.option
-      uuid      : options.uuid
+      uuid      : @getUUID options.name, options.uuid
       hostname  : @getHostName()
       timestamp : @isoDateString()
       pid       : options.pid
@@ -94,6 +94,17 @@

   getRabbitKey:() ->
     version = (fs.readFileSync nodePath.join(__dirname, '../../KEY'), 'utf-8').trim()
+
+  # Create Uuid only once and store it in a file. If the worker restarts get
+  # the uuid from the file next time instead of creating one.
+  getUUID:(name, uuid) ->
+    file = "kontrolUUID-" + name
+    if fs.existsSync(file)
+      uuid = (fs.readFileSync nodePath.join(__dirname, "../../#{file}"), 'utf-8').trim()
+    else
+      fs.writeFileSync nodePath.join(__dirname, "../../#{file}"), uuid, 'utf-8'
+
+    return uuid

   getHostName:() ->
     hostName = os.hostname()


style: pluralize `error / errors`

style: pluralize `error / errors`

--- lib/view-left-tile.coffee
+++ lib/view-left-tile.coffee
@@ -6,9 +6,9 @@
       return @div class: 'linter-error inline-block', =>
         @span class: 'badge badge-flexible badge-error', =>
           @text '✘'
-        @text " #{nbErrors} lint errors"
+        @text if nbErrors > 1 then " #{nbErrors} errors" else " #{nbErrors} error"
     else
       return @div class: 'linter-success inline-block', =>
         @span class: 'badge badge-flexible badge-success', =>
           @text '✔'
-        @text ' No lint error'
+        @text ' No errors'


added extension box, domain extensions will be selected from selectbox from now on

--- client/landing/app/Applications/Environments.kdapplication/views/domains/domaincreationform.coffee
+++ client/landing/app/Applications/Environments.kdapplication/views/domains/domaincreationform.coffee
@@ -1,11 +1,5 @@
 class DomainCreationForm extends KDTabViewWithForms
-#  domainNameValidation =
-#    rules      :
-#      required : yes
-#      regExp   : /^([\da-z\.-]+)\.([a-z\.]{2,6})$/i
-#    messages   :
-#      required : "Enter your domain name"
-#      regExp   : "This doesn't look like a valid domain name."
+
   domainOptions = [
       { title : "Create a subdomain", value : "subdomain" }
       { title : "I want to register a domain", value : "new" }
@@ -35,7 +29,7 @@
                 @registerDomain()
             createButton              :
               title                   : "Add Domain"
-              style                   : "cupid-green hidden"
+              style                   : "cupid-green"
               type                    : "submit"
               loader                  :
                 color                 : "#ffffff"
@@ -75,14 +69,16 @@
               defaultValue            : "subdomain"
               radios                  : domainOptions
               change                  : =>
-                {DomainOption, domainName, domains, regYears} = @forms["Domain Address"].inputs
+                {DomainOption, domainName, domains, regYears, extensionSelect} = @forms["Domain Address"].inputs
                 {checkButton, registerButton} = @forms["Domain Address"].buttons
                 actionState = DomainOption.getValue()
+                domainName.setValue ''
                 domainName.getElement().setAttribute 'placeholder', switch actionState
                   when "new"
                     @suggestionBox?.show()
                     # domainName.setValidation domainNameValidation
                     domains.hide()
+                    extensionSelect.show()
                     regYears.show()
                     createButton.hide()
                     checkButton.show()
@@ -92,6 +88,7 @@
                     @suggestionBox?.hide()
                     # domainName.setValidation domainNameValidation
                     domains.hide()
+                    extensionSelect.hide()
                     regYears.hide()
                     checkButton.hide()
                     registerButton.hide()
@@ -100,6 +97,7 @@
                   when "subdomain"
                     # domainName.unsetValidation()
                     @suggestionBox?.hide()
+                    extensionSelect.hide()
                     domains.show()
                     regYears.hide()
                     checkButton.hide()
@@ -136,6 +134,14 @@
                       required        : yes
                     messages          :
                       required        : "Please select a parent domain."
+                extensionSelect       :
+                  cssClass            : "domains hidden"
+                  itemClass           : KDSelectBox
+                  validate            :
+                    rules             :
+                      required        : yes
+                    messages          :
+                      required        : "Please select an extension"
             suggestionBox             :
               type                    : "hidden"
     form = @forms["Domain Address"]
@@ -151,17 +157,22 @@
       for domain in userDomains
         if not domain.regYears > 0
           domainList.push {title:".#{domain.domain}", value:domain.domain}
-      @forms["Domain Address"].inputs.domains.setSelectOptions domainList
+      {domains, extensionSelect} = @forms["Domain Address"].inputs
+      domains.setSelectOptions domainList
+      availableTldList = ["com", "net", "org"]
+      extensionsList = ({title:'.'+ext, value:ext} for ext in availableTldList)
+      extensionSelect.setSelectOptions extensionsList
+      extensionSelect.setDefaultValue availableTldList[0]

   checkAvailability: ->
     form = @forms["Domain Address"]
-    domainInput       = domainName
-    domainName        = form.inputs.domainName.getValue()
-    splittedDomain    = domainName.match(/([\w\-]+)\.(.*)/)
-    domain            = splittedDomain[1]
-    tld               = splittedDomain[2]
-
+    domain            = form.inputs.domainName.getValue()
+    tld               = form.inputs.extensionSelect.getValue()
     {createButton, checkButton, registerButton} = form.buttons
+    unless domain.match(/^\w+$/)
+      notifyUser "Please select the extension from the select box"
+      checkButton.hideLoader()
+      return
     @clearSuggestions()
     KD.remote.api.JDomain.getTldPrice tld, (tldPrice) =>
       KD.remote.api.JDomain.isDomainAvailable domain, tld, (avErr, status, price, suggestions) =>
@@ -194,13 +205,14 @@
     {createButton, registerButton} = form.buttons
     @clearSuggestions()

-    {DomainOption, domainName, regYears, domains} = form.inputs
+    {DomainOption, domainName, regYears, domains, extensionSelect} = form.inputs
     domainInput       = domainName
-    domainName        = form.inputs.domainName.getValue()
-    splittedDomain    = domainName.match(/([\w\-]+)\.(.*)/)
-    domain            = splittedDomain[1]
-    tld               = splittedDomain[2]
-
+    domain            = domainName.getValue()
+    tld               = extensionSelect.getValue()
+    unless domain.match(/^\w+$/)
+      notifyUser "Please select the extension from the select box"
+      registerButton.hideLoader()
+      return
     domainOptionValue = DomainOption.getValue()

     if domainOptionValue is 'new'
@@ -233,7 +245,7 @@

     else if domainOptionValue is 'existing'
-      @createDomain {domainName, regYears:0, domainType:'existing'}, (err, domain)=>
+      @createDomain {domain, regYears:0, domainType:'existing'}, (err, domain)=>
         createButton.hideLoader()
         if err
           warn err
@@ -246,12 +258,12 @@

     else # create a subdomain
       subDomainPattern = /^([a-z0-9]([_\-](?![_\-])|[a-z0-9]){0,60}[a-z0-9]|[a-z0-9])$/
-      unless subDomainPattern.test domainName
+      unless subDomainPattern.test domain
         createButton.hideLoader()
         return notifyUser "#{domainName} is an invalid subdomain."
-      domainName = "#{domainName}.#{domains.getValue()}"
-
-      @createDomain {domainName, regYears:0, domainType:'subdomain'}, (err, domain)=>
+      domain = "#{domainName}.#{domains.getValue()}"
+
+      @createDomain {domain, regYears:0, domainType:'subdomain'}, (err, domain)=>
         createButton.hideLoader()
         if err
           warn err
@@ -285,7 +297,7 @@
     {domainName}    = form.inputs
     {suggestionBox} = form.fields
     if not available
-      partial         = "
This domain is already registered. #{'You may click and try one below.' ? suggestions.length > 0 : ''}
"
+      partial         = "
This domain is already registered. #{if suggestions.length > 0 then 'You may click and try one below.' else ''}
"
     else
       partial         = "
Domain price is: #{price}$
"

@@ -302,7 +314,7 @@
   showSuccess:(domain) ->
     @clearSuggestions()
     form            = @forms["Domain Address"]
-    {domainName}    = form.inputs
+    {domainName, extensionSelect}    = form.inputs
     {suggestionBox} = form.fields
     {close, createButton, cancel, another} = form.buttons

@@ -321,7 +333,7 @@
       # partial : "Thank you!
Your domain #{domainName.getValue()} has been added to our database. Please go to your provider's website and add a CNAME record mapping to kontrol.in.koding.com."

       # change this part when registering is there.
-      partial : "Thank you!
Your subdomain #{domainName.getValue()} has been added to our database. You can dismiss this panel and point your new domain to one of your VMs on the settings screen."
+      partial : "Thank you!
Your subdomain #{domainName.getValue()}.#{extensionSelect.getValue()} has been added to our database. You can dismiss this panel and point your new domain to one of your VMs on the settings screen."
       click   : => @reset()


- let the user enter only the subdomain to the text field when creating a subdomain. - remove any last occurences of dots from the subdomain if there's any. - move KD.remote.JDomain.createDomain calls to an internal function.

--- client/landing/app/Applications/Environments.kdapplication/views/domains/domaincreationform.coffee
+++ client/landing/app/Applications/Environments.kdapplication/views/domains/domaincreationform.coffee
@@ -153,10 +153,11 @@
     {createButton} = form.buttons
     @clearSuggestions()

-    {DomainOption, domainName, regYears} = form.inputs
+    {DomainOption, domainName, regYears, domains} = form.inputs
     splittedDomain    = domainName.getValue().split "."
     domain            = splittedDomain.first
     tld               = splittedDomain.slice(1).join('')
+    domainName        = domainName.getValue()

     domainOptionValue = DomainOption.getValue()

@@ -188,27 +189,19 @@
             domain.setDomainCNameToProxyDomain()

     else if domainOptionValue is 'existing'
-      KD.remote.api.JDomain.createDomain
-        domain         : domainName.getValue()
-        regYears       : 0
-        hostnameAlias  : []
-        loadBalancer   :
-            mode       : "roundrobin"
-      , (err, domain)=>
+      @createDomain {domainName, regYears:0}, (err, domain)=>
         createButton.hideLoader()
         if err
           warn err
           return notifyUser "An error occured. Please try again later."
         else
           @showSuccess()
-    else if domainOptionValue is 'subdomain'
-      KD.remote.api.JDomain.createDomain
-        domain         : domainName.getValue()
-        regYears       : 0
-        hostnameAlias  : []
-        loadBalancer   :
-            mode       : "roundrobin"
-      , (err, domain)=>
+
+    else # create a subdomain
+      subDomain = domainName.replace /\.{1,}(?=[^.]*$)/, ''
+      domainName = "#{subDomain}.#{domains.getValue()}"
+
+      @createDomain {domainName, regYears:0}, (err, domain)=>
         createButton.hideLoader()
         if err
           warn err
@@ -216,9 +209,15 @@
         else
           @showSuccess()

-    else # groupSubDomain
-
-
+  createDomain:(params, callback)->
+    KD.remote.api.JDomain.createDomain
+        domain         : params.domainName
+        regYears       : params.regYears
+        hostnameAlias  : []
+        loadBalancer   :
+            mode       : "roundrobin"
+      , (err, domain)=>
+        callback err, domain

   clearSuggestions:-> @suggestionBox?.destroy()


Clean-up batch saving

Clean-up batch saving

--- scripts/collections/content.coffee
+++ scripts/collections/content.coffee
@@ -65,22 +65,22 @@
         if not model.id
           newModels.push(model)

-      $.post '/api/contents', (data) =>
+      $.post '/api/contents', newModels, (data) =>
         # Update ids
         _.each data, (model, index, arr) =>
           @models.get(model.cid).set('id', model.id)

-      _.each @models, (model, index, arr) ->
-        if model.dirty
-          models.push(model)
+        _.each @models, (model, index, arr) ->
+          if model.dirty
+            models.push(model)

-      $.ajax
-        type: "PUT"
-        url: '/api/contents'
-        data: models
-        success: (data, textStatus, $xhr) ->
-          console.log 'successfuly updated'
+        $.ajax
+          type: "PATCH"
+          url: '/api/contents'
+          data: models
+          success: (data, textStatus, $xhr) ->
+            console.log 'successfuly updated'
+            options?.success?()

-      if typeof options?.success is 'function'
-        options.success()
+      return @
   )()


Wait for images to load before displaying

--- apps/show/client/index.coffee
+++ apps/show/client/index.coffee
@@ -29,6 +29,7 @@
           @carouselView = new CarouselView
             collection: installShots
             height: 480
+            hasDimensions: false
           @$carousel.html @carouselView.render().$el
         else
           @$carousel.remove()


Add kinetic scrolling to mouse wheel. Edge "pull" effect not yet working.

--- src/traits/ScrollableView.coffee
+++ src/traits/ScrollableView.coffee
@@ -106,8 +106,9 @@

 T_CONST = 325

-AMPLITUDE_CONST = 0.55
-MAX_EDGE_VELOCITY = 1000
+ELASTIC_CONST = 0.55
+AMPLITUDE_CONST = 0.7
+MAX_EDGE_VELOCITY = 450

 ###*
 # Start the view scrolling.
@@ -157,24 +158,23 @@

 stopKineticScrolling = ->
   clearInterval scrollTicker
-  if Math.abs(velocity) > 10
-
+
+  amplitude = AMPLITUDE_CONST * velocity
+  target = Math.round(offset + amplitude)
+
+  if target < min
+    target = min
+  else if target > max
+    target = max
+
+  if target is min or target is max
+    pv = velocity
+    velocity = Math.min Math.abs(velocity), MAX_EDGE_VELOCITY
+    if pv < 0 then velocity *= -1
     amplitude = AMPLITUDE_CONST * velocity
-    target = Math.round(offset + amplitude)
-
-    if target < min
-      target = min
-    else if target > max
-      target = max
-
-    if target is min or target is max
-      pv = velocity
-      velocity = Math.min Math.abs(velocity), MAX_EDGE_VELOCITY
-      if pv < 0 then velocity *= -1
-      amplitude = AMPLITUDE_CONST * velocity
-
-    scrollTimestamp = Date.now()
-    requestAnimationFrame => autoScroll.call @
+
+  scrollTimestamp = Date.now()
+  requestAnimationFrame => autoScroll.call @

 autoScroll = ->
@@ -255,8 +255,14 @@
 ###
 onWheel = (e) ->
   if wheelTimer then clearTimeout wheelTimer
-  if not scrolling then startScrolling.call @, e
-  wheelTimer = setTimeout (-> stopScrolling.call @), WHEEL_TIME
+  if not scrolling
+    startScrolling.call @, e
+    startKineticScrolling.call @, e
+  wheelTimer = setTimeout =>
+    onMove.call @, e
+    stopScrolling.call @
+    stopKineticScrolling.call @
+  , WHEEL_TIME
   onMove.call @, e

@@ -278,7 +284,7 @@
   # * c = constant value, UIScrollView uses 0.55
   # * d = dimension, either width or height
   x = Math.abs(limit - y)
-  c = 0.55
+  c = ELASTIC_CONST
   d = refHeight
   b = (1 - (1 / ((x * c / d) + 1.0))) * d
   -b


Update Cursor::onDidChangePosition doc string

--- src/cursor.coffee
+++ src/cursor.coffee
@@ -71,6 +71,7 @@
   #     * `newBufferPosition` {Point}
   #     * `newScreenPosition` {Point}
   #     * `textChanged` {Boolean}
+  #     * `Cursor` {Cursor} that triggered the event
   #
   # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
   onDidChangePosition: (callback) ->


Removed call to removed showAuthorityPopover

--- core/app/backbone/views/tour/tour_interesting_users_view.coffee
+++ core/app/backbone/views/tour/tour_interesting_users_view.coffee
@@ -42,7 +42,6 @@
     @shuffledCollection.reset @collection.shuffle()
     @resizeScrollingInner()
     @updateButtonStates()
-    @listView().children.first()?.showAuthorityPopover?()

   listView: ->
     @_listView ?= new TourUsersListView


ignore metric values where the time cannot be determined

--- src/analytics-router/representative-model.coffee
+++ src/analytics-router/representative-model.coffee
@@ -41,6 +41,6 @@
           return false

         model[point.metric].loopReference != model['secondsElapsed'].loopReference
-      isValid: -> !model[point.metric].isStale() && model[point.metric].time != 'undefined'
+      isValid: -> !model[point.metric].isStale() && model[point.metric].time != 'unknown'


Relocate jMod.includes to outside of module callback in eg_api.coffee Ensures that the included files are loaded before they are potentially used.

--- src/eg/eg_api.coffee
+++ src/eg/eg_api.coffee
@@ -7,10 +7,10 @@
 # Define i/o using functional compositions
 # Define object methods for user session

+# Synchronously load dependents that are not jModules.
+jMod.include 'lib.md5'
+
 module 'eg.eg_api', imports('eg.fieldmapper', 'eg.date'), (fm, date) ->
-
-	# Synchronously load dependents that are not jModules.
-	jMod.include 'lib.md5'

 	#attempted_username = 0
 	no_session = 0


using the new logo

using the new logo

--- src/scripts/controllers/main.coffee
+++ src/scripts/controllers/main.coffee
@@ -3,7 +3,7 @@
     config =
       apiUrl: "10.86.233.62:8000"
       event: "mgp2015"
-      logo: "http://www.dr.dk/NR/rdonlyres/497EED22-D0D9-4B3D-BA8A-75BDAE68B27A/6031766/74e99fcceda84b92aa9392b702420c4b_Melodi_gp_logo620.png"
+      logo: "/img/mgp2015logo.png"
     socket = socket.connet(config.apiUrl, config.event)
     cookie = null


Add note about adding githubot dependency.

--- src/scripts/github-commiters.coffee
+++ src/scripts/github-commiters.coffee
@@ -5,6 +5,7 @@

 # You need to set the following variables:
 #   HUBOT_GITHUB_TOKEN ="<oauth token>"
+# Add in "githubot":"0.2.0" to your package.json file.

 module.exports = (robot) ->
   github = require("githubot")(robot)


Trim the title on web.coffee.

Trim the title on web.coffee.

--- src/scripts/web.coffee
+++ src/scripts/web.coffee
@@ -20,11 +20,11 @@
             parser.parseComplete body
             results = (Select handler.dom, "head title")
             if results[0]
-              msg.send results[0].children[0].data.replace(/(\r\n|\n|\r)/gm,"")
+              msg.send results[0].children[0].data.replace(/(\r\n|\n|\r)/gm,"").trim()
             else
               results = (Select handler.dom, "title")
               if results[0]
-                msg.send results[0].children[0].data.replace(/(\r\n|\n|\r)/gm,"")
+                msg.send results[0].children[0].data.replace(/(\r\n|\n|\r)/gm,"").trim()
           else
             msg.send "Error " + res.statusCode

@@ -38,7 +38,7 @@
           format: "json"
         .get() (err, res, body) ->
           response = JSON.parse body
-          responseTitle = response.data.info[0].title.replace(/(\r\n|\n|\r)/gm,"")
+          responseTitle = response.data.info[0].title.replace(/(\r\n|\n|\r)/gm,"").trim()
           if responseTitle
             msg.send if response.status_code is 200 then responseTitle else response.status_txt
           else


Set location properties on the document element so the location can be determined when it's empty

--- src/trix/views/document_view.coffee
+++ src/trix/views/document_view.coffee
@@ -2,6 +2,8 @@

 class Trix.DocumentView
   constructor: (@element, @document) ->
+    @element.trixPosition = 0
+    @element.trixIndex = 0

   render: ->
     @element.removeChild(@element.lastChild) while @element.lastChild


dd wal logging

dd wal logging

--- services/clsi/app/coffee/db.coffee
+++ services/clsi/app/coffee/db.coffee
@@ -15,6 +15,7 @@
 )

 if Settings.mysql.clsi.dialect == "sqlite"
+	logger.log "running PRAGMA journal_mode=WAL;"
 	sequelize.query("PRAGMA journal_mode=WAL;")

 module.exports =


Tests: Fix setup wrt to msgflo-nodejs 0.4.2

No longer creates implicit queues for outports

--- spec/setup.coffee
+++ spec/setup.coffee
@@ -104,9 +104,11 @@
       onMessage = (msg) ->
         chai.expect(msg.data).to.eql input
         done()
-      client.subscribeToQueue 's_worker.OUT', onMessage, (err) ->
+      client.createQueue 'inqueue', 's_worker.OUT', (err) ->
         chai.expect(err).to.not.exist
-        client.sendTo 'inqueue', 's_api.IN', input, (err) ->
-          chai.expect(err).to.not.exit
+        client.subscribeToQueue 's_worker.OUT', onMessage, (err) ->
+          chai.expect(err).to.not.exist
+          client.sendTo 'inqueue', 's_api.IN', input, (err) ->
+            chai.expect(err).to.not.exit

     it 'should have set up deadlettering'


Conceptually we should be using Fact#isNew for FactVotes#isNew

--- core/app/backbone/models/fact_votes.coffee
+++ core/app/backbone/models/fact_votes.coffee
@@ -13,7 +13,7 @@
   initialize: (attributes, options) ->
     @_fact = options.fact

-  isNew: -> false
+  isNew: -> @_fact.isNew()

   url: -> @_fact.url() + '/opinion'


Test framework: Describe now show with console info

--- src/test/config.coffee
+++ src/test/config.coffee
@@ -40,7 +40,7 @@
 	r.run = ()->
 		while results.toTest.length > 0
 			results.running = results.toTest.pop()
-			console.log "Testing " + results.running.title
+			console.info "Testing " + results.running.title
 			try
 				results.running.fun()
 			catch e


Confirmation choice: Some fixes for UI attributes.

--- src/elements/ConfirmationChoice/ConfirmationChoice.coffee
+++ src/elements/ConfirmationChoice/ConfirmationChoice.coffee
@@ -70,15 +70,15 @@

 	init: ->
 		@_buttons = []
-		for choice in @_choices
+		for choice, index in @_choices
 			if not choice
 				continue

 			uiKey = "confirmation.choice"
-			if choice.text
-				uiKey += ":#{choice.text.toLowerCase().replace(/s+/g, '_')}"
-			else if choice.loca_key
+			if choice.loca_key
 				uiKey += ":#{choice.loca_key}"
+			else
+				uiKey += ":#{index}"

 			btn_opts =
 				left: true


google tr limit to 10000

google tr limit to 10000

--- app/assets/javascripts/ab_admin/components/google_translate.js.coffee
+++ app/assets/javascripts/ab_admin/components/google_translate.js.coffee
@@ -48,7 +48,7 @@
   @locales = ['ru', 'en', 'it']
   constructor: ->
     @locales = GoogleLocaleTabs.locales
-    @limit = 1000
+    @limit = 10000
     html = '
'
     for l in @locales
       html += "

"


Default encoding to utf8

Default encoding to utf8

--- src/text-buffer.coffee
+++ src/text-buffer.coffee
@@ -314,10 +314,10 @@
     @emitter.emit 'did-change-path', @getPath()
     @emit "path-changed", this

-  # Public: Sets the encoding for this buffer.
-  #
-  # * `encoding` The {String} encoding to use such as 'utf8'
-  setEncoding: (@encoding) ->
+  # Public: Sets the character set encoding for this buffer.
+  #
+  # * `encoding` The {String} encoding to use (default: 'utf8').
+  setEncoding: (@encoding='utf8') ->
     return unless @file?

     @file.setEncoding(@encoding)


Provide an `editorElement` shim on TextEditor

Signed-off-by: Nathan Sobo <2e8aa918660411855c6d44d5bb2da677aa033255@github.com>

--- src/text-editor.coffee
+++ src/text-editor.coffee
@@ -103,6 +103,17 @@

   Object.defineProperty @prototype, "element",
     get: -> @getElement()
+
+  Object.defineProperty @prototype, "editorElement",
+    get: ->
+      Grim.deprecate("""
+        `TextEditor.prototype.editorElement` has always been private, but now
+        it is gone. Reading the `editorElement` property still returns a
+        reference to the editor element but this field will be removed in a
+        later version of Atom, so we recommend using the `element` property instead.
+      """)
+
+      @getElement()

   Object.defineProperty(@prototype, 'displayBuffer', get: ->
     Grim.deprecate("""


We just say getElement now.

We just say getElement now.

--- src/text-editor.coffee
+++ src/text-editor.coffee
@@ -486,12 +486,12 @@
   onDidChangeScrollTop: (callback) ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::onDidChangeScrollTop instead.")

-    @viewRegistry.getView(this).onDidChangeScrollTop(callback)
+    @getElement().onDidChangeScrollTop(callback)

   onDidChangeScrollLeft: (callback) ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::onDidChangeScrollLeft instead.")

-    @viewRegistry.getView(this).onDidChangeScrollLeft(callback)
+    @getElement().onDidChangeScrollLeft(callback)

   onDidRequestAutoscroll: (callback) ->
     @displayBuffer.onDidRequestAutoscroll(callback)
@@ -3133,24 +3133,24 @@
   scrollToTop: ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::scrollToTop instead.")

-    @viewRegistry.getView(this).scrollToTop()
+    @getElement().scrollToTop()

   scrollToBottom: ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::scrollToTop instead.")

-    @viewRegistry.getView(this).scrollToBottom()
+    @getElement().scrollToBottom()

   scrollToScreenRange: (screenRange, options) -> @displayBuffer.scrollToScreenRange(screenRange, options)

   getHorizontalScrollbarHeight: ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::getHorizontalScrollbarHeight instead.")

-    @viewRegistry.getView(this).getHorizontalScrollbarHeight()
+    @getElement().getHorizontalScrollbarHeight()

   getVerticalScrollbarWidth: ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::getVerticalScrollbarWidth instead.")

-    @viewRegistry.getView(this).getVerticalScrollbarWidth()
+    @getElement().getVerticalScrollbarWidth()

   pageUp: ->
     @moveUp(@getRowsPerPage())
@@ -3217,11 +3217,11 @@

   pixelPositionForBufferPosition: (bufferPosition) ->
     Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForBufferPosition` instead")
-    @viewRegistry.getView(this).pixelPositionForBufferPosition(bufferPosition)
+    @getElement().pixelPositionForBufferPosition(bufferPosition)

   pixelPositionForScreenPosition: (screenPosition) ->
     Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForScreenPosition` instead")
-    @viewRegistry.getView(this).pixelPositionForScreenPosition(screenPosition)
+    @getElement().pixelPositionForScreenPosition(screenPosition)

   getSelectionMarkerAttributes: ->
     {type: 'selection', invalidate: 'never'}
@@ -3250,7 +3250,7 @@
       @displayBuffer.setHeight(height)
     else
       Grim.deprecate("This is now a view method. Call TextEditorElement::setHeight instead.")
-      @viewRegistry.getView(this).setHeight(height)
+      @getElement().setHeight(height)

   getHeight: ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::getHeight instead.")
@@ -3263,7 +3263,7 @@
       @displayBuffer.setWidth(width)
     else
       Grim.deprecate("This is now a view method. Call TextEditorElement::setWidth instead.")
-      @viewRegistry.getView(this).setWidth(width)
+      @getElement().setWidth(width)

   getWidth: ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::getWidth instead.")
@@ -3307,77 +3307,77 @@
   getScrollTop: ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollTop instead.")

-    @viewRegistry.getView(this).getScrollTop()
+    @getElement().getScrollTop()

   setScrollTop: (scrollTop) ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollTop instead.")

-    @viewRegistry.getView(this).setScrollTop(scrollTop)
+    @getElement().setScrollTop(scrollTop)

   getScrollBottom: ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollBottom instead.")

-    @viewRegistry.getView(this).getScrollBottom()
+    @getElement().getScrollBottom()

   setScrollBottom: (scrollBottom) ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollBottom instead.")

-    @viewRegistry.getView(this).setScrollBottom(scrollBottom)
+    @getElement().setScrollBottom(scrollBottom)

   getScrollLeft: ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollLeft instead.")

-    @viewRegistry.getView(this).getScrollLeft()
+    @getElement().getScrollLeft()

   setScrollLeft: (scrollLeft) ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollLeft instead.")

-    @viewRegistry.getView(this).setScrollLeft(scrollLeft)
+    @getElement().setScrollLeft(scrollLeft)

   getScrollRight: ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollRight instead.")

-    @viewRegistry.getView(this).getScrollRight()
+    @getElement().getScrollRight()

   setScrollRight: (scrollRight) ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollRight instead.")

-    @viewRegistry.getView(this).setScrollRight(scrollRight)
+    @getElement().setScrollRight(scrollRight)

   getScrollHeight: ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollHeight instead.")

-    @viewRegistry.getView(this).getScrollHeight()
+    @getElement().getScrollHeight()

   getScrollWidth: ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollWidth instead.")

-    @viewRegistry.getView(this).getScrollWidth()
+    @getElement().getScrollWidth()

   getMaxScrollTop: ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::getMaxScrollTop instead.")

-    @viewRegistry.getView(this).getMaxScrollTop()
+    @getElement().getMaxScrollTop()

   intersectsVisibleRowRange: (startRow, endRow) ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::intersectsVisibleRowRange instead.")

-    @viewRegistry.getView(this).intersectsVisibleRowRange(startRow, endRow)
+    @getElement().intersectsVisibleRowRange(startRow, endRow)

   selectionIntersectsVisibleRowRange: (selection) ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::selectionIntersectsVisibleRowRange instead.")

-    @viewRegistry.getView(this).selectionIntersectsVisibleRowRange(selection)
+    @getElement().selectionIntersectsVisibleRowRange(selection)

   screenPositionForPixelPosition: (pixelPosition) ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::screenPositionForPixelPosition instead.")

-    @viewRegistry.getView(this).screenPositionForPixelPosition(pixelPosition)
+    @getElement().screenPositionForPixelPosition(pixelPosition)

   pixelRectForScreenRange: (screenRange) ->
     Grim.deprecate("This is now a view method. Call TextEditorElement::pixelRectForScreenRange instead.")

-    @viewRegistry.getView(this).pixelRectForScreenRange(screenRange)
+    @getElement().pixelRectForScreenRange(screenRange)

   ###
   Section: Utility


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/text_screen.coffee
+++ src/text_screen.coffee
@@ -1,5 +1,5 @@
 ###*
-The Text Screen class sets up a simple game title screen using App.name
+The Text Screen class is a simple Gam

 @see TextScreen
 @name TitleScreen


change getBounds

change getBounds

--- syslibs/library.coffee
+++ syslibs/library.coffee
@@ -89,7 +89,7 @@
     width = document.body.clientWidth
     if (!width?)
         width = document.documentElement.clientWidth - 2
-    height = document.body.clientHeight
+    height = document.height
     if (!height?)
         height = document.documentElement.clientHeight - 2
     frame = JSRectMake(0, 0, width, height)


Remove newlines before objects in arrays

--- src/Dumper.coffee
+++ src/Dumper.coffee
@@ -34,8 +34,7 @@

                     output +=
                         prefix +
-                        '-' +
-                        (if willBeInlined then ' ' else "\n") +
+                        '- ' +
                         @dump(value, inline - 1, (if willBeInlined then 0 else indent + @indentation), exceptionOnInvalidType, objectEncoder) +
                         (if willBeInlined then "\n" else '')


Replace exception with warning

Replace exception with warning

--- src/tools/nodew.coffee
+++ src/tools/nodew.coffee
@@ -8,29 +8,40 @@
   if fs.FileExists dst = fs.BuildPath path, 'nodew.exe'
     return

-  echo "Generating", dst
+  stream = binstream()
+  stream.LoadFromFile src

-  assert = (ok)->
-    throw SyntaxError "Invalid executable: #{src}" unless ok
+  if check stream
+    echo "Generating", dst
+    stream.Write hex.dec '02'         # CUI
+    stream.SaveToFile dst
+  else
+    echo "Invalid executable:", src
+
+  stream.Close()
+
+# Validate PE header
+check = (stream)->

   readInt = (size)->
     hex.i stream.Read size

-  stream = binstream()
-  stream.LoadFromFile src
-  assert 0x5a4d == readInt 2        # MZ
+  if 0x5a4d != readInt 2          # MZ
+    return
   stream.Position = 60
   pe = readInt 4
-  assert pe < stream.size
+  if pe >= stream.size
+    return
   stream.Position = pe
-  assert 0x4550 == readInt 4        # PE
+  if 0x4550 != readInt 4          # PE
+    return
   stream.Position = pe + 20
-  assert 0xF0 == 0x80 | readInt 2   # SizeOfOptionalHeader 0xE0/0xF0
-  readInt 2                         # Characteristics
-  assert 0x30b == 0x30 | readInt 2  # Magic 0x10B/0x20B
+  if 0xF0 != (0x10 | readInt 2)   # SizeOfOptionalHeader: 0xE0/0xF0
+    return
+  readInt 2                       # Characteristics
+  if 0x30b != (0x300 | readInt 2) # Magic: 0x10B/0x20B
+    return
   stream.Position = subsys = pe + (24 + 68)
-  assert 3 == readInt 2             # GUI
+  if 3 != readInt 2               # GUI
+    return
   stream.Position = subsys
-  stream.Write hex.dec '02'         # CUI
-  stream.SaveToFile dst, 2
-  stream.Close()


Removed CoffeeScript based specs

Removed CoffeeScript based specs

--- spec/taglibSpec.coffee
+++ spec/taglibSpec.coffee
@@ -1,36 +0,0 @@
-assert = require 'assert'
-vows = require 'vows'
-fs = require 'fs'
-Taglib = require __dirname + '/../lib/taglib'
-
-vows.describe('taglib bindings')
-.addBatch
-  'reading Tags from File':
-    topic: new Taglib.Tag(__dirname+'/sample.mp3')
-    'should be a `Tag`': (tag) ->
-      assert.equal Taglib.Tag, tag.constructor
-    'should be `A bit-bucket full of tags`': (tag) ->
-      assert.equal 'A bit-bucket full of tags', tag.title
-    'should be a `A bit-bucket full of tags`': (tag) ->
-      assert.equal 'A bit-bucket full of tags', tag.title
-    'should be by `gitzer\'s`': (tag) ->
-      assert.equal 'gitzer\'s', tag.artist
-    'should be on `Waffles for free!`': (tag) ->
-      assert.equal "Waffles for free!", tag.album
-    'should be the first': (tag) ->
-      assert.equal 1, tag.track
-    'should be from 2011': (tag) ->
-      assert.equal 2011, tag.year
-  'writing Tags to File':
-    topic: ->
-      filename = __dirname+'/sample-write.mp3'
-      fs.writeFileSync filename, fs.readFileSync(__dirname+'/sample.mp3')
-      t = new Taglib.Tag filename
-      t.title = 'Something completely different…'
-      t.save()
-      filename
-    'should have written `Something completely different…` to title': (filename) ->
-      tag = new Taglib.Tag filename
-      assert.equal "Something completely different…", tag.title
-
-.export(module)


Added port from package.json as alternative to node environment

--- bin/www.coffee
+++ bin/www.coffee
@@ -2,9 +2,10 @@

 http = require("http")
 app = require("../app")
+{config} = require('../package.json')

 # Get port from environment and store it in Express
-port = parseInt(process.env.PORT, 100) or 3000
+port = parseInt(process.env.PORT, 100) or config.port or 3000
 app.set('port', port)

 # Create HTTP server


jump to begin of page on ship fixed

jump to begin of page on ship fixed

--- modules/levelcreator/app/assets/javascripts/main/routing.coffee
+++ modules/levelcreator/app/assets/javascripts/main/routing.coffee
@@ -79,6 +79,10 @@

       # set ship it
       $("#level-list .ship-stacks-poopover").popover()
+
+      $("#level-list .ship-stacks-poopover").on "click", (event) ->
+
+        event.preventDefault()

       $(document).on "click", "[data-prompt]", (event) ->
@@ -130,7 +134,7 @@
           "shouldAutoRender": autoShip is "true",
           "shouldBeShipped": true
         })
-        console.log json
+

         $.ajax(
           _.extend(


Adds credit test on API

Adds credit test on API

--- api/apps/articles/test/model/index/persistence.test.coffee
+++ api/apps/articles/test/model/index/persistence.test.coffee
@@ -516,6 +516,7 @@
                 title: 'The Piece'
                 date: '2015-04-01'
                 image: 'http://image.png'
+                credit: 'Credit Line'
               }
             ]
           }
@@ -530,6 +531,7 @@
         article.sections[0].images[1].type.should.equal 'artwork'
         article.sections[0].images[1].id.should.equal '123'
         article.sections[0].images[1].slug.should.equal 'andy-warhol'
+        article.sections[0].images[1].credit.should.equal 'Credit Line'
         done()

     it 'saves layouts', (done) ->


Add missing callback params

Add missing callback params

--- src/browser/squirrel-update.coffee
+++ src/browser/squirrel-update.coffee
@@ -31,7 +31,7 @@
 installContextMenu = (callback) ->
   fileKeyPath = 'HKCU\\Software\\Classes\\*\\shell\\Atom'

-  spawnReg = (args) ->
+  spawnReg = (args, callback) ->
     args.unshift('add')
     regProcess = ChildProcess.spawn('reg.exe', args)
     console.log args
@@ -43,7 +43,7 @@
       error?.code ?= code
       callback(error)

-  installFileMenu = ->
+  installFileMenu = (callback) ->
     args = [fileKeyPath, '/ve', '/d', 'Open with Atom', '/f']
     spawnReg args, (error) ->
       console.log 'done'


Support for displaying a right-justified popup when trigger at the right edge of window

--- lib/Popup.coffee
+++ lib/Popup.coffee
@@ -35,11 +35,12 @@

   offset = element.offset()

-  ul = $('
').attr('id', 'popup').addClass('popupMenu')
-      .css({
-        left: Math.round(offset.left) + 'px',
-        top: Math.floor(offset.top + element.height()) + 'px'
-      }).hide()
+  style = if offset.left < $(window).width() - 150
+    "left: #{Math.round offset.left}px"
+  else
+    "right: #{Math.round($(window).width() - offset.left - element.outerWidth())}px"
+
+  ul = $ "

"

   for item in items
     if (item == '-')
@@ -52,7 +53,7 @@
           item.action() if item.action
           item[1]() if item[1]
           options.close() if options.close
-          closePopup();
+          closePopup()
         li.append a
         ul.append li


update

update

--- lib/combo.coffee
+++ lib/combo.coffee
@@ -173,7 +173,7 @@
       @ensureSelection()
       @lastQuery = @input.val()

-      @container.trigger 'loaded'
+      @input.trigger 'loaded'

     setValue: (value) =>
       for item in @source when item.value is value
@@ -218,7 +218,7 @@
       @lastQuery = @input.val()
       @updateLastSelection()
       @internalCollapse()
-      _.delay (=> @container.trigger 'itemSelect', title: item.title), 10
+      _.delay (=> @input.trigger 'itemSelect', title: item.title), 10

     onListClick: (event) =>
       console.log "onListMouseDown"


vm.create(): fix updating existing disks (vatesfr/xo-web#774).

--- src/api/vm.coffee
+++ src/api/vm.coffee
@@ -1,3 +1,4 @@
+$assign = require 'lodash.assign'
 $debug = (require 'debug') 'xo:api:vm'
 $filter = require 'lodash.filter'
 $findIndex = require 'lodash.findindex'
@@ -107,7 +108,6 @@
   )

   xapiExistingVdis = existingDisks and map(existingDisks, (vdi, device) =>
-
     if vdi.size?
       size = parseSize(vdi.size)
       diskSizesByDevice[device] = size
@@ -116,11 +116,10 @@
       sr = @getObject(vdi.$SR)
       objectIds.push(sr.id)

-    return {
+    return $assign({}, vdi, {
       size,
-      $SR: sr and sr._xapiId,
-      type: vdi.type
-    }
+      $SR: sr and sr._xapiId
+    })
   )

   forEach(diskSizesByDevice, (size) => limits.disk += size)


Fix default migration

Fix default migration

--- src/api/vm.coffee
+++ src/api/vm.coffee
@@ -226,8 +226,8 @@

   yield @getXapi(vm).migrateVm(vm._xapiId, @getXapi(host), host._xapiId, {
     migrationNetworkId: migrationNetwork?._xapiId
-    mapVifsNetworks: mapVifsNetworksXapi,
-    mapVdisSrs: mapVdisSrsXapi,
+    mapVifsNetworks: mapVifsNetworks && mapVifsNetworksXapi,
+    mapVdisSrs: mapVdisSrs && mapVdisSrsXapi,
   })
   return


'Updating for version 0.12.5dev12'

'Updating for version 0.12.5dev12'

--- bokehjs/src/coffee/version.coffee
+++ bokehjs/src/coffee/version.coffee
@@ -1 +1 @@
-export version = '0.12.5dev11'
+export version = '0.12.5dev12'


[no-task]: some minor bugfix

[no-task]: some minor bugfix

--- app/assets/javascripts/app.coffee
+++ app/assets/javascripts/app.coffee
@@ -43,6 +43,9 @@
             .when('/topic/modify/:userID', {
                 templateUrl: '/assets/partials/myhip_modifyTopic.html'
             })
+            .when('/topic/create', {
+                templateUrl: '/assets/partials/myhip_createTopic.html'
+            })
             .when('/group/propose', {
               templateUrl: '/assets/partials/group_proposeTopic.html'
             })


Fix recentlyUpdatedSongs route is not highlighted.

--- app/client/js/react/header.coffee
+++ app/client/js/react/header.coffee
@@ -19,7 +19,10 @@
               route: routes.home
               text: Header.MSG_MY_SONGS
               activeFor: [routes.editSong, routes.newSong, routes.trash]
-            link.to routes.songs, Header.MSG_SONGS
+            link.to
+              route: routes.songs
+              text: Header.MSG_SONGS
+              activeFor: [routes.recentlyUpdatedSongs]
             link.to routes.about, Header.MSG_ABOUT
             if usersStore.isLogged()
               link.to routes.me, Header.MSG_ME


fix disable/enableMarkingSurfaces()

fix disable/enableMarkingSurfaces()

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -94,45 +94,41 @@
   states:
     whatKind:
       enter: ->
-        # console.log "STATE: \'whatKind/enter\'"
-        # @disableMarkingSurfaces()
+        @disableMarkingSurfaces()

         # reset asteroid/artifact selector
         for e in @el.find('input[name="classifier-type"]')
           e.checked = false
-
         @el.find('button[name="to-select"]').addClass 'hidden'
         @el.find('.what-kind').show()

       exit: ->
-        # console.log "STATE: \'whatKind/exit\'"
+        @enableMarkingSurfaces()
         @el.find('button[name="to-select"]').removeClass 'hidden'
         @el.find('.what-kind').hide()

     asteroidTool:
       enter: ->
         @activateFrame 0
-        # create new asteroid
+        @enableMarkingSurfaces()
         @currAsteroid = new Sighting({type:"asteroid"})
-        # @enableMarkingSurfaces()
         @el.find('.asteroid-classifier').show()
         @finishButton.hide()
         @doneButton.show()
-
         @doneButton.prop 'disabled', true

       exit: ->
-        # @disableMarkingSurfaces()
+        @disableMarkingSurfaces()
         @el.find('.asteroid-classifier').hide()
         @doneButton.hide()
         @finishButton.show()

     artifactTool:
       enter: ->
-        # @enableMarkingSurfaces()
+        @enableMarkingSurfaces()
         @el.find('.artifact-classifier').show()
       exit: ->
-        # @disableMarkingSurfaces()
+        @disableMarkingSurfaces()
         @el.find('.artifact-classifier').hide()

   constructor: ->
@@ -142,7 +138,6 @@
     @el.attr tabindex: 0
     @el.attr 'flicker', "true"

-    @setState 'whatKind'
     @invert = false
     @currFrameIdx = 0

@@ -192,7 +187,6 @@
     for surface in @markingSurfaceList
       surface.on "create-mark", @onCreateMark

-
   renderTemplate: =>
     super


remove unused invert code causing js error - fixes #116

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -617,10 +617,6 @@
       for i in [0...markElements.length]
         markElements[0].parentElement.appendChild markElements[0]

-    # invert using svg inverter - implement when cross origin ready
-    images = document.getElementsByClassName('frame-image')
-    InvertSvg(image) for image in images
-
   onClickFinishMarking: ->
     radio.checked = false for radio in @classifierTypeRadios
     @onClickCycleChannels() if @cycling


Fix incorrectly named functions

Fix incorrectly named functions

This scares me because there's likely more of the same throughout the codebase.

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -176,14 +176,13 @@
       @viewer.clearCache()

     # Unbind Talk event and clean collection ids
-    @unbind 'addToTalk'
+    @off 'addToTalk'
     @talkIds = {}

     # Set default counts
     @counter.updateAttributes({'classified': 0, 'potentials': 0, 'favorites': 0})

     if user?
-
       # Set up three collections (My Dashboard, My Candidates and My Simulations)
       names = ['My Dashboard', 'My Candidates', 'My Simulations']
       descriptions = [
@@ -193,7 +192,7 @@
       ]
       @setTalkCollections(user, names, descriptions)

-      @bind 'addToTalk', (collectionId, subjectId) =>
+      @on 'addToTalk', (collectionId, subjectId) =>
         @addToTalkCollection(user, collectionId, subjectId)

       project = user.project


Rename the tooltip div.

Rename the tooltip div.

--- app/javascripts/collection.coffee
+++ app/javascripts/collection.coffee
@@ -631,8 +631,6 @@
           d3.selection::moveToFront = ->
             @each ->
               @parentNode.appendChild this
-              # TODO - Why this return?
-              return

           # Convenience temp config variables.
           data = config.data
@@ -701,20 +699,18 @@
           chart.on 'renderlet', (chart) ->
             chart.selectAll '.symbol'
               .on 'mouseover', (d) ->
-                # TODO - What is div here?
-                # TODO - Remove the returns below if they are extraneous.
-                div.transition().duration(20).style('opacity', .9)
+                # The 'tooltip' is the selection returned by d3 after the chart
+                # rendering call.
+                tooltip.transition().duration(20).style('opacity', .9)
                 # TODO - make temp variables and interpolate the argument,
                 #   e.g.:
                 #     label = "Patient:#{ d.key[0] }"
                 #     ...
                 #     html = "#{ label }..."
-                #     div.html(html)
-                div.html('Patient: ' + d.key[0] + '
Visit: ' + d.key[1]).style('left', d3.event.pageX + 5 + 'px').style 'top', d3.event.pageY - 35 + 'px'
-                return
+                #     tooltip.html(html)
+                tooltip.html('Patient: ' + d.key[0] + '
Visit: ' + d.key[1]).style('left', d3.event.pageX + 5 + 'px').style 'top', d3.event.pageY - 35 + 'px'
               .on 'mouseout', (d) ->
-                div.transition().duration(50).style('opacity', 0)
-                return
+                tooltip.transition().duration(50).style('opacity', 0)

           # The axes determine the number of charts to display.
           chartCnt = axes.length
@@ -731,8 +727,8 @@
             yAxis = axes[i].y

             # Set up the dimension based on the X and Y axis user selections.
-# TODO - is d here the chart data object? If so, then comment and
-# rename to obj here and below.
+            # TODO - is d here the chart data object? If so, then comment and
+            # rename to obj here and below.
             dim = xFilter.dimension (d) ->
               [
                 d[xAxis]
@@ -774,12 +770,10 @@
             chart.on 'renderlet', (chart) ->
               chart.selectAll '.symbol'
                 .on 'mouseover', (d) ->
-                  div.transition().duration(20).style 'opacity', 1
-                  div.html('x: ' + d.key[0] + '
y: ' + d.key[1]).style('left', d3.event.pageX + 5 + 'px').style 'top', d3.event.pageY - 35 + 'px'
-                  return
+                  tooltip.transition().duration(20).style 'opacity', 1
+                  tooltip.html('x: ' + d.key[0] + '
y: ' + d.key[1]).style('left', d3.event.pageX + 5 + 'px').style 'top', d3.event.pageY - 35 + 'px'
                 .on 'mouseout', (d) ->
-                  div.transition().duration(50).style 'opacity', 0
-                  return
+                  tooltip.transition().duration(50).style 'opacity', 0
                 .style 'opacity', (d) ->
                   if d.key[0]? and d.key[1]? then 1 else 0

@@ -790,6 +784,6 @@
           d3.selectAll('.chart-body').moveToFront()

           # The tooltip div.
-          div = d3.select('body').append('div').attr('class', 'tooltip').style 'opacity', 0
+          tooltip = d3.select('body').append('div').attr('class', 'tooltip').style 'opacity', 0

       ]


Fix unknown props on links in FlexibleLink

--- app/partials/collection-card.cjsx
+++ app/partials/collection-card.cjsx
@@ -22,7 +22,7 @@
       {@props.children}
     else
       <Link
-        {...@props}
+        to={@props.to}
         onClick={@logClick?.bind(this, @props.logText)}>{@props.children}</Link>

 module.exports = React.createClass


Add transac fix

Add transac fix

--- app/src/wallet/transaction.coffee
+++ app/src/wallet/transaction.coffee
@@ -155,7 +155,7 @@
             else if hasNext is false and collectedAmount.lt(requiredAmount)
               # Not enough available funds
               callback?(null, {title: 'Not enough founds', code: ledger.errors.NotEnoughFunds})
-            else if hasNext is false and collectedAmount.gte requiredAmount
+            else if collectedAmount.gte requiredAmount
               # We have reached our required amount. It's to prepare the transaction
               _.defer -> transaction.prepare(outputs, changePath, callback)
             else


Add badge names and badge types

Add badge names and badge types

Added Translator badge to the badge list and badge type list.

--- src/badges.coffee
+++ src/badges.coffee
@@ -38,7 +38,8 @@
   'recursion',
   'seer1', 'seer2', 'seer3', 'seer4', 'seer5',
   'specops1', 'specops2', 'specops3', 'specops4', 'specops5',
-  'trekker1', 'trekker2', 'trekker3', 'trekker4', 'trekker5',
+  'trekker1', 'trekker2', 'trekker3', 'trekker4', 'trekker5', 'translator1',
+  'translator2', 'translator3', 'translator4', 'translator5',
   'verified'
 ]

@@ -66,7 +67,8 @@
   'seer': 5,
   'specops': 5,
   'trekker': 5,
-  'verified': 1,
+  'translator': 5,
+  'verified': 1
 }

 module.exports = (robot) ->


¯\_(ツ)_/¯

--- assets/javascripts/app/app.coffee
+++ assets/javascripts/app/app.coffee
@@ -187,7 +187,7 @@
   hideLoading: ->
     document.body.classList.remove '_booting'
     document.body.classList.remove '_loading'
-    $.remove document.getElementById('fontLoader')
+    try $.remove document.getElementById('fontLoader')
     return

   indexHost: ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera.coffee
+++ src/camera.coffee
@@ -14,7 +14,6 @@
     zoom: 1
     transform: Matrix()
     scroll: Point(0, 0)
-    maxSpeed: Infinity

   currentType = "centered"
   currentObject = null


placed the xhrField option onto the relationship adapter

--- addon/adapters/relationship.coffee
+++ addon/adapters/relationship.coffee
@@ -2,6 +2,12 @@
 `import DS from 'ember-data'`

 RelationshipAdapter = DS.JSONAPIAdapter.extend
+  ajaxOptions: ->
+    hash = @_super arguments...
+    hash.xhrFields =
+      withCredentials: true
+    hash
+
   deleteRecord: (store, type, snapshot) ->
     data = {}
     serializer = store.serializerFor(type.modelName)


remove logging

remove logging

--- test-integration/calendar.coffee
+++ test-integration/calendar.coffee
@@ -52,13 +52,12 @@
             Calendar.Popup.goReview(@)

             @driver.sleep(1000)
-            @waitClick(css: '.task-breadcrumbs button').then -> console.log 'Clicked back to dashboard'
+            @waitClick(css: '.task-breadcrumbs button')
             @driver.sleep(1000)
-            Calendar.Popup.verify(@).then -> console.log 'verified'
-            Calendar.Popup.close(@).then -> console.log 'cloased'
+            Calendar.Popup.verify(@)
+            Calendar.Popup.close(@)
             Calendar.verify(@).then ->
               doneCheckingCount += 1
-              console.log 'calendar'

       # Go back to the course selection
       @waitClick(css: '.navbar-brand').then ->


Missing import

Missing import

--- client/src/models/0-module.coffee
+++ client/src/models/0-module.coffee
@@ -2,6 +2,7 @@
   'ngResource'
 ]

+require './daily-report-ping.coffee'
 require './daily-report.coffee'
 require './feedback.coffee'
 require './organization.coffee'


Set default horizontalScrollMargin

Set default horizontalScrollMargin

--- src/editor.coffee
+++ src/editor.coffee
@@ -145,6 +145,7 @@
   selections: null
   suppressSelectionMerging: false
   verticalScrollMargin: 2
+  horizontalScrollMargin: 6

   @delegatesMethods 'suggestedIndentForBufferRow', 'autoIndentBufferRow', 'autoIndentBufferRows',
     'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows',


fix apply attribute to line to pass unit tests

--- src/editor.coffee
+++ src/editor.coffee
@@ -108,6 +108,7 @@
     this.emit(TandemEditor.events.API_TEXT_CHANGE, delta) if emitEvent

   applyAttributeToLine: (lineNode, startOffset, endOffset, attr, value) ->
+    return if endOffset == startOffset
     line = @doc.findLine(lineNode)
     if _.indexOf(Tandem.Constants.LINE_ATTRIBUTES, attr, true) > -1
       this.applyLineAttribute(line, attr, value)


Revert "Sometimes there might not be a selection."

This reverts commit a73e6e5bd07e07f38ee5295a33d919a92e2e2635.

--- src/editor.coffee
+++ src/editor.coffee
@@ -1306,7 +1306,7 @@
   addSelectionForBufferRange: (bufferRange, options={}) ->
     @markBufferRange(bufferRange, _.defaults(@getSelectionMarkerAttributes(), options))
     selection = @getLastSelection()
-    selection?.autoscroll() if @manageScrollPosition
+    selection.autoscroll() if @manageScrollPosition
     selection

   # Public: Set the selected range in buffer coordinates. If there are multiple


Fucking sections.

Fucking sections.

--- index.coffee
+++ index.coffee
@@ -6,8 +6,10 @@

 root = path.resolve(__dirname)

+## External configuration
 AYP_SECRET = process.env.AYP_SECRET or "That's my secret, they're all my pants."

+## The "Database"
 redis = do (->
   info = url.parse process.env.REDISTOGO_URL or
     process.env.REDISCLOUD_URL or
@@ -18,14 +20,16 @@
   return storage
 )

+## App config
 app = express()
-
 app.set 'port', (process.env.PORT or 5000)
 app.use express.static(path.resolve(root, 'public'))

+## Application routes
 app.get '/', (request, response) ->
   redis.info (err, res) ->
     response.send "All who's pants?"

+## Boot sequence
 app.listen app.get('port'), ->
   console.log "Your pants running at http://localhost:#{app.get('port')}/"


Plugin is done but can't seem to authenticate against the test instance :(

--- index.coffee
+++ index.coffee
@@ -31,10 +31,10 @@
 OPTIONS_SCHEMA =
   type: 'object'
   properties:
-    domain:
+    customerId:
       type: 'string'
       required: true
-    hostUrl:
+    domain:
       type: 'string'
       required: true
     username:
@@ -51,33 +51,37 @@
     @optionsSchema = OPTIONS_SCHEMA
     @queryKeys = [LATEST_SERVER_OS_FAILURE, LATEST_DESKTOP_OS_FAILURE, LATEST_CONNECTION_FAILURE, LOGON_COUNT, NUMBER_OF_RUNNING_ACTIVE_SESSIONS ]
     @queryMap =
-      LATEST_SERVER_OS_FAILURE : LATEST_SERVER_OS_FAILURE_QUERY
-      LATEST_DESKTOP_OS_FAILURE: LATEST_DESKTOP_OS_FAILURE_QUERY
-      LATEST_CONNECTION_FAILURE: LATEST_CONNECTION_FAILURE_QUERY
-      LOGON_COUNT : LOGON_COUNT_QUERY
-      NUMBER_OF_RUNNING_ACTIVE_SESSIONS: NUMBER_OF_RUNNING_ACTIVE_SESSIONS_QUERY
+      "#{LATEST_SERVER_OS_FAILURE}" : LATEST_SERVER_OS_FAILURE_QUERY
+      "#{LATEST_DESKTOP_OS_FAILURE}": LATEST_DESKTOP_OS_FAILURE_QUERY
+      "#{LATEST_CONNECTION_FAILURE}": LATEST_CONNECTION_FAILURE_QUERY
+      "#{LOGON_COUNT}" : LOGON_COUNT_QUERY
+      "#{NUMBER_OF_RUNNING_ACTIVE_SESSIONS}": NUMBER_OF_RUNNING_ACTIVE_SESSIONS_QUERY

   onMessage: (message) =>
-
+    debug "Message", message
     payload = message.payload
-    query = message.query? or payload.query?
+    query = message.query or payload.query
+    return @emit "error", "Missing customerId from config" unless @options.customerId?
     return @emit "error", "Missing domain from config" unless @options.domain?
     return @emit "error", "Missing username from config" unless @options.username?
-    return @emit "error", "Missing hostUrl from config" unless @options.hostUrl?
     return @emit "error", "Missing password from config" unless @options.password?
-    return @emit "error", "Missing query from message" unless query
+    return @emit "error", "Missing query from message" unless query?
     return @emit "error", "Invalid query option: #{query}" unless _.contains @queryKeys, query

-    queryUrl = "https://#{@options.domain}.#{@options.hostUrl}/#{@queryMap[query]}"
+    queryUrl = "https://#{@options.customerId}.#{@options.domain}/#{@queryMap[query]}"
+    debug "Query URL", queryUrl

-    authHeader = new Buffer("#{@options.username}:#{@options.password}").toString("base64")
+    authHeader = new Buffer("#{@options.domain}/#{@options.username}:#{@options.password}").toString("base64")
+
     reqOptions =
       method: "GET"
       uri : queryUrl
       json: true
       headers:
         Authorization: "Basic #{authHeader}"
+
+    debug "Request Options", reqOptions

     request reqOptions, (error, response, body) =>
       if error?
@@ -86,7 +90,7 @@

       debug "Response", response.statusCode
       debug "Body", body
-      result =
+      result =
         status : response.statusCode
         data: body


tilemap update

tilemap update

--- src/engine.coffee
+++ src/engine.coffee
@@ -251,7 +251,7 @@
     self.attrAccessor "cameraTransform"
     self.include Bindable

-    defaultModules = ["Shadows", "HUD", "Developer", "SaveState", "Selector", "Collision", "FPSCounter"]
+    defaultModules = ["Shadows", "HUD", "Developer", "SaveState", "Selector", "Collision", "Tilemap", "FPSCounter"]
     modules = defaultModules.concat(I.includedModules)
     modules = modules.without(I.excludedModules)


Name input fix, #517

Name input fix, #517

--- browser.coffee
+++ browser.coffee
@@ -45,27 +45,29 @@

 	# Common func for user and character name checking
 	nameStatusHelper = (formGroupSelector, feedbackSelector) ->
-		formGroup = $(formGroupSelector)
-		feedback = $(feedbackSelector)
 		(state, hint) ->
-			$(formGroup).removeClass 'has-error has-success'
-			$(feedback).removeClass 'glyphicon-ok glyphicon-remove glyphicon-refresh'
-			$(feedback).hide()
+			# init
+			formGroup = $(formGroupSelector)
+			feedback = $(feedbackSelector)
+			# cleanup
+			formGroup.removeClass 'has-error has-success'
+			feedback.removeClass 'glyphicon-ok glyphicon-remove glyphicon-refresh'
+			feedback.hide()
 			# state
 			if state is 'checking'
-				$(feedback).addClass 'glyphicon-refresh'
-				$(feedback).show()
+				feedback.addClass 'glyphicon-refresh'
+				feedback.show()
 			if state is 'ok'
-				$(feedback).addClass 'glyphicon-ok'
-				$(feedback).show()
-				$(formGroup).addClass 'has-success'
+				feedback.addClass 'glyphicon-ok'
+				feedback.show()
+				formGroup.addClass 'has-success'
 			if state is 'error'
-				$(feedback).addClass 'glyphicon-remove'
-				$(feedback).show()
-				$(formGroup).addClass 'has-error'
+				feedback.addClass 'glyphicon-remove'
+				feedback.show()
+				formGroup.addClass 'has-error'
 			# hint
 			if not hint? then hint = ''
-			$(feedback).attr('title', hint)
+			feedback.attr('title', hint)

 	# Registration page stuff


Client: Activity: Updated ActivityAppController to load global notification settings

--- client/activity/lib/index.coffee
+++ client/activity/lib/index.coffee
@@ -1,15 +1,16 @@
-kd                   = require 'kd'
-ActivityAppView      = require './activityappview'
-ActivityFlux         = require 'activity/flux'
-remote               = require('app/remote').getInstance()
-globals              = require 'globals'
-getGroup             = require 'app/util/getGroup'
-checkFlag            = require 'app/util/checkFlag'
-isKoding             = require 'app/util/isKoding'
-AppStorage           = require 'app/appstorage'
-AppController        = require 'app/appcontroller'
-KodingAppsController = require 'app/kodingappscontroller'
-keyboardKeys = require 'app/util/keyboardKeys'
+kd                       = require 'kd'
+ActivityAppView          = require './activityappview'
+ActivityFlux             = require 'activity/flux'
+remote                   = require('app/remote').getInstance()
+globals                  = require 'globals'
+getGroup                 = require 'app/util/getGroup'
+checkFlag                = require 'app/util/checkFlag'
+isKoding                 = require 'app/util/isKoding'
+AppStorage               = require 'app/appstorage'
+AppController            = require 'app/appcontroller'
+KodingAppsController     = require 'app/kodingappscontroller'
+keyboardKeys             = require 'app/util/keyboardKeys'
+NotificationSettingsFlux = require 'activity/flux/channelnotificationsettings'

 require('./routehandler')()

@@ -41,6 +42,8 @@

     helper.loadFonts()
     helper.loadEmojiStyles()
+
+    NotificationSettingsFlux.actions.channel.loadGlobal()

   post: (options = {}, callback = noop) ->


Correctly position popovers with variable width html tag

--- src/scripts/helpers/handlers/popover.coffee
+++ src/scripts/helpers/handlers/popover.coffee
@@ -46,7 +46,7 @@
           @$el.find('.arrow').css({top: '-7px', left: '100%'})
           @$el.css
             'left': 'auto'
-            'right': document.body.clientWidth - (@$owner.offset().left + @$owner.outerWidth())
+            'right': $('html').outerWidth(true) - (@$owner.offset().left + @$owner.outerWidth())

     render: () -> return @ # noop


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color2.coffee
+++ src/color2.coffee
@@ -173,7 +173,7 @@

       [@r, @g, @b, @a] = hslToRgb(hsl)

-      @r = @r.roun()
+      @r = @r.round()

       return this


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color2.coffee
+++ src/color2.coffee
@@ -15,18 +15,22 @@

     switch hexString.length
       when 3, 4
-        alpha = (parseInt(hexString.substr(3, 1), 16) * 0x11) / 255.0 if hexString.length == 4
+        if hexString.length == 4
+          alpha = ((parseInt(hexString.substr(3, 1), 16) * 0x11) / 255.0) || 1.0

         rgb = for i in [0..2]
           parseInt(hexString.substr(i, 1), 16) * 0x11

-        return rgb.concat(alpha)
+        return rgb.push(alpha)

       when 6, 8
+        if hexString.length == 8
+          alpha = (parseInt(hexString.substr(6, 2), 16) / 255.0) || 1.0
+
         rgb = for i in [0..2]
           parseInt(hexString.substr(2 * i, 2), 16)

-        return rgb.concat(if hexString.substr(6, 2).length then parseInt(hexString.substr(6, 2), 16) / 255.0 else 1.0)
+        return rgb.push(alpha)

       else
         return undefined


Update team

Update team

--- client/landing/About/team.coffee
+++ client/landing/About/team.coffee
@@ -28,17 +28,14 @@
         username  : 'cihangirsavas'
         title     : 'Software Engineer'
       ,
-        username  : 'geraint'
+        username  : 'kiwigeraint'
         title     : 'Director of Infrastructure'
       ,
-        username  : 'erdinc'
-        title     : 'Software Engineer'
-      ,
         username  : 'szkl'
-        title     : 'Software Engineer'
+        title     : 'DevOps'
       ,
         username  : 'leventyalcin'
-        title     : 'System Administrator'
+        title     : 'DevOps'
       ,
         username  : 'burakcan'
         title     : 'CSS Wizard'
@@ -129,4 +126,4 @@
       # ,
       #   username  : 'psanchezdl'
       #   title     : 'Growth Engineer'
-      # ]+      # ]


add c.firstRun check

add c.firstRun check

--- client/navigator-location.coffee
+++ client/navigator-location.coffee
@@ -22,8 +22,8 @@
   onLocation: (action) -> # TODO: validate it's a function
     Tracker.autorun (c) ->
       location = Nav.get.location()
-      console.log 'autorun location: ',location
-      action location, c if location?
+      if not c.firstRun and location?
+        action location, c
     return

   # set state in the browser's push api for the current location


Added debug option

Added debug option

--- src/common.coffee
+++ src/common.coffee
@@ -196,6 +196,14 @@
           # alter offset
           offset += layout.font_stretch * width

+      # check if debug pattern should be printed (use with prefix=false)
+      if @settings.debug
+        for x in [0..width] by item_width*2
+          context.beginPath()
+          context.rect(x, height*0.4, item_width, height*0.1)
+          context.fillStyle = 'red'
+          context.fill()
+
       @settings.onSuccess.call()
     else
       #call error callback
@@ -234,6 +242,7 @@
       number: true
       prefix: true
       color: "#000"
+      debug: false

       # callbacks
       onValid: ->


Initialize the new flag and pendingOperations in clear()

--- src/config.coffee
+++ src/config.coffee
@@ -399,8 +399,6 @@

   # Created during initialization, available as `atom.config`
   constructor: ({@notificationManager, @enablePersistence}={}) ->
-    @settingsLoaded = false
-    @pendingOperations = []
     @clear()

   initialize: ({@configDirPath, @resourcePath, projectHomeSchema}) ->
@@ -420,9 +418,11 @@
     @settings = {}
     @scopedSettingsStore = new ScopedPropertyStore

+    @settingsLoaded = false
     @savePending = false
     @configFileHasErrors = false
     @transactDepth = 0
+    @pendingOperations = []

     @requestLoad = _.debounce =>
       @loadUserConfig()


Don't assign defaults to array config values

--- src/config.coffee
+++ src/config.coffee
@@ -108,7 +108,10 @@

     if value?
       value = _.deepClone(value)
-      _.defaults(value, defaultValue) if typeof defaultValue is 'object'
+      valueIsObject = _.isObject(value) and not _.isArray(value)
+      defaultValueIsObject = _.isObject(defaultValue) and not _.isArray(defaultValue)
+      if valueIsObject and defaultValueIsObject
+        _.defaults(value, defaultValue)
     else
       value = _.deepClone(defaultValue)


chore (Module) require latest version to have been published before installing

--- src/steroids/module/commands/install.coffee
+++ src/steroids/module/commands/install.coffee
@@ -19,7 +19,9 @@
       Please run again with the target module name as an argument.
     """

-  moduleApi.repository.findByName(args.moduleName)
+  moduleApi.repository
+    .findByName(args.moduleName)
+    .then(getLatestVersionZipUrl)
     .catch((e) ->
       throw new Error """
         Module '#{args.moduleName}' is not published in the repository.
@@ -27,13 +29,15 @@
     )
     .tap (module) ->
       console.log "About to install #{module.namespace}..."
-    .then(getLatestVersionZipUrl)
     .then(installModule getModuleInstallationTargetDir args.moduleName)
     .then ->
       log.ok "Module installation complete."

 getLatestVersionZipUrl = (module) ->
   [ latestVersion ] = module.versions
+
+  if !latestVersion.published
+    throw new Error "No published version of module available"

   moduleZipUrl = latestVersion.source


Add unit tests for robot.http

Add unit tests for robot.http

--- test/robot_test.coffee
+++ test/robot_test.coffee
@@ -11,6 +11,8 @@
 Robot = require '../src/robot.coffee'
 { CatchAllMessage, EnterMessage, TextMessage } = require '../src/message'
 Adapter = require '../src/adapter'
+
+ScopedHttpClient = require 'scoped-http-client'

 # Preload the Hubot mock adapter but substitute in the latest version of Adapter
 mockery.enable()
@@ -40,6 +42,25 @@
    @robot.shutdown()

   describe 'Unit Tests', ->
+    describe '#http', ->
+      beforeEach ->
+        url = 'http://localhost'
+        @httpClient = @robot.http(url)
+
+      it 'creates a new ScopedHttpClient', ->
+        # 'instanceOf' check doesn't work here due to the design of
+        # ScopedHttpClient
+        expect(@httpClient).to.have.property('get')
+        expect(@httpClient).to.have.property('post')
+
+      it 'passes options through to the ScopedHttpClient', ->
+        agent = {}
+        httpClient = @robot.http('http://localhost', agent: agent)
+        expect(httpClient.options.agent).to.equal(agent)
+
+      it 'sets a sane user agent', ->
+        expect(@httpClient.options.headers['User-Agent']).to.contain('Hubot')
+
     describe '#receive', ->
       it 'calls all registered listeners', ->
         # Need to use a real Message so that the CatchAllMessage constructor works