Clean up and clarify settings grammar

Clean up and clarify settings grammar

--- lib/main.coffee
+++ lib/main.coffee
@@ -21,31 +21,30 @@
         type: 'string'
       order: 2
     ignoreVCSIgnoredFiles:
-      title: 'Ignore VCS Ignored Files'
-      description: 'Do not lint files ignored by VCS'
+      title: 'Do Not Lint Files Ignored by VCS'
+      description: 'E.g., ignore files specified in .gitignore'
       type: 'boolean'
       default: true
       order: 2

     showErrorInline:
-      title: 'Show Inline Tooltips'
-      description: 'Show inline tooltips for errors'
+      title: 'Show Inline Error Tooltips'
       type: 'boolean'
       default: true
       order: 3
     inlineTooltipInterval:
-      title: 'Inline tooltip interval'
+      title: 'Inline Tooltip Interval'
       description: 'Interval at which inline tooltip is updated (in ms)'
       type: 'integer'
       default: 60
       order: 3
     gutterEnabled:
-      title: 'Highlight error lines in gutter'
+      title: 'Highlight Error Lines in Gutter'
       type: 'boolean'
       default: true
       order: 3
     gutterPosition:
-      title: 'Position of gutter highlights'
+      title: 'Position of Gutter Highlights'
       enum: ['Left', 'Right']
       default: 'Right'
       order: 3
@@ -56,59 +55,59 @@
       default: true
       order: 3
     showProviderName:
-      title: 'Show Provider Name (when available)'
+      title: 'Show Provider Name (When Available)'
       type: 'boolean'
       default: true
       order: 3

     showErrorPanel:
-      title: 'Show Error Panel at the Bottom'
-      description: 'Show the list of errors in a bottom panel'
+      title: 'Show Error Panel'
+      description: 'Show a list of errors at the bottom of the editor'
       type: 'boolean'
       default: true
       order: 4
     errorPanelHeight:
       title: 'Error Panel Height'
-      description: 'The error panel height in pixels'
+      description: 'Height of the error panel (in px)'
       type: 'number'
       default: 150
       order: 4
     alwaysTakeMinimumSpace:
-      title: 'Always Take Minimum Space'
-      description: 'Resize the error panel smaller than the height where possible'
+      title: 'Automatically Reduce Error Panel Height'
+      description: 'Reduce panel height when it exceeds the height of the error list'
       type: 'boolean'
       default: true
       order: 4

     displayLinterInfo:
-      title: 'Display Linter Info in Status Bar'
+      title: 'Display Linter Info in the Status Bar'
       description: 'Whether to show any linter information in the status bar'
       type: 'boolean'
       default: true
       order: 5
     showErrorTabLine:
-      title: 'Show Line tab in Status Bar'
+      title: 'Show Line Errors Tab in the Status Bar'
       type: 'boolean'
       default: false
       order: 5
     showErrorTabFile:
-      title: 'Show File tab in Status Bar'
+      title: 'Show File Errors Tab in the Status Bar'
       type: 'boolean'
       default: true
       order: 5
     showErrorTabProject:
-      title: 'Show Project tab in Status Bar'
+      title: 'Show Project Errors Tab in the Status Bar'
       type: 'boolean'
       default: true
       order: 5
     statusIconScope:
-      title: 'Scope of messages to show in status icon'
+      title: 'Scope of Error Messages to Show in Status Icon'
       type: 'string'
       enum: ['File', 'Line', 'Project']
       default: 'Project'
       order: 5
     statusIconPosition:
-      title: 'Position of Status Icon in Status Bar'
+      title: 'Position of Status Icon in the Status Bar'
       enum: ['Left', 'Right']
       type: 'string'
       default: 'Left'


clean up cruft

clean up cruft

--- lib/main.coffee
+++ lib/main.coffee
@@ -46,12 +46,8 @@
           arr
       else ''

-tf = (bool) ->
-  if bool then 'T' else 'F'
-
 tagsArray = _(processStatements(result.statements)).flatten().join('').match(/<.+?>|{{.+?}}|[^<>{}]+/g);
 _(tagsArray).reject((t,i,ctx) -> t == '{{else}}' && _(['{{/if}}', '{{/unless}}']).include(ctx[i+1]))
-debugger

 indent = -1
 prevTag = ''
@@ -70,7 +66,6 @@
   isHtmlSelfClosing = t[0] == '<' && t[t.length-2] == '/'
   isSelfClosed =  isPlainString || isHtmlSelfClosing || (isMustachey && !isTokenTag)
   currentTag = t.match(/\w+/)[0]
-  debug = '' # "#{tf(prevTagIsOpening)}, #{tf(isClosing)}, #{prevTag}, #{currentTag}"
   unless !isElse && ((isSelfClosed && prevTagIsSelfClosed) || (prevTagIsClosed && !isClosing) || prevTagIsOpening && isClosing && (prevTag == currentTag))
     indent += (if isOpening then 1 else -1)
   prevTag = currentTag
@@ -78,13 +73,8 @@
   prevTagIsClosed = isClosing
   prevTagIsElse = isElse
   prevTagIsSelfClosed = isSelfClosed
-  debug + (if indent == 0 then '' else ("  " for n in [0..indent-1]).join('')) + t
+  if indent == 0 then '' else ("  " for n in [0..indent-1]).join('')) + t
+
+fs.writeFileSync hbsFile, spaced.join("\n")

-
-# output = _(processStatements(result.statements)).flatten().join('')
-# pretty = html.prettyPrint(output, {'indent_size': 2, 'indent_char': ' ','max_char': 0, 'brace_style': 'collapse'})
-# pretty = pretty.replace(/" }}/g, '"}}')
-fs.writeFileSync hbsFile, spaced.join("\n") #pretty
-
-


transposing the arrays

transposing the arrays

--- dkobo/koboform/static/js/xlform/XLF.view.icons.coffee
+++ dkobo/koboform/static/js/xlform/XLF.view.icons.coffee
@@ -103,6 +103,6 @@
         ii = grp_keys.indexOf(grping)
         @_groups[ii] or @_groups[ii] = []
         @_groups[ii].push model
-    @_groups
+    _.zip.apply(null, @_groups)

 XLF.icons = new QtypeIconCollection(XLF.iconDetails)


autoexport

autoexport

--- chrome/content/zotero-better-bibtex/cache.coffee
+++ chrome/content/zotero-better-bibtex/cache.coffee
@@ -25,7 +25,10 @@

   translation = new Zotero.Translate.Export()
   translation.setCollection(Zotero.Collections.get(ae.collection_id))
-  translation.setLocation(ae.path) # TODO: nsiFile
+
+  path = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile)
+  path.initWithPath(ae.path);
+  translation.setLocation(path)
   translation.setTranslator(ae.translatorID)
   translation.setDisplayOptions(JSON.parse(ae.context))


first item, not non-existent second

first item, not non-existent second

--- chrome/content/zotero-better-bibtex/cache.coffee
+++ chrome/content/zotero-better-bibtex/cache.coffee
@@ -263,7 +263,7 @@
           items = {}

         when m = /^library:([0-9]+)$/.exec(ae.collection)
-          items = {items: Zotero.Items.getAll(false, m[2])}
+          items = {items: Zotero.Items.getAll(false, m[1])}
           items.items = [] unless items.items
           if items.items.length == 0
             Zotero.BetterBibTeX.debug('auto.process: empty library')


activity: set user like interaction on realtime update

--- client/Social/Activity/messageeventhelper.coffee
+++ client/Social/Activity/messageeventhelper.coffee
@@ -44,6 +44,7 @@

     like.actorsCount = count
     like.actorsPreview.unshift accountOldId  if accountOldId not in like.actorsPreview
+    like.isInteracted = yes  if KD.whoami().getId() is accountOldId

     message.emit "LikeAdded"
     message.emit "update"
@@ -55,6 +56,8 @@

     like.actorsCount   = count
     like.actorsPreview = like.actorsPreview.filter (id) -> id isnt accountOldId
+
+    like.isInteracted = no  if KD.whoami().getId() is accountOldId

     message.emit "LikeRemoved"
     message.emit "update"


Client: All PMs scroll to bottom properly.

--- client/app/js/views/private_messages_view.coffee
+++ client/app/js/views/private_messages_view.coffee
@@ -61,13 +61,13 @@
         messageHtml += "
#{username}: #{message}
"

     $messages = $popup.find('.popup_messages').append($(messageHtml))
-    @scrollToBottom()
+    @scrollToBottom($popup)

   # todo: make this and addLogMessages construct messages from a common source
   receiveMessage: (messageId, username, message, options) =>
     $popup = @$findOrCreatePopup(messageId)
     $messages = $popup.find('.popup_messages')
