fixed typo

fixed typo

--- src/main.coffee
+++ src/main.coffee
@@ -1,3 +1,3 @@
-Client = require './Client'
+Client = require './client'

 exports.Client = Client


Add langFilter

Add langFilter

--- lib/adapters/hTwitterAdapter.coffee
+++ lib/adapters/hTwitterAdapter.coffee
@@ -47,27 +47,29 @@
         @stream = stream
         stream.on "data", (data) =>
           unless data.disconnect
-            hTweet = {}
-            hTweetAuthor = {}
-            hTweetAuthor.listed = data.user.listed_count
-            hTweetAuthor.geo = data.user.geo_enabled
-            hTweetAuthor.verified = data.user.verified
-            hTweetAuthor.status = data.user.statuses_count
-            hTweetAuthor.location = data.user.location
-            hTweetAuthor.lang = data.user.lang
-            hTweetAuthor.url = data.user.url
-            hTweetAuthor.scrName = data.user.screen_name
-            hTweetAuthor.followers = data.user.followers_count
-            hTweetAuthor.profileImg = data.user.profile_image_url
-            hTweetAuthor.friends = data.user.friends_count
-            hTweetAuthor.description = data.user.description
-            hTweetAuthor.createdAt = new Date(data.user.created_at)
-            hTweetAuthor.name = data.user.name
-            hTweet.id = data.id_str
-            hTweet.source = data.source
-            hTweet.text = data.text
-            hTweet.author = hTweetAuthor
-            @owner.emit "message", @owner.buildMessage(@owner.actor, "hTweet", hTweet, {author: data.user.screen_name + "@twitter.com"})
+            console.log data.user.lang
+            if @properties.langFilter is undefined or data.user.lang is @properties.langFilter
+              hTweet = {}
+              hTweetAuthor = {}
+              hTweetAuthor.listed = data.user.listed_count
+              hTweetAuthor.geo = data.user.geo_enabled
+              hTweetAuthor.verified = data.user.verified
+              hTweetAuthor.status = data.user.statuses_count
+              hTweetAuthor.location = data.user.location
+              hTweetAuthor.lang = data.user.lang
+              hTweetAuthor.url = data.user.url
+              hTweetAuthor.scrName = data.user.screen_name
+              hTweetAuthor.followers = data.user.followers_count
+              hTweetAuthor.profileImg = data.user.profile_image_url
+              hTweetAuthor.friends = data.user.friends_count
+              hTweetAuthor.description = data.user.description
+              hTweetAuthor.createdAt = new Date(data.user.created_at)
+              hTweetAuthor.name = data.user.name
+              hTweet.id = data.id_str
+              hTweet.source = data.source
+              hTweet.text = data.text
+              hTweet.author = hTweetAuthor
+              @owner.emit "message", @owner.buildMessage(@owner.actor, "hTweet", hTweet, {author: data.user.screen_name + "@twitter.com"})
           else
             @owner.log "debug", "twitter stream close"
       super


Changing port number to correspond with service definition

--- src/mint.coffee
+++ src/mint.coffee
@@ -27,7 +27,7 @@
 #====================
 app = connect()
 app.use harp.mount(__dirname + "/../public")
-http.createServer(app).listen(3000, () ->
+http.createServer(app).listen(80, () ->
    console.log "\nMint is online."
 )


Remove unused function

Remove unused function

--- app/javascript/src/legacy/common.coffee
+++ app/javascript/src/legacy/common.coffee
@@ -51,11 +51,6 @@
       $(element).showBase()
     else
       $(element).hide()
-  setClassName: (element, className, enabled) ->
-    if enabled
-      $(element).addClassName className
-    else
-      $(element).removeClassName className
   isParentNode: (element, parentNode) ->
     while element
       if element == parentNode


:lipstick: Add whitespace

:lipstick: Add whitespace

--- src/random/seeds/paul_houle.coffee
+++ src/random/seeds/paul_houle.coffee
@@ -10,7 +10,9 @@
   @include mixins.Formattable('PaulHoule','seed')

   ### Public ###
+
   constructor: (@seed) ->
+
   get: ->
     @seed = (@seed * 9301 + 49297) % 233280
     @seed / 233280.0


chore (Test) Add mock steroids.view.on and steroids.view.off


Fix throw test

Fix throw test

should.throw needs to be executed

--- test/mocha/kissmetrics-batch.coffee
+++ test/mocha/kissmetrics-batch.coffee
@@ -24,7 +24,7 @@
     failToInstantiate = ->
       new KM 'apiKey', 'evan@example.com', {batch: {queue: failedQueue}}

-    failToInstantiate.should.throw
+    failToInstantiate.should.throw()

 describe 'Use the queue', ->


initial commit of completed zh_hk translation

--- t9n/zh_hk.coffee
+++ t9n/zh_hk.coffee
@@ -1,33 +1,33 @@
-#Language: Traditional Chinese
-#Translators: victorleungtw
+#Language: Traditional Chinese (Hong Kong)
+#Translators: daveeel

-zh_tw =
+zh_hk =

-  add: "添加"
+  add: "新增"
   and: "和"
   back: "返回"
   changePassword: "修改密碼"
   choosePassword: "選擇密碼"
   clickAgree: "點擊註冊, 您同意我們的"
-  configure: "配置"
+  configure: "設定"
   createAccount: "建立帳號"
-  currentPassword: "當前密碼"
-  dontHaveAnAccount: "還沒有賬戶?"
-  email: "電子郵箱"
+  currentPassword: "現有密碼"
+  dontHaveAnAccount: "還沒有賬號？"
+  email: "電郵"
   emailAddress: "電郵地址"
-  emailResetLink: "電子郵件重設連結"
+  emailResetLink: "重設電郵連結"
   forgotPassword: "忘記密碼?"
-  ifYouAlreadyHaveAnAccount: "如果您已有賬戶"
+  ifYouAlreadyHaveAnAccount: "如果已有賬號"
   newPassword: "新密碼"
   newPasswordAgain: "新密碼 (重新輸入)"
-  optional: "可選的"
+  optional: "可選填"
   OR: "或"
   password: "密碼"
-  passwordAgain: "密碼 (重新輸入)"
-  privacyPolicy: "隱私政策"
+  passwordAgain: "密碼（重新輸入）"
+  privacyPolicy: "私隱條款"
   remove: "刪除"
-  resetYourPassword: "重置您的密碼"
-  setPassword: "設置密碼"
+  resetYourPassword: "重置密碼"
+  setPassword: "設定密碼"
   sign: "登"
   signIn: "登入"
   signin: "登入"
@@ -43,22 +43,22 @@

   info:
-    emailSent: "郵件已發送"
-    emailVerified: "郵件已驗證"
-    passwordChanged: "密碼已修改"
+    emailSent: "已發送郵件"
+    emailVerified: "已驗證郵件"
+    passwordChanged: "已修改密碼"
     passwordReset: "密碼重置"

   error:
     emailRequired: "必須填寫電子郵件。"
-    minChar: "密碼至少需要7個字符。"
+    minChar: "密碼至少需要 7 個字符。"
     pwdsDontMatch: "密碼不一致。"
-    pwOneDigit: "密碼必須至少有一位數字。"
-    pwOneLetter: "密碼必須至少有一位字母。"
+    pwOneDigit: "密碼必須至少包括一個數字。"
+    pwOneLetter: "密碼必須至少有包括一個字符。"
     signInRequired: "您必須先登錄才能繼續。"
-    signupCodeIncorrect: "註冊碼錯誤。"
+    signupCodeIncorrect: "註冊碼不符。"
     signupCodeRequired: "必須有註冊碼。"
-    usernameIsEmail: "用戶名不能為電郵地址。"
+    usernameIsEmail: "用戶名不能設為電郵地址。"
     usernameRequired: "必須有用戶名。"

@@ -67,18 +67,18 @@
       #---- accounts-base
       #"@" + domain + " email required"
       #"A login handler should return a result or undefined"
-      "Email already exists.": "電郵地址已被使用。"
+      "Email already exists.": "電郵地址已在本服務登記使用。"
       "Email doesn't match the criteria.": "電郵地址不符合條件。"
-      "Invalid login token": "無效的登錄令牌"
+      "Invalid login token": "無效的登錄編碼"
       "Login forbidden": "禁止登錄"
       #"Service " + options.service + " already configured"
       "Service unknown": "未知服務"
-      "Unrecognized options for login request": "無法識別的登錄請求選項"
+      "Unrecognized options for login request": "無法識別的登錄請求"
       "User validation failed": "用戶驗證失敗"
-      "Username already exists.": "用戶名已經存在。"
+      "Username already exists.": "用戶名已存在。"
       "You are not logged in.": "您尚未登入。"
-      "You've been logged out by the server. Please log in again.": "你已被伺服器登出，請重新登入。"
-      "Your session has expired. Please log in again.": "您的協定已過期，請重新登入。"
+      "You've been logged out by the server. Please log in again.": "您已被強制登出，請重新登入。"
+      "Your session has expired. Please log in again.": "閒置時間過長，請重新登入。"

       #---- accounts-oauth
@@ -86,7 +86,7 @@

       #---- accounts-password-client
-      "Password is old. Please reset your password.": "密碼是舊的。請重置您的密碼。"
+      "Password is old. Please reset your password.": "密碼已失效，請重置。"

       #---- accounts-password
@@ -95,20 +95,20 @@
       "Must be logged in": "必須先登入"
       "Need to set a username or email": "必須設置用戶名或電郵地址"
       "old password format": "舊密碼格式"
-      "Password may not be empty": "密碼不能為空的"
+      "Password may not be empty": "密碼不能為空"
       "Signups forbidden": "註冊被禁止"
-      "Token expired": "密匙過期"
-      "Token has invalid email address": "密匙具有無效的電郵地址"
-      "User has no password set": "用戶沒有設置密碼"
+      "Token expired": "編碼已經過期"
+      "Token has invalid email address": "編碼中的電郵地址無效"
+      "User has no password set": "用戶尚未設置密碼"
       "User not found": "找不到用戶"
       "Verify email link expired": "驗證電郵連結已過期"
       "Verify email link is for unknown address": "驗證電郵連結是未知的地址"

       #---- match
-      "Match failed": "匹配失敗"
+      "Match failed": "無法配對"

       #---- Misc...
-      "Unknown error": "未知錯誤"
+      "Unknown error": "無法確認的系統問題"

-T9n.map "zh_tw", zh_tw
+T9n.map "zh_hk", zh_hk


remove font-size from atom cfg

remove font-size from atom cfg

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -5,7 +5,6 @@
       "exception-reporting"
     ]
   editor:
-    fontSize: 16
     invisibles: {}
     showIndentGuide: true
     softWrapAtPreferredLineLength: true


Customizing atom

Customizing atom

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,6 +1,38 @@
 "*":
+  editor:
+    showIndentGuide: true
+    fontFamily: "Menlo"
+    invisibles: {}
+    fontSize: 15
+    softWrapAtPreferredLineLength: true
   core:
+    ignoredNames: [
+      ".bundle"
+      ".git"
+      "log"
+      "repositories"
+      "tmp"
+      "vendor"
+    ]
+    themes: [
+      "unity-ui"
+      "glacier-syntax"
+    ]
+    hideGitIgnoredFiles: true
     disabledPackages: [
+      "background-tips"
+      "exception-reporting"
+      "metrics"
       "markdown-preview"
     ]
-  linter: {}
+  "spell-check":
+    grammars: [
+      "text.plain"
+      "source.gfm"
+      "text.git-commit"
+    ]
+  welcome:
+    showOnStartup: false
+  "markdown-preview-plus":
+    useLazyHeaders: false
+    useGitHubStyle: true


bump atom config

bump atom config

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,34 +1,35 @@
-'editor':
-  'showIndentGuide': true
-  'fontFamily': 'Menlo'
-  'fontSize': 15
-  'invisibles': {}
-'core':
-  'ignoredNames': [
-    '.bundle'
-    '.git'
-    'log'
-    'repositories'
-    'tmp'
-    'vendor'
-  ]
-  'themes': [
-    'unity-ui'
-    'glacier-syntax'
-  ]
-  'hideGitIgnoredFiles': true
-  'disabledPackages': [
-    'background-tips'
-    'exception-reporting'
-    'metrics'
-  ]
-'spell-check':
-  'grammars': [
-    'text.plain'
-    'source.gfm'
-    'text.git-commit'
-  ]
-'welcome':
-  'showOnStartup': false
-'release-notes':
-  'viewedVersion': '0.89.0'
+'global':
+  'editor':
+    'showIndentGuide': true
+    'fontFamily': 'Menlo'
+    'fontSize': 15
+  'core':
+    'ignoredNames': [
+      '.bundle'
+      '.git'
+      'log'
+      'repositories'
+      'tmp'
+      'vendor'
+    ]
+    'themes': [
+      'unity-ui'
+      'glacier-syntax'
+    ]
+    'hideGitIgnoredFiles': true
+    'disabledPackages': [
+      'background-tips'
+      'exception-reporting'
+      'metrics'
+    ]
+  'spell-check':
+    'grammars': [
+      'text.plain'
+      'source.gfm'
+      'text.git-commit'
+    ]
+  'welcome':
+    'showOnStartup': false
+  'release-notes':
+    'viewedVersion': '0.89.0'
+  'go-plus': {}


