fix height miscalculations when element has hidden or display=none children

Former-commit-id: 8f9860398b153bb663f7024a031997492a1496d3 [formerly 19428be648ad3f5aef87ac0f5e66465e780d0aa2] [formerly d39427bb7a74c149b7c69fae596986e4e2cbe216 [formerly 1f232c7d10d19e1b74cf27e133d02a12212e6969]] [formerly 0b8371e3ace37094a8b0a9ab6eb84c297d012808 [formerly 2353e8483d71651e1192310d5481dfc86a29ac50] [formerly 239435c381783b7cc59bff1c8549c7922c23ec53 [formerly 239435c381783b7cc59bff1c8549c7922c23ec53 [formerly e684d008f11b37f9616376b12755508d26fc32ce]]]]
Former-commit-id: 6594c96d1836b17ab3a05c6c4dacb124c643c0e3 [formerly 41cf09aa9679f3a06596ab92ed4b537d3fd754ea] [formerly d0699d60156ab1657d62488cb29b6481c1855b8f [formerly debaa8db16a1431f3d829e9f9edd57ece84b58db]]
Former-commit-id: 55c81020f567614eeceabf927d03d3f2e2fa90ce [formerly c6581981335328cc53915c3f9e4a9346c474ad0e]
Former-commit-id: 6f7367bfe347ecfcda7d1644ad1eeddac1f0a6a0
Former-commit-id: 6a3be938fdd3c5255af756b88f49b3e3725359d4

--- @client/dock.coffee
+++ @client/dock.coffee
@@ -119,7 +119,7 @@

   componentDidMount : ->

-    # Register this dock with docker. Send docker a callback that it
+    # Register this dock with dockingStation. Send dockingStation a callback that it
     # can invoke to learn about this dock when making calculations.

     $el = $(@refs.dock_child.getDOMNode()).children()
@@ -145,8 +145,8 @@
     # For caching results of realDimensions (see below)
     serializer = new XMLSerializer()

-    docker.register @key, =>
-      # This callback is invoked each time the dock is laid out by docker.
+    dockingStation.register @key, =>
+      # This callback is invoked each time the dock is laid out by dockingStation.
       #
       # We can't use $el.height() to determine the height of the docking
       # component because there may be absolutely positioned elements
@@ -181,30 +181,30 @@
       }

   componentWillUnmount : ->
-    docker.unregister @key
+    dockingStation.unregister @key

 ####
-# docker
-#
-# The docker updates on scroll and resize the docked state and location of
+# dockingStation
+#
+# The dockingStation updates on scroll and resize the docked state and location of
 # all registered docks.
 #
-# The docker will update the state(bus) of the docks so that
+# The dockingStation will update the state(bus) of the docks so that
 # they know if they're docked and where they should position.

 # For console output:
 debug = false

-docker =
+dockingStation =

   ####
   # Internal state
   registry: {}
           # all registered docks, by key
   listening_to_scroll_events : false
-          # whether docker is bound to scroll event
+          # whether dockingStation is bound to scroll event

   component_history: {}
           # caches component location info at t, t-1, and time of docking
@@ -218,80 +218,83 @@
   # Make sure we're listening to scroll event only if there is
   # at least one registered dock.
   register : (key, info_callback) ->
-    docker.registry[key] = info_callback
-    docker.component_history[key] = {previous: {}, on_dock: {}}
-
-    if !docker.listening_to_scroll_events
+    dockingStation.registry[key] = info_callback
+    dockingStation.component_history[key] = {previous: {}, on_dock: {}}
+
+    if !dockingStation.listening_to_scroll_events

-      $(window).on "scroll.docker", -> docker.user_scrolled = true
-      $(window).on "resize.docker", docker.onResize
+      $(window).on "scroll.dockingStation", -> dockingStation.user_scrolled = true
+      $(window).on "resize.dockingStation", dockingStation.onResize

       # If the height of a docked component changes, we need to recalculate
       # the layout. Unfortunately, it is non-trivial and error prone to detect
       # when the height of an element changes, so we'll just check periodically.
-      docker.check_resize_interval = setInterval docker.onCheckStickyResize, 500
-
-      docker.listening_to_scroll_events = true
+      dockingStation.check_resize_interval = setInterval dockingStation.onCheckStickyResize, 500
+
+      dockingStation.listening_to_scroll_events = true

       # Recompute layout if we've seen a scroll in past X ms
-      docker.interval = setInterval ->
-        if docker.user_scrolled
-          docker.user_scrolled = false
-          docker.onScroll()
+      dockingStation.interval = setInterval ->
+        if dockingStation.user_scrolled
+          dockingStation.user_scrolled = false
+          dockingStation.onScroll()
       , 100

   unregister : (key) ->
-    delete docker.registry[key]
-    if _.keys(docker.registry).length == 0
-      $(window).off ".docker"
-      docker.listening_to_scroll_events = false
-      clearInterval docker.check_resize_interval
-      docker.check_resize_interval = null
-      clearInterval docker.interval
-      docker.interval = null
+    delete dockingStation.registry[key]
+    if _.keys(dockingStation.registry).length == 0
+      $(window).off ".dockingStation"
+      dockingStation.listening_to_scroll_events = false
+      clearInterval dockingStation.check_resize_interval
+      dockingStation.check_resize_interval = null
+      clearInterval dockingStation.interval
+      dockingStation.interval = null

   #######
   # onScroll
   onScroll : ->
-    docker.updateViewport()
+    dockingStation.updateViewport()

     # At most we will shift the docked components by the distance scrolled
-    max_change = if docker.viewport.last.top?
-                   Math.abs(docker.viewport.top - docker.viewport.last.top)
+    max_change = if dockingStation.viewport.last.top?
+                   Math.abs(dockingStation.viewport.top - dockingStation.viewport.last.top)
                  else
                    Infinity

-    docker.layout max_change
+    dockingStation.layout max_change

   #######
   # onResize
   onResize : ->
-    docker.updateViewport()
+    dockingStation.updateViewport()

     # Shift the docked components by at most the change in window height
-    max_change = Math.abs(docker.viewport.height - docker.viewport.last.height)
-    docker.layout max_change
+    max_change = Math.abs(dockingStation.viewport.height - dockingStation.viewport.last.height)
+    dockingStation.layout max_change

   #######
   # onCheckStickyResize
   onCheckStickyResize : ->
-    height_changes = 0
-
-    for own k,v of docker.registry
+
+
+    for own k,v of dockingStation.registry
       dock = fetch k
-      if dock.docked && v().height != docker.component_history[k].previous.height
-        console.error "HEIGHT RESIZE at most #{height_changes}" if debug
-        docker.layout Infinity
+
+      if dock.docked && v().height != dockingStation.component_history[k].previous.height
+        height_change = v().height - dockingStation.component_history[k].previous.height
+
+        console.log "HEIGHT RESIZE at most #{height_change}" if debug
+        dockingStation.layout Math.abs(height_change)
         break

   #######
   # updateViewport()
   updateViewport : ->
-    docker.viewport =
+    dockingStation.viewport =
       last:
-        top: docker.viewport.top
-        height: docker.viewport.height
+        top: dockingStation.viewport.top
+        height: dockingStation.viewport.height
       top: document.documentElement.scrollTop || document.body.scrollTop
       height: Math.max(document.documentElement.clientHeight, window.innerHeight || 0)

@@ -307,34 +310,34 @@

     # The registered docks with updated context values
     docks = {}
-    for own k,v of docker.registry
+    for own k,v of dockingStation.registry
       docks[k] = v()
       docks[k].key = k

     # Figure out which components are docked
-    [docked, undocked] = docker.determineIfDocked docks
+    [docked, undocked] = dockingStation.determineIfDocked docks

     # undock components that were docked
     for k in undocked
       if fetch(k).docked
-        docker.toggleDocked k, docks[k]
+        dockingStation.toggleDocked k, docks[k]

     if docked.length > 0
       # Calculate y-positions for all docked components
-      y_pos = docker.solveForY docked, docks, max_change
+      y_pos = dockingStation.solveForY docked, docks, max_change

       for k in docked
         dock = fetch k
-        docker.component_history[k].previous = _.extend docks[k],
+        dockingStation.component_history[k].previous = _.extend docks[k],
                                                     calculated_y: y_pos[k].value

-        [x, y] = docker.adjustForDevice y_pos[k].value, docks[k]
+        [x, y] = dockingStation.adjustForDevice y_pos[k].value, docks[k]
         if dock.y != y || dock.x != x
           console.log "UPDATING #{dock.key}" if debug
           dock.y = y
           dock.x = x
           if !dock.docked
-            docker.toggleDocked k, docks[k]
+            dockingStation.toggleDocked k, docks[k]

           save dock

@@ -361,11 +364,11 @@
         is_docked = false
       else
         dimensions =  if fetch(v.key).docked
-                        docker.component_history[v.key].on_dock
+                        dockingStation.component_history[v.key].on_dock
                       else
                         {height: v.height, jut_above: v.jut_above}

-        is_docked = docker.viewport.top + y_stack + dimensions.jut_above >= v.start
+        is_docked = dockingStation.viewport.top + y_stack + dimensions.jut_above >= v.start

       if is_docked
         y_stack += dimensions.height
@@ -387,9 +390,9 @@
     dock.docked = is_docked
     if !is_docked
       dock.y = dock.x = null
-      docker.component_history[k].previous = {}
+      dockingStation.component_history[k].previous = {}
     else
-      docker.component_history[k].on_dock = v
+      dockingStation.component_history[k].on_dock = v

     save dock

@@ -420,12 +423,12 @@
     solver = new c.SimplexSolver()

     # We modify the contraints slightly based on whether we're scrolling up or down
-    scroll_distance = Math.abs(docker.viewport.top - docker.viewport.last.top)
+    scroll_distance = Math.abs(dockingStation.viewport.top - dockingStation.viewport.last.top)
     if scroll_distance > 0
-      docker.scrolling_down = docker.viewport.top > docker.viewport.last.top
-
-
-    console.log("viewport height: ", docker.viewport.height) if debug
+      dockingStation.scrolling_down = dockingStation.viewport.top > dockingStation.viewport.last.top
+
+
+    console.log("viewport height: ", dockingStation.viewport.height) if debug
     # We'll iterate through each component in order of their stacking priority
     y_stack = 0

@@ -485,7 +488,7 @@
     for v, i in sorted
       console.log "**#{v.key} constraints**" if debug
       k = v.key; dock = fetch k
-      previous_calculated_y = docker.component_history[k].previous.calculated_y
+      previous_calculated_y = dockingStation.component_history[k].previous.calculated_y

       # START
       console.log "\tSTART: #{k} >= #{v.start}, strong" if debug
@@ -515,22 +518,22 @@

       # TOP OF COMPONENT VISIBLE
       # Try to keep it at or below the viewport, especially when scrolling up
-      console.log "\tTOP OF COMPONENT VISIBLE: #{k} >= #{docker.viewport.top} + #{v.jut_above} + #{y_stack}, #{if docker.scrolling_down then 'weak' else 'medium'}" if debug
+      console.log "\tTOP OF COMPONENT VISIBLE: #{k} >= #{dockingStation.viewport.top} + #{v.jut_above} + #{y_stack}, #{if dockingStation.scrolling_down then 'weak' else 'medium'}" if debug
       solver.addConstraint new c.Inequality \
         y_pos[k], \
         c.GEQ, \
-        docker.viewport.top + v.jut_above + y_stack, \
-        if docker.scrolling_down then c.Strength.weak else c.Strength.medium
+        dockingStation.viewport.top + v.jut_above + y_stack, \
+        if dockingStation.scrolling_down then c.Strength.weak else c.Strength.medium
       y_stack += v.height

       # BOTTOM OF COMPONENT VISIBLE
       # Try to keep the bottom above the viewport, especially when scrolling down
-      console.log "\tBOTTOM OF COMPONENT VISIBLE: #{k} + #{v.height} <= #{docker.viewport.top} + #{docker.viewport.height}, #{if docker.scrolling_down then 'medium' else 'weak'}" if debug
+      console.log "\tBOTTOM OF COMPONENT VISIBLE: #{k} + #{v.height} <= #{dockingStation.viewport.top} + #{dockingStation.viewport.height}, #{if dockingStation.scrolling_down then 'medium' else 'weak'}" if debug
       solver.addConstraint new c.Inequality \
         y_pos[k], \
         c.LEQ, \
-        docker.viewport.top + docker.viewport.height - v.height, \
-        if docker.scrolling_down then c.Strength.medium else c.Strength.weak
+        dockingStation.viewport.top + dockingStation.viewport.height - v.height, \
+        if dockingStation.scrolling_down then c.Strength.medium else c.Strength.weak

       # RELATIONAL
       for sv, j in sorted
@@ -583,7 +586,7 @@
       x = 0
     else
       # Fixed positioning is relative to the viewport, not the document
-      y -= docker.viewport.top
+      y -= dockingStation.viewport.top

       # Adjust for horizontal scroll for fixed position elements because they don't
       # move with the rest of the content (they're fixed to the viewport).
