stacks: minor copy adjustments

stacks: minor copy adjustments

--- client/admin/lib/views/stacks/definestackview.coffee
+++ client/admin/lib/views/stacks/definestackview.coffee
@@ -288,8 +288,7 @@
       @emit 'Reload'

       if err
-        @outputView.add "Parsing failed, please check your
-                         template and try again"
+        @outputView.add "Parsing failed, please check your template and try again"
         return

       { groupsController } = kd.singletons
@@ -304,13 +303,9 @@
           @inputTitle.setClass 'three-buttons'

           @outputView.add """
-
             Your stack script has been successfully saved.

-            If you want your team members to use this template you need to
-            apply it for your team.
-
-            You can now close this window or continue working with your stack.
+            You can now close the stack editor or continue editing your stack.
           """

         else
@@ -319,7 +314,7 @@
       else
         setToGroup 'addAndWarn'

-      @cancelButton.setTitle 'Close'
+      @cancelButton.setTitle 'Ok'

   checkAndBootstrapCredentials: (callback) ->


Ace: initially saved fetched content as file content.

--- client/app/Applications/Ace.kdapplication/ace.coffee
+++ client/app/Applications/Ace.kdapplication/ace.coffee
@@ -28,7 +28,9 @@
           @editor = ace.edit "editor#{@getId()}"
           @prepareEditor()
           @utils.defer => @emit "ace.ready"
-          @setContents contents if contents
+          if contents
+            @setContents contents
+            @lastSavedContents = contents
           @editor.gotoLine 0
           @focus()
           @show()


app: make ActivityModal a variation of Modal

--- client/app/lib/components/activitymodal/index.coffee
+++ client/app/lib/components/activitymodal/index.coffee
@@ -1,77 +1,32 @@
 kd     = require 'kd'
 React  = require 'kd-react'
-Portal = require 'react-portal'
-
-noop = ->
-
-
-class ModalOverlay extends React.Component
-
-  render: ->
-

-
+Modal  = require 'app/components/modal'

 module.exports = class ActivityModal extends React.Component

   @defaultProps =
-    onClose             : noop
+    onClose             : kd.noop
     closeOnEsc          : yes
     closeOnOutsideClick : yes
     hasOverlay          : yes
     isOpen              : no
-    className           : ''
     buttonAbortTitle    : 'CANCEL'
-
-  onClose: (args...) -> @props.onClose? args...
-
-
-  getPortalProps: ->
-    isOpened            : @props.isOpen
-    onClose             : @bound 'onClose'
-    closeOnEsc          : @props.closeOnEsc
-    closeOnOutsideClick : @props.closeOnOutsideClick
-
-
-  renderModal: ->
-
-    return null  unless @props.isOpen
-
-    portalProps = @getPortalProps()
-
-    return (
-      <Portal {...portalProps}>
-

-
{@props.title}

-

-
{@props.children}

-

-

-            <button className="Button Modal-Button Button--danger" onClick={@props.onConfirm}>
-              {@props.buttonConfirmTitle}
-            </button>
-            <button className="Button Modal-Button Button--secondary" onClick={@props.onAbort}>
-              {@props.buttonAbortTitle}
-            </button>
-

-

-      </Portal>
-    )
-
-
-  renderOverlay: ->
-    return null  unless @props.isOpen and @props.hasOverlay
-
-    return (
-      <Portal isOpened={@props.isOpen}>
-        <ModalOverlay />
-      </Portal>
-    )

   render: ->
-

-      {@renderOverlay()}
-      {@renderModal()}
-

+    <Modal {...@props}>
+      <Modal.Title>{@props.title}</Modal.Title>
+      <Modal.Content>
+        {@props.children}
+      </Modal.Content>
+      <Modal.ButtonGroup>
+        <Modal.Button className="Button--danger" onClick={@props.onConfirm}>
+          {@props.buttonConfirmTitle}
+        </Modal.Button>
+        <Modal.Button className="Button--secondary" onClick={@props.onAbort}>
+          {@props.buttonAbortTitle}
+        </Modal.Button>
+      </Modal.ButtonGroup>
+    </Modal>


Make snap server keep trying to connect to database during startup; thus snap will work even if the database isn't up when snap is started.

--- salvus/snap.coffee
+++ salvus/snap.coffee
@@ -1453,7 +1453,12 @@
         (cb) ->
             generate_secret_key(cb)
         (cb) ->
-            connect_to_database(cb)
+            # keep retrying until database is up and we succeed in connecting.
+            misc.retry_until_success
+                f           : connect_to_database
+                start_delay : 1000
+                max_delay   : 10000
+                cb          : cb
         (cb) ->
             if program.resend_all_commits
                 resend_all_commits(cb)


Change and add platform specific keybindings

--- keymaps/table-edit.cson
+++ keymaps/table-edit.cson
@@ -7,24 +7,43 @@

 # For more detailed documentation see
 # https://atom.io/docs/latest/advanced/keymaps
-
 'atom-table-editor':
   'tab': 'table-edit:move-right-in-selection'
   'shift-tab': 'table-edit:move-left-in-selection'
+
+'.platform-darwin atom-table-editor':
   'cmd-left': 'table-edit:move-to-beginning-of-line'
   'cmd-right': 'table-edit:move-to-end-of-line'
   'cmd-shift-right': 'table-edit:select-to-end-of-line'
   'cmd-shift-left': 'table-edit:select-to-beginning-of-line'
   'cmd-shift-up': 'table-edit:select-to-beginning-of-table'
   'cmd-shift-down': 'table-edit:select-to-end-of-table'
-  'cmd-alt-up': 'table-edit:insert-row-before'
-  'cmd-alt-down': 'table-edit:insert-row-after'
-  'cmd-alt-backspace': 'table-edit:delete-row'
-  'cmd-alt-ctrl-left': 'table-edit:insert-column-before'
-  'cmd-alt-ctrl-right': 'table-edit:insert-column-after'
-  'cmd-alt-ctrl-backspace': 'table-edit:delete-column'
+  'cmd-alt-n up': 'table-edit:insert-row-before'
+  'cmd-alt-n down': 'table-edit:insert-row-after'
+  'cmd-alt-n left': 'table-edit:insert-column-before'
+  'cmd-alt-n right': 'table-edit:insert-column-after'
+  'cmd-alt-backspace left': 'table-edit:delete-row'
+  'cmd-alt-backspace right': 'table-edit:delete-row'
+  'cmd-alt-backspace up': 'table-edit:delete-column'
+  'cmd-alt-backspace down': 'table-edit:delete-column'

-'atom-table-editor atom-text-editor:not([mini])':
+'.platform-win32, .platform-linux':
+  'ctrl-left': 'table-edit:move-to-beginning-of-line'
+  'ctrl-right': 'table-edit:move-to-end-of-line'
+  'ctrl-shift-right': 'table-edit:select-to-end-of-line'
+  'ctrl-shift-left': 'table-edit:select-to-beginning-of-line'
+  'ctrl-shift-up': 'table-edit:select-to-beginning-of-table'
+  'ctrl-shift-down': 'table-edit:select-to-end-of-table'
+  'ctrl-alt-n up': 'table-edit:insert-row-before'
+  'ctrl-alt-n down': 'table-edit:insert-row-after'
+  'ctrl-alt-n left': 'table-edit:insert-column-before'
+  'ctrl-alt-n right': 'table-edit:insert-column-after'
+  'ctrl-alt-backspace left': 'table-edit:delete-row'
+  'ctrl-alt-backspace right': 'table-edit:delete-row'
+  'ctrl-alt-backspace up': 'table-edit:delete-column'
+  'ctrl-alt-backspace down': 'table-edit:delete-column'
+
+'atom-table-editor atom-text-editor':
   'enter': 'core:confirm'
   'ctrl-enter': 'editor:newline'
   'tab': 'table-edit:move-right'


Muda "loading..." para "caregando..."

Muda "loading..." para "caregando..."

--- src/coffee/portal-template-as-modal.coffee
+++ src/coffee/portal-template-as-modal.coffee
@@ -13,7 +13,7 @@

-					Loading...
+					Carregando...