add keymaps for next and prev words

add keymaps for next and prev words

--- atom.symlink/keymap.cson
+++ atom.symlink/keymap.cson
@@ -12,7 +12,12 @@
   # go to line prompt
   'cmd-m': 'go-to-line:toggle'

-  'shift-cmd-S': 'unset!'
+  'cmd-shift-S': 'core:save'
+
+  'alt-j': 'editor:move-to-previous-word-boundary'
+  'alt-shift-j': 'editor:select-to-previous-word-boundary'
+  'alt-k': 'editor:move-to-next-word-boundary'
+  'alt-shift-k': 'editor:select-to-next-word-boundary'

 'atom-workspace atom-text-editor:not([mini])':
   'cmd-j': 'unset!'


Now checks that box.name is set

Now checks that box.name is set

--- util/migrateBoxToServer.coffee
+++ util/migrateBoxToServer.coffee
@@ -99,6 +99,12 @@
     return callback()

 Box.findOneByName BOX_NAME, (err, box) ->
+  if err?
+    console.log "Error #{err}"
+    process.exit 1
+  if not box
+    console.log "Box not found. #{BOX_NAME}"
+    process.exit 1
   console.log "Migrating box #{box.name}"
   box = Box.makeModelFromMongo box
   User.findByShortName box.users[0], (err, user) ->


coffee-script template should require jQuery

--- lib/generators/templates/application.js.coffee
+++ lib/generators/templates/application.js.coffee
@@ -1,3 +1,4 @@
+#= require jquery
 #= require handlebars
 #= require ember
 #= require ember-data


Constructor refactoring.

Constructor refactoring.

--- lib/chat.coffee
+++ lib/chat.coffee
@@ -676,16 +676,19 @@

 class ChatService

-  constructor : (@options = {}, @hooks = {}, state = 'memory') ->
-    @io = @options.io
-    @sharedIO = true if @io
-    @http = @options.http unless @io
-    state = switch state
-      when 'memory' then MemoryState
-      when typeof state == 'function' then state
-      else throw new Error "Invalid state: #{state}"
-
-    # options, constant for a server instance
+  constructor : (@options = {}, @hooks = {}, @state = 'memory') ->
+    @setOptions()
+
+    @setServer()
+
+    if @hooks.onStart
+      @hooks.onStart @, (error) =>
+        if error then return @close null, error
+        @setEvents()
+    else
+      @setEvents()
+
+  setOptions : ->
     @namespace = @options.namespace || '/chat-service'
     @historyMaxMessages = @options.historyMaxMessages || 100
     @useRawErrorObjects = @options.useRawErrorObjects || false
@@ -694,26 +697,26 @@
     @enableDirectMessages = @options.enableDirectMessages || false
     @serverOptions = @options.serverOptions

-    @errorBuilder = new ErrorBuilder @useRawErrorObjects, @hooks.serverErrorHook
-    @userCommands = userCommands
-    @User = User
-    @Room = Room
-    @chatState = new state @
-
+  setServer : ->
+    @io = @options.io
+    @sharedIO = true if @io
+    @http = @options.http unless @io
+    state = switch @state
+      when 'memory' then MemoryState
+      when typeof @state == 'function' then @state
+      else throw new Error "Invalid state: #{@state}"
     unless @io
       if @http
         @io = socketIO @http, @serverOptions
       else
         port = @serverOptions?.port || 8000
         @io = socketIO port, @serverOptions
-
     @nsp = @io.of @namespace
-    if @hooks.onStart
-      @hooks.onStart @, (error) =>
-        if error then return @close null, error
-        @setEvents()
-    else
-      @setEvents()
+    @userCommands = userCommands
+    @User = User
+    @Room = Room
+    @errorBuilder = new ErrorBuilder @useRawErrorObjects, @hooks.serverErrorHook
+    @chatState = new state @

   setEvents : ->
     if @hooks.auth


stop rotating body on mobile landscape, that is an ugly hack

--- client/main.coffee
+++ client/main.coffee
@@ -21,21 +21,13 @@
 ua = navigator.userAgent
 iphone = ~ua.indexOf('iPhone') || ~ua.indexOf('iPod')

-hideNavbar = ->
+iPhoneHideNavbar = ->
   if iphone
     height = document.documentElement.clientHeight + 60
     $("body").css(height: height + 'px')
     setTimeout((-> window.scrollTo(0, 0)), 1)

-rotateBody = ->
-  if iphone
-    rotate = -1 * window.orientation
-    $("body").css("-webkit-transform", "rotate(#{rotate}deg)")
-    $("body").css("transform", "rotate(#{rotate}deg)")
-
 Meteor.startup ->
-  hideNavbar()
-  rotateBody()
+  iPhoneHideNavbar()
   $("body").on "orientationchange", ->
-    hideNavbar()
-    rotateBody()
+    iPhoneHideNavbar()


Restructure/add some new notice tests.

Restructure/add some new notice tests.

--- spec/notice.spec.coffee
+++ spec/notice.spec.coffee
@@ -7,73 +7,91 @@
       error = e
     error

+  describe 'defaults', ->
+    [notice, output] = [null, null, null]

-  describe 'context option', ->
-    it 'allows setting context from options array', ->
-      Honeybadger.resetContext()
-      notice = new Notice(context: { user_id: '1' })
-      expect(notice.context).toEqual({ user_id: '1' })
+    beforeEach () ->
+      notice = new Notice
+      output = notice.payload()

-    it 'overrides global context without changing it', ->
-      Honeybadger.resetContext({ user_id: '2', user_name: 'Jack' })
-      notice = new Notice(context: { user_id: '1' })
-      expect(notice.context).toEqual({ user_id: '1', user_name: 'Jack' })
-      expect(Honeybadger.context).toEqual({ user_id: '2', user_name: 'Jack' })
+    describe 'error payload', ->
+      it 'exists', ->
+        expect(output.error).toBeDefined()

-  describe '#payload()', ->
-    it 'is defined', ->
-      notice = new Notice
-      expect(notice.payload).toBeDefined()
+      it 'has a default message', ->
+        expect(output.error.message).toMatch(/message/)

-    describe 'error is present', ->
-      [error, notice, output] = [null, null, null]
+      it 'has a default class', ->
+        expect(output.error.class).toEqual('Error')

-      beforeEach () ->
-        e = mockError()
-        notice = new Notice({ stack: e.stack, message: e.message, name: e.name })
-        output = notice.payload()
+      it 'has a null backtrace', ->
+        expect(output.error.backtrace).toEqual(null)

-      describe 'server', ->
-        it 'exists', ->
-          expect(output.server).toBeDefined()
+      it 'has source extract', ->
+        expect(output.error.source).toBeDefined()

-      describe 'error', ->
-        it 'exists', ->
-          expect(output.error).toBeDefined()
+      it 'doesn\'t have a fingerprint by default', ->
+        expect(output.error.fingerprint).toEqual(null)

-        it 'has backtrace', ->
-          expect(output.error.backtrace).toBeDefined()
+    describe 'request payload', ->
+      it 'exists', ->
+        expect(output.request).toBeDefined()

-        it 'has source extract', ->
-          expect(output.error.source).toBeDefined()
+      it 'sends a null action', ->
+        expect(output.request.action).toEqual(null)

-        it 'doesn\'t have a fingerprint by default', ->
-          expect(output.error.fingerprint).toEqual(null)
+      it 'sends a null component', ->
+        expect(output.request.component).toEqual(null)

-      describe "cyclic structures in payload", ->
-        it "converts cyclic structures", ->
-          e = mockError()
-          c = { "foo": "bar" }
-          c["c"] = c
-          notice = new Notice({ stack: e.stack, message: e.message, name: e.name, context: c })
-          json = JSON.stringify(notice.payload()) # shouldn't cause error.
-          expect(json.match(/CIRCULAR DATA STRUCTURE/g).length).toEqual(1)
+    describe 'server payload', ->
+      it 'exists', ->
+        expect(output.server).toBeDefined()

-        it 'converts arrays in context', ->
-          Array.prototype.blah = -> 'whatevs'
-          e = mockError()
-          c = { "foo": ['boo'], 'bar': ['baz'] }
-          notice = new Notice({ stack: e.stack, message: e.message, name: e.name, context: c })
-          json = JSON.stringify(notice.payload()) # shouldn't cause error.
-          expect(json.match(/CIRCULAR DATA STRUCTURE/g)).toBeNull()
+  describe 'with options', ->
+    it 'overrides the message', ->
+      output = new Notice({ message: "Badgers" }).payload()
+      expect(output.error.message).toEqual("Badgers")
+
+    it 'overrides the class', ->
+      output = new Notice({ name: "Badgers" }).payload()
+      expect(output.error.class).toEqual("Badgers")
+
+    it 'overrides the backtrace', ->
+      output = new Notice({ stack: "foo" }).payload()
+      expect(output.error.backtrace).toEqual("foo")
+
+    it 'overrides the component', ->
+      output = new Notice({ component: "Badgers" }).payload()
+      expect(output.request.component).toEqual("Badgers")
+
+  describe 'options which should be strings', ->
+    it 'converts the message to a string', ->
+      output = new Notice({ message: { badgers: true } }).payload()
+      expect(output.error.message).toEqual("[object Object]")
+
+  describe "cyclic structures in payload", ->
+    it "converts cyclic structures", ->
+      e = mockError()
+      c = { "foo": "bar" }
+      c["c"] = c
+      notice = new Notice({ stack: e.stack, message: e.message, name: e.name, context: c })
+      json = JSON.stringify(notice.payload()) # shouldn't cause error.
+      expect(json.match(/CIRCULAR DATA STRUCTURE/g).length).toEqual(1)
+
+    it 'converts arrays in context', ->
+      Array.prototype.blah = -> 'whatevs'
+      e = mockError()
+      c = { "foo": ['boo'], 'bar': ['baz'] }
+      notice = new Notice({ stack: e.stack, message: e.message, name: e.name, context: c })
+      json = JSON.stringify(notice.payload()) # shouldn't cause error.
+      expect(json.match(/CIRCULAR DATA STRUCTURE/g)).toBeNull()

   describe 'with a fingerprint', ->
-    describe '#payload()', ->
-      it 'has a fingerprint', ->
-        notice = new Notice({ fingerprint: 'asdf' })
-        output = notice.payload()
-        expect(output.error.fingerprint).toBeDefined()
-        expect(output.error.fingerprint).toEqual('asdf')
+    it 'adds fingerprint to payload', ->
+      notice = new Notice({ fingerprint: 'asdf' })
+      output = notice.payload()
+      expect(output.error.fingerprint).toBeDefined()
+      expect(output.error.fingerprint).toEqual('asdf')

   describe "#_sanitize()", ->
     notice = new Notice()
@@ -103,3 +121,15 @@
     it 'converts functions', ->
       o = { foo: () -> console.log("foo") }
       expect(sanitize(o)).toEqual({ foo: "[FUNC]" })
+
+  describe 'context option', ->
+    it 'allows setting context from options array', ->
+      Honeybadger.resetContext()
+      notice = new Notice(context: { user_id: '1' })
+      expect(notice.context).toEqual({ user_id: '1' })
+
+    it 'overrides global context without changing it', ->
+      Honeybadger.resetContext({ user_id: '2', user_name: 'Jack' })
+      notice = new Notice(context: { user_id: '1' })
+      expect(notice.context).toEqual({ user_id: '1', user_name: 'Jack' })
+      expect(Honeybadger.context).toEqual({ user_id: '2', user_name: 'Jack' })


Never again will changes to 'sample.js' bite us in the ass

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -150,3 +150,19 @@

 $.fn.simulateDomAttachment = ->
   $('<html>').append(this)
+
+throw "Sample.js is modified" unless fs.read(require.resolve('fixtures/sample.js')) == """
+  var quicksort = function () {
+    var sort = function(items) {
+      if (items.length <= 1) return items;
+      var pivot = items.shift(), current, left = [], right = [];
+      while(items.length > 0) {
+        current = items.shift();
+        current < pivot ? left.push(current) : right.push(current);
+      }
+      return sort(left).concat(pivot).concat(sort(right));
+    };
+
+    return sort(Array.apply(this, arguments));
+  };
+"""


bug fix for clear archive in progress flag

--- services/track-changes/app/coffee/MongoManager.coffee
+++ services/track-changes/app/coffee/MongoManager.coffee
@@ -150,7 +150,7 @@
 		db.docHistory.update { _id: update._id }, { $set : { inS3 : false } }, callback

 	clearDocHistoryAsArchiveInProgress: (doc_id, update, callback) ->
-		db.docHistory.update { _id: update._id }, { $set : { inS3 : false } }, callback
+		db.docHistory.update { _id: update._id }, { $unset : { inS3 : true } }, callback

 	markDocHistoryAsArchived: (doc_id, update, callback)->
 		db.docHistory.update { _id: update._id }, { $set : { inS3 : true } }, (error)->


fix(conf): changed path default config

fix(conf): changed path default config

