JAccount: add stackTemplate relation

JAccount: add stackTemplate relation

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -428,6 +428,9 @@
         as          : ['owner', 'user']
         targetType  : 'JCredential'

+      stackTemplate :
+        as          : 'user'
+        targetType  : 'JStackTemplate'

   constructor:->
     super


account: factor #fetchSubscriptions out of @fetchPlansAndSubscriptions

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -153,6 +153,7 @@
         'isEmailVerified'
         'fetchEmail'
         'fetchPaymentMethods'
+        'fetchSubscriptions'
         'fetchPlansAndSubscriptions'
       ]
     schema                  :
@@ -1279,9 +1280,7 @@
     if delegate is this or delegate.can 'administer accounts'
       @fetchDecoratedPaymentMethods callback

-  fetchPlansAndSubscriptions: secure ({connection:{ delegate }}, tags, callback) ->
-    JPaymentPlan = require './payment/plan'
-
+  fetchSubscriptions$: secure ({ connection:{ delegate }}, tags, callback) ->
     return callback { message: 'Access denied!' }  unless @equals delegate

     [callback, tags] = [tags, callback]  unless callback
@@ -1291,7 +1290,12 @@
       then targetOptions: selector: tags: $in: tags
       else {}

-    @fetchSubscriptions {}, options, (err, subscriptions) ->
+    @fetchSubscriptions {}, options, callback
+
+  fetchPlansAndSubscriptions: secure (client, tags, callback) ->
+    JPaymentPlan = require './payment/plan'
+
+    @fetchSubscriptions$ client, tags, (err, subscriptions) ->
       return callback err  if err

       planCodes = (s.planCode for s in subscriptions)


JSession:activeSession: check username on client object with in selector

--- workers/social/lib/social/models/session.coffee
+++ workers/social/lib/social/models/session.coffee
@@ -62,7 +62,15 @@

   @activeSession = secure (client, callback) ->
-    @one { clientId: client.sessionToken }, callback
+
+    username = client.connection?.delegate?.profile?.nickname
+    clientId = client.sessionToken
+
+    if not username or not clientId
+      return callback new KodingError 'Access denied'
+
+    @one { username, clientId }, callback
+

   # TODO not sure why we are creating session only for guest user
@@ -177,6 +185,6 @@

     # check if requester is the owner of the current session
     unless @username is username
-      return callback new KodingError 'Access denied.'
+      return callback new KodingError 'Access denied'

     @remove callback


fixes typo

fixes typo

--- workers/social/lib/social/models/session.coffee
+++ workers/social/lib/social/models/session.coffee
@@ -58,7 +58,7 @@
             callback null, session, guest

   @fetchSession =(clientId, callback)->
-    selector = {clientId}=
+    selector = {clientId}
     @one selector, (err, session)=>
       if err
         callback err


Call split classification log after the post, so we have an id (#3759)

--- app/pages/project/classify.cjsx
+++ app/pages/project/classify.cjsx
@@ -240,7 +240,6 @@
     classification = @state.classification
     console?.info 'Completed classification', classification

-    Split.classificationCreated(classification)
     {workflow, subjects} = classification.links
     seenThisSession.add workflow, subjects
     @queueClassification classification unless @state.demoMode
@@ -265,6 +264,7 @@
         apiClient.type('classifications').create(classificationData).save()
           .then (actualClassification) =>
             console?.log 'Saved classification', actualClassification.id
+            Split.classificationCreated(actualClassification) # Metric log needs classification id
             actualClassification.destroy()
             indexInQueue = queue.indexOf classificationData
             queue.splice indexInQueue, 1


enhance: dont track if it is an appknox user

--- app/routes/authenticated.coffee
+++ app/routes/authenticated.coffee
@@ -49,6 +49,8 @@
     try
       userName = user.get "username"
       accountId = user.get("email").split("@").pop().trim();
+      if accountId is "appknox.com"
+        return
       analytics.login(userName,accountId)
     catch error


feat: track login

feat: track login

--- app/routes/authenticated.coffee
+++ app/routes/authenticated.coffee
@@ -45,7 +45,13 @@
       Appcues.identify user.get("id"),
         name: user.get "username"
         email: user.get "email"
-      Appcues.start()
+      Appcues.start()
+    try
+      userId = user.get "id"
+      accountId = user.get("email").split("@").pop().trim();
+      analytics.login(userId,accountId)
+    catch error
+

     trial = @get "trial"
     trial.set "isTrial", user.get "isTrial"


Properly bubble helper errors

Properly bubble helper errors

--- lib/worker.coffee
+++ lib/worker.coffee
@@ -354,10 +354,12 @@
           if yielded
             @fiber.run([err, result])
           else
-            the_result = result
+            the_result = [err, result]
         if the_result != undefined
           Worker.current = this
-          return the_result
+          [e, v] = the_result
+          throw e if e
+          return v
         yielded = true
         [e, v] = Fiber.yield()
         Worker.current = this


Update Main.coffee

Update Main.coffee

--- src/旅立ちの街_フンケ/生け贄/夜との契約/sjcl/Main.coffee
+++ src/旅立ちの街_フンケ/生け贄/夜との契約/sjcl/Main.coffee
@@ -12,7 +12,7 @@
 isNotComplete = (element, index, array) ->
   element == 0

-getWidgh = (y) ->
+getWidth = (y) ->
   magic[y]

 getHeight = (x) ->
@@ -24,32 +24,22 @@
   array

 getSlant = (x) ->
-  slant = undefined
-  switch x
-    when 0
-      slant = ->
-        array = []
-        i = 0
-        while i < size
-          array.push magic[i][i]
-          i++
-        array
-    when size - 1
-      slant = ->
-        array = []
-        h = size - 1
-        i = 0
-        while i < size
-          array.push magic[h][i]
-          h--
-          i++
-        array
-  slant()
+  array = []
+  h = size - 1
+  i = 0
+  while i < size
+    if x == 0
+      array.push magic[i][i]
+    else if x == size - 1
+      array.push magic[h][i]
+    h--
+    i++
+  array

 getSum = ->
   i = 0
   while i < size
-    w = getWidgh(i)
+    w = getWidth(i)
     if !w.some(isNotComplete)
       return getArraySum(w)
     h = getHeight(i)


ComputeProvider:createDefaultStack: make adding admins into machine step optional and disable it for koding and guests group

--- workers/social/lib/social/models/computeproviders/computeprovider.coffee
+++ workers/social/lib/social/models/computeproviders/computeprovider.coffee
@@ -200,7 +200,11 @@
       ComputeProvider.createGroupStack client, callback

-  @createGroupStack = (client, callback = ->)->
+  @createGroupStack = (client, options, callback) ->
+
+    [options, callback] = [callback, options]  unless callback
+    callback ?= ->
+    options  ?= {}

     fetchStackTemplate client, (err, res)->

@@ -237,12 +241,18 @@
         template.machines?.forEach (machineInfo)->

           queue.push ->
+
             machineInfo.stack = stack

             create = (machineInfo) ->
               ComputeProvider.create client, machineInfo, (err, machine)->
                 results.machines.push { err, obj: machine }
                 queue.next()
+
+            # This is optional, since for koding group for example
+            # we don't want to add our admins into users machines ~ GG
+            unless options.addGroupAdminToMachines
+              return create machineInfo

             # TODO Do we need all admins or only some of them? ~ GG
             # Maybe some of them as admin some of them as user etc.
@@ -334,7 +344,9 @@
           delegate : member
         context    : group : group.slug

-      ComputeProvider.createGroupStack client, (err, res = {})->
+      ComputeProvider.createGroupStack client,
+        addGroupAdminToMachines: yes
+      , (err, res = {})->

         {stack, results} = res


Add tests for primary and secondary CSS classes

--- cms/static/coffee/spec/views/feedback_spec.coffee
+++ cms/static/coffee/spec/views/feedback_spec.coffee
@@ -58,14 +58,17 @@
       actions:
         primary:
           text: "Save",
+          class: "save-button",
           click: jasmine.createSpy('primaryClick')
         secondary: [{
             text: "Revert",
+            class: "cancel-button",
             click: jasmine.createSpy('secondaryClick')
           }]

       )

+    setFixtures(sandbox({id: "page-alert"}))
     @view = new CMS.Views.Alert({model: @model})

   it "should trigger the primary event on a primary click", ->
@@ -75,3 +78,10 @@
   it "should trigger the secondary event on a secondary click", ->
     @view.secondaryClick()
     expect(@model.get('actions').secondary[0].click).toHaveBeenCalled()
+
+  it "should apply class to primary action", ->
+    expect(@view.$(".action-primary")).toHaveClass("save-button")
+
+  it "should apply class to secondary action", ->
+    expect(@view.$(".action-secondary")).toHaveClass("cancel-button")
+


change from global to slef

change from global to slef

--- coffeescript/004-webworkers/multiplication.coffee
+++ coffeescript/004-webworkers/multiplication.coffee
@@ -3,19 +3,14 @@

   a demo webworker for mutiplication:
 ###
-( ->
+define [
+  'underscore'
+], (_) ->
+    self.onmessage = (e) ->
+        self.postMessage('hello from worker!')
+        result = _.reduce(_.values(e.data), ((memo, elem) -> memo * elem), 1)
+        self.postMessage(result)
+        false
+    self.postMessage('after binding')
+    false

-    global = this
-
-    define [
-      'underscore'
-    ], (_) ->
-        global.onmessage = (e) ->
-            global.postMessage('hello from worker!')
-            result = _.reduce(_.values(e.data), ((memo, elem) -> memo * elem), 1)
-            global.postMessage(result)
-            false
-        global.postMessage('after binding')
-        false
-)()
-


feeder added to member content displays

feeder added to member content displays

--- core/KD.coffee
+++ core/KD.coffee
@@ -46,6 +46,8 @@
   whoami:-> KD.getSingleton('mainController').getVisitor().currentDelegate

   isLoggedIn:-> @whoami() instanceof bongo.api.JAccount
+
+  isMine:(account)-> @whoami().profile.nickname is account.profile.nickname

   setAuthKey:->


Toggle view mode on clicking icon

Toggle view mode on clicking icon

--- components/view_menu/client/view_menu_view.coffee
+++ components/view_menu/client/view_menu_view.coffee
@@ -17,7 +17,19 @@
   initialize: ->
     @desktopEvents = _.extend @desktopEvents, @events
     @mobileEvents = _.extend @mobileEvents, @events
+
     super
