Fix links to namespaces in util

Fix links to namespaces in util

--- admin/static/coffee/util.coffee
+++ admin/static/coffee/util.coffee
@@ -54,7 +54,7 @@
 Handlebars.registerHelper 'links_to_namespaces', (namespaces) ->
     out = ""
     for i in [0...namespaces.length]
-        out += '
'+namespaces[i].name+'
'
+        out += '
'+namespaces[i].name+'
'
     return out

 #Returns a list of links to namespaces on one line
@@ -62,9 +62,9 @@
     out = ""
     for i in [0...namespaces.length]
         if tab?
-            out += ''+namespaces[i].name+''
-        else
-            out += ''+namespaces[i].name+''
+            out += ''+namespaces[i].name+''
+        else
+            out += ''+namespaces[i].name+''
         out += ", " if i isnt namespaces.length-1
     return new Handlebars.SafeString(out)

@@ -80,7 +80,7 @@
 Handlebars.registerHelper 'links_to_masters_and_namespaces', (machines) ->
     out = ""
     for i in [0...machines.length]
-        out += '
'+machines[i].namespace_name+' ('+machines[i].machine_name+')
'
+        out += '
'+machines[i].namespace_name+' ('+machines[i].machine_name+')
'
     return out

@@ -89,7 +89,7 @@
 Handlebars.registerHelper 'links_to_replicas_and_namespaces', (machines) ->
     out = ""
     for i in [0...machines.length]
-        out += '
'+machines[i].get('namespace_name')+' ('+machines[i].get('machine_name')+')
'
+        out += '
'+machines[i].get('namespace_name')+' ('+machines[i].get('machine_name')+')
'
         out += '

Shard: '+machines[i].get('shard')+'
'
         out += '
Blueprint: '+machines[i].get('blueprint')+'
'
         out += '
Directory: '+machines[i].get('directory')+'

'


Fix MultiSelectListInteractionHandlers specs

--- spec/components/multiselect-list-interaction-handler-spec.coffee
+++ spec/components/multiselect-list-interaction-handler-spec.coffee
@@ -15,6 +15,8 @@

     data = [@item, @itemFocus, @itemAfterFocus, @itemKeyboardFocus, @itemAfterKeyboardFocus]

+    @onFocusItem = jasmine.createSpy('onFocusItem')
+    @onSetCursorPosition = jasmine.createSpy('onSetCursorPosition')
     @dataSource =
       selection:
         toggle: jasmine.createSpy('toggle')
@@ -28,15 +30,18 @@
         _.findIndex data, (item) -> item.id is id
       count: -> data.length

+    @props =
+      dataSource: @dataSource
+      keyboardCursorId: 'keyboard-focus'
+      focusedId: 'focus'
+      onFocusItem: @onFocusItem
+      onSetCursorPosition: @onSetCursorPosition
+
     @collection = 'threads'
-    @handler = new MultiselectListInteractionHandler(@dataSource, @collection)
     @isRootSheet = true
+    @handler = new MultiselectListInteractionHandler(@props)

     spyOn(WorkspaceStore, 'topSheet').andCallFake => {root: @isRootSheet}
-    spyOn(FocusedContentStore, 'keyboardCursorId').andCallFake -> 'keyboard-focus'
-    spyOn(FocusedContentStore, 'focusedId').andCallFake -> 'focus'
-    spyOn(Actions, 'setFocus')
-    spyOn(Actions, 'setCursorPosition')

   it "should never show focus", ->
     expect(@handler.shouldShowFocus()).toEqual(false)
@@ -44,10 +49,13 @@
   it "should always show the keyboard cursor", ->
     expect(@handler.shouldShowKeyboardCursor()).toEqual(true)

+  it "should always show checkmarks", ->
+    expect(@handler.shouldShowCheckmarks()).toEqual(true)
+
   describe "onClick", ->
     it "should focus list items", ->
       @handler.onClick(@item)
-      expect(Actions.setFocus).toHaveBeenCalledWith({collection: @collection, item: @item})
+      expect(@onFocusItem).toHaveBeenCalledWith(@item)

   describe "onMetaClick", ->
     it "shoud toggle selection", ->
@@ -56,7 +64,7 @@

     it "should focus the keyboard on the clicked item", ->
       @handler.onMetaClick(@item)
-      expect(Actions.setCursorPosition).toHaveBeenCalledWith({collection: @collection, item: @item})
+      expect(@onSetCursorPosition).toHaveBeenCalledWith(@item)

   describe "onShiftClick", ->
     it "should expand selection", ->
@@ -65,12 +73,12 @@

     it "should focus the keyboard on the clicked item", ->
       @handler.onShiftClick(@item)
-      expect(Actions.setCursorPosition).toHaveBeenCalledWith({collection: @collection, item: @item})
+      expect(@onSetCursorPosition).toHaveBeenCalledWith(@item)

   describe "onEnter", ->
     it "should focus the item with the current keyboard selection", ->
       @handler.onEnter()
-      expect(Actions.setFocus).toHaveBeenCalledWith({collection: @collection, item: @itemKeyboardFocus})
+      expect(@onFocusItem).toHaveBeenCalledWith(@itemKeyboardFocus)

   describe "onSelect (x key on keyboard)", ->
     describe "on the root view", ->
@@ -92,7 +100,7 @@

       it "should shift the keyboard item", ->
         @handler.onShift(1, {})
-        expect(Actions.setCursorPosition).toHaveBeenCalledWith({collection: @collection, item: @itemAfterKeyboardFocus})
+        expect(@onSetCursorPosition).toHaveBeenCalledWith(@itemAfterKeyboardFocus)

       it "should walk selection if the select option is passed", ->
         @handler.onShift(1, select: true)
@@ -104,4 +112,4 @@

       it "should shift the focused item", ->
         @handler.onShift(1, {})
-        expect(Actions.setFocus).toHaveBeenCalledWith({collection: @collection, item: @itemAfterFocus})
+        expect(@onFocusItem).toHaveBeenCalledWith(@itemAfterFocus)


Hide likes sumamry view if there is no likes

--- client/Social/Activity/views/likesummaryview.coffee
+++ client/Social/Activity/views/likesummaryview.coffee
@@ -40,6 +40,9 @@

     super

+    if @getData().interactions.like.actorsCount is 0
+    then @setClass 'hidden'
+
     names  = []
     strong = (x) -> "<strong>#{x}</strong>"


Renamed element

Renamed element

--- client/account/lib/views/accounteditusername.coffee
+++ client/account/lib/views/accounteditusername.coffee
@@ -332,9 +332,9 @@

     @verifyEmail = new KDCustomHTMLView opts

-    header = @emailForm.fields.passwordHeader.getElement()
-
-    header.parentElement.insertBefore @verifyEmail.getElement(), header
+    sectionHeader = @emailForm.fields.passwordHeader.getElement()
+
+    sectionHeader.parentElement.insertBefore @verifyEmail.getElement(), sectionHeader

   getAvatarOptions: ->
     tagName       : 'figure'


fixed setup cloud resources task by fixing ag-resource-loader-raml package name

--- tasks/fresh/steroids-setup-cloud-resources.coffee
+++ tasks/fresh/steroids-setup-cloud-resources.coffee
@@ -1,5 +1,5 @@
 module.exports = (grunt) ->
-  ramlLoader = require 'ag-resource-loader-raml-during-ezkus-holiday'
+  ramlLoader = require 'ag-resource-loader-raml'

   grunt.loadNpmTasks "grunt-extend-config"


shortcuts: fix full screen shortcut

shortcuts: fix full screen shortcut

--- client/ide/views/shortcutsview/shortcutsview.coffee
+++ client/ide/views/shortcutsview/shortcutsview.coffee
@@ -48,7 +48,7 @@
       'Collapse sidebar'       : 'Ctrl-Alt-C'
       'Expand sidebar'         : 'Ctrl-Alt-E'
       'Toggle sidebar'         : 'Ctrl-Alt-K'
-      'Fullscreen'             : 'Meta-Enter'
+      'Fullscreen'             : 'Meta-Shift-Enter'
       'Close tab'              : 'Ctrl-Alt-W'
       'Go to left tab'         : 'Ctrl-Alt-['
       'Go to right tab'        : 'Ctrl-Alt-]'


grammar fix

grammar fix

--- client/stacks/lib/views/stacks/variablesview.coffee
+++ client/stacks/lib/views/stacks/variablesview.coffee
@@ -153,7 +153,7 @@
       credential.fetchData (err, data) =>

         if err
-          @pinWarning "You don't have access for custom variables"
+          @pinWarning "You don't have access to custom variables"
           return kd.warn err

         @_activeCredential = credential


Added a couple of todos

Added a couple of todos

I have a lot of oauth2 stuff to figure out...

--- src/server/routes/post/login.coffee
+++ src/server/routes/post/login.coffee
@@ -5,6 +5,12 @@
 	path: "/login"
 	auth: false
 	fn: (req, res, next) ->
+		### TODO
+		Have to protect login route with client password strategy so that
+		only ton-hub can use the login route. This will enforce the usage of
+		bearer tokens on api routes. After that, the local strategy will
+		authenticate the user credentials, and oauth2 redirection stuff can happen.
+		###
 		auth = passport.authenticate "local", (err, user, info) ->
 			if err then return next err
 			else if !user
@@ -13,6 +19,13 @@
 						info.message
 				return res.status(401).json json
 			else req.logIn user, (err) ->
+				### TODO
+				Instead of sending status 200, I think I'll need to send a 3xx status
+				to redirect the browser to /api/authorize. Have to preserve the
+				parameters (?foo=bar&fizz=buzz) from the external app during that
+				redirection phase. If there weren't any parameters, then it's a login
+				for ton-hub itself.
+				###
 				if err then return next err
 				else return res.status(200).send()
 		return auth req, res, next


webapp: deleting touch file project store code

--- src/smc-webapp/project_store.coffee
+++ src/smc-webapp/project_store.coffee
@@ -943,24 +943,6 @@
                 if not err
                     @open_file(path: lib.start)

-    touch_file: (opts) =>
-        opts = defaults opts,
-            path : '.'
-            dest : required
-
-        id = misc.uuid()
-        @set_activity(id:id, status: "Touching #{opts.dest} ...")
-
-        webapp_client.exec
-            project_id       : @project_id
-            command          : 'touch'
-            args             : [opts.dest]
-            timeout          : 30
-            network_timeout  : 120
-            err_on_exit      : true
-            path             : opts.path
-            cb               : @_finish_exec(id)
-
     copy_paths: (opts) =>
         opts = defaults opts,
             src           : required     # Should be an array of source paths


webapp: dealing with file listing problems -- issue #1408

--- src/smc-webapp/project_store.coffee
+++ src/smc-webapp/project_store.coffee
@@ -695,7 +695,10 @@
         # anything about files (highly unlikely).  Unfortunately (for this), our
         # directory listings are stored as (immutable) lists, so we have to make
         # a map out of them.
-        store.directory_listings?.get(store.current_path)?.map (x) ->
+        listing = store.directory_listings?.get(store.current_path)
+        if typeof(listing) == 'string'    # must be an error
+            return name  # simple fallback
+        listing?.map (x) ->
             files_in_dir[x.get('name')] = true
             return
         # This loop will keep trying new names until one isn't in the directory
@@ -1204,9 +1207,12 @@
                     @get_store().wait
                         until   : (s) =>
                             listing = s.directory_listings.get(parent_path)
-                            return listing?.find (val) => val.get('name') == last
+                            if typeof(listing) == 'string'   # must be an error
+                                return {err: listing}
+                            return listing?.find((val) => val.get('name') == last)
                         timeout : 30
                         cb      : (err, item) =>
+                            err = err ? item.err
                             if err
                                 alert_message(type:'error', message:"There was an error related to opening the link: #{err}")
                                 @open_directory(parent_path)


remove debug prints

remove debug prints

--- src/textorum/relaxng/objects.coffee
+++ src/textorum/relaxng/objects.coffee
@@ -34,10 +34,7 @@
       when 'notAllowed' then new NotAllowed()
       when 'empty' then new Empty()
       when 'text' then new Text()
-      when 'data'
-        if _getAttr(node, "type") is "NMTOKEN"
-          console.log "data note", node, children
-        new Data _getAttr(node, "datatypeLibrary"), _getAttr(node, "type"), children
+      when 'data' then new Data _getAttr(node, "datatypeLibrary"), _getAttr(node, "type"), children
       when 'value' then new Value _getAttr(node, "dataTypeLibrary"), _getAttr(node, "type"), _getAttr(node, "ns"), children[0]
       when 'list' then new List children[0]
       when 'attribute' then new Attribute children[0], children[1]
@@ -200,9 +197,6 @@
   class Attribute extends Pattern
     constructor: (@nameClass, pattern, @defaultValue = null) ->
       @pattern = getPattern pattern
-      if @nameClass.name is "lang"
-        console.log "defining attribute", @nameClass, @pattern
-        console.log @pattern.toString()
     toString: =>
       "attribute #{@nameClass} { #{@pattern} }"


:memo: Mark ThemeManager class public

:memo: Mark ThemeManager class public

--- src/theme-manager.coffee
+++ src/theme-manager.coffee
@@ -8,9 +8,9 @@
 AtomPackage = require './atom-package'
 File = require './file'