-    wasAtBottom = @isAtBottom()
+    wasAtBottom = @isAtBottom($popup)
     if options.type == 'error'
       $messages.append("
#{message}
")
     else if options.type == 'alert'
@@ -77,7 +77,7 @@
         $popup.addClass('new_message')
         PokeBattle.notifyUser(PokeBattle.NotificationTypes.PRIVATE_MESSAGE, username)
       $messages.append("
#{username}: #{message}
")
-    if wasAtBottom then @scrollToBottom()
+    if wasAtBottom then @scrollToBottom($popup)

   openChallenge: (messageId, generation, conditions) =>
     $popup = @$findOrCreatePopup(messageId)
@@ -115,12 +115,12 @@

   # Returns true if the chat is scrolled to the bottom of the screen.
   # This also returns true if the messages are hidden.
-  isAtBottom: =>
-    $el = @$('.popup_messages')
+  isAtBottom: ($popup) =>
+    $el = $popup.find('.popup_messages')
     ($el[0].scrollHeight - $el.scrollTop() <= $el.outerHeight())

-  scrollToBottom: =>
-    messages = @$('.popup_messages')[0]
+  scrollToBottom: ($popup) =>
+    messages = $popup.find('.popup_messages')[0]
     messages.scrollTop = messages.scrollHeight
     false

@@ -204,14 +204,14 @@
   toggleChallengeEvent: (e) =>
     $popup = @$closestPopup(e.currentTarget)
     $challenge = $popup.find('.challenge')
-    wasAtBottom = @isAtBottom()
+    wasAtBottom = @isAtBottom($popup)
     if $challenge.hasClass("hidden")
       @createChallenge($popup)
     else if $challenge.find('.cancel_challenge').text() == 'Cancel'
       $popup.find('.send_challenge').click()
     else
       @closeChallenge(@messageFromPopup($popup))
-    if wasAtBottom then @scrollToBottom()
+    if wasAtBottom then @scrollToBottom($popup)

   sendChallengeEvent: (e) =>
     $popup = @$closestPopup(e.currentTarget)


Show that user is blocked in parent reply link

--- resources/assets/lib/components/comment.coffee
+++ resources/assets/lib/components/comment.coffee
@@ -537,6 +537,7 @@

   parentLink: (parent) =>
     props = title: makePreview(parent)
+    parentUser = @userFor(parent)

     if @props.linkParent
       component = a
@@ -548,7 +549,7 @@
     component props,
       span className: 'fas fa-reply'
       ' '
-      @userFor(parent).username
+      if !isBlocked(parentUser) then @userFor(parent).username else osu.trans('users.blocks.blocked_user')

   userFor: (comment) =>


Correct controller syntax

Correct controller syntax

--- client/src/project/states/main/controller.coffee
+++ client/src/project/states/main/controller.coffee
@@ -7,13 +7,11 @@
   Organization
 ) ->
   TrelloClient.get('/members/me/boards').then (response) ->
-    $scope.boards = response.data
-    $scope.boards = _.map($scope.boards, (board) ->
+    $scope.boards = _.map response.data, (board) ->
       board.idOrganization ?= 'myboards'
       return board
-    )

-  $scope.organization = [{id: 'myboards', displayName: 'Your boards'}];
+  $scope.organization = [{id: 'myboards', displayName: 'Your boards'}]

   TrelloClient.get('/members/me/organizations').then (organizationData) ->
     $scope.organizations = $scope.organization.concat(organizationData.data)


 Merge branch 'master.jraphical' into 'master'

Master.Jraphical

--- node_modules_koding/jraphical/lib/module.coffee
+++ node_modules_koding/jraphical/lib/module.coffee
@@ -280,6 +280,7 @@
           """
           You must specify the role when there are multiple options available!
           """
+
       unless target.constructor is targetType or
              target.constructor.encapsulatedBy is targetType
         if Array.isArray(targetType)
@@ -291,20 +292,29 @@
             return callback new TypeError 'Type mismatch'
         else
           return callback new TypeError 'Type mismatch'
+
       rdef = {
         targetId    : target.getId()
         targetName  : targetType.name
         sourceId    : @getId()
         sourceName  : constructor.name
         as
-        data
       }
+
+      rdef.data = data  if data
+
       if target.constructor isnt targetType
         rdef.abstractTargetName = targetType.name
         rdef.targetName = target.constructor.name
+
       unless target.getId()
-        callback new Error 'No target id!'
-      else
+        return callback new Error 'No target id!'
+
+      Relationship.one rdef, (err, rel)->
+
+        return callback err             if err
+        return callback null, [rel], 1  if rel
+
         new Relationship(rdef).save (err, docs)->
           if err
             callback err


Photo#load: do not attach event handlers when it is not needed

--- lib/assets/javascripts/googleplus.photo.js.coffee
+++ lib/assets/javascripts/googleplus.photo.js.coffee
@@ -20,9 +20,10 @@

     element = $('<img/>')

-    element.on 'load', ->
-      element.off 'load'
-      callback element if callback?
+    if callback?
+      element.on 'load', ->
+        element.off 'load'
+        callback element

     element.attr src: url


- fixed tiny bug : now doubledsided attribute of meshes is set correctly (for canvas/software renderer only)

--- src/app/modules/editors/visualEditor/visualEditorView.coffee
+++ src/app/modules/editors/visualEditor/visualEditorView.coffee
@@ -18,7 +18,6 @@

   THREE.CSG = require 'modules/core/projects/csg/csg.Three'

-  #TODO:
   #FIXME: memory leaks: When removing objects from scene do we really need: renderer.deallocateObject(Object); ?

   class MyAxisHelper
@@ -1156,7 +1155,7 @@
       @assembly = new THREE.Mesh(new THREE.Geometry())
       @assembly.name = "assembly"

-      for index, part of res.parts
+      for index, part of res.children
         @_importGeom(part,@assembly)

       @scene.add @assembly
@@ -1183,7 +1182,7 @@
       mesh.geometry.computeCentroids()

       if @renderer instanceof THREE.CanvasRenderer
-        @mesh.doubleSided = true
+        mesh.doubleSided = true

       #get object connectors
       for i, conn of geom.connectors
@@ -1202,9 +1201,9 @@

       rootObj.add mesh
       #recursive, for sub objects
-      if csgObj.parts?
-        for index, part of csgObj.parts
-          @_importGeom(part,mesh)
+      if csgObj.children?
+        for index, child of csgObj.children
+          @_importGeom(child, mesh)

   return VisualEditorView


keepScroll option

keepScroll option

Attach a “data-keep-scroll” attribute to a link, and clicking it will
keep the window’s scroll position instead of scrolling to the top of
the page.

--- lib/assets/javascripts/turbolinks.js.coffee
+++ lib/assets/javascripts/turbolinks.js.coffee
@@ -11,7 +11,7 @@
 xhr                     = null

-fetch = (url) ->
+fetch = (url, keepScroll = false) ->
   url = new ComponentUrl url

   rememberReferer()
@@ -20,6 +20,8 @@

   if transitionCacheEnabled and cachedPage = transitionCacheFor(url.absolute)
     fetchHistory cachedPage
+    fetchReplacement url
+  else if keepScroll
     fetchReplacement url
   else
     fetchReplacement url, resetScrollPosition
@@ -320,7 +322,8 @@
     return if @event.defaultPrevented
     @_extractLink()
     if @_validForTurbolinks()
-      visit @link.href unless pageChangePrevented()
+      keepScroll = @link.link.getAttribute && @link.link.getAttribute('data-keep-scroll')?
+      visit @link.href, keepScroll unless pageChangePrevented()
       @event.preventDefault()

   _extractLink: ->
@@ -403,7 +406,7 @@
   visit = (url) -> document.location.href = url

 # Public API
-#   Turbolinks.visit(url)
+#   Turbolinks.visit(url, keepScroll=false)
 #   Turbolinks.pagesCached()
 #   Turbolinks.pagesCached(20)
 #   Turbolinks.enableTransitionCache()


refactory caching, much better behavior

refactory caching, much better behavior

--- lib/assets/javascripts/turbolinks.js.coffee
+++ lib/assets/javascripts/turbolinks.js.coffee
@@ -1,7 +1,8 @@
-window.historyCache = []
-window.testArray = []
+@historyCache = []
+
 visit = (url) ->
   if browserSupportsPushState?
+    @historyCache.push({url:document.location.href,body:document.body,title:document.title})
     reflectNewUrl url
     fetchReplacement url
   else
@@ -17,8 +18,8 @@
   xhr.send()

 fetchHistory = (url) ->
-  while(window.historyCache.length > 0)
-    cache = window.historyCache.pop()
+  while(@historyCache.length > 0)
+    cache = @historyCache.pop()
     if cache.url == url
       replaceDocument cache.body, cache.title
       triggerPageChange
@@ -65,10 +66,9 @@

 replaceDocument = (body,title,cache) ->
   originalBody = document.body
-  document.documentElement.appendChild body.cloneNode(true), originalBody
+  document.documentElement.appendChild body, originalBody
   document.documentElement.removeChild originalBody
   document.title = title
-  window.historyCache.push({url: document.location.href, title:title,body:body}) if cache

 extractLink = (event) ->
@@ -108,7 +108,6 @@
 rememberInitialPage = ->
   window.history.replaceState { turbolinks: true }, "", document.location.href

-
 if browserSupportsPushState
   rememberInitialPage()


Coffee style

Coffee style

--- lib/assets/javascripts/turbolinks.js.coffee
+++ lib/assets/javascripts/turbolinks.js.coffee
@@ -37,7 +37,7 @@
   triggerPageChange()

 reflectNewUrl = (url) ->
-  window.history.pushState { turbolinks: true,position: window.history.length }, "", url
+  window.history.pushState { turbolinks: true, position: window.history.length }, "", url

@@ -76,7 +76,7 @@
   document.documentElement.appendChild body, originalBody
   document.documentElement.removeChild originalBody
   document.title = title
-  historyCache[window.history.state.position] = {url:document.location.href,body:body,title:title} if cache
+  historyCache[window.history.state.position] = url: document.location.href, body: body, title: title if cache

@@ -122,4 +122,4 @@
     handleClick event

 # Call Turbolinks.visit(url) from client code
-@Turbolinks = { visit: visit }
+@Turbolinks = visit: visit


Add close handle to cropper

Add close handle to cropper

--- scanblog/static/js/moderation/documents.coffee
+++ scanblog/static/js/moderation/documents.coffee
@@ -707,6 +707,17 @@
         ctx.strokeRect(x-m, y1-m, 2*m, 2*m) # SW
         ctx.strokeRect(x + (x1-x)/2 -m, y1-m, 2*m, 2*m) # S
         ctx.strokeRect(x1-m, y1-m, 2*m, 2*m) # SE
+
+        # Close handle
+        ctx.strokeRect(x1+m, y-5*m, 4*m, 4*m)
+        ctx.beginPath()
+        ctx.moveTo(x1+m, y-5*m)
+        ctx.lineTo(x1+5*m, y-m)
+        ctx.stroke()
+        ctx.beginPath()
+        ctx.moveTo(x1+5*m, y-5*m)
+        ctx.lineTo(x1+m, y-m)
+        ctx.stroke()

   handleMouse: (mx, my, type, crop) =>
     directions = ""
@@ -730,6 +741,10 @@
         else
           cursor = "move"
           directions = "+"
+      else if (x1 + m/2) <= mx <= (x1 + 5*m/2) and (y - m/2) >= my >= (y - 5*m/2)
+        # Inside close handle
+        cursor = "pointer"
+        directions = "x"
     @cursor = cursor or "crosshair"
     if type == "down"
       if crop and not directions
@@ -740,11 +755,15 @@
         directions: directions
         crop: (d for d in crop if crop)
     else if type == "up"
-      @mouseDownState = {}
-      if crop
-        [x, y, x1, y1] = crop
-        if x - x1 == 0 or y - y1 == 0
-          return null
+      if "x" == @mouseDownState?.directions
+        @mouseDownState = {}
+        return null
+      else
+        @mouseDownState = {}
+        if crop
+          [x, y, x1, y1] = crop
+          if x - x1 == 0 or y - y1 == 0
+            return null
     else if type == "move" and @mouseDownState?.x?
       if crop
         [x, y, x1, y1] = crop
@@ -858,9 +877,9 @@
             cursor = "move"
             directions = "+"
         else if (x1 + m/2) <= mx <= (x1 + 5*m/2) and (y - m/2) >= my >= (y - 5*m/2)
+          # Inside close handle
           cursor = "pointer"
           directions = "x"
-          # Inside close handle
         if directions
           matches.push({
             cursor: cursor


webapp: typo in billing -- fixes #623

webapp: typo in billing -- fixes #623

--- src/smc-webapp/billing.cjsx
+++ src/smc-webapp/billing.cjsx
@@ -992,7 +992,7 @@
                 You can distribute these upgrades to your own projects or any projects where you are a collaborator —
                 everyone participating in such a collective project benefits and can easily change their allocations at any time!
                 You can get higher-quality hosting on members-only machines and enable access to the internet from projects.
-                You can also increas quotas for CPU and RAM, so that you can work on larger problems and
+                You can also increase quotas for CPU and RAM, so that you can work on larger problems and
                 do more computations simultaneously.
             </div>
         </div>


Trigger travis

Trigger travis

--- src/spec/oauth2.spec.coffee
+++ src/spec/oauth2.spec.coffee
@@ -20,7 +20,7 @@
   beforeEach ->
     @oa = new OAuth2 Config

-  xit "should send request for access token", (done)->
+  it "should send request for access token", (done)->
     @oa.getAccessToken (data)->
       expect(data.access_token).toBeDefined()
       done()


remove initial hasOne and hasMany

remove initial hasOne and hasMany

--- lib/client/javascripts/nali/model.js.coffee
+++ lib/client/javascripts/nali/model.js.coffee
@@ -12,8 +12,6 @@
     @views = {}

   tables:      {}
-  hasOne:      []
-  hasMany:     []
   attributes:  {}
   updated:     0
   noticesWait: []


Call getFilterKey() instead of filterKey ivar

--- src/select-list-view.coffee
+++ src/select-list-view.coffee
@@ -136,7 +136,7 @@

     filterQuery = @getFilterQuery()
     if filterQuery.length
-      filteredArray = fuzzyFilter(@array, filterQuery, key: @filterKey)
+      filteredArray = fuzzyFilter(@array, filterQuery, key: @getFilterKey())
     else
       filteredArray = @array

@@ -213,6 +213,19 @@
   #
   # item - The selected model item.
   confirmed: (item) ->
+
+  # Public: Get the property name to use when filtering items.
+  #
+  # This method may be overridden by classes to allow fuzzy filtering based
+  # on a specific property of the item objects.
+  #
+  # For example if the objects you pass to {.setItems} are of the type
+  # `{"id": 3, "name": "Atom"}` then you would return `"name"` from this method
+  # to fuzzy filter by that property when text is entered into this view's
+  # editor.
+  #
+  # Returns a {String} property name to fuzzy filter by.
+  getFilterKey: ->

   attach: ->
     @storeFocusedElement()


Use ReactEditorView in SelectListView when flag is enabled

--- src/select-list-view.coffee
+++ src/select-list-view.coffee
@@ -1,5 +1,8 @@
 {$, View} = require './space-pen-extensions'
-EditorView = require './editor-view'
+if atom.config.get('core.useReactMiniEditors')
+  EditorView = require './react-editor-view'
+else
+  EditorView = require './editor-view'
 fuzzyFilter = require('fuzzaldrin').filter

 # Public: Provides a view that renders a list of items with an editor that


:arrow_down: Revert fix some typing errors

--- lib/plus.coffee
+++ lib/plus.coffee
@@ -26,12 +26,12 @@
       return unless atom.workspace.getActiveTextEditor()
       @lint()
     @Subscriptions.add atom.workspace.observeTextEditors (editor)=>
+      return if @InProgress
       return unless editor.getPath()
       editor.onDidSave(@lint.bind(@))
       @Subscriptions.add editor.onDidChangeCursorPosition ({newBufferPosition})=>
         @View.updateBubble(newBufferPosition)
   lint:->
-    return if @InProgress
     @InProgress = true

     ActiveEditor = atom.workspace.getActiveTextEditor()
@@ -59,7 +59,6 @@
       @Messages = Messages
       @render()
     , =>
-      console.error.call console, arguments
       @InProgress = false
   render:->
     if not @Messages.length


add missing error handler

add missing error handler

--- services/docstore/app/coffee/DocManager.coffee
+++ services/docstore/app/coffee/DocManager.coffee
@@ -35,6 +35,8 @@

 	getAllNonDeletedDocs: (project_id, filter, callback = (error, docs) ->) ->
 		DocArchive.unArchiveAllDocs project_id, (error) ->
+			if error?
+				return callback(error)
 			MongoManager.getProjectsDocs project_id, {include_deleted: false}, filter, (error, docs) ->
 				if err?
 					return callback(error)


reactivity: React key warning fix

reactivity: React key warning fix

--- client/activity/lib/components/mentiondropboxitem/channelmentionitem.coffee
+++ client/activity/lib/components/mentiondropboxitem/channelmentionitem.coffee
@@ -25,9 +25,9 @@
     if names.size > 1
       secondaryNames = names.skip(1)
       secondaryItems = secondaryNames.map (name, index) ->
-        name = highlightQueryInWord name, query, { isBeginningMatch : yes }
-
-          @{ name }{ if index is secondaryNames.size - 1 then '' else ', ' }
+        highlightedName = highlightQueryInWord name, query, { isBeginningMatch : yes }
+
+          @{ highlightedName }{ if index is secondaryNames.size - 1 then '' else ', ' }


Fix channel suggestion in add-to-channel on channel page

--- core/app/backbone/views/channels/add_channel_to_channels_button_view.coffee
+++ core/app/backbone/views/channels/add_channel_to_channels_button_view.coffee
@@ -23,8 +23,10 @@
     e.stopImmediatePropagation()
     e.preventDefault()

+    suggestion_collection = @options.suggested_topics || new SuggestedTopics([@model.topic()])
+
     FactlinkApp.Modal.show 'Add to Channels',
       new AddChannelToChannelsModalView
             model: @model,
             collection: @collection
-            suggestions: @options.suggested_topics
+            suggestions: suggestion_collection


class to className

class to className

--- src/components/questions/sections-chooser.cjsx
+++ src/components/questions/sections-chooser.cjsx
@@ -52,7 +52,7 @@

-

+

Question Library

           <BackButton fallbackLink={


Static Pages: Update asset URL paths

Static Pages: Update asset URL paths

--- servers/lib/crawler/staticpages/graphmeta.coffee
+++ servers/lib/crawler/staticpages/graphmeta.coffee
@@ -54,9 +54,9 @@

   <link rel="shortcut icon" href="#{uri.address}/a/images/favicon.ico">
   <link rel="fluid-icon" href="#{uri.address}/a/images/logos/fluid512.png" title="Koding">
-  <link rel="stylesheet" href="/a/css/kd.css?#{version}">
-  <link rel="stylesheet" href="/a/css/koding.css?#{version}">
-  <link class="internal-style-app-members" rel="stylesheet" href="/a/css/__app.members.css?#{version}">
+  <link rel="stylesheet" href="/a/p/p/kd.css?#{version}">
+  <link rel="stylesheet" href="/a/p/p/app.css?#{version}">
+  <link class="internal-style-app-activity" rel="stylesheet" href="/a/p/p/activity.css?#{version}">

   <link href='https://chrome.google.com/webstore/detail/koding/fgbjpbdfegnodokpoejnbhnblcojccal' rel='chrome-webstore-item'>


Only display non-archived periods

Only display non-archived periods

--- src/components/course-settings/change-period.cjsx
+++ src/components/course-settings/change-period.cjsx
@@ -25,7 +25,9 @@
     </BS.NavItem>

   selectNewPeriod: ->
-    course = CourseStore.get(@props.courseId)
+    periods = CourseStore.getPeriods(@props.courseId)
+    return null if periods.length is 1
+
     title =
       if @isSaving()

@@ -37,20 +39,20 @@

     <BS.Popover className='change-period' title={title} {...@props}>
       <BS.Nav stacked bsStyle='pills' onSelect={@updatePeriod}>
-        {for period in course.periods
+        {for period in periods
           @renderPeriod(period) unless period.id is @props.student.period_id }
       </BS.Nav>
     </BS.Popover>

   render: ->
     # if we have only 1 period, it's imposible to move a student
-    course = CourseStore.get(@props.courseId)
-    return null if course.periods.length is 1
+    periods = CourseStore.getPeriods(@props.courseId)
+    return null if periods.length is 1

     <BS.OverlayTrigger rootClose={true} trigger='click' placement='left'
       overlay={@selectNewPeriod()}>

-           Change <CourseGroupingLabel
+           Change <CourseGroupingLabel
             courseId={@props.courseId} />

     </BS.OverlayTrigger>


ContentEditable: WIP fix for the unfired focus event

--- src/components/inputs/contenteditableview.coffee
+++ src/components/inputs/contenteditableview.coffee
@@ -14,6 +14,14 @@
     super options, data

     @getDelegate()?.on "EditingModeToggled", (state) => @setEditingMode state
+
+    # we shouldn't do per instance
+    # quick hack unf - SY
+    document.addEventListener 'focus', (event)=>
+      if event.target is @editableElement
+        log 'gelmiyo musun buraya'
+        @focus()
+    , yes

     @validationNotifications = {}


updating exercises to not have to parse json, due to karen's change

--- src/components/task-plan/homework/exercises.cjsx
+++ src/components/task-plan/homework/exercises.cjsx
@@ -17,7 +17,7 @@
     {tag}

   renderExercise: ->
-    content = JSON.parse(@props.exercise.content)
+    content = @props.exercise.content
     question = content.questions[0]
     renderedAnswers = _.map(question.answers, @renderAnswers)
     renderedTags = _.map(content.tags, @renderTags)


fixed correct return type

fixed correct return type

--- src/scripts/services/twitterSearchService.coffee
+++ src/scripts/services/twitterSearchService.coffee
@@ -27,4 +27,6 @@

     @.stop = ->
       return
+
+    return @
 ])


Move not-found route to bottom of router

--- app/router.cjsx
+++ app/router.cjsx
@@ -117,10 +117,9 @@
   </Route>

   <Route path="todo" component={->
 TODO
} />
-  <Route path="*" component={require './pages/not-found'} />
-
   <Route path="dev/workflow-tasks-editor" component={require './components/workflow-tasks-editor'} />
   <Route path="dev/classifier" component={require './classifier'} />
   <Route path="dev/aggregate" component={require './components/aggregate-view'} />
   <Route path="dev/ribbon" component={require './components/classifications-ribbon'} />
+  <Route path="*" component={require './pages/not-found'} />
 </Route>


Randomized the values for top and left

Randomized the values for top and left

--- test/map-overlay.spec.coffee
+++ test/map-overlay.spec.coffee
@@ -1,6 +1,6 @@
 jsdom = require 'jsdom'
 assert = require('chai').assert
-sinon = require('sinon')
+sinon = require 'sinon'

 google = require('../resources/google-maps-stub')

@@ -12,7 +12,8 @@
 global.window = window
 global.document = document

-$ = require('jquery')
+$ = require 'jquery'
+_ = require 'lodash'

 MapOverlay = require '../lib/map-overlay'

@@ -23,8 +24,8 @@
     overlay = null
     sandbox = null

-    expectedTop = 123
-    expectedLeft = 456
+    expectedTop = _.random 1, 300
+    expectedLeft = _.random 1, 300

     setupStubs = () ->
         sandbox = sinon.sandbox.create()


Refactor response test.

Refactor response test.

--- test/messageStoreTest.coffee
+++ test/messageStoreTest.coffee
@@ -3,20 +3,21 @@
 http = require "http"
 messageStore = require "../lib/messageStore"
 MongoClient = require('mongodb').MongoClient
-
+collection = null

 describe ".storeTransaction", ->
-	# beforeEach (done)->
-	# 	MongoClient.connect "mongodb://127.0.0.1:27017/test", {native_parser:true},(error,db) ->
-	# 		if error
-	# 			return done error
-	# 	done()
-	after (done)->
+	before (done) ->
 		MongoClient.connect "mongodb://127.0.0.1:27017/test", {native_parser:true},(error,db) ->
 			if error
 				return done error
-			db.collection("transaction").remove (err, doc) ->
+			root = exports ? that
+			db.collection "transaction", (err, coll) ->
+				collection = coll
+				done()
+	after (done)->
+		collection.remove (err, doc) ->
 			done()
+
 	it "it should be able to save the transaction in the db", (done) ->
 		request =
 			path: "/store/provider"
@@ -72,10 +73,7 @@
 				body: "<HTTP body>"
 				method: "POST"
 				timestamp: "<ISO 8601>"
-		MongoClient.connect "mongodb://127.0.0.1:27017/test", (error,db) ->
-			if error
-				return done error
-			db.collection("transaction").insert transaction, (err, doc) ->
+		collection.insert transaction, (err, doc) ->
 				throw err if err
 		response =
 			status: 201
@@ -96,7 +94,7 @@
 				throw err if err
 				doc.should.have.property "status", "Completed"
 				doc.response.should.be.ok
-		done()
+				done()


Splitter does not calculate new height correctly

It needs to take the height of the statusbar into account.

--- lib/Components/drag-handler.coffee
+++ lib/Components/drag-handler.coffee
@@ -9,11 +9,12 @@
   onmove = (ev) ->
     docHeight = $(document).height()
     docWidth = $(document).width()
-
     {pageY, pageX} = ev
-
+    statusBarHeight = $('div.status-bar-left').height()
+    statusBarHeight = 0 unless statusBarHeight?
+
     delta = {
-      height: docHeight - pageY
+      height: docHeight - pageY - statusBarHeight
       sideWidth: docWidth - pageX
     }


change expectations slightly

change expectations slightly

--- spec/BaconSpec.coffee
+++ spec/BaconSpec.coffee
@@ -173,7 +173,7 @@
         s.onValue (value) ->
           throw "testing"
         s
-      [])
+      ["lol", "wut"])
   it "toString", ->
     expect(Bacon.sequentially(1, [2]).toString()).to.equal("Bacon.sequentially(1,[2])")

@@ -503,7 +503,7 @@
         s.onValue (value) ->
           throw "testing"
         s
-      [])
+      ["lol", "wut"])
   describe "works with synchronous source", ->
     expectStreamEvents(
       -> Bacon.fromArray([1,2,3,4]).take(2)


more tests

more tests

--- spec/BaconSpec.coffee
+++ spec/BaconSpec.coffee
@@ -309,6 +309,10 @@
           throw "testing"
         s
       [])