@@ -594,9 +597,9 @@

   initialize : ->
-    docker.updateViewport()
-
-docker.initialize()
+    dockingStation.updateViewport()
+
+dockingStation.initialize()

 #####
 # realDimensions
@@ -607,11 +610,16 @@
 #
 # This method is expensive, use it sparingly.
 realDimensions = ($el) ->
-
+  tar = $el.is('.opinion_region')
   recurse = ($e, min_top, max_top) ->
-    return [min_top, max_top] if $e.is('defs') # skip svg defs
+
     t = $e.offset().top
     h = $e.height()
+
+    return [min_top, max_top] if h == 0 ||
+                                 $e[0].style.display == 'none'
+                              # skip elements that don't take up space
+
     if min_top > t
       min_top = t
     if t + h > max_top


Switch to gama12

Switch to gama12

--- app/models/subject.coffee
+++ app/models/subject.coffee
@@ -100,7 +100,7 @@
   @randomSurveyId: ->
     n = Math.random()
     if n <= (0.333)
-      @::surveys.gama09.id
+      @::surveys.gama12.id
     else if n < (0.667)
       @::surveys.sdss_lost_set.id
     else


Fix backend URL setting

Fix backend URL setting

--- src/servicemap.coffee
+++ src/servicemap.coffee
@@ -17,7 +17,8 @@
     paths:
         app: '../js'

-SMBACKEND_BASE_URL = "http://localhost:8000/v1/"
+SMBACKEND_BASE_URL = sm_settings.backend_url + '/'
+
 LANGUAGE = 'fi'

 SRV_TEXT =


Client: Sidebar: Updated setActiveInvitationMachineId method. passed machine instead of id to action

--- client/app/lib/components/sidebar/index.coffee
+++ client/app/lib/components/sidebar/index.coffee
@@ -45,12 +45,10 @@

   setActiveInvitationMachineId: ->

-    id = @getRequiredInvitationMachineId()
+    { setActiveInvitationMachineId } = EnvironmentFlux.actions

-    EnvironmentFlux.actions.setActiveInvitationMachineId id  if id
-
-
-
+    if @state.requiredInvitationMachine
+      setActiveInvitationMachineId @state.requiredInvitationMachine

   renderInvitationWidget: ->


flux/environment: filter stack's machine if there is no data

--- client/app/lib/flux/environment/getters.coffee
+++ client/app/lib/flux/environment/getters.coffee
@@ -136,14 +136,16 @@
         stack
           .set 'accessLevel', templates.getIn [stack.get('baseStackId'), 'accessLevel']
           .update 'machines', (machines) ->
-            machines.map (id) ->
-              machine = machinesWorkspaces.get(id)
-              type    = if machine.getIn ['meta', 'oldOwner'] then 'reassigned' else 'own'
-
-              machine
-                .set 'type', type
-                .set 'owner', getMachineOwner machine
-                .set 'isApproved', yes
+            machines
+              .filter (id) -> !!machinesWorkspaces.get(id)
+              .map (id) ->
+                machine = machinesWorkspaces.get(id)
+                type    = if machine.getIn ['meta', 'oldOwner'] then 'reassigned' else 'own'
+
+                machine
+                  .set 'type', type
+                  .set 'owner', getMachineOwner machine
+                  .set 'isApproved', yes
 ]

 teamStacks = [


ComputeHelpers: handleNewMachineRequest: reload IDE after machine creation

--- client/app/lib/providers/computehelpers.coffee
+++ client/app/lib/providers/computehelpers.coffee
@@ -87,6 +87,8 @@
             unless showError err
               globals.userMachines.push machine

+              kd.singletons.router.handleRoute "/IDE/#{machine.slug}"
+

   # Helper method to run a specific app
   # with a specific machine


video: model emit event when offline user selected

--- client/app/lib/videocollaboration/model.coffee
+++ client/app/lib/videocollaboration/model.coffee
@@ -420,9 +420,13 @@
   changeActiveParticipant: (nick) ->

     return  unless @state.active
-    return  unless @getParticipant nick

     @setState { activeParticipant: nick }
+
+    # see if the user is in the session, if not emit special event.
+    unless @getParticipant nick
+      @emit 'OfflineUserSelected', nick
+
     @emit 'ActiveParticipantChanged', nick


hide toolbar

hide toolbar

--- app/javascripts/application.coffee
+++ app/javascripts/application.coffee
@@ -14,6 +14,7 @@
     vizURL = 'https://public.tableau.com/views/Chess_3/Board'
     options =
       hideTabs: true
+      hideToolbar: true
       onFirstInteractive: ->
         getSheet().applyFilterAsync "Field Name + Piece", "", tableau.FilterUpdateType.ALL
         .then ->


HomeStackImport: copy updates and some review issues fixed

--- client/home/lib/stacks/homestacksimport.coffee
+++ client/home/lib/stacks/homestacksimport.coffee
@@ -32,7 +32,7 @@

     @addSubView new kd.CustomHTMLView
       tagName: 'h2'
-      partial: "Stack Importer"
+      partial: 'Stack Importer'

     @addSubView @loader = new kd.LoaderView
       showLoader : yes
@@ -42,7 +42,7 @@

     @addSubView @message = new kd.CustomHTMLView
       tagName: 'p'
-      partial: "Loading..."
+      partial: 'Loading...'

     @addSubView @outputView = new OutputView
       delegate: @getDelegate()
@@ -69,10 +69,10 @@
       @actionButton.setCallback -> window.open _host, '_blank'

       @message.updatePartial """
-        This tool is intended to use with GitLab integration which is enabled
-        for this team on #{host}. You can use action
-        endpoints provided in your GitLab service to be able to use this tool
-        to try your projects on Koding.
+        This tool is intended to be used with GitLab. The integration is
+        enabled for this team at #{host}. To be able to
+        run your projects on Koding, please use action endpoints provided in
+        your GitLab service.
       """

       @emit 'ready'


Use JMailNotification instead JEmailNotificationGG

--- client/landing/app/MainApp/kodingrouter.coffee
+++ client/landing/app/MainApp/kodingrouter.coffee
@@ -251,7 +251,7 @@
       ({params:{unsubscribeToken, opt}})->
         opt              = decodeURIComponent opt
         unsubscribeToken = decodeURIComponent unsubscribeToken
-        KD.remote.api.JEmailNotificationGG.unsubscribeWithId \
+        KD.remote.api.JMailNotification.unsubscribeWithId \
         unsubscribeToken, opt, (err, content)=>
           if err or not content
             title   = 'An error occured'


Tests: Account: Accountsettings: Added toggleNotificationsPopup test.

--- client/test/lib/account/accountsettings.coffee
+++ client/test/lib/account/accountsettings.coffee
@@ -93,3 +93,18 @@
     notificationText = 'Your account information is updated.'

     changePasswordHelper(browser, newPassword, newPassword, null, notificationText, fn)
+
+
+ toggleNotificationsPopup: (browser) ->
+
+    notificationIconSelector = '.avatar-area .acc-notification-icon'
+
+    helpers.beginTest(browser)
+
+    browser
+      .waitForElementVisible     notificationIconSelector, 20000
+      .click                     notificationIconSelector
+      .waitForElementVisible     '.popup-notifications.active', 20000 # Assertion
+      .click                     notificationIconSelector
+      .waitForElementNotPresent  '.popup-notifications.active', 20000 # Assertion
+      .end()


:fire: Remove limit when previewing a file

It turns out that if a parsing issue is present after the 5 first rows
the preview becomes useless.

--- lib/csv-editor.coffee
+++ lib/csv-editor.coffee
@@ -258,17 +258,13 @@
       parser = csv.parse(options)
       output = []

-      limit = 5
-      limit = 6 if options.header
-
       stop = ->
         input.unpipe(parser)
         parser.end()
-        resolve(output[0...limit])
+        resolve(output)

       read = ->
         output.push record while record = parser.read()
-        stop() if output.length > limit

       end = ->
         resolve(output)


camelize() function optimization

camelize() function optimization

--- src/Moon.coffee
+++ src/Moon.coffee
@@ -67,10 +67,18 @@

         # capitalizes the first letter
         camelize: (str) ->
-            return str.replace(/-([\da-z])/gi, ($1) ->
-                return $1.toUpperCase().replace('-','')
+            return str.replace(Moon.fn.rdashAlpha, Moon.fn.camelizeReplaceCallback)

-        # defines an animation step. Moon animations must have at least one step
+        # RegExp to match the dash and the char after it
+        rdashAlpha: "/-([\D])/g"
+
+        # camelize replace callback function to return
+        # just the capitalized char
+        camelizeReplaceCallback: ($1) ->
+            return $1.charAt(1).toUpperCase()
+
+        # defines an animation step. Moon animations
+        # must have at least one step
         animate: (args) ->
             animationProps =
                 duration: 0


Trying to get the grammars correct

Trying to get the grammars correct

--- grammars/gherkin.cson
+++ grammars/gherkin.cson
@@ -0,0 +1,8 @@
+"fileTypes": [
+    'feature'
+]
+"name": 'Gherkin'
+"patterns": [
+
+]
+"scopeName": 'source.feature'


change flagging language

change flagging language

--- app/assets/javascripts/components/buttons/bad-subject-button.cjsx
+++ app/assets/javascripts/components/buttons/bad-subject-button.cjsx
@@ -5,7 +5,7 @@
   displayName: 'BadSubjectButton'

   render: ->
-    label = @props.label ? ( if @props.active then 'Bad Playbill' else 'Bad Playbill?' )
+    label = @props.label ? ( if @props.active then 'Report Problem' else 'Report Problem?' )

     additional_classes = []
     additional_classes.push 'toggled' if @props.active


Remove trailing } when autocompleting from within a \begin{...} command

--- services/web/public/coffee/auto-complete/AutoCompleteManager.coffee
+++ services/web/public/coffee/auto-complete/AutoCompleteManager.coffee
@@ -2,10 +2,12 @@
 	"auto-complete/SuggestionManager"
 	"auto-complete/Snippets"
 	"ace/autocomplete/util"
+	"ace/autocomplete"
 	"ace/range"
 	"ace/ext/language_tools"
-], (SuggestionManager, Snippets, Util) ->
+], (SuggestionManager, Snippets, Util, AutoComplete) ->
 	Range = require("ace/range").Range
+	Autocomplete = AutoComplete.Autocomplete

 	Util.retrievePrecedingIdentifier = (text, pos, regex) ->
 		currentLineOffset = 0
@@ -38,6 +40,20 @@

 			@aceEditor.completers = [@suggestionManager, SnippetCompleter]