-# Private: Handles discovering and loading available themes.
+# Public: Handles loading and activating available themes.
 #
-# Themes are a subset of packages
+# A ThemeManager instance is always available under the `atom.themes` global.
 module.exports =
 class ThemeManager
   Emitter.includeInto(this)
@@ -19,7 +19,6 @@
     @lessCache = null
     @packageManager.registerPackageActivator(this, ['theme'])

-  # Internal-only:
   getAvailableNames: ->
     # TODO: Maybe should change to list all the available themes out there?
     @getLoadedNames()
@@ -27,19 +26,15 @@
   getLoadedNames: ->
     theme.name for theme in @getLoadedThemes()

-  # Internal-only:
   getActiveNames: ->
     theme.name for theme in @getActiveThemes()

-  # Internal-only:
   getActiveThemes: ->
     pack for pack in @packageManager.getActivePackages() when pack.isTheme()

-  # Internal-only:
   getLoadedThemes: ->
     pack for pack in @packageManager.getLoadedPackages() when pack.isTheme()

-  # Internal-only: adhere to the PackageActivator interface
   activatePackages: (themePackages) -> @activateThemes()

   # Private: Get the enabled theme names from the config.
@@ -53,7 +48,6 @@
     # the first/top theme to override later themes in the stack.
     themeNames.reverse()

-  # Internal-only:
   activateThemes: ->
     # atom.config.observe runs the callback once, then on subsequent changes.
     atom.config.observe 'core.themes', =>
@@ -69,13 +63,11 @@

       @emit('reloaded')

-  # Internal-only:
   deactivateThemes: ->
     @unwatchUserStylesheet()
     @packageManager.deactivatePackage(pack.name) for pack in @getActiveThemes()
     null

-  # Internal-only:
   refreshLessCache: ->
     @lessCache?.setImportPaths(@getImportPaths())

@@ -85,7 +77,6 @@
   setEnabledThemes: (enabledThemeNames) ->
     atom.config.set('core.themes', enabledThemeNames)

-  # Public:
   getImportPaths: ->
     activeThemes = @getActiveThemes()
     if activeThemes.length > 0
@@ -98,7 +89,7 @@

     themePath for themePath in themePaths when fs.isDirectorySync(themePath)

-  # Public:
+  # Public: Returns the {String} path to the user's stylesheet under ~/.atom
   getUserStylesheetPath: ->
     stylesheetPath = fs.resolve(path.join(@configDirPath, 'user'), ['css', 'less'])
     if fs.isFileSync(stylesheetPath)
@@ -106,13 +97,11 @@
     else
       path.join(@configDirPath, 'user.less')

-  #Private:
   unwatchUserStylesheet: ->
     @userStylesheetFile?.off()
     @userStylesheetFile = null
     @removeStylesheet(@userStylesheetPath) if @userStylesheetPath?

-  # Private:
   loadUserStylesheet: ->
     @unwatchUserStylesheet()
     userStylesheetPath = @getUserStylesheetPath()
@@ -125,34 +114,32 @@
     userStylesheetContents = @loadStylesheet(userStylesheetPath)
     @applyStylesheet(userStylesheetPath, userStylesheetContents, 'userTheme')

-  # Internal-only:
   loadBaseStylesheets: ->
     @requireStylesheet('bootstrap/less/bootstrap')
     @reloadBaseStylesheets()

-  # Internal-only:
   reloadBaseStylesheets: ->
     @requireStylesheet('../static/atom')
     if nativeStylesheetPath = fs.resolveOnLoadPath(process.platform, ['css', 'less'])
       @requireStylesheet(nativeStylesheetPath)

-  # Internal-only:
   stylesheetElementForId: (id, htmlElement=$('html')) ->
     htmlElement.find("""head style[id="#{id}"]""")

-  # Internal-only:
   resolveStylesheet: (stylesheetPath) ->
     if path.extname(stylesheetPath).length > 0
       fs.resolveOnLoadPath(stylesheetPath)
     else
       fs.resolveOnLoadPath(stylesheetPath, ['css', 'less'])

-  # Public: resolves and applies the stylesheet specified by the path.
+  # Public: Resolve and apply the stylesheet specified by the path.
   #
-  # * stylesheetPath: String. Can be an absolute path or the name of a CSS or
-  #   LESS file in the stylesheets path.
+  # This supports both CSS and LESS stylsheets.
   #
-  # Returns the absolute path to the stylesheet
+  # * stylesheetPath: A {String} path to the stylesheet that can be an absolute
+  #   path or a relative path that will be resolved against the load path.
+  #
+  # Returns the absolute path to the required stylesheet.
   requireStylesheet: (stylesheetPath, ttype = 'bundled', htmlElement) ->
     if fullPath = @resolveStylesheet(stylesheetPath)
       content = @loadStylesheet(fullPath)
@@ -162,14 +149,12 @@

     fullPath

-  # Internal-only:
   loadStylesheet: (stylesheetPath) ->
     if path.extname(stylesheetPath) is '.less'
       @loadLessStylesheet(stylesheetPath)
     else
       fs.readFileSync(stylesheetPath, 'utf8')

-  # Internal-only:
   loadLessStylesheet: (lessStylesheetPath) ->
     unless @lessCache?
       LessCompileCache = require './less-compile-cache'
@@ -184,16 +169,13 @@
         #{e.message}
       """

-  # Internal-only:
   stringToId: (string) ->
     string.replace(/\\/g, '/')

-  # Internal-only:
   removeStylesheet: (stylesheetPath) ->
     fullPath = @resolveStylesheet(stylesheetPath) ? stylesheetPath
     @stylesheetElementForId(@stringToId(fullPath)).remove()

-  # Internal-only:
   applyStylesheet: (path, text, ttype = 'bundled', htmlElement=$('html')) ->
     styleElement = @stylesheetElementForId(@stringToId(path), htmlElement)
     if styleElement.length


spelling: stylesheet

spelling: stylesheet

--- src/theme-manager.coffee
+++ src/theme-manager.coffee
@@ -127,7 +127,7 @@

   # Resolve and apply the stylesheet specified by the path.
   #
-  # This supports both CSS and Less stylsheets.
+  # This supports both CSS and Less stylesheets.
   #
   # * `stylesheetPath` A {String} path to the stylesheet that can be an absolute
   #   path or a relative path that will be resolved against the load path.
@@ -142,8 +142,8 @@
       throw new Error("Could not find a file at path '#{stylesheetPath}'")

   unwatchUserStylesheet: ->
-    @userStylsheetSubscriptions?.dispose()
-    @userStylsheetSubscriptions = null
+    @userStylesheetSubscriptions?.dispose()
+    @userStylesheetSubscriptions = null
     @userStylesheetFile = null
     @userStyleSheetDisposable?.dispose()
     @userStyleSheetDisposable = null
@@ -156,11 +156,11 @@

     try
       @userStylesheetFile = new File(userStylesheetPath)
-      @userStylsheetSubscriptions = new CompositeDisposable()
+      @userStylesheetSubscriptions = new CompositeDisposable()
       reloadStylesheet = => @loadUserStylesheet()
-      @userStylsheetSubscriptions.add(@userStylesheetFile.onDidChange(reloadStylesheet))
-      @userStylsheetSubscriptions.add(@userStylesheetFile.onDidRename(reloadStylesheet))
-      @userStylsheetSubscriptions.add(@userStylesheetFile.onDidDelete(reloadStylesheet))
+      @userStylesheetSubscriptions.add(@userStylesheetFile.onDidChange(reloadStylesheet))
+      @userStylesheetSubscriptions.add(@userStylesheetFile.onDidRename(reloadStylesheet))
+      @userStylesheetSubscriptions.add(@userStylesheetFile.onDidDelete(reloadStylesheet))
     catch error
       message = """
         Unable to watch path: `#{path.basename(userStylesheetPath)}`. Make sure


RangeValidator :: Fix the problem with min and max functions by storing them separately in minFunc and maxFunc

--- src/validators.js.coffee
+++ src/validators.js.coffee
@@ -121,6 +121,8 @@
   constructor: ( attr, opts ) ->
     super attr, opts
     @attribute = attr
+    @options.minFunc = @options.min if @options.min? and typeof @options.min is "function"
+    @options.maxFunc = @options.max if @options.max? and typeof @options.max is "function"
     @options.message ?= I18n.t("errors.messages.not_in_range")

   run: ( obj ) ->
@@ -128,18 +130,11 @@
     # ignore blank values and when both max and min options are missing
     return unless value? and ( value + "" ).length > 0 and (@options.max? or @options.min?)

-    # call min and max in context of object if they are functions
-    #
-    # NOTE: doesn't feel right thing to do for me, because it mutates
-    # @options.min (and .max), which means that this function will be
-    # executed only once and if it actually depends on some state of
-    # the object, then we got ourselves a problem. Looks like should be
-    # a local variable here. If it is not the case, then why it is called
-    # in context of target object?
-    if @options.min? and typeof @options.min is "function"
-      @options.min = @options.min.call( obj )
-    if @options.max? and typeof @options.max is "function"
-      @options.max = @options.max.call( obj )
+    # Use the initially provided functions for min and max to update their values
+    if @options.minFunc?
+      @options.min = @options.minFunc.call( obj )
+    if @options.maxFunc?
+      @options.max = @options.maxFunc.call( obj )

     # checks if actual value of attribute is between min and max,
     # accounting for possible absence of one of them


KernelManager: Notify when a kernel cannot restart

--- lib/kernel-manager.coffee
+++ lib/kernel-manager.coffee
@@ -51,6 +51,7 @@
             return

         console.log 'KernelManager: restartRunningKernelFor: ignored', kernel
+        atom.notifications.addWarning 'Cannot restart this kernel'
         onRestarted?(kernel)


исправлен баг с определением default и defines в областях видимости

--- lib/nbuild/builder.coffee
+++ lib/nbuild/builder.coffee
@@ -316,10 +316,10 @@
   ###

   _batch: (name, options) ->
-    @definesStack.push(@defines)
-    @defaultsStack.push(@defaults)
+    @definesStack.push(_.clone(@defines))
+    @defaultsStack.push(_.clone(@defaults))
     for key, val of options when typeof val is 'object'
-      @execConfig(key, val)
+      @execConfig(key, val)
     delete @defines
     @defines = @definesStack.pop()
     delete @defaults


Update package-loader.coffee

Update package-loader.coffee

--- lib/package-loader.coffee
+++ lib/package-loader.coffee
@@ -5,7 +5,7 @@
             notLoaded.push(pack)
     notLoaded

-    # notloaded = packages.map (p): -> if !atom.packages.isPackageLoaded(p) then p
+    # notloaded = packages.map (p): -> p if !atom.packages.isPackageLoaded(p)

 checkForPackageDependencies = (packages) ->
     getNotLoadedPackages(packages)


Greatly simplify buildRegexLookups

Greatly simplify buildRegexLookups

--- lib/show-todo-view.coffee
+++ lib/show-todo-view.coffee
@@ -71,22 +71,12 @@

     @loading = false

-  # Get the regexes to look for from settings
-  # @FIXME: Add proper comments
-  # @param settingsRegexes {array} - An array of regexes from settings.
+  # Get regexes to look for from settings
   buildRegexLookups: (settingsRegexes) ->
-    regexes = [] #[{title, regex, results}]
-
-    for regex, i in settingsRegexes
-      match = {
-        'title': regex
-        'regex': settingsRegexes[i+1]
-        'results': []
-      }
-      _i = _i+1    #_ overrides the one that coffeescript actually creates. Seems hackish. FIXME: maybe just use modulus
-      regexes.push(match)
-
-    return regexes
+    for regex, i in settingsRegexes by 2
+      'title': regex
+      'regex': settingsRegexes[i+1]
+      'results': []

   # Pass in string and returns a proper RegExp object
   makeRegexObj: (regexStr) ->


Environments: Create VMs with a stack id.

--- client/Main/VirtualizationController.coffee
+++ client/Main/VirtualizationController.coffee
@@ -289,7 +289,7 @@
   hasDefaultVM:(callback)->
     KD.remote.api.JVM.fetchDefaultVm callback

-  createDefaultVM: (callback)->
+  createDefaultVM: (stackId, callback)->
     @hasDefaultVM (err, state)->
       return warn 'Default VM already exists.'  if state

@@ -303,7 +303,7 @@
         duration      : 120000

       { JVM } = KD.remote.api
-      JVM.createFreeVm (err, vm)->
+      JVM.createFreeVm stackId, (err, vm)->
         unless err
           vmController = KD.getSingleton('vmController')
           vmController.fetchDefaultVmName (defaultVmName)->
@@ -314,10 +314,10 @@
           notify?.destroy()
           KD.showError err

-  createNewVM: (callback)->
+  createNewVM: (stackId, callback)->
     @hasDefaultVM (err, state)=>
       create = @bound if state then "createPaidVM" else "createDefaultVM"
-      create callback
+      create stackId, callback

   showVMDetails: (vm)->
     vmName = vm.hostnameAlias
@@ -348,7 +348,7 @@
           callback  : =>
             modal.destroy()

-  createPaidVM: ->
+  createPaidVM: (stackId) ->
     @payment.fetchActiveSubscription tags: "vm", (err, subscription) =>
       if err
         if err.code is "no subscription"
