update def/template/menu_win32.cson

update def/template/menu_win32.cson

--- def/template/menu_win32.cson
+++ def/template/menu_win32.cson
@@ -1,298 +1,296 @@
 Menu:
   "&File":
-    value: "ファイル(&F)"
+    value: "File(&F)"
     submenu:
       "New &Window":
-        value: "新規ウインドウ(&W)"
+        value: "New Window(&W)"
       "&New File":
-        value: "新規ファイル(&N)"
+        value: "New File(&N)"
       "&Open File…":
-        value: "開く(&O)..."
+        value: "Open File(&O)..."
       "Open Folder…":
-        value: "フォルダを開く..."
+        value: "Open Folder..."
       "Add Project Folder…":
-        value: "プロジェクトフォルダを追加..."
+        value: "Add Project Folder..."
       "Reopen Last &Item":
-        value: "最後に使用したファイルを開く(&I)"
+        value: "Reopen Last Item(&I)"
       "Se&ttings":
-        value: "環境設定(&T)..."
+        value: "Settings(&T)..."
       "Config…":
-        value: "個人設定..."
+        value: "Config..."
       "Init Script…":
-        value: "起動スクリプト..."
+        value: "Init Script..."
       "Keymap…":
-        value: "キーマップ..."
+        value: "Keymap..."
       "Snippets…":
-        value: "スニペット..."
+        value: "Snippets..."
       "Stylesheet…":
-        value: "スタイルシート..."
+        value: "Stylesheet..."
       "&Save":
-        value: "保存(&S)"
+        value: "Save(&S)"
       "Save &As…":
-        value: "別名で保存(&A)..."
+        value: "Save As(&A)..."
       "Save A&ll":
-        value: "すべて保存(&L)"
+        value: "Save All(&L)"
       "&Close Tab":
-        value: "タブを閉じる(&C)"
+        value: "Close Tab(&C)"
       "Close &Pane":
-        value: "ペインを閉じる(&P)"
+        value: "Close Pane(&P)"
       "Clos&e Window":
-        value: "ウインドウを閉じる(&E)"
+        value: "Close Window(&E)"
       "E&xit":
-        value: "終了(&X)"
+        value: "Exit(&X)"
       "Close All Tabs":
-        value: "タブをすべて閉じる"
+        value: "Close All Tabs"
   "&Edit":
-    value: "編集(&E)"
+    value: "Edit(&E)"
     submenu:
       "&Undo":
-        value: "取り消す(&U)"
+        value: "Undo(&U)"
       "&Redo":
-        value: "やり直す(&R)"
+        value: "Redo(&R)"
       "Cu&t":
-        value: "カット(&T)"
+        value: "Cut(&T)"
       "&Copy":
-        value: "コピー(&C)"
+        value: "Copy(&C)"
       "Copy Pat&h":
-        value: "パスをコピー(&H)"
+        value: "Copy Path(&H)"
       "&Paste":
-        value: "ペースト(&P)"
+        value: "Paste(&P)"
       "Select &All":
-        value: "すべて選択(&A)"
+        value: "Select All(&A)"
       "&Toggle Comments":
-        value: "コメントの切替(&T)"
+        value: "Toggle Comments(&T)"
       Lines:
-        value: "行"
+        value: "Lines"
         submenu:
           "&Indent":
-            value: "インデントを追加(&I)"
+            value: "Indent(&I)"
           "&Outdent":
-            value: "インデントを戻す(&O)"
+            value: "Outdent(&O)"
           "&Auto Indent":
-            value: "自動インデント(&A)"
+            value: "Auto Indent(&A)"
           "Move Line &Up":
-            value: "選択中の行を上に移動(&U)"
+            value: "Move Line Up(&U)"
           "Move Line &Down":
-            value: "選択中の行を下に移動(&D)"
+            value: "Move Line Down(&D)"
           "Du&plicate Lines":
-            value: "行を複製(&P)"
+            value: "Duplicate Lines(&P)"
           "D&elete Line":
-            value: "行を削除(&E)"
+            value: "Delete Line(&E)"
           "&Join Lines":
-            value: "行を結合(&J)"
+            value: "Join Lines(&J)"
       Columns:
-        value: "列"
+        value: "Columns"
         submenu:
           "Move Selection &Left":
-            value: "選択範囲を左に移動(&L)"
+            value: "Move Selection Left(&L)"
           "Move Selection &Right":
-            value: "選択範囲を右に移動(&R)"
+            value: "Move Selection Right(&R)"
       Text:
-        value: "テキスト"
+        value: "Text"
         submenu:
           "&Upper Case":
-            value: "大文字に変換(&U)"
+            value: "Upper Case(&U)"
           "&Lower Case":
-            value: "小文字に変換(&L)"
+            value: "Lower Case(&L)"
           "Delete to End of &Word":
-            value: "単語の末尾まで削除(&W)"
+            value: "Delete to End of Word(&W)"
           "Delete to Previous Word Boundary":
-            value: "前の単語の境界まで削除"
+            value: "Delete to Previous Word Boundary"
           "Delete to Next Word Boundary":
-            value: "次の単語の境界まで削除"
+            value: "Delete to Next Word Boundary"
           "&Delete Line":
-            value: "行を削除(&D)"
+            value: "Delete Line(&D)"
           "&Transpose":
-            value: "前後を入れ替え(&T)"
+            value: "Transpose(&T)"
       Folding:
-        value: "折りたたみ"
+        value: "Folding"
         submenu:
           "&Fold":
-            value: "折りたたむ(&F)"
+            value: "Fold(&F)"
           "&Unfold":
-            value: "折りたたみを戻す(&U)"
+            value: "Unfold(&U)"
           "Unfold &All":
-            value: "すべての折りたたみを戻す(&A)"
+            value: "Unfold All(&A)"
           "Fol&d All":
-            value: "すべて折りたたむ(&D)"
+            value: "Fold All(&D)"
           "Fold Level 1":
-            value: "1段階折りたたむ"
+            value: "Fold Level 1"
           "Fold Level 2":
-            value: "2段階折りたたむ"
+            value: "Fold Level 2"
           "Fold Level 3":
-            value: "3段階折りたたむ"
+            value: "Fold Level 3"
           "Fold Level 4":
-            value: "4段階折りたたむ"
+            value: "Fold Level 4"
           "Fold Level 5":
-            value: "5段階折りたたむ"
+            value: "Fold Level 5"
           "Fold Level 6":
-            value: "6段階折りたたむ"
+            value: "Fold Level 6"
           "Fold Level 7":
-            value: "7段階折りたたむ"
+            value: "Fold Level 7"
           "Fold Level 8":
-            value: "8段階折りたたむ"
+            value: "Fold Level 8"
           "Fold Level 9":
-            value: "9段階折りたたむ"
+            value: "Fold Level 9"
       "Reflow Selection":
-        value: "選択範囲をリフロー"
+        value: "Reflow Selection"
       Bookmark:
-        value: "ブックマーク"
+        value: "Bookmark"
         submenu:
           "View All":
-            value: "すべて表示"
+            value: "View All"
           "Toggle Bookmark":
-            value: "ブックマークの切替"
+            value: "Toggle Bookmark"
           "Jump to Next Bookmark":
-            value: "次のブックマークへ"
+            value: "Jump to Next Bookmark"
           "Jump to Previous Bookmark":
-            value: "前のブックマークへ"
+            value: "Jump to Previous Bookmark"
       "Select Encoding":
-        value: "エンコーディング選択"
+        value: "Select Encoding"
       "Go to Line":
-        value: "指定行に移動"
+        value: "Go to Line"
       "Select Grammar":
-        value: "文法を選択"
+        value: "Select Grammar"
   "&View":
-    value: "表示(&V)"
+    value: "View(&V)"
     submenu:
       "Toggle &Full Screen":
-        value: "フルスクリーン切替(&F)"
+        value: "Toggle Full Screen(&F)"
       "Toggle Menu Bar":
-        value: "メニューバー切替"
+        value: "Toggle Menu Bar"
       Panes:
-        value: "ペイン"
+        value: "Panes"
         submenu:
           "Split Up":
-            value: "ペイン分割 ↑"
+            value: "Split Up"
           "Split Down":
-            value: "ペイン分割 ↓"
+            value: "Split Down"
           "Split Left":
-            value: "ペイン分割 ←"
+            value: "Split Left"
           "Split Right":
-            value: "ペイン分割 →"
+            value: "Split Right"
           "Focus Next Pane":
-            value: "次のペインにフォーカス"
+            value: "Focus Next Pane"
           "Focus Previous Pane":
-            value: "前のペインにフォーカス"
+            value: "Focus Previous Pane"
           "Focus Pane Above":
-            value: "ペインにフォーカス ↑"
+            value: "Focus Pane Above"
           "Focus Pane Below":
-            value: "ペインにフォーカス ↓"
+            value: "Focus Pane Below"
           "Focus Pane On Left":
-            value: "ペインにフォーカス ←"
+            value: "Focus Pane On Left"
           "Focus Pane On Right":
-            value: "ペインにフォーカス →"
+            value: "Focus Pane On Right"
           "Close Pane":
-            value: "ペインを閉じる"
+            value: "Close Pane"
       Developer:
-        value: "開発"
+        value: "Developer"
         submenu:
           "Open In &Dev Mode…":
-            value: "開発モードで開く(&D)"
+            value: "Open In Dev Mode(&D)..."
           "&Reload Window":
-            value: "ウィンドウの再読み込み(&R)"
+            value: "Reload Window(&R)"
           "Run Package &Specs":
-            value: "パッケージ Specs を実行(&S)"
+            value: "Run Package Specs(&S)"
           "Toggle Developer &Tools":
-            value: "デベロッパー ツール(&T)"
+            value: "Toggle Developer Tools(&T)"
       "&Increase Font Size":
-        value: "フォントサイズの拡大"
+        value: "Increase Font Size(&I)"
       "&Decrease Font Size":
-        value: "フォントサイズの縮小"
+        value: "Decrease Font Size(&D)"
       "Re&set Font Size":
-        value: "フォントサイズのリセット"
+        value: "Reset Font Size(&S)"
       "Toggle Soft &Wrap":
-        value: "自動折り返しの切替(&W)"
+        value: "Toggle Soft Wrap(&W)"
       "Toggle Command Palette":
-        value: "コマンドパレット"
+        value: "Toggle Command Palette"
       "Toggle Tree View":
-        value: "ツリービュー"
+        value: "Toggle Tree View"
   "&Selection":
-    value: "選択(&S)"
+    value: "Selection(&S)"
     submenu:
       "Add Selection &Above":
-        value: "選択範囲を広げる ↑(&A)"
+        value: "Add Selection Above(&A)"
       "Add Selection &Below":
-        value: "選択範囲を広げる ↓(&B)"
+        value: "Add Selection Below(&B)"
       "S&plit into Lines":
-        value: "選択範囲を各行に分割して同時操作(&P)"
+        value: "Split into Lines(&P)"
       "Single Selection":
-        value: "同時操作状態を解除"
+        value: "Single Selection"
       "Select to &Top":
-        value: "ファイル先頭まで選択(&T)"
+        value: "Select to Top(&T)"
       "Select to Botto&m":
-        value: "ファイル末尾まで選択(&M)"
+        value: "Select to Bottom(&M)"
       "Select &Line":
-        value: "行を選択(&L)"
+        value: "Select Line(&L)"
       "Select &Word":
-        value: "単語を選択(&W)"
+        value: "Select Word(&W)"
       "Select to Beginning of W&ord":
-        value: "単語の先頭まで選択(&O)"
+        value: "Select to Beginning of Word(&O)"
       "Select to Beginning of L&ine":
-        value: "行頭まで選択(&I)"
+        value: "Select to Beginning of Line(&I)"
       "Select to First &Character of Line":
-        value: "行の最初の文字まで選択(&C)"
+        value: "Select to First Character of Line(&C)"
       "Select to End of Wor&d":
-        value: "単語の末尾まで選択(&D)"
+        value: "Select to End of Word(&D)"
       "Select to End of Lin&e":
-        value: "行末まで選択(&E)"
+        value: "Select to End of Line(&E)"
       "Select Inside Brackets":
-        value: "カッコ内を選択"
+        value: "Select Inside Brackets"
   "F&ind":
-    value: "検索(&I)"
+    value: "Find(&I)"
     submenu:
       "Find in Buffer":
-        value: "検索..."
+        value: "Find in Buffer"
       "Replace in Buffer":
-        value: "置換..."
+        value: "Replace in Buffer"
       "Select Next":
-        value: "次の一致も選択"
+        value: "Select Next"
       "Select All":
-        value: "一致をすべて選択"
+        value: "Select All"
       "Toggle Find in Buffer":
-        value: "検索パネル切替"
+        value: "Toggle Find in Buffer"
       "Find in Project":
-        value: "プロジェクト内検索..."
+        value: "Find in Project"
       "Toggle Find in Project":
-        value: "プロジェクト内検索パネル切替"
+        value: "Toggle Find in Project"
       "Find Next":
-        value: "次を検索"
+        value: "Find Next"
       "Find Previous":