+  describe "works with synchronous source", ->
+    expectStreamEvents(
+      -> Bacon.fromArray([1,2,3,4]).take(2)
+      [1,2])

 describe "EventStream.takeWhile", ->
   describe "takes while predicate is true", ->
@@ -327,6 +331,10 @@
         odd = src.map((x) -> x % 2).toProperty()
         src.takeWhile(odd)
       [1,1])
+  describe "works with synchronous source", ->
+    expectStreamEvents(
+      -> Bacon.fromArray([1, 2, 3]).takeWhile(lessThan(3))
+      [1, 2])

 describe "EventStream.skip", ->
   describe "should skip first N items", ->
@@ -337,6 +345,10 @@
     expectStreamEvents(
       -> series(1, [1, 2]).skip(-1)
     [1, 2])
+  describe "works with synchronous source", ->
+    expectStreamEvents(
+      -> Bacon.fromArray([1, 2, 3]).skip(1)
+    [2, 3])

 describe "EventStream.skipWhile", ->
   describe "skips filter predicate holds true", ->
@@ -1339,10 +1351,19 @@
     expectPropertyEvents(
       -> series(1, [2]).toProperty(1).scan(null, add)
       [1, 3])
-  describe "works with synchronously responding empty source", ->
-    expectPropertyEvents(
-      -> Bacon.never().toProperty(1).scan(0, add)
-      [1])
+  describe "for synchronous source", ->
+    describe "with Init value, starts with f(seed, init)", ->
+      expectPropertyEvents(
+        -> Bacon.fromArray([2,3]).toProperty(1).scan(0, add)
+        [1, 3, 6])
+    describe "without Init value, starts with seed", ->
+      expectPropertyEvents(
+        -> Bacon.fromArray([2,3]).toProperty().scan(0, add)
+        [0, 2, 5])
+    describe "works with synchronously responding empty source", ->
+      expectPropertyEvents(
+        -> Bacon.never().toProperty(1).scan(0, add)
+        [1])

 describe "EventStream.withStateMachine", ->
   describe "runs state machine on the stream", ->


added notes

added notes

--- src/scripts/gauges.coffee
+++ src/scripts/gauges.coffee
@@ -10,6 +10,16 @@
 # Commands:
 #   hubot gauges for (today|yesterday) - Get views/people from today or yesterday
 #   hubot gauges for YYYY-MM-DD - Get views/people for the specified date
+#
+# Notes:
+#   Also you can trigger a event to call gauges in another script
+#     Example:
+#
+#       module.exports = (robot) ->
+#         robot.respond /emit gauges/i, (msg) ->
+#            robot.emit "gauges", { user: msg.user, for: 'today' }
+#
+#
 #
 # Author:
 #   tombell


Fix spec

Fix spec

--- spec/atom-spec.coffee
+++ spec/atom-spec.coffee
@@ -55,7 +55,7 @@
   describe "loading default config", ->
     it 'loads the default core config', ->
       expect(atom.config.get('core.excludeVcsIgnoredPaths')).toBe true
-      expect(atom.config.get('core.followSymlinks')).toBe false
+      expect(atom.config.get('core.followSymlinks')).toBe true
       expect(atom.config.get('editor.showInvisibles')).toBe false

   describe "window onerror handler", ->


Added PING support

Added PING support

--- drivers/javascript/net.coffee
+++ drivers/javascript/net.coffee
@@ -1415,6 +1415,10 @@
     # one.
     DEFAULT_PROTOCOL: 'ws'

+
+    # We define the default ping interval in case the user doesn't specify one.
+    DEFAULT_PING_INTERVAL: 37*1000
+
     # A static method used by `r.connect` to decide which kind of
     # connection to create in a given environment. Here we check if
     # XHRs are defined. If not, we aren't in the browser and shouldn't
@@ -1439,6 +1443,8 @@
         # also allowed to be), then use the default protocol, which is
         # 'ws'
         protocol = if host.protocol is 'wss' then 'wss' else @DEFAULT_PROTOCOL
+
+        ping_interval = host.ping_interval or @DEFAULT_PING_INTERVAL

         # Next we construct an XHR with the path to the reql query
         # endpoint on the http server.
