autosize of editable table

autosize of editable table

--- app/assets/javascripts/backbone_js/ladas_editable_table_aligner.js.coffee
+++ app/assets/javascripts/backbone_js/ladas_editable_table_aligner.js.coffee
@@ -21,6 +21,10 @@
     # aligning heights of static left or right columns and center content of table
     EditableTableAligner.align_heights(obj)
     console.log("align heights")
+
+    if (obj.editable_table_automatic_size? && obj.editable_table_automatic_size)
+      if !xhr
+        EditableTableAligner.register_align_table_size()

   @align_after_rows_update: (obj) ->
     # move colhead class to left column
@@ -40,9 +44,12 @@
   ##############################

   @align_widths: (obj) ->
+    # HAVE TO UNSET TABLE WIDTH IF AUTOSET
+    #todo it then moves with the table when cell editing, i will only make it bigger
+    #EditableTableAligner.unset_table_size()
+
     # going trough headers th
-#    console.log($("#" + obj.form_id).find('td[data-width-align-id]'))
-
+    #    console.log($("#" + obj.form_id).find('td[data-width-align-id]'))
     $("#" + obj.form_id).find('th[data-width-align-id]').each (index, element) =>

       # loading paired td and th
@@ -87,7 +94,9 @@
       'min-width': max_width,
       'max-width': max_width
       })
-
+    # automatic width of the table, if required
+    if (obj.editable_table_automatic_size? && obj.editable_table_automatic_size)
+      EditableTableAligner.align_table_size()

     return

@@ -132,8 +141,8 @@
       orig_head.find("thead tr").each (index, element) =>
         EditableTableAligner.move_cell_to_static_column(element, head)

-      # can delete orid headcols when I duplicated them, otherwise the height info is wrong
-      #$(orig_head).find(".headcol").remove()
+    # can delete orid headcols when I duplicated them, otherwise the height info is wrong
+    #$(orig_head).find(".headcol").remove()

     orig_body =  $("#" + obj.form_id).find('.centerContainer .detachedTableContainer')
@@ -151,7 +160,6 @@
     ##################### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11
     ###################### omezim je na thead, tbody bude mit fixni vysku sloupcu, prepocinani s 500 radky, trva strasne dlouho
     #$("#" + obj.form_id).find('.fixedLeftColumn tr').each (index, element) =>
-
     $("#" + obj.form_id).find('.fixedLeftColumn thead tr').each (index, element) =>

       # loading paired tr of left column and right
@@ -235,6 +243,42 @@
       # have copy colors of the center table to left column
       $(destination_row).attr("style", $(element).attr("style"))

+  @register_align_table_size: ->
+    $(window).resize ->
+      EditableTableAligner.unset_table_size()
+      EditableTableAligner.align_table_size()
+
+  @unset_table_size: ->
+    $(".tableContainer, .centerContainer .detachedTableContainer, .centerContainer .scrollTargetContainter, .fixedLeftColumn .detachedTableContainer,.fixedLeftColumn table").css({'width': "", 'height': ""})
+
+  @align_table_size: ->
+
+    #    console.log $(window).width()
+    #    console.log $(window).height()
+    #    console.log $(document).width()
+    #    console.log $(document).height()
+    scroller_size = 16
+    upper_panel_size = 300
+    width_border = 80
+
+
+    left_column_width = $(".fixedLeftColumn table").width()
+    center_width = $(window).width() - left_column_width - scroller_size - width_border
+    table_height  = $(window).height() - upper_panel_size
+
+    console.log left_column_width
+    #    console.log center_width
+
+
+    $(".tableContainer").css({'width': (left_column_width + center_width + scroller_size + width_border)})
+
+    $(".centerContainer .detachedTableContainer").css({'width': (center_width + scroller_size), 'height': (table_height + scroller_size)})
+    $(".centerContainer .scrollTargetContainter").css({'width': center_width })
+
+    $(".fixedLeftColumn .detachedTableContainer").css({'height': table_height})
+    $(".fixedLeftColumn table").css({'width': left_column_width})
+
+
 window.EditableTableAligner = EditableTableAligner


"Loading ..." was showing up after loading was complete

Some filters have no matches sometimes.

--- app/assets/javascripts/components/filter_reports/filter_reports.js.coffee
+++ app/assets/javascripts/components/filter_reports/filter_reports.js.coffee
@@ -145,7 +145,7 @@
     else
       agg = @state.filterables[name]

-    isLoading = agg.length is 0
+    isLoading = @state["waitingFor_#{name}"]
     placeholder = unless isLoading then "Select ..." else "Loading ..."

     # convert to all strings
@@ -171,7 +171,7 @@
         multi: true
         joinValues: true
         placeholder: placeholder
-        isLoading: @state["waitingFor_#{name}"]
+        isLoading: isLoading
         value: @state[name]
         onInputChange: (value) =>
           if (value.length == 4)


Fixed bug in configuration panel

Fixed bug in configuration panel

--- app/assets/javascripts/widgit/admin/plugins/configuration_panel.js.coffee
+++ app/assets/javascripts/widgit/admin/plugins/configuration_panel.js.coffee
@@ -41,6 +41,7 @@
     @activePanels[@activePanels.length-1] || { panel: $(), element: $() }

   resetPanels: ->
+    @$panels.addClass('hidden')
     @activePanels = []

   addPanel: (type, $element)->


Client: Activity: Added channelName to message when message updating.

--- client/activity/lib/components/chatlistitem/index.coffee
+++ client/activity/lib/components/chatlistitem/index.coffee
@@ -36,6 +36,7 @@
     account                       : null
     isDeleting                    : no
     isMenuOpen                    : no
+    channelName                   : ''
     editInputValue                : ''
     isUserMarkedAsTroll           : no
     isBlockUserModalVisible       : no
@@ -241,7 +242,13 @@

   updateMessage: ->

+    name  = @props.channelName
+    value = @state.editInputValue
     messageId = @props.message.get '_id'
+
+    unless value.match ///\##{name}///
+      value += " ##{name} "
+
     ActivityFlux.actions.message.unsetMessageEditMode messageId

     ActivityFlux.actions.message.editMessage(


Fix draft edition

Fix draft edition

--- client/app/components/compose.coffee
+++ client/app/components/compose.coffee
@@ -137,6 +137,7 @@
                         className: classLabel,
                         t "compose content"
                     ComposeEditor
+                        messageID: @props.message?.get 'id'
                         html: @linkState('html')
                         text: @linkState('text')
                         settings: @props.settings
@@ -376,6 +377,10 @@
             text: @props.text
         }

+    componentWillReceiveProps: (nextProps) ->
+        if nextProps.messageID isnt @props.messageID
+            @setState html: nextProps.html, text: nextProps.text
+
     shouldComponentUpdate: (nextProps, nextState) ->
         return not(_.isEqual(nextState, @state)) or not (_.isEqual(nextProps, @props))

@@ -569,8 +574,9 @@
     componentDidMount: ->
         @_initCompose()

-    #componentDidUpdate: ->
-    #    @_initCompose()
+    componentDidUpdate: (nextProps, nextState) ->
+        if nextProps.messageID isnt @props.messageID
+            @_initCompose()

     onKeyDown: (evt) ->
         if evt.ctrlKey and evt.key is 'Enter'


added lat and lon to the start location of a vehicle

--- lib/models/vehicle.coffee
+++ lib/models/vehicle.coffee
@@ -81,6 +81,8 @@
     SC.Object.create
       id: 'startLocation-' + @get('id')
       address: @getPath('journeys.firstObject.startAddress')
+      lat: @getPath('journeys.firstObject.messages.firstObject.lat')
+      lon: @getPath('journeys.firstObject.messages.firstObject.lon')
       addressMessage: @getPath('journeys.firstObject.messages.firstObject')
       leaveTime: @getPath('journeys.firstObject.startTime')
   ).property().cacheable()


removed Atom

removed Atom

--- lisp.coffee
+++ lisp.coffee
@@ -1,15 +1,11 @@
-class Atom
-  constructor: (@value) ->
-  toString: -> "#{@value}"
-
 class Symbol
   constructor: (@name) ->
   toString: -> @name

-class Nil extends Atom
+class Nil
   toString: -> 'nil'
 nil = new Nil
-class T extends Atom
+class T
   toString: -> 't'
 t = new T

@@ -37,6 +33,10 @@
     return val
   set: (name, val) -> @variables[name] = val

+isAtom = (val) ->
+  typeof val == 'string' or typeof val == 'number' or
+    val instanceof Nil or val instanceof T
+
 envstack = []
 currentEnv = ->
   throw "envstack is empty" unless envstack.length > 0
@@ -73,7 +73,7 @@
     if @expects /[0-9]/
       num = ''
       num += @code[@pos++] while @expects /[0-9]/
-      return new Atom(parseInt(num))
+      return parseInt(num)

     #string
     if @expects '"'
@@ -81,7 +81,7 @@
       str = ''
       str += @code[@pos++] until @expects '"'
       @forwards '"'
-      return new Atom(str)
+      return str

     #nil
     if @expects 'nil'
@@ -184,10 +184,10 @@
           when 'Symbol'
             switch funname.name
               when 'alert'
-                alert args[0].value
+                alert args[0]
                 nil
               when '+'
-                new Atom args.reduce(((sum, n) -> sum + n.value), 0)
+                args.reduce(((sum, n) -> sum + n), 0)
               when 'car'
                 args[0].values[0]
               when 'cdr'
@@ -197,9 +197,9 @@
                 newList.unshift(args[0])
                 new List newList
               when 'eq'
-                if args[0].value == args[1].value then t else nil
+                if args[0] == args[1] then t else nil
               when 'atom'
-                if args[0] instanceof Atom then t else nil
+                if isAtom(args[0]) then t else nil
               else
                 lambda = currentEnv().get(funname.name)
                 if lambda


Sanitize messages for chat.

Sanitize messages for chat.

--- client/app/js/views/chat_view.coffee
+++ client/app/js/views/chat_view.coffee
@@ -165,6 +165,8 @@
     sanitizedMessage = sanitizedMessage.replace(
       /\b(https?:\/\/\S+\.\S+)\b/g,
       """$1""")
+    sanitizedMessage = sanitizedMessage.replace(
+      /[\u0300-\u036F\u20D0-\u20FF\uFE20-\uFE2F]/g, '')
     sanitizedMessage

   # Returns true if the chat is scrolled to the bottom of the screen.


pass apikey in hash of iframe

pass apikey in hash of iframe

--- client/code/view/view_content.coffee
+++ client/code/view/view_content.coffee
@@ -4,8 +4,7 @@

   initialize: ->
     # Need a view name here
-    console.log @
     boxurl = "#{window.boxServer}/#{@model.get 'box'}"
     @model.publishToken (token) =>
-      @$el.html """"""
+      @$el.html """"""


Add closing parenthesis.

Add closing parenthesis.

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -120,7 +120,7 @@
   withMethodCallSupport (f, args...) ->
     stream = partiallyApplied(wrapped, [(values, callback) ->
       f(values..., callback)])