-        value: "前を検索"
+        value: "Find Previous"
       "Replace Next":
-        value: "次を置換"
+        value: "Replace Next"
       "Replace All":
-        value: "すべて置換"
+        value: "Replace All"
       "Clear History":
-        value: "履歴をクリア"
+        value: "Clear History"
       "Find Buffer":
-        value: "バッファを検索"
+        value: "Find Buffer"
       "Find File":
-        value: "ファイルを検索"
+        value: "Find File"
       "Find Modified File":
-        value: "修正されたファイルを検索"
+        value: "Find Modified File"
   "&Packages":
-    value: "パッケージ(&P)"
+    value: "Packages(&P)"
   "&Help":
-    value: "ヘルプ(&H)"
+    value: "Help(&H)"
     submenu:
       "View &Terms of Use":
-        value: "利用条件"
+        value: "View &Terms of Use"
       "View &License":
-        value: "ライセンス"
+        value: "View &License"
       "&Documentation":
-        value: "ドキュメント(&D)"
-      Roadmap:
-        value: "ロードマップ"
+        value: "Documentation(&D)"
       "Frequently Asked Questions":
-        value: "よくあるご質問"
+        value: "Frequently Asked Questions"
       "Community Discussions":
-        value: "コミュニティ ディスカッション"
+        value: "Community Discussions ディスカッション"
       "Report Issue":
-        value: "問題の報告"
+        value: "Report Issue"
       "Search Issues":
-        value: "報告されている問題"
+        value: "Search Issues"
       "About Atom":
-        value: "Atom について"
+        value: "About Atom について"
       "Welcome Guide":
-        value: "ウェルカムガイド"
+        value: "Welcome Guide"


configure css loader

configure css loader

--- configs/webpack/base.coffee
+++ configs/webpack/base.coffee
@@ -15,6 +15,7 @@
   css:    'css-loader?minimize=true'
   less:   'less-loader'

+
 RESOLVABLES =
   js:     { test: /\.js$/,     use: LOADERS.babel,  exclude: /node_modules/ }
   jsx:    { test: /\.jsx$/,    use: LOADERS.babel,  exclude: /node_modules/ }
@@ -32,11 +33,11 @@
   cjsx:   RESOLVABLES.cjsx
   less: {
     test: /\.less$/
-    use: ExtractTextPlugin.extract({
-      fallback: 'style-loader',
-      use: [ LOADERS.css, LOADERS.less ]
-    })
-    exclude: /node_modules/
+    use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: [ LOADERS.css, LOADERS.less ]})
+  }
+  css: {
+    test: /\.css$/
+    use: [ LOADERS.css ]
   }

 DEV_LOADERS = ['react-hot-loader/webpack']


kill refresh route

kill refresh route

--- apps/auth/index.coffee
+++ apps/auth/index.coffee
@@ -11,6 +11,5 @@

 # Log out
 app.get '/me/sign_out', routes.logout, routes.redirectBack
-app.get '/me/refresh', routes.refresh
 app.get '/go', routes.redirect
 app.get '/reset/:token', routes.resetPassword


License header.

License header.

--- angular-pouchdb.coffee
+++ angular-pouchdb.coffee
@@ -1,3 +1,27 @@
+###
+The MIT License
+
+Copyright (c) 2013-2014 Wilfred Springer, http://nxt.flotsam.nl/
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+###
+
 pouchdb = angular.module 'pouchdb', ['ng']

 # Quick access to array functions


Assert new Image

Assert new Image

--- test/suite.coffee
+++ test/suite.coffee
@@ -116,7 +116,14 @@
         image = new Upload.Image src, dest, opts, client

       describe 'constructor', ->
-        it 'should set default values'
+        it 'should set default values', ->
+          assert image instanceof Upload.Image
+          assert image.config instanceof Upload
+          assert.equal image.src, __dirname + 'test/assets/photo.jpg'
+          assert.equal image.dest, 'images_test/Wm/PH/f3/I0'
+          assert /[a-z0-9]{24}/.test image.tmpName
+          assert.deepEqual image.meta, {}
+          assert.equal image.gm, null

       describe '#getMeta()', ->
         it 'should store image matadata'


Hackishly fade out once dropped

Hackishly fade out once dropped

--- app/frontend/scripts/upload.js.coffee
+++ app/frontend/scripts/upload.js.coffee
@@ -39,6 +39,10 @@
   $('body').bind 'dragenter', (e) ->
     $('body').fadeTo(200,0.4)

+  # If we drop some file, try to fade shit out. This is a hack. It's okay.
+  $('body').bind 'drop', (e) ->
+    $('body').fadeTo(200,1)
+
   # If the mouse leaves, try to fade shit out. This is a hack. It's okay.
   $('body').bind 'mouseout', (e) ->
     $('body').fadeTo(200,1)


Add safety

Add safety

--- src/lib/ComponentLoader.coffee
+++ src/lib/ComponentLoader.coffee
@@ -86,6 +86,8 @@
   # Creates an instance of a component.
   createComponent: (name, component, metadata, callback) ->
     implementation = component
+    unless implementation
+      return callback new Error "Component #{name} not available"

     # If a string was specified, attempt to `require` it.
     if typeof implementation is 'string'


removed semicolon

removed semicolon

git-svn-id: 00f01ee4f729ccc52c3e336777c3e81b5adc88db@105877 ef392f78-ee14-0410-84e5-9db46baae5bb

--- app/scripts/search_controllers.coffee
+++ app/scripts/search_controllers.coffee
@@ -123,7 +123,7 @@
             searches.kwicSearch(cqp, page)
             # simpleSearch.makeLemgramSelect() if settings.lemgramSelect
             if settings.wordpicture != false and s.word_pic and " " not in search.val
-                lemgramResults.makeRequest(search.val, "word");
+                lemgramResults.makeRequest(search.val, "word")
                 # lemgramProxy.makeRequest(search.val, "word", $.proxy(lemgramResults.onProgress, lemgramResults));
             else
                 lemgramResults.resetView()


Fix broken results of users in search results

--- core/app/backbone/views/react_user_search.coffee
+++ core/app/backbone/views/react_user_search.coffee
@@ -2,9 +2,7 @@
   displayName: 'ReactUserSearch'

   render: ->
-    _div [],
-      _a [rel:"backbone", href:@model().link()],
-        _img ["feed-activity-user-avatar image-30px", alt:" ", src: @model().avatar_url(30)]
-      _strong ['search-user-name'],
-        _a [rel:"backbone", href:@model().link()],
-          @model().get('name')
+    _div ['feed-activity-heading'],
+      _a [' feed-activity-username', rel:"backbone", href:@model().link()],
+        _img ["avatar-image", alt:" ", src: @model().avatar_url(32), style: {height: '32px', width: '32px', margin: '0 5px 0 0'}]
+        @model().get('name')


Support \textasciitilde in LaTeX mode. #261

--- lib/formats.coffee
+++ lib/formats.coffee
@@ -230,6 +230,7 @@
   .replace /\\begin\s*{(proof|pf)}(\s*\[([^\]]*)\])?/g, (m, env, x, opt) -> "Proof#{if opt then " (#{opt})" else ''}: "
   .replace /\\end\s*{(proof|pf)}/g, ' ∎

'
   .replace /\\(dots|ldots)\b\s*/g, '…'
+  .replace /\\textasciitilde\b\s*/g, '∼'  ## Avoid ~ -> \nbsp
   .replace /\\"{(.)}/g, '&$1uml;'
   .replace /\\"(.)/g, '&$1uml;'
   .replace /\\'c|\\'{c}/g, 'ć'


fixed problem with empty ignoredirs setting

--- src/music.coffee
+++ src/music.coffee
@@ -147,9 +147,9 @@
       if contents?
         for entry in contents
           if entry.isFolder
-            if scansubs? and entry.name.match new RegExp scansubs, 'i'
+            if scansubs? and scansubs != '' and entry.name.match new RegExp scansubs, 'i'
               subs.push readAlbums path + '/' + entry.name
-            else if !ignoredirs? or not entry.name.match new RegExp ignoredirs, 'i'
+            else if !ignoredirs? or ignoredirs == '' or not entry.name.match new RegExp ignoredirs, 'i'
               album = $('<a href="#">').attr('data-path', path + '/' + entry.name).html(entry.name).click ->
                 $('#albums li').removeClass 'active'
                 $(this).parent('li').addClass 'active'


Fixed: Copy site static folder

Fixed: Copy site static folder

--- lib/Site.coffee
+++ lib/Site.coffee
@@ -25,10 +25,10 @@
   ###
   @init: (root,override) ->
     # copyFolder __dirname+"/tpl",root,override
-    files = ['config.js','main.js','main.html','web.config','package.json',
-              'static/bundle.js','static/bundle.min.js']
+    files = ['config.js','main.js','main.html','web.config','package.json']
     staticDir = root + '/static'
     fs.mkdirSync staticDir  if !fs.existsSync(staticDir)
+    copyFolder __dirname + "/tpl/static/" , staticDir
     for f in files
       copyFile __dirname + "/tpl/" + f , root + "/" + f


Explain the home screen (wow)

Explain the home screen (wow)

--- assets/javascripts/screens/home.coffee
+++ assets/javascripts/screens/home.coffee
@@ -1,3 +1,9 @@
+# Home screen
+# ===========
+#
+# Just the app's home screen. Shows a text field and when the form
+# is submitted, it takes the user to the search results list.
+
 class HomeScreen extends Tres.Screen
   className : 'home-screen'
   template  : _.template $('#home-template').html()


remove history root

remove history root

--- apps/tag/client.coffee
+++ apps/tag/client.coffee
@@ -17,4 +17,4 @@
   new TagView
     el: $ 'body'
     model: tag = new Tag TAG
-  Backbone.history.start pushState: true, root: "/tag/#{tag.id}"+  Backbone.history.start pushState: true


Before hook number of arguments error unit test.

--- test/tests.coffee
+++ test/tests.coffee
@@ -1111,20 +1111,33 @@
         it 'should support changing arguments in before hooks', (done) ->
           beforeHook = (server, username, id, args, cb) ->
             [ name , mode ] = args
-            cb(null, null, roomName2, mode)
+            cb null, null, roomName2, mode
           chatServer = new ChatService { port : port
             , enableRoomsManagement : true}
           , { 'roomCreateBefore' : beforeHook }
           , state
           socket1 = clientConnect user1
-          socket1.on 'loginConfirmed', (u, data) ->
-            sid = data.id
+          socket1.on 'loginConfirmed',  ->
             socket1.emit 'roomCreate', roomName1, true, ->
               socket1.emit 'listRooms', (error, data) ->
                 expect(error).not.ok
                 expect(data).lengthOf(1)
                 expect(data[0]).length.equal(roomName2)
                 done()
+
+        it 'should send errors if new arguments have a different length'
+        , (done) ->
+          beforeHook = (server, username, id, args, cb) ->
+            cb null, null, roomName2
+          chatServer = new ChatService { port : port
+            , enableRoomsManagement : true}
+          , { 'roomCreateBefore' : beforeHook }
+          , state
+          socket1 = clientConnect user1
+          socket1.on 'loginConfirmed', ->
+            socket1.emit 'roomCreate', roomName1, true, (error) ->
+              expect(error).ok
+              done()

         it 'should execute disconnect After and Before hooks', (done) ->
           before = false


Don't shadow request var

Don't shadow request var

--- test/test_process.coffee
+++ test/test_process.coffee
@@ -125,7 +125,7 @@

   process = createProcess "#{__dirname}/fixtures/once.ru", runOnce: true

-  request = (callback) ->
+  createRequest = (callback) ->
     process.createConnection (err, client) ->
       test.ifError err

@@ -147,7 +147,7 @@
         response.on 'end', ->
           test.same "true", body

-  async.series [request, request, request], ->
+  async.series [createRequest, createRequest, createRequest], ->
     process.quit ->
       test.done()

@@ -156,7 +156,7 @@

   process = createProcess "#{__dirname}/fixtures/once.ru"

-  request = (callback) ->
+  createRequest = (callback) ->
     process.createConnection (err, client) ->
       test.ifError err

@@ -178,10 +178,10 @@
         response.on 'end', ->
           test.same "true", body

-  request ->
+  createRequest ->
     process.runOnce = true
-    request ->
-      request ->
+    createRequest ->
+      createRequest ->
         process.quit ->
           test.done()

@@ -190,7 +190,7 @@

   process = createProcess "#{__dirname}/fixtures/once.ru", runOnce: true

-  request = (callback) ->
+  createRequest = (callback) ->
     process.createConnection (err, client) ->
       test.ifError err

@@ -212,7 +212,7 @@
         response.on 'end', ->
           test.same "true", body

-  async.parallel [request, request, request], ->
+  async.parallel [createRequest, createRequest, createRequest], ->
     process.quit ->
       test.done()


fix a glitch

fix a glitch

--- app/coffee/newentry.coffee
+++ app/coffee/newentry.coffee
@@ -80,6 +80,6 @@

   # Hide the elements in the browsers they cant be seen in
-  if window.BrowserDetect.browser is "Safari" or window.BrowserDetect.browser is "Chrome"
-    $('.typeSelection, .listSelection').hide()
-    $('.entryType').css('border', 'none')
+  #if window.BrowserDetect.browser is "Safari" or window.BrowserDetect.browser is "Chrome"
+    #$('.typeSelection, .listSelection').hide()
+    #$('.entryType').css('border', 'none')


Added some logging

Added some logging

--- source/Downloader.coffee
+++ source/Downloader.coffee
@@ -66,3 +66,4 @@
     links = $('.item').find('.play')
     title = []
     downloads = []
+    winston.info('Fetched results.')


waits and fors should be bound to self

waits and fors should be bound to self

--- test-integration/helpers/utils/wait.coffee
+++ test-integration/helpers/utils/wait.coffee
@@ -35,7 +35,7 @@
       el = find(locator)
       el

-  forMultiple: (locator, ms = 60 * 1000) ->
+  forMultiple: (locator, ms = 60 * 1000) =>
     settings =
       find: @test.driver.findElements.bind(@test.driver)
       untilLocated: selenium.until.elementsLocated
@@ -49,11 +49,11 @@
     @_for(settings)(locator, ms)

   # Waits for an element to be displayed and bumps up the timeout to be at least 60sec from now
-  for: (locator, ms = 60 * 1000) ->
+  for: (locator, ms = 60 * 1000) =>
     @_for()(locator, ms)

   # Waits for an element to be enabled and bumps up the timeout to be at least 60sec from now
-  forHidden: (locator, ms = 60 * 1000) ->
+  forHidden: (locator, ms = 60 * 1000) =>
     settings =
       untilReady: selenium.until.elementIsEnabled


fix champion.gg 404 error

fix champion.gg 404 error

fixes #145

--- lib/helpers.coffee
+++ lib/helpers.coffee
@@ -23,6 +23,7 @@
       }
       request options, (err, res, body) ->
         return step(err) if err
