webapp: first steps towards making the file listing a dropzone

--- src/smc-webapp/project_files.cjsx
+++ src/smc-webapp/project_files.cjsx
@@ -22,6 +22,8 @@
 {React, ReactDOM, rtypes, rclass, Redux} = require('./smc-react')
 {Col, Row, ButtonToolbar, ButtonGroup, MenuItem, Button, Well, Input,
  ButtonToolbar, Popover, OverlayTrigger, SplitButton, MenuItem, Alert} =  require('react-bootstrap')
+ReactDOMServer = require('react-dom/server')   # for dropzone below
+Dropzone = require('react-dropzone-component')
 misc = require('smc-util/misc')
 {ActivityDisplay, DeletedProjectWarning, DirectoryInput, Icon, Loading, ProjectState, SAGE_LOGO_COLOR
  SearchInput, TimeAgo, ErrorDisplay, Space, Tip, LoginLink, Footer} = require('./r_misc')
@@ -512,6 +514,9 @@
     getDefaultProps : ->
         file_search : ''

+    getInitialState : ->
+        dragover    : false
+
     render_row : (name, size, time, mask, isdir, display_name, public_data, index) ->
         checked = @props.checked_files.has(misc.path_to_file(@props.current_path, name))
         is_public = @props.file_map[name].is_public
@@ -561,6 +566,14 @@
         @props.actions.set_current_path(path, update_file_listing=true)
         @props.actions.set_url_to_path(path)

+    dragover : (e, enter) ->
+        #e.preventDefault()
+        @setState(dragover: enter)
+        if enter
+            console.log "dragarea entered"#, e
+        else
+            console.log "dragarea left"#, e
+
     parent_directory : ->
         styles =
             fontWeight   : 'bold'
@@ -602,13 +615,39 @@
         if @props.file_search[0] == TERM_MODE_CHAR
             <TerminalModeDisplay/>

+    dropzone_template : ->
+

+

+

+
+

+

+
<Icon name='check'>

+
<Icon name='times'>

+

+

+
     render : ->
-        <Col sm=12>
-            {@render_terminal_mode()}
-            {@parent_directory()}
-            {@render_rows()}
-            {@render_no_files()}
-        </Col>
+        if @state.dragover
+            <Col sm=12 onDragLeave={(e) => @dragover(e, false)}>
+                <Tip icon='file' title='Drag and drop files'
+                    tip='Drag and drop files from your computer into the box below to upload them into your project.  You can upload individual files that are up to 30MB in size.'>
+
Drag and drop files (Currently, each file must be under 30MB; for bigger files, use SSH as explained in project settings.)

+                </Tip>
+

+                    <Dropzone
+                        config={postUrl: @postUrl }
+                        eventHandlers={{}}
+                        djsConfig={previewTemplate: ReactDOMServer.renderToStaticMarkup(@dropzone_template())} />
+

+            </Col>
+        else
+            <Col sm=12 onDragEnter={(e) => @dragover(e, true)}>
+                {@render_terminal_mode()}
+                {@parent_directory()}
+                {@render_rows()}
+                {@render_no_files()}
+            </Col>

 EmptyTrash = rclass
     displayName : 'ProjectFiles-EmptyTrash'


Make Dir Separator platform-aware

Make Dir Separator platform-aware

--- lib/add-dialog.coffee
+++ lib/add-dialog.coffee
@@ -12,7 +12,9 @@
     else
       directoryPath = initialPath
     relativeDirectoryPath = atom.project.relativize(directoryPath)
-    relativeDirectoryPath += '/' if relativeDirectoryPath.length > 0
+
+    dirSeparator = if process.platform is 'win32' then '\\' else '/'
+    relativeDirectoryPath += dirSeparator if relativeDirectoryPath.length > 0

     super
       prompt: "Enter the path for the new " + if isCreatingFile then "file." else "folder."
@@ -22,7 +24,7 @@

   onConfirm: (relativePath) ->
     relativePath = relativePath.replace(/\s+$/, '') # Remove trailing whitespace
-    endsWithDirectorySeparator = /\/$/.test(relativePath)
+    endsWithDirectorySeparator = /\/|\\$/.test(relativePath)
     pathToCreate = atom.project.resolve(relativePath)
     return unless pathToCreate

@@ -31,7 +33,7 @@
         @showError("'#{pathToCreate}' already exists.")
       else if @isCreatingFile
         if endsWithDirectorySeparator
-          @showError("File names must not end with a '/' character.")
+          @showError("File names must not end with a '#{dirSeparator}' character.")
         else
           fs.writeFileSync(pathToCreate, '')
           atom.project.getRepo()?.getPathStatus(pathToCreate)


Collaboration: Toggle modify flag

Collaboration: Toggle modify flag

--- client/ide/workspace/panes/editorpane.coffee
+++ client/ide/workspace/panes/editorpane.coffee
@@ -229,6 +229,10 @@

     @setContent string.getText(), no

+    ace = @getAce()
+    if ace.contentChanged = ace.isCurrentContentChanged()
+      ace.emit 'FileContentChanged'
+

   listenCollaborativeStringChanges: ->


Added parens

Added parens

--- lib/atom-utils.coffee
+++ lib/atom-utils.coffee
@@ -133,7 +133,7 @@

   extractImportPath: (moduleName) ->
     # look for `import moduleName from 'path/to/module'`
-    importPath = @getEditor().getText().match 'import ' + moduleName + ' from [\'"](.*?)[\'"]'
+    importPath = @getEditor().getText().match('import ' + moduleName + ' from [\'"](.*?)[\'"]')
     return importPath?[1]

   extractProjectName: (json) ->


Remove the check for app.settings.env in the middleware.

This has no place in this module.

--- src/client-compile.coffee
+++ src/client-compile.coffee
@@ -251,8 +251,6 @@
     Compiler: Compiler
     middleware: (basepath, options) ->
         (req, res, next) ->
-            return next() if req.app.settings.env != 'development'
-
             found = false
             for name, opts of options
                 if req.url == "/js/#{name}.bundle.js"


Add context menu to toggle the minimap

Add context menu to toggle the minimap

Closes #326

--- menus/minimap.cson
+++ menus/minimap.cson
@@ -10,3 +10,10 @@
     ]
   }
 ]
+'context-menu':
+  'atom-text-editor': [
+    {
+      'label': 'Toggle Minimap'
+      'command': 'minimap:toggle'
+    }
+  ]


refactor(util/getCurrentProfile): put callback into the event loop queue

Don't execute callback immediately in an async method.

--- src/util/getCurrentProfile.coffee
+++ src/util/getCurrentProfile.coffee
@@ -32,6 +32,7 @@
 			version: version
 		winston.verbose "util.getCurrentProfile: success", result

-		callback undefined, result
+		setTimeout ->
+			callback undefined, result

 module.exports = getCurrentProfile


Fix Spec

Fix Spec

--- spec/gocode-spec.coffee
+++ spec/gocode-spec.coffee
@@ -115,7 +115,7 @@
         expect(provider.getSuggestions.calls.length).toBe(1)
         expect(editorView.querySelector('.autocomplete-plus')).toExist()
         expect(editorView.querySelector('.autocomplete-plus span.word').innerHTML).toBe('Print(a ...interface)')
-        expect(editorView.querySelector('.autocomplete-plus span.completion-label').innerHTML).toBe('func')
+        expect(editorView.querySelector('.autocomplete-plus span.left-label').innerHTML).toBe('n int, err error')
         editor.backspace()

     xit 'does not display suggestions when no gocode suggestions exist', ->


Should remove field if false

Should remove field if false

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -74,7 +74,10 @@
     keydown keys, event
   else
     for key in keys.split('')
-      event.shift = key.match(/[A-Z]/)
+      if key.match(/[A-Z]/)
+        event.shift = true
+      else
+        delete event.shift
       keydown key, event

 isPoint = (obj) ->


Make error messages more descriptive

Make error messages more descriptive

--- app/assets/javascripts/admin/order_cycle.js.erb.coffee
+++ app/assets/javascripts/admin/order_cycle.js.erb.coffee
@@ -203,7 +203,7 @@
       	  if data['success']
       	    $window.location = '/admin/order_cycles'
       	  else
-      	    console.log('fail')
+            console.log('Failed to create order cycle')

       update: ->
       	oc = new OrderCycle({order_cycle: this.dataForSubmit()})
@@ -211,7 +211,7 @@
       	  if data['success']
       	    $window.location = '/admin/order_cycles'
       	  else
-      	    console.log('fail')
+            console.log('Failed to update order cycle')

       dataForSubmit: ->
         data = angular.extend({}, this.order_cycle)


FIx map refresh condition if shape is empty. Related to #759.

--- app/assets/javascripts/backend/interventions.js.coffee
+++ app/assets/javascripts/backend/interventions.js.coffee
@@ -52,10 +52,11 @@
                   element.selector('value', value)
             else if element.is(":ui-mapeditor")
               value = $.parseJSON(value)
-              element.mapeditor "show", value
-              element.mapeditor "edit", value
-              try
-                element.mapeditor "view", "edit"
+              if (value.geometries? and value.geometries.length > 0) || (value.coordinates? and value.coordinates.length > 0)
+                element.mapeditor "show", value
+                element.mapeditor "edit", value
+                try
+                  element.mapeditor "view", "edit"
             else if element.is('select')
               element.find("option[value='#{value}']")[0].selected = true
             else


Add Utils.getQueryString method

Add Utils.getQueryString method

--- app/assets/javascripts/martian_components/utils.coffee
+++ app/assets/javascripts/martian_components/utils.coffee
@@ -21,3 +21,14 @@
       when window.innerWidth >= 768 && window.innerWidth < 992 then 'sm'
       when window.innerWidth >= 992 && window.innerWidth < 1200 then 'md'
       when window.innerWidth >= 1200 then 'lg'
+
+  # Based on http://gomakethings.com/how-to-get-the-value-of-a-querystring-with-native-javascript/
+  @getQueryString: (field, url) ->
+    href = url || window.location.href
+    reg = new RegExp('[?&]' + field + '=([^&#]*)', 'i')
+    string = reg.exec(href)
+
+    if string
+      decodeURIComponent(string[1]).replace(/\+/g, ' ')
+    else
+      null


other manufacturer display working again

--- app/assets/javascripts/views/bikes/bikes_new.js.coffee
+++ app/assets/javascripts/views/bikes/bikes_new.js.coffee
@@ -88,8 +88,7 @@
       ).done (data) ->
         that.getModelList(data.manufacturer.name)

-  otherManufacturerDisplay: ->
-    current_value = $('#bike_manufacturer_id').val()
+  otherManufacturerDisplay: (current_value) ->
     expand_value = $('#bike_manufacturer_id').parents('.input-group').find('.other-value').text()
     hidden_other = $('#bike_manufacturer_id').parents('.input-group').find('.hidden-other')
     if parseInt(current_value, 10) == parseInt(expand_value, 10)
@@ -128,6 +127,7 @@
     that = @
     $(target).on "change", (e) ->
       id = e.val
+      that.otherManufacturerDisplay(id)
       console.log("#{window.root_url}/api/v1/manufacturers/#{id}")
       $.ajax("#{window.root_url}/api/v1/manufacturers/#{id}",
       ).done (data) ->


fixed coordinate transform bug

fixed coordinate transform bug

--- app/controllers/Annotation.coffee
+++ app/controllers/Annotation.coffee
@@ -34,6 +34,17 @@
     # Create the root SVG group
     @gRoot = document.createElementNS(@svgns, "g")
     @gRoot.setAttribute("transform", "translate(#{@x}, #{@y})")
