fs = require 'fs'
apm = require '../lib/apm-cli'

describe 'apm command line interface', ->
  describe 'when no arguments are present', ->
    it 'prints a usage message', ->
      spyOn(console, 'log').andCallThrough()
      spyOn(console, 'error')
      apm.run([])
      expect(console.log).not.toHaveBeenCalled()
      expect(console.error).toHaveBeenCalled()
      expect(console.error.argsForCall[0][0].length).toBeGreaterThan 0

  describe 'when the version flag is specified', ->
    it 'prints a usage message', ->
      spyOn(console, 'log').andCallThrough()
      spyOn(console, 'error')
      apm.run(['-h'])
      expect(console.log).not.toHaveBeenCalled()
      expect(console.error).toHaveBeenCalled()
      expect(console.error.argsForCall[0][0].length).toBeGreaterThan 0

  describe 'when the version flag is specified', ->
    it 'prints the version', ->
      spyOn(console, 'log')
      spyOn(console, 'error')
      apm.run(['-v'])
      expect(console.error).not.toHaveBeenCalled()
      expect(console.log).toHaveBeenCalled()
      expect(console.log.argsForCall[0][0]).toBe JSON.parse(fs.readFileSync('package.json')).version

  describe 'when an unrecognized command is specified', ->
    it 'prints an error message', ->
      spyOn(console, 'log').andCallThrough()
      spyOn(console, 'error')
      apm.run(['this-will-never-be-a-command'])
      expect(console.log).not.toHaveBeenCalled()
      expect(console.error).toHaveBeenCalled()
      expect(console.error.argsForCall[0][0].length).toBeGreaterThan 0

Add spec for unrecognized command

Add spec for unrecognized command


angular.module 'qbn.engine', ['qbn.quality', 'qbn.storylet', 'qbn.choice', 'qbn.resolve']
  .controller 'QbnEngine',
    ($scope, qualities, storylets, frontalChoices, choiceFactory, resolveFilter) ->
      $scope.qualities = qualities.getAll()

      updateFrontalChoices = () ->
        $scope.choices = frontalChoices.getAll()
        return
      updateFrontalChoices()

      retreat = choiceFactory '!!retreat!!',
        'On second thought, maybe not…'
        'Return to the previous screen.'
        {}, {}, undefined

      onwards = choiceFactory '!!onwards!!',
        'The story continues…'
        '', {}, {}, undefined

      $scope.choose = (choice) ->
        next = resolveFilter choice.next
        storylet = storylets.lookup next
        if storylet?
          unless $scope.storylet?
            storylet.choices = storylet.choices.concat retreat
          unless storylet.choices?
            storylet.choices = [onwards]
        else
          updateFrontalChoices()
        $scope.storylet = storylet
        return
      return

angular.module 'qbn.engine', ['qbn.quality', 'qbn.storylet', 'qbn.choice', 'qbn.resolve']
  .controller 'QbnEngine',
    ($scope, qualities, storylets, frontalChoices, choiceFactory, resolveFilter) ->
      $scope.qualities = qualities.getAll()

      updateFrontalChoices = () ->
        $scope.choices = frontalChoices.getAll()
        return
      updateFrontalChoices()

      retreat = choiceFactory '!!retreat!!',
        'On second thought, maybe not…'
        'Return to the previous screen.'
        {}, {}, undefined

      onwards = choiceFactory '!!onwards!!',
        'The story continues…'
        '', {}, {}, undefined

      $scope.choose = (choice) ->
        next = resolveFilter choice.next
        storylet = storylets.lookup next
        if storylet?
          unless $scope.storylet?
            storylet.choices = storylet.choices.concat retreat
          unless storylet.choices.length > 0
            storylet.choices = [onwards]
        else
          updateFrontalChoices()
        $scope.storylet = storylet
        return
      return

Fix Bug in Onwards Concatenation

Fix Bug in Onwards Concatenation


angular.module('loomioApp').factory 'RecordLoader', (Records) ->
  class RecordLoader
    constructor: (opts = {}) ->
      @loadingFirst = true
      @collection = opts.collection
      @params     = opts.params or {from: 0, per: 25, order: 'id'}
      @path       = opts.path
      @numLoaded  = opts.numLoaded or 0
      @then       = opts.then or (data) -> data

    reset: ->
      @params['from'] = 0
      @numLoaded  = 0

    fetchRecords: ->
      @loading = true
      Records[_.camelCase(@collection)].fetch
        path:   @path
        params: @params
      .then (data) =>
        if data[@collection].length > 0
          @numLoaded += data[@collection].length
        else
          @exhausted = true
        data
      .then(@then)
      .finally =>
        @loadingFirst = false
        @loading = false

    loadMore: (from) ->
      if from?
        @params['from'] = from
      else
        @params['from'] += @params['per'] if @numLoaded > 0
      @loadingMore = true
      @fetchRecords().finally => @loadingMore = false

    loadPrevious: (from) ->
      if from?
        @params['from'] = from
      else
        @params['from'] -= @params['per'] if @numLoaded > 0
      @loadingPrevious = true
      @fetchRecords().finally => @loadingPrevious = false

angular.module('loomioApp').factory 'RecordLoader', (Records) ->
  class RecordLoader
    constructor: (opts = {}) ->
      @loadingFirst = true
      @collection = opts.collection
      @params     = _.merge({from: 0, per: 25, order: 'id'}, opts.params)
      @path       = opts.path
      @numLoaded  = opts.numLoaded or 0
      @then       = opts.then or (data) -> data

    reset: ->
      @params['from'] = 0
      @numLoaded  = 0

    fetchRecords: ->
      @loading = true
      Records[_.camelCase(@collection)].fetch
        path:   @path
        params: @params
      .then (data) =>
        if data[@collection].length > 0
          @numLoaded += data[@collection].length
        else
          @exhausted = true
        data
      .then(@then)
      .finally =>
        @loadingFirst = false
        @loading = false

    loadMore: (from) ->
      if from?
        @params['from'] = from
      else
        @params['from'] += @params['per'] if @numLoaded > 0
      @loadingMore = true
      @fetchRecords().finally => @loadingMore = false

    loadPrevious: (from) ->
      if from?
        @params['from'] = from
      else
        @params['from'] -= @params['per'] if @numLoaded > 0
      @loadingPrevious = true
      @fetchRecords().finally => @loadingPrevious = false

Fix load more on polls

Fix load more on polls


window.addAddressRow = ->
  count = $("[id^='organization_addresses_attributes']:text").length
  newRow = $ """

    Mailing Address

      <input class="form-control" data-guard="different" type="text" value="" name="organization[addresses_attributes][#{count}][address]" id="organization_addresses_attributes_#{count}_address">

  <input type="hidden" value="" name="organization[addresses_attributes][#{count}][id]" id="organization_addresses_attributes_#{count}_id">
  """

  $("#organization_info").append newRow

$(document).on "click", "#add-new-address", (event) ->
  event.preventDefault()
  addAddressRow(count)

window.addAddressRow = ->
  count = $("[id^='organization_addresses_attributes']:text").length
  newRow = $ """

    Mailing Address

      <input class="form-control" data-guard="different" type="text" value="" name="organization[addresses_attributes][#{count}][address]" id="organization_addresses_attributes_#{count}_address">

  """

  $("#organization_info").append newRow

$(document).on "click", "#add-new-address", (event) ->
  event.preventDefault()
  addAddressRow()

Remove hidden field and unneeded argument count


module.exports = (grunt) ->
    grunt.initConfig
        pkg: '<json:package.json>'
        coffee:
            client:
                expand: true
                cwd: 'src'
                src: ['*.coffee']
                dest: 'static/js/'
                ext: '.js'
            server:
                expand: true
                cwd: 'server-src'
                src: ['*.coffee']
                dest: 'server-js/'
                ext: '.js'
        less:
            development:
                options:
                    paths: ['styles']
                files:
                    'static/css/servicemap.css': 'styles/servicemap.less'
                    'static/css/bootstrap.css': 'styles/bootstrap/bootstrap.less'

        watch:
            files: [
                'Gruntfile.coffee'
                'src/*.coffee'
                'server-src/*.coffee'
            ]
            tasks: 'default'

        express:
            options:
                port: 9001
                spawn: true
            dev:
                options:
                    script: 'server-js/dev.js'

    grunt.loadNpmTasks 'grunt-contrib-coffee'
    grunt.loadNpmTasks 'grunt-contrib-watch'
    grunt.loadNpmTasks 'grunt-contrib-less'
    grunt.loadNpmTasks 'grunt-express-server'

    grunt.registerTask 'default', ['coffee', 'less']
    grunt.registerTask 'server', ['coffee', 'less', 'express', 'watch']

module.exports = (grunt) ->
    grunt.initConfig
        pkg: '<json:package.json>'
        coffee:
            client:
                expand: true
                cwd: 'src'
                src: ['*.coffee']
                dest: 'static/js/'
                ext: '.js'
            server:
                expand: true
                cwd: 'server-src'
                src: ['*.coffee']
                dest: 'server-js/'
                ext: '.js'
        less:
            development:
                options:
                    paths: ['styles']
                files:
                    'static/css/servicemap.css': 'styles/servicemap.less'
                    'static/css/bootstrap.css': 'styles/bootstrap/bootstrap.less'

        watch:
            files: [
                'Gruntfile.coffee'
                'src/*.coffee'
                'server-src/*.coffee'
                'styles/*.less'
            ]
            tasks: 'default'

        express:
            options:
                port: 9001
                spawn: true
            dev:
                options:
                    script: 'server-js/dev.js'

    grunt.loadNpmTasks 'grunt-contrib-coffee'
    grunt.loadNpmTasks 'grunt-contrib-watch'
    grunt.loadNpmTasks 'grunt-contrib-less'
    grunt.loadNpmTasks 'grunt-express-server'

    grunt.registerTask 'default', ['coffee', 'less']
    grunt.registerTask 'server', ['coffee', 'less', 'express', 'watch']

Make grunt watch .less files

Make grunt watch .less files


# Description:
#   Display an oblique strategy
#
# Dependencies:
#   None
#
# Configuration:
#   None
#
# Commands:
#   hubot strategy - Returns an oblique strategy
#
# Author:
#   hakanensari

module.exports = (robot) ->
  robot.respond /\W*(?:an? )?(?:oblique )?strategy\??$/i, (msg) ->
    msg.http('http://oblique.io')
      .get() (err, res, body) ->
        msg.send JSON.parse body

# Description:
#   Suggests an oblique strategy
#
# Dependencies:
#   None
#
# Configuration:
#   None
#
# Commands:
#   hubot strategy - Suggests a strategy
#   hubot a strategy for <user> - Suggests a strategy to user
#
# Notes:
#   You can be as verbose as you want as long as you address Hubot and mention
#   the word strategy and, optionally, one or more users.
#
#   Thanks, Brian Eno.
#
# Author:
#   hakanensari

module.exports = (robot) ->
  robot.respond /.*strategy/i, (msg) ->
    mentions = msg.message.text.match(/(@\w+)/g)
    robot.http('http://oblique.io')
      .get() (err, res, body) ->
        strategy = JSON.parse body
        strategy = "#{mentions.join(', ')}: #{strategy}" if mentions
        msg.send strategy

Allow Hubot to suggest strategies to others, in multiple ways


eval("window = {};")
eval("console = {};")
console.warn = ->
  self.postMessage
    type: 'warn'
    details: arguments
console.log = ->
  self.postMessage
    type: 'warn'
    details: arguments
eval("attachEvent = function(){};")

self.addEventListener 'message', (event) ->
  switch event.data.type
    when 'start'
      window.resourcePath = event.data.resourcePath
      importScripts(event.data.requirePath)
      self.postMessage(type:'started')
    else
      self[event.data.type](event.data)

self.loadTextmateSnippets = ({path}) ->
  fs = require 'fs'
  snippetsDirPath = fs.join(path, 'Snippets')
  snippets = fs.list(snippetsDirPath).map (snippetPath) ->
    fs.readPlist(snippetPath)
  self.postMessage
    type: 'loadSnippets'
    snippets: snippets

self.loadAtomSnippets = ({path}) ->
  fs = require 'fs'
  snippetsDirPath = fs.join(path, 'snippets')
  snippets = []
  for snippetsPath in fs.list(snippetsDirPath)
    continue if fs.base(snippetsPath).indexOf('.') is 0
    try
      snippets.push(fs.readObject(snippetsPath))
    catch e
      console.warn "Error reading snippets file '#{snippetsPath}'"
  self.postMessage
    type: 'loadSnippets'
    snippets: snippets