+        return step(new cErrors.RequestError(404)) if (res.statusCode == 404)

         if _.contains(res.headers?['content-type'], 'text/json') or _.contains(url, '.json')
           try


direct-access to model and cleanup

direct-access to model and cleanup

--- lib/base.coffee
+++ lib/base.coffee
@@ -257,14 +257,13 @@
       null

   @registerCommand: ->
-    atom.commands.add(@getCommandScope(), @getCommandName(), (event) => @run(event))
-
-  @run: (event) ->
-    vimState = getEditorState(event.target.getModel()) ? getEditorState(atom.workspace.getActiveTextEditor())
-    if vimState?
-      vimState.domEvent = event
-      # Reason: https://github.com/t9md/atom-vim-mode-plus/issues/85
-      vimState.operationStack.run(this)
-    event.stopPropagation()
+    klass = this
+    atom.commands.add @getCommandScope(), @getCommandName(), (event) ->
+      vimState = getEditorState(@getModel()) ? getEditorState(atom.workspace.getActiveTextEditor())
+      if vimState?
+        vimState.domEvent = event
+        # Reason: https://github.com/t9md/atom-vim-mode-plus/issues/85
+        vimState.operationStack.run(klass)
+      event.stopPropagation()

 module.exports = Base


Add player links

Add player links

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -46,6 +46,19 @@
   $('#new_comment').on 'ajax:success', (event) ->
     this.reset()

+  $('a[href^="#play-"]').on 'click', (event) ->
+    event.preventDefault()
+    link = $(this).attr('href')
+    time = link.replace('#play-', '')
+    min_sec = time.split(':')
+    if min_sec.length == 2
+      mins = parseInt(min_sec[0], 10)
+      secs = parseInt(min_sec[1], 10)
+      player = $(this).parents('article.post').first().find('audio')[0]
+      if player && mins >= 0 && mins < 120 && secs >=0 && secs < 60
+        player.currentTime = mins * 60 + secs
+        player.play()
+
   $(document).on 'click', '.btn-opinions-popover', (event) ->
     $this = $(this)
     if 'opened' != $this.data 'popover-status'


Correctly include JS templates

Correctly include JS templates

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -1,4 +1,5 @@
 #= require libraries
+#= require_tree ./templates
 #= require albums
 #= require comments
 #= require images


og tag

og tag

--- both/_config/seo.coffee
+++ both/_config/seo.coffee
@@ -5,5 +5,5 @@
       meta:
         description:  @Config.subtitle

-      og:
-        image: "http://manuel-schoebel.com/images/authors/manuel-schoebel.jpg"+      # og:
+      #   image: "http://manuel-schoebel.com/images/authors/manuel-schoebel.jpg"


really expose synth

really expose synth

--- app/application.coffee
+++ app/application.coffee
@@ -23,10 +23,11 @@
     @synths[name] = synth
     synth

+synth1 = null
+synth2 = null
+
 $ ->
   sound = new Sound
-  synth1 = null
-  synth2 = null

   Tone.Transport.start()


Fixed checkboxes js

Fixed checkboxes js

--- app/assets/javascripts/form/toggle.js.coffee
+++ app/assets/javascripts/form/toggle.js.coffee
@@ -40,11 +40,10 @@
   # Hide/show blocks depending on check boxes
   $(document).behave "load", "input[type='checkbox'][data-show], input[type='checkbox'][data-hide]", toggleCheckboxes
   $(document).behave "load", "input[type='radio'][data-show], input[type='radio'][data-hide]", toggleRadios
-  $(document).ready ->
-    $("input[type='radio'][data-show], input[type='radio'][data-hide]").on "change", toggleRadios
-    $("input[type='checkbox'][data-show], input[type='checkbox'][data-hide]").on "change",  toggleCheckboxes
+  $(document).on "change", "input[type='checkbox'][data-show], input[type='checkbox'][data-hide]", toggleCheckboxes
+  $(document).on "change", "input[type='radio'][data-show], input[type='radio'][data-hide]", toggleRadios
   $(document).behave "load", ".ui-dialog", ->
     $("input[type='radio'][data-show], input[type='radio'][data-hide]").on "change", toggleRadios
-    $("input[type='checkbox'][data-show], input[type='checkbox'][data-hide]").on "change",  toggleCheckboxes
+    $("input[type='checkbox'][data-show], input[type='checkbox'][data-hide]").on "change", toggleCheckboxes
   return
 ) jQuery


DeclarationTask should be a metadata task

--- app/assets/javascripts/models/task.js.coffee
+++ app/assets/javascripts/models/task.js.coffee
@@ -33,6 +33,7 @@

 ETahi.DeclarationTask = ETahi.Task.extend
   surveys: DS.hasMany('survey')
+  isMetadataTask: true

 ETahi.MessageTask = ETahi.Task.extend
   participants: DS.hasMany('user')


Remove debugger statement from a spec

Remove debugger statement from a spec

--- spec_app/spec/javascripts/up/proxy_spec.js.coffee
+++ spec_app/spec/javascripts/up/proxy_spec.js.coffee
@@ -219,7 +219,6 @@
           up.request('/path', method: 'post')
           next =>
             headers = @lastRequest().requestHeaders
-            debugger
             expect(headers['X-Requested-With']).toEqual('XMLHttpRequest')

         it 'does not overrride an existing X-Requested-With header', asyncSpec (next) ->


fix for project members

fix for project members

--- app/assets/javascripts/projects/members.js.coffee
+++ app/assets/javascripts/projects/members.js.coffee
@@ -10,8 +10,8 @@

   initSelectRole: ->
-    $("#user-search").select2
-      placeholder: "Type a username"
+    $('#user-search').select2
+      placeholder: 'Type a username'
       minimumInputLength: 2
       multiple: true
       query: (query) ->
@@ -29,8 +29,20 @@
         ) for id in ids
       formatResult: Members.userFormatResult
       formatSelection: Members.userFormatSelection
-      dropdownCssClass: "bigdrop"
+      dropdownCssClass: 'bigdrop'
       escapeMarkup: (m) -> m

-    $(".role-select").on "change", ->
-      $(this.form).submit()
+    $('.role-select').on 'change', ->
+      canSubmit = false
+
+      roles = $('.role-select')
+      for role in roles
+        if role.value == 'admin'
+          canSubmit = true
+          break
+
+      if canSubmit
+        $(this.form).submit()
+      else
+        alert('Role not updated. A project needs to have at least one admin')
+


fix load without internet (missing geocoder)

--- webapp/views/PlaceEdit.coffee
+++ webapp/views/PlaceEdit.coffee
@@ -4,8 +4,11 @@

 # geocode
 window.lastGeocodeCallback = 0
-geocoder = new google.maps.Geocoder()
-
+try
+  geocoder = new google.maps.Geocoder()
+catch err
+  console.log "Warning: could not create geocoder - location lookup will not work!"
+
 myIcon = L.icon
     iconUrl: '../../vendor/leaflet/images/my-icon.png'
     iconRetinaUrl: '../../vendor/leaflet/images/my-icon-2x.png'
@@ -122,6 +125,9 @@
     console.log "lookupAddress #{address}... (request #{geocodeCallback})"
     $('.do-lookup-address', @$el).addClass 'disabled'

+    if not geocode?
+      return alert "Sorry - cannot look up addresses (may be due to an Internet connection problem; couldn't load geocoder library)"
+
     geocoder.geocode { 'address': address}, (results, status) =>
       if geocodeCallback != window.lastGeocodeCallback
         console.log "ignore old geocode response #{geocodeCallback}"


test the bug

test the bug

--- spec/motions-spec.coffee
+++ spec/motions-spec.coffee
@@ -1596,6 +1596,13 @@
       normalModeInputKeydown('b')
       expect(editor.getText()).toBe 'abcbcabc\n'

+    it "selects character under cursor even when no movement happens", ->
+      editor.setCursorBufferPosition([0, 0])
+      keydown('d')
+      keydown('t')
+      commandModeInputKeydown('b')
+      expect(editor.getText()).toBe 'bcabcabcabc\n'
+
   describe 'the V keybinding', ->
     beforeEach ->
       editor.setText("01\n002\n0003\n00004\n000005\n")


:white_check_mark: to ensure to put cursor on non-blank char.

--- spec/motions-spec.coffee
+++ spec/motions-spec.coffee
@@ -1013,7 +1013,7 @@
             cursorBuffer: [1, 0]
           ensure '*', cursorBuffer: [3, 0]

-  describe "the H keybinding", ->
+  describe "the H, M, L keybinding", ->
     beforeEach ->
       set
         text: """
@@ -1026,77 +1026,46 @@
           7
           8
           9
-            10\n
+            10
           """
         cursor: [8, 0]
-        # spy:
-        #   obj: editor.getLastCursor(),
-        #   method: 'setScreenPosition'
-      # spyOn(editor.getLastCursor(), 'setScreenPosition')
-
-    it "moves the cursor to the non-blank-char on first row if visible", ->
-      set spy: obj: editor, method: 'getFirstVisibleScreenRow', return: 0
-      ensure 'H', cursor: [0, 2]
-
-    it "moves the cursor to the non-blank-char on first visible row plus scroll offset", ->
-      set spy: obj: editor, method: 'getFirstVisibleScreenRow', return: 2
-      ensure 'H', cursor: [4, 2]
-
-    it "respects counts", ->
-      set spy: obj: editor, method: 'getFirstVisibleScreenRow', return: 0
-      ensure '4H', cursor: [3, 0]
-
-  describe "the L keybinding", ->
-    beforeEach ->
-      set
-        text: "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
-        cursor: [8, 0]
-        spy:
-          obj: editor.getLastCursor(), method: 'setScreenPosition'
-
-    it "moves the cursor to the first row if visible", ->
-      set
-        spy:
-          obj: editor, method: 'getLastVisibleScreenRow', return: 10
-      ensure 'L',
-        called:
-          func: editor.getLastCursor().setScreenPosition
-          with: [10, 0]
-
-    it "moves the cursor to the first visible row plus offset", ->
-      set
-        spy:
-          obj: editor, method: 'getLastVisibleScreenRow', return: 6
-      ensure 'L',
-        called:
-          func: editor.getLastCursor().setScreenPosition
-          with: [4, 0]
-
-    it "respects counts", ->
-      set
-        spy:
-          obj: editor, method: 'getLastVisibleScreenRow', return: 10
-      ensure '3L',
-        called:
-          func: editor.getLastCursor().setScreenPosition
-          with: [8, 0]
-
-  describe "the M keybinding", ->
-    beforeEach ->
-      set
-        text: "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
-        cursor: [8, 0]
-        spy: [
-          {obj: editor.getLastCursor(), method: 'setScreenPosition'},
-          {obj: editor, method: 'getLastVisibleScreenRow', return: 10},
-          {obj: editor, method: 'getFirstVisibleScreenRow', return: 0},
-        ]
-
-    it "moves the cursor to the first row if visible", ->
-      ensure 'M',
-        called:
-          func: editor.getLastCursor().setScreenPosition
-          with: [5, 0]
+
+    describe "the H keybinding", ->
+      it "moves the cursor to the non-blank-char on first row if visible", ->
+        set spy: obj: editor, method: 'getFirstVisibleScreenRow', return: 0
+        ensure 'H', cursor: [0, 2]
+
+      it "moves the cursor to the non-blank-char on first visible row plus scroll offset", ->
+        set spy: obj: editor, method: 'getFirstVisibleScreenRow', return: 2
+        ensure 'H', cursor: [4, 2]
+
+      it "respects counts", ->
+        set spy: obj: editor, method: 'getFirstVisibleScreenRow', return: 0
+        ensure '4H', cursor: [3, 0]
+
+    describe "the L keybinding", ->
+      it "moves the cursor to non-blank-char on last row if visible", ->
+        set spy: obj: editor, method: 'getLastVisibleScreenRow', return: 9
+        ensure 'L', cursor: [9, 2]
+
+      it "moves the cursor to the first visible row plus offset", ->
+        set spy: obj: editor, method: 'getLastVisibleScreenRow', return: 6
+        ensure 'L', cursor: [4, 2]
+
+      it "respects counts", ->
+        set spy: obj: editor, method: 'getLastVisibleScreenRow', return: 9
+        ensure '3L', [8, 0]
+
+    describe "the M keybinding", ->
+      beforeEach ->
+        set
+          spy: [
+            {obj: editor, method: 'getFirstVisibleScreenRow', return: 0},
+            {obj: editor, method: 'getLastVisibleScreenRow',  return: 9},
+          ]
+
+      it "moves the cursor to the non-blank-char of middle of screen", ->
+        ensure 'M', cursor: [4, 2]

   describe 'the mark keybindings', ->
     beforeEach ->