"""


1671、1674、1675翻译修改 (#5233)

1671、1674、1675翻译修改 (#5233)

--- app/locale/zh-HANS.coffee
+++ app/locale/zh-HANS.coffee
@@ -1668,11 +1668,11 @@
 #    removed_course_msg: "{{numberRemoved}} students were removed from {{courseName}}."
     remove_course: "移除课程"
     not_assigned_modal_title: "课程未分配"
-#    not_assigned_modal_starter_body_1: "This course requires a Starter License. You do not have enough Starter Licenses available to assign this course to all __selected__ selected students."
+    not_assigned_modal_starter_body_1: "本课程需要学生许可证。您没有足够的学生许可证来分配本课程给所有选课的学生。"
 #    not_assigned_modal_starter_body_2: "Purchase Starter Licenses to grant access to this course."
 #    not_assigned_modal_full_body_1: "This course requires a Full License. You do not have enough Full Licenses available to assign this course to all __selected__ selected students."
-#    not_assigned_modal_full_body_2: "You only have __numFullLicensesAvailable__ Full Licenses available (__numStudentsWithoutFullLicenses__ students do not currently have a Full License active)."
-#    not_assigned_modal_full_body_3: "Please select fewer students, or reach out to __supportEmail__ for assistance."
+    not_assigned_modal_full_body_2: "您只有可用的__numFullLicensesAvailable__完整许可证（__numStudentsWithoutFullLicenses__学生目前没有激活完整许可证）。"
+    not_assigned_modal_full_body_3: "请选择更少的学生，或者联系__supportEmail__寻求帮助。"
     assigned: "已添加"
     enroll_selected_students: "注册选中的学生"
     no_students_selected: "没有学生被选中。"


updating csv.coffee to wrap all cells in delimiter

previously, it was only if there were spaces or the delimiter. (note:
the regex is illogical, and basically just checks if the cell is a
string)

--- source/javascripts/lib/csv.coffee
+++ source/javascripts/lib/csv.coffee
@@ -132,7 +132,9 @@
   if param instanceof Csv then param else new Csv param, opts

 asCsvCellValue = (cell)->
-  if ///\W|#{csv.settings.delimiter}///.test cell
+  if cell is undefined
+    ""
+  else if ///\W|\w|#{csv.settings.delimiter}///.test cell
     JSON.stringify("#{cell}")
   else
     cell
@@ -283,7 +285,7 @@
       sheet = @_sheets[sheetId]
       cols = sheet.columns
       rowA = sheet.rowArray
-      headRowStr = sheetId
+      headRowStr = asCsvCellValue sheetId
       headRowStr += delimiter  for i in [0...cols.length]
       outp.push headRowStr
       outp.push delimiter + (asCsvCellValue col for col in cols).join delimiter


Create backbone model that represents discussion activities

--- core/app/backbone/collections/feed_activities.coffee
+++ core/app/backbone/collections/feed_activities.coffee
@@ -7,9 +7,21 @@

   url: -> "/api/beta/feed.json?count=#{@_count}"

+class window.DiscussionsFeedActivities extends Backbone.Factlink.Collection
+  _.extend @prototype, AutoloadCollectionOnTimestamp
+  model: Activity
+
+  initialize: (models, options={}) ->
+    @_count = options.count || 20
+
+  url: -> "/api/beta/feed/discussions.json?count=#{@_count}"
+
+

 class window.PersonalFeedActivities extends Backbone.Collection
   _.extend @prototype, AutoloadCollectionOnTimestamp
   model: Activity

   url: -> '/api/beta/feed/personal'
+
+


functions for link

functions for link

--- app/scripts/editor.coffee
+++ app/scripts/editor.coffee
@@ -141,7 +141,7 @@
 		top = Math.min startEl.offset().top, endEl.offset().top
 		left = ( startEl.offset().left + endEl.offset().left ) / 2
 		$('#toolpad').css 'top', top - 35
-		$('#toolpad').css 'left', left - 30
+		$('#toolpad').css 'left', left - 90
 	hideToolpad: ->
 		$('#toolpad').addClass 'hidden'

@@ -173,9 +173,6 @@
 		$('body').delegate '#tooltip', 'mouseleave', (e)->
 			self.hideTooltip()

-		# $('body').delegate '#editor', 'click', (e)->
-		# 	$('#editor').focus()
-
 		# toolpad
 		$('body').delegate '#editor', 'mouseup', (e)=>
 			sel = @selection()
@@ -187,6 +184,10 @@
 					@saveSelection 'm'
 					@showToolpadOverSelection 'm'
 					@restoreSelection 'm'
+		$('#toolpad').delegate 'li:first-child', 'click', (e)->
+			$(@).addClass 'toggled'
+		$('#toolpad').delegate '.cancel', 'click', (e)->
+			$(@).removeClass 'toggled'

 	update: ->
 		self = @


remove unused saving messages

remove unused saving messages

--- app/scripts/editor.coffee
+++ app/scripts/editor.coffee
@@ -3,8 +3,6 @@
 	## PROPERTIES ##
 	titlePromptMessage: 'New title'
 	promptMessage: 'Type your article here'
-	savingMessage: 'Saving...'
-	savedMessage: 'Saved!'
 	status:
 		cmd: false
 		ctrl: false


Fix: URI encode fragments in type param before param is encoded

--- lib/assets/javascripts/collection.js.coffee
+++ lib/assets/javascripts/collection.js.coffee
@@ -35,6 +35,9 @@
       limit: TentStatus.config.PER_PAGE
     }, @options.params, params

+    params.types = [params.types] unless _.isArray(params.types)
+    params.types = _.map params.types, (type) => (new TentClient.PostType type).toURIString()
+
     TentStatus.tent_client.post.list(params: params, callback: complete)

   fetchSuccess: (params, options, res, xhr) =>


Tweak regexps to be more liberal with white space

--- lib/assets/javascripts/jax/shader.js.coffee
+++ lib/assets/javascripts/jax/shader.js.coffee
@@ -8,7 +8,7 @@
 class Parser
   findVariables: ->
     variables = []
-    rx = /(shared |)(varying|uniform|attribute) (\w+) ([^;]+);/
+    rx = /(shared[\s\t\n]+|)(varying|uniform|attribute)[\s\t\n]+(\w+)[\s\t\n]+(((\w+)([\s\t\n]*,[\s\t\n]*|))+)[\s\t\n]*;/
     src = @src
     while match = rx.exec src
       offsetStart = match.index
@@ -24,7 +24,7 @@

   findFunctions: ->
     functions = []
-    rx = /(\w+) (\w+)\((.*?)\) {/
+    rx = /(\w+)[\s\t\n]+(\w+)[\s\t\n]*\([\s\t\n]*[\s\t\n]*(.*?)[\s\t\n]*\)[\s\t\n]*{/
     src = @src
     while match = rx.exec src
       offsetStart = match.index
@@ -109,7 +109,7 @@

   processExportsAndImports: (code) ->
     exports = []
-    rx = /export\(/
+    rx = /export[\s\t\n]*\(/
     offset = 0
     exportID = 0
     while match = rx.exec code[offset..-1]
@@ -117,7 +117,7 @@
       offsetEnd = offsetStart + match[0].length
       remainder = Jax.Util.scan code[offsetEnd..-1]
       offsetEnd += remainder.length + 1
-      exp = /^(.*?), (.*?), (.*)$/.exec remainder
+      exp = /^(.*?)[\s\t\n]*,[\s\t\n]*(.*?)[\s\t\n]*,[\s\t\n]*(.*)$/.exec remainder
       exports.push
         fullMatch: code[offsetStart...offsetEnd]
         type: exp[1]
@@ -128,7 +128,7 @@
         offsetEnd: offsetEnd
       offset = offsetEnd

-    rx = /import\(/
+    rx = /import[\s\t\n]*\(/
     for offset in [(code.length-1)..0]
       if match = rx.exec code[offset..-1]
         offsetStart = match.index + offset
@@ -137,7 +137,7 @@
         offsetEnd += remainder.length + 1
         # consume terminators to prevent empty statements
         offsetEnd++ if code[offsetEnd] == ';'
-        imp = /^(.*?), (.*)$/.exec remainder
+        imp = /^(.*?)[\s\t\n]*,[\s\t\n]*(.*)$/.exec remainder
         imp =
           fullMatch: code[offsetStart...offsetEnd]
           name: imp[1]
@@ -182,7 +182,7 @@

     # caches
     caches = {}
-    while match = /cache\(([^,]+?), (.*?)\) \{/.exec body
+    while match = /cache[\s\t\n]*\([\s\t\n]*([^,]+?)[\s\t\n]*,[\s\t\n]*(.*?)[\s\t\n]*\)[\s\t\n]*\{/.exec body
       cacheType = match[1].trim()
       cacheName = match[2].trim()
       offsetStart = match.index


wrote jade action

wrote jade action

--- movieExample.coffee
+++ movieExample.coffee
@@ -5,8 +5,8 @@

 # Q: How to "package" things like the loading screen together?

-B.declareActions [
-  B.doInSequence [
+B.setRootAction
+  doInSequence :
     "init page": ui.html.show
       location: "body"
       html: B.asset("baseTemplate")
@@ -40,7 +40,7 @@
           ]
       ]
   ]
-]
+

 B.declareModels
   status: new B.Object
@@ -54,17 +54,17 @@
     introScreen "in"

 B.declareAssets
-  baseTemplate: "template.html"
-  loadingScreen: "loading.html"
+  baseTemplate:
+    type: B.String
+    url: "template.html"
+  loadingScreen: "loading.html" # type auto-detection
   pauseScreen: "pause.html"
   introScreen: "intro.html"
   creditsScreen: "credits.html"

 # allows action to be changed later
-# Q: how avoid duplication of "name", while still allowing library and modules to work?
-ui.html.show = B.makeAction
-  name: "ui.html.show"
+B.defineAction "ui.html.show",
   doc: "Shows HTML in the given location"
   parameterDefs:
     html:
@@ -73,7 +73,7 @@
     location:
       type: B.String
       default: "body"
-      constant: true
+      constant: true # means that changes to this parameter changes will be ignored

   action: (params) ->
     init: -> $(params.location).html(params.html.get())
@@ -81,4 +81,23 @@
     update: ->

+B.defineAction "ui.html.jade",
+  doc: "Compiles a template using the Jade template engine"
+  parameterDefs:
+    template:
+      type: B.String
+      constant: true
+    output: B.String # shorthand syntax
+    locals: B.Object({}) # shorthand syntax

+  action: (temp, params) ->
+    init: ->
+      jade = require("jade")
+      temp.compiledTemplate = jade.compile(params.template.value)
+    destroy: ->
+    update: ->
+      # in case params don't change, do nothing
+      if not params.locals.value.hasChanged then return
+
+      params.output.value = temp.compiledTemplate(params.locals.value)
+


enabling gettoken to work when a browser app is opening

--- client/app/routers/main_router.coffee
+++ client/app/routers/main_router.coffee
@@ -28,7 +28,8 @@
             intent = event.data
             switch intent.action
                 when 'getToken'
-                    iframeName = document.activeElement.id
+                    elements = document.getElementsByTagName 'iframe'
+                    iframeName = elements[0].getAttribute 'id'
                     appName = iframeName.substring 0, iframeName.indexOf '-'
                     token = new Token appName
                     token.getToken


[misc-robust] some attachments has no mime/type

--- client/app/utils/message_utils.coffee
+++ client/app/utils/message_utils.coffee
@@ -109,6 +109,7 @@
         return res.join "\n"

     getAttachmentType: (type) ->
+        return null unless type
         sub = type.split '/'
         switch sub[0]
             when 'audio', 'image', 'text', 'video'


Social: if user is troll, then do show exempt content

--- workers/social/lib/social/models/socialapi/helper.coffee
+++ workers/social/lib/social/models/socialapi/helper.coffee
@@ -54,6 +54,7 @@

       options.groupName = group.slug
       options.accountId = socialApiId
+      options.showExempt = delegate.isExempt

       requests = require './requests'
       requests[funcName] options, callback


added cron cron job that persist the storage at a specified time (every 6hours for now)

--- lib/coffeeRunner.coffee
+++ lib/coffeeRunner.coffee
@@ -2,6 +2,7 @@
 {ItemStorage} = require './itemStorage'
 {Recommender} = require './recommender'
 {Server} = require './server'
+CronJob = require('cron').CronJob

 STORAGE_FILE_PATH = 'item.store'

@@ -10,5 +11,12 @@
 server = new Server(recommender)

 process.on 'exit', -> storage.persist(STORAGE_FILE_PATH)
-process.on 'uncaughtException', -> storage.persist(STORAGE_FILE_PATH)
+
+# pattern for cron jobs can be found at
+# http://help.sap.com/saphelp_xmii120/helpdata/en/44/89a17188cc6fb5e10000000a155369/content.htm
+new CronJob '0 0 */6 * * *',
+            -> storage.persist(STORAGE_FILE_PATH),
+            -> console.log 'Stopped cron job',
+            true
+
 server.start()


further restrict the places we can do the RemoveIIFE pass to just the ones that don't return a value

--- lib/echo-desugar.coffee
+++ lib/echo-desugar.coffee
@@ -81,11 +81,20 @@

 class RemoveIIFE extends NodeVisitor
+        constructor: ->
+                @validLocation = false
+
+        visitExpressionStatement: (n) ->
+                @validLocation = n.expression.type is syntax.CallExpression
+                n.expression = @visit n.expression
+                n
+
         visitCallExpression: (n) ->
-                if n.callee.type is syntax.FunctionExpression and n.callee.params.length is 0  # let's limit this to 0-arg IIFE's for now
-                        n.callee.body
-                else
-                        n
+                return n if not @validLocation
+
+                @validLocation = false
+                return (@visit n.callee.body) if n.callee.type is syntax.FunctionExpression and n.callee.params.length is 0  # let's limit this to 0-arg IIFE's for now
+                n

 class FlattenExpressionStatements extends NodeVisitor
         visitExpressionStatement: (n) ->


Set linter name to clang

Set linter name to clang

--- lib/linter-clang.coffee
+++ lib/linter-clang.coffee
@@ -14,6 +14,8 @@
   # containing the command line (with arguments) used to lint.

   @cmd: ''
+
+  linterName: 'clang'

   errorStream: 'stderr'


Disconnect on package deactivation

Disconnect on package deactivation

--- lib/python-tools.coffee
+++ lib/python-tools.coffee
@@ -56,6 +56,8 @@
     @modalPanel.destroy()
     @subscriptions.dispose()
     @pythonToolsView.destroy()
+    @readline.close()
+    @provider.kill()

   serialize: ->
     pythonToolsViewState: @pythonToolsView.serialize()


Adds additional check for selectionRange.end.row, fixes #39

--- lib/range-finder.coffee
+++ lib/range-finder.coffee
@@ -32,7 +32,7 @@
     startRow = selectionRange.start.row
     startCol = 0
     endRow = if selectionRange.end.column == 0
-      selectionRange.end.row - 1
+      if selectionRange.end.row then selectionRange.end.row - 1 else 0
     else
       selectionRange.end.row
     endCol = @editor.lineTextForBufferRow(endRow).length


Check ids before sending channel event

Check ids before sending channel event

--- lib/tab-bar-view.coffee
+++ lib/tab-bar-view.coffee
@@ -232,8 +232,10 @@
           activeItemIndex = activePane.getActiveItemIndex()
           @moveItemBetweenPanes(activePane, activeItemIndex, toPane, toIndex, item)

-          # Let the window where the drag started know that the tab was dropped
-          BrowserIpc.sendChannel(fromProcessId, fromRoutingId, 'tab:dropped', fromIndex, fromPaneIndex)
+
+          unless isNaN(fromProcessId) or isNan(fromProcessId)
+            # Let the window where the drag started know that the tab was dropped
+            BrowserIpc.sendChannel(fromProcessId, fromRoutingId, 'tab:dropped', fromIndex, fromPaneIndex)

         atom.focus()


Sometimes git just sucks

Sometimes git just sucks

--- app/assets/javascripts/views/clouds/user_dialog.js.coffee
+++ app/assets/javascripts/views/clouds/user_dialog.js.coffee
@@ -49,12 +49,4 @@
     else
       @model.ban
         success: (user) =>
-          @model.set(user)  skypeAdd: ->
-    window.open("skype:#{@model.get('skype_name')}?add")
-  skypeAdd: ->
-    window.open("skype:#{@model.get('skype_name')}?add").close()
-    false
-
-  skypeCall: ->
-    window.open("skype:#{@model.get('skype_name')}?call").close()
-    false+          @model.set(user)


Add a small useless fix

Add a small useless fix

Just put a 'return' statement to avoid returning something.

--- app/gem/component.cjsx
+++ app/gem/component.cjsx
@@ -8,6 +8,7 @@

   onClick: (event) ->
     toggleGem()
+    return

   render: ->
     statusStr = if @state?.status then 'activated' else 'deactivated'


Render header and footer in index

Render header and footer in index

--- app/index/index.coffee
+++ app/index/index.coffee
@@ -6,6 +6,5 @@
 	}]

 handler = (req, reply) =>
-	console.log @
-	console.log exports
-	reply 'hello world'+	html = @renderer.header('home') + "
Hey there!
" + @renderer.footer()
+	reply html


temp disable cpp (#6236)

temp disable cpp (#6236)

Co-authored-by: smallst_wsl <6c42689ff77371401bf43b7d56b93ac1ca3e92d3@163.com>

--- app/models/User.coffee
+++ app/models/User.coffee
@@ -589,7 +589,7 @@
   showChinaResourceInfo: -> features?.china ? false
   useChinaHomeView: -> features?.china ? false
   showChinaRegistration: -> features?.china ? false
-  enableCpp: -> me.hasSubscription() || me.isStudent() || me.isTeacher()
+  enableCpp: -> false # me.hasSubscription() || me.isStudent() || me.isTeacher()
   useQiyukf: -> features?.china ? false
   useChinaServices: -> features?.china ? false
   useGeneralArticle: -> not (features?.china ? false)


Movable bounding box.

Movable bounding box.

--- src/js/directives/mapping-box/index.coffee
+++ src/js/directives/mapping-box/index.coffee
@@ -13,10 +13,15 @@
     else
         scale = height / box.height

-    return {
-        height: (Math.floor box.height * scale),
-        width: (Math.floor box.width * scale)
-    }
+    box.height = (Math.floor box.height * scale)
+    box.width = (Math.floor box.width * scale)
+
+    # calculate bounding box for top left corner
+
+    box.maxX = width - box.width
+    box.maxY = height - box.height
+
+    return box

 mod.directive "mappingBox", () ->
     {
@@ -34,7 +39,7 @@
                 darkBackground: false
             }

-            mappingBox = false
+            mappingBox = false

             stage = new createjs.Stage canvas

@@ -46,13 +51,40 @@
                 # add our Box!
                 boxDimensions = makeBox canvas.height, canvas.width, scope.aspectRatio
                 mappingBox = new createjs.Shape()
+                hitBox = new createjs.Shape()
+
+                # calculate line width based on the on screen canvas size
+                boxWidth = canvas.clientWidth * 0.0075
+                boxWidth = Math.max(boxWidth, 1)

                 # setup a sane box color
                 boxColor = if options.darkBackground then "white" else "black"

                 mappingBox.graphics
-                    .ss(5).s(boxColor).r(0,0,boxDimensions.width, boxDimensions.height)
+                    .ss(boxWidth).s(boxColor).r(0,0,boxDimensions.width, boxDimensions.height)

+                hitBox.graphics.f('#000').r(0,0,boxDimensions.width, boxDimensions.height)
+
+                mappingBox.hitArea = hitBox
+
+                # tracks where the mose is inside the mapping box
+                mouseOffset = { x: 0, y: 0 }
+
+                # Handle mouse event listeners
+                mappingBox.addEventListener 'mousedown', (e) ->
+                    # Map mouse position to the upper left corner of the canvas
+                    mouseOffset.x = e.stageX - mappingBox.x
+                    mouseOffset.y = e.stageY - mappingBox.y
+
+                mappingBox.addEventListener 'pressmove', (e) ->
+                    mouseX = e.stageX - mouseOffset.x
+                    mouseY = e.stageY - mouseOffset.y
+
+                    mappingBox.x = Math.max(0, Math.min(mouseX, boxDimensions.maxX))
+                    mappingBox.y = Math.max(0, Math.min(mouseY, boxDimensions.maxY))
+
+                    stage.update()
+
                 stage.addChild(mappingBox)

             # make sure we update on changes
@@ -82,11 +114,9 @@

                         if scope.resetCallback then resetCallback()

-
-
-
                 image.src = scope.file
-
-            # setup canvase event handlers
+
+            #stage.addEventListener 'pressmove', (e) ->
+            #    console.log e
     }


pass current element to tool

pass current element to tool

--- app/views/ubret_tool.iced
+++ app/views/ubret_tool.iced
@@ -20,15 +20,14 @@
     else
       # @$el.html @template(@) if typeof @template is 'function'
       opts =
+        el: @$el
         data: _.map( data, (datum) -> datum.toJSON() )
         selector: '#' + @id
         keys: @dataKeys(data)
         selectElementCb: @selectElement
         selectKeyCb: @selectKey
-
+
       @tool = new Ubret[@formatToolType(@model.get('type'))](opts)
-      @$el.html @tool.getTemplate()
-      @tool.start()
     @

   selectById: (id) ->


Add wrap guide and markdown preview to default config

--- .atom/default-config.coffee
+++ .atom/default-config.coffee
@@ -6,4 +6,5 @@
 requireExtension 'keybindings-view'
 requireExtension 'snippets'
 requireExtension 'status-bar'
-
+requireExtension 'wrap-guide'
+requireExtension 'markdown-preview'


Remove a console log

Remove a console log

--- assets/javascripts/controllers/index_controller.js.coffee
+++ assets/javascripts/controllers/index_controller.js.coffee
@@ -44,12 +44,11 @@
         messageParams.formattedBody = App.plugins.processMessageBody(formatted.body, formatted.type)

       msg = @store.createRecord("message", messageParams)
-      console.log "backup", msg.get("formattedBody")
+      console.log "formatted body: ", msg.get("formattedBody")

       if room.get("messages.length") == (MogoChat.config.messagesPerLoad + 1)
         room.get("messages").shiftObject()

-      console.log "backup again", msg.get("formattedBody")
       successCallback = =>
         room.get("messages").pushObject(msg)
       errorCallback   = =>


add ZipManager comments

add ZipManager comments

--- app/coffee/ZipManager.coffee
+++ app/coffee/ZipManager.coffee
@@ -2,6 +2,31 @@
 logger = require('logger-sharelatex')
 metrics = require('./Metrics')
 zlib = require('zlib')
+
+# Compress and uncompress data sent to Redis using the node 'zlib'
+# module, to reduce load on Redis.
+#
+# Measurements show that most of the load on Redis comes from a very
+# large documents. We can shift some of that CPU load from redis to
+# the docupdaters (which are scalable) by compressing the data in the
+# docupdater first.
+#
+# To avoid overloading the docupdater clients we impose a minimum size
+# on data we will compress, so we only catch the large ones.
+#
+# The optimimum size for the cutoff is about 10K, below this we do
+# more work but don't really gain any extra reduction in Redis CPU
+#
+# |--------------------+-----------+--------------------------|
+# | Compression cutoff | Redis CPU | Extra doc updater CPU(*) |
+# |--------------------+-----------+--------------------------|
+# | N/A                |      100% |                       0% |
+# | 100k               |       80% |                      10% |
+# | 10k                |       50% |                      30% |
+# |--------------------+-----------+--------------------------|
+#
+# (*) percentage of a single core, because node zlib runs in multiple
+# threads.

 ZIP_WRITES_ENABLED = Settings.redis.zip?.writesEnabled
 ZIP_MINSIZE = Settings.redis.zip?.minSize || 64*1024
@@ -18,7 +43,7 @@
 		# now uncompress the text (result[0]) if needed
 		buf = result?[0]

-		# Check if we have a GZIP file
+		# Check if we have a GZIP file (magic numbers in header)
 		if buf? and buf[0] == 0x1F and buf[1] == 0x8B
 			zlib.gunzip buf, (err, newbuf) ->
 				if err?


Prevent Enter Key

Prevent Enter Key

--- app/controllers/tasks.coffee
+++ app/controllers/tasks.coffee
@@ -14,6 +14,7 @@
   events:
     "keyup input.new-task": "new"
     "keyup h1": "rename"
+    "keypress h1": "preventer"

   constructor: ->
     super
@@ -64,4 +65,8 @@
     # This is fired on keyup when a list is renamed
     List.current.updateAttribute("name", @listName.text())

+  preventer: (e) ->
+    # Prevents the enter key
+    e.preventDefault() if e.keyCode is 13
+
 module.exports = Tasks


added: findElementsWithKey findElementWithKey

--- src/art/engine/core/element.coffee
+++ src/art/engine/core/element.coffee
@@ -1462,6 +1462,13 @@
       child.find pattern, arguments[1], matches for child in @_children
     matches

+  findElementsWithKey: (key) ->
+    @find (e) -> e.key == key
+
+  findElementWithKey: (key) ->
+    [first] = @findElementsWithKey key
+    first
+
   @getter
     elementPath: ->
       if @parent


collision: first version of component

collision: first version of component


Set up the dialog in initialize instead of on each click

--- app/assets/javascripts/browse_everything/behavior.js.coffee
+++ app/assets/javascripts/browse_everything/behavior.js.coffee
@@ -1,8 +1,12 @@
 $(document).ready ->
   context = {}
   active = null
+  dialog = $('div#browse-everything')

   initialize = (obj,options) ->
+    if dialog.length == 0
+      dialog = $('

').appendTo('body')
+    dialog.modal({ backdrop: 'static', show: false });
     context[obj] =
       opts: $.extend(true, {}, options)
       callbacks:
@@ -27,12 +31,8 @@
   $.fn.browseEverything = (options) ->
     if options?
       initialize(this[0], options)
-
       $(this).click () ->
         active = context[this]
-        dialog = $('div#browse-everything')
-        if dialog.length == 0
-          dialog = $('

').appendTo('body')
         dialog.load active.opts.route, () -> dialog.modal('show')
     else
       context[this[0]].callback_proxy


Dealing with multiple datacenter issue in pinnings

--- admin/static/coffee/namespaceview.coffee
+++ admin/static/coffee/namespaceview.coffee
@@ -246,6 +246,16 @@
             @change_hints_state = false
             super @template

+
+        get_currently_pinned: ->
+            # Grab pinned machines for this shard
+            currently_pinned = _.find @namespace.get('secondary_pinnings'), (pins, shard) =>
+                return JSON.stringify(@secondary.shard) is JSON.stringify(shard)
+            # Filter out the ones for our datacenter, since we're changing them
+            currently_pinned = _.filter currently_pinned, (uuid) =>
+                return machines.get(uuid).get('datacenter_uuid') isnt @secondary.datacenter_uuid
+            return currently_pinned
+
         disable_used_options: ->
             # Make sure the same machine cannot be selected
             # twice. Also disable the machine used for the master.
@@ -316,7 +326,7 @@
                         clear_modals()
                         return
                     output = {}
-                    output[@secondary.shard] = _.map pinned_machines, (m)->m.value
+                    output[@secondary.shard] = _.union (_.map pinned_machines, (m)->m.value), @get_currently_pinned()
                     output =
                         secondary_pinnings: output
                     $.ajax
@@ -476,6 +486,23 @@
             directory.on 'all', @render
             @shards = []

+        bind_edit_machines: (shard) ->
+            # TODO: deal with this later
+            @.$('#assign_master_' + shard.index).click (e) =>
+                e.preventDefault()
+
+            # Fucking JS closures
+            bind_shard = (shard, secondary) =>
+                @.$('#assign_machines_' + shard.index + '_' + secondary.datacenter_uuid).click (e) =>
+                    e.preventDefault()
+                    modal = new NamespaceView.EditMachinesModal @model, _.extend secondary,
+                        name: shard.name
+                        shard: shard.shard
+                    modal.render()
+
+            for secondary in shard.secondaries
+                bind_shard shard, secondary
+
         render: =>
             log_render '(rendering) namespace view: shards'

@@ -485,15 +512,7 @@

             # Bind events to 'assign machine' links
             for shard in shards_array
-                @.$('#assign_master_' + shard.index).click (e) =>
-                    e.preventDefault()
-                for secondary in shard.secondaries
-                    @.$('#assign_machines_' + shard.index + '_' + secondary.datacenter_uuid).click (e) =>
-                        e.preventDefault()
-                        modal = new NamespaceView.EditMachinesModal @model, _.extend secondary,
-                            name: shard.name
-                            shard: shard.shard
-                        modal.render()
+                @bind_edit_machines(shard)

             return @


More detailed replies

More detailed replies

--- modules/danbooru.coffee
+++ modules/danbooru.coffee
@@ -39,11 +39,11 @@
       }
       danbooru.get '/posts.json', { json: true, qs }
       .then (r)=>
-        try
+        if r.length
           url = "https://danbooru.donmai.us#{r[0].file_url}"
           msg.channel.uploadFile request(url), @getFileName(url)
-        catch
-          console.error r
+        else
+          msg.reply 'No results.'
       .catch (e)=>
         console.error e
         msg.reply 'Something went wrong.'
@@ -59,11 +59,11 @@
       }
       safebooru.get '/posts.json', { json: true, qs }
       .then (r)=>
-        try
+        if r.length
           url = "https://safebooru.donmai.us#{r[0].file_url}"
           msg.channel.uploadFile request(url), @getFileName(url)
-        catch
-          console.error r
+        else
+          msg.reply 'No results.'
       .catch (e)=>
         console.error e
         msg.reply 'Something went wrong.'
@@ -107,11 +107,11 @@
         }
         safebooru.get '/posts.json', { json: true, qs }
       .then (r)=>
-        try
+        if r.length
           url = "https://safebooru.donmai.us#{r[0].file_url}"
           msg.channel.uploadFile request(url), @getFileName(url)
-        catch
-          console.error r
+        else
+          msg.reply 'No results.'
       .catch (e)=>
         console.error e
         return msg.reply e.msg if e.msg


update stable nodejs version to 7.x

update stable nodejs version to 7.x

--- test/node/integration.test.coffee
+++ test/node/integration.test.coffee
@@ -51,7 +51,7 @@
         .end (err, res) ->
           return done(err) if err
           assert semver.valid(res.text)
-          assert.equal(res.text.charAt(0), '5');
+          assert.equal(res.text.charAt(0), '7');
           done()

     it "works with a failing endpoint", (done) ->
@@ -62,7 +62,7 @@
         .end (err, res) ->
           return done(err) if err
           assert semver.valid(res.text)
-          assert.equal(res.text.charAt(0), '5');
+          assert.equal(res.text.charAt(0), '7');
           done()

   describe "GET /node/unstable", ->
@@ -75,7 +75,7 @@
         .end (err, res) ->
           return done(err) if err
           assert semver.valid(res.text)
-          assert.equal(res.text.charAt(0), '5');
+          assert.equal(res.text.charAt(0), '7');
           done()

     it "works with a failing endpoint", (done) ->
@@ -86,7 +86,7 @@
         .end (err, res) ->
           return done(err) if err
           assert semver.valid(res.text)
-          assert.equal(res.text.charAt(0), '5');
+          assert.equal(res.text.charAt(0), '7');
           done()

   describe "GET /node/resolve/0.8.x", ->


adding uncovered test case

adding uncovered test case

Former-commit-id: fbe0709fee5a58a01f5bc25d92c9f26accacec23 [formerly 6bfd119893f9562541ffdc3bb9a5a85fd75646e2] [formerly 5a294e6f0b43008b6590305c93efedc398522fe6 [formerly 521085c9549d5b43fc53b1d439fcac8e0aba6ca9]] [formerly 2aba9bf38ce88d0a30a638d577274e5d2aab9041 [formerly 50164a26a5aa671f9290acdbed9a5e90308b5af4] [formerly 939c35d0d3e4c57b30f00fd454b87e82fcd67112 [formerly 939c35d0d3e4c57b30f00fd454b87e82fcd67112 [formerly dc6b58445f316c3687ba920a00488c57c23b098e]]]]
Former-commit-id: 47e67514b5603479a24acdd0c0853fd10cd999d1 [formerly 458053ffe5556cce2b1d596adc9a5bcb4003cfa4] [formerly 4a427b91be6df2877e181b751e0290c4713021f8 [formerly bd5480ea37d45c744e7c933058cf2c3e436df8d6]]
Former-commit-id: b99cac51004ba3a1af5249832f42a80958ed6f69 [formerly 82ea2a4277a54fc362ac2192e659a3c0762f84dd]
Former-commit-id: 9dcc191f4048a7be8e9f66b452079883e8018452
Former-commit-id: 835b4fdefc041eb8e725ec7fba00d0fc29c7a937

--- test/tests/lurker_scenario.coffee
+++ test/tests/lurker_scenario.coffee
@@ -15,6 +15,7 @@
   - when navigating back to the user profile page from e.g. a user's point, does not check nav behavior of closing the point
   - lurking on an inactive proposal
   - lurking on a no-activity proposal
+  - going to right page after opening and closing points and positions
 ###


fixup: fix month abbr

fixup: fix month abbr

--- tests_javascript/test_util.coffee
+++ tests_javascript/test_util.coffee
@@ -4,20 +4,6 @@
 util = require '../evesrp/static/js/util'

 suite 'Utilities', () ->
-
-    test 'Should return the abbreviated month for the given int', () ->
-        assert.strictEqual (util.monthAbbr 0), 'Jan'
-        assert.strictEqual (util.monthAbbr 1), 'Feb'
-        assert.strictEqual (util.monthAbbr 2), 'Mar'
-        assert.strictEqual (util.monthAbbr 3), 'Apr'
-        assert.strictEqual (util.monthAbbr 4), 'May'
-        assert.strictEqual (util.monthAbbr 5), 'Jun'
-        assert.strictEqual (util.monthAbbr 6), 'Jul'
-        assert.strictEqual (util.monthAbbr 7), 'Aug'
-        assert.strictEqual (util.monthAbbr 8), 'Sep'
-        assert.strictEqual (util.monthAbbr 9), 'Oct'
-        assert.strictEqual (util.monthAbbr 10), 'Nov'
-        assert.strictEqual (util.monthAbbr 11), 'Dec'

     test 'Should return the Bootstrap color label for the given status', () ->
         assert.strictEqual (util.statusColor 'evaluating'), 'warning'


page title underscores -> dashes

page title underscores -> dashes

--- src/scripts/helpers/handlebars/trim.coffee
+++ src/scripts/helpers/handlebars/trim.coffee
@@ -1,7 +1,7 @@
 define (require) ->
   Handlebars = require('hbs/handlebars')

-  trim = (str = '') -> str.replace(/\s/g, '_').substring(0, 30)
+  trim = (str = '') -> str.replace(/\s/g, '-').substring(0, 30)

   Handlebars.registerHelper 'trim', (str) -> trim(str)


fix history issue, fix anchor link position

--- src/scripts/modules/media/body/body.coffee
+++ src/scripts/modules/media/body/body.coffee
@@ -69,7 +69,8 @@
       currentRoute = Backbone.history.getFragment()
       canonicalPath = linksHelper.getPath('contents', {model: @model, page: pageId}, []) + window.location.hash
       if (canonicalPath isnt "/#{currentRoute}")
-        router.navigate(canonicalPath, {replace: true})
+        # replace previous URL with the canonical path
+        history.replaceState({}, @model.get('title'), canonicalPath)

     updateTeacher: ($temp = @$el) ->
       $els = $temp.find('.os-teacher')
@@ -81,7 +82,8 @@

     goToPage: (pageNumber, href) ->
       @model.setPage(pageNumber)
-      router.navigate href, {trigger: false}, => @parent.parent.parent.trackAnalytics()
+
+      router.navigate href, {trigger: true, replace: false}, => @parent.parent.parent.trackAnalytics()

     getCoach: ->
       moduleUUID = @model.getUuid()?.split('?')[0]
@@ -440,8 +442,8 @@
         @jaxing = false
         @processCoachMath?()

-      # Update the hash fragment after the content has loaded
-      # to force the browser window to find the intended content
+      # Clear and replace the hash fragment after the content has loaded
+      # to force the browser window to find the intended content (as a side effect)
       jumpToHash = () =>
         if currentPage.get('loaded') and not @fragmentReloaded and window.location.hash
           @fragmentReloaded = true
@@ -449,11 +451,16 @@
           window.location.hash = ''
           window.location.hash = hash

+          # scroll up by width of nav bar
+          # FIXME - make this dynamic
+          window.scrollBy(0, -145)
+
       $target = $(window.location.hash)
       if $target.prop('tagName')?.toLowerCase() is 'iframe'
         $target.on('load', jumpToHash)
       else
         jumpToHash()
+

     changePage: (e) ->
       # Don't intercept cmd/ctrl-clicks intended to open a link in a new tab


Unfocus spec

Unfocus spec

--- spec/language-haskell-spec.coffee
+++ spec/language-haskell-spec.coffee
@@ -532,7 +532,7 @@
           [5, ['punctuation.definition.quasiquotes.end.haskell']]
           ]]

-    fit "parses qualified quasiquotes", ->
+    it "parses qualified quasiquotes", ->
       g = grammarExpect grammar, '[Some.Module.Name.q| do maybe String|]'
       g.toHaveTokens [['[', 'Some.Module.Name.', 'q', '|', ' do maybe String', '|', ']']]
       g.toHaveScopes [['source.haskell']]


:fire: runs ->

:fire: runs ->

--- spec/markdown-preview-spec.coffee
+++ spec/markdown-preview-spec.coffee
@@ -351,8 +351,7 @@

   describe "when there is an image with a relative path and no directory", ->
     it "does not alter the image src", ->
-      runs ->
-        atom.project.removePath(projectPath) for projectPath in atom.project.getPaths()
+      atom.project.removePath(projectPath) for projectPath in atom.project.getPaths()

       filePath = path.join(temp.mkdirSync('atom'), 'bar.md')
       fs.writeFileSync(filePath, "![rel path](/foo.png)")


:green_heart: Fix TextDecorationLayer API specs in TokenizedBuffer

--- spec/tokenized-buffer-spec.coffee
+++ spec/tokenized-buffer-spec.coffee
@@ -1064,22 +1064,13 @@
         iterator = tokenizedBuffer.buildIterator()
         iterator.seek(Point(0, 0))

-        boundaries = []
-        loop
-          boundaries.push({
-            position: iterator.getPosition(),
-            closeTags: iterator.getCloseTags(),
-            openTags: iterator.getOpenTags()
-          })
-          break unless iterator.moveToSuccessor()
-
-        expect(boundaries).toEqual([
+        expectedBoundaries = [
           {position: Point(0, 0), closeTags: [], openTags: ["source.js", "storage.type.var.js"]}
           {position: Point(0, 3), closeTags: ["storage.type.var.js"], openTags: []}
           {position: Point(0, 8), closeTags: [], openTags: ["keyword.operator.assignment.js"]}
           {position: Point(0, 9), closeTags: ["keyword.operator.assignment.js"], openTags: []}
-          {position: Point(0, 10), closeTags: [], openTags: ["constant.numeric.js"]}
-          {position: Point(0, 11), closeTags: ["constant.numeric.js"], openTags: []}
+          {position: Point(0, 10), closeTags: [], openTags: ["constant.numeric.decimal.js"]}
+          {position: Point(0, 11), closeTags: ["constant.numeric.decimal.js"], openTags: []}
           {position: Point(0, 12), closeTags: [], openTags: ["comment.block.js", "punctuation.definition.comment.js"]}
           {position: Point(0, 14), closeTags: ["punctuation.definition.comment.js"], openTags: []}
           {position: Point(1, 5), closeTags: [], openTags: ["punctuation.definition.comment.js"]}
@@ -1087,9 +1078,19 @@
           {position: Point(1, 10), closeTags: ["storage.type.var.js"], openTags: []}
           {position: Point(1, 15), closeTags: [], openTags: ["keyword.operator.assignment.js"]}
           {position: Point(1, 16), closeTags: ["keyword.operator.assignment.js"], openTags: []}
-          {position: Point(1, 17), closeTags: [], openTags: ["constant.numeric.js"]}
-          {position: Point(1, 18), closeTags: ["constant.numeric.js"], openTags: []}
-        ])
+          {position: Point(1, 17), closeTags: [], openTags: ["constant.numeric.decimal.js"]}
+          {position: Point(1, 18), closeTags: ["constant.numeric.decimal.js"], openTags: []}
+        ]
+
+        loop
+          boundary = {
+            position: iterator.getPosition(),
+            closeTags: iterator.getCloseTags(),
+            openTags: iterator.getOpenTags()
+          }
+
+          expect(boundary).toEqual(expectedBoundaries.shift())
+          break unless iterator.moveToSuccessor()

         expect(iterator.seek(Point(0, 1))).toEqual(["source.js", "storage.type.var.js"])
         expect(iterator.getPosition()).toEqual(Point(0, 3))
@@ -1097,7 +1098,7 @@
         expect(iterator.getPosition()).toEqual(Point(0, 8))
         expect(iterator.seek(Point(1, 0))).toEqual(["source.js", "comment.block.js"])
         expect(iterator.getPosition()).toEqual(Point(1, 5))
-        expect(iterator.seek(Point(1, 18))).toEqual(["source.js", "constant.numeric.js"])
+        expect(iterator.seek(Point(1, 18))).toEqual(["source.js", "constant.numeric.decimal.js"])
         expect(iterator.getPosition()).toEqual(Point(1, 18))

         expect(iterator.seek(Point(2, 0))).toEqual(["source.js"])


fix(sorting): Remove debug messages (#61)

--- src/coffee/csv/categorysort.coffee
+++ src/coffee/csv/categorysort.coffee
@@ -45,8 +45,7 @@

     outBuffer.push(rows.shift())
     header = outBuffer[0].split(',')
-    console.log outBuffer, header
-    debugger
+
     # preprocess: parse id and parentIds
     rows.forEach (row) =>
       if row.length
@@ -80,8 +79,7 @@

         outBuffer = outBuffer.concat _.pluck(dataToProcess, 'row')
         dataToProcess = []
-    debugger
-    console.log outBuffer
+
     fs.writeFileSync(fileOut, outBuffer.join('\n'), 'utf-8')

 module.exports = CategorySort


Add shows findall and load url from env

Add shows findall and load url from env

--- node_modules/application/models/show.coffee
+++ node_modules/application/models/show.coffee
@@ -6,7 +6,13 @@

   self.findByName = (name, callback) ->
     request
-      .get('localhost:3000/shows/' + name)
+      .get([process.env.API_URL, 'shows', name].join('/'))
+      .end (err, res) ->
+        callback res.body
+
+  self.findAll = (callback) ->
+    request
+      .get([process.env.API_URL, 'shows'].join('/'))
       .end (err, res) ->
         callback res.body


update dev tools on debug #2

update dev tools on debug #2

--- lib/app.coffee
+++ lib/app.coffee
@@ -1,7 +1,7 @@
 $ = jQuery = require 'jquery'
 View = require './view'
 favicon = require 'favicon'
-{settings} = packageFile
+{settings} = require '../package.json'

 module.exports =
 class App extends View


Get a `req.ip` we can use anywhere.

Get a `req.ip` we can use anywhere.

--- lib/app.coffee
+++ lib/app.coffee
@@ -11,6 +11,9 @@

 ## Set up the app
 module.exports = app = express()
+
+# Heroku forwards our clients with `X-Forarded-For`
+app.set 'trust proxy', true

 # Logging
 app.use morgan('short')


fixed some typo on comments

fixed some typo on comments

--- app/_src/helpers/rio-images-loaded.coffee
+++ app/_src/helpers/rio-images-loaded.coffee
@@ -1,19 +1,20 @@
-# Helper that returns a promise with the of the loading images.
+# Helper that returns a promise with the status of the loading images.
+#
 # For example, if you want to animate a section only when
 # all images have been loaded through Responsive.io.
 #
-# E.g.:
+# E.g. usage:
 #
 # refreshImages: ($images) ->
-# 	i = 0
 # 	imagesLen = $images.length
 # 	imagesLoaded = new FOURTEEN.RIOImagesLoaded( $images )
 # 	for i in [0..imagesLen] do ResponsiveIO.refresh( $images[i] )
 #
 # init: () =>
 # 	$.when( imagesLoaded.getState() ).done =>
-# 		# hide spinner..
-# 		# animate stuff....
+# 		# hide spinner...
+# 		# animate stuff...
+# 		# etc...
 #

 class FOURTEEN.RIOImagesLoaded


callback issues

callback issues

--- app/assets/javascripts/is_building.coffee
+++ app/assets/javascripts/is_building.coffee
@@ -66,8 +66,10 @@
 		$.get("/fixer/flag",
 			i: @currentPolygon.id
 			f: type
-			, () ->
-				fixer.showNextPolygon()
+			# , () ->
+			# 	fixer.showNextPolygon()
+		).done( () ->
+			fixer.showNextPolygon()
 		).fail( () ->
 			fixer.showNextPolygon()
 		)


remember to animate the html element so the smooth scrolling also works in firefox

--- app/assets/javascripts/static_page.coffee
+++ app/assets/javascripts/static_page.coffee
@@ -19,7 +19,7 @@
     # get href from the link clicked
     $target = $($(this).attr('href'))

-    $('body').stop().animate {
+    $('body,html').stop().animate {
       'scrollTop': Math.abs($('#index-banner').offset().top) +
         $target.position().top -
         $('#navigation').height() + 1


Add create comment keyboard shoutcut.

Add create comment keyboard shoutcut.

--- app/assets/javascripts/undersky.js.coffee
+++ app/assets/javascripts/undersky.js.coffee
@@ -241,6 +241,9 @@

       @show: (e) ->
         e && e.preventDefault()
+        container = $('.modal.create-comment')
+        if container.size() > 0
+          return container.find('textarea').focus()
         self = $(this)
         panel = self.parents('.modal.media-panel')
         caption_data = panel.find('.caption').children()
@@ -326,12 +329,21 @@
           self = $(this)
           self.find('input, textarea').each(-> $(this).enableElement())

+      @action: (e) ->
+        return if $(e.target).isInput()
+        return if e.which != 67 # c
+        panel = $('.modal.media-panel.show')
+        return if panel.size() == 0
+        e && e.preventDefault()
+        panel.find('.comments-button.create-comment a').click()
+
       do ->
         $d.delegate '.comments-button.create-comment a', 'click', self.show
         $d.delegate '.modal.create-comment .username a', 'click', self.reply
         $d.delegate '.modal.create-comment [name="text"]', 'keyup change', self.validate
         $d.delegate '.modal.create-comment [name="cancel"]', 'click', self.hide
         $('.modal.create-comment form').bindAjaxHandler self.handler
+        $d.keydown self.action

   class Relationships
     self = this


Render demand visualizer legend in separate function

--- app/coffeescripts/DemandVisualizer.coffee
+++ app/coffeescripts/DemandVisualizer.coffee
@@ -31,32 +31,8 @@
     windowContent = constSpan + table
     @$el.html @vizWindow(elemId: @link.id, content: windowContent)

-  renderGraph: (sel) ->
-    textSizeImprecisionOffset = 2
-    labelFontSize = 10
-    width = 450
-    height = 400
-    padding = 50
-
-    @graph = d3.select(sel).append('svg:svg').
-      attr('width', width + padding).
-      attr('height', height + padding)
-
-    @graph.append("svg:rect").
-      attr("width", width + padding).
-      attr("height", height + padding).
-      attr("fill", 'white')
-
-    @graph.append("svg:rect").
-      attr('id', 'legend').
-      attr('x', 5).
-      attr('y', 5).
-      attr('width', width + padding - 10).
-      attr('height', padding - 12).
-      attr('fill', 'white').
-      attr('stroke', 'lightGray')
-
-    @graph.append('svg:text').
+  renderLegend: (graphEl) ->
+    graphEl.append('svg:text').
       attr('x', 10).
       attr('y', 30).
       style('font-size', '20px').
@@ -65,14 +41,14 @@
     _.each @typeOrder.get('vehicle_type'), (vtype, idx) =>
       name = vtype.get('name')

-      @graph.append('svg:text').
+      graphEl.append('svg:text').
         attr('x', 100 + 50*idx).
         attr('y', 30).
         style('font-size', '14px').
         style('background-color', vehicleTypeColors[idx]).
         text(name)

-      @graph.append('svg:rect').
+      graphEl.append('svg:rect').
         attr('id', "legend-#{idx}").
         attr('x', 100 + 50*idx).
         attr('y', 10).
@@ -92,6 +68,33 @@
             el.attr('enabled', true)
             d3.selectAll(".vehicle-graph-#{idx}").style('visibility','visible')

+  renderGraph: (sel) ->
+    textSizeImprecisionOffset = 2
+    labelFontSize = 10
+    width = 450
+    height = 400
+    padding = 50
+
+    @graph = d3.select(sel).append('svg:svg').
+      attr('width', width + padding).
+      attr('height', height + padding)
+
+    @graph.append("svg:rect").
+      attr("width", width + padding).
+      attr("height", height + padding).
+      attr("fill", 'white')
+
+    @graph.append("svg:rect").
+      attr('id', 'legend').
+      attr('x', 5).
+      attr('y', 5).
+      attr('width', width + padding - 10).
+      attr('height', padding - 12).
+      attr('fill', 'white').
+      attr('stroke', 'lightGray')
+
+    @renderLegend(@graph)
+
     vals = @demand.demands_by_vehicle_type()

     if vals.length > 0


simplifyClaims: added support for wikibase-property datatype

--- src/helpers/simplify_claims.coffee
+++ src/helpers/simplify_claims.coffee
@@ -31,7 +31,7 @@
   switch datatype
     when 'string', 'commonsMedia', 'url', 'external-id' then return datavalue.value
     when 'monolingualtext' then return datavalue.value.text
-    when 'wikibase-item' then return 'Q' + datavalue.value['numeric-id']
+    when 'wikibase-item', 'wikibase-property' then return datavalue.value.id
     when 'time' then return helpers.normalizeWikidataTime datavalue.value.time
     when 'globe-coordinate' then return getLatLngFromCoordinates datavalue.value
     else return null


group HEAD.changes with branch.changes

group HEAD.changes with branch.changes

--- content/gitoe-repo.coffee
+++ content/gitoe-repo.coffee
@@ -7,6 +7,18 @@

 clone = (obj)->
   $.extend {}, obj
+
+strcmp = (str1, str2, pos = 0)->
+  c1 = str1.charAt( pos )
+  c2 = str2.charAt( pos )
+  if c1 < c2
+    return 1
+  else if c1 > c2
+    return -1
+  else if c1 == '' # which means c2 == ''
+    return 0
+  else
+    return strcmp(str1, str2, pos+1)

 class DAGtopo
   constructor: ()->
@@ -86,27 +98,30 @@

   parse_repo : (repo)->
     # repo :: { ref: logs }
-    parsed_changes = []
-    repo.HEAD ?= { log: [] }
-
-    all_changes = []
+    reflog_head     = []
+    reflog_branches = []
     for branch, content of repo
-      #if branch isnt "HEAD"
+      if branch is 'HEAD'
+        cumulator = reflog_head
+      else
+        cumulator = reflog_branches
       for change in content.log
         change["branch"] = branch
-        all_changes.push {
+        cumulator.push {
           time: change.committer.time
           branch: branch
           message: change.message
+          oid_old: change.oid_old
+          oid_new: change.oid_new
           # orig: change
         }
-    all_changes.sort (a,b)->( (a.time - b.time) or (b.branch - a.branch) )
-    console.log JSON.stringify all_changes
-    all_changes
-  split_head: (changes, head)->
-
-
-    all_changes
+    reflog_branches.sort (a,b)->( a.time - b.time )
+    for change in reflog_branches
+      while reflog_head.length > 0 and reflog_head[0].time <= change.time
+        change.head ?= []
+        change.head.push reflog_head.shift()
+    console.log reflog_branches
+    []

 class GitoeRepo
   constructor: ()->


Add IPC API: foreach

Add IPC API: foreach

--- lib/ipc.coffee
+++ lib/ipc.coffee
@@ -8,26 +8,29 @@
 #   remote = require('electron').remote
 #   ipc = remote.require('./lib/ipc')
 #
-#   ipc.register("plugin-name", {
-#     api_name:   @ref_to_function.bind(@)
-#     api_name2:  @ref_to_function_2.bind(@)
+#   ipc.register("scope_name", {
+#     api_name:   @ref_to_function
+#     api_name2:  @ref_to_function_2
 #   })
 #
-#   ipc.unregister("plugin-name", "api_name")
-#   ipc.unregister("plugin-name", ["api_name", "api_name2"])
-#   ipc.unregister("plugin-name", {
+#   ipc.unregister("scope_name", "api_name")
+#   ipc.unregister("scope_name", ["api_name", "api_name_2"])
+#   ipc.unregister("scope_name", {
 #     api_name:   @whatever
-#     api_name2:  @whatever
+#     api_name_2: @whatever
 #   })
 #
-#   plugin = ipc.access("plugin-name")
-#   if plugin?
-#     plugin.api_name(args)
+#   ipc.unregisterAll("scope_name")
+#
+#   scope = ipc.access("scope_name")
+#   scope?.api_name?(args)
+#
+#   ipc.foreach("api_name", arg1, arg2, ...)
 #

 class IPC
   constructor: ->
-    @data = {}
+    @data = new Object()

   # scope:  string
   # opts:   key-func Object
@@ -40,6 +43,7 @@
     @unregister(scope, Object.keys(opts))
     for key, func of opts
       @data[scope][key] = func
+    return

   # scope:  string
   # keys:   string / Array of string / key-func Object
@@ -55,6 +59,7 @@
       keys = Object.keys(opts)
     for key in keys
       delete @data[scope][key]
+    return

   unregisterAll: (scope) ->
     delete @data[scope]
@@ -62,4 +67,12 @@
   access: (scope) ->
     return @data[scope]

+  # key:    string
+  # args:   arguments passing to api
+  foreach: (key, args...) ->
+    for scope, apis of @data
+      if apis.hasOwnProperty(key)
+        apis[key].apply(null, args)
+    return
+
 module.exports = new IPC()


Don't crash if the query params are invalid json

--- lib/nbi.coffee
+++ lib/nbi.coffee
@@ -339,7 +339,10 @@

       func = (aliases) ->
         if urlParts.query.query?
-          q = JSON.parse(urlParts.query.query)
+          try
+            q = JSON.parse(urlParts.query.query)
+          catch e
+            q = {}
         else
           q = {}
         q = query.expand(q, aliases) if collectionName is 'devices'


mac fix

mac fix

--- lib/watch.iced
+++ lib/watch.iced
@@ -13,15 +13,23 @@

   await helpers.loadConfig(defer(err, config, projDir))

-  watcher = chokidar.watch('.', {
-    ignored: /[\/\\]\./
-    persistent: true
-    ignoreInitial: true
-    usePolling: true
-    interval: 500
-    binaryInterval: 500
-    cwd: projDir
-  })
+  if process.platform is "darwin"
+    watcher = chokidar.watch('.', {
+      ignored: /[\/\\]\./
+      persistent: true
+      ignoreInitial: true
+      cwd: projDir
+    })
+  else
+    watcher = chokidar.watch('.', {
+      ignored: /[\/\\]\./
+      persistent: true
+      ignoreInitial: true
+      usePolling: true
+      interval: 500
+      binaryInterval: 500
+      cwd: projDir
+    })

   watcher.on('all', (event, filepath) ->
     # console.log event, filepath


Disable dragging when a resizing.

Disable dragging when a resizing.

--- src/resizable/ResizableView.coffee
+++ src/resizable/ResizableView.coffee
@@ -3,6 +3,7 @@
 #
 # @module stout-ui/resizable/ResizableView
 ###
+Draggable  = require '../traits/Draggable'
 Foundation = require 'stout-core/base/Foundation'
 isString   = require 'lodash/isString'
 vars       = require '../vars'
@@ -343,6 +344,13 @@
   else
     @__resizeDir = null

+  # Disable dragging when inside resizable area.
+  if @usingTrait Draggable
+    if @__resizeDir
+      @draggable = false
+    else
+      @draggable = true
+
   # Add appropriate listeners and set cursor classes.
   if nesw
     @classes.add NESW_CURSOR_CLASS


$apply inside seek so it's snappy

$apply inside seek so it's snappy

--- src/scripts/directives/seek.coffee
+++ src/scripts/directives/seek.coffee
@@ -7,6 +7,7 @@
                 x = e.offsetX or e.layerX
                 progress = x / e.target?.offsetWidth
                 if progress
-                    scope.player.seek progress
+                    scope.$apply ->
+                        scope.player.seek progress
     }
 ])


small correction on archive request

small correction on archive request

--- app/models/task.coffee
+++ app/models/task.coffee
@@ -10,8 +10,8 @@
         Task.request "archive", callback
     else
         params =
-            startkey: [listId, {}]
-            endkey: [listId + "0", {}]
+            startkey: [listId]
+            endkey: [listId + "0"]
             limit: 30
         Task.request "archiveList", params, callback


adds berlin to location (closes #94)

adds berlin to location (closes #94)

--- maps/contributors.coffee
+++ maps/contributors.coffee
@@ -229,7 +229,7 @@
   ,
   {
     name: 'Sascha Pohflepp'
-    location: 'San Diego'
+    location: 'Berlin'
     links: ['[pohflepp.net](http://pohflepp.net/)', '[@plugimi](https://twitter.com/plugimi)']
     bio: 'Sascha Pohflepp is a German-born artist, researcher and writer. Notable exhibitions include Talk To Me at MoMA New York, _Hyperlinks_ at the Art Institute of Chicago, _ Micro Impact_ at Boijmans Van Beuningen Museum Rotterdam, _Pre-History of the Image_ at STUK Kunstencentrum Leuven, and _Science Fiction: New Death_ at FACT Liverpool. Pohflepp’s work has won two Honorary Mentions from the VIDA Art and Artificial Life Awards and in June 2015 was shortlisted for the Berlin Art Prize.'
     azone_username: ''


keller easterling bio

keller easterling bio

--- maps/contributors.coffee
+++ maps/contributors.coffee
@@ -59,9 +59,9 @@
   ,
   {
     name: 'Keller Easterling'
-    location: 'New York and New Haven'
+    location: 'New York'
     links: ['[kellereasterling.com](http://kellereasterling.com/)', '[extrastatecraft.net](http://extrastatecraft.net/Projects)']
-    bio: 'Keller Easterling is an architect, writer, and professor at Yale University. Easterling’s research and writing was included in the 2014 Venice Biennale, and her work has been exhibited at the Architectural League, New York; the Rotterdam Biennale; and Storefront for Art and Architecture, New York. Easterling has lectured and published widely in the United States and abroad.'
+    bio: 'Keller Easterling is an architect, writer, and professor at Yale University who considers space as a heavy information system, a portfolio of assets, and a medium of global polity. Two of Easterling’s most recent books are #[em Extrastatecraft: the power of Infrastructure Space] (2014) and #[em Subtraction] (2014). Her research and writing was included in the 2014 Venice Biennale.'
     azone_username: ''
     azone_reviews: []
     azone_funds: []


Add some easy translations. (#5633)

Add some easy translations. (#5633)


Fix supermodel.trackModel

Fix supermodel.trackModel

--- app/models/SuperModel.coffee
+++ app/models/SuperModel.coffee
@@ -83,7 +83,7 @@

   # Eventually should use only these functions. Use SuperModel just to track progress.
   trackModel: (model, value) ->
-    res = @addModelResource(collection, '', {}, value)
+    res = @addModelResource(model, '', {}, value)
     res.listen()

   trackCollection: (collection, value) ->


Fix cleanup at end of level

Fix cleanup at end of level

--- app/scripts/lib/Level.coffee
+++ app/scripts/lib/Level.coffee
@@ -243,7 +243,7 @@
     Crafty.unbind('EnterBlock')
     Crafty.unbind('ShipSpawned')
     Crafty.unbind('ViewportScroll')
-    b.clean() for b in @blocks
+    b?.clean() for b in @blocks

   _update: ->
     @generationDefinition ?= 0


account: show a loader when emails are being loaded

--- client/account/lib/views/accountemailnotifications.coffee
+++ client/account/lib/views/accountemailnotifications.coffee
@@ -12,9 +12,17 @@

   viewAppended: ->

+    @addSubView loader = new kd.LoaderView
+      cssClass   : 'AccountEmailNotifications-loader'
+      showLoader : yes
+      size       :
+        width    : 25
+        height   : 25
+
     whoami().fetchEmailFrequency (err, frequency) =>
       @putContents frequency or {}
       @handleGlobalState frequency.global
+      loader.destroy()

     @on 'EmailPrefSwitched', (flag, state) => @["handle#{flag.capitalize()}State"]? state


Used a default, rather than Math.max

Used a default, rather than Math.max

--- client/app/lib/providers/environmentsprogressmodal.coffee
+++ client/app/lib/providers/environmentsprogressmodal.coffee
@@ -115,8 +115,8 @@
    *
    * @param {Number} percentage - The percentage to set the bar to.
   ###
-  updatePercentage: (percentage) ->
+  updatePercentage: (percentage = 10) ->

-    @progressBar.updateBar Math.max percentage, 10
+    @progressBar.updateBar percentage


provider google instead of GooglePlus

provider google instead of GooglePlus

--- app/scripts/services/auth-service.coffee
+++ app/scripts/services/auth-service.coffee
@@ -73,7 +73,7 @@

   googleLogin: (callback) =>
     @GooglePlus.login().then((authResult) =>
-      @setSignIn('GooglePlus', authResult.access_token).then((response) =>
+      @setSignIn('google', authResult.access_token).then((response) =>
         if response.data.authenticated
           @isAuthenticated = true
           @location.url @options['redirectWhenLogin']


update patterns

update patterns


singleton class - extend from it.

singleton class - extend from it.

--- app/static/coffee/Components/meta.coffee
+++ app/static/coffee/Components/meta.coffee
@@ -1,7 +1,12 @@
 #Move headers and genomes to meta class
 #Follow tutorial to get asych requests

-
+class Singleton
+    instance = null
+    @get:(data)->
+        instance ?= new @(data)
+        return instance
+
 class Meta_Data
     headers = []
     genomes = []


Hooked up new inventory recommendations for new levels.

--- app/views/game-menu/InventoryView.coffee
+++ app/views/game-menu/InventoryView.coffee
@@ -348,14 +348,22 @@
       'gems-in-the-deep': {feet: 'simple-boots'}
       'forgetful-gemsmith': {feet: 'simple-boots'}
       'shadow-guard': {feet: 'simple-boots'}
+      'kounter-kithwise': {feet: 'simple-boots'}
+      'crawlways-of-kithgard': {feet: 'simple-boots'}
       'true-names': {feet: 'simple-boots', 'right-hand': 'simple-sword'}
+      'favorable-odds': {feet: 'simple-boots', 'right-hand': 'simple-sword'}
       'the-raised-sword': {feet: 'simple-boots', 'right-hand': 'simple-sword', torso: 'leather-tunic'}
       'the-first-kithmaze': {feet: 'simple-boots', 'programming-book': 'programmaticon-i'}
+      'descending-further': {feet: 'simple-boots', 'programming-book': 'programmaticon-i'}
       'the-second-kithmaze': {feet: 'simple-boots', 'programming-book': 'programmaticon-i'}
       'new-sight': {'right-hand': 'simple-sword', 'programming-book': 'programmaticon-i'}
+      'known-enemy': {'right-hand': 'simple-sword', 'programming-book': 'programmaticon-i'}
+      'master-of-names': {feet: 'simple-boots', 'right-hand': 'simple-sword', 'programming-book': 'programmaticon-i', eyes: 'crude-wooden-glasses'}
       'lowly-kithmen': {feet: 'simple-boots', 'right-hand': 'simple-sword', 'programming-book': 'programmaticon-i', eyes: 'crude-wooden-glasses'}
       'closing-the-distance': {feet: 'simple-boots', 'right-hand': 'simple-sword', torso: 'leather-tunic', eyes: 'crude-wooden-glasses'}
+      'tactical-strike': {feet: 'simple-boots', 'right-hand': 'simple-sword', torso: 'leather-tunic', eyes: 'crude-wooden-glasses'}
       'the-final-kithmaze': {feet: 'simple-boots', 'right-hand': 'simple-sword', torso: 'leather-tunic', 'programming-book': 'programmaticon-i', eyes: 'crude-wooden-glasses'}
+      'the-gauntlet': {feet: 'simple-boots', 'right-hand': 'simple-sword', torso: 'leather-tunic', 'programming-book': 'programmaticon-i', eyes: 'crude-wooden-glasses'}
       'kithgard-gates': {feet: 'simple-boots', 'right-hand': 'builders-hammer', torso: 'leather-tunic'}
       'defense-of-plainswood': {feet: 'simple-boots', 'right-hand': 'builders-hammer'}
       'winding-trail': {feet: 'leather-boots', 'right-hand': 'builders-hammer'}


Add a comment line to removeItem method.

--- client/account/lib/views/accountsshkeylistcontroller.coffee
+++ client/account/lib/views/accountsshkeylistcontroller.coffee
@@ -139,7 +139,9 @@
     @sshKeyHelpLink?.show()

-  # Override parent method and use it for different thing.
+  # Override parent method.
+  # We don't need to use removeItem method of KodingListController.
+  # Because it shows a confirm dialog and continues to work according to response of confirm.
   removeItem: (item) ->

     @getListView().removeItem item


temporarily avoid exception in ace event handler

full fix will be to use the angular $http cancellation mechanism

--- services/web/public/coffee/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.coffee
+++ services/web/public/coffee/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.coffee
@@ -23,8 +23,8 @@

 			@editor.on "changeSession", (e) =>
 				@highlightedWordManager.reset()
-				if @inProgressRequest?
-					@inProgressRequest.abort()
+				# if @inProgressRequest?
+				# 	@inProgressRequest.abort()

 				if @$scope.spellCheckEnabled and @$scope.spellCheckLanguage and @$scope.spellCheckLanguage != ""
 					@runSpellCheckSoon(200)


Minor modifications

Minor modifications


Include eco compiler in bokeh-compiler bundle

--- bokehjs/src/coffee/compiler/main.coffee
+++ bokehjs/src/coffee/compiler/main.coffee
@@ -1 +1,2 @@
 coffee = require "coffee-script"
+eco = require "eco"


Attribute is "prop", singular

Attribute is "prop", singular

--- client/lanes/react/mixins/Screen.coffee
+++ client/lanes/react/mixins/Screen.coffee
@@ -5,8 +5,8 @@
     listenNetworkEvents: true

     loadOrCreateModel: (options) ->
-        if options.prop and @props[options.props]
-            @props[options.props]
+        if options.prop and @props[options.prop]
+            @props[options.prop]
         else
             model = new options.klass
             if options.attribute and @props.args?.length


whitespace trim

whitespace trim

--- cms/static/coffee/src/views/unit.coffee
+++ cms/static/coffee/src/views/unit.coffee
@@ -190,7 +190,7 @@

     # save the name after a slight delay
     if @timer
-      clearTimeout @timer
+      clearTimeout @timer
     @timer = setTimeout( =>
       @model.save()
       @timer = null


Remove specialist_feedback test

Remove specialist_feedback test

--- components/simple_contact/test/specialist_feedback.coffee
+++ components/simple_contact/test/specialist_feedback.coffee
@@ -1,72 +0,0 @@
-benv = require 'benv'
-sinon = require 'sinon'
-Backbone = require 'backbone'
-{ fabricate } = require 'antigravity'
-CurrentUser = require '../../../models/current_user'
-SpecialistFeedbackView = benv.requireWithJadeify require.resolve('../views/specialist_feedback'), ['template']
-
-describe 'SpecialistFeedbackView', ->
-  before (done) ->
-    benv.setup ->
-      benv.expose $: benv.require 'jquery'
-      Backbone.$ = $
-      done()
-
-  after ->
-    benv.teardown()
-
-  beforeEach ->
-    @view = new SpecialistFeedbackView
-    sinon.stub Backbone, 'sync'
-      .yieldsTo 'success'
-
-  afterEach ->
-    Backbone.sync.restore()
-
-  describe 'logged out', ->
-    beforeEach ->
-      @view.render()
-
-    it 'renders correctly', ->
-      @view.$('h1').text().should.equal 'Send message to Artsy'
-      @view.$('textarea').attr('placeholder').should.equal 'Leave your comments'
-      @view.$('.scontact-from').should.have.lengthOf 0
-      @view.$('input[name="user_name"]').should.have.lengthOf 1
-      @view.$('input[name="user_email"]').should.have.lengthOf 1
-
-    it 'submits the feedback', ->
-      Backbone.sync.called.should.be.false()
-      @view.$('input[name="user_name"]').val 'Iam Loggedout'
-      @view.$('input[name="user_email"]').val 'foo@bar.com'
-      @view.$('textarea[name="message"]').val 'My message'
-      @view.$('button').click()
-      Backbone.sync.called.should.be.true()
-      Backbone.sync.args[0][1].url.should.containEql '/api/v1/feedback'
-      Backbone.sync.args[0][1].attributes.should.have.keys 'url', 'message', 'user_name', 'user_email'
-      Backbone.sync.args[0][1].attributes.user_name.should.equal 'Iam Loggedout'
-      Backbone.sync.args[0][1].attributes.message.should.equal 'My message'
-
-  describe 'logged in', ->
-    before ->
-      sinon.stub(CurrentUser, 'orNull')
-        .returns new CurrentUser(fabricate 'user', name: 'Iam Loggedin')
-
-    after ->
-      CurrentUser.orNull.restore()
-
-    beforeEach ->
-      @view.render()
-
-    it 'renders correctly', ->
-      @view.$('h1').text().should.equal 'Send message to Artsy'
-      @view.$('textarea').attr('placeholder').should.equal 'Leave your comments'
-      @view.$('.scontact-from').text().should.equal 'From: Iam Loggedin (craigspaeth@gmail.com)'
-
-    it 'submits the feedback', ->
-      Backbone.sync.called.should.be.false()
-      @view.$('textarea[name="message"]').val 'My message'
-      @view.$('button').click()
-      Backbone.sync.called.should.be.true()
-      Backbone.sync.args[0][1].url.should.containEql '/api/v1/feedback'
-      Backbone.sync.args[0][1].attributes.should.have.keys 'url', 'message', 'user_name', 'user_email'
-      Backbone.sync.args[0][1].attributes.message.should.equal 'My message'


following_id is no longer part of post

following_id is no longer part of post

--- assets/javascripts/models/post.js.coffee
+++ assets/javascripts/models/post.js.coffee
@@ -33,14 +33,7 @@
       @set 'profile', new TentStatus.Models.Profile(profile)
       return

-    if @get('following_id')
-      new HTTP 'GET', "#{TentStatus.config.tent_api_root}/followings/#{@get('following_id')}", null, (following, xhr) =>
-        return unless xhr.status == 200
-        profile = new TentStatus.Models.Profile following.profile
-        @set 'profile', profile
-        TentStatus.Cache.set cache_key, profile
-
-    else if TentStatus.config.current_entity?.hostname == (new HTTP.URI @get('entity')).hostname
+    if TentStatus.config.current_entity?.hostname == (new HTTP.URI @get('entity')).hostname
       if TentStatus.Models.profile.get('id')
         @set 'profile', TentStatus.Models.profile
         TentStatus.Cache.set cache_key, profile.toJSON()


Add comment explaining code purpose

Add comment explaining code purpose

--- core/app/assets/javascripts/local_storage_polyfill.coffee
+++ core/app/assets/javascripts/local_storage_polyfill.coffee
@@ -23,14 +23,18 @@

   window.localStorageIsEnabled = false

-bad_keys = []
-for i in [0...safeLocalStorage.length]
-  key = safeLocalStorage.key i
-  if !key.lastIndexOf('add_comment_to_fact_',0) && !safeLocalStorage.getItem key
-    bad_keys.push key
-
-for key in bad_keys
-  safeLocalStorage.removeItem key
-
 for property, value of csrfDataForLocalStorage
   window.safeLocalStorage[property] = value
+
+
+do ->
+  # Client side "migration" to delete dead keys (2014-03-26).  Eventually delete.
+  bad_keys = []
+  for i in [0...safeLocalStorage.length]
+    key = safeLocalStorage.key i
+    if !key.lastIndexOf('add_comment_to_fact_',0) && !safeLocalStorage.getItem key
+      bad_keys.push key
+
+  for key in bad_keys
+    safeLocalStorage.removeItem key
+


Increase discussion page size to 20

Increase discussion page size to 20

--- app/talk/config.coffee
+++ app/talk/config.coffee
@@ -1,6 +1,6 @@
 module?.exports =

-  discussionPageSize: 10
+  discussionPageSize: 20

   inboxPageSize: 10


Revert "Push initial values in frame 0"

Revert "Push initial values in frame 0"

This reverts commit c249f6f8407ac5b11ecb02354b18bf2adbe8d63e.

[#113117887]

--- src/code/models/simulation.coffee
+++ src/code/models/simulation.coffee
@@ -130,7 +130,7 @@
   generateFrame: (time) ->
     nodes = _.map @nodes, (node) ->
       title: node.title
-      value: if time is 0 then node.initialValue else node.currentValue
+      value: node.currentValue
     frame =
       time: time
       nodes: nodes
@@ -149,9 +149,6 @@

     nodeNames = _.pluck @nodes, 'title'
     @onStart(nodeNames)
-
-    # start with a single frame, to get initial values
-    @generateFrame(time)

     step = =>
       _.each @nodes, (node) => @nextStep node  # toggles previous / current val.


Console.log removed

Console.log removed

--- src/component/Footer/index.coffee
+++ src/component/Footer/index.coffee
@@ -4,8 +4,6 @@
 define ['App'], (App) ->

 	App.module 'Footer', (Module, a, Backbone, Marionette, $, _) ->
-
-		console.log('Footer')

 		class Module.Controller extends App.module('Abstract').Controller


resize echarts when window.resize

resize echarts when window.resize

--- views/akashic-resource-chart.cjsx
+++ views/akashic-resource-chart.cjsx
@@ -42,6 +42,11 @@
     @showAsDay = config.get "plugin.Akashic.resource.chart.showAsDay", true
     @showAllSymbol = config.get "plugin.Akashic.resource.chart.showAllSymbol", false
     @sleepMode = config.get "plugin.Akashic.resource.chart.sleepMode", true
+    window.onresize = ()=>
+      document.getElementById('ECharts').style.height = "#{window.remote.getCurrentWindow().getBounds().height - 150}px"
+      if @resourceChart isnt 0
+        @resourceChart.resize()
+      true
   dataFilter: (data)->
     dateString = ""
     showAsDay = @showAsDay


add class name snippet

add class name snippet

--- snippets/html.cson
+++ snippets/html.cson
@@ -11,6 +11,9 @@
         </div>
       </div>
     """
