# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

roundUpBy = (value, round_to) ->
  return round_to * Math.ceil(value / round_to)

$ ->
  animateMetric = $(".metric-box strong").each (index) ->
    $this = $(this)
    starting_point = 0
    $target_count = parseInt($this.text().replace(/\,/g, ''))

    $this.counter = starting_point

    tween = createjs.Tween.get($this).to( {counter: $target_count}, (1200 + index * 800) , createjs.Ease.quintOut)

    tween.addEventListener 'change', (event) ->
      # if the number is under 90 of the target, increment number by thousands
      if $this.counter < $target_count * 0.7
        $this.counter = roundUpBy($this.counter, 1000)
      else if $this.counter < $target_count * 0.8
        $this.counter = roundUpBy($this.counter, 100)
      else if $this.counter < $target_count * 0.99
        $this.counter = roundUpBy($this.counter, 10)
      $this.text(Math.round($this.counter).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","))
      return

# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

roundUpBy = (value, round_to) ->
  return round_to * Math.ceil(value / round_to)

$ ->
  animateMetric = $(".metric-box strong").each (index) ->
    $this = $(this)
    starting_point = 0
    $target_count = parseInt($this.text().replace(/\,/g, ''))

    $this.counter = starting_point

    tween = createjs.Tween.get($this).to( {counter: $target_count}, (1000 + index * 400) , createjs.Ease.quintOut)

    tween.addEventListener 'change', (event) ->
      # if the number is under 90 of the target, increment number by thousands
      if $this.counter < $target_count * 0.7
        $this.counter = roundUpBy($this.counter, 1000)
      else if $this.counter < $target_count * 0.8
        $this.counter = roundUpBy($this.counter, 100)
      else if $this.counter < $target_count * 0.99
        $this.counter = roundUpBy($this.counter, 10)
      $this.text(Math.round($this.counter).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","))
      return

Reduce the animation duration more

Reduce the animation duration more


Impromptu = require './impromptu'

class Cacheable
  constructor: (@impromptu, @name, @options) ->
  run: (fn) => throw Impromptu.AbstractError
  get: (fn) -> throw Impromptu.AbstractError
  set: (fn) -> throw Impromptu.AbstractError
  unset: (fn) -> throw Impromptu.AbstractError

# Expose `Cacheable`.
exports = module.exports = Cacheable

Impromptu = require './impromptu'

# An abstract class that manages how a method is cached.
class Cacheable
  constructor: (@impromptu, @name, @options) ->

  # The main method.
  #
  # Accepts a `fn` with a signature of `err, results`, where `results` is the
  # cached value. Optionally updates the cache.
  #
  # This should be bound to the instance so the method can be passed around
  # without the instance.
  run: (fn) => throw Impromptu.AbstractError

  # Gets the cached value.
  #
  # Accepts a `fn` with a signature of `err, results`, where `results` is the
  # cached value. Does not update the cache.
  get: (fn) -> throw Impromptu.AbstractError

  # Updates the cached value.
  #
  # Accepts a `fn` with a signature of `err, success`, where `success` is a
  # boolean indicating whether the cached value was updated.
  set: (fn) -> throw Impromptu.AbstractError

  # Clears the cached value.
  #
  # Accepts a `fn` with a signature of `err, success`, where `success` is a
  # boolean indicating whether the value was removed from the cache.
  unset: (fn) -> throw Impromptu.AbstractError

# Expose `Cacheable`.
exports = module.exports = Cacheable

Document the abstract Cacheable class.

Document the abstract Cacheable class.


Steam.ScoringListView = (_) ->
  _items = do nodes$

  #TODO ugly
  _isLive = node$ yes

  activateItem = (item) ->
    for other in _items()
      if other is item
        other.isActive yes
      else
        other.isActive no

    _.displayScoring item.data

  createItem = (scoring) ->
    #TODO replace with type checking
    self =
      data: scoring
      title: scoring.frameKey
      caption: describeCount scoring.scores.length, 'model'
      cutline: new Date(scoring.timestamp).toString()
      display: -> activateItem self
      isActive: node$ no
      isSelected: node$ no

    apply$ _isLive, self.isSelected, (isLive, isSelected) ->
      _.scoringSelectionChanged isSelected, _predicate, scoring if isLive
    self

  displayScorings = (scorings) ->
    _items items = map scorings, createItem
    activateItem head items unless isEmpty items

  _predicate = null
  loadScorings = (predicate) ->
    console.assert isDefined predicate
    _predicate = predicate

    pastScorings = (_.getFromCache 'scoring') or _.putIntoCache 'scoring', []
    if predicate.type is 'scoring'
      pastScorings.unshift predicate.scoring

    displayScorings pastScorings

    return

  link$ _.loadScorings, loadScorings
  link$ _.deselectAllScorings, ->
    #TODO ugly
    _isLive no
    for item in _items()
      item.isSelected no
    _isLive yes

  items: _items
  template: 'scoring-list-view'

Steam.ScoringListView = (_) ->
  _items = do nodes$
  _hasItems = lift$ _items, (items) -> items.length > 0

  #TODO ugly
  _isLive = node$ yes

  activateItem = (item) ->
    for other in _items()
      if other is item
        other.isActive yes
      else
        other.isActive no

    _.displayScoring item.data

  createItem = (scoring) ->
    #TODO replace with type checking
    self =
      data: scoring
      title: scoring.frameKey
      caption: describeCount scoring.scores.length, 'model'
      cutline: new Date(scoring.timestamp).toString()
      display: -> activateItem self
      isActive: node$ no
      isSelected: node$ no

    apply$ _isLive, self.isSelected, (isLive, isSelected) ->
      _.scoringSelectionChanged isSelected, _predicate, scoring if isLive
    self

  displayScorings = (scorings) ->
    _items items = map scorings, createItem
    if isEmpty items
      _.displayEmpty()
    else
      activateItem head items

  _predicate = null
  loadScorings = (predicate) ->
    console.assert isDefined predicate
    _predicate = predicate

    pastScorings = (_.getFromCache 'scoring') or _.putIntoCache 'scoring', []
    if predicate.type is 'scoring'
      pastScorings.unshift predicate.scoring

    displayScorings pastScorings

    return

  link$ _.loadScorings, loadScorings
  link$ _.deselectAllScorings, ->
    #TODO ugly
    _isLive no
    for item in _items()
      item.isSelected no
    _isLive yes

  items: _items
  hasItems: _hasItems
  template: 'scoring-list-view'

Handle empty scoring lists properly PP-8


Template.date.helpers

Template.date.rendered = ->
  template = @
  $editor = template.$("input")
  $editor.datepicker(
    changeMonth: true
    changeYear: true
    dateFormat: "yy/mm/dd"
    constrainInput: false
    onSelect: (date) ->
      $set = {}
      $set[template.data.property] = date
      editor = share.EditorCache.editors[template.data.family]
      editor.collection.update(template.data._id, {$set: $set})
  )
  $editor.datepicker("setDate", @data.value)

Template.date.events

Template.date.helpers

Template.date.rendered = ->
  template = @
  $editor = template.$("input")
  $editor.datepicker(
    changeMonth: true
    changeYear: true
    dateFormat: "yy/mm/dd"
    constrainInput: false
    onSelect: (date) ->
      $set = {}
      $set[template.data.property] = date
      editor = share.EditorCache.editors[template.data.family]
      editor.collection.update(template.data._id, {$set: $set})
  )
  date = @data.value.replace(/\:.+$/i, "") # actually, the format is yy/mm/dd:hh, but ":hh" part should be stripped for datepicker
  $editor.datepicker("setDate", date)
  $editor.val(@data.value)

Template.date.events

Fix date with hours display

Fix date with hours display


###
# # Write JSON File Tree
###

fs = require 'fs'
path = require 'path'
through = require 'through2'

log = require '../utils/log'

module.exports = (fileName, opts={}) ->
  unless fileName
    throw new PluginError("Render File Tree", "Missing fileName option")

  filePrefix = opts.filePrefix or "window.#{opts.varName or 'files'} = [\n"
  fileSuffix = opts.fileSuffix or "\n];"

  output = fs.createWriteStream(fileName)
  output.write filePrefix
  first = true

  bufferContents = (file, enc, cb) ->
    output.write (if first then '' else ',\n') + JSON.stringify({
      path: file.relative
      originalName: path.basename file.originalPath
      originalPath: file.originalRelative
      name: path.basename file.path
      lang: file.extra?.lang?.highlightJS or file.extra?.lang?.pygmentsLexer
      title: file.extra?.toc?[0]?.title
      toc: file.extra?.toc
    }, false, 2)
    first = false

    cb null, file

  endStream = (cb) ->
    output.write fileSuffix
    if opts.verbose
      log "File tree written to #{path.basename fileName}"
    cb()

  through.obj bufferContents, endStream

###
# # Write JSON File Tree
###

fs = require 'fs'
path = require 'path'
through = require 'through2'
_ = require 'lodash'

log = require '../utils/log'

module.exports = (fileName, opts={}) ->
  unless fileName
    throw new PluginError("Render File Tree", "Missing fileName option")

  filePrefix = opts.filePrefix or "window.#{opts.varName or 'files'} = [\n"
  fileSuffix = opts.fileSuffix or "\n];"

  output = fs.createWriteStream(fileName)
  output.write filePrefix
  first = true

  bufferContents = (file, enc, cb) ->
    output.write (if first then '' else ',\n') + JSON.stringify({
      path: file.relative
      originalName: path.basename file.originalPath
      originalPath: file.originalRelative
      name: path.basename file.path
      lang: file.extra?.lang?.highlightJS or file.extra?.lang?.pygmentsLexer
      title: _.find(file.extra?.toc, level: 1)?.title
      toc: file.extra?.toc
    }, false, 2)
    first = false

    cb null, file

  endStream = (cb) ->
    output.write fileSuffix
    if opts.verbose
      log "File tree written to #{path.basename fileName}"
    cb()

  through.obj bufferContents, endStream

Choose First h1 for File Title

Choose First h1 for File Title


{EditorView, ScrollView} = require 'atom'

module.exports =
class MinimapEditorView extends ScrollView

  @content: ->
    @div class: 'minimap-editor editor editor-colors', =>
      @div class: 'scroll-view', outlet: 'scrollView', =>
        @div class: 'lines', outlet: 'lines'

  initialize: ->
    super

  update: (@editorView) ->
    start = Date.now()

    @lines.html ''
    console.log('cleaning time:', (Date.now() - start) + 'ms')
    # FIXME: If the file is very large, the tokenizes doesn't generate
    # completely, so doesn't have the syntax highlight until a new view
    # is activated in the same pane.
    numLines = @editorView.getModel().displayBuffer.getLines().length
    lines = @editorView.buildLineElementsForScreenRows(0, numLines)

    @lines.append lines
    @lines.css fontSize: "#{@editorView.getFontSize()}px"

    console.log('Update MinimapEditorView response time:', (Date.now() - start) + 'ms')

  getClientRect: ->
    sv = @scrollView[0]
    {
      width: sv.scrollWidth,
      height: sv.scrollHeight
    }

{EditorView, ScrollView, $} = require 'atom'

module.exports =
class MinimapEditorView extends ScrollView

  @content: ->
    @div class: 'minimap-editor editor editor-colors', =>
      @div class: 'scroll-view', outlet: 'scrollView', =>
        @div class: 'lines', outlet: 'lines', =>
          @div class: 'lines-wrapper'

  initialize: ->
    super

  update: (@editorView) ->
    start = Date.now()

    @lines[0].removeChild(@lines[0].childNodes[0])
    @lines.css fontSize: "#{@editorView.getFontSize()}px"

    console.log('cleaning:', (Date.now() - start) + 'ms')
    # FIXME: If the file is very large, the tokenizes doesn't generate
    # completely, so doesn't have the syntax highlight until a new view
    # is activated in the same pane.
    numLines = @editorView.getModel().displayBuffer.getLines().length
    lines = @editorView.buildLineElementsForScreenRows(0, numLines)
    console.log(' build lines:', (Date.now() - start) + 'ms')
    wrapper = $('<div/>')
    wrapper.append lines
    @lines.append wrapper

    console.log('Update MinimapEditorView response time:', (Date.now() - start) + 'ms')

  getClientRect: ->
    sv = @scrollView[0]
    {
      width: sv.scrollWidth,
      height: sv.scrollHeight
    }