@@ -1520,7 +1526,16 @@
                         # just giving it as a callback directly so
                         # that it gets bound to the correct
                         # `this`.
-                        @socket.onmessage = (e) => @_data(new Buffer(new Uint8Array(e.data)))
+                        @socket.onmessage = (e) =>
+                          if e.data != 'pong'
+                            @_data(new Buffer(new Uint8Array(e.data)))
+
+                        if ping_interval > 0
+                          @ping = setInterval =>
+                            @socket.send('ping')
+                          , ping_interval
+                        else
+                          @ping = null

                         # Notify listeners we've connected
                         # successfully. Notably, the Connection
@@ -1546,6 +1561,9 @@
     # throws out any data for unconsumed cursors etc and invalidates
     # this connection id.
     cancel: ->
+        if @ping
+          clearInterval @ping
+
         @socket.close()
         super()


:art:

:art:

--- spec/link-spec.coffee
+++ spec/link-spec.coffee
@@ -146,9 +146,8 @@
       runs ->
         expect(fs.existsSync(path.join(atomHome, 'packages', path.basename(numericPackageName)))).toBeTruthy()
         expect(fs.realpathSync(path.join(atomHome, 'packages', path.basename(numericPackageName)))).toBe fs.realpathSync(numericPackageName)
+
         callback.reset()
-
-      runs ->
         apm.run(['unlink', numericPackageName], callback)

       waitsFor 'unlink to complete', ->


Fix pane spec

Fix pane spec

--- spec/pane-spec.coffee
+++ spec/pane-spec.coffee
@@ -693,8 +693,7 @@

       pane.showItem(new Unserializable)

-      state = pane.testSerialization()
-      newPane = atom.deserializers.deserialize(state)
+      newPane = pane.testSerialization()
       expect(newPane.activeItem).toEqual pane.items[0]
       expect(newPane.items.length).toBe pane.items.length - 1


Fixed recalculate dimensions after destroy bug

--- packages/emberella/lib/views/list_view.coffee
+++ packages/emberella/lib/views/list_view.coffee
@@ -746,7 +746,9 @@

     @method _recalculateWidth
   ###
-  _recalculateWidth: -> @set('_width', if @get('state') is 'inDOM' then +@$().width() else window.innerWidth)
+  _recalculateWidth: ->
+    return if get(@, 'isDestroyed') or get(@, 'isDestroying')
+    @set('_width', if @get('state') is 'inDOM' then +@$().width() else window.innerWidth)

   ###
     @private
@@ -756,7 +758,9 @@

     @method _recalculateHeight
   ###
-  _recalculateHeight: -> @set('_height', if @get('state') is 'inDOM' then +@$().height() else window.innerHeight)
+  _recalculateHeight: ->
+    return if get(@, 'isDestroyed') or get(@, 'isDestroying')
+    @set('_height', if @get('state') is 'inDOM' then +@$().height() else window.innerHeight)

   ###
     @private


Change user list function name to camelCase

--- static/coffee/modals.coffee
+++ static/coffee/modals.coffee
@@ -96,15 +96,15 @@
   $scope.prompt = prompt
   $scope.partners = partners

-  user_list_from_users = (users) ->
+  userListFromUsers = (users) ->
     return [{id: null, name: "Anyone"}].concat(users)

-  $scope.users = user_list_from_users(users)
+  $scope.users = userListFromUsers(users)
   $scope.fields = { assignee: partners[0], user: $scope.users[0] }

   $scope.refreshUserList = () ->
     UserService.fetchInPartner($scope.fields.assignee, true).then((users) ->
-      $scope.users = user_list_from_users(users)
+      $scope.users = userListFromUsers(users)
     )

   $scope.ok = () -> $uibModalInstance.close({assignee: $scope.fields.assignee, user: $scope.fields.user})


Pattern matching on syntax

Pattern matching on syntax

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -700,7 +700,7 @@
   (isSimpleTranslated result) or (Array.isArray result) and (isSimpleTranslated result[0])

 isSimpleTranslated = (result) ->
-  result.js or result.ir
+  result.js or result.ir or result.precs or result.assigns

 callUnknownCompile = (ctx, call) ->
   callUnknownTranslate ctx, (operatorCompile ctx, call), call
@@ -2090,8 +2090,9 @@
     compiledMacro = translateToJs translateIr ctx,
         (termCompile ctx, call_ (token_ 'fn'), (join [paramTuple], rest))
     macroFn = eval compiledMacro
-    ctx.declareMacro ctx.definitionPattern(), (ctx, call) ->
-      constantToSource macroFn (_arguments call)...
+    if macroFn
+      ctx.declareMacro ctx.definitionPattern(), (ctx, call) ->
+        constantToSource macroFn (_arguments call)...

   jsNoop()

@@ -2099,20 +2100,44 @@
   [res] = _arguments call
   # call.tea = toConstrained typeConstant 'Exp'
   # assignCompile ctx, call, res
-  call.tea = toConstrained typeConstant 'Expression'
-
-  serializeAst = (ast) ->
-    if isForm ast
-      if (_operator ast)?.symbol is ','
-        termCompile ctx, ast
+
+  if ctx.assignTo()
+
+    matchAst = (ast) ->
+      matched = ctx.assignTo()
+      if isForm ast
+        if (_operator ast)?.symbol is ','
+          termCompile ctx, ast
+        else
+          combinePatterns (for term, i in _terms ast
+            ctx.setAssignTo (jsAccess (jsCall "_terms", [matched]), i)
+            precs = matchAst term
+            ctx.resetAssignTo()
+            precs)
       else
-        (jsArray (map serializeAst, ast))
-    else
-      (jsValue (JSON.stringify ast))
-  serializeAst res
+        precs: [(cond_ (jsBinary "===",
+            (jsAccess matched, "symbol"), toJsString ast.symbol))]
+
+    matchAst res
+  else
+    call.tea = toConstrained expressionType
+
+    serializeAst = (ast) ->
+      if isForm ast
+        if (_operator ast)?.symbol is ','
+          termCompile ctx, ast
+        else
+          (jsArray (map serializeAst, ast))
+      else
+        (jsValue (JSON.stringify ast))
+    serializeAst res

 ms[','] = ms_comma = (ctx, call) ->
-  (jsCall 'constantToSource', [expressionCompile ctx, (_arguments call)[0]])
+  [res] = (_arguments call)
+  if matched = ctx.assignTo()
+    expressionCompile ctx, res
+  else
+    (jsCall 'constantToSource', [expressionCompile ctx, res])

 constantToSource = (value) ->
   switch typeof value
@@ -3766,6 +3791,7 @@
     boolType
     numType
     jsType
+    expressionType
   ]

 builtInDefinitions = ->
@@ -4482,6 +4508,7 @@
 numType = typeConstant 'Num'
 regexType = typeConstant 'Regex'
 jsType = typeConstant 'Js'
+expressionType = typeConstant 'Expression'

 safePrintType = (type) ->
   try


Describe options value models as optional

--- src/shared-objects.coffee
+++ src/shared-objects.coffee
@@ -22,27 +22,27 @@
 		optionsDefinitions:
 			directory:
 				defaultValue: '.'
-				commands: '-d, --directory <path>'
+				commands: '-d, --directory [path]'
 				commandDescription: 'Set templates directory source (String)'
 			templatesExt:
 				defaultValue: ['html', 'htm', 'hbs', 'handlebars']
-				commands: '-t, --templates-ext <list>'
+				commands: '-t, --templates-ext [list]'
 				commandDescription: 'Set templates authorized extensions (Array or String)'
 			outputDirectory:
 				defaultValue: null
-				commands: '-o, --output-directory <path>'
+				commands: '-o, --output-directory [path]'
 				commandDescription: 'Set templates directory destination (String)'
 			assets:
 				defaultValue: '.'
-				commands: '-a, --assets <path>'
+				commands: '-a, --assets [path]'
 				commandDescription: 'Set assets directory source (String)'
 			assetsExt:
 				defaultValue: ['svg']
-				commands: '-A, --assets-ext <list>'
+				commands: '-A, --assets-ext [list]'
 				commandDescription: 'Set assets authorized extensions (Array or String)'
 			logLevels:
 				defaultValue: ['warning', 'error', 'info']
-				commands: '-l, --log-levels <list>'
+				commands: '-l, --log-levels [list]'
 				commandDescription: 'Set level of logs (Array or String)'
 			preserveRoot:
 				defaultValue: true


Don't show topic favourite button when not signed in

--- core/app/backbone/views/topics/topic_view.coffee
+++ core/app/backbone/views/topics/topic_view.coffee
@@ -37,6 +37,8 @@
     @factList.show new FactsView collection: facts

   showFavouriteTopicButton: ->
+    return unless Factlink.Global.signed_in
+
     view = new FavouriteTopicButtonView(topic: @model, mini: true)
     @favouriteTopicRegion.show view


Revert "fixes for broken URLs"

Revert "fixes for broken URLs"

This reverts commit e8d0eccdecec007543328b38a3c8eea86f3e0baa.

--- noddy/service/v2/find.coffee
+++ noddy/service/v2/find.coffee
@@ -104,6 +104,8 @@
       afnd.data.meta.article.reversed = true if 'reverse' in afnd.v2.checked
       if afnd.v2.url
         afnd.data.availability.push({type: 'article', url: afnd.v2.url})
+      else if afnd.v2.open
+        afnd.data.availability.push({type: 'article', url: afnd.v2.open})
     try
       if afnd.data.availability.length is 0 and (afnd.v2.metadata.doi or afnd.v2.metadata.title or afnd.v2.metadata.url)
         eq = {type: 'article'}
@@ -130,6 +132,7 @@
   # https://docs.google.com/spreadsheets/d/1lMaOg1zqpAX0GZpJ_d-U9KoNRiTeTy2tLK5lSfJw7E0/edit#gid=1753325698
   abbs = API.use.google.sheets.feed '1lMaOg1zqpAX0GZpJ_d-U9KoNRiTeTy2tLK5lSfJw7E0'
   for abb in abbs
+    console.log abb
     for w of tjw
       if not tj[w]?
         ltjw = tjw[w].toLowerCase().trim()
@@ -153,7 +156,7 @@
   options.find = false
   return API.service.oab.find(options, metadata, content).metadata

-API.service.oab.find = (options={}, metadata={}, content) ->
+API.service.oab.find = (options={}, metadata={}, content, sources={}) ->
   started = Date.now()
   res = {url: false, checked: []}

@@ -177,6 +180,7 @@
         delete options.doi # don't allow the user-provided data to later override if we can't validate it on crossref
       if metadata.licence? and metadata.licence.indexOf('creativecommons') isnt -1
         res.url = 'https://doi.org/' + metadata.doi
+        res.open = res.url
         res.found.crossref = res.url
   _get_reversed_crossref = () ->
     if (not _got() or (res.find and not res.url)) and 'reverse' in res.sources and not metadata.doi? and metadata.title? and metadata.title.length > 8 and metadata.title.split(' ').length > 2 and not options.reversed?
@@ -186,8 +190,8 @@
     if (not _got() or (res.find and not res.url)) and 'epmc' in res.sources and (metadata.doi or metadata.pmid or metadata.pmcid or metadata.title or cr?)
       res.checked.push('epmc') if 'epmc' not in res.checked
       metadata = API.use.europepmc.format cr, metadata
-      if metadata.url
-        res.url = metadata.url
+      if metadata.url or metadata.open
+        res.url = metadata.url ? metadata.open
         res.found.epmc = res.url

   if typeof options is 'string'
@@ -207,11 +211,14 @@

   if metadata.url
     options.url ?= metadata.url
-    delete metadata.url
   if metadata.id
     options.id = metadata.id
     delete metadata.id
   options.url = options.url[0] if _.isArray options.url
+
+  for src of sources
+    try _get_formatted_crossref(sources[src]) if src is 'crossref'
+    try _get_formatted_europepmc(sources[src]) if src is 'europepmc'

   metadata.doi ?= options.doi.replace('doi:','').replace('doi.org/','').trim() if typeof options.doi is 'string'
   metadata.title ?= options.title.trim() if typeof options.title is 'string'
@@ -289,6 +296,7 @@
   res.found = {}

   API.log msg: 'OAB finding academic content', level: 'debug', metadata: JSON.stringify metadata
+  try metadata[w] ?= options[w] for w in options.metadata # get whatever other metadata we may have been given to begin with, just in case

   # special cases for instantill/shareyourpaper/other demos - dev and live demo accounts that always return a fixed answer
   if (options.plugin is 'instantill' or options.plugin is 'shareyourpaper') and (metadata.doi is '10.1234/567890' or (metadata.doi? and metadata.doi.indexOf('10.1234/oab-syp-') is 0) or metadata.title is 'Engineering a Powerfully Simple Interlibrary Loan Experience with InstantILL') and options.from in ['qZooaHWRz9NLFNcgR','eZwJ83xp3oZDaec86']
@@ -316,7 +324,6 @@
   _findoab = () ->
     catalogued = oab_catalogue.finder metadata
     # if user wants a total refresh, don't use any of it (we still search for it though, because will overwrite later with the fresh stuff)