+  'Add className':
+    'prefix': 'className'
+    'body': 'className={styles.$1}'
   'Create a br':
     'prefix': 'br'
     'body': '<br />'


ActivityTicker: add caching mechanism for activity ticker

--- workers/social/lib/social/models/activityticker.coffee
+++ workers/social/lib/social/models/activityticker.coffee
@@ -184,3 +184,20 @@
         daisy queue

+  @fetch = secure (client, options = {}, callback) ->
+    # TODO - add group security here
+    requestOptions = { client, options }
+
+    if options.from or options.filters
+      @_fetch requestOptions, callback
+    else
+      Cache  = require '../cache/main'
+      feedFn = @_fetch
+      getCacheKey =-> return "activityticker"
+      Cache.fetch getCacheKey(), feedFn, requestOptions, (err, data)=>
+        # if data is not set, or it is empty
+        # fetch from db
+        if err or not data or Object.keys(data).length is 0
+          @_fetch requestOptions, callback
+        else
+          callback err, data


fixed coffeelint errors on workers/social/lib/social/models/payment/schema.coffee

--- workers/social/lib/social/models/payment/schema.coffee
+++ workers/social/lib/social/models/payment/schema.coffee
@@ -3,11 +3,13 @@
   feeUnit   :
     type    : String
     default : 'month'