Optimize minimap update by removing a wrapper instead of all lines


Marbles.Views.PermissionsFieldsToggle = class PermissionsFieldsToggleView extends TentStatus.View
  @template_name: 'permissions_fields_toggle'
  @view_name: 'permissions_fields_toggle'

  constructor: ->
    super

    @once 'ready', =>
      setImmediate @bindEvents

    @render()

  context: (permissions = @parentView()?.post()?.get('permissions')) =>
    _.extend super,
      permissions: permissions

  permissionsFieldsView: =>
    _.last(@parentView()?.childViews('PermissionsFields') || [])

  bindEvents: =>
    permissions_fields_view = @permissionsFieldsView()
    return unless permissions_fields_view

    permissions_fields_view.on 'change:options', =>
      permissions = permissions_fields_view.buildPermissions()
      @render(@context(permissions))

    @text ?= {}
    @text.visibility_toggle = {
      show: Marbles.DOM.attr(@el, 'data-show-text')
      hide: Marbles.DOM.attr(@el, 'data-hide-text')
    }

    Marbles.DOM.on @el, 'click', (e) =>
      e.stopPropagation()
      @toggleVisibility()

  toggleVisibility: =>
    if @visible
      @hide()
    else
      @show()

  hide: =>
    @visible = false
    @permissionsFieldsView()?.hide()

  show: (should_focus = true) =>
    @visible = true
    @permissionsFieldsView()?.show()

Marbles.Views.PermissionsFieldsToggle = class PermissionsFieldsToggleView extends TentStatus.View
  @template_name: 'permissions_fields_toggle'
  @view_name: 'permissions_fields_toggle'

  constructor: ->
    super

    @once 'ready', =>
      setImmediate @bindEvents

    @render()

  context: (permissions) =>
    permissions ?= @parentView()?.post()?.get('permissions')
    permissions ?= { public: true }
    _.extend super,
      permissions: permissions

  permissionsFieldsView: =>
    _.last(@parentView()?.childViews('PermissionsFields') || [])

  bindEvents: =>
    permissions_fields_view = @permissionsFieldsView()
    return unless permissions_fields_view

    permissions_fields_view.on 'change:options', =>
      permissions = permissions_fields_view.buildPermissions()
      @render(@context(permissions))

    @text ?= {}
    @text.visibility_toggle = {
      show: Marbles.DOM.attr(@el, 'data-show-text')
      hide: Marbles.DOM.attr(@el, 'data-hide-text')
    }

    Marbles.DOM.on @el, 'click', (e) =>
      e.stopPropagation()
      @toggleVisibility()

  toggleVisibility: =>
    if @visible
      @hide()
    else
      @show()

  hide: =>
    @visible = false
    @permissionsFieldsView()?.hide()

  show: (should_focus = true) =>
    @visible = true
    @permissionsFieldsView()?.show()

Fix permissions toggle label for new posts


class Views.Application extends View
  @content: ->
    @div id: 'application', class: 'container', =>
      @div class: 'navbar navbar-fixed-top navbar-inverse', =>
        @div class: 'navbar-inner', =>
          @div class: 'container', =>
            @a "Hyperarchy", class: 'brand', href: '/'
            @ul class: 'nav pull-right', =>
              @li =>
                @button "New Question", class: 'btn btn-primary', click: 'showNewQuestionForm'
      @subview 'questionsList', new Views.RelationView(
        tag: 'div'
        attributes: { id: 'questions' }
        buildItem: (question) ->
          new Views.QuestionView(question)
      )

  initialize: ->
    Monarch.Remote.Server.fetch([Models.User, Models.Question, Models.Answer, Models.Ranking, Models.Vote, Models.QuestionComment])
      .onSuccess =>
        @questionsList.setRelation(Models.Question.table)
        @buildAndStartRouter()

  buildAndStartRouter: ->
    view = this
    Davis ->
      @configure ->
        @generateRequestOnPageLoad = true
      @get '/:questionId', ({params}) ->
        view.showQuestion(params.questionId)

  showQuestion: (id) ->
    questionView = @questionsList.find(".question[data-question-id=#{id}]")
    $.scrollTo(questionView, offset: -60) if questionView.length

  showNewQuestionForm: ->
    new Views.ModalForm(
      headingText: "Ask an open-ended question:"
      buttonText: "Ask Question"
      onSubmit: (body) =>
        Models.Question.create({body})
    )

class Views.Application extends View
  @content: ->
    @div id: 'application', =>
      @div class: 'navbar navbar-fixed-top navbar-inverse', =>
        @div class: 'navbar-inner', =>
          @div class: 'container', =>
            @a "Hyperarchy", class: 'brand', href: '/'
            @ul class: 'nav pull-right', =>
              @li =>
                @button "New Question", class: 'btn btn-primary', click: 'showNewQuestionForm'
      @subview 'questionsList', new Views.RelationView(
        tag: 'div'
        attributes: { id: 'questions', class: 'container' }
        buildItem: (question) ->
          new Views.QuestionView(question)
        )

  initialize: ->
    Monarch.Remote.Server.fetch([Models.User, Models.Question, Models.Answer, Models.Ranking, Models.Vote, Models.QuestionComment])
      .onSuccess =>
        @questionsList.setRelation(Models.Question.table)
        @buildAndStartRouter()

  buildAndStartRouter: ->
    view = this
    Davis ->
      @configure ->
        @generateRequestOnPageLoad = true
      @get '/:questionId', ({params}) ->
        view.showQuestion(params.questionId)

  showQuestion: (id) ->
    questionView = @questionsList.find(".question[data-question-id=#{id}]")
    $.scrollTo(questionView, offset: -60) if questionView.length

  showNewQuestionForm: ->
    new Views.ModalForm(
      headingText: "Ask an open-ended question:"
      buttonText: "Ask Question"
      onSubmit: (body) =>
        Models.Question.create({body})
    )

Fix title bar appearance at smaller screen widths


H2O.StackTraceOutput = (_, _stackTrace) ->
  _activeNode = signal null

  createThread = (thread) ->
    lines = split thread, '\n'

    title: head lines
    stackTrace: join (tail lines), '\n'

  createNode = (node) ->
    display = -> _activeNode self

    self =
      name: node._node
      timestamp: new Date node._time
      threads: (createThread thread for thread in node._traces)
      display: display

  _nodes = for node in _stackTrace.traces
    createNode node

  _activeNode head _nodes

  nodes: _nodes
  activeNode: _activeNode
  template: 'flow-stacktrace-output'

H2O.StackTraceOutput = (_, _stackTrace) ->
  _activeNode = signal null

  createThread = (thread) ->
    lines = split thread, '\n'

    title: head lines
    stackTrace: join (tail lines), '\n'

  createNode = (node) ->
    display = -> _activeNode self

    self =
      name: node.node
      timestamp: new Date node.time
      threads: (createThread thread for thread in node.thread_traces)
      display: display

  _nodes = for node in _stackTrace.traces
    createNode node

  _activeNode head _nodes

  nodes: _nodes
  activeNode: _activeNode
  template: 'flow-stacktrace-output'

Fix stack trace processing to match refactored API PUBDEV-371


Controller = require 'lib/controller'
User = require 'models/user'
FirstUserView = require 'views/install/firstuser'

mediator = require('chaplin').mediator

module.exports = class InstallController extends Controller

  firstuser: ->
    @adjustTitle 'Install'

    newUser = new User

    @view = new FirstUserView
      model: newUser

    newUser.on 'sync', =>
      mediator.options.needsInstall = no
      @redirectTo url: '/'

Controller = require 'lib/controller'
User = require 'models/user'
FirstUserView = require 'views/install/firstuser'

mediator = require('chaplin').mediator

module.exports = class InstallController extends Controller

  firstuser: ->
    @adjustTitle 'Install'

    newUser = new User
      roles: [{name: 'administrator'}]

    @view = new FirstUserView
      model: newUser

    newUser.on 'sync', =>
      mediator.options.needsInstall = no
      @redirectTo url: '/'

Make the first installed user an administrator by default


define [
    '../core'
    './index'
    './search'
    'tpl!templates/concept/panel.html'
], (c, index, search, templates...) ->

    templates = c._.object ['panel'], templates

    class ConceptSearch extends search.ConceptSearch
        events:
            'typeahead:autocompleted input': 'autocomplete'

        autocomplete: (event, datum) ->
            c.publish c.CONCEPT_FOCUS, datum.id

    class ConceptPanel extends c.Marionette.Layout
        className: 'concept-panel'

        template: templates.panel

        regions:
            search: '.search-region'
            index: '.index-region'

        onRender: ->
            @index.show new index.ConceptIndex
                collection: @collection
                collapsable: false

            @search.show new ConceptSearch
                collection: @collection
                handler: (query, resp) =>
                    @index.currentView.filter(query, resp)

            # Defer focus of concept search until end of event loop
            c._.defer =>
                @search.currentView.ui.input.focus()

    { ConceptPanel }

define [
    '../core'
    './index'
    './search'
    'tpl!templates/concept/panel.html'
], (c, index, search, templates...) ->

    templates = c._.object ['panel'], templates

    class ConceptSearch extends search.ConceptSearch
        events:
            'typeahead:autocompleted input': 'autocomplete'

        autocomplete: (event, datum) ->
            c.publish c.CONCEPT_FOCUS, datum.id

    # Takes a collection of c.models.ConceptModel objects
    class ConceptPanel extends c.Marionette.Layout
        className: 'concept-panel'

        template: templates.panel

        # Two primary regions for the concept panel including the search
        # and the index (listing) of concepts
        regions:
            search: '.search-region'
            index: '.index-region'

        onRender: ->
            # Pass the collection of concepts to be rendered in the index
            @index.show new index.ConceptIndex
                collection: @collection
                collapsable: false

            # When a search occurs, the index is filtered relative to the
            # response which contains a listing of IDs that the search
            # has matched.
            @search.show new ConceptSearch
                collection: @collection
                handler: (query, resp) =>
                    @index.currentView.filter(query, resp)

            # Defer focus of concept search until end of event loop
            c._.defer =>
                @search.currentView.ui.input.focus()

    { ConceptPanel }

Add comments to ConceptPanel for clarity of implementation


fs = require('fs')
instanceLookup = require('../../lib/instance-lookup')

getConfig = ->
  server: JSON.parse(fs.readFileSync(process.env.HOME + '/.tedious/test-connection.json', 'utf8')).config.server
  instanceName: JSON.parse(fs.readFileSync(process.env.HOME + '/.tedious/test-connection.json', 'utf8')).instanceName

exports.goodInstance = (test) ->
  config = getConfig()

  callback = (err, port) ->
    test.ok(!err)
    test.ok(port)

    test.done()

  instanceLookup(config.server, config.instanceName, callback)

exports.badInstance = (test) ->
  config = getConfig()

  callback = (err, port) ->
    test.ok(err)
    test.ok(!port)

    test.done()

  instanceLookup(config.server, 'badInstanceName', callback)

exports.badServer = (test) ->
  config = getConfig()

  callback = (err, port) ->
    test.ok(err)
    test.ok(!port)

    test.done()

  instanceLookup('badServer', config.instanceName, callback)

fs = require('fs')
instanceLookup = require('../../lib/instance-lookup')

getConfig = ->
  server: JSON.parse(fs.readFileSync(process.env.HOME + '/.tedious/test-connection.json', 'utf8')).config.server
  instanceName: JSON.parse(fs.readFileSync(process.env.HOME + '/.tedious/test-connection.json', 'utf8')).instanceName

exports.goodInstance = (test) ->
  config = getConfig()

  if !config.instanceName
    # Config says don't do this test (probably because SQL Server Browser is not available).
    console.log('Skipping goodInstance test')
    test.done()
    return

  callback = (err, port) ->
    test.ok(!err)
    test.ok(port)

    test.done()

  instanceLookup(config.server, config.instanceName, callback)