+
+    @$el.on 'click', @toggleView
+
+  toggleView: (e) ->
+    return if $(e.currentTarget).hasClass 'view-menu__dropdown__option'
+    mode = if @model.get('view_mode') is 'list' then 'grid' else 'list'
+    model.set view_mode: setMode
+    glyph = @glyphs[mode]
+    @$el.removeClass 'dropdown--is_active'
+    @$('.view-menu__selected').attr 'data-glyph', glyph
+    window.location.reload()

   setMode: (e) ->
     mode = $(e.currentTarget).data 'mode'


webapp/editor: safeguard undefined codemirror in programmatical_goto_line -- #3321

--- src/smc-webapp/editor.coffee
+++ src/smc-webapp/editor.coffee
@@ -624,6 +624,7 @@

     programmatical_goto_line: (line) =>
         cm = @codemirror_with_last_focus
+        return if not cm?
         pos = {line:line-1, ch:0}
         info = cm.getScrollInfo()
         cm.scrollIntoView(pos, info.clientHeight/2)


better yaml support.

better yaml support.

--- src/smc-webapp/editor.coffee
+++ src/smc-webapp/editor.coffee
@@ -142,7 +142,6 @@
     bbl    : 'stex'
     xml    : 'xml'
     xsl    : 'xsl'
-    yaml   : 'yaml'
     ''     : 'text'

 file_associations = exports.file_associations = {}
@@ -233,6 +232,12 @@
     icon   : 'fa-file-code-o'
     opts   : {mode:'text/x-sass', indent_unit:2, tab_size:2}
     name   : "SASS"
+
+file_associations['yml'] = file_associations['yaml'] =
+    editor : 'codemirror'
+    icon   : 'fa-code'
+    opts   : {mode:'yaml', indent_unit:2, tab_size:2}
+    name   : "YAML"

 file_associations['css'] =
     editor : 'codemirror'


webapp: comment load_single_project and point to william's comment

--- src/smc-webapp/projects.cjsx
+++ src/smc-webapp/projects.cjsx
@@ -1009,6 +1009,9 @@
 _project_tables = {}
 _previous_project_id = undefined

+# This function makes it possible to switch between projects in kiosk mode.
+# If the project changes, it also recreates the users table.
+# Warning: https://github.com/sagemathinc/cocalc/pull/3985#discussion_r336828374
 load_single_project = (project_id) =>
     redux.getActions('page').setState({kiosk_project_id:project_id})
     if _previous_project_id != project_id


polish create project with hosting and network upgrades

--- src/smc-webapp/projects.cjsx
+++ src/smc-webapp/projects.cjsx
@@ -843,9 +843,9 @@
         if require('./customize').commercial then @render_upgrade_buttons() else @render_create_button()

     render_confirm_memebers_and_network_upgrades: ->
-

+        <Well style={'marginTop': '20px'}>
             <ButtonToolbar>
-                Create this project on a members-only host with full network access.
+
Create this project on a members-only host with full network access.

                 <Button
                     bsStyle  = 'success'
                     onClick  = {=>@create_project({member_host: 1, network: 1})} >
@@ -856,7 +856,7 @@
                     Cancel
                 </Button>
             </ButtonToolbar>
-

+        </Well>

     render_input_section: (subs)  ->
         create_btn_disabled = @state.title_text == '' or @state.state == 'saving'
@@ -903,6 +903,7 @@
             <Row>
                 <Col sm=12>
                     {if @state.title_text then @render_create_buttons() else @render_no_title_warning()}
+                    {@render_confirm_memebers_and_network_upgrades() if @state.create_button_hit == 'with_members_and_network'}

A project is your own private computational workspace that you can share
                     with others.

                     {@render_commercial_explanation_of_project() if require('./customize').commercial}

@@ -913,7 +914,6 @@
                 <Col sm=12>

                     {@render_upgrade_before_create(subs) if @state.create_button_hit == 'with_custom_upgrades'}
-                    {@render_confirm_memebers_and_network_upgrades() if @state.create_button_hit == 'with_members_and_network'}
                 </Col>
             </Row>
             <Row>


payment: show errors as notification if the error type is unknown

--- client/Main/payment/stripeformview.coffee
+++ client/Main/payment/stripeformview.coffee
@@ -169,6 +169,8 @@
         cardMonth.setValidationResult 'checkMonth', 'Invalid month!'
       when 'cvc'
         cardCVC.setValidationResult 'checkCVC', 'CVC is not valid'
+      else
+        KD.showError error.message


add task for rsync

add task for rsync

--- app/templates/_Gruntfile.coffee
+++ app/templates/_Gruntfile.coffee
@@ -138,6 +138,21 @@
 					dest: "src"
 					syncDestIgnoreExcl: true

+			# staging dry run down
+			stagingdowndry:
+				options:
+					args: ["--dry-run", "--verbose"]
+					src: "<%= pkg.domain.username %>@<%= pkg.domain.name %>:public_html/staging.<%= pkg.domain.name %>/site/assets/files/"
+					dest: "src/site/assets/files"
+					syncDestIgnoreExcl: true
+
+			# sync local with remote
+			stagingdown:
+				options:
+					src: "<%= pkg.domain.username %>@<%= pkg.domain.name %>:public_html/staging.<%= pkg.domain.name %>/site/assets/files/"
+					dest: "src/site/assets/files"
+					syncDestIgnoreExcl: true
+
 			# dry-run sync to prod
 			updry:
 				options:


Update gulpconfig.coffee

Update gulpconfig.coffee

--- app/templates/gulpconfig.coffee
+++ app/templates/gulpconfig.coffee
@@ -9,6 +9,6 @@
     fallback: "index.html"

   open:
-    host: "0.0.0.0"
+    host: "localhost"
     port: 9000
     path: "/"


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/string_extensions.coffee
+++ src/string_extensions.coffee
@@ -70,7 +70,10 @@

   return target

-String::constantize = ->
+###*
+
+###
+String::extension = ->
   return this.match(/\.([^\.]*)$/, '').last() || '';

 ###*


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/string_extensions.coffee
+++ src/string_extensions.coffee
@@ -137,7 +137,7 @@
 @name startsWith
 @methodOf String#

-@returns {Boolean} True if this string starts with the
+@returns {Boolean} True if this string starts with the given string, false otherwise.
 ###
 String::startsWith = (str) ->
   @lastIndexOf(str, 0) is 0


activity: map name to purpose, purpose to description when saving

If being created channel is a private channel, then map name to
purpose, purpose to payload's description.

--- client/app/lib/socialapicontroller.coffee
+++ client/app/lib/socialapicontroller.coffee
@@ -259,8 +259,14 @@
     item.accountOldId        = channel.accountOldId
     # we only allow name, purpose and payload to be updated
     item.payload             = data.payload
-    item.name                = data.name
-    item.purpose             = data.purpose
+
+    if item.typeConstant is 'privatemessage'
+      item.name = data.purpose
+      item.purpose = item.payload?.description or ''
+    else
+      item.name = data.name
+      item.purpose = data.purpose
+
     item.participantCount    = channel.participantCount
     item.participantsPreview = mapAccounts channel.participantsPreview
     item.unreadCount         = channel.unreadCount


undo follow artist change

undo follow artist change

--- apps/artist/client/index.coffee
+++ apps/artist/client/index.coffee
@@ -103,12 +103,8 @@
            button#artist-follow-button'     : 'followArtist'

   followArtist: (e) ->
-    currentUser = window.currentUser
-    if currentUser
-      currentUser.followArtist()
-    else
-      e.preventDefault()
-      mediator.trigger 'open:auth', { mode: 'login' }
+    e.preventDefault()
+    mediator.trigger 'open:auth', { mode: 'login' }

   nextRelatedArtistsPage: (e) ->
     type = if _.isString(e) then e else $(e).data 'type'


set name of ace editor

set name of ace editor

--- imports/ui/editors/YamlEditor.cjsx
+++ imports/ui/editors/YamlEditor.cjsx
@@ -34,7 +34,7 @@
         mode="yaml"
         theme="github"
         onChange={@onChange}
-        name="compose-editor"
+        name="ace-#{@props.name}"
         height='calc(100vh - 147px)'
         width='100%'
         fontSize=16


Call #image_path on map cluster icon

Call #image_path on map cluster icon

--- app/assets/javascripts/darkswarm/services/map_configuration.js.erb.coffee
+++ app/assets/javascripts/darkswarm/services/map_configuration.js.erb.coffee
@@ -4,7 +4,7 @@
       center:
         latitude: -37.4713077
         longitude: 144.7851531
-      cluster_icon: 'assets/map_009-cluster.svg'
+      cluster_icon: "<%= image_path('map_009-cluster.svg') %>"
       zoom: 12
       additional_options:
         # mapTypeId: 'satellite'


[skip] Tilted the labels on the burndown chart (3m)

--- app/assets/javascripts/houston-scheduler/views/show_milestone_view.coffee
+++ app/assets/javascripts/houston-scheduler/views/show_milestone_view.coffee
@@ -172,7 +172,7 @@
       .append('text')
         .text((d) -> d.effort)
         .attr('class', 'effort-remaining')
-        .attr('transform', (d)-> "translate(#{x(d.sprint) + 4.5}, #{y(d.effort) - 11}) rotate(-90)")
+        .attr('transform', (d)-> "translate(#{x(d.sprint) + 5.5}, #{y(d.effort) - 10}) rotate(-75)")

     insertLinebreaks = (d)->
       el = d3.select(this)


Backup commit

Backup commit

--- client/coffeescript/templates/post.coffee
+++ client/coffeescript/templates/post.coffee
@@ -15,6 +15,7 @@
     # NotImplementedYet
     cooked_showdown = raw_showdown
     #4. Links made ready for Oembed.
+    $("a").attr('class', 'oembed')

     return cooked_showdown
   identifier: -> @_id


onAddRecord isn't a prop

onAddRecord isn't a prop

--- client/lanes/components/grid/Toolbar.cjsx
+++ client/lanes/components/grid/Toolbar.cjsx
@@ -13,7 +13,7 @@
         @props.startEdit(0)

     AddButton: ->
-        return null unless @props.onAddRecord and @props.allowCreate
+        return null unless @props.allowCreate
         <BS.Button className="navbar-btn add-row pull-right"
             onClick={@onAddRecord} bsSize='small'
         >


KDFramework: KDinputViewWithPreview needs refactoring first entrance

--- components/inputs/KDInputViewWithPreview.coffee
+++ components/inputs/KDInputViewWithPreview.coffee
@@ -185,11 +185,6 @@
               left      : 35
             overlay     : yes
             buttons     :
-              Cancel    :
-                title   : "Discard changes"
-                style   : "modal-clean-gray"
-                callback:=>
-                  modal.destroy()
               Apply     :
                 title   : "Apply changes"
                 style   : "modal-clean-gray"