module.exports =
  loadTextmateSnippets: ({path}) ->
    fs = require 'fs'
    snippetsDirPath = fs.join(path, 'Snippets')
    snippets = fs.list(snippetsDirPath).map (snippetPath) ->
      fs.readPlist(snippetPath)
    self.postMessage
      type: 'loadSnippets'
      snippets: snippets

  loadAtomSnippets: ({path}) ->
    fs = require 'fs'
    snippetsDirPath = fs.join(path, 'snippets')
    snippets = []
    for snippetsPath in fs.list(snippetsDirPath)
      continue if fs.base(snippetsPath).indexOf('.') is 0
      try
        snippets.push(fs.readObject(snippetsPath))
      catch e
        console.warn "Error reading snippets file '#{snippetsPath}'"
    self.postMessage
      type: 'loadSnippets'
      snippets: snippets

Create task shell that bootstraps worker


_ = require 'underscore'
flux = require 'flux-react'

LOADING = 'loading'
FAILED  = 'failed'

EcosystemsActions = flux.createActions [
  'load'
  'loaded'
  'FAILED'
]

EcosystemsStore = flux.createStore
  actions: _.values(EcosystemsActions)

  _asyncStatus: null

  load: -> # Used by API
    @_asyncStatus = LOADING
    @emit('load')

  loaded: (ecosystems) ->
    @_ecosystems = ecosystems
    @emit('loaded')

  FAILED: ->
    @_asyncStatus = FAILED
    @emit('failed')

  exports:
    isLoaded: -> not _.isEmpty(@_ecosystems)
    isLoading: -> @_asyncStatus is LOADING
    isFailed:  -> @_asyncStatus is FAILED

    allBooks: ->
      _.map @_ecosystems, (ecosystem) ->
        _.extend( _.first(ecosystem.books), {ecosystemId: "#{ecosystem.id}"} )

    first: ->
      _.first @_ecosystems

    getBook: (ecosystemId) ->
      _.first( _.findWhere(@_ecosystems, id: parseInt(ecosystemId, 10)).books )

module.exports = {EcosystemsActions, EcosystemsStore}

_ = require 'underscore'
flux = require 'flux-react'

LOADING = 'loading'
FAILED  = 'failed'

EcosystemsActions = flux.createActions [
  'load'
  'loaded'
  'FAILED'
]

EcosystemsStore = flux.createStore
  actions: _.values(EcosystemsActions)

  _asyncStatus: null

  load: -> # Used by API
    @_asyncStatus = LOADING
    @emit('load')

  loaded: (ecosystems) ->
    @_ecosystems = ecosystems
    @emit('loaded')

  FAILED: ->
    @_asyncStatus = FAILED
    @emit('failed')

  exports:
    isLoaded: -> not _.isEmpty(@_ecosystems)
    isLoading: -> @_asyncStatus is LOADING
    isFailed:  -> @_asyncStatus is FAILED

    allBooks: ->
      _.map @_ecosystems, (ecosystem) ->
        _.extend( _.first(ecosystem.books), {ecosystemId: "#{ecosystem.id}", ecosystemComments: ecosystem.comments} )

    first: ->
      _.first @_ecosystems

    getBook: (ecosystemId) ->
      _.first( _.findWhere(@_ecosystems, id: parseInt(ecosystemId, 10)).books )

module.exports = {EcosystemsActions, EcosystemsStore}

Add ecosystem comments to book object

Add ecosystem comments to book object


Handlebars.registerHelper(
  "accountButtons", ->
    return new Handlebars.SafeString(Template.entryAccountButtons())
  )

Template.entryAccountButtons.helpers
  profileUrl: ->
    return false unless AccountsEntry.settings.profileRoute
    Router.path(AccountsEntry.settings.profileRoute)

  wrapLinks: ->
    AccountsEntry.settings.wrapLinks

Handlebars.registerHelper
  "accountButtons", ->
    return new Handlebars.SafeString(Template.entryAccountButtons())

Template.entryAccountButtons.helpers
  profileUrl: ->
    return false unless AccountsEntry.settings.profileRoute
    AccountsEntry.settings.profileRoute

  wrapLinks: ->
    AccountsEntry.settings.wrapLinks

Fix bug - routes are now paths not route names


{BufferedProcess} = require 'atom'
StatusView = require './status-view'

# if all param true, then 'git add .'
gitWrite = (all=false)->
  dir = atom.project.getRepo().getWorkingDirectory()
  currentFile = atom.workspace.getActiveEditor().getPath()
  toStage = if all then '.' else currentFile
  new BufferedProcess({
    command: 'git'
    args: ['add', toStage]
    options:
      cwd: dir
    stderr: (data) ->
      new StatusView(type: 'alert', message: data.toString())
    exit: (data) ->
      new StatusView(type: 'success', message: "Added #{toStage}")
  })

module.exports = gitWrite

{BufferedProcess} = require 'atom'
StatusView = require './status-view'

# if all param true, then 'git add .'
gitWrite = (all=false)->
  dir = atom.project.getRepo().getWorkingDirectory()
  currentFile = atom.workspace.getActiveEditor().getPath()
  toStage = if all then '.' else currentFile
  new BufferedProcess({
    command: 'git'
    args: ['add', toStage]
    options:
      cwd: dir
    stderr: (data) ->
      new StatusView(type: 'alert', message: data.toString())
    exit: (data) ->
      file = if toStage is '.' then 'all files' else toStage
      new StatusView(type: 'success', message: "Added #{file}")
  })

module.exports = gitWrite

Change GitWrite success message to show 'all files' or filepath


React = require 'react'
Router = require 'react-router'
DocumentTitle = require 'react-document-title'

RouteHandler = Router.RouteHandler
Link = Router.Link

module.exports = React.createClass
	render: ->
		title = 'Third Hand Information'
		<DocumentTitle title={ title }>

				 { title }

<Link to="app">Home</Link>

				<RouteHandler title={ title } {... @props }/>

		</DocumentTitle>

React = require 'react'
Router = require 'react-router'
DocumentTitle = require 'react-document-title'

RouteHandler = Router.RouteHandler
Link = Router.Link

module.exports = React.createClass
	displayName: 'App'
	render: ->
		title = 'Third Hand Information'
		<DocumentTitle title={ title }>

				 { title }

<Link to="app">Home</Link>

				<RouteHandler title={ title } {... @props }/>

		</DocumentTitle>

Set displayName on App for prettier debugging.


define ['../core', './field'], (c, field) ->

    class ConceptModel extends Backbone.Model
        parse: (resp) ->
            @fields = []
            # Parse and attach field model instances to concept
            for attrs in resp.fields
                @fields.push(new field.FieldModel attrs, parse: true)
            return resp

    class ConceptCollection extends Backbone.Collection
        model: ConceptModel

        url: ->
            c.getSessionUrl('concepts')

        initialize: ->
            super
            c.subscribe c.SESSION_OPENED, => @fetch()
            c.subscribe c.SESSION_CLOSED, => @reset()
            @on 'reset', @resolve

        search: (query, handler) ->
            c.Backbone.ajax
                url: c._.result @, 'url'
                data: q: query
                dataType: 'json'
                success: (resp) -> handler(resp)

    { ConceptModel, ConceptCollection }

define ['../core', './field'], (c, field) ->

    class ConceptModel extends c.Backbone.Model
        parse: (resp) ->
            @fields = []
            # Parse and attach field model instances to concept
            for attrs in resp.fields
                @fields.push(new field.FieldModel attrs, parse: true)
            return resp

    class ConceptCollection extends c.Backbone.Collection
        model: ConceptModel

        url: ->
            c.getSessionUrl('concepts')

        initialize: ->
            super
            c.subscribe c.SESSION_OPENED, => @fetch()
            c.subscribe c.SESSION_CLOSED, => @reset()
            @on 'reset', @resolve

        search: (query, handler) ->
            c.Backbone.ajax
                url: c._.result @, 'url'
                data: q: query
                dataType: 'json'
                success: (resp) -> handler(resp)

    { ConceptModel, ConceptCollection }

Fix missing reference to cilantro namespace


Whitespace = require './whitespace'

module.exports =
  configDefaults:
    removeTrailingWhitespace: true
    ignoreWhitespaceOnCurrentLine: true
    ignoreWhitespaceOnlyLines: false
    ensureSingleTrailingNewline: true

  activate: ->
    @whitespace = new Whitespace()

  deactivate: ->
    @whitespace?.destroy()
    @whitespace = null

Whitespace = require './whitespace'

module.exports =
  config:
    removeTrailingWhitespace:
      type: 'boolean'
      default: true
      scopes:
        '.source.jade':
          default: false
    ignoreWhitespaceOnCurrentLine:
      type: 'boolean'
      default: true
    ignoreWhitespaceOnlyLines:
      type: 'boolean'
      default: false
    ensureSingleTrailingNewline:
      type: 'boolean'
      default: true

  activate: ->
    @whitespace = new Whitespace()

  deactivate: ->
    @whitespace?.destroy()
    @whitespace = null

Convert configDefaults into config schema

Default jade to removeWhitespace: false


#= require ./vendor/qunit

QUnit.config.hidepassed = true
QUnit.config.testTimeout = 5000

QUnit.begin (suiteDetails) ->
  Blade.suiteDidBegin(suiteDetails)

failedAssertions = []

QUnit.testStart (testDetails) ->
  failedAssertions = []

QUnit.log (assertionDetails) ->
  unless assertionDetails.result
    failedAssertions.push(assertionDetails)

QUnit.testDone (testDetails) ->
  name = "#{testDetails.module}: #{testDetails.name}"
  pass = testDetails.failed is 0
  message = formatAssertions(failedAssertions)
  Blade.testDidEnd({name, pass, message})

QUnit.done (suiteDetails) ->
  window.global_test_results = suiteDetails
  Blade.suiteDidEnd(suiteDetails)

formatAssertions = (assertions = []) ->
  if assertions.length
    (formatAssertion(assertion) for assertion in assertions).join("\n---\n")

formatAssertion = ({message, actual, expected, source}) ->
  lines = []
  if message
    lines.push("Message: #{JSON.stringify(message)}")
  if expected
    lines.push("Expected: #{JSON.stringify(expected)}")
  if actual
    lines.push("Actual: #{JSON.stringify(actual)}")
  if source
    lines.push("Source:")
    for sourceLine in source.split("\n").slice(0,3)
      lines.push("  #{sourceLine.trim()}")
  lines.join("\n")

#= require ./vendor/qunit

QUnit.config.hidepassed = true
QUnit.config.testTimeout = 5000

QUnit.begin (suiteDetails) ->
  total = suiteDetails.totalTests
  Blade.suiteDidBegin({total})

failedAssertions = []

QUnit.testStart (testDetails) ->
  failedAssertions = []

QUnit.log (assertionDetails) ->
  unless assertionDetails.result
    failedAssertions.push(assertionDetails)

QUnit.testDone (testDetails) ->
  name = "#{testDetails.module}: #{testDetails.name}"
  status = if testDetails.failed is 0 then "pass" else "fail"
  message = formatAssertions(failedAssertions)
  Blade.testDidEnd({name, status, message})

QUnit.done (suiteDetails) ->
  window.global_test_results = suiteDetails
  total = suiteDetails.totalTests
  Blade.suiteDidEnd({total})

formatAssertions = (assertions = []) ->
  if assertions.length
    (formatAssertion(assertion) for assertion in assertions).join("\n---\n")

formatAssertion = ({message, actual, expected, source}) ->
  lines = []
  if message
    lines.push("Message: #{JSON.stringify(message)}")
  if expected
    lines.push("Expected: #{JSON.stringify(expected)}")
  if actual
    lines.push("Actual: #{JSON.stringify(actual)}")
  if source
    lines.push("Source:")
    for sourceLine in source.split("\n").slice(0,3)
      lines.push("  #{sourceLine.trim()}")
  lines.join("\n")

Fix "total", set "status" not "pass"

Fix "total", set "status" not "pass"


window.bone = {}

eventSplitter = /^(\S+)\s*(.*)$/

setupEvent = (eventName, rootSelector, selector, action) ->