exports.badInstance = (test) ->
  config = getConfig()

  callback = (err, port) ->
    test.ok(err)
    test.ok(!port)

    test.done()

  instanceLookup(config.server, 'badInstanceName', callback)

exports.badServer = (test) ->
  config = getConfig()

  callback = (err, port) ->
    test.ok(err)
    test.ok(!port)

    test.done()

  instanceLookup('badServer', config.instanceName, callback)

Allow integration test looking up by instance name to be bypassed (if SQL Server Browser not available).


Promise = require 'bluebird'
fs = Promise.promisifyAll require 'fs'
_ = require 'lodash'

module.exports = () ->

        # For performance reasons, we'll do this asynchronously.
        fs.readdirAsync('./controllers/').then (controllers) ->

                #This probably isn't necessary: I wanted to parse through and grab all these controllers
                # asynchronously, so I threw them in a promise
                makeAsyncControllerParse = (file) ->
                        return new Promise (resolve, reject) ->
                                if file.match(/.+\.js/g) != null || file.match(/.+\.coffee/g) != null
                                        # When requiring the module, we don't really want to specify an extension.
                                        # Let's get rid of it.
                                        myObject = {}
                                        name = file.replace('.js', '').replace('.coffee', '')

                                        # Require the controller, feed it into the controllers
                                        myObject[name] = require "../controllers/#{name}"
                                        resolve(myObject)

                # Create a big ol' object of all the promises so that we have a handle on all the files.
                #
                # We're utilizing lodash's "chain" function simply because it gives us somewhat sane list
                # comprehension comparable to linq.
                promiseObject =
                        do
                                _.chain controllers
                                .map makeAsyncControllerParse
                                .reduce _.extend
                                .value

                # Once everything is done from above, we return back the collective promise object and
                # pipe that to whomever feels fit.
                return Promise.props promiseObject

Promise = require 'bluebird'
fs = Promise.promisifyAll require 'fs'
_ = require 'lodash'

module.exports = () ->

	# For performance reasons, we'll do this asynchronously.
	fs.readdirAsync('./controllers/').then (controllers) ->

		#This probably isn't necessary: I wanted to parse through and grab all these controllers
		# asynchronously, so I threw them in a promise
		makeAsyncControllerParse = (file) ->
			return new Promise (resolve, reject) ->
				if file.match(/.+\.js/g)? or file.match(/.+\.coffee/g)?
					# When requiring the module, we don't really want to specify an extension.
					# Let's get rid of it.
					myObject = {}
					name = file.replace('.js', '').replace('.coffee', '')

					# Require the controller, feed it into the controllers
					myObject[name] = require "../controllers/#{name}"
					resolve(myObject)

		# Create a big ol' object of all the promises so that we have a handle on all the files.
		#
		# We're utilizing lodash's "chain" function simply because it gives us somewhat sane list
		# comprehension comparable to linq.
		promiseObject =
			do
				_.chain controllers
				.map makeAsyncControllerParse
				.reduce _.extend
				.value

		# Once everything is done from above, we return back the collective promise object and
		# pipe that to whomever feels fit.
		return Promise.props promiseObject

Convert to using tabs so as to allow editor diversity.


window.LC = window.LC ? {}

slice = Array.prototype.slice

LC.util =
  last: (array, n = null) ->
    if n
      return slice.call(array, Math.max(array.length - n, 0))
    else
      return array[array.length - 1]

  sizeToContainer: (canvas, callback = ->) ->
    $canvas = $(canvas)
    $container = $canvas.parent()
    resize = =>
      canvas.style.height = "#{$container.height()}px"
      canvas.setAttribute('width', $canvas.width())
      canvas.setAttribute('height', $canvas.height())
      callback()

    $container.resize(resize)
    $(window).bind('orientationchange resize', resize)
    resize()

  combineCanvases: (a, b) ->
    c = $('<canvas>').get(0)
    c.width = Math.max(a.width, b.width)
    c.height = Math.max(a.height, b.height)
    ctx = c.getContext('2d')
    ctx.drawImage(a, 0, 0)
    ctx.drawImage(b, 0, 0)
    c

window.LC = window.LC ? {}

slice = Array.prototype.slice

LC.util =
  last: (array, n = null) ->
    if n
      return slice.call(array, Math.max(array.length - n, 0))
    else
      return array[array.length - 1]

  sizeToContainer: (canvas, callback = ->) ->
    $canvas = $(canvas)
    $container = $canvas.parent()
    resize = =>
      canvas.style.width = "#{$container.width()}px"
      canvas.style.height = "#{$container.height()}px"
      canvas.setAttribute('width', $canvas.width())
      canvas.setAttribute('height', $canvas.height())
      callback()

    $container.resize(resize)
    $(window).bind('orientationchange resize', resize)
    resize()

  combineCanvases: (a, b) ->
    c = $('<canvas>').get(0)
    c.width = Math.max(a.width, b.width)
    c.height = Math.max(a.height, b.height)
    ctx = c.getContext('2d')
    ctx.drawImage(a, 0, 0)
    ctx.drawImage(b, 0, 0)
    c

Fix sizeToContainer - actually set width


BaseTool = window.Ubret.BaseTool or require('./base_tool')

class SubjectViewer extends BaseTool
  name: 'Subject Viewer'
  template:
    """

      <% for(i = 0; i < keys.length; i++) { %>

          <%- keys[i] %>: <%- subject[keys[i]] %>

      <% } %>

    """

  start: =>
    # data = @dimensions.id.top(Infinity)
    unless @selectedElements
      subject = @data[0]
      # subject = data[0]
    else
      subject = _.find data, (record) =>
        record.id == @selectedElements[0]

    compiled = _.template @template, { subject: subject, keys: @keys }
    @el.html compiled

if typeof require is 'function' and typeof module is 'object' and typeof exports is 'object'
  module.exports = SubjectViewer
else
  window.Ubret['SubjectViewer'] = SubjectViewer

BaseTool = window.Ubret.BaseTool or require('./base_tool')

class SubjectViewer extends BaseTool

  constructor: (opts) ->
    super
    @count = 0
    @div = d3.select(@selector)
    @start()

  start: =>
    subjects = new Array
    if @selectedElements.length isnt 0
      subjects = @dimensions.uid.top(Infinity).filter (item) =>
        item.uid in @selectedElements
    else
      subjects = [@dimensions.uid.top(1)[0]]
      @selectElements subjects
    @render(subjects)

  render: (subjects) =>
    @div.selectAll('div.subject').remove()

    subject = @div.selectAll('div')
      .data(subjects).enter()
        .append('div')
        .attr('class', 'subject')

    subject.selectAll('img')
      .append('img')
        .attr('src', (d) -> d.image)

    subject.selectAll('ul')
      .append('ul')
      .data((d) => @toArray(d)).enter()
        .append('li')
        .attr('data-key', (d) -> d[0])
        .text((d) => "#{@formatKey(d[0])}: #{d[1]}")

    subject.select("[data-key=\"#{@selectedKey}\"]")
      .attr('class', 'selected')

  toArray: (data) =>
    arrayedData = new Array
    arrayedData.push [key, data[key]] for key in @keys
    arrayedData

if typeof require is 'function' and typeof module is 'object' and typeof exports is 'object'
  module.exports = SubjectViewer
else
  window.Ubret['SubjectViewer'] = SubjectViewer

Revert to multi-select version of subejct_viewer


$(document).load ->
  readyMenuToggle()
  registerJobPriority()

$(document).on 'ready page:change', ->
  readyMenuToggle()
  registerJobPriority()

readyMenuToggle = ->
  $('#menu-toggle').click (e) ->
    e.preventDefault()
    $('#wrapper').toggleClass 'toggled'

  $('#menu-close').click (e) ->
    e.preventDefault()
    $('#wrapper').toggleClass 'toggled'

registerJobPriority = ->
  $('#increase_priority').on 'click', ->
    $('#job_priority').val(parseInt($('#job_priority').val(), 10) + 1)

  $('#decrease_priority').on 'click', ->
    console.log 'decreasing'
    $('#job_priority').val(parseInt($('#job_priority').val(), 10) - 1)

$(document).load ->
  readyMenuToggle()
  registerJobPriority()

$(document).on 'ready page:change', ->
  readyMenuToggle()
  registerJobPriority()

readyMenuToggle = ->
  $('#menu-toggle').click (e) ->
    e.preventDefault()
    $('#wrapper').toggleClass 'toggled'

  $('#menu-close').click (e) ->
    e.preventDefault()
    $('#wrapper').toggleClass 'toggled'

registerJobPriority = ->
  $('#increase_priority').on 'click', ->
    $('#job_priority').val(parseInt($('#job_priority').val(), 10) + 1)

  $('#decrease_priority').on 'click', ->
    $('#job_priority').val(parseInt($('#job_priority').val(), 10) - 1)

Remove console log message from decrease job priority button.


googleTranslate = new practical.GoogleTranslate()

Tinytest.add 'Google Translate - should translate text' , (test)->
  translation = googleTranslate.translate("My name is Brandon", "es")
  expect(translation).to.be.an("Object")
  expect(translation.translatedText).to.equal("Mi Nombre Es Brandon")

googleTranslate = new practical.GoogleTranslate()

Tinytest.add 'Google Translate - should translate text' , (test)->
  translation = googleTranslate.translate("my name is Brandon", "es")
  expect(translation).to.be.an("Object")
  expect(translation.translatedText).to.equal("mi nombre es Brandon")

Tinytest.add 'Google Translate - should translate text with multiple lines' , (test)->
  translation = googleTranslate.translate("my name is Brandon\ni like apples\n", "es")
  expect(translation).to.be.an("Object")
  expect(translation.translatedText).to.equal("mi nombre es Brandon me gusta manzanas")

Add test for multiple lines translation

Add test for multiple lines translation


require 'should'

Base58 = require '..'

examples = require './examples'

describe 'Base58', ->
  describe '.encode', ->
    it 'encodes number to Base58 string', ->
      for str, num of examples
        Base58.encode(num).should.eql(str)

    describe 'when passed a string only containing numbers', ->
      it 'encodes string after first converting it to an integer', ->
        for str, num of examples
          Base58.encode(num.toString()).should.eql(str)

    describe 'when passed a float', ->
      it 'throws an error', ->
        (-> Base58.encode(3.14)).should
          .throw('Value passed is not an integer.')

    describe 'when passed a non-number value', ->
      it 'throws an error', ->
        (-> Base58.encode('hi')).should
          .throw('Value passed is not an integer.')

  describe '.decode', ->
    it 'decodes Base58 string to number', ->
      for str, num of examples
        Base58.decode(str).should.eql(num)

    describe 'when passed a non-Base58 string', ->
      it 'throws an error', ->
        (-> Base58.decode('>_<')).should
          .throw('Value passed is not a valid Base58 string.')

should = require 'should'

Base58 = require '..'

describe 'Base58', ->
  beforeEach ->
    @examples = require './examples' unless @examples?
    should.exist(@examples)

  describe '.encode', ->
    it 'encodes number to Base58 string', ->
      for str, num of @examples
        Base58.encode(num).should.eql(str)

    describe 'when passed a string only containing numbers', ->
      it 'encodes string after first converting it to an integer', ->
        for str, num of @examples
          Base58.encode(num.toString()).should.eql(str)

    describe 'when passed a float', ->
      it 'throws an error', ->
        (-> Base58.encode(3.14)).should
          .throw('Value passed is not an integer.')

    describe 'when passed a non-number value', ->
      it 'throws an error', ->
        (-> Base58.encode('hi')).should
          .throw('Value passed is not an integer.')

  describe '.decode', ->
    it 'decodes Base58 string to number', ->
      for str, num of @examples
        Base58.decode(str).should.eql(num)

    describe 'when passed a non-Base58 string', ->
      it 'throws an error', ->
        (-> Base58.decode('>_<')).should
          .throw('Value passed is not a valid Base58 string.')

Update test with slightly cleaner and safer code


Q = require('q')
async = require('async')

Theme = require('../../models/theme').model
HeadlineService = require('../services/headline')