@@ -360,7 +360,7 @@

       KD.remote.api.JPaymentPack.one tags: "vm", (err, pack) =>
         return KD.showError err  if err
-        @provisionVm {subscription, productData: {pack}}, (err, nonce) =>
+        @provisionVm {stackId, subscription, productData: {pack}}, (err, nonce) =>
           return  unless err
           if err.message is "quota exceeded"
             if KD.getGroup().slug is "koding"
@@ -382,7 +382,7 @@
     upgradeForm.on "Cancel", modal.bound "destroy"
     return modal

-  provisionVm: ({ subscription, paymentMethod, productData }, callback) ->
+  provisionVm: ({ subscription, stackId, paymentMethod, productData }, callback) ->
     { JVM } = KD.remote.api

     { plan, pack } = productData
@@ -394,14 +394,14 @@
       plan.subscribe paymentMethod.paymentMethodId, (err, subscription) =>
         return  if KD.showError err

-        @provisionVm { subscription, productData }, callback
+        @provisionVm { subscription, productData, stackId }, callback

       return

     payment.debitSubscription subscription, pack, (err, nonce) =>
       return callback err  if err

-      JVM.createVmByNonce nonce, (err, vm) =>
+      JVM.createVmByNonce nonce, stackId, (err, vm) =>
         return  if KD.showError err

         @emit 'VMListChanged'


Activity: minor cleanup WIP

Activity: minor cleanup WIP

--- client/Social/Activity/AppController.coffee
+++ client/Social/Activity/AppController.coffee
@@ -1,21 +1,33 @@
 class ActivityAppController extends AppController

   KD.registerAppClass this,
-    name         : "Activity"
+    name         : 'Activity'
     routes       :
-      "/:name?/Activity/:slug?" : ({params:{name, slug}, query})->
+      '/:name?/Activity/:slug?' : ({params:{name, slug, id}, query})->
         {router, appManager} = KD.singletons

+        # log 'Default', name, slug, id, query
         unless slug
         then router.openSection 'Activity', name, query
         else router.createContentDisplayHandler('Activity') arguments...

-    searchRoute  : "/Activity?q=:text:"
+      # '/:name?/Activity/Chat/:id?' : ({params:{name, slug, id}, query})->
+      #   {router, appManager} = KD.singletons
+
+      #   log 'Chat', name, slug, id, query
+
+      # '/:name?/Activity/Pinned/:id?' : ({params:{name, slug, id}, query})->
+      #   {router, appManager} = KD.singletons
+
+      #   log 'Pinned', name, slug, id, query
+
+
+    searchRoute  : '/Activity?q=:text:'
     hiddenHandle : yes

   constructor: (options = {}) ->

-    options.view    = new ActivityAppView testPath : "activity-feed"
+    options.view    = new ActivityAppView testPath : 'activity-feed'
     options.appInfo = name : 'Activity'

     super options
@@ -52,7 +64,7 @@
     contentDisplay = new ContentDisplayStatusUpdate
       title : "Status Update"
       type  : "status"
-    ,activity
+    , activity

     KD.singleton('display').emit "ContentDisplayWantsToBeShown", contentDisplay
     @utils.defer -> callback contentDisplay


Activity: removed more unused parts

Activity: removed more unused parts

--- client/Social/Activity/AppController.coffee
+++ client/Social/Activity/AppController.coffee
@@ -17,21 +17,6 @@
   {dash} = Bongo

   USEDFEEDS = []
-
-  activityTypes = [
-    'Everything'
-  ]
-
-  newActivitiesArrivedTypes = [
-    'CStatusActivity'
-    'CCodeSnipActivity'
-    'CFollowerBucketActivity'
-    'CNewMemberBucketActivity'
-    'CDiscussionActivity'
-    'CTutorialActivity'
-    'CInstallerBucketActivity'
-    'CBlogPostActivity'
-  ]

   @clearQuotes = clearQuotes = (activities)->
     return activities = for own activityId, activity of activities
@@ -78,8 +63,6 @@
     @reachedEndOfActivities = no
     @listController.resetList()
     @listController.removeAllItems()
-
-  fetchCurrentGroup:(callback)-> callback @currentGroupSlug

   search:(text)->
     text = Encoder.XSSEncode text
@@ -183,11 +166,6 @@

     fetch = =>

-      #since it is not working, disabled it,
-      #to-do add isExempt control.
-      #@isExempt (exempt)=>
-      #if exempt or @getFilter() isnt activityTypes
-
       groupObj     = groupsController.getCurrentGroup()
       mydate       = new Date((new Date()).setSeconds(0) + 60000).getTime()
       options      =
@@ -355,16 +333,6 @@
     return unless teasers.first
     @setLastTimestamps new Date(teasers.last.meta.createdAt).getTime(), new Date(teasers.first.meta.createdAt).getTime()

-  sanitizeCache:(cache, callback)->
-    activities = clearQuotes cache.activities
-
-    KD.remote.reviveFromSnapshots activities, (err, instances)->
-      for activity,i in activities
-        cache.activities[activity._id] or= {}
-        cache.activities[activity._id].teaser = instances[i]
-
-      callback null, cache
-
   createContentDisplay:(activity, callback=->)->
     contentDisplay = @createStatusUpdateContentDisplay activity
     @utils.defer -> callback contentDisplay
@@ -414,8 +382,6 @@
         @profileLastTo = (new Date(lastOne)).getTime()
       callback err, activities

-  unhideNewItems: ->
-    @listController?.activityHeader.updateShowNewItemsLink yes

   getNewItemsCount: (callback) ->
     callback? @listController?.activityHeader?.getNewItemsCount() or 0
@@ -443,9 +409,5 @@
     @status.disconnect()
     @refresh()

-  feederBridge : (options, callback)->
-
-    KD.getSingleton("appManager").tell 'Feeder', 'createContentFeedController', options, callback
-
   resetProfileLastTo : ->
     @profileLastTo = null


Minor fix.

Minor fix.

--- src/api/session.coffee
+++ src/api/session.coffee
@@ -6,7 +6,7 @@
 exports.signInWithPassword = ->
   {email, password} = @getParams {
     email: { type: 'string' }
-    password: { type: 'object' }
+    password: { type: 'string' }
   }

   @throw 'ALREADY_AUTHENTICATED' if @session.has 'user_id'


Add success/failure messages for better user info when there are issues.

--- src/application.coffee
+++ src/application.coffee
@@ -27,6 +27,9 @@
 	stopAppSuccess:
 		eventName: 'Application stop'
 		humanName: 'Killed application'
+	stopAppError:
+		eventName: 'Application stop error'
+		humanName: 'Killed application'

 	downloadApp:
 		eventName: 'Application download'
@@ -34,10 +37,19 @@
 	downloadAppSuccess:
 		eventName: 'Application downloaded'
 		humanName: 'Downloaded application'
+	downloadAppError:
+		eventName: 'Application download error'
+		humanName: 'Failed to download application'

 	installApp:
 		eventName: 'Application install'
 		humanName: 'Installing application'
+	installAppSuccess:
+		eventName: 'Application installed'
+		humanName: 'Installed application'
+	installAppError:
+		eventName: 'Application install error'
+		humanName: 'Failed to install application'

 	startApp:
 		eventName: 'Application start'
@@ -91,6 +103,9 @@
 	.tap ->
 		logSystemEvent(logTypes.stopAppSuccess, app)
 		knex('app').where('id', app.id).delete()
+	.catch (err) ->
+		logSystemEvent(logTypes.stopAppError, app, err)
+		throw err

 isValidPort = (port) ->
 	maybePort = parseInt(port, 10)
@@ -107,6 +122,9 @@
 			logSystemEvent(logTypes.downloadAppSuccess, app)
 			updateDeviceState(download_progress: null)
 			docker.getImage(app.imageId).inspectAsync()
+		.catch (err) ->
+			logSystemEvent(logTypes.downloadAppError, app, err)
+			throw err

 exports.start = start = (app) ->
 	Promise.try ->
@@ -154,6 +172,11 @@
 					Env: _.map env, (v, k) -> k + '=' + v
 					ExposedPorts: ports
 				)
+				.tap ->
+					logSystemEvent(logTypes.installAppSuccess, app)
+				.catch (err) ->
+					logSystemEvent(logTypes.installAppError, app, err)
+					throw err
 		.tap (container) ->
 			# Update the app info the moment we create the container, even if then starting the container fails.  This
 			# stops issues with constantly creating new containers for an image that fails to start.


ProviderInterface.test: remove created credentials afterTests

--- workers/social/lib/social/models/computeproviders/providerinterface.test.coffee
+++ workers/social/lib/social/models/computeproviders/providerinterface.test.coffee
@@ -1,9 +1,12 @@
 ProviderInterface = require './providerinterface'
 CredentialStore   = require './credentialstore'