bone.view = (selector, options) ->
    view = {}
    events = options.events
    for eventSelector, functionName of events
        continue if functionName is 'events'
        do (eventSelector, functionName) ->
            match = eventSelector.match eventSplitter
            eventName = match[1]
            subSelector = match[2]
            fullSelector = selector
            fullSelector += " #{subSelector}" if subSelector?
            action = options[functionName]
            #View: [Selector:Action]
            console.log('View: ['+fullSelector+" : "+eventName+"]");
            $('body').on eventName, fullSelector, (event) ->
                root = $(fullSelector).parents(selector)[0]
                action root, event

    for name, action of options
        continue if name is 'events'
        do (name, action) ->
            view[name] = (data) ->
                for element in $(selector)
                    do (element) ->
                        action element, data
    return view

bone.io = {}

bone.io.sources = {}

bone.io.get = (source) ->
    socket = bone.io.sources[source]
    return socket if socket?
    socket = io.connect()
    bone.io.sources[source] = socket
    return socket

bone.io.route = (source, actions) ->
    socket = bone.io.get(source)
    for name, action of actions
        socket.on "#{source}:#{name}", action

bone.io.configure = (source, options) ->
    # Configure this somehow...

window.bone = {}

eventSplitter = /^(\S+)\s*(.*)$/

setupEvent = (eventName, rootSelector, selector, action) ->

bone.view = (selector, options) ->
    view = {}
    events = options.events
    for eventSelector, functionName of events
        continue if functionName is 'events'
        do (eventSelector, functionName) ->
            match = eventSelector.match eventSplitter
            eventName = match[1]
            subSelector = match[2]
            fullSelector = selector
            fullSelector += " #{subSelector}" if subSelector?
            action = options[functionName]
            #View: [Selector:Action]
            console.log('View: ['+fullSelector+" : "+eventName+"]");
            $ -> $('body').on eventName, fullSelector, (event) ->
                root = $(fullSelector).parents(selector)[0]
                action root, event

    for name, action of options
        continue if name is 'events'
        do (name, action) ->
            view[name] = (data) ->
                for element in $(selector)
                    do (element) ->
                        action element, data
    return view

bone.io = {}

bone.io.sources = {}

bone.io.get = (source) ->
    socket = bone.io.sources[source]
    return socket if socket?
    socket = io.connect()
    bone.io.sources[source] = socket
    return socket

bone.io.route = (source, actions) ->
    socket = bone.io.get(source)
    for name, action of actions
        socket.on "#{source}:#{name}", action

bone.io.configure = (source, options) ->
    # Configure this somehow...

Move ready function into view.

Move ready function into view.


noflo = require 'noflo'

class IDBJournalStore extends noflo.journal.JournalStore
  constructor: (graph, @db) ->
    super graph
    @transactions = []

  genKey: (revId) -> "#{@graph.properties.id}_#{revId}"

  putTransaction: (revId, entries) ->
    @lastRevision = revId if revId > @lastRevision
    trans = @db.transaction ['journals'], 'readwrite'
    store = trans.objectStore 'journals'

    # We're using add for writing, which will correctly fail if revId alreadyn exists
    # for the graph
    req = store.add
      id: @genKey revId
      graph: @graph.properties.id
      revId: revId
      entries: entries

  fetchTransaction: (revId) ->
    return @transactions[revId]

  init: (cb) ->
    trans = @db.transaction ['journals']
    store = trans.objectStore 'journals'
    idx = store.index 'graph'
    idx.openCursor().onsuccess = (event) =>
      cursor = event.target.result
      return cb() unless cursor
      @transactions[cursor.value.revId] = cursor.value.entries
      @lastRevision = cursor.value.revId if cursor.value.revId > @lastRevision
      do cursor.continue

exports.IDBJournalStore = IDBJournalStore

noflo = require 'noflo'

class IDBJournalStore extends noflo.journal.JournalStore
  constructor: (graph, @db) ->
    super graph
    @transactions = []

  genKey: (revId) -> "#{@graph.properties.id}_#{revId}"

  putTransaction: (revId, entries) ->
    super revId, entries

    trans = @db.transaction ['journals'], 'readwrite'
    store = trans.objectStore 'journals'

    # We're using add for writing, which will correctly fail if revId alreadyn exists
    # for the graph
    req = store.add
      id: @genKey revId
      graph: @graph.properties.id
      revId: revId
      entries: entries

    @transactions[revId] = entries

  fetchTransaction: (revId) ->
    return @transactions[revId]

  init: (cb) ->
    trans = @db.transaction ['journals']
    store = trans.objectStore 'journals'
    idx = store.index 'graph'
    idx.openCursor().onsuccess = (event) =>
      cursor = event.target.result
      return cb() unless cursor
      @transactions[cursor.value.revId] = cursor.value.entries
      @lastRevision = cursor.value.revId if cursor.value.revId > @lastRevision
      do cursor.continue

exports.IDBJournalStore = IDBJournalStore

Call parent to get events going for journal activities


entryModule = angular.module("entertain.io.app.entry", [])

.controller 'EntryCtrl', ['$scope', '$http'
  ($scope, $http) ->
    $scope.entries = []

    socket = io()

    $scope.userAmount = 0

    $scope.yeah = ->
      socket.emit 'yeah', "foobar"
      false

    socket.on 'userAmount', (msg) ->
      $scope.userAmount = msg
      $scope.$apply()
      return

    socket.on 'yeah', (socket) ->
      console.log "OMFG"
      return

]

module.exports = entryModule.name

entryModule = angular.module("entertain.io.app.entry", [])

.controller 'EntryCtrl', ['$scope', '$http'
  ($scope, $http) ->
    $scope.entries = []

    socket = io()

    $scope.updateFeed = ->
      socket.emit 'updateFeed'
      false

    socket.on 'feedUpdate', (feeds) ->
      $scope.entries.push feeds
      $scope.$apply()
      return

]

module.exports = entryModule.name

Update Client-Logic (recieve feeds fromt the server)


describe 'when', ->
  Given -> @when = requireSubject('lib/when')
  Given -> @create = requireSubject('lib/create')

  describe 'unconditional stubbing', ->
    Given -> @testDouble = @create()
    context 'foo', ->
      Given -> @when(@testDouble()).thenReturn("foo")
      Then -> @testDouble() == "foo"
    context 'bar', ->
      Given -> @when(@testDouble()).thenReturn("bar")
      Then -> @testDouble() == "bar"

  describe 'conditional stubbing', ->
    Given -> @testDouble = @create()
    Given -> @when(@testDouble(1)).thenReturn("foo")
    Given -> @when(@testDouble(2)).thenReturn("bar")
    Then -> @testDouble() == undefined
    Then -> @testDouble(1) == "foo"
    Then -> @testDouble(2) == "bar"

  describe 'multiple test doubles', ->
    Given -> @td1 = @when(@create()()).thenReturn("lol1")
    Given -> @td2 = @when(@create()()).thenReturn("lol2")
    Then -> @td1() == "lol1"
    Then -> @td2() == "lol2"

describe 'when', ->
  Given -> @when = requireSubject('lib/when')
  Given -> @create = requireSubject('lib/create')

  describe 'unconditional stubbing', ->
    Given -> @testDouble = @create()
    context 'foo', ->
      Given -> @when(@testDouble()).thenReturn("foo")
      Then -> @testDouble() == "foo"
    context 'bar', ->
      Given -> @when(@testDouble()).thenReturn("bar")
      Then -> @testDouble() == "bar"

  describe 'conditional stubbing', ->
    Given -> @testDouble = @create()
    Given -> @when(@testDouble(1)).thenReturn("foo")
    Given -> @when(@testDouble(2)).thenReturn("bar")
    Given -> @when(@testDouble(lol: 'cheese')).thenReturn('nom')
    Given -> @when(@testDouble(lol: 'fungus')).thenReturn('eww')
    Given -> @when(@testDouble({lol: 'fungus'}, 2)).thenReturn('eww2')
    Then -> @testDouble() == undefined
    And -> @testDouble(1) == "foo"
    And -> @testDouble(2) == "bar"
    And -> @testDouble(lol: 'cheese') == "nom"
    And -> @testDouble(lol: 'fungus') == "eww"
    And -> @testDouble({lol: 'fungus'}, 2) == "eww2"

  describe 'multiple test doubles', ->
    Given -> @td1 = @when(@create()()).thenReturn("lol1")
    Given -> @td2 = @when(@create()()).thenReturn("lol2")
    Then -> @td1() == "lol1"
    Then -> @td2() == "lol2"

Add some complexities to the conditional stubbing


do ->

  KD.registerRoutes 'IDE',

    '/:name?/IDE' : ({params:{name}, query})->
      router = KD.getSingleton 'router'
      router.openSection 'IDE', name, query

    '/:name?/IDE/VM' : ({params:{name}, query})->
      KD.singletons.router.handleRoute 'IDE'

    '/:name?/IDE/VM/:slug' : ({params:{name, slug}, query})->
      {appManager} = KD.singletons
      callback = (app) ->
        log '@acet handle this VM please', slug
      appManager.open 'IDE', callback

do ->

  KD.registerRoutes 'IDE',

    '/:name?/IDE' : ({params:{name}, query})->

      router = KD.getSingleton 'router'
      router.openSection 'IDE', name, query

    '/:name?/IDE/VM/:slug' : ({params:{name, slug}, query})->

      appManager  = KD.getSingleton 'appManager'
      ideApps     = appManager.appControllers.IDE
      fallback    = ->
        appManager.open 'IDE', { forceNew: yes }, (app) ->
          app.mountedMachineUId = slug

      return fallback()  unless ideApps?.instances

      for instance in ideApps.instances when instance.mountedMachineUId is slug
          ideInstance = instance

      if ideInstance then appManager.showInstance ideInstance else fallback()

Finder: Handle route to mount VM specific filetree.


@expectRequiredParameters = (type, expectedParameterNames) ->
  originalType = type
  paramList = {}

  #check is this is an Abstract type
  if(type.isAbstract && type.isAbstract())
    type = class A extends type

  #add the super classes parameters so that they arent in the tests
  if originalType.__super__ && originalType.__super__.constructor
    for name in originalType.__super__.constructor.expectedParameters
      paramList[name] = name

  doTest = (name, params) ->
    it "should fail without parameter '#{name}'", ->
      try
        new type params
        expect("Should have failed").toEqual("because parameter is required")
      catch e
        if e.getRootError
          message = e.getRootError().message
        else
          message = e.message

        expect(message).toEqual("The constructor expects the parameter '#{name}' to be passed in as a config parameter")

  describe "New Object", ->
    for name in expectedParameterNames
      #build each test case for expected parameters
      params = _.clone(paramList) if _.toArray(paramList).length > 0
      doTest(name, params)
      paramList[name] = name

@expectRequiredParameters = (type, expectedParameterNames) ->
  originalType = type
  paramList = {}
  baseExpectedParams = []

  #check is this is an Abstract type
  if(type.isAbstract && type.isAbstract())
    type = class A extends type

  #add the super classes parameters so that they arent in the tests
  if originalType.__super__ && originalType.__super__.constructor && originalType.__super__.constructor.expectedParameters
    baseExpectedParams = originalType.__super__.constructor.expectedParameters
    for name in originalType.__super__.constructor.expectedParameters
      paramList[name] = name

  doTest = (name, params) ->
    it "should fail without parameter '#{name}'", ->
      try
        new type params
        expect("Should have failed").toEqual("because parameter is required")
      catch e
        if e.getRootError
          message = e.getRootError().message
        else
          message = e.message

        expect(message).toEqual("The constructor expects the parameter '#{name}' to be passed in as a config parameter")

  describe "New Object", ->
    #if this has expectedParameters then make sure we are testing for all expected params
    if(originalType.expectedParameters)
      it "should be testing for all expected parameters", ->
        diff = _.difference(originalType.expectedParameters, baseExpectedParams)
        expect(expectedParameterNames).toEqual(diff)

    for name in expectedParameterNames
      #build each test case for expected parameters
      params = _.clone(paramList) if _.toArray(paramList).length > 0
      doTest(name, params)
      paramList[name] = name

Add default test when checking Expected parameters to ensure that tests are being aware of 'required' option params


runtime = require '../src/runtime'

## Main
program = require 'commander'