module.exports = class ThemePresenter
  constructor: (@theme) ->

  @populateIndicatorRecencyStats: (themes) ->
    for theme in themes
      theme.outOfDateIndicatorCount = 0
      for indicator in theme.indicators
        indicator.isUpToDate = HeadlineService.narrativeRecencyTextIsUpToDate(
          indicator.narrativeRecency
        )
        unless indicator.isUpToDate
          theme.outOfDateIndicatorCount++

  filterIndicatorsWithData: ->
    deferred = Q.defer()

    indicatorsWithData = []

    indicatorHasData = (indicator, callback) ->
      indicator.hasData().then( (hasData) ->
        if hasData
          indicatorsWithData.push(indicator)

        callback(null)
      ).fail(callback)

    if @theme.indicators?
      async.each @theme.indicators, indicatorHasData, (err) =>
        if err?
          deferred.reject(err)
        else
          @theme.indicators = indicatorsWithData
          deferred.resolve()
    else
      deferred.reject(new Error('filterIndicatorsWithData called on a theme without an indicator attribute'))

    deferred.promise

  @populateIndicators: (themes, filter) ->
    Q.nfcall(
      async.each, themes, (theme, callback) ->
        Q.nfcall(
          Theme.getIndicatorsByTheme, theme.id, filter
        ).then( (indicators) ->
          theme.indicators = indicators
          callback()
        ).fail(callback)
    )

Q = require('q')
async = require('async')

Theme = require('../../models/theme').model
HeadlineService = require('../services/headline')

module.exports = class ThemePresenter
  constructor: (@theme) ->

  @populateIndicatorRecencyStats: (themes) ->
    for theme in themes
      theme.outOfDateIndicatorCount = 0
      for indicator in theme.indicators
        indicator.isUpToDate = HeadlineService.narrativeRecencyTextIsUpToDate(
          indicator.narrativeRecency
        )
        unless indicator.isUpToDate
          theme.outOfDateIndicatorCount++

  filterIndicatorsWithData: ->
    deferred = Q.defer()

    indicatorsWithData = []

    indicatorHasData = (indicator, callback) ->
      indicator.hasData().then( (hasData) ->
        if hasData
          indicatorsWithData.push(indicator)

        callback(null)
      ).catch(callback)

    if @theme.indicators?
      async.each @theme.indicators, indicatorHasData, (err) =>
        if err?
          deferred.reject(err)
        else
          @theme.indicators = indicatorsWithData
          deferred.resolve()
    else
      deferred.reject(new Error('filterIndicatorsWithData called on a theme without an indicator attribute'))

    deferred.promise

  @populateIndicators: (themes, filter) ->
    Q.nfcall(
      async.each, themes, (theme, callback) ->
        Q.nfcall(
          Theme.getIndicatorsByTheme, theme.id, filter
        ).then( (indicators) ->
          theme.indicators = indicators
          callback()
        ).catch(callback)
    )

Use catch rather than fail, as bluebird only supports catch


#= require partystreusel/base
#= require partystreusel/scroll_to
#= require jquery.cycle2
#= require jquery.cycle2.swipe

class Slider extends Partystreusel.Base
  @className = 'Slider'

  constructor: (el) ->
    super
    @initializeCycle()

  initializeCycle: ->
    # see for documenation and options:
    # https://github.com/malsup/cycle2
    @$el.cycle
      slides: '.slider__item'
      fx: 'scrollHorz'
      speed: 300
      timeout: 0
      next: '.slider__control-next'
      prev: '.slider__control-prev'
      pager: '.slider__nav'
      pagerActiveClass: 'slider__nav-item--active'
      pagerTemplate: ""
      swipe: true

Partystreusel.Slider = Slider

#= require partystreusel/base
#= require partystreusel/scroll_to
#= require jquery.cycle2
#= require jquery.cycle2.swipe

class Slider extends Partystreusel.Base
  @className = 'Slider'

  constructor: (el) ->
    super
    @slidelist = @$el.find('.slider__list')
    @initializeCycle()

  initializeCycle: ->
    # see for documenation and options:
    # https://github.com/malsup/cycle2
    @slidelist.cycle
      slides: '.slider__item'
      fx: 'scrollHorz'
      speed: 300
      timeout: 0
      next: '.slider__control-next'
      prev: '.slider__control-prev'
      pager: '.slider__nav'
      pagerActiveClass: 'slider__nav-item--active'
      pagerTemplate: ""
      swipe: true

Partystreusel.Slider = Slider

Initialize slider on top element of slider


angular.module("app").filter "formatVotes", () ->
    (number) ->  # TODO  use real precision, not available in web wallet yet
        return number / 100000

angular.module("app").filter "formatVotes", ($filter) ->
    (number) ->  # TODO  use real precision, not available in web wallet yet
        return $filter('number')(number / 100000,0)+' BTS'

Make votes format a bit prettier: Add number formatting and BTS unit


{Serenade} = require './serenade'
{Cache} = require './cache'
{Associations} = require './associations'
{extend} = require './helpers'

class Serenade.Model
  extend(@prototype, Serenade.Properties)
  extend(@prototype, Associations)

  @property: -> @prototype.property(arguments...)
  @collection: -> @prototype.collection(arguments...)
  @belongsTo: -> @prototype.belongsTo(arguments...)
  @hasMany: -> @prototype.hasMany(arguments...)

  @find: (id) -> Cache.get(this, id) or new this(id: id)

  @property 'id', serialize: true

  @extend: (name, ctor) ->
    class New extends this
      @modelName: name
      constructor: ->
        super
        ctor.apply(this, arguments) if ctor

  constructor: (attributes, bypassCache=false) ->
    unless bypassCache
      if attributes?.id
        fromCache = Cache.get(@constructor, attributes.id)
        if fromCache
          fromCache.set(attributes)
          return fromCache
        else
          Cache.set(@constructor, attributes.id, this)
    if @constructor.localStorage is 'save'
      @bind('saved', => Cache.store(@constructor, @get('id'), this))
    else if @constructor.localStorage
      @bind('change', => Cache.store(@constructor, @get('id'), this))
    @set(attributes)

  save: ->
    @trigger('saved')

{Serenade} = require './serenade'
{Cache} = require './cache'
{Associations} = require './associations'
{extend} = require './helpers'

class Serenade.Model
  extend(@prototype, Serenade.Properties)
  extend(@prototype, Associations)

  @property: -> @prototype.property(arguments...)
  @collection: -> @prototype.collection(arguments...)
  @belongsTo: -> @prototype.belongsTo(arguments...)
  @hasMany: -> @prototype.hasMany(arguments...)

  @find: (id) -> Cache.get(this, id) or new this(id: id)

  @property 'id', serialize: true

  @extend: (name, ctor) ->
    class New extends this
      @modelName: name
      constructor: ->
        super
        ctor.apply(this, arguments) if ctor

  constructor: (attributes, bypassCache=false) ->
    unless bypassCache
      if attributes?.id
        fromCache = Cache.get(@constructor, attributes.id)
        if fromCache
          fromCache.set(attributes)
          # temporary workaround until CS bug is fixed
          # otherwise, we neither return the cached object
          # nor set attributes on the new one
          @set(attributes)
          return fromCache
        else
          Cache.set(@constructor, attributes.id, this)
    if @constructor.localStorage is 'save'
      @bind('saved', => Cache.store(@constructor, @get('id'), this))
    else if @constructor.localStorage
      @bind('change', => Cache.store(@constructor, @get('id'), this))
    @set(attributes)

  save: ->
    @trigger('saved')

Work around CS identity map bug

Work around CS identity map bug


config =
  data_file_location: 'http://www.chimpandsee.org/identified-chimps/identified-species.json'
  is_scientist: 'no' # This doesn't do anything yet.
  speciesToTrack: ['chimpanzee', 'other-primate']

pairs = location.search.slice(1).split(',')
for pair in pairs
  for key, value of pair
    continue unless config.hasOwnProperty(key)
    config[key] = value

module.exports = config

config =
  data_file_location: 'https://www.chimpandsee.org/identified-chimps/identified-species.json'
  is_scientist: 'no' # This doesn't do anything yet.
  speciesToTrack: ['chimpanzee', 'other-primate']

pairs = location.search.slice(1).split(',')
for pair in pairs
  for key, value of pair
    continue unless config.hasOwnProperty(key)
    config[key] = value

module.exports = config

Update data file location to use https

Update data file location to use https


"*":
  core:
    disabledPackages: [
      "background-tips"
      "exception-reporting"
      "metrics"
      "styleguide"
      "timecop"
      "welcome"
    ]
    telemetryConsent: "no"
  editor:
    invisibles: {}
    showIndentGuide: true
    showInvisibles: true
  "file-icons":
    forceShow: true
    onChanges: true
  "line-ending-selector":
    defaultLineEnding: "LF"
  linter:
    lintOnChange: false
  "markdown-preview":
    useGitHubStyle: true
  "omni-ruler":
    columns: [
      "80"
      "100"
      "120"
      "200"
    ]
  pigments:
    markerType: "native-dot"
    mergeColorDuplicates: true
  "spell-check":
    locales: [
      "en-US"
    ]

Set Atom spell-check locales to en-US

Set Atom spell-check locales to en-US

A workaround to fix the "Cannot load the system dictionary..." error
message when opening Atom.


angular.module("admin.utils").directive "datepicker", ($window, $timeout) ->
  require: "ngModel"
  link: (scope, element, attrs, ngModel) ->
    $timeout ->
      flatpickr(element,  Object.assign(
                            {},
                            $window.FLATPICKR_DATE_DEFAULT, {
                            onOpen: (selectedDates, dateStr, instance) ->
                              instance.setDate(ngModel.$modelValue)
                            }
                          ));

angular.module("admin.utils").directive "datepicker", ($window, $timeout) ->
  require: "ngModel"
  link: (scope, element, attrs, ngModel) ->
    $timeout ->
      flapickrInstance = flatpickr(element,  Object.assign(
                            {},
                            $window.FLATPICKR_DATE_DEFAULT, {
                            onOpen: (selectedDates, dateStr, instance) ->
                              instance.setDate(ngModel.$modelValue)
                            }
                          ));
      ngModel.$render = () ->
        newValue = ngModel.$viewValue;
        flapickrInstance?.setDate(newValue)

Update flatpickr input value if ng-model change


class Lanes.Components.Input extends Lanes.React.Component

    mixins: [
        Lanes.Components.Form.FieldMixin
    ]
    formGroupClass: 'input'

    propTypes:
        unlabled:  React.PropTypes.bool

    getValue: ->
        @refs.input.getValue()

    renderEdit: (label) ->
        colProps = _.omit(@props, 'name')
        <BS.Col {...colProps} >
            <BS.Input
                ref="input"
                className={_.classnames('value', changeset: @state.changeset)}
                type='text'
                label={label}
                value={@props.model[@props.name]}
                onChange={@handleChange}
                {...@props}
            />
        </BS.Col>

class Lanes.Components.Input extends Lanes.React.Component

    mixins: [
        Lanes.Components.Form.FieldMixin
    ]
    formGroupClass: 'input'

    propTypes:
        unlabled:  React.PropTypes.bool

    getValue: ->
        @refs.input.getValue()

    renderEdit: (label) ->
        colProps = _.omit(@props, 'name')
        value = @props.model[@props.name] or ''
        <BS.Col {...colProps} >
            <BS.Input
                ref="input"
                className={_.classnames('value', changeset: @state.changeset)}
                type='text'
                label={label}
                value={value}
                onChange={@handleChange}
                {...@props}
            />
        </BS.Col>

Set to empty string instead of undefined


class visualization.Simple

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

  # Build layer as wanted
  buildLayerGroup: (widget, globalStyle = {}) ->
    group = []
    for zone in @data
      zoneLayer = new L.GeoJSON(zone.shape, globalStyle)
      widget._bindPopup(zoneLayer, zone)
      group.push(zoneLayer)
    group

  # Build HTML legend for given categories computed layer
  buildLegend: () ->
    html  = "
"
    # html += "
#{@layer.label}
"
    html += "
"
    html += ""
    html += ""
    html += ""
    html += " #{@layer.label}"
    html += ""
    html += ""
    html += "
"
    html += "
"
    return html

  # Check if categories are valid
  valid: () ->
    true

visualization.registerLayerType "simple", visualization.Simple