-    delete catalogued.found.oabutton if catalogued?.found?.oabutton? # fix for mistakenly cached things, we now won't record as found in OAB, just show as cached response
     if catalogued? and res.refresh isnt 0
       res.permissions ?= catalogued.permissions if catalogued.permissions?.permissions? and (catalogued.metadata?.journal? or catalogued.metadata?.issn?)
       if 'oabutton' in res.sources
@@ -325,11 +332,13 @@
           _get metadata, catalogued.metadata
           res.cached = true if _got() # no need for further finding if we have the url and all necessary metadata
           res.url = catalogued.url
+          res.open = res.url
+          res.found.oabutton = res.url
         else if catalogued.createdAt > Date.now() - res.refresh*86400000
           _get metadata, catalogued.metadata # it is in the catalogue but we don't have a link for it, and it is within refresh days old, so re-use the metadata from it
           res.cached = true if _got() # and cause an immediate return, we don't bother looking for everything again if we already couldn't find it within a given refresh window
   _findoab()
-
+
   # TODO update requests so successful ones write the source to the catalogue - but updating requests is not priority yet, so not doing right now

   if not res.cached
@@ -368,11 +377,7 @@
     # if we have a url or content but no doi or title yet, try scraping the url/content
     if (not _got() or (res.find and not res.url)) and not metadata.doi and not metadata.title and ((options.url and 'scrape' in res.sources) or content)
       res.checked.push 'scrape' if not content? # scrape the page if we have to - this is slow, so we hope not to do this much
-      sc = API.service.oab.scrape options.url, content
-      if sc?.url?
-        options.url ?= sc.url
-        delete sc.url
-      _get(metadata, sc) if sc?
+      _get metadata, API.service.oab.scrape options.url, content
       _get_formatted_crossref() # try crossref / epmc / reverse if we found useful metadata now
       _get_formatted_europepmc() if 'epmc' not in res.checked # don't bother if we were already able to look, e.g. by pmcid or pmid
       _get_reversed_crossref()
@@ -395,10 +400,11 @@
             rs = if src is 'doaj' then API.use[src].articles[which](metadata[which]) else if src is 'epmc' then API.use.europepmc[which](metadata[which]) else API.use[src][which] metadata[which]
             res.checked.push(src) if src not in res.checked
             mt = rs.title ? rs.dctitle ? rs.bibjson?.title ? rs.metadata?['oaf:result']?.title?.$
-            if rs?.url and (which isnt 'title' or (mt and mt.length <= metadata.title.length*1.2 and mt.length >= metadata.title.length*.8 and metadata.title.toLowerCase().replace(/ /g,'').indexOf(mt.toLowerCase().replace(' ','').replace(' ','').replace(' ','').split(' ')[0]) isnt -1))
+            if (rs?.url or rs?.open) and (which isnt 'title' or (mt and mt.length <= metadata.title.length*1.2 and mt.length >= metadata.title.length*.8 and metadata.title.toLowerCase().replace(/ /g,'').indexOf(mt.toLowerCase().replace(' ','').replace(' ','').replace(' ','').split(' ')[0]) isnt -1))
               if rs.redirect isnt false
-                res.redirect = if rs.redirect then rs.redirect else rs.url
+                res.redirect = if rs.redirect then rs.redirect else if rs.open then rs.open else rs.url
                 res.url = res.redirect
+                res.open = res.url
                 res.found[src] ?= res.url
               metadata.licence ?= rs.licence
               metadata.licence ?= rs.best_oa_location?.license if rs.best_oa_location?.license
@@ -496,13 +502,14 @@
     delete metadata.author if typeof metadata.author is 'string'
     delete metadata.author if _.isArray metadata.author and metadata.author.length > 0 and typeof metadata.author[0] is 'string'

-  metadata.url ?= []
+  metadata.url = catalogued.metadata.url if catalogued?.metadata?.url?
   metadata.url = [metadata.url] if typeof metadata.url is 'string'
-  if catalogued?.metadata?.url?
-    for cu in (if typeof catalogued.metadata.url is 'string' then [catalogued.metadata.url] else catalogued.metadata.url)
-      metadata.url.push(cu) if cu not in metadata.url
-  metadata.url.push(options.url) if options.url? and options.url not in metadata.url
-  metadata.url.push(res.url) if res.url? and res.url not in metadata.url
+  if options.url?
+    metadata.url ?= []
+    metadata.url.push(options.url) if options.url not in metadata.url
+  if res.url
+    metadata.url ?= []
+    metadata.url.push(res.url) if res.url not in metadata.url
   res.permissions ?= API.service.oab.permissions(metadata) if options.permissions and not _.isEmpty(metadata)
   res.test = true if JSON.stringify(metadata).toLowerCase().replace(/'/g,' ').replace(/"/g,' ').indexOf(' test ') isnt -1 #or (options.embedded? and options.embedded.indexOf('openaccessbutton.org') isnt -1)
   res.metadata = metadata
@@ -514,6 +521,7 @@
     if catalogued?
       upd = {}
       upd.url = res.url if res.url? and res.url isnt catalogued.url
+      upd.open = res.open if res.open? and res.open isnt catalogued.open
       upd.metadata = metadata if not _.isEqual metadata, catalogued.metadata
       upd.sources = _.union(res.sources, catalogued.sources) if JSON.stringify(res.sources.sort()) isnt JSON.stringify catalogued.sources.sort()
       uc = _.union res.checked, catalogued.checked
@@ -529,6 +537,7 @@
       res.catalogue = catalogued._id
     else
       fl =
+        open: res.open
         url: res.url
         metadata: metadata
         sources: res.sources


fix reference to karma init command

fix reference to karma init command

--- src/steroids/Karma.coffee
+++ src/steroids/Karma.coffee
@@ -82,7 +82,7 @@
   ensureConfigExists: =>
     exists = fs.existsSync(paths.test.karma.configFilePath)
     unless exists
-      util.log "Could not find karma configuration file. Please run steroids karma init to generate #{paths.test.karma.configFilePath}"
+      util.log "Could not find karma configuration file. Please run steroids test karma init to generate #{paths.test.karma.configFilePath}"
       process.exit(1)

   startTestRun: (options={})=>


Add TentClient.PostType.prototype.setFragment

--- src/tent-client.js.coffee
+++ src/tent-client.js.coffee
@@ -32,6 +32,9 @@
         [m, @base, @version, @fragment] = m
         @fragment = @decodeFragment(@fragment) if @fragment
         @version = parseInt(@version)
+
+    setFragment: (fragment) =>
+      @fragment = @decodeFragment(fragment)

     assertMatch: (other_type) =>
       return false unless @base is other_type.base


refactor: fix load from url

refactor: fix load from url

--- src/ui/application.coffee
+++ src/ui/application.coffee
@@ -74,7 +74,7 @@

   getViewBase: ->
     return unity unless @keys.viewbase?
-    RegularTiling.parse @keys.viewbase
+    RegularTiling::parse @keys.viewbase

   getViewOffset: ->
     return M.eye() unless @keys.viewoffset?


Whitespace

Whitespace

--- src/model/storage_adapters/rest_storage.coffee
+++ src/model/storage_adapters/rest_storage.coffee
@@ -47,7 +47,7 @@
         if id = @get('id')
           url += '/' + id
         url
-    )
+    )

   @RecordMixin: Batman.extend({}, @BaseMixin)

@@ -63,10 +63,10 @@
   recordJsonNamespace: (record) -> Batman.helpers.singularize(@storageKey(record))
   collectionJsonNamespace: (constructor) -> Batman.helpers.pluralize(@storageKey(constructor.prototype))

-  _execWithOptions: (object, key, options, context = object) ->
-    if typeof object[key] is 'function'
+  _execWithOptions: (object, key, options, context = object) ->
+    if typeof object[key] is 'function'
       object[key].call(context, options)
-    else
+    else
       object[key]

   _defaultCollectionUrl: (model) -> "#{@storageKey(model.prototype)}"
@@ -259,5 +259,5 @@
       error = new errorClass
       error.request = request
       error.env = env
-    error
-
+    error
+


added tests for monadic rho

added tests for monadic rho

--- src/vocabulary/rho.coffee
+++ src/vocabulary/rho.coffee
@@ -1,16 +1,15 @@
 {APLArray} = require '../array'
 {assert, prod} = require '../helpers'

-# Shape of (`⍴`)
 #
-# Reshape (`⍴`)
-#
-#     ⍴ 1 2 3 ⍴ 0    ⍝ returns 1 2 3
-#     ⍴ ⍴ 1 2 3 ⍴ 0  ⍝ returns ,3
-#     3 3 ⍴ ⍳ 4      ⍝ returns 3 3 ⍴ 0 1 2 3 0 1 2 3 0
-#     ⍴ 3 3 ⍴ ⍳ 4    ⍝ returns 3 3
 @['⍴'] = (omega, alpha) ->
   if alpha
+    # Reshape (`⍴`)
+    #
+    #     ⍴ 1 2 3 ⍴ 0    ⍝ returns 1 2 3
+    #     ⍴ ⍴ 1 2 3 ⍴ 0  ⍝ returns ,3
+    #     3 3 ⍴ ⍳ 4      ⍝ returns 3 3 ⍴ 0 1 2 3 0 1 2 3 0
+    #     ⍴ 3 3 ⍴ ⍳ 4    ⍝ returns 3 3
     if alpha.shape.length > 1 then throw Error 'RANK ERROR'
     shape = alpha.toArray()
     for d in shape when typeof d isnt 'number' or d isnt Math.floor(d) or d < 0
@@ -22,4 +21,14 @@
     if a.length isnt n then a = a.concat a[... n - a.length]
     new APLArray a, shape
   else
+    # Shape of (`⍴`)
+    #
+    #     ⍴ 0           ⍝ returns 0 ⍴ 0
+    #     ⍴ 0 0         ⍝ returns 1 ⍴ 2
+    #     ⍴ ⍴ 0         ⍝ returns 1 ⍴ 0
+    #     ⍴ ⍴ ⍴ 0       ⍝ returns 1 ⍴ 1
+    #     ⍴ ⍴ ⍴ 0 0     ⍝ returns 1 ⍴ 1
+    #     ⍴ 'a'         ⍝ returns 0 ⍴ 0
+    #     ⍴ 'ab'        ⍝ returns 1 ⍴ 2
+    #     ⍴ 2 3 4 ⍴ 0   ⍝ returns 2 3 4
     new APLArray omega.shape


Method is showErrorDialog not showDialog

--- src/workspace-view.coffee
+++ src/workspace-view.coffee
@@ -141,11 +141,11 @@
     resourcePath = atom.getLoadSettings().resourcePath
     CommandInstaller.installAtomCommand resourcePath, (error) =>
       if error?
-        showDialog(error)
+        showErrorDialog(error)
       else
         CommandInstaller.installApmCommand resourcePath, (error) =>
           if error?
-            showDialog(error)
+            showErrorDialog(error)
           else
             atom.confirm
               message: "Commands installed."


fix If a theme doesn’t have any pledges, validation for new users from third party is never enabled

Former-commit-id: 4b7bb24d4bfa3f89a4f2445e77a2b276c53389d3 [formerly cc22e430fb4854a08ddd48ab6778f3c17c64c2e8] [formerly 681bbac885d90731403c47e799f0f5bb05255f3c [formerly 681bbac885d90731403c47e799f0f5bb05255f3c [formerly 559a8a3850dd8d8cc3b8ee6155f91f7e8dc8950a]]]
Former-commit-id: 352a52a8af7dc0c8117cc33144415fdd0b067418 [formerly 56b14c9c84233a490f235d88452a82a527c13c29]
Former-commit-id: 6057f46fee173413566152003c290ca7862b42c6
Former-commit-id: 12cf4ba0122c454fc5f78ae9110ad60b44c11da2

--- app/assets/javascripts/backbone/apps/auth/register/auth_register_view.coffee
+++ app/assets/javascripts/backbone/apps/auth/register/auth_register_view.coffee
@@ -38,7 +38,7 @@

       $submit_button_register = @$el.find('.m-user-accounts-complete-paperwork-footer input[type="submit"]')

-      if pledges_checked && $email_field.is('.ui-state-valid') && $password_field.is('.ui-state-valid') && $name_field.is('.ui-state-valid')
+      if pledges_checked && $email_field.is('.ui-state-valid') && $name_field.is('.ui-state-valid') && ($password_field.is('.ui-state-valid') || @model.authMethod() != 'email')
         $submit_button_register.removeAttr('disabled')
       else
         $submit_button_register.attr 'disabled', 'true'


Need to check it here

Need to check it here

--- client/app/Applications/Topics.kdapplication/Views/TopicsListItemView.coffee
+++ client/app/Applications/Topics.kdapplication/Views/TopicsListItemView.coffee
@@ -11,7 +11,7 @@
       pistachio   : '{{#(title)}}'
       click       : (pubInst, event) =>
         @titleReceivedClick()
-        event.stopPropagation()
+        event?.stopPropagation()
         no
     , data


test self closing

test self closing

--- src/test/template.coffee
+++ src/test/template.coffee
@@ -115,3 +115,23 @@
             ''
         ]