--- lib/init.coffee
+++ lib/init.coffee
@@ -2,4 +2,4 @@

 module.exports =
   configDefaults:
-    jshintExecutablePath: path.join __dirname, '..', 'node_modules', '.bin'
+    jshintExecutablePath: path.join __dirname, '..', 'node_modules', 'jshint', 'bin'


Reload window after compile has finished

--- lib/main.coffee
+++ lib/main.coffee
@@ -16,7 +16,7 @@
     # via which the compiler can be executed
     activate: ->
       @subscriptions = new CompositeDisposable()
-      @subscriptions.add atom.commands.add 'atom-workspace', 'language-markdown:compile-grammar': => @compileGrammar()
+      @subscriptions.add atom.commands.add 'atom-workspace', 'markdown:compile-grammar-and-reload': => @compileGrammar()

     # Reads fixtures from {input},
     # parses {data} to expand shortened syntax,
@@ -52,9 +52,11 @@
       grammar.repository['fenced-code-blocks'] =
         patterns: @compileFencedCodeGrammar()

+      # Write {grammar} to {filepath},
+      # and reload window when complete
       filepath = path.join(__dirname, output)
       CSON.writeFileSync filepath, grammar, do ->
-        console.log "[language-markdown] Done!"
+        atom.commands.dispatch 'body', 'window:reload'

     # Transform an {item} into a {pattern} object,
     # and adds it to the {patterns} array.


Remove another old conditional

Remove another old conditional

--- lib/main.coffee
+++ lib/main.coffee
@@ -102,8 +102,3 @@
           notification.dismiss()
       }]
     localStorage.setItem('hasSeenDeprecatedNotification', true)
-
-if parseFloat(atom.getVersion()) < 1.7
-  atom.deserializers.add
-    name: 'SettingsView'
-    deserialize: module.exports.createSettingsView.bind(module.exports)


registerCommandFromSpec take name as 1st-arg

--- lib/main.coffee
+++ lib/main.coffee
@@ -31,6 +31,6 @@

     commandPrefix = 'vim-mode-plus-user'
     @subscriptions.add(
-      registerCommandFromSpec({name: 'JasmineIncreaseFocus', commandPrefix, getClass})
-      registerCommandFromSpec({name: 'JasmineDecreaseFocus', commandPrefix, getClass})
+      registerCommandFromSpec('JasmineIncreaseFocus', {commandPrefix, getClass})
+      registerCommandFromSpec('JasmineDecreaseFocus', {commandPrefix, getClass})
     )


Partial backbone implementation

Partial backbone implementation

--- coffee/main.coffee
+++ coffee/main.coffee
@@ -135,6 +135,28 @@

   continue: (x, y, lc) ->
     lc.primaryColor = lc.getPixel(x, y)
+
+
+LC.Drawing = Backbone.Model.extend
+
+  initialize: ->
+    console.log()
+
+
+LC.Canvas = Backbone.View.extend
+
+  initialize: ->
+    @ctx = @el.getContext('2d')
+
+  render: ->
+    @ctx.clearRect(0, 0, @el.width, @el.height)
+    @ctx.save()
+    @ctx.translate @model.get('position.x'), @model.get('position.y')
+    @ctx.scale @scale, @scale
+    _.each @shapes, (s) =>
+      s.draw(@ctx)
+    currentShape.draw(@ctx) if currentShape
+    @ctx.restore()

 class LC.LiterallyCanvas


debug start/install app (undefined variable)

--- lib/paas.coffee
+++ lib/paas.coffee
@@ -95,13 +95,13 @@
                             console.log err.stack
                             callback err
                         else
-                            console.log res.body
-                            callback(res.body)
+                            console.log body
+                            callback(body)
                     else
                         #@client.brunch app.getHaibuDescriptor(), (err, res) =>
                         console.info "Successfully spawned app: #{app.name}"
                         console.info "Update proxy..."
-                        callback null, result
+                        callback null, body

     # Remove and reinstall app inside Haibu.
     updateApp: (app, callback) ->
@@ -137,7 +137,7 @@
                             else
                                 #@client.brunch app.getHaibuDescriptor(), (err, res) =>
                                 console.info "Successfully update app: #{app.name}"
-                                callback null, result
+                                callback null, body

     # Send a uninstall request to controller server ("clean" request).


Remove function fixRoundingError

Remove function fixRoundingError

--- lib/path.coffee
+++ lib/path.coffee
@@ -310,12 +310,12 @@

     th_half = 0.5 * (th1 - th0)
     t = (8 / 3) * Math.sin(th_half * 0.5) * Math.sin(th_half * 0.5) / Math.sin(th_half)
-    x1 = fixRoundingError(cx + Math.cos(th0) - t * Math.sin(th0))
-    y1 = fixRoundingError(cy + Math.sin(th0) + t * Math.cos(th0))
-    x3 = fixRoundingError(cx + Math.cos(th1))
-    y3 = fixRoundingError(cy + Math.sin(th1))
-    x2 = fixRoundingError(x3 + t * Math.sin(th1))
-    y2 = fixRoundingError(y3 - t * Math.cos(th1))
+    x1 = cx + Math.cos(th0) - t * Math.sin(th0)
+    y1 = cy + Math.sin(th0) + t * Math.cos(th0)
+    x3 = cx + Math.cos(th1)
+    y3 = cy + Math.sin(th1)
+    x2 = x3 + t * Math.sin(th1)
+    y2 = y3 - t * Math.cos(th1)

     return [
       a00 * x1 + a01 * y1,   a10 * x1 + a11 * y1,
@@ -323,9 +323,4 @@
       a00 * x3 + a01 * y3,   a10 * x3 + a11 * y3
     ]

-  fixRoundingError = (x) ->
-    if Math.abs(Math.round(x) - x) < 0.0000000000001
-      return Math.round(x);
-    return x
-
-module.exports = SVGPath+module.exports = SVGPath


opt: npm

opt: npm

--- libs/npm.coffee
+++ libs/npm.coffee
@@ -1,18 +1,15 @@
+require 'colors'
 which = require 'which'
 fs = require 'nofs'
-require 'colors'

 GLOBAL_NPM_BIN = fs.realpathSync which.sync 'npm'
-
-if process.platform is "win32"
-    GLOBAL_NPM_PATH = fs.path.join GLOBAL_NPM_BIN, '../node_modules/npm'
-else
-    GLOBAL_NPM_PATH = fs.path.join GLOBAL_NPM_BIN, '../..'
+GLOBAL_NPM_PATH = fs.path.join GLOBAL_NPM_BIN,
+    if process.platform is "win32" then '../node_modules/npm' else '../..'

 try
     npm = require GLOBAL_NPM_PATH
 catch
-    console.error "npm not found in #{GLOBAL_NPM_PATH}!".red
+    console.error "npm not found in #{GLOBAL_NPM_PATH} !".red
     process.exit 1

 console.log "npm version: #{npm.version or 'Unknown'}".cyan


multiply with 2

multiply with 2

--- mechanics/001-binary-stars/csmain.coffee
+++ mechanics/001-binary-stars/csmain.coffee
@@ -28,8 +28,8 @@
         a = parseFloat(ps['a'])
         e = parseFloat(ps['e'])
         M = m1 + m2
-        x1 = m2 / M * a
-        x2 = - m1 / M * a
+        x1 = m2 / M * a * 2
+        x2 = - m1 / M * a * 2

         v  = Math.sqrt(au.G * M / a * (1 - e) / (1 + e))
         v1 = v / M * m2


Projects removed also treated as archived

--- services/web/app/coffee/Features/Project/ProjectController.coffee
+++ services/web/app/coffee/Features/Project/ProjectController.coffee
@@ -444,7 +444,7 @@
 			lastUpdated: moment.unix(project.updated_at)
 #			publicAccessLevel:
 #			accessLevel:
-			archived: project.archived
+			archived: project.removed || project.archived
 #			owner_ref:
 			isOLProject: true
 		}


test regex endpoint

test regex endpoint

--- src/poll.coffee
+++ src/poll.coffee
@@ -60,9 +60,10 @@
 		catch error
 			msg.send error
 			@robot.logger.info error
+
+	robot.respond /vote\s+([a-f\d]{5})\s+(\d)/i, (ms) ->
+		msg.reply "Thanks for your vote"

-
-
 	robot.respond /poll ping/i, (msg) ->
 		@robot.logger.info "ping called"
 		msg.reply "poll pong"


formatting

formatting

--- test/mustdo-manager.coffee
+++ test/mustdo-manager.coffee
@@ -13,25 +13,41 @@

   it 'is initialized with empty task list', ->
-    assert.deepStrictEqual @manager.full_task_list, {}, 'task list for all days is empty object'
+    assert.deepStrictEqual @manager.full_task_list, {},
+      'task list for all days is empty object'

-    assert.deepStrictEqual @manager.task_list(), [], 'task list for today is empty list'
+    assert.deepStrictEqual @manager.task_list(), [],
+      'task list for today is empty list'

   it 'can be initialized with a task list', ->
     @manager = new MustDoManager { 20151010: [ {description: 'walk the house'} ] }
-    assert.deepStrictEqual @manager.full_task_list, { 20151010: [ {description: 'walk the house'} ] }
+    assert.deepStrictEqual @manager.full_task_list,
+      { 20151010: [ {description: 'walk the house'} ] }

-    assert.deepStrictEqual @manager.task_list('20151010'), [ {description: 'walk the house'} ]
+    assert.deepStrictEqual @manager.task_list('20151010'),
+      [ {description: 'walk the house'} ]

   it 'adds simple tasks to the default task list', ->
-    assert.strictEqual @manager.add_task({description: 'do the laundry'}), 1, 'result is the task ordinal, 1'
+    assert.strictEqual @manager.add_task({description: 'do the laundry'}),
+      1,
+      'result is the task ordinal, 1'

-    assert.strictEqual @manager.task_list()[0].description, 'do the laundry', 'description is preserved: first task'
-    assert.strictEqual @manager.task_list()[0].ordinal, 1, 'ordinal is preserved: first task'
+    assert.strictEqual @manager.task_list()[0].description,
+      'do the laundry',
+      'description is preserved: first task'
+    assert.strictEqual @manager.task_list()[0].ordinal,
+      1,
+      'ordinal is preserved: first task'

-    assert.strictEqual @manager.add_task({description: 'turn out the lights'}), 2, 'result is the task ordinal, 2'
-    assert.strictEqual @manager.task_list()[1].description, 'turn out the lights', 'description is preserved: second task'
-    assert.strictEqual @manager.task_list()[1].ordinal, 2, 'ordinal is preserved: second task'
+    assert.strictEqual @manager.add_task({description: 'turn out the lights'}),
+      2,
+      'result is the task ordinal, 2'
+    assert.strictEqual @manager.task_list()[1].description,
+      'turn out the lights',
+      'description is preserved: second task'
+    assert.strictEqual @manager.task_list()[1].ordinal,
+      2,
+      'ordinal is preserved: second task'

   it 'completes tasks without removing them', ->
     manager = @manager
@@ -41,5 +57,9 @@
     ].forEach (task) ->
       manager.add_task(task)

-    assert.strictEqual manager.complete_task(2), 2, 'Returns ordinal of completed task'
-    assert.strictEqual manager.task_list()[1].completed, true, 'Completing a task results in turning on its completed attribute'
+    assert.strictEqual manager.complete_task(2),
+      2,
+      'Returns ordinal of completed task'
+    assert.strictEqual manager.task_list()[1].completed,
+      true,
+      'Completing a task results in turning on its completed attribute'


Missed removing removed method

Missed removing removed method

--- resources/assets/coffee/react/beatmaps/search-content.coffee
+++ resources/assets/coffee/react/beatmaps/search-content.coffee
@@ -38,10 +38,6 @@
 export class SearchContent extends React.Component
   constructor: ->
     @virtualListMeta = new VirtualListMeta
-
-
-  componentWillUnmount: ->
-    @virtualListMeta.destroy()

   render: ->


Fixing the example

Fixing the example

--- examples/kitchen-sink/coffeescript/kitchen-sink.coffee
+++ examples/kitchen-sink/coffeescript/kitchen-sink.coffee
@@ -90,8 +90,8 @@
               # The 3 formats for options
               # 1. An object with a label and a value (perfered)
               {label: "Stuff", value: "stuff-value"},
-              # 2. An array of the [label, value]
-              ["Things", "thing-value"],
+              # 2. An array of the [value, label]
+              ["thing-value", "Things"],
               # 3. A string. For scenarios where the label equals the value.
               "why not both?"
             ]


Fixes arguments.slice bug in Repo.diff().

The variable `arguments` is not an array, and does not have a slice method.

--- src/repo.coffee
+++ src/repo.coffee
@@ -149,7 +149,7 @@
       else if arguments[2] instanceof Object
         options = arguments[2]
     else if arguments.length is 5
-      [paths, options, callback] = arguments.slice(2)
+      [paths, options, callback] = Array.prototype.slice.call(arguments, 2)

     commitA = commitA.id if _.isObject(commitA)
     commitB = commitB.id if _.isObject(commitB)


Fix VM_guest_metrics.

Fix VM_guest_metrics.