main = () ->
  program
    .option('--host <hostname>', 'Host', String, 'localhost')
    .option('--port <port>', 'Port', Number, 3569)
    .option('--broker <uri>', 'Broker address', String, 'amqp://localhost')
    .option('--ide <uri>', 'FBP IDE address', String, 'http://app.flowhub.io')
    .option('--graph <file.json>', 'Initial graph to load', String, '')
    .parse(process.argv)

  r = new runtime.Runtime program
  r.start (err, address, liveUrl) ->
    throw err if err
    console.log "msgflo started on #{address}"
    console.log 'Open in Flowhub: ' + liveUrl

exports.main = main
exports.transport = require('msgflo-nodejs').transport
exports.participant = require('msgflo-nodejs').participant
exports.foreignParticipant = require '../src/foreign-participant'

exports.coordinator = require '../src/coordinator'
exports.runtime = require '../src/runtime'
exports.common = require '../src/common'
exports.setup = require '../src/setup'
exports.manager = require '../src/manager'
exports.library = require '../src/library'
exports.procfile = require '../src/procfile'
exports.utils
  spy: require '../src/utils/spy'

Make available as public interface

utils/spy: Make available as public interface


SYNC_RESPONSE = {}

Lanes.Test.syncSucceedWith = (data) ->
    SYNC_RESPONSE.success = true
    SYNC_RESPONSE.total = data.length if _.isArray(data)
    SYNC_RESPONSE.data = _.cloneDeep(data)

Lanes.Test.syncRespondWith = (obj) ->
    _.extend(SYNC_RESPONSE, obj)

afterEach ->
    Lanes.current_user._events = @__user_events

beforeEach ->
    @__user_events = Lanes.current_user._events
    Lanes.Models.ServerCache.MODELS = {}
    Lanes.Models.ServerCache.COLLECTIONS = {}
    window.LT = Lanes.Test

    SYNC_RESPONSE = {
        success: true
        message: ''
        data: []
    }

    originalFn = Lanes.Models.Sync.perform
    spyOn(Lanes.Models.Sync, 'perform').and.callFake( (method, options) ->
        _.Promise.resolve(SYNC_RESPONSE)
    )
    Lanes.Models.Sync.perform.lastOptions = ->
        this.calls.mostRecent()?.args[1]
    Lanes.Models.Sync.restorePerform = (fn) ->
        spy = Lanes.Models.Sync.perform
        Lanes.Models.Sync.perform = originalFn
        try
            fn()
        finally
            Lanes.Models.Sync.perform = spy

SYNC_RESPONSE = {}

Lanes.Test.syncSucceedWith = (data) ->
    SYNC_RESPONSE.success = true
    SYNC_RESPONSE.total = data.length if _.isArray(data)
    SYNC_RESPONSE.data = _.cloneDeep(data)

Lanes.Test.syncRespondWith = (obj) ->
    _.extend(SYNC_RESPONSE, obj)

afterEach ->
    Lanes.current_user._events = @__user_events
    Lanes.Models.PubSub.types.reset()
    Lanes.Models.PubSub.mb = @prevMB

beforeEach ->
    @__user_events = Lanes.current_user._events
    Lanes.Models.ServerCache.MODELS = {}
    Lanes.Models.ServerCache.COLLECTIONS = {}
    window.LT = Lanes.Test

    SYNC_RESPONSE = {
        success: true
        message: ''
        data: []
    }

    @prevMB = Lanes.Models.PubSub.mb
    Lanes.Models.PubSub.mb = jasmine.createSpyObj('MessageBus', [
        'subscribe', 'unsubscribe'
    ])

    originalFn = Lanes.Models.Sync.perform
    spyOn(Lanes.Models.Sync, 'perform').and.callFake( (method, options) ->
        _.Promise.resolve(SYNC_RESPONSE)
    )
    Lanes.Models.Sync.perform.lastOptions = ->
        this.calls.mostRecent()?.args[1]
    Lanes.Models.Sync.restorePerform = (fn) ->
        spy = Lanes.Models.Sync.perform
        Lanes.Models.Sync.perform = originalFn
        try
            fn()
        finally
            Lanes.Models.Sync.perform = spy

Reset PubSub after each spec

Reset PubSub after each spec


class App

  Routers: {}

  Models: {}

  Collections: {}

  Views: {}

  init: ->
    window.flight = new Flight()
    new @Routers.AppRouter
    Backbone.history.start()

    @Collections.Activities.fetch()

window.app = new App

`
String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/g, '');
};
String.prototype.truncate = function(n,useWordBoundary) {
     var toLong = this.length>n,
         s_ = toLong ? this.substr(0,n-1) : this;
     s_ = useWordBoundary && toLong ? s_.substr(0,s_.lastIndexOf(' ')) : s_;
     return  toLong ? s_ +'...' : s_;
};
String.prototype.escapeHTML = function () {
    return(this.replace(/&/g,'&').replace(/>/g,'>').replace(/</g,'<').replace(/"/g,'"'));
};
String.prototype.ellipse = function(len) {
  return (this.length > len) ? this.substr(0, len) + "..." : this;
}
`

class App

  Routers: {}

  Models: {}

  Collections: {}

  Views: {}

  init: ->
    window.flight = new Flight()
    new @Routers.AppRouter
    Backbone.history.start()

    @Collections.Activities.fetch()

    $('#menu-button').click ->
      flight.slideOutMenu()

window.app = new App

`
String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/g, '');
};
String.prototype.truncate = function(n,useWordBoundary) {
     var toLong = this.length>n,
         s_ = toLong ? this.substr(0,n-1) : this;
     s_ = useWordBoundary && toLong ? s_.substr(0,s_.lastIndexOf(' ')) : s_;
     return  toLong ? s_ +'...' : s_;
};
String.prototype.escapeHTML = function () {
    return(this.replace(/&/g,'&').replace(/>/g,'>').replace(/</g,'<').replace(/"/g,'"'));
};
String.prototype.ellipse = function(len) {
  return (this.length > len) ? this.substr(0, len) + "..." : this;
}
`

Call menu on menu button click, this should be a class.


class AppRouter extends Backbone.Router

  routes:
    '': 'homePage'
    'panel/:id': 'goToPanel'

  homePage: ->
    collection = new app.Collections.ActivityCollection
    @view = new app.Views.Home collection: collection
    collection.fetch()

    flight.goTo "#panel-1"

  goToPanel: (id) ->
    @view = new app.Views["Panel_" + id]
    page = @view.render(id).el
    flight.goTo page

@app = window.app ? {}
@app.Routers.AppRouter = AppRouter

class AppRouter extends Backbone.Router

  routes:
    '': 'homePage'
    'panel/:id': 'goToPanel'

  homePage: ->
    collection = new app.Collections.ActivityCollection
    @view = new app.Views.Home collection: collection
    collection.fetch()
    @view.render()
    flight.goTo "#panel-1"

  goToPanel: (id) ->
    @view = new app.Views["Panel_" + id]
    @view.render(id).el
    flight.goTo "#panel-" + id

@app = window.app ? {}
@app.Routers.AppRouter = AppRouter

Use id's to transition page instead of rendered page element.


'menu': [
  'label': 'Packages'
  'submenu': [
    'label': 'Markdown'
    'submenu': [
      'label': 'Toggle Preview'
      'command': 'markdown-preview:toggle'
    ]
  ]
]

'context-menu':
  '.markdown-preview':
    'Save As HTML\u2026': 'core:save-as'

Add save as HTML menu

Add save as HTML menu


__ = window.i18n.data.__.bind(i18n.data)
__n = window.i18n.data.__n.bind(i18n.data)

types =
  "api_taik": "HP"
  "api_souk": "Armor"
  "api_houg": "Firepower"
  "api_raig": "Torpedo"
  "api_soku": "Speed"
  "api_baku": "Bombing"
  "api_tyku": "AA"
  "api_tais": "ASW"
  "api_houm": "Accuracy"
  "api_raim": "Torpedo Accuracy"
  "api_houk": "Evasion"
  "api_raik": "Torpedo Evasion"
  "api_bakk": "Bombing Evasion"
  "api_saku": "LOS"
  "api_sakb": "Anti-LOS"
  "api_luck": "Luck"
  "api_leng": "Range"

module.exports =
  getItemData: (slotitem) ->
    data = []
    for type of types
      if slotitem[type] > 0
        data.push "#{__ types[type]}: #{slotitem[type]}"
    return data

if window.i18n?.data?
  __ = window.i18n.data.__.bind(i18n.data)
else
  path = require 'path-extra'
  i18n = new (require 'i18n-2')
    locales: ['en-US', 'ja-JP', 'zh-CN', 'zh-TW']
    defaultLocale: 'zh-CN'
    directory: path.join ROOT, 'i18n', 'data'
    updateFiles: false
    indent: "\t"
    extension: '.json'
    devMode: false
  i18n.setLocale(window.language)
  __ = i18n.__.bind(i18n)

types =
  "api_taik": "HP"
  "api_souk": "Armor"
  "api_houg": "Firepower"
  "api_raig": "Torpedo"
  "api_soku": "Speed"
  "api_baku": "Bombing"
  "api_tyku": "AA"
  "api_tais": "ASW"
  "api_houm": "Accuracy"
  "api_raim": "Torpedo Accuracy"
  "api_houk": "Evasion"
  "api_raik": "Torpedo Evasion"
  "api_bakk": "Bombing Evasion"
  "api_saku": "LOS"
  "api_sakb": "Anti-LOS"
  "api_luck": "Luck"
  "api_leng": "Range"

module.exports =
  getItemData: (slotitem) ->
    data = []
    for type of types
      if slotitem[type] > 0
        data.push "#{__ types[type]}: #{slotitem[type]}"
    return data

Add i18n when env.coffee isn't required

Add i18n when env.coffee isn't required


sys = require "sys"
fs = require "fs"
assert_module = require "assert"
coffee = require "coffee-script"
helpers = require("coffee-script/helpers").helpers

# Parse our command-line arguments.
test_file_paths = process.argv[1...process.argv.length]

# Set up a basic test environment.  This code is based on the code at
# http://github.com/jashkenas/coffee-script/blob/master/Cakefile ,
# which implements the standard Coffee
passed = failed = 0
helpers.extend global, assert_module
global.ok = (args...) ->
  res = assert_module.ok(args...)
  passed += 1
  res

# Called when the tests are done.
testsDone = ->
  tag = if failed > 0 then "ERR" else "OK"
  sys.puts "#{tag}: #{passed} passed, #{failed} failed"
  if failed > 0
    process.exit(1)

# Pretend to run our test files.  Again, this is based on the standard
# Cakefile.
files_left = test_file_paths.length
for path in test_file_paths
  fs.readFile path, (err, data) ->
    files_left -= 1
    try
      coffee.run data.toString(), fileName: path
    catch err
      failed += 1
      sys.puts err.stack.toString()
    if files_left is 0
      testsDone()

sys = require "sys"
fs = require "fs"
assert_module = require "assert"
coffee = require "coffee-script"
helpers = require("coffee-script/helpers").helpers

# Parse our command-line arguments.
test_file_paths = process.argv[1...process.argv.length]

# ANSI color codes.  Borrowed from
# http://github.com/jashkenas/coffee-script/blob/master/Cakefile , which
# implements a test runner for internal use by CoffeeScript.
red   = '\033[0;31m'
green = '\033[0;32m'
reset = '\033[0m'

# Set up a basic test environment.  Based on the standard Cakefile.
passed = failed = 0
helpers.extend global, assert_module
global.ok = (args...) ->
  res = assert_module.ok(args...)
  passed += 1
  res

# Called when the tests are done.
testsDone = ->
  tag = if failed > 0 then "#{red}ERR" else "#{green}OK"
  sys.puts "\n#{tag}:#{reset} #{passed} passed, #{failed} failed"
  if failed > 0
    process.exit(1)

# Pretend to run our test files.  Again, this is based on the standard
# Cakefile.
files_left = test_file_paths.length
for path in test_file_paths
  fs.readFile path, (err, data) ->
    files_left -= 1
    try
      coffee.run data.toString(), fileName: path
      sys.print "."
    catch err
      failed += 1
      sys.puts "\n#{err.stack.toString()}"
    if files_left is 0
      testsDone()

Make cosmetic improvements to the output


fs = require 'fs'
path = require 'path'

{sync: resolve} = require 'resolve'

CORE_MODULES = require './core-modules'
isCore = require './is-core'
canonicalise = require './canonicalise'

