factor histogram into its own class

factor histogram into its own class

--- examples/audio/static/coffee/spectrogram.coffee
+++ examples/audio/static/coffee/spectrogram.coffee
@@ -9,37 +9,35 @@
 FREQ_SAMPLES = NUM_SAMPLES / 8
 SPECTROGRAM_LENGTH = 512

+window.TIMESLICE = 40 # ms
+
+BORDER = 50
+
+NGRAMS = 1020
+
+HIST_NUM_BINS = 16
+
 FREQ_SLIDER_FACTOR = 2
 FREQ_SLIDER_MAX = MAX_FREQ/FREQ_SLIDER_FACTOR
 FREQ_SLIDER_MIN = 0

-BORDER = 50
-
-NGRAMS = 1020
-
-HISTSIZE = 256
-NUM_BINS = 16
-
-window.TIMESLICE = 40 # ms
-
 GAIN_DEFAULT = 1
 GAIN_MIN = 1
 GAIN_MAX = 20

-
 requestAnimationFrame = window.requestAnimationFrame || \
   window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||\
   window.msRequestAnimationFrame

-
 class SpectrogramApp
   constructor: () ->

     @gain = GAIN_DEFAULT
-    @last_render = new Date()

     @paused = false
+
     @throttled_request_data = _.throttle((=> @request_data()), 40)
+
     # Set up image plot for the spectrogram
     @image_width = NGRAMS
     @image_height = 256
@@ -58,12 +56,9 @@
       x0: FREQ_SLIDER_MIN, x1: FREQ_SLIDER_MAX, y0: -1, y1: 10, width: 550, height: 220, border: BORDER
     })

-    # Set up the radial histogram
-    @hist_source = Collections('ColumnDataSource').create(
-      data: {inner_radius:[], outer_radius:[], start_angle:[], end_angle:[], fill_alpha: []}
-    )
-    hist_model = @create_hist()
-    @hist_view = new hist_model.default_view(model: hist_model)
+    @hist_plot = new RadialHistogramPlot({
+      num_bins: HIST_NUM_BINS, width: 500, height: 500
+    })

     @render()

@@ -75,7 +70,6 @@
     dataType: 'json'
     error: (jqXHR, textStatus, errorThrown) =>

-      #console.log "AJAX Error: #{textStatus}"
     success: (data, textStatus, jqXHR) =>
       if not data[0]?
         _.delay((=> @throttled_request_data), 130)
@@ -84,14 +78,7 @@
         requestAnimationFrame(
           => @throttled_request_data())

-
-    new_render = new Date()
-    #console.log("render_time", new_render - @last_render)
-    @last_render = new_render
-
   on_data: (data) ->
-    if not data[0]?
-      return

     # apply the gain
     for i in [0..(data[0].length-1)]
@@ -117,51 +104,14 @@
     @spec_source.set('data', {image: @image})
     @spec_source.trigger('change', @spec_source, {})

-    # update the simple line plots
     @power_plot.update(data[1])
+
     @fft_plot.update(data[0][0..data[0].length/FREQ_SLIDER_FACTOR])

-    # update the radial histogram data
-    hist = new Float32Array(NUM_BINS)
-    if @fft_xrange
-      bin_min = Math.round(@fft_xrange.get('start'))
-      bin_max = Math.round(@fft_xrange.get('end'))
-    else
-      bin_min = 0
-      bin_max = 256
-    bin_start = bin_min
-    bin_size = Math.ceil((bin_max - bin_min) / NUM_BINS)
-    for i in [0..NUM_BINS-1]
-      hist[i] = 0
-      bin_end = Math.min(bin_start+bin_size-1, bin_max)
-      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, {})
+    @hist_plot.update(data[0][0..data[0].length/FREQ_SLIDER_FACTOR], @fft_range[0], @fft_range[1])

   set_freq_range : (event, ui) ->
-    [min, max] = ui.values
+    [min, max] = @fft_range = ui.values
     @fft_plot.set_xrange(min, max)
     return null

@@ -185,6 +135,7 @@
     slider.css('float', 'left')
     slider.css('margin', '30px')
     controls.append(slider)