--- src/spec.coffee
+++ src/spec.coffee
@@ -50,48 +50,57 @@
   #     console.log event
   #     emit.call collection, event, items

-  $link = (keyFn, valFn = (-> @val), once = false) ->
+  $link = (keyFn, valFn = (-> @val)) ->
+    keyPerItem = Object.create null
+    listenerPerItem = Object.create null
     valuePerItem = Object.create null
     updating = false

     ->
       {key} = this

-      # Returns the value if already defined.
-      return valuePerItem[key] if key of valuePerItem
-
       # Gets the key of the remote object.
       remoteKey = keyFn.call this
+
+      keyHasChanged = remoteKey isnt keyPerItem[key]
+
+      if keyHasChanged
+        keyPerItem[key] = remoteKey
+      else
+        # Returns the value if already defined.
+        return valuePerItem[key] if key of valuePerItem
+
+      eventName = "key=#{remoteKey}"
+      listener = listenerPerItem[key]
+
+      if listener and keyHasChanged
+        collection.remove eventName, listener
+        listener = null

       # Special case for `OpaqueRef:NULL`.
       if remoteKey is 'OpaqueRef:NULL'
         return valuePerItem[key] = null

+      unless listener
+        listener = (event, item) ->
+          # If the events are due to an update of this link or if the item is
+          # exiting, just returns.
+          return if updating or event isnt 'enter'
+
+          # Register its value.
+          valuePerItem[key] = valFn.call item
+
+          # Force the object to update.
+          try
+            updating = true
+            collection.touch key
+          finally
+            updating = false
+        collection.on eventName, listener
+
       # Tries to find the remote object in the collection.
       try
         return valuePerItem[key] = valFn.call (collection.getRaw remoteKey)
-
-      # If not found, listens for its apparition.
-      eventName = "key=#{remoteKey}"
-      listener = (event, item) ->
-        # If the events are due to an update of this link or if the item is
-        # exiting, just returns.
-        return if updating or event isnt 'enter'
-
-        # Register its value.
-        valuePerItem[key] = valFn.call item
-
-        if once
-          # Removes the now unnecessary listener.
-          collection.removeListener eventName, listener
-
-        # Force the object to update.
-        try
-          updating = true
-          collection.touch key
-        finally
-          updating = false
-      collection.on eventName, listener

       # Returns `null` for now.
       valuePerItem[key] = null


adding a test for holmsand's patch for Object.prototype-named variables.

--- test/test_functions.coffee
+++ test/test_functions.coffee
@@ -154,6 +154,7 @@
   7 + 9
 , ->
   1 + 3
+
 ok result is 20

 # Test more function passing:
@@ -167,4 +168,13 @@
 sum: (a, b) -> a + b
 result: sum(1
 , 2)
+
 ok result is 3
+
+
+# Assignment to a Object.prototype-named variable should not leak to outer scope.
+(->
+  constructor: 'word'
+)()
+
+ok constructor isnt 'word'


Don't mark callback field as public

Don't mark callback field as public

--- src/task.coffee
+++ src/task.coffee
@@ -35,7 +35,7 @@
     task.start(args...)
     task

-  # Public: Called upon task completion.
+  # Called upon task completion.
   #
   # It receives the same arguments that were passed to the task.
   #


Fixing various CLI not responding issues.

--- src/tegh.coffee
+++ src/tegh.coffee
@@ -225,7 +225,8 @@

   _parseLine: (line) =>
-    line = line.toString()
+    line = line.toString().trim()
+    return if line == ""
     words = line.split(/\s/)
     cmd = words.shift()
     if cmd == "add_job"
@@ -233,20 +234,22 @@
       @_uploading = true

     if cmd == "help" then @_appendHelp(words[0])
-    else if cmd == "exit" then return process.exit()
+    else if cmd == "exit" then process.exit()
     else if @commands[cmd]?
       try
         @client.send(line)
+        @cli.render()
+        # Temporarily overriding readline's _ttyWrite to pause the CLI input.
+        @cli.rl._ttyWrite = ( -> )
+        return
       catch e
         @_append "Error: #{e}"
-    else if cmd != ""
+    else
       @_append """
         Error: '#{cmd}' is not a valid command.
         Try typing 'help' for more info.
       """
     @cli.render()
-    # Temporarily overriding readline's _ttyWrite to pause the CLI input.
-    @cli.rl._ttyWrite = ( -> )

   _appendHelp: (cmd) ->
     return @_appendSpecificHelp(cmd) if cmd? and cmd.length > 0


Persist tell messages in brain.

Persist tell messages in brain.

--- src/tell.coffee
+++ src/tell.coffee
@@ -29,17 +29,18 @@
   relativeTime: process.env.HUBOT_TELL_RELATIVE_TIME?

 module.exports = (robot) ->
-  localstorage = {}
-
   commands = ['tell'].concat(config.aliases)
   commands = commands.join('|')

   REGEX = ///(#{commands})\s+([\w,.-]+):?\s+(.*)///i

   robot.respond REGEX, (msg) ->
+    localstorage = JSON.parse(robot.brain.get 'hubot-tell') or {}
+
     verb = msg.match[1]
     recipients = msg.match[2].split(',').filter((x) -> x?.length)
     message = msg.match[3]
+
     room = msg.message.user.room
     tellmessage = [msg.message.user.name, new Date(), message]
     if not localstorage[room]?
@@ -50,10 +51,14 @@
       else
         localstorage[room][recipient] = [tellmessage]
     msg.send("Ok, I'll #{verb} #{recipients.join(', ')} '#{message}'.")
+    robot.brain.set 'hubot-tell', JSON.stringify(localstorage)
+    robot.brain.save()
     return

   # When a user enters, check if someone left them a message
   robot.enter (msg) ->
+    localstorage = JSON.parse(robot.brain.get 'hubot-tell') or {}
+
     if config.relativeTime
       timeago = require('timeago')
     username = msg.message.user.name
@@ -70,5 +75,7 @@
               timestr = "at #{message[1].toLocaleString()}"
             tellmessage += "#{message[0]} said #{timestr}: #{message[2]}\r\n"
           delete localstorage[room][recipient]
+          robot.brain.set 'hubot-tell', JSON.stringify(localstorage)
+          robot.brain.save()
           msg.send(tellmessage)
     return


hideEl and showEl helpers

hideEl and showEl helpers

--- oridomi.coffee
+++ oridomi.coffee
@@ -55,6 +55,14 @@
   el = document.createElement 'div'
   el.className = elClasses[className]
   el
+
+
+hideEl = (el) ->
+  el.styleEl[css.transform] = 'translate3d(-9999px, 0, 0)'
+
+
+showEl = (el) ->
+  el.styleEl[css.transform] = 'translate3d(0, 0, 0)'

 # This function is used to extend option object literals with a set of defaults.


No longer errors if choices not defined

No longer errors if choices not defined

--- src/NovelManager.coffee
+++ src/NovelManager.coffee
@@ -106,6 +106,10 @@
     for s in json.scenes
       s.combinedText = ""
       s.parsedText = ""
+      if s.text == undefined
+        s.text = ""
+      if s.choices == undefined
+        s.choices = []
       for c in s.choices
         c.parsedText = ""
         if c.alwaysShow == undefined


Disallow unsized types from being pointed to and used as fields

--- src/type.coffee
+++ src/type.coffee
@@ -163,9 +163,9 @@
 PointerType::lint = (types) ->
   return this if @linted
   @linted = true
-  @base = @base.lint types
-  if @base instanceof ArrowType
-    throw TypeError "cannot take pointers of function types"
+  @base = base = @base.lint types
+  if base and not base.size
+    throw TypeError "cannot take pointers of unsized type `#{base}'"
   this
 PointerType::baseAlignment = -> @base?.view.BYTES_PER_ELEMENT or 1

@@ -211,6 +211,8 @@
   # Field offsets must be aligned to the type of the field.
   for field in fields
     ty = field.type
+    unless ty.size
+      throw TypeError "cannot store unsized type `#{ty}' as a struct field"
     # Record the max view encountered to set as the view of this struct.
     maxView = ty.view if ty.view.BYTES_PER_ELEMENT > maxView.BYTES_PER_ELEMENT
     if (offset = field.offset)?
@@ -413,7 +415,7 @@
     first = @first.unwrapAll()
     return @computedType = if op is 'new' and first.value of o.types
       ty1 = o.types[first.value]
-      throw TypeError 'cannot allocate type with size 0' unless ty1?.size
+      throw TypeError "cannot allocate unsized type `#{ty1}'" unless ty1?.size
       Scope.root.needsMalloc = yes
       new PointerType ty1
     else if op is 'delete' and (ty1 = first.computedType)


Added util.clone for deep JavaScript object copying.

--- src/util.coffee
+++ src/util.coffee
@@ -1,9 +1,11 @@
-#
-# JavaScript Language Utility Methods
-#
-util = {}
-
-util.extend = (obj, source) ->
+util = require("util")
+
+
+###
+  JavaScript Language Utilities
+  ------------------------------------------------------------------------------------------
+###
+extend = (obj, source) ->
   # ECMAScript5 compatibility based on: http://www.nczonline.net/blog/2012/12/11/are-your-mixins-ecmascript-5-compatible/
   if Object.keys
     keys = Object.keys(source)
@@ -21,8 +23,157 @@
   obj

+###
+
+Clones (copies) an Object using deep copying.
+
+This function supports circular references by default, but if you are certain
+there are no circular references in your object, you can save some CPU time
+by calling clone(obj, false).
+
+Caution: if `circular` is false and `parent` contains circular references,
+your program may enter an infinite loop and crash.
+
+@param `parent` - the object to be cloned
+@param `circular` - set to true if the object to be cloned may contain
+circular references. (optional - true by default)
+
+###
+clone = (parent, circular) ->
+  circular = true  if typeof circular is "undefined"
+  useBuffer = typeof Buffer isnt "undefined"
+  i = undefined
+  if circular
+    _clone = (parent, context, child, cIndex) ->
+      i = undefined # Use local context within this function
+      # Deep clone all properties of parent into child
+      if typeof parent is "object"
+        return parent  unless parent?
+
+        # Check for circular references
+        for i of circularParent
+          if circularParent[i] is parent
+
+            # We found a circular reference
+            circularReplace.push
+              resolveTo: i
+              child: child
+              i: cIndex
+
+            return null #Just return null for now...
+        # we will resolve circular references later
+
+        # Add to list of all parent objects
+        circularParent[context] = parent
+
+        # Now continue cloning...
+        if util.isArray(parent)
+          child = []
+          for i of parent
+            child[i] = _clone(parent[i], context + "[" + i + "]", child, i)
+        else if util.isDate(parent)
+          child = new Date(parent.getTime())
+        else if util.isRegExp(parent)
+          child = new RegExp(parent.source)
+        else if useBuffer and Buffer.isBuffer(parent)
+          child = new Buffer(parent.length)
+          parent.copy child
+        else
+          child = {}
+
+          # Also copy prototype over to new cloned object
+          child.__proto__ = parent.__proto__
+          for i of parent
+            child[i] = _clone(parent[i], context + "[" + i + "]", child, i)
+
+        # Add to list of all cloned objects
+        circularResolved[context] = child
+      else #Just a simple shallow copy will do
+        child = parent
+      child
+    circularParent = {}
+    circularResolved = {}
+    circularReplace = []
+    cloned = _clone(parent, "*")
+
+    # Now this object has been cloned. Let's check to see if there are any
+    # circular references for it
+    for i of circularReplace
+      c = circularReplace[i]
+      c.child[c.i] = circularResolved[c.resolveTo]  if c and c.child and c.i of c.child
+    cloned
+  else
+
+    # Deep clone all properties of parent into child
+    child = undefined
+    if typeof parent is "object"
+      return parent  unless parent?
+      if parent.constructor.name is "Array"
+        child = []
+        for i of parent
+          child[i] = clone(parent[i], circular)
+      else if util.isDate(parent)
+        child = new Date(parent.getTime())
+      else unless util.isRegExp(parent)
+        child = {}
+        child.__proto__ = parent.__proto__
+        for i of parent
+          child[i] = clone(parent[i], circular)
+    else # Just a simple shallow clone will do
+      child = parent
+    child
+
+
+clone.clonePrototype = (parent) ->
+  return null  if parent is null
+  ctor = ->
+
+  ctor:: = parent
+  new ctor()
+
+
+###
+
+JavaScript getter and setter support for CoffeeScript classes
+Ref: https://github.com/jashkenas/coffee-script/issues/1039
+
+Note:
+Classes using this wont work under IE6 + IE7
+
+Usage:
+class Vector3D extends EXObject
+  constructor: (@x, @y, @z) ->
+
+  @get 'x', -> @[0]
+  @get 'y', -> @[1]
+  @get 'z', -> @[2]
+
+  @set 'x', (x) -> @[0] = x
+  @set 'y', (y) -> @[1] = y
+  @set 'z', (z) -> @[2] = z
+
+###
+class EXObject
+  @get: (propertyName, func) ->
+    Object.defineProperty @::, propertyName,
+      configurable: true
+      enumerable: true
+      get: func
+
+  @set: (propertyName, func) ->
+    Object.defineProperty @::, propertyName,
+      configurable: true
+      enumerable: true
+      set: func
+
+
+
+###
+  Array Utilities
+  ------------------------------------------------------------------------------------------
+###
 # removes the element from the given list (if it exists) and returns the list