Every paren ever

Every paren ever

--- spec/motions-spec.coffee
+++ spec/motions-spec.coffee
@@ -394,7 +394,7 @@

     describe "as a motion", ->
       it "moves the cursor to the specified search pattern", ->
-        keydown '/'
+        keydown('/')

         editor.commandModeInputView.editor.setText 'def'
         editor.commandModeInputView.editor.trigger 'core:confirm'
@@ -403,7 +403,7 @@

       it "loops back around", ->
         editor.setCursorBufferPosition([3, 0])
-        keydown '/'
+        keydown('/')
         editor.commandModeInputView.editor.setText 'def'
         editor.commandModeInputView.editor.trigger 'core:confirm'

@@ -411,91 +411,91 @@

       describe "repeating", ->
         beforeEach ->
-          keydown '/'
+          keydown('/')
           editor.commandModeInputView.editor.setText 'def'
           editor.commandModeInputView.editor.trigger 'core:confirm'

         describe "the n keybinding", ->
           it "repeats the last search", ->
-            keydown 'n'
+            keydown('n')
             expect(editor.getCursorBufferPosition()).toEqual [3, 0]

         describe "the N keybinding", ->
           it "repeats the last search backwards", ->
             editor.setCursorBufferPosition([0, 0])
-            keydown 'N', shift: true
+            keydown('N', shift: true)
             expect(editor.getCursorBufferPosition()).toEqual [3, 0]

       describe "composing", ->
         it "composes with operators", ->
-          keydown 'd'
-          keydown '/'
-          editor.commandModeInputView.editor.setText 'def'
-          editor.commandModeInputView.editor.trigger 'core:confirm'
+          keydown('d')
+          keydown('/')
+          editor.commandModeInputView.editor.setText('def')
+          editor.commandModeInputView.editor.trigger('core:confirm')
           expect(editor.getText()).toEqual "def\nabc\ndef\n"

         it "repeats correctly with operators", ->
-          keydown 'd'
-          keydown '/'
-          editor.commandModeInputView.editor.setText 'def'
-          editor.commandModeInputView.editor.trigger 'core:confirm'
-
-          keydown '.'
+          keydown('d')
+          keydown('/')
+          editor.commandModeInputView.editor.setText('def')
+          editor.commandModeInputView.editor.trigger('core:confirm')
+
+          keydown('.')
           expect(editor.getText()).toEqual "def\n"

     describe "when reversed as ?", ->
       it "moves the cursor backwards to the specified search pattern", ->
-        keydown '?'
-        editor.commandModeInputView.editor.setText 'def'
-        editor.commandModeInputView.editor.trigger 'core:confirm'
+        keydown('?')
+        editor.commandModeInputView.editor.setText('def')
+        editor.commandModeInputView.editor.trigger('core:confirm')
         expect(editor.getCursorBufferPosition()).toEqual [3, 0]

       describe "repeating", ->
         beforeEach ->
-          keydown '?'
-          editor.commandModeInputView.editor.setText 'def'
-          editor.commandModeInputView.editor.trigger 'core:confirm'
+          keydown('?')
+          editor.commandModeInputView.editor.setText('def')
+          editor.commandModeInputView.editor.trigger('core:confirm')

         describe 'the n keybinding', ->
           it "repeats the last search backwards", ->
             editor.setCursorBufferPosition([0, 0])
-            keydown 'n'
+            keydown('n')
             expect(editor.getCursorBufferPosition()).toEqual [3, 0]

         describe 'the N keybinding', ->
           it "repeats the last search forwards", ->
             editor.setCursorBufferPosition([0, 0])
-            keydown 'N', shift: true
+            keydown('N', shift: true)
             expect(editor.getCursorBufferPosition()).toEqual [1, 0]

     describe "using search history", ->
       beforeEach ->
-        keydown '/'
-        editor.commandModeInputView.editor.setText 'def'
-        editor.commandModeInputView.editor.trigger 'core:confirm'
+        keydown('/')
+        editor.commandModeInputView.editor.setText('def')
+        editor.commandModeInputView.editor.trigger('core:confirm')
         expect(editor.getCursorBufferPosition()).toEqual [1, 0]

-        keydown '/'
-        editor.commandModeInputView.editor.setText 'abc'
-        editor.commandModeInputView.editor.trigger 'core:confirm'
+        keydown('/')
+        editor.commandModeInputView.editor.setText('abc')
+        editor.commandModeInputView.editor.trigger('core:confirm')
         expect(editor.getCursorBufferPosition()).toEqual [2, 0]

       it "allows searching history in the search field", ->
-        keydown '/'
-        editor.commandModeInputView.editor.trigger 'core:move-up'
-        expect(editor.commandModeInputView.editor.getText()).toEqual 'abc'
-        editor.commandModeInputView.editor.trigger 'core:move-up'
-        expect(editor.commandModeInputView.editor.getText()).toEqual 'def'
-        editor.commandModeInputView.editor.trigger 'core:move-up'
-        expect(editor.commandModeInputView.editor.getText()).toEqual 'def'
+        keydown('/')
+        editor.commandModeInputView.editor.trigger('core:move-up')
+        expect(editor.commandModeInputView.editor.getText()).toEqual('abc')
+        editor.commandModeInputView.editor.trigger('core:move-up')
+        expect(editor.commandModeInputView.editor.getText()).toEqual('def')
+        editor.commandModeInputView.editor.trigger('core:move-up')
+        expect(editor.commandModeInputView.editor.getText()).toEqual('def')

       it "resets the search field to empty when scrolling back", ->
-        keydown '/'
-        editor.commandModeInputView.editor.trigger 'core:move-up'
-        expect(editor.commandModeInputView.editor.getText()).toEqual 'abc'
-        editor.commandModeInputView.editor.trigger 'core:move-up'
-        expect(editor.commandModeInputView.editor.getText()).toEqual 'def'
-        editor.commandModeInputView.editor.trigger 'core:move-down'
-        expect(editor.commandModeInputView.editor.getText()).toEqual 'abc'
-        editor.commandModeInputView.editor.trigger 'core:move-down'
+        keydown('/')
+        editor.commandModeInputView.editor.trigger('core:move-up')
+        expect(editor.commandModeInputView.editor.getText()).toEqual('abc')
+        editor.commandModeInputView.editor.trigger('core:move-up')
+        expect(editor.commandModeInputView.editor.getText()).toEqual('def')
+        editor.commandModeInputView.editor.trigger('core:move-down')
+        expect(editor.commandModeInputView.editor.getText()).toEqual('abc')
+        editor.commandModeInputView.editor.trigger('core:move-down')
         expect(editor.commandModeInputView.editor.getText()).toEqual ''


FERRY in itinerary summary

FERRY in itinerary summary

instead of very long name of the route

--- app/assets/transit/lib/models/itinerary.js.coffee
+++ app/assets/transit/lib/models/itinerary.js.coffee
@@ -3,7 +3,9 @@
 		_.pluck(_.filter(@get('legs'), (leg) -> leg.mode not in ['WALK', 'BIKE']), 'route').join(', ')

 	summaryHTML: =>
-		_.map(_.filter(@get('legs'), (leg) -> leg.mode not in ['WALK', 'BIKE']), (leg) -> "#{leg.route}").join(' ')
+		_.map(_.filter(@get('legs'), (leg) -> leg.mode not in ['WALK', 'BIKE']), (leg) ->
+			"#{if leg.mode == 'FERRY' then 'FERRY' else leg.route}"
+		).join(' ')

 	timing: =>
 		start = Transit.format_time(@get('startTime'))


only append diff

only append diff

--- app/assets/javascripts/build.coffee
+++ app/assets/javascripts/build.coffee
@@ -41,10 +41,14 @@
             dataType: "json"
             success: (build) =>
               if build.status == "running"
-                $('#build-trace code').html build.trace_html
-                $('#build-trace code').append '<i class="icon-refresh icon-spin"/>'
-                $('#build-report .results').html build.report_html
-                $('#build-report .results').append '<i class="icon-refresh icon-spin"/>'
+                previous_build_trace_html = $('#build-trace code').html()
+                build_trace_diff = build.trace_html.substr(previous_build_trace_html.length)
+                previous_results_html = $('#build-report .results').html()
+                build_result_diff = build.report_html.substr(previous_results_html.length)
+                $('#build-trace code').append(build_trace_diff)
+                $('#build-trace').append '<i class="icon-refresh icon-spin"/>' unless $('#build-trace').find('i.icon-spin')
+                $('#build-report .results').append(build_result_diff)
+                $('#build-report').append '<i class="icon-refresh icon-spin"/>' unless $('#build-report').find('i.icon-spin')
                 Build.styleResults()
                 Build.updateInfo()
                 Build.checkAutoscroll()


Added failing tests. See #6.

Added failing tests. See #6.

--- test/wordnet_test.coffee
+++ test/wordnet_test.coffee
@@ -52,6 +52,13 @@
         should.exist(results)
         results.should.be.an.instanceOf(Array)
         results.should.have.length(1)
+        done()
+
+    it 'should succeed for alter#v', (done) ->
+      wordnet.lookup 'alter#v', (results) ->
+        should.exist(results)
+        results.should.be.an.instanceOf(Array)
+        results.should.have.length(7)
         done()

@@ -204,6 +211,13 @@
         results.should.eql(['fight#v'])
         done()

+    ## Tests for #6
+    it 'should succeed for alter', (done) ->
+      wordnet.validForms 'alter', (results) ->
+        should.exist(results)
+        results.should.eql(['alter#v'])
+        done()
+
     it 'should succeed for a set of queries pushed asynchronously', (done) ->
       query = (item, callback) ->
         wordnet.validForms item, (results) ->


don't use clock state to determine closed/open/preview

--- models/sale.coffee
+++ models/sale.coffee
@@ -59,9 +59,6 @@
     else if moment().isBefore(start) or moment().isSame(start)
       'preview'

-  state: ->
-    if @has('clockState') then @get('clockState') else @get('auction_state')
-
   auctionState: ->
     @calculateAuctionState _.values(@pick('start_at', 'end_at', 'offset'))...

@@ -108,13 +105,13 @@
     @isAuction() and _.include(['preview'], @get('auction_state'))

   isOpen: ->
-    @state() is 'open'
+    @get('auction_state') is 'open'

   isPreview: ->
-    @state() is 'preview'
+    @get('auction_state') is 'preview'

   isClosed: ->
-    @state() is 'closed'
+    @get('auction_state') is 'closed'

   isRegistrationEnded: ->
     @isAuction() and moment().isAfter(@get 'registration_ends_at')


removed profiling

removed profiling

--- app/assets/javascripts/model.coffee
+++ app/assets/javascripts/model.coffee
@@ -34,9 +34,8 @@
 			mat = M4x4.translateSelf moveVector, mat

 			_.defer ->
-				console.time "test"
 				callback null, M4x4.transformPointsAffine(mat, data, output)
-				console.timeEnd "test"
+

 		else


just a few more teams

just a few more teams

--- models/team.coffee
+++ models/team.coffee
@@ -43,7 +43,7 @@
   Team.count {}, (err, count) ->
     console.log 'count checked'
     return next err if err
-    max = 305 + 1 # +1 because team fortnight labs doesn't count
+    max = 307 + 1 # +1 because team fortnight labs doesn't count
     next null, count < max, max - count

 TeamSchema.static 'uniqueName', (name, next) ->


List of published songs for me page.

List of published songs for me page.