+			insertMatch = Autocomplete::insertMatch
+			editor = @aceEditor
+			Autocomplete::insertMatch = (data) ->
+				pos = editor.getCursorPosition()
+				range = new Range(pos.row, pos.column, pos.row, pos.column + 1)
+				nextChar = editor.session.getTextRange(range)
+
+				# If we are in \begin{it|}, then we need to remove the trailing }
+				# since it will be adding in with the autocomplete of \begin{item}...
+				if this.completions.filterText.match(/^\\begin\{/) and nextChar == "}"
+					editor.session.remove(range)
+
+				insertMatch.call editor.completer, data
+
 			@bindToEditorEvents()

 		bindToEditorEvents: () ->


Check batch length

Check batch length

--- app/partials/subject-uploader.cjsx
+++ app/partials/subject-uploader.cjsx
@@ -84,7 +84,7 @@
       @finish()

   finish: ->
-    unless @state.batch is 0
+    unless @state.batch.length is 0
       newSubjectIDs = (id for {id} in @state.batch)
       @props.subjectSet.addLink 'subjects', newSubjectIDs
         .then =>


Fixed readystate check

Fixed readystate check

--- js-library/app/js/loader.coffee
+++ js-library/app/js/loader.coffee
@@ -41,7 +41,7 @@
   coreScriptTag.src = FactlinkConfig.lib + FactlinkConfig.srcPath

 coreScriptTag.onload = coreScriptTag.onreadystatechange = ->
-  return false if coreScriptTag.readyState? not in ['complete', 'loaded']
+  return false if coreScriptTag.readyState && coreScriptTag.readyState not in ['complete', 'loaded']

   coreScriptTag.onload = coreScriptTag.onreadystatechange = null


Fix forward/backward buttons

Fix forward/backward buttons

--- app/views/settings.coffee
+++ app/views/settings.coffee
@@ -37,10 +37,10 @@
     @

   next: =>
-    @toolSettings.next()
+    @toolSettings[0].next()

   prev: =>
-    @toolSettings.prev()
+    @toolSettings[0].prev()

   # Events
   toggleState: =>


Fixed specs

Fixed specs

--- spec/wave-datepicker.unittests.coffee
+++ spec/wave-datepicker.unittests.coffee
@@ -16,6 +16,7 @@
           on: sinon.spy()
         $el:
           on: sinon.stub()  # Stub because we need to return $el
+          is: sinon.stub()
         _cancelEvent: 'FUNCTION'
         prev: 'FUNCTION'
         next: 'FUNCTION'
@@ -27,6 +28,7 @@
         show: 'FUNCTION'
         hide: 'FUNCTION'
       @context.$el.on.returns @context.$el
+      @context.$el.is.returns true

     it 'should bind cancel events to click on datepicker', ->
       WDP.WaveDatepicker.prototype._initEvents.call @context
@@ -144,6 +146,7 @@
           addClass: sinon.spy()
         $el:
           outerHeight: sinon.stub()
+          is: sinon.stub()
         _place: sinon.spy()
         $window:
           on: sinon.spy()
@@ -153,6 +156,8 @@
         _isShown: false
         hideInactive: sinon.spy()
       @context.$el.outerHeight.returns 'HEIGHT'
+      # false means it's visible
+      @context.$el.is.returns false

     it 'should place datepicker and show it', ->
       WDP.WaveDatepicker.prototype.show.call @context


Exists to metadata section

Exists to metadata section

--- src/file.coffee
+++ src/file.coffee
@@ -109,6 +109,10 @@

   # Public: Returns a {Boolean}, always false.
   isDirectory: -> false
+
+  # Public: Returns a {Boolean}, true if the file exists, false otherwise.
+  exists: ->
+    fs.existsSync(@getPath())

   # Public: Returns the {String} path for the file.
   getPath: -> @path
@@ -193,10 +197,6 @@
     promise.then (contents) =>
       @setDigest(contents)
       @cachedContents = contents
-
-  # Public: Returns a {Boolean}, true if the file exists, false otherwise.
-  exists: ->
-    fs.existsSync(@getPath())

   setDigest: (contents) ->
     @digest = crypto.createHash('sha1').update(contents ? '').digest('hex')


Added more file upload unit tests.

Added more file upload unit tests.


Exo.Controller: Separated isTransitioning() from isActive(). Its better to check for both individually.

--- controller.coffee
+++ controller.coffee
@@ -227,7 +227,9 @@
 			@doDeactivate()

 	isActive: ->
-		@sm.getCurrentState() == Controller.STATE_ACTIVATED && @sm.getNextState() == null
+		@sm.getCurrentState() == Controller.STATE_ACTIVATED
+		# Removing this for now, it's better to check both isActive and isTransitioning separately.
+		# && @sm.getNextState() == null

 	isTransitioning: ->
 		@sm.getNextState() != null


Remove redundant actions

Remove redundant actions

--- app/assets/javascripts/actions/timeline_actions.coffee
+++ app/assets/javascripts/actions/timeline_actions.coffee
@@ -9,30 +9,5 @@
         { actionType: 'SAVED_TIMELINE', data: data }
       .catch (data) ->
         { actionType: 'API_FAIL', data: data }
-  addWeek: ->
-    { actionType: 'ADD_WEEK' }
-  updateWeek: (week) ->
-    { actionType: 'UPDATE_WEEK', data: {
-      week: week
-    }}
-  deleteWeek: (week_id) ->
-    { actionType: 'DELETE_WEEK', data: {
-      week_id: week_id
-    }}

-  addBlock: (week_id) ->
-    { actionType: 'ADD_BLOCK', data: {
-      week_id: week_id
-    }}
-  updateBlock: (week_id, block) ->
-    { actionType: 'UPDATE_BLOCK', data: {
-      week_id: week_id,
-      block: block
-    }}
-  deleteBlock: (week_id, block_id) ->
-    { actionType: 'DELETE_BLOCK', data: {
-      week_id: week_id,
-      block_id: block_id
-    }}
-
-module.exports = TimelineActions+module.exports = TimelineActions


Remove co2 emissions biomass chart

Remove co2 emissions biomass chart

--- app/assets/javascripts/d3/co2_emissions_biomass.coffee
+++ app/assets/javascripts/d3/co2_emissions_biomass.coffee
@@ -1,344 +0,0 @@
-D3.co2_emissions_biomass =
-  View: class extends D3ChartView
-    initialize: ->
-      D3ChartView.prototype.initialize.call(this)
-      @series = @model.series.models
-
-    gquery_keys:
-      start:          '1990_in_co2_emissions'
-      domestic:       'co2_emissions_of_final_demand_excluding_imported_' +
-                      'electricity_in_co2_emissions'
-      imported:       'co2_emissions_of_imported_electricity_in_co2_emissions'
-      gas_present:    'climate_relevant_co2_biomass_gas_present'
-      gas_future:     'climate_relevant_co2_biomass_gas_future'
-      liquid_present: 'climate_relevant_co2_biomass_liquid_present'
-      liquid_future:  'climate_relevant_co2_biomass_liquid_future'
-      solid_present:  'climate_relevant_co2_biomass_solid_present'
-      solid_future:   'climate_relevant_co2_biomass_solid_future'
-      target:         'policy_goal_co2_emissions_target_value'
-
-    can_be_shown_as_table: -> true
-
-    margins:
-      top: 20
-      bottom: 20
-      left: 30
-      right: 40
-
-    # This method is called right before rendering because the series are
-    # added when the JSON request is complete, ie after the initialize method
-    #
-    setup_series: =>
-      @serie_1990           = @serie_for(@gquery_keys.start)
-      @serie_domestic       = @serie_for(@gquery_keys.domestic)
-      @serie_imported       = @serie_for(@gquery_keys.imported)
-      @serie_gas_present    = @serie_for(@gquery_keys.gas_present)
-      @serie_gas_future     = @serie_for(@gquery_keys.gas_future)
-      @serie_liquid_present = @serie_for(@gquery_keys.liquid_present)
-      @serie_liquid_future  = @serie_for(@gquery_keys.liquid_future)
-      @serie_solid_present  = @serie_for(@gquery_keys.solid_present)
-      @serie_solid_future   = @serie_for(@gquery_keys.solid_future)
-      @serie_target         = @serie_for(@gquery_keys.target)
-
-    draw: =>
-      @setup_series()
-
-      [@width, @height] = @available_size()
-
-      legend_margin = 20
-      @series_height = @height - legend_margin
-
-      @svg = @create_svg_container @width, @series_height, @margins
-
-      # Ugly stuff. Check the db to see which series have been defined.
-      # Since this chart is very specific the series could actually be
-      # hard-coded
-      series_for_legend = [
-        @serie_1990,
-        @serie_gas_present,
-        @serie_domestic,
-        @serie_liquid_present,
-        @serie_imported,
-        @serie_solid_present,
-        @serie_target
-      ]
-
-      @draw_legend
-        svg: @svg
-        series: series_for_legend
-        width: @width
-        vertical_offset: @series_height + legend_margin
-        columns: 2
-
-      @x = d3.scale.ordinal().rangeRoundBands([0, @width - 25])
-        .domain([1990, @start_year, @end_year])
-      @x_axis = d3.svg.axis()
-        .scale(@x)
-        .tickSize(2, 2, 0)
-        .orient("bottom")
-      @svg.append("svg:g")
-        .attr("class", "x_axis inner_grid")
-        .attr("transform", "translate(0, #{@series_height})")
-        .call(@x_axis)
-
-      @y = d3.scale.linear().range([0, @series_height]).domain([0, 1])
-      @inverted_y = d3.scale.linear().range([@series_height, 0]).domain([0, 1])
-
-      # draw a nice axis
-      @y_axis = d3.svg.axis()
-        .scale(@inverted_y)
-        .ticks(5)
-        .tickSize(-(@width - 25), 10, 0)
-        .orient("right")
-        .tickFormat(@main_formatter())
-      @svg.append("svg:g")
-        .attr("class", "y_axis inner_grid")
-        .attr("transform", "translate(#{@width - 25}, 0)")
-        .call(@y_axis)
-
-      # there we go
-      @block_width = @x.rangeBand() * 0.5
-      rect = @svg.selectAll('rect.serie')
-        .data(@prepare_data(), (s) -> s.id)
-        .enter().append('svg:rect')
-        .attr('class', 'serie')
-        .attr("width", @block_width)
-        .attr('x', (s) => @x(s.x) + @block_width / 2)
-        .attr('y', @series_height)
-        .style('fill', (d) => d.color)
-        .style('opacity', 0.8)
-
-      $("#{@container_selector()} rect.serie").qtip
-        content: -> $(this).attr('data-tooltip')
-        position:
-          my: 'bottom center'
-          at: 'top center'
-
-      # target lines
-      @svg.selectAll('rect.target_line')
-        .data([@serie_target], (d) -> d.get 'gquery_key')
-        .enter()
-        .append('svg:rect')
-        .attr('class', 'target_line')
-        .style('fill', '#ff0000')
-        .attr('height', 2)
-        .attr('width', @block_width * 1.2)
-        .attr('x', @x(@end_year) + @block_width * 0.4)
-        .attr('y', @series_height)
-        .style('opacity', 0.0)
-
-    max_series_value: ->
-      _.max([
-        @serie_1990.safe_future_value(),
-        @serie_domestic.safe_present_value() +
-          @serie_imported.safe_present_value() +
-          @serie_gas_present.safe_present_value() +
-          @serie_liquid_present.safe_present_value() +
-          @serie_solid_present.safe_present_value(),
-        @serie_domestic.safe_future_value() +
-          @serie_imported.safe_future_value() +
-          @serie_gas_future.safe_future_value() +
-          @serie_liquid_future.safe_future_value() +
-          @serie_solid_future.safe_future_value()
-      ])
-
-    refresh: =>
-      # calculate tallest column
-      tallest = @max_series_value()
-
-      # update the scales as needed
-      @y = @y.domain([0, tallest])
-      @inverted_y = @inverted_y.domain([0, tallest])
-
-      # animate the y-axis
-      @svg.selectAll(".y_axis").transition().call(@y_axis.scale(@inverted_y))
-
-      # let the stack method filter the data again, adding the offsets as needed
-      @svg.selectAll('rect.serie')
-        .data(@prepare_data(), (s) -> s.id)
-        .transition()
-        .attr('y', (d) => @series_height - @y((d.y0 || 0.0) + d.y))
-        .attr('height', (d) => @y(d.y))
-        .attr("data-tooltip", (d) => @main_formatter()(d.y))
-
-      # move the target lines
-      @svg.selectAll('rect.target_line')
-        .data([@serie_target], (d) -> d.get 'gquery_key')
-        .transition()
-        .attr('y', (d) => @series_height - (@y d.safe_future_value()))
-        .style('opacity', (d) -> if d.future_value() == null then 0.0 else 0.8)
-
-
-    prepare_data: =>
-      stack = d3.layout.stack().offset('zero')
-
-      target = {
-        id:    'co2_1990',
-        x:     1990,
-        y:     @serie_1990.safe_future_value(),
-        color: @serie_1990.get('color'),
-        label: @serie_1990.get('label')
-      }
-
-      stacked = _.flatten(stack([[{
-        id:   'co2_present_domestic',
-        x:     @start_year,
-        y:     @serie_domestic.safe_present_value(),
-        color: @serie_domestic.get('color'),
-        label: @serie_domestic.get('label')
-      }, {
-        id:   'co2_future_domestic',
-        x:     @end_year,
-        y:     @serie_domestic.safe_future_value(),
-        color: @serie_domestic.get('color'),
-        label: @serie_domestic.get('label')
-      }], [{
-        id:    'co2_present_imported',
-        x:     @start_year,
-        y:     @serie_imported.safe_present_value(),
-        color: @serie_imported.get('color'),
-        label: @serie_imported.get('label')
-      }, {
-        id:    'co2_future_imported',
-        x:     @end_year,
-        y:     @serie_imported.safe_future_value(),
-        color: @serie_imported.get('color'),
-        label: @serie_imported.get('label')
-      }], [{
-        id:    'co2_present_gas',
-        x:     @start_year,
-        y:     @serie_gas_present.safe_present_value(),
-        color: @serie_gas_present.get('color'),
-        label: @serie_gas_present.get('label')
-      }, {
-        id:    'co2_future_gas',
-        x:     @end_year,
-        y:     @serie_gas_future.safe_future_value(),
-        color: @serie_gas_future.get('color'),
-        label: @serie_gas_future.get('label')
-      }], [{
-        id:    'co2_present_liquid',
-        x:     @start_year,
-        y:     @serie_liquid_present.safe_present_value(),
-        color: @serie_liquid_present.get('color'),
-        label: @serie_liquid_present.get('label')
-      }, {
-        id:    'co2_future_liquid',
-        x:     @end_year,
-        y:     @serie_liquid_future.safe_future_value(),
-        color: @serie_liquid_future.get('color'),
-        label: @serie_liquid_future.get('label')
-      }], [{
-        id:    'co2_present_solid',
-        x:     @start_year,
-        y:     @serie_solid_present.safe_present_value(),
-        color: @serie_solid_present.get('color'),
-        label: @serie_solid_present.get('label')
-      }, {
-        id:    'co2_future_solid',
-        x:     @end_year,
-        y:     @serie_solid_future.safe_future_value(),
-        color: @serie_solid_future.get('color'),
-        label: @serie_solid_future.get('label')
-      }]]))
-
-      [target, stacked...]
-
-    serie_for: (gquery_key) =>
-      _.detect(@series, (s) -> s.get('gquery_key') == gquery_key)
-
-    # This chart has to override the standard render_as_table method
-    #
-    render_as_table: =>
-      # return false
-      @clear_container()
-      @setup_series()
-
-      formatter = @main_formatter(precision: 4)
-
-      unit = @model.get('unit')
-      raw_target = @serie_target.future_value()
-      target = if raw_target?
-        target = formatter(raw_target)
-      else
-        '-'
-      html = "
-

-

-

-
-              1990
-              #{@start_year}
-              #{@end_year}
-              #{I18n.t('output_element_series.target')}
-

-

-

-

-              #{I18n.t('output_element_series.co2_emissions_1990')}
-              #{formatter(@serie_1990.safe_present_value())}

-              —
-              —
-              —
-

-
-

-              #{I18n.t('output_element_series.co2_emission_local_production')}
-              —
-              #{formatter(@serie_domestic.safe_present_value())}

-              #{formatter(@serie_domestic.safe_future_value())}
-              —
-

-
-

-              #{I18n.t('output_element_series.co2_emission_imported_electricity')}
-              —
-              #{formatter(@serie_imported.safe_present_value())}

-              #{formatter(@serie_imported.safe_future_value())}
-              —
-

-
-

-              #{I18n.t('output_element_series.co2_biomass_gas_present')}
-              —
-              #{formatter(@serie_gas_present.safe_present_value())}

-              #{formatter(@serie_gas_future.safe_future_value())}
-              —
-

-
-

-              #{I18n.t('output_element_series.co2_biomass_liquid_present')}
-              —
-              #{formatter(@serie_liquid_present.safe_present_value())}

-              #{formatter(@serie_liquid_future.safe_future_value())}
-              —
-

-
-

-              #{I18n.t('output_element_series.co2_biomass_solid_present')}
-              —
-              #{formatter(@serie_solid_present.safe_present_value())}

-              #{formatter(@serie_solid_future.safe_future_value())}
-              —
-

-

-

-

-              #{I18n.t('output_element_series.total')}
-              #{formatter(@serie_1990.safe_future_value())}
-              #{formatter(@serie_domestic.safe_present_value() +
-                                @serie_imported.safe_present_value() +
-                                @serie_gas_present.safe_present_value() +
-                                @serie_liquid_present.safe_present_value() +
-                                @serie_solid_present.safe_present_value())}

