Rephrasing for clarity

Rephrasing for clarity

--- wikipedia.coffee
+++ wikipedia.coffee
@@ -1,5 +1,5 @@
 # Description:
-#   Wikipedia API - Wikipedia Open Search
+#   Wikipedia API - Search for Wikipedia articles
 #
 # Dependencies:
 #   None
@@ -8,7 +8,7 @@
 #   None
 #
 # Commands:
-#   hubot wiki <query> - Search Wikipedia for articles using the query (returns first 5 matches)
+#   hubot wiki <query> - Search Wikipedia for articles using the query (returns the first 5 matches)
 #
 # Author:
 #   MrSaints
@@ -33,7 +33,7 @@
             data = JSON.parse body

             if data[1].length is 0
-                msg.reply "Your query ('#{query}') returned no results."
+                msg.reply "Your query ('#{query}') returned no articles."
                 return

             for article in data[1][0..4]


Permissions: add new role button to fields

--- client/Dashboard/views/permissionsform.coffee
+++ client/Dashboard/views/permissionsform.coffee
@@ -15,13 +15,15 @@
         style       : "solid green"
         loader      : yes
         callback    : =>
-
-          group.updatePermissions @reducedList(), (err,res)=>
+          @buttons["Save"].hideLoader()
+          @group.updatePermissions @reducedList(), (err,res)=>
             @buttons["Save"].hideLoader()
-            unless err
-              new KDNotificationView
-                title : "Group permissions have been updated."
-            KD.showError err
+            return KD.showError err if err
+            new KDNotificationView title: "Group permissions have been updated."
+      Add           :
+        title       : "Add"
+        style       : "solid green"
+        callback    : @bound "showNewRoleModal"

     options.fields or= optionizePermissions roles, permissionSet
     super options,data


Teamwork: Now we can invite multiple people via TBot.

--- client/Teamwork/Views/teamworkchatpane.coffee
+++ client/Teamwork/Views/teamworkchatpane.coffee
@@ -65,11 +65,14 @@
     hasHandler   = replyHandlers[keyword] isnt undefined
     isHelp       = keyword is "help"
     isStopWatch  = keyword is "stop"
+    isInvite     = keyword is "invite"

     if isHelp
       return splitted.length is 1
     else if isStopWatch
       return message is "stop watching"
+    else if isInvite
+      return hasHandler
     else
       return hasMaxLength and hasHandler

@@ -101,27 +104,26 @@
       @botReply messages.invalidKey

   replyForInvite: (usernames) ->
-    # TODO: fatihacet - currently invite only first user
-    username = usernames.first
-    return if usernames.length is 0 or username.trim() is ""
-
-    # TODO: fatihacet
-    # Kinda hacky to create user list here to send an invite. Instead of this,
-    # I should implement a method in CW that will handle to invite stuff.
-    @workspace.createUserList()
-    query = { "profile.nickname": username }
-
-    KD.remote.api.JAccount.one query, {}, (err, account) =>
-      @workspace.userList.once "UserInvited", =>
-        message    = getMessage "invited", username
-        if usernames.length > 1
-          message += messages.inviteOneByOne
-        @botReply message
-
-      @workspace.userList.once "UserInviteFailed", =>
-        @botReply getMessage "inviteFailed", username
-
-      @workspace.userList.sendInviteTo account
+    query = { "profile.nickname": { "$in": usernames } }
+
+    KD.remote.api.JAccount.someWithRelationship query, {}, (err, accounts) =>
+      stack = []
+      usernames.forEach (username) =>
+        account = null
+        user    = account for account in accounts when account.profile.nickname is username
+
+        if user
+          stack.push (cb) =>
+            @workspace.createUserList() # TODO: fatihacet - find a better way for invite
+
+            @workspace.userList.once "UserInvited", =>
+              @botReply getMessage "invited", username
+
+            @workspace.userList.sendInviteTo account
+        else
+          @botReply getMessage "inviteFailed", username
+
+      async.parallel stack, noop

   replyForWatch: (usernames) ->
     username = usernames.first
@@ -169,6 +171,12 @@
       cssClass : "tw-bot-avatar"
       tooltip  :
         title  : messages.botTooltip
+
+    @avatars.addSubView new KDCustomHTMLView
+      cssClass : "tw-add-user"
+      tooltip  :
+        title  : "Click here to invite your friends"
+      click    : => new TeamworkInviteModal delegate: this

   getMessage = (key, data) ->
     return messages[key].replace "$0", data