+
+    # Apply coordinate transforms
+    halfWidth = Annotation.halfWidth
+    halfHeight = Annotation.halfHeight
+    zoom = Annotation.zoom
+
+    deltaX = halfWidth + Annotation.xOffset
+    deltaY = halfHeight + Annotation.yOffset
+
+    @x = (@x - halfWidth) / zoom + halfWidth - deltaX
+    @y = (@y - halfHeight) / zoom + halfHeight + deltaY

     # Append elements to root group
     @gRoot.appendChild(@gBox)


set up event handler onChangeSupplementalOption

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -52,6 +52,7 @@
     'mouseenter #course-yes-container'       : 'onMouseoverCourseYes'
     'mouseleave  #course-yes-container'      : 'onMouseoutCourseYes'
     'change #course-interval'                : 'onChangeCourseInterval'
+    'change .supplemental-option'            : 'onChangeSupplementalOption'

   constructor: ->
     super
@@ -120,6 +121,9 @@
     @el.find('#course-interval-setter').hide 400, =>
       @blockCourseIntervalDisplay = false
   # /////////////////////////////////////////////////
+
+  onChangeSupplementalOption: ->
+    console.log 'onChangeSupplementalOption(): '

   onChangeCourseInterval: ->
     # console.log 'VALUE: ', @el.find('#course-interval').val()
@@ -484,7 +488,7 @@

         newElement = document.createElement('div')
         newElement.setAttribute 'class', "supplemental-tutorial-option-container"
-        newElement.setAttribute 'style', "float: right; padding: 5px;"
+        newElement.setAttribute 'style', "float: 1right; padding: 5px;"
         newElement.innerHTML = """
           <input class=\"supplemental-option\" type=\"checkbox\"></input>
           <label>Do not show tips in the fiture.</label>


Don't keep reveal count unless signed in

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -130,7 +130,7 @@

     availableSubjects = CycloneSubject.count()

-    if availableSubjects is 1
+    if User.current and availableSubjects is 1
       User.current.project.reveal_count or= 0
       User.current.project.reveal_count += 1
       @classification.annotate 'last_image', true


removing oab catches - too much to change

--- server/accounts.coffee
+++ server/accounts.coffee
@@ -132,10 +132,6 @@

 API.accounts.token = (tok, send=true) ->
-  try
-    if tok and typeof tok is 'object' and tok.location? and typeof tok.location is 'string' and tok.location.indexOf('openaccessbutton.org') isnt -1
-      delete tok.location
-      tok.service = 'openaccessbutton'
   settings = API.settings.service?[tok.service]?.accounts ? API.settings.accounts
   settings.cookie ?= API.settings.accounts?.cookie
   settings.timeout ?= 30
@@ -223,10 +219,6 @@
 # login requires params.hash OR params.email and params.token OR params.timestamp and params.resume OR user
 # should provide url and service name too, and device fingerprint will be saved if provided
 API.accounts.login = (params, user, request) ->
-  try
-    if params and typeof params is 'object' and params.location? and typeof params.location is 'string' and params.location.indexOf('openaccessbutton.org') isnt -1
-      delete params.location
-      params.service = 'openaccessbutton'
   Tokens.remove 'timeout:<' + Date.now() # get rid of old tokens
   token
   user = API.accounts.retrieve(user) if typeof user is 'string'


Removing superfluous calls to undelegateEvents

--- ribs.coffee
+++ ribs.coffee
@@ -402,7 +402,6 @@

         renderList: ->
             for view in @subviews("list")
-                view.undelegateEvents()
                 view.render()
                 view.delegateEvents()

@@ -519,7 +518,6 @@

             # Render our individual cells
             for cell in @listItemCells
-                cell.undelegateEvents()
                 @$el.append cell.el
                 cell.render()
                 cell.delegateEvents()
@@ -527,7 +525,6 @@
             # Add inline actions.
             ul = $ "<ul/>", class: "actions"
             for inlineAction in @inlineActions
-                inlineAction.undelegateEvents()
                 $(ul).append inlineAction.el
                 inlineAction.render()
                 inlineAction.delegateEvents()


Update workload_list_item_view.coffee

Update workload_list_item_view.coffee

--- app/assets/javascripts/admin/views/workload/workload_list_item_view.coffee
+++ app/assets/javascripts/admin/views/workload/workload_list_item_view.coffee
@@ -10,7 +10,7 @@
   template : _.template("""
     <%- name %>

-      <% _.each(teams, function(team){ %>
+      <% _.each(teams.sort(), function(team){ %>
           <span class="label label-default" style="background-color: <%- TemplateHelpers.stringToColor(team) %>"><%- team %>
       <% }) %>


add comment to rebuild semaphore

add comment to rebuild semaphore

--- app/assets/javascripts/components/participant-selector-component.js.coffee
+++ app/assets/javascripts/components/participant-selector-component.js.coffee
@@ -24,7 +24,7 @@
     new Handlebars.SafeString "<img alt='#{name}' class='user-thumbnail-small' src='#{url}' data-toggle='tooltip' title='#{name}'/>"

   sortByCollaboration: (a, b) ->
-    # sort first by if they are collabs, then by name
+    # sort first by if they are collaborators, then by name
     # works, consider enhancing
     if a.roles.length && !b.roles.length
       -1


Add a placeholder name for new timelets.

--- app/assets/javascripts/modules/timelet/views/composites/timelets.js.coffee
+++ app/assets/javascripts/modules/timelet/views/composites/timelets.js.coffee
@@ -27,7 +27,7 @@
   # @param [jQuery.Event] event the click event
   #
   createTimelet: (event) =>
-    model = new Essence.Models.Timelet
+    model = new Essence.Models.Timelet name: 'New Timelet'
     model.state.expanded = true
     @collection.add model
     Backbone.history.navigate '/timelet'


#567 Enable static moving in trackball controls

--- app/assets/javascripts/oxalis/controller/viewmodes/plane_controller.coffee
+++ app/assets/javascripts/oxalis/controller/viewmodes/plane_controller.coffee
@@ -143,6 +143,7 @@

     @controls.noZoom = true
     @controls.noPan = true
+    @controls.staticMoving = true

     @controls.target.set(
       @model.scaleInfo.voxelToNm(@flycam.getPosition())...)


added server action

added server action

--- lib/dispatcher.coffee
+++ lib/dispatcher.coffee
@@ -5,4 +5,7 @@
   handleViewAction: (action) ->
     @dispatch source: 'VIEW_ACTION', action: action

-module.exports = new AppDispatcher()
+  handleServerAction: (action) ->
+    @dispatch source: 'SERVER_ACTION', action: action
+
+module.exports = new AppDispatcher()


Small prettify.

Small prettify.

--- src/compilers/base.coffee
+++ src/compilers/base.coffee
@@ -7,7 +7,7 @@
 # Takes 2-element array.
 # Examples
 #
-#   > group [['a', 1], ['b', 2], ['a', 3], ['c', 4], ['a', 0]]
+#   coffee> group [['a', 1], ['b', 2], ['a', 3], ['c', 4], ['a', 0]]
 #   [['a', [1, 3, 0]], ['b', [2]], ['c', [4]]]
 #
 # Returns new array in format [[key, values]].
@@ -130,12 +130,11 @@

   map: (file, callback) ->
     fs.readFile file, (error, result) =>
-      console.log 'EREAJIAWJADJOASOIDJS', error if error?
       callback error, result.toString()

   reduce: (memo, file, callback) ->
     memo ?= ''
-    callback null, memo + file.toString()
+    callback null, memo + file

   write: (data, callback) ->
     @globalWriteQueue.add [@getBuildPath(@destination), data], callback


fix for loader

fix for loader

--- client/app/Applications/Groups.kdapplication/Views/permissionsmodal.coffee
+++ client/app/Applications/Groups.kdapplication/Views/permissionsmodal.coffee
@@ -59,7 +59,6 @@
                 style     : "add-role-cancel modal-cancel"
                 cssClass  : 'add-role-cancel'
                 callback  : =>
-                  @buttons["Add Role"].hideLoader()
                   addRoleDialog.hide()

           addRoleDialog.addSubView wrapper = new KDView


Teamwork: Fixed emptying the file content when page reloaded.

--- client/landing/CollaborativeWorkspace/panes/collaborativeeditorpane.coffee
+++ client/landing/CollaborativeWorkspace/panes/collaborativeeditorpane.coffee
@@ -28,7 +28,10 @@
     @setData file
     isLocalFile = file.path.indexOf("localfile") is 0
     content     = "" if @amIHost and isLocalFile
-    @firepad.setText content  if @amIHost
+
+    if @amIHost and not @getOptions().useFirepadContent
+      @firepad.setText content
+
     @codeMirrorEditor.scrollTo 0, 0
     @emit "OpenedAFile", file, content


Wrap-around reactive array

Wrap-around reactive array

--- src/config/turtles.coffee
+++ src/config/turtles.coffee
@@ -58,7 +58,7 @@
     signal = program.at(counter)
     action = world.get('signals')[signal]
     counter = counter + 1
-    counter= 0 if counter >= program.length
+    counter= 0 if counter >= program.length()
     world.put('program_counter', counter)
     turtles = world.find_parent 'turtles'
     turtles.map_children (child) ->


Cleanup turtle file

Cleanup turtle file

--- src/config/turtles.coffee
+++ src/config/turtles.coffee
@@ -14,17 +14,10 @@
    a3,2 0 0,0 #{2*scale},0
    a3,2 0 0,0 #{-2*scale},0
    z m#{-3.5*scale},0"
-
-draw_eyes = (scale) ->
-  "m#{3.3*scale},0.3
-   a3,2 0 1,0 #{-0.4*scale},0
-   a3,2 0 1,0 #{0.4*scale},0
-   z "

 draw_shell = (scale) ->
   "m#{-3*scale},0 a3,2 0 1,0 #{6*scale},0
-   m0,0           a3,2 0 1,0 #{-6*scale},0z
-  "
+   m0,0           a3,2 0 1,0 #{-6*scale},0z"

 exports.turtles = {
   _LABEL: "turtles"
@@ -42,10 +35,7 @@
     value
   path: (world, args) ->
     scale = world.get('scale') / 10
-    [
-      draw_legs(scale) + draw_face(scale)# + draw_eyes(scale)
-      draw_shell(scale)
-    ]
+    [draw_legs(scale) + draw_face(scale), draw_shell(scale)]
   go: (world, args) ->
     split = world.get('split')
     {dir} = args
@@ -57,19 +47,16 @@
     assert dir, "expects dir"
     next_v_i =  dir * world.get('v_j')
     next_v_j = -1 * dir * world.get('v_i')
-    #console.log "turn[#{dir}]: #{next_v_i} x #{next_v_j}"
     world.put 'v_i', next_v_i
     world.put 'v_j', next_v_j
-  actions: [["go", {dir: 1}],["turn", {dir: 1}],["go", {dir: 1}],["turn", {dir: -1}]]
-  program: ['front', 'left', 'front', 'right']
+
+  program: ['front', 'right', 'front', 'left']
   program_counter: 0
-  action_index: 0
   step: (world, args) ->
     program = world.get('program')
     counter = world.get('program_counter')
     signal = program[counter]
     action = world.get('signals')[signal]
-
     counter = counter + 1
     counter= 0 if counter >= program.length
     world.put('program_counter', counter)


Activity: fixed activity routes for itself and for its sub-routes

--- client/Social/Activity/AppController.coffee
+++ client/Social/Activity/AppController.coffee
@@ -2,7 +2,14 @@

   KD.registerAppClass this,
     name         : "Activity"
-    route        : "/:name?/Activity/:slug?"
+    routes       :
+      "/:name?/Activity/:slug?" : ({params:{name, slug}, query})->
+        {router, appManager} = KD.singletons
+
+        unless slug
+        then router.openSection 'Activity', name, query
+        else router.createContentDisplayHandler('Activity') arguments...
+
     searchRoute  : "/Activity?q=:text:"
     hiddenHandle : yes


client: fix bug where prefetched was conflicting with popular posts

--- client/Social/Activity/AppController.coffee
+++ client/Social/Activity/AppController.coffee
@@ -14,7 +14,7 @@
       { command: 'previous tab',  binding: 'alt+[',    global: yes }
     ]

-  firstFetch = yes
+  FIRST_FETCH = yes

   constructor: (options = {}) ->

@@ -74,31 +74,35 @@
     socialapi.message.sendPrivateMessage options, callback

+  isCorrectPath = (key)->
+    return true  unless key is "navigated"
+
+    {router} = KD.singletons
+    {section, name, slug} = KD.socialApiData.navigated
+    routeToLookUp  = "#{name}/#{section}"
+    routeToLookUp += "/#{slug}"  if slug and slug isnt '/'
+
+    return router.getCurrentPath().search(routeToLookUp) > 0
+

   fetch: ({channelId, from, limit, skip, mostLiked}, callback = noop) ->

     prefetchedKey = if mostLiked then "popularPosts" else "navigated"
     id = channelId
-    {socialapi, router} = KD.singletons
+    {socialapi} = KD.singletons
     {socialApiChannelId} = KD.getGroup()
     id ?= socialApiChannelId
     prefetchedItems = socialapi.getPrefetchedData prefetchedKey

-    isCorrectPath = ->
-      {section, name, slug} = KD.socialApiData.navigated
-      routeToLookUp  = "#{name}/#{section}"
-      routeToLookUp += "/#{slug}"  if slug and slug isnt '/'
-
-      return router.getCurrentPath().search(routeToLookUp) > 0
-
-    if firstFetch and prefetchedItems.length > 0 and isCorrectPath()
+    if FIRST_FETCH and prefetchedItems.length > 0 and isCorrectPath(prefetchedKey)
       messages = socialapi.getPrefetchedData prefetchedKey
       KD.utils.defer ->  callback null, messages
     else
       if mostLiked then @fetchMostLikedPosts({skip, limit}, callback)
       else socialapi.channel.fetchActivities {id, from, limit}, callback

-    firstFetch = no
+    FIRST_FETCH = no
+

   fetchMostLikedPosts : (options, callback)->
     options.group       = KD.getGroup().slug


Activity: avoid redirection bug, temp fix until we have #koding and #public tags in the default db setup

--- client/Social/Activity/AppController.coffee
+++ client/Social/Activity/AppController.coffee
@@ -75,6 +75,13 @@
     {socialApiChannelId} = KD.getGroup()
     id ?= socialApiChannelId

+    # FIXME
+    # remove this once there are koding and public channels in default db setup
+    # otherwise this will continue pollute your feeds - SY
+    if firstFetch
+      {generatePassword, getRandomNumber} = KD.utils
+      KD.singletons.socialapi.message.post body: "Hello world, #{generatePassword getRandomNumber(7), yes} #koding #public", log
+
     if firstFetch and socialapi.getPrefetchedData('navigated').length > 0
       messages   = socialapi.getPrefetchedData 'navigated'
       KD.utils.defer ->  callback null, messages


Use the augment method correctly following location as string instead of array

--- src/d3-flame-graph.coffee
+++ src/d3-flame-graph.coffee
@@ -122,7 +122,7 @@

       # initial processing of data
       @console.time('augment')
-      @original = d3.flameGraphUtils.augment(root, [0])
+      @original = d3.flameGraphUtils.augment(root, '0')
       @console.timeEnd('augment')
       @root(@original)


:lipstick:

:lipstick:

--- src/display-buffer.coffee
+++ src/display-buffer.coffee
@@ -1064,6 +1064,7 @@

   computeScrollWidth: ->
     @scrollWidth = @pixelPositionForScreenPosition([@longestScreenRow, @maxLineLength]).left + 1
+
   handleBufferMarkersUpdated: =>
     if event = @pendingChangeEvent
       @pendingChangeEvent = null


Use deserialized display layer when possible

--- src/display-buffer.coffee
+++ src/display-buffer.coffee
@@ -52,7 +52,7 @@
       @grammarRegistry, @packageManager, @assert
     })
     @buffer = @tokenizedBuffer.buffer