class visualization.Simple

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

  # Build layer as wanted
  buildLayerGroup: (widget, globalStyle = {}) ->
    group = []
    for zone in @data
      zoneLayer = new L.GeoJSON(zone.shape, globalStyle)
      zoneLayer.bindLabel(zone.name, globalStyle)
      widget._bindPopup(zoneLayer, zone)
      group.push(zoneLayer)
    group

  # Build HTML legend for given categories computed layer
  buildLegend: () ->
    html  = "
"
    # html += "
#{@layer.label}
"
    html += "
"
    html += ""
    html += ""
    html += ""
    html += " #{@layer.label}"
    html += ""
    html += ""
    html += "
"
    html += "
"
    return html

  # Check if categories are valid
  valid: () ->
    true

visualization.registerLayerType "simple", visualization.Simple

Add static label in simple visualisation map.


# Description:
#   In which Hubot gives you bugzilla information
#
# Dependencies:
#   None
#
# Configuration:
#   None
#
# Commands:
#   hubot bug <number> - Shows bug summary
#
# Author:
#   greenb

QS      = require 'querystring'
Cheerio = require 'cheerio'

module.exports = (robot) ->

  domain = 'http://bugs.sfolab.ibm.com'
  makePath = (bug) ->
    '/bugzilla/show_bug.cgi?id=' + bug

  robot.hear /bug #?(\d+)/ig, (msg) ->
    notUniq = {}
    for b in msg.match
      bug = b.substr b.search /\d/
      if notUniq[bug]
        continue
      notUniq[bug] = true

      params =
        id: bug

      msg.http(domain)
        .path(makePath(bug))
        .header('Content-Type', 'application/x-www-form-urlencoded')
        .post(QS.stringify(params)) (err, res, body) ->
          if err
            msg.send 'Failed to query bug status. ' + err
            return

          if res.statusCode != 200
            msg.send 'Failed to query bug status. Got status ' + res.statusCode
            return

          $ = Cheerio.load body
          title = $('title').text()

          if title != 'Invalid Bug ID'
            msg.send "#{title} #{domain}#{makePath(bug)}"

# Description:
#   In which Hubot gives you bugzilla information
#
# Dependencies:
#   None
#
# Configuration:
#   None
#
# Commands:
#   hubot bug <number> - Shows bug summary
#
# Author:
#   greenb

QS      = require 'querystring'
Cheerio = require 'cheerio'

module.exports = (robot) ->

  domain = 'http://bugs.sfolab.ibm.com'
  makePath = (bug) ->
    '/bugzilla/show_bug.cgi?id=' + bug

  fetchBug = (msg, bug) ->
    params =
      id: bug

    msg.http(domain)
      .path(makePath(bug))
      .header('Content-Type', 'application/x-www-form-urlencoded')
      .post(QS.stringify(params)) (err, res, body) ->
        if err
          msg.send 'Failed to query bug status. ' + err
          return

        if res.statusCode != 200
          msg.send 'Failed to query bug status. Got status ' + res.statusCode
          return

        $ = Cheerio.load body
        title = $('title').text()

        if title != 'Invalid Bug ID'
          msg.send "#{title} #{domain}#{makePath(bug)}"

  robot.hear /bug #?(\d+)/ig, (msg) ->
    notUniq = {}
    for b in msg.match
      bug = b.substr b.search /\d/
      if notUniq[bug]
        continue
      notUniq[bug] = true

      fetchBug msg, bug

Fix issue with incorrect bug links when multiple bug numbers given The "bug" variable was not closed over in the for loop. Fix is to move it out into a separate function.


#= require trix/views/attachment_view
#= require trix/models/image_attachment

{defer, makeElement, measureElement} = Trix

class Trix.ImageAttachmentView extends Trix.AttachmentView
  getPreloadOperation: ->
    if @attachment.preloadOperation?.hasSucceeded()
      @attachment.preloadOperation
    else if @attachment.previewPreloadOperation?
      @attachment.previewPreloadOperation
    else
      @attachment.preloadOperation

  createContentNodes: ->
    image = makeElement("img", src: "", "data-trix-mutable": true)
    @refresh(image)

    if operation = @attachment.preloadOperation
      operation.then =>
        @refresh(image)
        @refresh()

    [image]

  getClassName: ->
    [super, "image"].join(" ")

  refresh: (image) ->
    image ?= @findElement()?.querySelector("img")
    @updateAttributesForImage(image) if image

  updateAttributesForImage: (image) ->
    attachmentURL = @attachment.getURL()
    operation = @getPreloadOperation()
    image.src = url = operation.url

    if url is attachmentURL
      image.removeAttribute("data-trix-serialized-attributes")
    else
      serializedAttributes = JSON.stringify(src: attachmentURL)
      image.setAttribute("data-trix-serialized-attributes", serializedAttributes)

    width = @attachmentPiece.getWidth() ? @attachment.getWidth()
    height = @attachmentPiece.getHeight() ? @attachment.getHeight()

    image.width = width if width?
    image.height = height if height?

#= require trix/views/attachment_view
#= require trix/models/image_attachment

{defer, makeElement, measureElement} = Trix

class Trix.ImageAttachmentView extends Trix.AttachmentView
  getPreloadOperation: ->
    if @attachment.preloadOperation?.hasSucceeded()
      @attachment.preloadOperation
    else if @attachment.previewPreloadOperation?
      @attachment.previewPreloadOperation
    else
      @attachment.preloadOperation

  createContentNodes: ->
    image = makeElement("img", src: "", "data-trix-mutable": true)
    @refresh(image)

    if operation = @attachment.preloadOperation
      operation.then =>
        @refresh(image)
        @refresh()

    [image]

  getClassName: ->
    [super, "image preview"].join(" ")

  refresh: (image) ->
    image ?= @findElement()?.querySelector("img")
    @updateAttributesForImage(image) if image

  updateAttributesForImage: (image) ->
    attachmentURL = @attachment.getURL()
    operation = @getPreloadOperation()
    image.src = url = operation.url

    if url is attachmentURL
      image.removeAttribute("data-trix-serialized-attributes")
    else
      serializedAttributes = JSON.stringify(src: attachmentURL)
      image.setAttribute("data-trix-serialized-attributes", serializedAttributes)

    width = @attachmentPiece.getWidth() ? @attachment.getWidth()
    height = @attachmentPiece.getHeight() ? @attachment.getHeight()

    image.width = width if width?
    image.height = height if height?

Add .preview class for img attachments, since we display a preview


Tasks = new Meteor.Collection("tasks")
Lists = new Meteor.Collection("lists")
Folders = new Meteor.Collection("folders")

if Meteor.isClient
  Template.todos.tasks = ->
    Tasks.find()

  Template.todos.events
    'click a.completeBox': (e) ->
      Tasks.update this._id,
        $set: completed: not @completed

  Template.newTaskForm.events
    'submit #new-task, click #addTaskButton': (e) ->
      e.preventDefault()
      body = $('#new-task-text').val()
      $('#new-task-text').val("")
      now = moment()
      priority = 'low'
      list = 'Home'
      Tasks.insert
        body: body
        date: now.format('D MMM YYYY')
        dateDue: now
        dateCreated: now
        dateCompleted: false
        modified: now
        list: list
        priority: priority
        completed: false
        repeating: false

Tasks = new Meteor.Collection("tasks")
Lists = new Meteor.Collection("lists")
Folders = new Meteor.Collection("folders")

if Meteor.isClient
  Template.todos.tasks = ->
    Tasks.find()

  Template.todos.events
    'click a.completeBox': (e) ->
      now = moment()
      Tasks.update this._id,
        $set:
          completed: not @completed
          dateCompleted: now
          modified: now

  Template.newTaskForm.events
    'submit #new-task, click #addTaskButton': (e) ->
      e.preventDefault()
      body = $('#new-task-text').val()
      $('#new-task-text').val("")
      now = moment()
      priority = 'low'
      list = 'Home'
      Tasks.insert
        body: body
        date: now.format('D MMM YYYY')
        dateDue: now
        dateCreated: now
        dateCompleted: false
        modified: now
        list: list
        priority: priority
        completed: false
        repeating: false

Update dateCompleted and modified when completing task


# Object which holds the methods that can be called from the factlink core iframe

modalOpen = false

FactlinkJailRoot.annotatedSiteReceiver =
  modalFrameReady: (featureToggles) ->
    FactlinkJailRoot.can_haz = featureToggles
    window.FACTLINK_ON_CORE_LOAD?()

  openModalOverlay: ->
    return if modalOpen
    FactlinkJailRoot.$modalFrame.addClass 'factlink-control-visible'
    modalOpen = true
    FactlinkJailRoot.trigger 'modalOpened'

  highlightNewFactlink: (displaystring, id) ->
    FactlinkJailRoot.selectRanges(FactlinkJailRoot.search(displaystring), id)
    FactlinkJailRoot.trigger 'factlinkAdded'

  closeModal_noAction: ->
    FactlinkJailRoot.$modalFrame.removeClass 'factlink-control-visible'
    setTimeout( ->
      return unless modalOpen
      modalOpen = false
      FactlinkJailRoot.trigger 'modalClosed'
    , 300)

  # For compatibility, please remove the next time you see this
  closeModal_highlightNewFactlink: (displaystring, id) ->
    @highlightNewFactlink(displaystring, id)
    @closeModal_noAction()

  closeModal_deleteFactlink: (id) ->
    $("span.factlink[data-factid=#{id}]").each (i, val) ->
      $(val).contents().unwrap()
    @closeModal_noAction()

# Object which holds the methods that can be called from the factlink core iframe

modalOpen = false

FactlinkJailRoot.annotatedSiteReceiver =
  modalFrameReady: (featureToggles) ->
    FactlinkJailRoot.can_haz = featureToggles
    window.FACTLINK_ON_CORE_LOAD?()

  openModalOverlay: ->
    if modalOpen
      console.error 'trying to open an already open modal: bug?'
      return
    FactlinkJailRoot.$modalFrame.addClass 'factlink-control-visible'
    modalOpen = true
    FactlinkJailRoot.trigger 'modalOpened'

  highlightNewFactlink: (displaystring, id) ->
    FactlinkJailRoot.selectRanges(FactlinkJailRoot.search(displaystring), id)
    FactlinkJailRoot.trigger 'factlinkAdded'

  closeModal_noAction: ->
    FactlinkJailRoot.$modalFrame.removeClass 'factlink-control-visible'
    setTimeout( ->
      if !modalOpen
        console.error 'trying to close an already closed modal: bug?'
        return
      modalOpen = false
      FactlinkJailRoot.trigger 'modalClosed'
    , 300)

  # For compatibility, please remove the next time you see this
  closeModal_highlightNewFactlink: (displaystring, id) ->
    @highlightNewFactlink(displaystring, id)
    @closeModal_noAction()

  closeModal_deleteFactlink: (id) ->
    $("span.factlink[data-factid=#{id}]").each (i, val) ->
      $(val).contents().unwrap()
    @closeModal_noAction()

Add warning logging when unusual things happen


### Configuration file

This file contains all the necessary options for running an instance of the
hog winrate calculator.
###

# Database and daemon settings

module.exports.docker =
  socket: "/var/run/docker.sock"
  runner:
    image: "arbiter"
    networkDisabled: true
    memory: 50e6
    timeout: 1e5
    maxLength: 1e3
    volumes:
      share: "/opt/share"
      env: "/opt/env"
    output:
      stream: false
      stdout: false
      stderr: false
      tty: false

### Configuration file

This file contains all the necessary options for running an instance of the
hog winrate calculator.
###

# Database and daemon settings

module.exports.docker =
  socket: "/var/run/docker.sock"
  runner:
    image: "arbiter"
    networkDisabled: true
    memory: 50e6
    timeout: 15e3
    maxLength: 1e3
    volumes:
      share: "/opt/share"
      env: "/opt/env"
    output:
      stream: false
      stdout: false
      stderr: false
      tty: false

Change timeout to 15 seconds

Change timeout to 15 seconds


path = require 'path'
CSON = require 'season'
fs = require 'fs-plus'