-    enum    : ['fee unit should be "month" or "days"',[
+    enum    : ['fee unit should be "month" or "days"', [
       'month'
       'days'
     ]]

   tags    :
     type  :[String]
-    set   : (value) -> (value.map (tag)-> tag.trim()).filter(Boolean)
+    set   : (value) -> (value.map (tag) -> tag.trim()).filter(Boolean)
+
+


match css classes for id selector

match css classes for id selector

--- grammars/pug.cson
+++ grammars/pug.cson
@@ -865,7 +865,7 @@
     name: "constant.language.js"
   tag_id:
     match: "#[\\w-]+"
-    name: "constant.id.tag.pug"
+    name: "entity.other.attribute-name.id.pug"
   tag_mixin_attributes:
     begin: "(&attributes\\()"
     captures:


Add letter of support JS fix

Add letter of support JS fix

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -424,7 +424,7 @@

         if can_add
           add_eg = add_eg.replace(/(form\[(\w+|_)\]\[)(\d+)\]/g, "$1#{li_size+1}]")
-          question.find(".list-add").append("
#{add_eg}
")
+          question.find(".list-add").append("
#{add_eg}
")

           clear_example = question.find(".list-add").attr("data-need-to-clear-example")
           if (typeof(clear_example) != typeof(undefined) && clear_example != false)


refs #712 remove jquery_ujs

refs #712 remove jquery_ujs

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -2,7 +2,6 @@
 #= require qtip2/dist/jquery.qtip.min
 #= require jquery-ui/ui/widgets/datepicker
 #= require jquery-ui/ui/i18n/datepicker-ja
-#= require jquery_ujs
 #= require moment/moment
 #= require moment/locale/ja
 #= require d3/d3.min


Hound linter comments

Hound linter comments

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -381,7 +381,7 @@

   # Show innovation amount info when the amount is greater than 1 on innovation eligibility
   if $(".innovative_amount_input").size() > 0
-    $(".innovative_amount_input").bind "propertychange change click keyup input paste", () ->
+    $(".innovative_amount_input").bind "propertychange change click keyup input paste", ->
       if $(this).val() > 1
         $("#innovative-amount-info").removeClass("visuallyhidden")
       else
@@ -390,7 +390,7 @@
   # Show trade org fulfilled info when checked yes
   trade_org_q = ".question-organisation-fulfill-above-exceptions"
   if $(trade_org_q).size() > 0
-    $("#{trade_org_q} input[type='radio']").bind "propertychange change click keyup input paste", () ->
+    $("#{trade_org_q} input[type='radio']").bind "propertychange change click keyup input paste", ->
       radio_val = $("#{trade_org_q} input[type='radio']:checked").val()
       if radio_val == "yes"
         $("#trade-org-fulfilled-info").removeClass("visuallyhidden")


Removed twitter-text

Removed twitter-text

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -15,7 +15,6 @@
 #= require hamlcoffee
 #= require date
 #= require faye
-#= require twitter-text
 #= require autolink
 #= require select2
 #= require konami-1.3.3
@@ -35,5 +34,3 @@
 #= require_tree ./views
 #= require_tree ./routers
 #= require_tree ./modules
-#
-#


pjax failing in production ...

pjax failing in production ...

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -7,8 +7,8 @@
 #= require jquery
 #= require jquery-ui
 #= require jquery_ujs
-#= require jquery.pjax
-#= require pjax/page_triggers
+## require jquery.pjax
+## require pjax/page_triggers
 #= require slides
 #= require bootstrap
 #= require active_scaffold
@@ -18,14 +18,14 @@
   $(document).popover(selector: '[rel=popover]')
   $(document).tooltip(selector: '[rel=tooltip]')

-  pjaxContainer = '[data-pjax-container]'
-  $('.pjax-nav a:not([data-remote]):not([data-behavior]):not([data-skip-pjax])').pjax(pjaxContainer)
-  $pjaxContainer = $(pjaxContainer)
-  $pjaxContainerParent = $(pjaxContainer).parent()
-  $pjaxContainer.on 'pjax:success', (event, data, status, xhr, options) ->
-    $('.pjax-nav').find('li.active').removeClass 'active'
-    $(".pjax-nav a[href=\"#{window.location.pathname}\"]").parents('li').addClass 'active'
-    if $pjaxContainer.find('.container').length > 0
-      $pjaxContainerParent.removeClass 'container'
-    else
-      $pjaxContainerParent.addClass 'container'
+#  pjaxContainer = '[data-pjax-container]'
+#  $('.pjax-nav a:not([data-remote]):not([data-behavior]):not([data-skip-pjax])').pjax(pjaxContainer)
+#  $pjaxContainer = $(pjaxContainer)
+#  $pjaxContainerParent = $(pjaxContainer).parent()
+#  $pjaxContainer.on 'pjax:success', (event, data, status, xhr, options) ->
+#    $('.pjax-nav').find('li.active').removeClass 'active'
+#    $(".pjax-nav a[href=\"#{window.location.pathname}\"]").parents('li').addClass 'active'
+#    if $pjaxContainer.find('.container').length > 0
+#      $pjaxContainerParent.removeClass 'container'
+#    else
+#      $pjaxContainerParent.addClass 'container'


merit order: custom label for must_run item. Closes #877

--- app/assets/javascripts/d3/merit_order.coffee
+++ app/assets/javascripts/d3/merit_order.coffee
@@ -188,6 +188,8 @@
           html += "Installed capacity: #{Metric.autoscale_value(d.value_x() * 1000000, 'MW', 2)}"
           html += "
"
           html += "Operating costs: #{Metric.autoscale_value d.original_y_value(), 'euro', 2}"
+          if d.get('key') == 'must_run'
+            html += '*
* Does not participate in merit order'
           html
         )


[#65843404] Fix the bug that selectAll/clearAll does not work after ajax refresh.

--- app/assets/javascripts/settlements.js.coffee
+++ app/assets/javascripts/settlements.js.coffee
@@ -47,12 +47,13 @@
     refreshTargets()
     return false

-  $('#target_deals a.selectAll').click ->
+  $('#target_deals').on('click', 'a.selectAll', (e)->
     $('table.book input[type=checkbox]').each ->
       $(@).click() if !@checked
-    false
-
-  $('#target_deals a.clearAll').click ->
+    e.preventDefault()
+  )
+  $('#target_deals').on('click', 'a.clearAll', (e)->
     $('table.book input[type=checkbox]').each ->
       $(@).click() if @checked
-    false
+    e.preventDefault()
+  )


conn: use broker ping to check internet conn

--- client/app/MainApp/monitor_status.coffee
+++ client/app/MainApp/monitor_status.coffee
@@ -169,7 +169,7 @@
     @callback = callback
     KD.externalPong = @pong.bind(this)
     $.ajax
-      url : url+"?callback"+KD.externalPong
+      url : @url+"?callback"+KD.externalPong
       timeout: 3000
       dataType: "jsonp"
       error : ->
@@ -177,17 +177,41 @@
   pong: ->
     @callback()

-url = "https://s3.amazonaws.com/koding-ping/ping.json"
-external = new ExternalPing url
-
-monitorItems = new MonitorItems
-monitorItems.register {external}
-
-KD.troubleshoot = (showNotifications=true)->
-  monitorItems = KD.getSingleton("monitorItems").items
-  monitor = new MonitorStatus monitorItems
-  monitor.showNotifications = showNotifications
-  monitor.run()
-
-window.jsonp = ->
-  KD.externalPong()
+do ->
+  url = "https://s3.amazonaws.com/koding-ping/ping.json"
+  external = new ExternalPing url
+
+  monitorItems = new MonitorItems
+  monitorItems.register {external}
+
+  KD.troubleshoot = (showNotifications=true)->
+    monitorItems = KD.getSingleton("monitorItems").items
+    monitor = new MonitorStatus monitorItems
+    monitor.showNotifications = showNotifications
+    monitor.run()
+
+  window.jsonp = ->
+    KD.externalPong()
+
+  brokerInterval = null
+
+  pingBrokerOnInterval = ->
+    brokerInterval = setInterval ->
+      failureCallback = setTimeout ->
+        log 'broker ping failed, running troubleshoot'
+        KD.troubleshoot(false)
+      , 2000
+
+      KD.remote.ping ->
+        log 'ping callback'
+        clearTimeout failureCallback
+    , 5000
+
+  KD.remote.on 'connected', ->
+    pingBrokerOnInterval()
+    log 'connected, starting broker ping', brokerInterval
+
+  KD.remote.on 'disconnected', ->
+    clearInterval brokerInterval
+    brokerInterval = null
+    log 'disconnected, stopping broker ping', brokerInterval


create fetchotatoken action to store the token

--- client/app/lib/flux/teams/actions.coffee
+++ client/app/lib/flux/teams/actions.coffee
@@ -15,7 +15,8 @@
 kookies = require 'kookies'
 Tracker = require 'app/util/tracker'
 VerifyPasswordModal = require 'app/commonviews/verifypasswordmodal'
-
+KodingKontrol = require 'app/kite/kodingkontrol'
+globals = require 'globals'

 loadTeam = ->

@@ -346,6 +347,21 @@
   team = groupsController.getCurrentGroup()
   state = team.isApiEnabled is yes
   reactor.dispatch actions.SET_API_ACCESS_STATE, { state }
+
+fetchOtaToken = ->
+
+  { reactor } = kd.singletons
+  whoami().fetchOtaToken (err, token) ->
+
+    cmd = if err
+      "Failed to generate your command, click to try again!"
+    else
+      if globals.config.environment in ['dev', 'default', 'sandbox']
+        "export KONTROLURL=#{KodingKontrol.getKontrolUrl()}; curl -sL https://sandbox.kodi.ng/c/d/kd | bash -s #{token}"
+      else "curl -sL https://kodi.ng/c/p/kd | bash -s #{token}"
+
+    reactor.dispatch actions.FETCH_OTA_TOKEN_SUCCESS, { cmd }
+

 module.exports = {
@@ -372,4 +388,5 @@
   addApiToken
   disableApiTokens
   fetchCurrentStateOfApiAccess
+  fetchOtaToken
 }


Fix AccountSettingsView delete and reset account actions

--- app/views/account/AccountSettingsView.coffee
+++ app/views/account/AccountSettingsView.coffee
@@ -64,7 +64,7 @@
         decline: 'Cancel'
         confirm: 'DELETE Your Account'
       confirmModal = new ConfirmModal renderData
-      confirmModal.on 'confirm', @deleteAccount
+      confirmModal.on 'confirm', @deleteAccount, @
       @openModalView confirmModal

   onClickResetProgressButton: ->
@@ -75,7 +75,7 @@
         decline: 'Cancel'
         confirm: 'Erase ALL Progress'
       confirmModal = new ConfirmModal renderData
-      confirmModal.on 'confirm', @resetProgress
+      confirmModal.on 'confirm', @resetProgress, @
       @openModalView confirmModal

   onClickResendVerificationEmail: (e) ->
@@ -150,7 +150,7 @@
   resetProgress: ->
     $.ajax
       type: 'POST'
-      success: ->
+      success: =>
         noty
           timeout: 5000
           text: 'Your progress is gone.'


Maintain new window opening in Styleguide

--- ui/scripts/views/styleguide.coffee
+++ ui/scripts/views/styleguide.coffee
@@ -27,5 +27,5 @@

         openInNewWindow: (e) ->
             $target = $(e.target).closest 'a'
-            $target.target = "_blank"
+            $target[0].target = "_blank"


Fix tweet dvr name

Fix tweet dvr name

--- assets/js/controllers/home_controller.coffee
+++ assets/js/controllers/home_controller.coffee
@@ -7,7 +7,7 @@

   class HomeController extends Chaplin.Controller

-    title: 'Twitter DVR'
+    title: 'Tweet DVR'

     historyURL: (params) ->
       '/'


Use Handlebars.helper instead of registerBoundHelper

--- assets/scripts/app/helpers/handlebars.coffee
+++ assets/scripts/app/helpers/handlebars.coffee
@@ -18,8 +18,9 @@
 Ember.registerBoundHelper 'formatDuration', (duration, options) ->
   safe Travis.Helpers.timeInWords(duration)

-Ember.registerBoundHelper 'formatCommit', (commit, options) ->
+Ember.Handlebars.helper('formatCommit', (commit) ->
   safe Travis.Helpers.formatCommit(commit.get('sha'), commit.get('branch')) if commit
+, 'sha', 'branch')

 Ember.registerBoundHelper 'formatSha', (sha, options) ->
   safe Travis.Helpers.formatSha(sha)


No need to send message to embedder after it is closed

--- atom/browser/lib/guest-window-manager.coffee
+++ atom/browser/lib/guest-window-manager.coffee
@@ -21,7 +21,6 @@
   # guest is closed by user then we should prevent |embedder| from double
   # closing guest.
   closedByEmbedder = ->
-    embedder.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED', guest.id
     guest.removeListener 'closed', closedByUser
     guest.destroy()
   closedByUser = ->


LikeView: Add count as cssClass Option for ActivityLikeCount

--- client/Social/Activity/views/likeview.coffee
+++ client/Social/Activity/views/likeview.coffee
@@ -12,6 +12,7 @@
     @link = new ActivityLikeLink {}, data

     @count = new ActivityLikeCount
+      cssClass    : 'count'
       tooltip     :
         gravity   : @getOption "tooltipPosition"
         title     : ""


Markers: show implemented, various fixes

--- client/landing/Intro/markercontroller.coffee
+++ client/landing/Intro/markercontroller.coffee
@@ -23,9 +23,10 @@

     return @collection[name]

+
   reset:->

-    for own name, marker of @collection when name.search 'm_' is 0
+    for own name, marker of @collection when name.slice(2) is 'm_'

       marker._windowDidResize()

@@ -35,21 +36,35 @@
     groupName = "g_#{groupName}"
     @collection[groupName] = markers

-    return @groups[groupName]
+    return markers
+

   hide:(name)->

     # hide group if it is a group name
     if markers = @collection["g_#{name}"]
-
       marker.hide() for marker in markers

       return markers

     # hide marker if it is a marker name
     if marker = @collection["m_#{name}"]
-
       marker.hide()
+
+      return marker
+
+
+  show:(name)->
+
+    # show group if it is a group name
+    if markers = @collection["g_#{name}"]
+      marker.show() for marker in markers
+
+      return markers
+
+    # show marker if it is a marker name
+    if marker = @collection["m_#{name}"]
+      marker.show()

       return marker


Dont forget to call callback

Dont forget to call callback

--- client/landing/app/MainApp/AppStorage.coffee
+++ client/landing/app/MainApp/AppStorage.coffee
@@ -21,7 +21,7 @@

     @reset()
     @fetchStorage (storage)=>
-      if storage[group]?[key] then storage[group][key] else defaultValue
+      callback if storage[group]?[key] then storage[group][key] else defaultValue

   getValue: (key, defaultValue, group = 'bucket')->


Let people can use AppStorage

Let people can use AppStorage

--- client/landing/app/MainApp/AppStorage.coffee
+++ client/landing/app/MainApp/AppStorage.coffee
@@ -55,3 +55,6 @@
     _key = group+'.'+key
     pack[_key] = value
     pack
+
+# Let people can use AppStorage
+KD.classes.AppStorage = AppStorage


Add path in output

Add path in output

--- app/src/models/output.coffee
+++ app/src/models/output.coffee
@@ -20,5 +20,6 @@
       transaction_hash: transactionHash
       value: output['value']
       address: output['addresses'][0]
+      path: ledger.wallet.Wallet.instance.cache.getDerivationPath(output['addresses'][0])
       script_hex: output['script_hex']
     @findOrCreate(uid: uid, base, context)


Dynamically read block attribute names

Dynamically read block attribute names

--- src/trix/models/composition.coffee
+++ src/trix/models/composition.coffee
@@ -316,7 +316,8 @@

   canAddBlockAttribute: (attributeName) ->
     return true unless @getBlock()?.hasAttributes()
-    if attributeName in ["quote", "code", "bullet", "number"]
+    if attributeName in Object.keys(Trix.config.blockAttributes)
+      console.log Trix.config.blockAttributes
       if @hasCurrentAttribute("header") and attributeName not in @getBlock()?.getAttributes()
         return false
       return true


Use getter to access block attributes

Use getter to access block attributes

--- src/trix/models/composition.coffee
+++ src/trix/models/composition.coffee
@@ -89,7 +89,7 @@
         position += 1

     newDocument = new Trix.Document [block.removeLastAttribute().copyWithoutText()]
-    if "header" in block.attributes
+    if @hasCurrentAttribute("header")
       document = document.removeTextAtRange([position - 1, position])
       @setDocument(document.insertDocumentAtRange(newDocument, [position - 1, position]))
     else
@@ -117,7 +117,7 @@
           @removeLastBlockAttribute()
         else if block.text.getStringAtRange([endLocation.offset - 1, endLocation.offset]) is "\n"
           @breakFormattedBlock()
-        else if "header" in block.attributes and block.text.getStringAtRange([endLocation.offset, endLocation.offset + 1]) is "\n"
+        else if @hasCurrentAttribute("header") and block.text.getStringAtRange([endLocation.offset, endLocation.offset + 1]) is "\n"
           @breakFormattedBlock()
         else
           @insertString("\n")
@@ -219,7 +219,7 @@
     @currentAttributes[attributeName]?

   toggleCurrentAttribute: (attributeName) ->
-    if ("header" in @getBlock()?.getAttributes() and
+    if (@hasCurrentAttribute("header") and
     attributeName in @getBlock()?.getAttributes() and
     attributeName != "header")
       @removeBlockAttribute("header")
@@ -317,7 +317,7 @@
   canAddBlockAttribute: (attributeName) ->
     return true unless @getBlock()?.hasAttributes()
     if attributeName in ["quote", "code", "bullet", "number"]
-      if "header" in @getBlock()?.getAttributes() and attributeName not in @getBlock()?.getAttributes()
+      if @hasCurrentAttribute("header") and attributeName not in @getBlock()?.getAttributes()
         return false
       return true
     return true


functional copy-button in context menu

functional copy-button in context menu

--- lib/editor/results.coffee
+++ lib/editor/results.coffee
@@ -17,17 +17,20 @@
       'inline-results:clear': (e) ->
         result = e.currentTarget.result
         setTimeout (-> result.destroy()), 0
+      'inline-results:copy': (e) ->
+        atom.clipboard.write(e.currentTarget.result.view.getAttribute('plain'))

   deactivate: ->
     @subs.dispose()

   timeout: (t, f) -> setTimeout f, t

-  result: (ed, content, {error, clas}) ->
+  result: (ed, content, {error, clas, plainresult}) ->
     view = document.createElement 'div'
     view.classList.add 'ink', 'inline', 'result'
     if error then view.classList.add 'error'
     if clas then view.classList.add clas
+    if plainresult then view.setAttribute 'plain', plainresult
     if @monotypeResults then view.style.font = 'inherit'
     view.style.position = 'relative'
     view.style.top = -ed.getLineHeightInPixels() + 'px'
@@ -42,11 +45,11 @@
     r.invalidate = => @invalidate r
     r.validate = => @validate r

-  show: (ed, mark, {watch, content, error, clas}={}) ->
+  show: (ed, mark, {watch, content, error, clas, plainresult}={}) ->
     mark.getBufferRange().isReversed and throw "Cannot add result to reversed marker"
     flag = @removeLines ed, mark.getHeadBufferPosition().row,
                             mark.getTailBufferPosition().row
-    result = @result ed, content, {error, clas}
+    result = @result ed, content, {error, clas, plainresult}
     mark.result = result
     result.editor = ed
     result.marker = mark


Select: Fixed the UI attribute when the value is an object.

--- src/elements/Select/Select.coffee
+++ src/elements/Select/Select.coffee
@@ -120,7 +120,7 @@

 				if @_ui
 					uiValue = opt.value
-					if CUI.util.isPlainObject(opt.value)
+					if not CUI.util.isInteger(opt.value) and not CUI.util.isString(opt.value)
 						uiValue = idx
 					opt.ui = "#{@_ui}.option:#{uiValue}"


Enable to set "null" for channel in sidebar

--- core/app/backbone/views/channels_view.coffee
+++ core/app/backbone/views/channels_view.coffee
@@ -74,7 +74,9 @@
     @header.show new ChannelHeaderView(model: @model, collection: @collection)

   setActiveChannel: (channel)->
-    if channel.get('is_all')
+    if not channel?
+      @unsetActive()
+    else if channel.get('is_all')
       @setActive('stream')
     else
       @collection.setActiveChannel(channel)
@@ -88,5 +90,5 @@
     @collection.unsetActiveChannel()
     @header.currentView.trigger 'activate', type

-  unsetActive: () ->
+  unsetActive: ->
     @setActive()