-    @displayLayer = @buffer.addDisplayLayer()
+    @displayLayer = @buffer.getDisplayLayer() ? @buffer.addDisplayLayer()
     @displayLayer.setTextDecorationLayer(@tokenizedBuffer)
     @charWidthsByScope = {}
     @defaultMarkerLayer = @displayLayer.addMarkerLayer()


Events: Fix touch events and make them more efficient

--- engine/events.coffee
+++ engine/events.coffee
@@ -79,7 +79,7 @@
         touch_start = (event)=>
             event.preventDefault()
             for t in event.targetTouches
-                touch = {}
+                touch = @touch.touch_events[t.identifier] or {}
                 touch.touching = true
                 touch.id = t.identifier
                 touch.client_x = t.clientX
@@ -108,16 +108,13 @@
             event.preventDefault()
             for id,touch of @touch.touch_events
                 touch.touching = false
-            for t in event.targetTouches
-                touch = @touch.touch_events[t.identifier]
-                touch.touching = true
-                touch.force = 0
-                touch.radius_x = 0
-                touch.radius_y = 0
-                touch.rel_x = 0
-                touch.rel_y = 0
+            touch_start(event)
             for id,touch of @touch.touch_events when not touch.touching
+                if @touch.first_touch_event == touch
+                    @touch.first_touch_event = null
                 delete @touch.touch_events[id]
+            if @touch.first_touch_event == null and event.targetTouches.length != 0
+                @touch.first_touch_event = @touch.touch_events[event.targetTouches.identifier]
             if event.targetTouches.length == 0
                 @touch.first_touch_event = null
             @touch.touches = event.targetTouches.length
@@ -131,7 +128,11 @@
             event.preventDefault()

             for t in event.targetTouches
-                touch = {}
+                touch = @touch.touch_events[t.identifier] or {}
+                x = t.clientX
+                y = t.clientY
+                rel_x = x - (touch.client_x or 0)
+                rel_y = y - (touch.client_y or 0)
                 touch.id = t.identifier
                 touch.touching = true
                 touch.client_x = t.clientX
@@ -144,15 +145,9 @@
                 touch.rotation_angle = t.rotationAngle
                 touch.x = t.clientX - root_element.rect.left
                 touch.y = t.clientY - root_element.rect.top
-                x = t.clientX
-                y = t.clientY
-                if @touch.touch_events[touch.id]?
-                    touch.rel_x = x - @touch.touch_events[touch.id].client_x
-                    touch.rel_y = y - @touch.touch_events[touch.id].client_y
-                else
-                    touch.rel_x = 0
-                    touch.rel_y = 0
-                touch.movement_since_touch = Math.abs(touch.rel_x) + Math.abs(touch.rel_y)
+                touch.rel_x = rel_x
+                touch.rel_y = rel_y
+                touch.movement_since_touch = Math.abs(rel_x) + Math.abs(rel_y)
                 @touch.touch_events[touch.id] = touch
             @touch.touches = event.targetTouches.length


Duplicate code in SymbolsView for futher modification

--- lib/go-to-view.coffee
+++ lib/go-to-view.coffee
@@ -7,6 +7,16 @@
 class GoToView extends SymbolsView
   constructor: (@stack) ->
     super
+
+  viewForItem: ({position, name, file}) ->
+    $$ ->
+      @li class: 'two-lines', =>
+        @div name, class: 'primary-line'
+        if position
+          text = "Line #{position.row + 1}"
+        else
+          text = path.basename(file)
+        @div text, class: 'secondary-line'

   toggle: ->
     if @hasParent()


Revert "Correct toolbar_location default to be the same default as python"

This reverts commit 5530449e3febc2d48a8f1b1173c54d77ca02833a.

--- bokehjs/src/coffee/api/plotting.coffee
+++ bokehjs/src/coffee/api/plotting.coffee
@@ -391,7 +391,7 @@
 color = (r, g, b) -> sprintf("#%02x%02x%02x", r, g, b)

 gridplot = (children, options={}) ->
-  toolbar_location = if _.isUndefined(options.toolbar_location) then 'right' else options.toolbar_location
+  toolbar_location = if _.isUndefined(options.toolbar_location) then 'left' else options.toolbar_location
   sizing_mode = if _.isUndefined(options.sizing_mode) then 'fixed' else options.sizing_mode

   tools = []


[LikeView]  Fixed "and 0 more" bug on like views

--- client/app/CommonViews/LikeView.coffee
+++ client/app/CommonViews/LikeView.coffee
@@ -77,12 +77,18 @@
             when 3 then "3 guests"

         tooltip =
-          switch peopleWhoLiked.length
+          switch data.meta.likes
             when 0 then "#{guestLikes}"
             when 1 then "#{peopleWhoLiked[0]} #{guestLikes}"
             when 2 then "#{peopleWhoLiked[0]} and #{peopleWhoLiked[1]} #{guestLikes}"
-            else "#{peopleWhoLiked[0]}#{sep}#{peopleWhoLiked[1]}#{sep}#{peopleWhoLiked[2]} and #{data.meta.likes - 3} more."
-
+            when 3 then "#{peopleWhoLiked[0]}#{sep}#{peopleWhoLiked[1]} and #{peopleWhoLiked[2]} #{guestLikes}"
+            else
+              # there is no guarantee that likes will not satisfy upper cases
+              # and it will be an integer which is more than 3
+              if data.meta.likes > 3
+                "#{peopleWhoLiked[0]}#{sep}#{peopleWhoLiked[1]}#{sep}#{peopleWhoLiked[2]} and #{data.meta.likes - 3} more."
+              else
+                ""
         @likeCount.getTooltip().update { title: tooltip }
         @_lastUpdatedCount = likes.length


Newkite improvements, ping handler and show error

--- client/app/MainApp/kite/newkite.coffee
+++ client/app/MainApp/kite/newkite.coffee
@@ -46,11 +46,13 @@
     xhr.send JSON.stringify requestData
     xhr.onload = =>
        if xhr.status is 200
-         data = JSON.parse xhr.responseText
-         @token = data[0].token
-         console.log {@token}
-         @addr = data[0].addr
-         @connectDirectly()
+          data = JSON.parse xhr.responseText
+          @token = data[0].token
+          console.log {@token}
+          @addr = data[0].addr
+          @connectDirectly()
+        else
+          log "kontrol request error", xhr.responseText

   disconnect:(reconnect=true)->
     @autoReconnect = !!reconnect  if reconnect?
@@ -72,14 +74,23 @@
     try
       args = JSON.parse evt.data
       {method} = args
-      # console.log "received", {args}
-      callback = @localStore.get method
+      callback = switch method
+        when 'ping'             then @bound 'handlePing'
+        else (@localStore.get method) ? ->
+
+      # callback = @localStore.get method
       callback.apply this, @unscrub args
     catch e
       console.log "error: ", e, evt.data

   onError: (evt) ->
     # console.log "#{@kiteName}: error #{evt.data}"
+
+  handlePing: ->
+    @send JSON.stringify
+      method      : 'pong'
+      arguments   : []
+      callbacks   : {}

   initBackoff:(options)->
     backoff = options.backoff ? {}
@@ -127,7 +138,7 @@
       callback scrubbed

   tell:(options, callback) ->
-    @ready =>
+    @ready =>
       # token is needed to initiate a valid session
       options.token = @token
       options.username  = "#{KD.nick()}"


Changed how data is loade

Changed how data is loade

--- client/app/main/main.controller.coffee
+++ client/app/main/main.controller.coffee
@@ -48,6 +48,10 @@
         console.log('cache found')
         loadPlayerData(playerCache)
       else