module.exports = (grunt) ->
  {spawn} = require('./task-helpers')(grunt)

  grunt.registerTask 'compile-packages-slug', 'Add package metadata information to to the main package.json file', ->
    appDir = grunt.config.get('atom.appDir')

    modulesDirectory = path.join(appDir, 'node_modules')
    packages = {}

    for moduleDirectory in fs.listSync(modulesDirectory)
      continue if path.basename(moduleDirectory) is '.bin'

      metadata = grunt.file.readJSON(path.join(moduleDirectory, 'package.json'))
      continue unless metadata?.engines?.atom?

      pack = {metadata, keymaps: {}, menus: {}}

      for keymapPath in fs.listSync(path.join(moduleDirectory, 'keymaps'), ['.cson', '.json'])
        keymapPath = path.relative(appDir, keymapPath)
        pack.keymaps[keymapPath] = CSON.readFileSync(keymapPath)

      for menuPath in fs.listSync(path.join(moduleDirectory, 'menus'), ['.cson', '.json'])
        menuPath = path.relative(appDir, menuPath)
        pack.menus[menuPath] = CSON.readFileSync(menuPath)

      packages[metadata.name] = pack

    metadata = grunt.file.readJSON(path.join(appDir, 'package.json'))
    metadata._atomPackages = packages

    grunt.file.write(path.join(appDir, 'package.json'), JSON.stringify(metadata, null, 2))

path = require 'path'
CSON = require 'season'
fs = require 'fs-plus'

module.exports = (grunt) ->
  {spawn} = require('./task-helpers')(grunt)

  grunt.registerTask 'compile-packages-slug', 'Add package metadata information to to the main package.json file', ->
    appDir = grunt.config.get('atom.appDir')

    modulesDirectory = path.join(appDir, 'node_modules')
    packages = {}

    for moduleDirectory in fs.listSync(modulesDirectory)
      continue if path.basename(moduleDirectory) is '.bin'

      metadata = grunt.file.readJSON(path.join(moduleDirectory, 'package.json'))
      continue unless metadata?.engines?.atom?

      pack = {metadata, keymaps: {}, menus: {}}

      for keymapPath in fs.listSync(path.join(moduleDirectory, 'keymaps'), ['.cson', '.json'])
        relativePath = path.relative(appDir, keymapPath)
        pack.keymaps[relativePath] = CSON.readFileSync(keymapPath)

      for menuPath in fs.listSync(path.join(moduleDirectory, 'menus'), ['.cson', '.json'])
        relativePath = path.relative(appDir, menuPath)
        pack.menus[relativePath] = CSON.readFileSync(menuPath)

      packages[metadata.name] = pack

    metadata = grunt.file.readJSON(path.join(appDir, 'package.json'))
    metadata._atomPackages = packages

    grunt.file.write(path.join(appDir, 'package.json'), JSON.stringify(metadata, null, 2))

Use proper relative paths in cache

Use proper relative paths in cache


#= require ./abstract_binding

class Batman.DOM.RouteBinding extends Batman.DOM.AbstractBinding
  onAnchorTag: false
  onlyObserve: Batman.BindingDefinitionOnlyObserve.Data

  @accessor 'dispatcher', ->
    @view.lookupKeypath('dispatcher') || Batman.App.get('current.dispatcher')

  bind: ->
    if @node.nodeName.toUpperCase() is 'A'
      @onAnchorTag = true

    super

    Batman.DOM.events.click(@node, @routeClick)

  routeClick: (node, event) =>
      return if event.__batmanActionTaken
      event.__batmanActionTaken = true
      params = @pathFromValue(@get('filteredValue'))
      Batman.redirect(params) if params?

  dataChange: (value) ->
    if value
      path = @pathFromValue(value)

    if @onAnchorTag
      if path and Batman.navigator
        path = Batman.navigator.linkTo(path)
      else
        path = "#"

      @node.href = path

  pathFromValue: (value) ->
    if value
      if value.isNamedRouteQuery
        value.get('path')
      else
        @get('dispatcher')?.pathFromParams(value)

#= require ./abstract_binding

class Batman.DOM.RouteBinding extends Batman.DOM.AbstractBinding
  onAnchorTag: false
  onlyObserve: Batman.BindingDefinitionOnlyObserve.Data

  @accessor 'dispatcher', ->
    @view.lookupKeypath('dispatcher') || Batman.App.get('current.dispatcher')

  bind: ->
    if @node.nodeName.toUpperCase() is 'A'
      @onAnchorTag = true

    super

    return if @onAnchorTag && @node.getAttribute('target')
    Batman.DOM.events.click(@node, @routeClick)

  routeClick: (node, event) =>
    return if event.__batmanActionTaken
    event.__batmanActionTaken = true
    params = @pathFromValue(@get('filteredValue'))
    Batman.redirect(params) if params?

  dataChange: (value) ->
    if value
      path = @pathFromValue(value)

    if @onAnchorTag
      if path and Batman.navigator
        path = Batman.navigator.linkTo(path)
      else
        path = "#"

      @node.href = path

  pathFromValue: (value) ->
    if value
      if value.isNamedRouteQuery
        value.get('path')
      else
        @get('dispatcher')?.pathFromParams(value)

Allow click events to propagate for anchors with target="_blank"


exports.site_docs =
  index: (doc) ->
    blocks = ['site_intro','site_home']
    types = ['essay','scene','video','profile']

    if doc.site and doc.type and types.indexOf(doc.type) >= 0 and doc.published is true
      content = doc.title + ' ' + doc.intro + ' ' + doc.body

      published = parseInt(doc.published_at.replace(/-/g,'').split('T')[0]) or 0
      updated = parseInt(doc.updated_at.replace(/-/g,'').split('T')[0]) or 0

      index 'default', content
      index 'site', doc.site
      index 'type', doc.type, {'store': 'yes'}
      index 'slug', doc.slug, {'store': 'yes'}
      index 'title', doc.title, {'store': 'yes'}
      index 'published', published, {'store': 'yes'}
      index 'updated', updated, {'store': 'yes'}

    else if doc.site and doc.type is 'collection'
      content = doc.title + ' ' + doc.intro
      index 'default', content
      index 'site', doc.site
      index 'type', doc.type, {'store': 'yes'}
      index 'slug', doc.slug, {'store': 'yes'}
      index 'title', doc.title, {'store': 'yes'}

    else if doc.type is 'block' and doc.code and blocks.indexOf(doc.code) >= 0 and doc.enabled is true
      index 'default', doc.content
      index 'site', doc.site
      index 'type', doc.type, {'store': 'yes'}

exports.site_docs =
  index: (doc) ->
    blocks = ['site_intro','site_home']
    types = ['essay','scene','video','profile']

    if doc.site and doc.type and types.indexOf(doc.type) >= 0 and doc.published is true
      content = doc.title + ' ' + doc.intro + ' ' + doc.body

      published = parseInt(doc.published_at.replace(/-/g,'').split('T')[0]) or 0
      updated = parseInt(doc.updated_at.replace(/-/g,'').split('T')[0]) or 0

      index 'default', content
      index 'site', doc.site
      index 'type', doc.type, {'store': 'yes'}
      index 'slug', doc.slug, {'store': 'yes'}
      index 'title', doc.title, {'store': 'yes'}
      index 'published', published, {'store': 'yes'}
      index 'updated', updated, {'store': 'yes'}

    else if doc.site and doc.type is 'collection'
      content = doc.name + ' ' + doc.intro
      index 'default', content
      index 'site', doc.site
      index 'type', doc.type, {'store': 'yes'}
      index 'slug', doc.slug, {'store': 'yes'}
      index 'title', doc.name, {'store': 'yes'}

    else if doc.type is 'block' and doc.code and blocks.indexOf(doc.code) >= 0 and doc.enabled is true
      index 'default', doc.content
      index 'site', doc.site
      index 'type', doc.type, {'store': 'yes'}

Fix collection names to show up in search results


# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

$ ->
  animateMetric = $(".metric-box strong").each ->
    $this = $(this)
    jQuery(counter: 0).animate { counter: $this.text().replace(/\,/g, '') },
      duration: 3000
      easing: 'swing'
      step: ->
        $this.text Math.ceil(@counter).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
        return
    return

# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

$ ->
  animateMetric = $(".metric-box strong").each ->
    $this = $(this)
    starting_point = 0
    $target_count = parseInt($this.text().replace(/\,/g, ''))

    # set the test to 0
    $this.text(starting_point)
    $this.counter = starting_point

    tween = createjs.Tween.get($this).to( {counter: $target_count}, 3000 )

    tween.addEventListener 'change', (event) ->
      $this.text(Math.round($this.counter).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","))
      return

Convert number animation to use TweenJS

Convert number animation to use TweenJS


class Skr.Screens.Locations extends Skr.Screens.Base

    dataObjects:
        location: ->
            @props.location || new Skr.Models.Location

    getInitialState: ->
        commands: new Lanes.Screens.Commands(this, modelName: 'location')

    render: ->
        <LC.ScreenWrapper identifier="locations">
            <Lanes.Screens.CommonComponents commands={@state.commands} />
            <BS.Row>
                <SC.LocationChooser label='Code' editOnly displayFinder
                    commands={@state.commands} model={@location} name="code" />
                <LC.Input sm=6 name='name' model={@location} />
            </BS.Row>
            <BS.Row>
                <SC.Address lg=6 model={@location.address}  />
            </BS.Row>

        </LC.ScreenWrapper>

class Skr.Screens.Locations extends Skr.Screens.Base

    dataObjects:
        location: ->
            @props.location || new Skr.Models.Location

    getInitialState: ->
        commands: new Lanes.Screens.Commands(this, modelName: 'location')

    render: ->
        <LC.ScreenWrapper identifier="locations">
            <Lanes.Screens.CommonComponents commands={@state.commands} />
            <BS.Row>
                <SC.LocationChooser label='Code' editOnly displayFinder
                    commands={@state.commands} model={@location} name="code" />
                <LC.Input sm=6 name='name' model={@location} />
            </BS.Row>
            <BS.Row>
                <LC.ImageSaver label='Logo' sm=4 model={@location} name='logo' />
            </BS.Row>
            <BS.Row>
                <SC.Address lg=6 model={@location.address}  />
            </BS.Row>

        </LC.ScreenWrapper>

Add image chooser for logo

Add image chooser for logo


assert = chai.assert

$ = Rye

suite 'Basic functionality', ->

    test 'Rye()', ->
        assert.instanceof Rye('div'), Rye, 'returns instance of Rye'

suite 'Querying', ->

    test 'ID query', ->

        el = $('#hello')
        assert.lengthOf el, 1, 'result has length 1'

assert = chai.assert

$ = Rye

setup ->
    document.getElementById('test').style.display = 'block'

teardown ->
    document.getElementById('test').style.display = 'none'

suite 'Basic functionality', ->

    test 'Rye()', ->
        assert.instanceOf Rye('div'), Rye, 'returns instance of Rye'

suite 'Querying', ->

    test 'ID query', ->

        el = $('#hello')
        assert.lengthOf el.elements, 1, 'result has length 1'

Hide test HTML on teardown, fix tests

Hide test HTML on teardown, fix tests


window.initClientCommunicator = ->
  local =
    showFactlink: (id) -> showUrl "/client/facts/#{id}"

    prepareNewFactlink: (displaystring, url, fact_title, current_user_opinion='no_vote') ->
      showUrl "/client/facts/new" +
        "?displaystring=" + encodeURIComponent(displaystring) +
        "&url=" + encodeURIComponent(url) +
        "&fact_title=" + encodeURIComponent(fact_title) +
        "&current_user_opinion=" + encodeURIComponent(current_user_opinion)

  showUrl = (url) ->
    # Force (re)loading the url, even if already showing that url
    # If history.fragment is equal to the current url, it doesn't reload,
    # so we reset it to null
    Backbone.history.fragment = null

    Backbone.history.navigate url, trigger: true

  Factlink.createReceiverEnvoy local

  Factlink.createSenderEnvoy window.parent