+    'self closing': (æ) ->
+        xml = streamify new Template schema:5, pretty:" ", doctype:on, ->
+            @$html ->
+                @$body ->
+                    @$div()
+                    @$br()
+        xml.ready æ.done
+        xml.stream.on 'data', (tag) -> æ.equal results.shift(), tag
+        results = [
+            '<!DOCTYPE html>\n'
+            '\n'
+            ' \n'
+            '
\n'
+            '
\n'
+            '
\n'
+            ' \n'
+            '\n'
+        ]
+
+


typo in homeloginbar

typo in homeloginbar

--- client/landing/app/Applications/Home.kdapplication/Views/homeloginbar.coffee
+++ client/landing/app/Applications/Home.kdapplication/Views/homeloginbar.coffee
@@ -77,7 +77,7 @@
       click       : (event)=>
         @utils.stopDOMEvent event
         requiresLogin =>
-          @getSingleton('mainController').emit "groupAccessRequested", @group, @policy, (err)=>
+          @appManager.tell 'Groups', "showRequestAccessModal", @group, @policy, (err)=>
             unless err
               @access.hide()
               @requested.show()


[fix] Fixed copying feedback to the clipboard (6m)

--- app/assets/javascripts/houston/feedback/models/comment.coffee
+++ app/assets/javascripts/houston/feedback/models/comment.coffee
@@ -21,7 +21,7 @@
       success()

   text: ->
-    lines = @get("text").lines()
+    lines = @get("text").match(/^.*$/gm)

     # Replace H_ tags with bold text of the same font size
     # and get rid of inner quotes.
@@ -35,7 +35,7 @@
       .replace /^(> \*.*\*\n)> \n(?!> \*)/mg, "$1"

   html: ->
-    lines = @get("text").lines()
+    lines = @get("text").match(/^.*$/gm)

     # Replace H_ tags with bold text of the same font size
     # and get rid of inner quotes.


allow space or enter to operate subscribe button

test plan:
 - on the discussions index page, ensure the "Subscribe
   to this Topic" button (which looks like a speech bubble)
   can be toggled with enter or space

fixes CNVS-33265

Change-Id: Ifc914ae9f8206bc56bc69f8738d7fcca55eb9a9d
Reviewed-on: https://gerrit.instructure.com/95195
Tested-by: Jenkins
Reviewed-by: Felix Milea-Ciobanu <9384aa226ac9d3237ed0bc52e18ffcb251ee0bf7@instructure.com>
QA-Review: Nathan Rogowski <2e8aa918660411855c6d44d5bb2da677aa033255@instructure.com>
Product-Review: Jeremy Stanley <b3f594e10a9edcf5413cf1190121d45078c62290@instructure.com>

--- app/coffeescripts/views/ToggleableSubscriptionIconView.coffee
+++ app/coffeescripts/views/ToggleableSubscriptionIconView.coffee
@@ -26,7 +26,7 @@
       position: my: 'center bottom', at: 'center top-10', collision: 'none'
       tooltipClass: 'center bottom vertical'

-    events: { 'click', 'hover', 'focus', 'blur' }
+    events: { 'click', 'keyclick' : 'click', 'hover', 'focus', 'blur' }

     initialize: ->
       @model.on('change:subscribed', @render)


Always show stderr on stack path

Always show stderr on stack path

--- lib/util.coffee
+++ lib/util.coffee
@@ -75,11 +75,11 @@
         env: env
         timeout: atom.config.get('haskell-ghc-mod.syncTimeout')
       CP.execFile 'stack', ['path', '--snapshot-install-root', '--local-install-root'], opts, (error, stdout, stderr) ->
+        Util.warn stderr if stderr
         if error?
           Util.warn("Running stack failed with ", error)
           reject error
         else
-          Util.warn stderr if stderr
           resolve stdout
     .then (out) ->
       lines = out.split(EOL)


added access token path

added access token path

--- packages/rocketchat-github-enterprise/common.coffee
+++ packages/rocketchat-github-enterprise/common.coffee
@@ -2,6 +2,7 @@
 	serverURL: ''
 	identityPath: '/api/v3/user'
 	authorizePath: '/login/oauth/authorize'
+	tokenPath: '/login/oauth/access_token'
 	addAutopublishFields:
 		forLoggedInUser: ['services.github-enterprise']
 		forOtherUsers: ['services.github-enterprise.username']


align

align

--- js/src/auth/CredentialService.coffee
+++ js/src/auth/CredentialService.coffee
@@ -89,7 +89,7 @@
           return Promise.resolve(@initializeKeypair({ password }))
         else
           log.info('using existing keypair')
-          passwordCrypto = new PasswordCryptoService()
+          passwordCrypto   = new PasswordCryptoService()
           privateKeyBytes  = passwordCrypto.decrypt(blockCiphertext, password)
           privateKeyBuffer = Forge.util.createBuffer(privateKeyBytes, 'raw')
           privateKeyAsn1   = Forge.asn1.fromDer(privateKeyBuffer)


On signout, group needs to be set to public (__world__)

Fixes #31

--- annotran/static/scripts/widget-controller.coffee
+++ annotran/static/scripts/widget-controller.coffee
@@ -50,6 +50,7 @@
     $scope.threadRoot = threading.root
     $scope.sortOptions = ['Newest', 'Oldest', 'Location']
     $scope.$root.currentUser = session.state.userid
+    $scope.session = session

     this.crossframe = crossframe

@@ -150,6 +151,9 @@
       _resetAnnotations(annotationMapper, drafts, threading)
       loaded = []
       loadAnnotations crossframe.frames
+      if $scope.session.state.groups.length == 1
+        # move focus to world when the user can only see the public group
+        groups.focus("__world__")

     $scope.$on events.GROUP_FOCUSED, ->
       $scope.$root.selectedUser = undefined


formating, selectors, role

formating, selectors, role

--- src/ui/views/menu.coffee
+++ src/ui/views/menu.coffee
@@ -2,98 +2,125 @@
 Menu = remote.Menu

 acceleratorMap = {
-    hideyakyak:           {others: 'Control+H', osx: 'Command+H'}
-    hideothers:           {others: '', osx: 'Command+Shift+H'}
-    showall:              {others: '', osx: ''}
-    openinspector:        {others: 'Control+Alt+I', osx: 'Command+Alt+I'}
-    quit:                 {others: 'Control+Q', osx: 'Command+Q'}
-    undo:                 {others: 'Control+Z', osx: 'Command+Z'}
-    redo:                 {others: 'Control+Shift+Z', osx: 'Command+Shift+Z'}
-    cut:                  {others: '', osx: 'Command+X'}
-    copy:                 {others: '', osx: 'Command+C'}
-    paste:                {others: '', osx: 'Command+V'}
-    selectall:            {others: '', osx: 'Command+A'}
-    togglefullscreen:     {others: 'Control+Alt+F', osx: 'Command+Control+F'}
-    zoomin:               {others: 'Control+Plus', osx: 'Command+Plus'}
-    zoomout:              {others: 'Control+-', osx: 'Command+-'}
-    resetzoom:            {others: 'Control+0', osx: 'Command+0'}
-    previousconversation: {others: 'Control+K', osx: 'Command+Shift+Tab'}
-    nextconversation:     {others: 'Control+J', osx: 'Command+Tab'}
-    conversation1:        {others: 'Alt+1', osx: 'Command+1'}
-    conversation2:        {others: 'Alt+2', osx: 'Command+2'}
-    conversation3:        {others: 'Alt+3', osx: 'Command+3'}
-    conversation4:        {others: 'Alt+4', osx: 'Command+4'}
-    conversation5:        {others: 'Alt+5', osx: 'Command+5'}
-    conversation6:        {others: 'Alt+6', osx: 'Command+6'}
-    conversation7:        {others: 'Alt+7', osx: 'Command+7'}
-    conversation8:        {others: 'Alt+8', osx: 'Command+8'}
-    conversation9:        {others: 'Alt+9', osx: 'Command+9'}
-    minimize:             {others: '', osx: 'Command+M'}
-    close:                {others: '', osx: 'Command+W'}
+    hideyakyak:           {others: 'Control+H', darwin:'Command+H'}
+    hideothers:           {others: '', darwin:'Command+Shift+H'}
+    showall:              {others: '', darwin:''}
+    openinspector:        {others: 'Control+Alt+I', darwin:'Command+Alt+I'}
+    quit:                 {others: 'Control+Q', darwin:'Command+Q'}
+    undo:                 {others: 'Control+Z', darwin:'Command+Z'}
+    redo:                 {others: 'Control+Shift+Z', darwin:'Command+Shift+Z'}
+    cut:                  {others: '', darwin:'Command+X'}
+    copy:                 {others: '', darwin:'Command+C'}
+    paste:                {others: '', darwin:'Command+V'}
+    selectall:            {others: '', darwin:'Command+A'}
+    togglefullscreen:     {others: 'Control+Alt+F', darwin:'Command+Control+F'}
+    zoomin:               {others: 'Control+Plus', darwin:'Command+Plus'}
+    zoomout:              {others: 'Control+-', darwin:'Command+-'}
+    resetzoom:            {others: 'Control+0', darwin:'Command+0'}
+    previousconversation: {others: 'Control+K', darwin:'Command+Shift+Tab'}
+    nextconversation:     {others: 'Control+J', darwin:'Command+Tab'}
+    conversation1:        {others: 'Alt+1', darwin:'Command+1'}
+    conversation2:        {others: 'Alt+2', darwin:'Command+2'}
+    conversation3:        {others: 'Alt+3', darwin:'Command+3'}
+    conversation4:        {others: 'Alt+4', darwin:'Command+4'}
+    conversation5:        {others: 'Alt+5', darwin:'Command+5'}
+    conversation6:        {others: 'Alt+6', darwin:'Command+6'}
+    conversation7:        {others: 'Alt+7', darwin:'Command+7'}
+    conversation8:        {others: 'Alt+8', darwin:'Command+8'}
+    conversation9:        {others: 'Alt+9', darwin:'Command+9'}
+    minimize:             {others: '', darwin:'Command+M'}
+    close:                {others: '', darwin:'Command+W'}
 }

-templateYakYak = (viewstate, os) ->
+templateYakYak = (viewstate, platform) ->
     tmpl = []
-    if os == 'darwin'
-        tmpl.push [
+    if platform == 'darwin'
+        tmpl.concat [
             { label: 'About YakYak', selector: 'orderFrontStandardAboutPanel:' }
             #{ type: 'separator' }
             # { label: 'Preferences...', accelerator: 'Command+,',
             # click: => delegate.openConfig() }
             { type: 'separator' }
         ]
-    tmpl.push [
-        {
-            label: 'Hide YakYak'
-            accelerator: acceleratorMap['hideyakyak'][os]
-            selector: 'hide:'
-        }
-    ]
-
-    if os == 'darwin'
+    tmpl.push {
+        label: 'Hide YakYak'
+        accelerator: acceleratorMap['hideyakyak'][platform]
+        selector: 'hide:' if platform == 'darwin'
+        role: 'minimize' if platform == 'others'
+    }
+
+    if platform == 'darwin'
         tmpl.push [{
-              label: 'Hide Others'
-              accelerator: acceleratorMap['hideother'][os]
-              selector: 'hideOtherApplications:'
-        }
-        { label: 'Show All', selector: 'unhideAllApplications:' }
+                label: 'Hide Others'
+                accelerator: acceleratorMap['hideother'][platform]
+                selector: 'hideOtherApplications:' if platform == 'darwin'
+            }
+            {
+                label: 'Show All'
+                selector: 'unhideAllApplications:' if platform == 'darwin'
+            }
         ]
     tmpl.push [
-      { type: 'separator' }
-      {
-          label: 'Open Inspector'
-          accelerator: acceleratorMap['openinspector'][os]
-          click: -> action 'devtools'
-      }
-      { type: 'separator' }
-      {
-          label: 'Logout',
-          click: -> action 'logout'
-          enabled: viewstate.loggedin
-      }
-      {
-          label: 'Quit'
-          accelerator: acceleratorMap['quit'][os]
-          click: -> action 'quit'
-      }
-  ]
-
-templateEdit = (viewstate, os) ->
+        { type: 'separator' }
+        {
+            label: 'Open Inspector'
+            accelerator: acceleratorMap['openinspector'][platform]
+            click: -> action 'devtools'
+        }
+        { type: 'separator' }
+        {
+            label: 'Logout',
+            click: -> action 'logout'
+            enabled: viewstate.loggedin
+        }
+        {
+            label: 'Quit'
+            accelerator: acceleratorMap['quit'][platform]
+            click: -> action 'quit'
+        }
+    ]
+    tmpl
+
+templateEdit = (viewstate, platform) ->
     tmpl = [
-        { label: 'Undo', accelerator: acceleratorMap['undo'][os], selector: 'undo:' }
-        { label: 'Redo', accelerator: acceleratorMap['redo'][os], selector: 'redo:' }
+        {
+          label: 'Undo'
+          accelerator: acceleratorMap['undo'][platform]
+          selector: 'undo:' if platform == 'darwin'
+        }
+        {
+          label: 'Redo'
+          accelerator: acceleratorMap['redo'][platform]
+          selector: 'redo:' if platform == 'darwin'
+        }
     ]