-util.removeElement = (element, list) ->
+removeElement = (element, list) ->
   index = list.indexOf element
   list.splice index, 1 unless index is -1
   list
@@ -31,7 +182,7 @@
 # shuffles the order of the given object or array
 # optionally takes a random number generator object
 # returns the shuffled object
-util.shuffle = (object, rng) ->
+shuffle = (object, rng) ->
   rng = Math unless rng?
   i = object.length
   while i
@@ -42,41 +193,10 @@
   object

-
-###
-
-  JavaScript getter and setter support for CoffeeScript classes
-  Ref: https://github.com/jashkenas/coffee-script/issues/1039
-
-  Note:
-  Classes using this wont work under IE6 + IE7
-
-  Usage:
-  class Vector3D extends EXObject
-    constructor: (@x, @y, @z) ->
-
-    @get 'x', -> @[0]
-    @get 'y', -> @[1]
-    @get 'z', -> @[2]
-
-    @set 'x', (x) -> @[0] = x
-    @set 'y', (y) -> @[1] = y
-    @set 'z', (z) -> @[2] = z
-
-###
-util.EXObject = class EXObject
-
-  @get: (propertyName, func) ->
-    Object.defineProperty @::, propertyName,
-      configurable: true
-      enumerable: true
-      get: func
-
-  @set: (propertyName, func) ->
-    Object.defineProperty @::, propertyName,
-      configurable: true
-      enumerable: true
-      set: func
-
-
-module.exports = util+module.exports =
+  extend: extend
+  clone: clone
+  EXObject: EXObject
+
+  removeElement: removeElement
+  shuffle: shuffle


update describe in cede test

update describe in cede test

--- test/cede.coffee
+++ test/cede.coffee
@@ -1,13 +1,13 @@
 cc = require '../lib/coffeecup'

 describe 'cede', ->
-  describe 'p "This text could use \#{yield -> strong -> a href: \'/\', \'a link\'}."', ->
+  describe 'p "This text could use \#{cede strong -> a href: \'/\', \'a link\'}."', ->
     it 'should render
This text could use a link.
', ->
       t = -> p "This text could use #{cede -> strong -> a href: '/', 'a link'}."
       cc.render(t).should.equal '
This text could use a link.
'

 describe 'cede optimized', ->
-  describe 'p "This text could use \#{yield -> strong -> a href: \'/\', \'a link\'}."', ->
+  describe 'p "This text could use \#{cede -> strong -> a href: \'/\', \'a link\'}."', ->
     it 'should render
This text could use a link.
', ->
       t = -> p "This text could use #{cede -> strong -> a href: '/', 'a link'}."
       cc.render(t, optimized: true, cache: on).should.equal '
This text could use a link.
'


Add ajax request for marker investment info

--- app/assets/javascripts/map.js.coffee
+++ app/assets/javascripts/map.js.coffee
@@ -70,9 +70,18 @@
       $(zoomInputSelector).val ''
       return

-    contentPopup = (title,investment,budget) ->
-      content = "#{title}"
-      return  content
+    openMarkerPopup = (e) ->
+      marker = e.target
+
+      $.ajax 'investments/' + marker.options['id'] + '/json_data',
+        type: 'GET'
+        dataType: 'json'
+        success: (data) ->
+          e.target.bindPopup(getPopupContent(data)).openPopup()
+
+    getPopupContent = (data) ->
+      content = "#{data['investment_title']}"
+      return content

     mapCenterLatLng  = new (L.LatLng)(mapCenterLatitude, mapCenterLongitude)
     map              = L.map(element.id).setView(mapCenterLatLng, zoom)
@@ -88,8 +97,11 @@

     if addMarkerInvestments
       for i in addMarkerInvestments
-        add_marker=createMarker(i.lat , i.long)
-        add_marker.bindPopup(contentPopup(i.investment_title, i.investment_id, i.budget_id))
+        if App.Map.validCoordinates(i)
+          marker = createMarker(i.lat, i.long)
+          marker.options['id'] = i.id
+
+          marker.on 'click', openMarkerPopup

   toogleMap: ->
       $('.map').toggle()


Trigger state events on self and on root element.

--- src/view.coffee
+++ src/view.coffee
@@ -135,11 +135,9 @@

             if success is false then return false

-            @root().trigger(@eventPrefix + 'transition', {
-                from: @state
-                to: state
-                options: options
-            })
+            pkg = from: @state, to: state, options: options
+            @trigger('transition', pkg)
+            @root().trigger(@eventPrefix + 'transition', pkg)

             # Change state
@@ -148,10 +146,10 @@

             if _.isFunction(@[@states[state]]) then @[@states[state]](options)

-            @root().trigger(@eventPrefix + 'changestate', {
-                state: @state
-                options: options
-            })
+            pkg = state: @state, options: options
+            @trigger('changestate', pkg)
+            @root().trigger(@eventPrefix + 'changestate', pkg)
+

             # Bind new events


Fix tests - stringify scoped records

Fix tests - stringify scoped records

--- test/crud.coffee
+++ test/crud.coffee
@@ -80,7 +80,7 @@
       fakeResponse
         success: true
         id: 1
-        scoped_records: [{ id: 1, name: 'John' }]
+        scoped_records: JSON.stringify([{ id: 1, name: 'John' }])
       , 'create'

       User.create(name: 'John').then (user) ->
@@ -91,7 +91,7 @@
       fakeResponse
         success: true
         id: 2
-        scoped_records: [{ id: 2, name: 'Peter' }]
+        scoped_records: JSON.stringify([{ id: 2, name: 'Peter' }])
       , 'update'

       User.update(id: 2, name: 'Peter').then (user) ->
@@ -101,7 +101,7 @@
     it 'should destroy a record and return if it was successful', ->
       fakeResponse
         success: true
-        scoped_records: []
+        scoped_records: JSON.stringify([])
       , 'destroy'

       User.destroy(id: 2).then (success) ->
@@ -111,7 +111,7 @@
     it 'should throw an error', ->
       fakeResponse
         success: true
-        scoped_records: [{ id: 2, name: 'Peter' }]
+        scoped_records: JSON.stringify([{ id: 2, name: 'Peter' }])
       , 'destroy'

       User.destroy(id: 2).then (success) ->


Moved TODOs into github issues

Moved TODOs into github issues

--- test/misc.coffee
+++ test/misc.coffee
@@ -2,29 +2,6 @@
 should      = chai.should()
 expect      = chai.expect
 create_liar = require '../create_liar'
-
-# TODO
-# "Value should be implicit if on_value defined" breaks if you change to yields_in_order
-# yield
-#  yields must have value or on_value
-# yields with null
-# Check for value on callback arguments
-# Give context to error messages
-# times called
-# delay
-# required
-# Maybe some nice debug output
-# better variable names ("liar" sucks)
-# Some kind of terminology to separate the caller and the callee
-#   crazy argument confusion in run_callback
-# yield is probably not the greatest word.
-# Test duplication!
-# Implicit arrays
-# plugins
-  # yields_result plugin
-  # yeilds_error
-  # promise plugin
-

 # FIXME WHY DOES THIS FAIL IF changed to YIELDS IN ORDER?
 it 'Value should be implicit if on_value defined', (done) ->


CoffeeScript.compile returns a string

CoffeeScript.compile returns a string

--- src/browser/main.coffee
+++ src/browser/main.coffee
@@ -61,7 +61,7 @@
   require.extensions['.coffee'] = (module, filePath) ->
     CoffeeScript ?= require('coffee-script')
     coffee = fs.readFileSync(filePath, 'utf8')
-    {js} = CoffeeScript.compile(coffee, filename: filePath)
+    js = CoffeeScript.compile(coffee, filename: filePath)
     module._compile(js, filePath)

 parseCommandLine = ->


updated convenience method args

updated convenience method args

--- oriDomi.coffee
+++ oriDomi.coffee
@@ -509,37 +509,36 @@
     @_callback options

-  collapse: (options = {}) ->
+  collapse: (anchor, options = {}) ->
     options.sticky = false
-    @accordion -90
-
-
-  collapseAlt: (options = {}) ->
+    @accordion -90, anchor, options
+
+
+  collapseAlt: (anchor, options = {}) ->
     options.sticky = false
-    @accordion 90
-
-
-  reveal: (angle, options = {}) ->
+    @accordion 90, anchor, options
+
+
+  reveal: (angle, anchor, options = {}) ->
     options.sticky = true
-    @accordion angle, options
-
-
-  stairs: (angle, options = {}) ->
+    @accordion angle, anchor, options
+
+
+  stairs: (angle, anchor, options = {}) ->
     options.stairs = true
     options.sticky = true
-    @accordion angle, options
-
-
-  fracture: (angle, options = {}) ->
+    @accordion angle, anchor, options
+
+
+  fracture: (angle, anchor, options = {}) ->
     options.fracture = true
-    @accordion angle, options
-
-
-  twist: (angle, options = {}) ->
+    @accordion angle, anchor, options
+
+
+  twist: (angle, anchor, options = {}) ->
     options.fracture = true
     options.twist = true
-    @accordion angle / 10, options
-
+    @accordion angle / 10, anchor, options

   curl: (angle, anchor, options = {}) ->


fix query params with link

fix query params with link

--- shared/src/factories/link.cjsx
+++ shared/src/factories/link.cjsx
@@ -1,7 +1,7 @@
 React = require 'react'
 {Link} = require 'react-router-dom'
-concat    = require 'lodash/concat'
-
+concat = require 'lodash/concat'
+qs = require 'qs'
 {filterProps} = require '../helpers/react'
 filterPropsBase = filterProps

@@ -27,7 +27,8 @@

       to =
         pathname: pathname or to
-        query: query
+      if query
+        to.search = qs.stringify(query)

       # TODO see about isActive
       <Link to={to} {...filterProps(@props)} />


typo fix.

typo fix.

--- assets/coffeescript/product_list.coffee
+++ assets/coffeescript/product_list.coffee
@@ -167,7 +167,7 @@
     cartSpecs: "1 x 120hz eye tracking add-on for Oculus Rift DK2."
     dimensions: 0
     weight: 20
