FIX: save edit changes when unmount

FIX: save edit changes when unmount

--- client/app/components/compose.coffee
+++ client/app/components/compose.coffee
@@ -54,6 +54,10 @@
         !!nextProps.accounts

     render: ->
+        # Each render do not send data to server
+        # update date for client modifications
+        @state.date = new Date().toISOString()
+
         closeUrl = @buildClosePanelUrl @props.layout

         classLabel = 'compose-label'
@@ -243,7 +247,7 @@
                 @setState focus: ''

     showModal: (params, success) ->
-        return unless @state.originalConversationID
+        return if @isNew()

         doDelete = =>
             messageID = @state.id
@@ -270,8 +274,7 @@
                 cid = message.conversationID
                 MessageActionCreator.fetchConversation cid

-
-        if @props.lastUpdate is @state.date
+        unless (hasChanged = @props.lastUpdate isnt @state.date)
             message = @state
             error = null
             setTimeout ->
@@ -279,28 +282,25 @@
             , 0
             return

-
-        doSave = =>
-            LayoutActionCreator.hideModal()
-            MessageActionCreator.send @state, (error, message) ->
-                if error? or not message?
-                    msg = "#{t "message action draft ko"} #{error}"
-                    LayoutActionCreator.alertError msg
-                    success error, message
-                    return
-
-                success error, message
-
+        # Show Modal
         init = =>
             @showModal
                 title       : t 'app confirm delete'
                 subtitle    : t 'compose confirm keep draft'
                 closeLabel  : t 'compose confirm draft keep'
                 actionLabel : t 'compose confirm draft delete'
-                closeModal  : doSave
+                closeModal  : =>
+                    LayoutActionCreator.hideModal()
+                    MessageActionCreator.send @state, (error, message) ->
+                        if error? or not message?
+                            msg = "#{t "message action draft ko"} #{error}"
+                            LayoutActionCreator.alertError msg
+                            success error, message
+                            return
+
+                        success error, message

         setTimeout init, 0
-

     getInitialState: ->
         MessageUtils.makeReplyMessage @props
@@ -331,11 +331,9 @@
             success() if _.isFunction success
             return

-        message = _.clone @state
-
         @props.isSaving = true
-        @props.lastUpdate = message.date
-        MessageActionCreator.send message, (error, message) =>
+        @props.lastUpdate = @state.date
+        MessageActionCreator.send @state, (error, message) =>
             if error? or not message?
                 if @state.isDraft
                     msgKo = t "message action draft ko"


fix lowercase namespace

fix lowercase namespace

--- lib/namespace.coffee
+++ lib/namespace.coffee
@@ -7,6 +7,7 @@
 # can be inserted in them such as `Posts.destroy()`

 fs = require "fs-extra"
+parseName = require './parse_name'

 class Namespace
   nsFile: "both/lib/namespaces.js",
@@ -28,6 +29,7 @@
   # resName - The {String} name of the resource, eg `posts`
   #
   add: (resName) ->
+    resName = parseName(resName).pascalPlural
     namespace = "#{resName} = {}\n"
     nsFileStr = fs.readFileSync(@nsFile, {encoding: "utf-8"})
     namespaceExists = nsFileStr.match(namespace)


Clean synthax + remove useless attributes

--- client/app/components/file_picker.coffee
+++ client/app/components/file_picker.coffee
@@ -226,10 +226,8 @@
         li className: "file-item", key: @props.key,
             i className: "mime #{type} fa #{iconClass}"
             a
-                className: 'file-name',
-                target: '_blank',
-                onClick: @doDisplay,
-                href: file.url
+                'className': 'file-name'
+                'onClick': @doDisplay
                 'data-file-url': file.url
                 'data-file-name': file.generatedFileName
                 'data-file-type': file.contentType


ChatPane: Disable chat settings pane.

ChatPane: Disable chat settings pane.

--- client/ide/views/chat/messagepane.coffee
+++ client/ide/views/chat/messagepane.coffee
@@ -101,9 +101,9 @@
       cssClass   : 'workspace-name'
       partial    : 'My Workspace'
       attributes : href : '#'
-      click      : (event) =>
-        KD.utils.stopDOMEvent event
-        @getDelegate().showSettingsPane()
+      # click      : (event) =>
+      #   KD.utils.stopDOMEvent event
+      #   @getDelegate().showSettingsPane()

     appManager.tell 'IDE', 'getWorkspaceName', @title.bound 'updatePartial'

@@ -136,7 +136,7 @@

     menu =
       'Search'     : cssClass : 'disabled', callback: noop
-      'Settings'   : callback : @getDelegate().bound 'showSettingsPane'
+      # 'Settings'   : callback : @getDelegate().bound 'showSettingsPane'
       'Minimize'   : callback : @getDelegate().bound 'end'
       'Learn More' : separator: yes, callback : -> KD.utils.createExternalLink 'http://learn.koding.com/collaboration'


Set left as number without px suffix

Set left as number without px suffix

--- lib/wrap-guide-view.coffee
+++ lib/wrap-guide-view.coffee
@@ -38,7 +38,7 @@
     if column > 0
       columnWidth = @editor.charWidth * column
       if columnWidth < @editor.layerMinWidth or columnWidth < @editor.width()
-        @css('left', "#{columnWidth}px").show()
+        @css('left', columnWidth).show()
       else
         @hide()
     else


Alias assign globally

Alias assign globally

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -294,7 +294,6 @@
 class Observable
   constructor: (desc) ->
     @id = ++idCounter
-    @assign = @onValue
     withDescription(desc, this)
   onValue: ->
     f = makeFunctionArgs(arguments)
@@ -508,6 +507,7 @@
     describe(arguments...).apply(this)

 Observable :: reduce = Observable :: fold
+Observable :: assign = Observable :: onValue

 flatMap_ = (root, f, firstOnly) ->
   new EventStream describe(root, "flatMap" + (if firstOnly then "First" else ""), f), (sink) ->


add Bacon.spy

add Bacon.spy

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -80,6 +80,19 @@
 Bacon.repeatedly = (delay, values) ->
   index = 0
   Bacon.fromPoll(delay, -> values[index++ % values.length])
+
+Bacon.spy = (spy) -> spys.push(spy)
+
+spys = []
+registerObs = (obs) ->
+  if spys.length
+    if not registerObs.running
+      try
+        registerObs.running = true
+        _.each spys, (_, spy) ->
+          spy(obs)
+      finally
+        delete registerObs.running

 withMethodCallSupport = (wrapped) ->
   (f, args...) ->
@@ -487,6 +500,7 @@
     @subscribe = dispatcher.subscribe
     @subscribeInternal = @subscribe
     @hasSubscribers = dispatcher.hasSubscribers
+    registerObs(this)
   delay: (delay) ->
     @flatMap (value) ->
       Bacon.later delay, value
@@ -680,6 +694,7 @@
       ->
         reply = Bacon.noMore
         unsub()
+    registerObs(this)

   sample: (interval) =>
     @sampledBy Bacon.interval(interval, {})


adiciona a propriedade visible na mensagem para cudar dos templates de modal customizados e verfica a mesma na remoção da mensagem do DOM

--- src/script/vtex-message.coffee
+++ src/script/vtex-message.coffee
@@ -28,7 +28,8 @@
         title: ''
         detail: ''
       close: 'Close'
-      type: 'info'
+      type: 'info' # possible types are: ['success', 'info', 'warning', 'danger', 'fatal', 'error']
+      visible: true
       usingModal: false
       domElement: $()
       insertMethod: 'append'
@@ -99,6 +100,7 @@
     # Adiciona o Elemento no DOM
     if @usingModal
       $(@domElement).on 'hidden', =>
+        @visible = false
         $(window).trigger('removeMessage.vtex', @)
       $(vtex.Messages.getInstance().modalPlaceholder).append(@domElement)
     else
@@ -118,16 +120,19 @@
       flagVisibleSet = false
       for modal in $('.modal.' + @classes.MESSAGEINSTANCE)
         modalData = $(modal).data('vtex-message')
-        if modalData.domElement[0] isnt @domElement[0]
+        if (modalData.domElement[0] isnt @domElement[0]) and (modalData.visible is true)
           flagVisibleSet = true
           $(modal).one 'hidden', =>
             $(@domElement).modal('show')
+            @visible = true

       if not flagVisibleSet
+        $(@domElement).on 'show', => @visible = true
         $(@domElement).modal('show')

     if !@usingModal
       @domElement.show()
+      @visible = true
       # se necessário, cria timer para a mensagem
       if @.timeout? and @.timeout isnt 0
         window.setTimeout =>
@@ -144,6 +149,7 @@
       @domElement.modal('hide')
     if !@usingModal
       @domElement.hide()
+      @visible = false
     $(window).trigger('removeMessage.vtex', @)

 ###
@@ -204,8 +210,9 @@
       for i in [@messagesArray.length - 1..0] by -1
         currentMessage = @messagesArray[i]
         if (currentMessage.id is message.id)
-          currentMessage.domElement.remove()
           @messagesArray.splice(i,1)
+          if !message.usingModal
+            currentMessage.domElement.remove()
       @.changeContainerVisibility()

     ###


do not show ajax on non boorgle ajax (like pubnub)