resolvePath = ({extensions, aliases, root, cwd, path: givenPath}, pkgMainField = 'browser') ->
  packageFilter = (pkg) ->
    if pkg[pkgMainField]
      pkg.main = pkg[pkgMainField]
    return pkg
  aliases ?= {}
  if isCore givenPath
    return if {}.hasOwnProperty.call aliases, givenPath
    corePath = CORE_MODULES[givenPath]
    unless fs.existsSync corePath
      throw new Error "Core module \"#{givenPath}\" has not yet been ported to the browser"
    givenPath = corePath
  # try regular CommonJS requires
  try
    resolve givenPath, {extensions, basedir: cwd or root, packageFilter}
  catch e
    # support non-standard root-relative requires
    try
      resolve (path.join root, givenPath), {extensions, packageFilter}
    catch e
      throw new Error "Cannot find module \"#{givenPath}\" in \"#{root}\""

module.exports = ({extensions, aliases, root, cwd, path: givenPath}) ->
  aliases ?= {}
  resolved = resolvePath {extensions, aliases, root, cwd, path: givenPath}
  canonicalName = if isCore givenPath then givenPath else canonicalise root, resolved
  if {}.hasOwnProperty.call aliases, canonicalName
    resolved = aliases[canonicalName] and resolvePath {extensions, aliases, root, path: aliases[canonicalName]}
  {filename: resolved, canonicalName}

fs = require 'fs'
path = require 'path'

{sync: resolve} = require 'resolve'

CORE_MODULES = require './core-modules'
isCore = require './is-core'
canonicalise = require './canonicalise'

resolvePath = ({extensions, aliases, root, cwd, path: givenPath}, pkgMainField = 'browser') ->
  packageFilter = (pkg) ->
    if pkg[pkgMainField]
      pkg.main = pkg[pkgMainField]
    return pkg
  aliases ?= {}
  if isCore givenPath
    return if {}.hasOwnProperty.call aliases, givenPath
    corePath = CORE_MODULES[givenPath]
    unless fs.existsSync corePath
      throw new Error "Core module \"#{givenPath}\" has not yet been ported to the browser"
    givenPath = corePath
  # try regular CommonJS requires
  try
    resolve givenPath, {extensions, basedir: cwd or root, packageFilter}
  catch e
    # support non-standard root-relative requires
    try
      resolve (path.join root, givenPath), {extensions, packageFilter}
    catch e
      throw new Error "Cannot find module \"#{givenPath}\" in \"#{root}\""

module.exports = ({extensions, aliases, root, cwd, path: givenPath}) ->
  aliases ?= {}
  resolved = resolvePath {extensions, aliases, root, cwd, path: givenPath}
  canonicalName = canonicalise root, resolved
  if {}.hasOwnProperty.call aliases, canonicalName
    resolved = aliases[canonicalName] and resolvePath {extensions, aliases, root, path: aliases[canonicalName]}
  {filename: resolved, canonicalName}

Fix canonicalization of core modules

Fix canonicalization of core modules


path = require 'path'
fs = require 'fs-plus'

# This is loaded by atom.coffee. See https://atom.io/docs/api/latest/Config for
# more information about config schemas.
module.exports =
  core:
    type: 'object'
    properties:
      showUnreadBadge:
        type: 'boolean'
        default: true
      showImportant:
        type: 'boolean'
        default: true
      disabledPackages:
        type: 'array'
        default: []
        items:
          type: 'string'
      themes:
        type: 'array'
        default: ['ui-light']
        items:
          type: 'string'
      keymapTemplate:
        type: 'string'
        default: 'Gmail'
      attachments:
        type: 'object'
        properties:
          downloadPolicy:
            type: 'string'
            default: 'on-read'
            enum: ['on-receive', 'on-read', 'manually']
      reading:
        type: 'object'
        properties:
          markAsReadDelay:
            type: 'integer'
            default: 500
      sending:
        type: 'object'
        properties:
          sounds:
            type: 'boolean'
            default: true
          defaultReplyType:
            type: 'string'
            default: 'reply-all'
            enum: ['reply', 'reply-all']

if process.platform in ['win32', 'linux']
  module.exports.core.properties.autoHideMenuBar =
    type: 'boolean'
    default: false
    description: 'Automatically hide the menu bar and toggle it by pressing Alt. This is only supported on Windows & Linux.'

path = require 'path'
fs = require 'fs-plus'

# This is loaded by atom.coffee. See https://atom.io/docs/api/latest/Config for
# more information about config schemas.
module.exports =
  core:
    type: 'object'
    properties:
      workspace:
        type: 'object'
        properties:
          mode:
            type: 'string'
            default: 'list'
            enum: ['split', 'list']
      showUnreadBadge:
        type: 'boolean'
        default: true
      showImportant:
        type: 'boolean'
        default: true
      disabledPackages:
        type: 'array'
        default: []
        items:
          type: 'string'
      themes:
        type: 'array'
        default: ['ui-light']
        items:
          type: 'string'
      keymapTemplate:
        type: 'string'
        default: 'Gmail'
      attachments:
        type: 'object'
        properties:
          downloadPolicy:
            type: 'string'
            default: 'on-read'
            enum: ['on-receive', 'on-read', 'manually']
      reading:
        type: 'object'
        properties:
          markAsReadDelay:
            type: 'integer'
            default: 500
      sending:
        type: 'object'
        properties:
          sounds:
            type: 'boolean'
            default: true
          defaultReplyType:
            type: 'string'
            default: 'reply-all'
            enum: ['reply', 'reply-all']

if process.platform in ['win32', 'linux']
  module.exports.core.properties.autoHideMenuBar =
    type: 'boolean'
    default: false
    description: 'Automatically hide the menu bar and toggle it by pressing Alt. This is only supported on Windows & Linux.'

fix(workspace-mode): Add to config schema so it defaults to list properly


url = require 'url'
fs = require 'fs-plus'

MarkdownPreviewView = require './markdown-preview-view'

module.exports =
  configDefaults:
    grammars: [
      'source.gfm'
      'text.plain'
      'text.plain.null-grammar'
    ]

  activate: ->
    atom.workspaceView.command 'markdown-preview:show', =>
      @show()

    atom.workspace.registerOpener (uriToOpen) ->
      {protocol, host, pathname} = url.parse(uriToOpen)
      pathname = decodeURI(pathname) if pathname
      return unless protocol is 'markdown-preview:'

      if host is 'editor'
        new MarkdownPreviewView(editorId: pathname.substring(1))
      else
        new MarkdownPreviewView(filePath: pathname)

  show: ->
    editor = atom.workspace.getActiveEditor()
    return unless editor?

    grammars = atom.config.get('markdown-preview.grammars') ? []
    return unless editor.getGrammar().scopeName in grammars

    previousActivePane = atom.workspace.getActivePane()
    uri = "markdown-preview://editor/#{editor.id}"
    atom.workspace.open(uri, split: 'right', searchAllPanes: true).done (markdownPreviewView) ->
      if markdownPreviewView instanceof MarkdownPreviewView
        markdownPreviewView.renderMarkdown()
        previousActivePane.activate()

url = require 'url'
fs = require 'fs-plus'

MarkdownPreviewView = require './markdown-preview-view'

module.exports =
  configDefaults:
    grammars: [
      'source.gfm'
      'source.litcoffee'
      'text.plain'
      'text.plain.null-grammar'
    ]

  activate: ->
    atom.workspaceView.command 'markdown-preview:show', =>
      @show()

    atom.workspace.registerOpener (uriToOpen) ->
      {protocol, host, pathname} = url.parse(uriToOpen)
      pathname = decodeURI(pathname) if pathname
      return unless protocol is 'markdown-preview:'

      if host is 'editor'
        new MarkdownPreviewView(editorId: pathname.substring(1))
      else
        new MarkdownPreviewView(filePath: pathname)

  show: ->
    editor = atom.workspace.getActiveEditor()
    return unless editor?

    grammars = atom.config.get('markdown-preview.grammars') ? []
    return unless editor.getGrammar().scopeName in grammars

    previousActivePane = atom.workspace.getActivePane()
    uri = "markdown-preview://editor/#{editor.id}"
    atom.workspace.open(uri, split: 'right', searchAllPanes: true).done (markdownPreviewView) ->
      if markdownPreviewView instanceof MarkdownPreviewView
        markdownPreviewView.renderMarkdown()
        previousActivePane.activate()

Add source.litcoffee to default grammars

Closes #38


Presenters = require "../lib/presenters"
helpers = require "./helpers"

describe "Presenters", ->

  before ->
    @prediction1 = new helpers.PredictionStub stopName: "Michigan & 29th Street"
    @prediction2 = new helpers.PredictionStub {stopName: "Michigan & 28th Street", minutesFromNow: 1}
    @allPredictions = [@prediction1, @prediction2]

  describe "WebPresenter", ->
    beforeEach ->
      @presenter = new Presenters.WebPresenter({}, @allPredictions)

    describe "formatPredictions", ->
      it "returns an object with values for the given prediction data", ->
        @presenter.formatPrediction(@prediction2).should.eql
          stopName: '28th Street'
          estimate: 1
          percentComplete: 90

    describe "buildTitle", ->
      it "returns an object with route data", ->
        @presenter.buildTitle().should.eql
          routeNumber: '1'
          routeDirection: 'North Bound'
          busNumber: '1234'

    # describe "generateBody", ->

    # describe "respond", ->

  describe "SMSPresenter", ->
    beforeEach ->
      @presenter = new Presenters.SMSPresenter({}, @allPredictions)

    describe "formatPredictions", ->
      it "returns a string for the given prediction", ->
        @presenter.formatPrediction(@prediction2).should.equal "In 1m: 28th Street"

    describe "buildTitle", ->
      it "returns a string with route data", ->
        @presenter.buildTitle().should.equal "Rt 1:"

    # describe "generateBody", ->

    # describe "respond", ->

Presenters = require "../lib/presenters"
helpers = require "./helpers"

describe "Presenters", ->

  before ->
    @prediction1 = new helpers.PredictionStub stopName: "Michigan & 29th Street"
    @prediction2 = new helpers.PredictionStub {stopName: "Michigan & 28th Street", minutesFromNow: 1}
    @allPredictions = [@prediction1, @prediction2]

  describe "WebPresenter", ->
    beforeEach ->
      @presenter = new Presenters.WebPresenter({}, @allPredictions)

    describe "formatPredictions", ->
      it "returns an object with values for the given prediction data", ->
        @presenter.formatPrediction(@prediction2).should.eql
          stopName: '28th Street'
          estimate: 1
          percentComplete: 90

    describe "buildGeneralContext", ->
      it "returns an object with route data", ->
        @presenter.buildGeneralContext().should.eql
          routeNumber: '1'
          routeDirection: 'North Bound'
          busNumber: '1234'

    # describe "generateBody", ->

    # describe "respond", ->

  describe "SMSPresenter", ->
    beforeEach ->
      @presenter = new Presenters.SMSPresenter({}, @allPredictions)

    describe "formatPredictions", ->
      it "returns a string for the given prediction", ->
        @presenter.formatPrediction(@prediction2).should.equal "In 1m: 28th Street"

    describe "buildTitle", ->
      it "returns a string with route data", ->
        @presenter.buildTitle().should.equal "Rt 1:"

    # describe "generateBody", ->

    # describe "respond", ->

Fix method name in presenter spec

Fix method name in presenter spec


{View} = require 'space-pen'

module.exports =
class WrapGuide extends View
  @activate: (rootView) ->
    requireStylesheet 'wrap-guide.css'

    for editor in rootView.getEditors()
      @appendToEditorPane(rootView, editor) if rootView.parents('html').length

    rootView.on 'editor-open', (e, editor) =>
      @appendToEditorPane(rootView, editor)

  @appendToEditorPane: (rootView, editor) ->
    if lines = editor.pane()?.find('.lines')
      lines.append(new WrapGuide(rootView, editor))

  @content: ->
    @div class: 'wrap-guide'

  column: 80

  initialize: (@rootView, @editor) =>
    @updateGuide(@editor)
    @editor.on 'editor-path-change', => @updateGuide(@editor)
    @rootView.on 'font-size-change', => @updateGuide(@editor)

  updateGuide: (editor) ->
    width = editor.charWidth * @column
    @css("left", width + "px")

{View} = require 'space-pen'