--- app/client/js/react/pages/me.coffee
+++ app/client/js/react/pages/me.coffee
@@ -3,21 +3,30 @@
 class app.react.pages.Me

   ###*
+    @param {app.Routes} routes
+    @param {app.react.Login} login
+    @param {app.react.Touch} touch
     @param {app.user.Store} userStore
-    @param {app.react.Login} login
     @constructor
   ###
-  constructor: (userStore, login) ->
-    {div,p,img,div} = React.DOM
+  constructor: (routes, login, touch, userStore) ->
+    {div,p,img,ul,li} = React.DOM
+    {a} = touch.none 'a'

     @component = React.createClass

       render: ->
         user = userStore.user
+        publishedSongs = for id, url of userStore.publishedSongs
+          li {}, a href: routes.editSong.url(id: id), url

         div className: 'page',
           p {}, @getWelcomeMessage user.displayName
           img src: user.thirdPartyUserData.picture.data.url
+          if publishedSongs.length
+            div {},
+              p {}, 'Published songs:'
+              ul {}, publishedSongs
           div {}, login.component {}

       getWelcomeMessage: (displayName) ->


Explicitly look for output.pdf file, not any pdf

--- app/coffee/CompileController.coffee
+++ app/coffee/CompileController.coffee
@@ -24,7 +24,7 @@
 					else
 						status = "failure"
 						for file in outputFiles
-							if file.type == "pdf"
+							if file.path?.match(/output\.pdf$/)
 								status = "success"

 					timer.done()


add logging to each stage of archiving

add logging to each stage of archiving

--- app/coffee/DocArchiveManager.coffee
+++ app/coffee/DocArchiveManager.coffee
@@ -41,17 +41,22 @@
 						return callback()
 					MongoManager.getLastCompressedUpdate doc_id, (error, update) ->
 						return callback(error) if error?
+						logger.log {doc_id, project_id}, "archiving got last compressed update"
 						MongoManager.markDocHistoryAsArchiveInProgress doc_id, update, (error) ->
 							return callback(error) if error?
+							logger.log {doc_id, project_id}, "marked doc history as archive in progress"
 							MongoAWS.archiveDocHistory project_id, doc_id, update, (error) ->
 								if error?
+									logger.log {doc_id, project_id, error}, "error exporting document to S3"
 									MongoManager.clearDocHistoryAsArchiveInProgress doc_id, update, (err) ->
 										return callback(err) if err?
+										logger.log {doc_id, project_id}, "cleared archive in progress flag"
 										callback(error)
 								else
 									logger.log doc_id:doc_id, project_id:project_id, "exported document to S3"
 									MongoManager.markDocHistoryAsArchived doc_id, update, (error) ->
 										return callback(error) if error?
+										logger.log {doc_id, project_id}, "marked doc history as archived"
 										callback()

 	unArchiveAllDocsChanges: (project_id, callback = (error, docs) ->) ->


created remderSort method

created remderSort method

--- app/coffee/drm-sort/drm-sort.coffee
+++ app/coffee/drm-sort/drm-sort.coffee
@@ -10,14 +10,15 @@
             self = @

             $('.drm-sort-list').on 'click', ->
-                values = self.getValues.call @
+                that = $ @
+                listId = that.data 'list'
+                list = $ "ul##{listId}"
+                values = self.getValues.call @, list
                 direction = $(@).data 'sort'
-                self.sortValues values, direction
+                self.renderSort values, direction, list

-        getValues: ->
+        getValues: (list) ->
             that = $ @
-            listId = that.data 'list'
-            list = $ "ul##{listId}"
             listItems = list.find 'li'
             values = []

@@ -101,29 +102,26 @@
                         0

                 values = if direction is 'ascending' then values.sort _sortAsc else values.sort _sortDesc
-                console.log values

             else if type is 'integer'

                 _sortAsc = (a, b) ->
-                    parseInt a, 10 - parseInt b, 10
+                    parseInt(a, 10) - parseInt(b, 10)

                 _sortDesc = (a, b) ->
-                    parseInt b, 10 - parseInt a, 10
+                    parseInt(b, 10) - parseInt(a, 10)

                 values = if direction is 'ascending' then values.sort _sortAsc else values.sort _sortDesc
-                console.log values

             else if type is 'number'

                 _sortAsc = (a, b) ->
-                    parseFloat a - parseFloat b
+                    parseFloat(a) - parseFloat(b)

                 _sortDesc = (a, b) ->
-                    parseFloat b - parseFloat a
+                    parseFloat(b) - parseFloat(a)

                 values = if direction is 'ascending' then values.sort _sortAsc else values.sort _sortDesc
-                console.log values

             else if type is 'date'

@@ -138,7 +136,6 @@
                     b - a

                 values = if direction is 'ascending' then values.sort _sortAsc else values.sort _sortDesc
-                console.log values

             else if type is 'time'
                 _parseTime = (time) ->
@@ -160,21 +157,25 @@
                         time24 = "#{hour + 12}:#{minutes}"

                 _sortAsc = (a, b) ->
-                    a = _parseTime a
-                    b = _parseTime b
-                    a = new Date "04-22-2014 #{a}"
-                    b = new Date "04-22-2014 #{b}"
-                    a - b
+                    a = _parseTime(a)
+                    b = _parseTime(b)
+                    new Date("04-22-2014 #{a}") - new Date("04-22-2014 #{b}")

                 _sortDesc = (a, b) ->
-                    a = _parseTime a
-                    b = _parseTime b
-                    a = new Date "04-22-2014 #{a}"
-                    b = new Date "04-22-2014 #{b}"
-                    b - a
+                    a = _parseTime(a)
+                    b = _parseTime(b)
+                    new Date("04-22-2014 #{b}") - new Date("04-22-2014 #{a}")

                 values = if direction is 'ascending' then values.sort _sortAsc else values.sort _sortDesc
-                console.log values
+
+        renderSort: (values, direction, list) =>
+            values = @sortValues values, direction
+            listHtml = ''
+
+            $.each values, (key, value) ->
+                listHtml += "<li>#{value}</li>"
+
+            list.html listHtml

     new DrmSort()


Fix parsing URIs with newlines in the string

--- src/marbles/http/uri.js.coffee
+++ src/marbles/http/uri.js.coffee
@@ -7,6 +7,7 @@
     return @url unless @url
     return @url if @url.isURI

+    @url = @url.replace(/\n/g, '')
     m = @url.match(/^(https?:\/\/)?([^\/]+)?(.*)$/)
     h = m[2]?.split(':')
     @scheme = m[1] or (window.location.protocol + '//')


reverse layout check

reverse layout check

--- index.cjsx
+++ index.cjsx
@@ -660,7 +660,7 @@
           sortiePlane={@state.sortiePlane}
           enemyPlane={@state.enemyPlane}
           cols={if @state.combinedFlag == 0 then 0 else 1}
-          lay={if layout == 'horizontal' || window.tabbed == 'single' then 0 else 1}
+          lay={if layout == 'horizontal' || window.doubleTabbed then 0 else 1}
           goBack={@state.goBack}
           compactMode={@state.compactMode}
           mvpPos = {@state.mvpPos}/>


Activity: add length control for perfected feed

--- client/Social/Activity/AppController.coffee
+++ client/Social/Activity/AppController.coffee
@@ -271,7 +271,7 @@
         # if current user is exempt, fetch from db, not from cache
         and not KD.whoami().isExempt
       prefetchedActivity = KD.prefetchedFeeds["activity.main"]
-      if prefetchedActivity and ('activities.main' not in USEDFEEDS)
+      if prefetchedActivity and prefetchedActivity.length > 0 and ('activities.main' not in USEDFEEDS)
         log "exhausting feed:", "activity.main"
         USEDFEEDS.push 'activities.main'
         # update this function


Add gate logic

Add gate logic

--- client/main.coffee
+++ client/main.coffee
@@ -31,6 +31,10 @@
   Session.set 'currentPartyName', false
   Session.set 'currentPartyTime', false
   Session.set 'currentGuestId', false
+  Session.set 'currentGateNumber', 1
+  Session.set 'choseCorrectOption', false
+  Session.set 'choseWrongOption', false
+  Session.set 'disableOptions', false

 # Parties
@@ -98,6 +102,15 @@
       throw err if err
       Session.set 'myGuestId', id

+Template.guestItem.events
+  'click input.check-in-button': (e, template) ->
+    e.preventDefault()
+    Guests.update
+      _id: template.data._id
+    ,
+      $set:
+        check: true
+

 # Invite

@@ -118,11 +131,26 @@
       $set:
         rsvp: true

-Template.guestItem.events
-  'click input.check-in-button': (e, template) ->
-    e.preventDefault()
-    Guests.update
-      _id: template.data._id
-    ,
-      $set:
-        check: true+Template.gate.number = ->
+  Session.get 'currentGateNumber'
+
+Template.gate.events
+  'click .advance-gate-button': (e) ->
+    # Reset
+    Session.set 'choseCorrectOption', false
+    Session.set 'choseWrongOption', false
+    Session.set 'disableOptions', false
+
+    current = Session.get 'currentGateNumber'
+    next = current + 1
+    $('.gate').hide()
+    $('.gate [name=\'gate-' + next + '\']').show()
+    Session.set 'currentGateNumber', next
+
+  'click .correct-option': (e) ->
+    Session.set 'choseCorrectOption', true
+    Session.set 'disableOptions', true
+
+  'click .wrong-option': (e) ->
+    Session.set 'choseWrongOption', true
+    Session.set 'disableOptions', true


point

point

--- src/point.coffee
+++ src/point.coffee
@@ -260,7 +260,6 @@

     @name scale$
     @methodOf Point#
-
     @param {Number} scalar The amount to scale this point by.
     @returns {Point} this * scalar.
     ###


Fix missing tooltip on some cut off text

--- resources/assets/coffee/_classes/tooltip-default.coffee
+++ resources/assets/coffee/_classes/tooltip-default.coffee
@@ -4,7 +4,7 @@
 class @TooltipDefault
   constructor: ->
     $(document).on 'mouseover touchstart', '[title]:not(iframe)', @onMouseOver
-    $(document).on 'mouseenter touchstart', '.u-ellipsis-overflow, .u-ellipsis-overflow-desktop', @autoAddTooltip
+    $(document).on 'mouseenter touchstart', '.u-ellipsis-overflow, .u-ellipsis-overflow-desktop, .u-ellipsis-pre-overflow', @autoAddTooltip
     $(document).on 'turbolinks:before-cache', @rollback


Set telementry consent to "no" for atom

Set telementry consent to "no" for atom

--- .atom/config.cson
+++ .atom/config.cson
@@ -1,5 +1,6 @@
 "*":
   core:
+    telemetryConsent: "no"
     themes: [
       "one-light-ui"
       "solarized-dark-syntax"


Fix á villu sem birti "Translator" þótt það væri ekki skilgreint

--- app/scripts/widgets.coffee
+++ app/scripts/widgets.coffee
@@ -115,7 +115,8 @@
         return [posItems, structItems]

     renderItem: (key, value, attrs, wordData, sentenceData, tokens) ->
-        if attrs.label and value
+        console.log attrs.label, value, attrs.renderItem
+        if (attrs.label and value) and value != "|" and value != ""
             output = $("
:
")
         else
             output = $("

")


Fix f'rate off-by-one

Fix f'rate off-by-one

Test with one-character f'rate inputs. f'rate a, f'rate b, etc.

--- modules/rng.coffee
+++ modules/rng.coffee
@@ -51,10 +51,10 @@
     # Not actually random but ¯\_(ツ)_/¯
     @registerCommand 'rate', (msg, args, d)=>
       return unless args and d.data.allowRNG
+      hash = 0
       for i in [0 ... args.length]
         chr   = args.charCodeAt(i)
         hash  = ((hash << 5) - hash) + chr
-        hash |= 0
       rate = Math.ceil(((hash & 0xFF) / 255) * 10)
       msg.reply "I'd give #{args} a #{rate}/10."


Rename to D3Chart::defineBaseElement from ::defineRootElement

--- src/chart-d3-chart.coffee
+++ src/chart-d3-chart.coffee
@@ -17,7 +17,7 @@

   constructor: (@selectors, @data, @options, margin) ->
     margin or= top: 0, right: 0, bottom: 0, left: 0
-    @defineRootElement(
+    @defineBaseElement(
       @getRootElement(),
       @getRootElementWidth(),
       @getRootElementHeight(),
@@ -34,7 +34,7 @@
     [ '#dcdcdc', '#97bbcd', '#ed91a2', '#7abf8a', '#f1af31' ]

   # http://bl.ocks.org/mbostock/3019563
-  defineRootElement: (element, width, height, margin) ->
+  defineBaseElement: (element, width, height, margin) ->
     @width = width - margin.left - margin.right
     @height = height - margin.top - margin.bottom
     @getRootElement()


Adds sample to javascript driver.

Adds sample to javascript driver.

--- drivers/javascript/src/ast.coffee
+++ drivers/javascript/src/ast.coffee
@@ -91,6 +91,7 @@
         new GroupBy {}, @, attrs, collector

     info: ar () -> new Info {}, @
+    sample: ar (count) -> new Sample {}, @, count

 class DatumTerm extends RDBVal
     args: []
@@ -451,6 +452,10 @@
     tt: Term.TermType.INFO
     mt: 'info'

+class Sample extends RDBOp
+    tt: Term.TermType.SAMPLE
+    mt: 'sample'
+
 class Update extends RDBOp
     tt: Term.TermType.UPDATE
     mt: 'update'


Client library fix

Client library fix

--- Client/src/library/clientLibrary.coffee
+++ Client/src/library/clientLibrary.coffee
@@ -100,7 +100,7 @@
                 "id": id
             })
         else
-            this.sendMessage("reportBackWhenBrickMovedToAnyOfPositions", {
+            this.sendMessage("reportBackWhenBrickMovedToPosition", {
                 "position": position,
                 "validPositions": validPositions
             })


Tests:Environments: Added deleteDomain test.

--- tests/src/environments/environments.coffee
+++ tests/src/environments/environments.coffee
@@ -145,3 +145,19 @@
     browser.end()

+  deleteDomain: (browser) ->
+
+    domainName = addDomain(browser)
+
+    domainItem = '.domains-view .kdlistitemview-domain:last-child'
+    loader     = '.domains-view .in-progress.kdloader'
+
+    browser
+      .moveToElement             domainItem, 10, 10
+      .click                     domainItem + ' span.remove-domain'
+      .waitForElementVisible     loader, 10000
+      .waitForElementNotVisible  loader, 20000
+      .getText                   domainItem, (result) =>
+        assert.notEqual          result.value, domainName # Assertion
+
+        browser.end()


Use in-path 7z on AppVeyor, tidy-up publish

--- build/tasks/publish-build-task.coffee
+++ build/tasks/publish-build-task.coffee
@@ -11,6 +11,7 @@
 grunt = null

 token = process.env.ATOM_ACCESS_TOKEN
+repo = process.env.ATOM_REPO ? 'atom/atom'
 defaultHeaders =
   Authorization: "token #{token}"
   'User-Agent': 'Atom'
@@ -119,7 +120,8 @@
 zipAssets = (buildDir, assets, callback) ->
   zip = (directory, sourcePath, assetName, callback) ->
     if process.platform is 'win32'
-      zipCommand = "C:/psmodules/7z.exe a -r #{assetName} \"#{sourcePath}\""
+      sevenZipPath = if process.env.JANKY_SHA1? then "C:/psmodules/" else ""
+      zipCommand = "#{sevenZipPath}7z.exe a -r \"#{assetName}\" \"#{sourcePath}\""
     else
       zipCommand = "zip -r --symlinks '#{assetName}' '#{sourcePath}'"
     options = {cwd: directory, maxBuffer: Infinity}
@@ -134,10 +136,10 @@
   async.parallel(tasks, callback)

 getAtomDraftRelease = (isPrerelease, branchName, callback) ->
-  atomRepo = new GitHub({repo: 'atom/atom', token})
+  atomRepo = new GitHub({repo: repo, token})
   atomRepo.getReleases {prerelease: isPrerelease}, (error, releases=[]) ->
     if error?
-      logError('Fetching atom/atom releases failed', error, releases)
+      logError("Fetching #{repo} #{if isPrerelease then "pre" else "" }releases failed", error, releases)
       callback(error)
     else
       [firstDraft] = releases.filter ({draft}) -> draft
@@ -160,7 +162,7 @@
 createAtomDraftRelease = (isPrerelease, branchName, callback) ->
   {version} = require('../../package.json')
   options =
-    uri: 'https://api.github.com/repos/atom/atom/releases'
+    uri: "https://api.github.com/repos/#{repo}/releases"
     method: 'POST'
     headers: defaultHeaders
     json:
@@ -177,7 +179,7 @@

   request options, (error, response, body='') ->
     if error? or response.statusCode isnt 201
-      logError("Creating atom/atom draft release failed", error, body)
+      logError("Creating #{repo} draft release failed", error, body)
       callback(error ? new Error(response.statusCode))
     else
       callback(null, body)


SocialController: Add private message search function call

--- client/Main/socialapicontroller.coffee
+++ client/Main/socialapicontroller.coffee
@@ -380,6 +380,11 @@
       validateOptionsWith     : ['body', 'channelId']
       mapperFn                : mapPrivateMessages

+    search               : messageRequesterFn
+      fnName             : 'search'
+      validateOptionsWith: ['name']
+      mapperFn           : mapPrivateMessages
+
     fetchPrivateMessages : messageRequesterFn
       fnName             : 'fetchPrivateMessages'
       mapperFn           : mapPrivateMessages


snapshots: Added custom Kloud.coffee method for deleteSnapshot

To default the provider to `koding`, in the event of the source machine
not existing.

--- client/app/lib/kite/kites/kloud.coffee
+++ client/app/lib/kite/kites/kloud.coffee
@@ -55,7 +55,6 @@

     # Snapshots
     createSnapshot  : 'createSnapshot'
-    deleteSnapshot  : 'deleteSnapshot'

     # Stack, Teams, Credentials related methods
     bootstrap       : 'bootstrap'
@@ -64,7 +63,6 @@
     checkCredential : 'authenticate'

-
   constructor: (options) ->
     super options

@@ -72,6 +70,7 @@
     @needsRequest   = kd.utils.dict()

     @_reconnectedOnce = no
+

   # first info request sends message to kite requesting info
   # subsequent info requests while the first request is pending
@@ -182,3 +181,34 @@

         kd.warn '[kloud:info] failed, sending current state back:', { currentState, err }
         @resolveRequestingInfos machineId, State: currentState
+
+
+  ###*
+   * Delete the given snapshot.
+   *
+   * Note that we're using a custom method here (rather than @createMethod)
+   * to default the provider to Koding, as is needed for Machine's that
+   * no longer exist. They don't have a provider, because they don't exist.
+   *
+   * @param {Object} payload
+   * @param {String} payload.machineId - The machine that created the snapshot
+   * @param {String} payload.snapshotId - The snapshotId to delete.
+  ###
+  deleteSnapshot: (payload) ->
+
+    if payload?.machineId?
+
+      provider = getProvider payload.machineId
+      provider = 'koding'  unless provider
+
+      if provider not in SUPPORTED_PROVIDERS
+        # machine provider is not supported by kloud #{payload.machineId}
+        return Promise.reject
+          name    : 'NotSupported'
+          message : 'Operation is not supported for this VM'
+
+      payload.provider = provider
+
+    @tell 'deleteSnapshot', payload
+
+


Remove extra newline in progress reporting

--- src/quest.coffee
+++ src/quest.coffee
@@ -276,7 +276,7 @@
     count = queries.length
     for i, query of queries
       counter = parseInt(i)
-      console.log "\nNow executing #{counter+1} of #{count}\n"
+      console.log "\nNow executing #{counter+1} of #{count}"
       console.log "\n#{query}\n".green
       if cb?
         @client.query(query, params, cb)


:memo: improves document consistency

:memo: improves document consistency

--- src/range.coffee
+++ src/range.coffee
@@ -83,7 +83,7 @@

   # Public: Call this with the result of {Range::serialize} to construct a new Range.
   #
-  # * `array` {array} of params to pass to the {::constructor}
+  # * `array` {Array} of params to pass to the {::constructor}
   @deserialize: (array) ->
     if Array.isArray(array)
       new this(array[0], array[1])


Remove misleading log line about lock value

--- services/document-updater/app/coffee/LockManager.coffee
+++ services/document-updater/app/coffee/LockManager.coffee
@@ -35,7 +35,7 @@
 				callback err, true, lockValue
 			else
 				metrics.inc "doc-blocking"
-				logger.log {doc_id, lockValue}, "doc is locked"
+				logger.log {doc_id}, "doc is locked"
 				callback err, false

 	getLock: (doc_id, callback = (error) ->) ->


don't try to append to packs when using the old op code

--- services/track-changes/app/coffee/UpdatesManager.coffee
+++ services/track-changes/app/coffee/UpdatesManager.coffee
@@ -50,6 +50,7 @@
 			if temporary and (not lastCompressedUpdate? or lastCompressedUpdate.pack?) # handle pack append as a special case
 				UpdatesManager._updatePack project_id, doc_id, rawUpdates, temporary, lastCompressedUpdate, lastVersion, callback
 			else #use the existing op code
+				lastCompressedUpdate = null if lastCompressedUpdate?.pack? # can't handle packs with op code
 				UpdatesManager._updateOp project_id, doc_id, rawUpdates, temporary, lastCompressedUpdate, lastVersion, callback

 	_updatePack: (project_id, doc_id, rawUpdates, temporary, lastCompressedUpdate, lastVersion, callback) ->


fixes #85

fixes #85

--- lib/motions.coffee
+++ lib/motions.coffee
@@ -12,6 +12,8 @@

   select: (count=1) ->
     _.times(count, -> true)
+
+  isLinewise: -> @editor.mode == 'visual' and @editor.submode == 'linewise'

 class SelectLeft extends Motion
   execute: (count=1) ->


ensure that command response is a string type

--- src/relay.coffee
+++ src/relay.coffee
@@ -139,7 +139,7 @@

   # Returns a decrypt promise or direct response data
   _processResponse: (d, mbx, cmd, params)->
-    datain = @_processData d
+    datain = @_processData String(d)

     if cmd is 'upload'
       unless datain.length is 1 and datain[0].length is Config.RELAY_TOKEN_B64
@@ -151,7 +151,7 @@
       unless datain.length is 1
         throw new Error("#{@url} - #{cmd}: Bad response")
       return parseInt(datain[0])
-
+
     # rest of commands
     unless datain.length is 2
       throw new Error("#{@url} - #{cmd}: Bad response")


Fixed: reordering should be done based on baseCollection

--- client/app/views/task_list_view.coffee
+++ client/app/views/task_list_view.coffee
@@ -130,7 +130,7 @@
         previousModel = @collection.at previousIndex

         if previousIndex >= 0
-            @views.findByModel(previousModel).$el.find('input').focus()
+            @views.findByModel(previousModel).setFocus()
         else
             @taskForm.$el.find('input').focus()

@@ -144,16 +144,16 @@
             nextModel = @collection.at nextIndex

         if nextIndex < @views.length
-            @views.findByModel(nextModel).$el.find('input').focus()
+            @views.findByModel(nextModel).setFocus()

     onMoveUp: (cid, toFocus = null) ->
         currentModel = @views.findByModelCid(cid).model
-        previousIndex = @collection.indexOf(currentModel) - 1
-        previous = @collection.at previousIndex
+        previousIndex = @baseCollection.indexOf(currentModel) - 1
+        previous = @baseCollection.at previousIndex

         if previousIndex >= 1
             newOrder = null
-            newPrevious = @collection.at previousIndex - 1
+            newPrevious = @baseCollection.at previousIndex - 1
             newOrder = @baseCollection.getNewOrder newPrevious, previous
         else if previousIndex is 0
             newOrder = @baseCollection.getNewOrder null, previous
@@ -169,8 +169,8 @@

     onMoveDown: (cid) ->
         currentModel = @views.findByModelCid(cid).model
-        nextIndex = @collection.indexOf(currentModel) + 1
-        nextModel = @collection.at nextIndex
+        nextIndex = @baseCollection.indexOf(currentModel) + 1
+        nextModel = @baseCollection.at nextIndex

         # moving down is moving up the next element
         if nextModel?


Added support for "xOpenedLabel", "xClosedLabel" extensions on UniPiDigitalInput

--- device-config-schema.coffee
+++ device-config-schema.coffee
@@ -36,7 +36,7 @@
     title: "UniPi Digital Input"
     description: "UniPi Digital Input"
     type: "object"
-    extensions: ["xLink"]
+    extensions: ["xLink", "xOpenedLabel", "xClosedLabel"]
     properties:
       circuit:
         description: "The Digital Input circuit id"


Use superagent instead on client

Use superagent instead on client

--- client/apps/queue/client/client.coffee
+++ client/apps/queue/client/client.coffee
@@ -9,8 +9,7 @@
 ArticleList = require '../../../components/article_list/index.coffee'
 query = require '../query.coffee'
 { API_URL } = require('sharify').data
-Lokka = require('lokka')
-Transport = require('lokka-transport-http')
+request = require 'superagent'

 module.exports.QueueView = QueueView = React.createClass

@@ -19,12 +18,6 @@
     queuedArticles: @props.queuedArticles or []
     scheduledArticles: @props.scheduledArticles or []
     feed: @props.feed or 'scheduled'
-
-  componentDidMount: ->
-    headers =
-      'X-Access-Token': sd.USER.get('access_token')
-    @client = new Lokka
-      transport: new Transport(API_URL + '/graphql', {headers})

   saveSelected: (data, isQueued) ->
     article = new Article
@@ -56,24 +49,32 @@

   setFeed: (type) ->
     @setState feed: type
-    # @fetchFeed()
+    @fetchFeed type

-  # fetchFeed: ->
-  #   @client.query(query "#{@state.feed}: true, published: true")
-  #     .then (result) =>
-  #       return if err or not result.body?.data
-  #       if @state.feed is 'scheduled'
-  #         @setState scheduledArticles: result.body.data.articles
-  #       else
-  #         @setState queuedArticles: result.body.data.articles
-  #         @fetchLatest()
+  fetchFeed: (type) ->
+    published = type in ['daily_email', 'weekly_email']
+    feedQuery = query "#{type}: true, published: #{published}, channel_id: \"#{sd.CURRENT_CHANNEL.id}\""
+    request
+      .post API_URL + '/graphql'
+      .set 'X-Access-Token', sd.USER?.access_token
+      .send query: feedQuery
+      .end (err, res) =>
+        return if err or not res.body?.data
+        if type is 'scheduled'
+          @setState scheduledArticles: res.body.data.articles
+        else
+          @setState queuedArticles: res.body.data.articles
+          @fetchLatest()

-  # fetchLatest: ->
-  #   latestQuery = query "channel_id: \"#{sd.CURRENT_CHANNEL.id}\", published: true, sort: \"-published_at\", daily_email: false"
-  #   @client.query(latestQuery)
-  #     .then (result) =>
-  #       return if err or not result.body?.data
-  #       @setState publishedArticles: result.body.data.articles
+  fetchLatest: ->
+    latestQuery = query "channel_id: \"#{sd.CURRENT_CHANNEL.id}\", published: true, sort: \"-published_at\", daily_email: false"
+    request
+      .post API_URL + '/graphql'
+      .set 'X-Access-Token', sd.USER?.access_token
+      .send query: latestQuery
+      .end (err, res) =>
+        return if err or not res.body?.data
+        @setState publishedArticles: res.body.data.articles

   render: ->
     div {


remove old, obsolete test

remove old, obsolete test

--- spec/javascripts/suite/controller_select_spec.js.coffee
+++ spec/javascripts/suite/controller_select_spec.js.coffee
@@ -1,24 +0,0 @@
-#= require "jquery"
-#= require "jax/controller-select"
-
-describe "The select box in the dev suite runtime", ->
-  select = null
-
-  beforeEach ->
-    Jax.routes.clear()
-    Jax.views.push 'welcome/index', -> 1
-    Jax.Controller.create "Welcome", index: -> 1
-    select = document.createElement "select"
-    _controller_select_fill select
-
-  it "should contain the 'Welcome' controller", ->
-    expect(select.options[0].value).toEqual("welcome")
-
-  describe "clicked", ->
-    beforeEach ->
-      select.webgl_context = SPEC_CONTEXT
-      select.selectedIndex = 0
-      $(select).trigger("change");
-
-    it "should redirect to the selected controller", ->
-      expect(SPEC_CONTEXT.current_controller.getControllerName()).toEqual("Welcome")


Added missing import (index file template).

--- app/templates/index.coffee
+++ app/templates/index.coffee
@@ -5,6 +5,7 @@
 Security = require "./modules/Security"
 Log = require "./modules/Log"
 Resources = require "./modules/Resources"
+User = require "./modules/User"

 mongoose.connect config.mongoUrl, (error) ->
 	Log.error error if error


fixed the missing include

fixed the missing include

--- client/includes.coffee
+++ client/includes.coffee
@@ -714,6 +714,7 @@
   "app/Applications/Account.kdapplication/account/accSettingsDevRepos.coffee",
   "app/Applications/Account.kdapplication/account/accSettingsDevSshKeys.coffee",
   "app/Applications/Account.kdapplication/account/accSettingsDevKodingKeys.coffee",
+  "app/Applications/Account.kdapplication/account/accSettingsPersReferralSystem.coffee",

   "app/Applications/Account.kdapplication/account/accSettingsSubscriptions.coffee",
   "app/Applications/Account.kdapplication/account/accSettingsPaymentHistory.coffee",


fix how does bidding work dialog on bid page

--- apps/auction/client/registration_form.coffee
+++ apps/auction/client/registration_form.coffee
@@ -4,6 +4,7 @@
 Marketplace        = require '../../../models/marketplace.coffee'
 CurrentUser        = require '../../../models/current_user.coffee'
 ErrorHandlingForm  = require('../../../components/credit_card/client/error_handling_form.coffee')
+ModalPageView      = require '../../../components/modal/page.coffee'

 { SESSION_ID } = require('sharify').data

@@ -13,12 +14,19 @@

   events:
     'click .registration-form-content .avant-garde-button' : 'onSubmit'
+    'click .bidding-question' : 'showBiddingDialog'

   initialize: (options) ->
     @success = options.success
     @currentUser = CurrentUser.orNull()
     @$submit = @$('.registration-form-content .avant-garde-button')
     @setUpFields()
+
+  showBiddingDialog: (e) ->
+    e.preventDefault()
+    new ModalPageView
+      width  : '700px'
+      pageId : 'auction-info'

   setUpFields: ->
     @fields =


Remove unused code.

Remove unused code.

--- client/controllers/incidentForm.coffee
+++ client/controllers/incidentForm.coffee
@@ -9,8 +9,7 @@
     if @incidentData.url
       @incidentData.articleSource = _.findWhere(@data.articles, {
         url: @incidentData.url[0]
-      })?._id
-    @incidentData.dateReported = @incidentData.date
+      })?._id
     if @incidentData.cases
       @incidentType.set("cases")
     else if @incidentData.deaths
@@ -27,7 +26,7 @@
 Template.incidentForm.helpers
   incidentData: ->
     Template.instance().incidentData
-  incidentDate: ->
+  incidentDate: ->
     moment(Template.instance().data.incident.date).format('MM/DD/YYYY')
   incidentStatus: ->
     "#{Template.instance().incidentData.status}": true


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/active_bounds.coffee
+++ src/active_bounds.coffee
@@ -18,7 +18,9 @@
     bullet2 = GameObject
       x: 50
       y: 50
-      width:
+      width: 30
+      height: 20
+

 ActiveBounds module
 @name ActiveBounds


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/active_bounds.coffee
+++ src/active_bounds.coffee
@@ -8,6 +8,7 @@
       y: 50
       width: 20
       height: 20
+      velocity: Point()

     player.include ActiveBounds


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/active_bounds.coffee
+++ src/active_bounds.coffee
@@ -13,9 +13,10 @@
     bullet.include ActiveBounds

     # => Now the bullet will be removed when it
-         goes outside of the
-        game bounds.
+         goes outside of the game bounds.

+
+
 ActiveBounds module
 @name ActiveBounds
 @module


[IMPAC-855] - Include code review suggestions

--- src/components/widgets-settings/forecast-payroll/forecast-payroll.directive.coffee
+++ src/components/widgets-settings/forecast-payroll/forecast-payroll.directive.coffee
@@ -1,14 +1,14 @@
 module = angular.module('impac.components.widgets-settings.forecast-payroll',[])
-module.controller('SettingForecastPayrollCtrl', ($scope, $log, ImpacDashboardsSvc, ImpacMainSvc, ImpacWidgetsSvc) ->
+module.controller('SettingForecastPayrollCtrl', ($scope, ImpacDashboardsSvc) ->

   w = $scope.parentWidget
-  w.selectedForecastPayroll = false
+  $scope.selectedForecastPayroll = false

   $scope.toggleForecastPayroll = ->
-    w.selectedForecastPayroll = !w.selectedForecastPayroll
+    $scope.selectedForecastPayroll = !$scope.selectedForecastPayroll

   $scope.isToggleForecastPayroll = ->
-    return w.selectedForecastPayroll
+    return $scope.selectedForecastPayroll

   # What will be passed to parentWidget
   setting = {}
@@ -21,12 +21,12 @@
       (config) ->
         currentDashboard = config.currentDashboard
         return unless w.metadata? && w.metadata.forecast_payroll?
-        w.selectedForecastPayroll = w.metadata.forecast_payroll
+        $scope.selectedForecastPayroll = w.metadata.forecast_payroll
         setting.isInitialized = true
     )

   setting.toMetadata = ->
-    return { forecast_payroll: w.selectedForecastPayroll }
+    return { forecast_payroll: $scope.selectedForecastPayroll }

   w.settings.push(setting)


adding functionalities for leaflet in nmis.coffee

--- dashboard/static/coffee/nmis.coffee
+++ dashboard/static/coffee/nmis.coffee
@@ -984,7 +984,7 @@
       $elem = $(eselector).css width: 680, height: 476, position: 'absolute'
       launcher = NMIS.loadOpenLayers()
       launcher.done ()->
-        OpenLayers._getScriptLocation = ()-> NMIS.settings.openLayersRoot
+        OpenLayers._getScriptLocation = ()-> NMIS.settings.openLayersRoot
         $(".map-loading-message").hide()
         elem = $elem.get(0)
         mapId = "nmis-ol-country-map"
@@ -1761,6 +1761,7 @@
     all: all
     validate: validate
     clear: clear
+
 # begin c_launch_open_layers.coffee
 do ->
   NMIS.loadGoogleMaps = do ->
@@ -1783,6 +1784,10 @@

   NMIS.loadOpenLayers = (url)->
     url = "#{NMIS.settings.openLayersRoot}OpenLayers.js" if !url and NMIS.settings.openLayersRoot
+    $.ajax url: url, dataType: "script", cache: false
+
+  NMIS.loadLeaflet = (url)->
+    url = "#{NMIS.settings.leafletRoot}leaflet.js" if !url and NMIS.settings.leafletRoot
     $.ajax url: url, dataType: "script", cache: false

   NMIS.loadGmapsAndOpenlayers = do ->
@@ -1797,6 +1802,21 @@
           olLoad.done (ol)->
             launchDfd.resolve()
           olLoad.fail (o, err, message)-> launchDfd.reject o, err, message
+        gmLoad.fail (o, err, message)-> launchDfd.reject o, err, message
+      launchDfd.promise()
+
+  NMIS.loadGmapsAndLeaflet = do ->
+    launchDfd = $.Deferred()
+    scriptsStarted = false
+    () ->
+      unless scriptsStarted
+        scriptsStarted = true
+        gmLoad = NMIS.loadGoogleMaps()
+        gmLoad.done (gmaps)->
+          llLoad = NMIS.loadLeaflet()
+          llLoad.done (ol)->
+            launchDfd.resolve()
+          lllLoad.fail (l, err, message)-> launchDfd.reject l, err, message
         gmLoad.fail (o, err, message)-> launchDfd.reject o, err, message
       launchDfd.promise()

@@ -1906,6 +1926,114 @@
           launchDfd.reject o, err, message

       launchDfd.promise()
+
+  NMIS.launchLeaflet = do ->
+    launchDfd = $.Deferred()
+
+    scriptsStarted = false
+    scriptsFinished = false
+    mapElem = undefined
+    opts = undefined
+    context = {}
+    loadingMessageElement = false
+    defaultOpts =
+      elem: "#map"
+      centroid:
+        lat: 0.000068698255561324
+        lng: 0.000083908685869343
+
+      llImgPath: "/static/leaflet/images/"
+      tileUrl: "http://b.tiles.mapbox.com/modilabs/"
+      layers: [["Nigeria", "nigeria_base"]]
+      overlays: []
+      defaultLayer: "google"
+      layerSwitcher: true
+      loadingElem: false
+      loadingMessage: "Please be patient while this map loads..."
+      zoom: 6
+      maxExtent: [-20037500, -20037500, 20037500, 20037500]
+      restrictedExtent: [-4783.9396188051, 463514.13943762, 1707405.4936624, 1625356.9691642]
+
+    scriptsAreLoaded = ->
+      ifDefined = (str) ->
+        if str is "" or str is `undefined`
+          `undefined`
+        else
+          str
+      loadingMessageElement.hide()  unless not loadingMessageElement
+      OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3
+      OpenLayers.ImgPath = opts.olImgPath
+      ob = opts.maxExtent
+      re = opts.restrictedExtent
+      options =
+        projection: new OpenLayers.Projection("EPSG:900913")
+        displayProjection: new OpenLayers.Projection("EPSG:4326")
+        units: "m"
+        maxResolution: 156543.0339
+        restrictedExtent: new OpenLayers.Bounds(re[0], re[1], re[2], re[3])
+        maxExtent: new OpenLayers.Bounds(ob[0], ob[1], ob[2], ob[3])
+
+      mapId = mapElem.get(0).id
+      mapserver = opts.tileUrl
+      mapLayerArray = []
+      context.mapLayers = {}
+      $.each opts.overlays, (k, ldata) ->
+        ml = new OpenLayers.Layer.TMS(ldata[0], [mapserver],
+          layername: ldata[1]
+          type: "png"
+          transparent: "true"
+          isBaseLayer: false
+        )
+        mapLayerArray.push ml
+        context.mapLayers[ldata[1]] = ml
+
+      $.each opts.layers, (k, ldata) ->
+        ml = new OpenLayers.Layer.TMS(ldata[0], [mapserver],
+          layername: ldata[1]
+          type: "png"
+        )
+        mapLayerArray.push ml
+        context.mapLayers[ldata[1]] = ml
+
+      context.waxLayerDict = {}
+      context.activeWax
+      mapId = mapElem.get(0).id = "-openlayers-map-elem"  unless mapId
+      context.map = new OpenLayers.Map(mapId, options)
+      window.__map = context.map
+      googleSat = new OpenLayers.Layer.Google("Google",
+        type: "satellite"
+      )
+      googleMap = new OpenLayers.Layer.Google("Roads",
+        type: "roadmap"
+      )
+      mapLayerArray.push googleSat, googleMap
+      context.map.addLayers mapLayerArray
+      context.map.setBaseLayer googleSat  if opts.defaultLayer is "google"
+      context.map.addControl new OpenLayers.Control.LayerSwitcher()  if opts.layerSwitcher
+      scriptsFinished = true
+
+    # the launch function is returned
+    launch = (_opts) ->
+      opts = $.extend({}, defaultOpts, _opts)  if opts is `undefined`
+      mapElem = $(opts.elem)  if mapElem is `undefined`
+      loadingMessageElement = $(opts.loadingElem).text(opts.loadingMessage).show()  if !!opts.loadingElem and !!opts.loadingMessage
+      unless scriptsStarted
+        scriptsStarted = true
+        gmLoad = NMIS.loadGoogleMaps()
+        gmLoad.done (gmaps)->
+          olLoad = NMIS.loadOpenLayers()
+          olLoad.done (ol)->
+            scriptsAreLoaded()
+            launchDfd.resolve()
+
+          olLoad.fail (o, err, message)->
+            launchDfd.reject o, err, message
+
+        gmLoad.fail (o, err, message)->
+          launchDfd.reject o, err, message
+
+      launchDfd.promise()
+
 # begin c_variables.coffee
 do ->
   variablesById = {}
@@ -2793,6 +2921,7 @@

   NMIS.settings =
     openLayersRoot: "/static/openlayers/"
+    leafletRoot: "/static/leaflet/"
     pathToMapIcons: "/static/images"

   NMIS.url_root = do ->


minimal changes

minimal changes

--- lib/appHelper.coffee
+++ lib/appHelper.coffee
@@ -81,11 +81,12 @@
   ###
   @newBase: (dir, options, cb) =>
     args = Args([
-      {dir    : Args.STRING   | Args.Optional, _default: "#{process.cwd()}"}
-      {options: Args.OBJECT   | Args.Optional, _default: OPTIONS           }
-      {cb     : Args.FUNCTION | Args.Optional, _default: undefined         }
-    ], arguments)
-    @_newTemplate(args.dir, args.options, TEMPLATE.BASE, args.cb)
+      {dir  : Args.STRING   | Args.Optional, _default: "#{process.cwd()}"}
+      {opts : Args.OBJECT   | Args.Optional, _default: OPTIONS           }
+      {cb   : Args.FUNCTION | Args.Optional, _default: undefined         }
+    ], arguments)
+
+    @_newTemplate(args.dir, args.opts, TEMPLATE.BASE, args.cb)

@@ -100,11 +101,12 @@
   ###
   @newModule: (dir, options, cb) =>
     args = Args([
-      {dir    : Args.STRING   | Args.Optional, _default: "#{process.cwd()}"}
-      {options: Args.OBJECT   | Args.Optional, _default: OPTIONS           }
-      {cb     : Args.FUNCTION | Args.Optional, _default: undefined         }
-    ], arguments)
-    @_newTemplate(args.dir, args.options, TEMPLATE.MODULE, args.cb)
+      {dir  : Args.STRING   | Args.Optional, _default: "#{process.cwd()}"}
+      {opts : Args.OBJECT   | Args.Optional, _default: OPTIONS           }
+      {cb   : Args.FUNCTION | Args.Optional, _default: undefined         }
+    ], arguments)
+
+    @_newTemplate(args.dir, args.opts, TEMPLATE.MODULE, args.cb)

@@ -116,9 +118,9 @@
   ###
   @link: (orig, dist, cb) ->
     args = Args([
-      {orig: Args.STRING   | Args.Required                     }
-      {dist: Args.STRING   | Args.Required                     }
-      {cb  : Args.FUNCTION | Args.Optional, _default: undefined}
+      {orig: Args.STRING   | Args.Optional,  _default: "#{process.cwd()}"}
+      {dist: Args.STRING   | Args.Required                              }
+      {cb  : Args.FUNCTION | Args.Optional, _default: undefined         }
     ], arguments)

     fs.symlinkSync args.orig, args.dist
@@ -144,7 +146,9 @@
       moduleList = (require configFile).modules
       moduleList.push args.moduleName
       fs.writeFileSync configFile, "module.exports.modules = #{JSON.stringify(moduleList)}"
-    args.cb?()
+
+    args.cb?()
+

   ###
@@ -159,6 +163,7 @@
     ], arguments)

     wrench.rmdirSyncRecursive args.dir  if fs.existsSync(args.dir)