-    img: "../media/additional_products/web/addon_oculus_dk2.png"
+    img: "../media/images/additional_products/web/addon_oculus_dk2.png"
     order: 1
   }, {
     id: "product_oculus_bi"
@@ -178,7 +178,7 @@
     cartSpecs: "2 x 120hz IR eye cameras, 1 x 120hz world camera, custom designed mounts for Epson Moverio BT-200"
     dimensions: 0
     weight: 20
-    img: "../media/additional_products/web/addon_oculus_dk2.png"
+    img: "../media/images/additional_products/web/addon_oculus_dk2.png"
     order: 2
   }, {
     id: "product_epson_mono"
@@ -189,7 +189,7 @@
     cartSpecs: "2 x camera mounts for Epson Moverio BT-200 with cables for 120hz cameras. Use with 120hz eye camera upgrade or existing 120hz eye camera from Pupil."
     dimensions: 0
     weight: 20
-    img: "../media/additional_products/web/addon_epson_bt200.png"
+    img: "../media/images/additional_products/web/addon_epson_bt200.png"
     order: 3
   }, {
     id: "product_support_6"


Handle errors better in QueryResult

Handle errors better in QueryResult

--- admin/static/coffee/dataexplorer.coffee
+++ admin/static/coffee/dataexplorer.coffee
@@ -110,23 +110,31 @@
         # Gets the next result from the cursor
         fetch_next: =>
             if not @ended
-                @cursor.next (error, row) =>
-                    if error?
-                        if error.message is 'No more rows in the cursor.'
-                            @ended = true
-                            @trigger 'end', @
+                try
+                    @cursor.next (error, row) =>
+                        if error?
+                            if error.message is 'No more rows in the cursor.'
+                                @ended = true
+                                @trigger 'end', @
+                            else
+                                @set_error error
                         else
-                            @error = error
-                            @trigger 'error', @, error
-                            @discard_results = true
-                    else
-                        if @discard_results
-                            return
-                        @results.push row
-                        @trigger 'add', @, row
-                        @missing--
-                        if @missing >= 0
-                            @fetch_next()
+                            if @discard_results
+                                return
+                            @results.push row
+                            @trigger 'add', @, row
+                            @missing--
+                            if @missing >= 0
+                                @fetch_next()
+                catch error
+                    @set_error error
+
+        set_error: (error) =>
+            @error = error
+            @trigger 'error', @, error
+            @discard_results = true
+
+

     class @Container extends Backbone.View
         id: 'dataexplorer'


Ctrl+tab should switch tab on Firefox 31 - #2959

--- admin/static/coffee/dataexplorer.coffee
+++ admin/static/coffee/dataexplorer.coffee
@@ -958,7 +958,7 @@
                                 @codemirror.indentLine cursor.line+1, 'smart'
                                 @codemirror.setCursor cursor
                                 return false
-                else if event.which is 9  or (event.type is 'keydown' and ((event.ctrlKey is true or event.metaKey is true) and event.which is 32) and (@$('.suggestion_description').css('display') is 'none' and @.$('.suggestion_name_list').css('display') is 'none'))
+                else if (event.which is 9 and event.ctrlKey is false)  or (event.type is 'keydown' and ((event.ctrlKey is true or event.metaKey is true) and event.which is 32) and (@$('.suggestion_description').css('display') is 'none' and @.$('.suggestion_name_list').css('display') is 'none'))
                     # If the user just hit tab, we are going to show the suggestions if they are hidden
                     # or if they suggestions are already shown, we are going to cycle through them.
                     #


people cmd

people cmd

--- test/test.coffee
+++ test/test.coffee
@@ -4,7 +4,7 @@

 methods = [
 		'filters', 'projects', 'areas', 'milestones',
-		'categories', 'priorities', 'search', 'events'
+		'categories', 'priorities', 'people', 'search', 'events'
 	]

 reserved = ['email', 'pwd', 'password', '_', '$0'].concat(methods)


Age in seconds

Age in seconds

--- test/text.coffee
+++ test/text.coffee
@@ -19,11 +19,12 @@
   text = TextEffect()

   text.update(1)
-  text.t
+  text.trigger "afterUpdate", 1

   equals text.I.alpha, 1

   text.update(1)
+  text.trigger "afterUpdate", 1

   equals text.I.alpha, 1 - 1/40


Align numeral's tests

Align numeral's tests


update test index file

update test index file

--- bokehjs/test/models/glyphs/index.coffee
+++ bokehjs/test/models/glyphs/index.coffee
@@ -1,2 +1 @@
 require "./image_url"
-require "./glyph"


Selectors refactoring

Selectors refactoring

--- app/assets/javascripts/common.js.coffee
+++ app/assets/javascripts/common.js.coffee
@@ -45,7 +45,7 @@
           coursesCollection = world.get('coursesCollection')
           courseSelector ?= new Langtrainer.LangtrainerApp.Views.CourseSelector(
             collection: coursesCollection
-            model: world.get('course')
+            model: Langtrainer.LangtrainerApp.currentUser.getCurrentCourse()
           )
           courseSelector
             .render()
@@ -55,8 +55,8 @@
         if unitSelectorContainer?
           unitsCollection = world.get('unitsCollection')
           unitSelector ?= new Langtrainer.LangtrainerApp.Views.UnitSelector(
-            collection: unitsCollection
-            model: world.get('unit')
+            collection: Langtrainer.LangtrainerApp.currentUser.getCurrentCourse().get('unitsCollection')
+            model: Langtrainer.LangtrainerApp.currentUser.getCurrentCourse().getCurrentUnit()
           )
           unitSelector
             .render()
@@ -65,7 +65,7 @@
         nativeLanguageSelectorContainer = $('.native-language-selector-container').first()
         if nativeLanguageSelectorContainer?
           nativeLanguagesCollection = world.get('nativeLanguagesCollection')
-          nativeLanguageSelector ?= new Langtrainer.LangtrainerApp.Views.LanguageSelector(
+          nativeLanguageSelector ?= new Langtrainer.LangtrainerApp.Views.NativeLanguageSelector(
             collection: nativeLanguagesCollection
             model: world.get('nativeLanguage')
             label: 'native_language'
@@ -77,7 +77,7 @@
         languageSelectorContainer = $('.language-selector-container').first()
         if languageSelectorContainer?
           languagesCollection = world.get('languagesCollection')
-          languageSelector ?= new Langtrainer.LangtrainerApp.Views.LanguageSelector(
+          languageSelector ?= new Langtrainer.LangtrainerApp.Views.ForeignLanguageSelector(
             collection: languagesCollection
             model: world.get('language')
             label: 'language'
@@ -87,7 +87,7 @@
             .$el.detach().appendTo(languageSelectorContainer)

         if stepViewContainer?
-          stepView ?= new Langtrainer.LangtrainerApp.Views.StepView(model: world.get('step'))
+          stepView ?= new Langtrainer.LangtrainerApp.Views.StepView(model: Langtrainer.LangtrainerApp.currentUser.getCurrentCourse().getCurrentUnit().getCurrentStep())
           stepView.$el.detach().appendTo(stepViewContainer)
           stepView.render()


Temporarily removed transition cache

Temporarily removed transition cache

--- app/assets/javascripts/global.js.coffee
+++ app/assets/javascripts/global.js.coffee
@@ -27,7 +27,7 @@
   setFocusToField("#collection_form #s, #page_name, #search_form #s")
   $("img.lazy").lazyload( effect : "fadeIn" )
   Turbolinks.allowLinkExtensions('md')
-  Turbolinks.enableTransitionCache()
+  # Turbolinks.enableTransitionCache()

 $(document).ready(ready)
 $(document)


Select2 clear

Select2 clear

--- app/assets/javascripts/search.js.coffee
+++ app/assets/javascripts/search.js.coffee
@@ -95,11 +95,11 @@
     $("#search_debate_level").val("")
     $("#search_debate_type").val("")
     $("#search_year").val("")
-    $("#search_tournament").val("")
-    $("#search_school").val("")
-    $("#search_team").val("")
-    $("#search_debater").val("")
-    $("#search_tag").val("")
+    $("#search_tournament").select2('data', null)
+    $("#search_school").select2('data', null)
+    $("#search_team").select2('data', null)
+    $("#search_debater").select2('data', null)
+    $("#search_tag").select2('data', null)

 $(document).ready ready
 $(document).on 'page:load', ready


Prevent tweet expansion from firing more than once

--- app/assets/javascripts/tweets.js.coffee
+++ app/assets/javascripts/tweets.js.coffee
@@ -1,6 +1,7 @@
 $ ->
   $('.tweet-body').each ->
     $(this).click ->
+      $(this).off('click')
       twttr.widgets.createTweet(
         this.dataset.tweetId
         this


changed to new parse format for CSV files

--- app/classifier/tasks/survey/editor.cjsx
+++ app/classifier/tasks/survey/editor.cjsx
@@ -161,7 +161,7 @@

-      {unless @props.task.questionsOrder.length is 0
+      {if @props.task.questionsOrder?.length

             {for questionID in @props.task.questionsOrder
@@ -310,31 +310,32 @@
     @props.task.choices[choiceID]?.confusions[confusionID] = details

   addQuestion: ({question, multiple, required, answers, include, exclude, __parsedExtra}) ->
-    unless question?
+    unless !!question
       throw new Error 'Questions require a "question" column'
-    unless answers?
+    unless !!answers
       throw new Error 'Questions require a "answers" column'

-    includeChoices = include?.split /\s*;\s*/
-    excludeChoices = exclude?.split /\s*;\s*/
+    includeChoices = include.split /\s*;\s*/ if !!include
+    excludeChoices = exclude.split /\s*;\s*/ if !!exclude
     questionID = @makeID question

     # don't put it in the default questionsOrder if we've specified choices it should map to
-    unless include? or questionID in @props.task.questionsOrder
-      (maybeProp @props.task.questionsOrder, []).push questionID
+    unless !!includeChoices or !questionID or (questionID in @props.task.questionsOrder)
+      qOrder = @maybeProp @props.task, 'questionsOrder', []
+      qOrder.push questionID

     # if we specified mapped choices, create those entries instead
     if includeChoices?
       for choice in includeChoices
-        continue unless choice?
         choiceID = @makeID choice
-        (maybeProp @props.task, inclusions, []).push [choiceID, questionID]
+        continue unless !!choiceID
+        (@maybeProp @props.task, 'inclusions', []).push [choiceID, questionID]

     if excludeChoices?
       for choice in excludeChoices
-        continue unless choice?
         choiceID = @makeID choice
-        (maybeProp @props.task, exclusions, []). push [choiceID, questionID]
+        continue unless !!choiceID
+        (@maybeProp @props.task, 'exclusions', []).push [choiceID, questionID]

     @props.task.questions[questionID] =
       label: question
@@ -354,21 +355,29 @@
     owner[prop]

   cleanQuestions: () ->
-    if @props.task.includeChoices?
-      for includeTuple in @props.task.includeChoices
-        (maybeProp (maybeProp @props.task.questionsMap, {}) includeTuple[0], []).push includeTuple[1]
-
     if @props.task.questionsOrder?
       for questionID in @props.task.questionsOrder
         for choiceID in @props.task.choicesOrder
-          (maybeProp (maybeProp @props.task.questionsMap, {}) choiceID, []).push questionID
-
-    if @props.task.excludeChoices?
-      for excludeTuple in @props.task.excludeChoices
-        questionList = @props.task.questionsMap[excludeTuple[0]]
-        questionList.splice (questionList.indexOf excludeTuple[1]) 1
-
-    return
+          continue if @props.task.choices[choiceID].noQuestions
+          qMap = @maybeProp @props.task, 'questionsMap', {}
+          qSet = @maybeProp qMap, choiceID, []
+          qSet.push questionID
+
+    if @props.task.inclusions?
+      for includeTuple in @props.task.inclusions
+        qMap = @maybeProp @props.task, 'questionsMap', {}
+        qSet = @maybeProp qMap, includeTuple[0], []
+        qSet.push includeTuple[1]
+
+    if @props.task.exclusions?
+      for excludeTuple in @props.task.exclusions
+        qMap = @maybeProp @props.task, 'questionsMap', {}
+        qSet = @maybeProp qMap, excludeTuple[0], []
+        index = qSet.indexOf excludeTuple[1]
+        qSet.splice index, 1
+
+    delete @props.task.inclusions
+    delete @props.task.exclusions

   handleImageAdd: (media) ->
     @props.task.images[media.metadata.filename] = media.src
@@ -387,6 +396,9 @@
         choices: {}
         questionsOrder: []
         questions: {}
+        inclusions: []
+        exclusions: []
+        questionsMap: {}
       @props.workflow.update 'tasks'

   resetMedia: (e) ->


Fix missing Rows on front page

Fix missing Rows on front page

--- picoCTF-web/web/coffee/front-page.coffee
+++ picoCTF-web/web/coffee/front-page.coffee
@@ -188,16 +188,20 @@

     if @state.page == "Team Management"

-        <Col md={6} mdOffset={3}>
-          <TeamManagementForm/>
-        </Col>
+        <Row>
+          <Col md={6} mdOffset={3}>
+            <TeamManagementForm/>
+          </Col>
+        </Row>

     else

-        <Col md={6} mdOffset={3}>
-          <LoginForm setPage={@setPage} status={@state.page} onRegistration={@onRegistration}
-            onLogin={@onLogin} onPasswordReset={@onPasswordReset} {...links}/>
-        </Col>
+        <Row>
+          <Col md={6} mdOffset={3}>
+            <LoginForm setPage={@setPage} status={@state.page} onRegistration={@onRegistration}
+              onLogin={@onLogin} onPasswordReset={@onPasswordReset} {...links}/>
+          </Col>
+        </Row>

 $ ->


Atom: Update config.cson

Atom: Update config.cson

--- opt/config.cson
+++ opt/config.cson
@@ -17,10 +17,9 @@
     invisibles: {}
     showInvisibles: true
   "highlight-line": {}
-  "node-debugger":
-    nodePath: "/usr/local/bin/node"
   hashrocket:
     nodeExecutablePath: "/usr/local/bin/node"
     phpExecutablePath: "/usr/local/bin/php"
     pythonExecutablePath: "/usr/local/bin/python"
     rubyExecutablePath: "/usr/bin/ruby"
+  linter: {}


Updated function names in test script

Updated function names in test script

--- test/integration/contactGroupsAPITests.coffee
+++ test/integration/contactGroupsAPITests.coffee
@@ -74,7 +74,7 @@
 							done()

-		describe "*getClient(_id)", ->
+		describe "*getContactGroup(_id)", ->
 			contactGroupData =
 				group: "Group 1"
 				users: [{user: 'User 1', method: 'sms', maxAlerts: 'no max'},
@@ -141,7 +141,7 @@
 						else
 							done()

-		describe  "*getClients()", ->
+		describe  "*getContactGroups()", ->
 			contactGroupData1 =
 				group: "Group 1"
 				users: [{user: 'User 1', method: 'sms', maxAlerts: 'no max'},
@@ -207,7 +207,7 @@
 						else
 							done()

-		describe  "*updateClient", ->
+		describe  "*updateContactGroup", ->
 			contactGroupData =
 				group: "Group 1"
 				users: [{user: 'User 1', method: 'sms', maxAlerts: 'no max'},


[grunt] add `urlify` as one of Nunjucks filters

--- tasks/grunt-nunjucks-2-html.coffee
+++ tasks/grunt-nunjucks-2-html.coffee
@@ -205,6 +205,15 @@
             moment.locale(locale);
             moment(date).format(format)

+          ###*
+           * Transform string into usable in urls form
+           * @param {string} string       String to transform
+           * @param {object} options = {} Options overrides as per https://github.com/Gottox/node-urlify
+           * @return {string} Urlified string
+          ###
+          env.addFilter 'urlify', (string, options = {}) ->
+            ulrlify(string, options)
+
         preprocessData: (data) ->
           fullFilepath = path.dirname(@src[0])


Unit tests

Unit tests

--- spec/tree-view-package-spec.coffee
+++ spec/tree-view-package-spec.coffee
@@ -2549,7 +2549,7 @@

           atom.commands.dispatch(treeView.element, 'tree-view:remove')
           expect(atom.notifications.getNotifications().length).toBe 0
-
+
         it "focuses the first selected entry's parent folder", ->
           jasmine.attachToDOM(workspaceElement)

@@ -2894,24 +2894,40 @@

     describe "when a file is modified", ->
       it "adds a custom style", ->
-        expect(treeView.element.querySelector('.file.status-modified')).toHaveText('b.txt')
+        expect(treeView.element.querySelector('.project-root .file.status-modified')).toHaveText('b.txt')
+
+    describe "when a file is modified", ->
+      it "adds a custom style to the project root", ->
+        expect(treeView.element.querySelector('.project-root')).toHaveClass('status-modified')

     describe "when a directory is modified", ->
       it "adds a custom style", ->
-        expect(treeView.element.querySelector('.directory.status-modified').header).toHaveText('dir')
+        expect(treeView.element.querySelector('.project-root .directory.status-modified').header).toHaveText('dir')
+
+    describe "when a directory is modified", ->
+      it "adds a custom style to the project root", ->
+        expect(treeView.element.querySelector('.project-root')).toHaveClass('status-modified')

     describe "when a file is new", ->
       it "adds a custom style", ->
         treeView.roots[0].entries.querySelectorAll('.directory')[2].expand()
-        expect(treeView.element.querySelector('.file.status-added')).toHaveText('new2')
+        expect(treeView.element.querySelector('.project-root .file.status-added')).toHaveText('new2')
+
+    describe "when a file is new", ->
+      it "adds a custom style to the project root", ->
+        expect(treeView.element.querySelector('.project-root')).toHaveClass('status-modified')

     describe "when a directory is new", ->
       it "adds a custom style", ->
-        expect(treeView.element.querySelector('.directory.status-added').header).toHaveText('dir2')
+        expect(treeView.element.querySelector('.project-root .directory.status-added').header).toHaveText('dir2')
+
+    describe "when a directory is new", ->
+      it "adds a custom style to the project root", ->
+        expect(treeView.element.querySelector('.project-root')).toHaveClass('status-modified')

     describe "when a file is ignored", ->
       it "adds a custom style", ->
-        expect(treeView.element.querySelector('.file.status-ignored')).toHaveText('ignored.txt')
+        expect(treeView.element.querySelector('.project-root .file.status-ignored')).toHaveText('ignored.txt')

     describe "when a file is selected in a directory", ->
       beforeEach ->
@@ -2952,16 +2968,18 @@

       describe "when a file is modified", ->
         it "updates its and its parent directories' styles", ->
-          expect(treeView.element.querySelector('.file.status-modified')).toHaveText('b.txt')
-          expect(treeView.element.querySelector('.directory.status-modified').header).toHaveText('dir')
+          expect(treeView.element.querySelector('.project-root .file.status-modified')).toHaveText('b.txt')
+          expect(treeView.element.querySelector('.project-root .directory.status-modified').header).toHaveText('dir')
+          expect(treeView.element.querySelector('.project-root')).toHaveClass('status-modified')

       describe "when a file loses its modified status", ->
         it "updates its and its parent directories' styles", ->
           fs.writeFileSync(modifiedFile, originalFileContent)
           atom.project.getRepositories()[0].getPathStatus(modifiedFile)

-          expect(treeView.element.querySelector('.file.status-modified')).not.toExist()
-          expect(treeView.element.querySelector('.directory.status-modified')).not.toExist()
+          expect(treeView.element.querySelector('.project-root .file.status-modified')).not.toExist()
+          expect(treeView.element.querySelector('.project-root .directory.status-modified')).not.toExist()
+          expect(treeView.element.querySelector('.project-root.status-modified')).not.toExist()

   describe "selecting items", ->
     [dirView, fileView1, fileView2, fileView3, treeView, rootDirPath, dirPath, filePath1, filePath2, filePath3] = []


change keymap to `ctrl-k ctrl-m` #45

change keymap to `ctrl-k ctrl-m` #45

--- keymaps/minimap.cson
+++ keymaps/minimap.cson
@@ -8,4 +8,4 @@
 # For more detailed documentation see
 # https://atom.io/docs/latest/advanced/keymaps
 '.workspace':
-  'ctrl-alt-o': 'minimap:toggle'
+  'ctrl-k ctrl-m': 'minimap:toggle'


Fix test

Fix test

--- spec/display-layer-spec.coffee
+++ spec/display-layer-spec.coffee
@@ -550,10 +550,8 @@
       expect(e.message).toMatch(/Invalid text decoration iterator position/)

   it "updates the displayed text correctly when the underlying buffer changes", ->
-    for i in [0...1] by 1
+    for i in [0...100] by 1
       seed = Date.now()
-      console.log seed
-      seed = 1455817945083
       seedFailureMessage = "Seed: #{seed}"
       random = new Random(seed)
       buffer = new TextBuffer(text: buildRandomLines(random, 10))
@@ -568,7 +566,7 @@

       foldIds = []

-      for j in [0...1] by 1
+      for j in [0...10] by 1
         global.debug = true
         k = random(10)
         if k < 2
@@ -590,9 +588,7 @@
         return if currentSpecFailed()

         # token iterator matches contents of display layer
-        console.log getTokenLines(displayLayer)
-
-        verifyTokenIterator(displayLayer, textDecorationLayer, seedFailureMessage)
+        # verifyTokenIterator(displayLayer, textDecorationLayer, seedFailureMessage)
         return if currentSpecFailed()

         verifyRightmostScreenPosition(displayLayer, seedFailureMessage)


:arrow_down: Re-add specs for EditorLinter::getMessages

--- spec/editor-linter-spec.coffee
+++ spec/editor-linter-spec.coffee
@@ -33,6 +33,15 @@
       expect(textEditor.getDecorations().length).toBe(countDecorations + 1)
       editorLinter.deleteMessage(message)
       expect(textEditor.getDecorations().length).toBe(countDecorations)
+
+  describe '::getMessages', ->
+    it 'returns a set of messages', ->
+      message = getMessage('Hey!', __dirname + '/fixtures/file.txt', [[0, 1], [0, 2]])
+      messageSet = editorLinter.getMessages()
+      editorLinter.addMessage(message)
+      expect(messageSet.has(message)).toBe(true)
+      editorLinter.deleteMessage(message)
+      expect(messageSet.has(message)).toBe(false)

   describe '::onDidMessage{Add, Change, Delete}', ->
     it 'notifies us of the changes to messages', ->


examples/quadtree: fix import

examples/quadtree: fix import

--- examples/quadtree.coffee
+++ examples/quadtree.coffee
@@ -1,7 +1,7 @@
 #!/usr/bin/env coffee

-WKTReader = (require "../geos").WKTReader
-Quadtree = (require "../geos").Quadtree
+WKTReader = (require "../lib").WKTReader
+Quadtree = (require "../lib").Quadtree

 tree = new Quadtree()
 reader = new WKTReader()


update app id

update app id

--- caspertests/tests/iosapp.coffee
+++ caspertests/tests/iosapp.coffee
@@ -53,8 +53,8 @@
   casper.thenOpen settings.baseURL() + "/admin/api/v1/iosapp",
     method: "post"
     data: JSON.stringify({
-      app_id:"503424369"
-      title:"日本経済新聞 紙面ビューアー"
+      app_id:"579581125"
+      title:"smart news"
       webhook_url: "http://xxx.xxx/xxxx"
       content: "moo bar"
       region: "143462"


Fix name of default meta attribute for csrfParam

--- lib/assets/javascripts/unpoly/protocol.coffee
+++ lib/assets/javascripts/unpoly/protocol.coffee
@@ -246,7 +246,7 @@
     The parameter name can be configured as a string or as function that returns the parameter name.
     If no name is set, no token will be sent.

-    Defaults to the `content` attribute of a `<meta>` tag named `csrf-token`:
+    Defaults to the `content` attribute of a `<meta>` tag named `csrf-param`:

         <meta name="csrf-param" content="authenticity_token" />


Log total module count

Log total module count

--- build/tasks/output-module-counts.coffee
+++ build/tasks/output-module-counts.coffee
@@ -18,6 +18,7 @@
       diff = name1.localeCompare(name2) if diff is 0
       diff

+    console.log "Total Modules: #{sortedNames.length}"
     sortedNames.forEach (name) ->
       {count, versions} = modules[name]
       grunt.log.error "#{name}: #{count} (#{Object.keys(versions).join(', ')})" if count > 1


Update turbolinks_slide.js.coffee

Update turbolinks_slide.js.coffee

removed query strings from the current url.

--- turbolinks_slide.js.coffee
+++ turbolinks_slide.js.coffee
@@ -30,7 +30,11 @@

   _domain_removed_current_url: ->
     port = if document.location.port == '' then '' else ":#{document.location.port}"
-    document.location.href.replace(document.location.protocol + '//' + document.location.host + port + '/', '')
+    url = document.location.href.replace(document.location.protocol + '//' + document.location.host + port + '/', '')
+    pos = url.indexOf('?')
+    if pos > 0
+      url = url.substring(0, pos)
+    url

   _get_controller: ->
     return @current_absolute_path[0] if @current_absolute_path.length >= 1


Fix polymorphic association test which could occasionally fail if some implicit loads triggered by the autocreated records in the test setup didn't return fast enough.


fixed addUserToRoom duplicated conditional

--- server/methods/addUserToRoom.coffee
+++ server/methods/addUserToRoom.coffee
@@ -5,7 +5,7 @@

 		room = ChatRoom.findOne data.rid

-		if room.username isnt Meteor.user().username and room.t is 'c'
+		# if room.username isnt Meteor.user().username and room.t is 'c'
 		if room.u.username isnt Meteor.user().username and room.t is 'c'
 			throw new Meteor.Error 403, '[methods] addUserToRoom -> Not allowed'


Remove file that I forgot about

Remove file that I forgot about

--- test/specs/models/factories.coffee
+++ test/specs/models/factories.coffee
@@ -1,17 +0,0 @@
-GalaxyZooSubject = require('models/GalaxyZooSubject')
-Factory = require 'rosie'
-
-Factory.define('galaxyZooSubject', GalaxyZooSubject)
-  .sequence('id')
-  .attr('coords', ->
-    [Math.random()*100, Math.random()*100]
-  )
-  .atrr('metadata', ->
-    return {
-      magnitude: ((Math.random()*20)+10)
-      distance: (Math.random()*10000)
-    }
-  )
-  .atrr('location', { standard: "image/120341241.jpg", thumbnail: "image/120341241-thumb.jpg", inverted: "image/120341241-invert.jpg", fitts: "iamge/120341241.fitts" })
-
-module.export = Factory


test/replace: Add object method replacement test

--- test/src/replace/index-test.coffee
+++ test/src/replace/index-test.coffee
@@ -32,6 +32,17 @@
         When -> td.reset()
         Then -> td.explain(new @dependency.thingConstructor().foo).isTestDouble == false
         And -> new @dependency.thingConstructor().foo() == 'og foo'
+
+    describe 'Replacing an object method', ->
+      Given -> @thing = new @dependency.thingConstructor()
+      When -> @doubleFoo = td.replace(@thing, 'foo')
+      Then -> td.explain(@thing.foo).isTestDouble == true
+      And -> @thing.foo() == undefined
+
+      describe 'reset restores it', ->
+        When -> td.reset()
+        Then -> td.explain(@thing.foo).isTestDouble == false
+        And -> @thing.foo() == 'og foo'

     describe 'Replacing an object / function bag', ->
       When -> @doubleBag = td.replace(@dependency, 'dog')


:bug:Fix admin demo requests 7-day average

--- app/views/admin/DemoRequestsView.coffee
+++ app/views/admin/DemoRequestsView.coffee
@@ -26,7 +26,8 @@
       @dayCounts.push(day: day, count: count)
     @dayCounts.sort((a, b) -> b.day.localeCompare(a.day))
     sevenCounts = []
-    for dayCount in @dayCounts
+    for i in [@dayCounts.length - 1..0]
+      dayCount = @dayCounts[i]
       sevenCounts.push(dayCount.count)
       while sevenCounts.length > 7
         sevenCounts.shift()


Client: Activity: Updated isUserGroupAdmin method

--- client/activity/lib/components/channelparticipantavatars/index.coffee
+++ client/activity/lib/components/channelparticipantavatars/index.coffee
@@ -57,9 +57,7 @@

       return showErrorNotification err  if err

-      if isAdmin
-      then @setState isGroupAdmin: yes
-      else @setState isGroupAdmin: no
+      @setState isGroupAdmin: isAdmin

     document.addEventListener 'mousedown', @bound 'handleOutsideMouseClick'


fix url encoding of / in search parameters. fixes #72

Former-commit-id: f512e93e2c97c5054f06a0507f21903c83213fe4 [formerly fbac817fe110cdfda3608f9a764071157ca38ef4] [formerly c35206bfd5c8841dfa183f7cef33cc99edc85609 [formerly ee1c4d8908a252d669ca47a1ca26e5e24d4b9654]] [formerly 379750445039364701a84576934b92e739187083 [formerly 66978271e20f7ae7fb9cda7a9ca023d93c5bd271] [formerly 889593f42bb8dda5eb0cb5ce7b314549dc9e2c09 [formerly 889593f42bb8dda5eb0cb5ce7b314549dc9e2c09 [formerly a630951bf7f96cea9f7b3c091057694983c0a734]]]]
Former-commit-id: ab00fd6c1628d3af5893a8be6b530438c217ef2c [formerly 9aa7fc6659ff0a284cdcbded4e355c239b58635c] [formerly cf94a7df1200c4554f80cf364f20244ed5344fe6 [formerly 7b955a14b65b656f45bd531129765109642cf6bb]]
Former-commit-id: 29948b885399bed533e74a85e46f7628be83ecb1 [formerly 1d83e01e9effd75ed324f16119ff7c423ebccd77]
Former-commit-id: 3823e40108348ff045c60226a2cb6b73731b8888
Former-commit-id: f80088e5bb7f20426d92cabde1adad89c802e458

--- @client/browser_location.coffee
+++ @client/browser_location.coffee
@@ -159,7 +159,10 @@

 relativeURLFromLocation = ->
   # location.search returns query parameters
-  "#{location.pathname}#{location.search}#{location.hash}"
+
+  # fix url encoding of /
+  search = location.search?.replace(/\%2f/g, '/')
+  "#{location.pathname}#{search}#{location.hash}"

 relativeURLFromStatebus = ->
   loc = fetch 'location'


atom-beautify markdown beautify on save true

--- Atom/config.cson
+++ Atom/config.cson
@@ -24,5 +24,6 @@
     js_end_with_newline: true
     language_js_beautify_on_save: true
     language_json_beautify_on_save: true
+    language_markdown_beautify_on_save: true
   "pigments":
     markerType: "dot"


modify url api for paging

modify url api for paging

--- server/api/url/url.controller.coffee
+++ server/api/url/url.controller.coffee
@@ -6,6 +6,7 @@
 ddurl = require '../../components/ddurl'

 _checkUrl = (url) ->
+  return false  unless url
   regexp = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi
   return regexp.test url

@@ -14,8 +15,14 @@
   UrlModel.count (err, length) ->
     return handleError res, err  if err

+    page = (req.query.page || 1) - 1
+    return handleError res, new Error 'Wrong page parameter'  if page < 0
+
+    pagePerNumber = req.query.pagePerNumber || 20
     result = {total: length}
-    query = UrlModel.find().sort({createdAt: -1}).limit(20)
+    query = UrlModel.find().sort({createdAt: -1})
+      .skip(page * pagePerNumber)
+      .limit(pagePerNumber)
     query.exec (err, urls) ->
       return handleError res, err  if err
       res.status(200).json _.merge result, {urls: urls}
@@ -55,7 +62,7 @@

 # expand url in the DB.
 exports.expand = (req, res) ->
-  if not _checkUrl.isUri req.query.shortUrl
+  if not _checkUrl req.query.shortUrl
     return res.status(400).send 'Bad Request'

   parse = url.parse req.query.shortUrl, true


add default weibo

add default weibo

--- lib/api/weibo.coffee
+++ lib/api/weibo.coffee
@@ -29,8 +29,8 @@
                 }, {
                   $set: {company: company}
                 }, (err, num) ->
-            return res.json posts[company] or {}
-    res.send 404
+            return res.json(posts[company] or posts['default'] or {})
+    res.json posts['default']

   data: ->
     devices: devices
@@ -46,6 +46,7 @@
       lines = body.match(/[^\r\n]+/g)
       tmpDevices = {}
       company = null
+      retrieveWeibo 'default'
       for line in lines
         if m = /^##\s+(.+)\s*/g.exec(line)
           company = m[1].trim()


Remove unnessary variable

Remove unnessary variable

--- lib/fonts-cjk.coffee
+++ lib/fonts-cjk.coffee
@@ -24,9 +24,8 @@

 applyFont = (type, font) ->
   unless font == '(Default)' or font == ''
-    font = "'#{font}'"
     document.body.classList.add("fonts-cjk-#{type}")
-    document.body.style.setProperty("--fonts-cjk-#{type}", font)
+    document.body.style.setProperty("--fonts-cjk-#{type}", "'#{font}'")
   else
     document.body.classList.remove("fonts-cjk-#{type}")
     document.body.style.removeProperty("--fonts-cjk-#{type}")


Reposition *after* you add to the DOM.

Reposition *after* you add to the DOM.

It doesn't seem to flicker, and you need the parent for positioning to work
properly.

--- lib/side-view.coffee
+++ lib/side-view.coffee
@@ -12,27 +12,18 @@
   initialize: (@side) ->

   installIn: (editorView) ->
-    console.log "== Initial installation // #{@side.description()}"
-    @reposition(editorView, true)
     @appendTo editorView.overlayer
+    @reposition(editorView)

     @side.refBannerMarker.on "changed", =>
-      console.log ">> Banner marker changed // #{@side.description()}"
       @reposition(editorView)

   reposition: (editorView, initial) ->
     # @side.lines().addClass("conflict-line #{@side.klass()}")
     anchor = editorView.renderedLines.offset()
     ref = @side.refBannerOffset()
-    if initial
-      top = ref.top
-    else
-      top = ref.top + anchor.top

-    console.log "anchor: #{anchor.top} moving to: #{top}"
-    console.log "matched lines: #{@side.lines().text()}"
-
-    @offset top: top
+    @offset top: ref.top + anchor.top
     @height @side.refBannerLine().height()

   useMe: ->


Close PathWatcher on deactivation

Close PathWatcher on deactivation

--- lib/spark-dev.coffee
+++ lib/spark-dev.coffee
@@ -145,6 +145,7 @@
       @watchConfig()

   deactivate: ->
+    @PathWatcher.close()
     @statusView?.destroy()
     @emitter.dispose()
     @disposables.dispose()


Eliminate `rootView.project` references.

--- lib/tree-view.coffee
+++ lib/tree-view.coffee
@@ -41,7 +41,7 @@
         @selectActiveFile()

     rootView.on 'root-view:active-path-changed', => @selectActiveFile()
-    rootView.project.on 'path-changed', => @updateRoot()
+    project.on 'path-changed', => @updateRoot()
     @observeConfig 'core.hideGitIgnoredFiles', => @updateRoot()

     if @root
@@ -78,7 +78,7 @@
         @attach()

   attach: ->
-    return unless rootView.project.getPath()
+    return unless project.getPath()
     rootView.horizontal.prepend(this)
     @focus()

@@ -122,8 +122,8 @@

   updateRoot: ->
     @root?.remove()
-    if rootDirectory = rootView.project.getRootDirectory()
-      @root = new DirectoryView(directory: rootDirectory, isExpanded: true, project: rootView.project)
+    if rootDirectory = project.getRootDirectory()
+      @root = new DirectoryView(directory: rootDirectory, isExpanded: true, project: project)
       @treeViewList.append(@root)
     else
       @root = null
@@ -137,7 +137,6 @@

     return unless activeFilePath = rootView.getActiveEditor()?.getPath()

-    project = rootView.project
     activePathComponents = project.relativize(activeFilePath).split('/')
     currentPath = project.getPath().replace(/\/$/, '')
     for pathComponent in activePathComponents
@@ -217,11 +216,11 @@

     dialog = new Dialog
       prompt: prompt
-      path: rootView.project.relativize(oldPath)
+      path: project.relativize(oldPath)
       select: true
       iconClass: 'move'
       onConfirm: (newPath) =>
-        newPath = rootView.project.resolve(newPath)
+        newPath = project.resolve(newPath)
         directoryPath = fs.directory(newPath)
         try
           fs.makeTree(directoryPath) unless fs.exists(directoryPath)
@@ -249,7 +248,7 @@
     selectedEntry = @selectedEntry() or @root
     selectedPath = selectedEntry.getPath()
     directoryPath = if fs.isFile(selectedPath) then fs.directory(selectedPath) else selectedPath
-    relativeDirectoryPath = rootView.project.relativize(directoryPath)
+    relativeDirectoryPath = project.relativize(directoryPath)
     relativeDirectoryPath += '/' if relativeDirectoryPath.length > 0

     dialog = new Dialog
@@ -259,7 +258,7 @@
       iconClass: 'add'
       onConfirm: (relativePath) =>
         endsWithDirectorySeparator = /\/$/.test(relativePath)
-        path = rootView.project.resolve(relativePath)
+        path = project.resolve(relativePath)
         try
           if fs.exists(path)
             pathType = if fs.isFile(path) then "file" else "directory"


small fixes

small fixes

--- lib/tree-view.coffee
+++ lib/tree-view.coffee
@@ -39,7 +39,7 @@
     @roots = []
     @selectedPath = null
     @selectOnMouseUp = null
-    @lastFocusedElement = null
+    @lastFocusedEntry = null
     @ignoredPatterns = []
     @useSyncFS = false
     @currentlyOpening = new Map
@@ -822,7 +822,7 @@
     return unless entry?

     @selectedPath = entry.getPath()
-    @lastFocusedElement = entry
+    @lastFocusedEntry = entry

     selectedEntries = @getSelectedEntries()
     if selectedEntries.length > 1 or selectedEntries[0] isnt entry
@@ -873,7 +873,7 @@
       return

     entryName = path.basename(initialPath)
-    newPath = "#{newDirectoryPath}#{path.sep}#{entryName}".replace(/\s+$/, '')
+    newPath = "#{newDirectoryPath}/#{entryName}".replace(/\s+$/, '')

     try
       @emitter.emit 'will-move-entry', {initialPath, newPath}
@@ -910,7 +910,6 @@

     # return early if clicking on a selected entry
     if entryToSelect.classList.contains('selected')
-
       # mouse right click or ctrl click as right click on darwin platforms
       if e.button is 2 or (e.ctrlKey and process.platform is 'darwin')
         return
@@ -921,18 +920,18 @@
         return

     if e.shiftKey and cmdKey
-      # select continuous from @lastFocusedElement but leave others
+      # select continuous from @lastFocusedEntry but leave others
       @selectContinuousEntries(entryToSelect, false)
-      @toggleMultiSelectMenu()
+      @showMultiSelectMenuIfNecessary()
     else if e.shiftKey
-      # select continuous from @lastFocusedElement and deselect rest
+      # select continuous from @lastFocusedEntry and deselect rest
       @selectContinuousEntries(entryToSelect)
-      @toggleMultiSelectMenu()
+      @showMultiSelectMenuIfNecessary()
     # only allow ctrl click for multi selection on non darwin systems
     else if cmdKey
       @selectMultipleEntries(entryToSelect)
-      @lastFocusedElement = entryToSelect
-      @toggleMultiSelectMenu()
+      @lastFocusedEntry = entryToSelect
+      @showMultiSelectMenuIfNecessary()
     else
       @selectEntry(entryToSelect)
       @showFullMenu()
@@ -948,18 +947,18 @@
     e.stopPropagation()

     if shiftKey and cmdKey
-      # select continuous from @lastFocusedElement but leave others
+      # select continuous from @lastFocusedEntry but leave others
       @selectContinuousEntries(entryToSelect, false)
-      @toggleMultiSelectMenu()
+      @showMultiSelectMenuIfNecessary()
     else if shiftKey
-      # select continuous from @lastFocusedElement and deselect rest
+      # select continuous from @lastFocusedEntry and deselect rest
       @selectContinuousEntries(entryToSelect)
-      @toggleMultiSelectMenu()
+      @showMultiSelectMenuIfNecessary()
     # only allow ctrl click for multi selection on non darwin systems
     else if cmdKey
       @deselect([entryToSelect])
-      @lastFocusedElement = entryToSelect
-      @toggleMultiSelectMenu()
+      @lastFocusedEntry = entryToSelect
+      @showMultiSelectMenuIfNecessary()
     else
       @selectEntry(entryToSelect)
       @showFullMenu()
@@ -977,7 +976,7 @@
   #
   # Returns array of selected elements
   selectContinuousEntries: (entry, deselectOthers = true) ->
-    currentSelectedEntry = @lastFocusedElement ? @selectedEntry()
+    currentSelectedEntry = @lastFocusedEntry ? @selectedEntry()
     parentContainer = entry.parentElement
     elements = []
     if parentContainer is currentSelectedEntry.parentElement
@@ -1011,7 +1010,7 @@
     @list.classList.remove('full-menu')
     @list.classList.add('multi-select')

-  toggleMultiSelectMenu: ->
+  showMultiSelectMenuIfNecessary: ->
     if @getSelectedEntries().length > 1
       @showMultiSelectMenu()
     else
@@ -1080,7 +1079,6 @@
           newElement.style.paddingRight = "1em"
           dragImage.append(newElement)

-
       document.body.appendChild(dragImage)

       e.dataTransfer.effectAllowed = "move"


fixing global stats page again

fixing global stats page again

--- shared/idle/IdleServer.coffee
+++ shared/idle/IdleServer.coffee
@@ -33,6 +33,7 @@
     mapRegion: 1
     achievements: 1
     hp: 1
+    xp: 1
     mp: 1
     gold: 1
     level: 1