@@ -197,6 +192,10 @@
                   @setValue @text.getValue()
                   @generatePreview()
                   modal.destroy()
+              Cancel    :
+                title   : "cancel"
+                style   : "modal-cancel"
+                callback: -> modal.destroy()

           @utils.defer =>


Small revert

Small revert

--- components/modules/Home/includes/js/_map.coffee
+++ components/modules/Home/includes/js/_map.coffee
@@ -30,7 +30,7 @@
 		if navigator.geolocation
 			navigator.geolocation.getCurrentPosition(
 				(position) ->
-					#map.setCenter([position.coords.latitude, position.coords.longitude])
+					map.setCenter([position.coords.latitude, position.coords.longitude])
 				->
 				{
 					enableHighAccuracy	: true


Only delete a tooltip when it exists.

Only delete a tooltip when it exists.

--- core/app/backbone/factlink/tooltip_mixin.coffee
+++ core/app/backbone/factlink/tooltip_mixin.coffee
@@ -26,8 +26,9 @@

   tooltipRemove: (selector) ->
     tooltip = @_tooltips[selector]
-    tooltip.positionedRegion.resetFade()
-    delete @_tooltips[selector]
+    if tooltip?
+      tooltip.positionedRegion.resetFade()
+      delete @_tooltips[selector]

   tooltipBindAll: ->
     for selector, tooltip of @_tooltips


fix minor typo

fix minor typo

--- library/nucleus/watch.coffee
+++ library/nucleus/watch.coffee
@@ -247,7 +247,7 @@
     directoryTracking: (directory) ->
         assert pattern = /^(?:\.{2}\/?)+$/
         assert resolved = paths.resolve directory
-        assert _.iArray tracked = @tracked ?= []
+        assert _.isArray tracked = @tracked ?= []
         return undefined if resolved in tracked
         relA = (p) -> paths.relative(p, resolved)
         relB = (p) -> paths.relative(resolved, p)


debug change

debug change

--- manager/app/assets/javascripts/stark.js.coffee
+++ manager/app/assets/javascripts/stark.js.coffee
@@ -36,7 +36,7 @@
   # bound to app:route event
   matchRoute: (route, params) ->
     console.log "matchRoute()", route.state_name
-    console.log route, params
+    console.log route, "params: ", params
     @transition route.state_name, { params: params }

   transition: (state_name, state_data) ->


account/test: add test to delete resources associated account

--- workers/social/lib/social/models/account.test.coffee
+++ workers/social/lib/social/models/account.test.coffee
@@ -8,10 +8,26 @@
   generateRandomEmail
   checkBongoConnectivity } = require '../../../testhelper'

+{ generateMetaData } = require \
+  '../../../testhelper/models/computeproviders/credentialhelper'
+
+{ withConvertedUserAnd } = require  \
+  '../../../testhelper/models/computeproviders/computeproviderhelper'
+
 JUser            = require './user'
 JGroup           = require './group'
 JAccount         = require './account'
 { Relationship } = require 'jraphical'
+JInvitation      = require './invitation'
+JApiToken        = require './apitoken'
+JComputeStack    = require './stack'
+
+JStackTemplate   = require './computeproviders/stacktemplate'
+JCredential      = require './computeproviders/credential'
+
+{ generateStackTemplateData } = require \
+  '../../../testhelper/models/computeproviders/stacktemplatehelper'
+

 # making sure we have db connection before tests
@@ -170,37 +186,174 @@
     group  = {}
     group1 = {}
     group2 = {}
-    client = {}
+
+    adminClient  = {}
+
+    email = generateRandomEmail()
+
+    group2Slug = null
+
+    client  = {}
     account = {}

-    describe 'create group with user', ->
-
-      group1Slug = generateRandomString()
+    stackTemplate = null
+
+    describe 'create groups as owner and admin', ->

       groupData1         =
-        slug           : group1Slug
+        slug           : generateRandomString()
         title          : generateRandomString()
         visibility     : 'visible'

       before (done) ->
-        withConvertedUser { createGroup: yes }, (data) ->
-          { client, account, group } = data
-
-          # creating a new group
-          JGroup.create client, groupData1, account, (err, group_) ->
-            expect(err).to.not.exist
-            group1 = group_
-
-            account.fetchRelativeGroups {}, (err, groups) ->
+
+        withConvertedUser { createGroup: true }, (data) ->
+          { account, client, group } = data
+
+          queue = [
+            (next) ->
+              # creating a new group as owner
+              JGroup.create client, groupData1, account, (err, group_) ->
+                expect(err).to.not.exist
+                group1 = group_
+                next()
+
+            (next) ->
+              # creeate new group and add account as an admin to this team
+              withConvertedUser { createGroup: true }, (data) ->
+                { group: group2 } = data
+                group2Slug = group2.getAt 'slug'
+                group2.addAdmin account, next
+
+            (next) ->
+              # create a session for AdminAccount to be able to create resources
+              JSession = require './session'
+              sessionOptions =
+                username  : account.getAt 'profile.nickname'
+                groupName : group2Slug
+
+              JSession.createNewSession sessionOptions, (err, session) ->
+                expect(err).to.not.exist
+
+                adminClient =
+                  sessionToken : session.clientId
+                  context      : { group: group2Slug }
+                  clientIP     : '127.0.0.1'
+                  connection   :
+                    delegate   : account
+
+                next()
+
+            (next) ->
+              # creating resources for group2 for adminAccount
+              createResourcesQueue = [
+                (next) ->
+                  provider = 'aws'
+
+                  options =
+                    meta     : generateMetaData provider
+                    title    : 'someCredentialTitle'
+                    provider : provider
+
+                  options.meta.foobar = '  trim this white space   '
+                  JCredential.create adminClient, options, (err, credential) ->
+                    expect(err).to.not.exist
+                    expect(credential).to.exist
+                    next()
+
+                (next) ->
+                  stackTemplateData = generateStackTemplateData adminClient
+                  JStackTemplate.create adminClient, stackTemplateData, (err, template) ->
+                    expect(err).to.not.exist
+                    expect(template).to.exist
+                    stackTemplate = template
+                    next()
+
+                (next) ->
+                  config = { verified: yes }
+                  stackTemplate.update$ adminClient, { config }, (err) ->
+                    expect(err).to.not.exist
+                    next()
+
+                (next) ->
+                  stackTemplate.generateStack adminClient, (err, res) ->
+                    { stack, results: { machines } } = res
+                    expect(err).to.not.exist
+                    expect(machines).to.exist
+                    expect(stack).to.exist
+                    next()
+
+                (next) ->
+                  JInvitation.create adminClient, { invitations: [{ email }] }, (err) ->
+                    expect(err).to.not.exist
+                    next()
+
+                (next) ->
+                  group2.modify adminClient, { isApiEnabled : yes }, (err) ->
+                    expect(err).to.not.exist
+
+                    JApiToken.create { account, group : group2Slug }, (err, apiToken) ->
+                      expect(err).to.not.exist
+                      expect(apiToken).to.exist
+                      next()
+              ]
+
+              async.series createResourcesQueue, next
+          ]
+
+          async.series queue, ->
+            # number of groups that I am owner of
+            account.fetchRelativeGroups (err, groups) ->
+
+              expect(err).to.not.exist

               groups = groups.filter (group) -> group.slug isnt 'koding'
-
-              expect(err).to.not.exist
+              expect(groups.length).to.be.equal 3
+
+              groups = groups.filter (group) -> 'owner' in group.roles
               expect(groups.length).to.be.equal 2

-              groups.forEach (group) ->
-                expect(true).to.be.equal 'owner' in group.roles
               done()
+
+      it 'should ensure that group2 have resources for adminAccount', (done) ->
+
+        queue = [
+          (next) ->
+            JComputeStack.some { originId: account.getId(), group: group2Slug }, {}, (err, stacks) ->
+              expect(err).to.not.exist
+              expect(stacks.length).to.be.equal 1
+              expect(group2Slug).to.be.equal stacks[0].group
+              next()
+
+          (next) ->
+            JCredential.some$ adminClient, { originId: account.getId() }, (err, creds) ->
+              expect(err).to.not.exist
+              expect(creds.length).to.be.equal 1
+              next()
+
+          (next) ->
+            JApiToken.some { originId: account.getId() }, {}, (err, apiTokens) ->
+              expect(err).to.not.exist
+              expect(apiTokens.length).to.be.equal 1
+              expect(group2Slug).to.be.equal apiTokens[0].group
+              next()
+
+          (next) ->
+            JStackTemplate.some$ adminClient, { originId: account.getId() }, (err, stackTemplates) ->
+              expect(err).to.not.exist
+              expect(stackTemplates.length).to.be.equal 1
+              expect(group2Slug).to.be.equal stackTemplates[0].group
+              next()
+
+          (next) ->
+            JInvitation.some { inviterId: account.getId() }, {}, (err, invitations) ->
+              expect(err).to.not.exist
+              expect(invitations.length).to.be.equal 1
+              expect(group2Slug).to.be.equal invitations[0].groupName
+              next()
+        ]
+
+        async.series queue, done

       it 'should not be able to delete account when there more than one ownership', (done) ->
@@ -211,7 +364,7 @@
           done()

-    describe 'delete team and account', ->
+    describe 'delete team that I am owner of and account will clean all resources', ->

       before (done) ->

@@ -225,7 +378,41 @@

         async.series queue, done

-      it 'should account and group be deleted', (done) ->
+
+      it 'should delete resources of the adminAccount', (done) ->
+
+        queue = [
+          (next) ->
+            JApiToken.some { originId: account.getId() }, {}, (err, apiTokens) ->
+              expect(err).to.not.exist
+              expect(apiTokens.length).to.be.equal 0
+              next()
+
+          (next) ->
+            JCredential.some { originId: account.getId() }, {}, (err, creds) ->
+              expect(err).to.not.exist
+              expect(creds.length).to.be.equal 0
+              next()
+
+
+          (next) ->
+            JStackTemplate.some { originId: account.getId() }, {}, (err, stackTemplates) ->
+              expect(err).to.not.exist
+              expect(stackTemplates.length).to.be.equal 0
+              next()
+
+          (next) ->
+            JInvitation.some { inviterId: account.getId() }, {}, (err, invitations) ->
+              expect(err).to.not.exist
+              expect(invitations.length).to.be.equal 0
+              next()
+        ]
+
+        async.series queue, done
+
+
+      it 'should ensure that account and group are deleted', (done) ->
+
         queue = [
           (next) ->
             username = account.profile.nickname


update def/template/menu_darwin.cson

update def/template/menu_darwin.cson

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


Removed the guard as it seems unnecessary

--- core/app/backbone/views/evidence/ndp_fact_relation_or_comment_view.coffee
+++ core/app/backbone/views/evidence/ndp_fact_relation_or_comment_view.coffee
@@ -1,9 +1,7 @@
 class window.NDPFactRelationOrCommentBottomView extends Backbone.Marionette.Layout
   template:
     text: """
-      {{#time_ago}}
-        {{time_ago}} {{ global.t.ago }}
-      {{/time_ago}}
+      {{time_ago}} {{ global.t.ago }}
     """

 class NDPCommentView extends Backbone.Marionette.ItemView


Load all of the bootstraps

Load all of the bootstraps

Loading bootstrap and bootstrap/modal leads to loading bootstrap/modal
twice, which breaks all of the modals.

--- app/cells/modal/modal.coffee
+++ app/cells/modal/modal.coffee
@@ -1,2 +1,2 @@
 #= require jquery
-#= require bootstrap/modal
+#= require bootstrap


more coffee tweaks

more coffee tweaks

--- app/coffee/dreamfield.coffee
+++ app/coffee/dreamfield.coffee
@@ -15,10 +15,10 @@

     # adds the loading wheel
     $('.filterList').click( (event) =>
-      $(event.currentTarget).parent().find('.trigger').addClass('loading')
-      return false
+      # $(event.currentTarget).parent().find('.trigger').addClass('loading')
     )
     $('.next').click( (event) =>
+      $(event.currentTarget).addClass('loading')
       @loadNextPage()
     )

@@ -38,7 +38,7 @@
         @currentlyLoading = true # No more entries to load.
         $('#noMoreEntries').show()

-      @$container.append(data.html)
+      @$container.prepend(data.html)

   update: (html) ->
     @clear()


DEMO: fix ListView demo, add compatibility with webpack

--- demo/src/demos/ListView/ListViewTreeDemo.coffee
+++ demo/src/demos/ListView/ListViewTreeDemo.coffee
@@ -11,7 +11,8 @@
 	loadFiles: ->
 		dfr = new CUI.Deferred()

-		data = require('./files.txt')
+		# webpack will use the raw-loader to load txt file, we need to reference the default export here
+		data = require('./files.txt').default

 		@files = []
 		for line in data.split("\n")
@@ -359,4 +360,4 @@
 	d.toLocaleDateString()+" "+d.toLocaleTimeString()

-Demo.register(new Demo.ListViewTreeDemo())+Demo.register(new Demo.ListViewTreeDemo())


Expand on the alert text.

Expand on the alert text.

--- app/javascripts/image.coffee
+++ app/javascripts/image.coffee
@@ -68,7 +68,8 @@
           # Return the loaded image.
         .catch (res) =>
           # Display an alert with the status text.
-          alert "The image volume file load was unsuccessful: #{ res.statusText }."
+          alert("The image volume file load was unsuccessful: " +
+                "#{ res.statusText } (#{ res.status }).")
           # Set the state to 'error'.
           @state = Image.STATES.ERROR


refactor: check for isNaN

refactor: check for isNaN

--- app/models/manualscan.coffee
+++ app/models/manualscan.coffee
@@ -14,13 +14,13 @@

   filteredAppEnv: (->
     appEnv = parseInt @get "appEnv"
-    if appEnv isnt [ENUMS.APP_ENV.NO_PREFERENCE, ENUMS.APP_ENV.STAGING, ENUMS.APP_ENV.PRODUCTION]
+    if isNaN(appEnv)
       return ENUMS.APP_ENV.NO_PREFERENCE
   ).property "appEnv"

   filteredAppAction: (->
     appAction = parseInt @get "appAction"
-    if appAction isnt [ENUMS.APP_ACTION.NO_PREFERENCE, ENUMS.APP_ACTION.HALT, ENUMS.APP_ACTION.PROCEED]
+    if isNaN(appAction)
       return ENUMS.APP_ACTION.NO_PREFERENCE
   ).property "appAction"


Remove unnecessary loading state

Remove unnecessary loading state

--- app/pages/notifications.cjsx
+++ app/pages/notifications.cjsx
@@ -18,7 +18,6 @@
   getInitialState: ->
     firstMeta: { }
     lastMeta: { }
-    loading: true

   componentWillMount: ->
     @getNotifications() if @props.user
@@ -53,8 +52,7 @@
       else
         firstMeta = lastMeta = meta

-      loading = false
-      @setState {loading, notifications, firstMeta, lastMeta}
+      @setState {notifications, firstMeta, lastMeta}

   markAsRead: (meta)->
     =>


Use just one type

Use just one type

--- components/tree/treeviewcontroller.coffee
+++ components/tree/treeviewcontroller.coffee
@@ -296,7 +296,6 @@
       view               : new options.listViewClass
         type             : options.type
         tagName          : "ul"
-        type             : "jtree"
         itemClass        : options.treeItemClass
         itemChildClass   : options.itemChildClass
         itemChildOptions : options.itemChildOptions


Fix adding first marker to playlist item

--- app/assets/javascripts/me-add-to-playlist.coffee
+++ app/assets/javascripts/me-add-to-playlist.coffee
@@ -81,6 +81,25 @@
             $('#add_marker_to_playlist_item_result_message')[0].innerHTML = response.message
             $('#add_marker_to_playlist_item_alert').show(300)
             $('#add_marker_to_playlist_item').hide(500)
+            if $('#markers').length == 0
+              new_marker_section = $("

+

+
+                    Markers
+

+

+

+

+

+

+
Name

+
Time

+
Actions

+

+

+

+
")
+              $('#heading0').after(new_marker_section)
             new_marker = $("

                 <form accept-charset='UTF-8' action='/avalon_marker/"+response.id+"' class='edit_avalon_marker' data-remote='true' id='edit_avalon_marker_"+response.id+"' method='post'>

@@ -88,7 +107,7 @@
                     <input name='_method' type='hidden' value='patch' />

-                    "+response.marker.title+"
+                    "+response.marker.title+"

                     "+mejs.Utility.secondsToTimeCode(response.marker.start_time/1000)+"
@@ -103,6 +122,10 @@
             new_marker.find('button.edit_marker').click(enableMarkerEditForm);
             new_marker.find('.edit_avalon_marker').on('ajax:success', handle_edit_save).on 'ajax:error', (e, xhr, status, error) ->
               alert 'Request failed.'
+              return
+            new_marker.find('.marker_title').click ->
+              if typeof currentPlayer != typeof undefined
+                currentPlayer.setCurrentTime parseFloat(@dataset['offset']) or 0
               return
             new_marker.find('button[name="delete_marker"]').popover(
               trigger: 'manual'


Restore an "if" which went missing

Restore an "if" which went missing

--- app/assets/javascripts/testing_grounds.js.coffee
+++ app/assets/javascripts/testing_grounds.js.coffee
@@ -177,8 +177,12 @@
     self = this

     @data.forEach (series) ->
-      for point in [1..364]
-        series.values.push x: series.values[0].x + point, y: series.values[0].y
+      if series.values.length == 1
+        for point in [1..364]
+          series.values.push(
+            x: series.values[0].x + point,
+            y: series.values[0].y
+          )

     nv.addGraph =>
       d3.select(intoSelector).datum(@data).call(@chart())


ENHANCE: Skip LSR step if LSR is already uploaded

--- src/app/projects/project-portfolio-wizard/project-portfolio-wizard.coffee
+++ src/app/projects/project-portfolio-wizard/project-portfolio-wizard.coffee
@@ -63,6 +63,8 @@
     $scope.advanceActivePortfolioTab = (advanceBy) ->
       newSeq = $scope.activePortfolioTab.seq + advanceBy
       $scope.activePortfolioTab = (tab for tabKey, tab of $scope.portfolioTabsData when tab.seq is newSeq)[0]
+      if $scope.activePortfolioTab is $scope.portfolioTabsData.summaryStep and advanceBy > 0 and $scope.projectHasLearningSummaryReport()
+        $scope.advanceActivePortfolioTab 1
     $scope.setActivePortfolioTab $scope.portfolioTabsData.welcomeStep

     $scope.projectHasLearningSummaryReport = ->


Fixed a bug (#67) that led to error messages in Atom

--- lib/atom-html-preview-view.coffee
+++ lib/atom-html-preview-view.coffee
@@ -39,7 +39,8 @@

   destroy: ->
     # @unsubscribe()
-    @editorSub.dispose()
+    if editorSub?
+      @editorSub.dispose()

   subscribeToFilePath: (filePath) ->
     @trigger 'title-changed'


Protects minimal API from invalid arguments

--- lib/mixins/view-management.coffee
+++ lib/mixins/view-management.coffee
@@ -19,7 +19,7 @@
   # Returns the {MinimapView} object associated to the pane containing
   # the passed-in {EditorView}.
   minimapForEditorView: (editorView) ->
-    @minimapForPaneView(editorView.getPane())
+    @minimapForPaneView(editorView?.getPane())

   # Public: Returns the {MinimapView} object associated to the passed-in
   # {PaneView} object.
@@ -28,7 +28,7 @@
   #
   # Returns the {MinimapView} object associated to the passed-in
   # {PaneView} object.
-  minimapForPaneView: (paneView) -> @minimapForPane(paneView.model)
+  minimapForPaneView: (paneView) -> @minimapForPane(paneView?.model)

   # Public: Returns the {MinimapView} object associated to the passed-in
   # {Pane} object.
@@ -37,7 +37,7 @@
   #
   # Returns the {MinimapView} object associated to the passed-in
   # {Pane} object.
-  minimapForPane: (pane) -> @minimapViews[pane.id]
+  minimapForPane: (pane) -> @minimapViews[pane.id] if pane?

   # Internal: Destroys all views currently in use.
   destroyViews: ->


Fixes with-minimal class removed from pane on tab close

--- lib/mixins/view-management.coffee
+++ lib/mixins/view-management.coffee
@@ -1,3 +1,4 @@
+{EditorView} = require 'atom'
 Mixin = require 'mixto'
 MinimapView = require '../minimap-view'

@@ -45,6 +46,7 @@
     # the callback.
     @eachEditorViewSubscription = atom.workspaceView.eachEditorView (editorView) =>
       editorId = editorView.editor.id
+      paneView = editorView.getPane()
       view = new MinimapView(editorView)

       @minimapViews[editorId] = view
@@ -61,3 +63,5 @@
           view.destroy()
           delete @minimapViews[editorId]
           @emit('minimap-view:destroyed', {view})
+
+          paneView.addClass('with-minimap') if paneView.activeView instanceof EditorView


Use mixin for attachment thumbnail component.

--- app/assets/javascripts/components/attachment_thumbnail_component.js.coffee
+++ app/assets/javascripts/components/attachment_thumbnail_component.js.coffee
@@ -1,4 +1,4 @@
-ETahi.AttachmentThumbnailComponent = Ember.Component.extend
+ETahi.AttachmentThumbnailComponent = Ember.Component.extend ETahi.SpinnerMixin,
   classNameBindings: ['destroyState:_destroy', 'editState:_edit']
   destroyState: false
   previewState: false
@@ -35,12 +35,7 @@
     , 500, 'easeInCubic'

   toggleSpinner: (->
-    if @get('showSpinner')
-      @spinnerDiv = @$('.replace-spinner')[0]
-      @spinner ||= new Spinner(@get('spinnerOpts')).spin(@spinnerDiv)
-      $(@spinnerDiv).show()
-    else
-      $(@spinnerDiv).hide()
+    @createSpinner('showSpinner', '.replace-spinner', @get('spinnerOpts'))
   ).observes('showSpinner').on('didInsertElement')

   isProcessing: ( ->


Fixing a missing reference to Navigation

--- app/assets/javascripts/darkswarm/controllers/hub_node_controller.js.coffee
+++ app/assets/javascripts/darkswarm/controllers/hub_node_controller.js.coffee
@@ -1,4 +1,4 @@
-Darkswarm.controller "HubNodeCtrl", ($scope, HashNavigation, $location, $anchorScroll, $templateCache, CurrentHub) ->
+Darkswarm.controller "HubNodeCtrl", ($scope, HashNavigation, Navigation, $location, $anchorScroll, $templateCache, CurrentHub) ->
   $scope.toggle = ->
     HashNavigation.toggle $scope.hub.hash


after many other attempts, just trying to debounce the api call

--- app/assets/javascripts/sprangular/directives/shippingRatesSelection.coffee
+++ app/assets/javascripts/sprangular/directives/shippingRatesSelection.coffee
@@ -4,7 +4,7 @@
   scope:
     order: '='

-  controller: ($scope, Checkout, Env) ->
+  controller: ($scope, Checkout, Env, _) ->
     $scope.loading = false
     $scope.address = {}
     $scope.currencySymbol = Env.currency.symbol
@@ -25,8 +25,10 @@
       $scope.address = $scope.order.actualShippingAddress()
     , true)

-    validateAddress = (address) ->
-      $scope.isValid = address.firstname && address.lastname && address.city && address.address1 && address.zipcode && address.country && address.state && address.phone
+    validateAddress = _.debounce(
+      (address) ->
+        $scope.isValid = address.firstname && address.lastname && address.city && address.address1 && address.zipcode && address.country && address.state && address.phone
+    , 3000)

     $scope.$watch('address', validateAddress, true)


Fix keying operator components

Fix keying operator components

--- assets/javascripts/react/components/observable.coffee
+++ assets/javascripts/react/components/observable.coffee
@@ -43,8 +43,8 @@
     {root} = @props.observable

     operatorNodes = @props.observable.operators.map (operator, index) =>
-      <ObservableOperator operator={operator} onRemove={@removeOperator} onChildOperatorChange={@handleChildObservableChange} recursionLevel={@props.recursionLevel}
-        onChange={@handleOperatorChange} key={operator.id} ObservableComponent={Observable}>
+      <ObservableOperator key={operator.type + operator.id + index} operator={operator} onRemove={@removeOperator} onChildOperatorChange={@handleChildObservableChange} recursionLevel={@props.recursionLevel}
+        onChange={@handleOperatorChange} ObservableComponent={Observable}>
         <AddOperator id={operator.id} onSelect={handleAddOperatorTo(operator)}/>
       </ObservableOperator>


Fix reply textarea autofocus

Fix reply textarea autofocus

--- lib/assets/javascripts/views/004_mentions_auto_complete_textarea.js.coffee
+++ lib/assets/javascripts/views/004_mentions_auto_complete_textarea.js.coffee
@@ -9,3 +9,6 @@
   initInlineMentionsManager: =>
     @inline_mentions_manager = new TentStatus.InlineMentionsManager(el: @el)

+  focus: =>
+    @el.focus()
+


Fix window.language not update

Fix window.language not update

--- views/components/settings/parts/poi-config.cjsx
+++ views/components/settings/parts/poi-config.cjsx
@@ -208,6 +208,7 @@
     config.set 'poi.language', language
     for namespace of window.i18n
       window.i18n[namespace].setLocale language
+    window.language = language
     @setState {language}
   handleClearCookie: (e) ->
     remote.getCurrentWebContents().session.clearStorageData {storages: ['cookies']}, ->


Fix bug

Fix bug

--- views/components/settings/parts/poi-config.cjsx
+++ views/components/settings/parts/poi-config.cjsx
@@ -32,7 +32,7 @@
     enableConfirmQuit: config.get 'poi.confirm.quit', false
     enableDoubleTabbed: config.get 'poi.tabarea.double', false
     enableNotify: config.get 'poi.notify.enabled', true
-    notifyVolume: config.get 'poi.notify.volume', true
+    notifyVolume: config.get 'poi.notify.volume', 1.0
     zoomLevel: config.get 'poi.zoomLevel', 1
     mapStartCheckShip: config.get 'poi.mapstartcheck.ship', false
     freeShipSlot: config.get 'poi.mapstartcheck.freeShipSlot', 4


Working transaction

Working transaction

--- app/assets/javascripts/app/transaction.js.coffee
+++ app/assets/javascripts/app/transaction.js.coffee
@@ -270,7 +270,6 @@
     self = @
     $('#transaction_currency_id').bind 'change keyup', (event)->
       self.set({currency_id: $(this).val() * 1})
-      console.log self.get("currency_id")
   # Sets the discount
   setDiscount: ->
     discount = @.get("subtotal") * @.get("discount")
@@ -320,6 +319,8 @@
     @model.bind("change:currency_id", (model, name)->
       unless self.model.get("currency_id") == self.model.get("default_currency")
         self.openDialog()
+        self.setExchange()
+        self.setLabel()
       else
         self.model.set({exchange_rate: 1})
         self.setLabel()
@@ -328,7 +329,7 @@
       self.setLabel()
     )

-    $(@el).find("span.default_symbol").html(@model.get("default_symbol"))
+    @el.find("span.default_symbol").html(@model.get("default_symbol"))

     @.setEvents()
   # Set events for edit
@@ -338,11 +339,10 @@
       self.openDialog()
       false
     )
-    # button
-    $('#exchange_rate').live "change", -> self.setExchange()
+
   # Events
   events:
-    "click button": "setExchange"
+    "click button": "closeDialog"
   # Label
   setLabel: ->
     @label.find("span.rate_details").html('')
@@ -356,14 +356,14 @@
   setExchange: ->
     rate = ($(@el).find("#exchange_rate").val() * 1).round(4)
     @model.set({exchange_rate: rate})
-    @.closeDialog()
   # present dialog
   openDialog: ->
-    $(@el).find("#exchange_rate").val(@model.get("exchange_rate"))
-    $(@el).find("span.currency_symbol").html(@model.get("currency_symbol"))
-    $( @el ).dialog("open")
+    @el.find("#exchange_rate").val(@model.get("exchange_rate"))
+    @el.find("span.currency_symbol").html(@model.get("currency_symbol"))
+    @el.dialog("open")
   closeDialog: ->
-    $( @el ).dialog("close")
+    @.setExchange()
+    @el.dialog("close")

 window.ExchangeRateDialog = ExchangeRateDialog

@@ -414,8 +414,9 @@
       autoOpen: false
       title: 'Tipo de cambio'
       id: 'currency_dialog'
-      width: 500,
-      position: 'center',
+      width: 500
+      position: 'center'
+      modal: true
       close: (event, ui)->
         $(this).hide()
         $('#exchange_rate').trigger("change")


Pods store write to index ddb.

Pods store write to index ddb.

--- app/assets/javascripts/pods/pods_store.js.coffee
+++ app/assets/javascripts/pods/pods_store.js.coffee
@@ -4,3 +4,20 @@
     @records
   update: (new_records) ->
     @records = @records.concat(new_records)
+    @writeObjects(new_records)
+  writeObjects: (pods) ->
+    r = indexedDB.open('pods', 1)
+    r.onupgradeneeded = (e) ->
+      db = event.target.result
+      if !db.objectStoreNames.contains 'pods'
+        store = db.createObjectStore 'pods',
+          keyPath: 'name'
+        store.createIndex "stars", "stars",
+          unique: false
+    r.onsuccess = (e) ->
+      db = r.result
+      t = db.transaction 'pods', 'readwrite'
+      s = t.objectStore('pods')
+      for pod in pods
+        r = s.put(pod)
+


Fix coffeescript function bindings

Fix coffeescript function bindings

--- app/assets/javascripts/resque_poll/poller.coffee
+++ app/assets/javascripts/resque_poll/poller.coffee
@@ -2,14 +2,13 @@
   @INTERVAL: 2000

   constructor: (opts) ->
-    @$elem = opts.elem
-    @url   = opts.url
-
-  poll: => @interval = setInterval(_poll, @INTERVAL)
+    @$elem    = opts.elem
+    @url      = opts.url
+    @interval = setInterval(@_poll, ResquePoller.INTERVAL)

   # private

-  _poll: -> $.getJSON @url, (resp) -> _handleResponse(resp)
+  _poll: => $.getJSON @url, (resp) => @_handleResponse(resp)

   _handleResponse: (resp) ->
     return if resp.status is 'queued'


force_render fakeish changer now responds to finish()

--- app/assets/javascripts/roofpig/Display.js.coffee
+++ app/assets/javascripts/roofpig/Display.js.coffee
@@ -86,4 +86,5 @@
         this.reset()

   force_render: ->
-    this.add_changer('force_render', { finished: true, update: (now) -> })+    null_func = ->
+    this.add_changer('force_render', { finished: true, finish: null_func, update: null_func })


Update APIClient schema formatting

Update APIClient schema formatting

--- app/schemas/models/api-client.schema.coco.coffee
+++ app/schemas/models/api-client.schema.coco.coffee
@@ -39,10 +39,7 @@
       description: 'The APIClient can grant licenses to its users for this number of days'
       default: 0
     },
-    autoClanOwner: {
-      type: c.objectId(),
-      description: 'owner(user) of apiclient auto clan'
-    },
+    autoClanOwner: c.objectId { description: 'owner (user) of APIClient auto clan' }
     accessPermissions: c.array { description: 'list users who have the access permission to the api-client-auto-clan'}, {
       type: 'object',
       properties: {


fix constructor: new array without args

fix constructor: new array without args

--- src/coffee/core/constructor.coffee
+++ src/coffee/core/constructor.coffee
@@ -2,7 +2,10 @@
   object: (prop)->
     new Object(prop)
   array: (items)->
-    new Array(items)
+    unless items
+      new Array()
+    else
+      new Array(items)
   true: ->
     new Boolean(true)
   false: ->


fixed a typo in getHandler

fixed a typo in getHandler

--- app/routes/getHandler.coffee
+++ app/routes/getHandler.coffee
@@ -39,7 +39,7 @@
         if err?
           algo = AlgorithmManagement.getStatusByRoute(req.originalUrl)
           if(algo?)
-            error = createError(algot.status.statusCode, algo.status.statusMessage)
+            error = createError(algo.status.statusCode, algo.status.statusMessage)
           else
             error = createError(404,'This algorithm is not available')
           callback error


Fix reference to `@key` in log expression.

--- services/web/app/coffee/Features/Notifications/NotificationsBuilder.coffee
+++ services/web/app/coffee/Features/Notifications/NotificationsBuilder.coffee
@@ -11,7 +11,7 @@
 			messageOpts =
 				groupName: licence.name
 				subscription_id: licence.subscription_id
-			logger.log user_id:user._id, key:key, "creating notification key for user"
+			logger.log user_id:user._id, key: @key, "creating notification key for user"
 			NotificationsHandler.createNotification user._id, @key, "notification_group_invite", messageOpts, null, callback

 		read: (callback = ->)->


Support an empty DragonView

Support an empty DragonView

... which can act as a placeholder for a dynamically generate dragon.

--- app/views/dragon-view.coffee
+++ app/views/dragon-view.coffee
@@ -7,7 +7,7 @@
     @showCharacteristics ?= false
     @visibleTraits ?= []

-    @_addListeners(@dragon)
+    @_addListeners()
     @div = $(domId)[0]
     @div.classList.add 'dragon-view-parent'
     @_injectHtml()
@@ -24,7 +24,7 @@
   setCharacteristicsVisible: (@showCharacteristics) ->
     @_updateVisibility()

-  _addListeners: (dragon)->
+  _addListeners: ->
     Events.addEventListener EventTypes.DRAGON.ALLELES_CHANGED, (evt)=>
       if evt.detail.dragon is @dragon
         @_updateClasses()
@@ -34,22 +34,26 @@
   _updateClasses: ->
     @phenoView.setAttribute('class', '')
     @phenoView.classList.add 'dragon-view'
+    if not @dragon?
+      @phenoView.classList.add 'no-dragon'
+      return
     for characteristic in @dragon.getAllCharacteristics()
       characteristic = characteristic.toLowerCase().replace(' ', '-')
       @phenoView.classList.add characteristic

   _updateVisibility: ->
-    if @showSex
+    if @dragon? and @showSex
       @sexLabel.classList.remove('hidden') if @sexLabel.classList.contains('hidden')
     else
       @sexLabel.classList.add 'hidden'

-    if @showCharacteristics
+    if @dragon? and @showCharacteristics
       @characteristicList.classList.remove('hidden') if @characteristicList.classList.contains('hidden')
     else
       @characteristicList.classList.add 'hidden'

   _updateCharacteristics: ->
+    return unless @dragon?
     out = []
     for own trait, characteristic of @dragon.phenotype.characteristics
       continue if @visibleTraits.length > 0 and trait not in @visibleTraits
@@ -58,6 +62,7 @@
     @characteristicList.innerHTML = out.join('')

   _updateSexLabel: ->
+    return unless @dragon?
     @sexLabel.innerHTML = if @dragon.sex is BioLogica.MALE then "male" else "female"

   _injectHtml: ->


add missing command

add missing command

--- menus/browse.cson
+++ menus/browse.cson
@@ -15,6 +15,11 @@
         {
           'label': 'Open Packages Folder'
           'command': 'browse:packages-folder'
+        },
+        { 'type': 'separator' },
+        {
+          'label': 'Open Enclosing Folder'
+          'command': 'browse:enclosing-folder'
         }
       ]
     ]


:art:

:art:

--- menus/darwin.cson
+++ menus/darwin.cson
@@ -189,7 +189,7 @@
       { label: 'Minimize', command: 'application:minimize' }
       { label: 'Zoom', command: 'application:zoom' }
       { type: 'separator' }
-      { label: 'Bring All to Front', command: 'application:bring-all-windows-to-front'}
+      { label: 'Bring All to Front', command: 'application:bring-all-windows-to-front' }
     ]
   }


Test toString

Test toString

Signed-off-by: Ian Macalinao <08370e385f4778cad8fe504ec5445edd3d45bd9a@gmail.com>

--- test/items.coffee
+++ test/items.coffee
@@ -71,6 +71,11 @@
         longSword = findOne "Long Sword"
         longSword.getTotalCost().should.equal longSword.cost

+    describe "toString", ->
+
+      it "should use the item's name", ->
+        testItem.toString().should.equal testItem.name
+
   describe "find", ->

     it "should return all items when nothing is passed to it", ->


Remove unused protocol config props

Remove unused protocol config props

--- lib/assets/javascripts/unpoly/protocol.coffee
+++ lib/assets/javascripts/unpoly/protocol.coffee
@@ -568,13 +568,6 @@
   @stable
   ###
   config = new up.Config ->
-    acceptLayerHeader: 'X-Up-Accept-Layer'     # @header
-    dismissLayerHeader: 'X-Up-Dismiss-Layer'   # @header
-    eventsHeader: 'X-Up-Events'                # @header
-    contextHeader: 'X-Up-Context'              # @header, also Up-Fail-Context
-                                               # @header X-Up-Target, X-Up-Fail-Target
-                                               # @header X-Up-Mode, X-Up-Fail-Mode
-
     methodParam: '_method'                     # up.network.config.methodParam

     csrfParam: -> e.metaContent('csrf-param')  # das muss echt configurierbar sein, evtl. up.network.config.csrfParam


set module.exports & CamelCase class name

--- countUp.coffee
+++ countUp.coffee
@@ -1,7 +1,7 @@
 ###*
  * @author inorganik
  * @example
- * numAnim = new countUp(
+ * numAnim = new CountUp(
  *   document.getElementById("SomeElementYouWantToAnimate"),
  *   99.99,
  *   2,
@@ -10,7 +10,7 @@
  * numAnim.start();
  * @version 0.0.6
 ###
-class countUp
+class CountUp
   useEasing: true
   startTime: null
   remaining: null
@@ -107,7 +107,7 @@
     unless isNaN(endVal) and isNan(startVal) isnt null
       requestAnimationFrame @count
     else
-      console.log('countUp error: startVal or endVal is not a number')
+      console.log('CountUp error: startVal or endVal is not a number')
       @target.innerHTML = '--'
     false

@@ -138,3 +138,5 @@
       x1 = x1.replace(rgx, '$1' + ',' + '$2')

     x1 + x2
+
+module.exports = CountUp


Don't use JS.Set in subscription node

Don't use JS.Set in subscription node

--- lib/assets/javascripts/monarch/util/node.coffee
+++ lib/assets/javascripts/monarch/util/node.coffee
@@ -3,22 +3,23 @@
     @clear()

   clear: ->
-    @subscriptions = new JS.Set()
+    @subscriptions = []

   publish: ->
     @publishArgs(arguments)

   publishArgs: (args) ->
-    @subscriptions.forEach (subscription) ->
+    for subscription in @subscriptions
       subscription.publish(args)

   subscribe: (callback, context) ->
     subscription = new Monarch.Util.Subscription(callback, context, this)
-    @subscriptions.add(subscription)
+    @subscriptions.push(subscription)
     subscription

   unsubscribe: (subscription) ->
-    @subscriptions.remove(subscription)
+    index = @subscriptions.indexOf(subscription)
+    @subscriptions.splice(index, 1) unless index == -1
     @emptyNode?.publish() if @size() == 0

   onEmpty: (callback, context) ->
@@ -29,4 +30,4 @@
     @subscriptions.length

   size: ->
-    @subscriptions.size
+    @subscriptions.length


iterate all available files

iterate all available files

--- lib/assets/javascripts/turbograft/remote.coffee
+++ lib/assets/javascripts/turbograft/remote.coffee
@@ -78,7 +78,8 @@
     formData = new FormData
     @_iterateOverFormInputs form, (input) =>
       if input.type == 'file'
-        formData.append(input.name, input.files[0]) # <- just a guess
+        for file in input.files
+          formData.append(input.name, file)
       else
         formData.append(input.name, input.value)
     formData


Keep click handlers for closing the modal around after password instructions set

--- desktop/components/auth_modal/view.coffee
+++ desktop/components/auth_modal/view.coffee
@@ -128,9 +128,9 @@
         when 'forgot'
           mediator.trigger 'auth:change:mode', 'reset'

-      @undelegateEvents()
-
-      @$('form').submit() unless @state.get('mode') is 'reset'
+      unless @state.get('mode') is 'reset'
+        @undelegateEvents()
+        @$('form').submit()

   showError: (msg) =>
     @$('button').attr 'data-state', 'error'


#6913 更改hook为plugin:run

#6913 更改hook为plugin:run

--- honey-image-demo-upload/index.coffee
+++ honey-image-demo-upload/index.coffee
@@ -43,7 +43,7 @@
   ZIPFOLDER = _path.join TEMPDIR, DISTDIR
   ZIPFILE = "#{ZIPFOLDER}.tar.gz"

-  silky.registerHook("build:initial", {async: true}, (data, done)->
+  silky.registerHook("plugin:run", {async: true}, (data, done)->
     console.log "----------- Uploading image to server... ----------- "
     #copy Dir To Tmp
     #delete tmp


Search completion; add space in vomnibar.

--- pages/vomnibar.coffee
+++ pages/vomnibar.coffee
@@ -99,7 +99,7 @@
     if 0 <= @selection and @completions[@selection].insertText
       @previousText ?= @input.value
       suggestion = @completions[@selection]
-      @input.value = (suggestion.reinsertPrefix ? "") + suggestion.title
+      @input.value = (suggestion.reinsertPrefix ? "") + suggestion.title + " "
     else if @previousText?
         @input.value = @previousText
         @previousText = null


Remove some comments

Remove some comments

--- lib/init.coffee
+++ lib/init.coffee
@@ -19,8 +19,8 @@
     proc = process
     provider =
       grammarScopes: ['source.elm']
-      scope: 'file' # or 'project'
-      lintOnFly: true # must be false for scope: 'project'
+      scope: 'file'
+      lintOnFly: true
       lint: (textEditor) =>
         return new Promise (resolve, reject) =>
           filePath = textEditor.getPath()


Cleanup

Cleanup

--- src/podroller/core.coffee
+++ src/podroller/core.coffee
@@ -1,11 +1,11 @@
-_u = require "underscore"
-path = require 'path'
-express = require 'express'
-fs = require "fs"
-ffmpegmeta = require('fluent-ffmpeg').Metadata
-http = require "http"
-Parser = require "./mp3parser"
-qs = require 'qs'
+_u          = require "underscore"
+path        = require 'path'
+express     = require 'express'
+fs          = require "fs"
+ffmpegmeta  = require('fluent-ffmpeg').Metadata
+http        = require "http"
+Parser      = require "./mp3parser"
+qs          = require 'qs'

 module.exports = class Core
     DefaultOptions:
@@ -15,130 +15,120 @@
         # after a new deployment, allow a 30 minute grace period for
         # connected listeners to finish their downloads
         max_zombie_life:    2 * 60 * 1000
-
-    constructor: (opts) ->
-        @options = _u.defaults opts||{}, @DefaultOptions
-
+
+
+
+    constructor: (opts={}) ->
+        @options = _u.defaults opts, @DefaultOptions
+
         # -- make sure our audio dir is valid -- #
-
         if !path.existsSync(@options.audio_dir)
             console.error "Audio path is invalid!"
             process.exit()
-
+
         # -- set up cache storage -- #
-
         @key_cache  = {}
         @listeners  = 0
         @_counter   = 0
-
+
         # -- set up a server -- #
-
         console.log "config is ", @options
-
         @app = express()
         @app.use (req,res,next) => @podRouter(req,res,next)
         @server = @app.listen @options.port
-
+
         # -- set up a shutdown handler -- #
-
+
         process.on "SIGTERM", =>
             # stop listening
             @server.close()
-
+
             # now start polling to see how many files we're delivering
             # when should we get pushy?
             @_shutdownMaxTime = (new Date).getTime() + @options.max_zombie_life
-
+
             console.log "Got SIGTERM. Starting graceful shutdown with #{@listeners} listeners."
-
+
             # need to start a process to quit when existing connections disconnect
             @_shutdownTimeout = setInterval =>
                 # have we used up the grace period yet?
                 force_shut = if (new Date).getTime() > @_shutdownMaxTime then true else false
-
+
                 if @listeners == 0 || force_shut
                     # everyone's out...  go ahead and shut down
                     console.log "Shutdown complete"
                     process.exit()
                 else
                     console.log "Still awaiting shutdown; #{@listeners} listeners"
-
             , 60 * 1000
-
-    #----------
-
-    podRouter: (req,res,next) ->
+
+
+
+    podRouter: (req, res, next) ->
         # if we take prefix away from req.url, does it match an audio file?
         match = ///^#{@options.prefix}(.*)///.exec req.path
-
-        if match?[1]
-            filename = path.join(@options.audio_dir,match[1])
-            fs.stat filename, (err,stats) =>
-                # if there was a stat error or this isn't a file, move on
-                if err || !stats.isFile()
-                    next()
-                    return true
-
-                # is this a file we already know about? if so, has it not been changed?
-                if @key_cache[ filename ] && @key_cache[filename]?.mtime == stats.mtime.getTime() && @key_cache[filename].stream_key
-                    # we're good.  use the cached stream key for preroll, then send our file
-                    @streamPodcast req, res, filename, stats.size, @key_cache[filename].stream_key, @key_cache[filename].id3
-                else
-                    # never seen this one, or it's changed since we saw it
-
-                    # -- validate it and get its audio settings -- #
-                    ffmpegmeta.get filename, (meta) =>
-                        if meta
-                            # stash our stream key and mtime
-                            key = [meta.audio.codec,meta.audio.sample_rate,meta.audio.bitrate,(if meta.audio.channels == 2 then "s" else "m")].join("-")
-                            mtime = stats.mtime.getTime()
-
-                            # -- now look for ID3 tag -- #
-
-                            # we do this by streaming the file into our parser,
-                            # and seeing which comes first: an ID3 tag or an
-                            # mp3 header.  Once we hit first audio, we assume
-                            # no tag and move on.  we cache any tag we get to
-                            # deliver at the head of the combined file
-
-                            @checkForID3 filename, (id3) =>
-                                @key_cache[ filename ] = mtime:mtime, stream_key:key, id3:id3
-                                @streamPodcast req, res, filename, stats.size, key, id3
-                        else
-                            @res.writeHead 404, "Content-Type":"text/plain", "Connection":"close"
-                            @res.end("File not found.")
-
-        else
-            # didn't match prefix...
-            next()
-
-    #----------
-
-    checkForID3: (filename,cb) =>
+        next() and return unless match?[1]
+
+        filename = path.join(@options.audio_dir,match[1])
+        fs.stat filename, (err,stats) =>
+            # if there was a stat error or this isn't a file, move on
+            if err || !stats.isFile()
+                next()
+                return true
+
+            # is this a file we already know about? if so, has it not been changed?
+            if @key_cache[ filename ] && @key_cache[filename]?.mtime == stats.mtime.getTime() && @key_cache[filename].stream_key
+                # we're good.  use the cached stream key for preroll, then send our file
+                @streamPodcast req, res, filename, stats.size, @key_cache[filename].stream_key, @key_cache[filename].id3
+            else
+                # never seen this one, or it's changed since we saw it
+
+                # -- validate it and get its audio settings -- #
+                ffmpegmeta.get filename, (meta) =>
+                    if meta
+                        # stash our stream key and mtime
+                        key = [meta.audio.codec,meta.audio.sample_rate,meta.audio.bitrate,(if meta.audio.channels == 2 then "s" else "m")].join("-")
+                        mtime = stats.mtime.getTime()
+
+                        # -- now look for ID3 tag -- #
+                        # we do this by streaming the file into our parser,
+                        # and seeing which comes first: an ID3 tag or an
+                        # mp3 header.  Once we hit first audio, we assume
+                        # no tag and move on.  we cache any tag we get to
+                        # deliver at the head of the combined file
+                        @checkForID3 filename, (id3) =>
+                            @key_cache[ filename ] = mtime:mtime, stream_key:key, id3:id3
+                            @streamPodcast req, res, filename, stats.size, key, id3
+                    else
+                        @res.writeHead 404, "Content-Type":"text/plain", "Connection":"close"
+                        @res.end("File not found.")
+
+
+
+    checkForID3: (filename, cb) =>
         parser = new Parser(true)
-
+
         cb = _u.once(cb) if cb
-
+
         parser.on "id3v2", (buf) =>
             # got an ID3
             cb?(buf)
-
+
         parser.on "header", (h,buf) =>
             # got a frame
             cb?()
-
+
         # we only read the first 4k
         rstream = fs.createReadStream filename, bufferSize:256*1024, start:0, end:4096
         rstream.pipe parser, end:false
-
+
         rstream.on "end", => parser.end()
-
-    #----------
-
-    streamPodcast: (req,res,filename,size,stream_key,id3) ->
-        if req.connection.destroyed
-            return false
-
+
+
+
+    streamPodcast: (req, res, filename, size, stream_key, id3) ->
+        return false if req.connection.destroyed
+
         @loadPreroll stream_key, req, (predata = null) =>
             console.log "url is", req.url
             console.log "request method is ", req.method
@@ -149,7 +139,7 @@
             console.log "fsize is", fsize

             console.log "id3 length is ", id3?.length||0
-
+
             @listeners++

             # Check if range request
@@ -164,23 +154,23 @@
             # Get the requested start and end
             if _u.isString rangeStr
                 rangeVals = rangeStr.match(/bytes ?= ?(\d+)-(\d+)?/)
-
+
                 if rangeVals
                     # Request is for a range
                     rangeRequest = true
-
+
                     # Force into integers
                     requestStart    = rangeVals[1] - 0
                     requestEnd      = rangeVals[2] - 0 or undefined
-
+
                     console.log "requested start, end is", requestStart, requestEnd
-
+
                     rangeStart  = if (requestStart  <= fend) then requestStart else 0
                     rangeEnd    = if (requestEnd    <= fend) then requestEnd   else fend
                     console.log "rangeStart, rangeEnd, rangeRequest is", rangeStart, rangeEnd, rangeRequest

                     length = (rangeEnd - rangeStart) + 1
-
+
             # What is the actual length of content being sent back?
             console.log "actual length is", length

@@ -198,12 +188,12 @@
                 res.writeHead 206, headers
             else
                 res.writeHead 200, headers
-
+
             console.log "response headers are", headers

             # if we have an id3, write that
             res.write id3 if id3
-
+
             # write the preroll
             res.write predata if predata

@@ -213,50 +203,46 @@
                 # now set up our file read as a stream
                 console.log "creating read stream. #{@listeners} active downloads."
                 readStreamOpts = bufferSize: 256*1024
-
+
                 # If this is a range request, only deliver that range of bytes
                 if rangeRequest
                     console.log "Sending byte range #{rangeStart}-#{rangeEnd}"
                     readStreamOpts['start'] = rangeStart
                     readStreamOpts['end']   = rangeEnd
-
+
                 console.log "read stream opts are", readStreamOpts
                 rstream = fs.createReadStream filename, readStreamOpts
                 rstream.pipe res, end:false
-
+
                 rstream.on "end", =>
                     # got to the end of the file.  close our response
                     console.log "(stream end) wrote #{ res.socket?.bytesWritten } bytes. #{@listeners} active downloads."
                     res.end()
-
+
                 req.connection.on "end", =>
                     # connection aborted.  destroy our stream
                     console.log "(connection end) wrote #{ res.socket?.bytesWritten } bytes. #{@listeners} active downloads."
                     rstream?.destroy() if rstream?.readable
-
+
                 req.connection.on "close", =>
                     console.log "(conn close) in close. #{@listeners} active downloads."
                     @listeners--
-
+
                 req.connection.setTimeout 30*1000, =>
                     # handle connection timeout
                     res.end()
                     rstream?.destroy() if rstream?.readable
-
-    #----------
-
-    loadPreroll: (key,req,cb) ->
+
+
+
+    loadPreroll: (key, req, cb) ->
         count = @_counter++
-
+
         # short-circuit if we're missing any options
-        console.log "preroller opts is ", @options.preroll
+        console.log "preroller opts is ", @options.preroll, key
         unless @options.preroll?.server && @options.preroll?.key && @options.preroll?.path
             cb?()
             return true
-
-        # -- make a request to the preroll server -- #
-
-        console.log "making a preroll request"

         # Pass along any query string to Preroller
         query = qs.stringify(req.query)
@@ -266,14 +252,14 @@
             path:       [@options.preroll.path,@options.preroll.key,key,"?"+query].join("/")

         conn = req.connection
-
+
         console.log "firing preroll request", count
         req = http.get opts, (rres) =>
             console.log "got preroll response ", count
             if rres.statusCode == 200
                 # collect preroll and return it so length can be computed
                 pre_data = new Buffer(0)
-
+
                 rres.on "data", (chunk) =>
                     buf = new Buffer(pre_data.length + chunk.length)
                     pre_data.copy(buf,0)


Revert "Don't depend on modalOpened events but on factlinkAdded events for hiding the loading button"

This reverts commit 5ba5108e925cde7082a0e1e837b2d28ae2388c7f.

--- js-library/app/js/jail_iframe/util/create.coffee
+++ js-library/app/js/jail_iframe/util/create.coffee
@@ -10,7 +10,7 @@
 FactlinkJailRoot.createFactFromSelection = ->
   success = ->
     FactlinkJailRoot.createButton.hide()
-    FactlinkJailRoot.off 'factlinkAdded', success
+    FactlinkJailRoot.off 'modalOpened', success

   selInfo = FactlinkJailRoot.getSelectionInfo()

@@ -19,7 +19,7 @@
   siteTitle = selInfo.title
   guided = !!FactlinkConfig.guided

-  FactlinkJailRoot.on 'factlinkAdded', success
+  FactlinkJailRoot.on 'modalOpened', success
   FactlinkJailRoot.factlinkCoreEnvoy 'prepareNewFactlink', text, siteUrl, siteTitle, guided

 # We make this a global function so it can be used for direct adding of facts


fixed NPE

fixed NPE

--- lib/assets/javascripts/stark/view_partial.js.coffee
+++ lib/assets/javascripts/stark/view_partial.js.coffee
@@ -32,7 +32,7 @@
   add_render_hook: (func) ->
     if @parent instanceof Stark.Partial
       @parent.add_render_hook(func)
-    else
+    else if @parent
       @parent.after_render_hooks.unshift(func)

   redraw: ->


Add some more fallback for the Highlights runner

If the file we are passed doesn't exist, we check back to see if it is then created.
We give an error regardless if we don't find the file the first time, but this makes it
a little more fault tolerant.

--- highlights/highlight-filename-from-stdin.coffee
+++ highlights/highlight-filename-from-stdin.coffee
@@ -13,6 +13,16 @@
 mystdout = process.stdout
 process_file = (given_path) ->
   full_path = path.resolve given_path
+  i = 0
+  e = true
+  while e && !fs.existsSync(given_path)
+      i++
+      if i > 100000
+          console.error "Highlights runner: ERROR Giving up looking for the file. Cannot read file #{full_path}"
+          e = false
+  if i > 0
+    console.error "Highlights runner: file #{full_path} does not exist. tried #{i} times."
+
   fs.readFile full_path, 'utf8', (read_err, file_str) ->
     if read_err
       console.error read_err


Document pizza option better

Document pizza option better

--- src/scripts/pizza.coffee
+++ src/scripts/pizza.coffee
@@ -5,8 +5,8 @@
 #   "tumblrbot": "0.1.0"
 #
 # Configuration:
-#   HUBOT_MORE_PIZZA
 #   HUBOT_TUMBLR_API_KEY - A Tumblr OAuth Consumer Key will work fine
+#   HUBOT_MORE_PIZZA - Show pizza whenever anyone mentions it (default: false)
 #
 # Commands:
 #   hubot pizza - Show a pizza gif


IDE: some language improvements

IDE: some language improvements

--- client/ide/views/modals/machinestatemodal.coffee
+++ client/ide/views/modals/machinestatemodal.coffee
@@ -54,7 +54,7 @@
       Running        : 'up and running.'
       Building       : 'is building now.'
       NotInitialized : 'is not initialized.'
-      NotFound       : 'This machine is not exist.' # additional class level state to show a fancy modal for route hacking.
+      NotFound       : 'This machine does not exist.' # additional class level state to show a modal for unknown routes.

     @label     = new KDCustomHTMLView
       tagName  : 'p'


Correct controller syntax

Correct controller syntax

--- client/src/project/states/main/controller.coffee
+++ client/src/project/states/main/controller.coffee
@@ -11,10 +11,10 @@
       board.idOrganization ?= 'myboards'
       return board

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

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

   Project.getUserProject().then (project) ->
     $scope.project = project


Fix broken test caused by parameter change.

--- test/saml2.coffee
+++ test/saml2.coffee
@@ -99,7 +99,7 @@
       idp = new saml2.IdentityProvider 'login_url', 'logout_url', 'other_service_cert'

       async.waterfall [
-        (cb_wf) => sp.create_login_url idp, cb_wf
+        (cb_wf) => sp.create_login_url idp, 'assert_url', cb_wf
       ], (err, login_url) ->
         assert not err?, "Error creating login URL: #{err}"
         parsed_url = url.parse login_url, true


NodeList.prototype.forEach polyfill

NodeList.prototype.forEach polyfill

--- resources/assets/coffee/_classes/polyfills.coffee
+++ resources/assets/coffee/_classes/polyfills.coffee
@@ -21,6 +21,7 @@
     @customEvent()
     @localStorage()
     @mathTrunc()
+    @forEach()

   # For IE9+.
@@ -60,3 +61,12 @@
   mathTrunc: ->
     Math.trunc ?= (x) ->
       x - x % 1
+
+  # For IE.
+  # Reference: https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach
+  forEach: ->
+    if window.NodeList && !NodeList.prototype.forEach
+      NodeList.prototype.forEach = (callback, thisArg) ->
+        thisArg = thisArg || window
+        for value, index in @
+          callback.call(thisArg, value, index, @)


callbackUrl -> callback

callbackUrl -> callback

--- app/routes.coffee
+++ app/routes.coffee
@@ -27,8 +27,8 @@
     response.render 'index'

   storeCallbackUrl: (request, response, next) =>
-    if request.query.callbackUrl?
-      response.cookie 'callbackUrl', request.query.callbackUrl, maxAge: 60 * 60 * 1000
+    if request.query.callback?
+      response.cookie 'callbackUrl', request.query.callback, maxAge: 60 * 60 * 1000
     else
       response.cookie 'callbackUrl', null, maxAge: -1
     next()


update registration url

update registration url

--- js/src/http/RegistrationApi.coffee
+++ js/src/http/RegistrationApi.coffee
@@ -8,7 +8,7 @@
   axios         = require 'axios'
   Configuration = require 'kryptnostic.configuration'

-  registrationUrl = -> Configuration.get('heraclesUrl') + '/registration/developers'
+  registrationUrl = -> Configuration.get('heraclesUrl') + '/registration/user'

   #
   # HTTP calls for registration.


Removes unnecessary if statement

Removes unnecessary if statement

--- src/jquery-inline-footnotes.coffee
+++ src/jquery-inline-footnotes.coffee
@@ -34,9 +34,8 @@
     @closeModal = (event) =>
       if @modal
         if @hoveringFootnote(event)
-          if @closeTimeout
-            clearTimeout(@closeTimeout)
-            @closeTimeout = null
+          clearTimeout(@closeTimeout)
+          @closeTimeout = null
         else
           unless @closeTimeout
             @closeTimeout = setTimeout (=>


fixed possible NPE

fixed possible NPE

--- manager/app/assets/javascripts/stark/view.js.coffee
+++ manager/app/assets/javascripts/stark/view.js.coffee
@@ -196,6 +196,7 @@
       return v.render_html()

   create_partial: (clazz, data) ->
+    data ||= {}
     data.app = @app
     data.state = @state


fixed some issues around syntax checking

--- lib/omnisharp-atom/features/syntax-errors.coffee
+++ lib/omnisharp-atom/features/syntax-errors.coffee
@@ -58,7 +58,10 @@

     drawDecorations: ({QuickFixes}) ->
       #short out if we have no quickfixes
-      return if QuickFixes.length is 0
+      if QuickFixes.length is 0
+        #todo: we have no errors, but we don't know what editor we're on
+        #so we have no reference as to what editor to clear
+        return

       quickFixPath = _.first(_.pluck(QuickFixes, "FileName"));


modify default transpile flags

modify default transpile flags

--- lib/main.coffee
+++ lib/main.coffee
@@ -4,7 +4,7 @@
 {exec} = require 'child_process'
 os = require 'os'

-module.exports = NslCore =
+module.exports =
   config:
     pathToJar:
       title: "Path To JAR"
@@ -16,12 +16,11 @@
       title: "Custom Arguments"
       description: "Specify your preferred arguments for nsL Assembler"
       type: "string"
-      default: "/nopause /nomake"
+      default: "/nomake"
       order: 1
   subscriptions: null

   activate: (state) ->
-    require('atom-package-deps').install(meta.name)

     {CompositeDisposable} = require 'atom'

@@ -30,6 +29,7 @@

     # Register commands
     @subscriptions.add atom.commands.add 'atom-workspace', 'nsl-assembler:save-&-transpile': => @buildScript()
+    require('atom-package-deps').install(meta.name)

   deactivate: ->
     @subscriptions?.dispose()


Remove unused requires

Remove unused requires

Closes #189

--- lib/main.coffee
+++ lib/main.coffee
@@ -1,6 +1,4 @@
 url = require 'url'
-fs = require 'fs-plus'
-{$} = require 'atom-space-pen-views'

 MarkdownPreviewView = null # Defer until used
 renderer = null # Defer until used


Main: Refactor runAllAbove

Main: Refactor runAllAbove

--- lib/main.coffee
+++ lib/main.coffee
@@ -253,11 +253,13 @@

     runAllAbove: ->
-        codeBlock = @findCodeBlock(true)
-        unless codeBlock?
-            return
-
-        [code, row] = codeBlock
+        cursor = @editor.getLastCursor()
+        row = cursor.getBufferRow()
+        if row > 0
+            for i in [0 .. row - 1] when @blank(row)
+                row -= 1
+        code = @getRows(0, row)
+
         if code? and row?
             @createResultBubble code, row

@@ -372,7 +374,7 @@
                     @watchSidebar.show()
         @watchKernelPicker.toggle()

-    findCodeBlock: (runAllAbove = false) ->
+    findCodeBlock: ->
         buffer = @editor.getBuffer()
         selectedText = @editor.getSelectedText()

@@ -390,12 +392,6 @@
         row = cursor.getBufferRow()
         console.log 'findCodeBlock:', row

-        if runAllAbove
-            if row > 0
-                for i in [0 .. row - 1] when @blank(row)
-                    row -= 1
-            return [@getRows(0, row), row]
-
         indentLevel = cursor.getIndentLevel()

         foldable = @editor.isFoldableAtBufferRow(row)