+        $scope.error = 'Loading Player Data'
+        $scope.profile = {}
+        $scope.gameLog = []
+        $scope.playerData = {}
         $http.get("/api/data/" + playerName).success(loadPlayerData).error(errorSearch)

   $scope.refreshPlayer = ->


KD: added an entry.coffee to compile a subset of KD

--- client/landing/app/coffee/entry.coffee
+++ client/landing/app/coffee/entry.coffee
@@ -1,32 +1,34 @@
-utils      = require './Framework/src/core/utils.coffee'
-KD         = require './Framework/src/core/kd.coffee'
-KD.classes = {}
-KD.classes.KDButtonView = require './Framework/src/components/buttons/buttonview.coffee'
-KD.classes.KDFormView = require './Framework/src/components/forms/formview.coffee'
-KD.classes.KDInputValidator = require './Framework/src/components/inputs/inputvalidator.coffee'
-KD.classes.KDInputView = require './Framework/src/components/inputs/inputview.coffee'
-KD.classes.KDLabelView = require './Framework/src/components/inputs/labelview.coffee'
-KD.classes.KDModalView = require './Framework/src/components/modals/modalview.coffee'
-KD.classes.KDNotificationView = require './Framework/src/components/notifications/notificationview.coffee'
-KD.classes.KDScrollThumb = require './Framework/src/components/scrollview/scrollthumb.coffee'
-KD.classes.KDScrollTrack = require './Framework/src/components/scrollview/scrolltrack.coffee'
-KD.classes.KDScrollView = require './Framework/src/components/scrollview/scrollview.coffee'
-KD.classes.KDTabHandleContainer = require './Framework/src/components/tabs/tabhandlecontainer.coffee'
-KD.classes.KDTabHandleMoveNav = require './Framework/src/components/tabs/tabhandlemovenav.coffee'
-KD.classes.KDTabHandleView = require './Framework/src/components/tabs/tabhandleview.coffee'
-KD.classes.KDTabPaneView = require './Framework/src/components/tabs/tabpaneview.coffee'
-KD.classes.KDTabView = require './Framework/src/components/tabs/tabview.coffee'
-KD.classes.KDCustomHTMLView = require './Framework/src/core/customhtmlview.coffee'
-KD.classes.KDRouter = require './Framework/src/core/router.coffee'
-KD.classes.KDObject = require './Framework/src/core/object.coffee'
-KD.classes.KDLoaderView = require './Framework/src/components/loader/loaderview.coffee'
-KD.classes.KDView = require './Framework/src/core/view.coffee'
-KD.classes.KDController = require './Framework/src/core/controller.coffee'
-KD.classes.KDViewController = require './Framework/src/core/viewcontroller.coffee'
-KD.classes.KDListView = require './Framework/src/components/list/listview.coffee'
-KD.classes.KDListItemView = require './Framework/src/components/list/listitemview.coffee'
-KD.classes.KDListViewController = require './Framework/src/components/list/listviewcontroller.coffee'
-KD.classes.KDKeyboardListener = require './Framework/src/core/keyboard/listener.coffee'
-KD.classes.KDKeyboardMap = require './Framework/src/core/keyboard/map.coffee'
-KD.classes.KDWindowController = require './Framework/src/core/windowcontroller.coffee'
-KD.exportKDFramework()
+utils                           = require './core/utils.coffee'
+KD                              = require './core/kd.coffee'
+KD.classes                      = {}
+KD.classes.KDObject             = require './core/object.coffee'
+KD.classes.KDView               = require './core/view.coffee'
+KD.classes.KDCustomHTMLView     = require './core/customhtmlview.coffee'
+KD.classes.KDRouter             = require './core/router.coffee'
+KD.classes.KDKeyboardListener   = require './core/keyboard/listener.coffee'
+KD.classes.KDKeyboardMap        = require './core/keyboard/map.coffee'
+KD.classes.KDController         = require './core/controller.coffee'
+KD.classes.KDViewController     = require './core/viewcontroller.coffee'
+KD.classes.KDWindowController   = require './core/windowcontroller.coffee'
+KD.classes.KDLoaderView         = require './components/loader/loaderview.coffee'
+KD.classes.KDButtonView         = require './components/buttons/buttonview.coffee'
+KD.classes.KDFormView           = require './components/forms/formview.coffee'
+KD.classes.KDInputValidator     = require './components/inputs/inputvalidator.coffee'
+KD.classes.KDInputView          = require './components/inputs/inputview.coffee'
+KD.classes.KDLabelView          = require './components/inputs/labelview.coffee'
+KD.classes.KDModalView          = require './components/modals/modalview.coffee'
+KD.classes.KDModalViewWithForms = require './components/modals/modalviewwithforms.coffee'
+KD.classes.KDNotificationView   = require './components/notifications/notificationview.coffee'
+KD.classes.KDScrollThumb        = require './components/scrollview/scrollthumb.coffee'
+KD.classes.KDScrollTrack        = require './components/scrollview/scrolltrack.coffee'
+KD.classes.KDScrollView         = require './components/scrollview/scrollview.coffee'
+KD.classes.KDTabHandleContainer = require './components/tabs/tabhandlecontainer.coffee'
+KD.classes.KDTabHandleMoveNav   = require './components/tabs/tabhandlemovenav.coffee'
+KD.classes.KDTabHandleView      = require './components/tabs/tabhandleview.coffee'
+KD.classes.KDTabPaneView        = require './components/tabs/tabpaneview.coffee'
+KD.classes.KDTabView            = require './components/tabs/tabview.coffee'
+KD.classes.KDListView           = require './components/list/listview.coffee'
+KD.classes.KDListItemView       = require './components/list/listitemview.coffee'
+KD.classes.KDListViewController = require './components/list/listviewcontroller.coffee'
+
+do KD.exportKDFramework


Fix error with device not defined

Fix error with device not defined

--- client/lib/cordova/keyboard-fix.coffee
+++ client/lib/cordova/keyboard-fix.coffee
@@ -1,11 +1,13 @@
 if Meteor.isCordova
-	if device.platform.toLowerCase() isnt 'android'
-		document.addEventListener 'deviceready', ->
+	document.addEventListener 'deviceready', ->
+		if device?.platform.toLowerCase() isnt 'android'
 			cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
 			cordova.plugins.Keyboard.disableScroll(true);

-		window.addEventListener 'native.keyboardshow', ->
+	window.addEventListener 'native.keyboardshow', ->
+		if device?.platform.toLowerCase() isnt 'android'
 			$('.main-content').css 'height', window.innerHeight

-		window.addEventListener 'native.keyboardhide', ->
+	window.addEventListener 'native.keyboardhide', ->
+		if device?.platform.toLowerCase() isnt 'android'
 			$('.main-content').css 'height', window.innerHeight


TextEditView focuses on textarea on click

--- client/src/views/text_edit_view.coffee
+++ client/src/views/text_edit_view.coffee
@@ -9,6 +9,11 @@
     "click .save-content": "saveContent"
     "click .add-content": "startEdit"
     "click .content-text": "startEdit"
+    "change textarea.content-text-field": "resize"
+    "cut textarea.content-text-field": "delayedResize"
+    "paste textarea.content-text-field": "delayedResize"
+    "drop textarea.content-text-field": "delayedResize"
+    "keydown textarea.content-text-field": "delayedResize"

   initialize: (options) ->
     @type   = options.type
@@ -21,7 +26,25 @@

     @$el.html(template(content: @report.get(@type), type: @type))

+    @text = @$el.find("textarea.content-text-field")
+    @text.focus()
+    @text.select()
+    @resize()
+
     return @