-    if os == 'darwin'
+    if platform == 'darwin'
         tmpl.push [
           { type: 'separator' }
-          { label: 'Cut', accelerator: acceleratorMap['cut'][os], selector: 'cut:' }
-          { label: 'Copy', accelerator: acceleratorMap['copy'][os], selector: 'copy:' }
-          { label: 'Paste', accelerator: acceleratorMap['paste'][os], selector: 'paste:' }
-          { label: 'Select All', accelerator: acceleratorMap['selectall'][os], selector: 'selectAll:' }
+          {
+            label: 'Cut'
+            accelerator: acceleratorMap['cut'][platform]
+            selector: 'cut:' if platform == 'darwin'
+          }
+          {
+            label: 'Copy'
+            accelerator: acceleratorMap['copy'][platform]
+            selector: 'copy:' if platform == 'darwin'
+          }
+          {
+            label: 'Paste'
+            accelerator: acceleratorMap['paste'][platform]
+            selector: 'paste:' if platform == 'darwin'
+          }
+          {
+            label: 'Select All'
+            accelerator: acceleratorMap['selectall'][platform]
+            selector: 'selectAll:' if platform == 'darwin'
+          }
         ]
     tmpl

-templateView = (viewstate, os) ->
+templateView = (viewstate, platform) ->
     tmpl = [
         {
             label: 'Conversation List'
@@ -199,31 +226,31 @@
             ]
         }, {
             label: 'Toggle Full Screen',
-            accelerator: acceleratorMap['togglefullscreen'][os],
+            accelerator: acceleratorMap['togglefullscreen'][platform],
             click: -> action 'togglefullscreen'
         }, {
             # seee https://github.com/atom/electron/issues/1507
             label: 'Zoom In',
-            accelerator: acceleratorMap['zoomin'][os],
+            accelerator: acceleratorMap['zoomin'][platform],
             click: -> action 'zoom', +0.25
         }, {
             label: 'Zoom Out',
-            accelerator: acceleratorMap['zoomout'][os],
+            accelerator: acceleratorMap['zoomout'][platform],
             click: -> action 'zoom', -0.25
         }, {
             label: 'Reset Zoom',
-            accelerator: acceleratorMap['resetzoom'][os],
+            accelerator: acceleratorMap['resetzoom'][platform],
             click: -> action 'zoom'
         }, {
             type: 'separator'
         }, {
             label: 'Previous Conversation',
-            accelerator: acceleratorMap['previousconversation'][os]
+            accelerator: acceleratorMap['previousconversation'][platform]
             enabled: viewstate.loggedin
             click: -> action 'selectNextConv', -1
         }, {
             label: 'Next Conversation',
-            accelerator: acceleratorMap['nextconversation'][os]
+            accelerator: acceleratorMap['nextconversation'][platform]
             enabled: viewstate.loggedin
             click: -> action 'selectNextConv', +1
         }, {
@@ -232,39 +259,39 @@
             submenu: [
               {
                   label: 'Conversation 1'
-                  accelerator: acceleratorMap['conversation1'][os]
+                  accelerator: acceleratorMap['conversation1'][platform]
                   click: -> action 'selectConvIndex', 0
               }, {
                   label: 'Conversation 2'
-                  accelerator: acceleratorMap['conversation2'][os]
+                  accelerator: acceleratorMap['conversation2'][platform]
                   click: -> action 'selectConvIndex', 1
               }, {
                   label: 'Conversation 3'
-                  accelerator: acceleratorMap['conversation3'][os]
+                  accelerator: acceleratorMap['conversation3'][platform]
                   click: -> action 'selectConvIndex', 2
               }, {
                   label: 'Conversation 4'
-                  accelerator: acceleratorMap['conversation4'][os]
+                  accelerator: acceleratorMap['conversation4'][platform]
                   click: -> action 'selectConvIndex', 3
               }, {
                   label: 'Conversation 5'
-                  accelerator: acceleratorMap['conversation5'][os]
+                  accelerator: acceleratorMap['conversation5'][platform]
                   click: -> action 'selectConvIndex', 4
               }, {
                   label: 'Conversation 6'
-                  accelerator: acceleratorMap['conversation6'][os]
+                  accelerator: acceleratorMap['conversation6'][platform]
                   click: -> action 'selectConvIndex', 5
               }, {
                   label: 'Conversation 7'
-                  accelerator: acceleratorMap['conversation7'][os]
+                  accelerator: acceleratorMap['conversation7'][platform]
                   click: -> action 'selectConvIndex', 6
               }, {
                   label: 'Conversation 8'
-                  accelerator: acceleratorMap['conversation8'][os]
+                  accelerator: acceleratorMap['conversation8'][platform]
                   click: -> action 'selectConvIndex', 7
               }, {
                   label: 'Conversation 9'
-                  accelerator: acceleratorMap['conversation9'][os]
+                  accelerator: acceleratorMap['conversation9'][platform]
                   click: -> action 'selectConvIndex', 8
               }
             ]
@@ -278,7 +305,7 @@
             click: -> action 'toggleshowtray'
         }
     ]
-    if os == 'darwin'
+    if platform == 'darwin'
         tmpl.push {
             label: 'Hide Dock icon'
             type: 'checkbox'
@@ -288,42 +315,44 @@
         }
     tmpl