-    withDescription(Bacon, desc, f, args..., Bacon.combineAsArray(args).flatMap(stream)
+    withDescription(Bacon, desc, f, args..., Bacon.combineAsArray(args).flatMap(stream))

 Bacon.fromCallback = liftCallback "fromCallback", (f, args...) ->
   Bacon.fromBinder (handler) ->


added more test values

added more test values


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/active_bounds.coffee
+++ test/active_bounds.coffee
@@ -32,8 +32,8 @@
   obj2.bind 'destroy', ->
     destroySpy = true

-  obj2.I.x = 10000
-  obj2.I.y = 50
+  obj2.I.x = 100
+  obj2.I.y = 50000

   obj.update()


more tests

more tests

--- tests/test_builder.coffee
+++ tests/test_builder.coffee
@@ -760,7 +760,11 @@
         builder.build()
         expect(fs.existsSync("/testimonial/manifest.json")).to.be.true
         manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8"))
-
+
+        expect(manifest)
+            .to.have.property('modules')
+            .to.be.an("Array").with.length(4)
+
         expect(manifest.modules[0]).to.have.properties
             id: -> @that.equals("lib_main")
             deps: -> @that.deep.equals({})
@@ -787,6 +791,64 @@
                 "m2": "lib_main"
             type: -> @that.equals("cjs")
             url: -> @that.equals("http://127.0.0.1:8010/a.js")
+
+describe 'Building modules with dependency from node_modules (multifile module)', ->
+    beforeEach ->
+        mock(yaml.safeLoad("""
+            testimonial:
+                lib:
+                    a.js:
+                        var b = require("b");
+                node_modules:
+                    b:
+                        index.js:
+                            var c = require("./c");
+                        c.js:
+                            module.exports = 1;
+                spa.yaml: |
+                    pretty: true
+                    root: "/testimonial/"
+                    hosting:
+                        "./(**/*.*)": "http://127.0.0.1:8010/$1"
+                    extensions:
+                        - .js
+                    excludes:
+                        - "./node_modules/**"
+                    manifest: "manifest.json"
+                    grab: true
+                    default_loader: junk
+            """))
+
+    it 'should successfully build', ->
+        builder = spa.Builder.from_config("/testimonial/spa.yaml")
+
+        builder.build()
+        expect(fs.existsSync("/testimonial/manifest.json")).to.be.true
+        manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8"))
+
+        expect(manifest)
+            .to.have.property('modules')
+            .to.be.an("Array").with.length(3)
+
+        expect(manifest.modules[0]).to.have.properties
+            id: -> @that.equals("c")
+            deps: -> @that.deep.equals({})
+            type: -> @that.equals("cjs")
+            url: -> @that.equals("http://127.0.0.1:8010/node_modules/b/c.js")
+
+        expect(manifest.modules[1]).to.have.properties
+            id: -> @that.equals("b")
+            deps: -> @that.deep.equals
+                "./c": "c"
+            type: -> @that.equals("cjs")
+            url: -> @that.equals("http://127.0.0.1:8010/node_modules/b/index.js")
+
+        expect(manifest.modules[2]).to.have.properties
+            id: -> @that.equals("a")
+            deps: -> @that.deep.equals
+                "b": "b"
+            type: -> @that.equals("cjs")
+            url: -> @that.equals("http://127.0.0.1:8010/lib/a.js")

 describe 'Remaping standart-like modules inside dependencies from node_modules', ->
     beforeEach ->


Add some extra CoffeeScript error output.

--- src/client-compile.coffee
+++ src/client-compile.coffee
@@ -58,6 +58,8 @@
             @output = coffee.compile(@output, filename: @fileName, bare: true)
             cb(null)
         catch e
+            @compileUnit.compiler.log "  \u001b[31m error in file: #{@fileName}\u001b[0m"
+            @compileUnit.compiler.log e
             cb(e)

 class JadeSourceFile extends SourceFile


Code style (lint was complaining).

Code style (lint was complaining).

--- server/migrations/0018-publication-cacheid.coffee
+++ server/migrations/0018-publication-cacheid.coffee
@@ -1,10 +1,10 @@
 getOldFilename = (document) ->
-    if document.source is 'arXiv'
-      'pdf' + Storage._path.sep + 'arxiv' + Storage._path.sep + document.foreignId + '.pdf'
-    else
-      # We use import also as a fallback for any unsupported document source.
-      # This allows us to go first backward in migrations and then again forward.
-      'pdf' + Storage._path.sep + 'import' + Storage._path.sep + document._id + '.pdf'
+  if document.source is 'arXiv'
+    'pdf' + Storage._path.sep + 'arxiv' + Storage._path.sep + document.foreignId + '.pdf'
+  else
+    # We use import also as a fallback for any unsupported document source.
+    # This allows us to go first backward in migrations and then again forward.
+    'pdf' + Storage._path.sep + 'import' + Storage._path.sep + document._id + '.pdf'

 getNewFilename = (cachedId) ->
   'pdf' + Storage._path.sep + 'cache' + Storage._path.sep + cachedId + '.pdf'


Refactor visualisation edit event bindings

--- client/src/views/section_view.coffee
+++ client/src/views/section_view.coffee
@@ -9,9 +9,7 @@
   events:
     "click .add-narrative": "addNarrative"
     "click .add-visualisation": "chooseIndicatorForVisualisation"
-    "click .bar-chart-view": "editVisualisation"
-    "click .visualisation-table-view": "editVisualisation"
-    "click .map-view": "editVisualisation"
+    "click .visualisation": "editVisualisation"
     "click .delete": "confirmDestroy"

   initialize: (options) ->


Change the way widgets are initialized

Change the way widgets are initialized

Attaching the initialization entry point to the first change in
Dashing.Widget.node. This occurs right after widget construction in recent
batman releases (0.15.0+) and seems more reliable and logical than the
loadNode method.

--- vendor/assets/javascripts/dashing/dashing-src.coffee
+++ vendor/assets/javascripts/dashing/dashing-src.coffee
@@ -29,20 +29,23 @@
   constructor: ->
     # Set the view path
     @constructor::source = Batman.Filters.underscore(@constructor.name)
+
     super

-  loadView: (_node) ->
-    node = super
+    @observe 'node', (newValue, oldValue) ->
+      if !oldValue && !@_registeredAtDashing
+        @_registeredAtDashing = true

-    @mixin($(node).data())
-    Dashing.widgets[@id] ||= []
-    Dashing.widgets[@id].push(@)
-    @mixin(Dashing.lastEvents[@id]) # in case the events from the server came before the widget was rendered
+        @mixin($(@node).data())
+        Dashing.widgets[@id] ||= []
+        Dashing.widgets[@id].push(@)

-    type = Batman.Filters.dashize(@constructor.name)
-    $(node).addClass("widget widget-#{type} #{@id}")
+        # in case the events from the server came
+        # before the widget was rendered
+        @mixin(Dashing.lastEvents[@id])

-    return node
+        type = Batman.Filters.dashize(@constructor.name)
+        $(@node).addClass("widget widget-#{type} #{@id}")

   @accessor 'updatedAtMessage', ->
     if updatedAt = @get('updatedAt')


initial equalizer demo

initial equalizer demo

--- examples/audio/static/coffee/spectrogram.coffee
+++ examples/audio/static/coffee/spectrogram.coffee
@@ -8,23 +8,30 @@

 NGRAMS = 1620

-TIMESLICE = 50 # ms
+HISTSIZE = 256
+NUM_BINS = 16
+
+TIMESLICE = 35 # ms

 class Spectrogram
   constructor: () ->
     @canvas_width = NGRAMS
     @canvas_height = 512

-    @y = [0]
-    @dh = [NGRAMS]
     @image = [new Float32Array(SPECTROGRAM_LENGTH * NGRAMS)]
     @power = [new Float32Array(NUM_SAMPLES)]
     @idx = [new Array(NUM_SAMPLES)]
     for i in [0..@idx[0].length-1]
       @idx[0][i] = (i/(@idx[0].length-1))*TIMESLICE

-    @data_source = Collections('ColumnDataSource').create(
-      data: {image: @image, power: @power, idx: @idx}
+    @spec_source = Collections('ColumnDataSource').create(
+      data:{image: @image}
+    )
+    @power_source = Collections('ColumnDataSource').create(
+      data:{power: @power, idx: @idx}
+    )
+    @hist_source = Collections('ColumnDataSource').create(
+      data: {inner_radius:[], outer_radius:[], start_angle:[], end_angle:[], fill_alpha: []}
     )

     spec_model = @create_spec()
@@ -32,6 +39,9 @@

     power_model = @create_power()
     @power_view = new power_model.default_view(model: power_model)
+
+    hist_model = @create_hist()
+    @hist_view = new hist_model.default_view(model: hist_model)

     @render()

@@ -47,14 +57,51 @@
   on_data: (data) =>
     if not data[0]?
       return
+
     for i in [0..(SPECTROGRAM_LENGTH-1)]
       for j in [(NGRAMS-1)..1]
         @image[0][i*NGRAMS + j] = @image[0][i*NGRAMS + j - 1]
       @image[0][i*NGRAMS] = data[0][i]
+    @spec_source.set('data', {image: @image})
+    @spec_source.trigger('change', @spec_source, {})
+
     for i in [0..@power[0].length-1]
       @power[0][i] = data[1][i]
-    @data_source.set('data', {image: @image, power: @power, idx: @idx})
-    @data_source.trigger('change', @data_source, {})
+    @power_source.set('data', {power: @power, idx: @idx})
+    @power_source.trigger('change', @power_source, {})
+
+    hist = new Float32Array(NUM_BINS)
+    bin_start = 0
+    bin_size = Math.ceil(HISTSIZE / NUM_BINS)
+    for i in [0..NUM_BINS-1]
+      hist[i] = 0
+      bin_end = Math.min(bin_start+bin_size-1, data[0].length)
+      for j in [bin_start..bin_end]
+        hist[i] += data[0][j]
+      bin_start += bin_size
+
+    inner = []
+    outer = []
+    start = []
+    end = []
+    fill_alpha = []
+    vals = []
+    angle = 2*Math.PI/NUM_BINS
+    for i in [0..(hist.length-1)]
+      n = hist[i]/16
+      for j in [0..n]
+        vals.push(j)
+        inner.push(2+j)
+        outer.push(2+j+0.95)
+        start.push((i+0.05)*angle)
+        end.push((i+0.95)*angle)
+        fill_alpha.push(1-0.08*j)
+
+
+    @hist_source.set('data', {
+      inner_radius: inner, outer_radius: outer, start_angle: start, end_angle: end, fill_alpha: fill_alpha
+    })
+    @hist_source.trigger('change', @power_source, {})

   render: () ->
     div = $('

')
@@ -64,6 +111,8 @@
       @spec_view.render()
       div.append(@power_view.$el)
       @power_view.render()
+      div.append(@hist_view.$el)
+      @hist_view.render()
     _.defer(myrender)

   create_spec: () ->
@@ -96,11 +145,11 @@
         default: 'YlGnBu-9'
     }
     glyph = Collections('GlyphRenderer').create({
-        data_source: @data_source.ref()
-        xdata_range: xrange.ref()
-        ydata_range: yrange.ref()
-        glyphspec: glyphspec
-      })
+      data_source: @spec_source.ref()
+      xdata_range: xrange.ref()
+      ydata_range: yrange.ref()
+      glyphspec: glyphspec
+    })

     plot_model.set(
       renderers: [glyph.ref()]
@@ -135,11 +184,11 @@
       ys: 'power'
     }
     glyph = Collections('GlyphRenderer').create({
-        data_source: @data_source.ref()
-        xdata_range: xrange.ref()
-        ydata_range: yrange.ref()
-        glyphspec: glyphspec
-      })
+      data_source: @power_source.ref()
+      xdata_range: xrange.ref()
+      ydata_range: yrange.ref()
+      glyphspec: glyphspec
+    })

     plot_model.set(
       renderers: [glyph.ref()]
@@ -151,6 +200,41 @@

     return plot_model

+  create_hist: () ->
+    plot_model = Collections('Plot').create()
+
+    range = Collections('Range1d').create({start: -20, end: 20})
+
+    glyphspec = {
+      type: 'annular_wedge',
+      line_color: null
+      x: 0
+      y: 0
+      fill: '#688AB9'
+      fill_alpha: 'fill_alpha'
+      inner_radius: 'inner_radius'
+      outer_radius: 'outer_radius'
+      start_angle: 'start_angle'
+      end_angle: 'end_angle'
+      direction: 'clock'
+    }
+    glyph = Collections('GlyphRenderer').create({
+      data_source: @hist_source.ref()
+      xdata_range: range.ref()
+      ydata_range: range.ref()
+      glyphspec: glyphspec
+    })
+
+    plot_model.set(
+      renderers: [glyph.ref()]
+      axes: []
+      tools: []
+      width: 500
+      height: 500
+    )
+
+    return plot_model
+
 $(document).ready () ->
   spec = new Spectrogram()
   setInterval(spec.request_data, TIMESLICE)


Translate more resources

Translate more resources

--- index.cjsx
+++ index.cjsx
@@ -17,6 +17,27 @@
   window.addEventListener 'initialize.complete', (e) ->
     for ship, index in window.$ships
       window.$ships[index]?.api_name = __ ship.api_name
+
+    for shipType, index in window.$shipTypes
+      window.$shipTypes[index]?.api_name = __ shipType.api_name
+
+    for slotitem, index in window.$slotitems
+      window.$slotitems[index]?.api_name = __ slotitem.api_name
+
+    for slotitemType, index in window.$slotitemTypes
+      window.$slotitemTypes[index]?.api_name = __ slotitemType.api_name
+
+    for maparea, index in window.$mapareas
+      window.$mapareas[index]?.api_name = __ maparea.api_name
+
+    for map, index in window.$maps
+      window.$maps[index]?.api_name = __ map.api_name
+
+    for mission, index in window.$missions
+      window.$missions[index]?.api_name = __ mission.api_name
+
+    for useitem, index in window.$useitems
+      window.$useitems[index]?.api_name = __ useitem.api_name
 module.exports =
   name: 'Translator'
   author: [KochiyaOcean]


Fix bug

Fix bug

--- index.cjsx
+++ index.cjsx
@@ -53,7 +53,7 @@
     index = random(iday, j) % result.length
     result.splice(index, 1)
   result
-parse = (e) ->
+parse = (iday, e) ->
   result = Object.clone e
   if result.name.indexOf('%v') != -1
     result.name = result.name.replace('%v', varNames[random(iday, 12) % varNames.length])
@@ -65,7 +65,7 @@
 pickRandomActivity = (iday, activities, size) ->
   picked_events = pickRandom(iday, activities, size)
   for e, i in picked_events
-    picked_events[i] = parse e
+    picked_events[i] = parse iday, e
   picked_events
 bbRecipe = (iday, num) ->
   r = switch num


Add support for lvl of multiple remodelling ship

--- index.cjsx
+++ index.cjsx
@@ -76,6 +76,15 @@
   __("MVP and flagship")
 ]