@@ -195,11 +203,7 @@
         You can type "stop watching" anytime.
       """
     watchNobody   : "It's done. Now you are watching nobody."
-    invited       : "Sure thing! I invited $0 for you. I will let you know when they join."
-    inviteOneByOne: """
-
-      Sorry, you can invite only one person at a time for now. My master is working on this feature. Please type one by one.
-    """
+    invited       : "I invited $0 for you. I will let you know when they join."
     inviteFailed  : "Sorry, are you sure your friend's nickname is $0? Because I can't find it."
     validateKey   : "01001101 ... I am checking this session key, $0."
     joinSession   : "01001010 ... Joining session, $0"


Add comment

Add comment

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -585,7 +585,7 @@
       @removeInitialViews()
       mapLength = @myWatchMap.values()?.length

-      ## `mapLength=0` meant the participant joined the collaboration just now.
+      ## The `mapLength=0` meant the participant joined the collaboration just now.
       if not mapLength or @amIWatchingChangeOwner(@collaborationHost)
         @getHostSnapshot (snapshot) =>
           @layoutManager.resurrectSnapshot snapshot, yes


Update useragent for bots

Update useragent for bots

--- bots/libs/HexBot.coffee
+++ bots/libs/HexBot.coffee
@@ -3,7 +3,7 @@
 #require = patchRequire(global.require)
 #utils = require('utils')

-exports.userAgent = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1516.3 Safari/537.36'
+exports.userAgent = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1530.2 Safari/537.36'

 #argumentData = [{name:'argName1',default:'optionalArg'}, {name:'argName2',csv:true}, ...]
 exports.parseArgs = (casper, argumentData) ->


don't expose contact email

don't expose contact email

Former-commit-id: ab9f5f0d7d11f82f76d0b6841b2712a08e7c1299 [formerly bdb3f0a6a6f9b5e8633d9fa11727c363a42aa4bf] [formerly 33403d526e9dd38fca320eb92b47f5e9af33d3c3 [formerly 1f4c862af12fe1ae05d63c5ef783552806ac0dd8]] [formerly f22ea0a733bb041982857fe491bc0e89d9fe2f11 [formerly 45a787f64990db9c6602a5fd32ba8cd731a59357] [formerly f3b2c45249d1b513b61470bd22ec2e98fd5d21cd [formerly f3b2c45249d1b513b61470bd22ec2e98fd5d21cd [formerly e256246460713c61613c53f4d988eb4f541899f6]]]]
Former-commit-id: 620953dbc70573cb197ae482aa7ae194d447a972 [formerly 53afe55767d4eaf181b00d44f9cf3eb52115e2fb] [formerly 166244151705733f0089d1f29af5997b658be833 [formerly 9c43b70903032f719da3dfa5504229d151618128]]
Former-commit-id: 09eb4c34bd70951192feb12abab79526f8bf75d3 [formerly cd071d1e022d1f39b8acf1235d3ffd6a1a3e72ee]
Former-commit-id: b7bec55b7eddfc10e65d2fef3280bb61aa16dafa
Former-commit-id: 74ff0c8c965a645aed2d586812c9c69613bb6e1a

--- @client/admin.coffee
+++ @client/admin.coffee
@@ -200,14 +200,14 @@
               defaultValue: subdomain.external_project_url
               placeholder: 'A link to the main project\'s homepage, if any.'

-          DIV className: 'input_group',
-            LABEL htmlFor: 'notifications_sender_email', 'Contact email'
-            INPUT
-              id: 'notifications_sender_email'
-              type: 'text'
-              name: 'notifications_sender_email'
-              defaultValue: subdomain.notifications_sender_email
-              placeholder: 'Sender email address for notification emails. Default is admin@consider.it.'
+          # DIV className: 'input_group',
+          #   LABEL htmlFor: 'notifications_sender_email', 'Contact email'
+          #   INPUT
+          #     id: 'notifications_sender_email'
+          #     type: 'text'
+          #     name: 'notifications_sender_email'
+          #     defaultValue: subdomain.notifications_sender_email
+          #     placeholder: 'Sender email address for notification emails. Default is admin@consider.it.'

           DIV className: 'input_group',
             LABEL htmlFor: 'about_page_url', 'About Page URL'


filter out null files

filter out null files

--- browser/frontend.coffee
+++ browser/frontend.coffee
@@ -153,7 +153,7 @@
     files =
       for key, file of localStorage when key[..5] == 'file::'
         DoppioFile.load key[6..]
-    (f.name for f in files).sort().join '\n'
+    (f.name for f in files when f?).sort().join '\n'
   edit: (args) ->
     data = DoppioFile.load(args[0])?.read() or defaultFile
     $('#console').fadeOut 'fast', ->


Add #getUpstreamBranch to Git

Add #getUpstreamBranch to Git

--- src/git.coffee
+++ src/git.coffee
@@ -217,6 +217,17 @@
   # Public: Returns the origin url of the repository.
   getOriginUrl: -> @getConfigValue('remote.origin.url')

+  # Public: Returns the upstream branch for the current HEAD, or null if there
+  # is no upstream branch for the current HEAD.
+  #
+  # Examples
+  #
+  #   getUpstreamBranch()
+  #   # => "refs/remotes/origin/master"
+  #
+  # Returns a String.
+  getUpstreamBranch: -> @getRepo().getUpstreamBranch()
+
   # Public: ?
   getReferenceTarget: (reference) -> @getRepo().getReferenceTarget(reference)


Adds additional funnel event

Adds additional funnel event

--- components/after_inquiry/questionnaire.coffee
+++ components/after_inquiry/questionnaire.coffee
@@ -78,6 +78,8 @@
         # And we're done...
         @close()

+    analytics.track.funnel 'Submitted questionnaire during after inquiry flow'
+
   auth: (e) ->
     return unless @validateForm()


LEV-53 probability added

LEV-53 probability added

--- modules/levelcreator/app/assets/javascripts/level_creator/plugins/write_path_to_meta_file.coffee
+++ modules/levelcreator/app/assets/javascripts/level_creator/plugins/write_path_to_meta_file.coffee
@@ -40,10 +40,15 @@
     for segment in activeSegments
       segmentPayload = {}
       segmentPayload.isEndSegment = _.contains(endValues, segment.value)
+
       segmentPayload.isStartSegment = _.contains(startValue, segment.value)
       segmentPayload.path = segment.path
       segmentPayload.id = segment.id
       segmentPayload.value = segment.value
+      if segmentPayload.isEndSegment
+        segmentPayload.probability = _.find(mission.possibleEnds, (m) => m.id is segmentPayload.value).probability
+      else
+        segmentPayload.probability = 0

       payload.push segmentPayload


commits table component to support pagination [#67023622]

--- app/assets/javascripts/components/commits_table_component.js.coffee
+++ app/assets/javascripts/components/commits_table_component.js.coffee
@@ -1,3 +1,21 @@
 Review.CommitsTableComponent = Ember.Component.extend
-  tagName: 'article'
+  tagName:    'article'
   classNames: ['commits']
+  page:           1
+  perPage:        4
+
+  paginatedContent: (->
+    page    = @get('page')
+    perPage = @get('perPage')
+    start   = (page - 1) * perPage
+    end     = page * perPage
+
+    @get('commits.content').slice(start, end)
+  ).property('arrangedContent.[]', 'page', 'perPage')
+
+  pages: (->
+    result = parseInt(@get('commits.content.length') / @get('perPage'))
+    ++result if @get('commits.content.length') % @get('perPage') > 0
+
+    result
+  ).property('content.[]', 'perPage')


add same new on<Event> attributes for cleaning

--- src/back/back-transport.coffee
+++ src/back/back-transport.coffee
@@ -6,8 +6,21 @@
 gonzales = require '../modules/gonzales.coffee'
 select = require('optimal-select').select

-META_ATTRIBS_FOR_DEL = ['Content-Security-Policy', 'refresh']
-ONEVENT_ATTRIBS = [ 'onload', 'onclick', 'onkeypress' ]
+META_ATTRIBS_FOR_DEL = [
+  'Content-Security-Policy'
+  'refresh'
+]
+
+ONEVENT_ATTRIBS = [
+  'onload'
+  'onclick'
+  'onkeyup'
+  'onkeydown'
+  'onenter'
+  'onmouseenter',
+  'onmouseleave'
+  'onkeypress'
+]

 class TreeElementNotFound extends Error

@@ -236,4 +249,4 @@
     return src+">"

-module.exports = BackTransport+module.exports = BackTransport


Only perform validation on fields that are not disabled

--- tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/fields.coffee
+++ tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/fields.coffee
@@ -98,11 +98,10 @@

     dom.onDocument events.field.inputValidation, (event, formMemo) ->

-      # When not visible to the user, ignore the input validation. Components
-      # are generally configured so that they do not submit a value to the server
-      # when not visible ... this is what the core/FormFragment component is responsible
-      # for.
-      return unless @deepVisible()
+      # Fields that are disbled, or not visible to the user are not subject to
+      # validation. Typically, a field will only be invisible due to the
+      # core/FormFragment component.
+      return if @element.disabled or (not @deepVisible())

       failure = false


fix(autoload-images): Check to see if whitelist exists

--- internal_packages/message-autoload-images/lib/autoload-images-store.coffee
+++ internal_packages/message-autoload-images/lib/autoload-images-store.coffee
@@ -30,11 +30,13 @@
     true

   _loadWhitelist: =>
-    fs.readFile @_whitelistEmailsPath, (err, body) =>
-      return console.log(err) if err or not body
-      @_whitelistEmails = {}
-      for email in body.toString().split(/[\n\r]+/)
-        @_whitelistEmails[Utils.toEquivalentEmailForm(email)] = true
+    fs.exists @_whitelistEmailsPath, (exists) =>
+      return unless exists
+      fs.readFile @_whitelistEmailsPath, (err, body) =>
+        return console.log(err) if err or not body
+        @_whitelistEmails = {}
+        for email in body.toString().split(/[\n\r]+/)
+          @_whitelistEmails[Utils.toEquivalentEmailForm(email)] = true

   _saveWhitelist: =>
     data = Object.keys(@_whitelistEmails).join('\n')


Update `vim-mode-plus`

Update `vim-mode-plus`

--- .atom/config.cson
+++ .atom/config.cson
@@ -13,7 +13,7 @@
       "one-light-syntax"
     ]
   editor:
-    fontSize: 2
+    fontSize: 1
     showInvisibles: true
   "exception-reporting":
     userId: ""
@@ -48,7 +48,6 @@
     createOnChange: true
     forceOverwrite: true
   "vim-mode-plus":
-    notifiedCoffeeScriptNoLongerSupportedToExtendVMP: true
     startInInsertMode: true
   welcome:
     showOnStartup: false


Comment explaining the ChunkedFileReader

--- src/chunked-line-reader.coffee
+++ src/chunked-line-reader.coffee
@@ -8,6 +8,16 @@
     return i if buffer[i] == char
   -1

+# Will ensure data will be read on a line boundary. So this will always do the
+# right thing:
+#
+#   lines = []
+#   reader = new ChunkedLineReader('some/file.txt')
+#   reader.on 'data', (chunk) ->
+#     lines = lines.concat(chunk.toString().split(/\r\n|\n|\r/))
+#
+# This will collect all the lines in the file, or you can process each line in
+# the data handler for more efficiency.
 module.exports =
 class ChunkedLineReader extends Readable


goplus atom config

goplus atom config

--- atom/config.cson
+++ atom/config.cson
@@ -28,3 +28,4 @@
   linter: {}
   "atom-beautify":
     _analyticsUserId: "a6a0720b-ef9b-4635-a6bf-67af0c531216"
+  "go-plus": {}


Enable linting for .ss files

Enable linting for .ss files

--- atom/config.cson
+++ atom/config.cson
@@ -132,6 +132,16 @@
   linter:
     lintOnChange: false
     lintPreviewTabs: false
+  "linter-eslint":
+    scopes: [
+      "source.js"
+      "source.jsx"
+      "source.js.jsx"
+      "source.flow"
+      "source.babel"
+      "source.js-semantic"
+      "source.js.sca.ss"
+    ]
   "linter-ui-default":
     hidePanelWhenEmpty: true
     showPanel: true


update atom config

update atom config

--- atom/config.cson
+++ atom/config.cson
@@ -19,3 +19,4 @@
   whitespace:
     removeTrailingWhitespace: false
     ignoreWhitespaceOnlyLines: true
+    ensureSingleTrailingNewline: false


Exclude LocalDistribution/DeployDistribution from find-and-replace results

--- atom/config.cson
+++ atom/config.cson
@@ -63,6 +63,8 @@
       ".svn"
       ".virtualenv"
       ".Trashes"
+      "LocalDistribution"
+      "DeployDistribution"
       "node_modules"
       "Thumbs.db"
     ]


Update to scoped configuration

Update to scoped configuration

--- atom/config.cson
+++ atom/config.cson
@@ -1,99 +1,103 @@
-'exception-reporting':
-  'userId': 'ee24cf00-f793-9081-be2a-2cdae5536b7f'
-'welcome':
-  'showOnStartup': false
-'metrics':
-  'userId': '51eeb6113c1ae801c9aade9b6d679aa5189ced25'
-'editor':
-  'fontFamily': 'Source Code Pro'
-  'preferredLineLength': 100
-  'invisibles':
-    'cr': '↩'
-    'tab': '⇥'
-    'eol': ' '
-  'normalizeIndentOnPaste': false
-  'showInvisibles': true
-  'scrollPastEnd': true
-'core':
-  'projectHome': '/Volumes/Data/Users/Lee/Source'
-  'disabledPackages': [
-    'autosave'
-    'emacs-flow'
-  ]
-  'ignoredNames': [
-    '.git'
-    '.hg'
-    '.svn'
-    '.DS_Store'
-    '.keep'
-    '._*'
-    '*.pyc'
-  ]
-  'themes': [
-    'soda-light-ui'
-    'solarized-light-syntax'
-  ]
-'auto-copyright':
-  'buffer': 1
-  'owner': 'Lifted Studios'
-'spell-check':
-  'grammars': [
-    'source.gfm'
-    'text.git-commit'
-    'text.plain'
-  ]
-'tree-view':
-  'hideIgnoredNames': true
-  'hideVcsIgnoredFiles': true
-'remember-window':
-  'storeOutsideMainConfig': true
-'tabs-to-spaces':
-  'onSave': 'untabify'
-'autocomplete':
-  'includeCompletionsFromAllBuffers': true
-'fancy-new-file':
-  'suggestCurrentFilePath': true
-'autocomplete-plus':
-  'fileBlacklist': '.*'
-'autocomplete-emojis':
-  'fileWhitelist': '*.md, COMMIT_EDITMSG'
-'overrides':
-  'scopes':
-    'source':
-      'gfm':
-        'showInvisibles': false
-        'softWrap': true
-        'tabLength': 4
-      'java':
-        'tabLength': 4
-      'python':
-        'tabLength': 4
-      'shell':
-        'tabLength': 4
-'wrap-guide':
-  'columns': [
-    {
-      'scope': 'source.gfm'
-      'column': -1
-    }
-    {
-      'scope': 'text.git-commit'
-      'column': 72
-    }
-    {
-      'scope': 'text.haml'
-      'column': -1
-    }
-  ]
-'atom-color-highlight':
-  'hideMarkersInComments': true
-  'hideMarkersInStrings': true
-'package-generator':
-  'createInDevMode': true
-'atom-lint':
-  'rubocop':
-    'showDisplayCopNames': true
-'enhanced-package-list':
-  'highlightAuthor': 'lee-dohm'
-'white-cursor':
-  'enabled': 'detect'
+'.shell.source':
+  'editor':
+    'tabLength': 4
+'.python.source':
+  'editor':
+    'tabLength': 4
+'.java.source':
+  'editor':
+    'tabLength': 4
+'.gfm.source':
+  'editor':
+    'showInvisibles': false
+    'softWrap': true
+    'tabLength': 4
+'.c.source':
+  'editor':
+    'tabLength': 4
+'global':
+  'exception-reporting':
+    'userId': 'ee24cf00-f793-9081-be2a-2cdae5536b7f'
+  'welcome':
+    'showOnStartup': false
+  'metrics':
+    'userId': '51eeb6113c1ae801c9aade9b6d679aa5189ced25'
+  'editor':
+    'fontFamily': 'SourceCodePro-Regular'
+    'preferredLineLength': 100
+    'invisibles':
+      'cr': '↩'
+      'tab': '⇥'
+      'eol': ' '
+    'normalizeIndentOnPaste': false
+    'showInvisibles': true
+    'scrollPastEnd': true
+  'core':
+    'projectHome': '/Volumes/Data/Users/Lee/Source'
+    'disabledPackages': [
+      'autosave'
+      'emacs-flow'
+      'overrides'
+    ]
+    'ignoredNames': [
+      '.git'
+      '.hg'
+      '.svn'
+      '.DS_Store'
+      '.keep'
+      '._*'
+      '*.pyc'
+    ]
+    'themes': [
+      'soda-light-ui'
+      'solarized-light-syntax'
+    ]
+  'auto-copyright':
+    'buffer': 1
+    'owner': 'Lifted Studios'
+  'spell-check':
+    'grammars': [
+      'source.gfm'
+      'text.git-commit'
+      'text.plain'
+    ]
+  'tree-view':
+    'hideIgnoredNames': true
+    'hideVcsIgnoredFiles': true
+  'remember-window':
+    'storeOutsideMainConfig': true
+  'tabs-to-spaces':
+    'onSave': 'untabify'
+  'autocomplete':
+    'includeCompletionsFromAllBuffers': true
+  'fancy-new-file':
+    'suggestCurrentFilePath': true
+  'autocomplete-plus':
+    'fileBlacklist': '.*'
+  'atom-color-highlight':
+    'hideMarkersInComments': true
+    'hideMarkersInStrings': true
+  'package-generator':
+    'createInDevMode': true
+  'atom-lint':
+    'rubocop':
+      'showDisplayCopNames': true
+  'enhanced-package-list':
+    'highlightAuthor': 'lee-dohm'
+  'white-cursor':
+    'enabled': 'detect'
+  'wrap-guide':
+    'columns': [
+      {
+        'scope': 'source.gfm'
+        'column': -1
+      }
+      {
+        'scope': 'text.git-commit'
+        'column': 72
+      }
+      {
+        'scope': 'text.haml'
+        'column': -1
+      }
+    ]


Fixed an issue where the browser interface would fail to reprompt if the main class's initialization failed or if the main class had no main method.

--- src/jvm.coffee
+++ src/jvm.coffee
@@ -40,7 +40,7 @@
           rs.init_args cmdline_args
           # wrap it in run_until_finished to handle any exceptions correctly
           rs.run_until_finished (-> main_method = rs.method_lookup cls, main_spec), true, (success) ->
-            return unless success and main_method?
+            return done_cb?() unless success and main_method?
             rs.run_until_finished (-> main_method.setup_stack(rs)), false, (success) ->
               done_cb?() if success
         ), except_cb


Added a label

Added a label

--- src/log.coffee
+++ src/log.coffee
@@ -8,6 +8,10 @@

 module.exports = new winston.Logger
 	transports: [
-		new winston.transports.Console timestamp: timestamp, colorize: true, level: level
+		new winston.transports.Console
+			timestamp: timestamp
+			colorize:  true
+			level:     level
+			label:     "redis-port"
 	]


Client: Activity: Deleted onKeyDown and OnChange method. we use search instead

--- client/activity/lib/components/sidebarmodallist/index.coffee
+++ client/activity/lib/components/sidebarmodallist/index.coffee
@@ -40,14 +40,10 @@
     @setState threads: @props.sidebarModalChannels.followed

-  onChange: ->
-
-    console.log 'onchange'

-  onKeyDown: ->

-    console.log 'onKeyDown'
+

   renderHeader: ->
@@ -58,8 +54,6 @@
         <input
           className   = 'ChannelList-searchInput'
           placeholder = 'Search'
-          onChange    = { @bound 'onChange' }
-          onKeyDown   = { @bound 'onKeyDown' }
           ref         = 'ChannelSearchInput'
         />
       </div>


hackathon: added nginx and made prize a pull from db value

--- client/landing/site.hackathon/coffee/home/AppViewFull.coffee
+++ client/landing/site.hackathon/coffee/home/AppViewFull.coffee
@@ -345,7 +345,7 @@

To celebrate 500,000 developers...

ANNOUNCING THE WORLD’S FIRST GLOBAL VIRTUAL #HACKATHON

Let's hack together, wherever we are!

-
Apply today with your Koding account to get a chance to win up to $10,000 in cash prizes.

+
Apply today with your Koding account to get a chance to win up to $#{prize.toLocaleString()} in cash prizes.

#{@getStats()}

@@ -414,6 +414,7 @@

What are the prizes?

+        Total prizes over $25,000! Here are the details.

$10,000 cash prize from Koding, split amongst the top 3 teams ($5k, $3k, $2k each).

Winners will be offered credits for services like DigitalOcean, Tutum and many more!

@@ -423,6 +424,12 @@

Additional Prizes

+

+

+
+
nginx is adding an additional $2,000 to the overall prize money.

+

+


fix(Resource): correctly handle 0 and id values and [] defaults for m2m.

--- src/ORM.coffee
+++ src/ORM.coffee
@@ -20,6 +20,15 @@

   startsWith = (s, sub) -> s.slice(0, sub.length) == sub
   endsWith   = (s, sub) -> sub == '' or s.slice(-sub.length) == sub
+
+  isKeyLike = (value) ->
+    if not value?
+      return false
+    if angular.isUndefined(value) or (value == null)
+      return false
+    if angular.isObject(value) or angular.isArray(value)
+      return false
+    return true

   # based on http://stackoverflow.com/a/2676231
   _urljoin = (components...) ->
@@ -664,7 +673,7 @@
       _urljoin @constructor.urlPrefix, @constructor.urlEndpoint

     _fetchRelations: ->
-      if @$id
+      if @$id?
         @_fetchReferences()
         @_fetchM2M()
       @
@@ -672,7 +681,7 @@
     _fetchReferences: ->
       fetchReference = (instance, reference, promises) ->
         fieldName = reference.name
-        if (fieldName of instance) and instance[fieldName]
+        if (fieldName of instance) and instance[fieldName]? and isKeyLike(instance[fieldName])
           ref_id = instance[fieldName]
           record = reference.model.Get(ref_id)
           instance[fieldName] = record
@@ -689,7 +698,7 @@
     _fetchM2M: ->
       fetchM2M = (instance, m2m, promises) ->
         fieldName = m2m.name
-        if (fieldName of instance) and instance[fieldName]
+        if (fieldName of instance) and instance[fieldName]? and isKeyLike(instance[fieldName])
           refs_promises = []
           refs_collection = m2m.model._MakeCollection()
           for ref_id in instance[fieldName]


Only zoom in, not out, when automatically centering.

--- src/map.coffee
+++ src/map.coffee
@@ -502,7 +502,7 @@
                 zoom: @get_zoomlevel_to_show_all_markers()
             else if @selected_units.isSet()
                 center: @lat_lng_from_geojson @selected_units.first()
-                zoom: @get_max_auto_zoom()
+                zoom: Math.max @get_max_auto_zoom(), @map.getZoom()
             else
                 null


[Prefetch] Divide prefetched activity into 2

--- client/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/app/Applications/Activity.kdapplication/AppController.coffee
@@ -159,7 +159,7 @@
         group      :
           slug     : groupObj?.slug or "koding"
           id       : groupObj.getId()
-        limit      : 20
+        limit      : 50
         facets     : @getActivityFilter()
         withExempt : no

@@ -202,15 +202,34 @@
       @listController.listActivitiesFromCache sanitizedCache
       callback sanitizedCache

+
+  FETCHING_ATTEMPT = 0
   fetchPublicActivities:(options = {})->
     {CStatusActivity} = KD.remote.api

     if @getFeedFilter() is "Public" and @getActivityFilter() is "Everything"
       prefetchedActivity = KD.prefetchedFeeds["activity.main"]
-      if prefetchedActivity and ('activities.main' not in USEDFEEDS) and prefetchedActivity.activities
+      if prefetchedActivity and prefetchedActivity.activities and ('activities.main' not in USEDFEEDS)
         log "exhausting feed:", "activity.main"
-        USEDFEEDS.push 'activities.main'
-        return @prepareCacheForListing KD.prefetchedFeeds["activity.main"]
+
+        if FETCHING_ATTEMPT > 0 then USEDFEEDS.push 'activities.main'
+
+        activity = $.extend {}, KD.prefetchedFeeds["activity.main"]
+        overview = activity.overview
+        firstCount = 25
+        secondCount = 50
+
+        switch ++FETCHING_ATTEMPT
+          when 1
+            firstCount = -24
+            secondCount = 50
+          when 2
+            firstCount = -50
+            secondCount = 25
+
+        overview = overview[firstCount..secondCount]
+        activity.overview = overview
+        return @prepareCacheForListing activity

     CStatusActivity.fetchPublicActivityFeed options, (err, cache)=>
       return @emit "activitiesCouldntBeFetched", err  if err


Use new non-intermediate representation

Use new non-intermediate representation

--- js-library/app/js/jail_iframe/initializers/xdm.coffee
+++ js-library/app/js/jail_iframe/initializers/xdm.coffee
@@ -3,7 +3,7 @@
 frame_container.appendChild(iframe)
 FactlinkJailRoot.createReceiverEnvoy FactlinkJailRoot.annotatedSiteReceiver
 iframe.id = "factlink-modal-frame"
-iframe.src = "#{FactlinkConfig.api}/factlink/intermediate"
+iframe.src = "#{FactlinkConfig.api}/client/blank"
 FactlinkJailRoot.factlinkCoreEnvoy = FactlinkJailRoot.createSenderEnvoy iframe.contentWindow, ['showFactlink', 'prepareNewFactlink' ]

 FactlinkJailRoot.openFactlinkModal = FactlinkJailRoot.factlinkCoreEnvoy.showFactlink


Removed unused code

Removed unused code

site_id and suggestion-region

--- core/app/backbone/views/channels/auto_complete_channels_view.coffee
+++ core/app/backbone/views/channels/auto_complete_channels_view.coffee
@@ -5,7 +5,6 @@
     "click div.auto-complete-search-list": "addCurrent"

   regions:
-    'suggestionRegion': '.suggestion-region'
     'results': 'div.auto-complete-results-container'
     'search_list': 'div.auto-complete-search-list-container'
     'text_input': 'div.auto-complete-input-container'
@@ -13,8 +12,6 @@
   template: "auto_complete/box_with_results"

   initialize: (options) ->
-    @site_id = options.site_id
-
     @initializeChildViews
       filter_on: 'slug_title'
       search_list_view: (options) -> new AutoCompleteSearchChannelsView(options)


Fix blockquote at the first line of reply [#39]

--- coffee/lib/formatters.coffee
+++ coffee/lib/formatters.coffee
@@ -25,6 +25,7 @@
                        "magnet", "mailto", "xmpp"]
         return @output link.href
     # Always generate links
+    # Note that marked's escape function is slightly differ
     "<a href=\"#{formatters.escape2 link.href}\"" +
     (if link.title then "title=\"#{formatters.escape2 link.title}\"" else "") +
     ">" + @output(cap[1]) +
@@ -74,10 +75,19 @@
     markdown: (raw) ->
       ###Markdown with some additional BnW-specific rules.###

+      # Fix blockquote at the first line of reply comment
+      # TODO: Does it proper API behaviour? bnw_core/post.py:
+      # 'text': ('@' + old_comment['user'] + ' ' if comment_id else '') + text
+      FIX_BLOCKQUOTE =
+        [/^(@[-0-9A-Za-z_]+ )>/g
+        , (_m, user) -> "#{user}\n>"
+        ]
+
       format = (text) =>
         ###Apply BnW additional formatters.###
+        text = text.replace FIX_BLOCKQUOTE[0], FIX_BLOCKQUOTE[1]
         text = text.replace @USER_LINK_FORMATTER[0], @USER_LINK_FORMATTER[2]
-        text.replace @POST_LINK_FORMATTER[0], @POST_LINK_FORMATTER[2]
+        text = text.replace @POST_LINK_FORMATTER[0], @POST_LINK_FORMATTER[2]

       # Walk through raw input text and apply bnw formatters only
       # for non-code blocks.


fix #184: expand isolated points after simplifying

--- app/graph.coffee
+++ app/graph.coffee
@@ -201,7 +201,7 @@
       transform_value = (v) -> v
       filter_scatter_values = (values) ->
         simplify _.filter values, (d) -> d.value?
-      expand_line_values = _.compose simplify, expandIsolatedValuesToLineSegments
+      expand_line_values = _.compose expandIsolatedValuesToLineSegments, simplify

     value_min = null
     value_max = null


Add isRecorded() to AVStream

Add isRecorded() to AVStream

--- avstreams.coffee
+++ avstreams.coffee
@@ -61,6 +61,9 @@
     @spropParameterSets  = ''    # string
     @type                = null  # string ('live' or 'recorded')

+  isRecorded: ->
+    return @type is api.STREAM_TYPE_RECORDED
+
   reset: ->
     logger.debug "[stream:#{@id}] reset"
     @initAVParams()


イベントリスナー消す

イベントリスナー消す

--- src/coffee/kazitori.coffee
+++ src/coffee/kazitori.coffee
@@ -390,6 +390,8 @@
     return @

   _bindChild:(rule, child)->
+    child.reject()
+    child.stop()
     childHandlers = child.handlers.concat()
     for childRule in childHandlers
       childRule.update(rule)
@@ -440,12 +442,12 @@
       return

     if child instanceof Kazitori
-      #@_unbindChild(child)
+      @_unbindChild(child, childRoot)
     else
       if name.hasOwnProperty('__super__')
         try
           child = new name({'isAutoStart':false})
-          # @_unbindChild(rule, child)
+          @_unbindChild(child, childRoot)
           return @
         catch e
           throw new Error("引数の値が不正です。 引数に指定する値は Kazitori を継承している必要があります。")


Allow packets to be passed to Underscore.js function in a batch

--- components/Underscore.coffee
+++ components/Underscore.coffee
@@ -8,31 +8,36 @@
   function name"

   constructor: ->
+    @stream = true
+
     @inPorts =
       in: new noflo.Port
+      stream: new noflo.Port
       name: new noflo.Port
     @outPorts =
       out: new noflo.Port

+    @inPorts.stream.on "data", (stream) =>
+      @stream = stream is "true"
+
     @inPorts.name.on "data", (@name) =>

-    @inPorts.in.on "begingroup", (group) =>
-      @outPorts.out.beginGroup(group)
+    @inPorts.in.on "connect", =>
+      @packets = []

     @inPorts.in.on "data", (data) =>
-      console.log "* DDD"
-      console.log @name
-      console.log data
-      console.log _[@name] data
-      if @name?
-        @outPorts.out.send _[@name] data
+      if @stream
+        if @name?
+          @outPorts.out.send _[@name] data
+        else
+          @outPorts.out.send data
       else
-        @outPorts.out.send data
-
-    @inPorts.in.on "endgroup", =>
-      @outPorts.out.endGroup()
+        @packets.push(data)

     @inPorts.in.on "disconnect", =>
+      unless @stream
+        @outPorts.out.send _[@name].apply _, @packets
+
       @outPorts.out.disconnect()

 exports.getComponent = -> new Underscore


Apply review

Apply review

--- src/components/common/transactions-list/transactions-list.component.coffee
+++ src/components/common/transactions-list/transactions-list.component.coffee
@@ -176,13 +176,11 @@
     deleteTransactionsGroup = (trx) ->
       # TODO: should be accessible by recurring transactions only
       return $q.when(null) unless trx.recurring_parent
-      args = { resourcesType: ctrl.resourcesType, trxId: trx.recurring_parent }
-      ctrl.onDeleteParentTransaction(args).finally(->
-        # Remove all children transactions and parent transaction if it is a forecast
-        _.remove(ctrl.currentAttributes.transactions, (trxInList) ->
-          (trxInList.recurring_parent == trx.recurring_parent) || (trxInList.id == trx.recurring_parent && trxInList.status == 'FORECAST')
-        )
+      # Remove all children transactions and parent transaction if it is a forecast
+      _.remove(ctrl.currentAttributes.transactions, (trxInList) ->
+        (trxInList.recurring_parent == trx.recurring_parent) || (trxInList.id == trx.recurring_parent && trxInList.status == 'FORECAST')
       )
+      ctrl.onDeleteParentTransaction({ resourcesType: ctrl.resourcesType, trxId: trx.recurring_parent })

     return ctrl
 })


Update price option uses env User Agent,

--- src/commands/import.coffee
+++ src/commands/import.coffee
@@ -57,7 +57,7 @@
         service = new PriceImport log,
           clientConfig:
             config: options.credentials
-            user_agent: 'sphere-node-cli'
+            user_agent: USER_AGENT
           errorDir: errorDir
           errorLimit: options.errorLimit
         processFn = _.bind(service.performStream, service)


Retry on init errors

Retry on init errors

--- src/app.coffee
+++ src/app.coffee
@@ -56,48 +56,51 @@
 						console.log("Server listening")

 console.log("Starting node connman app")
-connman.init (err) ->
-	throw err if err?
-	console.log("Connman initialized")
-	connman.initWiFi (err, wifi, properties) ->
-		throw err if err?
-		console.log("WiFi initialized")
+manageConnection = (retryCallback) ->
+	connman.init (err) ->
+		retryCallback(err) if err?
+		console.log("Connman initialized")
+		connman.initWiFi (err, wifi, properties) ->
+			retryCallback(err) if err?
+			console.log("WiFi initialized")

-		app.use(bodyParser())
-		app.use(express.static(__dirname + '/public'))
-		app.get '/ssids', (req, res) ->
-			res.send(ssidList)
-		app.post '/connect', (req, res) ->
-			if req.body.ssid and req.body.passphrase
-				console.log("Selected " + req.body.ssid)
-				res.send('OK')
-				server.close()
+			app.use(bodyParser())
+			app.use(express.static(__dirname + '/public'))
+			app.get '/ssids', (req, res) ->
+				res.send(ssidList)
+			app.post '/connect', (req, res) ->
+				if req.body.ssid and req.body.passphrase
+					console.log("Selected " + req.body.ssid)
+					res.send('OK')
+					server.close()
+					iptables.delete { table: 'nat', rule: "PREROUTING -i tether -j TETHER"}, ->
+						iptables.flush 'nat', 'TETHER', ->
+							dnsServer.kill()
+							console.log("Server closed and captive portal disabled")
+							wifi.joinWithAgent req.body.ssid, req.body.passphrase, (err) ->
+								console.log(err) if err
+								return startServer(wifi) if err
+								console.log("Joined! Exiting.")
+								retryCallback()
+			app.use (req, res) ->
+				res.redirect('/')
+
+			# Create TETHER iptables chain (will silently fail if it already exists)
+			iptables.createChain 'nat', 'TETHER', ->
+				# Ensure no rules exist from an unclean shutdown
 				iptables.delete { table: 'nat', rule: "PREROUTING -i tether -j TETHER"}, ->
 					iptables.flush 'nat', 'TETHER', ->
-						dnsServer.kill()
-						console.log("Server closed and captive portal disabled")
-						wifi.joinWithAgent req.body.ssid, req.body.passphrase, (err) ->
-							console.log(err) if err
-							return startServer(wifi) if err
-							console.log("Joined! Exiting.")
-							process.exit()
-		app.use (req, res) ->
-			res.redirect('/')
-
-		# Create TETHER iptables chain (will silently fail if it already exists)
-		iptables.createChain 'nat', 'TETHER', ->
-			# Ensure no rules exist from an unclean shutdown
-			iptables.delete { table: 'nat', rule: "PREROUTING -i tether -j TETHER"}, ->
-				iptables.flush 'nat', 'TETHER', ->
-					if !properties.connected
-						console.log("Trying to join wifi")
-						wifi.joinFavorite (err) ->
-							if err
-								startServer(wifi)
-					else
-						console.log("Already connected")
-						process.exit()
-
-
+						if !properties.connected
+							console.log("Trying to join wifi")
+							wifi.joinFavorite (err) ->
+								if err
+									startServer(wifi)
+						else
+							console.log("Already connected")
+							retryCallback()
+
+async.retry {times: 10, interval: 1000}, manageConnection, (err) ->
+	throw err if err?
+	process.exit()


chore(getFile) reuseable know (AWS) client, no need to recreate again

--- src/aws.coffee
+++ src/aws.coffee
@@ -1,13 +1,14 @@
 knox = require 'knox'

+clients = {}

 getFile = (bucket, fileName, cb) ->
-  client = knox.createClient
+  clients[bucket] ?= knox.createClient
     key:    process.env.ACCESS_KEY
     secret: process.env.SECRET_KEY
     bucket: bucket

-  client.getFile "/#{fileName}", cb
+  clients[bucket].getFile "/#{fileName}", cb

 module.exports = {
   getFile


Missing argument

Missing argument

--- src/context/context.coffee
+++ src/context/context.coffee
@@ -5,7 +5,7 @@

     @messages = []

-  _error: (message, info, innerErrors) ->
+  _error: (message, info = {}, innerErrors = []) ->
     new SchemaError(
       message,
       @,
@@ -14,7 +14,7 @@
     )

   msg: (level, message, info, innerErrors) ->
-    error = @_error(message, info)
+    error = @_error(message, info, innerErrors)
     @messages.push({
       level: level
       error: error


Add Analytics

Add Analytics

sigh

--- app/index.coffee
+++ app/index.coffee
@@ -70,6 +70,10 @@
 topBar = new TopBar
 topBar.el.appendTo 'body'

+new Analytics
+  account: 'UA-1224199-43'
+  domain: 'spacewarps.org'
+
 User.fetch()
 Route.setup()


adding add, remove events to Luca.Collection cachedMethods expiration events

--- src/core/collection.coffee
+++ src/core/collection.coffee
@@ -31,7 +31,7 @@

   # cachedMethods expects an array of strings representing the method name
   # or objects containing @method and @resetEvents properties.  by default
-  # @resetEvents are 'reset' and 'change'.
+  # @resetEvents are 'add','remove',reset' and 'change'.
   cachedMethods: []

   restoreMethodCache: ()->
@@ -47,7 +47,7 @@

   setupMethodCaching: ()->
     collection = @
-    resetEvents = ["reset","change"]
+    resetEvents = ["reset","change","add","remove"]

     cache = @_methodCache = {}


Adapt pin view controler with the new error parameter

--- app/src/controllers/onboarding/device/onboarding_device_pin_view_controller.coffee
+++ app/src/controllers/onboarding/device/onboarding_device_pin_view_controller.coffee
@@ -9,7 +9,8 @@
     @view.pinCode.insertIn(@select('div#pin_container')[0])
     @view.pinCode.setStealsFocus(yes)
     @view.pinCode.once 'complete', (event, value) =>
-      ledger.app.wallet.unlockWithPinCode value, (success, retryCount) =>
+      ledger.app.wallet.unlockWithPinCode value, (success, error) =>
+        {retryCount} = error
         if success == yes
           ledger.app.router.go '/onboarding/device/opening'
         else if retryCount > 0


just exclude webstorage

just exclude webstorage

--- coffee/zeno-controllers.coffee
+++ coffee/zeno-controllers.coffee
@@ -130,11 +130,12 @@
       return

     # do not keep success image
-    # do not keep offset results because there is no thumb (too large)
-    if data.percentage != '0.00' and !data.offsets[0] and !data.offsets[1]
+    if data.percentage != '0.00'
       updatedRow.src = data.src
       # try to add the image in the browser local storage
-      ResultsFactory.setStorageImage(updatedRow.name, data.src)
+      # do not keep offset results because there is no thumb (too large)
+      if !data.offsets[0] and !data.offsets[1]
+        ResultsFactory.setStorageImage(updatedRow.name, data.src)
     else if updatedRow.src || $scope.hasStoredImage(updatedRow)
       # clean error data
       ResultsFactory.removeStorageImage(updatedRow.name)


artik533s.coffee: Set board as experimental

This reverts commit 22b374077e9b90ffb7fd7a64c4ae3fcbfd2b7236

Signed-off-by: Vicentiu Galanopulo <316f1858a504e73da779fe12f7a460349852883d@balena.io>

--- artik533s.coffee
+++ artik533s.coffee
@@ -19,7 +19,7 @@
 	aliases: [ 'artik533s' ]
 	name: 'Samsung Artik 530s 1G'
 	arch: 'armv7hf'
-	state: 'discontinued'
+	state: 'experimental'

 	stateInstructions:
 		postProvisioning: postProvisioningInstructions


default-apps: Changed Open With menu items for selected file types.

--- client/landing/app/MainApp/filetree/controllers/findercontextmenucontroller.coffee
+++ client/landing/app/MainApp/filetree/controllers/findercontextmenucontroller.coffee
@@ -51,18 +51,7 @@
         action                    : 'openFile'
       'Open with...'              :
         separator                 : yes
-        children                  :
-          'Ace Editor'            :
-            action                : 'openFile'
-          'CodeMirror'            :
-            action                : 'openFileWithCodeMirror'
-          'Viewer'                :
-            separator             : yes
-            action                : 'previewFile'
-          'Search the App Store'  :
-            disabled              : yes
-          'Contribute an Editor'  :
-            disabled              : yes
+        children                  : @getOpenWithMenuItems fileView
       Delete                      :
         action                    : 'delete'
         separator                 : yes
@@ -347,20 +336,6 @@
     items =
       'Open Files'                :
         action                    : 'openFile'
-      'Open with...'              :
-        separator                 : yes
-        children                  :
-          'Ace Editor'            :
-            action                : 'openFile'
-          'CodeMirror'            :
-            action                : 'openFileWithCodeMirror'
-          'Viewer'                :
-            separator             : yes
-            action                : 'previewFile'
-          'Search the App Store'  :
-            disabled              : yes
-          'Contribute an Editor'  :
-            disabled              : yes
       'Delete all'                :
         action                    : 'delete'
         separator                 : yes
@@ -382,6 +357,21 @@

     return items

+  getOpenWithMenuItems: (fileView) ->
+    # TODO: acet, test for non existing file extension
+    items            = {}
+    fileExtension    = FSItem.getFileExtension fileView.getData().path
+    appsController   = @getSingleton "kodingAppsController"
+    {extensionToApp} = appsController
+    possibleApps     = extensionToApp[fileExtension] or extensionToApp.txt
+    for appName in possibleApps
+      items[appName] = action: "openFile"
+
+    items["separator"]            = type     : "separator"
+    items["Search the App Store"] = disabled : yes
+    items["Contribute an Editor"] = disabled : yes
+
+    return items

 # this is shorter but needs coffee script update


Moved variable to where it's used

Moved variable to where it's used

--- src/cli.coffee
+++ src/cli.coffee
@@ -7,7 +7,6 @@
 pkg = require '../package.json'
 fs = require 'fs'

-cmd = argv._.shift() || 'help'
 if argv.env then config.env argv.env

 cli =
@@ -111,5 +110,6 @@
     console.log 'Enter your Versal credentials to sign in:'
     prompt.get promptParams, callback

+cmd = argv._.shift() || 'help'
 if typeof cli[cmd] == 'function'
   cli[cmd](argv)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_selector.coffee
+++ src/engine_selector.coffee
@@ -59,7 +59,7 @@
   @param {String} selector
   @returns {Array} An array of the objects found
   ###
-  each: (selector, )
+  each: (selector, fn)

   find: (selector) ->
     results = []


Get basic parse/format working

Get basic parse/format working

--- tapestry-core/src/main/coffeescript/META-INF/modules/core/datefield.coffee
+++ tapestry-core/src/main/coffeescript/META-INF/modules/core/datefield.coffee
@@ -15,8 +15,9 @@
 # ##core/datefield
 #
 # Provides support for the `core/DateField` component.
-define ["core/dom", "core/events", "core/messages", "core/builder", "_"],
-  (dom, events, messages, builder, _) ->
+define ["core/dom", "core/events", "core/messages", "core/builder", "core/ajax",
+  "core/alert", "_"],
+  (dom, events, messages, builder, ajax, alert, _) ->

     # Translate from the provided order (SUNDAY = 0, MONDAY = 1), to
     # the order needed by the DatePicker component (MONDAY = 0 ... SUNDAY = 6)
@@ -42,12 +43,43 @@

         unless @popup
           @createPopup()
+        else if @popup.visible()
+          @popup.hide()
           return

-        if @popup.visible()
-          @popup.hide()
-        else
+        value = @field.value()
+
+        if value is ""
+          @datePicker.setDate null
           @popup.show()
+          return
+
+        @field.addClass "ajax-wait"
+
+        ajax (@container.attribute "data-parse-url"),
+          parameters:
+            input: value
+          onerror: =>
+            @field.removeClass "ajax-wait"
+            @field.focus()
+
+          onsuccess: (response) =>
+            @field.removeClass "ajax-wait"
+            reply = response.responseJSON
+
+            if reply.result
+              date = new Date()
+              date.setTime reply.result
+              @datePicker.setDate date
+              @popup.show()
+              return
+
+            @field.focus()
+
+            @fieldError reply.error
+
+      fieldError: (message) ->
+        alert { message }

       createPopup: ->
         @datePicker = new DatePicker()
@@ -55,10 +87,31 @@
         @popup.append dom @datePicker.create()
         @trigger.insertAfter @popup

-      # @popup.absolutize().hide()
+        @datePicker.onselect = _.bind @onSelect, this

-      positionPopup: ->
-        reference = @container.findFirst "input[type=text], button"
+      onSelect: ->
+        @field.addClass "t-ajax-wait"
+
+        date = @datePicker.getDate()
+
+        if date is null
+          @popup.hide()
+          @field.value ""
+          return
+
+        ajax (@container.attribute "data-format-url"),
+          parameters:
+            input: date.getTime()
+          onerror: (message) =>
+            @field.removeClass "t-ajax-wait"
+            @fieldError message
+            @popup.hide()
+          onsuccess: (response) =>
+            @field.removeClass "t-ajax-wait"
+            @field.value response.responseJSON.result
+            @popup.hide()
+
+

     scan = (root) ->
       for container in root.find "[data-component-type=core/DateField]"


Support unprefixed MultiFilePatch commands until they're editable

--- keymaps/git.cson
+++ keymaps/git.cson
@@ -76,6 +76,13 @@
   'ctrl-right': 'github:surface'

 '.github-FilePatchView atom-text-editor:not([mini])':
+  # Only support unprefixed file patch keybindings until MultiFilePatch is
+  # editable
+  '/': 'github:toggle-patch-selection-mode'
+  'backspace': 'github:discard-selected-lines'
+  'enter': 'core:confirm'
+  'right': 'github:surface'
+  'o': 'github:jump-to-file'
 '.platform-darwin .github-FilePatchView atom-text-editor:not([mini])':
   'cmd-/': 'github:toggle-patch-selection-mode'
   'cmd-backspace': 'github:discard-selected-lines'


Update infinite-scroll.coffee

Update infinite-scroll.coffee

Fix issue with containing element calculation

--- src/infinite-scroll.coffee
+++ src/infinite-scroll.coffee
@@ -24,7 +24,7 @@
     height = (elem) ->
       elem = elem[0] or elem

-      if isNaN(elem.offsetHeight) then height(elem.document.documentElement) else elem.offsetHeight
+      if isNaN(elem.offsetHeight) then elem.document.documentElement.clientHeight else elem.offsetHeight

     offsetTop = (elem) ->
       if not elem[0].getBoundingClientRect or elem.css('none')


Misc module section now using callouts and icons

--- src/javascript/main.coffee
+++ src/javascript/main.coffee
@@ -150,6 +150,21 @@
     icon: 'images/duel.png'
   overheat:
     icon: 'images/overheat.png'
+
+  cyno:
+    iconId: 21096
+  cloak:
+    iconId: 11370
+  gangLink:
+    iconId: 20070
+  damp:
+    iconId: 1968
+  ecm:
+    iconId: 1957
+  painter:
+    iconId: 12709
+  nos:
+    iconId: 12261

   high:
     label: 'High Sec'
@@ -433,7 +448,9 @@

       pveStats = React.createElement(PvePanel, {stats: @state.stats})

-      miscModules = React.createElement(MiscModulePanel, {stats: @state.stats})
+      miscModules1 = React.createElement(MiscModuleOnePanel, {stats: @state.stats})
+      miscModules2 = React.createElement(MiscModuleTwoPanel, {stats: @state.stats})
+      miscModules3 = React.createElement(MiscModuleThreePanel, {stats: @state.stats})

       industryJobs = React.createElement(IndustryJobsPanel, {stats: @state.stats})
       blueprints = React.createElement(IndustryBlueprintPanel, {stats: @state.stats})
@@ -499,8 +516,12 @@
         # PVE Stats

         dom.div {className: 'row'},
+          dom.div {className: 'col-md-4'}, miscModules1
+          dom.div {className: 'col-md-4'}, miscModules3
+          dom.div {className: 'col-md-4'}, miscModules2
+
+        dom.div {className: 'row'}
           dom.div {className: 'col-md-6'}, pveStats
-          dom.div {className: 'col-md-6'}, miscModules

         # ISK / Markets
         dom.div {className: 'row'},
@@ -509,12 +530,12 @@

         # Industry
         dom.div {className: 'row'},
+          dom.div {className: 'col-md-6'}, miningPanel
           dom.div {className: 'col-md-6'}, industryJobs
-          dom.div {className: 'col-md-6'}, blueprints

         # Mining
         dom.div {className: 'row'},
-          dom.div {className: 'col-md-6'}, miningPanel
+          dom.div {className: 'col-md-6'}, blueprints

         # Social
@@ -1091,19 +1112,70 @@
         dom.li null, "Webbed #{numFmt @props.stats.combatWebifiedbyNPC} times by NPCs"
 )

-MiscModulePanel = React.createClass(
-  displayName: 'MiscModulePanel'
-  render: ->
-    dom.div {className: ''},
-      dom.h3 null, 'Modules'
-      dom.ul null,
-        dom.li null, "Lit #{numFmt @props.stats.moduleActivationsCyno} cynos"
-        dom.li null, "Cloaked #{numFmt @props.stats.moduleActivationsCloaking} times"
-        dom.li null, "Activated #{numFmt @props.stats.moduleActivationsFleetAssist} links"
-        dom.li null, "#{numFmt @props.stats.moduleActivationsEwarDampener} sensor damp activations"
-        dom.li null, "Violated SPACE BUSHIDO #{numFmt @props.stats.moduleActivationsEwarECM} times (ECM Activations)"
-        dom.li null, "#{numFmt @props.stats.moduleActivationsEwarTargetPainter} TP activations"
-        dom.li null, "#{numFmt @props.stats.moduleActivationsEwarVampire} NOS activations"
+MiscModuleOnePanel = React.createClass(
+  displayName: 'MiscModulePanelOne'
+  render: ->
+    if @props.stats
+      callouts = [
+        {
+          value: @props.stats.moduleActivationsCloaking
+          description: 'Activated Cloak'
+          iconId: styleIconId 'cloak'
+        }
+        {
+          value: @props.stats.moduleActivationsCyno
+          description: 'Cynos Lit'
+          iconId: styleIconId 'cyno'
+        }
+      ]
+      return React.createElement(CalloutPanel, {callouts: callouts})
+    else
+      return null
+)
+MiscModuleTwoPanel = React.createClass(
+  displayName: 'MiscModulePanelTwo'
+  render: ->
+    if @props.stats
+      callouts = [
+        {
+          value: @props.stats.moduleActivationsFleetAssist
+          description: 'Activated Gang Link'
+          iconId: styleIconId 'gangLink'
+        }
+        {
+          value: @props.stats.moduleActivationsEwarVampire
+          description: 'Activated NOS'
+          iconId: styleIconId 'nos'
+        }
+      ]
+      return React.createElement(CalloutPanel, {callouts: callouts})
+    else
+      return null
+)
+MiscModuleThreePanel = React.createClass(
+  displayName: 'MiscModulePanelThree'
+  render: ->
+    if @props.stats
+      callouts = [
+        {
+          value: @props.stats.moduleActivationsEwarECM
+          description: 'Violated Space Bushido'
+          iconId: styleIconId 'ecm'
+        }
+        {
+          value: @props.stats.moduleActivationsEwarDampener
+          description: 'Activated Sensor Damp'
+          iconId: styleIconId 'damp'
+        }
+        {
+          value: @props.stats.moduleActivationsEwarTargetPainter
+          description: 'Activated Target Painter'
+          iconId: styleIconId 'painter'
+        }
+      ]
+      return React.createElement(CalloutPanel, {callouts: callouts})
+    else
+      return null
 )

 IndustryJobsPanel = React.createClass(


Adds a new element directive method for checking the presence of ingredient

--- app/assets/javascripts/alchemy-angular/directives/alchemy_element.js.coffee
+++ app/assets/javascripts/alchemy-angular/directives/alchemy_element.js.coffee
@@ -6,16 +6,27 @@
     }
     replace: true
     link: (scope, element, attrs) ->
+
+      # Every element has its very own template.
+      # The elements are placed at your angular template path
+      # with 'alchemy/elements' prefix
       scope.elementTemplate = "alchemy/elements/#{scope.element.name}.html"

+      # The ingredients of current element
       scope.ingredients = scope.element.ingredients

+      # Returns all ingredients with given haven
       scope.ingredients_with_name = (name) ->
         _.where(scope.ingredients, {name: name})

+      # Returns the ingredient value of given name
       scope.ingredient = (name) ->
         ingredient = _.findWhere(scope.ingredients, {name: name})
         ingredient.value if ingredient
+
+      # Checks if the ingredient with given name is not null or empty
+      scope.ingredient_present = (name) ->
+        scope.ingredient(name) && scope.ingredient(name) != ''

       return
     template: '

'


Fixed javascript tests of Discovery

Fixed javascript tests of Discovery

--- app/modules/discover/discover-search/discover-search.controller.spec.coffee
+++ app/modules/discover/discover-search/discover-search.controller.spec.coffee
@@ -28,6 +28,22 @@

         $provide.value "$translate", mocks.translate

+    _mockTgLocation = () ->
+        mocks.mockTgLocation = {
+            url: sinon.stub()
+            search: sinon.stub()
+        }
+
+        $provide.value "$tgLocation", mocks.mockTgLocation
+
+    _mockTgAnalytics = () ->
+        mocks.tgAnalytics = {
+            trackEvent: sinon.stub(),
+            trackPage: sinon.stub()
+        }
+
+        $provide.value "$tgAnalytics", mocks.tgAnalytics
+
     _mockAppMetaService = () ->
         mocks.appMetaService = {
             setAll: sinon.spy()
@@ -63,6 +79,8 @@
             _mockAppMetaService()
             _mockRoute()
             _mockRouteParams()
+            _mockTgLocation()
+            _mockTgAnalytics()
             _mockDiscoverProjects()

             return null


v2.0.0 add motion check

v2.0.0 add motion check

--- src/hue.coffee
+++ src/hue.coffee
@@ -185,6 +185,21 @@
       debug 'got state', state
       callback null, button: BUTTON_EVENTS[state.buttonevent], state: state

+  checkMotion: (callback=->) =>
+    debug 'checking motion'
+    @checkSensors (error, body) =>
+      return callback error if error?
+      motionSensors = _.filter body, { modelid: 'SML001'}
+      presence = _.filter motionSensors, { type: 'ZLLPresence' }
+      light = _.filter motionSensors, { type: 'ZLLLightLevel' }
+      temp = _.filter motionSensors, { type: 'ZLLTemperature' }
+      response = {
+        presence: @_filterSensorArray presence
+        light_level: @_filterSensorArray light
+        temperature: @_filterSensorArray temp
+      }
+      callback null, response
+
   checkSensors: (callback=->) =>
     @verify (error) =>
       return callback error if error?
@@ -195,4 +210,10 @@
       debug 'retrieving sensors', requestOptions
       request requestOptions, @handleResponse(callback)

+  _filterSensorArray: (sensors) =>
+    filtered = {}
+    _.forEach sensors, (sensor) =>
+      filtered[sensor.name] = sensor.state
+    return filtered
+
 module.exports = Hue


Remove console.log

Remove console.log

--- src/index.cjsx
+++ src/index.cjsx
@@ -43,7 +43,7 @@

     bar.append("rect")
         .attr("y", (d) -> return y(d))
-        .attr("height", (d) => console.log(d, y(d)); return @props.height - y(d))
+        .attr("height", (d) => return @props.height - y(d))
         .attr("width", barWidth - 1)
         .attr("fill", @props.fillColor)


fixed domain name parsing

fixed domain name parsing

--- client/landing/app/Applications/Environments.kdapplication/views/domains/domaincreationform.coffee
+++ client/landing/app/Applications/Environments.kdapplication/views/domains/domaincreationform.coffee
@@ -1,3 +1,10 @@
+splitDomain = (domainName) ->
+  splitted =  domainName.split "."
+  return {
+    first: splitted[0],
+    extension: if splitted.length > 1 then splitted[1..].join "." else ""
+  }
+
 class DomainCreationForm extends KDTabViewWithForms

   domainOptions = [
@@ -153,9 +160,9 @@
     form = @forms["Domain Address"]
     domainInput       = domainName
     domainName        = form.inputs.domainName.getValue()
-    splittedDomain    = domainName.match(/([\w\-]+)\.(.*)/)
-    domain            = splittedDomain[1]
-    tld               = splittedDomain[2]
+    splittedDomain    = splitDomain(domainName)
+    domain            = splittedDomain.first
+    tld               = splittedDomain.extension
     {createButton, checkButton, registerButton} = form.buttons
     @clearSuggestions()
     KD.remote.api.JDomain.getTldPrice tld, (tldPrice) =>
@@ -196,9 +203,9 @@
     domainOptionValue = DomainOption.getValue()

     if domainOptionValue is 'new'
-      splittedDomain    = domainName.match(/([\w\-]+)\.(.*)/)
-      domain            = splittedDomain[1]
-      tld               = splittedDomain[2]
+      splittedDomain    = splitDomain(domainName)
+      domain            = splittedDomain.first
+      tld               = splittedDomain.extension
       form = @forms["Domain Address"]
       {createButton, registerButton} = form.buttons
       paymentController = KD.getSingleton('paymentController')


Keep container positions in appStorage and load them again for next reload

--- client/landing/app/Applications/Environments.kdapplication/views/scene/environmentcontainer.coffee
+++ client/landing/app/Applications/Environments.kdapplication/views/scene/environmentcontainer.coffee
@@ -7,12 +7,16 @@

     super options, data

+    sc = KD.getSingleton 'appStorageController'
+    @appStorage = sc.storage 'EnvironmentsScene', '1.0'
+
     title   = @getOption 'title'
     @header = new KDHeaderView {type : "medium", title}

     @itemHeight = options.itemHeight ? 40

     @on "DataLoaded", => @_dataLoaded = yes
+    @on "DragFinished", @bound 'savePosition'

     @newItemPlus = new KDCustomHTMLView
       cssClass   : 'new-item-plus'
@@ -22,15 +26,18 @@
     super
     @addSubView @header
     @header.addSubView @newItemPlus
+    @appStorage.ready @bound 'loadPosition'
     @loadItems()

   addDia:(diaObj, pos)->
     pos = x: 20, y: 60 + @diaCount() * (@itemHeight + 10)
     super diaObj, pos
+
+    diaObj.on "KDObjectWillBeDestroyed", @bound 'updatePositions'
     @updateHeight()
-    diaObj.on "KDObjectWillBeDestroyed", @bound 'updatePositions'

   updatePositions:->
+
     index = 0
     for _, dia of @dias
       dia.setX 20
@@ -41,7 +48,23 @@
   diaCount:-> Object.keys(@dias).length

   updateHeight:->
+
     @setHeight 80 + @diaCount() * 50
     @emit 'UpdateScene'

-  loadItems:-> yes+  savePosition:->
+
+    name      = @constructor.name
+    bounds    = x: @getRelativeX(), y: @getRelativeY()
+    positions = (@appStorage.getValue 'containerPositions') or {}
+    positions[name] = bounds
+    @appStorage.setValue 'containerPositions', positions
+
+  loadPosition:->
+
+    name     = @constructor.name
+    position = ((@appStorage.getValue 'containerPositions') or {})[name]
+    return  unless position
+    @setX position.x; @setY position.y
+
+  loadItems:-> yes


Add Nuclide configs

Add Nuclide configs

--- atom/config.cson
+++ atom/config.cson
@@ -5,10 +5,61 @@
   "autocomplete-python":
     useKite: false
   core:
+    customFileTypes:
+      "source.ini": [
+        ".hgrc"
+        ".buckconfig"
+        ".flowconfig"
+      ]
+      "source.json": [
+        ".arcconfig"
+        ".jfconfig"
+        ".watchmanconfig"
+        "BUCK.autodeps"
+      ]
+      "source.python": [
+        "BUILD_DEFS"
+        "TARGETS"
+        "BUCK_WIN"
+        "bzl"
+        "cconf"
+        "cinc"
+        "ctest"
+        "ctw"
+        "mcconf"
+        "tw"
+        "thrift-cvalidator"
+        "BUCK"
+      ]
+      "source.reason": [
+        ".re"
+      ]
+      "source.yaml": [
+        "yarn.lock"
+      ]
     disabledPackages: [
       "markdown-preview"
+      "metrics"
+      "encoding-selector"
+      "line-ending-selector"
+      "fuzzy-finder"
+      "linter"
+      "github"
+      "tree-view"
+      "image-view"
+      "git-diff"
     ]
-    telemetryConsent: "limited"
+    ignoredNames: [
+      ".git"
+      ".hg"
+      ".svn"
+      ".DS_Store"
+      "._*"
+      "Thumbs.db"
+      "desktop.ini"
+      "**/xplat/**/.*.metadata"
+    ]
+    telemetryConsent: "no"
     themes: [
       "one-dark-ui"
       "monokai"
@@ -20,7 +71,659 @@
     showIndentGuide: true
   "exception-reporting":
     userId: "b3bd855a-38b4-44af-961e-0c6cfa5383f2"
+  notifications:
+    showErrorsInDevMode: true
+  nuclide:
+    "atom-ide-code-format":
+      formatOnSave: false
+      formatOnType: true
+    "atom-ide-console":
+      diffUrlPattern: "https://phabricator.intern.facebook.com/%s"
+      fontScale: 0.9
+      maximumMessageCount: 10000
+      maximumSerializedHistory: 20
+      maximumSerializedMessages: 10
+      taskUrlPattern: "https://our.intern.facebook.com/intern/tasks?t=%s"
+    "atom-ide-datatip":
+      datatipDebounceDelay: 200
+      datatipInteractedWithDebounceDelay: 1000
+      onlyTopDatatip: false
+    "atom-ide-debugger":
+      showDebuggerOnBpSet: true
+    "atom-ide-diagnostics-ui":
+      autoVisibility: false
+      showDiagnosticTraces: false
+      showDirectoryColumn: false
+      statusBarPosition: "left"
+    "atom-ide-find-references":
+      defaultLocationForPane: "bottom"
+    "atom-ide-outline-view":
+      nameOnly: false
+    "atom-ide-signature-help":
+      enable: true
+    "atom-ide-terminal":
+      allowTransparency: false
+      black: "#2e3436"
+      blue: "#3465a4"
+      brightBlack: "#555753"
+      brightBlue: "#729fcf"
+      brightCyan: "#34e2e2"
+      brightGreen: "#8ae234"
+      brightMagenta: "#ad7fa8"
+      brightRed: "#ef2929"
+      brightWhite: "#eeeeec"
+      brightYellow: "#fce94f"
+      charAtlas: "dynamic"
+      cursorBlink: false
+      cursorStyle: "block"
+      cyan: "#06989a"
+      documentationMessage: true
+      fontFamily: "courier-new, courier, monospace"
+      fontScale: 1
+      green: "#4e9a06"
+      lineHeight: 1.5
+      magenta: "#75507b"
+      optionIsMeta: false
+      preservedCommands: [
+        "command-palette:toggle"
+        "fb-interactive-smartlog:toggle"
+        "nuclide-quick-open:find-anything"
+        "atom-ide-terminal:add-escape-prefix"
+        "atom-ide-terminal:new-terminal"
+        "atom-ide-terminal:toggle-terminal-focus"
+        "pane:move-active-item-to-top-of-stack"
+        "pane:show-next-recently-used-item"
+        "window:focus-next-pane"
+        "window:focus-previous-pane"
+        "window:focus-pane-above"
+        "window:focus-pane-below"
+        "window:focus-pane-on-left"
+        "window:focus-pane-on-right"
+      ]
+      red: "#cc0000"
+      rendererType: "auto"
+      scrollback: 1000
+      white: "#d3d7cf"
+      yellow: "#c4a000"
+    "fb-ai-code-search":
+      usePrefixOnly: true
+    "fb-ai-complete-blocks":
+      enableDevelopmentMode: false
+    "fb-android-native-debugger":
+      "devserver-android-tunnel": true
+    "fb-arc-lint":
+      blacklistedLinters: [
+        "FBHACK"
+        "FLAKE8"
+        "FLOW"
+        "HACK"
+        "HACKSYNTAX"
+        "PEP8"
+      ]
+      lintTimeout: 60000
+    "fb-atomprojects":
+      localPaths: []
+      remotePaths: []
+    "fb-aurora-language-server":
+      logLevel: "INFO"
+    "fb-biggrep":
+      filterToProject: true
+    "fb-codex-pages":
+      priority: 30
+    "fb-component-search":
+      resultCountLimit: -1
+      shouldDisplayFullJSX: false
+    "fb-componentscript":
+      warnGraphQLChanged: false
+    "fb-cquery":
+      "enable-libclang-logs": false
+      "indexer-threads": 0
+      "memory-limit": 30
+      "use-cquery": false
+    "fb-debugger-mobilejs":
+      autoAttachComponentScript: "None"
+      autoAttachReactNative: "None"
+      logInspectorProxyMessages: false
+      showConsoleMessages: false
+    "fb-eslint-client":
+      "disable-arc-lint-results": true
+      logLevel: "INFO"
+    "fb-generated-file-support":
+      allowEdits: false
+    "fb-go":
+      goLanguageFeaturesProvider: "Default"
+    "fb-graphql-metrics":
+      priority: 50
+    "fb-intellij":
+      intelliJKeybindings: false
+    "fb-interactive-smartlog":
+      autorunPostResolveScripts: false
+      conflictResolverEnabled: true
+      externalMergeToolArguments: ""
+      externalMergeToolEnabled: false
+      externalMergeToolPath: ""
+      fetchCommitTemplateOption: "File"
+      fetchOption: "arc patch"
+      pullOption: "arc pull"
+      showCommitInfoViewInline: false
+      showTools: true
+    "fb-java":
+      autoBuild: false
+      autoFold: true
+      coverageType: "Symbols"
+      eclipseLogLevel: "ERROR"
+      languageServer: "Java Language Server"
+      logLevel: "Finer"
+      problemsToIgnore: ""
+      showCompleteDiagnostics: true
+    "fb-jellyfish":
+      pathToJellyfish: "jf"
+    "fb-miso":
+      authType: "token"
+      gateway: "http://localhost:8888"
+    "fb-new-file-template":
+      oncall_name: "set_oncall_in_nuclide_settings @nocommit"
+    "fb-notes":
+      "fb-notes": {}
+    "fb-on-demand":
+      autoSetCwd: true
+      "close-behavior": "ask"
+      "duo-push-immediately": false
+      "mobile-android-tunnel": true
+      "mobile-fbandroid-target": "fb4a-noexo"
+      "mobile-fbobjc-target": "fbios"
+      "mobile-subdirectory-notification": true
+      "mobile-xplat-metro": true
+    "fb-oneworld":
+      apertureAppExecPath: ""
+      apertureAppUri: "https://our.intern.facebook.com/intern/aperture/app"
+    "fb-osmeta-core":
+      hideInternalTargets: true
+    "fb-package-manager":
+      "fuzzy-finder": false
+      github: false
+      linter: false
+      metrics: false
+      overriddenThirdPartySettings: []
+      showChangelogs: true
+    "fb-phabricator-comments-client":
+      autoRefreshMinutes: 3
+      commentOpener: "Editor"
+      showComments: true
+      showCommentsInDiffView: true
+      showCommentsInEditors: true
+      showOnlyMostRecentDiff: true
+      showResolvedComments: false
+    "fb-populate-symbols":
+      populateSymbolsView: true
+    "fb-prettier":
+      formatAlreadyFormattedFilesOnSave: true
+    "fb-rating":
+      rating: 0
+    "fb-similar-code-detector":
+      debug: false
+    "fb-skip":
+      includeTypeErrors: true
+      logLevel: "INFO"
+      pathToSkip: ""
+      remotePathToSkip: "~/www/scripts/skip"
+      useLSP: true
+    "fb-symbol-wiki":
+      priority: 10
+    "fb-terminal-dash-provider":
+      defaultTerminalPane: "bottom"
+    hyperclick:
+      darwinTriggerKeys: "metaKey"
+      linuxTriggerKeys: "ctrlKey"
+      win32TriggerKeys: "ctrlKey"
+    installRecommendedPackages: true
+    "nuclide-adb-logcat":
+      pathToAdb: "adb"
+      whitelistedTags: "^((unknown:|)React|ReactNativeJS|ACRA|AndroidRuntime|TTI|BuckReporting|unknown)$"
+    "nuclide-bookshelf":
+      changeActiveBookmarkBehavior: "Prompt to Restore"
+    "nuclide-buck":
+      buildDbErrorNotify: true
+      compileErrorDiagnostics: true
+      pathToBuck: "buck"
+    "nuclide-clang":
+      defaultDiagnostics: false
+      defaultFlags: [
+        "-std=c++14"
+        "-x"
+        "c++"
+      ]
+      enableDefaultFlags: true
+      libclangPath: ""
+      serverProcessMemoryLimit: 15
+    "nuclide-code-search":
+      localTool: ""
+      localUseVcsSearch: true
+      maxResults: 30
+      remoteTool: ""
+      remoteUseVcsSearch: true
+    "nuclide-css-lsp-client":
+      logLevel: "INFO"
+    "nuclide-ctags":
+      disableWithHack: true
+    "nuclide-debugger-java":
+      sourceFilePaths: ""
+    "nuclide-debugger-php":
+      hhvmRuntimeArgs: ""
+      hhvmRuntimePath: "/usr/local/bin/hhvm"
+      hhvmServerAttachPort: 8999
+    "nuclide-definition-preview":
+      editorHeight: 50
+      priority: 20
+    "nuclide-distraction-free-mode":
+      hideFindAndReplace: false
+      hideStatusBar: false
+      hideToolBar: false
+    "nuclide-file-tree":
+      allowKeyboardPrefixNavigation: true
+      autoExpandSingleChild: true
+      focusEditorOnFileSelection: false
+      hideIgnoredNames: true
+      hideVcsIgnoredPaths: true
+      revealFileOnSwitch: false
+      showOpenFiles: true
+      showUncommittedChanges: true
+      showUncommittedChangesKind: "Uncommitted changes"
+    "nuclide-flow":
+      canUseFlowBin: false
+      excludeOtherAutocomplete: false
+      flowAutocompleteResultsFirst: true
+      functionSnippetShouldIncludeArguments: true
+      liveSyntaxErrors: true
+      logLevel: "DEBUG"
+      pathToFlow: "flow"
+      stopFlowOnExit: true
+      warnOnNotInstalled: false
+    "nuclide-fuzzy-filename-provider":
+      smartCase: false
+    "nuclide-hack":
+      hhClientPath: ""
+      legacyHackIde: false
+      logLevel: "DEBUG"
+    "nuclide-health":
+      analyticsTimeout: 20
+      viewTimeout: 20
+    "nuclide-hg-repository":
+      enableDiffStats: true
+    "nuclide-home":
+      showHome: true
+    "nuclide-infer-al":
+      pathToInfer: "infer"
+    "nuclide-ios-simulator-logs":
+      pathToSyslog: "syslog"
+      senderBlacklist: [
+        "assertiond"
+        "routined"
+        "syslogd"
+        "SpringBoard"
+        "installd"
+        "pkd"
+        "lsd"
+        "searchd"
+        "itunesstored"
+        "backboardd"
+      ]
+      whitelistedTags: "^(core\\.react|tid:com\\.facebook\\.react\\.JavaScript|com.apple.console)$"
+    "nuclide-js-imports-client":
+      componentModulePathFilter: "html/js"
+      diagnosticsWhitelist: [
+        "/nuclide"
+        "/www"
+        "/instance-ide"
+        "/xplat/js"
+        "/oculus-skyline"
+        "/Software/Apps/skyline"
+        "/www-hg"
+        "/trunk-hg-www"
+      ]
+      logLevel: "INFO"
+      requiresWhitelist: [
+        "/www"
+        "/instance-ide"
+        "/xplat/js"
+        "/www-hg"
+        "/trunk-hg-www"
+      ]
+    "nuclide-notifications":
+      onlyNativeFriendly: true
+      whenFocused: false
+    "nuclide-objc":
+      enableAutomaticSquareBracketInsertion: true
+    "nuclide-ocaml":
+      codeLens: true
+      codeLensCopy: true
+      logLevel: "DEBUG"
+      pathToMerlin: "ocamlmerlin"
+      pathToOcpIndent: ""
+      pathToRefmt: "refmt"
+      refmtFlags: ""
+    "nuclide-python":
+      autocompleteArguments: true
+      enableLinting: true
+      includeOptionalArguments: false
+      lintExtensionBlacklist: [
+        ".bzl"
+        ".tw"
+        ""
+      ]
+      pathToFlake8: "flake8"
+      pathToPython: "python"
+      showGlobalVariables: true
+      showSignatureHelp: false
+    "nuclide-quick-open":
+      useSelection: true
+    "nuclide-remote-atom":
+      enableLocalCommandService: false
+      shouldNotifyWhenCommandLineIsWaitingOnFile: false
+    "nuclide-remote-projects":
+      connectionProfiles: [
+        {
+          deletable: true
+          displayTitle: "www"
+          params:
+            authMethod: "PASSWORD"
+            cwd: "/home/cmcginty/www"
+            displayTitle: "www"
+            pathToPrivateKey: "/Users/cmcginty/.ssh/fb_id_rsa"
+            remoteServerCommand: ""
+            server: "our.cmcginty.sb.facebook.com"
+            sshPort: "22"
+            username: "cmcginty"
+          saveable: true
+        }
+        {
+          deletable: true
+          displayTitle: "fbsource"
+          params:
+            authMethod: "PASSWORD"
+            cwd: "/home/cmcginty/fbsource"
+            displayTitle: "fbsource"
+            pathToPrivateKey: "/Users/cmcginty/.ssh/fb_id_rsa"
+            remoteServerCommand: ""
+            server: "our.cmcginty.sb.facebook.com"
+            sshPort: "22"
+            username: "cmcginty"
+          saveable: true
+        }
+      ]
+      shutdownServerAfterDisconnection: false
+    "nuclide-swift":
+      sourceKittenDisabled: false
+      sourceKittenPath: "/usr/local/bin/sourcekitten"
+      swiftToolchainPath: ""
+    "nuclide-type-coverage":
+      colorizeStatusBar: true
+    "nuclide-vcs-log":
+      showDifferentialRevision: true
+    "nuclide-welcome-page":
+      hiddenTopics: [
+        "fb-nuclide-welcome-page"
+      ]
+    "nuclide-working-sets": {}
+    overriddenThirdPartySettings: [
+      "core.closeDeletedFileTabs"
+      "core.closeEmptyWindows"
+      "tool-bar.position"
+      "tool-bar.iconSize"
+      "nuclide.installRecommendedPackages"
+      "file-icons.coloured"
+      "nuclide.atom-ide-console.diffUrlPattern"
+      "nuclide.atom-ide-console.taskUrlPattern"
+      "whitespace.ignoreWhitespaceOnCurrentLine"
+      "tool-bar.useTouchBar"
+      "core.useTreeSitterParsers"
+      "core.automaticallyUpdate"
+    ]
+    use:
+      "atom-ide-busy-signal": "default"
+      "atom-ide-code-actions": "default"
+      "atom-ide-code-format": "default"
+      "atom-ide-code-highlight": "default"
+      "atom-ide-console": "default"
+      "atom-ide-datatip": "default"
+      "atom-ide-debugger": "default"
+      "atom-ide-debugger-java": "default"
+      "atom-ide-debugger-java-android": "default"
+      "atom-ide-debugger-native-gdb": "default"
+      "atom-ide-debugger-node": "default"
+      "atom-ide-debugger-ocaml": "default"
+      "atom-ide-debugger-python": "default"
+      "atom-ide-debugger-react-native": "default"
+      "atom-ide-definitions": "default"
+      "atom-ide-diagnostics": "default"
+      "atom-ide-diagnostics-ui": "default"
+      "atom-ide-find-references": "default"
+      "atom-ide-global": "default"
+      "atom-ide-outline-view": "default"
+      "atom-ide-refactor": "default"
+      "atom-ide-signature-help": "default"
+      "atom-ide-terminal": "default"
+      "fb-ai-code-search": "default"
+      "fb-ai-complete-blocks": "default"
+      "fb-ai-google-code-search": "default"
+      "fb-alitepath-provider": "default"
+      "fb-analytics-client": "default"
+      "fb-android-menu-items": "default"
+      "fb-android-native-debugger": "default"
+      "fb-android-welcome-page": "default"
+      "fb-arc-lint": "default"
+      "fb-arc-paste": "default"
+      "fb-arcanist": "default"
+      "fb-arcanist-editor": "default"
+      "fb-atom-command-dash-provider": "default"
+      "fb-atom-snippets": "default"
+      "fb-atomprojects": "default"
+      "fb-aurora-language-server": "default"
+      "fb-biggrep": "default"
+      "fb-biggrep-dash-provider": "default"
+      "fb-breadcrumbs": "default"
+      "fb-buck-java": "default"
+      "fb-buck-mobilejs": "default"
+      "fb-code-patterns": "default"
+      "fb-codegraph": "default"
+      "fb-codex": "default"
+      "fb-codex-pages": "default"
+      "fb-component-search": "default"
+      "fb-componentscript": "default"
+      "fb-componentscript-fiddle": "default"
+      "fb-cquery": "default"
+      "fb-css-constants": "default"
+      "fb-dash": "default"
+      "fb-dataswarm": "default"
+      "fb-debugger-mobilejs": "default"
+      "fb-debugger-native-config-resolver": "default"
+      "fb-debugger-source-paths": "default"
+      "fb-devserver-checkup": "default"
+      "fb-diff-view": "default"
+      "fb-disable-lf-utf8": "default"
+      "fb-dumpapp": "default"
+      "fb-employee": "default"
+      "fb-entschema": "default"
+      "fb-eslint-client": "default"
+      "fb-file-a-bug": "default"
+      "fb-file-family-data-plugins": "default"
+      "fb-fuzzy-file-dash-provider": "default"
+      "fb-gatekeeper": "default"
+      "fb-generated-file-support": "default"
+      "fb-go": "default"
+      "fb-go-to-file-symbol-dash-provider": "default"
+      "fb-go-to-line-dash-provider": "default"
+      "fb-go-to-project-symbol-dash-provider": "default"
+      "fb-graphql-metrics": "default"
+      "fb-hack-playground": "default"
+      "fb-hackast-refactorizer": "default"
+      "fb-haskell-lsp": "default"
+      "fb-hg-dash-provider": "default"
+      "fb-home": "default"
+      "fb-http-request-sender": "default"
+      "fb-instarn": "default"
+      "fb-intellij": "default"
+      "fb-interactive-smartlog": "default"
+      "fb-intern-dash-provider": "default"
+      "fb-intl-fbt-str": "default"
+      "fb-java": "default"
+      "fb-java-test-runner": "default"
+      "fb-jellyfish": "default"
+      "fb-jest-test-runner": "default"
+      "fb-js-refactorizer": "default"
+      "fb-js-require-size-client": "default"
+      "fb-language-capirca": "default"
+      "fb-language-dataswarm": "default"
+      "fb-login": "default"
+      "fb-miso": "default"
+      "fb-neuralcodesearch-provider": "default"
+      "fb-new-file-template": "default"
+      "fb-notes": "default"
+      "fb-nuclide-beta-indicator": "default"
+      "fb-nuclide-node-playground": "default"
+      "fb-nuclide-onboarding": "default"
+      "fb-nuclide-onboarding-core-tasks": "default"
+      "fb-nuclide-remote-transfer": "default"
+      "fb-nux": "default"
+      "fb-observe-www-directory": "default"
+      "fb-on-demand": "default"
+      "fb-oneworld": "default"
+      "fb-osmeta": "default"
+      "fb-osmeta-core": "default"
+      "fb-package-center": "default"
+      "fb-package-manager": "default"
+      "fb-perf-gutter": "default"
+      "fb-phabricator": "default"
+      "fb-phabricator-comments-client": "default"
+      "fb-populate-symbols": "default"
+      "fb-prettier": "default"
+      "fb-product-alert": "default"
+      "fb-pyre-language-server": "default"
+      "fb-python-lsp": "default"
+      "fb-rating": "default"
+      "fb-relay": "default"
+      "fb-remote-uri-formatters": "default"
+      "fb-rust-language-server": "default"
+      "fb-sample-dash-provider": "never"
+      "fb-scala-lsp": "default"
+      "fb-scmquery": "default"
+      "fb-services": "default"
+      "fb-similar-code-detector": "default"
+      "fb-sitevar-notification": "default"
+      "fb-skip": "default"
+      "fb-slog": "default"
+      "fb-smoothscroll": "default"
+      "fb-sparse-file-preview": "default"
+      "fb-symbol-wiki": "default"
+      "fb-terminal-dash-provider": "default"
+      "fb-terminal-onboarding": "default"
+      "fb-test-pilot-test-runner": "default"
+      "fb-test-runner": "default"
+      "fb-test-runner-ui": "default"
+      "fb-thrift-client-service": "default"
+      "fb-thrift-language-server": "default"
+      "fb-trace-collector": "default"
+      "fb-ui-component-tools": "default"
+      "fb-xml": "default"
+      hyperclick: "default"
+      "nuclide-adb-logcat": "default"
+      "nuclide-atom-notifications": "default"
+      "nuclide-autocomplete": "default"
+      "nuclide-blame": "default"
+      "nuclide-blame-provider-hg": "default"
+      "nuclide-bookshelf": "default"
+      "nuclide-buck": "default"
+      "nuclide-buck-ios": "default"
+      "nuclide-clang": "default"
+      "nuclide-clipboard-path": "default"
+      "nuclide-code-search": "default"
+      "nuclide-context-view": "default"
+      "nuclide-css-lsp-client": "default"
+      "nuclide-ctags": "default"
+      "nuclide-current-working-directory": "default"
+      "nuclide-debugger-java": "default"
+      "nuclide-debugger-native": "default"
+      "nuclide-debugger-php": "default"
+      "nuclide-debugger-prepack": "default"
+      "nuclide-debugger-vsp": "default"
+      "nuclide-deep-link": "default"
+      "nuclide-definition-preview": "default"
+      "nuclide-definition-preview-provider": "default"
+      "nuclide-deprecation-cop": "default"
+      "nuclide-device-panel": "default"
+      "nuclide-device-panel-android": "default"
+      "nuclide-device-panel-ios": "default"
+      "nuclide-diagnostics-extras": "default"
+      "nuclide-diff-gutters": "default"
+      "nuclide-distraction-free-mode": "default"
+      "nuclide-file-family": "default"
+      "nuclide-file-family-projectionist": "default"
+      "nuclide-file-tree": "default"
+      "nuclide-file-watcher": "default"
+      "nuclide-flow": "default"
+      "nuclide-fuzzy-filename-provider": "default"
+      "nuclide-graphql": "default"
+      "nuclide-hack": "default"
+      "nuclide-health": "default"
+      "nuclide-hg-repository": "default"
+      "nuclide-hhvm": "default"
+      "nuclide-home": "default"
+      "nuclide-http-request-sender": "default"
+      "nuclide-image-view": "default"
+      "nuclide-infer-al": "default"
+      "nuclide-ios-simulator-logs": "default"
+      "nuclide-js-imports-client": "default"
+      "nuclide-json": "default"
+      "nuclide-key-binding-hint-status": "default"
+      "nuclide-language-hack": "default"
+      "nuclide-language-infer-al": "default"
+      "nuclide-language-reason": "default"
+      "nuclide-language-service-client": "default"
+      "nuclide-language-status": "default"
+      "nuclide-metro": "default"
+      "nuclide-move-item-to-available-pane": "default"
+      "nuclide-navigation-stack": "default"
+      "nuclide-navigation-stack-status-bar": "default"
+      "nuclide-notifications": "default"
+      "nuclide-nux": "default"
+      "nuclide-objc": "default"
+      "nuclide-ocaml": "default"
+      "nuclide-open-filenames-provider": "default"
+      "nuclide-outline-view-extras": "default"
+      "nuclide-project": "default"
+      "nuclide-python": "default"
+      "nuclide-quick-open": "default"
+      "nuclide-react-inspector": "default"
+      "nuclide-recent-files-provider": "default"
+      "nuclide-recent-files-service": "default"
+      "nuclide-reload-deep-link": "default"
+      "nuclide-remote-atom": "default"
+      "nuclide-remote-projects": "default"
+      "nuclide-settings": "default"
+      "nuclide-ssh-tunnel": "default"
+      "nuclide-swift": "default"
+      "nuclide-syntactic-selection": "default"
+      "nuclide-task-runner": "default"
+      "nuclide-test-runner": "default"
+      "nuclide-type-coverage": "default"
+      "nuclide-type-hint": "default"
+      "nuclide-ui": "default"
+      "nuclide-unicode-datatip": "default"
+      "nuclide-url-hyperclick": "default"
+      "nuclide-vcs-log": "default"
+      "nuclide-welcome-page": "default"
+      "nuclide-working-sets": "default"
+    useLocalRpc: true
+  "tool-bar":
+    iconSize: "16px"
+    position: "Left"
+    useTouchBar: false
+  "vim-mode-plus":
+    ignoreCaseForSearch: true
   welcome:
     showOnStartup: false
   whitespace:
     ignoreWhitespaceOnCurrentLine: false
+".text.xml":
+  editor:
+    nonWordCharacters: "/\\()\"',.;<>~!@#$%^&*|+=[]{}`?…"


chore(atom/config.cson): update atom/config.cson

--- atom/config.cson
+++ atom/config.cson
@@ -53,6 +53,7 @@
       "autocomplete-java-minus"
       "autocomplete-java"
       "linter-javac"
+      "file-header"
     ]
     packagesWithKeymapsDisabled: [
       "file-header"
@@ -65,7 +66,7 @@
   "cursor-history":
     flashOnLand: true
   editor:
-    fontFamily: "FiraCode-Regular"
+    fontFamily: "FiraCode-Medium"
     invisibles: {}
     scrollPastEnd: true
     showIndentGuide: true
@@ -89,8 +90,7 @@
       _analyticsUserId: "531f1de0-9539-4faa-9854-c3bf2d523b05"
   jumpy:
     fontSize: 1
-  "linter-ui-default":
-    panelHeight: 81
+  "linter-ui-default": {}
   "markdown-preview":
     liveUpdate: false
     useGitHubStyle: true
@@ -99,17 +99,31 @@
     userId: "1fb1a4b11cc74709a8f29f6ea5dd2b441a8e95cb"
   minimap:
     absoluteMode: true
-    autoToggle: false
     plugins:
+      bookmarks: true
+      bookmarksDecorationsZIndex: 0
+      codeglance: true
+      codeglanceDecorationsZIndex: 0
+      cursorline: false
+      cursorlineDecorationsZIndex: 0
       "find-and-replace": true
       "find-and-replaceDecorationsZIndex": 0
       "git-diff": true
       "git-diffDecorationsZIndex": 0
       "highlight-selected": true
       "highlight-selectedDecorationsZIndex": 0
+      linter: true
+      linterDecorationsZIndex: 0
+      "minimap-autohider": true
+      "minimap-autohiderDecorationsZIndex": 0
       pigments: true
       pigmentsDecorationsZIndex: 0
+      selection: true
+      selectionDecorationsZIndex: 0
     scrollAnimation: true
+  "minimap-autohider": {}
+  "minimap-selection":
+    highlightCursorsLines: true
   "one-dark-ui": {}
   pigments:
     markerType: "native-dot"


Disable Script and Pigments

Disable Script and Pigments

--- atom/config.cson
+++ atom/config.cson
@@ -25,6 +25,8 @@
       "autosave"
       "git-diff"
       "language-perl"
+      "script"
+      "pigments"
     ]
     followSymlinks: false
     ignoredNames: [


Tweak and reorganize Atom keymap selectors

--- atom/keymap.cson
+++ atom/keymap.cson
@@ -1,11 +1,17 @@
 # Your keymap

-'body':
+'atom-workspace':
+
   # Disable MRU tab switching
   'ctrl-tab ^ctrl': 'unset!'
   'ctrl-tab': 'pane:show-next-item'
   'ctrl-shift-tab ^ctrl': 'unset!'
   'ctrl-shift-tab': 'pane:show-previous-item'
+
+'.platform-darwin atom-workspace':
+
+  # Create new files using advanced-open-file
+  'alt-cmd-n': 'advanced-open-file:toggle'

 '.platform-darwin atom-text-editor:not([mini])':

@@ -80,8 +86,3 @@

   # Opens inline URL in default web browser if cursor is within URL
   'alt-cmd-o': 'link:open'
-
-'atom-workspace':
-
-  # Create new files using advanced-open-file rather than open existing files
-  'alt-cmd-n': 'advanced-open-file:toggle'


[➠] Improved “scrolly”.

[➠] Improved “scrolly”.

--- vendor/assets/javascripts/jquery/plugins/scrollify/scrolly.js.coffee
+++ vendor/assets/javascripts/jquery/plugins/scrollify/scrolly.js.coffee
@@ -10,25 +10,30 @@

   constructor: (theatre, options) ->
     @theatre = $ theatre
-    @roof    = @theatre.find '> .roof'
-    @stage   = @theatre.find '> .stage'
     @options = $.extend @defaults, options

+    @window = $ window
+    @roof   = @theatre.find '> .roof'
+    @stage  = @theatre.find '> .stage'
+
     initialize.call @
+
+    return
+
+  updateRoof: ->
+    scrollTop = do @window.scrollTop
+
+    if scrollTop > 0
+      minimizeRoof.call @
+    else
+      expandRoof.call @

     return

   # === Events ===

   onWindowScroll: (event) =>
-    window = $ event.target
-
-    scrollTop = do window.scrollTop
-
-    if scrollTop > 0
-      minimizeRoof.call @
-    else
-      expandRoof.call @
+    do @updateRoof

     return

@@ -41,6 +46,8 @@
     setupWindow.call @

     setupWaypoints.call @
+
+    do @updateRoof

     return


(just do something tiny) "find students..." vs "add new students" -- these boxes *are* confusing even me.  Need a better design.

--- salvus/page/editor_course.cjsx
+++ salvus/page/editor_course.cjsx
@@ -1345,10 +1345,10 @@
                         on_change   = {(value)=>@setState(search:value)}
                     />
                 </Col>
-                <Col md=3>
+                <Col md=4>
                     {
(Omitting {num_omitted} students)
 if num_omitted}
                 </Col>
-                <Col md=6>
+                <Col md=5>
                     <form onSubmit={@do_add_search}>
                         <Input
                             ref         = 'student_add_input'
@@ -2195,10 +2195,10 @@
                         on_change   = {(value)=>@setState(search:value)}
                     />
                 </Col>
-                <Col md=3>
+                <Col md=4>
                     {
(Omitting {num_omitted} assignments)
 if num_omitted}
                 </Col>
-                <Col md=6>
+                <Col md=5>
                     <form onSubmit={@do_add_search}>
                         <Input
                             ref         = 'assignment_add_input'


fix controller tests

fix controller tests

--- karma/flows/test_controllers.coffee
+++ karma/flows/test_controllers.coffee
@@ -579,11 +579,13 @@
         modalScope = $modalStack.getTop().value.modalScope

         expect(modalScope.validActionFilter(getAction('reply'))).toBe(true)
+        expect(modalScope.validActionFilter(getAction('end_ussd'))).toBe(false)

         # ivr only
         expect(modalScope.validActionFilter(getAction('say'))).toBe(false)
         expect(modalScope.validActionFilter(getAction('play'))).toBe(false)
         expect(modalScope.validActionFilter(getAction('api'))).toBe(true)
+        expect(modalScope.validActionFilter(getAction('end_ussd'))).toBe(false)

         # pretend we are a voice flow
         flowService.flow.flow_type = 'V'
@@ -591,6 +593,7 @@
         expect(modalScope.validActionFilter(getAction('say'))).toBe(true)
         expect(modalScope.validActionFilter(getAction('play'))).toBe(true)
         expect(modalScope.validActionFilter(getAction('api'))).toBe(true)
+        expect(modalScope.validActionFilter(getAction('end_ussd'))).toBe(false)

         # now try a survey
         flowService.flow.flow_type = 'S'
@@ -598,13 +601,15 @@
         expect(modalScope.validActionFilter(getAction('say'))).toBe(false)
         expect(modalScope.validActionFilter(getAction('play'))).toBe(false)
         expect(modalScope.validActionFilter(getAction('api'))).toBe(false)
+        expect(modalScope.validActionFilter(getAction('end_ussd'))).toBe(false)

         # USSD flow
         flowService.flow.flow_type = 'U'
-        expect(modalScope.validActionFilter(getAction('reply'))).toBe(true)
+        expect(modalScope.validActionFilter(getAction('reply'))).toBe(false)
         expect(modalScope.validActionFilter(getAction('say'))).toBe(false)
         expect(modalScope.validActionFilter(getAction('play'))).toBe(false)
         expect(modalScope.validActionFilter(getAction('api'))).toBe(false)
+        expect(modalScope.validActionFilter(getAction('end_ussd'))).toBe(true)

       $timeout.flush()


activity feed: use bound

activity feed: use bound

--- client/landing/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Activity.kdapplication/AppController.coffee
@@ -339,7 +339,7 @@
       KD.utils.getTimedOutCallbackOne
         name      : "populateActivity",
 #        onSuccess : -> KD.logToMixpanel "refresh activity feed success"
-        onTimeout : @recover.bind this
+        onTimeout : @bound 'recover'

   recover:->
     #KD.logToMixpanel "activity feed render failed; recovering"


Removed typo (duplicate method)

Removed typo (duplicate method)

--- src/map-state-model.coffee
+++ src/map-state-model.coffee
@@ -143,10 +143,6 @@
                 return
             @adaptToBounds L.latLngBounds latLngs

-        zoomIn: ->
-            @wasAutomatic = true
-            @map.setZoom @map.getZoom() + 1
-
         _objectsInsideBounds: (bounds, objects) ->
             objects.find (object) ->
                 latLng = MapUtils.latLngFromGeojson (object)


modify system out message when starting index.j

--- web/index.coffee
+++ web/index.coffee
@@ -4,4 +4,4 @@

 port = process.env.APP_PORT or 3000
 app.listen port, ->
-	console.log "Listening on https://localhost:" + port
+	console.log "Listening on http://localhost:" + port


Close #10.

Close #10.

--- lib/break.coffee
+++ lib/break.coffee
@@ -54,7 +54,7 @@
     breakCount = atom.config.get 'break.macroBreakIntervalInMicroAmount'
     if @currentMicroCount >= breakCount
       duration = 1000 * atom.config.get 'break.macroBreakLengthInSeconds'
-      @currentMicroCount = 0
+      @currentMicroCount = -1
     else
       duration = 1000 * atom.config.get 'break.microBreakLengthInSeconds'
     # console.log duration


Normalize loader path

Normalize loader path

--- src/lib/ComponentLoader.coffee
+++ src/lib/ComponentLoader.coffee
@@ -42,7 +42,7 @@
       moduleName = moduleName.substr 1
     if definition.noflo.loader
       # Run a custom component loader
-      loader = require definition.noflo.loader
+      loader = require "/#{moduleName}/#{definition.noflo.loader}"
       loader @
     if definition.noflo.components
       for name, cPath of definition.noflo.components


Version in help

Version in help

--- lib/dscan.coffee
+++ lib/dscan.coffee
@@ -260,7 +260,7 @@

 main = ->
   argParser = new ArgumentParser
-    version: '0.0.1'
+    version: require('../package.json').version
     addHelp: true
     description: 'Search a directory for something'


修改配置文件名称

修改配置文件名称

--- lib/utils/text-description.coffee
+++ lib/utils/text-description.coffee
@@ -81,8 +81,8 @@
   publishModulePageOneTitle: '请选择需要发布的模块'
   publishModulePageTwoTitle: '确认发布模块信息'

-  moduleConfigFileName: 'package.json'
-  ProjectConfigFileName: 'appConfig.json'
+  moduleConfigFileName: 'module-config.json'
+  ProjectConfigFileName: 'app-config.json'

   projectConfig : '应用配置'
   moduleConfig : '模块配置'


Enforce one observer at a time

Enforce one observer at a time

--- lib/index.coffee
+++ lib/index.coffee
@@ -1,11 +1,11 @@
 {CompositeDisposable} = require 'atom'
+fs = require 'fs'
 url = require 'url'
+path = require 'path'
 ConsoleRuntimeObserver = require './console-runtime-observer'
 ConsoleRuntimeView = require './console-runtime-view'

 module.exports = SampleScriptConsumer =
-
-  # subscriptions: null

   config:
     evaluateOnSave:
@@ -24,7 +24,7 @@
         {protocol, host, pathname} = url.parse(uriToOpen)
       catch error
         return
-      return unless protocol is 'hyper-console:'
+      return unless protocol is 'magic-console:'
       try
         pathname = decodeURI(pathname) if pathname
       catch error
@@ -32,39 +32,28 @@
       if host is 'editor'
         editorId = pathname.substring(1)
         view = new ConsoleRuntimeView({editorId})
-        changeCount = view.editor.buffer.changeCount.valueOf()
         @views = [@views..., view]
         @subscriptions.add view.onDidDestroy =>
           @blankRuntime.stop()
           @views = @views.filter (view) -> view.editorId != editorId
         @subscriptions.add view.onDidSave (ev) =>
           if atom.config.get 'magic-console.evaluateOnSave'
-            if view.editor.buffer.changeCount > changeCount
-              console.log 'onDidSave', @blankRuntime.observers[0].view.editor.buffer.changeCount, changeCount
-              changeCount = @blankRuntime.observers[0].view.editor.buffer.changeCount
-              @blankRuntime.stop()
-              @runBlank(view)
+            @toggle() unless @blankRuntime.observers?.length > 0
         view
       else
         filePath = pathname
         view = new ConsoleRuntimeView({filePath})
-        changeCount = view.editor.buffer.changeCount.valueOf()
         @views = [@views..., view]
         @subscriptions.add view.onDidDestroy =>
           @blankRuntime.stop()
           @views = @views.filter (view) -> view.filePath != filePath
         @subscriptions.add view.onDidSave (ev) =>
           if atom.config.get 'magic-console.evaluateOnSave'
-            if view.editor.buffer.changeCount > changeCount
-              console.log 'onDidSave', @blankRuntime.observers[0].view.editor.buffer.changeCount, changeCount
-              changeCount = @blankRuntime.observers[0].view.editor.buffer.changeCount
-              @blankRuntime.stop()
-              @runBlank(view)
+            @toggle() unless @blankRuntime.observers?.length > 0
         view

   deactivate: ->
     @subscriptions.dispose()
-    @view.destroy()

   # serialize: ->
   #   view: @views.forEach (view) -> view.serialize()
@@ -85,26 +74,25 @@
     atomPackage.activateNow()

   runBlank: (view) ->
-    # @activatePackage('script')
-    @blankRuntime?.observers.forEach (observer) -> observer.destroy()
-    @blankRuntime.observers = []
+    @activatePackage('script')
     @blankRuntime.addObserver(new ConsoleRuntimeObserver(view))
     @blankRuntime.execute()

   runDefault: ->
-    @activatePackage('script')
+    # @activatePackage('script')
     @defaultRuntime.execute()

   toggle: ->
     editor = atom.workspace.getActiveTextEditor()
     return unless editor?
-    uri = "hyper-console://editor/#{editor.id}"
+    uri = "magic-console://editor/#{editor.id}"
     previewPane = atom.workspace.paneForURI(uri)
     if previewPane
       # previewPane.destroyItem(previewPane.itemForURI(uri))
       previousActivePane = atom.workspace.getActivePane()
       previewPane.activateItemForURI(uri)
-      @blankRuntime.stop()
+      if @blankRuntime.observers?.length > 0
+        return @blankRuntime.stop()
       previousActivePane.activate()
       return @runBlank(previewPane.itemForURI(uri))
       # return @blankRuntime.execute()


use better coffeescript conditionals

use better coffeescript conditionals

this will actually compile into the same thing, but it's much easier to read.

--- lib/index.coffee
+++ lib/index.coffee
@@ -8,7 +8,7 @@
   opts.root = path.resolve(root)

   return (req, res, next) ->
-    if req.method != 'GET' and req.method != 'HEAD' then return next()
+    if req.method not in ['GET', 'HEAD'] then return next()

     _url = url.parse(req.originalUrl or req.url)
     _path = parseurl(req).pathname


Adds an option for homing beacon to the settings.

--- lib/jumpy.coffee
+++ lib/jumpy.coffee
@@ -5,6 +5,7 @@
     configDefaults:
         fontSize: .75
         highContrast: false
+        useHomingBeaconEffectOnJumps: true # Needs react editor

     activate: (state) ->
         @jumpyView = new JumpyView state.jumpyViewState