-              #{formatter(@serie_domestic.safe_future_value() +
-                                @serie_imported.safe_future_value() +
-                                @serie_gas_future.safe_future_value() +
-                                @serie_liquid_future.safe_future_value() +
-                                @serie_solid_future.safe_future_value())}
-              #{target}
-

-

-

-      "
-      @container_node().html(html)


Improved menu

Improved menu

--- app/assets/javascripts/jquest_pg/application.js.coffee
+++ app/assets/javascripts/jquest_pg/application.js.coffee
@@ -13,11 +13,15 @@
 #= require_tree .
 angular.module 'jquest'
   .run (Menu)->
-      Menu.addItem name: "Watch intro again", state: 'main.pg.intro'
-      Menu.addItem name: "My tasks", state: 'main.pg.tasks'
-      Menu.addItem name: "Tutorials", state: 'main.pg.tutorials'
-      Menu.addItem name: "Leaderboard", state: 'main.pg.leaderboard'
-      Menu.addItem name: "Collected data", state: 'main.pg.data'
+      # Global menu option
+      Menu.setTitle 'Political Gaps'
+      Menu.setPrimaryColor '#81A9CC'
+      # Menus items
+      Menu.addItem name: "Watch intro again", state: 'main.pg.intro', category: 'Tutorials'
+      Menu.addItem name: "How-to", state: 'main.pg.tutorials', category: 'Tutorials'
+      Menu.addItem name: "My tasks", state: 'main.pg.tasks', category: 'Your mission', priority: 100
+      Menu.addItem name: "Leaderboard", state: 'main.pg.leaderboard', category: 'Your mission'
+      Menu.addItem name: "Collected data", state: 'main.pg.data', category: 'Your mission'
       Menu.addItem name: "About", state: 'main.pg.about'
   .run ($rootScope, $state)->
     $rootScope.$on '$stateChangeSuccess', (ev, state)->


Speed up firing even more

Speed up firing even more

--- app/scripts/components/weapons/RapidWeaponLaser.coffee
+++ app/scripts/components/weapons/RapidWeaponLaser.coffee
@@ -34,9 +34,9 @@
     if level isnt @level
       @cooldown = switch @level
         when 0 then 200
-        when 1 then 175
-        when 2 then 150
-        when 3 then 125
+        when 1 then 150
+        when 2 then 100
+        when 3 then 50
       @trigger 'levelUp', @level

   determineLevel: (xp) ->
@@ -74,10 +74,10 @@

   _createFrontBullet: ->
     settings = switch @level
-      when 0 then w: 6, speed: 350, h: 3
-      when 1 then w: 10, speed: 355, h: 4
-      when 2 then w: 14, speed: 360, h: 5
-      when 3 then w: 18, speed: 365, h: 5
+      when 0 then w: 6, speed: 550, h: 4
+      when 1 then w: 10, speed: 555, h: 4
+      when 2 then w: 14, speed: 560, h: 4
+      when 3 then w: 18, speed: 565, h: 4

     Crafty.e('Bullet')
       .attr
@@ -99,10 +99,10 @@

   _createBackBullet: ->
     settings = switch @level
-      when 0 then w: 5, speed: 350, h: 3
-      when 1 then w: 8, speed: 355, h: 3
-      when 2 then w: 10, speed: 360, h: 4
-      when 3 then w: 14, speed: 365, h: 4
+      when 0 then w: 5, speed: 550, h: 3
+      when 1 then w: 8, speed: 555, h: 3
+      when 2 then w: 10, speed: 560, h: 3
+      when 3 then w: 14, speed: 565, h: 3

     Crafty.e('Bullet')
       .attr


added support for cpp, cxx extensions and their header files (h, hpp, hxx)