window.initClientCommunicator = ->
  local =
    showFactlink: (id) -> showUrl "/client/facts/#{id}"

    prepareNewFactlink: (displaystring, url, fact_title, current_user_opinion='no_vote') ->
      showUrl "/client/facts/new" +
        "?displaystring=" + encodeURIComponent(displaystring) +
        "&url=" + encodeURIComponent(url) +
        "&fact_title=" + encodeURIComponent(fact_title) +
        "&current_user_opinion=" + encodeURIComponent(current_user_opinion)

  showUrl = (url) ->
    # Force (re)loading the url, even if already showing that url
    # If history.fragment is equal to the current url, it doesn't reload,
    # so we reset it to null
    Backbone.history.fragment = null

    Backbone.history.navigate url, trigger: true

  Factlink.createReceiverEnvoy local

  if window.parent
    Factlink.createSenderEnvoy window.parent
  else
    ->

Fix js tests in client

Fix js tests in client


showVersions = ->
  $('.jasmine-version').text """
  jQuery #{$.fn.jquery}
  Unpoly #{up.version}
  Jasmine #{jasmine.version}
  """

$ ->
  # Give Jasmine time to initialize
  setTimeout(showVersions, 0)

showVersions = ->
  $('.jasmine-version').text """
  jQuery #{$.fn.jquery}
  Jasmine #{jasmine.version}
  """

$ ->
  # Give Jasmine time to initialize
  setTimeout(showVersions, 0)

Remove Unpoly version from Jasmine spec runner


define (require) ->
  subjects = require('cs!collections/subjects')
  BaseView = require('cs!helpers/backbone/views/base')
  MainPageView = require('cs!modules/main-page/main-page')
  FindContentView = require('cs!modules/find-content/find-content')
  template = require('hbs!./browse-content-template')
  require('less!./browse-content')

  class InnerView extends BaseView
    collection: subjects
    template: template

    initialize: () ->
      super()
      @listenTo(@collection, 'reset', @render)

    onRender: ->
      super()
      @$el.addClass('browse-content')
      findContentView = new FindContentView()
      findContentView.$el.insertBefore(@$el)
      findContentView.render()

  return class BrowseContentView extends MainPageView

    onRender: () ->
      super()
      @regions.main.show(new InnerView(@options))

define (require) ->
  subjects = require('cs!collections/subjects')
  BaseView = require('cs!helpers/backbone/views/base')
  MainPageView = require('cs!modules/main-page/main-page')
  FindContentView = require('cs!modules/find-content/find-content')
  template = require('hbs!./browse-content-template')
  require('less!./browse-content')

  class InnerView extends BaseView
    collection: subjects
    template: template

    initialize: () ->
      super()
      @listenTo(@collection, 'reset', @render)

    onRender: ->
      super()
      @$el.addClass('browse-content')

  return class BrowseContentView extends MainPageView

    onRender: () ->
      super()
      findContentView = new FindContentView()
      @regions.main.show(findContentView)
      @regions.main.append(new InnerView(@options))

Move findContentView to page code

Move findContentView to page code

The way the Find Content bar was being inserted was causing it to
appear twice.


class ParamHandler
  all: (callback) ->

    process = 'src/server --port 8000 --env development'
    match = process.match /--[a-zA-Z]* ([a-zA-Z0-9]*)/g

    payload = {}

    match.map (found) ->
      parse = found.match(/--([a-zA-Z]*)\s/)
      payload[parse[1]] = found.replace parse[0], ''

    callback payload

    return

module.exports = new ParamHandler

class ParamHandler
  constructor: (@payload = {}) ->

  getArguments: (process, callback) ->
    match = process.argv.join(' ').match /--[a-zA-Z]* ([a-zA-Z0-9]*)/g
    match.map (found) =>
      parse = found.match(/--([a-zA-Z]*)\s/)
      @payload[parse[1]] = found.replace parse[0], ''

    callback @payload

module.exports = new ParamHandler

Handle with Process-Arguments and tidy

Handle with Process-Arguments and tidy


'use strict'

angular.module('taarifaWaterpointsApp')
  .controller 'MainCtrl', ($scope, Waterpoint) ->
    $scope.waterpoints = Waterpoint.query()
  .controller 'MapCtrl', ($scope, Waterpoint) ->
    $scope.dar =
      lat: -6.7701973
      lng: 39.2664484
      zoom: 6
    $scope.markers = {}
    Waterpoint.query (waterpoints) ->
      for p in waterpoints
        $scope.markers[p._id] =
          group: p.district
          lat: p.latitude
          lng: p.longitude
          message: "#{p.wpt_code}\nStatus: #{p.status}"

Add MapCtrl to build markers grouped by district


class WebTermController extends AppController

  KD.registerAppClass this,
    name         : "WebTerm"
    route        : "/Develop"
    multiple     : yes
    hiddenHandle : no
    behavior     : "application"
    preCondition :
      condition  : (options, cb)->
        KD.singletons.vmController.info (err, vm, info)=>
          cb  if info?.state is 'RUNNING' then yes else no
      failure    : (options, cb)->
        KD.singletons.vmController.askToTurnOn 'Terminal', cb

  constructor:(options = {}, data)->
    vmName          = options.params?.vmName or \
                      KD.singletons.vmController.getDefaultVmName()
    options.view    = new WebTermAppView {vmName}
    options.appInfo =
      title         : "Terminal on #{vmName}"
      cssClass      : "webterm"

    super options, data

WebTerm = {}

class WebTermController extends AppController

  KD.registerAppClass this,
    name         : "WebTerm"
    route        : "/Develop"
    multiple     : yes
    hiddenHandle : no
    behavior     : "application"
    preCondition :
      condition  : (options, cb)->
        {params} = options
        vmName   = params?.vmName or "koding~#{KD.nick()}~0"
        KD.singletons.vmController.info vmName, (err, vm, info)=>
          cb  if info?.state is 'RUNNING' then yes else no
      failure    : (options, cb)->
        KD.singletons.vmController.askToTurnOn 'Terminal', cb

  constructor:(options = {}, data)->
    vmName          = options.params?.vmName or "koding~#{KD.nick()}~0"
    options.view    = new WebTermAppView {vmName}
    options.appInfo =
      title         : "Terminal on #{vmName}"
      cssClass      : "webterm"

    super options, data

WebTerm = {}

Fix WebTerm to work correctly with multiple VMs


_  = require 'underscore'
traverse = require 'traverse'

KONFIG = {}

try
  module.exports = KONFIG = JSON.parse process.env.KONFIG_JSON
catch err
  console.error 'error: could not parse KONFIG_JSON environment variable'
  console.error err
  process.exit 1

traverse.forEach KONFIG, (node) ->
  if val = process.env["KONFIG_#{this.path.join('_').toUpperCase()}"]
    try val = JSON.parse val
  return val or node

KONFIG.getConfigScriptTag = (mixin = {}) ->
  config = _.extend {}, @client.runtimeOptions, mixin
  """
  <script>var KD = #{JSON.stringify {config}};</script>
  """

_  = require 'underscore'
traverse = require 'traverse'

KONFIG = {}

do ->
  unless 'first' of Array.prototype
    Object.defineProperty Array.prototype, 'first',
      get: -> this[0]
  unless 'last' of Array.prototype
    Object.defineProperty Array.prototype, 'last',
      get: -> this[this.length-1]

try
  module.exports = KONFIG = JSON.parse process.env.KONFIG_JSON
catch err
  console.error 'error: could not parse KONFIG_JSON environment variable'
  console.error err
  process.exit 1

traverse.forEach KONFIG, (node) ->
  if val = process.env["KONFIG_#{this.path.join('_').toUpperCase()}"]
    try val = JSON.parse val
  return val or node

KONFIG.getConfigScriptTag = (mixin = {}) ->
  config = _.extend {}, @client.runtimeOptions, mixin
  """
  <script>var KD = #{JSON.stringify {config}};</script>
  """

Add Array::first and Array::last back

node: Add Array::first and Array::last back


# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