module.exports =
class WrapGuide extends View
  @activate: (rootView) ->
    requireStylesheet 'wrap-guide.css'

    for editor in rootView.getEditors()
      @appendToEditorPane(rootView, editor) if rootView.parents('html').length

    rootView.on 'editor-open', (e, editor) =>
      @appendToEditorPane(rootView, editor)

  @appendToEditorPane: (rootView, editor) ->
    if lines = editor.pane()?.find('.lines')
      lines.append(new WrapGuide(rootView, editor))

  @content: ->
    @div class: 'wrap-guide'

  column: 80

  initialize: (@rootView, @editor) =>
    @updateGuide(@editor)
    @editor.on 'editor-path-change', => @updateGuide(@editor)
    @rootView.on 'font-size-change', => @updateGuide(@editor)

  updateGuide: (editor) ->
    @css('left', "#{editor.charWidth * @column}px")

Use interpolated string for setting left offset


logger = new Logger("browserpolicy")

Meteor.startup(->
  BrowserPolicy.content.allowImageOrigin(
    "https://s3-#{Meteor.settings.AWSRegion}.amazonaws.com")
  BrowserPolicy.content.allowImageOrigin("https://*.githubusercontent.com")
  BrowserPolicy.content.allowImageOrigin("blob:")
  BrowserPolicy.content.allowImageOrigin("https://*.flattr.com")
  BrowserPolicy.content.allowEval()
  BrowserPolicy.framing.allowAll()
  BrowserPolicy.content.allowFrameOrigin("*.googletagmanager.com")
  logger.debug("Configured BrowserPolicy")
)

logger = new Logger("browserpolicy")

Meteor.startup(->
  BrowserPolicy.content.allowImageOrigin(
    "https://s3-#{Meteor.settings.AWSRegion}.amazonaws.com")
  BrowserPolicy.content.allowImageOrigin("blob:")
  BrowserPolicy.content.allowImageOrigin("https://*")
  BrowserPolicy.content.allowImageOrigin("http://*")
  BrowserPolicy.content.allowEval()
  BrowserPolicy.framing.allowAll()
  BrowserPolicy.content.allowFrameOrigin("*.googletagmanager.com")
  logger.debug("Configured BrowserPolicy")
)

Allow images from any origin

Allow images from any origin


SelectorLinter = require 'atom-selector-linter'
CSON = require 'season'
fs = require 'fs-plus'

exports.getSelectorDeprecations = ->
  linter = new SelectorLinter(maxPerPackage: 50)
  linter.checkPackage(pkg) for pkg in atom.packages.getLoadedPackages()

  userKeymapPath = atom.keymaps.getUserKeymapPath()

  if fs.existsSync(userKeymapPath)
    linter.checkKeymap(CSON.readFileSync(atom.keymaps.getUserKeymapPath()), {
      packageName: "your local #{path.basename(userKeymapPath)} file",
      packagePath: "",
      sourcePath: userKeymapPath
    })

  userStyleSheetPath = atom.styles.getUserStyleSheetPath()

  if fs.existsSync(userStyleSheetPath)
    userStyleSheet = fs.readFileSync(atom.styles.getUserStyleSheetPath(), 'utf8')
    linter.checkSyntaxStylesheet(userStyleSheet, {
      packageName: "your local #{path.basename(userStyleSheetPath)} file",
      packagePath: "",
      sourcePath: userStyleSheetPath
    })
    linter.checkUIStylesheet(userStyleSheet, {
      packageName: "your local #{path.basename(userStyleSheetPath)} file",
      packagePath: "",
      sourcePath: userStyleSheetPath
    })

  linter.getDeprecations()

exports.getSelectorDeprecationsCount = ->
  count = 0
  deprecationsByPackageName = exports.getSelectorDeprecations()
  for packageName, deprecationsByFile of deprecationsByPackageName
    for fileName, deprecations of deprecationsByFile
      count += deprecations.length
  count

SelectorLinter = require 'atom-selector-linter'
CSON = require 'season'
fs = require 'fs-plus'

exports.getSelectorDeprecations = ->
  linter = new SelectorLinter(maxPerPackage: 50)
  linter.checkPackage(pkg) for pkg in atom.packages.getLoadedPackages()

  userKeymapPath = atom.keymaps.getUserKeymapPath()

  if fs.isFileSync(userKeymapPath)
    linter.checkKeymap(CSON.readFileSync(atom.keymaps.getUserKeymapPath()), {
      packageName: "your local #{path.basename(userKeymapPath)} file",
      packagePath: "",
      sourcePath: userKeymapPath
    })

  userStyleSheetPath = atom.styles.getUserStyleSheetPath()

  if fs.isFileSync(userStyleSheetPath)
    userStyleSheet = fs.readFileSync(atom.styles.getUserStyleSheetPath(), 'utf8')
    linter.checkSyntaxStylesheet(userStyleSheet, {
      packageName: "your local #{path.basename(userStyleSheetPath)} file",
      packagePath: "",
      sourcePath: userStyleSheetPath
    })
    linter.checkUIStylesheet(userStyleSheet, {
      packageName: "your local #{path.basename(userStyleSheetPath)} file",
      packagePath: "",
      sourcePath: userStyleSheetPath
    })

  linter.getDeprecations()

exports.getSelectorDeprecationsCount = ->
  count = 0
  deprecationsByPackageName = exports.getSelectorDeprecations()
  for packageName, deprecationsByFile of deprecationsByPackageName
    for fileName, deprecations of deprecationsByFile
      count += deprecations.length
  count

Use isFileSync instead of existsSync for checking file existence


# Description:
#  Listens for ac webhooks and post in chat
#
# Dependencies:
#   None
#
# Configuration:
#   None
#
# Commands:
#   None
#
# Notes:
#   None
#
# Author:
#   digitalsadhu

ac = require('node-activecollab').init process.env.AC_API_URL, process.env.AC_API_KEY

module.exports = (robot) ->

  robot.router.post "/hubot/ac-webhooks", (req, res) ->

    ac.apiUrl.check (state) ->
        console.log state

    data = JSON.parse req.body['data']
    console.log data
    data = data['data']
    timeRecord = data['time_record']

    billableStatus = 'billable'
    if timeRecord['billable_status'] != 1 then billableStatus = 'non billable'

    userName = timeRecord['user_name']
    time = timeRecord['value']
    projectType = timeRecord['parent_type']
    jobTypeId = timeRecord['job_type_id']
    summary = timeRecord['summary']
    parentId = timeRecord['parent_id']

    user = {}
    user.room = process.env['HUBOT_CAMPFIRE_ROOMS'].split(',')[0]

    ac.project parentId, (project) ->
        robot.send user, userName + ' logged ' + time + ' ' + billableStatus + ' hours against ' + projectType + ' ' + project['name'] + ' (' + summary + ')'
        res.end '{"success":true}'

# Description:
#  Listens for ac webhooks and post in chat
#
# Dependencies:
#   None
#
# Configuration:
#   None
#
# Commands:
#   None
#
# Notes:
#   None
#
# Author:
#   digitalsadhu
module.exports = (robot) ->

  robot.router.post "/hubot/ac-webhooks", (req, res) ->

    data = JSON.parse req.body['data']
    console.log data
    data = data['data']
    timeRecord = data['time_record']

    billableStatus = 'billable'
    if timeRecord['billable_status'] != 1 then billableStatus = 'non billable'

    userName = timeRecord['user_name']
    time = timeRecord['value']
    projectType = timeRecord['parent_type']
    jobTypeId = timeRecord['job_type_id']
    summary = timeRecord['summary']
    parentId = timeRecord['parent_id']
    projectName = timeRecord['project_name']
    taskName = timeRecord['task_name']

    taskMessage = ''
    if typeof taskName != undefined then taskMessage = 'task ' + taskName + ' for '

    message = userName + ' logged ' + time + ' ' + billableStatus + ' hours against the ' +
      taskMessage + 'project ' + projectName + ' with the description ' + summary

    user = {}
    user.room = process.env['HUBOT_CAMPFIRE_ROOMS'].split(',')[0]

    robot.send user, message
    res.end '{"success":true}'

Remove ac node module, handle new data being sent


angular
   .module("angularTodoList", ["ui.router"])
   .config(['$stateProvider', '$urlMatcherFactoryProvider',
      ($stateProvider, $urlMatcherFactoryProvider) ->

         $urlMatcherFactoryProvider.strictMode(false)

         $stateProvider
            .state("index",
               url: ""
               templateUrl: "templates/index.html"
            )
            .state("page2",
               url: "page2"
               templateUrl: "templates/page2.html"
            )
   ])

Remove trailing whitespace for jshint

Remove trailing whitespace for jshint


jQuery ->
    $('.locales a:first').tab('show')
    $('.accordion-body').on('hidden', ->
        $(@).prev().find('i').first().removeClass().addClass('icon-chevron-right')
        )
    $('.accordion-body').on('shown', ->
        $(@).prev().find('i').first().removeClass().addClass('icon-chevron-down'))
    $('body').on('.toggle-hidden', 'click', ->
        $(@).parents('td').find('div:hidden').show()
        false)
    $('#request_hidden_user_explanation_reasons').on('click', 'input', ->
        $('#request_hidden_user_subject, #request_hidden_user_explanation, #request_hide_button').show()
        info_request_id = $('#hide_request_form').attr('data-info-request-id')
        reason = $(this).val()
        $('#request_hidden_user_explanation_field').attr("value", "[loading default text...]")
        $.ajax "/hidden_user_explanation?reason=" + reason + "&info_request_id=" + info_request_id,
          type: "GET"
          dataType: "text"
          error: (data, textStatus, jqXHR) ->
            $('#request_hidden_user_explanation_field').attr("value", "Error: #{textStatus}")
          success: (data, textStatus, jqXHR) ->
            $('#request_hidden_user_explanation_field').attr("value", data)
      )

jQuery ->
    $('.locales a:first').tab('show')
    $('.accordion-body').on('hidden', ->
        $(@).prev().find('i').first().removeClass().addClass('icon-chevron-right')
        )
    $('.accordion-body').on('shown', ->
        $(@).prev().find('i').first().removeClass().addClass('icon-chevron-down'))
    $('body').on('.toggle-hidden', 'click', ->
        $(@).parents('td').find('div:hidden').show()
        false)
    $('#request_hidden_user_explanation_reasons').on('click', 'input', ->
        $('#request_hidden_user_subject, #request_hidden_user_explanation, #request_hide_button').show()
        info_request_id = $('#hide_request_form').attr('data-info-request-id')
        reason = $(this).val()
        $('#request_hidden_user_explanation_field').val("[loading default text...]")
        $.ajax "/hidden_user_explanation?reason=" + reason + "&info_request_id=" + info_request_id,
          type: "GET"
          dataType: "text"
          error: (data, textStatus, jqXHR) ->
            $('#request_hidden_user_explanation_field').val("Error: #{textStatus}")
          success: (data, textStatus, jqXHR) ->
            $('#request_hidden_user_explanation_field').val(data)
      )

Replace .attr("value", val) with .val(val)

Looks like this has changed behviour in the later version of jquery
we now use https://github.com/jquery/jquery-migrate/blob/master/warnings.md#jqmigrate-jqueryfnattrvalue-val-no-longer-sets-properties


# This is a manifest file that'll be compiled into including all the files listed below.
# Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
# be included in the compiled file accessible from http://example.com/assets/application.js
# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
# the compiled file.
#
#= require jquery
#= require jquery_ujs
#= require foundation
#= require modernizr-2.6.2.min
#= require_tree .

$ ->
  $(document).foundation()
  $(".notice").not(".alert").delay(3000).slideUp "slow"

# This is a manifest file that'll be compiled into including all the files listed below.
# Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
# be included in the compiled file accessible from http://example.com/assets/application.js
# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
# the compiled file.
#
#= require jquery
#= require jquery_ujs
#= require foundation
#= require_tree .

$ ->
  $(document).foundation()
  $(".notice").not(".alert").delay(3000).slideUp "slow"

Remove modernizr from app asset precompilation


# This is a manifest file that'll be compiled into application.js, which will include all the files
# listed below.

# Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
# or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.

# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
# compiled file.

# WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
# GO AFTER THE REQUIRES BELOW.

#= require jquery
#= require jquery_ujs
#= require ember
#= require ember-data
#= require csrf
#= require zeroclipboard
#= require moment
#= require_self
#= require review