+# get the remodel lvs for a ship, [0] for it can't
+getRemodelLvsById = (shipId) ->
+  remodelLvs = [$ships[shipId].api_afterlv]
+  nextShipId = parseInt $ships[shipId].api_aftershipid
+  while(nextShipId != 0 && remodelLvs[remodelLvs.length - 1] < $ships[nextShipId].api_afterlv)
+    remodelLvs.push $ships[nextShipId].api_afterlv
+    nextShipId = parseInt $ships[nextShipId].api_aftershipid
+  return remodelLvs
+
 getExpInfo = (shipId) ->
   return [1, 100, 99] unless shipId > 0
   {$ships, _ships} = window
@@ -83,8 +92,12 @@
   goalLevel = 99
   if _ships[idx].api_lv > 99
     goalLevel = 150
-  if $ships[_ships[idx].api_ship_id].api_afterlv != 0 && $ships[_ships[idx].api_ship_id].api_afterlv > _ships[idx].api_lv
-    goalLevel = Math.min(goalLevel, $ships[_ships[idx].api_ship_id].api_afterlv)
+  else if $ships[_ships[idx].api_ship_id].api_afterlv != 0 # it has remodel
+    remodelLvs = getRemodelLvsById _ships[idx].api_ship_id
+    for lv in remodelLvs
+      if lv > _ships[idx].api_lv
+        goalLevel = lv
+        break
   return [_ships[idx].api_lv, _ships[idx].api_exp[1], goalLevel]

 module.exports =


Change author's name

Change author's name

--- index.cjsx
+++ index.cjsx
@@ -47,7 +47,7 @@
   displayName: <FontAwesome key={0} name='book' /> {__ "Logbook"}
   #displayName: <FontAwesome key={0} name='book' /> 航海日志
   description: "#{__ "Logs"}. #{__ "Senka module is developed by rui"}."
-  author: 'W.G.'
+  author: 'Jennings Wu'
   link: 'https://github.com/JenningsWu'
   version: '2.3.0'
   handleClick: ->


in sunrise-clock.coffe, renamed variables and function names to make them more intuitive and camelCase

--- source/javascripts/countdown/sunrise-clock.coffee
+++ source/javascripts/countdown/sunrise-clock.coffee
@@ -1,16 +1,18 @@
 //= require ../vendor/flipclock
 //= require ../site/sunrise

-get_time_to_sunrise = ->
-  time_now = moment().startOf('day')
-  sunrise = new Sunrise(time_now).get()
-  sunrise = new Sunrise(time_now.add(1, 'days')).get() if moment().isAfter(sunrise)
+secondsToSunrise = ->
+  today = moment().startOf('day')
+  sunrise = new Sunrise(today).get()
+  sunrise = new Sunrise(today.add(1, 'days')).get() if moment().isAfter(sunrise)
   sunrise.diff(moment(), 'seconds')

-set_countdown_clock_repeatedly = (clock) ->
-  time_left = get_time_to_sunrise()
-  clock.setTime(time_left)
-  console.log "Resetting sunrise clock, with #{time_left} seconds left" if console?
-  setTimeout((-> set_countdown_clock_repeatedly(clock)), 1e4) if time_left > 10
+countDown = (clock) ->
+  seconds = secondsToSunrise()
+  clock.setTime(seconds)
+  console.log "Resetting sunrise clock, with #{seconds} seconds left" if console?
+  setTimeout((-> countDown(clock)), 1e4) if seconds > 10

-$ -> set_countdown_clock_repeatedly($('.countdown-to-sunrise').FlipClock get_time_to_sunrise(), countdown:true)
+$ ->
+  clock = $('.countdown-to-sunrise').FlipClock 60, countdown:true
+  countDown(clock)


update instance data via api instead of upserting

--- routes/api/instances.coffee
+++ routes/api/instances.coffee
@@ -25,7 +25,7 @@
         check(@params.name, String)
         instance = Instances.findOne(project: Settings.findOne().project, name: @params.name) or {}
         updatedInstance = lodash.merge instance, @request.body
-        Instances.upsert {project: Settings.findOne().project, name: @params.name}, {$set: _.omit(updatedInstance, '_id')}, (err, result) =>
+        Instances.update {project: Settings.findOne().project, name: @params.name}, {$set: _.omit(updatedInstance, '_id')}, (err, result) =>
           console.log err, result
           if err or not result
             @response.writeHead 404, 'Content-Type': 'application/json'


Use the gutterWidth in the calc

Use the gutterWidth in the calc

The overlay has a new parent as of atom 190.

--- spec/autocomplete-manager-integration-spec.coffee
+++ spec/autocomplete-manager-integration-spec.coffee
@@ -379,7 +379,8 @@
           expect(overlayElement).toExist()

           left = editorView.pixelPositionForBufferPosition([0, 2]).left
-          expect(overlayElement.style.left).toBe "#{left}px"
+          gutterWidth = editorView.shadowRoot.querySelector('.gutter').offsetWidth
+          expect(overlayElement.style.left).toBe "#{left + gutterWidth}px"

           atom.commands.dispatch(editorView, 'autocomplete-plus:cancel')
           expect(editorView.querySelector('.autocomplete-plus')).not.toExist()


improved description

improved description

--- lib/package/config.coffee
+++ lib/package/config.coffee
@@ -33,7 +33,7 @@
         items:
           type: 'string'
       numberOfThreads:
-        title: 'Number of Threads'
+        title: 'Number of Threads (only on Julia v0.6+, experimental)'
         type: 'integer'
         default: 1
     order: 3


Fix variable names

Fix variable names

--- bots/libs/HexBot.coffee
+++ bots/libs/HexBot.coffee
@@ -12,7 +12,7 @@
   for arg in argumentData # get the arguments from the command line
     if casper.cli.raw.has arg.name
       ARGS[argCount] = casper.cli.raw.get arg.name # use the option argument
-    else if casper.cli.raw.has cliCount
+    else if casper.cli.raw.has posArg
       ARGS[argCount] = casper.cli.raw.get posArg # use the positional argument
       posArg++ # move to the next positional argument
     else if arg.default? # use the default value if one exists


 Merge branch 'master.rollbarFix' into 'master'

Master.Rollbar Fix

--- server/lib/crawler/staticpages/analytics.coffee
+++ server/lib/crawler/staticpages/analytics.coffee
@@ -19,6 +19,7 @@
     <!-- End Google Analytics -->

     <!-- ROLLBAR -->