+
+  # Following 2 methods are used for dynamically resize the textarea.
+  # From: http://goo.gl/9gRC4H
+
+  resize: =>
+    if @text.length > 0
+      @text.css("height", "auto")
+      @text.css("height", @text[0].scrollHeight + "px")
+
+  # Used to push the resize method onto the event queue,
+  # ensuring it actually gets evaluated after the events have completed.
+  delayedResize: ->
+    setTimeout @resize, 0

   saveContent: (event) =>
     @report.set(@type,


Use JS date

Use JS date

--- models/article.coffee
+++ models/article.coffee
@@ -115,7 +115,7 @@
     crop @get(attr), args...

   date: (attr) ->
-    moment(@get(attr)).local()
+    moment(new Date(@get(attr))).local()

   strip: (attr) ->
     stripTags(@get attr)


[module] fix not returned input value in case of `number` in `printf()`

--- modules/printf.coffee
+++ modules/printf.coffee
@@ -10,7 +10,7 @@
  * @return {string} String with replaced placeholders
 ###
 module.exports = (input, placeholders...) ->
-  if typeof input == 'number' then return
+  if typeof input == 'number' then return input

   isObject = typeof input == 'object'
   input = if isObject then JSON.stringify(input) else input


Invert

Invert

--- modules/status.coffee
+++ modules/status.coffee
@@ -3,8 +3,8 @@
 class StatusModule extends BotModule
   ready: =>
     if Core.settings.debug
-      Core.bot.User.setStatus 'dnd', "#{Core.settings.prefix}help | focabot.xyz"
+      Core.bot.User.setStatus 'dnd', Core.settings.version
     else
-      Core.bot.User.setStatus 'online', Core.settings.version
+      Core.bot.User.setStatus 'online', "#{Core.settings.prefix}help | focabot.xyz"

 module.exports = StatusModule


updated methods

updated methods

--- src/drm-validation.coffee
+++ src/drm-validation.coffee
@@ -9,6 +9,7 @@
 ###
 "use strict"

+$ = jQuery
 class @DrmValidation
     constructor: (@speed = 300) ->
         self = @
@@ -36,7 +37,7 @@
             # mm/dd/yyyy
             monthDayYear: new RegExp '^(?:[0]?[1-9]|[1][012]|[1-9])[-\/.](?:[0]?[1-9]|[12][0-9]|[3][01])[-\/.][0-9]{4}$'
             # 00:00pm
-            time: new RegExp '^(?:[12][012]|[0]?[0-9]):[012345][0-9](?:am|pm)$', 'i'
+            time: new RegExp '^(?:[12][012]:|[0]?[0-9]:)[012345][0-9](?:\/:[012345][0-9])?(?:am|pm)$', 'i'
             # matched all major cc
             creditCard: new RegExp '^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$'
             cvv: new RegExp '^[0-9]{3,4}$'
@@ -49,6 +50,18 @@
             self.removeValidationClass.call @, validate.status
             self.applyValidationClass.call @, validate.status

+        validateFields = (fields, validate) ->
+            if validate.message?
+                self.issueNotice.call @, validate, self.speed
+                self.issueNotice.call requireField, validate, self.speed
+            else
+                self.removeNotice.call @, validate.issuer, self.speed
+                self.removeNotice.call requireField, validate.issuer, self.speed
+            self.removeValidationClass.call @, validate.status
+            self.applyValidationClass.call @, validate.status
+            self.removeValidationClass.call requireField, validate.status
+            self.applyValidationClass.call requireField, validate.status
+
         body.on 'click', ':disabled', (e) -> e.preventDefault()

         body.on 'keyup', ':input.drm-valid-integer', ->
@@ -235,21 +248,70 @@
                 self.removeValidationClass.call @
                 self.removeAllNotices.call @, self.speed

-        body.on 'blur', ':input[data-required-with]', ->
-            value = self.getValue.call @
-            validate = self.validateRequiredWith.call @, value
-            if validate?
-                validateField.call @, value, validate
+        body.on 'change', ':input[data-required-with]', ->
+            # need to monitor required field also
+            requireFieldId = $(@).data 'required-with'
+
+            if requireFieldId.search(':') isnt -1
+                requireFieldId = requireFieldId.split ':'
+                fieldId = requireFieldId[0]
+            else
+                fieldId = requireFieldId
+
+            requireField = $ "##{fieldId}"
+            validate = self.validateRequiredWith.call @
+            # issue and remove notices on both fields
+            if validate?
+                if validate.message?
+                    self.issueNotice.call @, validate, self.speed
+                    self.issueNotice.call requireField, validate, self.speed
+                else
+                    self.removeNotice.call @, validate.issuer, self.speed
+                    self.removeNotice.call requireField, validate.issuer, self.speed
+                self.removeValidationClass.call @, validate.status
+                self.applyValidationClass.call @, validate.status
+                self.removeValidationClass.call requireField, validate.status
+                self.applyValidationClass.call requireField, validate.status
+
+        body.on 'blur', ':input[data-require-with]', ->
+            # need to monitor required field also
+            requiredFieldId = $(@).data 'require-with'
+
+            if requiredFieldId.search(':') isnt -1
+                requiredFieldId = requiredFieldId.split ':'
+                fieldId = requiredFieldId[0]
+            else
+                fieldId = requiredFieldId
+
+            requiredField = $ "##{fieldId}"
+            validate = self.validateRequiredWith.call @
+            # issue and remove notices on both fields
+            if validate?
+                if validate.message?
+                    self.issueNotice.call @, validate, self.speed
+                    self.issueNotice.call requiredField, validate, self.speed
+                else
+                    self.removeNotice.call @, validate.issuer, self.speed
+                    self.removeNotice.call requiredField, validate.issuer, self.speed
+                self.removeValidationClass.call @, validate.status
+                self.applyValidationClass.call @, validate.status
+                self.removeValidationClass.call requiredField, validate.status
+                self.applyValidationClass.call requiredField, validate.status
+
+        body.on 'change', ':input[data-allowed-with]', ->
+            # remove disabled attribute on related field
+            value = self.getValue.call @
+            self.validateAllowedWith.call @, value

     trackLength: (value) ->
-        that = $ @
+        _that = $ @
         validate =
             status: 'length'
             message: null
             issuer: 'length-notice'
         if value?
-            length = value.length
-            validate.message = if length is 1 then "#{length} character" else "#{length} characters"
+            _length = value.length
+            validate.message = if _length is 1 then "#{_length} character" else "#{_length} characters"
         validate

     getValue: ->
@@ -258,22 +320,22 @@
         if value.length > 0 then value else null

     issueNotice: (validate, speed) ->
-        that = $ @
-        lengthNotice = that.nextUntil ':input', "p.form-length-notice"
-        notice = that.nextUntil ':input', "p.form-#{validate.status}-notice:contains(#{validate.message})"
+        _that = $ @
+        lengthNotice = _that.nextUntil ':input', "p.form-length-notice"
+        notice = _that.nextUntil ':input', "p.form-#{validate.status}-notice:contains(#{validate.message})"

         _addNotice = (item) ->
-            if that.css('float') isnt 'none'
-                noticeHolder = that.parent 'div.form-notice-holder'
-                if noticeHolder.length is 0
-                    that.wrap('

').focus()
-                    noticeHolder = that.parent 'div.form-notice-holder'
-                    item.hide().appendTo(noticeHolder).slideDown speed
+            if _that.css('float') isnt 'none'
+                _noticeHolder = _that.parent 'div.form-notice-holder'
+                if _noticeHolder.length is 0
+                    _that.wrap('

').focus()
+                    _noticeHolder = _that.parent 'div.form-notice-holder'
+                    item.hide().appendTo(_noticeHolder).slideDown speed
                 else
-                    item.hide().appendTo(noticeHolder).slideDown speed
-                noticeHolder.children().css 'float', 'none'
-            else
-                item.hide().insertAfter(that).slideDown speed
+                    item.hide().appendTo(_noticeHolder).slideDown speed
+                _noticeHolder.children().css 'float', 'none'
+            else
+                item.hide().insertAfter(_that).slideDown speed

         if validate.status is 'length' and lengthNotice.length is 0
             notice = $ '

',
@@ -296,46 +358,43 @@

     removeNotice: (issuer, speed) ->
         self = $ @
-        notice = self.nextUntil ':input', "p[data-issuer='#{issuer}']"
-
-        if notice.length isnt 0
-            notice.slideUp speed, ->
-                that = $ @
-                that.remove()
+        _notice = self.nextUntil ':input', "p[data-issuer='#{issuer}']"
+
+        if _notice.length isnt 0 then _notice.slideUp speed, -> $(@).remove()

     removeAllNotices: (speed) ->
-        that = $ @
-        notices = that.nextUntil ':input','p.form-notice'
-
-        if notices.length isnt 0
-            notices.slideUp speed, ->
+        _that = $ @
+        _notices = _that.nextUntil ':input','p.form-notice'
+
+        if _notices.length isnt 0
+            _notices.slideUp speed, ->
                 $(@).remove()

     applyValidationClass: (status) ->
-        that = $ @
+        _that = $ @

         switch status
-            when 'danger' then that.addClass 'drm-form-danger'
-            when 'warning' then that.addClass 'drm-form-warning'
-            when 'success' then that.addClass 'drm-form-success'
+            when 'danger' then _that.addClass 'drm-form-danger'
+            when 'warning' then _that.addClass 'drm-form-warning'
+            when 'success' then _that.addClass 'drm-form-success'

     removeValidationClass: (status) ->
-        that = $ @
+        _that = $ @

         switch status
             when 'danger'
-                that.removeClass 'drm-form-warning'
-                that.removeClass 'drm-form-success'
+                _that.removeClass 'drm-form-warning'
+                _that.removeClass 'drm-form-success'
             when 'warning'
-                that.removeClass 'drm-form-danger'
-                that.removeClass 'drm-form-success'
+                _that.removeClass 'drm-form-danger'
+                _that.removeClass 'drm-form-success'
             when 'success'
-                that.removeClass 'drm-form-danger'
-                that.removeClass 'drm-form-warning'
-            else
-                that.removeClass 'drm-form-danger'
-                that.removeClass 'drm-form-warning'
-                that.removeClass 'drm-form-success'
+                _that.removeClass 'drm-form-danger'
+                _that.removeClass 'drm-form-warning'
+            else
+                _that.removeClass 'drm-form-danger'
+                _that.removeClass 'drm-form-warning'
+                _that.removeClass 'drm-form-success'

     validateRequired: (value) ->
         validate =
@@ -365,8 +424,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateNumber: (value, pattern) ->
@@ -385,8 +444,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateURL: (value, pattern) ->
@@ -405,8 +464,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateEmail: (value, pattern) ->
@@ -425,8 +484,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validatePhone: (value, pattern) ->
@@ -445,8 +504,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateFullName: (value, pattern) ->
@@ -465,8 +524,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateAlpha: (value, pattern) ->
@@ -485,8 +544,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateAlphaNum: (value, pattern) ->
@@ -505,8 +564,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateNoSpaces: (value, pattern) ->
@@ -525,8 +584,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateAlphaNumDash: (value, pattern) ->
@@ -545,8 +604,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateAlphaNumUnderscore: (value, pattern) ->
@@ -565,8 +624,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateNoTags: (value, pattern) ->
@@ -585,8 +644,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateMonthDayYear: (value, pattern) ->
@@ -605,8 +664,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateTime: (value, pattern) ->
@@ -625,8 +684,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateCreditCard: (value, pattern) ->
@@ -645,8 +704,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateCvv: (value, pattern) ->
@@ -665,8 +724,8 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateZip: (value, pattern) ->
@@ -685,13 +744,13 @@
             validate

         if value?
-            pattern = new RegExp pattern
-            result = $.trim pattern.exec value
+            _pattern = new RegExp pattern
+            result = $.trim _pattern.exec value
             _evaluate result, value

     validateEqual: (value) ->
-        that = $ @
-        equal = that.data 'equal'
+        _that = $ @
+        equal = _that.data 'equal'
         validate =
             status: null
             message: null
@@ -710,8 +769,8 @@
             _evaluate equal, value

     validateNotEqual: (value) ->
-        that = $ @
-        notEqual = that.data 'not-equal'
+        _that = $ @
+        notEqual = _that.data 'not-equal'
         validate =
             status: null
             message: null
@@ -736,8 +795,8 @@
     validateSelect: () ->

     validateInList: (value) ->
-        that = $ @
-        list = that.data 'in-list'
+        _that = $ @
+        list = _that.data 'in-list'
         listItems = []
         listItems = list.split ','

@@ -748,9 +807,9 @@

         _evaluate = (listItems, value) ->
             if $.inArray(value, listItems) is -1
-                list = listItems.join ', '
-                validate.status = 'danger'
-                validate.message = "this field should be one of these: #{list}"
+                _list = listItems.join ', '
+                validate.status = 'danger'
+                validate.message = "this field should be one of these: #{_list}"
             else
                 validate.message = null
                 validate.status = 'success'
@@ -760,8 +819,8 @@
             _evaluate listItems, value

     validateNotList: (value) ->
-        that = $ @
-        list = that.data 'not-list'
+        _that = $ @
+        list = _that.data 'not-list'
         listItems = []
         listItems = list.split ','

@@ -772,9 +831,9 @@

         _evaluate = (listItems, value) ->
             if $.inArray(value, listItems) isnt -1
-                list = listItems.join ', '
-                validate.status = 'danger'
-                validate.message = "this field cannot be one of these: #{list}"
+                _list = listItems.join ', '
+                validate.status = 'danger'
+                validate.message = "this field cannot be one of these: #{_list}"
             else
                 validate.message = null
                 validate.status = 'success'
@@ -783,49 +842,91 @@
         if value?
             _evaluate listItems, value

-    validateRequiredWith: (value) ->
-        that = $ @
-        requiredWith = that.data 'required-with'
-        validate =
-            status: null
-            message: null
-            issuer: 'not-equal'
-
-        if requiredWith.search(':') isnt -1
-            requiredWith = requiredWith.split ':'
-            fieldID = requiredWith[0]
-            fieldValue = requiredWith[1]
-        else
-            fieldID = requiredWith
-
-        _evaluate = (value, fieldID, fieldValue) ->
-            field = $ "##{fieldID}"
-            requiredFieldValue = $.trim field.val()
-
-            checkValue = ->
-                if not value
+    validateRequiredWith: ->
+        # determine whether or not the field is required-with or require-with
+        # if field is required-with check to see that it is filled in
+        # if field is require-with check to see that required field is filled in
+        # if an action takes place on either field remove notices
+
+        _that = $ @
+        _requiredWith = _that.data 'required-with'
+        _requireWith = _that.data 'require-with'
+        console.log 'validating'
+
+        validate =
+            status: null
+            message: null
+            issuer: 'requiredWith'
+
+        if _requiredWith
+
+            if _requiredWith.search(':') isnt -1
+                _requiredWith = _requiredWith.split ':'
+                fieldId = _requiredWith[0]
+                fieldValue = _requiredWith[1]
+            else
+                fieldId = _requiredWith
+
+        else if _requireWith
+
+            if _requireWith.search(':') isnt -1
+                _requireWith = _requireWith.split ':'
+                fieldId = _requireWith[0]
+                fieldValue = _requireWith[1]
+            else
+                fieldId = _requireWith
+
+        _evaluate = (fieldId, fieldValue) ->
+            # if criteria is met then required field must be filled out
+            # fieldId = _that.attr 'id'
+            requiredField = if _requiredWith then $("##{fieldId}") else _that
+            requiredFieldId = if _requiredWith then fieldId else _that.attr 'id'
+            requiredFieldValue = $.trim requiredField.val()
+            requireField = if _requireWith then $("##{fieldId}") else _that
+            requireFieldValue = $.trim requireField.val()
+
+            _checkValue = ->
+                if !requireFieldValue
+                    validate.message = null
+                    validate.status = 'success'
+                else if requireFieldValue? and !fieldValue and !requiredFieldValue
+                    validate.message = "#{requiredFieldId} is required"
                     validate.status = 'danger'
-                    validate.message = "this field is required with #{fieldID}"
-                else
+                else if (requireFieldValue is fieldValue) and !requiredFieldValue
+                    validate.message = "#{requiredFieldId} is required"
+                    validate.status = 'danger'
+                else if requireFieldValue? and requiredFieldValue?
                     validate.message = null
                     validate.status = 'success'
                 validate

-            if fieldValue? and (requiredFieldValue is fieldValue)
-                validate = checkValue()
-            else if requiredFieldValue.length > 0 and (not fieldValue?)
-                validate = checkValue()
-            else if requiredFieldValue.length == 0
-                validate.message = null
-                validate.status = 'success'
+            _checkValue()
+
+            validate
+
+        _evaluate fieldId, fieldValue

-            validate
-
-        _evaluate value, fieldID, fieldValue
+    validateAllowedWith: (value) ->
+        _that = $ @
+        _allowedWith = _that.data 'allowed-with'
+
+        if _allowedWith.search(':') isnt -1
+            _allowedWith = _allowedWith.split ':'
+            _allowedId = _allowedWith[0]
+            _allowedValue = _allowedWith[1]
+        else
+            _allowedId = _allowedWith
+
+        _allowedField = $ "##{_allowedId}"
+
+        if (value is _allowedValue) or (value? and !_allowedValue)
+            _allowedField.prop "disabled", false
+        else
+            _allowedField.prop("disabled", true).val ''

     validateMaxValue: (value) ->
-        that = $ @
-        max = that.data 'max-value'
+        _that = $ @
+        max = _that.data 'max-value'
         validate =
             status: null
             message: null
@@ -844,8 +945,8 @@
             _evaluate max, value

     validateMinValue: (value) ->
-        that = $ @
-        min = that.data 'min-value'
+        _that = $ @
+        min = _that.data 'min-value'
         validate =
             status: null
             message: null
@@ -864,9 +965,9 @@
             _evaluate min, value

     validateBetweenValue: (value) ->
-        that = $ @
-        min = that.data 'min-value'
-        max = that.data 'max-value'
+        _that = $ @
+        min = _that.data 'min-value'
+        max = _that.data 'max-value'
         validate =
             status: null
             message: null
@@ -885,8 +986,8 @@
             _evaluate min, max, value

     validateMaxLength: (value) ->
-        that = $ @
-        max = that.data 'max-length'
+        _that = $ @
+        max = _that.data 'max-length'
         validate =
             status: null
             message: null
@@ -906,8 +1007,8 @@
             _evaluate max, length

     validateMinLength: (value) ->
-        that = $ @
-        min = that.data 'min-length'
+        _that = $ @
+        min = _that.data 'min-length'
         validate =
             status: null
             message: null
@@ -927,9 +1028,9 @@
             _evaluate min, length

     validateBetweenLength: (value) ->
-        that = $ @
-        min = that.data 'min-length'
-        max = that.data 'max-length'
+        _that = $ @
+        min = _that.data 'min-length'
+        max = _that.data 'max-length'
         validate =
             status: null
             message: null


make sure canvas avatars are loaded when user changes profile pic

--- @client/auth/upload_avatar.coffee
+++ @client/auth/upload_avatar.coffee
@@ -116,5 +116,10 @@
       time_between *= 1.5
       if time_between < 100000
         setTimeout update_user, time_between
+    else
+      loading = fetch('avatar_loading')
+      loading.dummy ?= 0
+      loading.dummy += 1
+      save loading

   update_user()


Fix silent (it seems) syntax error in supervision.js.coffee

--- app/assets/javascripts/backend/supervision.js.coffee
+++ app/assets/javascripts/backend/supervision.js.coffee
@@ -42,7 +42,7 @@
     # Show point on map
     map = $('#map .map')
     if point
-       map.find('.crumb.hover').each ->
+      map.find('.crumb.hover').each ->
         L.DomUtil.removeClass(this, 'hover')
       console.log map.find(".crumb-t#{point.x}")
       L.DomUtil.addClass(map.find(".crumb-t#{point.x}")[0], 'hover')


fix: bug for empty data

fix: bug for empty data

--- app/assets/javascripts/group/group_ranking.js.coffee
+++ app/assets/javascripts/group/group_ranking.js.coffee
@@ -7,7 +7,7 @@
   that.init = ->
     $.getJSON '/group_ranking/by_day', (data) ->
       console.log(data)
-
+      return if data.ranking.length == 0
       series = []
       for group in data.ranking
         sum = 0


Bound group creation to backend.

Bound group creation to backend.

--- client/Environments/views/environmentsmainscene.coffee
+++ client/Environments/views/environmentsmainscene.coffee
@@ -91,8 +91,11 @@
         new KDNotificationView
           title: "You need to login to create a new machine."

-      new KDNotificationView
-          title: "Will be implemented soon."
+      KD.remote.api.JVM.createSharedVm (err, vm)->
+        return KD.showError err  if err
+        vmc = KD.getSingleton("vmController")
+        vmc.emit 'VMListChanged'
+
       # TODO Add shared VM creation here.
       # vmController.createNewVM()


activity: keep the focus on comment input element

--- client/Social/Activity/views/comments/inputform.coffee
+++ client/Social/Activity/views/comments/inputform.coffee
@@ -35,7 +35,7 @@

       @input.setValue ''
       @input.resize()
-      @input.setBlur()
+      @input.setFocus()

     KD.requireMembership
       callback  : kallback


StacksCustomViews: updateStackTemplate if machines passed only udpate that part

--- client/admin/lib/views/stacks/stackscustomviews.coffee
+++ client/admin/lib/views/stacks/stackscustomviews.coffee
@@ -95,13 +95,15 @@

   updateStackTemplate = (data, callback) ->

-    { template, credential, title, stackTemplate } = data
+    { template, credential, title, stackTemplate, machines } = data

     title     or= 'Default stack template'
-    credentials = [credential.publicKey]
+    credentials = [credential.publicKey]  if credential

     if stackTemplate
-      stackTemplate.update {title, template, credentials}, (err) ->
+      dataToUpdate = if machines \
+        then {machines} else {title, template, credentials}
+      stackTemplate.update dataToUpdate, (err) ->
         callback err, stackTemplate
     else
       remote.api.JStackTemplate.create {


added some space for readability

added some space for readability

--- app/assets/javascripts/oxalis/view/plane_view.coffee
+++ app/assets/javascripts/oxalis/view/plane_view.coffee
@@ -69,7 +69,7 @@
     @scene.add( directionalLight )

     # Attach the canvas to the container
-    @renderer.setSize 2*WIDTH+20, 2*HEIGHT+20
+    @renderer.setSize 2 * WIDTH + 20, 2 * HEIGHT + 20
     $(@renderer.domElement).attr("id": "render-canvas")
     container.append @renderer.domElement


allow crop settings with multiple

allow crop settings with multiple

--- app/assets/javascripts/uploadcare/settings.js.coffee
+++ app/assets/javascripts/uploadcare/settings.js.coffee
@@ -141,7 +141,7 @@
     ])

     if settings.crop != false and not $.isArray(settings.crop)
-      if /^(disabled?|false|null)$/i.test(settings.crop) or settings.multiple
+      if /^(disabled?|false|null)$/i.test(settings.crop)
         settings.crop = false
       else if $.isPlainObject(settings.crop)  # old format
         settings.crop = [settings.crop]


api update

api update

--- app/js/services/wallet_api.coffee
+++ app/js/services/wallet_api.coffee
@@ -267,16 +267,6 @@
     @rpc.request('wallet_approve', [name, approval], error_handler).then (response) ->
       response.result

-  # Authorizes a public key to control funds of a particular asset class.  Requires authority of asset issuer
-  # parameters:
-  #   account_name `paying_account` - the account that will pay the transaction fee
-  #   asset_symbol `symbol` - the asset granting authorization
-  #   string `address` - the address being granted permission, or the public key, or the account name
-  # return_type: `transaction_record`
-  asset_authorize_key: (paying_account, symbol, address, error_handler = null) ->
-    @rpc.request('wallet_asset_authorize_key', [paying_account, symbol, address], error_handler).then (response) ->
-      response.result
-
   # Burns given amount to the given account.  This will allow you to post message and +/- sentiment on someones account as a form of reputation.
   # parameters:
   #   string `amount_to_burn` - the amount of shares to burn
@@ -315,13 +305,13 @@
     @rpc.request('wallet_note', [amount_to_pay, asset_symbol, owner_account_name, message, encrypted], error_handler).then (response) ->
       response.result

-  # Get and decrypt specific secret note
+  # Fetch notes and decrypt it if it is a secret note
   # parameters:
   #   sending_account_name `owner_account_name` - the owner of the secret_note
   #   string `transaction_id` - the id of the transaction including the secret note
   # return_type: `string`
-  decrypt_secret_note: (owner_account_name, transaction_id, error_handler = null) ->
-    @rpc.request('wallet_decrypt_secret_note', [owner_account_name, transaction_id], error_handler).then (response) ->
+  fetch_note: (owner_account_name, transaction_id, error_handler = null) ->
+    @rpc.request('wallet_fetch_note', [owner_account_name, transaction_id], error_handler).then (response) ->
       response.result

   # Creates an address which can be used for a simple (non-TITAN) transfer.
@@ -339,8 +329,8 @@
   #   string `amount_to_transfer` - the amount of shares to transfer
   #   asset_symbol `asset_symbol` - the asset to transfer
   #   sending_account_name `from_account_name` - the source account to draw the shares from
-  #   string `recipient` - the account name, public key, address, or btc address which will receive the funds
-  #   string `memo_message` - a memo to store with the transaction
+  #   string `recipient` - the account name, public key, address, btc address, or contact label (prefixed by "label:") which will receive the funds
+  #   string `memo_message` - a memo to send if the recipient is an account
   #   vote_strategy `strategy` - enumeration [vote_none | vote_all | vote_random | vote_recommended]
   # return_type: `transaction_record`
   transfer: (amount_to_transfer, asset_symbol, from_account_name, recipient, memo_message, strategy, error_handler = null) ->
@@ -434,8 +424,8 @@
   #   account_name `pay_fee_with_account_name` - when releasing escrow a transaction fee must be paid by funds not in escrow, this account will pay the fee
   #   address `escrow_balance_id` - The balance id of the escrow to be released.
   #   account_name `released_by_account` - the account that is to perform the release.
-  #   real_amount `amount_to_sender` - Amount to release back to the sender.
-  #   real_amount `amount_to_receiver` - Amount to release to receiver.
+  #   string `amount_to_sender` - Amount to release back to the sender.
+  #   string `amount_to_receiver` - Amount to release to receiver.
   # return_type: `transaction_record`
   release_escrow: (pay_fee_with_account_name, escrow_balance_id, released_by_account, amount_to_sender, amount_to_receiver, error_handler = null) ->
     @rpc.request('wallet_release_escrow', [pay_fee_with_account_name, escrow_balance_id, released_by_account, amount_to_sender, amount_to_receiver], error_handler).then (response) ->
@@ -523,7 +513,7 @@
   #   account_name `pay_from_account` - the account from which fees will be paid
   #   json_variant `public_data` - public data about the account
   #   uint8_t `delegate_pay_rate` - -1 for non-delegates; otherwise the percent of delegate pay to accept per produced block
-  #   string `account_type` - titan_account | public_account - public accounts do not receive memos and all payments are made to the active key
+  #   string `account_type` - titan_account | public_account - public accounts receive memos too but all payments are made to the active key
   # return_type: `transaction_record`
   account_register: (account_name, pay_from_account, public_data, delegate_pay_rate, account_type, error_handler = null) ->
     @rpc.request('wallet_account_register', [account_name, pay_from_account, public_data, delegate_pay_rate, account_type], error_handler).then (response) ->
@@ -584,50 +574,54 @@
     @rpc.request('wallet_account_rename', [current_account_name, new_account_name], error_handler).then (response) ->
       response.result

-  # Creates a new user issued asset
-  # parameters:
-  #   asset_symbol `symbol` - the ticker symbol for the new asset
-  #   string `asset_name` - the name of the asset
-  #   string `issuer_name` - the name of the issuer of the asset
-  #   string `description` - a description of the asset
-  #   real_amount `maximum_supply` - the maximum number of shares of the asset
-  #   uint64_t `precision` - defines where the decimal should be displayed, must be a power of 10
-  #   json_variant `public_data` - arbitrary data attached to the asset
-  #   bool `is_market_issued` - creation of a new BitAsset that is created by shorting
-  # return_type: `transaction_record`
-  asset_create: (symbol, asset_name, issuer_name, description, maximum_supply, precision, public_data, is_market_issued, error_handler = null) ->
-    @rpc.request('wallet_asset_create', [symbol, asset_name, issuer_name, description, maximum_supply, precision, public_data, is_market_issued], error_handler).then (response) ->
-      response.result
-
-  # Updates an existing user-issued asset; only the public_data can be updated if any shares of the asset exist
-  # parameters:
-  #   asset_symbol `symbol` - the ticker symbol for the asset to update
-  #   optional_string `name` - the new name to give the asset; or null to keep the current name
-  #   optional_string `description` - the new description to give the asset; or null to keep the current description
-  #   optional_variant `public_data` - the new public_data to give the asset; or null to keep the current public_data
-  #   optional_double `maximum_supply` - the new maximum_supply to give the asset; or null to keep the current maximum_supply
-  #   optional_uint64_t `precision` - the new precision to give the asset; or null to keep the current precision
-  #   share_type `issuer_transaction_fee` - an additional fee (denominated in issued asset) charged by the issuer on every transaction that uses this asset type
-  #   real_amount `issuer_market_fee` - an additional fee (denominated in percent) charged by the issuer on every order that is matched
-  #   asset_permission_array `flags` - a set of flags set by the issuer (if they have permission to set them)
-  #   asset_permission_array `issuer_permissions` - a set of permissions an issuer retains
-  #   account_name `issuer_account_name` - used to transfer the asset to a new user
-  #   uint32_t `required_sigs` - number of signatures from the authority required to control this asset record
-  #   address_list `authority` - owner keys that control this asset record
-  # return_type: `transaction_record`
-  asset_update: (symbol, name, description, public_data, maximum_supply, precision, issuer_transaction_fee, issuer_market_fee, flags, issuer_permissions, issuer_account_name, required_sigs, authority, error_handler = null) ->
-    @rpc.request('wallet_asset_update', [symbol, name, description, public_data, maximum_supply, precision, issuer_transaction_fee, issuer_market_fee, flags, issuer_permissions, issuer_account_name, required_sigs, authority], error_handler).then (response) ->
-      response.result
-
-  # Issues new shares of a given asset type
-  # parameters:
-  #   real_amount `amount` - the amount of shares to issue
-  #   asset_symbol `symbol` - the ticker symbol for asset
-  #   account_name `to_account_name` - the name of the account to receive the shares
-  #   string `memo_message` - the memo to send to the receiver
-  # return_type: `transaction_record`
-  asset_issue: (amount, symbol, to_account_name, memo_message, error_handler = null) ->
-    @rpc.request('wallet_asset_issue', [amount, symbol, to_account_name, memo_message], error_handler).then (response) ->
+  # Create a new market-issued asset (BitAsset) on the blockchain. Warning: creation fees can be very high!
+  # parameters:
+  #   string `payer_account` - The local account name that will pay the creation fee
+  #   asset_symbol `symbol` - A unique symbol that will represent the new asset. Short symbols are very expensive!
+  #   string `name` - A human-readable name for the new asset
+  #   string `description` - A human-readable description of the new asset
+  #   string `max_divisibility` - Choose the max share divisibility for the new asset. Must be an inverse power of ten. For example: 0.00001 or 1
+  # return_type: `transaction_record`
+  mia_create: (payer_account, symbol, name, description, max_divisibility, error_handler = null) ->
+    @rpc.request('wallet_mia_create', [payer_account, symbol, name, description, max_divisibility], error_handler).then (response) ->
+      response.result
+
+  # Create a new game(chip)-issued asset (Chip Asset) on the blockchain. Warning: creation fees can be very high!
+  # parameters:
+  #   string `payer_account` - The local account name that will pay the creation fee
+  #   string `game_name` - The name of the game that can issue to this asset
+  #   asset_symbol `symbol` - A unique symbol that will represent the new asset. Short symbols are very expensive!
+  #   string `name` - A human-readable name for the new asset
+  #   string `description` - A human-readable description of the new asset
+  #   string `max_divisibility` - Choose the max share divisibility for the new asset. Must be an inverse power of ten. For example: 0.00001 or 1
+  #   string `init_supply` - Choose the init share supply
+  #   string `init_collateral` - Choose the init share collateral
+  # return_type: `transaction_record`
+  gia_create: (payer_account, game_name, symbol, name, description, max_divisibility, init_supply, init_collateral, error_handler = null) ->
+    @rpc.request('wallet_gia_create', [payer_account, game_name, symbol, name, description, max_divisibility, init_supply, init_collateral], error_handler).then (response) ->
+      response.result
+
+  # Create a new user-issued asset on the blockchain. Warning: creation fees can be very high!
+  # parameters:
+  #   string `issuer_account` - The registered account name that will pay the creation fee and control the new asset
+  #   asset_symbol `symbol` - A unique symbol that will represent the new asset. Short symbols are very expensive!
+  #   string `name` - A human-readable name for the new asset
+  #   string `description` - A human-readable description of the new asset
+  #   string `max_supply_with_trailing_decimals` - Choose the max share supply and max share divisibility for the new asset. For example: 10000000000.00000 or 12345.6789
+  # return_type: `transaction_record`
+  uia_create: (issuer_account, symbol, name, description, max_supply_with_trailing_decimals, error_handler = null) ->
+    @rpc.request('wallet_uia_create', [issuer_account, symbol, name, description, max_supply_with_trailing_decimals], error_handler).then (response) ->
+      response.result
+
+  # Issue shares of a user-issued asset to the specified recipient
+  # parameters:
+  #   string `asset_amount` - the amount of shares of the asset to issue
+  #   asset_symbol `asset_symbol` - specify the unique symbol of the asset
+  #   string `recipient` - the account name, public key, address, btc address, or contact label (prefixed by "label:") which will receive the funds
+  #   string `memo_message` - a memo to send if the recipient is an account
+  # return_type: `transaction_record`
+  uia_issue: (asset_amount, asset_symbol, recipient, memo_message, error_handler = null) ->
+    @rpc.request('wallet_uia_issue', [asset_amount, asset_symbol, recipient, memo_message], error_handler).then (response) ->
       response.result

   # Issues new UIA shares to specific addresses.
@@ -635,8 +629,84 @@
   #   asset_symbol `symbol` - the ticker symbol for asset
   #   snapshot_map `addresses` - A map of addresses-to-amounts to transfer the new shares to
   # return_type: `transaction_record`
-  asset_issue_to_addresses: (symbol, addresses, error_handler = null) ->
-    @rpc.request('wallet_asset_issue_to_addresses', [symbol, addresses], error_handler).then (response) ->
+  uia_issue_to_addresses: (symbol, addresses, error_handler = null) ->
+    @rpc.request('wallet_uia_issue_to_addresses', [symbol, addresses], error_handler).then (response) ->
+      response.result
+
+  # Withdraw fees collected in the specified user-issued asset and deposit to the specified recipient
+  # parameters:
+  #   asset_symbol `asset_symbol` - specify the unique symbol of the asset
+  #   string `recipient` - the account name, public key, address, btc address, or contact label (prefixed by "label:") which will receive the funds
+  #   string `memo_message` - a memo to send if the recipient is an account
+  # return_type: `transaction_record`
+  uia_collect_fees: (asset_symbol, recipient, memo_message, error_handler = null) ->
+    @rpc.request('wallet_uia_collect_fees', [asset_symbol, recipient, memo_message], error_handler).then (response) ->
+      response.result
+
+  # Update the name, description, public data of the specified user-issue asset
+  # parameters:
+  #   account_name `paying_account` - the account that will pay the transaction fee
+  #   asset_symbol `asset_symbol` - the user-issued asset to update
+  #   string `name` - A human-readable name for the new asset
+  #   string `description` - A human-readable description of the new asset
+  #   variant `public_data` - Extra data to attach to the asset
+  # return_type: `transaction_record`
+  uia_update_description: (paying_account, asset_symbol, name, description, public_data, error_handler = null) ->
+    @rpc.request('wallet_uia_update_description', [paying_account, asset_symbol, name, description, public_data], error_handler).then (response) ->
+      response.result
+
+  # Update the max supply and max divisibility of the specified user-issued asset if permitted
+  # parameters:
+  #   account_name `paying_account` - the account that will pay the transaction fee
+  #   asset_symbol `asset_symbol` - the user-issued asset to update
+  #   string `max_supply_with_trailing_decimals` - Choose the max share supply and max share divisibility for the asset. For example: 10000000000.00000 or 12345.6789
+  # return_type: `transaction_record`
+  uia_update_supply: (paying_account, asset_symbol, max_supply_with_trailing_decimals, error_handler = null) ->
+    @rpc.request('wallet_uia_update_supply', [paying_account, asset_symbol, max_supply_with_trailing_decimals], error_handler).then (response) ->
+      response.result
+
+  # Update the transaction fee, market fee rate for the specified user-issued asset if permitted
+  # parameters:
+  #   account_name `paying_account` - the account that will pay the transaction fee
+  #   asset_symbol `asset_symbol` - the user-issued asset to update
+  #   string `withdrawal_fee` - the transaction fee for the asset in shares of the asset
+  #   string `market_fee_rate` - the market fee rate for the asset as a percentage between 0.01 and 100, or 0
+  # return_type: `transaction_record`
+  uia_update_fees: (paying_account, asset_symbol, withdrawal_fee, market_fee_rate, error_handler = null) ->
+    @rpc.request('wallet_uia_update_fees', [paying_account, asset_symbol, withdrawal_fee, market_fee_rate], error_handler).then (response) ->
+      response.result
+
+  # Activate or deactivate one of the special flags for the specified user-issued asset as permitted
+  # parameters:
+  #   account_name `paying_account` - the account that will pay the transaction fee
+  #   asset_symbol `asset_symbol` - the user-issued asset to update
+  #   asset_flag_enum `flag` - the special flag to enable or disable; one of {dynamic_max_supply, dynamic_fees, halted_markets, halted_withdrawals, retractable_balances, restricted_deposits}
+  #   bool `enable_instead_of_disable` - true to enable, or false to disable
+  # return_type: `transaction_record`
+  uia_update_active_flags: (paying_account, asset_symbol, flag, enable_instead_of_disable, error_handler = null) ->
+    @rpc.request('wallet_uia_update_active_flags', [paying_account, asset_symbol, flag, enable_instead_of_disable], error_handler).then (response) ->
+      response.result
+
+  # Update the authority's special flag permissions for the specified user-issued asset. Warning: If any shares have been issued, then revoked permissions cannot be restored!
+  # parameters:
+  #   account_name `paying_account` - the account that will pay the transaction fee
+  #   asset_symbol `asset_symbol` - the user-issued asset to update
+  #   asset_flag_enum `permission` - the special permission to enable or disable; one of {dynamic_max_supply, dynamic_fees, halted_markets, halted_withdrawals, retractable_balances, restricted_deposits}
+  #   bool `add_instead_of_remove` - True to add, or false to remove. Use with extreme caution!
+  # return_type: `transaction_record`
+  uia_update_authority_permissions: (paying_account, asset_symbol, permission, add_instead_of_remove, error_handler = null) ->
+    @rpc.request('wallet_uia_update_authority_permissions', [paying_account, asset_symbol, permission, add_instead_of_remove], error_handler).then (response) ->
+      response.result
+
+  # Add or remove the specified address or public key from the specified user-issued asset's whitelist
+  # parameters:
+  #   account_name `paying_account` - the account that will pay the transaction fee
+  #   asset_symbol `asset_symbol` - the user-issued asset that will have its whitelist updated
+  #   string `address_or_public_key` - the address or public key to add or remove from the whitelist
+  #   bool `add_to_whitelist` - true to add to whitelist, or false to remove
+  # return_type: `transaction_record`
+  uia_update_whitelist: (paying_account, asset_symbol, address_or_public_key, add_to_whitelist, error_handler = null) ->
+    @rpc.request('wallet_uia_update_whitelist', [paying_account, asset_symbol, address_or_public_key, add_to_whitelist], error_handler).then (response) ->
       response.result

   # Lists the total asset balances for all open escrows
@@ -707,7 +777,7 @@

   # Set the fee to add to new transactions
   # parameters:
-  #   real_amount `fee` - the wallet transaction fee to set
+  #   string `fee` - the wallet transaction fee to set
   # return_type: `asset`
   set_transaction_fee: (fee, error_handler = null) ->
     @rpc.request('wallet_set_transaction_fee', [fee], error_handler).then (response) ->
@@ -1012,7 +1082,7 @@
   # publishes a price feed for BitAssets, only active delegates may do this
   # parameters:
   #   account_name `delegate_account` - the delegate to publish the price under
-  #   real_amount `price` - the number of this asset per XTS
+  #   string `price` - the number of this asset per XTS
   #   asset_symbol `asset_symbol` - the type of asset being priced
   # return_type: `transaction_record`
   publish_price_feed: (delegate_account, price, asset_symbol, error_handler = null) ->
@@ -1030,7 +1100,7 @@

   # publishes a set of feeds for BitAssets for all active delegates, most useful for testnets
   # parameters:
-  #   price_map `symbol_to_price_map` - maps the BitAsset symbol to its price per share
+  #   string_map `symbol_to_price_map` - maps the BitAsset symbol to its price per share
   # return_type: `vector<std::pair<string, wallet_transaction_record>>`
   publish_feeds_multi_experimental: (symbol_to_price_map, error_handler = null) ->
     @rpc.request('wallet_publish_feeds_multi_experimental', [symbol_to_price_map], error_handler).then (response) ->


feat: clean POC to add embedded images in scrumble template

--- client/src/daily-report/services/report-builder.coffee
+++ client/src/daily-report/services/report-builder.coffee
@@ -10,7 +10,10 @@
 )->
   converter = new showdown.Converter()

-  renderImages = (message, useCid) ->
+  addImageInCid = (message, type, name, base64, id) ->
+    message.cids = (message.cids || []).concat([{type: type, name: name, base64: base64, id: id}])
+
+  renderEmbeddedImages = (message, useCid) ->
     images = message.body.match(/data:image\/(.*);base64,([^"]*)/gm)

     if images.length > 0
@@ -26,12 +29,7 @@
           message.body = message.body.replace(imageBase64, "#{src}")

           if useCid
-            message.cids = (message.cids || []).concat([{
-              type: "image/#{imageType}"
-              name: "Image #{imageIdx}"
-              base64: imageBase64.split(',')[1]
-              id: "image#{imageIdx}"
-            }])
+            addImageInCid(message, "image/#{imageType}", "Image #{imageIdx}", imageBase64.split(',')[1], "image#{imageIdx}")

     return message

@@ -43,14 +41,12 @@
       message.body = message.body.replace '{bdc}', "<img src='#{src}' />"

       if useCid
-        message.cids = [{
-          type: 'image/png'
-          name: 'BDC'
-          base64: bdcBase64.split(',')[1]
-          id: 'bdc'
-        }]
-      renderImages(message, useCid)
+        addImageInCid(message, 'image/png','BDC', bdcBase64.split(',')[1], 'bdc')
       return message
+
+  renderImages = (message, svg, useCid) ->
+    renderEmbeddedImages(message, useCid)
+    renderBDC(message, svg, useCid)

   renderTo = (project) ->
     emails = (member.email for member in project.team when member.daily is 'to')
@@ -168,5 +164,4 @@
       , svg, false
   buildCid: ->
     dynamicFieldsPromise.then (builtDict) ->
-      renderBDC prebuildMessage, _svg, true
-]+      renderImages(prebuildMessage, _svg, true)


Fetching card urls

Fetching card urls

--- scripts/card-fetcher.coffee
+++ scripts/card-fetcher.coffee
@@ -11,6 +11,7 @@
 #   JacobGinsparg

 rCardNames = /\[\[(.*)\]\]/i
+baseUrl = "http://gatherer.wizards.com/Handlers/Image.ashx"

 loadCardDatabase = ->
   req = new XMLHttpRequest()
@@ -23,13 +24,13 @@
   req.send()

 verifyCardName = (cardName, db) ->
+  cardName in db

-
-getCardImageUrl = (cardName, db) ->
-
+getCardImageUrl = (cardName, validCard) ->
+  fullUrl = "#{baseUrl}?type=card&name=#{validCard ? encodeURIComponent(cardName) : "Dismal%20Failure"}"

 module.exports = (robot) ->
   robot.hear rCardNames, (msg) ->
     cardDB = loadCardDatabase()
     valid = verifyCardName msg.match[1], cardDB
-    msg.send getCardImageUrl msg.match[1], cardDB if valid
+    msg.send getCardImageUrl msg.match[1], valid


Adds artist_filtered_search_suggest

Adds artist_filtered_search_suggest

--- node/fabricate.coffee
+++ node/fabricate.coffee
@@ -758,4 +758,50 @@
       end_at: "2014-03-08T17:30:00+00:00"
       updated_at: "2014-02-24T16:34:25Z"

+    when 'artist_filtered_search_suggest'
+      total: 65
+      related_gene: {}
+      medium:
+        design: 1
+        drawing: 10
+        installation: 1
+        painting: 7
+        prints: 8
+        sculpture: 23
+        "work-on-paper": 41
+      dimension:
+        96: 63
+      gallery:
+        "armand-bartos-fine-art": 2
+        "artware-editions": 1
+        "barbara-krakow-gallery": 4
+        "carolina-nitsch-contemporary-art": 15
+        "casterline-goodman-gallery": 1
+        caviar20: 1
+        "cheim-and-read": 21
+        "galerie-le-minotaure": 1
+        "galerie-zlotowski": 1
+        "lora-reynolds-gallery": 1
+        mixografia: 1
+        "peter-blum-gallery": 4
+        "robert-miller-gallery": 2
+        "senior-and-shopmaker-gallery": 3
+        "susan-sheehan-gallery": 1
+        "xavier-hufkens": 3
+      institution:
+        "miniature-museum-ria-and-lex-daniels": 1
+        "museum-of-arts-and-design": 1
+        "serpentine-gallery": 1
+      period:
+        1940: 4
+        1960: 8
+        1970: 1
+        1980: 3
+        1990: 16
+        2000: 27
+        2010: 3
+      sale_status: {}
+      price_range:
+        "-1:1000000000000": 58
+
   , extObj


Actually find executables..

Actually find executables..

--- node/fileutils.coffee
+++ node/fileutils.coffee
@@ -6,7 +6,7 @@
   exeGlob: (appPath) ->
     switch process.platform
       when "win32"
-        "#{appPath}/**/*.app"
+        "#{appPath}/**/*.exe"
       when "darwin"
         "#{appPath}/**/*.app"
       when "linux"


start indexing entry details

start indexing entry details

--- models/team.coffee
+++ models/team.coffee
@@ -270,7 +270,7 @@

 ## search index
 TeamSchema.pre 'save', (next) ->
-  only = name: 1, location: 1, 'github.login': 1, 'twit.screenName': 1
+  only = name: 1, location: 1, 'github.login': 1, 'twit.screenName': 1, entry: 1
   Person.find _id: { '$in': @peopleIds }, only, (err, people) =>
     return next err if err
     @search =
@@ -279,6 +279,8 @@
       #{@description}
       #{_.pluck(people, 'login').join(';')}
       #{_.pluck(people, 'location').join(';')}
+      #{@entry?.name || ''}
+      #{@entry?.description || ''}
       """
     next()


Ensure loadCompletions only called once

Ensure loadCompletions only called once

--- lib/latextools.coffee
+++ lib/latextools.coffee
@@ -359,5 +359,6 @@
           SnippetManager ?= require './snippet-manager'
           @snippetManager ?= new SnippetManager(@ltConsole)
         when "cwl-provider"
-          @cwlProvider ?= require './ltcwl-completion'
-          @cwlProvider.loadCompletions()
+          unless @cwlProvider?
+            @cwlProvider = require './ltcwl-completion'
+            @cwlProvider.loadCompletions()


remove period

remove period

--- scripts/movie-quotes.coffee
+++ scripts/movie-quotes.coffee
@@ -4,5 +4,5 @@
 #

 module.exports = (robot) ->
-  robot.hear /.*one (in|out of) a million.*/, (msg) ->
+  robot.hear /.*one (in|out of) a million*/, (msg) ->
     msg.send "so you're telling me there's a chance: http://www.youtube.com/watch?v=yCFB2akLh4s"


+ ExpressionStack: tested .pop

+ ExpressionStack: tested .pop

--- test/unit/expression-stack.coffee
+++ test/unit/expression-stack.coffee
@@ -31,3 +31,10 @@
     it ".stackName is 'next'", ->
       testedStack.stackName.should.equal "next"

+    describe "after .pop()", ->
+      beforeEach ->
+        testedStack.pop()
+
+      it ".stackName is 'bottom'", ->
+        testedStack.stackName.should.equal "bottom"
+


Added infinite loop handling to Simulator.

--- app/lib/simulator/Simulator.coffee
+++ app/lib/simulator/Simulator.coffee
@@ -81,7 +81,13 @@

   commenceSimulationAndSetupCallback: ->
     @god.createWorld()
+    Backbone.Mediator.subscribeOnce 'god:infinite-loop', @onInfiniteLoop, @
     Backbone.Mediator.subscribeOnce 'god:new-world-created', @processResults, @
+
+  onInfiniteLoop: ->
+    console.warn "Skipping infinitely looping game."
+    @trigger 'statusUpdate', 'Infinite loop detected; grabbing a new game.'
+    _.delay @cleanupAndSimulateAnotherTask, 5000

   processResults: (simulationResults) ->
     taskResults = @formTaskResultsObject simulationResults


Add Quote Textbox

Add Quote Textbox

--- app/pages/lab/project-details.cjsx
+++ app/pages/lab/project-details.cjsx
@@ -123,6 +123,15 @@
             Add text here when you have multiple workflows and want to help your volunteers decide which one they should do. <CharLimit limit={500} string={@props.project.workflow_description ? ''} />

+

+            <AutoSave resource={@props.project}>
+              Researcher Quote
+

+              <textarea className="standard-input full" name="researcher_quote" value={@props.project.researcher_quote} onChange={handleInputChange.bind @props.project} />
+            </AutoSave>
+            This text will appear on a project landing page alongside an avatar of the selected researcher. <CharLimit limit={255} string={@props.project.researcher_quote ? ''} />
+

+

             <AutoSave resource={@props.project}>
               Announcement Banner