jQuery ->

  console.log 'Page loaded!'

  map = L.map('mapid').setView([40.75, -74.00], 12)

  # OSM Tile layer
  osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    minZoom: 4,
    maxZoom: 16,
    attribution: 'Map data © OpenStreetMap contributors'
  })
  map.addLayer(osm)

  $('.btn-load-dataset').click((event) ->
    event.preventDefault()

    button = $(this)
    datasetId = button.attr('id')
    console.log "Clicked dataset: #{datasetId}"

    # Load geobjects of dataset
    $.getJSON("/datasets/#{datasetId}.json", (data) ->
      console.log data
      L.geoJSON(data.feature_collection, {
        onEachFeature: (feature, layer) ->
          if (feature.properties && feature.properties)
            layer.bindPopup(JSON.stringify(feature.properties, null, 2).replace(/\n/g, '
'));
      }).addTo(map);
    )
  )

# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

jQuery ->

  console.log 'Page loaded!'

  if $('#mapid').length > 0

    map = L.map('mapid').setView([40.75, -74.00], 12)

    # OSM Tile layer
    osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      minZoom: 4,
      maxZoom: 16,
      attribution: 'Map data © OpenStreetMap contributors'
    })
    map.addLayer(osm)

    geojsonMarkerOptions = {
      radius: 8,
      fillColor: "#ff7800",
      weight: 4,
      opacity: 1,
      fillOpacity: 0.8
    }

    $('.btn-load-dataset').click((event) ->
      event.preventDefault()

      button = $(this)
      datasetId = button.attr('id')
      console.log "Clicked dataset: #{datasetId}"

      # Load geobjects of dataset
      $.getJSON("/datasets/#{datasetId}.json", (data) ->
        console.log data
        L.geoJSON(data.feature_collection, {
          style: data.style,
          pointToLayer: (feature, latlng) ->
            L.circleMarker(latlng, geojsonMarkerOptions)
          ,
          onEachFeature: (feature, layer) ->
            if (feature.properties && feature.properties)
              layer.bindPopup(JSON.stringify(feature.properties, null, 2).replace(/\n/g, '
'));
        }).addTo(map);
      )
    )

Customize geojson markers based on dataset styles


proxies =  [
  'koding-proxy-ap-s-e-1'
  'koding-proxy-us-east-1'
  'koding-proxy-eu-west-1'
  'koding-proxy-us-west-2'
  'koding-proxy-dev-us-e-1'
  'koding-proxy-dev-us-e-1-v2'
]

envs =  [
  'dev'
  'default'
  'koding-latest'
  'koding-monitor'
  'koding-prod'
  'koding-sandbox'
]

groupToEnv =
  'webserver'   : envs
  'environment' : envs
  'socialapi'   : envs
  'proxy'       : proxies
  'default'     : [ 'default' ]
  'bucket'      : envs
  'static'      : envs

module.exports.isAllowed = (group, env) ->
  # if group name is not in groupToEnv
  unless groupToEnv[group]
    console.error "#{group} is not defined in groupToEnv map"
    process.exit 1

  return env in groupToEnv[group]

# isProxy returns true if given env is in proxies
module.exports.isProxy = (env) -> return env in proxies

proxies =  [
  'koding-proxy-ap-s-e-1'
  'koding-proxy-us-east-1'
  'koding-proxy-eu-west-1'
  'koding-proxy-us-west-2'
  'koding-proxy-dev-us-e-1'
  'koding-proxy-dev-us-e-1-v2'
]

envs =  [
  'dev'
  'default'
  'koding-latest'
  'koding-monitor'
  'koding-prod'
  'koding-sandbox'
]

groupToEnv =
  'webserver'   : envs
  'environment' : envs
  'socialapi'   : envs
  'proxy'       : proxies
  'default'     : [ 'default' ]
  'bucket'      : envs
  'static'      : envs
  'external'    : envs.concat proxies

module.exports.isAllowed = (group, env) ->
  # if group name is not in groupToEnv
  unless groupToEnv[group]
    console.error "#{group} is not defined in groupToEnv map"
    process.exit 1

  return env in groupToEnv[group]

# isProxy returns true if given env is in proxies
module.exports.isProxy = (env) -> return env in proxies

Add external group to worker environment mapping

Signed-off-by: Sonmez Kartal <d2d15c3d37396a5f2a09f8b42cf5f27d43a3fbde@koding.com>


_ = require 'underscore'

View = require 'lib/view'
tpl = require 'templates/users/edit'
FormMixin = require 'views/base/mixins/form'

mediator = require('chaplin').mediator

module.exports = class EditUserView extends View
  @mixin FormMixin

  template: tpl
  autoRender: yes
  region: 'contactCard'

  events:
    'submit form': 'submitForm'
    'click [href="#remove"]': 'clickRemove'

  getTemplateData: ->
    _.extend super,
      currentUser: mediator.user?.toJSON()
      isAdmin: @model.hasRole('administrator')

  submitForm: (e) ->
    e.preventDefault()
    data = @formParams()

    data.roles = @model.get('roles')

    if data.admin
      data.roles.push name: 'administrator' unless @model.hasRole('administrator')
    else
      data.roles = _.reject data.roles, (r)->
        r.name =='administrator'

    @submit @model.save(data, wait: yes)

  clickRemove: (e) ->
    e.preventDefault()
    if confirm 'Are you sure?'
      @model.destroy(wait: yes).done =>
        toastr.success 'User has been removed.'
        @dispose()

_ = require 'underscore'

View = require 'lib/view'
tpl = require 'templates/users/edit'
FormMixin = require 'views/base/mixins/form'

mediator = require('chaplin').mediator

module.exports = class EditUserView extends View
  @mixin FormMixin

  template: tpl
  autoRender: yes
  region: 'contactCard'

  events:
    'submit form': 'submitForm'
    'click [href="#remove"]': 'clickRemove'

  getTemplateData: ->
    _.extend super,
      currentUser: mediator.user?.toJSON()
      isAdmin: @model.hasRole('administrator')

  submitForm: (e) ->
    e.preventDefault()
    data = @formParams()

    data.roles = @model.get('roles')

    if data.admin
      data.roles.push name: 'administrator' unless @model.hasRole('administrator')
    else
      data.roles = _.reject data.roles, (r)->
        r.name =='administrator'

    @submit(@model.save(data, wait: yes)).done ->
      toastr.success "Saved #{@model.get('name')}"

  clickRemove: (e) ->
    e.preventDefault()
    if confirm 'Are you sure?'
      @model.destroy(wait: yes).done =>
        toastr.success 'User has been removed.'
        @dispose()

Add a success message when saving a user


debug = require('debug') 'gc:geologs'
upsert = require '../db/upsert'
Promise = require 'bluebird'

module.exports = (db) ->
    upsert: (data) ->
        debug "upsert #{data.Code?.toLowerCase()}"
        upsert db, 'logs', data

    latest: Promise.coroutine (username) ->
        debug "latest #{username}"
        [client, done] = yield db.connect()
        try
            sql = db.select()
                .from 'logsRel'
                .field 'id'
                .order 'visitdate', false
                .limit 1
            sql = sql.where 'lower(username) = ?', username.trim().toLowerCase() if username?
            sql = sql.toString()

            result = yield client.queryAsync sql
            if result.rowCount is 0
                return null
            else
                return result.rows[0].id.toUpperCase()
        finally
            done()

debug = require('debug') 'gc:geologs'
upsert = require '../db/upsert'
Promise = require 'bluebird'

module.exports = (db) ->
    upsert: (data) ->
        debug "upsert #{data.Code?.toLowerCase()}"
        upsert db, 'logs', data

    latest: Promise.coroutine (username) ->
        debug "latest #{username}"
        [client, done] = yield db.connect()
        try
            sql = db.select()
                .from 'logsRel'
                .field 'id'
                .order 'visitdate', false
                .limit 1
            sql = sql.where 'lower(username) = ?', username.trim().toLowerCase() if username?
            sql = sql.toString()

            result = yield client.queryAsync sql
            if result.rowCount is 0
                return null
            else
                return result.rows[0].id.trim().toUpperCase()
        finally
            done()

Trim username for latest geolog

Trim username for latest geolog


React = require 'react'
deep = require 'deep-get-set'

module.exports = React.createClass
  displayName: "SimpleTable"

  propTypes:
    columns: React.PropTypes.array
    data: React.PropTypes.array

  render: ->
    columns = @props.columns.map (column) ->
      if typeof column is "string"
        {column}
      else
        {column.displayName}

    body = @props.data.map (rowData, i) =>
      row = []
      for column in @props.columns
        # Columns can either be a simple string or be an object that defines
        # both a displayName and path for accessing the data.
        if typeof column is "string"
          datum = rowData[column.toLowerCase()]
          key = i + "-" + column
        else if column.path?
          datum = deep(rowData, column.path)
          key = i + "-" + column.path
        else if column.function?
          datum = column.function(rowData)
          key = i + "-" + column.displayName
        row.push {datum}
      return
{row}

    return (

{columns}

{body}

    )

React = require 'react'
deep = require 'deep-get-set'

module.exports = React.createClass
  displayName: "SimpleTable"

  propTypes:
    columns: React.PropTypes.array
    data: React.PropTypes.array

  render: ->
    columns = @props.columns.map (column) ->
      if typeof column is "string"
        {column}
      else
        {column.displayName}

    body = @props.data.map (rowData, i) =>
      row = []
      for column in @props.columns
        # Columns can either be a simple string or be an object that defines
        # both a displayName and path for accessing the data.
        if typeof column is "string"
          datum = deep(rowData, column.toLowerCase())
          key = i + "-" + column
        else if column.path?
          datum = deep(rowData, column.path)
          key = i + "-" + column.path
        else if column.function?
          datum = column.function(rowData)
          key = i + "-" + column.displayName
        row.push {datum}
      return
{row}

    return (

{columns}

{body}

    )

Allow for accessing data with dot-notation in simple column case as well


# Ctrl-e switches to edit mode
$(window).keydown (event) ->
  if event.ctrlKey && String.fromCharCode(event.keyCode) == "E"
    href = window.location.href.replace(/\.html/, '')
    href = href.replace(/\/index$/, '/')
    window.location = href

# Ctrl-e switches to edit mode
$(window).keydown (event) ->
  if event.ctrlKey && String.fromCharCode(event.keyCode) == "E"
    href = window.location.href.replace(/\.html(#.*)?/, '')
    href = href.replace(/\/index$/, '/')
    window.location = href

Switch to edit mode even with a hashtag in the URL


#--[ MEDIA SELECTED ]--#

$(document).on "dblclick", ".mediaModalContainer img.selectable", (event) ->
  event.preventDefault()
  mediaModalContainer = $(event.target).parents(".mediaModalContainer")
  mediaSrc = $(event.target).attr('src')
  mediaId = $(event.target).data('id')
  inputId = '#' + mediaModalContainer.data('input')
  previewId = '#previewImage_' + mediaModalContainer.data('input')
  $(inputId).val(mediaId)
  $(previewId).attr('src', mediaSrc)
  modalId = mediaModalContainer.find('.mediaModalClose').click()

$(document).on "click", ".clear-media", (event) ->
  event.preventDefault()
  inputId = '#' + $(event.target).data('input')
  previewId = '#previewImage_' + $(event.target).data('input')
  $(inputId).val('')
  $(previewId).removeAttr('src')

Add css for no src image

Add css for no src image


[
  {
    title: "Spyns"
    group: "Development"
    paths: [
      "~/Development/spyns"
    ]
  }
  {
    title: "CSI-702: Homework02 Instructor Attempt"
    group: "Mason Fall 2017"
    paths: [
      "~/Documents/work/teaching/2017_Spring_Semester/CSI-702_High_Performance_Computing/assignments/homework02-instructor-attempt"
    ]
  }
]

[
  {
    title: "CDS-411 Instructors"
    group: "CDS-411"
    paths: [
      "~/Courses/CDS-411/instructors"
    ]
  }
  {
    title: "Spyns"
    group: "Development"
    paths: [
      "~/Development/spyns"
    ]
  }
  {
    title: "CSI-702 Spr17: Homework02 Instructor Attempt"
    group: "CSI-702"
    paths: [
      "~/Documents/work/teaching/2017_Spring_Semester/CSI-702_High_Performance_Computing/assignments/homework02-instructor-attempt"
    ]
  }
]

Update projects on oryx pro

Update projects on oryx pro


namespace 'SensuDashboard.Collections', (exports) ->

  class exports.Base extends Backbone.Collection
    longPolling: false

    intervalSeconds: 10

    startLongPolling: (intervalSeconds) =>
      @longPolling = true
      if intervalSeconds
        @intervalSeconds = @intervalSeconds
      @executeLongPolling()

    stopLongPolling: =>
      @longPolling = false

    executeLongPolling: =>
      @fetch
        success: =>
          @onFetch()

    onFetch: =>
      setTimeout(@executeLongPolling, 10000) if @longPolling

namespace 'SensuDashboard.Collections', (exports) ->

  class exports.Base extends Backbone.Collection
    longPolling: false

    intervalSeconds: 10

    startLongPolling: (intervalSeconds) =>
      @longPolling = true
      @intervalSeconds = intervalSeconds if intervalSeconds
      @executeLongPolling()

    stopLongPolling: =>
      @longPolling = false

    executeLongPolling: =>
      @fetch
        success: =>
          @onFetch()

    onFetch: =>
      setTimeout(@executeLongPolling, 1000 * @intervalSeconds) if @longPolling

Use correct interval for polling

Use correct interval for polling


App.IndexController = Ember.ArrayController.extend
  needs: ["application"]
  currentUser: Ember.computed.alias("controllers.application.currentUser")
  itemController: "RoomUserStateItem"

  detectMessageType: (msgTxt)->
    if msgTxt.match("\n")
      "paste"
    else
      "text"

  actions:
    postMessage: (msgTxt)->
      msgTxt = msgTxt.trim()
      room = @get("activeState").get("room")
      console.log "To room #{room.get("name")}:", msgTxt
      currentUser = @get("currentUser")
      messageParams =
        roomId: room.get("id")
        body: msgTxt
        type: @detectMessageType(msgTxt)
        createdAt: new Date()
        user: currentUser

      console.log messageParams
      msg = @store.createRecord("message", messageParams)
      successCallback = ->
        console.log "message has been posted"
      errorCallback   = ->
        console.log "error posting message"
      msg.save().then(successCallback, errorCallback)

Add new msg posting to IndexController

Add new msg posting to IndexController


#= require comply/config
#= require_tree .

$ -> $('[data-validate-model]').each -> new Comply.ValidatableForm $(this)

#= require comply/config
#= require_tree .

$ ->
  $('[data-validate-model]').each ->
    $(this).data('comply-form', new Comply.ValidatableForm($(this)))

Store ValidatableForm object on DOM element


modalize = require '../modalize/index.coffee'
FlashMessage = require '../flash/index.coffee'
# We intentionally escape HTML in the template due to an XSS vulnerability.
# Consciously and manually override that here for this instance:
FlashMessage::template = -> "#{@message}"
InquiryQuestionnaireView = require './view.coffee'

module.exports = (options = {}) ->
  { user } = options

  questionnaire = new InquiryQuestionnaireView options

  modal = modalize questionnaire,
    className: 'modalize inquiry-questionnaire-modal'
    dimensions: width: '500px', height: '580px'

  modal.load (done) ->
    user.fetch().then done

  questionnaire.state.on 'abort', ->
    modal.close()

  questionnaire.state.on 'done', ->
    modal.close ->
      new FlashMessage message: '
        Your inquiry has been sent.

        Thank you for completing your profile.
      '

  modal

modalize = require '../modalize/index.coffee'
FlashMessage = require '../flash/index.coffee'
# We intentionally escape HTML in the template due to an XSS vulnerability.
# Consciously and manually override that here for this instance:
FlashMessage::template = -> "#{@message}"
InquiryQuestionnaireView = require './view.coffee'

module.exports = (options = {}) ->
  { user } = options

  questionnaire = new InquiryQuestionnaireView options

  modal = modalize questionnaire,
    className: 'modalize inquiry-questionnaire-modal'
    dimensions: width: '500px', height: '580px'

  modal.load (done) ->
    user.fetch().then ->
      if user.id?
        # We have an existing anonymous session
        # or a logged in user
        done()
      else
        # Create an anonymous session before continuing
        user.save().then done

  questionnaire.state.on 'abort', ->
    modal.close()

  questionnaire.state.on 'done', ->
    modal.close ->
      new FlashMessage message: '
        Your inquiry has been sent.

        Thank you for completing your profile.
      '

  modal

Create an anonymous session if one does not exist