Only show 'Init' command when there is no repo in project.

Re-activate package after 'Init' to enable all other commands

--- lib/git-plus.coffee
+++ lib/git-plus.coffee
@@ -84,66 +84,67 @@
     @subscriptions = new CompositeDisposable
     repos = atom.project.getRepositories().filter (r) -> r?
     if repos.length is 0
-      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:init', -> GitInit()
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:menu', -> new GitPaletteView()
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:add', -> git.getRepo().then((repo) -> git.add(repo, file: currentFile(repo)))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:add-modified', -> git.getRepo().then((repo) -> git.add(repo, update: true))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:add-all', -> git.getRepo().then((repo) -> git.add(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:commit', -> git.getRepo().then((repo) -> GitCommit(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:commit-all', -> git.getRepo().then((repo) -> GitCommit(repo, stageChanges: true))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:commit-amend', -> git.getRepo().then((repo) -> new GitCommitAmend(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:add-and-commit', -> git.getRepo().then((repo) -> git.add(repo, file: currentFile(repo)).then -> GitCommit(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:add-and-commit-and-push', -> git.getRepo().then((repo) -> git.add(repo, file: currentFile(repo)).then -> GitCommit(repo, andPush: true))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:add-all-and-commit', -> git.getRepo().then((repo) -> git.add(repo).then -> GitCommit(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:add-all-commit-and-push', -> git.getRepo().then((repo) -> git.add(repo).then -> GitCommit(repo, andPush: true))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:commit-all-and-push', -> git.getRepo().then((repo) -> GitCommit(repo, stageChanges: true, andPush: true))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:checkout', -> git.getRepo().then((repo) -> GitBranch.gitBranches(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:checkout-remote', -> git.getRepo().then((repo) -> GitBranch.gitRemoteBranches(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:checkout-current-file', -> git.getRepo().then((repo) -> GitCheckoutFile(repo, file: currentFile(repo)))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:checkout-all-files', -> git.getRepo().then((repo) -> GitCheckoutAllFiles(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:new-branch', -> git.getRepo().then((repo) -> GitBranch.newBranch(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:delete-local-branch', -> git.getRepo().then((repo) -> GitDeleteLocalBranch(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:delete-remote-branch', -> git.getRepo().then((repo) -> GitDeleteRemoteBranch(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:cherry-pick', -> git.getRepo().then((repo) -> GitCherryPick(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:diff', -> git.getRepo().then((repo) -> GitDiff(repo, file: currentFile(repo)))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:difftool', -> git.getRepo().then((repo) -> GitDifftool(repo, file: currentFile(repo)))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:diff-all', -> git.getRepo().then((repo) -> GitDiffAll(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:fetch', -> git.getRepo().then((repo) -> GitFetch(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:fetch-prune', -> git.getRepo().then((repo) -> GitFetchPrune(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:pull', -> git.getRepo().then((repo) -> GitPull(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:pull-using-rebase', -> git.getRepo().then((repo) -> GitPull(repo, rebase: true))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:push', -> git.getRepo().then((repo) -> GitPush(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:push-set-upstream', -> git.getRepo().then((repo) -> GitPush(repo, setUpstream: true))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:remove', -> git.getRepo().then((repo) -> GitRemove(repo, showSelector: true))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:remove-current-file', -> git.getRepo().then((repo) -> GitRemove(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:reset', -> git.getRepo().then((repo) -> git.reset(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:show', -> git.getRepo().then((repo) -> GitShow(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:log', -> git.getRepo().then((repo) -> GitLog(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:log-current-file', -> git.getRepo().then((repo) -> GitLog(repo, onlyCurrentFile: true))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:stage-files', -> git.getRepo().then((repo) -> GitStageFiles(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:unstage-files', -> git.getRepo().then((repo) -> GitUnstageFiles(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:stage-hunk', -> git.getRepo().then((repo) -> GitStageHunk(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:stash-save', -> git.getRepo().then((repo) -> GitStashSave(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:stash-save-message', -> git.getRepo().then((repo) -> GitStashSaveMessage(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:stash-pop', -> git.getRepo().then((repo) -> GitStashPop(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:stash-apply', -> git.getRepo().then((repo) -> GitStashApply(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:stash-delete', -> git.getRepo().then((repo) -> GitStashDrop(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:status', -> git.getRepo().then((repo) -> GitStatus(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:tags', -> git.getRepo().then((repo) -> GitTags(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:run', -> git.getRepo().then((repo) -> new GitRun(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:merge', -> git.getRepo().then((repo) -> GitMerge(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:merge-remote', -> git.getRepo().then((repo) -> GitMerge(repo, remote: true))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:merge-no-fast-forward', -> git.getRepo().then((repo) -> GitMerge(repo, noFastForward: true))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:rebase', -> git.getRepo().then((repo) -> GitRebase(repo))
-    @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:git-open-changed-files', -> git.getRepo().then((repo) -> GitOpenChangedFiles(repo))
-    @subscriptions.add atom.commands.add '.tree-view', 'git-plus-context:add', -> GitAddContext()
-    @subscriptions.add atom.commands.add '.tree-view', 'git-plus-context:add-and-commit', -> GitAddAndCommitContext()
-    @subscriptions.add atom.commands.add '.tree-view', 'git-plus-context:checkout-file', -> GitCheckoutFileContext()
-    @subscriptions.add atom.commands.add '.tree-view', 'git-plus-context:diff', -> GitDiffContext()
-    @subscriptions.add atom.commands.add '.tree-view', 'git-plus-context:difftool', -> GitDifftoolContext()
-    @subscriptions.add atom.commands.add '.tree-view', 'git-plus-context:unstage-file', -> GitUnstageFileContext()
-    @subscriptions.add atom.config.observe 'git-plus.syntaxHighlighting', setDiffGrammar
-    @subscriptions.add atom.config.observe 'git-plus.wordDiff', setDiffGrammar
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:init', => GitInit().then => @activate()
+    else
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:menu', -> new GitPaletteView()
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:add', -> git.getRepo().then((repo) -> git.add(repo, file: currentFile(repo)))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:add-modified', -> git.getRepo().then((repo) -> git.add(repo, update: true))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:add-all', -> git.getRepo().then((repo) -> git.add(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:commit', -> git.getRepo().then((repo) -> GitCommit(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:commit-all', -> git.getRepo().then((repo) -> GitCommit(repo, stageChanges: true))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:commit-amend', -> git.getRepo().then((repo) -> new GitCommitAmend(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:add-and-commit', -> git.getRepo().then((repo) -> git.add(repo, file: currentFile(repo)).then -> GitCommit(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:add-and-commit-and-push', -> git.getRepo().then((repo) -> git.add(repo, file: currentFile(repo)).then -> GitCommit(repo, andPush: true))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:add-all-and-commit', -> git.getRepo().then((repo) -> git.add(repo).then -> GitCommit(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:add-all-commit-and-push', -> git.getRepo().then((repo) -> git.add(repo).then -> GitCommit(repo, andPush: true))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:commit-all-and-push', -> git.getRepo().then((repo) -> GitCommit(repo, stageChanges: true, andPush: true))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:checkout', -> git.getRepo().then((repo) -> GitBranch.gitBranches(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:checkout-remote', -> git.getRepo().then((repo) -> GitBranch.gitRemoteBranches(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:checkout-current-file', -> git.getRepo().then((repo) -> GitCheckoutFile(repo, file: currentFile(repo)))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:checkout-all-files', -> git.getRepo().then((repo) -> GitCheckoutAllFiles(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:new-branch', -> git.getRepo().then((repo) -> GitBranch.newBranch(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:delete-local-branch', -> git.getRepo().then((repo) -> GitDeleteLocalBranch(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:delete-remote-branch', -> git.getRepo().then((repo) -> GitDeleteRemoteBranch(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:cherry-pick', -> git.getRepo().then((repo) -> GitCherryPick(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:diff', -> git.getRepo().then((repo) -> GitDiff(repo, file: currentFile(repo)))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:difftool', -> git.getRepo().then((repo) -> GitDifftool(repo, file: currentFile(repo)))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:diff-all', -> git.getRepo().then((repo) -> GitDiffAll(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:fetch', -> git.getRepo().then((repo) -> GitFetch(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:fetch-prune', -> git.getRepo().then((repo) -> GitFetchPrune(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:pull', -> git.getRepo().then((repo) -> GitPull(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:pull-using-rebase', -> git.getRepo().then((repo) -> GitPull(repo, rebase: true))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:push', -> git.getRepo().then((repo) -> GitPush(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:push-set-upstream', -> git.getRepo().then((repo) -> GitPush(repo, setUpstream: true))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:remove', -> git.getRepo().then((repo) -> GitRemove(repo, showSelector: true))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:remove-current-file', -> git.getRepo().then((repo) -> GitRemove(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:reset', -> git.getRepo().then((repo) -> git.reset(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:show', -> git.getRepo().then((repo) -> GitShow(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:log', -> git.getRepo().then((repo) -> GitLog(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:log-current-file', -> git.getRepo().then((repo) -> GitLog(repo, onlyCurrentFile: true))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:stage-files', -> git.getRepo().then((repo) -> GitStageFiles(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:unstage-files', -> git.getRepo().then((repo) -> GitUnstageFiles(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:stage-hunk', -> git.getRepo().then((repo) -> GitStageHunk(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:stash-save', -> git.getRepo().then((repo) -> GitStashSave(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:stash-save-message', -> git.getRepo().then((repo) -> GitStashSaveMessage(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:stash-pop', -> git.getRepo().then((repo) -> GitStashPop(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:stash-apply', -> git.getRepo().then((repo) -> GitStashApply(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:stash-delete', -> git.getRepo().then((repo) -> GitStashDrop(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:status', -> git.getRepo().then((repo) -> GitStatus(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:tags', -> git.getRepo().then((repo) -> GitTags(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:run', -> git.getRepo().then((repo) -> new GitRun(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:merge', -> git.getRepo().then((repo) -> GitMerge(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:merge-remote', -> git.getRepo().then((repo) -> GitMerge(repo, remote: true))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:merge-no-fast-forward', -> git.getRepo().then((repo) -> GitMerge(repo, noFastForward: true))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:rebase', -> git.getRepo().then((repo) -> GitRebase(repo))
+      @subscriptions.add atom.commands.add 'atom-workspace', 'git-plus:git-open-changed-files', -> git.getRepo().then((repo) -> GitOpenChangedFiles(repo))
+      @subscriptions.add atom.commands.add '.tree-view', 'git-plus-context:add', -> GitAddContext()
+      @subscriptions.add atom.commands.add '.tree-view', 'git-plus-context:add-and-commit', -> GitAddAndCommitContext()
+      @subscriptions.add atom.commands.add '.tree-view', 'git-plus-context:checkout-file', -> GitCheckoutFileContext()
+      @subscriptions.add atom.commands.add '.tree-view', 'git-plus-context:diff', -> GitDiffContext()
+      @subscriptions.add atom.commands.add '.tree-view', 'git-plus-context:difftool', -> GitDifftoolContext()
+      @subscriptions.add atom.commands.add '.tree-view', 'git-plus-context:unstage-file', -> GitUnstageFileContext()
+      @subscriptions.add atom.config.observe 'git-plus.syntaxHighlighting', setDiffGrammar
+      @subscriptions.add atom.config.observe 'git-plus.wordDiff', setDiffGrammar

   deactivate: ->
     @subscriptions.dispose()


Fix View require and editor value.

Fix View require and editor value.

see https://github.com/atom-community/autocomplete-plus/commit/4fe30ec8edfd2c38a01dc52176e6d88f8cdba637

--- lib/provider.coffee
+++ lib/provider.coffee
@@ -1,4 +1,4 @@
-{View} = require 'space-pen'
+{View} = require 'atom'
 {deprecate} = require 'grim'

 # Public: A provider provides an interface to the autocomplete package. Third-party


Use atom.getVersion()

Use atom.getVersion()

--- lib/reporter.coffee
+++ lib/reporter.coffee
@@ -11,7 +11,7 @@
           user_agent: navigator.userAgent
           screen_resolution: screen.width + "x" + screen.height
           pixel_ratio: window.devicePixelRatio
-          version: atom.version
+          version: atom.getVersion()
         context:
           packages: @getPackageData()
           themes: @getThemeData()
@@ -24,7 +24,7 @@
         dimensions:
           actor_login: process.env.USER
           user_agent: navigator.userAgent
-          version: atom.version
+          version: atom.getVersion()
         measures:
           session_length: sessionLength


add description to promote maximize-pane

--- lib/settings.coffee
+++ lib/settings.coffee
@@ -137,7 +137,9 @@
   showHoverSearchCounterDuration:
     default: 700
     description: "Duration(msec) for hover search counter"
-  hideTabBarOnMaximizePane: true
+  hideTabBarOnMaximizePane:
+    default: true
+    description: "If set to `false`, tab still visible after maximize-pane( `cmd-enter` )"
   smoothScrollOnFullScrollMotion:
     default: false
     description: "For `ctrl-f` and `ctrl-b`"


Minor changes to follow Atom guides

Minor changes to follow Atom guides

--- lib/snippets.coffee
+++ lib/snippets.coffee
@@ -4,6 +4,7 @@
 CSON = require 'season'
 {File} = require 'pathwatcher'
 fs = require 'fs-plus'
+
 {Point, Range} = require 'atom'

 Snippet = require './snippet'
@@ -141,7 +142,7 @@
     editor.setSelectedBufferRange new Range(startPoint, endPoint)
     startPoint

-  insert: (snippet, editor = atom.workspace.getActiveEditor()) ->
+  insert: (snippet, editor=atom.workspace.getActiveEditor()) ->
     if typeof snippet is 'string'
       bodyTree = @getBodyParser().parse(snippet)
       snippet = new Snippet({name: '__anonymous', prefix: '', bodyTree: bodyTree, bodyText: snippet})


Extra an handleEvents helper

Extra an handleEvents helper

--- lib/tab-view.coffee
+++ lib/tab-view.coffee
@@ -9,6 +9,14 @@
       @div class: 'close-icon'

   initialize: (@item, @pane) ->
+    @handleEvents()
+    @updateDataAttributes()
+    @updateTitle()
+    @updateIcon()
+    @updateModifiedStatus()
+    @setupTooltip()
+
+  handleEvents: ->
     @titleSubscription = @item.onDidChangeTitle? =>
       @updateDataAttributes()
       @updateTitle()
@@ -22,12 +30,6 @@

     @configSubscription = atom.config.observe 'tabs.showIcons', =>
       @updateIconVisibility()
-
-    @updateDataAttributes()
-    @updateTitle()
-    @updateIcon()
-    @updateModifiedStatus()
-    @setupTooltip()

   setupTooltip: ->
     # Defer creating the tooltip until the tab is moused over


Always call clearPreview

Always call clearPreview

--- lib/tab-view.coffee
+++ lib/tab-view.coffee
@@ -169,7 +169,7 @@

   updateModifiedStatus: ->
     if @item.isModified?()
-      @clearPreview() if atom.config.get('tabs.usePreviewTabs')
+      @clearPreview()
       @classList.add('modified') unless @isModified
       @isModified = true
     else


:new: Add support for indie linters in validators

--- lib/validate.coffee
+++ lib/validate.coffee
@@ -3,13 +3,14 @@

 module.exports = Validate =

-  linter: (linter) ->
-    unless linter.grammarScopes instanceof Array
-      throw new Error("grammarScopes is not an Array. Got: #{linter.grammarScopes}")
-    if linter.lint
-      throw new Error("linter.lint isn't a function on provider") if typeof linter.lint isnt 'function'
-    else
-      throw new Error('Missing linter.lint on provider')
+  linter: (linter, indie = false) ->
+    unless indie
+      unless linter.grammarScopes instanceof Array
+        throw new Error("grammarScopes is not an Array. Got: #{linter.grammarScopes}")
+      if linter.lint
+        throw new Error("linter.lint isn't a function on provider") if typeof linter.lint isnt 'function'
+      else
+        throw new Error('Missing linter.lint on provider')
     if linter.name
       throw new Error('Linter.name must be a string') if typeof linter.name isnt 'string'
     else


Fix require

Fix require

--- src/space-pencil.coffee
+++ src/space-pencil.coffee
@@ -1,4 +1,4 @@
-Builder = require '../src/builder'
+Builder = require './builder'
 builder = new Builder

 exports.$$ = (fn) -> builder.buildElement(fn)


fixed a typo

fixed a typo

--- src/spatial-hash.coffee
+++ src/spatial-hash.coffee
@@ -44,7 +44,7 @@
     minX = MAX(minX, 0)
     maxX = CEIL(maxX/pixelWidth)*pixelWidth - 1  if maxX % pixelHeight != 0
     minY = FLOOR(minY/pixelHeight)*pixelHeight + 1 if minY % pixelHeight != 0
-    minY = MAX(minX, 0)
+    minY = MAX(minY, 0)
     maxY = CEIL(maxY/pixelHeight)*pixelHeight - 1  if maxY % pixelHeight != 0

     for x in [minX..maxX] by pixelWidth


translate settings.cson into zh-tw

translate settings.cson into zh-tw

--- def/zh-tw/settings.cson
+++ def/zh-tw/settings.cson
@@ -1,388 +1,350 @@
 Settings:
-  "tab-title": "Settings"
+  "tab-title": "設定"
   menu: [
     {
       _label: "Core"
-      value: "Core"
+      value: "核心"
     }
     {
       _label: "Editor"
-      value: "Editor"
+      value: "編輯器"
     }
     {
       _label: "Keybindings"
-      value: "Keybindings"
+      value: "快捷鍵綁定"
     }
     {
       _label: "Packages"
-      value: "Packages"
+      value: "擴充套件"
     }
     {
       _label: "Themes"
-      value: "Themes"
+      value: "佈景主題"
     }
     {
       _label: "Updates"
-      value: "Updates"
+      value: "更新"
     }
     {
       _label: "Install"
-      value: "Install"
+      value: "安裝"
     }
   ]
-  "btn-open-config-folder": "Open Config Folder"
+  "btn-open-config-folder": "開啟設定資料夾"
   sectionHeadings: [
-    {_label: "Core Settings", value: "Core Settings"}
-    {_label: "Editor Settings", value: "Editor Settings"}
-    {_label: "Keybindings", value: "Keybindings"}
-    {_label: "Installed Packages", value: "Installed Packages"}
-    {_label: "Choose a Theme", value: "Choose a Theme"}
-    {_label: "Installed Themes", value: "Installed Themes"}
-    {_label: "Install Packages", value: "Install Packages"}
-    {_label: "Featured Packages", value: "Featured Packages"}
-    {_label: "Install Themes", value: "Install Themes"}
-    {_label: "Featured Themes", value: "Featured Themes"}
+    {_label: "Core Settings", value: "核心設定"}
+    {_label: "Editor Settings", value: "編輯器設定"}
+    {_label: "Keybindings", value: "快捷鍵綁定"}
+    {_label: "Installed Packages", value: "已安裝的擴充套件"}
+    {_label: "Choose a Theme", value: "選擇一個佈景主題"}
+    {_label: "Installed Themes", value: "已安裝的佈景主題"}
+    {_label: "Install Packages", value: "安裝擴充套件"}
+    {_label: "Featured Packages", value: "特色擴充套件"}
+    {_label: "Install Themes", value: "安裝佈景主題"}
+    {_label: "Featured Themes", value: "特色佈景主題"}
   ]
-  "heading-available-updates": {_label: "Available Updates", value: "Available Updates"}
+  "heading-available-updates": {_label: "Available Updates", value: "可用的更新"}
   subSectionHeadings: [
-    {_label: "Invisible", value: "Invisible"}
-    {_label: "Community Packages", value: "Community Packages"}
-    {_label: "Core Packages", value: "Core Packages"}
-    {_label: "Development Packages", value: "Development Packages"}
-    {_label: "Git Packages", value: "Git Packages"}
-    {_label: "Community Themes", value: "Community Themes"}
-    {_label: "Core Themes", value: "Core Themes"}
-    {_label: "Development Themes", value: "Development Themes"}
-    {_label: "Git Themes", value: "Git Themes"}
+    {_label: "Invisible", value: "隱藏字元"}
+    {_label: "Community Packages", value: "社群開發的擴充套件"}
+    {_label: "Core Packages", value: "核心擴充套件"}
+    {_label: "Development Packages", value: "開發中的擴充套件"}
+    {_label: "Git Packages", value: "由 Git 倉庫（Repository）安裝的擴充套件"}
+    {_label: "Community Themes", value: "社群開發的佈景主題"}
+    {_label: "Core Themes", value: "核心佈景主題"}
+    {_label: "Development Themes", value: "開發中的佈景主題"}
+    {_label: "Git Themes", value: "由 Git 倉庫（Repository）安裝的佈景主題"}
   ]
   settings: {
     notes: [
       {
         _id: 'core-settings-note'
-        html: 'These are Atom\'s core settings which affect behavior
-               unrelated to text editing. Individual packages may have
-               their own additional settings found within their package
-               card in the Packages list.'
+        html: '這些 Atom 核心設定與文字編輯操作無關。各個擴充套件可能有額外的設定，可於擴充套件清單中的擴充套件卡片內檢視。'
       }
       {
         _id: 'editor-settings-note'
-        html: 'These settings are related to text editing. Some of these
-               can be overriden on a per-language basis. Check language
-               settings by clicking its package card in the
-               Packages list.'
+        html: '這些是文字編輯操作的相關設定。有些設定會被各種程式語言的擴充套件所覆寫，可於擴充套件清單中的擴充套件卡片內檢視各種程式語言的文法設定。'
       }
     ]
     controls: [
       {
         _id: 'core.allowPendingPaneItems'
-        title: "Allow Pending PaneItems"
-        desc: "Allow items to be previewed without adding them to a pane
-               permanently, such as when single clicking files in the tree view."
+        title: "允許預覽分頁"
+        desc: "允許使用預覽分頁預覽項目，不需將其加入窗格，例如於 tree view 點擊項目時開啟預覽分頁。"
       }
       {
         _id: 'core.audioBeep'
-        title: "Audio Beep"
-        desc: "Trigger the system's beep sound when certain actions cannot be
-               executed or there are no results."
+        title: "提示音"
+        desc: "當特定操作不能執行，或是沒有執行結果時，觸發系統提示音。"
       }
       {
         _id: 'core.automaticallyUpdate'
-        title: "Automatically Update"
-        desc: "Automatically update Atom when a new release is available."
+        title: "自動更新"
+        desc: "當有可用的更新時，自動更新 Atom 。"
       }
       {
         _id: 'core.autoHideMenuBar'
-        title: "Auto Hide Menu Bar"
-        desc: "Automatically hide the menu bar and toggle it by pressing Alt. This is only supported on Windows & Linux."
+        title: "自動隱藏功能表欄"
+        desc: "自動隱藏功能表欄，藉由點擊 Alt 鍵切換功能表欄。這項功能只支援於 Windows 與 Linux 作業系統。"
       }
       {
         _id: 'core.closeEmptyWindows'
-        title: "Close Empty Windows"
-        desc: "When a window with no open tabs or panes is given the 'Close Tab' command, close that window."
+        title: "關閉空視窗"
+        desc: "當視窗中沒有開啟的分頁或預覽分頁時，「關閉分頁」指令會關閉該視窗。"
       }
       {
         _id: 'core.destroyEmptyPanes'
-        title: "Destroy Empty Panes"
-        desc: "When the last tab of a pane is closed, remove that pane as well."
+        title: "自動移除空窗格"
+        desc: "當窗格中的最後一個分頁被關閉時，也移除該窗格。"
       }
       {
         _id: 'core.excludeVcsIgnoredPaths'
-        title: "Exclude VCS Ignored Paths"
-        desc: "Files and directories ignored by the current project's VCS system will be ignored by some packages, such as the fuzzy finder and find and replace. For example, projects using Git have these paths defined in the .gitignore file. Individual packages might have additional config settings for ignoring VCS ignored files and folders."
+        title: "排除版本控制系統（VCS）所忽略的路徑"
+        desc: "讓某些擴充套件例如：模糊尋找（fuzzy finder）、尋找與取代（find and replace），忽略當前專案中版本控制系統所忽略的檔案及路徑。例如，使用 Git 的專案會在 .gitignore 檔案裡定義所忽略的路徑。個別的擴充套件可能會提供額外設定選項來選擇是否忽略這些路徑。"
       }
       {
         _id: 'core.fileEncoding'
-        title: "File Encoding"
-        desc: "Default character set encoding to use when reading and writing files."
+        title: "檔案編碼"
+        desc: "設定讀寫檔案時預設使用的字元集編碼。"
       }
       {
         _id: 'core.followSymlinks'
-        title: "Follow Symlinks"
-        desc: "Follow symbolic links when searching files and when opening files with the fuzzy finder."
+        title: "允許使用符號連結（symbolic link）"
+        desc: "使用模糊尋找（fuzzy finder）時，允許尋找及開啟符號連結（symbolic link）所對應的檔案。"
       }
       {
         _id: 'core.ignoredNames'
-        title: "Ignored Names"
-        desc: "List of glob patterns. Files and directories matching these patterns will be ignored by some packages, such as the fuzzy finder and tree view. Individual packages might have additional config settings for ignoring names."
+        title: "忽略的檔案名稱"
+        desc: "檔案路徑規則，其格式符合函式 glob() 的參數 pattern 。符合規則的檔案和資料夾將會被某些擴充套件忽略，例如模糊尋找（fuzzy finder）或是 tree view。個別的擴充套件可能會使用額外的設定來忽略檔案。"
       }
       {
         _id: 'core.openEmptyEditorOnStart'
-        title: "Open Empty Editor On Start"
-        desc: "Automatically open an empty editor on startup."
+        title: "啟動時開啟空白文字編輯器"
+        desc: "啟動時，自動開啟一個空白的文字編輯器。"
       }
       {
         _id: 'core.packagesWithKeymapsDisabled'
-        title: "Packages With Keymaps Disabled"
+        title: "停用快捷鍵綁定的擴充套件"
       }
       {
         _id: 'core.projectHome'
-        title: "Project Home"
-        desc: "The directory where projects are assumed to be located. Packages created using the Package Generator will be stored here by default."
+        title: "專案根目錄"
+        desc: "此資料夾為預設情況下專案之位置。使用 Package Generator 建立的擴充套件預設會放在此資料夾中。"
       }
       {
         _id: 'core.reopenProjectMenuCount'
-        title: "Reopen Project Menu Count"
-        desc: "How many recent projects to show in the Reopen Project menu."
+        title: "重新開啟專案之顯示數量"
+        desc: "在「重新開啟專案」選單中，顯示的專案數量。"
       }
       {
         _id: 'core.restorePreviousWindowsOnStart'
-        title: "Restore Previous Windows On Start"
+        title: "啟動時回復視窗狀態"
       }
       {
         _id: 'core.telemetryConsent'
-        title: "Send Telemetry to the Atom Team"
-        desc: "Allow usage statistics and exception reports to be sent to the Atom team to help improve the product."
+        title: "傳送遙測記錄給 Atom 開發團隊"
+        desc: "允許將使用紀錄及錯誤報告傳送給 Atom 開發團隊以助於改善本產品。"
         select:
-          limited: "Allow limited anonymous usage stats, exception and crash reporting"
-          no: "Do not send any telemetry data"
-          undecided: "Undecided (Atom will ask again next time it is launched)"
+          limited: "允許以匿名傳送有限的使用數據、例外及錯誤報告"
+          no: "不要傳送任何遙測記錄資料"
+          undecided: "尚未決定（Atom 會於下次啟動時再次詢問）"
       }
       {
         _id: 'core.useCustomTitleBar'
-        title: "Use Custom Title Bar"
+        title: "使用自訂的視窗標題樣式"
       }
       {
         _id: 'core.warnOnLargeFileLimit'
-        title: "Warn On Large File Limit"
-        desc: "Warn before opening files larger than this number of megabytes."
+        title: "大檔案警告的檔案容量設定"
+        desc: "開啟的檔案容量超過此數字（單位為百萬位元組）時，顯示警告視窗。"
       }
       {
         _id: 'editor.atomicSoftTabs'
-        title: "Atomic Soft Tabs"
-        desc: "Skip over tab-length runs of leading whitespace when moving the cursor."
+        title: "在行前空白區域建立軟定位點"
+        desc: "使用鍵盤方向鍵於行前空白移動時，游標會根據定位點長度設定，跳至下個軟定位點。"
       }
       {
         _id: 'editor.autoIndent'
-        title: "Auto Indent"
-        desc: "Automatically indent the cursor when inserting a newline."
+        title: "自動縮排"
+        desc: "新增一行時，自動縮排游標對齊上一行。"
       }
       {
         _id: 'editor.autoIndentOnPaste'
-        title: "Auto Indent On Paste"
-        desc: "Automatically indent pasted text based on the indentation of the previous line."
+        title: "貼上時自動縮排"
+        desc: "根據上一行，自動縮排貼上的文字。"
       }
       {
         _id: 'editor.backUpBeforeSaving'
-        title: "Back Up Before Saving"
+        title: "自動備份"
         desc: ""
       }
       {
         _id: 'editor.confirmCheckoutHeadRevision'
-        title: "Confirm Checkout HEAD Revision"
-        desc: "Show confirmation dialog when checking out the HEAD revision and discarding changes to current file since last commit."
+        title: "Checkout 至 HEAD 版本時跳出確認視窗"
+        desc: "當執行 Checkout 至 HEAD 版本，放棄對最後一個 commit 的檔案修改時，跳出確認視窗。"
       }
       {
         _id: 'editor.fontFamily'
-        title: "Font Family"
-        desc: "The name of the font family used for editor text."
+        title: "編輯器字型"
+        desc: "文字編輯器顯示的字型名稱。"
       }
       {
         _id: 'editor.fontSize'
-        title: "Font Size"
-        desc: "Height in pixels of editor text."
+        title: "字型大小"
+        desc: "以像素（px）表示文字編輯器內顯示文字的高度。"
       }
       {
         _id: 'editor.invisibles.cr'
-        title: "Invisibles Cr"
-        desc: "Character used to render carriage return characters
-               (for Microsoft-style line endings) when the Show
-               Invisibles setting is enabled."
+        title: "斷行字元（Cr）"
+        desc: "啟動顯示隱藏字元設定時，微軟系統用來表示斷行（carriage return）的字元。"
       }
       {
         _id: 'editor.invisibles.eol'
-        title: "Invisibles Eol"
-        desc: "Character used to render newline characters (\n) when the
-               Show Invisibles setting is enabled."
+        title: "斷行字元（Eol）"
+        desc: "啟動顯示隱藏字元設定時，用來表示斷行（\\n）的字元。"
       }
       {
         _id: 'editor.invisibles.space'
-        title: "Invisibles Space"
-        desc: "Character used to render leading and trailing space characters
-               when the Show Invisibles setting is enabled."
+        title: "空白字元（space）"
+        desc: "啟動顯示隱藏字元設定時，用來表示行首與行尾空白的字元。"
       }
       {
         _id: 'editor.invisibles.tab'
-        title: "Invisibles Tab"
-        desc: "Character used to render hard tab characters (\t) when the
-               Show Invisibles setting is enabled."
+        title: "定位點（Tab）"
+        desc: "啟動顯示隱藏字元設定時，用來表示定位點（\\t）的字元。"
       }
       {
         _id: 'editor.lineHeight'
-        title: "Line Height"
-        desc: "Height of editor lines, as a multiplier of font size."
+        title: "行高"
+        desc: "文字編輯器內文字的行高，為字型大小的倍數。"
       }
       {
         _id: 'editor.nonWordCharacters'
-        title: "Non Word Characters"
-        desc: "A string of non-word characters to define word boundaries."
+        title: "不視為詞彙的字元"
+        desc: "下列字元將不被視為詞彙，而是拿來做為詞彙邊界。"
       }
       {
         _id: 'editor.preferredLineLength'
-        title: "Preferred Line Length"
-        desc: "Identifies the length of a line which is used when wrapping text
-               with the Soft Wrap At Preferred Line Length setting
-               enabled, in number of characters."
+        title: "每行字數"
+        desc: "啟動依據每行字數自動換行設定後，自動換行所參考的字數。單位：字元。"
       }
       {
         _id: 'editor.scrollPastEnd'
-        title: "Scroll Past End"
-        desc: "Allow the editor to be scrolled past the end of the last line."
+        title: "捲動瀏覽超越最後一行"
+        desc: "允許編輯器捲動瀏覽超越最後一行。"
       }
       {
         _id: 'editor.scrollSensitivity'
-        title: "Scroll Sensitivity"
-        desc: "Determines how fast the editor scrolls when using a mouse or
-               trackpad."
+        title: "捲動速度"
+        desc: "設定編輯器中使用滑鼠或觸控板捲動瀏覽的速度。"
       }
       {
         _id: 'editor.showIndentGuide'
-        title: "Show Indent Guide"
-        desc: "Show indentation indicators in the editor."
+        title: "顯示縮排對齊線"
+        desc: "在編輯器中顯示縮排對齊線。"
       }
       {
         _id: 'editor.showInvisibles'
-        title: "Show Invisibles"
-        desc: "Render placeholders for invisible characters, such as tabs,
-               spaces and newlines."
+        title: "顯示隱藏字元"
+        desc: "在編輯器中顯示隱藏字元符號，例如：定位點、空白和斷行。"
       }
       {
         _id: 'editor.showLineNumbers'
-        title: "Show Line Numbers"
-        desc: "Show line numbers in the editor's gutter."
+        title: "顯示行號"
+        desc: "在編輯器側邊顯示行號。"
       }
       {
         _id: 'editor.softTabs'
-        title: "Soft Tabs"
-        desc: "If the Tab Type config setting is set to \"auto\"
-               and autodetection of tab type from buffer content fails, then
-               this config setting determines whether a soft tab or a hard tab
-               will be inserted when the Tab key is pressed."
+        title: "軟定位點"
+        desc: "如果定位（tab）模式設定為「自動偵測（auto）」且偵測失敗時，則當此設定啟用時，會以「軟定位點（soft）」模式，否則將以「硬定位點（hard）」模式插入定位字元。"
       }
       {
         _id: 'editor.softWrap'
-        title: "Soft Wrap"
-        desc: "Wraps lines that exceed the width of the window. When
-               Soft Wrap At Preferred Line Length is set, it will
-               wrap to the number of characters defined by the Preferred
-               Line Length setting."
+        title: "自動換行"
+        desc: "字數超過視窗寬度時，自動換行。當啟用依據每行字數自動換行設定時，換行字數會參考每行字數設定值，而非視窗寬度。"
       }
       {
         _id: 'editor.softWrapAtPreferredLineLength'
-        title: "Soft Wrap At Preferred Line Length"
-        desc: "Instead of wrapping lines to the window's width, wrap lines to
-               the number of characters defined by the Preferred Line
-               Length setting. This will only take effect when the soft
-               wrap config setting is enabled globally or for the current
-               language. Note: If you want to hide the wrap
-               guide (the vertical line) you can disable the
-               wrap-guide package."
+        title: "依據每行字數自動換行"
+        desc: "字數超過每行字數設定值時自動換行，而非依據視窗寬度。這項設定只有在該語言環境中啟用自動換行設定時才有效。備註：如果想要隱藏縮排對齊線（垂直線），可以關閉 wrap-guide 擴充套件。"
       }
       {
         _id: 'editor.softWrapHangingIndent'
-        title: "Soft Wrap Hanging Indent"
-        desc: "When soft wrap is enabled, defines length of additional
-               indentation applied to wrapped lines, in number of characters."
+        title: "自動換行的縮排長度"
+        desc: "啟動自動換行設定時，換行文字的額外縮排長度。單位：字元。"
       }
       {
         _id: 'editor.tabLength'
-        title: "Tab Length"
-        desc: "Number of spaces used to represent a tab."
+        title: "定位點（tab）長度"
+        desc: "顯示一個定位點（tab）字元的空白字元的數量。"
       }
       {
         _id: 'editor.tabType'
-        title: "Tab Type"
-        desc: "Determine character inserted when Tab key is pressed. Possible
-               values: \"auto\", \"soft\" and \"hard\". When set to \"soft\" or
-               \"hard\", soft tabs (spaces) or hard tabs (tab characters) are
-               used. When set to \"auto\", the editor auto-detects the tab type
-               based on the contents of the buffer (it uses the first leading
-               whitespace on a non-comment line), or uses the value of the Soft
-               Tabs config setting if auto-detection fails."
+        title: "定位（tab）模式"
+        desc: "點擊定位（tab）鍵時插入的字元。有三種設定值：「自動判斷（auto）」、「軟定位點 （soft）」或 「硬定位點（hard）」。「軟定位點」使用空白字元（space），「硬定位點」使用定位字元（\\t）。「自動判斷」模式將會使用該行行首的空白字元或定位字元。如果自動判斷失敗，將會直接採用軟定位點的設定值。"
       }
       {
         _id: 'editor.undoGroupingInterval'
-        title: "Undo Grouping Interval"
-        desc: "Time interval in milliseconds within which text editing
-               operations will be grouped together in the undo history."
+        title: "合併復原操作的時間間隔"
+        desc: "在此時間間隔內的文字編輯操作，在復原歷史紀錄中會被合併在一起。單位：毫秒。"
       }
       {
         _id: 'editor.zoomFontWhenCtrlScrolling'
-        title: "Zoom Font When Ctrl Scrolling"
-        desc: "Change the editor font size when pressing the Ctrl key and
-               scrolling the mouse up/down."
+        title: "使用 Ctrl 鍵搭配滑鼠滾輪縮放字型大小"
+        desc: "使用 Ctrl 鍵搭配上下捲動滑鼠滾輪改變編輯器字型大小。"
       }
     ]
   }
   keymaps: {
     notes: {
-      text1: "You can override these keybindings by copying "
-      text2: "and pasting them into "
-      text3: "your keymap file"
+      text1: "你可以點選複製按鈕"
+      text2: "複製這些快捷鍵設定，然後貼至"
+      text3: "你的快捷鍵設定檔。"
       text4: ""   # optional
       _template: "${text1} <icon /> ${text2} ${text3} ${text4}"
     }
-    "search-bar-placeholder": "Search keybindings"
-    "table-header-keystroke": "Keystroke"
-    "table-header-command": "Command"
-    "table-header-source": "Source"
-    "table-header-selector": "Selector"
+    "search-bar-placeholder": "搜尋快捷鍵設定"
+    "table-header-keystroke": "鍵盤輸入"
+    "table-header-command": "指令"
+    "table-header-source": "來源"
+    "table-header-selector": "選擇器"
   }
   packages: {
   }
   themes: {
     notes: {
-      text1: "You can also style Atom by editing "
-      text2: "your stylesheet"
-      text3: ""   # optional
+      text1: "你可以藉由編輯"
+      text2: "你的樣式表"
+      text3: "來調整 Atom 外觀"   # optional
       _template: "${text1} ${text2} ${text3}"
     }
-    title1: "UI Theme"
-    description1: "This styles the tabs, status bar, tree view, and dropdowns"
-    title2: "Syntax Theme"
-    description2: "This styles the text inside the editor"
+    title1: "使用者介面佈景主題"
+    description1: "分頁、狀態列、tree view 及下拉式選單的外觀"
+    title2: "語法佈景主題"
+    description2: "編輯器內部文字的外觀"
   }
   updates: {
-    "check-updates": "Check for Updates"
-    "update-all": "Update All"
-    "checking-updates": "Checking for updates..."
-    "all-updated-message": "All of your installed packages are up to date!"
+    "check-updates": "檢查更新"
+    "update-all": "安裝所有更新"
+    "checking-updates": "檢查更新中..."
+    "all-updated-message": "你所有的擴充套件都是最新版本了！"
   }
   install: {
     notes: {
-      text1: "Packages are published to "
-      text2: " and are installed to "
+      text1: "擴充套件會被發佈到 "
+      text2: " 且安裝在資料夾 "
       text3: ""   # optional
       _template: "${text1}atom.io${text2} /path/to/pkg ${text3}"
     }
-    "searchbar-placeholder": "Search packages"
-    "btn-packages": "Packages"
-    "btn-themes": "Themes"
+    "searchbar-placeholder": "搜尋擴充套件"
+    "btn-packages": "擴充套件"
+    "btn-themes": "佈景主題"
   }
   "control-btns":{
-    install: "Install"
-    update: "Update to"
-    setting: "Settings"
-    uninstall: "Uninstall"
-    disable: "Disable"
-    enable: "Enable"
-  }
+    install: "安裝"
+    update: "安裝版本"
+    setting: "設定"
+    uninstall: "解除安裝"
+    disable: "停用"
+    enable: "啟動"
+  }


better demo coords for gmap

better demo coords for gmap

--- demo/coffee/gmap.coffee
+++ demo/coffee/gmap.coffee
@@ -11,9 +11,9 @@

   plot_model = Collections('GMapPlot').create(
     map_options:
-      lat: 35.349
-      lng: -116.595
-      zoom: 17
+      lat: 30.267153
+      lng: -97.74306079999997
+      zoom: 15
     canvas_width: dims[0]
     canvas_height: dims[1]
     outer_width: dims[0]


Change Customer Analyst to Content Analyst

--- src/components/navbar/user-actions-menu.cjsx
+++ src/components/navbar/user-actions-menu.cjsx
@@ -68,7 +68,7 @@

     if CurrentUserStore.isContentAnalyst()
       menu.push @renderMenuItem({name: 'QADashboard', label: 'QA Content', params: {}}, menu.length )
-      menu.push @renderMenuItem({label: 'Customer Analyst', href: '/content_analyst', key: 'ca'}, menu.length )
+      menu.push @renderMenuItem({label: 'Content Analyst', href: '/content_analyst', key: 'ca'}, menu.length )

     menu.push <BS.MenuItem divider key='dropdown-item-divider'/>
     menu


remove step from game object default events

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -47,4 +47,4 @@
     if typeof fn is "function"
       fn.apply(self)
     else
-      sel+      self.send()


levels and default game states

levels and default game states

--- src/title_screen.coffee
+++ src/title_screen.coffee
@@ -9,6 +9,6 @@

     self.centerText canvas, "Press any key to start",
       size: 12
-      y: App
+      y: App.height

   return self


Nginx: set a new redirect rule requested by @gniting

--- deployment/nginx.coffee
+++ deployment/nginx.coffee
@@ -323,6 +323,15 @@
         proxy_pass https://teams-koding.hs-sites.com;
       }

+      location = /Hackathon/rules {
+        proxy_set_header      X-Real-IP       $remote_addr;
+        proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
+
+        resolver 8.8.8.8;
+        proxy_connect_timeout 10;
+        proxy_pass https://teams-koding.hs-sites.com/hackathon-rules;
+      }
+
       # mac and windows are case insensitive
       location ~ "(?-i)/hackathon" {
         return 301 /Hackathon ;


Fixed - #60 Dropdowns don't open in desktop view

--- src/coffee/bootstrap.offcanvas.coffee
+++ src/coffee/bootstrap.offcanvas.coffee
@@ -31,7 +31,7 @@

             # Show or hide element
             @dropdown.toggleClass "shown"
-            @element.parent().toggleClass 'active'
+            @element.parent().toggleClass 'open'

     class OffcanvasTouch
         #   Public: Constructor for offcanvas


More formatting update.

More formatting update.

--- src/chalkboard.coffee
+++ src/chalkboard.coffee
@@ -271,10 +271,10 @@
       if _(element).isObject()
         if element.name?
           output += "**#{element.name}**  \n"
+        if element.type?
+          output += "Type: `#{element.type}`  \n"
         if element.description? and element.description
           output += "#{element.description}  \n"
-        if element.type?
-          output += "Type: `#{element.type}`  \n"

       # Everything else with just string
       else
@@ -330,6 +330,10 @@
     if section.description?
       output += "#{section.description}\n"
       omitList.push "description"
+
+    if section.type?
+      output += "Type: `#{section.type}`  \n\n"
+      omitList.push "type"

     if section.version?
       output += "Version: `#{section.version}`  \n\n"


De-dupe autocomplete entries

De-dupe autocomplete entries

--- services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/SnippetManager.coffee
+++ services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/SnippetManager.coffee
@@ -126,7 +126,12 @@
 			docText = session.getValue()
 			customEnvironments = parseCustomEnvironments(docText)
 			beginCommands = parseBeginCommands(docText)
-			parsedItems = _.union(customEnvironments, beginCommands)
+			parsedItemsMap = {}
+			for environment in customEnvironments
+				parsedItemsMap[environment.name] = environment
+			for command in beginCommands
+				parsedItemsMap[command.name] = command
+			parsedItems = _.values(parsedItemsMap)
 			snippets = staticSnippets.concat(
 				parsedItems.map (item) ->
 					{


failing spec for asset registration with continue-wrapped branching

--- spec/Extensions.coffee
+++ spec/Extensions.coffee
@@ -363,6 +363,44 @@
         testAssetContest [contestant], done

+      it 'via continue-wrapped branching', (done) ->
+
+        contestant = (parent) ->
+          parent.tree('contestant')
+          .deliver()
+          .then (n) ->
+            n.continue()
+            .deliver()
+            .then (choice) ->
+
+              choice.branch 'loser', (c) ->
+                c.continue()
+                .deliver()
+                .then 'ignore-marker', (c) ->
+                  c.registerAsset
+                    id: 'display-font-css'
+                    type: 'css-file'
+                    data: './marker.css'
+                .then 'ignored-zapfino', (c) ->
+                  c.registerAsset
+                    id: 'body-font-css'
+                    type: 'css-file'
+                    data: './zapfino.css'
+
+              # second is chosen...
+              choice.branch 'winner', (c) ->
+                c.continue()
+                .deliver()
+                .all [winnerchild]
+                .then 'body-font', (c) ->
+                  c.registerAsset
+                    id: 'body-font-css'
+                    type: 'css-file'
+                    data: './georgia.css'
+
+        testAssetContest [contestant], done
+
+
     describe 'multi-level asset registration w/ contest & aborts', ->
       ###
       assets registered by child should not be overwritten by parent


Specs for auto checking when about is opened

--- spec/about-spec.coffee
+++ spec/about-spec.coffee
@@ -122,7 +122,6 @@
         expect(args[0]).toContain '/v1.2.3'

       it "executes checkForUpdate() when the check for update button is clicked", ->
-        spyOn(atom.autoUpdater, 'checkForUpdate')
         button = aboutElement.querySelector('.about-update-action-button')
         button.click()
         expect(atom.autoUpdater.checkForUpdate).toHaveBeenCalled()
@@ -172,6 +171,33 @@
           expect(aboutElement.querySelector('.about-default-update-message .about-default-enabled-update-message')).toBeVisible()
           expect(aboutElement.querySelector('.about-default-update-message .about-default-disabled-update-message')).not.toBeVisible()

+        it "checks for update when the about page is shown", ->
+          expect(atom.autoUpdater.checkForUpdate).not.toHaveBeenCalled()
+
+          atom.workspace.getActivePane().destroyActiveItem()
+          atom.workspace.open('atom://about')
+
+          waitsFor ->
+            atom.workspace.getActivePaneItem()
+
+          runs ->
+            expect(atom.autoUpdater.checkForUpdate).toHaveBeenCalled()
+
+        it "does not check for update when the about page is shown and auto updates are turned off", ->
+          atom.config.set('core.automaticallyUpdate', false)
+          expect(atom.autoUpdater.checkForUpdate).not.toHaveBeenCalled()
+
+          atom.workspace.getActivePane().destroyActiveItem()
+          atom.workspace.open('atom://about')
+
+          waitsFor ->
+            atom.workspace.getActivePaneItem()
+
+          runs ->
+            expect(atom.autoUpdater.checkForUpdate).not.toHaveBeenCalled()
+
+
+
 describe "the status bar", ->
   workspaceElement = null


Fix: don't attempt to fetch current profile if doesn't exist

--- assets/javascripts/application.js.coffee
+++ assets/javascripts/application.js.coffee
@@ -167,6 +167,7 @@
     params

   fetchCurrentProfile: ->
+    return unless @config.current_entity
     entity = @config.current_entity.toStringWithoutSchemePort()
     cache_key = "profile:#{entity}"
     expires_at_cache_key = "profile:#{entity}:expires_at"


Add hammer.js to application.js

Add hammer.js to application.js

--- assets/javascripts/application.js.coffee
+++ assets/javascripts/application.js.coffee
@@ -1,4 +1,6 @@
+#= require hammer
 #= require jquery-1.8.3
+#= require jquery.specialevent.hammer
 #= require hamlcoffee
 #= require underscore
 #= require backbone


Remove useless env config, fix livereload settings

--- lib/shuss-config.coffee
+++ lib/shuss-config.coffee
@@ -1,10 +1,6 @@
 convict = require 'convict'

 config = convict {
-  env:
-    doc: 'The application environment.'
-    default: 'development'
-    env: 'NODE_ENV'
   verbose:
     doc: 'speak to me'
     default: false
@@ -17,13 +13,13 @@
     doc: 'Served file directory'
     default: '.'
     env: 'SHUSS_DIR'
+  livereload:
+    doc: 'Enable livereload'
+    default: false
+    env: 'SHUSS_LR'
   livereloadport:
-    doc: 'Enable livereload'
+    doc: 'The livereload server port'
     default: 35729
-    env: 'SHUSS_LR'
-  livereload:
-    doc: 'The livereload server port'
-    default: false
     env: 'SHUSS_LR_PORT'
 }


:art: Merge updatePosition function into Initialize

--- lib/tooltip-view.coffee
+++ lib/tooltip-view.coffee
@@ -6,26 +6,22 @@
     @content: ->
       @div class: 'ide-hack-tooltip'

-    initialize: (@rect, @LeMessage) ->
+    initialize: (rect, @LeMessage) ->
       @append LeMessage
       $(document.body).append this
-      @updatePosition()
-
-    # smart position update
-    updatePosition: ->
-      coords = [@rect.right, @rect.bottom, undefined]
-      offset = 10
+      Coords = [rect.right, rect.bottom, undefined]
+      Offset = 10

       # x axis adjust
-      if coords[0] + this[0].offsetWidth >= $(document.body).width()
-        coords[0] = $(document.body).width() - this[0].offsetWidth - offset
-      if coords[0] < 0
+      if Coords[0] + this[0].OffsetWidth >= $(document.body).width()
+        Coords[0] = $(document.body).width() - this[0].OffsetWidth - Offset
+      if Coords[0] < 0
         this.css({ 'white-space': 'pre-wrap' })
-        coords[0] = offset
-        coords[2] = offset
+        Coords[0] = Offset
+        Coords[2] = Offset

       # y axis adjust
-      if coords[1] + this[0].offsetHeight >= $(document.body).height()
-        coords[1] = @rect.top - this[0].offsetHeight
+      if Coords[1] + this[0].OffsetHeight >= $(document.body).height()
+        Coords[1] = @rect.top - this[0].OffsetHeight

-      this.css({ left: coords[0], top: coords[1], right: coords[2] })+      this.css({ left: Coords[0], top: Coords[1], right: Coords[2] })


Use Builtin isString

Use Builtin isString

--- lib/suggestion-list-element.coffee
+++ lib/suggestion-list-element.coffee
@@ -1,6 +1,7 @@
 {CompositeDisposable} = require 'atom'
 _ = require 'underscore-plus'
 SnippetParser = require './snippet-parser'
+{isString} = require('./type-helpers')

 ItemTemplate = """

@@ -240,8 +241,8 @@
     typeIconContainer = li.querySelector('.icon-container')
     typeIconContainer.innerHTML = ''

-    sanitizedType = if _.isString(type) then type else ''
-    sanitizedIconHTML = if _.isString(iconHTML) then iconHTML else undefined
+    sanitizedType = if isString(type) then type else ''
+    sanitizedIconHTML = if isString(iconHTML) then iconHTML else undefined
     defaultLetterIconHTML = if sanitizedType then "#{sanitizedType[0]}" else ''
     defaultIconHTML = DefaultSuggestionTypeIconHTML[sanitizedType] ? defaultLetterIconHTML
     if (sanitizedIconHTML or defaultIconHTML) and iconHTML isnt false


adding in route changing once publish button is submitted

--- src/components/task-plan/reading.cjsx
+++ src/components/task-plan/reading.cjsx
@@ -84,7 +84,7 @@

 ReadingPlan = React.createClass
-  mixins: [Router.State]
+  mixins: [Router.State, Router.Navigation]

   getInitialState: ->
     if (@getParams().id)
@@ -116,6 +116,7 @@

   publish: ->
     TaskPlanActions.publish(@state.id)
+    @transitionTo('editReading', {id: @state.id})

   renderTopics: (topicId) ->
     topic = TocStore.getSectionInfo(topicId)


Added top/bottom classes for a paginator closes #135

--- wzk/ui/grid/Paginator.coffee
+++ wzk/ui/grid/Paginator.coffee
@@ -19,6 +19,13 @@
   ###
   @EventType:
     GO_TO: 'go-to'
+
+  ###*
+    @enum {string}
+  ###
+  @CLASSES:
+    TOP: 'top'
+    BOTTOM: 'bottom'

   ###*
     @type {number}
@@ -210,6 +217,8 @@
   clone: ->
     clone = @getElement().cloneNode true
     @hangPageListener clone
+    goog.dom.classes.add @getElement(), wzk.ui.grid.Paginator.CLASSES.TOP
+    goog.dom.classes.add clone, wzk.ui.grid.Paginator.CLASSES.BOTTOM
     clone

   ###*


Add description for command line options.

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -2,6 +2,10 @@
 fs = require 'fs'
 argv = require('optimist')
   .usage('Usage: $0 --projectKey key --clientId id --clientSecret secret --csv file')
+  .describe('projectKey', 'your SPHERE.IO project-key')
+  .describe('clientId', 'your OAuth client id for the SPHERE.IO API')
+  .describe('clientSecret', 'your OAuth client secret for the SPHERE.IO API')
+  .describe('csv', 'CSV file containing products to validate or import')
   .demand(['projectKey', 'clientId', 'clientSecret', 'csv'])
   .argv


Fix naming.

Fix naming.

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -3,7 +3,7 @@
   .usage('Usage: $0 --projectKey key --clientId id --clientSecret secret')
   .demand(['projectKey','clientId', 'clientSecret'])
   .argv
-OrderStatusSync = require('../main').OrderStatusSync
+OrderStateSync = require('../main').OrderStateSync
 Rest = require('sphere-node-connect').Rest

 Config.showProgress = true
@@ -14,10 +14,10 @@
     client_id: argv.clientId
     client_secret: argv.clientSecret

-updater = new OrderStatusSync Config
+sync = new OrderStateSync Config
 rest = new Rest options
-updater.getOrders(rest).then (orders) ->
-  updater.run orders, (msg) ->
+sync.getOrders(rest).then (orders) ->
+  sync.run orders, (msg) ->
     console.log msg
 .fail (msg) ->
   console.log msg


Allow for generating function for dropdowns

--- src/controller.coffee
+++ src/controller.coffee
@@ -2063,7 +2063,11 @@
       # Closure the text focus; dropdown should work
       # even after unfocused
       textFocus = @textFocus
-      for el, i in @textFocus.dropdown then do (el) =>
+      if (typeof @textFocus.dropdown is 'function')
+        dropdown = @textFocus.dropdown()
+      else
+        dropdown = @textFocus.dropdown
+      for el, i in dropdown then do (el) =>
         div = document.createElement 'div'
         div.innerHTML = el.display
         div.className = 'droplet-dropdown-item'


Added comment

Added comment

--- core/app/assets/javascripts/intermediate.coffee
+++ core/app/assets/javascripts/intermediate.coffee
@@ -34,7 +34,7 @@

 showUrl = (url, successFn) ->
   window.onModalReady = ->
-    window.onModalReady = ->
+    window.onModalReady = -> # nothing
     successFn()

   backbone = showFrame.contentWindow.Backbone


PUBDEV-6837 - TargetEncoder support.

PUBDEV-6837 - TargetEncoder support.

--- src/ext/components/model-input.coffee
+++ src/ext/components/model-input.coffee
@@ -278,7 +278,7 @@
   switch parameter.type
     when 'enum', 'Key<Frame>', 'VecSpecifier'
       createDropdownControl parameter
-    when 'string[]'
+    when 'string[]', 'VecSpecifier[]'
       createListControl parameter
     when 'boolean'
       createCheckboxControl parameter
@@ -378,7 +378,9 @@
       interactionPairsParameter,
       monotoneConstraintsParameter,
       startColumnParameter,
-      stopColumnParameter
+      stopColumnParameter,
+      targetColumnParameter,
+      encodedColumnsParameter
     ] = map [
       'training_frame',
       'validation_frame',
@@ -392,11 +394,13 @@
       'interaction_pairs',
       'monotone_constraints',
       'start_column',
-      'stop_column'
+      'stop_column',
+      'target_column',
+      'encoded_columns'
     ], findFormField

     if trainingFrameParameter
-      if responseColumnParameter or ignoredColumnsParameter
+      if responseColumnParameter or ignoredColumnsParameter or targetColumnParameter
         act trainingFrameParameter.value, (frameKey) ->
           if frameKey
             _.requestFrameSummaryWithoutData frameKey, (error, frame) ->
@@ -441,6 +445,13 @@

                 if stopColumnParameter
                   stopColumnParameter.values columnValues
+
+                # Target Encoding fields
+                if targetColumnParameter
+                  targetColumnParameter.values columnValues
+
+                if encodedColumnsParameter
+                  encodedColumnsParameter.values columnLabelsFromFrame(frame)

           return


Bind and update tooltip when view is already rendered

--- core/app/backbone/factlink/tooltip_mixin.coffee
+++ core/app/backbone/factlink/tooltip_mixin.coffee
@@ -13,6 +13,9 @@

     @_tooltips[selector] = new Backbone.Factlink.PositionedRegion _.extend(options, side: side)
     @_tooltips[selector].show view
+
+    unless @isClosed
+      @tooltipBindAll()

     @on 'render', @tooltipBindAll
     @on 'close', @tooltipResetAll


Send user not req

Send user not req

--- lib/graphql.coffee
+++ lib/graphql.coffee
@@ -7,7 +7,7 @@
       .post METAPHYSICS_ENDPOINT
       .set 'Accept', 'application/json'

-    if (token = req?.user?.get?('accessToken') or req?.user?.accessToken)?
+    if (token = user?.get?('access_token') or user?.access_token)?
       post.set 'X-AUTH-TOKEN"': token

     post


Remove unnecessary commas

Remove unnecessary commas

--- lib/helpers.coffee
+++ lib/helpers.coffee
@@ -10,8 +10,8 @@

   if fs.isFileSync(userKeymapPath)
     linter.checkKeymap(CSON.readFileSync(atom.keymaps.getUserKeymapPath()), {
-      packageName: "your local #{path.basename(userKeymapPath)} file",
-      packagePath: "",
+      packageName: "your local #{path.basename(userKeymapPath)} file"
+      packagePath: ""
       sourcePath: userKeymapPath
     })

@@ -20,13 +20,13 @@
   if fs.isFileSync(userStyleSheetPath)
     userStyleSheet = fs.readFileSync(atom.styles.getUserStyleSheetPath(), 'utf8')
     linter.checkSyntaxStylesheet(userStyleSheet, {
-      packageName: "your local #{path.basename(userStyleSheetPath)} file",
-      packagePath: "",
+      packageName: "your local #{path.basename(userStyleSheetPath)} file"
+      packagePath: ""
       sourcePath: userStyleSheetPath
     })
     linter.checkUIStylesheet(userStyleSheet, {
-      packageName: "your local #{path.basename(userStyleSheetPath)} file",
-      packagePath: "",
+      packageName: "your local #{path.basename(userStyleSheetPath)} file"
+      packagePath: ""
       sourcePath: userStyleSheetPath
     })


[module] always use Coffee `this` in Nunjucks extensions module

--- modules/nunjucks-extensions.coffee
+++ modules/nunjucks-extensions.coffee
@@ -44,7 +44,7 @@
    * @return {string} Logs to Grunt console
   ###
   env.addGlobal 'warn', (input...) ->
-    grunt.log.error(input..., '[' + this.ctx.page.href + ']')
+    grunt.log.error(input..., '[' + @ctx.page.href + ']')

   ###*
    * Get list of files or directories inside specified directory
@@ -73,7 +73,7 @@
    * @return {*}                   Value of `prop` if no `value` specified
   ###
   env.addGlobal 'config', (prop, value, merge = true) ->
-    ctx           = this.ctx
+    ctx           = @ctx
     ctxValue      = _.get(ctx, prop)
     valueIsArray  = Array.isArray(value)
     valueIsObject = typeof value == 'object' and value and not valueIsArray
@@ -94,22 +94,22 @@

   ###*
    * Get properties of page and its childs from specified object.
-   * @param {array}  path                             Path to page inside `data`
-   * @param {bool}   forceRender   = true             Force rendering of output via Nunjucks
-   * @param {object} renderContext = @getVariables()  Context with which should be made forced rendering
-   * @param {bool}   logUndefined  = false            Log or no undefined values
-   * @param {object} data = this.ctx.site.__matter__  Object with properties of page and its childs
+   * @param {array}  path                            Path to page inside `data`
+   * @param {bool}   forceRender   = true            Force rendering of output via Nunjucks
+   * @param {object} renderContext = @getVariables() Context with which should be made forced rendering
+   * @param {bool}   logUndefined  = false           Log or no undefined values
+   * @param {object} data = @ctx.site.__matter__     Object with properties of page and its childs
    * @return {object} Properties of the page, including its sub pages
   ###
-  env.addGlobal 'getPage', (path, forceRender = true, renderContext = @getVariables(), logUndefined = false, data = this.ctx.site.__matter__) ->
+  env.addGlobal 'getPage', (path, forceRender = true, renderContext = @getVariables(), logUndefined = false, data = @ctx.site.__matter__) ->
     result = _.get(data, path)

     if result
-      result = if forceRender then render(env, renderContext, result, false, grunt.log.error, logUndefined,  this.ctx.page.props.href) else result
+      result = if forceRender then render(env, renderContext, result, false, grunt.log.error, logUndefined,  @ctx.page.props.href) else result
       Object.defineProperty result, 'props', enumerable: false
       return result
     else
-      grunt.log.error('[getPage] can\'t find requested `' + path + '` inside specified object', '[' + this.ctx.page.href + ']')
+      grunt.log.error('[getPage] can\'t find requested `' + path + '` inside specified object', '[' + @ctx.page.href + ']')

   ###*
    * Explodes string into array breadcrumb. See `crumble` helper for details
@@ -119,14 +119,14 @@

   ###*
    * Determinate is current path active relatively to current page breadcrumb or no
-   * @param  {string} to                                         Absolute or relative path to page based
-   *                                                             based on `pages.yml`
-   * @param  {bool} onlyActiveOnIndex = false                    Set anchor to be active only in case current link's
-   *                                                             and page's breadcrumbs completely matches
-   * @param  {array} pageBreadcrumb   = this.ctx.page.breadcrumb Breadcrumb of current page for comparison
-   * @return {bool}                                              Is current path active or no
-  ###
-  env.addGlobal 'isActive', (to, onlyActiveOnIndex = false, pageBreadcrumb = this.ctx.page.breadcrumb) ->
+   * @param  {string} to                                     Absolute or relative path to page based
+   *                                                         based on `pages.yml`
+   * @param  {bool} onlyActiveOnIndex = false                Set anchor to be active only in case current link's
+   *                                                         and page's breadcrumbs completely matches
+   * @param  {array} pageBreadcrumb   = @ctx.page.breadcrumb Breadcrumb of current page for comparison
+   * @return {bool} Is current path active or no
+  ###
+  env.addGlobal 'isActive', (to, onlyActiveOnIndex = false, pageBreadcrumb = @ctx.page.breadcrumb) ->
     isAbsolute = if _.startsWith(to, '/') then true else false

     linkBreadcrumb = crumble(to)
@@ -182,7 +182,7 @@
    * @todo Related issue https://github.com/mozilla/nunjucks/issues/783
   ###
   env.addFilter 'render', (input, isCaller = false, logUndefined = false) ->
-    render(env, @getVariables(), input, isCaller, grunt.log.error, logUndefined, this.ctx.page.props.href)
+    render(env, @getVariables(), input, isCaller, grunt.log.error, logUndefined, @ctx.page.props.href)

   ###*
    * Replace placeholders with provided values. Refer to `printf` module for docs
@@ -241,7 +241,7 @@
   ###
   env.addFilter 'spread', (input, delimiter = ' ') ->
     if typeof input != 'object'
-      grunt.log.error('[spread] input should be object, but `' + typeof input + '` has been specified', '[' + this.ctx.page.href + ']')
+      grunt.log.error('[spread] input should be object, but `' + typeof input + '` has been specified', '[' + @ctx.page.href + ']')
       return

     spreaded = ' '


overlooked several mongoose-q usages

overlooked several mongoose-q usages

--- lib/request.coffee
+++ lib/request.coffee
@@ -178,7 +178,7 @@
 					deferred.resolve(query)
 				else

-					@$modelClass.countQ(filter)
+					@$modelClass.count(filter)
 					.then (count) =>
 						res.set('Time-PostCount', (new Date()).toISOString())
 						log 'There are ' + count.toString().yellow + ' total documents that fit filter'
@@ -234,7 +234,7 @@

 		@$runHook('pre_save', 'post', req, model).then (model) =>

-			return model.saveQ()
+			return model.save()
 		.then (model) =>
 			log('Finished save. Populating')
 			return @$populateDocument(model)
@@ -258,7 +258,7 @@
 		deferred = Q.defer()
 		model = new @$modelClass(obj)
 		@$runHook('pre_save', 'bulkpost', req, model).then (data) =>
-			return model.saveQ()
+			return model.save()
 		.then (model) =>
 			deferred.resolve()
 		.fail (err) =>
@@ -358,7 +358,7 @@
 				model.set(req.body)
 				return @$runHook('pre_save', 'put', req, model).then (model) =>
 			.then =>
-				return model.saveQ()
+				return model.save()
 			.then (model) =>
 				return @$populateDocument(model)
 			.then (model) =>
@@ -425,7 +425,7 @@
 					res.status(500).send()
 				.done()
 			@$runHook('post_retrieve', 'delete', req, model).then (model) =>
-				return model.removeQ()
+				return model.remove()
 			.then =>
 				res.status(200).send()
 			.fail (err) =>


Runtime: Fix state members not initialized

Was only added when graph:clear command was sent

--- lib/runtime.coffee
+++ lib/runtime.coffee
@@ -524,6 +524,8 @@
         @library = new c.ComponentLibrary
         @device = new devicecommunication.DeviceCommunication @transport, @graph, @library
         @io = new devicecommunication.RemoteIo @device
+        @exportedEdges = []
+        @edgesForInspection = []
         @conn =
             send: (response) =>
                 console.log 'FBP MICROFLO SEND:', response if util.debug_protocol


Round the logged spec time

Round the logged spec time

--- tasks/spec-task.coffee
+++ tasks/spec-task.coffee
@@ -56,5 +56,6 @@
     startTime = Date.now()
     async.parallel [runCoreSpecs, runPackageSpecs], (error, results) ->
       [coreSpecPassed, packageSpecsPassed] = results
-      grunt.log.writeln("Total spec time: #{(Date.now() - startTime)/1000}s")
+      elapsedTime = Math.round((Date.now() - startTime) / 100) / 10
+      grunt.log.writeln("Total spec time: #{elapsedTime}s")
       done(coreSpecPassed and packageSpecsPassed)


Use path.resolve instead of concatenation, refs #94

--- src/lib/nodejs/ComponentLoader.coffee
+++ src/lib/nodejs/ComponentLoader.coffee
@@ -101,7 +101,7 @@
       return if seen.indexOf(packageData.name) isnt -1
       seen.push packageData.name
       if packageData.name is packageId
-        found = "#{packageData.realPath}/package.json"
+        found = path.resolve packageData.realPath, './package.json'
         return
       _.each packageData.dependencies, find
     reader @baseDir, (err, data) ->


Fuck shimakaze-go and ACGPower. (Didnt support HTTP HEAD)

--- index.cjsx
+++ index.cjsx
@@ -95,7 +95,7 @@
   updateNotifyConfig: (ship_id) ->
     setConfig = (key, audio) ->
       config.set(key, audio)
-      request.head
+      request.get
         url: audio
         proxy: POI_PROXY
       , (error, response, body) ->


removed one out of two deprecated grunt.helpers

--- tasks/percolator.coffee
+++ tasks/percolator.coffee
@@ -109,12 +109,14 @@

     --------------------------------------------------
     ###
-    grunt.registerHelper "exec", (command, callback) ->
+    helper = (command, callback) ->
         exec command, (err, stdout, stderr) ->
             if err or stderr
                 callback err or stderr, stdout
                 return
             callback null, stdout
+
+    helper()

     grunt.registerTask 'percolator', 'Concatenate CoffeeScript ordered by imports', ->
         options = grunt.config(this.name) || {}


Use relative path to view class require

Use relative path to view class require

--- src/edit-session.coffee
+++ src/edit-session.coffee
@@ -131,7 +131,7 @@

   # Private:
   getViewClass: ->
-    require 'editor'
+    require './editor'

   # Private:
   destroy: ->


bypassed aliased in HebrewDate#occasions

--- src/hebrewDate.coffee
+++ src/hebrewDate.coffee
@@ -67,7 +67,7 @@
   isTaanit: -> @is9Ab() || @is17Tammuz() || @isFastOfGedaliah() || @isTaanitEster() || @is10Tevet()
   isHataratNedarim: -> @monthAndRangeAre('AB', [19,29]) || @monthAndRangeAre('ELUL', [29]) || @monthAndRangeAre('TISHRI', [9])
   # Till here
-  occasions: -> result = []; (result.push(chag.replace(/^is/, '')) if chag.match(/^is/) && @[chag]()) for chag, val of @; result.sort()
+  occasions: -> result = []; (result.push(chag.replace(/^is/, '')) if chag.match(/^is/) && @[chag]() && !(@[chag] in (@["is#{alias}"] for alias in result))) for chag, val of @; result.sort()

 (->
   @HELPERS = {


added global status endpoint

added global status endpoint

--- src/model/statsd.coffee
+++ src/model/statsd.coffee
@@ -34,11 +34,16 @@
   var data = []

   for (var i = 0; i < allowedIds.length; i++) {
-    console.log(allowedIds);
     var path = "/render?target=transformNull(summarize(stats.counters." + domain + ".Channels." + allowedIds[i] + ".*.count,'1week'))&from=-1weeks&format=json";
     var raw = yield fetchData(path);
-    console.log(path);
-    console.log(JSON.stringify(raw));
+    data.push({
+      _id : {"channelID": allowedIds[i] },
+      failed: raw.data[0][0],
+      successful: raw.data1[0][0],
+      processing:0,
+      completed:0,
+      completedWErrors:0
+    })
   }

   this.body = data


do not show selected items in the dropdown list

--- src/multi-select.coffee
+++ src/multi-select.coffee
@@ -1,5 +1,13 @@
 comp = (a, b)->
   a.toLowerCase().indexOf(b.toLowerCase()) > -1
+
+hash_key = (item)->
+  angular.toJson(item)
+
+difference = (a, b)->
+  hash = {}
+  hash[hash_key(b_element)] = true for b_element in b
+  a.filter ((a_element)-> not hash[hash_key(a_element)])

 filter = (x, xs, valueAttr)->
   if x then xs.filter ((i)-> comp(i[valueAttr], x)) else xs
@@ -64,14 +72,17 @@
           ul.scrollTop -= viewport.top - item.top

       search = (q) ->
-        if $scope.prevSearch != q
-          $scope.shownItems = filter(q, $scope.items, $scope.valueAttr).slice(0, $scope.limit)
-          $scope.activeItem = $scope.shownItems[0]
+        $scope.shownItems = difference(
+          filter(q, $scope.items, $scope.valueAttr).slice(0, $scope.limit),
+          [$scope.selectedItem]
+        )
+        $scope.activeItem = $scope.shownItems[0]
         $scope.prevSearch = q

       $scope.selection = (item)->
         $scope.selectedItem = item
         $scope.hideDropDown()
+        search ''

       $scope.reset = ->
         $scope.selectedItem = null


re-implement `format_number` without ES `Intl`


activity: pass key event to super method

--- client/Social/Activity/views/inputview.coffee
+++ client/Social/Activity/views/inputview.coffee
@@ -62,7 +62,7 @@
         return  true

   keyDown: (event) ->
-    super
+    super event
     return  if event.isPropagationStopped()
     switch event.which
       when 27 # Escape


PermissionsForm: Added missing permission header titles.

--- client/admin/lib/views/permissionsform.coffee
+++ client/admin/lib/views/permissionsform.coffee
@@ -85,18 +85,27 @@
   readableText = (text) ->

     dictionary =
-      "JNewApp"        : "Apps"
-      "JGroup"         : "Groups"
-      "SocialMessage"  : "Social API"
-      "JGroupBundle"   : "Group Bundles"
-      "JProposedDomain": "Domains"
-      "JProxyFilter"   : "Proxy Filters"
-      "JInvitation"    : "Invitations"
-      "JStack"         : "Stacks"
-      "JStackTemplate" : "Stack Templates"
-      "JCredential"    : "Credentials"
-
-    return dictionary[text] or text.charAt(0).toUpperCase()+text.slice(1)
+      JNewApp            : 'Apps'
+      JGroup             : 'Groups'
+      SocialMessage      : 'Social API'
+      JGroupBundle       : 'Group Bundles'
+      JProposedDomain    : 'Domains'
+      JProxyFilter       : 'Proxy Filters'
+      JInvitation        : 'Invitations'
+      JStack             : 'Stacks'
+      JStackTemplate     : 'Stack Templates'
+      JCredential        : 'Credentials'
+      ComputeProvider    : 'Compute Providers'
+      JComputeStack      : 'Compute Stacks'
+      JDomainAlias       : 'Domain Aliases'
+      JKite              : 'Kites'
+      JMachine           : 'Machines'
+      JProvisioner       : 'Provisioners'
+      JRewardCampaign    : 'Campaigns'
+      JSnapshot          : 'Snapshots'
+      SocialNotification : 'Social Notifications'
+
+    return dictionary[text] or text.capitalize()

   _getCheckboxName = (module, permission, role) ->


groups: added dataURL support to group avatar

--- client/app/MainApp/sidebar/sidebarview.coffee
+++ client/app/MainApp/sidebar/sidebarview.coffee
@@ -52,7 +52,10 @@
         unless currentGroupData?.data?.slug is 'koding'
           @avatar.setClass 'shared-avatar'
           @avatar.setWidth 80
-          @groupAvatar.$().css backgroundImage :  currentGroupData?.data?.avatar or "url(http://lorempixel.com/#{100+@utils.getRandomNumber(10)}/#{100+@utils.getRandomNumber(10)})"
+
+          # group avatar should be either a URL or a dataURL
+
+          @groupAvatar.$().css backgroundImage :  "url(#{currentGroupData?.data?.avatar or 'http://lorempixel.com/'+100+@utils.getRandomNumber(10)+'/'+100+@utils.getRandomNumber(10)})"
           @groupAvatar.show()
           @groupAvatar.setClass 'flash'
           @avatarHeader.setData currentGroupData


Fix directMessage documentation.

Fix directMessage documentation.

--- src/ChatService.coffee
+++ src/ChatService.coffee
@@ -21,14 +21,13 @@
 # @example Socket.io client example
 #   socket = io.connect url, params
 #   socket.once 'loginConfirmed', (userName) ->
-#     socket.on 'directMessage', (fromUser, msg) ->
+#     socket.on 'directMessage', (msg) ->
 #       # just the same as any event. no reply is required.
 #
 class ServerMessages
   # Direct message. A message will have timestamp and author fields,
   # but other fields can be used if {ChatService#constructor}
   # `directMessagesChecker` hook is set.
-  # @param fromUser [String] Message sender.
   # @param msg [Object<textMessage:String, timestamp:Number, author:String>]
   #   Message.
   # @see UserCommands#directMessage


JComputeStack: maintenance: add prepareForDestroy action

We eventually need to remove all users from target stacks machines to kloud to let admin to destroy the machine.

--- workers/social/lib/social/models/stack.coffee
+++ workers/social/lib/social/models/stack.coffee
@@ -391,6 +391,16 @@
           return callback err  if err
           @delete callback, force = yes

+      else if options.prepareForDestroy
+
+        JMachine = require './computeproviders/machine'
+
+        queue = []
+        @machines?.forEach (_id) -> queue.push (next) ->
+          JMachine.update { _id }, { $set: { users: [] } }, next
+
+        async.series queue, callback
+
       else

         callback new KodingError 'Please provide a vaild maintenance mode'


CollaborationController: Return ensureMachineShare for host.

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -160,10 +160,8 @@

     return  unless @stateMachine?.state is 'Active'

-    {sessionId} = data.collaborator
-
-    {targetUser} =
-      realtimeHelpers.getTargetUser @participants, 'sessionId', sessionId
+    { sessionId }  = data.collaborator
+    { targetUser } = realtimeHelpers.getTargetUser @participants, 'sessionId', sessionId

     unless targetUser
       return kd.warn 'Unknown user in collaboration, we should handle this case...'
@@ -171,7 +169,7 @@
     @chat.emit 'ParticipantJoined', targetUser
     @statusBar.emit 'ParticipantJoined', targetUser

-    if @amIHost
+    if @amIHost and targetUser isnt nick()
       @ensureMachineShare [targetUser], (err) =>
         return throwError err  if err


Refactor appending host snapshot out to a method

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -511,9 +511,8 @@

     return  if @collaborationJustInitialized or @fakeTabView

-    mySnapshot   = @mySnapshot.values().filter (item) -> return not item.isInitial
-    hostSnapshot = @rtm.getFromModel("#{@collaborationHost}Snapshot")?.values()
-    snapshot     = if hostSnapshot then mySnapshot.concat hostSnapshot else mySnapshot
+    snapshot = @mySnapshot.values().filter (item) -> not item.isInitial
+    snapshot = @appendHostSnapshot snapshot  unless @amIHost

     @forEachSubViewInIDEViews_ (pane) =>
       @removePaneFromTabView pane  if pane.isInitial
@@ -521,6 +520,16 @@
     for change in snapshot when change.context
       @changeActiveTabView change.context.paneType
       @createPaneFromChange change
+
+
+  appendHostSnapshot: (snapshot) ->
+
+    hostSnapshot = @rtm.getFromModel("#{@collaborationHost}Snapshot")?.values()
+
+    if hostSnapshot
+      return snapshot.concat hostSnapshot
+
+    return snapshot

   showShareButton: ->


collaboration: controller remove old session activation code

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -35,20 +35,6 @@
     @socialChannel = channel

-  initPrivateMessage: (callback) ->
-
-    socialHelpers.initChannel (err, channel) =>
-      return callback err  if err
-
-      @setSocialChannel channel
-      envHelpers.updateWorkspace @workspaceData, { channelId : channel.id }
-        .then =>
-          @workspaceData.channelId = channel.id
-          callback null, channel
-          @chat.ready => @chat.emit 'CollaborationNotInitialized'
-        .error callback
-
-
   fetchSocialChannel: (callback) ->

     if @socialChannel
@@ -94,39 +80,6 @@
       callback accounts

-  continuePrivateMessage: (callback) ->
-
-    @chat.emit 'CollaborationStarted'
-
-    @listChatParticipants (accounts) =>
-      @statusBar.emit 'ShowAvatars', accounts, @participants.asArray()
-
-    callback null
-
-
-  startChatSession: (callback) ->
-
-    if @getSocialChannelId()
-    then @reactivateChatSession callback
-    else @initPrivateMessage callback
-
-
-  reactivateChatSession: (callback) ->
-
-    @fetchSocialChannel (err, channel) =>
-      if err or not channel
-        return @initPrivateMessage callback
-
-      @createChatPaneView channel
-      @isRealtimeSessionActive channel.id, (isActive, file) =>
-        if isActive
-          @whenRealtimeReady => @continuePrivateMessage callback
-          return @loadCollaborationFile file.id
-
-        @statusBar.share.show()
-        @chat.emit 'CollaborationNotInitialized'
-
-
   getRealtimeFileName: (id) ->

     id or= @getSocialChannelId()
@@ -150,41 +103,6 @@
     if @rtm?.isReady
     then callback()
     else @once 'RTMIsReady', callback
-
-
-  showChat: ->
-
-    return @createChatPane()  unless @chat
-
-    @chat.start()
-
-
-  createChatPane: ->
-
-    @startChatSession (err, channel) =>
-
-      return showError err  if err
-
-      @createChatPaneView channel
-
-
-  createChatPaneView: (channel) ->
-    return throwError 'RealtimeManager is not set'  unless @rtm
-
-    options = { @rtm, @isInSession }
-    @getView().addSubView @chat = new IDEChatView options, channel
-    @chat.show()
-
-    @on 'RTMIsReady', =>
-      @listChatParticipants (accounts) =>
-        @chat.settingsPane.createParticipantsList accounts
-
-      @statusBar.emit 'CollaborationStarted'
-
-      {settingsPane} = @chat
-
-      settingsPane.on 'ParticipantKicked', @bound 'handleParticipantKicked'
-      settingsPane.updateDefaultPermissions()

   kickParticipant: (account) ->
@@ -313,20 +231,6 @@

     if @permissions.get(nick()) is 'read'
       @makeReadOnly()
-
-
-  loadCollaborationFile: (fileId) ->
-
-    return  unless fileId
-
-    @rtmFileId = fileId
-
-    realtimeHelpers.loadCollaborationFile @rtm, fileId, (err, doc) =>
-      return throwError err  if err
-
-      @activateRealtimeManager doc
-      @bindSocialChannelEvents()
-      @finderPane.on 'ChangeHappened', @bound 'syncChange'

   reviveHostSnapshot: ->


collaboration: controller minor

collaboration: controller minor

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -105,9 +105,7 @@

   startChatSession: (callback) ->

-    channelId = @channelId or @workspaceData.channelId
-
-    if channelId
+    if @getSocialChannelId()
     then @reactivateChatSession callback
     else @initPrivateMessage callback

@@ -130,7 +128,9 @@

   getRealtimeFileName: (id) ->

-    unless id = @getSocialChannelId()
+    id or= @getSocialChannelId()
+
+    unless id
       return showError 'social channel id is not provided'

     hostName = @getCollaborationHost()


minor: removed obsolete code from loggedout state

--- client/ide/lib/ideappcontrolleroptions.coffee
+++ client/ide/lib/ideappcontrolleroptions.coffee
@@ -1,15 +1,9 @@
 kd                    = require 'kd'
 isLoggedIn            = require 'app/util/isLoggedIn'
-showEnforceLoginModal = require 'app/util/showEnforceLoginModal'

 module.exports =

   name        : 'IDE'
   behavior    : 'application'
   multiple    : yes
-  dependencies: [ 'Ace', 'Finder' ]
-  preCondition:
-    condition  : (options, cb) -> cb isLoggedIn()
-    failure    : (options, cb) ->
-      kd.getSingleton('appManager').open 'IDE', conditionPassed : yes
-      showEnforceLoginModal()
+  dependencies: [ 'Ace', 'Finder' ]


main: cmd+option click to debug is back

main: cmd+option click to debug is back

--- client/landing/Core/mainviewcontroller.coffee
+++ client/landing/Core/mainviewcontroller.coffee
@@ -46,11 +46,11 @@

     windowController.on 'ScrollHappened', @bound 'handleScroll'

-    # if KD.config?.environment isnt 'production'
-    #   window.addEventListener 'click', (event) =>
-    #     if event.metaKey and event.altKey
-    #       logViewByElement event.target
-    #   , yes
+    if KD.config?.environment isnt 'production'
+      window.addEventListener 'click', (event) =>
+        if event.metaKey and event.altKey
+          logViewByElement event.target
+      , yes

   loadView:(mainView)->


Ignore l types (broken symbolic links) when parseLsOutput

--- client/landing/app/MainApp/fs/fshelper.coffee
+++ client/landing/app/MainApp/fs/fshelper.coffee
@@ -49,8 +49,9 @@
         [itemCount] = lines.splice(0,3)
         parentPath = parentPaths[0]
       for line in lines when line
-        unless systemFilesRegExp.test line
-          data.push FSHelper.createFile parseFile parentPath, line
+        unless line[0] is 'l' # broken symlinks has l type
+          unless systemFilesRegExp.test line
+            data.push FSHelper.createFile parseFile parentPath, line
     data

   @registry = {}


Adjust size and hide when editing is false

--- client/skr/screens/time-tracking/Popover.cjsx
+++ client/skr/screens/time-tracking/Popover.cjsx
@@ -4,7 +4,7 @@
 class Skr.Screens.TimeTracking.Popover extends Lanes.React.Component

     componentWillReceiveProps: (nextProps) ->
-        if @state.editing
+        if @state.editing and nextProps.editing is false
             @onCancel()
         else
             @setState(isCanceled: false)
@@ -46,7 +46,7 @@
         classes = _.classnames('edit-control', 'in')
         {x, y} = @props.position
         [width, height] = if @state.editing
-            [320, 320]
+            [320, 350]
         else
             [175, 60]


Can only send messages when there is one selected user.

--- client/templates/items_dial/items_dial.coffee
+++ client/templates/items_dial/items_dial.coffee
@@ -80,15 +80,16 @@
 Template.items_dial.events
   'click .circular': (e) ->
     e.preventDefault()
-    $(e.currentTarget).toggleClass "selected"
     item_id = $(e.currentTarget).attr("data-id")
-    selected_items = Session.get('selectedItems').slice()
-    if $(e.currentTarget).hasClass "selected"
-      selected_items.push item_id
-    else
-      index = selected_items.indexOf item_id
-      selected_items.splice(index, 1)
-    Session.set 'selectedItems', selected_items
+    if Router.current().route.getName() is "projectPage" and item_id != Meteor.userId()
+      $(e.currentTarget).toggleClass "selected"
+      selected_items = Session.get('selectedItems').slice()
+      if $(e.currentTarget).hasClass "selected"
+        selected_items.push item_id
+      else
+        index = selected_items.indexOf item_id
+        selected_items.splice(index, 1)
+      Session.set 'selectedItems', selected_items

   'click .title': (e) ->
     e.preventDefault()


bugfix showing missing report to normal participants

--- client/views/pages/dashboard/dashboard.coffee
+++ client/views/pages/dashboard/dashboard.coffee
@@ -19,11 +19,12 @@
 			reportSubmitted = false

 			for team in @teams
-				for user in team.participants when user._id == Meteor.userId()
+				for user in team.participants when user._id == Meteor.userId() && user.thisTeamleader
+					isTeamleader = true
 					if team.report && team.report.submitted
 						reportSubmitted = team.report.submitted

-			(@date < thisDate || @date == thisDate && @end <= thisTime) && !reportSubmitted
+			(@date < thisDate || @date == thisDate && @end <= thisTime) && !reportSubmitted && isTeamleader
 		else if a == 'accepted'
 			for team in @teams
 				for participant in team.participants
@@ -41,14 +42,14 @@
 	shiftRelation: ->
 		thisDate = parseInt moment(new Date).format 'YYYYDDDD'
 		thisTime = parseInt moment(new Date).format 'Hmm'
-		reportSubmitted = false

 		for team in @teams
-			for user in team.participants when user._id == Meteor.userId()
+			for user in team.participants when user._id == Meteor.userId() && user.thisTeamleader
+				isTeamleader = true
 				if team.report && team.report.submitted
 					reportSubmitted = team.report.submitted

-		if (@date < thisDate || @date == thisDate && @end <= thisTime) && !reportSubmitted
+		if (@date < thisDate || @date == thisDate && @end <= thisTime) && !reportSubmitted && isTeamleader
 			'missing'
 		else
 			for team in @teams


Removed private underscores from enable/disable.

--- src/ColorPicker.coffee
+++ src/ColorPicker.coffee
@@ -24,7 +24,7 @@
     #
     # Enable the color picker
     #
-    _enableColorPicker:() ->
+    enableColorPicker:() ->
         colorPickerElem = DOM.elemById('GENERATOR', 'COLORPICKER_CONTAINER')
         colorPickerElem.innerHTML = templates['generator-colorpicker'].render({})
         colorPickerElem.style.display = "block"
@@ -70,7 +70,7 @@
     #
     # Disable the color picker
     #
-    _disableColorPicker:() ->
+    disableColorPicker:() ->
         @_isColorPickerEnabled = false
         containerElem = DOM.elemById('GENERATOR','COLORPICKER_CONTAINER')
         containerElem.innerHTML = ""


Update entity.coffee

Update entity.coffee

--- src/lib/entity.coffee
+++ src/lib/entity.coffee
@@ -144,7 +144,7 @@
     #create proper position field
     pos =
       lat: data.latE6/1e6
-      lon: data.lngE6/1e6
+      lng: data.lngE6/1e6
     data.pos = pos

     data.time = timestamp


Printing special error to console of if errorHandler is defined

--- src/ometa-base.coffee
+++ src/ometa-base.coffee
@@ -510,7 +510,7 @@
               input = input.tl
             input.idx--
           return matchFailed(m, input.idx)
-        console.log "special error" + f
+        console.log "Special error: " + f if matchFailed?
         throw f

     @match: (obj, rule, args, matchFailed) ->


Updated cloudinary example with new event model.

--- src/sandbox/cloudinary-image-uploader.coffee
+++ src/sandbox/cloudinary-image-uploader.coffee
@@ -24,22 +24,22 @@
         @_dialog = dialog

         # Add event handlers for the dialog
-        @_dialog.bind 'imageuploader.cancelUpload', () =>
+        @_dialog.addEventListener 'imageuploader.cancelupload', () =>
             @_onCancelUpload()

-        @_dialog.bind 'imageuploader.clear', () =>
+        @_dialog.addEventListener 'imageuploader.clear', () =>
             @_onClear()

-        @_dialog.bind 'imageuploader.fileReady', (files) =>
+        @_dialog.addEventListener 'imageuploader.fileready', (files) =>
             @_onFileReady(files)

-        @_dialog.bind 'imageuploader.rotateCCW', () =>
+        @_dialog.addEventListener 'imageuploader.rotateccw', () =>
             @_onRotate(-90)

-        @_dialog.bind 'imageuploader.rotateCW', () =>
+        @_dialog.addEventListener 'imageuploader.rotatecw', () =>
             @_onRotate(90)

-        @_dialog.bind 'imageuploader.save', () =>
+        @_dialog.addEventListener 'imageuploader.save', () =>
             @_onSave()

     # Event handlers
@@ -61,8 +61,9 @@
         @_dialog.clear()
         @_image = null

-    _onFileReady: (file) ->
+    _onFileReady: (ev) ->
         # Handle a file being selected by the user
+        file = ev.file

         # Set the dialog state to uploading
         @_dialog.progress(0)


Fix #72 - allow zooming in to level 19

Fix #72 - allow zooming in to level 19

--- src/scripts/controllers/mapController.coffee
+++ src/scripts/controllers/mapController.coffee
@@ -30,6 +30,7 @@
       scrollWheelZoom: true
       zoom: 10
       minZoom: 2
+      maxZoom: 19
     @scope.tiles = maps.threedr_default

 class BoundsFactory


fix for missing accepts param on find response of new API code

--- noddy/service/oabutton/find.coffee
+++ noddy/service/oabutton/find.coffee
@@ -50,7 +50,7 @@
     opts.url = 'https://doi.org/' + (if opts.doi.indexOf('doi.org/') isnt -1 then opts.doi.split('doi.org/')[1] else opts.doi) if opts.doi
   return {} if not opts.url?

-  ret = {match:opts.url,availability:[],requests:[],meta:{article:{},data:{}}}
+  ret = {match:opts.url,availability:[],requests:[],accepts:[{type:'article'}],meta:{article:{},data:{}}}
   ret.library = API.service.oab.library(opts) if opts.library
   ret.libraries = API.service.oab.libraries(opts) if opts.libraries
   already = []


dont' die if peopleIds didn't change at all

--- models/team.coffee
+++ models/team.coffee
@@ -121,6 +121,7 @@
   v.init = @peopleIds
   v
 TeamSchema.pre 'save', (next) ->
+  return next() unless @peopleIds.init
   toString = (i) -> i.toString()
   o = @peopleIds.init.map toString
   n = @peopleIds.map toString


Simplify v1 constructor

Simplify v1 constructor

--- src/trix/core/helpers/custom_elements.coffee
+++ src/trix/core/helpers/custom_elements.coffee
@@ -62,14 +62,8 @@
 registerElement = do ->
   if window.customElements
     (tagName, properties) ->
-      constructor = ->
-        if typeof Reflect is "object"
-          Reflect.construct(HTMLElement, [], constructor)
-        else
-          HTMLElement.apply(this)
-      Object.setPrototypeOf(constructor.prototype, HTMLElement.prototype)
-      Object.setPrototypeOf(constructor, HTMLElement)
-      Object.defineProperties(constructor.prototype, properties)
+      constructor = -> Reflect.construct(HTMLElement, [], constructor)
+      constructor.prototype = Object.create(HTMLElement.prototype, properties)
       window.customElements.define(tagName, constructor)
       constructor
   else


don't scroll past container bottom

don't scroll past container bottom

Former-commit-id: 7ea1c5a31ccbc7f7f8566d2882e831ce45da8dd3 [formerly 84f68fc1eeacfc29bd4bcb6aa18cbffead524bcd] [formerly e3a0ba290206ad98dca38d1289d95458ea00252d [formerly 6fa31ff6a8f27afeefa9928d03d5157f261b2b54]] [formerly 10078f70c8edd9ab423d1532334e2e84870e32ed [formerly 8cdb33b15f6dadad41457efcfbaf6596b45695d8] [formerly 650dc99f0063757cc72fd6b55a667c469d70b694 [formerly 650dc99f0063757cc72fd6b55a667c469d70b694 [formerly a408c85bff05ffc42f4d02d4f75c9aac5995b35e]]]]
Former-commit-id: 4cba1c11c2da64c327c45a11708828e4ca52cc85 [formerly 4700e22bee0acdd9d1325d17d6330f34998ad737] [formerly ad1d96bbf28f575e0ba4d71d4898924bb10da575 [formerly 187d93d66da2b6ad735a8a3838cfb0feead923df]]
Former-commit-id: 82157af71a79f40410179fceadc854c1e03ff310 [formerly e7f43830309c587be78154819c4809341db81477]
Former-commit-id: b558f8a0ad50890c99c4b58692e977e6b22cf2d4
Former-commit-id: 0da68d7223d8966696e22bd3a0b2d06b2ecaf3bd

--- @client/assets/javascripts/vendor_extensions/jquery_extensions.js.coffee
+++ @client/assets/javascripts/vendor_extensions/jquery_extensions.js.coffee
@@ -106,9 +106,10 @@
           else
             new_translate = @current_translate + (@last_viewport_top - viewport_top) #- (effective_viewport_top - container_top)

-        # make sure that inertial scroll didn't force us to scroll past the bottom of the screen
-        if element_bottom + (new_translate - @current_translate) + @options.bottom_offset > $(document).height()
-          new_translate = $(document).height() - element_bottom + @current_translate - @options.bottom_offset
+        # make sure that inertial scroll didn't force us to scroll past the bottom of the container
+        container_bottom = container_top + @options.container.height()
+        if element_bottom + (new_translate - @current_translate) + @options.bottom_offset > container_bottom
+          new_translate = container_bottom - element_bottom + @current_translate - @options.bottom_offset

         if new_translate != @current_translate
           @current_translate = new_translate


global console keybinding

global console keybinding

--- keymaps/julia-client.cson
+++ keymaps/julia-client.cson
@@ -15,6 +15,7 @@
   'cmd-j cmd-r': 'julia-client:open-a-repl'
   'cmd-shift-j cmd-shift-r': 'julia-client:start-repl-client'
   'cmd-j cmd-s': 'julia-client:start-julia'
+  'cmd-j cmd-y': 'julia-client:toggle-console'
   'cmd-j cmd-c': 'julia-client:clear-console'
   'cmd-j cmd-l': 'julia-client:reset-loading-indicator'
   'cmd-j cmd-k': 'julia-client:kill-julia'


Thanks Madi for catching that spelling mistake

--- p/a-text-based-game/game/en.coffee
+++ p/a-text-based-game/game/en.coffee
@@ -129,7 +129,7 @@
     .then -> H.newLine(10)
     .then -> H.out 'You can’t see anymore.'
     .then -> H.out 'You’re tired, but can’t sleep.', 3
-    .then -> H.out 'You’re can’t feel your legs.', 3
+    .then -> H.out 'You can’t feel your legs.', 3
     .then -> H.out 'But you keep walking.', 3
     .then -> H.newLine(10)
     .then -> H.out 'Suddenly,'


fix method deepClone and underscore outcasts version

--- app/assets/javascripts/ultimate/underscore/underscore.outcasts.js.coffee
+++ app/assets/javascripts/ultimate/underscore/underscore.outcasts.js.coffee
@@ -15,7 +15,7 @@

 UnderscoreOutcasts =

-  VERSION: '0.1.5'
+  VERSION: '0.1.6'

   delete: (object, key) ->
     value = object[key]
@@ -179,14 +179,15 @@
   ###
    Create a (deep-cloned) duplicate of an object.
   ###
+  # TODO tests
   deepClone: (obj) ->
     return obj unless _.isObject(obj)
     if _.isArray(obj)
-      obj.slice()
+      @deepClone(element) for element in obj
     else
       newObj = {}
       if obj
-        for prop, value of obj
+        for prop, value of obj when not _.isFunction(value)
           newObj[prop] = @deepClone(value)
       newObj