-templateWindow = (viewstate, os) -> [
+templateWindow = (viewstate, platform) -> [
     {
         label: 'Minimize'
-        accelerator: acceleratorMap['minimize'][os]
-        selector: 'performMiniaturize:'
+        accelerator: acceleratorMap['minimize'][platform]
+        selector: 'performMiniaturize:' if platform == 'darwin'
     }, {
         label: 'Close'
-        accelerator: acceleratorMap['close'][os]
-        selector: 'performClose:'
+        accelerator: acceleratorMap['close'][platform]
+        selector: 'performClose:' if platform == 'darwin'
     }, {
         type: 'separator'
     }, {
         label: 'Bring All to Front',
-        selector: 'arrangeInFront:'
+        selector: 'arrangeInFront:' if platform == 'darwin'
     }
 ]

 templateMenu = (viewstate) ->
-    os = if require('os').platform() == 'darwin' then 'darwin' else 'others'
+    platform = if require('os').platform() == 'darwin' then 'darwin' else 'others'
     tmpl = [{
             label: 'YakYak'
-            submenu: templateYakYak viewstate, os
+            submenu: templateYakYak viewstate, platform
         }, {
             label: 'Edit'
-            submenu: templateEdit viewstate, os
+            submenu: templateEdit viewstate, platform
         },{
             label: 'View'
-            submenu: templateView viewstate, os
+            submenu: templateView viewstate, platform
         }
     ]
-    if os == 'darwin'
+    if platform == 'darwin'
         tmpl.push {
             label: 'Window'
-            submenu: templateWindow viewstate, os
+            submenu: templateWindow viewstate, platform
         }
     tmpl

 module.exports = (viewstate) ->
+    console.log "b4"
     Menu.setApplicationMenu Menu.buildFromTemplate templateMenu(viewstate)
+    console.log "done!"


correction on i18n tag

correction on i18n tag

--- src/ui/views/menu.coffee
+++ src/ui/views/menu.coffee
@@ -211,7 +211,7 @@
                 }
                 {
                   type: 'checkbox'
-                  label: i18n.__('menu.view.notification.custom')
+                  label: i18n.__('menu.view.notification.custom_sound')
                   checked: viewstate.forceCustomSound
                   enabled: viewstate.loggedin && viewstate.showPopUpNotifications && !viewstate.muteSoundNotification
                   click: (it) -> action 'forcecustomsound', it.checked


:memo: Attempt to document view resolution algorithm

--- src/view-registry.coffee
+++ src/view-registry.coffee
@@ -123,6 +123,24 @@
   #
   # * `object` The object for which you want to retrieve a view. This can be a
   #   pane item, a pane, or the workspace itself.
+  #
+  # ## View Resolution Algorithm
+  #
+  # The view associated with the object is resolved using the following
+  # heuristic sequence
+  #
+  #  1. Is the object an instance of `HTMLElement`? If true, return the object.
+  #  2. Does the object have a property named `element` with a value which is
+  #     an instance of `HTMLElement`? If true, return the property value.
+  #  3. Is the object a SpacePen view, which means it has a `jquery` property?
+  #     If true, return the root DOM node (i.e. `object[0]`).
+  #  4. Has a view provider been registered for the object? If true, use the
+  #     provider to create a view associated with the object, and return the
+  #     view.
+  #  5. Does the object have a `getViewClass` method? If true, use the method
+  #     to create a view associated with the object, and return the view.
+  #
+  # If no associated view is returned by the sequence an error is thrown.
   #
   # Returns a DOM element.
   getView: (object) ->


OX-444 fixed (0,0,0) direction bug

OX-444 fixed (0,0,0) direction bug

--- app/assets/javascripts/oxalis/model/route.coffee
+++ app/assets/javascripts/oxalis/model/route.coffee
@@ -109,15 +109,19 @@
       # dirty but this actually is what needs to be done
       TYPE_BRANCH = TYPE_USUAL

+
       #calculate direction of first edge in nm
-      firstEdge = @data.trees[0]?.edges[0]
-      if firstEdge
-        sourceNodeNm = @scaleInfo.voxelToNm(@findNodeInList(@trees[0].nodes, firstEdge.source).pos)
-        targetNodeNm = @scaleInfo.voxelToNm(@findNodeInList(@trees[0].nodes, firstEdge.target).pos)
-        @firstEdgeDirection = [targetNodeNm[0] - sourceNodeNm[0],
-                               targetNodeNm[1] - sourceNodeNm[1],
-                               targetNodeNm[2] - sourceNodeNm[2]]
-
+      if @data.trees[0]?.edges?
+        for edge in @data.trees[0].edges
+          sourceNodeNm = @scaleInfo.voxelToNm(@findNodeInList(@trees[0].nodes, edge.source).pos)
+          targetNodeNm = @scaleInfo.voxelToNm(@findNodeInList(@trees[0].nodes, edge.target).pos)
+          if sourceNodeNm != targetNodeNm
+            @firstEdgeDirection = [targetNodeNm[0] - sourceNodeNm[0],
+                                   targetNodeNm[1] - sourceNodeNm[1],
+                                   targetNodeNm[2] - sourceNodeNm[2]]
+            break
+
+      if @firstEdgeDirection
         @flycam.setSpaceDirection(@firstEdgeDirection)
         @flycam3d.setDirection(V3.normalize(@firstEdgeDirection))


whitespace fixes

whitespace fixes

Change-Id: If9233cd37a0fdca79e2428328a2cadcd7aaa079f
Reviewed-on: https://gerrit.instructure.com/11643
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
Reviewed-by: Cameron Matheson <1d572acbfa68c7c6e541c7b840d6b622e5c0dc91@instructure.com>

--- app/coffeescripts/SubmissionDetailsDialog.coffee
+++ app/coffeescripts/SubmissionDetailsDialog.coffee
@@ -15,7 +15,7 @@
   class SubmissionDetailsDialog
     constructor: (@assignment, @student, @options) ->
       @url = @options.change_grade_url.replace(":assignment", @assignment.id).replace(":submission", @student.id)
-      @submission = $.extend {}, @student["assignment_#{@assignment.id}"],
+      @submission = $.extend {}, @student["assignment_#{@assignment.id}"],
         assignment: @assignment
         speedGraderUrl: "#{@options.context_url}/gradebook/speed_grader?assignment_id=#{@assignment.id}#%7B%22student_id%22%3A#{@student.id}%7D"
         loading: true
@@ -33,7 +33,7 @@
           event.preventDefault()
           $(event.currentTarget).disableWhileLoading $.ajaxJSON @url, 'PUT', $(event.currentTarget).getFormData(), (data) =>
             @update(data)
-            setTimeout =>
+            setTimeout =>
               @dialog.dialog('close')
             , 500

@@ -42,10 +42,10 @@

     open: =>
       @dialog.dialog('open')
-
+
     scrollCommentsToBottom: =>
       @dialog.find('.submission_details_comments').scrollTop(999999)
-
+
     update: (newData) =>
       $.extend @submission, newData
       @submission.submission_history[0] = @submission
@@ -69,7 +69,7 @@
       @dialog.html(submissionDetailsDialog(@submission))
       @dialog.find('select').trigger('change')
       @scrollCommentsToBottom()
-
+
     @cachedDialogs: {}

     @open: (assignment, student, options) ->


CRITICAL, smart case is inverted by careless mistake.

--- lib/get-filter-spec-for-query.coffee
+++ lib/get-filter-spec-for-query.coffee
@@ -42,7 +42,7 @@
     patterns.push(pattern)

   options = ''
-  if (sensitivity is 'sensitive') or (sensitivity is 'smartcase' and isIncludeUpperCase)
+  if (sensitivity is 'sensitive') or (sensitivity is 'smartcase' and not isIncludeUpperCase)
     options += 'i'

   new RegExp(patterns.join('|'), options)


Fix: Error message doesn't dissapear on keyup after submitting via ctrl/cmd + enter

--- lib/assets/javascripts/views/post/002_new_post_form.js.coffee
+++ lib/assets/javascripts/views/post/002_new_post_form.js.coffee
@@ -109,6 +109,7 @@
     Marbles.DOM.on @elements.textarea, 'keyup', (e) =>
       clearTimeout @_validateTimeout
       return if @frozen
+      return if e.keyCode in [224, 17, 13] # ctrl/cmd + enter
       setTimeout @validate, 300

       @updateCharCounter()


Fixed actionHandler Browse not working if options.BrowseFlag is an array

--- lib/services/ContentDirectory.coffee
+++ lib/services/ContentDirectory.coffee
@@ -56,7 +56,7 @@
         browseCallback = (err, resp) =>
           cb null, (if err? then @buildSoapError(err) else resp)

-        switch options?.BrowseFlag
+        switch options?.BrowseFlag?.toString()
           when 'BrowseMetadata'
             @browseMetadata options, browseCallback
           when 'BrowseDirectChildren'


Refactoring: IDE: Remove duplicated code line.

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -372,7 +372,6 @@

     parent.attach targetView  # Attach again.

-    @setActiveTabView targetIdeView.tabView
     @updateLayoutMap_ splitView, targetView

     # I'm not sure about the usage of private method. I had to...


appcontroller: remove cleancollaboration from quit call

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -1203,7 +1203,6 @@

   quit: ->

-    @cleanupCollaboration()

     @mountedMachine.getBaseKite(createIfNotExists = no).disconnect()


appcontroller: emit an event when ide ready process is finished

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -926,6 +926,7 @@

     data = { machine, workspace: @workspaceData }
     kd.singletons.mainView.activitySidebar.selectWorkspace data
+    @emit 'IDEReady'

   removeFakeViews: ->


colourscheme Dürer is supposed to be greyscale only

--- client/prefs-colours.coffee
+++ client/prefs-colours.coffee
@@ -90,7 +90,7 @@
   '''}
   {name:'Albrecht Dürer', styles: '''
     com=I:1 diam=B:1 err=fg:f,bg:0,bgo:.5,B:1,I:1,U:1 glb=I:1 idm=U:1,bg:e,bgo:.5 kw=B:1 lnum=bg:f,bgo:1 mod=bg:e,bgo:1
-    mtch=bg:c,bgo:.5 norm=bg:f,bgo:1 ns=fg:8 num=fg:8 quad=fg:808 srch=bg:c,bgo:.5 str=fg:8 tc=bg:e,bgo:1 zld=fg:8
+    mtch=bg:c,bgo:.5 norm=bg:f,bgo:1 ns=fg:8 num=fg:8 quad=fg:8 srch=bg:c,bgo:.5 str=fg:8 tc=bg:e,bgo:1 zld=fg:8
   '''}
   {name:'Kazimir Malevich', styles: ''}
 ].map(decodeScheme).map (x) -> x.frozen = 1; x


payment: update price when interval toggle changes

--- client/Main/payment/form.coffee
+++ client/Main/payment/form.coffee
@@ -209,8 +209,19 @@

   handleToggleChanged: (subscription) ->

-    button = @intervalToggle.buttons[subscription.interval]
+    { interval } = subscription
+
+    @state.interval = interval
+    { monthPrice, yearPrice } = @state
+
+    button = @intervalToggle.buttons[interval]
     @intervalToggle.buttonReceivedClick button
+
+    pricePartial = if interval is PaymentWorkflow.interval.MONTH
+    then "#{monthPrice / 100.00}/mo"
+    else "#{(yearPrice / 100.00) / 12}/mo"
+
+    @price.updatePartial pricePartial

   pistachio: ->


Collaboration: Update method name.

Collaboration: Update method name.

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -500,7 +500,7 @@
       @registerPane pane

     ideView.on 'ChangeHappened', (change) =>
-      @writeChange change
+      @syncChange change

   registerPane: (pane) ->
     {view} = pane
@@ -511,7 +511,7 @@
     @generatedPanes[view.hash] = yes

     view.on 'ChangeHappened', (change) =>
-      @writeChange change
+      @syncChange change

   forEachSubViewInIDEViews_: (callback = noop, paneType) ->
     if typeof callback is 'string'
@@ -783,7 +783,7 @@
     return panes

-  writeChange: (change) ->
+  syncChange: (change) ->
     {context} = change

     return  if not @realTimeDoc or not context


Ace: save problem fixed

Ace: save problem fixed

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -1056,7 +1056,7 @@

       when 'editor'
         {path}        = context.file
-        file          = FSHelper.createFileInstance path
+        file          = FSHelper.createFileInstance {path, machine : @mountedMachine}
         file.paneHash = context.paneHash

         content = @rtm.getFromModel(path)?.getText() or ''


Fixed compilation in cond

Fixed compilation in cond

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -1902,7 +1902,7 @@
   args = _arguments call
   [conds, results] = unzip pairs args
   doneConds = termsCompileExpectingType ctx, boolType, conds
-  doneResults = termsCompileExpectingSameType ctx, results
+  doneResults = termsCompileExpectingSameType ctx, (filter _is, results)

   errorMessage =
     if ctx.definitionName()?
@@ -1914,7 +1914,7 @@
   branches = for res in doneResults.compiled
     [(jsReturn res)]
   assignCompile ctx, call,
-    (iife [(jsConditional (zip doneConds.compiled, branches),
+    (iife [(jsConditional (zip doneConds.compiled[0...branches.length], branches),
         "throw new Error('cond failed to match#{errorMessage}');")])


Fixed matching by adding deferrability to definitions

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -157,9 +157,15 @@
       name: pattern?.symbol
       pattern: pattern
       inside: 0
+      late: no
       deferredBindings: []
       definedNames: []
+      deferrable: yes
       _defer: undefined
+
+  defineNonDeferrablePattern: (pattern) ->
+    definition = @definePattern pattern
+    definition.deferrable = no

   leaveDefinition: ->
     @_scope().definition = undefined
@@ -185,6 +191,13 @@

   _definitionAtScope: (i) ->
     @scopes[i].definition or i > 0 and (@_definitionAtScope i - 1) or undefined
+
+  _deferrableDefinition: ->
+    @_deferrableDefinitionAtScope @scopes.length - 1
+
+  _deferrableDefinitionAtScope: (i) ->
+    (def = @scopes[i].definition) and def.deferrable and def or
+      i > 0 and (@_deferrableDefinitionAtScope i - 1) or undefined

   isDefining: ->
     !!@_scope().definition
@@ -229,13 +242,13 @@

   newLateScope: ->
     @newScope()
-    @_definition().late = yes
+    @_deferrableDefinition()?.late = yes

   closeScope: ->
     @scopes.pop()

   isInsideLateScope: ->
-    @_definition().late
+    @_deferrableDefinition()?.late

   isInTopScope: ->
     @_scope().topLevel
@@ -331,22 +344,11 @@
       []

   doDefer: (expression, dependencyName) ->
-    @_setDeferIn @_definition(), expression, dependencyName
-
-  dontDefer: ->
-    @_setDeferIn @_definition(), false
-
-  setDeferParent: (dependencyName) ->
-    if @scopes.length < 2
-      throw new Error "Deferring parent although this is top level scope"
-    @_setDeferIn @_parentScope(), dependencyName
+    @_setDeferIn @_deferrableDefinition(), expression, dependencyName

   _setDeferIn: (definition, expression, dependencyName) ->
     definition._defer =
-      if expression
-        (@_deferReasonOf definition) or [expression, dependencyName]
-      else
-        no
+      (@_deferReasonOf definition) or [expression, dependencyName]

   deferReason: ->
     @_deferReasonOf @_definition()
@@ -683,7 +685,6 @@

 assignCompile = (ctx, expression, translatedExpression) ->
   # if not translatedExpression # TODO: throw here?
-    #log expression
   if ctx.isAtDefinition()
     to = ctx.definitionPattern()

@@ -711,6 +712,7 @@

   definedNames = ctx.definedNames()

+  # log "is deferriing", pattern, ctx.shouldDefer()
   # Make sure deferred names are added to scope so they are compiled within functions
   if ctx.shouldDefer()
     for {name} in definedNames
@@ -1018,17 +1020,18 @@
     compiledCases = conditional (for [pattern, result] in pairs cases

       ctx.newScope() # for variables defined inside pattern
-
+      ctx.defineNonDeferrablePattern pattern
       {precs, assigns} = patternCompile ctx, pattern, subject, subjectCompiled

       # Compile the result, given current scope
       compiledResult = termCompile ctx, result #compileImpl result, furtherHoistable
+      ctx.leaveDefinition()
       ctx.closeScope()

       if ctx.shouldDefer()
         continue

-      #log "unifying in match", resultType, result.tea
+      # log "unifying in match", result, resultType, result.tea
       unify ctx, resultType, result.tea
       varNames.push (findDeclarables precs)...

@@ -1156,13 +1159,14 @@

 nameCompile = (ctx, atom, symbol) ->
   contextType = ctx.type symbol
+  # log "nameCompile", symbol, ctx.isInsideLateScope(), contextType, ctx.isDeclared symbol
   if exp = ctx.assignTo()
     if atom.label is 'const'
       if contextType
         type: freshInstance ctx, ctx.type symbol
         pattern: constPattern ctx, symbol
       else
-        #log "deferring in pattern for #{symbol}"
+        # log "deferring in pattern for #{symbol}"
         ctx.doDefer atom, symbol
         pattern: []
     else
@@ -1190,7 +1194,7 @@
         translation: nameTranslate ctx, atom, symbol
       }
     else
-      #log "deferring for #{symbol}"
+      # log "deferring in rhs for #{symbol}"
       ctx.doDefer atom, symbol
       translation: 'deferred'


Fix the const labeling in quote

Fix the const labeling in quote

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -2166,7 +2166,8 @@
       else
         commedAtom ast, ->
           serialized = (jsValue (JSON.stringify ast))
-          ast.label = 'const'
+          if (isExpression ast) or (ast.symbol in allDelims)
+            ast.label = 'const'
           serialized
     serializeAst expression


Outputting indent tokens and separate space tokens

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -4,7 +4,7 @@
     match = input.match ///
       ^ # must be at the start
       (
-        \x20+ # spaces
+        \x20 # space
       | \n # newline
       | [#{controls}] # delims
       | /([^\\x20]|\\/)([^/]|\\/)*?/ # regex
@@ -23,29 +23,35 @@

 controls = '\\(\\)\\[\\]\\{\\}'

-noWS = (tokens) ->
-  tokens.filter (token) -> token.label isnt 'whitespace'
-
 astize = (tokens) ->
   tree = []
   current = []
   stack = [[]]
+  indentAccumulator = []
   for token in tokens
-    if token.symbol in leftDelims
-      form = [token]
-      form.start = token.start
-      stack.push form
-    else if token.symbol in rightDelims
-      closed = stack.pop()
-      if not stack[stack.length - 1]
-        throw new Error "Missing opening delimeter matching #{token.symbol}"
-      if token.symbol isnt delims[closed[0].symbol]
-        throw new Error "Wrong closing delimiter #{token.symbol} for opening delimiter #{closed[0].symbol}"
-      closed.push token
-      closed.end = token.end
-      stack[stack.length - 1].push closed
+    if token.symbol is ' ' and indentAccumulator?.length <= 2 * (stack.length - 1)
+      indentAccumulator.push token
     else
-      stack[stack.length - 1].push token
+      if indentAccumulator?.length > 0
+        stack[stack.length - 1].push createIndent indentAccumulator
+      indentAccumulator = undefined
+      if token.symbol is '\n'
+        indentAccumulator = []
+      if token.symbol in leftDelims
+        form = [token]
+        form.start = token.start
+        stack.push form
+      else if token.symbol in rightDelims
+        closed = stack.pop()
+        if not stack[stack.length - 1]
+          throw new Error "Missing opening delimeter matching #{token.symbol}"
+        if token.symbol isnt delims[closed[0].symbol]
+          throw new Error "Wrong closing delimiter #{token.symbol} for opening delimiter #{closed[0].symbol}"
+        closed.push token
+        closed.end = token.end
+        stack[stack.length - 1].push closed
+      else
+        stack[stack.length - 1].push token
   ast = stack[0][0]
   if not ast
     throw new Error "Missing closing delimeter matching #{stack[stack.length - 1][0].symbol}"
@@ -55,6 +61,12 @@
 leftDelims = ['(', '[', '{']
 rightDelims = [')', ']', '}']
 delims = '(': ')', '[': ']', '{': '}'
+
+createIndent = (accumulator) ->
+  symbol: (new Array accumulator.length + 1).join ' '
+  start: accumulator[0].start
+  end: accumulator[accumulator.length - 1].end
+  label: 'indent'

 constantLabeling = (atom) ->
   {symbol} = atom
@@ -69,6 +81,9 @@
     ['bracket', symbol in ['[', ']']]
     ['brace', symbol in ['{', '}']]
     ['whitespace', /^\s+$/.test symbol]
+
+noWhitespace = (tokens) ->
+  tokens.filter (token) -> token.label not in ['whitespace', 'indent']

 labelMapping = (word, rules...) ->
   for [label, cond] in rules when cond
@@ -3648,7 +3663,7 @@
   (_terms call)[1..]

 _terms = (form) ->
-  form[1...-1].filter ({label}) -> label isnt 'whitespace'
+  noWhitespace form[1...-1]

 _snd = ([a, b]) -> b