# for more details see: http://emberjs.com/guides/application/
window.Review = Ember.Application.create(LOG_TRANSITIONS: true)
#= require_tree .

# This is a manifest file that'll be compiled into application.js, which will include all the files
# listed below.

# Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
# or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.

# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
# compiled file.

# WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
# GO AFTER THE REQUIRES BELOW.

#= require jquery
#= require jquery_ujs
#= require_self
#= require_tree .

Remove references to ember dependencies

Remove references to ember dependencies


React = require 'react'

class Header extends React.Component
  @displayName = 'Header'
  @propTypes:
    menuItems: React.PropTypes.array

  constructor: (@props) ->

  render: =>

      {@_renderLogo()}

        {@_renderMenuItems()}

  _renderLogo: ->
    if process.platform != 'win32'

    else return

  _renderMenuItems: =>
    @props.menuItems.map (item, index) ->
      classnames = if index is 0 then 'active' else ''

        {item.name}

module.exports = Header

React = require 'react'

class Header extends React.Component
  @displayName = 'Header'
  @propTypes:
    menuItems: React.PropTypes.array

  constructor: (@props) ->
    @state =
      menuItems: @props.menuItems

  render: =>

      {@_renderLogo()}

        {@_renderMenuItems()}

  _renderLogo: ->
    if process.platform != 'win32'

    else return

  _renderMenuItems: =>
    @state.menuItems.map (item, index) =>
      classnames = if index is 0 then 'active' else ''

        {item.name}

  _handleCloseItem: (e) =>
    index = parseInt(e.target.value, 10)

    @setState (state) ->
      state.menuItems.splice(index, 1)

      menuItems: state.menuItems

module.exports = Header

Add ability to close tabs

Add ability to close tabs


# Config holds general configuration, like the name suggests
class Config
  # String -> Config
  constructor: (uuid) ->
    protocol = if 'https:' == document.location.protocol then 'https' else 'http'

    # number (lifespan of the cookie in days from now)
    @cookieLifespan = 365
    # string
    @cookieName = "myna" + uuid
    # natural (ms)
    @timeout = 400
    # string (url)
    @baseurl = "#{protocol}://api.mynaweb.com"
    # natural: See LogLevel for values
    @loglevel = LogLevel.ERROR
    # json -> undefined: Default function used for reward success callback
    @rewardSuccess = (ok) -> undefined
    # json -> undefined: Default function used for error callback
    @error = (problem) -> undefined

  extend: (options) ->
    extend(extend({}, options), this)

# Config holds general configuration, like the name suggests
class Config
  # String -> Config
  constructor: (uuid) ->
    protocol = if 'https:' == document.location.protocol then 'https' else 'http'

    # number (lifespan of the cookie in days from now)
    @cookieLifespan = 365
    # string
    @cookieName = "myna" + uuid
    # natural (ms)
    @timeout = 1200
    # string (url)
    @baseurl = "#{protocol}://api.mynaweb.com"
    # natural: See LogLevel for values
    @loglevel = LogLevel.ERROR
    # json -> undefined: Default function used for reward success callback
    @rewardSuccess = (ok) -> undefined
    # json -> undefined: Default function used for error callback
    @error = (problem) -> undefined

  extend: (options) ->
    extend(extend({}, options), this)

Bump up the timeout so people with unfortunate connectivity don't get timeouts.


coffee = require 'gulp-coffee'
gulp = require 'gulp'
gutil = require 'gulp-util'
mocha = require 'gulp-mocha'
rimraf = require 'rimraf'

handleError = (err) ->
  gutil.log err
  @emit 'end'

gulp.task 'clean', (done) ->
  rimraf './lib', done

gulp.task 'build', ['clean'], ->
  gulp.src './lib-src/**/*.coffee'
    .pipe coffee(bare: true).on 'error', handleError
    .pipe gulp.dest './lib'

gulp.task 'test', ['build'], ->
  gulp.src './test/**/*.coffee', read: false
    .pipe mocha().on 'error', handleError

gulp.task 'watch', ->
  gulp.watch ['./lib-src/**/*.coffee', './test/**/*.coffee'], ['test']

gulp.task 'default', ['watch', 'test']

coffee = require 'gulp-coffee'
gulp = require 'gulp'
gutil = require 'gulp-util'
mocha = require 'gulp-mocha'
rimraf = require 'rimraf'

errorOccurred = no
process.once 'exit', (code) ->
  if errorOccurred and code == 0
    process.exit 1

handleError = (err) ->
  errorOccurred = yes
  gutil.log err
  @emit 'end'

gulp.task 'clean', (done) ->
  rimraf './lib', done

gulp.task 'build', ['clean'], ->
  gulp.src './lib-src/**/*.coffee'
    .pipe coffee(bare: true).on 'error', handleError
    .pipe gulp.dest './lib'

gulp.task 'test', ['build'], ->
  gulp.src './test/**/*.coffee', read: false
    .pipe mocha().on 'error', handleError

gulp.task 'watch', ->
  gulp.watch ['./lib-src/**/*.coffee', './test/**/*.coffee'], ['test']

gulp.task 'default', ['watch', 'test']

gulp: Fix exit code on error as in felixrabe/gulp-setup


AST = { }

class AST.Template
  constructor : ( @nodes ) ->

  compile : ( context ) -> ( node.compile context for node in @nodes ).join ''

class AST.ContentNode
  constructor : ( @content ) ->

  compile : ( context ) -> @content

class AST.MemberNode
  constructor : ( @path ) ->

  compile : ( context ) -> context[ @path ]

class AST.MethodNode
  constructor : ( @path, @arguments ) ->

  compile : ( context, base ) -> context[ @path ] (argument.compile base for argument in @arguments)...

class AST.PathNode
  constructor : ( @paths ) ->

  compile : ( context ) ->

    curr = context
    paths = @paths.concat( )

    while paths.length

      path = paths.shift( )

      curr = path.compile curr, context

    curr

module.exports = AST

AST = { }

class AST.Template
  constructor : ( @nodes ) ->

  compile : ( context ) -> ( node.compile context for node in @nodes ).join ''

class AST.ContentNode
  constructor : ( @content ) ->

  compile : ( context ) -> @content

class AST.MemberNode
  constructor : ( @path ) ->

  compile : ( context ) -> context[ @path ]

class AST.MethodNode
  constructor : ( @path, @arguments ) ->

  compile : ( context, base ) -> context[ @path ] (argument.compile base for argument in @arguments)...

class AST.PathNode
  constructor : ( @paths ) ->

  compile : ( context ) ->

    index = context
    paths = @paths.concat( )
    index = ( paths.shift( ) ).compile index, context while paths.length isnt 0
    index

module.exports = AST

Tidy up the PathNode compile method a bit


fs = require 'fs'
uuid = require 'node-uuid'

config =
    schemaPrefix: do -> 'urn:schemas-upnp-org'
    versions: do ->
        schema: do -> '1.0'
        upnp: do -> '1.0'
    devices: do ->
        MediaServer: do ->
            version: do -> 1
            services: do -> [ 'ConnectionManager', 'ContentDirectory' ]
    ssdp: do ->
        port: do -> 1900
        address: do -> '239.255.255.250'
        timeout: do -> 1800

# persist UUID across restarts
try
    config.uuid = do -> 'uuid:' + fs.readFileSync("#{__dirname}/../upnp-uuid", 'utf8')
catch error
    config.uuid = do -> 'uuid:' + uuid()
    fs.writeFileSync("#{__dirname}/../upnp-uuid", config.uuid)

module.exports = config

fs = require 'fs'
uuid = require 'node-uuid'

config =
    schemaPrefix: do -> 'urn:schemas-upnp-org'
    versions: do ->
        schema: do -> '1.0'
        upnp: do -> '1.0'
    devices: do ->
        MediaServer: do ->
            version: do -> 1
            services: do -> [ 'ConnectionManager', 'ContentDirectory' ]
    ssdp: do ->
        port: do -> 1900
        address: do -> '239.255.255.250'
        timeout: do -> 1800

# persist UUID across restarts
try
    config.uuid = do -> fs.readFileSync("#{__dirname}/../upnp-uuid", 'utf8')
catch error
    config.uuid = do -> 'uuid:' + uuid()
    fs.writeFileSync("#{__dirname}/../upnp-uuid", config.uuid)

module.exports = config

Fix typo in uuid generation

Fix typo in uuid generation


module.exports = (grunt, options) ->
  return {
    options:
      baseUrl: '<%= build %>/js'
      exclude: ['coffee-script']
      stubModules: ['cs/cs']
      mainConfigFile: '<%= build %>/js/app/config.js'
      optimize: 'uglify2'
      generateSourceMaps: true
      preserveLicenseComments: false
      findNestedDependencies: true
      useSourceUrl: true
    app:
      options:
        include: ['app/main']
        out: '<%= build %>/js/bundle.js'
    embed:
      options:
        include: ['app/main-embed']
        out: '<%= build %>/js/embed.js'
  }

module.exports = (grunt, options) ->
  return {
    options:
      baseUrl: '<%= build %>/js'
      exclude: ['coffee-script']
      stubModules: ['cs/cs']
      mainConfigFile: '<%= build %>/js/app/config.js'
      optimize: 'uglify2'
      optimizeAllPluginResources: true
      generateSourceMaps: true
      preserveLicenseComments: false
      findNestedDependencies: true
      useSourceUrl: false
    app:
      options:
        include: ['app/main']
        out: '<%= build %>/js/bundle.js'
    embed:
      options:
        include: ['app/main-embed']
        out: '<%= build %>/js/embed.js'
  }

Make source maps work in Sentry.

Make source maps work in Sentry.

Sentry can't seem to handle the unminified,
concatenated eval'd version of the bundle.
Minification loses the js -> coffee mapping
step, but the js stack traces and sources
are clear enough.


# # Kissmetrics Batch

class BatchKissmetricsClient
  @HOST: 'api.kissmetrics.com'
  @HTTP_METHOD: 'POST'

  constructor: (@options) ->
    @_validate_queue @options.queue

  add: (timestamp, data) ->
    data.timestamp = timestamp
    @_transformData data

    @queue.add data

  get: ->
    @queue.get()

  process: ->
    queue = @get()

  _transformData: (data) ->
    data.identity = data._p
    delete data._p

    if data.type is 'record'
      data.event = data._n
      delete data._n

    if data.type is 'alias'
      data.alias = data._n
      delete data._n

    delete data.type

  _validate_queue: ->
    for method in ['add', 'get']
      unless typeof @queue[method] is 'function'
        throw new Error "Missing method: #{required_method}"

module.exports = BatchKissmetricsClient

# # Kissmetrics Batch

class BatchKissmetricsClient
  @HOST: 'api.kissmetrics.com'
  @HTTP_METHOD: 'POST'

  constructor: (@options) ->
    @queue = options.queue
    @_validate_queue @queue

  add: (timestamp, data) ->
    data.timestamp = timestamp
    @_transformData data

    @queue.add data

  get: ->
    @queue.get()

  process: ->
    queue = @get()

  _transformData: (data) ->
    data.identity = data._p
    delete data._p

    if data.type is 'record'
      data.event = data._n
      delete data._n

    if data.type is 'alias'
      data.alias = data._n
      delete data._n

    delete data.type

  _validate_queue: ->
    for method in ['add', 'get']
      unless typeof @queue[method] is 'function'
        throw new Error "Missing method: #{required_method}"

module.exports = BatchKissmetricsClient

Set the queue object to a top level property of the batch instance


module.exports = [

  # the bongo api (or an empty file, depending on the config)
  "../../.build/api.js",

  "../../.build/logging-api.js",

  # --- Bongo Client ---
  "sockjs-0.3-patched.js",
  "broker.js",
  "bongo.js",

]

module.exports = [

  # the bongo api (or an empty file, depending on the config)
  "../../.build/api.js",

  "../../.build/logging-api.js",

  # --- Bongo Client ---
  # "sockjs-0.3-patched.js",
  "sockjs-0.3.4.js",
  "broker.js",
  "bongo.js",

]

Update SockJS-client to 0.3.4 stable

Update SockJS-client to 0.3.4 stable