+    <script>
     var _rollbarConfig = {
       accessToken: "#{rollbar}",
       captureUncaught: true,


Add missing field selector

Add missing field selector


Refactored logic for getting singular collection name.

--- src/Forms.coffee
+++ src/Forms.coffee
@@ -183,67 +183,6 @@
       template = @
       template.isDestroyed = true
       formArgs.onDestroy?.apply(@, arguments)
-
-    ################################################################################################
-    # AUXILIARY
-    ################################################################################################
-
-    Form.parseDocs = (template) ->
-      template = getTemplate(template)
-      data = template.data
-      if data.docs?
-        docs = data.docs
-      else if data.doc?
-        docs = [data.doc]
-      else
-        docs = []
-      _.map docs, (doc) ->
-        if Types.isString(doc)
-          Form.getCollection().findOne(doc)
-        else
-          doc
-
-    Form.getFormTitle = ->
-      collectionName = Collections.getTitle(formArgs.collection)
-      singularName = formArgs.singularName ? Strings.singular(collectionName)
-      docs = Form.getDocs()
-      suffix = Strings.pluralize(singularName, docs.length, collectionName)
-      suffix = Strings.toTitleCase(suffix)
-      if Form.isBulk()
-        suffix = docs.length + ' ' + suffix
-      (if docs.length > 0 then 'Edit' else 'Create') + ' ' + suffix
-
-    Form.getCollection = -> Collections.get(formArgs.collection)
-
-    Form.getSchema = -> Collections.getSchema(formArgs.schema ? Form.getCollection())
-
-    ################################################################################################
-    # AUXILIARY
-    ################################################################################################
-
-    getTemplate = Form.getTemplate = (template) -> Templates.getNamedInstance(name, template)
-
-    Form.getElement = (template) -> Forms.getFormElement(getTemplate(template))
-
-    Form.getFieldElement = (name, template) ->
-      Forms.getFieldElement(name, Form.getElement(), template)
-
-    Form.getSchemaInputs = (template) ->
-      template = getTemplate(template)
-      Forms.getSchemaInputs(template, formArgs.schema ? formArgs.collection)
-
-    Form.getValues = (template) ->
-      if Form.isBulk(template)
-        Form.getBulkValues(template)
-      else
-        Form.getDocs(template)[0] ? null
-
-    Form.setSubmitButtonDisabled = (disabled, template) ->
-      Form.getSubmitButton(template).toggleClass('disabled', !!disabled)
-
-    Form.getSubmitButton = (template) ->
-      $buttons = template.$('.crud.buttons')
-      template.$('[type="submit"]', $buttons)

     ################################################################################################
     # BULK EDITING
@@ -358,6 +297,67 @@
           count++
         return count >= 3

+    ################################################################################################
+    # AUXILIARY
+    ################################################################################################
+
+    Form.parseDocs = (template) ->
+      template = getTemplate(template)
+      data = template.data
+      if data.docs?
+        docs = data.docs
+      else if data.doc?
+        docs = [data.doc]
+      else
+        docs = []
+      _.map docs, (doc) ->
+        if Types.isString(doc)
+          Form.getCollection().findOne(doc)
+        else
+          doc
+
+    Form.getFormTitle = ->
+      collectionName = Collections.getTitle(Form.getCollection())
+      singularName = Form.getSingularName()
+      docs = Form.getDocs()
+      suffix = Strings.pluralize(singularName, docs.length, collectionName)
+      suffix = Strings.toTitleCase(suffix)
+      if Form.isBulk()
+        suffix = docs.length + ' ' + suffix
+      (if docs.length > 0 then 'Edit' else 'Create') + ' ' + suffix
+
+    Form.getCollection = -> Collections.get(formArgs.collection)
+
+    Form.getSchema = -> Collections.getSchema(formArgs.schema ? Form.getCollection())
+
+    getTemplate = Form.getTemplate = (template) -> Templates.getNamedInstance(name, template)
+
+    Form.getElement = (template) -> Forms.getFormElement(getTemplate(template))
+
+    Form.getFieldElement = (name, template) ->
+      Forms.getFieldElement(name, Form.getElement(), template)
+
+    Form.getSchemaInputs = (template) ->
+      template = getTemplate(template)
+      Forms.getSchemaInputs(template, formArgs.schema ? Form.getCollection())
+
+    Form.getValues = (template) ->
+      if Form.isBulk(template)
+        Form.getBulkValues(template)
+      else
+        Form.getDocs(template)[0] ? null
+
+    Form.setSubmitButtonDisabled = (disabled, template) ->
+      Form.getSubmitButton(template).toggleClass('disabled', !!disabled)
+
+    Form.getSubmitButton = (template) ->
+      $buttons = template.$('.crud.buttons')
+      template.$('[type="submit"]', $buttons)
+
+    Form.getSingularName = ->
+      collectionName = Collections.getTitle(Form.getCollection())
+      formArgs.singularName ? Strings.singular(collectionName)
+
     return Form

   ##################################################################################################


fixup docs and a robot.name check

fixup docs and a robot.name check

--- src/hubot/scripts/roles.coffee
+++ src/hubot/scripts/roles.coffee
@@ -1,7 +1,8 @@
 # Assign roles to people you're chatting with
 #
-# hubot <user> is a extraordinary role
-# hubot <user> is not a extraordinary role
+# hubot <user> is a extraordinary role - assign a role to a user
+# hubot <user> is not a extraordinary role - remove a role from a user
+# hubot who is <user> - see what roles a user has

 # hubot holman is an ego surfer
 # hubot holman is not an ego surfer
@@ -37,7 +38,7 @@
             msg.send "I know"
           else
             user.roles.push(newRole)
-            if name.toLowerCase() == "hubot"
+            if name.toLowerCase() == robot.name
               msg.send "Ok, I am #{newRole}."
             else
               msg.send "Ok, #{name} is #{newRole}."


minor

minor

--- src/eops.coffee
+++ src/eops.coffee
@@ -85,7 +85,7 @@
   # Nada

 program
-  .version('2.2.1')
+  .version('2.3.0')
   .usage('[options] <emails.csv>')
   .option('-c --compare <file>', 'hashed emails (already_hashed.csv)')
   .option('-e --case <alter>', 'whether to upper or lower case the email before hashing (upper, lower, as-is)', /^(upper|lower|as\-is)$/i, 'as-is')


Fix HLSSegmenter test

Fix HLSSegmenter test

--- test/hls_segmenter.coffee
+++ test/hls_segmenter.coffee
@@ -30,6 +30,7 @@
     rewind      = null
     beforeEach (done) ->
         rewind = new RewindBuffer liveStreaming:true
+        rewind._rmax = 100
         done()

     it "creates the Live Streaming Segmenter", (done) ->
@@ -48,10 +49,10 @@

         #console.log "segments is ", rewind.hls_segmenter._segments
         expect(rewind.hls_segmenter._segments).to.have.length 6
-        expect(rewind.hls_segmenter.segments()).to.have.length 4
+        expect(rewind.hls_segmenter.segments).to.have.length 4

         for seg in rewind.hls_segmenter._segments
-            if seg.buffer
+            if seg.data
                 expect(seg.duration).to.be.equal 10
             else
                 expect(seg.buffers).to.have.length.below 20
@@ -69,10 +70,10 @@
             rewind._insertBuffer c

         expect(rewind.hls_segmenter._segments).to.have.length 6
-        expect(rewind.hls_segmenter.segments()).to.have.length 4
+        expect(rewind.hls_segmenter.segments).to.have.length 4

         for seg in rewind.hls_segmenter._segments
-            if seg.buffer
+            if seg.data
                 expect(seg.duration).to.be.equal 10
             else
                 expect(seg.buffers).to.have.length.below 20
@@ -86,7 +87,7 @@
         expect(rewind.hls_segmenter._segments).to.have.length 11

         for seg in rewind.hls_segmenter._segments
-            if seg.buffer
+            if seg.data
                 expect(seg.duration).to.be.equal 10
             else
                 expect(seg.buffers).to.have.length.below 20


Add update notify

Add update notify

--- lib/plugin-manager.coffee
+++ lib/plugin-manager.coffee
@@ -5,6 +5,8 @@
 async = Promise.coroutine
 React = require 'react'
 fs = Promise.promisifyAll require 'fs-extra'
+__ = i18n.setting.__.bind(i18n.setting)
+__n = i18n.setting.__n.bind(i18n.setting)

 # we need only glob here
 globAsync = Promise.promisify require 'glob'
@@ -207,28 +209,40 @@

   # get all plugins that are outdated
   # @return {Plugin<Array<Plugin>>}
-  getOutdatedPlugins: ->
+  getOutdatedPlugins: (isNotif) ->
     # after getting mirrors, at least one mirror is set
     @getMirrors().then =>
       new Promise (resolve) =>
         @getInstalledPlugins().then (plugins) =>
           outdatedPlugins = []
+          outdatedList = []
           task = plugins.map (plugin) =>
             new Promise (resolve) =>
               npm.commands.distTag ['ls', plugin.packageName], (err, distTag) =>
-                if semver.gt distTag.latest, plugin.version
+                latest = plugin.version
+                if @config_.betaCheck && distTag.beta?
+                  if semver.gt distTag.beta, latest
+                    latest = distTag.beta
+                    if semver.gt distTag.latest, latest
+                      latest = distTag.latest
+                else
+                  if semver.gt distTag.latest, latest
+                    latest = distTag.latest
+                if semver.gt latest, plugin.version
                   outdatedPlugins.push plugin
                   index = @plugins_.indexOf(plugin)
                   @plugins_[index].isOutdated = true
-                  @plugins_[index].lastestVersion = distTag.latest
-                else if @config_.betaCheck && distTag.beta?
-                  if semver.gt distTag.beta, plugin.version
-                    outdatedPlugins.push plugin
-                    index = @plugins_.indexOf(plugin)
-                    @plugins_[index].isOutdated = true
-                    @plugins_[index].lastestVersion = distTag.beta
+                  @plugins_[index].lastestVersion = latest
+                  outdatedList.push plugin.stringName
                 resolve()
           Promise.all(task).then =>
+            if isNotif
+              content = "#{outdatedList.join(' ')} #{__ "have newer version. Please update your plugins."}"
+              notify content,
+                type: 'plugin update'
+                title: __ 'Plugin update'
+                icon: path.join(ROOT, 'assets', 'img', 'material', '7_big.png')
+                audio: "file://#{ROOT}/assets/audio/update.mp3"
             resolve outdatedPlugins

   # get all plugins which match a filer function
@@ -365,6 +379,8 @@
     else
       plugin.packageName = path.basename pluginPath

+    # Missing data of broken plugins
+
     if !plugin.displayName?
       if pluginData[plugin.packageName]?
         plugin.displayName =
@@ -392,6 +408,23 @@
         plugin.description = pluginData[plugin.packageName]["des#{window.language}"]
       else
         plugin.description = "unknown"
+
+    # For notifition
+    if typeof plugin.displayName is 'string'
+      plugin.stringName = plugin.displayName
+    else if pluginData[plugin.packageName]?
+        plugin.stringName = pluginData[plugin.packageName][window.language]
+      else
+        if plugin.displayName.props?.children?
+          displayItems = plugin.displayName.props.children
+        else
+          if plugin.displayName.props?.children?
+            displayItems = plugin.displayName.props.children
+          else
+            displayItems = plugin.displayName
+          for child in displayItems
+            if typeof child is "string"
+              plugin.stringName = child

     plugin.isInstalled = true
     plugin.isOutdated = false


Fix generating a new project config

Fix generating a new project config

--- lib/project-config.coffee
+++ lib/project-config.coffee
@@ -21,19 +21,25 @@
         @load(atom.project.getPaths())
         @disposables.push(atom.project.onDidChangePaths(@load))
         @disposables.push(atom.commands.add('atom-workspace', 'existdb:create-configuration-for-selected': =>
-            selected =
-                $('.tree-view .selected').map(() ->
-                    if this.getPath? then this.getPath() else ''
-                ).get()
-            if selected? and selected.length > 0
-                path = @getProjectConfigPath(selected[0])
-            else
-                path = atom.project.getPaths()?[0]
-            @createProjectConfig(path))
+            atom.packages.activatePackage('tree-view').then((pkg) =>
+                fileTree = pkg.mainModule.getTreeViewInstance()
+                selected = fileTree.selectedPaths()
+                if selected? and selected.length > 0
+                    path = @getProjectConfigPath(selected[0]) or selected[0]
+                else
+                    path = atom.project.getPaths()?[0]
+                @createProjectConfig(path)
+            ))
         )
         @disposables.push(atom.commands.add('atom-workspace', 'existdb:create-configuration-for-current': =>
             editor = atom.workspace.getActiveTextEditor()
+            if not editor?
+                atom.notifications.addError('No editor open')
+                return
+
             path = @getProjectConfigPath(editor.getPath())
+            if not path
+                path = atom.project.relativizePath(editor.getPath())[0]
             @createProjectConfig(path))
         )
         @disposables.push(atom.commands.add('atom-workspace', 'existdb:edit-configuration': =>


minor bug fixes

minor bug fixes

--- client/landing/app/MainApp/monitor_status.coffee
+++ client/landing/app/MainApp/monitor_status.coffee
@@ -207,13 +207,12 @@
         # we won't know that disconnection has happened.
         if lastPong && (Date.now() - lastPong) > 30*1000
           log "lastPong too long ago, possible computer sleep; disconnecting"
-
-          KD.logToMixpanel "computer woke up from sleep", 10
+          KD.logToMixpanel "computer woke up from sleep"

           status = KD.getSingleton "status"
           status.disconnect
             reason:"internetDownForLongTime"
-            showModal:false
+            notify:no

         clearTimeout failureCallback
         failureCallback = null


Test/Onboarding fix error

Test/Onboarding fix error

--- client/test/lib/helpers/onboardinghelpers.coffee
+++ client/test/lib/helpers/onboardinghelpers.coffee
@@ -64,11 +64,3 @@
         .pause 2000
         .waitForElementVisible WelcomeView, 20000
         .assert.containsText   pendingStack, 'Your Team Stack is Pending'
-        .waitForElementVisible WelcomeView, 20000
-        .click userstackLink
-        .waitForElementVisible stackEditor, 20000
-        .url  welcomeLink
-        .pause 2000
-        .waitForElementVisible WelcomeView, 20000
-        .click memberInstallKDLink
-        .waitForElementVisible kodingUtilities, 20000


fix test

fix test

--- test/scripts/hello.coffee
+++ test/scripts/hello.coffee
@@ -95,5 +95,5 @@
   describe 'robot.helpCommands()', ->
     it 'should be ["hubot XXX [<args>] - DESCRIPTION"]', ->
       assert.deepEqual @robot.helpCommands(), [
-        "hubot XXX [<args>] - DESCRIPTION"
+        'hubot XXX [<args>] - DESCRIPTION'
       ]


JCounter: Test: revert removed required requirement :facepalm: here

--- workers/social/lib/social/models/counter.test.coffee
+++ workers/social/lib/social/models/counter.test.coffee
@@ -1,5 +1,8 @@
+# Bongo
+{ daisy }  = require 'bongo'
+
 # Test Model
-JCounter = require './counter'
+JCounter   = require './counter'

 # Helpers
 { expect,


:white_check_mark: Improve test coverage for big count move and simplify

--- spec/vim-mode-plus-move-selected-text-spec.coffee
+++ spec/vim-mode-plus-move-selected-text-spec.coffee
@@ -134,8 +134,7 @@
       textData = new TextData """
         line0
         line1
-        line2
-
+        line2\n
         """
       set
         text: textData.getRaw()
@@ -143,60 +142,47 @@

     describe "linewise", ->
       describe "overwrite: false", ->
-        lines = (lines...) -> text.getLines(lines)
-        getEnsurerForLinewiseMove = (textData, {selectedText, selectionIsReversed}) ->
-          (keystroke, {rows, text}) ->
-            if (not text?) and rows?
-              text = textData.getLines(rows)
-            ensure keystroke, {text, selectedText, selectionIsReversed}
+        getEnsurerForLinewiseMove = ({selectedText, selectionIsReversed}) ->
+          (keystroke, {text}) ->
+            ensure(keystroke, {text, selectedText, selectionIsReversed})

         it "[case-1] one line", ->
-          ensureLinewiseMove = getEnsurerForLinewiseMove textData,
-            selectedText: "line0\n", selectionIsReversed: false
-          ensureLinewiseMove 'V', rows: [0, 1, 2]
-          ensureLinewiseMove 'ctrl-j', rows: [1, 0, 2]
-          ensureLinewiseMove 'ctrl-j', rows: [1, 2, 0]
-          ensureLinewiseMove 'ctrl-k', rows: [1, 0, 2]
-          ensureLinewiseMove 'ctrl-k', rows: [0, 1, 2]
+          options = {selectedText: "line0\n", selectionIsReversed: false}
+          ensureMove = getEnsurerForLinewiseMove(options)
+          ensureMove 'V', text: "line0\nline1\nline2\n"
+          ensureMove 'ctrl-j', text: "line1\nline0\nline2\n" # down
+          ensureMove 'ctrl-j', text: "line1\nline2\nline0\n" # down
+          ensureMove 'ctrl-k', text: "line1\nline0\nline2\n" # up
+          ensureMove 'ctrl-k', text: "line0\nline1\nline2\n" # up
         it "[case-2] two line", ->
-          ensureLinewiseMove = getEnsurerForLinewiseMove textData,
-            selectedText: "line0\nline1\n", selectionIsReversed: false
-          ensureLinewiseMove 'V j', rows: [0, 1, 2]
-          ensureLinewiseMove 'ctrl-j', rows: [2, 0, 1]
-          ensureLinewiseMove 'ctrl-k', rows: [0, 1, 2]
+          options = {selectedText: "line0\nline1\n", selectionIsReversed: false}
+          ensureMove = getEnsurerForLinewiseMove(options)
+          ensureMove 'V j', text: "line0\nline1\nline2\n"
+          ensureMove 'ctrl-j', text: "line2\nline0\nline1\n"
+          ensureMove 'ctrl-k', text: "line0\nline1\nline2\n"
         it "[case-3] two line, selection is reversed: keep reversed state", ->
-          ensureLinewiseMove = getEnsurerForLinewiseMove textData,
-            selectedText: "line0\nline1\n", selectionIsReversed: true
+          options = {selectedText: "line0\nline1\n", selectionIsReversed: true}
+          ensureMove = getEnsurerForLinewiseMove(options)
           set cursor: [1, 0]
-          ensureLinewiseMove 'V k', rows: [0, 1, 2]
-          ensureLinewiseMove 'ctrl-j', rows: [2, 0, 1]
-          ensureLinewiseMove 'ctrl-k', rows: [0, 1, 2]
+          ensureMove 'V k', text: "line0\nline1\nline2\n"
+          ensureMove 'ctrl-j', text: "line2\nline0\nline1\n"
+          ensureMove 'ctrl-k', text: "line0\nline1\nline2\n"
         it "extends final row when move down", ->
-          ensureLinewiseMove = getEnsurerForLinewiseMove textData,
-            selectedText: "line2\n", selectionIsReversed: false
+          options = {selectedText: "line2\n", selectionIsReversed: false}
+          ensureMove = getEnsurerForLinewiseMove(options)
           set cursor: [2, 0]
-          ensureLinewiseMove 'V', rows: [0, 1, 2]
-          ensureLinewiseMove 'ctrl-j', text: [
-            "line0"
-            "line1"
-            ""
-            "line2"
-            ""
-          ].join("\n")
-          ensureLinewiseMove 'ctrl-j', text: [
-            "line0"
-            "line1"
-            ""
-            ""
-            "line2"
-            ""
-          ].join("\n")
+          ensureMove 'V', text: "line0\nline1\nline2\n"
+          ensureMove 'ctrl-j', text: "line0\nline1\n\nline2\n"
+          ensureMove 'ctrl-j', text: "line0\nline1\n\n\nline2\n"
         it "support count", ->
-          ensureLinewiseMove = getEnsurerForLinewiseMove textData,
-            selectedText: "line0\n", selectionIsReversed: false
-          ensureLinewiseMove 'V', rows: [0, 1, 2]
-          ensureLinewiseMove '2 ctrl-j', rows: [1, 2, 0]
-          ensureLinewiseMove '2 ctrl-k', rows: [0, 1, 2]
+          options = {selectedText: "line0\nline1\n", selectionIsReversed: false}
+          ensureMove = getEnsurerForLinewiseMove(options)
+          ensureMove 'V j', text: "line0\nline1\nline2\n"
+          ensureMove '2 ctrl-j', text: "line2\n\nline0\nline1\n"
+          ensureMove '2 ctrl-k', text: "line0\nline1\nline2\n\n"
+          ensureMove '1 0 ctrl-j', text: "line2\n\n\n\n\n\n\n\n\n\nline0\nline1\n"
+          ensureMove '5 ctrl-k', text: "line2\n\n\n\n\nline0\nline1\n\n\n\n\n\n"
+
       describe "overwrite: true", ->
         beforeEach ->
           setOverwriteConfig(true)


fix spec which was failing due to altered preconditions

--- spec/javascripts/jax/input/mouse_spec.js.coffee
+++ spec/javascripts/jax/input/mouse_spec.js.coffee
@@ -17,8 +17,8 @@
       target = document.createElement('canvas')
       target.width = 150
       target.height = 100
-      target.style.width = '150px'
-      target.style.height = '100px'
+      target.style.width = '300px'
+      target.style.height = '200px'
       target.style.position = 'absolute'
       target.style.left = '202px'
       target.style.top = '252px'


cell failed to load test now uses error callback require API

--- test/unit/cellTest.coffee
+++ test/unit/cellTest.coffee
@@ -6,12 +6,14 @@
    "require(cell!) should not load cell that doesn't exist": (require,get,done)->
       get (cellPlugin)->
          loaded = false
-         require ['cell!/blarg/blarg'], (mockCell)->
-            loaded = true
-
-         defer ()->
-            ok not loaded, 'Should NOT load a non-existent cell'
-            done()
+         require ['cell!/blarg/blarg'],
+            (mockCell)->
+               ok not loaded, 'Should NOT load a non-existent cell'
+               done()
+            (loaded,failed)->
+               ok 'cell!/blarg/blarg' not of loaded, 'non-existent cell should NOT be in loaded map'
+               ok 'cell!/blarg/blarg' of failed, 'non-existent cell should be in failed map'
+               done()

    "define(cell!) should provide cell reference to cell's js": (require, get, done)->
       get (cellPlugin) ->


pre-release version number

pre-release version number

--- src/init.coffee
+++ src/init.coffee
@@ -13,7 +13,7 @@
 # @type String
 # @static
 ###
-d3plus.version = "1.8.0 - Cerulean"
+d3plus.version = "1.8.1 - Cerulean (pre-release)"

 ###*
 # The URL for the repo, used internally for certain error messages.


Fix version

Fix version

--- index.cjsx
+++ index.cjsx
@@ -11,7 +11,7 @@
   description: "远征信息查询 & 成功条件检查"
   author: "马里酱"
   link: "https://github.com/malichan"
-  version: "1.2.1"
+  version: "1.2.2"
   reactClass: React.createClass
     getInitialState: ->
       fs = require "fs-extra"


getCurrentScopeDescriptor -> getGrammarScopeDescriptor

--- src/display-buffer.coffee
+++ src/display-buffer.coffee
@@ -66,7 +66,7 @@
     @softWrapConfigSubscriptions?.dispose()
     @softWrapConfigSubscriptions = new CompositeDisposable

-    scopeDescriptor = @getCurrentScopeDescriptor()
+    scopeDescriptor = @getGrammarScopeDescriptor()

     @softWrapConfigSubscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.softWrap', =>
       @updateWrappedScreenLines()
@@ -329,7 +329,7 @@
     return 0 unless lineHeight > 0

     scrollHeight = @getLineCount() * lineHeight
-    if @height? and atom.config.get('editor.scrollPastEnd')
+    if @height? and atom.config.get(@getGrammarScopeDescriptor(), 'editor.scrollPastEnd')
       scrollHeight = scrollHeight + @height - (lineHeight * 3)

     scrollHeight
@@ -430,7 +430,7 @@
       @isSoftWrapped()

   isSoftWrapped: ->
-    @softWrapped ? atom.config.get(@getCurrentScopeDescriptor(), 'editor.softWrap') ? false
+    @softWrapped ? atom.config.get(@getGrammarScopeDescriptor(), 'editor.softWrap') ? false

   # Set the number of characters that fit horizontally in the editor.
   #
@@ -452,8 +452,8 @@
       @editorWidthInChars

   getSoftWrapColumn: ->
-    if atom.config.get(@getCurrentScopeDescriptor(), 'editor.softWrapAtPreferredLineLength')
-      Math.min(@getEditorWidthInChars(), atom.config.get(@getCurrentScopeDescriptor(), 'editor.preferredLineLength'))
+    if atom.config.get(@getGrammarScopeDescriptor(), 'editor.softWrapAtPreferredLineLength')
+      Math.min(@getEditorWidthInChars(), atom.config.get(@getGrammarScopeDescriptor(), 'editor.preferredLineLength'))
     else
       @getEditorWidthInChars()

@@ -1048,7 +1048,7 @@
       line = @tokenizedLineForScreenRow(row).text
       console.log row, @bufferRowForScreenRow(row), line, line.length

-  getCurrentScopeDescriptor: ->
+  getGrammarScopeDescriptor: ->
     @tokenizedBuffer.grammarScopeDescriptor

   handleTokenizedBufferChange: (tokenizedBufferChange) =>


Deprecate all events from ::on

Deprecate all events from ::on

--- src/display-buffer.coffee
+++ src/display-buffer.coffee
@@ -148,8 +148,8 @@
         Grim.deprecate("Use Decoration::onDidCreateMarker instead")
       when 'markers-updated'
         Grim.deprecate("Use Decoration::onDidUpdateMarkers instead")
-      # else
-      #   Grim.deprecate("DisplayBuffer::on is deprecated. Use event subscription methods instead.")
+      else
+        Grim.deprecate("DisplayBuffer::on is deprecated. Use event subscription methods instead.")

     EmitterMixin::on.apply(this, arguments)


Added limit option to crawler

Added limit option to crawler

--- src/main.coffee
+++ src/main.coffee
@@ -70,31 +70,37 @@
   post: (args...) ->
     this.callApi('post', args...)

-  _getTweets: (params, accumulatedTweets = []) ->
+  _getTweets: (params, options, accumulatedTweets = []) ->
     # Performs tweets crawling
     new Promise (resolve, reject) =>
       # Crawler function
       crawler = (incomingTweets) =>
-        if incomingTweets.length > 1
+        limitReached = options.limit and (accumulatedTweets.length + incomingTweets.length) > options.limit
+        if incomingTweets.length > 1 and not limitReached
           # Got tweets? Let's see if there more out there
           this._getTweets(
               extend(params, maxId : incomingTweets[-1].id -1),
+              options
               accumulatedTweets.concat(incomingTweets)
             ).done(resolve, reject)
         else
-          resolve accumulatedTweets.concat(incomingTweets)
+          output = accumulatedTweets.concat(incomingTweets)
+          if options.limit
+            output = output[0..options.limit]
+          resolve output
+
       # Get tweets
       this.get('statuses/user_timeline', params)
         .done(crawler, reject)

-  getTweets: (userId) ->
+  getTweets: (userId, options = {}) ->
     params =
       user_id: userId
       count: MAX_COUNT
       exclude_replies: true
       trim_user: true
       maxId: undefined
-    this._getTweets params
+    this._getTweets params, options

   getUser: (userId) ->
     this.get('users/show', { user_id: userId })


created prettify and duration methods

created prettify and duration methods


#728 adjust opacity also when deleting

#728 adjust opacity also when deleting

--- app/assets/javascripts/oxalis/controller/combinations/volumetracing_plane_controller.coffee
+++ app/assets/javascripts/oxalis/controller/combinations/volumetracing_plane_controller.coffee
@@ -60,9 +60,7 @@
         if event.shiftKey
           @volumeTracingController.enterDeleteMode()
         @model.volumeTracing.startEditing(plane)
-
-        if @model.user.get("segmentationOpacity") < 10
-          @model.user.set("segmentationOpacity", 50)
+        @adjustSegmentationOpacity()

       leftMouseUp : =>

@@ -77,6 +75,7 @@

         @volumeTracingController.enterDeleteMode()
         @model.volumeTracing.startEditing(plane)
+        @adjustSegmentationOpacity()

       rightMouseUp : =>

@@ -89,6 +88,12 @@
                   @calculateGlobalPos( pos ))

         @volumeTracingController.handleCellSelection( cellId )
+
+
+  adjustSegmentationOpacity : ->
+
+    if @model.user.get("segmentationOpacity") < 10
+      @model.user.set("segmentationOpacity", 50)

   getKeyboardControls : ->


Only close chosen by Esc on keyup event and if chosen is opened, otherwise allow event to be propagated

--- vendor/assets/javascripts/chosen/chosen.js.coffee
+++ vendor/assets/javascripts/chosen/chosen.js.coffee
@@ -225,8 +225,8 @@
           @open()
         evt.preventDefault()
       when 27
-        @close()
         evt.preventDefault()
+        evt.stopPropagation()
       when 38, 40
         @open()
         @move_selection(code - 39)
@@ -239,14 +239,19 @@
   keyup: (evt) ->
     code = evt.which ? evt.keyCode

-    return if [9, 13, 16, 27, 38, 40].indexOf(code) >= 0
-
-    if @ajax and @filter_has_changed()
-      @pull_updates()
+    return if [9, 13, 16, 38, 40].indexOf(code) >= 0
+
+    if code is 27 and @opened
+      @close()
+      evt.stopPropagation()
     else
-      @redraw_dropdown()
-
-    @open()
+      if @ajax and @filter_has_changed()
+        @pull_updates()
+      else
+        @redraw_dropdown()
+
+      @open()
+
     return

   redraw_dropdown: (data) ->


Correctly close the span element in the panel h1.

--- vendor/assets/javascripts/mercury/panel.js.coffee
+++ vendor/assets/javascripts/mercury/panel.js.coffee
@@ -6,7 +6,7 @@

   build: ->
     @element = jQuery('
', {class: 'mercury-panel loading', style: 'display:none;'})
-    @titleElement = jQuery("
#{Mercury.I18n(@options.title)}
").appendTo(@element)
+    @titleElement = jQuery("
#{Mercury.I18n(@options.title)}
").appendTo(@element)
     @paneElement = jQuery('
', {class: 'mercury-panel-pane'}).appendTo(@element)

     if @options.closeButton


Tweak the lookup for links to allow lots of kids

--- app/assets/utensils/toggle_group/toggle_group.coffee
+++ app/assets/utensils/toggle_group/toggle_group.coffee
@@ -64,7 +64,7 @@

   triggered: (e, link) ->
     @setTargets() unless @targets
-    element = @targets.find(link).closest('li')
+    element = @targets.find(link).closest('a, button').parent(@data.target)
     return if element.length <= 0
     return if @behavior == 'radio' && element.hasClass(@toggle_classes)
     if @behavior == 'radio' then @radio(element) else @checkbox(element)


vimeoShell: stylefix vimeo player id

vimeoShell: stylefix vimeo player id

--- coffee/src/shells/vimeo.shell.coffee
+++ coffee/src/shells/vimeo.shell.coffee
@@ -66,7 +66,7 @@
       '&byline=0' +
       '&portrait=0' +
       '&api=1' +
-      '&player_id=vimeoplayer' +
+      '&player_id=vimeo-player' +
       '&title=0' +
       '&byline=1' +
       '&portrait=0' +
@@ -104,7 +104,7 @@
   render: =>
     super
     @$el.empty()
-    @$el.append acorn.util.iframe @model.embedLink(), 'vimeoplayer'
+    @$el.append acorn.util.iframe @model.embedLink(), 'vimeo-player'
     @initializeVimeo()
     @

@@ -153,7 +153,7 @@

   onVimeoReady: =>
     # initialize the player object with the iframe
-    @player = Froogaloop @$('#vimeoplayer')[0]
+    @player = Froogaloop @$('#vimeo-player')[0]
     @player.addEvent 'ready', @onVimeoPlayerReady
     # @play()


Escape text box val before inserting into tinyMCE

HTML in the answer text field is saved raw. If the question is then
edited by some one else and they edit the answer using tinyMCE, they can
accidentally inject unknown html/js into their DOM. Fixed by escaping
the string in the answer_text input thus the content always shows up as
plain text in tinyMCE.

Fixes CNVS-22213

Test plan:
 - Create quiz
 - Set answer text to `<script>alert("XSS")</script>` using the
 answer_text text input field
 - Click the `pencil` edit icon
 - You should see the `<script>` html in the tinyMCE rich text editor
 - Click `Done`
 - You should not see a js alert.

Change-Id: I05c6d57159a02c098ef3d6320eb7768d4a0658a3
Reviewed-on: https://gerrit.instructure.com/59569
Tested-by: Jenkins
Reviewed-by: Matt Berns <e53c8988cd428dde240324ce2797c8eb7073560f@instructure.com>
QA-Review: Adam Stone <a0b2b61e2edcf99aa16080c2254a6ae6923d1fac@instructure.com>
Product-Review: Cameron Sutter <853bcc0cb8f5834b7805e8eb9a762054be43c731@instructure.com>

--- app/coffeescripts/editor/MultipleChoiceToggle.coffee
+++ app/coffeescripts/editor/MultipleChoiceToggle.coffee
@@ -1,4 +1,4 @@
-define ['jquery', 'compiled/editor/EditorToggle'], ($, EditorToggle) ->
+define ['jquery', 'str/htmlEscape', 'compiled/editor/EditorToggle'], ($, htmlEscape, EditorToggle) ->

   ##
   # Toggles a multiple choice quiz answer between an editor and an element
@@ -41,7 +41,7 @@
       id = @textArea.attr('id')
       @answerText.hide()
       if @content is ''
-        tinyMCE.get(id).setContent @answerText.val()
+        tinyMCE.get(id).setContent htmlEscape(@answerText.val())
       else
         tinyMCE.get(id).setContent @content


Cleanup.

Cleanup.

--- src/elementFactory.coffee
+++ src/elementFactory.coffee
@@ -37,6 +37,15 @@
       @attr(name, value) if value?

+class Select extends Element
+  ElementFactory.Elements['select'] = this
+
+  render: (value) ->
+    value = value.toString()
+    for child in getElements @el when child.nodeName == 'option'
+      child.el.selected = child.el.value == value
+
+
 class VoidElement extends Element

   # From http://www.w3.org/TR/html-markup/syntax.html: void elements in HTML
@@ -53,13 +62,3 @@
   ElementFactory.Elements['input'] = this

   render: (value) -> @attr 'value', value
-
-
-class Select extends Element
-  ElementFactory.Elements['select'] = this
-
-  render: (value) ->
-    value = value.toString()
-    for child in getElements @el when child.nodeName == 'option'
-      child.el.selected = child.el.value == value
-


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -4,7 +4,7 @@
   engine = Engine()

   engine.add
-    x:
+    t

 module()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -25,6 +25,6 @@
     x: 4
     y: 20

-  equals engine.first('type=testObj').length, 1
+  equals engine.first('type=testObj'), 1

 module()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -19,6 +19,6 @@

 test "#first", ->
   engine.add
-
+    type

 module()


remove submit() from payment.js.coffee

remove submit() from payment.js.coffee

--- frontend/app/assets/javascripts/spree/frontend/checkout/payment.js.coffee
+++ frontend/app/assets/javascripts/spree/frontend/checkout/payment.js.coffee
@@ -47,7 +47,6 @@
           couponStatus: $('#coupon_status')
         if $.trim(input.couponCodeField.val()).length > 0
           if new CouponManager(input).applyCoupon()
-            @submit()
             return true
           else
             Spree.enableSave()


package.json fixes

package.json fixes

--- tools/package.json.coffee
+++ tools/package.json.coffee
@@ -20,7 +20,7 @@
     "mongodb": "*"
     "bitcoinjs-lib": "https://github.com/bitfloor/bitcoinjs-lib/tarball/master"
 "keywords": '["bitcoin", "crypto", "finance"]'
-    "repository":
+    "repository" :
          "type": "git"
          "url": "https://github.com/kaustavha/tryethereum.git"
     "engines": { "node": "*" }


Deprecate string-based event subscriptions

--- src/pane.coffee
+++ src/pane.coffee
@@ -2,6 +2,7 @@
 {Model} = require 'theorist'
 {Emitter} = require 'event-kit'
 Serializable = require 'serializable'
+Grim = require 'grim'
 PaneAxis = require './pane-axis'
 Editor = require './editor'
 PaneView = null
@@ -187,6 +188,24 @@
   # unsubscribe.
   onWillDestroyItem: (callback) ->
     @emitter.on 'will-destroy-item', callback
+
+  on: (eventName) ->
+    switch eventName
+      when 'activated'
+        Grim.deprecate("Use Pane::onDidActivate instead")
+      when 'destroyed'
+        Grim.deprecate("Use Pane::onDidDestroy instead")
+      when 'item-added'
+        Grim.deprecate("Use Pane::onDidAddItem instead")
+      when 'item-removed'
+        Grim.deprecate("Use Pane::onDidRemoveItem instead")
+      when 'item-moved'
+        Grim.deprecate("Use Pane::onDidMoveItem instead")
+      when 'before-item-destroyed'
+        Grim.deprecate("Use Pane::onWillDestroyItem instead")
+      else
+        Grim.deprecate("Subscribing via ::on is deprecated. Use event subscription methods instead.")
+    super

   # Called by the view layer to indicate that the pane has gained focus.
   focus: ->


fixes #320

fixes #320

--- chrome/content/zotero-better-bibtex/cayw.coffee
+++ chrome/content/zotero-better-bibtex/cayw.coffee
@@ -189,7 +189,7 @@
       cite += " #{citation.suffix}" if citation.suffix
       formatted.push(cite)
     return '' if citation.length == 0
-    return '[' + citation.join(';') + ']'
+    return '[' + formatted.join(';') + ']'

   'scannable-cite': (citations) ->


Tooltip support contextual alternatives effect

--- vendor/assets/javascripts/mice/tooltip.coffee
+++ vendor/assets/javascripts/mice/tooltip.coffee
@@ -258,7 +258,7 @@
       @$element.attr('data-original-title') or (if typeof @options.title == 'function' then @options.title.call(@$element[0]) else  @options.title)

     tip: ->
-      @$tip = @$tip or $(@options.template)
+      @$tip = @$tip or $(@options.template).addClass @options.contextual

     arrow: ->
       @$arrow = @$arrow or @tip().find('.arrow')
@@ -312,6 +312,7 @@
   $.fn.tooltip.defaults =
     animation: true
     placement: 'top'
+    contextual: ''
     selector: false
     template: '

'
     trigger: 'hover focus'


contacts, wut?!

contacts, wut?!

--- src/engine_physics.coffee
+++ src/engine_physics.coffee
@@ -20,7 +20,7 @@
         a = contact.GetFixtureA().GetBody().GetUserData()
         b = contact.GetFixtureB().GetBody().GetUserData()

-        pendingCollisions.push([a, b])
+        pendingCollisions.push([a, b, contact])

       EndContact: (contact) ->
       PreSolve: (contact, oldManifold) ->
@@ -28,10 +28,10 @@

     fireCollisionEvents = () ->
       pendingCollisions.each (event) ->
-        [a, b] = event
+        [a, b, contact] = event

-        a.trigger "collision", b
-        b.trigger "collision", a
+        a.trigger "collision", b, contact
+        b.trigger "collision", a, contact

       pendingCollisions = []

@@ -68,7 +68,7 @@
       entityData.world = world

     self.bind "afterAdd", (object) ->
-      object.bind "destroy", ->
+      object.bind "remove", ->
         pendingDestructions.push object.body()

     return {}


Made 'resolveType' function less complex & confusing.

--- lib/typeresolution.coffee
+++ lib/typeresolution.coffee
@@ -114,7 +114,24 @@
   cb null, {name: inheritedTypeName, nested: []}

+# Ensures implicit nested types are added to given
+# 'simple type specification object' in case such option is applicable.
+ensureImplicitNestedTypes = (node, simpleTypeSpec, cb) ->
+  if simpleTypeSpec.nested?.length
+    # we already got some nested types
+    cb null, simpleTypeSpec
+  else
+    # no nested types, so we check whether it's not a situation where we can
+    # resolve implicit nested types - in that case we add them to the
+    # *simpleTypeSpec* object
+    name = simpleTypeSpec.name
+    resolveImplicitNestedTypes name, node, (err, nested) ->
+      cb err, ({name, nested} unless err)
+
+
 # Takes top-level *Named Type* or *Property Member* or *Value Member* tree node.
+# The *inheritedTypeName* argument is optional.
+#
 # Provides a sort of 'simple type specification object':
 #
 #     name: ...
@@ -124,23 +141,20 @@
 # base types only, ends with an error (Boutique builds no symbol table,
 # so it can't resolve any possible inheritance).
 resolveType = (node, inheritedTypeName, cb) ->
+  # process arguments
   if inheritedTypeName
     if typeof inheritedTypeName is 'function'
       cb = inheritedTypeName
     else
+      # we've got inherited type
       return resolveInheritedType node, inheritedTypeName, cb

+  # no inherited type, let's start regular type resolution
   typeSpec = inspect.findTypeSpecification node
   simplifyTypeSpecification typeSpec, (err, simpleTypeSpec) ->
     return cb err if err
     return resolveImplicitType node, cb unless simpleTypeSpec
-
-    if simpleTypeSpec.nested?.length
-      cb null, simpleTypeSpec
-    else
-      name = simpleTypeSpec.name
-      resolveImplicitNestedTypes name, node, (err, nested) ->
-        cb err, ({name, nested} unless err)
+    ensureImplicitNestedTypes node, simpleTypeSpec, cb

 module.exports = {


ManageDomainsView: cleanup unused methods

--- client/Main/domains/managedomainsview.coffee
+++ client/Main/domains/managedomainsview.coffee
@@ -8,7 +8,7 @@

     {@machine} = @getOptions()

-    domainSuffix = ".#{KD.nick()}.#{KD.config.userSitesDomain}"
+    @domainSuffix = ".#{KD.nick()}.#{KD.config.userSitesDomain}"

     @addSubView @inputView = new KDView
       cssClass          : 'input-view'
@@ -20,7 +20,7 @@
       callback          : => @emit 'AddDomain'

     @inputView.addSubView new KDView
-      partial           : domainSuffix
+      partial           : @domainSuffix
       cssClass          : 'domain-suffix'

     topDomain = "#{KD.nick()}.#{KD.config.userSitesDomain}"
@@ -30,8 +30,8 @@
         type            : 'domain'
         wrapper         : yes
         itemClass       : DomainItem
-        dataPath        : 'domain'
-    , items             : [{domain: topDomain}]
+        itemOptions     :
+          machineId     : @machine._id

     @addSubView @domainController.getView()
     @inputView.hide()
@@ -64,11 +64,3 @@
       return  if $(event.target).hasClass 'domain-toggle'
       @emit "DomainInputCancelled"
       @inputView.hide()
-
-  addDomain:(domain)->
-
-    @domainController.addItem {domain}
-
-  removeDomain:(domain)->
-
-    @domainController.removeItem null, {domain}


activity: style fix for collab chat window

--- client/activity/lib/views/messagepane.coffee
+++ client/activity/lib/views/messagepane.coffee
@@ -43,8 +43,19 @@

     {typeConstant} = @getData()

+    # this hack is mainly for css.
+    # collaboration chat pane depends on the css
+    # from activity private message, especially
+    # the specifity of the list items.
+    # This way, the activity list controller of collaboration
+    # chat window will have `kdlistview-privatemessage`
+    # cssClass. ~Umut
+    listType = if typeConstant is 'collaboration'
+    then 'privatemessage'
+    else typeConstant
+
     @listController = new ActivityListController {
-      type          : typeConstant
+      type          : listType
       viewOptions   :
         itemOptions : {channelId}
       wrapper


Changed downloadInBrowser() to optionally use Blobs if the download is string data to prevent to from opening in the browser.

--- src/common.coffee
+++ src/common.coffee
@@ -103,9 +103,16 @@
         collection.download(fileId).then (data) ->
           Blobs.fromString(data, type: file.type())

-      downloadInBrowser: (fileId) ->
+      downloadInBrowser: (fileId, args) ->
+        args = Setter.merge({
+          blob: false
+        }, args)
         file = collection.findOne(fileId)
-        Window.downloadFile(file.url())
+        if args.blob
+          blob = @toBlob(fileId)
+          Blobs.downloadInBrowser(blob, file.name())
+        else
+          Window.downloadFile(file.url())

 if Meteor.isServer
   createTempStore = _.once (args) ->


stop loop back to login during logout if auto-oauth is enabled

--- main.coffee
+++ main.coffee
@@ -147,8 +147,9 @@
   else res.json {success: false, error: 'incomplete request'}

 app.get '/logout', (req, res) ->
-  res.clearCookie 'ctfpad'
-  res.redirect 303, '/'
+    res.clearCookie 'ctfpad'
+    unless config.oauth
+        res.redirect 303, '/'

 app.post '/changepassword', (req, res) ->
   validateSession req.header('x-session-id'), (ans) ->


:cookie::bouquet: Updated at https://danielx.net/editor/

--- main.coffee
+++ main.coffee
@@ -46,19 +46,35 @@
 initFileDrop document, (file, path) ->
   os.put "#{path}/#{file.name}", file

+receivedCredentials = ->
+  console.log AWS.config.credentials
+  id = AWS.config.credentials.identityId
+
+  document.body.removeChild document.querySelector('#LoginWithAmazon')
+
+  bucket = new AWS.S3
+    params:
+      Bucket: "whimsy-fs"
+
+  fs = require('./fs')(id, bucket)
+
+  os.attachFS fs
+
 AWS.config.update
   region: 'us-east-1'

+try
+  logins = JSON.parse localStorage.WHIMSY_FS_AWS_LOGIN
+
 AWS.config.credentials = new AWS.CognitoIdentityCredentials
   IdentityPoolId: 'us-east-1:4fe22da5-bb5e-4a78-a260-74ae0a140bf9'
+  Logins: logins

-table = new AWS.DynamoDB
-  params:
-    TableName: 'whimsy-fs'
-
-bucket = new AWS.S3
-  params:
-    Bucket: "whimsy-fs"
+if logins
+  pinvoke AWS.config.credentials, "get"
+  .then receivedCredentials
+  .catch (e) ->
+    console.error e

 require "./amazon_login"
 document.body.appendChild require("./templates/login")
@@ -66,23 +82,22 @@
     options = { scope : 'profile' }
     amazon.Login.authorize options, (resp) ->
       if !resp.error
+        console.log resp
         token = resp.access_token
         creds = AWS.config.credentials

-        creds.params.Logins =
+        logins =
           'www.amazon.com': token
+        localStorage.WHIMSY_FS_AWS_LOGIN = JSON.stringify(logins)
+
+        creds.params.Logins = logins

         creds.expired = true

         queryUserInfo(token)

         pinvoke AWS.config.credentials, "get"
-        .then ->
-          id = AWS.config.credentials.identityId
-
-          fs = require('./fs')(id, bucket)
-
-          os.attachFS fs
+        .then receivedCredentials

 queryUserInfo = (token) ->
   fetch "https://api.amazon.com/user/profile",


:guardsman::feet: Updated in browser at strd6.github.io/editor

--- main.coffee
+++ main.coffee
@@ -131,12 +131,12 @@

 Track = ->
   notes = {}
-  playNote = (note, velocity, id, time=context.currentTime) ->
+  playNote = (note, velocity, time=context.currentTime) ->
     volume = velocity / 128

-    if notes[id]
+    if notes[note]
       # Technically this means another noteOn occured before a noteOff event :(
-      [osco] = notes[id]
+      [osco] = notes[note]
       osco.gain.setValueAtTime(volume, time)
       console.error "Double noteOn"
     else
@@ -153,22 +153,23 @@

       osco.start(time)

-      notes[id] = [osco, osco.gain, volume]
-
-  releaseNote = (id, time=context.currentTime) ->
+      notes[note] = [osco, osco.gain, volume]
+
+  releaseNote = (note, time=context.currentTime) ->
     # Bail out on double releases
-    unless notes[id]
+    unless notes[note]
       console.error "Double noteOff"
       return

-    [osco, gain, volume] = notes[id]
+    [osco, gain, volume] = notes[note]
     # Wow this is nutz!
     # Need to ramp to the current value because linearRampToValueAtTime
     # uses the previous ramp time to create the next ramp, yolo!
-
+
+    # TODO: Is there any way to get linearRampToValueAtTime to be reliable?
     # gain.linearRampToValueAtTime(volume, time)
     # gain.linearRampToValueAtTime(0.0, time + 0.125)
-
+
     gain.setValueAtTime(0, time)

     # osco.stop(time + 0.25)
@@ -199,7 +200,7 @@
         state.toSet = note
         state.moveNext = 2

-        playNote(note, velocity, note)
+        playNote(note, velocity)
       when 128 # Note off
         releaseNote(note)

@@ -215,7 +216,7 @@
   # Bad Apple 36MB MIDI

   Ajax = require "./lib/ajax"
-  Ajax.getBuffer(badApple)
+  Ajax.getBuffer(waltz)
   .then (buffer) ->
     array = new Uint8Array(buffer)
     midiFile = MidiFile(array)
@@ -235,7 +236,7 @@
         when "channel:controller"
           ; # TODO
         when "channel:noteOn"
-          playNote noteNumber, velocity, noteNumber, time
+          playNote noteNumber, velocity, time
         when "channel:noteOff"
           releaseNote noteNumber, time
         when "channel:programChange"


Firefox doesnt like semicolons!

Firefox doesnt like semicolons!

--- main.coffee
+++ main.coffee
@@ -14,7 +14,9 @@
 defer = (fn) ->
 	timeouts.push(window.setTimeout(fn, 0))

-toHslString = (h) -> "hsl(#{h}, 100%, 50%);"
+toHslString = (h) ->
+	# Firefox doesn't like a semicolon here. Go figure!
+	"hsl(#{h}, 100%, 50%)"

 initColours = ->
 	for x in [0...width] by rectWidth


remove unnecessary assignment

remove unnecessary assignment

--- main.coffee
+++ main.coffee
@@ -2,7 +2,7 @@
 { LivemarkSource } = require('lib/source')
 { HistoryFilter } = require('lib/filter')

-m = new FeedTicker(
+new FeedTicker(
   [ new LivemarkSource ],
   [ new HistoryFilter ]
 )


Revert "Revert "fix auto grow height calculation procedure""

This reverts commit 2fa9fbf0a6ebeb830532544fe3286f6660439e80.

--- components/inputs/KDInputView.coffee
+++ components/inputs/KDInputView.coffee
@@ -314,12 +314,14 @@
     $input = @$()

     @setClass "autogrow"
-    $growCalculator = $ "<div/>", class : "invisible"
+
+    # input content is copied into clone element to get calculated height
+    @_clone = $ "<div/>", class : "invisible"

     @on "focus", =>
       @utils.defer =>
-        $growCalculator.appendTo 'body'
-        $growCalculator.css
+        @_clone.appendTo 'body'
+        @_clone.css
           height        : "auto"
           "z-index"     : 100000
           width         : $input.width()
@@ -329,18 +331,23 @@
           "line-height" : $input.css('line-height')

     @on "blur", =>
-      $growCalculator.detach()
+      @_clone.detach()
       @$()[0].style.height = "none" # hack to set to initial

-    @on "keydown", =>
-      $growCalculator.text @getValue()
-      height = $growCalculator.height()
-      if @$().css('box-sizing') is "border-box"
-        padding    = parseInt($growCalculator.css("padding-top"), 10) + parseInt($growCalculator.css("padding-bottom"), 10)
-        border     = parseInt($growCalculator.css("border-top-width"), 10) + parseInt($growCalculator.css("border-bottom-width"), 10)
-        height     = height + border + padding
-
-      @setHeight height
+    @on "keydown", @bound "resize"
+    @on "keyup", (event) => @resize() if @getValue().length is 0
+
+  resize: ->
+    return  unless @_clone
+    @_clone.appendTo 'body' unless document.body.contains @_clone[0]
+    @_clone.html @getValue().replace /\n/gm, "<br />"
+    height = @_clone.height()
+    if @$().css('box-sizing') is "border-box"
+      padding    = parseInt(@_clone.css("padding-top"), 10) + parseInt(@_clone.css("padding-bottom"), 10)
+      border     = parseInt(@_clone.css("border-top-width"), 10) + parseInt(@_clone.css("border-bottom-width"), 10)
+      height     = height + border + padding
+
+    @setHeight height

   enableTabKey:-> @inputTabKeyEnabled = yes


Foreing profiles viewing through node.js

--- main.coffee
+++ main.coffee
@@ -173,8 +173,37 @@
 		response.redirect '/login/'

-app.get '/profile/id/:id/', phpgate # PHP
-app.get '/profile/user/:user/', phpgate # PHP
+app.get '/profile/id/:id/', (request, response) ->
+	id = parseInt request.param('id'), 10
+	utils.game.getUserCharacters mysqlConnection, id, (error, chars) ->
+		if error?
+			throw error
+		if chars is null
+			response.send 404
+			return
+		options = request.uonline.basicOpts
+		options.instance = 'profile'
+		options.profileIsMine = (options.loggedIn is true) and (id == options.userid)
+		for i of chars
+			options[i] = chars[i]
+		options.nickname = options.user # кастыль #273
+		response.render 'profile', options
+
+
+app.get '/profile/user/:nickname/', (request, response) ->
+	nickname = request.param('nickname')
+	chars = utils.game.getUserCharacters.sync null, mysqlConnection, nickname
+	if chars is null
+		response.send 404
+		return
+	options = request.uonline.basicOpts
+	options.instance = 'profile'
+	options.profileIsMine = (options.loggedIn is true) and (chars.id == options.userid)
+	for i of chars
+		options[i] = chars[i]
+	options.nickname = options.user # кастыль #273
+	response.render 'profile', options
+.async()

 app.get '/action/logout', (request, response) ->


:end::unamused: Updated at https://danielx.net/editor/

--- main.coffee
+++ main.coffee
@@ -21,7 +21,7 @@
 style.innerHTML = require "./style"
 document.head.appendChild style

-{log, emptyElement} = require "./util"
+{log, emptyElement, pinvoke} = require "./util"

 Drop = require("./lib/drop")

@@ -83,18 +83,11 @@

       queryUserInfo(token)

-      AWS.config.credentials.get (err) ->
-        return console.error err if err
-
+      pinvoke AWS.config.credentials, "get"
+      .then ->
         id = AWS.config.credentials.identityId

         fs = require('./fs')(id, bucket)
-
-        file = new File ['yolo'], "file.txt", type: "text/plain"
-        # fs.put "Desktop/stuff/cool/wat.txt", file
-        ->
-          ["Desktop/cool.txt", "Desktop/rad.txt", "Desktop/yolo.txt", "Desktop/duder.txt"].forEach (path) ->
-            fs.put path, file

         EditorTemplate = require "./templates/editor"
         FolderTemplate = require "./templates/folder"


More accurate timings in SQL logger.

More accurate timings in SQL logger.

--- main.coffee
+++ main.coffee
@@ -58,18 +58,18 @@
 	dbConnection.on 'query', (query) ->
 		start = process.hrtime()
 		query.on 'close', ->
-			logged = query.text
-			for value, index in query.values
-				index++
-				while logged.indexOf("$#{index}") isnt -1
-					logged = logged.replace "$#{index}", chalk.blue(JSON.stringify(value))
 			timetuple = process.hrtime(start)
 			time = Math.round(timetuple[0]*1000 + timetuple[1]/1000000)
 			time = switch
 				when time < 10 then chalk.green("#{time} ms")
 				when time < 20 then chalk.yellow("#{time} ms")
 				else chalk.red("#{time} ms")
-			console.log "#{time}: #{logged}"
+			logged = query.text
+			for value, index in query.values
+				index++
+				while logged.indexOf("$#{index}") isnt -1
+					logged = logged.replace "$#{index}", chalk.blue(JSON.stringify(value))
+			console.log " #{time}: #{logged}"

 # Set up Express


:taurus::grey_exclamation: Updated at https://danielx.net/editor/

--- main.coffee
+++ main.coffee
@@ -7,33 +7,108 @@

 gh = Github(p)

+Repository = gh.Repository
+
 log = (value) ->
   console.log value
   return value

+doItLive = false
+
 setTimeout ->
-  gh.api('orgs/distri/repos').then log
+  gh.api('orgs/distri/repos')
   .then (data) ->
-    data.forEach (datum, i) ->
-      template = URITemplates(datum.contents_url)
-      uri = template.fill(path: "") + "?ref=gh-pages"
-      console.log uri
+    convertResultPage(data)
+  .catch (e) ->
+    console.error e

-      if i is 1
-        gh.api(uri).then log
-        .then (files) ->
-          log(
-            files.filter (file) ->
-              file.type is "file" and file.path.match /\.json\.js$/
-            .map (file) ->
-              # TODO: Read the file, convert path to .json, write json data to gh-pages branch
-              file.path
-          )
+, 100

-    log gh.lastRequest().getResponseHeader("Link").split(',').map (link) ->
-      link.split(';').map (s) ->
-        s.trim()
-, 100
+getNextLink = () ->
+  gh.lastRequest().getResponseHeader("Link").split(',').map (link) ->
+    link.split(';').map (s) ->
+      s.trim()
+  .filter (link) ->
+    link[1] is 'rel="next"'
+  .map (link) ->
+    str = link[0]
+    str.substring 1, str.length - 1
+
+convertResultPage = (data) ->
+  nextLink = getNextLink()[0]
+
+  sequentially data, (datum) ->
+    template = URITemplates(datum.contents_url)
+    uri = template.fill(path: "") + "?ref=gh-pages"
+
+    repo = Repository(datum)
+
+    convertRepo(repo, uri)
+  .then ->
+    if nextLink
+      console.log nextLink
+
+      gh.api(nextLink)
+      .then convertResultPage
+    else
+      console.log 'DONE!'
+
+convertRepo = (repo, uri) ->
+  gh.api(uri)
+  .then (files) ->
+    Promise.all(
+      files.filter (file) ->
+        file.type is "file" and file.path.match /\.json\.js$/
+      .map (file) ->
+        gh.api(file.url)
+    )
+  .then (files) ->
+    files.map convertFile
+  .then (files) ->
+    if doItLive
+      repo.commitTree
+        baseTree: true
+        branch: "gh-pages"
+        message: "Converting .json.js to .json"
+        tree: files
+    else
+      console.log "Dry run #{uri}"
+  .then ->
+    log "converted #{uri}"
+
+convertFile = (file) ->
+  path: file.path.replace /\.js$/, ""
+  mode: "100644"
+  type: "blob"
+  content: extractJSON(atob(file.content))
+
+extractJSON = (content) ->
+  start = content.indexOf('{')
+  end = content.length - 2
+
+  jsonData = content.substring start, end
+
+  JSON.parse jsonData
+
+  jsonData + "\n"
+
+sequentially = (array, fn) ->
+  new Promise (resolve, reject) ->
+    index = 0
+    results = []
+
+    step = ->
+      if index < array.length
+        p = fn(array[index], index)
+        index += 1
+
+        results.push p
+
+        p.then step
+      else
+        resolve(results)
+
+    step()

 # We want to get all the repos in distri, STRd6
 # for each repo we want to look at the gh-pages branch


Added: option to only add documents for a specific doctype

--- main.coffee
+++ main.coffee
@@ -2,6 +2,7 @@
 async = require 'async'
 Client = require('request-json').JsonClient
 fs = require 'fs'
+util = require 'util'

 # Connection to the data system
 client = new Client "http://localhost:9101/"
@@ -10,7 +11,7 @@
 ## Where the fixture files are
 dirPath = './fixtures/'
 ## If the script must be restrain to one doctype, which one
-docTypeTarget = null
+doctypeTarget = null

 _readJSONFile = (filename, callback) ->

@@ -113,27 +114,35 @@
                 # starts next doctype importation
                 callback null, null

+
+# TODO
+##handling one file parameter
+##fs.readFileSync filePath
+
 # get the files and data
 async.concat fs.readdirSync(dirPath), _readJSONFile, (err, docs) ->

     # Track malformed document
-    skippedDoctypeMissing = 0
+    skippedDoctypeMissing = []

     # Store the document per doctypes
     doctypeSet = {}
     for doc in docs
         unless doc.docType?
-            skippedDoctypeMissing++
-        else
+            skippedDoctypeMissing.push doc
+        else if (not doctypeTarget? or doctypeTarget is "") \
+                or doctypeTarget is doc.docType
             doctypeSet[doc.docType] = [] unless doctypeSet[doc.docType]?
             doctypeSet[doc.docType].push doc

     # TODO: improving feedback by telling in which documents
     #       the doctype is missing
-    if skippedDoctypeMissing > 0
+    if skippedDoctypeMissing.length > 0
         msg = "[WARN] Missing doctype information in " + \
-                    "#{skippedDoctypeMissing} documents."
+                    "#{skippedDoctypeMissing.length} documents."
         console.log msg.red
+        for missingDoctypeDoc in skippedDoctypeMissing
+            console.log util.inspect missingDoctypeDoc

     # Process description:
     ## create the "all" request


fix buggy interaction between Bag of Gold and Watchtower

--- cards.coffee
+++ cards.coffee
@@ -568,9 +568,8 @@
   mayBeBought: (state) -> false

   playEffect: (state) ->
-    state.gainCard(state.current, c.Gold)
+    state.gainCard(state.current, c.Gold, 'draw')
     state.log("...putting the Gold on top of the deck.")
-    transferCardToTop(c.Gold, state.current.discard, state.current.draw)
 }

 makeCard 'Bank', c.Silver, {


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

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

   self.bind "update", ->
     for property in I.clamps
-      property
+      property.value = property.value.cl

       {approachBy, target} = cooldownOptions


Enhanced tokenizer for phone logs

Enhanced tokenizer for phone logs

--- server/lib/tokenizer.coffee
+++ server/lib/tokenizer.coffee
@@ -1,10 +1,5 @@
 Tokenizer = require 'tokenizer'
 module.exports = t = new Tokenizer((token, match) ->
-
-  # change the type of the token before emitting it
-  "phoneComLog" if match.type is "word" and token is "appel"
-  "phoneComLog" if match.type is "word" and token is "appele"
-  "phoneComLog" if match.type is "word" and token is "appelee"

 )
 #template
@@ -17,25 +12,29 @@
 t.addRule /^"[^"]*$/, "maybe citation"

 # REFERENCES TO SELF
-t.addRule /^je$/i, "moi"
-t.addRule /^m'a$/i, "moi"
-t.addRule /^j'ai$/i, "moi"
-t.addRule /^je$/i, "moi"
+t.addRule /^je$/i, "mySelf"
+t.addRule /^m'a$/i, "toSelf"
+t.addRule /^j'ai$/i, "myself"
+t.addRule /^je$/i, "myself"

 # Ponctuation

 # REFERENCES TO OTHERS
-t.addRule /^qui$/i,"contact"
-
+t.addRule /^qui$/i,"who"

 # PHONE COMMUNICATIONS
-t.addRule /^appele$/,"phoneComLog"
-t.addRule /^appelee$/,"phoneComLog"
-t.addRule /^appel$/,"phoneComLog"
-
-
+t.addRule /^appele$/,"phoneCall"
+t.addRule /^appelee$/,"phoneCall"
+t.addRule /^appel$/,"phoneCall"
+t.addRule /^contacte$/,"phoneComLog"
+t.addRule /^contactee$/,"phoneComLog"
+t.addRule /^ecrit$/,"phoneText"

 # TEMPORAL OBJECTS
+## Temporal helpers
+t.addRule /^ce$/, "currentTemporal"
+t.addRule /^cette$/, "currentTemporal"
+
 ## Years
 t.addRule /^\d{4}$/,"year"
 t.addRule /^en(\d{4})$/,"givenYear"
@@ -54,26 +53,32 @@
 t.addRule /^octobre$/,"month"
 t.addRule /^novembre$/,"month"
 t.addRule /^decembre$/,"month"
-
-
+## Weeks
+t.addRule /^semaine/, "week"
 ## Days
 ## Specific date : le 17-03-1997
 t.addRule /^(le(\s)\d{1,2})-(\d{1,2})-(\d{4})$/,"specificDate"
+## Quand
+t.addRule /^quand$/, "when"

 ## BLACKLIST
+t.addRule /^a$/, "blacklist"
 t.addRule /^ai$/,"blacklist"
-
+t.addRule /^en$/, "blacklist"

 # if it's a word and it's not been matched yet it's probably a name
 # wording for now
 t.addRule /^\w+$/, "word"
 t.addRule /^(\s)+$/, "whitespace"
-t.ignore /^(\s)+$/, "whitespace"
+t.ignore "whitespace"
+t.ignore "blacklist"
+t.ignore "ponctuation"
 t.addRule /^[',;.:!?-]$/, "ponctuation"

 unless module.parent
-    #t.addRule /^salut$/i, "salut"
     t.on 'token', (tok) -> console.log tok
     #t.write "qui ai-je appele en 2013"
-    t.write "qui ai-je appele en juin 2014"
+    #t.write "Quand Pierre m'a appele en juin"
+    #t.write "Quand ai-je appele Pierre en juin"
+    t.write "a qui ai-je ecrit cette semaine"
     t.end()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -507,16 +507,16 @@
     magenta.lightness()
     # => 0.9

-    darkerMagenta = magenta.lightness(0.75)
-
-    # to see what they look like
-    for color, index in ['yellow', 'gray']
-      canvas.drawRect
-        color: eval(color)
-        x: 20 + (60 * index)
-        y: 20 + (60 * index)
-        width: 60
-        height: 60
+    # modifies magenta in place to be lighter
+    magenta.lightness(0.75)
+
+    # to see what it looks like
+    canvas.drawRect
+      color: magenta
+      x: 50
+      y: 30
+      width: 80
+      height: 80
     </pre></code>

     @name lightness


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -7,7 +7,7 @@
     s = '0' + s if s.length == 1

   parseColor = (colorString) ->
-    false if !colorString || colorString == 'transparent'
+    return [0, 0, 0, 0] if !colorString || colorString == 'transparent'

     bits = rgbParser.exec(colorString)
     return [
@@ -21,7 +21,7 @@

     parsedColor = parseColor(color)

-    alpha = parsedColor[4]
+    alpha = parsedColor[3]

     channels = [
       parseInt(parsedColor[0])


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -84,7 +84,7 @@
         return "rgba(#{self.r}, #{self.g}, #{self.b}, #{self.a})"

       toString: ->
-        return (if self.a == 1 then toHex([self.r, self.g, self.b]) else self.rgba())
+        return self.rgba()

     return self


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com


adding hsl support to color class

adding hsl support to color class

--- src/color.coffee
+++ src/color.coffee
@@ -130,6 +130,53 @@
           return padString(hexString(number))

         "##{hexFromNumber(channels[0])}#{hexFromNumber(channels[1])}#{hexFromNumber(channels[2])}"
+
+      toHsl: ->
+        r = channels[0] / 255
+        g = channels[1] / 255
+        b = channels[2] / 255
+
+        min = [r, g, b].extremes[0]
+        max = [r, g, b].extremes[1]
+
+        h = s = l = (max + min) / 2
+
+        if max == min
+          h = s = 0
+        else
+          d = max - min
+          s = (if l > 0.5 then d / (2 - max - min) else d / (max + min))
+
+        Color.RGBtoHSL = function (rgb) {
+          // in JS 1.7 use: var [r, g, b] = rgb;
+          var r = rgb[0],
+              g = rgb[1],
+              b = rgb[2];
+
+          r /= 255;
+          g /= 255;
+          b /= 255;
+
+          var max = math.max(r, g, b),
+              min = math.min(r, g, b),
+          h, s, l = (max + min) / 2;
+
+          if (max === min) {
+            h = s = 0; // achromatic
+          } else {
+            var d = max - min;
+            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
+            switch (max) {
+                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+                case g: h = (b - r) / d + 2; break;
+                case b: h = (r - g) / d + 4; break;
+            }
+            h /= 6;
+          }
+
+          return [h, s, l];
+
+        };

       toString: -> self.rgba()


Double-fix stroke width slider

Double-fix stroke width slider

--- coffee/core/widgets.coffee
+++ coffee/core/widgets.coffee
@@ -46,7 +46,7 @@

     $input.change (e) =>
       @tool.strokeWidth = parseInt($(e.currentTarget).val(), 10)
-      $brushWidthVal.html("(#{@strokeWidth} px)")
+      $brushWidthVal.html("(#{@tool.strokeWidth} px)")
     return $el


gEDA: add support for mounting holes in pcb footprint

--- src/geda-generator.coffee
+++ src/geda-generator.coffee
@@ -260,11 +260,14 @@
         when 'pad'
           shape.clearance ?= pattern.settings.clearance.padToPad
           shape.mask ?= pattern.settings.clearance.padToMask
-          if (shape.type is 'through-hole')
+          if (shape.type is 'through-hole' or shape.type is 'mounting-hole')
             if (shape.width == shape.height)
+              flags = []
+              if shape.hole >= shape.width then flags.push('hole')
+              if shape.shape is 'rectangle' then flags.push('square')
               fs.writeSync(fd,
                 sprintf("  Pin [#{@f}mm #{@f}mm #{@f}mm #{@f}mm #{@f}mm #{@f}mm \"\" \"%s\" \"%s\"]\n",
-                  shape.x, shape.y, shape.width, shape.clearance, shape.width+2*shape.mask, shape.hole, shape.name, (if shape.shape is 'rectangle' then 'square' else ''))
+                  shape.x, shape.y, shape.width, shape.clearance, shape.width+2*shape.mask, shape.hole, shape.name, flags.join(','))
               )
             else
               width = if shape.width < shape.height then shape.width else shape.height


Ability to call endpoint directly

Ability to call endpoint directly

 - Somewhy not all service endpoints might be called via batch

--- endpoint.coffee
+++ endpoint.coffee
@@ -8,13 +8,16 @@
   constructor: (@key, @endpoint, @_db) ->
     check @key, String
     check @endpoint, String
-  get: (method = 'GET', body = {}) ->
-    data = @_db.__batch
-      method: method
-      to: @endpoint
-      body: body
-    data = data.get() if _.isFunction data.get
-    return data
+
+  get: (method = 'GET', options = {}, directly) ->
+    if directly
+      @_db.__call(@endpoint, options, method).data
+    else
+      data = @_db.__batch
+        method: method
+        to: @endpoint
+        body: options.body
+      data = data.get() if _.isFunction data.get

   __getAndProceed: (funcName, method = 'GET', body = {}, callback) ->
     if callback


Only match wat and win solo

Only match wat and win solo

--- scripts/starcraft.coffee
+++ scripts/starcraft.coffee
@@ -1,8 +1,8 @@
 module.exports = (robot) ->
-  robot.hear /.*wat.*/i, (msg) ->
+  robot.hear /^wat$/i, (msg) ->
     msg.send "http://img24.imageshack.us/img24/4287/snapshot20080215123519.png"

-  robot.hear /.*win.*/i, (msg) ->
+  robot.hear /^win$/i, (msg) ->
     msg.send "http://1.bp.blogspot.com/-0KhRbSdEkuE/TymtgxJtcRI/AAAAAAAAArY/zGVzZt5dQ1w/s379/so-much-win-starcraft-reaction.gif"

   robot.hear /.*(single point of failure|spof|artosis pylon).*/i, (msg) ->