--- lib/line-count.coffee
+++ lib/line-count.coffee
@@ -7,9 +7,14 @@
 suffixes = [
   'coffee'
   'js'
+  'h'
   'hx'
+  'hpp'
+  'hxx'
   'c'
   'cc'
+  'cpp'
+  'cxx'
   'java'
   'php'
   'php5'


client: main: make default route /Welcome

--- client/app/lib/kodingrouter.coffee
+++ client/app/lib/kodingrouter.coffee
@@ -85,20 +85,14 @@
     { groupsController } = kd.singletons
     currentGroup         = groupsController.getCurrentGroup()

-    # For koding default route still is /IDE always, for others if there is
-    # stack template defined for the active group, it goes again to /IDE but if
-    # there is no stack template defined for the current group it goes /Activity
-    # directly.
-    #
-    # This doesn't effect the routes direct accesses. ~ GG
-
     if not currentGroup or currentGroup.slug is 'koding'
       return '/IDE'

-    return '/Home'
+    return '/Welcome'

   setPageTitle: (title = 'Koding') -> kd.singletons.pageTitle.update title
+

   openContent : (name, section, models, route, query, passOptions = no) ->
     method   = 'createContentDisplay'


Fixed: data-screen was not properly set. Added: onLeave callback when a screen is left.

--- client/app/lib/popover_view.coffee
+++ client/app/lib/popover_view.coffee
@@ -46,19 +46,25 @@
             error = 'Popover must be rendered before switching its screen.'
             throw new Error(error)

+
+        # If the screen is switched back to the default one, call `onLeave` if
+        # it exists.
+        if screenID is 'default' and @screen?
+            @screen.onLeave?.call @
+
         # Get the screen data.
-        screen = @getScreen screenID
+        @screen = @getScreen screenID

         # Change the DOM with the new screen.
         renderData = @getRenderData()
-        @titleElement.html screen.title(renderData)
-        @contentElement.html screen.content(renderData)
+        @titleElement.html @screen.title(renderData)
+        @contentElement.html @screen.content(renderData)

         # Change current screen information
-        @screenElement.data 'screen', screenID
+        @screenElement.attr 'data-screen', screenID

         # Execute the screen's callback if it has been defined.
-        screen.afterRender?.call @
+        @screen.afterRender?.call @

     render: ->
@@ -67,10 +73,10 @@
         # Only create it if doesn't exist.
         unless @$popover?
             renderData = @getRenderData()
-            defaultScreen = @getScreen 'default'
+            @screen = @getScreen 'default'
             popoverWrapper = @template
-                title: defaultScreen.title(renderData)
-                content: defaultScreen.content(renderData)
+                title: @screen.title(renderData)
+                content: @screen.content(renderData)

             @$popover = $ popoverWrapper
             @titleElement = @$popover.find '.popover-title'
@@ -84,7 +90,7 @@
         @afterRender()

         # Execute the default screen's callback if it has been defined.
-        defaultScreen.afterRender.call @
+        @screen.afterRender.call @

         # Compute and et popover's position.
         @positionPopover()


Add mixin

Add mixin

--- lib/observable.coffee
+++ lib/observable.coffee
@@ -10,6 +10,10 @@
 class Observable
 	constructor: ->
 		@__eventStore = {}
+
+	mixin: (host) ->
+		host.__eventStore = {}
+		host[key] = fn for key, fn of Observable.prototype

 	on:  (topics, fn, once = false) ->
 		if isPlainObject(topics)
@@ -27,6 +31,9 @@
 			@on(topics, true)

 	off: (topics, fn) ->
+		if not fn
+			for topic in toArray(topics)
+				@__eventStore[topic] = []
 		if isPlainObject(topics)
 			@off(topic, fn) for topic, fn of topics
 		else


remove immediate opening of editShift modal after creating a shift #15

--- client/views/common/day/day.coffee
+++ client/views/common/day/day.coffee
@@ -26,18 +26,13 @@
 		project = Projects.findOne projectId, fields: tags: 1

 		if project?
-			for tag in project.tags
-				if tag._id == tagId
-					tagName = tag.name
+			for tag in project.tags when tag._id == tagId
+				tagName = tag.name

 			if date?
-				Meteor.call 'addShift', projectId, tagId, tagName, parseInt(date), parseInt(start), (e, shiftId) ->
-					if !e && shiftId
-						wrs -> FlowRouter.setQueryParams editShift: shiftId
+				Meteor.call 'addShift', projectId, tagId, tagName, parseInt(date), parseInt(start), handleError
 			else if weekId?
-				Meteor.call 'addTemplateShift', projectId, weekId, tagId, tagName, day, (e, shiftId) ->
-					if !e && shiftId
-						wrs -> FlowRouter.setQueryParams editShift: shiftId
+				Meteor.call 'addTemplateShift', projectId, weekId, tagId, tagName, day, handleError
 			else
 				throw new Meteor.Error 500, 'Not enough data provided'


prevent "native-key-bindings" from effecting the input box

--- lib/panel/view.coffee
+++ lib/panel/view.coffee
@@ -11,8 +11,8 @@
             @div outlet: 'head', class: 'inset-panel padded', =>
                 @span outlet: 'title'
                 @span outlet: 'inputMethod'
-            @div outlet: 'body', class: "block padded native-key-bindings", tabindex: "-1", =>
-                @div outlet: 'content', class: 'agda-panel-content', =>
+            @div outlet: 'body', class: "block padded", =>
+                @div outlet: 'content', class: 'agda-panel-content native-key-bindings', tabindex: "-1", =>
                     @ul outlet: 'contentList', class: 'list-group'
                 @subview 'inputBox', new TextEditorView mini: true


Add 'range' command for queues.

Add 'range' command for queues.

--- lib/adapters/redis/queue.coffee
+++ lib/adapters/redis/queue.coffee
@@ -13,3 +13,5 @@
       callback(null, v)
   del: (name, callback) ->
     @redis.del name, callback
+  range: (name, from, to, callback) ->
+    @redis.lrange name, from, to, callback


Add serialization version to image and archive edit sessions

--- lib/archive-edit-session.coffee
+++ lib/archive-edit-session.coffee
@@ -7,6 +7,7 @@
 module.exports=
 class ArchiveEditSession
   registerDeserializer(this)
+  @version: 1

   @activate: ->
     Project = require 'project'


can receive defaults to true

can receive defaults to true

--- lib/simpleAuth.coffee
+++ lib/simpleAuth.coffee
@@ -20,7 +20,7 @@
     checkLists fromDevice, toDevice, toDevice?.discoverWhitelist, toDevice?.discoverBlacklist, true

   canReceive: (fromDevice, toDevice) ->
-    checkLists fromDevice, toDevice, toDevice?.receiveWhitelist, toDevice?.receiveBlacklist, false
+    checkLists fromDevice, toDevice, toDevice?.receiveWhitelist, toDevice?.receiveBlacklist, true

   canSend: (fromDevice, toDevice) ->
     checkLists fromDevice, toDevice, toDevice?.sendWhitelist, toDevice?.sendBlacklist, true


Clean up view subscriptions when editor is destroyed

Fixes #218
Fixes atom/atom#10957

--- lib/bracket-matcher-view.coffee
+++ lib/bracket-matcher-view.coffee
@@ -53,7 +53,12 @@
     @subscriptions.add atom.commands.add editorElement, 'bracket-matcher:remove-matching-brackets', =>
       @removeMatchingBrackets()

+    @subscriptions.add @editor.onDidDestroy @destroy
+
     @updateMatch()
+
+  destroy: =>
+    @subscriptions.dispose()

   subscribeToCursor: ->
     cursor = @editor.getLastCursor()


:art:

:art:

--- lib/tag-reader.coffee
+++ lib/tag-reader.coffee
@@ -2,21 +2,23 @@
 ctags = require 'ctags'
 fs = require 'fs-plus'

-handlerPath = require.resolve('./load-tags-handler')
+handlerPath = require.resolve './load-tags-handler'

 module.exports =
   getTagsFile: ->
-    directory = atom.project.getDirectories()[0]
-    tagsFile = directory?.resolve("tags")
+    [directory] = atom.project.getDirectories()
+    return unless directory?
+
+    tagsFile = directory.resolve("tags")
     return tagsFile if fs.isFileSync(tagsFile)

-    tagsFile = directory?.resolve("TAGS")
+    tagsFile = directory.resolve("TAGS")
     return tagsFile if fs.isFileSync(tagsFile)

-    tagsFile = directory?.resolve(".tags")
+    tagsFile = directory.resolve(".tags")
     return tagsFile if fs.isFileSync(tagsFile)

-    tagsFile = directory?.resolve(".TAGS")
+    tagsFile = directory.resolve(".TAGS")
     return tagsFile if fs.isFileSync(tagsFile)

   find: (editor, callback) ->


Fixed a problem where a service point's click are would overshadow the click area of a public transit stop marker by increasing z-index

--- src/map-view.coffee
+++ src/map-view.coffee
@@ -337,6 +337,7 @@
             app.request 'selectUnit', unit, {}

         drawPublicTransitStops: (stops, route, stopsCache) ->
+            Z_INDEX = 1000
             for stop in stops
                 isStopInCache = false

@@ -351,6 +352,7 @@
                     latLng = L.latLng(stop.lat, stop.lon)
                     marker = L.marker latLng,
                         clickable: true
+                        zIndexOffset: Z_INDEX

                     do (stop) ->
                         marker.on 'click', (e) ->


Remove unneeded console.logs

Remove unneeded console.logs

--- src/jira.coffee
+++ src/jira.coffee
@@ -57,10 +57,8 @@

     fetch("#{jiraUrl}/rest/api/2/user/search?username=#{msg.message.user.email_address}", headers: headers)
     .then (res) ->
-      console.log "checking"
       checkStatus res
     .then (res) ->
-      console.log "parsing"
       parseJSON res
     .then (user) ->
       reporter = user[0] if user and user.length is 1
@@ -93,16 +91,13 @@
       issue.fields.reporter = reporter if reporter
       issue
     .then (issue) ->
-      console.log "fetching issue", issue
       fetch "#{jiraUrl}/rest/api/2/issue",
         headers: headers
         method: "POST"
         body: JSON.stringify issue
     .then (res) ->
-      console.log "checking", res
       checkStatus res
     .then (res) ->
-      console.log "parsing"
       parseJSON res
     .then (json) ->
       msg.send "<@#{msg.message.user.id}> Ticket created: #{jiraUrl}/browse/#{json.key}"


Change slack emoji and associated actions

--- src/jira.coffee
+++ src/jira.coffee
@@ -633,10 +633,11 @@
     send msg, "\n#{responses.join '\n\n\n'}"

   robot.on "jira_ticket_created_message", (msg) ->
-    reactions = ["+1", "-1", "watch", "raising_hand", "white_check_mark", "fast_forward"]
+    reactions = ["point_up_2", "point_down", "watch", "raising_hand", "soon", "fast_forward"]
     dispatchNextReaction = ->
       reaction = reactions.shift()
       return unless reaction
+      console.log "#{} reaction #{reaction}"
       params =
         channel: msg.channel
         timestamp: msg.ts
@@ -704,7 +705,7 @@
     getTicketInChannelByTs(msg.item.channel, msg.item.ts)
     .then (ticket) ->
       switch msg.reaction
-        when "+1", "-1"
+        when "point_up_2", "point_down"
           handleRankRequest
             message: room: msg.item.channel
             match: [ "", ticket, if msg.reaction is "+1" then "up" else "down" ]
@@ -714,8 +715,8 @@
             message: room: msg.item.channel
             match: [ "", ticket, robot.adapter.client.getUserByID(msg.user).name ]
           , no
-        when "white_check_mark", "fast_forward"
-          term = if msg.reaction is "white_check_mark" then "done" else "progress"
+        when "soon", "fast_forward"
+          term = if msg.reaction is "soon" then "selected" else "progress"
           result = fuzzyFind term, transitions, ['jira']
           if result
             handleTransitionRequest


bump up to a bigger nbits for testing

bump up to a bigger nbits for testing

--- src/keygen.iced
+++ src/keygen.iced
@@ -73,7 +73,7 @@
       s = ""
     interval = if obj.total? and obj.i? then "(#{obj.i} of #{obj.total})" else ""
     console.log "+ #{obj.what} #{interval} #{s}"
-  await generate_keypair { nbits : 512, userid : 'shitty', progress_hook, passphrase : "xxx333" }, defer err, res
+  await generate_keypair { nbits : 2048, userid : 'shitty', progress_hook, passphrase : "xxx333" }, defer err, res
   console.log res
   process.exit 0
   openpgp.init()


change arg position

change arg position

--- src/main.coffee
+++ src/main.coffee
@@ -4,7 +4,7 @@

 class Pipe

-  constructor: (@dir, @output, @pack) ->
+  constructor: (@dir, @pack, @output) ->

   launchPipe: (userPipe, cb) ->
     amdifyPipe = amdify @dir
@@ -16,5 +16,5 @@

 module.exports =
-  watch: (dir, output, pack) ->
-    new Pipe(dir, output, pack)+  watch: (dir, pack, output) ->
+    new Pipe(dir, pack, output)


Fix Issue 69: Unintentional content is shown when a long selection list is displayed on search form

--- src/main.coffee
+++ src/main.coffee
@@ -77,4 +77,7 @@

 		# Uncover the pages that were invisibile during the initial loading phase
 		$('div[data-role="page"]').css(visibility: 'visible')
+
+		# Do not show again the default message that was shown during initial loading
+		$('#messages').empty()
 		return


don't use asynchronous library resolution

--- src/main.coffee
+++ src/main.coffee
@@ -418,11 +418,12 @@
 do ->
   patterns  = [ '*.js', '!main.js', '!_*' ]
   settings  = { cwd: ( PATH.join __dirname ), deep: false, absolute: true, }
-  paths     = await glob patterns, settings
+  paths     = glob.sync patterns, settings
   #.........................................................................................................
   for path in paths
     module = require path
     for key, value of module
+      # debug '38833', "#{path}##{key}"
       continue if key.startsWith '_'
       throw new Error "duplicate key #{rpr key}" if L[ key ]?
       L[ key ] = value


webapp: polyfill for internet explorer not knowing String::startsWith

--- src/webapp-lib.coffee
+++ src/webapp-lib.coffee
@@ -9,6 +9,11 @@
 # TODO switch to npm packaging

 require("script!primus/primus-engine.min.js")
+
+# polyfill for internet explorer's lack of knowing String.prototype.startswith
+String::startsWith ?= (searchString, position) ->
+    pos = position ? 0
+    @indexOf(searchString, pos) == pos

 # this must come before anything that touches event handling, etc.
 require('webapp-lib/webapp-error-reporter.coffee')


add space

add space

--- src/nintendo.coffee
+++ src/nintendo.coffee
@@ -35,6 +35,7 @@
             #{gameCard.title}
             id: #{gameCard.id}
             link: http://www.nintendo.com/games/detail/#{gameCard.id}
+
             """
           results = gameNames.join("\n")
         else


BUG-FIX When no properties in string BUG-FIX When no property in scope

--- src/neck.coffee
+++ src/neck.coffee
@@ -54,9 +54,10 @@
     string = string.replace /\'[^\']+\'/g, (text)-> "###"
     result = []

-    for item in string.match /scope\.([a-zA-Z$_][^\ \(\)\{\}\;]*)/g
-      if result.indexOf(property = item.replace('scope.','')) is -1
-        result.push property.split('.')[0]
+    if (matches = string.match /scope\.([a-zA-Z$_][^\ \(\)\{\}\;]*)/g) instanceof Array
+      for item in matches
+        if result.indexOf(property = item.replace('scope.','')) is -1
+          result.push property.split('.')[0]

     result

@@ -137,11 +138,13 @@
           @bind "refresh:#{property}", callback
         else
           scope = @
-          while parentScope = scope.parent
-            if parentScope._resolvers[property]
-              for resolver in parentScope._resolvers[property]
+          while scope = scope.parent
+            if scope._resolvers[property]
+              for resolver in scope._resolvers[property]
                 @listenTo resolver.scope, "refresh:#{resolver.property}", callback
               break
+          unless scope
+            @listenTo @._root(), "refresh:#{property}", callback
     else
       @listenTo @_root(), "refresh:?", callback


Do not allow to delete root domains like username.kd.io or groupname.kd.io, Update UI issues with Environments app

--- core/utils.coffee
+++ core/utils.coffee
@@ -734,7 +734,7 @@
     resourceRoot = "#{KD.appsUri}/#{authorNick}/#{name}/#{version}/"

     if appManifest.devMode # TODO: change url to https when vm urls are ready for it
-      resourceRoot = "http://#{KD.getSingleton('vmController').defaultVm}/.applications/#{__utils.slugify name}/"
+      resourceRoot = "http://#{KD.getSingleton('vmController').defaultVm}/.applications/#{__utils.slugify name}/"

     image  = if name is "Ace" then "icn-ace" else "default.app.thumb"
     thumb  = "#{KD.apiUri}/images/#{image}.png"


protocol: Also return full runtime definition in getCapabilities()

--- src/protocol.coffee
+++ src/protocol.coffee
@@ -124,7 +124,7 @@
   return callback null, def.capabilities if def?.capabilities?.length
   onCapabilities = (capabilities) ->
     client.removeListener 'capabilities', onCapabilities
-    return callback null, capabilities
+    return callback null, capabilities, def
   client.on 'capabilities', onCapabilities

 exports.getComponentTests = (client, callback) ->


Changed to normal buffer from slow buffer

--- src/question.coffee
+++ src/question.coffee
@@ -21,6 +21,7 @@
   constructor: ->
     if typeof arguments['0'] == 'object'
       req = arguments['0']
+      req = new Buffer(req.toString('hex'), 'hex')

       @qName  = this.parseQname(req.slice(12, req.length - 4))
       @qType  = new QType(req.slice(req.length - 4, req.length - 2))


Simplify doPreprocess/doPostprocess

Simplify doPreprocess/doPostprocess

No longer use return values

--- src/svgtiler.coffee
+++ src/svgtiler.coffee
@@ -1189,14 +1189,12 @@
     @preprocessQueue.push fn
   postprocess: (fn) ->
     @postprocessQueue.push fn
-  doPreprocess: (render, onResult) ->
+  doPreprocess: (render) ->
     for callback in @preprocessQueue
-      result = callback.call render, render
-      onResult? result, @
-  doPostprocess: (render, onResult) ->
+      callback.call render, render
+  doPostprocess: (render) ->
     for callback in @postprocessQueue
-      result = callback.call render, render
-      onResult? result, @
+      callback.call render, render

 preprocess = (fn) ->
   unless currentMapping?
@@ -1313,12 +1311,12 @@
       value = @[i].lookup key, context
       return value if value?
     undefined
-  doPreprocess: (render, onResult) ->
+  doPreprocess: (render) ->
     for mapping in @
-      mapping.doPreprocess render, onResult
-  doPostprocess: (render, onResult) ->
+      mapping.doPreprocess render
+  doPostprocess: (render) ->
     for mapping in @
-      mapping.doPostprocess render, onResult
+      mapping.doPostprocess render

 blankCells = new Set [
   ''


Delete reference to scrollMonitor after destroy is called

Fixes issue with in-viewport directive

--- src/viewport.coffee
+++ src/viewport.coffee
@@ -112,6 +112,7 @@

 		# Update whether asset is in the viewport
 		updateInViewport: (asset) ->
+			return unless @[asset+'ScrollMonitor']
 			@[asset+'InViewport'] = @[asset+'ScrollMonitor'].isInViewport
 			@removeScrollListeners asset if @canRemoveScrollListeners asset

@@ -123,7 +124,9 @@

 		# Destroy scrollMonitor
 		removeScrollListeners: (asset) ->
-			@[asset+'ScrollMonitor'].destroy() if @[asset+'ScrollMonitor']
+			if @[asset+'ScrollMonitor']
+				@[asset+'ScrollMonitor'].destroy()
+				delete @[asset+'ScrollMonitor']

 		# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 		# Container sizing


Add recap

Add recap

--- src/worldcup.coffee
+++ src/worldcup.coffee
@@ -73,4 +73,18 @@
       msg.send "#{person}: one more and you're out"
     else if color == "red"
       msg.send "http://img.thesun.co.uk/aidemitlum/archive/01689/red_main_1689473a.jpg"
-      msg.send "#{person}: you're out"+      msg.send "#{person}: you're out"
+
+  robot.respond /(worldcup|wc)( recap)/i, (msg) ->
+    msg.http("http://worldcup2014bot.herokuapp.com/scores/recap")
+      .get() (err, res, body) ->
+        scores = JSON.parse(body).scores
+        if scores.length > 0
+          scores_array = scores.map (score) ->
+            score.score_summary
+
+          formatted_scores = scores_array.join("\n")
+
+          msg.send formatted_scores
+        else
+          msg.send "There were no matches yesterday :("


Fix configure bug.

Fix configure bug.

--- src/ex.coffee
+++ src/ex.coffee
@@ -19,7 +19,7 @@
   for env in ['development', 'production', 'test']
     do (env) ->
       wrapper[env] = (fn) ->
-        configure.call app, env, ->
+        app.configure.call app, env, ->
           fn.call app

   # inject req/res properties into route handlers


Support properties list in model generator

--- generators/model/templates/model.coffee
+++ generators/model/templates/model.coffee
@@ -1,6 +1,10 @@
 root = global ? window

-class <%= classified %> extends Document
-  @Meta()
+<%= classified %> = new Meteor.Collection "<%= tableized %>"
+
+<%= classified %>.attachSchema new SimpleSchema {<% properties.forEach(function (property){ %>
+  <%= property.name %>:
+    type: <%= property.type %><% }) %>
+}

 root.<%= classified %> = <%= classified %>


Remove chocolatey logging message

Remove chocolatey logging message

--- src/browser/auto-updater-win32.coffee
+++ src/browser/auto-updater-win32.coffee
@@ -40,7 +40,6 @@
     updateDotExe = @getUpdateExePath()

     unless fs.existsSync(updateDotExe)
-      console.log 'Running developer or Chocolatey version of Atom, skipping'
       @emit 'update-not-available'
       return


:lipstick:

:lipstick:

--- src/browser/auto-updater-win32.coffee
+++ src/browser/auto-updater-win32.coffee
@@ -56,7 +56,7 @@
       stdout: (output) -> updateOutput += output
       exit: (exitCode) ->
         unless exitCode is 0
-          console.log 'Failed to update: ' + exitCode + ' - ' + updateOutput
+          console.log "Failed to update: #{exitCode} - #{updateOutput}"
           emit 'update-not-available'
           return

@@ -68,8 +68,8 @@
           json = updateOutput.split("\n").reverse()[0]

           updateInfo = JSON.parse json
-        catch ex
-          console.log "Update output isn't valid: " + updateOutput
+        catch error
+          console.log "Update output isn't valid: #{updateOutput}"
           emit 'update-not-available'
           return

@@ -84,8 +84,8 @@
         # we always just download
         emit 'update-available'
         emit 'update-downloaded',
-          releaseNotes: latest.releaseNotes,
-          releaseName: "Atom " + latest.version,
-          releaseDate: "",   # NB: Squirrel doesn't provide this :(
-          updateUrl: "https://atom.io",
+          releaseNotes: latest.releaseNotes
+          releaseName: "Atom #{latest.version}"
+          releaseDate: ""   # NB: Squirrel doesn't provide this :(
+          updateUrl: "https://atom.io"
           quitAndUpdate: @quitAndInstall


staticpage: change About link to Koding University and fix Feature link

--- servers/lib/crawler/staticpages/feed.coffee
+++ servers/lib/crawler/staticpages/feed.coffee
@@ -209,8 +209,8 @@
             Login

-            Features
-            About Koding
+            Features
+            Koding University


Add a guard against fair profiles without icons

--- desktop/apps/fairs/helpers/view_helpers.coffee
+++ desktop/apps/fairs/helpers/view_helpers.coffee
@@ -49,7 +49,7 @@
     @isEligible(fair) and @isNotOver(fair)

   isEligible: (fair) ->
-    fair.is_published and fair.profile?.is_published
+    fair.is_published and fair.profile?.is_published and fair.profile?.icon?.url

   isNotOver: (fair) ->
     Date.parse(fair.end_at) > new Date


No need that anymore

No need that anymore

--- client/landing/app/MainApp/kodingappscontroller.coffee
+++ client/landing/app/MainApp/kodingappscontroller.coffee
@@ -438,13 +438,6 @@

     manifestFile  = FSHelper.createFileFromPath "#{appPath}/manifest.json"
     changeLogFile = FSHelper.createFileFromPath "#{appPath}/ChangeLog"
-
-    stack.push (cb)=>
-      @kiteController.run
-        method    : "fs.ensurePathExists"
-        withArgs  :
-          path    : "/home/#{KD.whoami().profile.nickname}/Applications"
-        , cb

     # Copy default app files (app Skeleton)
     stack.push (cb)=>


teams: routes: open /Teams route for general public but keep the subpages hidden

--- client/landing/site.landing/coffee/teams/routes.coffee
+++ client/landing/site.landing/coffee/teams/routes.coffee
@@ -15,6 +15,6 @@
         location.assign href
         return

-      return router.handleRoute '/'  unless KD.config.hasTeamAccess
+      cb = (app) -> app.handleQuery query  if KD.config.hasTeamAccess and query

-      KD.singletons.router.openSection 'Teams', null, null, (app) -> app.handleQuery query  if query
+      KD.singletons.router.openSection 'Teams', null, null, cb


send connectionAccepted/Rejected events on connect

let the client know whether it has successfully authenticated

--- services/real-time/app/coffee/Router.coffee
+++ services/real-time/app/coffee/Router.coffee
@@ -39,10 +39,21 @@
 		app.post "/drain", httpAuth, HttpApiController.startDrain

 		session.on 'connection', (error, client, session) ->
+			if client? and error?.message?.match(/could not look up session by key/)
+				logger.err err: error, client: client?, session: session?, "invalid session"
+				# tell the client to reauthenticate if it has an invalid session key
+				client.emit("connectionRejected", {message: "invalid session"})
+				client.disconnect()
+				return
+
 			if error?
-				logger.err err: error, "error when client connected"
+				logger.err err: error, client: client?, session: session?, "error when client connected"
+				client?.emit("connectionRejected", {message: "error"})
 				client?.disconnect()
 				return
+
+			# send positive confirmation that the client has a valid connection
+			client.emit("connectionAccepted")

 			metrics.inc('socket-io.connection')


tests: disable activity postwith suit cc/ @didemacet

--- scripts/test-instance/parallel-sets.coffee
+++ scripts/test-instance/parallel-sets.coffee
@@ -37,7 +37,7 @@
   [
     { name: 'messages privatemessage' }
     { name: 'account accountsettings' }
-    { name: 'activity postwith' }
+    # { name: 'activity postwith' }
   ]

   [


fixed and added tests

fixed and added tests

--- test/encrypt.coffee
+++ test/encrypt.coffee
@@ -75,6 +75,9 @@
     sinon.spy BasicEncryptedModel.prototype, 'decryptSync'

   beforeEach (done) ->
+    BasicEncryptedModel.prototype.encrypt.reset()
+    BasicEncryptedModel.prototype.decryptSync.reset()
+
     @simpleTestDoc2 = new BasicEncryptedModel
       text: 'Unencrypted text'
       bool: true
@@ -122,7 +125,12 @@
       assert.deepEqual doc.buf, new Buffer 'abcdefg'
       done err

-describe 'document.save() when only nonencrypted fields selected on .find()', ->
+   it 'should have called encrypt then decrypt', ->
+    assert.equal @simpleTestDoc2.encrypt.callCount, 1
+    assert.equal @simpleTestDoc2.decryptSync.callCount, 1
+    assert @simpleTestDoc2.encrypt.calledBefore @simpleTestDoc2.decryptSync
+
+describe 'document.save() when only certain fields are encrypted', ->
   before ->
     PartiallyEncryptedModelSchema = mongoose.Schema
       encryptedText: type: String
@@ -137,9 +145,6 @@
       encryptedText: 'Encrypted Text'
       unencryptedText: 'Unencrypted Text'

-    sinon.spy @partiallyEncryptedDoc, 'encrypt'
-    sinon.spy @partiallyEncryptedDoc, 'decryptSync'
-
     @partiallyEncryptedDoc.save (err) ->
       assert.equal err, null
       done()
@@ -148,11 +153,6 @@
     @partiallyEncryptedDoc.remove (err) ->
       assert.equal err, null
       done()
-
-  it 'should have called encrypt then decrypt', ->
-    assert.equal @partiallyEncryptedDoc.encrypt.callCount, 1
-    assert.equal @partiallyEncryptedDoc.decryptSync.callCount, 1
-    assert @partiallyEncryptedDoc.encrypt.calledBefore @partiallyEncryptedDoc.decryptSync

   it 'should have decrypted fields', ->
     assert.equal @partiallyEncryptedDoc.encryptedText, 'Encrypted Text'
@@ -562,55 +562,115 @@
         done()

 describe 'Array EmbeddedDocument', ->
-  before ->
-    ChildModelSchema = mongoose.Schema
-      text: type: String
-
-    ChildModelSchema.plugin encrypt, key: encryptionKey
-
-    ParentModelSchema = mongoose.Schema
-      text: type: String
-      children: [ChildModelSchema]
-
-    @ParentModel = mongoose.model 'Parent', ParentModelSchema
-    @ChildModel = mongoose.model 'Child', ChildModelSchema
-
-  beforeEach (done) ->
-    @parentDoc = new @ParentModel
-      text: 'Unencrypted text'
-
-    childDoc = new @ChildModel
-      text: 'Child unencrypted text'
-
-    @parentDoc.children.addToSet childDoc
-
-    @parentDoc.save done
-
-  after (done) ->
-    @parentDoc.remove done
-
-  describe 'document.save()', ->
-    it 'should have decrypted fields', ->
-      assert.equal @parentDoc.children[0].text, 'Child unencrypted text'
-
-    it 'should persist children as encrypted', (done) ->
-      @ParentModel.find
-        _id: @parentDoc._id
-        'children._ct': $exists: true
-        'children.text': $exists: false
-      , (err, docs) ->
-        assert.lengthOf docs, 1
-        assert.propertyVal docs[0].children[0], 'text', 'Child unencrypted text'
-        done()
-
-  describe 'document.find()', ->
-    it 'when parent doc found, should pass an unencrypted version of the embedded document to the callback', (done) ->
-      @ParentModel.findById @parentDoc._id, (err, doc) ->
-        assert.equal err, null
-        assert.propertyVal doc, 'text', 'Unencrypted text'
-        assert.isArray doc.children
-        assert.isObject doc.children[0]
-        assert.property doc.children[0], 'text', 'Child unencrypted text'
-        assert.property doc.children[0], '_id'
-        assert.notProperty doc.children[0], '_ct'
-        done()
+  describe 'when only child is encrypted', ->
+    before ->
+      ChildModelSchema = mongoose.Schema
+        text: type: String
+
+      ChildModelSchema.plugin encrypt, key: encryptionKey
+
+      ParentModelSchema = mongoose.Schema
+        text: type: String
+        children: [ChildModelSchema]
+
+      @ParentModel = mongoose.model 'Parent', ParentModelSchema
+      @ChildModel = mongoose.model 'Child', ChildModelSchema
+
+    beforeEach (done) ->
+      @parentDoc = new @ParentModel
+        text: 'Unencrypted text'
+
+      childDoc = new @ChildModel
+        text: 'Child unencrypted text'
+
+      @parentDoc.children.addToSet childDoc
+
+      @parentDoc.save done
+
+    after (done) ->
+      @parentDoc.remove done
+
+    describe 'document.save()', ->
+      it 'should have decrypted fields', ->
+        assert.equal @parentDoc.children[0].text, 'Child unencrypted text'
+
+      it 'should persist children as encrypted', (done) ->
+        @ParentModel.find
+          _id: @parentDoc._id
+          'children._ct': $exists: true
+          'children.text': $exists: false
+        , (err, docs) ->
+          assert.lengthOf docs, 1
+          assert.propertyVal docs[0].children[0], 'text', 'Child unencrypted text'
+          done()
+
+    describe 'document.find()', ->
+      it 'when parent doc found, should pass an unencrypted version of the embedded document to the callback', (done) ->
+        @ParentModel.findById @parentDoc._id, (err, doc) ->
+          assert.equal err, null
+          assert.propertyVal doc, 'text', 'Unencrypted text'
+          assert.isArray doc.children
+          assert.isObject doc.children[0]
+          assert.property doc.children[0], 'text', 'Child unencrypted text'
+          assert.property doc.children[0], '_id'
+          assert.notProperty doc.children[0], '_ct'
+          done()
+
+  describe 'when child and parent are encrypted', ->
+    before ->
+      ChildModelSchema = mongoose.Schema
+        text: type: String
+
+      ChildModelSchema.plugin encrypt, key: encryptionKey
+
+      ParentModelSchema = mongoose.Schema
+        text: type: String
+        children: [ChildModelSchema]
+
+      ParentModelSchema.plugin encrypt, key: encryptionKey, fields: ['text']
+
+      @ParentModel = mongoose.model 'ParentBoth', ParentModelSchema
+      @ChildModel = mongoose.model 'ChildBoth', ChildModelSchema
+
+    beforeEach (done) ->
+      @parentDoc = new @ParentModel
+        text: 'Unencrypted text'
+
+      childDoc = new @ChildModel
+        text: 'Child unencrypted text'
+
+      @parentDoc.children.addToSet childDoc
+
+      @parentDoc.save done
+
+    after (done) ->
+      @parentDoc.remove done
+
+    describe 'document.save()', ->
+      it 'should have decrypted fields on parent', ->
+        assert.equal @parentDoc.text, 'Unencrypted text'
+
+      it 'should have decrypted fields', ->
+        assert.equal @parentDoc.children[0].text, 'Child unencrypted text'
+
+      it 'should persist children as encrypted', (done) ->
+        @ParentModel.find
+          _id: @parentDoc._id
+          'children._ct': $exists: true
+          'children.text': $exists: false
+        , (err, docs) ->
+          assert.lengthOf docs, 1
+          assert.propertyVal docs[0].children[0], 'text', 'Child unencrypted text'
+          done()
+
+    describe 'document.find()', ->
+      it 'when parent doc found, should pass an unencrypted version of the embedded document to the callback', (done) ->
+        @ParentModel.findById @parentDoc._id, (err, doc) ->
+          assert.equal err, null
+          assert.propertyVal doc, 'text', 'Unencrypted text'
+          assert.isArray doc.children
+          assert.isObject doc.children[0]
+          assert.property doc.children[0], 'text', 'Child unencrypted text'
+          assert.property doc.children[0], '_id'
+          assert.notProperty doc.children[0], '_ct'
+          done()


a little refactoring to katex plugin

a little refactoring to katex plugin

--- packages/rocketchat-katex/katex.coffee
+++ packages/rocketchat-katex/katex.coffee
@@ -4,20 +4,18 @@
 ###

 class Katex
-	delimiters_map: {
-		'\\[': { closer: '\\]', displayMode: true  },
-		'\\(': { closer: '\\)', displayMode: false },
-
-		# Conflicts with message tokens syntax: $token$
-		'$$' : { closer: '$$' , displayMode: true  },
-		'$'  : { closer: '$'  , displayMode: false },
-	}
+	delimiters_map: [
+		{ opener: '\\[', closer: '\\]', displayMode: true  },
+		{ opener: '\\(', closer: '\\)', displayMode: false },
+		{ opener: '$$' , closer: '$$' , displayMode: true  },
+		{ opener: '$'  , closer: '$'  , displayMode: false },
+	]

 	# Searches for the first opening delimiter in the string
 	find_opening_delimiter: (str) ->
 		# Search the string for each opening delimiter
-		matches = ({options: o, pos: str.indexOf(b)} for b,o of @delimiters_map)
-		positions = (b.pos for b in matches when b.pos >= 0)
+		matches = ({options: o, pos: str.indexOf(o.opener)} for o in @delimiters_map)
+		positions = (m.pos for m in matches when m.pos >= 0)

 		# No opening delimiters were found
 		if positions.length == 0
@@ -26,7 +24,7 @@
 		# Take the first delimiter found
 		pos = Math.min.apply Math, positions

-		match_index = (b.pos for b in matches).indexOf(pos)
+		match_index = (m.pos for m in matches).indexOf(pos)
 		match = matches[match_index]

 		return match


more regex tests

more regex tests

--- test/regexps.coffee
+++ test/regexps.coffee
@@ -29,6 +29,8 @@
     eq 0, a(/b/i)
     eq 0, a /b /i

+  # FAIL Failing as LiveScript can't handle this
+  ###
   test 'regexps can start with spaces and = when unambiguous', ->
     a = -> 0
     eq 0, a(/ b/i)
@@ -37,6 +39,14 @@
     eq 0, a(/ /)
     eq 1, +/ /.test ' '
     eq 1, +/=/.test '='
+  ###

   test 'regexps can be empty', ->
     ok //.test ''
+
+  test 'regexps with spaces', ->
+    ok /hi there/.test 'hi there'
+
+  test 'regexps with interpolation', ->
+    x = 'hi'
+    ok ///#{x}!///.test 'hi!'


CUI: data-form: remove legacy appearance attributes and CSS classes (these were wrongly introduced for the fylr theme)

--- src/elements/DataForm/DataForm.coffee
+++ src/elements/DataForm/DataForm.coffee
@@ -231,7 +231,7 @@
 			trash = new CUI.defaults.class.Button
 				icon: "fa-trash-o"
 				appearance: "flat"
-				size: "mini"
+
 				onMouseenter: =>
 					CUI.dom.addClass(hl, "cui-data-form-row--trash")
 				onMouseleave: =>
@@ -268,4 +268,4 @@
 			move: move

 		@__verticalLayout.append(hl, "center")
-		return+		return


PUBDEV-2327 Update multivalued grid parameters when updated post-initialization.

--- src/ext/components/model-input.coffee
+++ src/ext/components/model-input.coffee
@@ -85,7 +85,8 @@
   control = createControl 'dropdown', parameter
   control.values = signals parameter.values
   control.value = _value
-  control.gridedValues = createGridableValues parameter.values
+  control.gridedValues = lift control.values, (values) ->
+    createGridableValues values
   control

 createListControl = (parameter) ->
@@ -326,7 +327,7 @@
               hyperParameters[control.name] = control.valueGrided()
             when 'dropdown'
               hyperParameters[control.name] = selectedValues = []
-              for item in control.gridedValues
+              for item in control.gridedValues()
                 if item.value()
                   selectedValues.push item.label
             else # checkbox


Change solvedByWeek start date

Change solvedByWeek start date


nuke stuff that doesn't belong here

nuke stuff that doesn't belong here

--- src/stream.iced
+++ src/stream.iced
@@ -58,20 +58,3 @@
   return out

 ##=======================================================================
-
-exports.colgrep = colgrep = ({patterns, buffer, separator}) ->
-  separator or= /:/
-  lines = buffer.toString('utf8').split '\n'
-  indices = (parseInt(k) for k,v of patterns)
-  max_index = Math.max indices...
-  out = []
-  for line in lines when (cols = line.split separator)? and (max_index < cols.length)
-    found = true
-    for k,v of patterns
-      unless cols[k].match v
-        found = false
-        break
-    out.push cols if found
-  return out
-
-##=======================================================================


Unset image with and height styles

Unset image with and height styles

--- src/trix/controllers/attachment_controller.coffee
+++ src/trix/controllers/attachment_controller.coffee
@@ -26,7 +26,7 @@
     setStyle(@element, width: "100%", height: "auto")

   uninstall: =>
-    setStyle(@element, getDimensions(@element))
+    setStyle(@element, width: null, height: null)
     @editor.parentElement.replaceChild(@element, @editor)
     @delegate?.attachmentControllerDidUninstall()


Fix tyop

Fix tyop

--- src/teak.coffee
+++ src/teak.coffee
@@ -145,7 +145,7 @@

   uiCallbackHandler: (callback, carrotResponse, fbResponse) ->
     if typeof(callback) == "function"
-      callback(carrotResonse, fbResponse)
+      callback(carrotResponse, fbResponse)
     else if typeof(callback) == "string" && @getSwf()
       @swfCallback(carrotResponse, fbResponse, callback)


Update my.button colors

Update my.button colors

--- src/my.coffee
+++ src/my.coffee
@@ -1,4 +1,5 @@
 # TODO: Make 'my' kinds inherit values somehow
+# TODO: Pull element colors into their own namespace

 # iPad sizes based on https://stackoverflow.com/questions/3375706/ipad-browser-width-height-standard/9049670#9049670
 PAGE = [1024, 690]


don't need from_heroku in _obj anymore

don't need from_heroku in _obj anymore

--- js/inner/_obj.coffee
+++ js/inner/_obj.coffee
@@ -5,8 +5,6 @@

     for k,v of $.extend {}, defaults, json
       if @observables().hasOwnProperty(k) then @[k](v) else @[k] = v
-
-    @from_heroku = ko.observable(window.renderContext.from_heroku)

   observables: () => {}


Handle errors from season. Fix #106

Handle errors from season. Fix #106

--- lib/project-manager-view.coffee
+++ lib/project-manager-view.coffee
@@ -58,20 +58,27 @@
     @panel?.hide()

   show: ->
-    @panel ?= atom.workspace.addModalPanel(item: this)
-    @panel.show()
-    projects = []
-    currentProjects = CSON.readFileSync(@projectManager.file())
-    for title, project of currentProjects
-      if project.template?
-        project = _.deepExtend(project, currentProjects[project.template])
-      projects.push(project) if project.paths?
+    CSON.readFile @projectManager.file(), (error, currentProjects) =>
+      unless error
+        projects = []
+        for title, project of currentProjects
+          if project.template?
+            project = _.deepExtend(project, currentProjects[project.template])
+          projects.push(project) if project.paths?

-    sortBy = atom.config.get('project-manager.sortBy')
-    if sortBy isnt 'default'
-      projects = @sortBy(projects, sortBy)
-    @setItems(projects)
-    @focusFilterEditor()
+        sortBy = atom.config.get('project-manager.sortBy')
+        if sortBy isnt 'default'
+          projects = @sortBy(projects, sortBy)
+
+        @panel ?= atom.workspace.addModalPanel(item: this)
+        @panel.show()
+        @setItems(projects)
+        @focusFilterEditor()
+      else
+        message = "There was an error trying to list your projects"
+        options =
+          detail: error.message
+        atom.notifications.addError message, options

   viewForItem: ({title, paths, icon, group, devMode}) ->
     icon = icon or 'icon-chevron-right'


Icon: Show the first letter of the 'icon' property when the icon does not exist. See #61124

--- src/base/Icon/Icon.coffee
+++ src/base/Icon/Icon.coffee
@@ -29,7 +29,12 @@
 		if svg_cls
 			@DOM = CUI.dom.htmlToNodes("<svg class=\"cui-icon-svg #{svg_cls} #{cls}\"><use xlink:href=\"##{svg_cls.split(" ")[0]}\"></svg>")[0]
 		else
-			@DOM = CUI.dom.element("I", class: "fa "+cls)
+			@DOM = CUI.dom.element("I", class: "fa " + cls)
+
+			if @_icon and not CUI.Icon.icon_map[@_icon]
+				span = CUI.dom.span()
+				span.textContent = @_icon[0]
+				CUI.dom.append(@DOM, span)

 		if @_tooltip
 			@_tooltip.element = @DOM


more debugging output in benchmark

more debugging output in benchmark

--- src/benchmark/pipe.coffee
+++ src/benchmark/pipe.coffee
@@ -39,6 +39,15 @@
                 length += chunk.length
                 cli.progress length / stats.size

+            buffer.on 'pause', () =>
+                @debug "buffer paused."
+
+            buffer.on 'resume', () =>
+                @debug "buffer resumed."
+
+            buffer.on 'end', () =>
+                @info "buffer ended."
+

         server.listen opts.port, 'localhost', () =>
             @ok "server listen on port #{opts.port} …"


add pupil mobile bundle to additional products in store


Fix a bug

Fix a bug

--- core/webHooks.coffee
+++ core/webHooks.coffee
@@ -47,9 +47,10 @@
       e.socket.socket.on('message', @rawGatewayHandler)

   rawGatewayHandler: (e)=>
-    {t,d} = JSON.parse(e);
-    if t is 'WEBHOOKS_UPDATE'
-      @updateCacheForGuild @bot.Guilds.get(d.guild_id)
+    try
+      {t,d} = JSON.parse(e);
+      if t is 'WEBHOOKS_UPDATE'
+        @updateCacheForGuild @bot.Guilds.get(d.guild_id)

   addToCache: (hook)=>
     # First check if not in cache


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/bounded.coffee
+++ test/bounded.coffee
@@ -12,7 +12,7 @@
   equals obj.bounds().width, 50
   equals obj.bounds().height, 100

-test "Bounds returns correct centered x, y, xw, yx", ->
+test "Bounds#centeredBounds returns correct x, y, xw, yx", ->
   obj = GameObject
     x: -5
     y: 20


transfer balance locale

transfer balance locale

--- app/js/controllers/transfer.coffee
+++ app/js/controllers/transfer.coffee
@@ -111,7 +111,7 @@

         my_transfer_form.$setValidity "funds", balance_after_transfer >= 0
         if balance_after_transfer < 0
-            $translate('tip.insufficient_balances').then (val) ->
+            $translate('market.tip.insufficient_balances').then (val) ->
                 my_transfer_form.amount.error_message = val

     #call to initialize and on symbol change
@@ -150,7 +150,7 @@
                 $translate('account.unknown').then (val) ->
                     my_transfer_form.payto.error_message = val
             else if error.data.error.code == 20010
-                $translate('tip.insufficient_balances').then (val) ->
+                $translate('market.tip.insufficient_balances').then (val) ->
                     my_transfer_form.amount.error_message = val
             else
                 my_transfer_form.payto.error_message = Utils.formatAssertException(error.data.error.message)


change fuzzy search to favor shorter paths in tie

--- src/util.coffee
+++ src/util.coffee
@@ -79,6 +79,7 @@
       if x >= 0
         slotResults.push
           tokenNum: tokenNum
+          slotLeng: slot.length
           x: x

     # sort by index
@@ -96,7 +97,7 @@
         else
           1

-      score += point + (result.x / 100)
+      score += point + (result.x / 100) + ((0 - result.slotLeng) / 1000)
       prev = result.tokenNum

     scores.push


Check if app files exists before download, otherwise return a proper error message

--- kites/sharedHosting/api.coffee
+++ kites/sharedHosting/api.coffee
@@ -211,10 +211,14 @@
     #   if err then cb err
     #   else
     #     cb null
-    exec "mv #{userAppPath} #{backupPath} && cp -r #{kpmAppPath}/ #{userAppPath} && chown -R #{username}: #{userAppPath}", (err, stdout, stderr)->
-      if err or stderr then cb err
-      else
-        cb null
+    exec "stat #{kpmAppPath}", (err, stdout, stderr)->
+      unless err or stderr.length
+        cb "[ERROR] App files not found! Download cancelled."
+      else
+        exec "mv #{userAppPath} #{backupPath} && cp -r #{kpmAppPath}/ #{userAppPath} && chown -R #{username}: #{userAppPath}", (err, stdout, stderr)->
+          if err or stderr then cb err
+          else
+            cb null

   installApp: (options, callback)->


reconfigures requires

reconfigures requires

--- drivers/javascript/src/rethinkdb.coffee
+++ drivers/javascript/src/rethinkdb.coffee
@@ -1,3 +1,8 @@
+net = require('net')
+fs = require('fs')
+node_protobuf = require('node-protobuf')
+events = require('events')
+
 # rethinkdb is both the main export object for the module
 # and a function that shortcuts `r.expr`.
 rethinkdb = (args...) -> rethinkdb.expr(args...)
@@ -36,13 +41,6 @@
          throw new RqlDriverError "Expected #{expectedPosArgs} argument(s) but found #{numPosArgs}."
     fun.apply(@, args)

-# Test if the requested node module is available
-testFor = (module) ->
-    try
-        return typeof require is 'function' and require(module)
-    catch e
-        return false
-
 funcWrap = (val) ->
     if val is undefined
         # Pass through the undefined value so it's caught by
@@ -211,9 +209,8 @@
 # Protobuf

 # Initialize message serializer with
-desc = require('fs').readFileSync(__dirname + "/ql2.desc")
-npb = require('node-protobuf').Protobuf
-NodePB = new npb(desc)
+desc = fs.readFileSync(__dirname + "/ql2.desc")
+NodePB = new node_protobuf.Protobuf(desc)

 # Errors

@@ -287,9 +284,7 @@

 # Networking code

-EventEmitter = require('events').EventEmitter
-
-class Connection extends EventEmitter
+class Connection extends events.EventEmitter
     DEFAULT_HOST: 'localhost'
     DEFAULT_PORT: 28015
     DEFAULT_AUTH_KEY: ''
@@ -486,7 +481,7 @@
         @write finalArray.buffer

 class TcpConnection extends Connection
-    @isAvailable: -> testFor('net')
+    @isAvailable: () -> true

     constructor: (host, callback) ->
         unless TcpConnection.isAvailable()
@@ -497,7 +492,6 @@
         if @rawSocket?
             @close()

-        net = require('net')
         @rawSocket = net.connect @port, @host
         @rawSocket.setNoDelay()


Cleanup unused helpers

Cleanup unused helpers

--- test/helpers.coffee
+++ test/helpers.coffee
@@ -1,7 +1,6 @@
 _ = require('underscore')
 global.sinon = require('sinon')
-boolHelpers = require('indeed')
-global.expect = boolHelpers.expect
+global.expect = require('indeed').expect
 sandboxedModule = require('sandboxed-module')

 global.sandbox = (path, requires, globals) ->
@@ -13,14 +12,6 @@
   fix: (obj) ->
     JSON.parse(JSON.stringify(obj))

-boolHelpers.indeed.mixin
-  truthy: () ->
-    (val) ->
-      if val then true else false
-  falsy: () ->
-    (val) ->
-      if val then false else true
-
 global.spyObj = (fns...) ->
   _(fns).reduce (obj, fn) ->
     obj[fn] = sinon.stub()


Some refactoring

Some refactoring

--- src/coffee/presets.coffee
+++ src/coffee/presets.coffee
@@ -3,7 +3,7 @@

   @author Sebastian Helzle (sebastian@helzle.net or @sebobo)
   @category jQuery plugin
-  @copyright (c) 2009-2011 Sebastian Helzle (www.sebastianhelzle.net)
+  @copyright (c) 2009-2012 Sebastian Helzle (www.sebastianhelzle.net)
   @license Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
 ###

@@ -13,7 +13,7 @@

     carousel:
       autoRotation:
-        enabled: true
+        enabled: false
         direction: 1
         once: false
         delay: 5000
@@ -28,8 +28,8 @@
           y: 260
       randomStart: true
       currentLayer: 1
-      funcSize: (layerDiff, rondell) ->
-        (rondell.maxItems / Math.abs(layerDiff)) / rondell.maxItems
+      funcSize: (l, r, i) ->
+        r.maxItems / Math.abs(l) / r.maxItems

     products:
       repeating: false
@@ -84,12 +84,12 @@
         size:
           width: 400
           height: 400
-      funcTop: (layerDiff, rondell) ->
-          rondell.center.top - rondell.itemProperties.size.height / 2
-      funcLeft: (layerDiff, rondell) ->
-          rondell.center.left + layerDiff * rondell.itemProperties.size.width
-      funcDiff: (layerDiff, rondell) ->
-          Math.abs(layerDiff) + 0.5
+      funcTop: (l, r, i) ->
+          r.center.top - r.itemProperties.size.height / 2
+      funcLeft: (l, r, i) ->
+          r.center.left + l * r.itemProperties.size.width
+      funcDiff: (l, r, i) ->
+          Math.abs(l) + 0.5

     cubic:
       center:
@@ -107,12 +107,12 @@
         margin:
           x: 70
           y: 330
-      funcTop: (layerDiff, rondell) ->
-          rondell.center.top - rondell.itemProperties.size.height / 2 + Math.pow(layerDiff / 2, 3) * rondell.radius.x
-      funcLeft: (layerDiff, rondell) ->
-          rondell.center.left - rondell.itemProperties.size.width / 2 + Math.sin(layerDiff) * rondell.radius.x
-      funcSize: (layerDiff, rondell) ->
-          Math.pow((Math.PI - Math.abs(layerDiff)) / Math.PI, 3)
+      funcTop: (l, r, i) ->
+          r.center.top - r.itemProperties.size.height / 2 + Math.pow(l / 2, 3) * r.radius.x
+      funcLeft: (l, r, i) ->
+          r.center.left - r.itemProperties.size.width / 2 + Math.sin(l) * r.radius.x
+      funcSize: (l, r, i) ->
+          Math.pow((Math.PI - Math.abs(l)) / Math.PI, 3)

     gallery:
       # Custom options
@@ -254,11 +254,11 @@
         size:
           width: 600
           height: 300
-      funcTop: (layerDiff, rondell) ->
+      funcTop: (l, r, i) ->
         0
-      funcLeft: (layerDiff, rondell) ->
+      funcLeft: (l, r, i) ->
         0
-      funcOpacity: (layerDist, rondell) ->
+      funcOpacity: (l, r, i) ->
         0.02

 )(jQuery)


Remove gratuitous log

Remove gratuitous log

--- src/view.coffee
+++ src/view.coffee
@@ -1454,7 +1454,6 @@
           # Otherwise, bring us gracefully to the next line
           # without lots of glue (minimize the extra colour).
           else if @bounds[line + 1]? and @multilineChildrenData[line] isnt MULTILINE_MIDDLE
-            console.log @model.stringify()
             # Instead of outward extremes, we take inner extremes this time,
             # to minimize extra colour between lines.
             innerLeft = Math.max @bounds[line + 1].x, @bounds[line].x


Add ctrl-[ keybinding to leave insert mode.

--- keymaps/vim-mode.cson
+++ keymaps/vim-mode.cson
@@ -1,6 +1,7 @@
 '.vim-mode.insert-mode:not(.mini)':
   'escape': 'vim-mode:activate-command-mode'
   'ctrl-c': 'vim-mode:activate-command-mode'
+  'ctrl-[': 'vim-mode:activate-command-mode'

 '.vim-mode.visual-mode:not(.mini)':
   'escape': 'vim-mode:activate-command-mode'


Removed a few more things JSDOM takes care of

--- lib/zombie/jsdom_patches.coffee
+++ lib/zombie/jsdom_patches.coffee
@@ -10,37 +10,14 @@
 HTML.HTMLElement.prototype.__defineGetter__ "offsetTop",    -> 0

-# Essentially all web browsers (Firefox, Internet Explorer, recent versions of
-# Opera, Safari, Konqueror, and iCab, as a non-exhaustive list) return null when
-# the specified attribute does not exist on the specified element. The DOM
-# specification says that the correct return value in this case is actually the
-# empty string, and some DOM implementations implement this behavior.
-# -- https://developer.mozilla.org/en/DOM/element.getAttribute#Notes
-HTML.Element.prototype.getAttribute = (name)->
-  attribute = @_attributes.getNamedItem(name)
-  return attribute?.value || null
-
 # Script elements should always respond to a src attribute with something
 HTML.HTMLScriptElement.prototype.__defineGetter__ "src", ->
   return @getAttribute('src') || ""

-# These two patches are required by the above fix.
-HTML.HTMLAnchorElement.prototype.__defineGetter__ "href", ->
-  return HTML.resourceLoader.resolve(@_ownerDocument, @getAttribute('href') || "")
-HTML.HTMLLinkElement.prototype.__defineGetter__ "href", ->
-  return HTML.resourceLoader.resolve(@_ownerDocument, @getAttribute('href') || "")
-
 # These properties return empty string when attribute is not set.
 HTML.HTMLElement.prototype.__defineGetter__ "id", ->
   return @getAttribute("id") || ""
-# These elements have a name property that must return empty string
-for element in [HTML.HTMLFormElement, HTML.HTMLMenuElement, HTML.HTMLSelectElement,
-                HTML.HTMLInputElement, HTML.HTMLTextAreaElement, HTML.HTMLButtonElement,
-                HTML.HTMLAnchorElement, HTML.HTMLImageElement, HTML.HTMLObjectElement,
-                HTML.HTMLParamElement, HTML.HTMLAppletElement, HTML.HTMLMapElement,
-                HTML.HTMLFrameElement, HTML.HTMLIFrameElement]
-  element.prototype.__defineGetter__ "name", ->
-    return @getAttribute("name") || ""
+
 # These elements have a value property that must return empty string
 for element in [HTML.HTMLInputElement, HTML.HTMLButtonElement, HTML.HTMLParamElement]
   element.prototype.__defineGetter__ "value", ->
@@ -105,41 +82,19 @@
 # textContent returns the textual content of nodes like text, comment,
 # attribute, but when operating on elements, return only textual content of
 # child text/element nodes.
-###
 HTML.Node.prototype.__defineGetter__ "textContent", ->
   if @nodeType == HTML.Node.TEXT_NODE || @nodeType == HTML.Node.COMMENT_NODE ||
      @nodeType == HTML.Node.ATTRIBUTE_NODE || @nodeType == HTML.Node.CDATA_SECTION_NODE
     return @nodeValue
   else if @nodeType == HTML.Node.ELEMENT_NODE || @nodeType == HTML.Node.DOCUMENT_FRAGMENT_NODE
-    return @childNodes
-      .filter((node)-> node.nodeType == HTML.Node.TEXT_NODE || node.nodeType == HTML.Node.ELEMENT_NODE ||
-                       node.nodeType == HTML.Node.CDATA_SECTION_NODE)
-      .map((node)-> node.textContent)
-      .join("")
+    text = []
+    for child in @childNodes
+      if child.nodeType == HTML.Node.TEXT_NODE || child.nodeType == HTML.Node.ELEMENT_NODE ||
+         child.nodeType == HTML.Node.CDATA_SECTION_NODE
+        text.push(child.textContent)
+    return text.join("")
   else
     return null
-###
-
-
-# Form elements collection should allow retrieving individual element by its
-# name, e.g. form.elements["username"] => <input name="username">
-HTML.NodeList.prototype.update = ->
-  if @_element && @_version < @_element._version
-    for i in [0.. @_length]
-      delete this[i]
-    if @_names
-      for name in @_names
-        delete this[name]
-    nodes = @_snapshot = @_query()
-    @_length = nodes.length
-    @_names = []
-    for i, node of nodes
-      this[i] = node
-      if name = node.name
-        @_names.push name
-        this[node.name] = node
-    @_version = @_element._version
-  return @_snapshot

 # For some reason HTML5 uses elementBuilder instead of createElement