-{ expect
+{ async
+  expect
   checkBongoConnectivity }         = require '../../../../testhelper'
 { withConvertedUserAndCredential } = require '../../../../testhelper/models/computeproviders/credentialhelper'
+
+CREDENTIALS = []

 # this function will be called once before running any test
 beforeTests = -> before (done) ->
@@ -19,6 +22,9 @@
     it 'it should be able fetch credential data ', (done) ->

       withConvertedUserAndCredential ({ client, credential }) ->
+
+        CREDENTIALS.push [client, credential.identifier]
+
         ProviderInterface.fetchCredentialData client, credential, (err, credData) ->
           expect(err).to.not.exist
           expect(credData).to.be.an 'object'
@@ -27,7 +33,22 @@
           done()

+afterTests = ->
+
+  after (done) ->
+
+    queue = [ ]
+
+    CREDENTIALS.forEach ([client, identifier]) -> queue.push (next) ->
+      CredentialStore.remove client, identifier, (err) ->
+        expect(err).to.not.exist
+        next()
+
+    async.series queue, done
+

 beforeTests()

 runTests()
+
+afterTests()


Set User-Agent header when making network requests to GitHub/Atom.io

--- lib/atom-io-client.coffee
+++ lib/atom-io-client.coffee
@@ -3,6 +3,7 @@

 glob = null    # defer until used
 request = null # defer until used
+DefaultRequestHeaders = {'User-Agent': navigator.userAgent}

 module.exports =
 class AtomIoClient
@@ -66,7 +67,12 @@

   request: (path, callback) ->
     request ?= require 'request'
-    request "#{@baseURL}#{path}", (err, res, body) =>
+    options = {
+      url: "#{@baseURL}#{path}"
+      headers: DefaultRequestHeaders
+    }
+
+    request options, (err, res, body) =>
       try
         data = JSON.parse(body)
       catch error
@@ -138,7 +144,10 @@
       writeStream.on 'error', (error) -> callback(error)

       request ?= require 'request'
-      readStream = request("https://github.com/#{login}.png")
+      readStream = request({
+        url: "https://github.com/#{login}.png"
+        headers: DefaultRequestHeaders
+      })
       readStream.on 'error', (error) -> callback(error)
       readStream.pipe(writeStream)
     else


Rename ivars in ViolationView

Rename ivars in ViolationView

--- lib/violation-view.coffee
+++ lib/violation-view.coffee
@@ -32,8 +32,8 @@

   initializeStates: ->
     screenRange = @editor.screenRangeForBufferRange(@violation.bufferRange)
-    @startScreenPosition = screenRange.start
-    @endScreenPosition = screenRange.end
+    @screenStartPosition = screenRange.start
+    @screenEndPosition = screenRange.end

     @isValid = true

@@ -72,8 +72,8 @@
       # A marker without a tail always reports an empty range at the head position.
       # A marker with a head position greater than the tail is in a "normal" orientation.
       # If the head precedes the tail the marker is in a "reversed" orientation.
-      @startScreenPosition = event.newTailScreenPosition
-      @endScreenPosition = event.newHeadScreenPosition
+      @screenStartPosition = event.newTailScreenPosition
+      @screenEndPosition = event.newHeadScreenPosition
       @isValid = event.isValid

       if @isValid
@@ -121,8 +121,8 @@
     @hide()

   updateHighlight: ->
-    startPixelPosition = @editorView.pixelPositionForScreenPosition(@startScreenPosition)
-    endPixelPosition = @editorView.pixelPositionForScreenPosition(@endScreenPosition)
+    startPixelPosition = @editorView.pixelPositionForScreenPosition(@screenStartPosition)
+    endPixelPosition = @editorView.pixelPositionForScreenPosition(@screenEndPosition)
     arrowSize = @editorView.charWidth / 2
     verticalOffset = @editorView.lineHeight + Math.floor(arrowSize / 4)

@@ -143,7 +143,7 @@
       'left': borderOffset # Avoid protruding left edge of the border from the arrow
       'width': endPixelPosition.left - startPixelPosition.left - borderOffset
       'height': verticalOffset
-    if @endScreenPosition.column - @startScreenPosition.column > 1
+    if @screenEndPosition.column - @screenStartPosition.column > 1
       @area.addClass("violation-border")
     else
       @area.removeClass("violation-border")
@@ -151,14 +151,14 @@
   toggleTooltipWithCursorPosition: ->
     cursorPosition = @editor.getCursor().getScreenPosition()

-    if cursorPosition.row is @startScreenPosition.row &&
-       cursorPosition.column is @startScreenPosition.column
+    if cursorPosition.row is @screenStartPosition.row &&
+       cursorPosition.column is @screenStartPosition.column
       @violationTooltip('show')
     else
       @violationTooltip('hide')

   getCurrentScreenRange: ->
-    new Range(@startScreenPosition, @endScreenPosition)
+    new Range(@screenStartPosition, @screenEndPosition)

   violationTooltip: (option) ->
     violationView = this


Allow //<hostname> URLs to be used in more places

--- lib/zombie/history.coffee
+++ lib/zombie/history.coffee
@@ -177,6 +177,7 @@

   # Location uses this to move to a new URL.
   _assign: (url)->
+    url = URL.resolve(@_stack[@_index]?.url, url)
     was = @_stack[@_index]?.url # before we destroy stack
     @_stack = @_stack[0..@_index]
     @_stack[++@_index] = new Entry(this, url)
@@ -184,6 +185,7 @@

   # Location uses this to load new page without changing history.
   _replace: (url)->
+    url = URL.resolve(@_stack[@_index]?.url, url)
     was = @_stack[@_index]?.url # before we destroy stack
     @_index = 0 if @_index < 0
     @_stack[@_index] = new Entry(this, url)


support V2 document server API

support V2 document server API

--- src/code/providers/document-store-url.coffee
+++ src/code/providers/document-store-url.coffee
@@ -44,4 +44,26 @@
   renameDocument: (params) ->
     @addParams "#{@docStoreUrl}/document/rename", params

+  #
+  # Version 2 API
+  #
+  v2Document: (id, params) ->
+    @addParams "#{@docStoreUrl}/v2/documents/#{id}", params
+
+  v2CreateDocument: (params) ->
+    { method: 'POST', url: @v2Document('', params) }
+
+  v2LoadDocument: (id, params) ->
+    { method: 'GET', url: @v2Document(id, params) }
+
+  v2SaveDocument: (id, params) ->
+    { method: 'PUT', url: @v2Document(id, params) }
+
+  v2PatchDocument: (id, params) ->
+    { method: 'PATCH', url: @v2Document(id, params) }
+
+  # Not implemented by the server
+  # v2DeleteDocument: (id, params) ->
+  #   { method: 'DELETE', url: @v2Document(id, params) }
+
 module.exports = DocumentStoreUrl


new end_ussd action type

new end_ussd action type

--- static/coffee/flows/services.coffee
+++ static/coffee/flows/services.coffee
@@ -421,7 +421,8 @@
       @actions = [
         { type:'say', name:'Play Message', verbose_name:'Play a message', icon: 'icon-bubble-3', message: true, filter:[VOICE] }
         { type:'play', name:'Play Recording', verbose_name:'Play a contact recording', icon: 'icon-mic', filter:[VOICE]}
-        { type:'reply', name:'Send Message', verbose_name:'Send an SMS response', icon: 'icon-bubble-3', message:true, filter:[TEXT,VOICE,SURVEY,USSD] }
+        { type:'reply', name:'Send Message', verbose_name:'Send an SMS response', icon: 'icon-bubble-3', message:true, filter:[TEXT,VOICE,SURVEY] }
+        { type:'end_ussd', name:'End USSD Session', verbose_name:'End USSD Session with message', icon: 'icon-bubble-3', message:true, filter:USSD }
         { type:'send', name:'Send Message', verbose_name: 'Send an SMS to somebody else', icon: 'icon-bubble-3', message:true, filter:[TEXT,VOICE] }
         { type:'add_label', name:'Add Label', verbose_name: 'Add a label to a Message', icon: 'icon-tag', filter:ALL }
         { type:'save', name:'Update Contact', verbose_name:'Update the contact', icon: 'icon-user', filter:ALL }


clean the tmp dir too #32

clean the tmp dir too #32

--- lib/commands/clean.coffee
+++ lib/commands/clean.coffee
@@ -3,5 +3,5 @@
 path = require('path')

 module.exports = ->
-  _(["dist", "generated"]).each (p) ->
+  _(["dist", "generated", "tmp"]).each (p) ->
     rimraf.sync(path.resolve(process.cwd(), p))


Use success flash when deleting an integration

--- app/assets/javascripts/admin/routers/home.js.coffee
+++ app/assets/javascripts/admin/routers/home.js.coffee
@@ -45,5 +45,5 @@
       integration.destroy()
       Augury.integrations.remove integration
       Backbone.history.navigate '/', trigger: true
-      Augury.Flash.notice "The integration has been deleted."
+      Augury.Flash.success "The integration has been deleted."
 )


Start controller with lazyloader support added

When startWithLazyLoader option given the list controller will
automatically add lazyLoader as first element on list.

While using this please be careful, if you don't call/emit
LazyLoadComplete after load finished in your list the LazyLoader
will stay in list until you call proper method to hide it (emit
LazyLoadComplete)

--- components/list/KDListViewController.coffee
+++ components/list/KDListViewController.coffee
@@ -2,11 +2,12 @@

   constructor:(options = {}, data)->

-    options.wrapper           ?= yes
-    options.scrollView        ?= yes
-    options.keyNav            ?= no
-    options.multipleSelection ?= no
-    options.selection         ?= yes
+    options.wrapper             ?= yes
+    options.scrollView          ?= yes
+    options.keyNav              ?= no
+    options.multipleSelection   ?= no
+    options.selection           ?= yes
+    options.startWithLazyLoader ?= no
     @itemsOrdered             = [] unless @itemsOrdered
     @itemsIndexed             = {}
     @selectedItems            = []
@@ -43,7 +44,8 @@
       scrollView = @scrollView
       mainView.addSubView scrollView
       scrollView.addSubView @getListView()
-      # @showLazyLoader()
+      if options.startWithLazyLoader
+        @showLazyLoader no
       scrollView.registerListener KDEventTypes : 'LazyLoadThresholdReached', listener : @, callback : @showLazyLoader
       @registerListener KDEventTypes : 'LazyLoadComplete', listener : @, callback : @hideLazyLoader

@@ -298,7 +300,7 @@
   LAZY LOADER
   ###

-  showLazyLoader:->
+  showLazyLoader:(emitWhenReached = yes)->

     unless @lazyLoader
       @scrollView.addSubView @lazyLoader = new KDCustomHTMLView cssClass : "lazy-loader", partial : "Loading..."
@@ -314,7 +316,8 @@
           FPS         : 24

       @lazyLoader.canvas.show()
-      @propagateEvent KDEventType : 'LazyLoadThresholdReached'
+      if emitWhenReached
+        @propagateEvent KDEventType : 'LazyLoadThresholdReached'

   hideLazyLoader:->
     if @lazyLoader


Update data-name and title attributes of squashed directories

--- lib/directory-view.coffee
+++ lib/directory-view.coffee
@@ -29,17 +29,19 @@
       else
         iconClass = 'icon-file-submodule' if @directory.submodule
     @directoryName.classList.add(iconClass)
-    @directoryName.dataset.name = @directory.name
-    @directoryName.title = @directory.name
     @directoryName.dataset.path = @directory.path

     if @directory.squashedNames?
+      @directoryName.dataset.name = @directory.squashedNames.join('')
+      @directoryName.title = @directory.squashedNames.join('')
       squashedDirectoryNameNode = document.createElement('span')
       squashedDirectoryNameNode.classList.add('squashed-dir')
       squashedDirectoryNameNode.textContent = @directory.squashedNames[0]
       @directoryName.appendChild(squashedDirectoryNameNode)
       @directoryName.appendChild(document.createTextNode(@directory.squashedNames[1]))
     else
+      @directoryName.dataset.name = @directory.name
+      @directoryName.title = @directory.name
       @directoryName.textContent = @directory.name

     @appendChild(@header)


Fix changing the chart on iOS

Fix changing the chart on iOS

Ref #1450

--- app/assets/javascripts/lib/models/chart_list.coffee
+++ app/assets/javascripts/lib/models/chart_list.coffee
@@ -214,6 +214,8 @@
   # event binding prevents memory/event leaks and will be called just once.
   #
   setup_callbacks: ->
+    load_chart = @load
+
     # Launch the chart picker popup
     #
     $(document).on "click", "a.select_chart, a.add_chart", (e) ->
@@ -226,16 +228,18 @@
         width: 1150
         height: 700
         padding: 0
-
-    # Pick a chart from the chart picker popup
-    #
-    $(document).on "click", "div.pick_chart", (e) =>
-      e.preventDefault()
-      data_holder = $(e.target).closest('div.pick_chart')
-      holder_id = data_holder.data('chart_holder')
-      chart_id  = data_holder.data('chart_id')
-      @load chart_id, holder_id, force: true
-      close_fancybox()
+        afterShow: ->
+          # Pick a chart from the chart picker popup
+          #
+          # $('body').on "click touchdown", "div.pick_chart", (e) =>
+          $('#select_charts .pick_chart').on 'click', (e) =>
+            data_holder = $(e.target).closest('div.pick_chart')
+            holder_id = data_holder.data('chart_holder')
+            chart_id  = data_holder.data('chart_id')
+            console.log("Loading: #{ chart_id }")
+            load_chart chart_id, holder_id, force: true
+            close_fancybox()
+            e.preventDefault()

     # Toggle chart lock
     #


fix(map): Keep MarkerCluster even in higher zoom to distinct similar location points

--- app/assets/javascripts/modules/map_module.js.coffee
+++ app/assets/javascripts/modules/map_module.js.coffee
@@ -29,7 +29,7 @@
     MM.oneMovieLayer = L.layerGroup()
     defaultLayers.push MM.oneMovieLayer

-    MM.allMovieLayer = new L.MarkerClusterGroup(maxClusterRadius: 30, disableClusteringAtZoom: 10)
+    MM.allMovieLayer = new L.MarkerClusterGroup(maxClusterRadius: 30)
     defaultLayers.push MM.allMovieLayer
     if options && options.movies
       @movies = options.movies


Stupid typo

Stupid typo

--- app/assets/javascripts/store/variant_options.coffee
+++ app/assets/javascripts/store/variant_options.coffee
@@ -15,7 +15,7 @@
   $("html").on "click", ".option-value", ->
     parent = $(@).parents('.variant-options')
     optionId = $(@).parents(".variant-options").attr("id").split("_")[2]
-    optionIndex = $().parents(".variant-options").data("index")
+    optionIndex = $(@).parents(".variant-options").data("index")
     elemId = $(@).attr("id").split("-")[1]

     # update selected and 'current' text


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/active_bounds.coffee
+++ test/active_bounds.coffee
@@ -1,7 +1,9 @@
 module "ActiveBounds"

+App = {}
+
 App.width = 640
-Ap
+App.height = 480

 test "should remove objects outside of activeBounds", 2, ->
   obj = GameObject


Match if both user ids are null/undefined

--- app/coffee/ConcatManager.coffee
+++ app/coffee/ConcatManager.coffee
@@ -19,13 +19,13 @@
 		firstUpdate =
 			op: firstUpdate.op
 			meta:
-				user_id:  firstUpdate.meta.user_id
+				user_id:  firstUpdate.meta.user_id or null
 				start_ts: firstUpdate.meta.start_ts or firstUpdate.meta.ts
 				end_ts:   firstUpdate.meta.end_ts   or firstUpdate.meta.ts
 		secondUpdate =
 			op: secondUpdate.op
 			meta:
-				user_id:  secondUpdate.meta.user_id
+				user_id:  secondUpdate.meta.user_id or null
 				start_ts: secondUpdate.meta.start_ts or secondUpdate.meta.ts
 				end_ts:   secondUpdate.meta.end_ts   or secondUpdate.meta.ts


Improve sorting in projects controller

Improve sorting in projects controller

--- app/controllers/projects.coffee
+++ app/controllers/projects.coffee
@@ -2,11 +2,13 @@
   index: (req, res, next) ->
     app.models.project
     .find()
+    .sort('updatedAt')
     .exec (err, projects) ->
       if err || !projects
         next err
       else
         res.render 'projects/index', projects: projects
+
   new: (req, res) ->
     res.render 'projects/new'

@@ -33,7 +35,7 @@
     app.models.project
     .findOneById(req.params.id)
     .populate('users')
-    .populate('milestones')
+    .populate('milestones', sort: 'complete desc')
     .exec (err, project) ->
       if err || !project
         next err


Just loading all bootstrap javascripts

Just loading all bootstrap javascripts

--- lib/assets/javascripts/nyulibraries.js.coffee
+++ lib/assets/javascripts/nyulibraries.js.coffee
@@ -1,11 +1,6 @@
 # Require all js files inside the 'nyulibraries' subdir next to this file.
 #= require jquery
 #= require jquery_ujs
-#= require bootstrap-tooltip
-#= require bootstrap-popover
-#= require bootstrap-transition
-#= require bootstrap-collapse
-#= require bootstrap-alert
-#= require bootstrap-dropdown
+#= require bootstrap
 #= require_tree './nyulibraries'
 window.nyulibraries = {}


ensuring error messages get displayed for all files (before fix each file would clear previous file's messages)

--- lib/atom-sharper/views/error-pane-view.coffee
+++ lib/atom-sharper/views/error-pane-view.coffee
@@ -35,7 +35,7 @@
               @td '{{Text}}'
               @td '{{FileName}}'

-  initialize: ->
+  initialize: =>
     @vm = new Vue
       el: this[0]
       data: _.extend OmniSharpServer.vm,
@@ -43,7 +43,17 @@
       methods:
         gotoError: ({targetVM}) -> atom.emit "omni:navigate-to", targetVM.$data

-    atom.on "omni:quick-fixes", (data) => @vm.errors = data.QuickFixes
+    atom.on "omni:quick-fixes", (data) =>
+      @displayQuickFixes data.QuickFixes
+
+  displayQuickFixes: (quickFixes) =>
+    existingErrorsCount = @vm.errors.length
+
+    while existingErrorsCount--
+      if @vm.errors[existingErrorsCount].FileName == quickFixes[0]?.FileName
+        @vm.errors.splice existingErrorsCount, 1
+
+    @vm.errors.unshift quickFix for quickFix in quickFixes

   destroy: ->
     @detach()


Injects the scope to the playlist service

--- app/js/services/playlist.coffee
+++ app/js/services/playlist.coffee
@@ -7,7 +7,7 @@
 #
 class PlaylistService

-  constructor: ->
+  constructor: (@$scope) ->
     @position = 0

     @list = [
@@ -27,7 +27,7 @@
         title: "Avril Lavigne - When You're Gone"
     ]

-    # @playlist = []
+    # @list = []

   # Returns the current element
   current: ->
@@ -61,6 +61,6 @@
 #
 angular.module('tubelistsApp.services.playlist', [])

-  .service('playlistService', PlaylistService)
+  .service('playlistService', ['$scope', PlaylistService])


add stuff

add stuff

--- app/modules/new-vm/index.coffee
+++ app/modules/new-vm/index.coffee
@@ -266,7 +266,7 @@
         title: 'VM creation'
         message: 'VM creation started'
       }
-
+      console.log data
       xoApi.call('vm.create', data).then (id) ->
         # If nothing to sets, just stops.
         return id unless CPUs or name_description or memory
@@ -288,8 +288,6 @@

         return xoApi.call('vm.set', data).then -> id
       .then (id) ->
-        console.log data
-        console.log 'Existing disks: ' + existingDisks
         # TODO
         # If we asked for bigger existing template disk(s)
         # we need to resize them after the VM is created


Step 6 - Tasks store waitFor CurrentUser store

--- app/scripts/stores/tasks.coffee
+++ app/scripts/stores/tasks.coffee
@@ -1,25 +1,19 @@
 Reflux = require "reflux"
 TasksActions = require "../actions/tasks"
+CurrentUserStore = require "./current.user"

 TasksStore = Reflux.createStore

   listenables: TasksActions

-  data: [
-    {name: "Clean the house"}
-    {name: "Do the laundry"}
-    {name: "Take care of the baby"}
-    {name: "Drop the kids at the school"}
-    {name: "Cook for the weekend"}
-    {name: "Fuel the car"}
-    {name: "Clean the garden"}
-    {name: "Pay the bills"}
-    {name: "Give me some money"}
-    {name: "Call your mother-in-law"}
-    {name: "Come home earlier"}
-    {name: "Throw the garbage"}
-    {name: "Fix the chair"}
-  ]
+  init: ->
+    @listenTo(CurrentUserStore, @onLoadTasks)
+
+  data: []
+
+  onLoadTasks: (currentUser) ->
+    @data = currentUser.tasks if currentUser.tasks?
+    @trigger @data

   getInitialState: ->
     @data


Revert "Fix for #1304 ... but disallows an alternative syntax."

This reverts commit 31bfe50831e3e7ac621fec77be69453d9d31bb73.

--- rewriter.coffee
+++ rewriter.coffee
@@ -103,7 +103,7 @@
       (tag in ['TERMINATOR', 'OUTDENT'] and
         not (two?[0] is ':' or one?[0] is '@' and three?[0] is ':')) or
         (tag is ',' and one and
-          one[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT', '->', '=>'])
+          one[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT'])
     action = (token, i) ->
       tok = ['}', '}', token[2]]
       tok.generated = yes


Fix crash when playing without sounds

Fix crash when playing without sounds

--- app/views/home-page-view.coffee
+++ app/views/home-page-view.coffee
@@ -54,7 +54,7 @@

   setup: (level) =>
-    @soundManager.stopAll()
+    @soundManager.stopAll() if mediator.PlayWithSounds
     mediator.activeLevel = level
     mediator.entities = []
     @physicsManager.setup()


Flip sort order for the stream

Flip sort order for the stream

--- javascripts/models/post_list.coffee
+++ javascripts/models/post_list.coffee
@@ -2,7 +2,7 @@
   model: app.Post

   comparator: (post) ->
-    post.get('created_time')
+    -post.get('created_time')

   sync: (method, model, options) ->
     FB.api '/me/home', (data) ->


fixed validation on addperiod form

fixed validation on addperiod form

--- src/components/course-settings/add-period.cjsx
+++ src/components/course-settings/add-period.cjsx
@@ -33,10 +33,7 @@
       onChange={@onChange}
       validate={@props.validate} />

-  validate: (name) ->
-    error = PeriodStore.validatePeriodName(name, @props.periods)
-    @setState({invalid: error?})
-    error
+

 module.exports = React.createClass
   displayName: 'AddPeriodLink'
@@ -49,14 +46,21 @@
     period_name: ''
     showModal: false
     isCreating: false
+    submitted: false

   close: ->
-    @setState({showModal: false, isCreating: false, period_name: ''})
+    @setState({showModal: false, isCreating: false, period_name: '', submitted: false})

   open: ->
     @setState({showModal: true})

+  validate: (name) ->
+    error = PeriodStore.validatePeriodName(name, @props.periods)
+    @setState({invalid: error?})
+    error
+
   performUpdate: ->
+    @setState({submitted: true})
     if not @state.invalid
       @setState(isCreating: true)
       PeriodActions.create(@props.courseId, name: @state.period_name)
@@ -64,7 +68,7 @@

   renderForm: ->
     formClasses = ['modal-body', 'teacher-edit-period-form']
-    if @state?.invalid
+    if @state?.invalid and @state.submitted
       formClasses.push('is-invalid-form')
       disabled = true
     title =
Add <CourseGroupingLabel courseId={@props.courseId} />


[➦] Merged changes.

[➦] Merged changes.

--- vendor/assets/javascripts/jquery/plugins/shadify/shady.js.coffee
+++ vendor/assets/javascripts/jquery/plugins/shadify/shady.js.coffee
@@ -14,14 +14,14 @@
     renderer: @WEBGL

     mesh:
-      width: 1.0
-      height: 1.0
-      depth: 5
-      segments: 16
+      width: 1.2
+      height: 1.2
+      depth: 4
+      segments: 8
       slices: 8
-      xRange: 1.6
-      yRange: 0.1
-      zRange: 1.0
+      xRange: 0.5
+      yRange: 0.5
+      zRange: 0
       ambient: '#555555'
       diffuse: '#FFFFFF'
       speed: 0.002


fixes favorite button on auction artwork page (closes #3658)

--- apps/artwork/client/sale.coffee
+++ apps/artwork/client/sale.coffee
@@ -37,7 +37,7 @@
       new SaveControls
         artworkCollection: @saved
         el: $artwork.find('.overlay-container')
-        model: @artwork
+        model: artwork

   render: ->
     @$el.html template(sale: @sale)


fix sale collection erroring

fix sale collection erroring

--- apps/artwork/client/view.coffee
+++ apps/artwork/client/view.coffee
@@ -128,8 +128,9 @@
         @trigger 'related:not_auction'

   hasAnyAuctions: (relatedCollections) ->
-    return false unless relatedCollections.length
+    return false unless relatedCollections?.length
     saleCollection = _.find(relatedCollections, (xs) -> xs.kind is 'sales')
+    return false unless saleCollection?.length
     _.some(saleCollection.pluck 'is_auction')

   setupCurrentUser: ->


DEMO: fix ListView inside of a panel example.

--- demo/src/demos/ListView/ListViewDemo.coffee
+++ demo/src/demos/ListView/ListViewDemo.coffee
@@ -1006,9 +1006,7 @@
 			closed: true
 			content: list_view2.DOM

-		layout = CUI.dom.append(CUI.dom.append(CUI.dom.div("listview-in-panel-panels-container"), p1.DOM), p2.DOM)
-
-		demo_table.addListview("Listviews inside Panels",layout)
+		demo_table.addExample("Listviews inside Panels", [p1, p2])

 		#----------------------


add @AdityaManohar's unit test for falsey set values

--- test/dynamodb/document_client.coffee
+++ test/dynamodb/document_client.coffee
@@ -28,12 +28,16 @@
       expect(docClient.createSet(['1', '2', 'string']).type).to.equal('String')
       expect(docClient.createSet([1, 2, 3]).type).to.equal('Number')
       expect(docClient.createSet([new Buffer('foo'), new Buffer('bar')]).type).to.equal('Binary')
-
+
+    it 'supports sets with falsy values', ->
+      expect(docClient.createSet([0]).type).to.equal('Number')
+      expect(docClient.createSet(['']).type).to.equal('String')
+
     it 'validates set elements if validate: true', ->
       expect(-> docClient.createSet([1, 2, 'string'], {validate: true})).to.throw('Number Set contains String value')
       expect(-> docClient.createSet(['string', 'string', 2], {validate: true})).to.throw('String Set contains Number value')
       expect(-> docClient.createSet([1, 2, new Buffer('foo')], {validate: true})).to.throw('Number Set contains Binary value')
-
+
     it 'does not validate set elements if validate: true unset', ->
       expect(-> docClient.createSet([1, 2, 'string'])).to.not.throw('Number Set contains String value')
       expect(-> docClient.createSet(['string', 'string', 2])).to.not.throw('String Set contains Number value')
@@ -80,7 +84,7 @@
           bar: S: 'string'
           baz: S: 'string'
       expect(translateInput(input)).to.eql(params)
-
+
     it 'translates lists', ->
       buffer = new Buffer 'quux'
       input = Item: foo:
@@ -93,7 +97,7 @@
             {B: buffer}
           ]
       expect(translateInput(input)).to.eql(params)
-
+
     it 'translates string sets', ->
       set  = docClient.createSet ['bar', 'baz', 'quux']
       input = Item:
@@ -102,7 +106,7 @@
         foo:
           'SS': ['bar', 'baz', 'quux']
       expect(translateInput(input)).to.eql(params)
-
+
     it 'translates number sets', ->
       set  = docClient.createSet [1, 2, 3]
       input = Item:


JMachine::fetchByUsername add fetcher helper for backend

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -349,6 +349,23 @@
         callback err, machines

+  @fetchByUsername = (username, callback)->
+
+    JUser = require '../user'
+    JUser.one {username}, (err, user)->
+
+      return callback err  if err
+      return callback new KodingError "User not found."  unless user
+
+      selector        =
+        'users.id'    : user.getId()
+        'users.sudo'  : yes
+        'users.owner' : yes
+
+      JMachine.some selector, limit: 30, (err, machines)->
+        callback err, machines
+
+
   # Instance Methods

   setProvisioner: permit 'set provisioner',


Fix typo.

Fix typo.

--- src/map-view.coffee
+++ src/map-view.coffee
@@ -433,8 +433,6 @@
             screenHeight = $(window).innerHeight()
             Math.min(screenWidth * 0.4, screenHeight * 0.3)

-        @
-
         preAdapt: =>
             MapView.setMapActiveAreaMaxHeight()


Correct fixed nav sticky positioning on resize

--- apps/about2/client/index.coffee
+++ apps/about2/client/index.coffee
@@ -15,21 +15,22 @@
     @scroller = new Scroller frequency: 100

     # Setup sticky nav
-    (@$nav = @scroller.listen @$('.about2-section-nav'))
-      .on('scroller:below', =>
-        @$nav.addClass 'is-fixed'
-      ).on 'scroller:above', =>
-        @$nav.removeClass 'is-fixed'
+    @$nav = @scroller.listen @$('.about2-section-nav')
+    @$fixedNav = @$nav.clone()
+    @$nav.on('scroller:below', =>
+      @$nav.css(visibility: 'hidden').after(@$fixedNav.addClass 'is-fixed')
+    ).on 'scroller:above', =>
+      @$fixedNav.remove()
+      @$nav.attr style: null

     # Setup section navigation
     _.map @$('.about2-section'), (el) =>
-      @scroller.listen($(el))
-        .on('scroller:enter', (e) =>
-          idx = $(e.currentTarget).addClass('is-active').data('idx')
-          @$nav.find("a[data-idx=#{idx}]").addClass 'is-active'
-        ).on 'scroller:leave', (e) =>
-          idx = $(e.currentTarget).removeClass('is-active').data('idx')
-          @$nav.find("a[data-idx=#{idx}]").removeClass 'is-active'
+      @scroller.listen($(el)).on('scroller:enter', (e) =>
+        idx = $(e.currentTarget).addClass('is-active').data('idx')
+        @$fixedNav.find("a[data-idx=#{idx}]").addClass 'is-active'
+      ).on 'scroller:leave', (e) =>
+        idx = $(e.currentTarget).removeClass('is-active').data('idx')
+        @$fixedNav.find("a[data-idx=#{idx}]").removeClass 'is-active'

     # Setup transitions
     @listenTo @scroller, 'position', (top) ->


Global marks; move marks to chrome.storage.

--- background_scripts/marks.coffee
+++ background_scripts/marks.coffee
@@ -1,40 +1,56 @@
-root = window.Marks = {}

-marks = {}
+Marks =
+  marks: {}

-root.create = (req, sender) ->
-  marks[req.markName] =
-    tabId: sender.tab.id
-    scrollX: req.scrollX
-    scrollY: req.scrollY
+  # This returns the key which is used for storing mark locations in chrome.storage.local.
+  getLocationKey: (markName) -> "vimiumGlobalMark|#{markName}"

-chrome.tabs.onUpdated.addListener (tabId, changeInfo, tab) ->
-  if changeInfo.url?
-    removeMarksForTab tabId
+  create: (req, sender) ->
+    chrome.storage.local.get "vimiumSecret", (items) =>
+      item = {}
+      item[@getLocationKey req.markName] =
+        vimiumSecret: items.vimiumSecret
+        tabId: sender.tab.id
+        url: sender.tab.url
+        scrollX: req.scrollX
+        scrollY: req.scrollY
+      console.log item
+      chrome.storage.local.set item

-chrome.tabs.onRemoved.addListener (tabId, removeInfo) ->
-  # XXX(jez): what about restored tabs?
-  removeMarksForTab tabId
+  goto: (req, sender) ->
+    key = @getLocationKey req.markName
+    chrome.storage.local.get [ "vimiumSecret", key ], (items) =>
+      markInfo = items[key]
+      if not markInfo
+        # The mark is not defined.
+        chrome.tabs.sendMessage sender.tab.id,
+          name: "showHUDforDuration",
+          text: "Global mark not set: '#{req.markName}'."
+          duration: 1000
+      else if markInfo.vimiumSecret != items.vimiumSecret
+        # This is a different Vimium instantiation, so markInfo.tabId is definitely out of date.
+        @focusOrLaunch markInfo
+      else
+        # Check whether markInfo.tabId still exists.
+        { tabId, url, scrollX, scrollY } = markInfo
+        chrome.tabs.get tabId, (tab) =>
+          if chrome.runtime.lastError or not tab
+            # The tab no longer exists.
+            @focusOrLaunch markInfo
+          else
+            # The original tab still exists.
+            chrome.tabs.update tabId, { selected: true }, ->
+              chrome.tabs.sendMessage tabId,
+                { name: "setScrollPosition", scrollX: scrollX, scrollY: scrollY }, ->
+                  chrome.tabs.sendMessage tabId,
+                    name: "showHUDforDuration",
+                    text: "Jumped to global mark '#{req.markName}'."
+                    duration: 1000

-removeMarksForTab = (id) ->
-  for markName, mark of marks
-    if mark.tabId is id
-      delete marks[markName]
+  # The tab we're trying to find no longer exists.  Either find another tab with a matching URL and use it, or
+  # create a new tab.
+  focusOrLaunch: (info) ->
+    console.log info

-root.goto = (req, sender) ->
-  mark = marks[req.markName]
-  if mark?
-    chrome.tabs.update mark.tabId, selected: true
-    chrome.tabs.sendMessage mark.tabId,
-      name: "setScrollPosition"
-      scrollX: mark.scrollX
-      scrollY: mark.scrollY
-    chrome.tabs.sendMessage mark.tabId,
-      name: "showHUDforDuration",
-      text: "Jumped to global mark '#{req.markName}'."
-      duration: 1000
-  else
-    chrome.tabs.sendMessage sender.tab.id,
-      name: "showHUDforDuration",
-      text: "Global mark not set: '#{req.markName}'."
-      duration: 1000
+root = exports ? window
+root.Marks = Marks


Fixed query parsing (different from body) - forms should autofill correctly now

--- controllers/contact.coffee
+++ controllers/contact.coffee
@@ -9,8 +9,8 @@
     res.locals.scripts.push '/js/contact.js'

     # Get and set form parameters
-    typeMeta = _getMeta res.locals.contacts, req.body.type
-    projectMeta = _getMeta res.locals.projects, req.body.project
+    typeMeta = _getMeta res.locals.contacts, req.query.type
+    projectMeta = _getMeta res.locals.projects, req.query.project
     res.locals.selected =
         type:
             title: typeMeta?.title ? res.locals.contacts[0].title
@@ -18,7 +18,7 @@
         project:
             title: projectMeta?.title ? res.locals.projects[0].title
             value: projectMeta?.value ? 0
-        showProjects: true if req.body.type is 'join'
+        showProjects: true if req.query.type is 'join'

 # POST index
 postIndex = (req, res, ctrl) ->


Tracker: mark events that sends email on outbound

we will need to create templates for these ones in source code again because with this pr we will try to remove outbound dependency

--- workers/social/lib/social/models/tracker.coffee
+++ workers/social/lib/social/models/tracker.coffee
@@ -53,11 +53,27 @@
     STACKS_REINIT             : 'reinitialized stack'
     STACKS_DELETE             : 'deleted stack'

+  @mailEvents = [
+  # 'START_REGISTER'  # it's an email event but not required for basic emails ~ GG
+    'REQUEST_NEW_PASSWORD'
+    'CHANGED_PASSWORD'
+    'REQUEST_EMAIL_CHANGE'
+    'CHANGED_EMAIL'
+    'INVITED_TEAM'
+    'INVITED_CREATE_TEAM'
+  ]
+
   @properties = {}

   @properties[@types.FINISH_REGISTER] = {
     category: 'NewAccount', label: 'VerifyAccount'
   }
+
+  @isEmailEvent = (event) ->
+
+    return yes  for type, val of @types when val is event and type in @mailEvents
+    return no
+

   @identifyAndTrack = (username, event, eventProperties = {}, callback = -> ) ->
     @identify username, {}, (err) =>
@@ -116,7 +132,7 @@
     # use `forcedRecipientEmail` for both username and email
     if forcedRecipientEmail
       username = forcedRecipientUsername
-      event.to  = forcedRecipientEmail
+      event.to = forcedRecipientEmail

     event.from       or= defaultFromMail
     event.properties   = @addDefaults { options, username }


test: Fix failing tests in cli-test.coffee on Windows

--- test/integration/cli/cli-test.coffee
+++ test/integration/cli/cli-test.coffee
@@ -1,5 +1,7 @@
+net = require('net')
+path = require('path')
+
 {assert} = require('chai')
-net = require('net')
 {exec} = require('child_process')

 {isProcessRunning, killAll, createServer, runDreddCommandWithServer, runDreddCommand, DEFAULT_SERVER_PORT} = require('../helpers')
@@ -194,7 +196,10 @@
         before (done) ->
           app = createServer()
           app.get '/machines', (req, res) ->
-            killAll('endless-ignore-term.+[^=]foo/bar/hooks', (err) ->
+            # path.posix|win32.normalize and path.join do not do the job in this case,
+            # hence this ingenious hack
+            normalizedPath = path.normalize('foo/bar/hooks').replace(/\\/g, '\\\\')
+            killAll("endless-ignore-term.+[^=]#{normalizedPath}", (err) ->
               done err if err
               res.json([{type: 'bulldozer', name: 'willy'}])
             )


don't log evt :)

don't log evt :)

--- lib/assets/javascripts/jax/input/mouse.js.coffee
+++ lib/assets/javascripts/jax/input/mouse.js.coffee
@@ -62,7 +62,6 @@
       y: evt.clientY - rect.top
     evt.x *= @receiver.width / rect.width
     evt.y *= @receiver.height/ rect.height
-    console.log evt
     if @_lastx is undefined
       evt.diffx = evt.diffy = 0
     else


don’t use cdn on dark

don’t use cdn on dark

--- services/web/app/coffee/infrastructure/ExpressLocals.coffee
+++ services/web/app/coffee/infrastructure/ExpressLocals.coffee
@@ -51,11 +51,7 @@

 logger.log "Finished generating file fingerprints"

-
-staticFilesBase = ""
-if Settings.cdn?.web?.host?
-	staticFilesBase = Settings.cdn?.web?.host
-
+cdnAvailable = Settings.cdn?.web?.host?

 module.exports = (app, webRouter, apiRouter)->
 	webRouter.use (req, res, next)->
@@ -63,11 +59,19 @@
 		next()

 	webRouter.use (req, res, next)->
+
+		isDark = req.headers?.host?.slice(0,4)?.toLowerCase() == "dark"
+		isSmoke = req.headers?.host?.slice(0,5)?.toLowerCase() == "smoke"
+		isLive = !isDark and !isSmoke
+
+		if cdnAvailable and isLive
+			staticFilesBase = Settings.cdn?.web?.host
+		else
+			staticFilesBase = ""
+
 		res.locals.jsPath = jsPath
 		res.locals.fullJsPath = Url.resolve(staticFilesBase, jsPath)

-		imgPath = "/img/"
-		cssPath = "/stylesheets/"

 		res.locals.buildJsPath = (jsFile, opts = {})->
 			path = Path.join(jsPath, jsFile)
@@ -89,11 +93,11 @@

 		res.locals.buildCssPath = (cssFile)->
-			path = Path.join(cssPath, cssFile)
+			path = Path.join("/stylesheets/", cssFile)
 			return Url.resolve(staticFilesBase, path) + "?fingerprint=" + getFingerprint(path)

 		res.locals.buildImgPath = (imgFile)->
-			path = Path.join(imgPath, imgFile)
+			path = Path.join("/img/", imgFile)
 			return Url.resolve(staticFilesBase, path)

 		next()


MainController: Remove LoginView from MainController

--- client/Main/maincontroller/maincontroller.coffee
+++ client/Main/maincontroller/maincontroller.coffee
@@ -86,9 +86,6 @@
       @emit "#{eventPrefix}.#{eventSuffix}", account, connectedState, firstLoad

   createMainViewController:->
-    @loginScreen = new LoginView
-      testPath   : "landing-login"
-    @loginScreen.appendToDomBody()
     KD.registerSingleton "dockController", new DockController
     @mainViewController  = new MainViewController
       view    : mainView = new MainView


don't reauthenticate to kontrol unless new kites are used

--- client/Main/maincontroller/maincontroller.coffee
+++ client/Main/maincontroller/maincontroller.coffee
@@ -78,7 +78,7 @@
     @on "pageLoaded.as.loggedIn", (account)-> # ignore othter parameters
       KD.utils.setPreferredDomain account if account

-    (KD.getSingleton 'kontrol').reauthenticate()
+    (KD.getSingleton 'kontrol').reauthenticate()  if KD.useNewKites

     account.fetchMyPermissionsAndRoles (err, permissions, roles)=>
       return warn err  if err


fix registration

fix registration

--- apps/registration/routes.coffee
+++ apps/registration/routes.coffee
@@ -6,6 +6,7 @@
   invitee = new Invitee invitation_token: req.params.token
   invitee.fetch
     success: ->
+      invitee.set invitation_token: req.query.invite_token
       res.locals.sd.INVITEE = invitee.toJSON()
       res.render 'index', invitee: invitee
     error: ->


Fix errors in infertyep

Fix errors in infertyep

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -1290,7 +1290,7 @@
     {success, error} = deferConstraints ctx,
       (substituteList ctx.substitution, constraints)
     if error
-      ctx.extendSubstitution substitutionFail error
+      ctx.extendSubstitution error
       return
     [deferredConstraints, retainedConstraints] = success
     # Finalizing type again after possibly added substitution when defer constraints
@@ -3981,6 +3981,9 @@
       '==', (
         type: (quantifyAll toConstrained (typeFn (atomicType 'a', star), (atomicType 'a', star), boolType)),
         arity: ['x', 'y'])
+      'is-null-or-undefined', (
+        type: (quantifyAll toConstrained (typeFn (atomicType 'a', star), boolType)),
+        arity: ['x'])
   # concatMaps (mapMap desiplifyTypeAndArity, newMapWith '&', '(Fn a b b)', # TODO: replace with actual type
   #   'show-list', '(Fn a b)' # TODO: replace with actual type
   #   'from-nullable', '(Fn a b)' # TODO: replace with actual type JS -> Maybe a
@@ -4926,12 +4929,8 @@
   return t;
 };

-var from__nullable = function (jsValue) {
-  if (typeof jsValue === "undefined" || jsValue === null) {
-    return {';none': true};
-  } else {
-    return {':just': [jsValue]};
-  }
+var is__null__or__undefined = function (jsValue) {
+  return typeof jsValue === "undefined" || jsValue === null;
 };
 """ +
 (for i in [1..9]


Fixed currying of type constructors by removing the check but discoverd that Js.x methods are broken

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -937,9 +937,10 @@
     labelOperator atom
   else
     atom.label = 'typename' unless isFake atom
-  if expectedKind and (not kindsEq expectedKind, finalKind)
-    malformed atom, "The kind of the type operator doesn't match the
-                  supplied number of arguments"
+  # if expectedKind and (not kindsEq expectedKind, finalKind)
+  #   log expectedKind, finalKind
+  #   malformed atom, "The kind of the type operator doesn't match the
+  #                 supplied number of arguments"
   # log type
   type

@@ -2251,7 +2252,7 @@
     precs: [cond_  (jsBinary "===", ctx.assignTo(), translation)]

 deferredExpression = ->
-  {js: 'deferred'}
+  jsNoop()

 # type expressions syntax
 # or
@@ -2511,7 +2512,7 @@
   finalType = substitute ctx.substitution, type
   translated = translateIr ctx, expression
   if isCustomCollectionType finalType
-    (jsCall (jsAccess translated, 'toJS'), [])
+    (jsCall (jsAccess translated, 'toArray'), [])
   else
     translated

@@ -5197,6 +5198,36 @@
   """
   "x", 2

+  'curried type constructor'
+  """
+  + (macro [x y]
+    (: (Fn Num Num Num))
+    (Js.binary "+" x y))
+
+  get (macro [key from]
+    (: (Fn k (Map k v) v))
+    (Js.method from "get" {key}))
+
+  put (macro [key value into]
+    (: (Fn k v (Map k v) (Map k v)))
+    (Js.method into "set" {key value}))
+
+  Mappable (class [wrapper]
+    map (fn [what onto]
+      (: (Fn (Fn a b) (wrapper a) (wrapper b)))
+      (# Apply what to every value inside onto .)))
+
+  reduce-map (macro [with initial over]
+    (: (Fn (Fn a v k a) a (Map k v) a))
+    (Js.method over "reduce" {with initial}))
+
+  map-mappable (instance (Mappable (Map k))
+    map (fn [what onto]
+      (reduce-map helper (Map) onto)
+      helper (fn [acc value key]
+        (put key (what value) acc))))
+  """
+  """(get "c" (map (+ 1) {a: 3 b: 2 c: 4}))""", 5

   # The following doesn't work because the Collection type class specifies
   # that the constructor takes only one argument.


environments: implement group context awareness to `ResourcesContainer` view

--- client/Environments/views/resourcescontainer.coffee
+++ client/Environments/views/resourcescontainer.coffee
@@ -5,12 +5,11 @@
     super options, data

   addSubscriptions: ->
-    KD.singleton("paymentController").fetchSubscriptionsWithPlans
-      tags : ['vm', 'custom-plan']
-    , (err, subscriptions) =>
+    tag = if KD.getGroup().slug is "koding" then "vm" else "custom-plan"
+    payment = KD.singleton "paymentController"
+    payment.fetchSubscriptionsWithPlans tags: [tag], (err, [subscription]) =>
       return new KDNotificationView title: err  if err
-      for subscription in subscriptions
-        @subscriptions.addSubView new SubscriptionUsageView null, subscription
+      @subscriptions.addSubView new SubscriptionUsageView null, subscription

   viewAppended: ->
     @addSubView @titleBar = new KDCustomHTMLView


Initial fix for verfiy account move

Initial fix for verfiy account move

--- client/account/lib/views/accounteditusername.coffee
+++ client/account/lib/views/accounteditusername.coffee
@@ -330,8 +330,7 @@
               return showError err if err
               notify "We've sent you a confirmation mail.", 3500

-    @addSubView @verifyEmail = new KDCustomHTMLView opts
-
+    @emailForm.fields.username.parent.prepend verifyEmail = new KDCustomHTMLView opts

   getAvatarOptions: ->
     tagName       : 'figure'


Add recursive loop to escape from formatting cells. Change to use jQuery based objects (accessed through Annotator reference).

--- annotran/static/scripts/annotator/plugin/sentenceselection.coffee
+++ annotran/static/scripts/annotator/plugin/sentenceselection.coffee
@@ -30,7 +30,14 @@
   makeSentenceSelection: (event = {}) =>
     # Get the currently selected ranges.

-    desiredText = event.target.innerText || event.target.textContent
+    tagName = $(event.target).prop("tagName").toLowerCase()
+
+    # this loop checks that we are not within a formatting cell and that we should recurse upwards through parent elements
+    while tagName is "i" or tagName is "strong" or tagName is "em" or tagName is "b" or tagName is "mark" or tagName is "small" or tagName is "del" or tagName is "ins" or tagName is "sub" or tagName is "sup"
+      event.target = $(event.target).parent()
+      tagName = $(event.target).prop("tagName").toLowerCase()
+
+    desiredText = $(event.target).text()
     desiredText = desiredText.split('.')[0]

     full_xpath = Util.xpathFromNode($(event.target), document)


Fix fr description of Mstsc

Fix fr description of Mstsc

--- client/app/locales/fr.coffee
+++ client/app/locales/fr.coffee
@@ -254,7 +254,7 @@
     "term description": "Un terminal pour votre Cozy."
     "ghost description": "Partagez vos histoires avec le monde entier avec la plateforme de blog Ghost."
     "leave google description": "Une application pour importer vos données de votre compte Google."
-    "mstsc.js description": "Prenez contrôle de votre bureau Windows à distance à traver le protocole RDP."
+    "mstsc.js description": "Depuis votre Cozy, prenez contrôle de votre bureau Windows à distance à travers le protocole RDP."
     "reminder title email": "[Cozy-Calendar] Rappel"
     "reminder title email expanded": "Rappel: %{description} - %{date} (%{calendar})"
     "reminder message expanded": """


No seriously, this ngmin dep goes away now.

--- lib/Watchers/Script.coffee
+++ lib/Watchers/Script.coffee
@@ -7,7 +7,6 @@

 esprima = require 'esprima'
 UglifyJS = require 'uglify-js'
-ngmin = require 'ngmin'

 class ScriptWatcher extends SourcemapWatcher
     constructor: (@config)->


don't autocomplete on the first line in an editor

--- client/autocompletion.coffee
+++ client/autocompletion.coffee
@@ -4,7 +4,7 @@
 module.exports = (cm, requestAutocompletion) -> # set up autocompletion, common code between session and editor
   tid = null # timeout id
   cm.on 'change', ->
-    if cm.getOption('mode') in ['apl', 'aplsession']
+    if cm.getOption('mode') in ['apl', 'aplsession'] and cm.getCursor().line
       clearTimeout tid
       tid = setTimeout(
         ->


fixed an issue where VideoPopup popup windows would only work from the activity stream

--- client/landing/app/CommonViews/VideoPopup.coffee
+++ client/landing/app/CommonViews/VideoPopup.coffee
@@ -161,7 +161,7 @@
     t=@getDelegate().$().offset()
     @videoPopup?.close()

-    popupUrl = "video-container.html"
+    popupUrl = "/video-container.html"

     @videoPopup = @controller.newPopup popupUrl, "KodingVideo_"+Math.random().toString(36).substring(7), "menubar=no,location=no,resizable=yes,titlebar=no,scrollbars=no,status=no,innerHeight=#{h},width=#{w},left=#{t.left+window.screenX},top=#{window.screenY+t.top+(window.outerHeight - window.innerHeight)}", @options.title, @options.thumb


modify: remove leakage ;p

modify: remove leakage ;p

--- tasks/gulp.config.coffee
+++ tasks/gulp.config.coffee
@@ -302,7 +302,6 @@
   # sourcemaps を本番ビルド時に削除する
   .pipe $.if isProduction, pathSearch(paths.pc.js.dest, 'js').on 'end', (cb) ->
     pathArray.unshift(paths.pc.js.dest + '**/*.map')
-    del pathArray, cb
     return

 # img check pc


EditorPane: trimWhiteSpaceOnSave and autoSave collision.

--- client/ide/lib/workspace/panes/ideeditorpane.coffee
+++ client/ide/lib/workspace/panes/ideeditorpane.coffee
@@ -77,14 +77,16 @@

   handleAutoSave: ->

-    return   if @getFile().path.indexOf('localfile:/') > -1
-    return   if @errorOnSave
-    @save()  if @getAce().isContentChanged()
-
-
-  save: ->
-
-    @getAce().requestSave()
+    return if @getFile().path.indexOf('localfile:/') > -1
+    return if @errorOnSave
+
+    if @getAce().isContentChanged()
+      @save ignoreActiveLineOnTrim: yes
+
+
+  save: (options = {}) ->
+
+    @getAce().requestSave options

   getAce: ->


Visual alert added to notify updating success

--- assets/controllers/shops.coffee
+++ assets/controllers/shops.coffee
@@ -99,7 +99,8 @@
       )
       .success (data, status) ->
         $scope.shop = data
-
+        AppAlert.add "success","INFORMATION_UPDATED"
       .error (data, status) ->
         $scope.errors = (if (status is 403) then ["NO_SHOP_HAS_BEEN_FOUND"] else ["UNKNOWN_ERROR"])
+        AppAlert.add "warning","ERROR"
   ]


Add ability for inner app to set provider options

This allows provider options to be updated even after initialization.

Specifically, this will be used to allow CODAP to update the buildNumber
etc. with its own buildNumber, as these properties will soon be handled
entirely by the provider.

--- src/code/client.coffee
+++ src/code/client.coffee
@@ -54,6 +54,14 @@
     if options.autoSaveInterval
       @autoSave options.autoSaveInterval

+  setProviderOptions: (name, newOptions) ->
+    for provider in @state.availableProviders
+      if provider.name is name
+        provider.options ?= {}
+        for key of newOptions
+          provider.options[key] = newOptions[key]
+        break
+
   # single client - used by the client app to register and receive callback events
   connect: (@eventCallback) ->
     @_event 'connected', {client: @}


improve logging, and handle different forms of authoredState

--- src/code/iframe.coffee
+++ src/code/iframe.coffee
@@ -51,7 +51,9 @@
     @iframePhone.addListener 'initInteractive', (data) ->
       l.info "Phone call: initInteractive: #{JSON.stringify data}"
       $('#interactiveState').val JSON.stringify(data.interactiveState) if data.interactiveState
-      $('#authoredState').val JSON.stringify(data.authoredState) if data.authoredState
+      # prior to LARA 1.26 the authorState would come in as a string during authoring and
+      # an object during runtime
+      $('#authoredState').val @convertIfNecessary(data.authoredState) if data.authoredState
       $('#interactiveStateGlobal').val JSON.stringify(data.globalInteractiveState) if data.globalInteractiveState

     # Logging
@@ -69,19 +71,25 @@
     @iframePhone.initialize()
     l.info("Phone ready")

-    @iframePhone.post("supportedFeatures", {
+    @postAndLog("supportedFeatures", {
       apiVersion: 1,
       features: {
         authoredState: true,
         interactiveState: true
       }
     })
-    l.info("Posted supported features")

     # TODO: (rpc)
     # @iframePhoneRpc = new iframePhone.IframePhoneRpcEndpoint
     #   phone: @iframePhone
     #   namespace: 'lara-logging'
+
+  postAndLog: (msgType, data=null) ->
+    @iframePhone.post(msgType, data)
+    l.info("posted #{msgType}: #{JSON.stringify data}")
+
+  convertIfNecessary: (objectOrString) ->
+    if typeof objectOrString == 'String' then objectOrString else JSON.stringify(objectOrString)

   constructor: () ->
     l.info("Starting the dummy iframe interactive")
@@ -90,15 +98,12 @@
       $('#logger').html('')

     $('#getAuthInfo').click () =>
-      l.info('posting getAuthInfo')
-      @iframePhone.post("getAuthInfo")
+      @postAndLog('getAuthInfo')

     $('#globalSaveState').click () =>
-      l.info('posting interactiveStateGlobal')
-      @iframePhone.post("interactiveStateGlobal", JSON.parse($('#interactiveStateGlobal').val()))
+      @postAndLog("interactiveStateGlobal", JSON.parse($('#interactiveStateGlobal').val()))

     $('#saveAuthoredState').click () =>
-      l.info('posting authoredState')
-      @iframePhone.post("authoredState", JSON.parse($('#authoredState').val()))
+      @postAndLog("authoredState", JSON.parse($('#authoredState').val()))

 window.MockInteractive = MockInteractive


remove token in constructor

remove token in constructor

--- app/controllers/applications_controller.coffee
+++ app/controllers/applications_controller.coffee
@@ -55,7 +55,7 @@
     body.state = "installing"

     setupApp = (appli) ->
-        manager = new AppManager(app.token)
+        manager = new AppManager()
         console.info 'attempt to install app ' + JSON.stringify(appli)
         manager.installApp appli, (err, result) ->
             if err
@@ -128,7 +128,7 @@
                             success: true
                             msg: 'Application succesfuly uninstalled'

-    manager = new AppManager(app.token)
+    manager = new AppManager()
     manager.uninstallApp @app, (err, result) =>
         if err
             markAppAsBroken()
@@ -149,7 +149,7 @@
             else
                 send_error "uninstallation failed"

-    manager = new AppManager(app.token)
+    manager = new AppManager()
     manager.updateApp @app, (err, result) =>
         if err
             markAppAsBroken()
@@ -179,7 +179,7 @@
                 send_error "starting failed"

-    manager = new AppManager(app.token)
+    manager = new AppManager()
     manager.start @app, (err, result) =>
         if err
             markAppAsBroken()
@@ -209,7 +209,7 @@
             else
                 send_error "stopping failed"

-    manager = new AppManager(app.token)
+    manager = new AppManager()
     manager.stop @app, (err, result) =>
         if err
             markAppAsBroken()


align columns

align columns

--- client/lanes/workspace/ActiveScreensSwitcher.coffee
+++ client/lanes/workspace/ActiveScreensSwitcher.coffee
@@ -53,10 +53,9 @@
         super
         _.bindAll(this, 'resetShownControls')
         @collection = Lanes.Screens.Definitions.displaying
-        this.listenTo( @collection, "change:active", this.onActiveChange )
-        this.listenTo( this.viewport,  "change:width", this.resetShownControls )
+        this.listenTo( @collection,        "change:active",     this.onActiveChange)
+        this.listenTo( this.viewport,      "change:width",      this.resetShownControls)
         this.listenTo( Lanes.current_user, "change:isLoggedIn", this.closeScreens)
-

     closeScreens: ->
         @collection.reset()


Minor text change to view test

Minor text change to view test

--- test/tb/views/base/index_test.coffee
+++ test/tb/views/base/index_test.coffee
@@ -2,7 +2,7 @@

 { assert } = helpers.chai

-describe 'BaseView', ->
+describe 'Backbone.View', ->

   it 'should create a Titanium view when initialized', ->
     assert.ok (new Backbone.View).el


ENH: Added beamer frame suggestion

ENH: Added beamer frame suggestion

--- lib/autocomplete/environment.coffee
+++ lib/autocomplete/environment.coffee
@@ -104,3 +104,5 @@
         text: 'thebibliography'
       titlepage:
         text: 'titlepage'
+      frame:
+        text: 'frame'


Faster autoscroll between pages, especially to top

--- client/lib/autoscroll.coffee
+++ client/lib/autoscroll.coffee
@@ -65,11 +65,15 @@
     lastURL = url
     top = pastTops[url] or 0  ## prevent from changing while page loads
     scroll = ->
-      $('html, body').animate
-        scrollTop: top
-      , 200
-    Tracker.autorun (computation) ->
-      if Router.current().ready()
-        scroll()
-        computation.stop()
-  , 100
+      $('html, body').scrollTop top
+      #$('html, body').animate
+      #  scrollTop: top
+      #, 200
+    if top > 0
+      Tracker.autorun (computation) ->
+        if Router.current().ready()
+          scroll()
+          computation.stop()
+    else
+      scroll()
+  , 0


Replacing `browser.back` and `browser.forward` by `history.go(index)` to workaround existent problems with Safari through Web Driver

--- test/tests/acceptance/general.coffee
+++ test/tests/acceptance/general.coffee
@@ -61,7 +61,7 @@
     describe '[buttons]', ->

       it 'click back button', (done)->
-        browser.back (err)->
+        browser.execute 'history.go(-1)', (err)->
           should.not.exist err
           browser.eval 'window.middleware.pathname()', (err, pathname)->
             should.not.exist err
@@ -69,7 +69,7 @@
             pass done

       it 'click back button', (done)->
-        browser.back (err)->
+        browser.execute 'history.go(-1)', (err)->
           should.not.exist err
           browser.eval 'window.middleware.pathname()', (err, pathname)->
             should.not.exist err
@@ -77,7 +77,7 @@
             pass done

       it 'click forward button', (done)->
-        browser.forward (err)->
+        browser.execute 'history.go(1)', (err)->
           should.not.exist err
           browser.eval 'window.middleware.pathname()', (err, pathname)->
             should.not.exist err


gizmo dance

gizmo dance

--- scripts/dance-party.coffee
+++ scripts/dance-party.coffee
@@ -26,9 +26,10 @@
   "http://media.tumblr.com/tumblr_lrzrlymUZA1qbliwr.gif",
   "http://3deadmonkeys.com/gallery3/var/albums/random_stuff/Carlton-Dance-GIF.gif",
   "http://i.imgur.com/a6Naj.gif",
-  "http://mlkshk.com/r/LP86.gif"
+  "http://mlkshk.com/r/LP86.gif",
+  "http://mlkshk.com/r/T3WN.gif"
 ]

 module.exports = (robot) ->
   robot.hear /.*(dance party).*/i, (msg) ->
-    msg.send msg.random dances+    msg.send msg.random dances


fix a fat-fingering to ~/.jupyter

fix a fat-fingering to ~/.jupyter

--- lib/kernel-manager.coffee
+++ lib/kernel-manager.coffee
@@ -7,7 +7,7 @@

 module.exports = KernelManager =
     kernelsDirOptions: [
-        path.join(process.env['HOME'], '.ijupyter/kernels'),
+        path.join(process.env['HOME'], '.jupyter/kernels'),
         path.join(process.env['HOME'], 'Library/Jupyter/kernels'),
         '/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/share/jupyter/kernels',
         '/usr/local/share/jupyter/kernels',


:bug: Fix broken activation due to renamed event in nightly

--- lib/minimap-git-diff-binding.coffee
+++ lib/minimap-git-diff-binding.coffee
@@ -14,8 +14,13 @@
     @subscriptions = new CompositeDisposable

   activate: ->
-    @subscriptions.add @editorView.getEditor().onDidChangePath @subscribeToBuffer
-    @subscriptions.add @editorView.getEditor().onDidChangeScreenLines @updateDiffs
+    editor = @editorView.getEditor()
+    @subscriptions.add editor.onDidChangePath @subscribeToBuffer
+    if editor.onDidChangeScreenLines?
+      @subscriptions.add editor.onDidChangeScreenLines @updateDiffs
+    else
+      @subscriptions.add editor.onDidChange @updateDiffs
+
     @subscriptions.add @getRepo().onDidChangeStatuses @scheduleUpdate
     @subscriptions.add @getRepo().onDidChangeStatus @scheduleUpdate


Fix tournament leaderboard spectate code

--- app/views/ladder/components/Leaderboard.coffee
+++ app/views/ladder/components/Leaderboard.coffee
@@ -120,8 +120,8 @@
     return unless data.length is 2
     @spectateTargets ?= {}
     leaderboards = @leaderboards.topPlayers.models
-    @spectateTargets.humans = leaderboards[data[0]].get('_id')
-    @spectateTargets.ogres = leaderboards[data[1]].get('_id')
+    @spectateTargets.humans = leaderboards[data[0]].get('levelSession')
+    @spectateTargets.ogres = leaderboards[data[1]].get('levelSession')

   handleClickAgeFilter: (ageBracket) ->
     @ageBracket = ageBracket


Physics: Fix missing triangles in trianglemeshes.

--- engine/physics/bullet.coffee
+++ engine/physics/bullet.coffee
@@ -596,7 +596,7 @@
             return mesh_data.phy_mesh
         vertices = mesh_data.varray
         # TODO: use all submeshes
-        indices = mesh_data.iarray.subarray(0, mesh_data.offsets[2])
+        indices = mesh_data.iarray.subarray(0, mesh_data.offsets[3])
         vstride = mesh_data.stride/4
         vlen = vertices.length/vstride
         if not Ammo._malloc


Method only being used in this file

Method only being used in this file

--- core/app/backbone/views/react_feed_selection.coffee
+++ core/app/backbone/views/react_feed_selection.coffee
@@ -9,7 +9,7 @@
       personal: new PersonalFeedActivities

-  handleFeedChoiceChange: (e) ->
+  _handleFeedChoiceChange: (e) ->
     if(e.target.checked)
       @setState
         feedChoice: e.target.value
@@ -18,11 +18,11 @@
     _div [],
       if FactlinkApp.signedIn()
         _div ['feed-selection-row'],
-          _input [ 'radio-toggle-button', type: 'radio', name: 'FeedChoice', value: 'global', id: 'FeedChoice_Global', onChange: @handleFeedChoiceChange, checked: @state.feedChoice=='global'  ]
+          _input [ 'radio-toggle-button', type: 'radio', name: 'FeedChoice', value: 'global', id: 'FeedChoice_Global', onChange: @_handleFeedChoiceChange, checked: @state.feedChoice=='global'  ]
           _label [ htmlFor: 'FeedChoice_Global' ],
             'Global'

-          _input [ 'radio-toggle-button', type: 'radio', name: 'FeedChoice', value: 'personal', id: 'FeedChoice_Personal', onChange: @handleFeedChoiceChange, checked: @state.feedChoice=='personal' ]
+          _input [ 'radio-toggle-button', type: 'radio', name: 'FeedChoice', value: 'personal', id: 'FeedChoice_Personal', onChange: @_handleFeedChoiceChange, checked: @state.feedChoice=='personal' ]
           _label [ htmlFor: 'FeedChoice_Personal' ],
             'Personal'


proper initialization for channel

proper initialization for channel

--- core/app/backbone/views/suggested_topic_view.coffee
+++ core/app/backbone/views/suggested_topic_view.coffee
@@ -9,6 +9,6 @@

   addModelError: (model)-> alert('something went wrong while creating this channel')

-  wrapNewModel: (model) -> new Channel(@model.toJSON())
+  wrapNewModel: (model) -> @model.newChannelForUser(window.currentUser)

 _.extend(window.SuggestedTopicView.prototype, Backbone.Factlink.AddModelToCollectionMixin)


Oops, forgot to start at the current node

--- scripts/mixins/tree.coffee
+++ scripts/mixins/tree.coffee
@@ -64,7 +64,8 @@

     getRoot: () ->
       root = null
-      while parent = getParent()
+      parent = @
+      while parent = parent.getParent()
         root = parent
       return root


fixed evaluation of initial date

fixed evaluation of initial date

--- source/javascripts/index/schedule.coffee
+++ source/javascripts/index/schedule.coffee
@@ -1,3 +1,8 @@
+initialDate = ->
+  initialDate = window.location.search.replace("?", "")
+  initialDate = if initialDate.length > 0 then moment(initialDate, "YYYYMMDD").toDate() else (new Date())
+  moment(initialDate).add(12, 'hours').format("YYYY-MM-DD")
+
 show_event = (day, event, hebrew_date) -> $(".#{day} .#{event}")[show_if(hebrew_date["is#{event}"]())]('hidden')

 event_array = (day) -> ($(".one_day.#{day} .#{event}").not(".hidden").length > 0) for event in events
@@ -50,7 +55,6 @@
     ($(".#{day} .#{column}").removeClass('hidden') for day in moment.weekdays()) unless $(".header .#{column}").hasClass('hidden')

 $ ->
-  initial_date = moment(window.location.search.replace("?", ""), "YYYYMMDD").toDate()
   window.events = (e.className.replace(/start-hidden/, '').replace(/event/, '').replace(/\s*/, '') for e in $('.Saturday .event'))
-  $('.calendar').change(-> write_schedule(moment(this.value))).val(moment(initial_date).add(12, 'hours').format("YYYY-MM-DD")).change()
+  $('.calendar').change(-> write_schedule(moment(this.value))).val(initialDate()).change()
   $(".Saturday.one_day td:nth-child(1)").html("שַׁבָּת")


流程框方法添加参数判断

流程框方法添加参数判断

--- lib/utils/chameleon-box-view.coffee
+++ lib/utils/chameleon-box-view.coffee
@@ -77,10 +77,13 @@
     @contentView.nextStep(@);

   onPrevClick: ->
-    @order--
-    console.log @options,@prevStep
-    @mergeOptions {subview:prevView} if prevView = @getPrevStep()
-    @_refresh()
+    if @prevBtn.hasClass('other')
+      @contentView.prevStep(@);
+    else
+      @order--
+      console.log @options,@prevStep
+      @mergeOptions {subview:prevView} if prevView = @getPrevStep()
+      @_refresh()

   onFinish: (callback) ->
     @emitter.on 'finish', callback
@@ -93,18 +96,22 @@
       @_refresh(@options)

-  setNextBtn: (type = 'normal') ->
+  setNextBtn: (type = 'normal',text) ->
     if type is 'finish'
-      @nextBtn.text(desc.finish).addClass('finish')
+      text?=desc.finish
+      @nextBtn.text(text).addClass('finish')
     else
-      @nextBtn.text(desc.next).removeClass('finish')
+      text?=desc.next
+      @nextBtn.text(text).removeClass('finish')
     @showNextBtn()

-  setPrevBtn: (type = 'normal') ->
+  setPrevBtn: (type = 'normal',text) ->
     if type is 'back'
-      @prevBtn.text(desc.back).addClass('back')
+      text?=desc.back
+      @prevBtn.text(text).addClass('back')
     else
-      @prevBtn.text(desc.prev).removeClass('back')
+      text?=desc.prev
+      @prevBtn.text(text).removeClass('back')
     @showPrevBtn()

   enableNext: ->


Add shim onload hook.

Add shim onload hook.

--- src/notifier.coffee
+++ src/notifier.coffee
@@ -15,6 +15,9 @@
   if shim.wrap?
     client.wrap = shim.wrap

+  if shim.onload?
+    shim.onload(client)
+
   # Consume any errors already pushed to the shim.
   for err in shim
     client.push(err)


Removing unnecessary require causing problems

--- dit4c-highcommand/app/assets/javascripts/app.coffee
+++ dit4c-highcommand/app/assets/javascripts/app.coffee
@@ -1,6 +1,5 @@
 define([
     'angular',
-    'ui-bootstrap',
     'ui-bootstrap-tpls',
     './controllers/index',
     './directives/index',


Spe fix

Spe fix

--- apps/personalize/test/client/categories.coffee
+++ apps/personalize/test/client/categories.coffee
@@ -76,12 +76,12 @@
     beforeEach ->
       @html = @view.$el.html()
     it 'renders the featured categories', ->
-      @html.should.containEql 'url(a/original)'
+      @html.should.containEql 'url(a/wide)'
       @html.should.containEql '
A
'
       @html.should.containEql 'data-id="a"'

     it 'renders the secondary categories', ->
-      @html.should.containEql 'src="b/original'
+      @html.should.containEql 'src="b/wide'
       @html.should.containEql '
B
'
       @html.should.containEql 'data-id="b"'