+
     args.cb?()

@@ -217,6 +222,7 @@
     ], arguments)

     process.chdir args.dir
+

   ###
@@ -302,14 +308,17 @@
     # copy the content of the variable into file
     fs.outputFileSync(destPath, contents)

+
+
   ###
   Generate the scaffold base on a template
   ###
   @_newTemplate: (dir, options, templatePath, cb) =>
-    SCOPE.APP    = "#{dir}/#{options.name}"
+
+    SCOPE.APP = "#{dir}/#{options.name}"
     wrench.copyDirSyncRecursive templatePath, SCOPE.APP,
-      forceDelete: true
-      exclude    : TEMPLATE.REGEX
+      forceDelete : true
+      exclude     : TEMPLATE.REGEX

     @_copyTemplate "#{templatePath}/#{template}", options for template in TEMPLATE.FILES


Properly age 'today' and 'yesterday' formatted dates (fix #497)

--- client/lib/date.coffee
+++ client/lib/date.coffee
@@ -1,7 +1,7 @@
 @formatDate = (date, prefix = '', absolute) ->
   return '???' unless date?
   return "?#{date}?" unless date instanceof Date  ## have seen this briefly, not sure when
-  now = new Date()
+  now = new Date
   options =
     weekday: 'short'
     month: 'short'
@@ -14,10 +14,12 @@
   time += date.getMinutes()
   if date.getFullYear() == now.getFullYear() and not absolute
     if date.getMonth() == now.getMonth() and date.getDate() == now.getDate()
+      Session.get 'today'  # depend on the current date; see below
       "today at #{time}"
     else
       now.setDate now.getDate()-1
       if date.getMonth() == now.getMonth() and date.getDate() == now.getDate()
+        Session.get 'today'  # depend on the current date; see below
         "yesterday at #{time}"
       else
         "#{prefix}#{date.toLocaleDateString 'en-US', options} at #{time}"
@@ -27,3 +29,21 @@

 Template.registerHelper 'formatDate', (date, kw) ->
   formatDate date, kw?.hash?.prefix
+
+formatDateISO = (date) ->
+  "#{date.getFullYear()}-#{date.getMonth()+1}-#{date.getDate()+1}"
+
+###
+Maintain the current date (year-month-day) in the Session variable 'today',
+allowing the code above to reactively depend on the current date via
+`Session.get 'today'`.
+###
+do maintainToday = ->
+  now = new Date
+  Session.set 'today', formatDateISO now
+  tomorrow = new Date
+  tomorrow.setDate tomorrow.getDate() + 1
+  tomorrow.setHours 0
+  tomorrow.setMinutes 0
+  tomorrow.setSeconds 0, 0
+  Meteor.setTimeout maintainToday, tomorrow - now


Changed "if drawn[0]?" to "if drawn.length > 0" for all cards using dig. Functionally should be the same, but I feel it looks better.

--- cards.coffee
+++ cards.coffee
@@ -515,7 +515,7 @@
     drawn = state.current.dig(state,
       (state, card) -> card.isTreasure
     )
-    if drawn[0]?
+    if drawn.length > 0
       treasure = drawn[0]
       trash = state.current.ai.choose('trash', state, [treasure, null])
       if trash?
@@ -569,7 +569,7 @@
     drawn = state.current.dig(state,
       (state, card) -> card.isTreasure
     )
-    if drawn[0]?
+    if drawn.length > 0
       treasure = drawn[0]
       state.log("...playing #{treasure}.")
       state.current.inPlay.push(treasure)
@@ -922,7 +922,7 @@
       drawn = opp.dig(state,
         (state, card) -> card.isVictory or card is c.Curse
       )
-      if drawn[0]?
+      if drawn.length > 0
         card = drawn[0]
         transferCardToTop(card, drawn, opp.draw)
         state.log("...#{opp.ai} puts #{card} on top of the deck.")
@@ -1046,7 +1046,7 @@
       drawn = opp.dig(state,
         (state, card) -> card.getCost(state)[0] >= 3
       )
-      if drawn[0]?
+      if drawn.length > 0
         cardToTrash = drawn[0]
         state.log("...#{state.current.ai} trashes #{opp.ai}'s #{cardToTrash}.")
         choices = upgradeChoices(state, drawn, c.Saboteur.upgradeFilter)
@@ -1065,8 +1065,8 @@
   playEffect: (state) ->
     state.attackOpponents (opp) ->
       state.discardFromDeck(opp, 1)
-      state.gainCard(opp, c.Curse, 'draw', true)
-      state.log("#{opp.ai} gains a Curse on top of the deck.")
+      state.gainCard(opp, c.Curse, 'draw')
+      state.log("...putting the Curse on top of the deck.")
 }

 makeCard 'Thief', attack, {


Refactor: Removed unnecessary storage variables in helper functions

--- app/scripts/controllers/bill.coffee
+++ app/scripts/controllers/bill.coffee
@@ -18,12 +18,10 @@
       console.log "Ready to annotate!"

     makeBillCode = ->
-      billCode = "BILLS-#{$scope.bill.congress}#{$scope.bill.bill_type}#{$scope.bill.number}#{$scope.bill.last_version.version_code}"
-      return billCode
+      return "BILLS-#{$scope.bill.congress}#{$scope.bill.bill_type}#{$scope.bill.number}#{$scope.bill.last_version.version_code}"

     makeBillUrl = (billCode) ->
-      requestUrl = "http://www.gpo.gov/fdsys/pkg/#{billCode}/html/#{billCode}.htm"
-      return requestUrl
+      return "http://www.gpo.gov/fdsys/pkg/#{billCode}/html/#{billCode}.htm"

     makeBillId = ->
       billCode = $location.path().split("").splice(13,15)


Simplify input parameter comparison in scoring view. PP-4

--- client/src/scripts/scoring-view.coffee
+++ client/src/scripts/scoring-view.coffee
@@ -177,6 +177,7 @@
     renderRocCurve rates

   createInputParameter = (key, value, isVisible) ->
+    # DL, DRF have array-valued params, so handle that case properly
     formattedValue = if isArray value then value.join ', ' else value

     key: key
@@ -206,17 +207,9 @@
     tailParameterss = tail parameterss
     for parameters, index in headParameters
       for tailParameters in tailParameterss
-        a = parameters.value
-        b = tailParameters[index].value
-        # DRF has array-valued params, so handle that case properly
-        if (isArray a) and (isArray b)
-          unless zipCompare a, b
-            markAsDifferent parameterss, index
-            break
-        else
-          if a isnt b
-            markAsDifferent parameterss, index
-            break
+        if parameters.value isnt tailParameters[index].value
+          markAsDifferent parameterss, index
+          break
     return

   renderComparisonTable = (scores) ->


ENHANCE: Update new user wizard to prefill names and email

--- src/app/home/home.coffee
+++ src/app/home/home.coffee
@@ -123,11 +123,18 @@
       $scope.user = currentUser.profile
       $scope.user.opt_in_to_research = null
     else
+      firstName = null
+      lastName = null
+      email = null
+      unless currentUser.profile.first_name.toLowerCase() is 'first name' or currentUser.profile.last_name.toLowerCase() is 'last name'
+        firstName = currentUser.profile.first_name
+        lastName = currentUser.profile.last_name
+        email = currentUser.profile.email
       $scope.user = {
-        first_name: null
-        last_name: null
+        first_name: firstName
+        last_name: lastName
         nickname: null
-        email: null
+        email: email
         receive_feedback_notifications: null
         receive_portfolio_notifications: null
         receive_task_notifications: null
@@ -138,8 +145,8 @@
     $scope.moveStep = (skip) ->
       # if about to enter grade step and no grades? skip twice
       if $scope.projects.length is 0
-        stepBeforeTargetStep = _.findWhere $scope.steps, { seq: $scope.currentStep.targetGradeStep - 1 }
-        stepAfterTargetStep = _.findWhere $scope.steps, { seq: $scope.currentStep.targetGradeStep + 1 }
+        stepBeforeTargetStep = _.findWhere $scope.steps, { seq: $scope.steps.targetGradeStep.seq - 1 }
+        stepAfterTargetStep = _.findWhere $scope.steps, { seq: $scope.steps.targetGradeStep.seq + 1 }
         if skip is 1 and $scope.currentStep is stepBeforeTargetStep
           skip += 1
         else if skip is -1 and $scope.currentStep is stepAfterTargetStep