--- app/index.coffee
+++ app/index.coffee
@@ -79,7 +79,8 @@

   setupAJAX: ->
     el = $('

').prependTo($('body'))
-    el.ajaxStart( ->
+    el.ajaxSend( (e, xhr, options) ->
+      return unless options.url.match(Spine.Model.host)
       el.show()
     ).ajaxStop( =>
       el.hide()


removed whitespaces

removed whitespaces

--- client/app/lib/terminal/webtermview.coffee
+++ client/app/lib/terminal/webtermview.coffee
@@ -298,8 +298,8 @@

   ringBell: do (bell = try new Audio '/a/audio/bell.wav') -> (event) ->
-      event?.preventDefault()
-
-      if not bell? or @terminal.controlCodeReader.visualBell
-      then new KDNotificationView title: 'Bell!', duration: 100
-      else bell.play()
+    event?.preventDefault()
+
+    if not bell? or @terminal.controlCodeReader.visualBell
+    then new KDNotificationView title: 'Bell!', duration: 100
+    else bell.play()


clean config application change related to icon

--- client/app/views/config_application.coffee
+++ client/app/views/config_application.coffee
@@ -29,10 +29,12 @@
         @id = "app-btn-#{options.model.id}"
         super

+
     initialize: ->
         # only re-render when 'version' changes, because it's the only displayed
         # field that can change during the update
         @listenTo @model, 'change:version', @render
+

     afterRender: =>
         @updateButton = new ColorButton @$ ".update-app"
@@ -45,10 +47,15 @@

         @listenTo @model, 'change', @onAppChanged
         @onAppChanged @model
-
         @icon = @$ '.icon'
+
+        @setIcon()
+
+
+    # Build icon from model information (depending of icon format and model
+    # name).
+    setIcon: ->
         if @model.isIconSvg()
-            @setBackgroundColor()
             extension = 'svg'
             @icon.addClass 'svg'
         else
@@ -57,16 +64,12 @@

         @icon.attr 'src', "api/applications/#{@model.get 'slug'}.#{extension}"

-        @setBackgroundColor()
-
-
-    setBackgroundColor: ->
         slug = @model.get 'slug'
         color = @model.get 'color'
         unless color?
             color = hashColor = ColorHash.getColor slug, 'cozy'
             # By default, look for the color in the market.
-            #color = @inMarket?.get('color') or hashColor
+            # color = @inMarket?.get('color') or hashColor
         @color = color
         @icon.css 'background-color', color


Better sync store encrypt/decrypt

Better sync store encrypt/decrypt

--- app/src/storage/synced_store.coffee
+++ app/src/storage/synced_store.coffee
@@ -26,7 +26,6 @@
   constructor: (name, addr, key, auxiliaryStore = ledger.storage.wallet) ->
     super(name)
     @_secureStore = new ledger.storage.SecureStore(name, key)
-    @_aes = @_secureStore._aes
     @mergeStrategy = @_overwriteStrategy
     @client = ledger.api.SyncRestClient.instance(addr)
     @throttled_pull = _.throttle _.bind((-> @._pull()),@), @PULL_THROTTLE_DELAY, trailing: no
@@ -255,9 +254,9 @@

   _encryptToJson: (data) ->
     data = _(data).chain().pairs().sort().object().value()
-    '{' + (JSON.stringify(@_aes.encrypt(key)) + ':' + JSON.stringify(@_aes.encrypt(value)) for key, value of data).join(',') + '}'
+    '{' + (JSON.stringify(@_secureStore._preprocessKey(key)) + ':' + JSON.stringify(@_secureStore._preprocessValue(value)) for key, value of data).join(',') + '}'

   _decrypt: (data) ->
     out = {}
-    out[@_aes.decrypt(key)] = @_aes.decrypt(value) for key, value of data
+    out[@_secureStore._deprocessKey(key)] = @_secureStore._deprocessValue(value) for key, value of data
     out


sync2: set string hash whenever updating file from disk, so that save button has proper state.

--- src/smc-util/syncstring.coffee
+++ src/smc-util/syncstring.coffee
@@ -587,6 +587,8 @@
                 else
                     dbg("got it")
                     @set(data)
+                    # we also know that this is the version on disk, so we update the hash
+                    @_set_save(state:'done', error:false, hash:misc.hash_string(data))
                     @_save(cb)

     _set_save: (x) =>


ShellOptionsView: added missing requires

--- coffee/src/views/shell_options_view.coffee
+++ coffee/src/views/shell_options_view.coffee
@@ -1,5 +1,7 @@
 goog.provide 'acorn.player.ShellOptionsView'

+goog.require 'acorn.shells.Registry'
+goog.require 'acorn.shells.Shell'
 goog.require 'acorn.player.DropdownView'

 # acorn player ShellOptionsView:


npm2nix: Generate all dependencies of the passed package too

--- npm2nix.coffee
+++ npm2nix.coffee
@@ -1,40 +1,40 @@
 #!/usr/bin/env coffee
 http = require 'http'
-util = require 'util'
 crypto = require 'crypto'

-name = process.argv[2]
+generated = {}

-version = process.argv[3] ? "latest"
+generateExpr = (name, version) ->
+   generated[name + "-" + version] = true
+   http.get "http://registry.npmjs.org/#{name}", (res) ->
+    res.setEncoding()
+    val = ""
+    res.on 'data', (chunk) ->
+      val += chunk
+    res.on 'end', ->
+      pkginfo = JSON.parse val
+      version = pkginfo['dist-tags'].stable ? pkginfo['dist-tags'].latest if version is "*"
+      deps = pkginfo.versions[version].dependencies ? {}
+      (generateExpr(nm, ver) unless generated[nm + "-" + ver]?) for nm, ver of deps
+      http.get "http://registry.npmjs.org/#{name}/-/#{name}-#{version}.tgz", (res) ->
+        hash = crypto.createHash 'sha256'
+        res.on 'data', (chunk) ->
+          hash.update chunk
+        res.on 'end', ->
+          console.log """
+            #{}  "#{name}" = self."#{name}-#{version}";

-deps = []
+              "#{name}-#{version}" = buildNodePackage rec {
+                name = "#{name}-#{version}";
+                src = fetchurl {
+                  url = "http://registry.npmjs.org/#{name}/-/${name}.tgz";
+                  sha256 = "#{hash.digest('hex')}";
+                };
+                deps = [
+            #{("      self.\"#{dep}#{if ver is "*" then "" else "-#{ver}"}\"" for dep, ver of deps).join "\n"}
+                ];
+              };

-hash = crypto.createHash 'sha256'
+          """

-http.get "http://registry.npmjs.org/#{name}", (res) ->
-  res.setEncoding()
-  val = ""
-  res.on 'data', (chunk) ->
-    val += chunk
-  res.on 'end', ->
-    pkginfo = JSON.parse val
-    version = pkginfo['dist-tags'].stable ? pkginfo['dist-tags'].latest if version is "latest"
-    http.get "http://registry.npmjs.org/#{name}/-/#{name}-#{version}.tgz", (res) ->
-      res.on 'data', (chunk) ->
-        hash.update chunk
-      res.on 'end', ->
-        process.stdout.write """
-                             #{}  "#{name}" = self."#{name}-#{version}";
-
-                               "#{name}-#{version}" = buildNodePackage rec {
-                                 name = "#{name}-#{version}";
-                                 src = fetchurl {
-                                   url = "http://registry.npmjs.org/#{name}/-/${name}.tgz";
-                                   sha256 = "#{hash.digest('hex')}";
-                                 };
-                                 deps = [
-                             #{("      self.\"#{dep}#{if ver is "*" then "" else "-#{ver}"}\"" for dep, ver of deps).join "\n"}
-                                 ];
-                               };
-                             """
-    deps = pkginfo.versions[version].dependencies ? {}
+generateExpr process.argv[2], process.argv[3] ? "*"


Enhance test data to cover empty attachment object case.

--- src/spec/elasticio.spec.coffee
+++ src/spec/elasticio.spec.coffee
@@ -49,6 +49,7 @@
       sphereProjectKey: Config.config.project_key

     msg =
+      attachments: {}
       body:
         SKU: 'mySKU'
         QUANTITY: 7


:art: use constant EXPORTED as

:art: use constant EXPORTED as

--- src/flux/performance-export.coffee
+++ src/flux/performance-export.coffee
@@ -5,7 +5,7 @@

 EXPORTING = 'exporting'
 EXPORT_QUEUED = 'export_queued'
-EXPORTED = 'exported'
+EXPORTED = 'completed'

 PerformanceExportConfig = {

@@ -58,7 +58,7 @@
       jobId ?= _.last(@_getJobs(id))
       job = JobStore.get(jobId)
       {state} = job if job?
-      state is 'completed'
+      state is EXPORTED

     getLatestExport: (id) ->
       perfExports = @_get(id)


server: added an invalid line

server: added an invalid line

--- servers/lib/server/handlers/invitetoteambycsv.test.coffee
+++ servers/lib/server/handlers/invitetoteambycsv.test.coffee
@@ -65,6 +65,7 @@

 brokenFile = """
+  this is not an valid line that contains email
   cihangir1@koding.com,   cihangir1,savas1  ,admin
   cihangir2@koding.com,,savas2,
   cihangir3@koding.com,cihangir3,


Changed App Message

Changed App Message

--- app/views.coffee
+++ app/views.coffee
@@ -305,7 +305,7 @@
   pistachio: ->
     """
     <h1 style="font-size: 90px; text-align: center; margin-top: 80px;">
-      Your App Here
+      Load your App
     </h1>
     """


Atom config updates

Atom config updates

--- atom/config.cson
+++ atom/config.cson
@@ -214,6 +214,7 @@
       pullOption: "hg pull"
       showCommitInfoViewInline: false
       showTools: true
+      syncMessagesToPhabricator: false
     "fb-java":
       autoBuild: false
       autoFold: true
@@ -499,6 +500,18 @@
             cwd: "/data/users/cmcginty/configerator"
             displayTitle: "configerator"
             pathToPrivateKey: ""
+            remoteServerCommand: ""
+            server: "our.cmcginty.sb.facebook.com"
+            sshPort: "22"
+            username: "cmcginty"
+          saveable: true
+        }
+        {
+          deletable: true
+          displayTitle: "configerator-dsi"
+          params:
+            cwd: "/home/cmcginty/configerator-dsi"
+            displayTitle: "configerator-dsi"
             remoteServerCommand: ""
             server: "our.cmcginty.sb.facebook.com"
             sshPort: "22"


chore: update atom config

chore: update atom config

--- atom/config.cson
+++ atom/config.cson
@@ -83,6 +83,10 @@
     crActive: false
     eolActive: false
     spaceActive: false
+  docblockr:
+    indentation_spaces: 2
+    indentation_spaces_same_para: 0
+    simple_mode: true
   editor:
     backUpBeforeSaving: true
     fontFamily: "Fantasque Sans Mono"
@@ -175,6 +179,8 @@
   "slim-dark-ui":
     layoutMode: "Compact"
   "status-bar": {}
+  "svg-preview":
+    openPreviewAutomatically: true
   tabs:
     showIcons: true
     usePreviewTabs: true


Undo some find/replace settings

Undo some find/replace settings

They didn’t work quite like I wanted

--- atom/config.cson
+++ atom/config.cson
@@ -27,8 +27,6 @@
     userId: "30e6f2d0-42d3-ab77-4984-dde4c431f019"
   "expand-region": {}
   "find-and-replace":
-    closeFindPanelAfterSearch: true
-    focusEditorAfterSearch: true
     scrollToResultOnLiveSearch: true
   "git-blame": {}
   "git-diff":


Update config.cson for Atom

Update config.cson for Atom

--- atom/config.cson
+++ atom/config.cson
@@ -1,47 +1,44 @@
-'global':
-  'core':
-    'hideGitIgnoredFiles': true
-    'ignoredNames': [
-      '.DS_Store'
-      '.git'
-      'vendor'
+"*":
+  core:
+    ignoredNames: [
+      ".DS_Store"
+      ".git"
+      "vendor"
     ]
-    'themes': [
-      'atom-dark-ui'
-      'solarized-dark-syntax'
+    disabledPackages: [
+      "center-line"
+      "branch-status"
+      "open-in-atom"
+      "terminal"
     ]
-    'disabledPackages': [
-      'center-line'
-      'branch-status'
-      'open-in-atom'
-      'terminal'
+    themes: [
+      "atom-dark-ui"
+      "solarized-dark-syntax"
     ]
-    'destroyEmptyPanes': false
-    'useReactEditor': true
-  'editor':
-    'hideGitIgnoredFiles': true
-    'normalizeIndentOnPaste': false
-    'scrollPastEnd': true
-    'autoIndentOnPaste': false
-    'fontSize': 13
-  'spell-check':
-    'grammars': [
-      'text.plain'
-      'source.gfm'
-      'text.git-commit'
+    destroyEmptyPanes: false
+  editor:
+    fontSize: 13
+    autoIndentOnPaste: false
+    scrollPastEnd: true
+    invisibles: {}
+  "spell-check":
+    grammars: [
+      "text.plain"
+      "source.gfm"
+      "text.git-commit"
     ]
-  'welcome':
-    'showOnStartup': false
-  'find-and-replace':
-    'openProjectFindResultsInRightPane': true
-  'wrap-guide':
-    'columns': [
+  welcome:
+    showOnStartup: false
+  "find-and-replace":
+    openProjectFindResultsInRightPane: true
+  "wrap-guide":
+    columns: [
       {
-        'pattern': 'COMMIT_EDITMSG'
-        'column': 72
+        pattern: "COMMIT_EDITMSG"
+        column: 72
       }
     ]
-  'autocomplete':
-    'includeCompletionsFromAllBuffers': true
-  'merge-conflicts':
-    'gitPath': 'bin/git'
+  autocomplete:
+    includeCompletionsFromAllBuffers: true
+  "merge-conflicts":
+    gitPath: "bin/git"


Update config.cson for Atom

Update config.cson for Atom

--- atom/config.cson
+++ atom/config.cson
@@ -35,5 +35,5 @@
   ]
 'autocomplete':
   'includeCompletionsFromAllBuffers': true
-'release-notes':
-  'viewedVersion': '0.78.0'
+'scroll-past-end':
+  'retainHalfScreen': true


Cleaned the config

Cleaned the config

--- atom/config.cson
+++ atom/config.cson
@@ -1,10 +1,11 @@
 "*":
   "atom-terminal":
     app: "/usr/bin/konsole"
+  "autocomplete-plus":
+    confirmCompletion: "enter"
   core:
     disabledPackages: [
-      "atom-terminal-panel"
-      "terminal-status"
+      "autocomplete-snippets"
     ]
     packagesWithKeymapsDisabled: [
       "highlight-line"


ingore some atom plugins

ingore some atom plugins

--- atom/config.cson
+++ atom/config.cson
@@ -16,6 +16,8 @@
       "ruby-test"
       "seeing-is-believing"
       "unity-ui"
+      "atom-beautify"
+      "script"
     ]
     themes: [
       "seti-ui"


Update keymaps to retain Atom's pre-1.6 funtionality

/cc https://github.com/atom/atom/pull/7953

--- atom/keymap.cson
+++ atom/keymap.cson
@@ -4,8 +4,8 @@
   'ctrl-k': 'window:focus-pane-above'
   'ctrl-l': 'window:focus-pane-on-right'

-  'ctrl-|': 'pane:split-right'
-  'ctrl--': 'pane:split-down'
+  'ctrl-|': 'pane:split-right-and-copy-active-item'
+  'ctrl--': 'pane:split-down-and-copy-active-item'

 'atom-workspace atom-text-editor:not(.mini)':
   'ctrl-;': 'editor:delete-to-end-of-line'


Account: removed unnecessary methods for static pages

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -333,56 +333,6 @@
       else JPermissionSet.wrapPermission permission
     JPermissionSet.checkPermission client, advanced, target, callback

-  setBackgroundImage: secure (client, type, value, callback=->)->
-    {delegate}    = client.connection
-    isMine        = @equals delegate
-    if isMine
-      if type is 'customImage'
-        operation =
-          $set: {}
-          $addToSet : {}
-        operation.$addToSet['profile.staticPage.customize.background.customImages'] = value
-      else
-        operation = $set : {}
-
-      operation.$set["profile.staticPage.customize.background.customType"] = type
-
-      if type in ['defaultImage','defaultColor','customColor','customImage']
-        operation.$set["profile.staticPage.customize.background.customValue"] = value
-
-
-      @update operation, callback
-
-  setAbout: secure (client, text, callback)->
-    {delegate} = client.connection
-    isMine      = @equals delegate
-    if isMine
-      @fetchAbout (err, about)=>
-        console.log err if err
-        unless about
-          JMarkdownDoc = require './markdowndoc'
-          about        = new JMarkdownDoc content: text
-
-          daisy queue = [
-            ->
-              about.save (err)->
-                console.log err
-                if err then callback err
-                else queue.next()
-            =>
-              @addAbout about, (err)->
-                console.log err
-                if err then callback err
-                else queue.next()
-            ->
-              callback null, about
-          ]
-
-        else
-          about.update $set:{ content: text }, (err)=>
-            if err then callback err
-            else callback null, about
-
   @renderHomepage: require '../render/profile.coffee'

   @fetchCachedUserCount: (callback)->
@@ -413,63 +363,6 @@
       @update operation, callback
     else
       callback? new KodingError 'Access denied'
-
-  setStaticPageTitle: secure (client, title, callback)->
-    {delegate}  = client.connection
-    selector    = "profile.staticPage.title"
-    isMine      = @equals delegate
-    if isMine
-      operation = $set: {}
-      operation.$set[selector] = title
-      @update operation, callback
-    else
-      callback? new KodingError 'Access denied'
-
-  setStaticPageAbout: secure (client, about, callback)->
-    {delegate} = client.connection
-    selector   = "profile.staticPage.about"
-    isMine     = @equals delegate
-    if isMine
-      operation = $set: {}
-      operation.$set[selector] = about
-      @update operation, callback
-    else
-      callback? new KodingError 'Access denied'
-
-
-  addStaticPageType: secure (client, type, callback)->
-    {delegate} = client.connection
-    isMine     = @equals delegate
-    if isMine
-      @update {$addToSet: 'profile.staticPage.showTypes': type}, callback
-    else
-      callback? new KodingError 'Access denied'
-
-  # addStaticBackground: secure (client, url, callback)->
-  #   {delegate}    = client.connection
-  #   isMine        = @equals delegate
-  #   if isMine
-  #     @update {$addToSet: 'profile.staticPage.backgrounds': url}, callback
-  #   else
-  #     callback? new KodingError 'Access denied'
-
-  removeStaticPageType: secure (client, type, callback)->
-    {delegate} = client.connection
-    isMine     = @equals delegate
-    if isMine
-      @update {$pullAll: 'profile.staticPage.showTypes': [type]}, callback
-    else
-      callback? new KodingError 'Access denied'
-
-
-  setStaticPageVisibility: secure (client, visible=yes, callback)->
-    {delegate} = client.connection
-    isMine     = @equals delegate
-    if isMine
-      @update ($set: 'profile.staticPage.show': visible), callback
-    else
-      callback? new KodingError 'Access denied'
-

   fetchGroups: secure (client, callback)->
     JGroup        = require './group'


SocialWorker: modify createOrFetchAppStorage method according to new schema

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -913,26 +913,23 @@

   fetchOrCreateAppStorage: (options, callback) ->
     { appId, version } = options
-    @fetchAppStorage { 'data.appId':appId, 'data.version':version }, (err, storage) =>
+
+    query = { accountId : @getId() }
+    query["storage.#{appId}.version"] = version
+
+    JAppStorage.one query, (err, storage) =>
       if err then callback err
       else unless storage?
-        # log.info 'Creating new storage:', appId, version, @profile.nickname
-        newStorage = new JAppStorage { appId, version }
-        newStorage.save (err) =>
+        version               ?= '1.0'
+        options                = { accountId : @getId(), storage : {} }
+        options.storage[appId] = { version, data : {} }
+        newStorage             = new JAppStorage options
+        newStorage.save (err) ->
           if err then callback err
-          else
-            # manually add the relationship so that we can
-            # query the edge instead of the target C.T.
-            rel = new Relationship
-              targetId    : newStorage.getId()
-              targetName  : 'JAppStorage'
-              sourceId    : @getId()
-              sourceName  : 'JAccount'
-              as          : 'appStorage'
-              data        : { appId, version }
-            rel.save (err) -> callback err, newStorage
+          callback null, newStorage
       else
         callback err, storage
+

   fetchAppStorage$: secure (client, options, callback) ->


SocialWorker: check delegate existance

SocialWorker: check delegate existance

--- workers/social/lib/social/models/datadog.coffee
+++ workers/social/lib/social/models/datadog.coffee
@@ -128,6 +128,9 @@

     { connection: { delegate } } = client

+    unless delegate
+      return callback new KodingError 'Account not found'
+
     unless delegate.type is 'registered'
       return callback new KodingError 'Not allowed'


session: add createNewSession method

session: add createNewSession method

--- workers/social/lib/social/models/session.coffee
+++ workers/social/lib/social/models/session.coffee
@@ -75,6 +75,14 @@
         else callback null, { session, account }

+  @createNewSession = (username, callback) ->
+    clientId = createId()
+
+    session = new JSession { clientId, username }
+    session.save (err) ->
+      return callback err  if err
+      return callback null, session
+
   @fetchSession = (clientId, callback)->

     return @createSession callback  unless clientId


Profile: removed an old chunk of code

Profile: removed an old chunk of code

--- workers/social/lib/social/render/profile.coffee
+++ workers/social/lib/social/render/profile.coffee
@@ -1,15 +1,4 @@
-addHomeLinkBar = ->
-  slug = 'koding'
-  """
-

-

-

-      Learn more...Request an InviteRegisterLogin
-

-

-  """
-
-module.exports = (options, callback)->
+module.exports = (options, callback) ->

   getStyles    = require './styleblock'
   fetchScripts = require './scriptblock'


allow options file to turn off caching

allow options file to turn off caching

--- plugin/browserify.coffee
+++ plugin/browserify.coffee
@@ -12,7 +12,7 @@
 fs = Npm.require 'fs'

 processFile = (step) ->
-
+
   # check for extension as filename
   checkFilename step

@@ -49,11 +49,13 @@
   try # try-catch for browserify errors

     # get browserify result from either the cache or processing
-    string = getResult step, bundle
+    string = getResult step, bundle, browserifyOptions?.cache

     # read the generated source map from the file
     sourceMap = fs.readFileSync mapFileName, encoding:'utf8'
-    # leave source map file so it's cached
+    # delete source map file only when caching is off
+    # otherwise leave it "cached"
+    if browserifyOptions?.cache is false then fs.unlinkSync mapFileName

     # now that we have the compiled result as a string we can add it using CompileStep
     # inside try-catch because this shouldn't run when there's an error.
@@ -226,19 +228,33 @@
   return readable

 # get compile result via cache or compiling
-getResult = (step, bundle) ->
-  cacheFileName = step.fullInputPath + '.cached'
-  compileChanges = checkFileChanges step, cacheFileName
-
-  if compileChanges
-    # call our wrapped function with the readable stream as its argument
-    string = getString bundle #wrappedFn bundle
-
-    # write result to a cache file
-    fs.writeFileSync cacheFileName, string
-
-  else
-    string = fs.readFileSync cacheFileName, encoding:'utf8'
+# step : CompileStep
+# bundle: the Browserify made readable stream
+# useCache: true by default, specifies whether caching will be used
+getResult = (step, bundle, useCache = true) ->
+
+  # TODO: getString line is in there twice. revise to eliminate duplication?
+
+  # if caching isn't turned off in options
+  if useCache
+    console.log '\n  caching is ON\n'
+    cacheFileName = step.fullInputPath + '.cached'
+    # checks if files have changed or we don't have cached values
+    compileChanges = checkFileChanges step, cacheFileName
+
+    if compileChanges
+      # call our wrapped function with the readable stream as its argument
+      string = getString bundle
+
+      # write result to a cache file
+      fs.writeFileSync cacheFileName, string
+
+    else # read the cached file instead
+      string = fs.readFileSync cacheFileName, encoding:'utf8'
+
+  else # call our wrapped function with the readable stream as its argument
+    console.log '\n  caching is off\n'
+    string = getString bundle

   return string


fix soundcloud

fix soundcloud

--- app/assets/javascripts/profile.js.coffee
+++ app/assets/javascripts/profile.js.coffee
@@ -47,7 +47,7 @@
   getClientID = () ->
     switch (window.location.hostname)
       when "127.0.0.1" then return "ee3d987c0fa30e22edd251a7bd046851"
-      when "ocelots-staging.herokuapp.com" then return "40d2c306162dcea94436672679aa6c25z"
+      when "ocelots-staging.herokuapp.com" then return "40d2c306162dcea94436672679aa6c25"
       when "iocelots.com" then return "bdb756070f00205c76a9563eafe8ca09"

   SC.initialize {


Fix scroll position issues in FF and Safari

--- app/assets/javascripts/utils/router.cjsx
+++ app/assets/javascripts/utils/router.cjsx
@@ -36,6 +36,21 @@

 history = useBasename(createHistory)(basename: '/')

+# Handle scroll position for back button, hashes, and normal links
+history.listen (location) =>
+  setTimeout () =>
+    if location.action == 'POP'
+      return
+    hash = window.location.hash
+    if hash
+      element = document.querySelector(hash)
+      if element
+        element.scrollIntoView
+          block: 'start'
+          behavior: 'smooth'
+    else
+      window.scrollTo 0, 0
+
 routes = (
   <Route path='/' component={App}>
     <Route path='onboarding' component={Onboarding.Root}>
@@ -73,7 +88,7 @@

 el = document.getElementById('react_root')
 render((
-  <Router onUpdate={() => window.scrollTo(0, 0)} history={history}>
+  <Router history={history}>
     {routes}
   </Router>
 ), el) if el?


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/animation.coffee
+++ test/animation.coffee
@@ -1,15 +1,10 @@
-test "Animation should default to first frame", ->
-  animation = Animation.fromPixieId 45
-
-  equals animation.active(), 0
-
 asyncTest "Animation should default to first frame", ->
   animation = Animation.fromPixieId 45

   milliseconds = 300

   setTimeout ->
-    equals(animation.active(), 0)
+    equals animation.active(), 0

     start()
   , milliseconds


resolve itinerary polyline cleanup bugs, fixes #70 again

remove old itineraries before fetching new ones. BOOMDONE!

--- app/assets/transit/lib/views/plan.coffee
+++ app/assets/transit/lib/views/plan.coffee
@@ -1,7 +1,6 @@
 class Transit.Views.Plan extends Backbone.View
   template: JST['templates/plan']
-  # el: "#navigation"
-  # tagName: 'div'
+
   className: 'plan'

   events:
@@ -35,10 +34,6 @@

   # update the plan when markers are dragged
   update_plan: =>
-    console.log "UPDATING PLAN..."
-    # clean up the existing views when markers are dragged
-    view.clean_up(true) for view in @views
-
     # set the model from/to locations from the marker positions
     @model.set
       from: @map.get('from').position.toHash()
@@ -52,6 +47,8 @@

   fetch_plan: =>
     @render()
+    # remove old itineraries from the map before fetching new ones
+    @remove_itineraries()
     # move the from/to markers to geocoded locations
     Transit.map.moveMarker 'from', @model.get('from')
     Transit.map.moveMarker 'to', @model.get('to')
@@ -69,7 +66,6 @@

   display_trip_options: =>
     @$('form.options').slideToggle()
-    console.log 'showing popover'

   change_trip_options: (event) =>
     event.preventDefault()
@@ -111,6 +107,9 @@
       view
     @fit_bounds()

+  # remove all itineraries from the map
+  remove_itineraries: =>
+    view?.clean_up(true) for view in @views if @views?

   fit_bounds: =>
     if @map.get('fit_bounds')


Spacing

Spacing

--- app/frontend/scripts/templates.js.coffee
+++ app/frontend/scripts/templates.js.coffee
@@ -35,18 +35,14 @@
 """

 templates.now_playing = """
-

{{name}}

by {{{artist_tag}}}

from {{{album_tag}}}

-
   {{>star}}
   {{>download_song}}
-
-

   {{{art_tag}}}
 """


space for function

space for function

--- tutor/src/components/scores/index.cjsx
+++ tutor/src/components/scores/index.cjsx
@@ -41,7 +41,7 @@
   selectPeriod: (period, key) ->
     @updateStudentData({period_id: period.id, periodIndex: key + 1})

-  changeDisplayAs:(mode) -> @updateStudentData({displayAs: mode})
+  changeDisplayAs: (mode) -> @updateStudentData({displayAs: mode})

   updateStudentData: (nextState) ->
     state = merge({}, @state, nextState)


Port to Process API

Port to Process API

--- components/CollectRemoteNodes.coffee
+++ components/CollectRemoteNodes.coffee
@@ -2,29 +2,52 @@

 exports.getComponent = ->
   c = new noflo.Component
-  c.context = null
   c.inPorts.add 'context',
     datatype: 'object'
-    process: (event, payload) ->
-      return unless event is 'data'
+  c.inPorts.add 'component',
+    datatype: 'object'
+  c.inPorts.add 'error',
+    datatype: 'object'
+  c.outPorts.add 'runtime',
+    datatype: 'object'
+  c.outPorts.add 'component',
+    datatype: 'string'
+  c.outPorts.add 'context',
+    datatype: 'object'
+  c.outPorts.add 'error',
+    datatype: 'object'
+  c.context = null
+  c.tearDown = (callback) ->
+    c.context = null
+    do callback
+  c.process (input, output) ->
+    if input.hasData 'context'
+      payload = input.getData 'context'
       unless payload.remote?.length
-        c.outPorts.context.send payload
-        c.outPorts.context.disconnect()
+        # No remote nodes to fetch
+        c.context = null
+        output.sendDone
+          context: payload
         return
       unless payload.runtime
-        c.error new Error 'No runtime connection for getting remote nodes'
+        output.done new Error 'No runtime connection for getting remote nodes'
         return
       c.context = payload
-      c.outPorts.runtime.send c.context.runtime
-      c.outPorts.runtime.disconnect()
-      c.outPorts.component.send c.context.remote.shift()
-  c.inPorts.add 'component',
-    datatype: 'object'
-    process: (event, payload) ->
-      return unless event is 'data'
-      return unless c.context
+      output.send
+        runtime: c.context.runtime
+      output.send
+        component: c.context.remote.shift()
+      output.done()
+      return
+    if input.hasData 'component'
+      payload = input.getData 'component'
+      unless c.context
+        # No pending context
+        output.done()
+        return
       if payload.language is 'json'
         noflo.graph.loadJSON JSON.parse(payload.code), (err, graph) ->
+          return output.done err if err
           graph.name = [payload.library, payload.name].join '/'
           unless graph.properties.environment
             graph.properties.environment = {}
@@ -33,34 +56,29 @@
           c.context.graphs.push graph
           unless c.context.remote.length
             c.context.state = 'ok'
-            c.outPorts.context.send c.context
-            c.outPorts.context.disconnect()
+            output.send
+              context: c.context
             c.context = null
+            output.done()
             return
-          node = graph.getNode c.context.remote.shift()
-          return c.error new Error 'Node not available' unless node
-          c.outPorts.component.send node.component
+          nodeName = c.context.remote.shift()
+          node = graph.getNode nodeName
+          return output.done new Error "Node '#{nodeName}' not available" unless node
+          output.sendDone
+            component: node.component
         return
       c.context.component = payload
       if c.context.remote.length
-        return c.error new Error 'Components are the lowest navigation level'
+        output.done new Error 'Components are the lowest navigation level'
+        return
       c.context.state = 'ok'
-      c.outPorts.context.send c.context
-      c.outPorts.context.disconnect()
+      output.send
+        context: c.context
       c.context = null
-  c.inPorts.add 'error',
-    datatype: 'object'
-    process: (event, payload) ->
-      return unless event is 'data'
+      output.done()
+      return
+    if input.hasData 'error'
+      payload = input.getData 'error'
       c.context = null
-      c.outPorts.component.disconnect()
-      c.error payload
-  c.outPorts.add 'runtime',
-    datatype: 'object'
-  c.outPorts.add 'component',
-    datatype: 'string'
-  c.outPorts.add 'context',
-    datatype: 'object'
-  c.outPorts.add 'error',
-    datatype: 'object'
-  c
+      output.done payload
+      return


dropdowns are exclusive

dropdowns are exclusive

--- components/layout/header/view.coffee
+++ components/layout/header/view.coffee
@@ -65,6 +65,9 @@

   toggleDropdown: (e)->
     $el = $(e.currentTarget).parent()
+    if !@$('.dropdown--is_active').is($el)
+      @$('.dropdown--is_active').removeClass 'dropdown--is_active'
+
     ac = $el.toggleClass('dropdown--is_active')
     $el.find('input').focus()


test for decrypting with wrong key

test for decrypting with wrong key

--- zechat/static/test_crypto.coffee
+++ zechat/static/test_crypto.coffee
@@ -81,6 +81,13 @@
       expect(out).toEqual(null)
       done()

+  it 'should return null for message encrypted with other key', (done) ->
+    other_key = zc.get_public_key(zc.generate_key())
+    new zc.Crypto(other_key).encrypt 'foo', (encrypted) ->
+      new zc.Crypto(PRIVATE_KEY).decrypt encrypted, (out) ->
+        expect(out).toEqual(null)
+        done()
+
   it 'should generate a usable key', (done) ->
     private_key = zc.generate_key()
     public_key = zc.get_public_key(private_key)


Teamwork: Removed recoverSessionTabs.

Teamwork: Removed recoverSessionTabs.

--- client/Teamwork/Views/teamworktabview.coffee
+++ client/Teamwork/Views/teamworktabview.coffee
@@ -8,7 +8,6 @@
     @keysRef  = @workspaceRef.child "keys"
     @indexRef = @workspaceRef.child "index"

-    @recoverSession()  if @isJoinedASession
     @tabView.on "PaneDidShow", (pane) =>
       @indexRef.set pane.getOptions().indexKey

@@ -61,19 +60,6 @@
         callback  : => @createChat()
     }

-  recoverSession: ->
-    @keysRef.once "value" , (snapshot) =>
-      data = snapshot.val()
-      return unless data
-
-      for key, value of data
-        switch value.type
-          when "dashboard" then @createDashboard()
-          when "editor"
-            file = FSHelper.createFileFromPath value.filePath
-            @createEditor file, "", value.sessionKey
-          when "terminal" then @createTerminal value.sessionKey
-          when "preview"  then @createPreview  value.sessionKey

   createDashboard: ->
     return @tabView.showPane @dashboard  if @dashboard


Delete user cookie once session has ended event is received

--- client/app/lib/notificationcontroller.coffee
+++ client/app/lib/notificationcontroller.coffee
@@ -78,6 +78,15 @@

     @on 'GuestTimePeriodHasEnded', deleteUserCookie

+    @on 'SessionHasEnded', ({ clientId }) ->
+
+      return deleteUserCookie()  unless clientId
+
+      # Delete user cookie if current session is not to be preserved.
+      # Session initiated password change procedure is meant to be kept.
+      if clientId isnt kookies.get 'clientId'
+        deleteUserCookie()
+
     @once 'EmailShouldBeConfirmed', ->
       {firstName, nickname} = whoami().profile
       kd.getSingleton('appManager').tell 'Account', 'displayConfirmEmailModal', name, nickname, (modal)=>


Ah @globalArgs does need to be an instance var


Fixed: if all optional fields had value, the 'more details' button was still shown

--- client/app/views/popover_screens/main.coffee
+++ client/app/views/popover_screens/main.coffee
@@ -140,6 +140,12 @@

         @refresh()

+        # If all the optional fields are shown by default (they all have a
+        # value), then hide the "more details" button.
+        if @$("[aria-hidden=true]").length is 0
+            @$moreDetailsButton.hide()
+
+
     onLeaveScreen: ->
         value = @$('.input-details').val()
         @model.set 'details', value


pass placeholder prop on through

pass placeholder prop on through

--- client/lanes/components/shared/TextArea.cjsx
+++ client/lanes/components/shared/TextArea.cjsx
@@ -9,6 +9,7 @@
         <textarea
             {...props}
             {...handlers}
+            {..._.pick(@props, 'placeholder')}
             className={className}
             onChange={@fieldMixinSetValue}
         />


fixed .map() function

fixed .map() function

--- src/array.coffee
+++ src/array.coffee
@@ -35,5 +35,5 @@

   map: (f) ->
     data = []
-    @each (x) -> data.push x
+    @each (x) -> data.push f x
     new APLArray data, @shape


nitrogen8mm: Update flashing instructions

The power LED, which is the only one on the board,
does not go off after flashing is completed. Therefore
we need to check the dashboard to see when provisioning
is finished.

Changelog-entry: nitrogen8mm: Update flashing instructions
Signed-off-by: Alexandru Costache <2d2dfcfad7b9832058fd41884a8955d042a85275@balena.io>

--- nitrogen8mm.coffee
+++ nitrogen8mm.coffee
@@ -2,9 +2,10 @@
 { networkOptions, commonImg, instructions } = deviceTypesCommon

 BOARD_POWEROFF = 'Remove and re-connect power to the board.'
+BOARD_SHUTDOWN =  'Monitor the device in Balena dashboard to see when it entered the post-provisioning state. Leave the state settle for around 10 seconds.'

 postProvisioningInstructions = [
-	instructions.BOARD_SHUTDOWN
+	BOARD_SHUTDOWN
 	instructions.REMOVE_INSTALL_MEDIA
 	instructions.BOARD_REPOWER
 ]


bugfix

bugfix

--- client.iced
+++ client.iced
@@ -117,8 +117,8 @@
       req.pipe writer
       await writer.on 'finish', defer()
       statusBar.cancel()
-      stats.retrieving = null
       return cb new Error '任务已删除' if req._aborted
+    stats.retrieving = null

     await queue.execute 'updateTasklist', defer e
     return cb e if e


added deamdify

added deamdify

--- Gulpfile.coffee
+++ Gulpfile.coffee
@@ -4,13 +4,15 @@
 browserify = require 'browserify'
 sourcemaps = require 'gulp-sourcemaps'
 coffee = require 'gulp-coffee'
+deamdify = require 'deamdify'
+

 # babel = require 'gulp-babel'
 concat = require 'gulp-concat'

 gulp.task 'js', ->
-	brwoserify 'src/coffee'
+	browserify 'src/coffee'

 gulp.task 'default', ->


Store formDef in Handler's state

Store formDef in Handler's state

--- containers/mixins/Handler.jsx.coffee
+++ containers/mixins/Handler.jsx.coffee
@@ -29,6 +29,7 @@
     submitting       : @props.submitting   ? false
     serverErrors     : @props.serverErrors ? null
     formData         : @props.formData     ? {}
+    formDef          : @props.formDef      ? {}
     originalFormData : @props.formData     ? {}
     buttons          : @bindButtons(@props.buttons ? @defaultButtons())

@@ -84,7 +85,7 @@
     form = `(
       <Form
         title={this.state.title}
-        formDef={this.props.formDef}
+        formDef={this.state.formDef}
         formData={this.state.formData}
         serverErrors={this.state.serverErrors}
         buttons={this.state.buttons}


KiteCache: to support async proxifyTransportUrl

--- client/app/lib/kite/kitecache.coffee
+++ client/app/lib/kite/kitecache.coffee
@@ -44,12 +44,14 @@
   signed = (queryString) -> "#{signature}#{queryString}"

-  proxifyTransport = (kite) ->
+  proxifyTransport = (kite, callback) ->

     if kite.kite.name is 'klient'
-      kite.url = proxifyTransportUrl kite.url
-
-    return kite
+      proxifyTransportUrl kite.url, (url) ->
+        kite.url = url
+        callback kite
+    else
+      callback kite

   @clearAll = ->
@@ -108,9 +110,8 @@
       return kd.warn '[KiteCache] KITE NOT PROVIDED, IGNORING TO CACHE'

     queryString = @generateQueryString query
-    kite = proxifyTransport kite
-
-    LocalStorage.setValue (signed queryString), (JSON.stringify kite)
+    proxifyTransport kite, (kite) ->
+      LocalStorage.setValue (signed queryString), (JSON.stringify kite)

   @get = (query) ->


fsfile: change isReadOnly() implementation

--- client/app/lib/util/fs/fsfile.coffee
+++ client/app/lib/util/fs/fsfile.coffee
@@ -234,34 +234,19 @@
         return response

-  checkIfReadOnly: (callback) ->
+  isReadOnly: (callback) ->

     kite = @getKite()

-    writable = 'writable'
-    readOnly = 'read only'
-    path = @getPath()
-
     kite.init()

     .then =>

-      ###
-      Since touching file works without error if file is not writable but user is owner,
-      let's do 2 separate checks:
-      - user is owner and file is not writable
-      - user is not owner and touch throws an error
-      ###
-      command = "if [ -O #{path} ]; then [ -w #{path} ]
-        && echo '#{writable}' || echo '#{readOnly}';
-        else touch -a #{path} && echo '#{writable}' || echo '#{readOnly}'; fi"
-
-      kite.exec({command})
+      kite.fsGetInfo path: @getPath()

     .nodeify (err, result) ->

       return callback err  if err

-      { stdout, stderr } = result
-      readOnly = (stdout.indexOf writable) is -1
+      readOnly = result.readable and not result.writable
       callback null, readOnly


Don't export classes that are unusable from a task

Detect if a task is being run in atom-api and only export
classes that are usable from that context.

--- exports/atom-api.coffee
+++ exports/atom-api.coffee
@@ -1,5 +1,4 @@
 {View, $$, $$$} = require '../src/space-pen-extensions'
-{pathForRepositoryUrl} = require '../src/project'

 module.exports =
   _: require '../src/underscore-extensions'
@@ -8,15 +7,19 @@
   $$$: $$$
   BufferedNodeProcess: require '../src/buffered-node-process'
   Directory: require '../src/directory'
-  Editor: require '../src/editor'
   EventEmitter: require '../src/event-emitter'
   File: require '../src/file'
   fs: require '../src/fs-utils'
   Git: require '../src/git'
-  pathForRepositoryUrl: pathForRepositoryUrl
-  RootView: require '../src/root-view'
   ScrollView: require '../src/scroll-view'
-  SelectList: require '../src/select-list'
   Subscriber: require '../src/subscriber'
-  Task: require '../src/task'
   View: View
+
+# The following classes can't be used from a Task handler and should therefore
+# only be exported when not running as a child node process
+unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
+  module.exports.Editor = require '../src/editor'
+  module.exports.pathForRepositoryUrl = require('../src/project').pathForRepositoryUrl
+  module.exports.RootView = require '../src/root-view'
+  module.exports.SelectList = require '../src/select-list'
+  module.exports.Task = require '../src/task'


fix empty p tag removal to account for paragraphs ending in a span such as em etc


Only execute drag/drop mechanism if there is a file otherwise, propagate to drag/drop mechanism for repos & studies.

--- frontend/coffeescript/app/dashboard/views.coffee
+++ frontend/coffeescript/app/dashboard/views.coffee
@@ -81,6 +81,10 @@
             @

         file_drop: ( event ) =>
+
+            if not event.originalEvent.dataTransfer?
+                return
+
             event.stopPropagation()
             event.preventDefault()


Removed dead code

Removed dead code

--- core/app/backbone/models/fact_votes.coffee
+++ core/app/backbone/models/fact_votes.coffee
@@ -29,9 +29,4 @@
         @setCurrentUserOpinion @previous_opinion_type
         FactlinkApp.NotificationCenter.error "Something went wrong while setting your opinion on the Factlink, please try again."

-  believe: -> @setActiveOpinionType 'believes'
-  disbelieve: -> @setActiveOpinionType 'disbelieves'
-  isBelieving: -> @get('current_user_opinion') == 'believes'
-  isDisBelieving: -> @get('current_user_opinion') == 'disbelieves'
-
   totalCount: -> @get('believes') + @get('disbelieves') + @get('doubts')


Extract parsing the environment into a function

It was getting in the way of reading what the message handler did.

--- src/child.coffee
+++ src/child.coffee
@@ -1,18 +1,19 @@
 Impromptu = require '../lib/impromptu'
 impromptu = new Impromptu()

+parseEnv = (printenvOutput) ->
+    env = {}
+    if printenvOutput
+      pairs = printenvOutput.split /(?:^|\n)([a-z0-9_]+)=/i
+      # Remove the first blank match.
+      pairs.shift()
+      for key, index in pairs by 2
+        env[key] = pairs[index+1]
+    env
+
 process.on 'message', (message) ->
   if message.type is 'env'
-    env = {}
-
-    if message.data
-      data = message.data.split /(?:^|\n)([a-z0-9_]+)=/i
-      # Remove the first blank match.
-      data.shift()
-
-      # Record the environment.
-      for key, index in data by 2
-        env[key] = data[index+1]
+    env = parseEnv message.data

     if env.IMPROMPTU_SHELL
       impromptu.options.shell = env.IMPROMPTU_SHELL


the best javascript color library

the best javascript color library

--- src/color.coffee
+++ src/color.coffee
@@ -43,7 +43,7 @@

     if arguments.length == 0
       parsedColor = [0, 0, 0, 0]
-    if arguments.length == 1 && Object.prototype.toString.call(arguments[0]) == '[object Array]'
+    else if arguments.length == 1 && Object.prototype.toString.call(arguments[0]) == '[object Array]'
       alpha = if arguments[0][3]? then arguments[0][3] else 1
       parsedColor = [
         parseInt(arguments[0][0]),


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -214,6 +214,14 @@
     darken: (amount) ->
       @copy().darken$(amount)

+    ###*
+    Modifies the color so that it is darkened by `amount` (Lightness of the color ranges from 0 - 1).
+
+    @name darken
+    @methodOf Color#
+
+    @returns {Color} the color with the lightness value reduced by `amount`
+    ###
     darken$: (amount) ->
       hsl = @toHsl()
       hsl[2] -= amount


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -40,7 +40,7 @@

     parsedColor = null

-    if arguments.length > 2
+    if color.length > 2
       alpha = if arguments[3]? then arguments[3] else 1
       parsedColor = [arguments[0], arguments[1], arguments[2], alpha]
     else


pixie

pixie

--- src/color.coffee
+++ src/color.coffee
@@ -1,3 +1,4 @@
+test = true
 Color = (I) ->
   I ||= {}


Redirect to user from /personalize to /personalize/interests server-side

finishes https://artsyproduct.atlassian.net/browse/GROWTH-367

--- src/desktop/apps/personalize/index.coffee
+++ src/desktop/apps/personalize/index.coffee
@@ -9,5 +9,5 @@
 app.set 'views', __dirname
 app.set 'view engine', 'jade'

-app.get '/personalize', index
+app.get '/personalize', (_, res) => res.redirect('/personalize/interests')
 app.get '/personalize/:slug', ensureLoggedInUser, index


KodingLogger.test: connect once and close the connection at the end to keep it short

--- workers/social/lib/social/models/kodinglogger.test.coffee
+++ workers/social/lib/social/models/kodinglogger.test.coffee
@@ -131,21 +131,6 @@
       KodingLogger.pt.on 'connect', -> done()

-  describe '# close', ->
-
-    it 'should close existing connection from papertrail', (done) ->
-
-      expect(KodingLogger.logger).to.exist
-      expect(KodingLogger.pt).to.exist
-
-      KodingLogger.close()
-
-      expect(KodingLogger.logger).to.not.exist
-      expect(KodingLogger.pt).to.not.exist
-
-      done()
-
-
   describe '# send', ->

     it 'should send a log to papertrail', (done) ->
@@ -158,9 +143,9 @@

       identifier = KodingLogger.getIdentifier scope, group

-      KodingLogger.connect()
-
-      KodingLogger.pt.on 'connect', ->
+      KodingLogger[scope] group, log
+
+      setTimeout ->

         KodingLogger.search { query }, (err, result) ->

@@ -170,11 +155,9 @@
           expect(result.logs).to.have.length.above 0
           expect(result.logs[0].message).to.be.equal "#{identifier} #{log}"

-          KodingLogger.close()
-
           done()

-      KodingLogger[scope] group, log
+      , 2000

   describe '# search', ->
@@ -190,9 +173,10 @@

       identifier = KodingLogger.getIdentifier scope, group

-      KodingLogger.connect()
-
-      KodingLogger.pt.on 'connect', ->
+      for log in logs
+        KodingLogger[scope] group, log
+
+      setTimeout ->

         KodingLogger.search { query }, (err, result) ->

@@ -203,12 +187,24 @@
           expect(result.logs[0].message).to.be.equal "#{identifier} #{logs[0]}"
           expect(result.logs[1].message).to.be.equal "#{identifier} #{logs[1]}"

-          KodingLogger.close()
-
           done()

-      for log in logs
-        KodingLogger[scope] group, log
+      , 4000
+
+
+  describe '# close', ->
+
+    it 'should close existing connection from papertrail', (done) ->
+
+      expect(KodingLogger.logger).to.exist
+      expect(KodingLogger.pt).to.exist
+
+      KodingLogger.close()
+
+      expect(KodingLogger.logger).to.not.exist
+      expect(KodingLogger.pt).to.not.exist
+
+      done()

 runTests()


Social: cleanup style and fix naming problems

--- workers/social/lib/social/models/socialapi/channel.coffee
+++ workers/social/lib/social/models/socialapi/channel.coffee
@@ -30,6 +30,8 @@
           (signature Object, Function)
         unfollow:
           (signature Object, Function)
+        fetchFollowedChannels:
+          (signature Object, Function)

     schema             :
       id               : Number
@@ -57,13 +59,12 @@
       delegate.createSocialApiId (err, socialApiId)->
         return callback err if err

-        data =
-          channelId: options.id
-          accountId: socialApiId
-          groupName: group.slug
+        options.channelId = options.id
+        options.accountId = socialApiId
+        options.groupName = group.slug

         {fetchChannelActivity} = require './requests'
-        fetchChannelActivity data, callback
+        fetchChannelActivity options, callback

   @fetchPopularTopics = secure (client, options = {}, callback)->
     fetchGroup client, (err, group)->
@@ -74,28 +75,33 @@
       fetchPopularTopics options, callback

   @fetchChannels = secure (client, options = {}, callback)->
+    fetchChannelReqeust 'fetchGroupChannels', client, options, callback
+
+  @fetchFollowedChannels = secure (client, options = {}, callback)->
+    fetchChannelReqeust 'fetchGroupChannels', client, options, callback
+
+  @fetchChannelReqeust = (funcName, client, options, callback)->
     fetchGroup client, (err, group)->
       return callback err if err
       {connection:{delegate}} = client
       delegate.createSocialApiId (err, socialApiId)->
         return callback err if err

-        data =
-          groupName: group.slug
-          accountId: socialApiId
+        options.groupName = group.slug
+        options.accountId = socialApiId

-        {fetchGroupChannels} = require './requests'
-        fetchGroupChannels data, callback
+        requests = require './requests'
+        requests[funcName] options, callback

   @listPinnedMessages = permit 'pin posts',
-    success:  (client, data, callback)->
+    success:  (client, options, callback)->
       {connection:{delegate}, context} = client
       delegate.createSocialApiId (err, socialApiId)->
         return callback err if err
-        data.accountId = socialApiId
-        data.groupName = context.group
+        options.accountId = socialApiId
+        options.groupName = context.group
         {listPinnedMessages} = require './requests'
-        listPinnedMessages data, callback
+        listPinnedMessages options, callback

   @pinMessage = permit 'pin posts',
     success:  (client, data, callback)->


bug fix..

bug fix..

--- src/plugins/faction/welcome.coffee
+++ src/plugins/faction/welcome.coffee
@@ -41,15 +41,15 @@
                     $exists: true
             .sort {time: -1}
             .limit 1
-            .toArray (err, records) ->
+            .toArray (err, rec) ->

                 # recent action not found / no markups
-                if err or not records
+                if err or not rec
                     plugin.sayHello player
                 else
                     plugin.sayHello player,
-                        latE6: records[0].markup.PORTAL1.latE6
-                        lngE6: records[0].markup.PORTAL1.lngE6
+                        latE6: rec.markup.PORTAL1.latE6
+                        lngE6: rec.markup.PORTAL1.lngE6

         , Config.Public.FetchInterval * 1.5


Updating

Updating

--- config.cson
+++ config.cson
@@ -1,8 +1,20 @@
 "*":
   core:
     allowPendingPaneItems: false
+    customFileTypes:
+      "source.ini": [
+        ".buckconfig"
+        ".flowconfig"
+      ]
+      "source.json": [
+        ".arcconfig"
+      ]
+      "source.python": [
+        "BUCK"
+      ]
     disabledPackages: [
       "language-gfm"
+      "nuclide"
     ]
     ignoredNames: [
       ".git"
@@ -24,6 +36,8 @@
     userId: "20e33b17-b6ee-be85-6d79-5468d2ceffbc"
   "exception-reporting":
     userId: "dd9e8706-e58c-0f4d-e03d-0c6bd5ab94e4"
+  "file-watcher":
+    promptWhenFileHasChangedOnDisk: false
   "markdown-writer":
     textStyles:
       codeblock:
@@ -34,6 +48,23 @@
       italic:
         after: "*"
         before: "*"
+  nuclide:
+    installRecommendedPackages: true
+    "nuclide-arcanist": {}
+    "nuclide-buck-files": {}
+    "nuclide-clang-atom": {}
+    "nuclide-console": {}
+    "nuclide-datatip": {}
+    "nuclide-debugger-hhvm": {}
+    "nuclide-flow": {}
+    "nuclide-format-js": {}
+    "nuclide-hack": {}
+    "nuclide-health": {}
+    "nuclide-ios-simulator-logs": {}
+    "nuclide-ocaml": {}
+    "nuclide-python": {}
+    "nuclide-react-native": {}
+    "nuclide-working-sets": {}
   "rss-ticker":
     feed: "https://aur.archlinux.org/rss/"
   "terminal-plus":


accordion working with top and bottom anchors

--- oriDomi.coffee
+++ oriDomi.coffee
@@ -381,7 +381,18 @@
   accordion: (angle, options) ->
     options = extendObj options, @_accordionDefaults
     {anchor} = options
-    angle = @_normalizeAngle angle
+
+    if anchor isnt @lastAnchor
+      return @reset =>
+        @stages[anchor].style.display = 'block'
+        @stages[@lastAnchor].style.display = 'none'
+        @lastAnchor = anchor
+        setTimeout =>
+          @accordion angle, options
+        , 0
+
+
+    @lastAngle = angle = @_normalizeAngle angle

     for panel, i in @panels[anchor]

@@ -395,14 +406,29 @@
         when 'right'
           y = 0
           if i is 0
-            x = @panelWidth * (@vPanels - 1)
+            x = @_getRightAnchorCoord()
           else
             x = -@panelWidth + 1
+        when 'top'
+          x = 0
+          if i is 0
+            y = 0
+          else
+            y = @panelHeight - 1
+        when 'bottom'
+          x = 0
+          if i is 0
+            y = @_getBottomAnchorCoord()
+          else
+            y = -@panelHeight + 1

       if i % 2 isnt 0 and !options.twist
         deg = -angle
       else
         deg = angle
+
+      if anchor is 'right'
+        deg = -deg

       if options.sticky
         if i is 0
@@ -415,7 +441,10 @@
       if options.fracture
         rotation = [1, 1, 1, deg]
       else
-        rotation = [0, 1, 0, deg]
+        if anchor is 'left' or anchor is 'right'
+          rotation = [0, 1, 0, deg]
+        else
+          rotation = [1, 0, 0, -deg]

       panel.style[transformProp] = @_transform [x, y], rotation

@@ -490,7 +519,7 @@
         when 'right'
           y = 0
           if i is 0
-            x = @panelWidth * (@vPanels - 1)
+            x = @_getRightAnchorCoord()
           else
             x = -@panelWidth + 1


simplified _conclude()

simplified _conclude()

--- oridomi.coffee
+++ oridomi.coffee
@@ -542,18 +542,9 @@
   # `_conclude` is used to handle the end process of transitions and to initialize
   # queued operations.
   _conclude: (cb) =>
-    # Empty the previous operation from the queue and invoke the next one in line.
-    # Defer until the next event loop.
     setTimeout =>
-      @_inTransition = false
-      next = @_queue.shift()
-      # Invoke the next operation if present.
-      if typeof next is 'function'
-        # In this case, `next` is a timeout supplied by `wait()`.
-        next()
-      else
-        @[next[0]].apply @, next[1] if next
-      # Invoke any supplied callback.
+      @_inTrans = false
+      @_step()
       cb?()
     , 0


addStyle function

addStyle function

--- oridomi.coffee
+++ oridomi.coffee
@@ -29,6 +29,18 @@
   return prop if testEl.style[prop]?
   # If no matches are found, return false to denote that the browser is missing this property.
   false
+
+
+addStyle = (selector, rules) ->
+  style = ".#{ selector }{"
+  for prop, val of rules
+    if prop of css
+      prop = css[prop]
+      prop = '-' + prop if prop.match /^(webkit|moz|ms)/i
+
+    style += "#{ prop.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase() }:#{ val };"
+
+  styleBuffer += style + '}'

 capitalize = (s) ->


set proper cursor when freezing and unfreezing

--- oridomi.coffee
+++ oridomi.coffee
@@ -706,8 +706,8 @@

   # Gives the element a resize cursor to prompt the user to drag the mouse.
-  _setCursor: ->
-    if @_touchEnabled
+  _setCursor: (bool = @_touchEnabled) ->
+    if bool
       @_stageHolder.style.cursor = css.grab
     else
       @_stageHolder.style.cursor = 'default'
@@ -874,6 +874,7 @@
         # Swap the visibility of the elements.
         hideEl @_stageHolder
         showEl @cloneEl
+        @_setCursor false
         callback?()
     @

@@ -886,6 +887,7 @@
       # Swap the visibility of the elements.
       hideEl @cloneEl
       showEl @_stageHolder
+      @_setCursor()
       # Set `lastAngle` to 0 so an immediately subsequent call to `freeze` triggers the callback.
       @_lastOp.angle = 0
     @


Blob test: use test repository

Blob test: use test repository

--- test/test.blob.coffee
+++ test/test.blob.coffee
@@ -5,24 +5,24 @@
 utils = require "./utils"
 fixtures = require "./fixtures"

-secondCommit = fixtures.projectRepo.secondCommit
+secondCommit = fixtures.testRepo.secondCommit

 describe "Blob", ->
 	repo = null
 	blob = null

-	describe "Using the project repo...", ->
-		it "can find the wscript blob (#{secondCommit.wscriptBlob}) file in second commit", (done) ->
-			gitteh.openRepository fixtures.projectRepo.path, (err, _repo) ->
+	describe "Using the test repo...", ->
+		it "can find the README blob (#{secondCommit.readmeBlob}) file in second commit", (done) ->
+			gitteh.openRepository fixtures.testRepo.path, (err, _repo) ->
 				repo = _repo
-				repo.blob secondCommit.wscriptBlob, (err, _blob) ->
+				repo.blob secondCommit.readmeBlob, (err, _blob) ->
 					should.not.exist err
 					blob = _blob
 					blob.should.be.an.instanceof gitteh.Blob
 					done()
 		describe "#id", ->
 			it "is correct", ->
-				blob.id.should.equal secondCommit.wscriptBlob
+				blob.id.should.equal secondCommit.readmeBlob
 			it "is immutable", -> utils.checkImmutable blob, "id"
 		describe "#data", ->
 			it "is a Buffer", ->
@@ -32,4 +32,4 @@
 				shasum.update "blob #{blob.data.length}\u0000"
 				shasum.update blob.data.toString("binary")
 				shasum.digest("hex").should.equal blob.id
-			it "is immutable", -> utils.checkImmutable blob, "data"+			it "is immutable", -> utils.checkImmutable blob, "data"


Add rename and delete menu items

Add rename and delete menu items

--- menus/tree-view.cson
+++ menus/tree-view.cson
@@ -1,3 +1,5 @@
 'context-menu':
   '.tree-view':
-    'Add file': 'tree-view:add'
+    'Add File': 'tree-view:add'
+    'Rename': 'tree-view:move'
+    'Delete': 'tree-view:remove'


:shirt: Clean up `Form.Field` template

:shirt: Clean up `Form.Field` template

--- src/field.coffee
+++ src/field.coffee
@@ -143,5 +143,21 @@
     return

 },
-  template: _.template('
      <label for="<%= editorId %>">        <% if (titleHTML){ %><%= titleHTML %>        <% } else { %><%- title %><% } %>

<%= help %>

  ', null, Form.templateSettings)
+  template: _.template '''
+

+      <label for="<%= editorId %>">
+        <% if (titleHTML){ %>
+          <%= titleHTML %>
+        <% } else { %>
+          <%- title %>
+        <% } %>
+
+
+

+
+

+
<%= help %>

+

+

+  ''', null, Form.templateSettings
   errorClassName: 'error')


Changed Auction Closed to Online Bidding Closed.

--- components/auction_clock/view.coffee
+++ components/auction_clock/view.coffee
@@ -35,7 +35,7 @@
         @$('.clock-header').html "#{@modelName} closes in:"
         @toDate = @model.get 'offsetEndAtMoment'
       when 'closed'
-        @$el.html "
#{@modelName} Closed
"
+        @$el.html "
Online Bidding Closed
"
         return
     @renderClock()
     @interval = setInterval @renderClock, 1000


filename

filename


Fix typo

Fix typo

--- framer/Importer.coffee
+++ framer/Importer.coffee
@@ -105,7 +105,7 @@

 		# A layer without an image, mask or sublayers should be zero
 		if not layer.image and not info.children.length and not info.maskFrame
-			layer.frame = Utils.zeroFrame()
+			layer.frame = Utils.frameZero()

 		_.clone(info.children).reverse().map (info) => @_createLayer info, layer


andnow

andnow

--- models/deploy.coffee
+++ models/deploy.coffee
@@ -74,13 +74,10 @@

 # callbacks
 DeploySchema.post 'save', ->
-  console.log 'STARTING SAVE!!!'
   @team (err, team) =>
     throw err if err
-    console.log 'GOING TO DO THE TOOBJECT!!!'
     # team.lastDeploy = @toObject()
     team.entry.url = "http://#{team.slug}.2013.nodeknockout.com"
-    console.log 'GOING TO DO THE TEAM.SAVE!!!'
     team.save (err) ->
       throw err if err
       return


Changing the compound index of metrics so it will be properly used by the metric aggregation

--- models/metric.coffee
+++ models/metric.coffee
@@ -31,8 +31,8 @@
 metricSchema.index(
   {
     node_id: 1
+    timestamp: 1
     path: 1
-    timestamp: 1
   },
   { unique: true }
 )


Small improvements

Small improvements

--- resources/coffee/main.coffee
+++ resources/coffee/main.coffee
@@ -10,7 +10,7 @@
     # Space key handling
     _ '#input-name'
         .keypress (event) ->
-            if (event.keyCode == 32)
+            if event.keyCode is 32
                 _ '#input-last'
                     .focus()
                 event.preventDefault()
@@ -111,7 +111,9 @@
             event.preventDefault()
             form = _ event.target
             swal
-                title: '...'
+                title: '

'
+                text: 'ვეძებ :3'
+                html: yes
                 showConfirmButton: no
             _.post form.attr('action'), form.serialize(), (response) ->
                 switch response.status


REPL once again permits indented expressions

--- repl.coffee
+++ repl.coffee
@@ -94,7 +94,7 @@
   backlog = ''
   try
     _ = global._
-    returnValue = CoffeeScript.eval "_=(undefined\n#{code}\n)", {
+    returnValue = CoffeeScript.eval "_=(undefined\n;#{code}\n)", {
       filename: 'repl'
       modulename: 'repl'
     }


corrected some SIGINT/EOT logic in REPL

corrected some SIGINT/EOT logic in REPL

--- repl.coffee
+++ repl.coffee
@@ -178,11 +178,12 @@
     repl.output.clearLine 1
     repl._onLine repl.line
     return
-  if backlog
+  if backlog or repl.line
     backlog = ''
-    repl.output.write '\n'
+    repl.historyIndex = -1
     repl.setPrompt REPL_PROMPT
-    repl.prompt()
+    repl.output.write '\n(^C again to quit)'
+    repl._line (repl.line = '')
   else
     repl.close()


Add reset and restart functions

Add reset and restart functions

--- framer/Animation.coffee
+++ framer/Animation.coffee
@@ -61,7 +61,6 @@
 			console.warn "Animation.origin: please use layer.originX and layer.originY"

 		@options.properties = Animation.filterAnimatableProperties(@options.properties)
-
 		@_parseAnimatorOptions()
 		@_originalState = @_currentState()
 		@_repeatCounter = @options.repeat
@@ -149,7 +148,6 @@
 			Utils.delay(@options.delay, start)
 		else
 			start()
-
 		return true

 	stop: (emit=true)->
@@ -166,7 +164,15 @@
 		animation = new Animation options
 		animation

-	copy: -> return new Animation(_.clone(@options))
+	reset: ->
+		for k, v of @_stateA
+			@_target[k] = v
+
+	restart: ->
+		@reset()
+		@start()
+
+	copy: -> new Animation(_.clone(@options))

 	# A bunch of common aliases to minimize frustration
 	revert: -> 	@reverse()
@@ -209,7 +215,7 @@

 	_prepareUpdateValues: =>
 		@_valueUpdaters = {}
-
+
 		for k, v of @_stateB
 			if Color.isColorObject(v) or Color.isColorObject(@_stateA[k])
 				@_valueUpdaters[k] = @_updateColorValue
@@ -222,7 +228,7 @@

 	_updateNumberValue: (key, value) =>
 		@_target[key] = Utils.mapRange(value, 0, 1, @_stateA[key], @_stateB[key])
-
+
 	_updateColorValue: (key, value) =>
 		@_target[key] = Color.mix(@_stateA[key], @_stateB[key], value, false, @options.colorModel)


workers: add tracing info

workers: add tracing info

--- workers/social/testhelper/index.coffee
+++ workers/social/testhelper/index.coffee
@@ -93,6 +93,10 @@

   withDummyClient context, ({ client }) ->
     JUser.convert client, userFormData, (err, data) ->
+      if err
+        console.trace()
+        console.log "Err: JUser.convert", err
+
       expect(err).to.not.exist

       { account, newToken, user } = data


Fix something

Fix something

--- src/6.web.coffee
+++ src/6.web.coffee
@@ -29,7 +29,7 @@
                     headers:
                         xhr.getAllResponseHeaders()
                         .stripTrailingNewline()
-                        .splitDeep("\r\n", ": ")
+                        .splitDeep("\r\n", ": ", 1)
                         .toObject()
                     body:
                         if responseBodyType == "binary"


using new features

using new features

--- spec/test.coffee
+++ spec/test.coffee
@@ -5,7 +5,7 @@
 class window.Contact extends Hamsa

   @define
-    id              : type: String
+    id              : type: Number
     mail            : type: String
     username        : type: String
     avatar          : type: String, default: "http://gravatar.org"
@@ -18,6 +18,37 @@
   @fullname: ->
     console.log "???fullname"

+for i in [1..5]
+  new Contact id: i, username: "user_#{i}",  name: "name_#{i}"
+
+console.log Contact.find()
+
+console.log Contact.find id: 1, username: 'user_1'
+
+
+console.log Contact.findAndModify
+  query : id: 1, name: 'name_1'
+  update: username: 'one'
+  upsert: false
+
+console.log Contact.findAndModify
+  query : id: 123, name: 'name_1'
+  update: username: 'one'
+  upsert: true
+
+console.log Contact.findAndModify
+  query : since: 2014
+  update: since: 2015
+  upsert: false
+
+console.log Contact.find()
+
+console.log 'since'
+console.log Contact.findOne since: 2015
+console.log Contact.findOne since: 2014
+
+
+return true
 Contact.observe (state) ->
   console.log "\nContact.observe #{state.type} [#{state.name}]", state


hub: handle /index.html static page

hub: handle /index.html static page

--- src/smc-hub/hub_http_server.coffee
+++ src/smc-hub/hub_http_server.coffee
@@ -153,7 +153,7 @@
     router.use '/doc',
         express.static(path_module.join(STATIC_PATH, 'doc'), {maxAge: 0})

-    router.get '/', (req, res) ->
+    handle_root = (req, res) ->
         # for convenicnece, a simple heuristic checks for the presence of the remember_me cookie
         # that's not a security issue b/c the hub will do the heavy lifting
         # TODO code in comments is a heuristic looking for the remember_me cookie, while when deployed the haproxy only
@@ -166,6 +166,9 @@
         else
             #res.cookie(opts.base_url + 'has_remember_me', 'false', { maxAge: 60*60*1000, httpOnly: false })
             res.sendFile(path_module.join(STATIC_PATH, 'index.html'), {maxAge: 0})
+
+    router.get '/', handle_root
+    router.get '/index.html', handle_root

     router.get '/app', (req, res) ->
         #res.cookie(opts.base_url + 'has_remember_me', 'true', { maxAge: 60*60*1000, httpOnly: false })


fix bug in pdf download

fix bug in pdf download

--- src/smc-webapp/editor_latex.coffee
+++ src/smc-webapp/editor_latex.coffee
@@ -667,7 +667,7 @@
         return elt

     download_pdf: (print = false) =>
-        project_tasks(@project_id).download_file
+        redux.getProjectActions(@project_id).download_file
             path : misc.change_filename_extension(@filename, 'pdf')
             print: print


Refactored: used proper coffee syntax in 'and' condition

--- client/app/collections/tasks.coffee
+++ client/app/collections/tasks.coffee
@@ -48,7 +48,7 @@
     insertTask: (previousTask, task, callbacks) ->
         index = @toArray().indexOf previousTask

-        if previousTask? && previousTask.get("nextTask")?
+        if previousTask? and previousTask.get("nextTask")?
             nextTask = @at(index + 1)
             nextTask?.set "previousTask", task.id
         else if (firstTask = @at(0))?


filter homepage tiles using search box

filter homepage tiles using search box

--- client/code/view/subnav-path.coffee
+++ client/code/view/subnav-path.coffee
@@ -15,6 +15,7 @@
     'click .new-dataset': 'showChooser'
     'focus .context-switch input': 'focusContextSearch'
     'keyup .context-switch input': 'keyupContextSearch'
+    'keyup #subnav-options .search-query': 'keyupPageSearch'

   render: ->
     if window.user.real.isStaff?
@@ -116,6 +117,22 @@
     else if t == ''
       results.remove()

+  keyupPageSearch: (e) ->
+    $input = $(e.target)
+    if e.keyCode is 27
+      $('.dataset.tile').show()
+      $input.val('').blur()
+    else
+      t = $input.val()
+      if t != ''
+        $('.dataset.tile').each ->
+          if $(this).children('h3').text().toUpperCase().indexOf(t.toUpperCase()) >= 0
+            $(this).show()
+          else
+            $(this).hide()
+      else if t == ''
+        $('.dataset.tile').show()
+

 class Cu.View.EditableSubnav extends Backbone.View
   initialize: ->


opt: api

opt: api

--- src/index.coffee
+++ src/index.coffee
@@ -126,9 +126,19 @@
     req.end()
     req

+
+getPromise = (maybes...) ->
+    for i in maybes
+        if isPromise i then return i
+
+    return null
+
 module.exports = (opts, cb) ->
-    if isPromise cb
-        new cb (resolve, reject) ->
+    if typeof cb is 'function'
+        kissRequest opts, cb
+    else if _Promise = getPromise cb, module.exports.Promise, Promise
+        new _Promise (resolve, reject) ->
             kissRequest opts, (err, data) ->
                 if err then reject(err) else resolve(data)
-    else kissRequest opts, cb
+
+module.exports.Promise = null


* [bug] catch the yaml error 2

* [bug] catch the yaml error 2

--- src/index.coffee
+++ src/index.coffee
@@ -92,7 +92,7 @@
       if aOptions.raiseError
         throw err
       else
-        Logger('isdk').status 'error', err.message
+        Logger('isdk').status 'error', folder, err.message
         return

     # check whether the cwd is changed via configuration!
@@ -101,7 +101,14 @@
     cwd = path.resolve cwd
     if newCwd != cwd
       vFolder = Resource newCwd
-      vFolder.loadSync read:true
+      try
+        vFolder.loadSync read:true
+      catch err
+        if aOptions.raiseError
+          throw err
+        else
+          Logger('isdk').status 'error', folder, err.message
+          return
       setPrototypeOf vFolder, folder
       folder = vFolder


Fix code style.

Fix code style.

--- src/index.coffee
+++ src/index.coffee
@@ -4,9 +4,11 @@
 sysPath = require 'path'
 watch = require './watch'

-create = (skeleton, path) ->
-  skeleton ?= sysPath.join(__dirname, '..', 'skeletons', 'brunch-with-chaplin')
-  path ?= '.'
+defaultSkeleton = sysPath.join(
+  __dirname, '..', 'skeletons', 'brunch-with-chaplin'
+)
+
+create = (skeleton = defaultSkeleton, path = '.') ->
   initSkeleton skeleton, path

 module.exports = {


Removed roundFloats by default.

Removed roundFloats by default.

--- src/Forms.coffee
+++ src/Forms.coffee
@@ -399,7 +399,7 @@
         # Round float fields to 2 decimal places.
         $input = $(input.node)
         field = input.field
-        if field.type == Number && field.decimal && formArgs.roundFloats != false
+        if field.type == Number && field.decimal && formArgs.roundFloats
           decimals = field.decimals ? 2
           value = Forms.getInputValue($input)
           value = parseFloat(value).toFixed(2)


Add default route

Add default route

--- app/routes.coffee
+++ app/routes.coffee
@@ -7,6 +7,7 @@
     @sessionController = new SessionController uuid, meshblu

   register: =>
+    @app.get  '/', (request, response) => response.status(200).send status: 'online'
     @app.post '/devices',                @deviceController.create
     @app.post '/devices/:uuid/sessions', @sessionController.create


hardcode the other api

hardcode the other api

--- app/routes/owner.coffee
+++ app/routes/owner.coffee
@@ -9,7 +9,7 @@
   model: (params) ->
     owner = {}

-    $.get("https://api-staging.travis-ci.org/v3/owner/#{params.owner}?include=user.repositories,organization.repositories,build.commit,repository.active").then( (data) ->
+    $.get("https://api.travis-ci.org/v3/owner/#{params.owner}?include=user.repositories,organization.repositories,build.commit,repository.active").then( (data) ->
       data
     )


cleanup

cleanup

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -1222,7 +1222,7 @@
     else
       f()
   independent = (waiter) ->
-    !waiter.obs || !_.any(waiters, ((other) -> other.obs && waiter.obs.dependsOn(other.obs)))
+    !_.any(waiters, ((other) -> waiter.obs.dependsOn(other.obs)))

   whenDoneWith = (obs, f) ->
     if rootEvent


Remove unused variable

Remove unused variable

--- src/auth.coffee
+++ src/auth.coffee
@@ -27,6 +27,6 @@

 getTokenFromKeychain = (tokenName, callback) ->
   command = "security -q find-generic-password -ws '#{tokenName}'"
-  child_process.exec command, (error, stdout='', stderr='') ->
+  child_process.exec command, (error, stdout='') ->
     token = stdout.trim()
     callback(error, token)


empty strings are falsey

empty strings are falsey

--- csrf.coffee
+++ csrf.coffee
@@ -70,10 +70,10 @@
   a.href = a.href

   # Make sure that the browser parses out a protocol.
-  a.protocol && origin.protocol && a.protocol != "" && origin.protocol != "" &&
+  a.protocol && origin.protocol &&

   # Make sure that the browser parses out host.
-  a.host && origin.host && a.host != "" && origin.host != "" &&
+  a.host && origin.host &&

   # Make sure that the protocols and hosts match.
   "#{origin.protocol}//#{origin.host}" == "#{a.protocol}//#{a.host}"


about styling

about styling

--- src/client.cjsx
+++ src/client.cjsx
@@ -33,25 +33,25 @@
   render: ->

-
 Creative teaching with MuSiika

+
 Creative teaching with MuSiika

-
-        MuSiika is a tool that combines the music education with a development
-        of pupils' eskills.

+
+
MuSiika is a tool that combines the music education with a development
+        of pupils' programming skills.

-        Why use Musiika?
-        Musiika supports colaboration skills, creative thinking,
+
Why use Musiika?

+
Musiika supports collaboration skills, creative thinking and logical reasoning.

-        How is that all possibly? Let us share an example
+
How is that all possibly? Let us share an example

-        Piece known as "Pachelbel's Canon" was composed by Johann Pachelbel in
+
Piece known as "Pachelbel's Canon" was composed by Johann Pachelbel in
         17th century. It belongs fundamentally to the history of music
         representing the Baroque era. Moreover, it's elements (especially the
         chord progression) can be found in many pop music song. In respect of
         music theory Pachelbel's Canon introduces the technique of canon and
-        ground bass.
+        ground bass.

-        We can use MuSiika to introduce this great piece of music in a manner
+
We can use MuSiika to introduce this great piece of music in a manner
         that the pupils can really dive in the logics of music. The teacher can
         divide the class in groups. This supports peer learning and develops
         collaboration skills. Each group will compose Pachelbel's canon of
@@ -61,47 +61,42 @@
         another cellos. Composing occurs in terms of simple commands. One can
         program a set of notes and listen the melody created. Ready version is
         sent to the teacher. Teacher can combine different parts and play them
-        simultaneously. The symphony is ready!
+        simultaneously. The symphony is ready!

-        The task can be performed at many levels.
-        1) Routine practice of musical notations and programming structures:
+
The task can be performed at many levels.

+
+
1) Routine practice of musical notations and programming structures:
           pupils can converts straight a sheet of music to commands that play
-          the music
-        2) pupils can create melodies of their own. Like in Pachelbel's canon
+          the music

+
2) pupils can create melodies of their own. Like in Pachelbel's canon
         the teacher can set a chord progression that must be followed. That also
-        ensures that separately composed parts will play in harmony.
+        ensures that separately composed parts will play in harmony.

-        to  Each member has their own responsibility of their own part.
+
to  Each member has their own responsibility of their own part.
+        Divide and conquer.
+        This provides an environment of learning logical thinking,  programming conditions function

+
Music production is strongly connected to technology. The purpose of MuSiika is to enlarge the variety of teaching methods

+
Lesson plan: Music 60 min

+
Exercise given last week: find a piece that represents the Baroque style)

-
-         This provides an environment of learning logical thinking,  programming conditions function
-
-        Music production is strongly connected to technology. As the Even more in Music As the music techThe purpose of MuSiika is to enlarge the variety of teaching methods
-
-        Lesson plan: Music 60 min
-        Exercise given last week: find a piece that represents the Baroque style)
-
-        5 min
-        - Check the exercises
-        - Introduce of Pachelbel's canon in terms of Baroque music
-        15 min
-        - Introduce of the MuSiika tool
-          - Explanation of the basic commands and how does the cooperating work
-        10 min
-        - set up the groups
-          - Each group member should have a part of their own to compose
-        15 min
-        - Group working
-        10 min
-        - Pointing out the chord progression and ground bass, demonstration of
-          the use in pop music (e.g. Oasis - "Don't look back in Anger" )
-        5 min
-        - Exercise: Compose a new part to Pachelbel's Canon
-
-
-
+
5 min

+
- Check the exercises

+
- Introduce of Pachelbel's canon in terms of Baroque music

+
15 min

+
- Introduce of the MuSiika tool

+
- Explanation of the basic commands and how does the cooperating work

+
10 min

+
- set up the groups

+
 - Each group member should have a part of their own to compose

+
15 min

+
- Group working

+
10 min

+
- Pointing out the chord progression and ground bass, demonstration of
+          the use in pop music (e.g. Oasis - "Don't look back in Anger" )

+
5 min

+
- Exercise: Compose a new part to Pachelbel's Canon


Use @mention for name

Use @mention for name

--- src/quip.coffee
+++ src/quip.coffee
@@ -65,8 +65,11 @@
         @robot.logger.error "Giving up"
     else
       @socketUrl = response.url
-      @robot.name = "https://quip.com/" + response.user_id
+      @robot.name = @.quipMention(response.user_id)
       @connect()
+
+  quipMention: (userId) ->
+    return "https://quip.com/" + userId

   messageSent: (error, response) =>
     @robot.logger.error error if error
@@ -118,7 +121,7 @@
       when "message"
         if @robot.name.indexOf(packet.user.id) != -1
           return
-        user = @robot.brain.userForId packet.user.id, name: packet.user.name, room: packet.thread.id
+        user = @robot.brain.userForId packet.user.id, name: @.quipMention(packet.user.id), room: packet.thread.id
         message = new TextMessage user, packet.message.text, packet.message.id
         @robot.receive message
       else


Add doc for undo.

Add doc for undo.


updated meme list command to send one message with all commands instead of one message per command

--- src/memes.coffee
+++ src/memes.coffee
@@ -58,8 +58,9 @@
   meme_choices = (meme for _, meme of memes).sort().join('|')

   robot.respond /meme list/i, (msg) ->
-    for code, meme of memes
-      msg.send "#{code} - #{meme}"
+    memelist = ''
+    memelist += "#{code} - #{meme}\n" for code, meme of memes
+    msg.send memelist

   robot.respond /meme me (\w+) (\"[^"]+\") (\"[^"]+\")/i, (msg) ->


Remove debug line

Remove debug line

--- data.coffee
+++ data.coffee
@@ -19,7 +19,6 @@
         @_node
     set: (newVal) ->
       unless EJSON.equals @_node, newVal
-        console.warn "[@define 'node'] [set] UPDATED!"
         @_node = newVal

   ###


remove unneeded trailing slash stuff

remove unneeded trailing slash stuff

--- router/router.coffee
+++ router/router.coffee
@@ -10,7 +10,6 @@
     add_change_listener: (fn) -> window.addEventListener 'hashchange', -> fn()
     get_address:         -> window.location.hash.substr 1
     redirect:            (address) -> window.location.hash = address
-    notrailingslash:     false

 # urls: array of urlpatterns
 exports.route = (_urls, _options={}) ->
@@ -22,8 +21,6 @@
     console.groupEnd()

     navigate = (address=options.get_address(), urls=_urls) ->
-        unless options.notrailingslash
-            address += '/' unless address[address.length-1] == '/'
         console.groupCollapsed "navigate to: #{address}"

         handler = null
@@ -45,7 +42,5 @@
     navigate()  # explicitly check address on initialization

 exports.redirect = (address) ->
-    unless options.notrailingslash
-        address += '/' unless address[address.length-1] == '/'
     console.log "redirecting to `#{address}'"
     options.redirect address


no justin

no justin

--- scripts/name-expander.coffee
+++ scripts/name-expander.coffee
@@ -9,7 +9,6 @@
 jesse = "Jesse Howarth"
 kyle = "kallan"
 andrew = "Andrew Garson"
-justin = "Justin Campbell"
 trotter = "Trotter Cashion"
 afeng = "Aaron Feng"
 bennett = "bsprugel"
@@ -19,14 +18,13 @@

 noc_members = ["Carter1", "Cames1", "jdowns", "jdowns1", "jtramullas", "nstuhring", "ctrytten1", "ctrytten", "akim", "nsanches", "jkim", "ebednik", "nhooper"]

-dert_mermbers = ["CDERCKERSERN", "MAHCHERLERVER", "JKERL", "CHIN YERN", "KERLERN", "ERNDRERW GERSERN", "JERSTEN CERMPBELL"]
+dert_mermbers = ["CDERCKERSERN", "MAHCHERLERVER", "JKERL", "CHIN YERN", "KERLERN", "ERNDRERW GERSERN"]

 build_members = ["mvuong", "mstewart", "jromigh", "pmckeown", "pmckeown2", "pmckeown_home2", "hzhang", "helen"]

 merlin_remote_members = [
   cliff,
   ivey,
-  justin
 ]

 merlin_lax_members = [


removing space for devinf/di

removing space for devinf/di

--- scripts/name-expander.coffee
+++ scripts/name-expander.coffee
@@ -100,5 +100,5 @@
   robot.hear /^@?(build)( team| dudes| guys)*(:| )(.+)/i, (msg) ->
     msg.send build_members.join(", ") + ": ^^"

-  robot.hear /^(di|devinf) ( team| dudes| guys)*:(.+)/i, (msg) ->
+  robot.hear /^(di|devinf)( team| dudes| guys)*:(.+)/i, (msg) ->
     msg.send devinf_members.join(", ") + ": ^^"


fix define_functions

fix define_functions

--- src/core.coffee
+++ src/core.coffee
@@ -55,6 +55,7 @@

   lead.define_functions = (ns, names) ->
     ns[name] = lead_fn name for name in names
+    ns

   lead.to_string = (node) ->
     unless node instanceof lead.type


add ml example

add ml example

--- server/scripts/load_scales.coffee
+++ server/scripts/load_scales.coffee
@@ -10,6 +10,8 @@
   get:
     #roleRequired: 'root',
     action: () ->
+
+      ml_scales.remove '*'

       sheet = '/home/cloo/scales.csv'
       scales = API.convert.csv2json(undefined,fs.readFileSync(sheet).toString())
@@ -19,5 +21,6 @@
         for k of s
           s[k] = 0 if typeof s[k] is 'string' and s[k].toLowerCase() is 'na'
         ml_scales.insert s
+        count += 1

       return count


fix a typo

fix a typo

--- src/data.coffee
+++ src/data.coffee
@@ -2,7 +2,7 @@
 yaml = require("js-yaml");
 {encrypt, decrypt} = require("triplesec");

-loadConfig = (fileLocation, key, callback) ->
+loadConfig = (fileLocation, key, cb) ->
   fileString = fs.readFileSync(fileLocation)
   data = new Buffer fileString
   decrypt { key, data }, (err, raw) ->


Removed unused test.

Removed unused test.

--- test/CsvTransformerSpec.coffee
+++ test/CsvTransformerSpec.coffee
@@ -1,38 +0,0 @@
-expect = require('chai').expect
-fs = require('fs')
-path = require('path')
-CsvTransformer = require('../src/CsvTransformer')
-TestUtils = require('./util/TestUtils')
-_ = require('lodash')
-
-getFixtureCsv = -> TestUtils.readFixture('ITEM.csv')
-getFixtureJson = -> TestUtils.readFixture('ITEM.json')
-
-describe 'A CsvTransformer', ->
-
-  transformer = expectedCsv = expectedJson = null
-
-  beforeEach ->
-    transformer = new CsvTransformer()
-    expectedCsv = getFixtureCsv()
-    expectedJson = JSON.parse(getFixtureJson())
-  afterEach -> transformer = null
-
-  it 'can be constructed', -> expect(transformer).not.to.equal(null)
-
-  # TODO(aramk) Empty string values should be changed to null in the JSON. This superclass does't
-  # do it yet.
-
-  xit 'can convert to JSON', (done) ->
-    transformer.toJson(expectedCsv).then (json) ->
-      expect(json).deep.to.equal(expectedJson)
-      done()
-
-  xit 'can convert from JSON', (done) ->
-    transformer.fromJson(expectedJson).then (newCsv) ->
-      expect(newCsv).to.deep.equal(expectedCsv)
-      transformer.toJson(newCsv).then (newJson) ->
-        # CSV input and stringifier will produce slightly different whitespace, so we check only
-        # the JSON.
-        expect(newJson).to.deep.equal(expectedJson)
-        done()


moved exports to flag on class/code objects

--- src/nodes.coffee
+++ src/nodes.coffee
@@ -381,11 +381,13 @@
         compiledNodes.push node.compileNode o
       else if top
         node.front = true
+        if @exportAll then node.match [  # add assignment in here
+          M("exported", Class), M("exported", Code)
+          new Assign(any, M("exported", Code)).when((a)->a.isCodeDef())
+          ({exported}) =>
+            exported.shouldExport = yes
+        ]
         fragments = node.compileToFragments o
-        if @exportAll then node.match [  # add assignment in here
-          Class, Code, new Assign(any, any).when((a)->a.isCodeDef()), () =>
-            fragments.unshift @makeCode "export "
-        ]
         unless node.isStatement o
           fragments.unshift @makeCode "#{@tab}"
           fragments.push @makeCode ";"
@@ -1205,6 +1207,7 @@
     prelude = []
     declaration = [
       @makeCode indent
+      @makeCode if @shouldExport then "export " else ""
       @makeCode "class #{name}"
       if @parent then [
         @makeCode( " extends "),
@@ -1557,7 +1560,8 @@
           ]
         [argscode, @makeCode(' => '), bodycode]
       else if @name? and not @bound
-        [@makeCode("#{@tab}function "), @name.compileNode(o), argscode, bodycode]
+        exportFlag = if @shouldExport then "export " else ""
+        [@makeCode("#{@tab}#{exportFlag}function "), @name.compileNode(o), argscode, bodycode]
       else if not @bound
         [@makeCode("function"), argscode, bodycode]
       else


Try to fix tabs

Try to fix tabs

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -17,8 +17,6 @@
     invisibles:
       tab: "→"
     showInvisibles: true
-    softTabs: false
-    tabLength: 4
   "file-icons":
     coloured: false
   fonts:
@@ -31,14 +29,14 @@
     elmMakeExecutablePath: "/home/dan/node/bin/elm-make"
   "linter-eslint":
     disableWhenNoEslintrcFileInPath: true
-  "linter-flake8":
-    projectConfigFile: ".flake8"
+  "linter-flake8": {}
   "linter-jscs":
     onlyConfig: true
   "linter-jshint":
     disableWhenNoJshintrcFileInPath: true
   "linter-scss-lint":
     disableWhenNoConfigFileInPath: true
+  "node-debugger": {}
   "proto-repl": {}
   tabs:
     showIcons: true
@@ -48,6 +46,9 @@
 ".elm.source":
   editor:
     autoIndentOnPaste: true
+".js.regexp.replacement.source":
+  editor:
+    tabLength: 4
 ".python.source":
   editor:
     autoIndentOnPaste: true


Set Baskfile file type to source.shell in atom config.

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -37,6 +37,7 @@
   "tree-view": {}
   "autocomplete-plus": {}
   "file-types":
+    "^Baskfile$": "source.shell"
     "^.gitignore": "source.git-config"
     "^.gvimrc.after": "source.viml"
     "^.profile$": "source.shell"


copy and paste everywhere

copy and paste everywhere

--- home/.atom/keymap.cson
+++ home/.atom/keymap.cson
@@ -179,6 +179,17 @@
   # Because vim-search is actually kinda lame
   '/':       'find-and-replace:show'
   'ctrl-/':  'project-find:show'
+
+##############################################################################
+# vim-mode-plus overrides (because I want these commands to work in every mode)
+##############################################################################
+'atom-text-editor.vim-mode-plus, atom-text-editor.vim-mode-plus-input':
+  # ctrl-c should *always* copy
+  'ctrl-c': 'core:copy'
+
+'atom-text-editor.vim-mode-plus.normal-mode, atom-text-editor.vim-mode-plus.visual-mode':
+  # ctrl-v should *always* paste
+  'ctrl-v': 'core:paste'

 ###############################################


Don't close pinned tabs when pressing x

Don't close pinned tabs when pressing x

Firefox doesn't allow closing pinned tabs with a GUI button nor by
pressing Ctrl+W. This commit introduces similar behaviour in VimFx.
Pinned tabs won't be closed by pressing x.

--- extension/packages/commands.coffee
+++ extension/packages/commands.coffee
@@ -166,7 +166,8 @@
 # Close current tab
 command_x = (vim) ->
   if rootWindow = utils.getRootWindow vim.window
-    rootWindow.gBrowser.removeCurrentTab()
+    unless rootWindow.gBrowser.selectedTab.pinned
+      rootWindow.gBrowser.removeCurrentTab()

 # Restore last closed tab
 command_X = (vim) ->


Translate function changes

Translate function changes

--- script/i18n.coffee
+++ script/i18n.coffee
@@ -26,10 +26,7 @@
 		# but it makes sense when you write it. Defaults to "span".
 		tag = tag.join('') || 'span'

-		markup = ''
-
-		for lang, string of translations
-			markup += "<#{tag} lang=\"#{lang}\">#{string}</#{tag}>"
-
-		# Generate an element list from the markup.
-		$(markup)
+		markup = do ->
+			temp = for lang, string of translations
+				markup += "<#{tag} lang=\"#{lang}\">#{string}</#{tag}>"
+			temp.join('')