# See https://atom.io/docs/latest/creating-a-package#menus for more details
'menu': [
  {
    'label': 'Packages'
    'submenu': [
      'label': 'Jekyll'
      'submenu': [
        { 'label': 'Manage Jekyll', 'command': 'jekyll:manage'},
        { 'label': 'New Post', 'command': 'jekyll:new-post' },
        { 'label': 'Open Config', 'command': 'jekyll:open-config' },
        { 'label': 'Open Layout', 'command': 'jekyll:open-layout' },
        { 'label': 'Open Include', 'command': 'jekyll:open-include' },
        { 'label': 'Open Data File', 'command': 'jekyll:open-data'}
      ]
    ]
  }
]

# See https://atom.io/docs/latest/creating-a-package#menus for more details
'menu': [
  {
    'label': 'Packages'
    'submenu': [
      'label': 'Jekyll'
      'submenu': [
        { 'label': 'Manage Jekyll', 'command': 'jekyll:manage'},
        { 'label': 'Open Toolbar', 'command': 'jekyll:toolbar'},
        { 'label': 'New Post', 'command': 'jekyll:new-post' },
        { 'label': 'Open Config', 'command': 'jekyll:open-config' },
        { 'label': 'Open Layout', 'command': 'jekyll:open-layout' },
        { 'label': 'Open Include', 'command': 'jekyll:open-include' },
        { 'label': 'Open Data File', 'command': 'jekyll:open-data'}
      ]
    ]
  }
]

Add the toolbar to the menu

Add the toolbar to the menu


$ ->
	variations = [
			participants: 100
			conversions: 45
		,
			participants: 100
			conversions: 50
	]

	calculator = new App.Calculator variations
	calculator.renderGraph()

$ ->
	data = [
			name: 'Original'
			participants: 100
			conversions: 45
			color: '#00aa00'
		,
			name: 'Variation'
			participants: 100
			conversions: 50
			color: 'blue'
	]

	variations = []
	variations.push new App.Variation item.name, item.color, item.participants, item.conversions for item in data

	calculator = new App.Calculator variations
	calculator.renderGraph()

Switch data over to use new variation class


'use strict'

toggleGem = Reflux.createAction()

module.exports =
  toggleGem: toggleGem

'use strict'

actions = Reflux.createActions [
  'toggleGem'
]

module.exports = actions

Refactor using Reflux sugar functions

Refactor using Reflux sugar functions

Reflux has quite a few sugar functions that prevent coderz from writing down
useless boilerplate.

- On the actions side, one can simply specify an array of action names
- On the store side, one can listen to an array of actions and handle them
with CoC methods

Beautiful.


NProgress.configure(showSpinner: false)

delay = 150
defaultClass = 'tanuki-shape'
pieces = [
  'path#tanuki-right-cheek',
  'path#tanuki-right-eye, path#tanuki-right-ear',
  'path#tanuki-nose',
  'path#tanuki-left-eye, path#tanuki-left-ear',
  'path#tanuki-left-cheek',
]
firstPiece = pieces[0]
timeout = null

clearHighlights = ->
  $(".#{defaultClass}.highlight").attr('class', defaultClass)

start = ->
  clearHighlights()
  pieces.reverse() unless pieces[0] == firstPiece
  work(0)

stop = ->
  window.clearTimeout(timeout)
  clearHighlights()

work = (pieceIndex) ->
  # jQuery's addClass won't work on an SVG. Who knew!
  $piece = $(pieces[pieceIndex])
  $piece.attr('class', "#{defaultClass} highlight")

  timeout = setTimeout(->
    $piece.attr('class', defaultClass)

    # If we hit the last piece, reset the index and then reverse the array to
    # get a nice back-and-forth sweeping look
    if pieceIndex + 1 >= pieces.length
      nextIndex = 0
      pieces.reverse()
    else
      nextIndex = pieceIndex + 1

    work(nextIndex)
  , delay)

$(document).on 'page:fetch',  start
$(document).on 'page:change', stop

NProgress.configure(showSpinner: false)

defaultClass = 'tanuki-shape'
pieces = [
  'path#tanuki-right-cheek',
  'path#tanuki-right-eye, path#tanuki-right-ear',
  'path#tanuki-nose',
  'path#tanuki-left-eye, path#tanuki-left-ear',
  'path#tanuki-left-cheek',
]
pieceIndex = 0
firstPiece = pieces[0]

currentTimer = null
delay        = 150

clearHighlights = ->
  $(".#{defaultClass}.highlight").attr('class', defaultClass)

start = ->
  clearHighlights()
  pieceIndex = 0
  pieces.reverse() unless pieces[0] == firstPiece
  currentTimer = setInterval(work, delay)

stop = ->
  clearInterval(currentTimer)
  clearHighlights()

work = ->
  clearHighlights()
  $(pieces[pieceIndex]).attr('class', "#{defaultClass} highlight")

  # If we hit the last piece, reset the index and then reverse the array to
  # get a nice back-and-forth sweeping look
  if pieceIndex == pieces.length - 1
    pieceIndex = 0
    pieces.reverse()
  else
    pieceIndex++

$(document).on('page:fetch',  start)
$(document).on('page:change', stop)

Restructure logo JS to use `setInterval`


NProgress.configure(showSpinner: false)

defaultClass = 'tanuki-shape'
pieces = [
  'path#tanuki-right-cheek',
  'path#tanuki-right-eye, path#tanuki-right-ear',
  'path#tanuki-nose',
  'path#tanuki-left-eye, path#tanuki-left-ear',
  'path#tanuki-left-cheek',
]
firstPiece = pieces[0]
timeout = null

clearHighlights = ->
  $(".#{defaultClass}").attr('class', defaultClass)

start = ->
  clearHighlights()
  pieces.reverse() unless pieces[0] == firstPiece
  work(0)

stop = ->
  window.clearTimeout(timeout)
  clearHighlights()

work = (pieceIndex) ->
  # jQuery's addClass won't work on an SVG. Who knew!
  $piece = $(pieces[pieceIndex])
  $piece.attr('class', "#{defaultClass} highlight")

  timeout = setTimeout(->
    $piece.attr('class', defaultClass)

    # If we hit the last piece, reset the index and then reverse the array to
    # get a nice back-and-forth sweeping look
    if pieceIndex + 1 >= pieces.length
      nextIndex = 0
      pieces.reverse()
    else
      nextIndex = pieceIndex + 1

    work(nextIndex)
  , 200)

$(document).on 'page:fetch',  start
$(document).on 'page:change', stop

NProgress.configure(showSpinner: false)

delay = 150
defaultClass = 'tanuki-shape'
pieces = [
  'path#tanuki-right-cheek',
  'path#tanuki-right-eye, path#tanuki-right-ear',
  'path#tanuki-nose',
  'path#tanuki-left-eye, path#tanuki-left-ear',
  'path#tanuki-left-cheek',
]
firstPiece = pieces[0]
timeout = null

clearHighlights = ->
  $(".#{defaultClass}.highlight").attr('class', defaultClass)

start = ->
  clearHighlights()
  pieces.reverse() unless pieces[0] == firstPiece
  work(0)

stop = ->
  window.clearTimeout(timeout)
  clearHighlights()

work = (pieceIndex) ->
  # jQuery's addClass won't work on an SVG. Who knew!
  $piece = $(pieces[pieceIndex])
  $piece.attr('class', "#{defaultClass} highlight")

  timeout = setTimeout(->
    $piece.attr('class', defaultClass)

    # If we hit the last piece, reset the index and then reverse the array to
    # get a nice back-and-forth sweeping look
    if pieceIndex + 1 >= pieces.length
      nextIndex = 0
      pieces.reverse()
    else
      nextIndex = pieceIndex + 1

    work(nextIndex)
  , delay)

$(document).on 'page:fetch',  start
$(document).on 'page:change', stop

Decrease the logo sweep delay

Decrease the logo sweep delay


{Point, Range} = require 'text-buffer'

module.exports =
  BufferedNodeProcess: require '../src/buffered-node-process'
  BufferedProcess: require '../src/buffered-process'
  Git: require '../src/git'
  Point: Point
  Range: Range

# The following classes can't be used from a Task handler and should therefore
# only be exported when not running as a child node process
unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
  {$, $$, $$$, View} = require '../src/space-pen-extensions'

  module.exports.$ = $
  module.exports.$$ = $$
  module.exports.$$$ = $$$
  module.exports.EditorView = require '../src/react-editor-view'
  module.exports.ScrollView = require '../src/scroll-view'
  module.exports.SelectListView = require '../src/select-list-view'
  module.exports.Task = require '../src/task'
  module.exports.View = View
  module.exports.WorkspaceView = require '../src/workspace-view'
  module.exports.Workspace = require '../src/workspace'

{Point, Range} = require 'text-buffer'

module.exports =
  BufferedNodeProcess: require '../src/buffered-node-process'
  BufferedProcess: require '../src/buffered-process'
  Git: require '../src/git'
  Point: Point
  Range: Range

# The following classes can't be used from a Task handler and should therefore
# only be exported when not running as a child node process
unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
  {$, $$, $$$, View} = require '../src/space-pen-extensions'

  module.exports.$ = $
  module.exports.$$ = $$
  module.exports.$$$ = $$$
  module.exports.EditorView = require '../src/editor-view'
  module.exports.ScrollView = require '../src/scroll-view'
  module.exports.SelectListView = require '../src/select-list-view'
  module.exports.Task = require '../src/task'
  module.exports.View = View
  module.exports.WorkspaceView = require '../src/workspace-view'
  module.exports.Workspace = require '../src/workspace'

Revert "Export ReactEditorView as EditorView"

This reverts commit be201485188cb8583bbfe0a2dd239a20efa8cbd9.


React = require 'react'
apiClient = require '../api/client'
PromiseRenderer = require '../components/promise-renderer'
Classifier = require '../classifier/classifier'

module.exports = React.createClass
  displayName: 'ClassifyPage'

  render: ->
    workflow = @props.project.attr('workflows').then ([workflow]) =>
      workflow

    subject = workflow.then (workflow) =>
      apiClient.createType('subjects').get({
        project_id: @props.project.id
        workflow_id: workflow.id
      }, 1).then ([subject]) ->
        subject

    classification = Promise.all([workflow, subject]).then ([workflow, subject]) ->
      initialAnnotation = task: workflow.first_task ? Object.keys(workflow.tasks)[0]
      classification = apiClient.createType('classifications').createResource
        annotations: [initialAnnotation]
        links:
          subjects: [subject.id]
      window.classification = classification
      classification

    <PromiseRenderer promise={Promise.all [workflow, subject, classification]} then={@renderClassifier} />

  renderClassifier: ([workflow, subject, classification]) ->
    <Classifier workflow={workflow} subject={subject} classification={classification} onFinishClassification={@handleFinishingClassification} />

  handleFinishingClassification: (classification) ->
    console.info 'FINISHED', JSON.stringify classification
    alert 'TODO: Save the classification and load another subject.'

React = require 'react'
apiClient = require '../api/client'
PromiseRenderer = require '../components/promise-renderer'
Classifier = require '../classifier/classifier'

module.exports = React.createClass
  displayName: 'ClassifyPage'

  render: ->
    workflow = @props.project.attr('workflows').then (workflows) ->
      # TODO: Allow workflow selection, maybe?
      workflows[Math.floor Math.random() * workflows.length]

    subject = workflow.then (workflow) =>
      apiClient.createType('subjects').get({
        project_id: @props.project.id
        workflow_id: workflow.id
        sort: 'cellect'
      }, 1).then (subjects) ->
        console.log 'Got these subjects', subjects
        subjects[Math.floor Math.random() * subjects.length]

    classification = Promise.all([workflow, subject]).then ([workflow, subject]) =>
      initialAnnotation = task: workflow.first_task ? Object.keys(workflow.tasks)[0]
      classification = apiClient.createType('classifications').createResource
        annotations: [initialAnnotation]
        links:
          project: @props.project.id
          workflow: workflow.id
          subject: subject.id
      window.classification = classification
      classification

    <PromiseRenderer promise={Promise.all [workflow, subject, classification]} then={@renderClassifier} />

  renderClassifier: ([workflow, subject, classification]) ->
    <Classifier workflow={workflow} subject={subject} classification={classification} onFinishClassification={@handleFinishingClassification} />

  handleFinishingClassification: (classification) ->
    console.info 'FINISHED', JSON.stringify classification
    alert 'TODO: Save the classification and load another subject.'

Choose a random workflow and subject

Choose a random workflow and subject