+    @fft_range = [FREQ_SLIDER_MIN, FREQ_SLIDER_MAX]

     slider = $('

')
     slider.append($("
gain:
"))
@@ -235,13 +186,12 @@
       @power_plot.render()
       @fft_plot.render()

-      div.append(@hist_view.$el)
-      @hist_view.render()
-      @hist_view.$el.css('float', 'left')
+      div.append(@hist_plot.view.$el)
+      @hist_plot.view.$el.css('float', 'left')
+      @hist_plot.render()
     _.defer(myrender)

   create_spec: () ->
-
     xrange = Collections('Range1d').create({start: 0, end: NGRAMS})
     yrange = Collections('Range1d').create({start: 0, end: MAX_FREQ})

@@ -298,20 +248,27 @@

     return plot_model

-
-  create_hist: () ->
-    plot_model = Collections('Plot').create()
-
-    range = Collections('Range1d').create({start: -20, end: 20})
-
-    plot_model = Collections('Plot').create(
-      x_range: range
-      y_range: range
+class RadialHistogramPlot
+  constructor: (options) ->
+    @num_bins = options.num_bins
+
+    @hist = new Float32Array(@num_bins)
+
+    @source = Collections('ColumnDataSource').create(
+      data: {inner_radius:[], outer_radius:[], start_angle:[], end_angle:[], fill_alpha: []}
+    )
+
+    @range = Collections('Range1d').create({start: -20, end: 20})
+
+    @model = Collections('Plot').create(
+      x_range: @range
+      y_range: @range
       border_fill: "#fff"
-      canvas_width: 500
-      canvas_height: 500
-      outer_width: 500
-      outer_height: 500
+      canvas_width:  options.width
+      canvas_height: options.height
+      outer_width:   options.width
+      outer_height:  options.height
+      border: 0
       tools: []
     )

@@ -327,15 +284,56 @@
       start_angle: 'start_angle'
       end_angle: 'end_angle'
     }
+
     glyph = Collections('GlyphRenderer').create({
-      data_source: @hist_source.ref()
-      xdata_range: range.ref()
-      ydata_range: range.ref()
+      data_source: @source
+      xdata_range: @range
+      ydata_range: @range
       glyphspec: glyphspec
     })
-    plot_model.add_renderers([glyph])
-
-    return plot_model
+
+    @model.add_renderers([glyph])
+    @view = new @model.default_view(model: @model)
+
+  update: (fft, fft_min, fft_max) ->
+    df = (FREQ_SLIDER_MAX - FREQ_SLIDER_MIN)
+
+    bin_min = Math.floor(fft_min/df)
+    bin_max = bin_min + Math.floor((fft_max-fft_min)/df * (fft.length-1))
+
+    bin_start = bin_min
+    bin_size = Math.ceil((bin_max - bin_min) / @num_bins)
+    for i in [0..@num_bins-1]
+      @hist[i] = 0
+      bin_end = Math.min(bin_start+bin_size-1, bin_max)
+      for j in [bin_start..bin_end]
+        @hist[i] += fft[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)
+
+    @source.set('data', {
+      inner_radius: inner, outer_radius: outer, start_angle: start, end_angle: end, fill_alpha: fill_alpha
+    })
+    @source.trigger('change', @source, {})
+
+  render: () ->
+    @view.render()

 class SimpleIndexPlot
@@ -410,10 +408,6 @@
   render: () ->
     @view.render()

-
-
-
-
 $(document).ready () ->
   spec = new SpectrogramApp()
   setInterval((() ->


ローカルサーバータスクの設定更新

ローカルサーバータスクの設定更新

--- root/Gruntfile.coffee
+++ root/Gruntfile.coffee
@@ -129,6 +129,7 @@
     connect:
       intermediate:
         options:
+          hostname: '0.0.0.0'
           port: 50000
           middleware: (connect, options) ->
             return [lrSnippet, folderMount(connect, '.intermediate')]


Fixed bug where partial device update from a faulty task gets committed in the next inform.

--- lib/update-device.coffee
+++ lib/update-device.coffee
@@ -116,7 +116,7 @@
         update['$set']["_customCommands.#{commandName}._timestamp"] = now

   processBatches = (cb) ->
-    if not commitQueue?
+    if not commitQueue
       processBatch(deviceUpdates) if deviceUpdates?
       return cb()


delete some done todo's

delete some done todo's

--- salvus/rethink.coffee
+++ salvus/rethink.coffee
@@ -993,7 +993,6 @@
         x = {}; x[opts.account_id] = {group:opts.group}
         @table('projects').get(opts.project_id).update(users:x).run(opts.cb)

-    # TODO: api change -- no longer give the group
     remove_user_from_project: (opts) =>
         opts = defaults opts,
             project_id : required
@@ -1124,8 +1123,6 @@

     # Gets all projects that the given account_id is a user on (owner,
     # collaborator, or viewer); gets columns data about them, not just id's
-    # TODO: API changes -- collabs are given only by account_id's now, so client code will
-    # need to change to reflect this. Which is better anyways.
     get_projects_with_user: (opts) =>
         opts = defaults opts,
             account_id       : required


weather in PLACE

weather in PLACE

--- botart.coffee
+++ botart.coffee
@@ -129,7 +129,21 @@
   message.say "I am learning to love."

 hear /help/, (message) ->
-  message.say "I listen for '@#{username} image me PHRASE' and '@#{username} wiki me PHRASE'"
+  message.say "I listen for '@#{username} image me PHRASE' and '@#{username} wiki me PHRASE' and '@#{username} weather in PLACE'"
+
+hear /weather in (.+)/i, (message) ->
+  place = message.match[1]
+  url   = "http://www.google.com/ig/api?weather=#{escape place}"
+
+  get url, (body) ->
+    try
+      console.log body
+      if match = body.match(/<current_conditions>(.+?)<\/current_conditions>/)
+        icon = match[1].match(/<icon data="(.+?)"/)
+        degrees = match[1].match(/<temp_f data="(\d+?)"/)
+        message.say "#{degrees[1]}° — http://www.google.com#{icon[1]}"
+    catch e
+      console.log "Weather error: " + e

 hear /wiki me (.*)/i, (message) ->
   term = escape(message.match[1])


Add curly brackets

Add curly brackets

--- scripts/bungie.coffee
+++ scripts/bungie.coffee
@@ -39,15 +39,17 @@
     else
       data['activityKey'] = activityKey

-    getPublicWeeklyActivity(res, data.activityKey).then (activityDetails) ->
+    getPublicWeeklyActivity(res, data.activityKey).then (activityDetails) -> {
+
       payload =
         message: res.message
         attachments: [dataHelper.parseActivityDetails(activityDetails)]

       robot.emit 'slack-attachment', payload
-
-    .fail (err) ->
+    }.fail (err) -> {
+
       sendError(robot, res, err)
+    }

     # # interprets input based on length
     # # if 3 elements, assume: gamertag, network, bucket


Clear up play command.

Clear up play command.

--- scripts/common.coffee
+++ scripts/common.coffee
@@ -17,7 +17,7 @@
         msg.send "You can find me on Twitter at http://twitter.com/masonest_ and on Facebook at http://facebook.com/masonest"

     robot.respond /(play|platforms)$/i, (msg) ->
-        msg.send "Want to join Masonest in game? Steam: Masonest & PSN: MasonestTV "
+        msg.send "Want to join Masonest in game? Steam — Masonest and PSN — MasonestTV "

     robot.respond /commands$/i, (msg) ->
         if robot.auth.hasRole(msg.envelope.user, ['admin', 'moderator'])


add anothert i\m out gif

add anothert i\m out gif

--- scripts/im-out.coffee
+++ scripts/im-out.coffee
@@ -1,6 +1,11 @@
+images = [
+  "http://i.imgur.com/XYfUN.gif",
+  "http://gifs.gifbin.com/062009/1245227615_colin_farrel.gif"
+]
+
 module.exports = (robot) ->
   robot.hear /i'm out/i, (msg) ->
-    msg.send "http://gifs.gifbin.com/062009/1245227615_colin_farrel.gif"
+    msg.send msg.random images
   robot.hear /tell (me|us) more/i, (msg) ->
     msg.send "http://mlkshk.com/r/BN75.gif"
   robot.hear /baws/i, (msg) ->


slight tweaks

slight tweaks

--- create_liar.coffee
+++ create_liar.coffee
@@ -57,18 +57,19 @@
   highest_index = 0
   # TODO perhaps use the funky coffescript Comprehensions here
   # to create a matches array
-  for property of lie
-    match = /callback_argument_(\d+)/.exec property
+
+  for property_name of lie
+    match = /callback_argument_(\d+)/.exec property_name
     if match?
       index = parseInt(match[1])-1
-      args[index] = lie[property].value
+      args[index] = lie[property_name].value
       highest_index = index if index > highest_index

   # fill em up
   for i in [0..highest_index]
     args[i] = null if not args[i]?

-  return  if args.length > 0 then args else null
+  if args.length > 0 then args else null

 arrays_equal = (a, b) ->
   for item, i in a


Filter saved scores into output.

Filter saved scores into output.

--- scripts/points.coffee
+++ scripts/points.coffee
@@ -114,6 +114,8 @@
                 # Winners is equal to one single string of points only
                 # robot.brain.set 'winners', points[username]

+                # Winners (and then recall) is equal to all users
+                # with points, and their points respectively.
                 robot.brain.set 'winners', points
     ), 60000

@@ -122,8 +124,10 @@
         if robot.auth.hasRole(msg.envelope.user, ['admin', 'moderator'])
             recall = robot.brain.get 'winners'

-            # savescore = ["#{username} has #{points[username]}" for username in recall]
-            # msg.send "Top points: #{savescore}"
+            savescore = ["#{username} has #{points[username]}" for username in recall]
+            msg.send "Top points: #{savescore}"
+
+            # Outputs an inspection of recall
             msg.send "#{Util.inspect(recall)}"

     # robot.respond /top (\d*)$/i, (msg) ->


Renamed a variable in a dashboard query

Renamed a variable in a dashboard query

--- admin/static/coffee/app.coffee
+++ admin/static/coffee/app.coffee
@@ -347,8 +347,8 @@

         num_connected_replicas: (table_status=driver.admin().table_status) ->
             table_status('shards')
-                .map((shard) ->
-                    shard('replicas').map((replica) ->
+                .map((shards) ->
+                    shards('replicas').map((replica) ->
                         replica('state').count((replica) ->
                             r.expr(['ready', 'looking_for_primary_replica']).contains(replica))
                     ).sum()


Add delay train to daily cron

Add delay train to daily cron

--- scripts/yamada.coffee
+++ scripts/yamada.coffee
@@ -122,6 +122,14 @@
         items.push($(this).text())
       callback(items)

+  getDelayedTrain = (callback) ->
+    cheerio-httpcli.fetch 'http://api.tetsudo.com/traffic/atom.xml?kanto', {}, (err, $, res)->
+      trains = []
+      $('entry > title').each ()->
+        if /JR東日本|東京メトロ|都営地下鉄|東武鉄道|西武鉄道|京成電鉄|京王電鉄|小田急電鉄|東急電鉄|京急電鉄|横浜市営地下鉄|りんかい線|つくばエクスプレス|ゆりかもめ|東京モノレール|日暮里・舎人ライナー/.test($(this).text())
+          trains.push($(this).text())
+      callback(trains)
+
   # example for calling API
   robot.respond /weather/i, (msg) ->
     getWeather (weathers) ->
@@ -146,11 +154,7 @@
     robot.send {room: "#general"}, msg.match[1].trim()

   robot.respond /train/i, (msg) ->
-    cheerio-httpcli.fetch 'http://api.tetsudo.com/traffic/atom.xml?kanto', {}, (err, $, res)->
-      trains = []
-      $('entry > title').each ()->
-        if /JR東日本|東京メトロ|都営地下鉄|東武鉄道|西武鉄道|京成電鉄|京王電鉄|小田急電鉄|東急電鉄|京急電鉄|横浜市営地下鉄|りんかい線|つくばエクスプレス|ゆりかもめ|東京モノレール|日暮里・舎人ライナー/.test($(this).text())
-          trains.push($(this).text())
+    getDelayedTrain (trains) ->
       if trains.length > 0
         msg.send "遅延してる電車な。"
         for train in trains
@@ -175,6 +179,13 @@
           message += "\n明日: #{weathers[1]['telop']}"
           message += " - 最高気温は#{weathers[1]['maxtemp']}度" if weathers[1]['maxtemp']?
           robot.send {room: ch}, message
+          getDelayedTrain (trains) ->
+            robot.send {room: ch}, "[電車遅延情報]"
+            if trains.length > 0
+              for train in trains
+                robot.send {room: ch}, "・#{train}"
+            else
+              robot.send {room: ch}, "遅延なし"
   , null, true, "Asia/Tokyo"

   new cron '00 30 17 * * 1-5', () ->


Add vmstat

Add vmstat

--- scripts/yamada.coffee
+++ scripts/yamada.coffee
@@ -29,6 +29,13 @@
      else
        res.send "YaMaDa"

+   robot.respond /vmstat/, (msg) ->
+     @exec = require('child_process').exec
+     @exec "vmstat", (error, stdout, stderr) ->
+       msg.send error if error?
+       msg.send stdout if stdout?
+       msg.send stderr if stderr?
+
    robot.hear /Good night/i, (res) ->
      res.emote "Have a good night"


event: default inviterJoinDay to undefined

--- services/event.coffee
+++ services/event.coffee
@@ -19,7 +19,7 @@
         uaDeviceModel: parser.getDevice().model
         language: negotiator.language()
         joinDay: String user.joinDay
-        inviterJoinDay: String(user.inviterJoinDay) or undefined
+        inviterJoinDay: String(user.inviterJoinDay or '') or undefined
         sessionEvents: String user.sessionEvents
       }, experimentGroups
     .then (tags) ->


Adds stuff

Adds stuff

--- api/apps/articles/model.coffee
+++ api/apps/articles/model.coffee
@@ -296,7 +296,7 @@
       credit_line: article.email_metadata?.credit_line
       credit_url: article.email_metadata?.credit_url
   , (err, response) =>
-    console.log response
+    return err if err

 # After merging article & input


Scroll window top on orientation change.

--- app/client/js/react/app.coffee
+++ app/client/js/react/app.coffee
@@ -1,5 +1,7 @@
 goog.provide 'app.react.App'

+goog.require 'goog.dom'
+goog.require 'goog.events'
 goog.require 'goog.net.HttpStatus'

 class app.react.App
@@ -34,4 +36,13 @@
           when routes.home then home
           when routes.myNewSong, routes.editMySong then editSong
           when routes.mySong then song
-          when routes.notFound then notFound+          when routes.notFound then notFound
+
+      componentDidMount: ->
+        goog.events.listen window, 'orientationchange', @onOrientationChange
+
+      onOrientationChange: (e) ->
+        @scrollWindowTop()
+
+      scrollWindowTop: ->
+        goog.dom.getDocumentScrollElement().scrollTop = 0


don't log errors from redis backend

don't log errors from redis backend

this also picks up errors from RedisManager like "doc ops range is not
loaded in redis"

--- app/coffee/RedisBackend.coffee
+++ app/coffee/RedisBackend.coffee
@@ -100,7 +100,8 @@
 					cb(error, result)
 		async.parallel jobs, (error, results) ->
 			if error?
-				logger.error {err: error}, "error in redis backend"
+				# suppress logging of errors
+				# logger.error {err: error}, "error in redis backend"
 			else
 				compareResults(results, "exec")
 			callback(primaryError, primaryResult)


added some other cases

added some other cases

--- node-type.coffee
+++ node-type.coffee
@@ -29,4 +29,6 @@
   'ProtoMemberAccessOp'
   'DivideOp'
   'SubtractOp'
+  'PlusOp'
+  'InOp'
 }