http = require '../../lib/http'
schedule = require '../../data/schedule'

exports.register = (server, baseRoute) ->
  http.get server, "#{baseRoute}/schedule", get

get = ->
  # TODO: get from Google API profile call
  googleId = 'foo'

  schedule.fetch(googleId)
    .then (schedule) ->
      userDisplayName: 'Joe User'
      routes:
        if schedule is null then []
        else
          for route in schedule.routes
            id: route.id
            # TODO: get actual route description
            description: '(route description)'
            am:
              direction:
                id: route.am.direction
                # TODO: get actual direction description
                description: '(direction description)'
              stops:
                for stop in route.am.stops
                  id: stop
                  # TODO: get actual stop description
                  description: '(stop description)'
            pm:
              direction:
                id: route.pm.direction
                # TODO: get actual direction description
                name: '(direction description)'
              stops:
                for stop in route.pm.stops
                  id: stop
                  # TODO: get actual stop description
                  description: '(stop description)'

http = require '../../lib/http'
schedule = require '../../data/schedule'

exports.register = (server, baseRoute) ->
  http.get server, "#{baseRoute}/schedule", fetch

fetch = ->
  # TODO: get from Google API profile call
  googleId = 'foo'

  schedule.fetch(googleId)
    .then (schedule) ->
      userDisplayName: 'Joe User'
      routes:
        if schedule is null then []
        else
          for route in schedule.routes
            id: route.id
            # TODO: get actual route description
            description: '(route description)'
            am:
              direction:
                id: route.am.direction
                # TODO: get actual direction description
                description: '(direction description)'
              stops:
                for stop in route.am.stops
                  id: stop
                  # TODO: get actual stop description
                  description: '(stop description)'
            pm:
              direction:
                id: route.pm.direction
                # TODO: get actual direction description
                name: '(direction description)'
              stops:
                for stop in route.pm.stops
                  id: stop
                  # TODO: get actual stop description
                  description: '(stop description)'

Rename 'get' function to 'fetch' for consistency


AtomStackIdeView = require './stack-ide-atom-view'
{CompositeDisposable} = require 'atom'

haskell = require('./haskell/generated/haskell')
p = haskell.getPackage()
console.log p

module.exports = AtomStackIde =
  atomStackIdeView: null
  modalPanel: null
  subscriptions: null

  activate: (state) ->
    @atomStackIdeView = new AtomStackIdeView(state.atomStackIdeViewState)
    @modalPanel = atom.workspace.addModalPanel(item: @atomStackIdeView.getElement(), visible: false)

    # Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
    @subscriptions = new CompositeDisposable

    # Register command that toggles this view
    @subscriptions.add atom.commands.add 'atom-text-editor',
      'stack-ide-atom:source-errors': (event) ->
        editor = @getModel()
        console.log editor.getText()

  deactivate: ->
    @modalPanel.destroy()
    @subscriptions.dispose()
    @atomStackIdeView.destroy()

  serialize: ->
    atomStackIdeViewState: @atomStackIdeView.serialize()

  toggle: ->
    console.log 'AtomStackIde was toggled!'

    if @modalPanel.isVisible()
      @modalPanel.hide()
    else
      @modalPanel.show()

AtomStackIdeView = require './stack-ide-atom-view'
{CompositeDisposable} = require 'atom'

haskell = require('./haskell/generated/haskell')

module.exports = haskell.getPackage()

###
module.exports = AtomStackIde =
  atomStackIdeView: null
  modalPanel: null
  subscriptions: null

  activate: (state) ->
    @atomStackIdeView = new AtomStackIdeView(state.atomStackIdeViewState)
    @modalPanel = atom.workspace.addModalPanel(item: @atomStackIdeView.getElement(), visible: false)

    # Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
    @subscriptions = new CompositeDisposable

    # Register command that toggles this view
    @subscriptions.add atom.commands.add 'atom-text-editor',
      'stack-ide-atom:source-errors': (event) ->
        editor = @getModel()
        console.log editor.getText()

  deactivate: ->
    @modalPanel.destroy()
    @subscriptions.dispose()
    @atomStackIdeView.destroy()

  serialize: ->
    atomStackIdeViewState: @atomStackIdeView.serialize()

  toggle: ->
    console.log 'AtomStackIde was toggled!'

    if @modalPanel.isVisible()
      @modalPanel.hide()
    else
      @modalPanel.show()
###

Use haskell package as actual package

Use haskell package as actual package


# See https://atom.io/docs/latest/hacking-atom-package-word-count#menus for more details
# TODO: Do we really want these in the context menu? Might be too much clutter.
'context-menu':
  'atom-text-editor': [
    {
      'label': 'Select List Element'
      'command': 'list-edit:select'
    }
    {
      'label': 'Cut List Element'
      'command': 'list-edit:cut'
    }
    {
      'label': 'Copy List Element'
      'command': 'list-edit:copy'
    }
    {
      'label': 'Paste List Element'
      'command': 'list-edit:paste'
    }
  ]
'menu': [
  {
    'label': 'Selection'
    'submenu': [
      {
        'label': 'Select List Element'
        'command': 'list-edit:select'
      }
    ]
  }
  {
    'label': 'Packages'
    'submenu': [
      'label': 'List Edit'
      'submenu': [
        {
          'label': 'Select List Element'
          'command': 'list-edit:select'
        }
        {
          'label': 'Cut List Element'
          'command': 'list-edit:cut'
        }
        {
          'label': 'Copy List Element'
          'command': 'list-edit:copy'
        }
        {
          'label': 'Paste List Element'
          'command': 'list-edit:paste'
        }
      ]
    ]
  }
]

# See https://atom.io/docs/latest/hacking-atom-package-word-count#menus for more details
# TODO: Do we really want these in the context menu? Might be too much clutter.
'context-menu':
  'atom-text-editor': [
    label: 'List edit'
    submenu: [
      {
        'label': 'Select'
        'command': 'list-edit:select'
      }
      {
        'label': 'Cut'
        'command': 'list-edit:cut'
      }
      {
        'label': 'Copy'
        'command': 'list-edit:copy'
      }
      {
        'label': 'Paste'
        'command': 'list-edit:paste'
      }
    ]
  ]
'menu': [
  {
    'label': 'Selection'
    'submenu': [
      {
        'label': 'Select List Element'
        'command': 'list-edit:select'
      }
    ]
  }
  {
    'label': 'Packages'
    'submenu': [
      'label': 'List Edit'
      'submenu': [
        {
          'label': 'List Select'
          'command': 'list-edit:select'
        }
        {
          'label': 'List Cut'
          'command': 'list-edit:cut'
        }
        {
          'label': 'List Copy'
          'command': 'list-edit:copy'
        }
        {
          'label': 'List Paste'
          'command': 'list-edit:paste'
        }
      ]
    ]
  }
]

Add submenu to context menu + Rename menu items


App = require '../app'

attr = DS.attr

App.Book = DS.Model.extend
  isbn: attr 'string'
  title: attr 'string'
  author: attr 'string'
  prices: attr 'raw'
  amazon: attr 'raw'

  currentPrice: (->
    ps = @get('prices')
    ps[ps.length - 1]?.value or 0
  ).property('prices')

  # second to last price
  penultimatePrice: (->
    ps = @get('prices')
    ps[ps.length - 2]?.value or 0
  ).property('prices')

  trend: (->
    now = @get('currentPrice')
    earlier = @get('penultimatePrice')

    if now > earlier then 'up'
    else if now == earlier then 'unchanged'
    else 'down'
  ).property('currentPrice')

  trend2glyph: (->
    trend = @get('trend')
    if trend is 'up' then "glyphicon-circle-arrow-up"
    else if trend is 'down' then "glyphicon-circle-arrow-down"
    else "glyphicon-circle-arrow-right"
  ).property('trend')

module.exports = App.Book

App = require '../app'

attr = DS.attr

App.Book = DS.Model.extend
  isbn: attr 'string'
  title: attr 'string'
  author: attr 'string'
  prices: attr 'raw'
  amazon: attr 'raw'

  currentPrice: (->
    ps = @get('prices')
    ps?[ps.length - 1]?.value or 0
  ).property('prices')

  # second to last price
  penultimatePrice: (->
    ps = @get('prices')
    ps?[ps.length - 2]?.value or 0
  ).property('prices')

  trend: (->
    now = @get('currentPrice')
    earlier = @get('penultimatePrice')

    if now > earlier then 'up'
    else if now == earlier then 'unchanged'
    else 'down'
  ).property('currentPrice')

  trend2glyph: (->
    trend = @get('trend')
    if trend is 'up' then "glyphicon-circle-arrow-up"
    else if trend is 'down' then "glyphicon-circle-arrow-down"
    else "glyphicon-circle-arrow-right"
  ).property('trend')

module.exports = App.Book

Fix Computed Prices When Price is Unknown


#
# Collection for a channel's collaborators
#

Base = require "./base.coffee"
sd = require("sharify").data
User = require "../models/user.coffee"
mediator = require '../lib/mediator.coffee'

module.exports = class Collaborators extends Base

  model: User

  url: -> "#{sd.API_URL}/channels/#{@channel_slug}/collaborators"

  parse: (data) -> data.users

  initialize: (options) ->
    @channel_slug = options.channel_slug
    super

  _remove: (id) ->
    mediator.trigger 'collaborator:removed'
    @remove @get(id)
    $.ajax
      type: 'DELETE'
      url: @url()
      data: { ids: [id] }
      success: (response) =>
        @reset response.users

  _add: (collaborator)->
    mediator.trigger 'collaborator:added'
    @add collaborator
    $.ajax
      type: 'POST'
      url: @url()
      data: { ids: [collaborator.id] }
      success: (response) =>
        @reset response.users

#
# Collection for a channel's collaborators
#

Base = require "./base.coffee"
sd = require("sharify").data
User = require "../models/user.coffee"
mediator = require '../lib/mediator.coffee'

module.exports = class Collaborators extends Base

  model: User

  url: -> "#{sd.API_URL}/channels/#{@channel_slug}/collaborators"

  inviteUrl: -> "#{sd.API_URL}/channels/#{@channel_slug}/collaborators/invite"

  parse: (data) -> data.users

  initialize: (options) ->
    @channel_slug = options.channel_slug
    super

  _remove: (id) ->
    mediator.trigger 'collaborator:removed'
    @remove @get(id)
    $.ajax
      type: 'DELETE'
      url: @url()
      data: { ids: [id] }
      success: (response) =>
        @reset response.users

  _add: (collaborator) ->
    mediator.trigger 'collaborator:added'
    @add collaborator
    $.ajax
      type: 'POST'
      url: @url()
      data: { ids: [collaborator.id] }
      success: (response) =>
        @reset response.users

  _invite: (email) ->
    user = new User username: email
    mediator.trigger 'collaborator:added'
    @add user
    $.ajax
      type: 'POST'
      url: @inviteUrl()
      data:
        email: email

Support adding collaborator via email

Support adding collaborator via email


_ = require 'underscore-plus'
spacePen = require 'space-pen'
ConfigObserver = require './config-observer'
{Subscriber} = require 'emissary'

_.extend spacePen.View.prototype, ConfigObserver
Subscriber.includeInto(spacePen.View)

jQuery = spacePen.jQuery
originalCleanData = jQuery.cleanData
jQuery.cleanData = (elements) ->
  for element in elements
    if view = jQuery(element).view()
      view.unobserveConfig()
      view.unsubscribe()
  originalCleanData(elements)

tooltipDefaults =
  delay:
    show: 500
    hide: 100
  container: 'body'
  html: true

getKeystroke = (bindings) ->
  if bindings and bindings.length
    "#{bindings[0].keystroke}"
  else
    ''

jQuery.fn.setTooltip = (title, {command, commandElement}={}) ->
  atom.requireWithGlobals('bootstrap/js/tooltip', {jQuery : jQuery})

  bindings = if commandElement
    atom.keymap.keyBindingsForCommandMatchingElement(command, commandElement)
  else
    atom.keymap.keyBindingsForCommand(command)

  this.tooltip(jQuery.extend(tooltipDefaults, {title: "#{title} #{getKeystroke(bindings)}"}))

module.exports = spacePen

_ = require 'underscore-plus'
spacePen = require 'space-pen'
ConfigObserver = require './config-observer'
{Subscriber} = require 'emissary'

_.extend spacePen.View.prototype, ConfigObserver
Subscriber.includeInto(spacePen.View)

jQuery = spacePen.jQuery
originalCleanData = jQuery.cleanData
jQuery.cleanData = (elements) ->
  for element in elements
    if view = jQuery(element).view()
      view.unobserveConfig()
      view.unsubscribe()
  originalCleanData(elements)

tooltipDefaults =
  delay:
    show: 500
    hide: 100
  container: 'body'
  html: true

getKeystroke = (bindings) ->
  if bindings?.length
    "#{bindings[0].keystroke}"
  else
    ''

jQuery.fn.setTooltip = (title, {command, commandElement}={}) ->
  atom.requireWithGlobals('bootstrap/js/tooltip', {jQuery})

  bindings = if commandElement
    atom.keymap.keyBindingsForCommandMatchingElement(command, commandElement)
  else
    atom.keymap.keyBindingsForCommand(command)

  this.tooltip(jQuery.extend(tooltipDefaults, {title: "#{title} #{getKeystroke(bindings)}"}))

module.exports = spacePen

Fix up things for kevin

Fix up things for kevin


{div, span, header, i} = React.DOM
{form, input, label} = React.DOM
{ul, li} = React.DOM

user = React.createClass
  render: ->
    li className: 'user',
      div className: 'user-name',
        @props.nick

usersList = React.createClass
  render: ->
    users = @props.users.map (u) ->
      user(u)
    ul className: "users-list", users

usersHeader = React.createClass
  handleRoomContentEditable: () ->
    node = @refs.roomName.getDOMNode()
    node.textContent = ""
    node.contentEditable = true
    node.focus()

  changeRoom: (ev) ->
    if ev.keyCode isnt 13 then return
    node = @refs.roomName.getDOMNode()
    node.contentEditable = false
    node.blur()

  render: ->
    header className: "users-header",
      div {},
        span {className: "room-name", ref: "roomName", onBlur: @changeRoom, onKeyDown: @changeRoom}, @props.room
        i className: "fa fa-times", onClick: @handleRoomContentEditable

usersContainer = React.createClass
  render: ->
    div id: "users-container",
      usersHeader {room: @props.room}
      usersList {users: @props.users}

module.exports.usersContainer = usersContainer

{div, span, header, i} = React.DOM
{form, input, label} = React.DOM
{ul, li} = React.DOM

user = React.createClass
  render: ->
    li className: 'user',
      div className: 'user-name',
        @props.nick

usersList = React.createClass
  render: ->
    users = @props.users.map (u) ->
      user(u)
    ul className: "users-list", users

usersHeader = React.createClass
  changeRoom: (ev) ->
    if ev.keyCode isnt 13 then return
    node = @refs.roomName.getDOMNode()
    node.contentEditable = false
    node.blur()

  render: ->
    header className: "users-header",
      div {},
        span {className: "room-name", ref: "roomName", onBlur: @changeRoom, onKeyDown: @changeRoom}, @props.room

usersContainer = React.createClass
  render: ->
    div id: "users-container",
      usersHeader {room: @props.room}
      usersList {users: @props.users}

module.exports.usersContainer = usersContainer

Remove change-room x, we are not using it


"*":
  core:
    autoHideMenuBar: true
    disabledPackages: [
      "vim-mode"
    ]
  editor:
    fontSize: 10
    invisibles: {}
    scrollPastEnd: true
    showIndentGuide: true
  "exception-reporting":
    userId: "d066aaa4-63cd-1f08-a0e5-c8efdcf5268d"
  "git-plus": {}
  "markdown-preview":
    useGitHubStyle: true
  minimap: {}
  pigments:
    markerType: "dot"
  "toggle-packages":
    togglePackages: [
      "vim-mode"
    ]
  "vim-mode": {}
  welcome:
    showOnStartup: false

"*":
  core:
    autoHideMenuBar: true
    disabledPackages: [
      "vim-mode"
    ]
  editor:
    fontSize: 10
    invisibles: {}
    scrollPastEnd: true
    showIndentGuide: true
  "exception-reporting":
    userId: "d066aaa4-63cd-1f08-a0e5-c8efdcf5268d"
  "git-plus": {}
  "markdown-preview":
    useGitHubStyle: true
  minimap: {}
  pigments:
    markerType: "dot"
  "toggle-packages":
    togglePackages: [
      "vim-mode"
    ]
  "tree-view":
    hideIgnoredNames: true
  "vim-mode": {}
  welcome:
    showOnStartup: false

Hide ignore names by default

[atom] Hide ignore names by default


App.RoomUserStateItemController = Em.ObjectController.extend
  needs: ["application"]
  currentUser: Ember.computed.alias("controllers.application.currentUser")

  actions:
    join: ->
      console.log("hi", arguments)
      room_item_state = @get("model")
      console.log room_item_state.get("joined")
      room_item_state.set("joined", true)
      console.log room_item_state.get("joined")

      # successCallback  = =>
      #   console.log("deleted")
      # errorCallback = =>
      #   console.log("error whatever...")
      # # user.save().then(successCallback, errorCallback)

App.RoomUserStateItemController = Em.ObjectController.extend
  needs: ["application"]
  currentUser: Ember.computed.alias("controllers.application.currentUser")

  actions:
    join: ->
      room_item_state = @get("model")
      room_item_state.set("joined", true)

      successCallback  = =>
        console.log("saved")
      errorCallback = =>
        console.log("error whatever...")
      room_item_state.save().then(successCallback, errorCallback)

Update join state in RoomUserState

Update join state in RoomUserState


{TextEditor} = require 'atom'
util = require './util'
pluginManager = require './plugin-manager'

module.exports =
class CoffeeCompileEditor extends TextEditor
  constructor: ({@sourceEditor}) ->
    super

    if atom.config.get('coffee-compile.compileOnSave') and not
        atom.config.get('coffee-compile.compileOnSaveWithoutPreview')
      @disposables.add @sourceEditor.getBuffer().onDidSave => @renderAndSave()
      @disposables.add @sourceEditor.getBuffer().onDidReload => @renderAndSave()

    # set editor grammar to correct language
    grammar = atom.grammars.selectGrammar pluginManager.getCompiledScopeByEditor(@sourceEditor)
    @setGrammar grammar

    if atom.config.get('coffee-compile.compileOnSave') or
        atom.config.get('coffee-compile.compileOnSaveWithoutPreview')
      util.compileToFile @sourceEditor

  renderAndSave: ->
    @renderCompiled()
    util.compileToFile @sourceEditor

  renderCompiled: ->
    code = util.getSelectedCode @sourceEditor

    try
      text = util.compile code, @sourceEditor
    catch e
      text = e.stack

    @setText text

  getTitle: -> "Compiled #{@sourceEditor?.getTitle() or ''}".trim()
  getURI:   -> "coffeecompile://editor/#{@sourceEditor.id}"

{TextEditor} = require 'atom'
util = require './util'
pluginManager = require './plugin-manager'

module.exports =
class CoffeeCompileEditor extends TextEditor
  constructor: ({@sourceEditor}) ->
    super

    if atom.config.get('coffee-compile.compileOnSave') and not
        atom.config.get('coffee-compile.compileOnSaveWithoutPreview')
      @disposables.add @sourceEditor.getBuffer().onDidSave => @renderAndSave()
      @disposables.add @sourceEditor.getBuffer().onDidReload => @renderAndSave()

    # set editor grammar to correct language
    grammar = atom.grammars.selectGrammar pluginManager.getCompiledScopeByEditor(@sourceEditor)
    @setGrammar grammar

    if atom.config.get('coffee-compile.compileOnSave') or
        atom.config.get('coffee-compile.compileOnSaveWithoutPreview')
      util.compileToFile @sourceEditor

    # HACK: Override TextBuffer saveAs function
    @buffer.saveAs = ->

  renderAndSave: ->
    @renderCompiled()
    util.compileToFile @sourceEditor

  renderCompiled: ->
    code = util.getSelectedCode @sourceEditor

    try
      text = util.compile code, @sourceEditor
    catch e
      text = e.stack

    @setText text

  getTitle: -> "Compiled #{@sourceEditor?.getTitle() or ''}".trim()
  getURI:   -> "coffeecompile://editor/#{@sourceEditor.id}"

Disable `save` on preview pane

Disable `save` on preview pane

Fixes #30


{CompositeDisposable} = require 'atom'
HistoryView = null
ChangesView = null

HISTORY_URI = 'atom://git-experiment/view-history'
CHANGES_URI = 'atom://git-experiment/view-changes'

module.exports = GitExperiment =
  subscriptions: null

  activate: (state) ->
    # Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
    @subscriptions = new CompositeDisposable
    @subscriptions.add atom.workspace.registerOpener (filePath) =>
      switch filePath
        when HISTORY_URI
          HistoryView ?= require './history-view'
          new HistoryView()
        when CHANGES_URI
          ChangesView ?= require './changes-view'
          new ChangesView()

  deactivate: ->
    @subscriptions.dispose()

  serialize: ->
    # gitExperimentViewState: @gitExperimentView.serialize()

  openHistoryView: ->
    atom.workspace.open(HISTORY_URI)

  openChangesView: ->
    atom.workspace.open(CHANGES_URI)

atom.commands.add 'atom-workspace', 'git-experiment:view-history', =>
  GitExperiment.openHistoryView()

atom.commands.add 'atom-workspace', 'git-experiment:view-and-commit-changes', =>
  GitExperiment.openChangesView()

{CompositeDisposable} = require 'atom'
HistoryView = null
ChangesView = null

HISTORY_URI = 'atom://git-experiment/view-history'
CHANGES_URI = 'atom://git-experiment/view-changes'

module.exports = GitExperiment =
  subscriptions: null

  activate: (state) ->
    # Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
    @subscriptions = new CompositeDisposable
    process.nextTick =>
      @subscriptions.add atom.workspace.registerOpener (filePath) =>
        switch filePath
          when HISTORY_URI
            HistoryView ?= require './history-view'
            new HistoryView()
          when CHANGES_URI
            ChangesView ?= require './changes-view'
            new ChangesView()

  deactivate: ->
    @subscriptions?.dispose()

  serialize: ->
    # gitExperimentViewState: @gitExperimentView.serialize()

  openHistoryView: ->
    atom.workspace.open(HISTORY_URI)

  openChangesView: ->
    atom.workspace.open(CHANGES_URI)

atom.commands.add 'atom-workspace', 'git-experiment:view-history', =>
  GitExperiment.openHistoryView()

atom.commands.add 'atom-workspace', 'git-experiment:view-and-commit-changes', =>
  GitExperiment.openChangesView()

Move opener registration into a nextTick.

Registering the openers is expensive for some reason


ready = ->

# Jitsi Meet integration

  if $('body').hasClass('c-discourse a-embed') > 0

    $('#launch-jitsi').click ->
      room = 'Fablabs.io-' + Math.random().toString(36).substr(2, 8)
      domain = 'meet.jit.si'
      jitsiUrl = "http://"+domain+"/"+room
      $("#jitsi-url").replaceWith 'Invite other users from within the video call or by sending them this link: '+jitsiUrl+''
      width = $("div").width '#jitsi-row'
      height = 600
      htmlElement = document.getElementById('jitsi-embed')
      configOverwrite = {}
      interfaceConfigOverwrite = filmStripOnly: false
      api = new JitsiMeetExternalAPI(domain, room, width, height, htmlElement, configOverwrite, interfaceConfigOverwrite)
      return

$(document).ready ready

ready = ->

# Jitsi Meet integration

  if $('body').hasClass('c-discourse a-embed') > 0

    $('#launch-jitsi').click ->
      room = 'Fablabs.io-' + Math.random().toString(36).substr(2, 8)
      domain = 'meet.jit.si'
      jitsiUrl = "http://"+domain+"/"+room
      $("#jitsi-url").replaceWith 'Success Invite other users from within the video call or by sending them this link: '+jitsiUrl+''
      width = $("div").width '#jitsi-row'
      height = 600
      htmlElement = document.getElementById('jitsi-embed')
      configOverwrite = {}
      interfaceConfigOverwrite = filmStripOnly: false
      api = new JitsiMeetExternalAPI(domain, room, width, height, htmlElement, configOverwrite, interfaceConfigOverwrite)
      return

$(document).ready ready

Add label to jitsi integration success

Add label to jitsi integration success


MinimapFindAndReplaceBinding = require './minimap-find-and-replace-binding'

module.exports =
  binding: null
  activate: (state) ->
    findPackage = atom.packages.getLoadedPackage('find-and-replace')
    minimapPackage = atom.packages.getLoadedPackage('minimap')

    return @deactivate() unless findPackage? and minimapPackage?

    @binding = new MinimapFindAndReplaceBinding findPackage, minimapPackage

  deactivate: ->
    @binding?.deactivate()
    @minimapPackage = null
    @findPackage = null
    @binding = null

MinimapFindAndReplaceBinding = require './minimap-find-and-replace-binding'

module.exports =
  binding: null
  activate: (state) ->
    findPackage = atom.packages.getLoadedPackage('find-and-replace')
    minimapPackage = atom.packages.getLoadedPackage('minimap')

    return @deactivate() unless findPackage? and minimapPackage?

    minimap = require(minimapPackage.path)
    return @deactivate() unless minimap.versionMatch('2.x')

    @binding = new MinimapFindAndReplaceBinding findPackage, minimapPackage

  deactivate: ->
    @binding?.deactivate()
    @minimapPackage = null
    @findPackage = null
    @binding = null

:bug: Fix missing minimap version check in plugin activation


linterPath = atom.packages.getLoadedPackage("linter").path

Linter = require "#{linterPath}/lib/linter"

class LinterFlake8 extends Linter
  @syntax: ['source.python']

  cmd: 'flake8'

  executablePath: null

  linterName: 'flake8'

  # A regex pattern used to extract information from the executable's output.
  regex:
    '(.*?):(?<line>\\d+):(?<col>\\d+): (?<message>((?<error>E11|E9)|(?<warning>W|E|F4|F84|N*|C)|F)\\d+ .*?)\n'

  constructor: (editor)->
    super(editor)

    atom.config.observe 'linter-python-flake8.executableDir', =>
      @executablePath = atom.config.get 'linter-python-flake8.executableDir'

  destroy: ->
    atom.config.unobserve 'linter-python-flake8.executableDir'

module.exports = LinterFlake8

linterPath = atom.packages.getLoadedPackage("linter").path

Linter = require "#{linterPath}/lib/linter"

class LinterFlake8 extends Linter
  @syntax: ['source.python']

  cmd: 'flake8'

  executablePath: null

  linterName: 'flake8'

  # A regex pattern used to extract information from the executable's output.
  regex:
    '(.*?):(?<line>\\d+):(?<col>\\d+): (?<message>((?<error>E11|E9)|(?<warning>W|E|F4|F84|N*|C)|F)\\d+ .*?)\n'

  constructor: (editor)->
    super(editor)

    atom.config.observe 'linter-python-flake8.executableDir', =>
      @executablePath = atom.config.get 'linter-python-flake8.executableDir'

    atom.config.observe 'linter-python-flake8.maxLineLength', =>
      @updateCommand()

    atom.config.observe 'linter-python-flake8.ignoreErrorCodes', =>
      @updateCommand()

  destroy: ->
    atom.config.unobserve 'linter-python-flake8.maxLineLength'
    atom.config.unobserve 'linter-python-flake8.ignoreErrorCodes'
    atom.config.unobserve 'linter-python-flake8.executableDir'

  updateCommand: ->
    cmd = 'flake8'
    maxLineLength = atom.config.get 'linter-python-flake8.maxLineLength'
    errorCodes = atom.config.get 'linter-pep8.ignoreErrorCodes'

    if maxLineLength
      cmd = "#{cmd} --max-line-length=#{maxLineLength}"

    if errorCodes and errorCodes.length > 0
      cmd += " --ignore=#{errorCodes.toString()}"

    @cmd = cmd
module.exports = LinterFlake8

Add options: max line length, ignore error codes

Added option to specify maximum line length and ignore specified error codes


# Github Credentials allows you to map your user against your GitHub user.
# This is specifically in order to work with apps that have GitHub Oauth users.
#
# who do you know - List all the users with github logins tracked by Hubot
# i am `maddox` - map your user to the github login `maddox`
# who am i - reveal your mapped github login
# forget me - de-map your user to your github login

module.exports = (robot) ->

  robot.respond /who do you know/i, (msg) ->
    theReply = "Here is who I know:\n"

    for own key, user of robot.brain.data.users
      if(user.githubLogin)
        theReply += user.name + " is " + user.githubLogin + "\n"

    msg.send theReply

  robot.respond /i am (\w+)/i, (msg) ->
    githubLogin = msg.match[1]
    msg.message.user.githubLogin = githubLogin
    msg.send "Ok, you are " + githubLogin + " on GitHub"

  robot.respond /who am i/i, (msg) ->
    user = msg.message.user
    if user.githubLogin
      msg.reply "You are known as " + user.githubLogin + " on GitHub"
    else
      msg.reply "I don't know who you are. You should probably identify yourself with your GitHub login"

  robot.respond /forget me/i, (msg) ->
    user = msg.message.user
    user.githubLogin = null

    msg.reply("Ok, I have no idea who you are anymore.")

# Github Credentials allows you to map your user against your GitHub user.
# This is specifically in order to work with apps that have GitHub Oauth users.
#
# who do you know - List all the users with github logins tracked by Hubot
# i am `maddox` - map your user to the github login `maddox`
# who am i - reveal your mapped github login
# forget me - de-map your user to your github login

module.exports = (robot) ->

  robot.respond /who do you know/i, (msg) ->
    theReply = "Here is who I know:\n"

    for own key, user of robot.brain.data.users
      if(user.githubLogin)
        theReply += user.name + " is " + user.githubLogin + "\n"

    msg.send theReply

  robot.respond /i am ([a-z-]+)/i, (msg) ->
    githubLogin = msg.match[1]
    msg.message.user.githubLogin = githubLogin
    msg.send "Ok, you are " + githubLogin + " on GitHub"

  robot.respond /who am i/i, (msg) ->
    user = msg.message.user
    if user.githubLogin
      msg.reply "You are known as " + user.githubLogin + " on GitHub"
    else
      msg.reply "I don't know who you are. You should probably identify yourself with your GitHub login"

  robot.respond /forget me/i, (msg) ->
    user = msg.message.user
    user.githubLogin = null

    msg.reply("Ok, I have no idea who you are anymore.")

Support dashes in the github username

Support dashes in the github username


BufferController = require './buffer-controller'
{Emitter} = require 'atom'

module.exports =
class AutocompleteProvider
  selector: '.source.haskell'
  blacklist: '.source.haskell .comment'
  inclusionPriority: 1
  excludeLowerPriority: false
  info:
    moduleList: []
    langOpts: []
    ghcFlags: []
  emitter: null
  bufferMap: null
  observers: null
  backend: null

  backendProvider: (@backend) =>
    @emitter.emit 'did-get-backend', @backend
    @backend.listModules(atom.project.getDirectories()[0]).then (res) =>
      @info.moduleList=res
    @backend.listLanguagePragmas().then (res) => @info.langOpts=res
    @backend.listCompilerOptions().then (res) => @info.ghcFlags=res

  onDidGetBackend: (callback) ->
    @emitter.on 'did-get-backend', callback

  constructor: ->
    @emitter = new Emitter
    @bufferMap = new WeakMap
    @observers=atom.workspace.observeTextEditors (editor) =>
      return unless editor.getGrammar().scopeName=="source.haskell"
      buf = editor.getBuffer()
      @bufferMap.set buf, new BufferController(buf,this)

  dispose: =>
    @observers.dispose()
    @emtitter?.destroy()
    for editor in atom.workspace.getTextEditors()
      @bufferMap.get(editor.getBuffer())?.desrtoy?()
      @bufferMap.delete(editor.getBuffer())

  getSuggestions: (options) =>
    @bufferMap.get(options.editor.getBuffer())?.getSuggestions? options,@info

BufferController = require './buffer-controller'
{Emitter} = require 'atom'

module.exports =
class AutocompleteProvider
  selector: '.source.haskell'
  disableForSelector: '.source.haskell .comment'
  inclusionPriority: 1
  excludeLowerPriority: false
  info:
    moduleList: []
    langOpts: []
    ghcFlags: []
  emitter: null
  bufferMap: null
  observers: null
  backend: null

  backendProvider: (@backend) =>
    @emitter.emit 'did-get-backend', @backend
    @backend.listModules(atom.project.getDirectories()[0]).then (res) =>
      @info.moduleList=res
    @backend.listLanguagePragmas().then (res) => @info.langOpts=res
    @backend.listCompilerOptions().then (res) => @info.ghcFlags=res

  onDidGetBackend: (callback) ->
    @emitter.on 'did-get-backend', callback

  constructor: ->
    @emitter = new Emitter
    @bufferMap = new WeakMap
    @observers=atom.workspace.observeTextEditors (editor) =>
      return unless editor.getGrammar().scopeName=="source.haskell"
      buf = editor.getBuffer()
      @bufferMap.set buf, new BufferController(buf,this)

  dispose: =>
    @observers.dispose()
    @emtitter?.destroy()
    for editor in atom.workspace.getTextEditors()
      @bufferMap.get(editor.getBuffer())?.desrtoy?()
      @bufferMap.delete(editor.getBuffer())

  getSuggestions: (options) =>
    @bufferMap.get(options.editor.getBuffer())?.getSuggestions? options,@info

Fix deprecated ac+ blacklist option

Fix deprecated ac+ blacklist option


# This script teaches Hubot to answer questions like "Who owns Collections Publisher?"
# and "Who owns publishing-api?"
module.exports = (robot) ->
  robot.hear /who owns (.*)\?/i, (res) ->
    # Best guess of the intended application.
    application = res.match[1].replace(' ', '-').toLowerCase()

    robot.http("https://docs.publishing.service.gov.uk/apps/#{application}.json")
      .get() (err, response, body) ->
        if response.statusCode == 200
          data = JSON.parse(body)
          res.reply "#{application} is owned by #{data.team}"

# This script teaches Hubot to answer questions like "Who owns Collections Publisher?"
# and "Who owns publishing-api?"
module.exports = (robot) ->
  robot.hear /who owns (.*)\?/i, (res) ->
    # Best guess of the intended application.
    application = res.match[1].replace(/ /g, '-').toLowerCase()
    console.log("Fetching owner for #{application}")

    robot.http("https://docs.publishing.service.gov.uk/apps/#{application}.json")
      .get() (err, response, body) ->
        if response.statusCode == 200
          data = JSON.parse(body)
          res.reply "#{application} is owned by #{data.team}"

Fix replacing spaces in app names

Fix replacing spaces in app names

This previously would translate `email alert api` into `email-alert
api` not `email-alert-api`.


kd              = require 'kd'
KDTabHandleView = kd.TabHandleView

module.exports = class IDETabHandleView extends KDTabHandleView

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

    options.droppable ?= yes
    options.bind       = 'dragstart'

    super options, data

  dragStart: (event) ->

    ## workaround for FF and ChromeApp
    event.originalEvent.dataTransfer.setData 'text/plain', ' '

    kd.singletons.appManager.tell 'IDE', 'setTargetTabView', @getDelegate()

kd              = require 'kd'
KDTabHandleView = kd.TabHandleView

module.exports = class IDETabHandleView extends KDTabHandleView

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

    options.draggable ?= yes
    options.bind       = 'dragstart'

    super options, data

  setDraggable: ->

    @setAttribute 'draggable', yes

  dragStart: (event) ->

    ## workaround for FF and ChromeApp
    event.originalEvent.dataTransfer.setData 'text/plain', ' '

    kd.singletons.appManager.tell 'IDE', 'setTargetTabView', @getDelegate()

Remove droppable attribute and override already defined method about this


"use strict"

Beautifier = require('./beautifier')
prettier = require("prettier")

module.exports = class Prettier extends Beautifier
  name: "Prettier"
  link: "https://github.com/prettier/prettier"
  options: {
    _:
      tabWidth: "indent_size"
      useTabs: ["indent_with_tabs", "indent_char", (indent_with_tabs, indent_char) ->
        return (indent_with_tabs is true) or (indent_char is "\t")
      ]
    JavaScript:
      bracketSpacing: "object_curly_spacing"
    TypeScript: false
    CSS: false
    LESS: false
    SCSS: false
    Vue: false
    JSON: false
    Markdown: false
  }

  beautify: (text, language, options) ->
    return new @Promise((resolve, reject) ->
      _ = require('lodash')

      prettierLanguage = _.find(prettier.getSupportInfo().languages, 'name': language)
      if prettierLanguage
        parser = prettierLanguage.parsers[0]
      else
        reject(new Error("Unknown language for Prettier"))

      try
        result = prettier.format(text, {
          options
          parser
        })
        resolve result
      catch err
        reject(err)
    )

"use strict"

Beautifier = require('./beautifier')
prettier = require("prettier")

module.exports = class Prettier extends Beautifier
  name: "Prettier"
  link: "https://github.com/prettier/prettier"
  options: {
    _:
      tabWidth: "indent_size"
      useTabs: ["indent_with_tabs", "indent_char", (indent_with_tabs, indent_char) ->
        return (indent_with_tabs is true) or (indent_char is "\t")
      ]
    JavaScript:
      bracketSpacing: "object_curly_spacing"
    TypeScript: false
    CSS: false
    LESS: false
    SCSS: false
    Vue: false
    JSON: false
    Markdown: false
  }

  beautify: (text, language, options) ->
    return new @Promise((resolve, reject) ->
      _ = require('lodash')

      prettierLanguage = _.find(prettier.getSupportInfo().languages, 'name': language)
      if prettierLanguage
        parser = prettierLanguage.parsers[0]
      else
        reject(new Error("Unknown language for Prettier"))

      filePath = atom.workspace.getActiveTextEditor().getPath()

      try
        prettier.resolveConfig(filePath).then((configOptions) ->
          result = prettier.format(text, configOptions or options, parser)
          prettier.clearConfigCache()
          resolve result
        )
      catch err
        reject(err)
    )

Fix options not working from Atom UI and config file


Path = require 'path'
{CompositeDisposable, Emitter} = require 'atom'

{LinterTrace, LinterMessage, LinterError, LinterWarning} = require './messages'
EditorLinter = require './editor-linter'

class Linter

  constructor: ->
    @Emitter = new Emitter
    @Subscriptions = new CompositeDisposable
    @EditorLinters = new Map # A map of Editor <--> Linter
    @Linters = new Set # I <3 ES6
    @Subscriptions.add atom.workspace.observeTextEditors (Editor) =>
      EditorLinter = new EditorLinter @, Editor
      @Emitter.emit 'linters-observe', EditorLinter
      Editor.onDidDestroy =>
        EditorLinter.destroy()
        @EditorLinters.delete EditorLinter

  getActiveEditorLinter:->
    ActiveEditor = atom.workspace.getActiveEditor()
    return ActiveEditor unless ActiveEditor
    return @EditorLinters.get ActiveEditor

  getLinter:(Editor)->
    return @EditorLinters.get Editor

  observeLinters:(Callback)->
    Callback(Linter[1]) for Linter of @EditorLinters
    @Emitter.on 'linters-observe', Callback

module.exports = Linter

Path = require 'path'
{CompositeDisposable, Emitter} = require 'atom'

{LinterTrace, LinterMessage, LinterError, LinterWarning} = require './messages'
EditorLinter = require './editor-linter'

class Linter

  constructor: ->
    @Emitter = new Emitter
    @Subscriptions = new CompositeDisposable
    @EditorLinters = new Map # A map of Editor <--> Linter
    @Linters = new Set # I <3 ES6
    @Subscriptions.add atom.workspace.observeTextEditors (Editor) =>
      CurrentEditorLinter = new EditorLinter @, Editor
      @Emitter.emit 'linters-observe', CurrentEditorLinter
      Editor.onDidDestroy =>
        CurrentEditorLinter.destroy()
        @EditorLinters.delete CurrentEditorLinter

  getActiveEditorLinter:->
    ActiveEditor = atom.workspace.getActiveEditor()
    return ActiveEditor unless ActiveEditor
    return @EditorLinters.get ActiveEditor

  getLinter:(Editor)->
    return @EditorLinters.get Editor

  observeLinters:(Callback)->
    Callback(Linter[1]) for Linter of @EditorLinters
    @Emitter.on 'linters-observe', Callback

module.exports = Linter

Fix a duplicate variable issue

:bug: Fix a duplicate variable issue


angular.module('loomioApp').directive 'positionButtonsPanel', ->
  scope: {proposal: '='}
  restrict: 'E'
  templateUrl: 'generated/components/thread_page/position_buttons_panel/position_buttons_panel.html'
  replace: true
  controller: ($scope, ModalService, VoteForm, CurrentUser, Records) ->

    $scope.showPositionButtons = ->
      CurrentUser.isMemberOf($scope.proposal.group()) and
      $scope.proposal.isActive() and $scope.undecided()

    $scope.undecided = ->
      !($scope.proposal.lastVoteByUser(CurrentUser)?)

    $scope.$on 'triggerVoteForm', (event, position) ->
      myVote = $scope.proposal.lastVoteByUser(CurrentUser) or {}
      $scope.select position, myVote.statement

    $scope.select = (position) ->
      ModalService.open(VoteForm, vote: -> Records.votes.build(proposalId: $scope.proposal.id, position: position))

angular.module('loomioApp').directive 'positionButtonsPanel', ->
  scope: {proposal: '='}
  restrict: 'E'
  templateUrl: 'generated/components/thread_page/position_buttons_panel/position_buttons_panel.html'
  replace: true
  controller: ($scope, ModalService, VoteForm, CurrentUser, Records, AbilityService) ->

    $scope.showPositionButtons = ->
      AbilityService.canVoteOn($scope.proposal) and $scope.undecided()

    $scope.undecided = ->
      !($scope.proposal.lastVoteByUser(CurrentUser)?)

    $scope.$on 'triggerVoteForm', (event, position) ->
      myVote = $scope.proposal.lastVoteByUser(CurrentUser) or {}
      $scope.select position, myVote.statement

    $scope.select = (position) ->
      ModalService.open(VoteForm, vote: -> Records.votes.build(proposalId: $scope.proposal.id, position: position))

Fix for position buttons panel

Fix for position buttons panel


Travis.AccountController = Ember.ObjectController.extend
  allHooks: []
  needs: ['currentUser']
  userBinding: 'controllers.currentUser'

  init: ->
    @_super.apply this, arguments

    self = this
    Travis.on("user:synced", (->
      self.reloadHooks()
    ))

  toggle: (hook) ->
    hook.toggle()

  reloadHooks: ->
    if login = @get('login')
      @set('allHooks', Travis.Hook.find(all: true, owner_name: login))

  hooks: (->
    @reloadHooks() unless hooks = @get('allHooks')
    @get('allHooks').filter (hook) -> hook.get('admin')
  ).property('allHooks.length', 'allHooks')

  hooksWithoutAdmin: (->
    @reloadHooks() unless hooks = @get('allHooks')
    @get('allHooks').filter (hook) -> !hook.get('admin')
  ).property('allHooks.length', 'allHooks')

  showPrivateReposHint: (->
    Travis.config.show_repos_hint == 'private'
  ) .property()

  showPublicReposHint: (->
    Travis.config.show_repos_hint == 'public'
  ) .property()

  actions:
    sync: ->
      @get('user').sync()

Travis.AccountController = Ember.ObjectController.extend
  allHooks: []
  needs: ['currentUser']
  userBinding: 'controllers.currentUser'

  init: ->
    @_super.apply this, arguments

    self = this
    Travis.on("user:synced", (->
      self.reloadHooks()
    ))

  actions:
    sync: ->
      @get('user').sync()

    toggle: (hook) ->
      hook.toggle()

  reloadHooks: ->
    if login = @get('login')
      @set('allHooks', Travis.Hook.find(all: true, owner_name: login))

  hooks: (->
    @reloadHooks() unless hooks = @get('allHooks')
    @get('allHooks').filter (hook) -> hook.get('admin')
  ).property('allHooks.length', 'allHooks')

  hooksWithoutAdmin: (->
    @reloadHooks() unless hooks = @get('allHooks')
    @get('allHooks').filter (hook) -> !hook.get('admin')
  ).property('allHooks.length', 'allHooks')

  showPrivateReposHint: (->
    Travis.config.show_repos_hint == 'private'
  ) .property()

  showPublicReposHint: (->
    Travis.config.show_repos_hint == 'public'
  ) .property()

Fix toggling hooks on profile page

Fix toggling hooks on profile page


module.exports = (grunt) ->
  grunt.registerTask 'check-licenses', 'Report the licenses of all dependencies', ->
    legalEagle = require 'legal-eagle'
    {size, keys} = require 'underscore-plus'
    done = @async()

    options =
      path: process.cwd()
      omitPermissive: true
      overrides: require './license-overrides'

    legalEagle options, (err, summary) ->
      if err?
        console.error(err)
        exit 1

      if size(summary)
        console.error "Found dependencies without permissive licenses:"
        for name in keys(summary).sort()
          console.error "#{name}"
          console.error "  License: #{summary[name].license}"
          console.error "  Repository: #{summary[name].repository}"
        process.exit 1
      done()

module.exports = (grunt) ->
  grunt.registerTask 'check-licenses', 'Report the licenses of all dependencies', ->
    legalEagle = require 'legal-eagle'
    {size, keys} = require 'underscore-plus'
    done = @async()

    options =
      path: process.cwd()
      omitPermissive: true
      overrides: require './license-overrides'

    legalEagle options, (err, summary) ->
      if err?
        console.error(err)
        exit 1

      # Omit failure for coffee-script bundle for now. It seems to be intended
      # to be open source but has no license.
      for dependencyName in keys(summary)
        if dependencyName.match /^language-coffee-script@/
          delete summary[dependencyName]

      if size(summary)
        console.error "Found dependencies without permissive licenses:"
        for name in keys(summary).sort()
          console.error "#{name}"
          console.error "  License: #{summary[name].license}"
          console.error "  Repository: #{summary[name].repository}"
        process.exit 1
      done()

Allow language-coffee-script without a license for now


mongoose = require 'mongoose'
timestamps = require 'mongoose-timestamps'
Schema = mongoose.Schema
db = mongoose.createConnection "mongodb://localhost:27017/badges-#{process.env.NODE_ENV}"

OrganizationSchema = new Schema
  name: String
  origin: String
  org: String
  contact: String
  created_at: Date
  updated_at: Date

OrganizationSchema.plugin(timestamps)

Organization = db.model 'Organization', OrganizationSchema

module.exports = Organization

mongoose = require 'mongoose'
timestamps = require 'mongoose-timestamps'
Schema = mongoose.Schema
db = mongoose.createConnection "mongodb://localhost:27017/badges-#{process.env.NODE_ENV}"

OrganizationSchema = new Schema
  name: String
  origin: String
  org: String
  api_key: String
  contact: String
  created_at: Date
  updated_at: Date

OrganizationSchema.plugin(timestamps)

Organization = db.model 'Organization', OrganizationSchema

module.exports = Organization

Add API key to the Organization model

Add API key to the Organization model


$ = jQuery

export default class Notice
  constructor: ->
    $ @initialize

  hide: =>
    $('#notice-container').hide()

  initialize: =>
    msg = Cookies.get 'notice'

    return unless msg? && msg != ''

    @show msg, true
    Cookies.remove 'notice'

  # If initial is true, this is a notice set by the notice cookie and not a
  # realtime notice from user interaction.
  show: (msg, initial) =>
    # If this is an initial notice, and this screen has a dedicated notice
    # container other than the floating notice, use that and don't hide it.
    if initial ? false
      $staticNotice = $('#static_notice')
      if $staticNotice.length > 0
        $staticNotice
          .html(msg)
          .show()
        return

    $('#notice').html msg
    $('#notice-container').show()

    clearTimeout @timeout
    @timeout = setTimeout @hide, 5000

$ = jQuery

export default class Notice
  constructor: ->
    $ @initialize

  hide: =>
    $('#notice-container').hide()

  initialize: =>
    msg = Cookies.get 'notice'

    return unless msg? && msg != ''

    @show msg, true
    Cookies.remove 'notice'

  # If initial is true, this is a notice set by the notice cookie and not a
  # realtime notice from user interaction.
  show: (msg, initial) =>
    # If this is an initial notice, and this screen has a dedicated notice
    # container other than the floating notice, use that and don't hide it.
    if initial ? false
      $staticNotice = $('#static_notice')
      if $staticNotice.length > 0
        $staticNotice
          .text(msg)
          .show()
        return

    $('#notice').text msg
    $('#notice-container').show()

    clearTimeout @timeout
    @timeout = setTimeout @hide, 5000

Use text instead of html

Use text instead of html

Safer, etc


StepView = require './step.coffee'
Form = require '../../form/index.coffee'
Feedback = require '../../../models/feedback.coffee'
Representatives = require '../../../collections/representatives.coffee'
template = -> require('../templates/specialist.jade') arguments...

module.exports = class Specialist extends StepView
  template: -> template arguments...

  __events__:
    'click button': 'serialize'

  initialize: ->
    @feedback = new Feedback
    @representatives = new Representatives
    @representatives.fetch()
      .then => (@representative = @representatives.first()).fetch()
      .then => @render()

    super

  serialize: (e) ->
    form = new Form model: @feedback, $form: @$('form')
    form.submit e, success: =>
      @next()

  render: ->
    @$el.html @template
      user: @user
      representative: @representative
    @autofocus()
    this

StepView = require './step.coffee'
Form = require '../../form/index.coffee'
Feedback = require '../../../models/feedback.coffee'
Representatives = require '../../../collections/representatives.coffee'
template = -> require('../templates/specialist.jade') arguments...

module.exports = class Specialist extends StepView
  template: -> template arguments...

  __events__:
    'click button': 'serialize'

  initialize: ->
    @feedback = new Feedback
    @representatives = new Representatives
    super

  setup: ->
    @representatives.fetch()
      .then => (@representative = @representatives.first()).fetch()
      .then => @render()

  serialize: (e) ->
    form = new Form model: @feedback, $form: @$('form')
    form.submit e, success: =>
      @next()

  render: ->
    @$el.html @template
      user: @user
      representative: @representative
    @autofocus()
    this

Use the explicit setup step

Use the explicit setup step


'core':
  'hideGitIgnoredFiles': true
  'ignoredNames': [
    '.DS_Store'
    '.git'
    'vendor'
  ]
  'themes': [
    'atom-dark-ui'
    'solarized-dark-syntax'
  ]
  'disabledPackages': []
  'destroyEmptyPanes': false
'editor':
  'fontSize': 13
  'hideGitIgnoredFiles': true
  'normalizeIndentOnPaste': false
'whitespace':
  'ensureSingleTrailingNewline': true
'spell-check':
  'grammars': [
    'text.plain'
    'source.gfm'
    'text.git-commit'
  ]
'welcome':
  'showOnStartup': false
'find-and-replace':
  'openProjectFindResultsInRightPane': true
'wrap-guide':
  'columns': [
    {
      'pattern': 'COMMIT_EDITMSG'
      'column': 72
    }
  ]
'autocomplete':
  'includeCompletionsFromAllBuffers': true
'scroll-past-end':
  'retainHalfScreen': true

'core':
  'hideGitIgnoredFiles': true
  'ignoredNames': [
    '.DS_Store'
    '.git'
    'vendor'
  ]
  'themes': [
    'atom-dark-ui'
    'solarized-dark-syntax'
  ]
  'disabledPackages': []
  'destroyEmptyPanes': false
  'useReactEditor': true
'editor':
  'fontSize': 13
  'hideGitIgnoredFiles': true
  'normalizeIndentOnPaste': false
'whitespace':
  'ensureSingleTrailingNewline': true
'spell-check':
  'grammars': [
    'text.plain'
    'source.gfm'
    'text.git-commit'
  ]
'welcome':
  'showOnStartup': false
'find-and-replace':
  'openProjectFindResultsInRightPane': true
'wrap-guide':
  'columns': [
    {
      'pattern': 'COMMIT_EDITMSG'
      'column': 72
    }
  ]
'autocomplete':
  'includeCompletionsFromAllBuffers': true
'scroll-past-end':
  'retainHalfScreen': true

Use React editor in Atom

Use React editor in Atom


'use strict'

app.directive 'pdfViewer', [
  () ->
    restrict: 'E'
    scope:
      asset:  '=asset'
    link: ($scope, $elem) ->
      pdfElement = $($elem)[0]
      objectTag = document.createElement('object')
      objectTag.setAttribute('data', $scope.asset.downloadRoute(true))
      objectTag.setAttribute('width', '80%')
      pdfElement.appendChild(objectTag)
      return

]

'use strict'

app.directive 'pdfViewer', [
  () ->
    restrict: 'E'
    scope:
      asset:  '=asset'
    link: ($scope, $elem) ->
      pdfElement = $($elem)[0]
      objectTag = document.createElement('object')
      objectTag.setAttribute('data', $scope.asset.downloadRoute(true))
      objectTag.setAttribute('width', '80%')
      objectTag.setAttribute('type', $scope.asset.format.mimetype)
      pdfElement.appendChild(objectTag)
      return

]

Set the type inside the directive.

Set the type inside the directive.


{cloneFragment, triggerEvent} = Trix

Trix.registerElement "trix-toolbar",
  defaultCSS: """
    %t {
      white-space: collapse;
    }

    %t .dialog {
      display: none;
    }

    %t .dialog.active {
      display: block;
    }

    %t .dialog input.validate:invalid {
      background-color: #ffdddd;
    }

    %t[native] {
      display: none;
    }
  """

  attachedCallback: ->
    if @innerHTML is ""
      @appendChild(cloneFragment(Trix.config.toolbar.content))

    if @hasAttribute("native")
      if Trix.NativeToolbarController
        @toolbarController = new Trix.NativeToolbarController this
      else
        throw "Host application must implement Trix.NativeToolbarController"
    else
      @toolbarController = new Trix.ToolbarController this

    triggerEvent("trix-element-attached", onElement: this)

{cloneFragment, triggerEvent} = Trix

Trix.registerElement "trix-toolbar",
  defaultCSS: """
    %t {
      white-space: collapse;
    }

    %t .dialog {
      display: none;
    }

    %t .dialog.active {
      display: block;
    }

    %t .dialog input.validate:invalid {
      background-color: #ffdddd;
    }

    %t[native] {
      display: none;
    }
  """

  attachedCallback: ->
    if @innerHTML is ""
      @appendChild(cloneFragment(Trix.config.toolbar.content))

    @toolbarController = new Trix.ToolbarController this

    triggerEvent("trix-element-attached", onElement: this)

Remove unused "native" toolbar element attribute


should = require 'should'
Impromptu = require '../src/impromptu'

describe 'Impromptu', ->
  it 'should exist', ->
    should.exist Impromptu

  it 'should use semantic versions', ->
    /^\d+\.\d+\.\d+(\D|$)/.test(Impromptu.VERSION).should.be.true

describe 'Impromptu.Error', ->
  it 'should have a message', ->
    error = new Impromptu.Error 'message'
    error.message.should.equal 'message'

  it 'should be throwable', ->
    (-> throw new Impromptu.Error('message')).should.throw 'message'

  it 'should support the `instanceof` keyword', ->
    error = new Impromptu.Error
    error.should.be.an.instanceof Impromptu.Error

  it 'should be extendable', ->
    class CustomError extends Impromptu.Error

    error = new CustomError
    error.should.be.an.instanceof Impromptu.Error
    error.should.be.an.instanceof CustomError

should = require 'should'
Impromptu = require '../src/impromptu'

describe 'Impromptu', ->
  it 'should exist', ->
    should.exist Impromptu

  it 'should use semantic versions', ->
    # https://github.com/coolaj86/semver-utils/blob/v1.0.1/semver-utils.js
    regex = /^((\d+)\.(\d+)\.(\d+))(?:-([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?(?:\+([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?$/
    regex.test(Impromptu.VERSION).should.be.true

describe 'Impromptu.Error', ->
  it 'should have a message', ->
    error = new Impromptu.Error 'message'
    error.message.should.equal 'message'

  it 'should be throwable', ->
    (-> throw new Impromptu.Error('message')).should.throw 'message'

  it 'should support the `instanceof` keyword', ->
    error = new Impromptu.Error
    error.should.be.an.instanceof Impromptu.Error

  it 'should be extendable', ->
    class CustomError extends Impromptu.Error

    error = new CustomError
    error.should.be.an.instanceof Impromptu.Error
    error.should.be.an.instanceof CustomError

Use an insanely complicated regex to test for a semantic version


noflo = require 'noflo'

exports.getComponent = ->
  c = new noflo.Component
  c.description = 'Get user token from action'
  c.icon = 'key'
  c.inPorts.add 'in',
    datatype: 'object'
  c.outPorts.add 'token',
    datatype: 'string'
  c.outPorts.add 'out',
    datatype: 'object'
  c.outPorts.add 'error',
    datatype: 'object'

  noflo.helpers.WirePattern c,
    in: 'in'
    out: ['token', 'out']
    async: true
  , (data, groups, out, callback) ->
    out.token.send data.state?.user?['github-token'] or null
    out.out.send data.payload
    do callback

noflo = require 'noflo'
octo = require 'octo'

exports.getComponent = ->
  c = new noflo.Component
  c.description = 'Get user token from action'
  c.icon = 'key'
  c.inPorts.add 'in',
    datatype: 'object'
  c.outPorts.add 'token',
    datatype: 'string'
  c.outPorts.add 'out',
    datatype: 'object'
  c.outPorts.add 'error',
    datatype: 'object'

  noflo.helpers.WirePattern c,
    in: 'in'
    out: ['token', 'out']
    async: true
  , (data, groups, out, callback) ->
    token = data.state?.user?['github-token'] or null

    # Check that user has some API calls remaining
    api = octo.api()
    api.token token if token
    request = api.get '/rate_limit'
    request.on 'success', (res) ->
      remaining = res.body.rate?.remaining or 0
      if remaining < 50
        if token
          callback new Error 'GitHub API access rate limited, try again later'
          return
        callback new Error 'GitHub API access rate limited. Please log in to increase the limit'
        return
      out.token.send token
      out.out.send data.payload
      do callback
    request.on 'error', (err) ->
      error = err.error or err.body
      callback new Error "Failed to communicate with GitHub: #{error}"
    do request

Check rate limit and warn user if about to be exceeded


_ = require "underscore"
Transform = require "./transform"
p = require "../../core/properties"
math = require "../../core/util/math"

class Jitter extends Transform.Model
  initialize: (attrs, options) ->
    super(attrs, options)

  @define {
      mean:         [ p.Number, 0        ]
      width:        [ p.Number, 1        ]
      distribution: [ p.String, 'uniform']
    }

  compute: (x) ->
    # Apply the transform to a single value
    if @get('distribution') == 'uniform'
        return(x + @get('mean') + ((Math.random() - 0.5) * @get('width')))

    if @get('distribution') == 'normal'
        return(x + math.rnorm(@get('mean'), @get('width')))

  v_compute: (xs) ->
    # Apply the tranform to a vector of values
    result = new Float64Array(xs.length)
    for x, idx in xs
      result[idx] = this.compute(x)
    return result

module.exports =
  Model: Jitter

_ = require "underscore"
Transform = require "./transform"
p = require "../../core/properties"
bokeh_math = require "../../core/util/math"

class Jitter extends Transform.Model
  initialize: (attrs, options) ->
    super(attrs, options)

  @define {
      mean:         [ p.Number, 0        ]
      width:        [ p.Number, 1        ]
      distribution: [ p.String, 'uniform']
    }

  compute: (x) ->
    # Apply the transform to a single value
    if @get('distribution') == 'uniform'
        return(x + @get('mean') + ((Math.random() - 0.5) * @get('width')))

    if @get('distribution') == 'normal'
        return(x + bokeh_math.rnorm(@get('mean'), @get('width')))

  v_compute: (xs) ->
    # Apply the tranform to a vector of values
    result = new Float64Array(xs.length)
    for x, idx in xs
      result[idx] = this.compute(x)
    return result

module.exports =
  Model: Jitter

Change imported name from "math" to "bokeh_math" to make it more obvious this is not related to the core JS "Math" facility.


$(document).on "page:change", ->
  $(".data-table").each ->
    table = $(@)

    return if $.fn.dataTable.isDataTable(table)

    options =
      responsive: true
      order: [[0, "desc"]]

    ascColumn = table.find("th.sort-asc").index()
    descColumn = table.find("th.sort-desc").index()

    if (ascColumn >= 0)
      options["order"] = [[ ascColumn, "asc" ]]

    if (descColumn >= 0)
      options["order"] = [[ descColumn, "desc" ]]

    if table.hasClass("no-paging")
      options["paging"] = false

    table.dataTable(options)

$(document).on "page:change", ->
  $(".data-table").each ->
    table = $(@)

    return if $.fn.dataTable.isDataTable(table)

    options =
      responsive: true
      order: [[0, "desc"]]
      pageLength: 25

    ascColumn = table.find("th.sort-asc").index()
    descColumn = table.find("th.sort-desc").index()

    if (ascColumn >= 0)
      options["order"] = [[ ascColumn, "asc" ]]

    if (descColumn >= 0)
      options["order"] = [[ descColumn, "desc" ]]

    if table.hasClass("no-paging")
      options["paging"] = false

    table.dataTable(options)

Add default page legth to 25 for datatable for readability


describe "RequireJS", ->
  beforeEach ->
    @addMatchers requirejsTobeUndefined: ->
      typeof requirejs is "undefined"

  it "check that the RequireJS object is present in the global namespace", ->
    expect(RequireJS).toEqual jasmine.any(Object)
    expect(window.RequireJS).toEqual jasmine.any(Object)

  it "check that requirejs(), require(), and define() are not in the global namespace", ->
    expect({}).requirejsTobeUndefined()

    # expect(require).not.toBeDefined();
    # expect(define).not.toBeDefined();
    expect(window.requirejs).not.toBeDefined()
    expect(window.require).not.toBeDefined()
    expect(window.define).not.toBeDefined()

describe "RequireJS", ->
  beforeEach ->
    @addMatchers
      requirejsTobeUndefined: ->
        typeof requirejs is "undefined"

      requireTobeUndefined: ->
        typeof require is "undefined"

      defineTobeUndefined: ->
        typeof define is "undefined"

  it "check that the RequireJS object is present in the global namespace", ->
    expect(RequireJS).toEqual jasmine.any(Object)
    expect(window.RequireJS).toEqual jasmine.any(Object)

  it "check that requirejs(), require(), and define() are not in the global namespace", ->
    expect({}).requirejsTobeUndefined()
    expect({}).requireTobeUndefined()
    expect({}).defineTobeUndefined()
    expect(window.requirejs).not.toBeDefined()
    expect(window.require).not.toBeDefined()
    expect(window.define).not.toBeDefined()

Work on RequireJS Jasmine test.

Work on RequireJS Jasmine test.


do ->

	mapOptions =
		center: new (google.maps.LatLng)(43.8321591, 4.3428536)
		mapTypeId: google.maps.MapTypeId.ROADMAP
		streetViewControl: false
		scrollwheel: false
		navigationControl: false
		mapTypeControl: false
		scaleControl: false
		draggable: false
		zoomControlOptions: style: google.maps.ZoomControlStyle.SMALL
		zoom: 9

	map = new (google.maps.Map)(document.getElementById('map'), mapOptions)

	Caman.remoteProxy = "proxy";
	Caman.DEBUG = true
	Caman "#uploaded-marker", () ->
		@brightness(5).render()

do ->

	mapOptions =
		center: new (google.maps.LatLng)(43.8321591, 4.3428536)
		mapTypeId: google.maps.MapTypeId.ROADMAP
		streetViewControl: false
		scrollwheel: false
		navigationControl: false
		mapTypeControl: false
		scaleControl: false
		draggable: false
		zoomControlOptions: style: google.maps.ZoomControlStyle.SMALL
		zoom: 9

	map = new (google.maps.Map)(document.getElementById('map'), mapOptions)

	marker = new (google.maps.Marker)(
		position: map.getCenter()
		map: map
		draggable:true
		animation: google.maps.Animation.DROP
		icon:
			url: window.originalImage
	)

	Caman.remoteProxy = "proxy";
	Caman.DEBUG = true
	Caman "#uploaded-marker", () ->
		@brightness(5).render()

Add uploaded marker to map

Add uploaded marker to map


angular.module('fileManager').
factory('Selection', ()->
  return class Selection
    @_files: {}
    @number: 0

    @add: (file)->
      if not @hasFile(file)
        @_files[file._id] = file
        @number++

    @remove: (file)->
      if @hasFile(file)
        delete @_files[file._id]
        @number--

    @clear: ->
      @_files  = {}
      @number = 0

    @hasFile: (file)->
      if typeof file == 'object'
        id = file._id
      else
        id = file
      return @_files.hasOwnProperty(id)

    @select: (file, ctrl = false, contextMenu = false) ->
      if contextMenu and @hasFile(file)
        return true
      @clear() if not ctrl
      if not @hasFile(file)
        @add(file)
      else
        @remove(file)

    @isEmpty: ->
      return @number == 0

    @isSingle: ->
      return @number == 1

    @isMultiple: ->
      return @number > 1

    @forEach: (callback)->
      for id, file of @_files
        callback(file)

    @getSize: ->
      total = 0
      for id, file of @_files
        total += file.metadata.size ? 0
      return total

    @getFirst: ->
      for i, file of @_files
        return file

    @hasAtLeastOneFolder: ->
      for i, file of @_files
        if file.isFolder()
          return true
      return false
)

angular.module('fileManager').
factory('Selection', ($rootScope)->
  class Selection
    @_files: {}
    @number: 0

    @add: (file)->
      if not @hasFile(file)
        @_files[file._id] = file
        @number++

    @remove: (file)->
      if @hasFile(file)
        delete @_files[file._id]
        @number--

    @clear: ->
      @_files  = {}
      @number = 0

    @hasFile: (file)->
      if typeof file == 'object'
        id = file._id
      else
        id = file
      return @_files.hasOwnProperty(id)

    @select: (file, ctrl = false, contextMenu = false) ->
      if contextMenu and @hasFile(file)
        return true
      @clear() if not ctrl
      if not @hasFile(file)
        @add(file)
      else
        @remove(file)

    @isEmpty: ->
      return @number == 0

    @isSingle: ->
      return @number == 1

    @isMultiple: ->
      return @number > 1

    @forEach: (callback)->
      for id, file of @_files
        callback(file)

    @getSize: ->
      total = 0
      for id, file of @_files
        total += file.metadata.size ? 0
      return total

    @getFirst: ->
      for i, file of @_files
        return file

    @hasAtLeastOneFolder: ->
      for i, file of @_files
        if file.isFolder()
          return true
      return false

  $rootScope.$on('$stateChangeSuccess', ->
    Selection.clear()
  )
  return Selection
)

Clear selection every time you change of folder.


path = require 'path'
KeybindingPanel = require '../lib/keybinding-panel'

describe "KeybindingPanel", ->
  panel = null

  describe "loads and displays core key bindings", ->
    beforeEach ->
      expect(atom.keymap).toBeDefined()
      spyOn(atom.keymap, 'getKeyBindings').andReturn [
        source: "#{atom.getLoadSettings().resourcePath}#{path.sep}keymaps", keystroke: 'ctrl-a', command: 'core:select-all', selector: '.editor'
      ]
      panel = new KeybindingPanel

    it "shows exactly one row", ->
      expect(panel.keybindingRows.children().length).toBe 1

      row = panel.keybindingRows.find(':first')
      expect(row.find('.keystroke').text()).toBe 'ctrl-a'
      expect(row.find('.command').text()).toBe 'core:select-all'
      expect(row.find('.source').text()).toBe 'Core'
      expect(row.find('.selector').text()).toBe '.editor'

path = require 'path'
KeybindingPanel = require '../lib/keybinding-panel'

describe "KeybindingPanel", ->
  panel = null

  beforeEach ->
    expect(atom.keymap).toBeDefined()
    spyOn(atom.keymap, 'getKeyBindings').andReturn [
      source: "#{atom.getLoadSettings().resourcePath}#{path.sep}keymaps", keystroke: 'ctrl-a', command: 'core:select-all', selector: '.editor'
    ]
    panel = new KeybindingPanel

  it "loads and displays core key bindings", ->
    expect(panel.keybindingRows.children().length).toBe 1

    row = panel.keybindingRows.find(':first')
    expect(row.find('.keystroke').text()).toBe 'ctrl-a'
    expect(row.find('.command').text()).toBe 'core:select-all'
    expect(row.find('.source').text()).toBe 'Core'
    expect(row.find('.selector').text()).toBe '.editor'

  describe "when a keybinding is copied", ->
    describe "when the keybinding file ends in .cson", ->
      it "writes a CSON snippet to the clipboard", ->
        spyOn(atom.keymap, 'getUserKeymapPath').andReturn 'keymap.cson'
        panel.find('.copy-icon').click()
        expect(atom.pasteboard.read()[0]).toBe """
          '.editor':
            'ctrl-a': 'core:select-all'
        """

    describe "when the keybinding file ends in .json", ->
      it "writes a JSON snippet to the clipboard", ->
        spyOn(atom.keymap, 'getUserKeymapPath').andReturn 'keymap.json'
        panel.find('.copy-icon').click()
        expect(atom.pasteboard.read()[0]).toBe """
          ".editor": {
            "ctrl-a": "core:select-all"
          }
        """

Add spec for copying keybinding

Add spec for copying keybinding


jQuery(document).ready ->
  class photographyGame
    constructor: (@debug, @map) ->

    init: () ->
  return

jQuery(document).ready ->
  class photographyGame
    constructor: (@debug, @map) ->

    init: () ->

  class location
    constructor: (@position, @name, @icon) ->
      @marker

    addTo: (map) ->
      if @icon
        marker = new google.maps.Marker({
          position: @position,
          map: map,
          icon: @icon,
          title: @name
        })
      else
        marker = new google.maps.Marker({
          position: @position,
          map: map,
          title: @name
        })
      @marker = marker
      @setListener(@marker)

    setListener: (marker) ->
      self = this
      marker.addListener 'click', ->
        mark.moveTo(self)

  class player extends location
    constructor: (@position, @name, @icon) ->
      super(@position, @name, @icon)
      @playerMarker

    initTo: (map) ->
      @playerMarker = new google.maps.Marker({
        position: @position,
        map: map,
        icon: @icon,
        title: 'Mark'
      })

    moveTo: (location) ->
      console.log("current position", this.position, "new position", location.position, "distance travelled", distanceTravelled(this.position, location.position) + 'km')
      @position = location.position
      @playerMarker.setPosition(new google.maps.LatLng(location.position.lat, location.position.lng))

Add location and player classes

Add location and player classes


_ = require 'underscore-plus'
{View} = require 'atom'

# Menu item view for an installed package
module.exports =
class PackageMenuView extends View
  @content: ->
    @li =>
      @a outlet: 'link', class: 'icon', =>
        @span outlet: 'nameLabel'
        @span outlet: 'packageAuthorLabel', class: 'package-author'

  initialize: (@pack, @packageManager) ->
    @attr('name', @pack.name)
    @attr('type', 'package')
    @nameLabel.text(@packageManager.getPackageTitle(@pack))
    @packageAuthorLabel.text(@packageManager.getAuthorUserName(@pack))
    @checkForUpdates()
    @subscribe @packageManager, 'package-updated theme-updated', ({name}) =>
      @link.removeClass('icon-squirrel') if @pack.name is name

  checkForUpdates: ->
    return if atom.packages.isBundledPackage(@pack.name)

    @getAvailablePackage (availablePackage) =>
      if @packageManager.canUpgrade(@pack, availablePackage)
        @link.addClass('icon-squirrel')

  getAvailablePackage: (callback) ->
    @packageManager.getOutdated().then (packages) =>
      for pack in packages when pack.name is @pack.name
        callback(pack)

_ = require 'underscore-plus'
{View} = require 'atom'

# Menu item view for an installed package
module.exports =
class PackageMenuView extends View
  @content: ->
    @li =>
      @a outlet: 'link', class: 'icon', =>
        @span outlet: 'nameLabel'
        @span outlet: 'packageAuthorLabel', class: 'package-author'

  initialize: (@pack, @packageManager) ->
    @attr('name', @pack.name)
    @attr('type', 'package')
    @nameLabel.text(@packageManager.getPackageTitle(@pack))
    @packageAuthorLabel.text(@packageManager.getAuthorUserName(@pack))
    @checkForUpdates()
    @subscribe @packageManager, 'package-updated theme-updated', ({name}) =>
      @link.removeClass('icon-squirrel') if @pack.name is name

  checkForUpdates: ->
    return if atom.packages.isBundledPackage(@pack.name)

    @getAvailablePackage (availablePackage) =>
      if @packageManager.canUpgrade(@pack, availablePackage.latestVersion)
        @link.addClass('icon-squirrel')

  getAvailablePackage: (callback) ->
    @packageManager.getOutdated().then (packages) =>
      for pack in packages when pack.name is @pack.name
        callback(pack)

Check if package can be upgraded using the latest version


require './setup'

Song = null
Album = null
spy = null

describe 'has one change', ->
  beforeEach ->
    Song = Ento()
      .use(Ento.relations)
      .attr('id')
      .attr('title')

    Album = Ento()
      .use(Ento.relations)
      .attr('id')
      .hasOne('song', Song, as: 'album')

  describe 'propagate change event of children', ->
    beforeEach ->
      spy = sinon.spy()

    it 'one level, change:attr', ->
      parent = new Album()
      parent.song = new Song(title: 'Wrecking Ball')
      parent.on('change:song', spy)
      parent.song.title = 'Party in the USA'
      expect(spy).calledOnce

    it 'one level, change', ->
      parent = new Album()
      parent.song = new Song(title: 'Wrecking Ball')
      parent.on('change', spy)
      parent.song.title = 'Party in the USA'
      expect(spy).calledOnce
      expect(spy.firstCall.args).be.like ['title']

require './setup'

Song = null
Album = null
spy = null

describe 'has one change', ->
  beforeEach ->
    Song = Ento()
      .use(Ento.relations)
      .attr('id')
      .attr('title')

    Album = Ento()
      .use(Ento.relations)
      .attr('id')
      .hasOne('song', Song, as: 'album')

  describe 'propagate change event of children', ->
    beforeEach ->
      spy = sinon.spy()

    it 'one level, change:attr', ->
      parent = new Album()
      parent.song = new Song(title: 'Wrecking Ball')
      parent.on('change:song', spy)
      parent.song.title = 'Party in the USA'
      expect(spy).calledOnce

    it 'one level, change', ->
      parent = new Album()
      parent.song = new Song(title: 'Wrecking Ball')
      parent.on('change', spy)
      parent.song.title = 'Party in the USA'
      expect(spy).calledOnce
      expect(spy.firstCall.args).be.like [['song']]

Fix test related to relations.

Fix test related to relations.


module.exports = class Organization
  constructor: (org, @api) ->
    @orgName = if typeof org is "object" then org.name else org

  node: (path, cb) ->
    @api.get @apiPath(path), {}, cb

  apiPath: (path) ->
    path = path.path || path.name if typeof path is "object"
    "/#{encodeURIComponent(@orgName)}/#{path}"

module.exports = class Organization
  constructor: (org, @api) ->
    @orgName = if typeof org is "object" then org.name else org

  node: (path..., cb) ->
    @api.get @apiPath(path), {}, cb

  apiPath: (path) ->
    compiledPath = []
    for p in path
      p = p.path || p.name if typeof p is "object"
      compiledPath.push p

    "/#{encodeURIComponent(@orgName)}/#{compiledPath.join('/')}"

Change semantics of node() a little to allow for string path or multiple arguments


winston = require 'winston'
util = require 'util'

winston
	.remove winston.transports.Console
	.add winston.transports.File,
		level: 'silly'
		filename: 'output.log'
		json: no

exports.log = (level, params...) ->
	winston.log level, (params.map util.inspect)...

winston = require 'winston'
util = require 'util'

winston
	.remove winston.transports.Console
	.add winston.transports.File,
		level: 'silly'
		filename: 'output.log'
		json: no

exports.log = (level, params...) ->
	if params[0] instanceof Error
		winston.log level, params[0], params[1..]...

	else winston.log level, (params.map util.inspect)...

Tweak to Winston output handler

Tweak to Winston output handler


Base = require 'base'

class ListItem extends Base.View

  template: require '../../templates/list'

  elements:
    '.name':  'name'
    '.count': 'count'

  events:
    'click': 'click'

  constructor: ->
    Base.touchify(@events)
    super

    return unless @list?

    @listen [
      @list,
        'select': @select
        'change': @updateName
        'before:destroy': @remove
      @list.tasks,
        'change': @updateCount
    ]

  # Create the list element
  render: =>

    @el = $ @template @list
    @bind()

    el = @el[0]
    el.list = @list
    mouse.addDrop(el)

    # TODO: Setup droppable
    # @el.droppable
    #   hoverClass: 'ui-state-active'
    #   tolerance: 'pointer'
    #   drop: (event, ui) =>
    #     movedTask = Task.get(ui.draggable.attr('id').slice(5))
    #     List.current.moveTask(movedTask, @list)

    return this

  updateCount: =>
    @count.text @list.tasks.length

  updateName: =>
    @name.text @list.name

  click: =>
    @list.trigger 'select'

  select: =>
    @el.addClass 'current'

  remove: =>
    @unbind()
    @el.remove()

module.exports = ListItem

Base = require 'base'

class ListItem extends Base.View

  template: require '../../templates/list'

  elements:
    '.name':  'name'
    '.count': 'count'

  events:
    'mousedown': 'click'

  constructor: ->
    Base.touchify(@events)
    super

    return unless @list?

    @listen [
      @list,
        'select': @select
        'change': @updateName
        'before:destroy': @remove
      @list.tasks,
        'change': @updateCount
    ]

  # Create the list element
  render: =>

    @el = $ @template @list
    @bind()

    el = @el[0]
    el.list = @list
    mouse.addDrop(el)

    # TODO: Setup droppable
    # @el.droppable
    #   hoverClass: 'ui-state-active'
    #   tolerance: 'pointer'
    #   drop: (event, ui) =>
    #     movedTask = Task.get(ui.draggable.attr('id').slice(5))
    #     List.current.moveTask(movedTask, @list)

    return this

  updateCount: =>
    @count.text @list.tasks.length

  updateName: =>
    @name.text @list.name

  click: =>
    @list.trigger 'select'

  select: =>
    @el.addClass 'current'

  remove: =>
    @unbind()
    @el.remove()

module.exports = ListItem

Use mousedown instead of click

Use mousedown instead of click


React = require 'react'
BS = require 'react-bootstrap'
_ = require 'underscore'

{History, Link} = require 'react-router'
{TransitionActions, TransitionStore} = require '../../flux/transition'

BackButton = React.createClass
  displayName: 'BackButton'

  propTypes:
    fallbackLink: React.PropTypes.shape(
      to: React.PropTypes.string
      params: React.PropTypes.object
      text: React.PropTypes.string
    ).isRequired

  contextTypes:
    router: React.PropTypes.func

  render: ->
    # Gets route to last path that was not the same as the current one
    # See TransitionStore for more detail.
    historyInfo = TransitionStore.getPrevious(@context.router)
    {fallbackLink, className} = @props
    {text} = fallbackLink

    backText = if historyInfo.name then "Back to #{historyInfo.name}" else fallbackLink.text

    href =  historyInfo.path or @context.router.makeHref(
      @props.fallbackLink.to, @props.fallbackLink.params
    )

    <BS.Button href={href} className={className} {...@props}>
      {backText}
    </BS.Button>

module.exports = BackButton

React = require 'react'
BS = require 'react-bootstrap'
_ = require 'underscore'

{History, Link} = require 'react-router'
{TransitionActions, TransitionStore} = require '../../flux/transition'

BackButton = React.createClass
  displayName: 'BackButton'

  propTypes:
    bsStyle: React.PropTypes.string
    fallbackLink: React.PropTypes.shape(
      to: React.PropTypes.string
      params: React.PropTypes.object
      text: React.PropTypes.string
    ).isRequired

  getDefaultProps: ->
    bsStyle: 'default'

  contextTypes:
    router: React.PropTypes.func

  render: ->
    # Gets route to last path that was not the same as the current one
    # See TransitionStore for more detail.
    historyInfo = TransitionStore.getPrevious(@context.router)
    {fallbackLink, className} = @props
    {text} = fallbackLink

    backText = if historyInfo.name then "Back to #{historyInfo.name}" else fallbackLink.text

    href =  historyInfo.path or @context.router.makeHref(
      @props.fallbackLink.to, @props.fallbackLink.params
    )

    <Link className={"btn btn-#{@props.bsStyle}"} to={href}>
      {backText}
    </Link>

module.exports = BackButton

Use router Link to prevent full page reload


NestNode = require('./NestNode')

module.exports = class NestThermostatNode extends NestNode
  aspects:
    "temperature-sensor": {}
    "humidity-sensor": {}
    "temperature-set-point":
      commands:
        "set-target": (node, temp) -> node.adapter.setTemperature(node.id, temp)
      events:
        "target-changed": (prev, cur) -> prev.target != cur.target
        "mode-changed"  : (prev, cur) -> prev.mode != cur.mode

  processData: (data) ->
    @getAspect("temperature-sensor").setData
      value: data["current-temperature"]
    @getAspect("humidity-sensor").setData
      value: data["current-humidity"]
    @getAspect("temperature-set-point").setData
      target: data["target-temperature"]
      mode: data["target-type"]

NestNode = require('./NestNode')

module.exports = class NestThermostatNode extends NestNode
  aspects:
    "temperature-sensor":
      events:
        changed: (prev, cur) -> prev.value != cur.value
    "humidity-sensor":
      events:
        changed: (prev, cur) -> prev.value != cur.value
    "temperature-set-point":
      commands:
        "set-target": (node, temp) -> node.adapter.setTemperature(node.id, temp)
      events:
        "target-changed": (prev, cur) -> prev.target != cur.target
        "mode-changed"  : (prev, cur) -> prev.mode != cur.mode

  processData: (data) ->
    @getAspect("temperature-sensor").setData
      value: data["current-temperature"]
    @getAspect("humidity-sensor").setData
      value: data["current-humidity"]
    @getAspect("temperature-set-point").setData
      target: data["target-temperature"]
      mode: data["target-type"]

Support events on nest temp and humidity


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

module.exports = (grunt) ->
  grunt.registerTask 'generate-license', 'Generate the license, including the licenses of all dependencies', (mode) ->
    legalEagle = require 'legal-eagle'
    done = @async()

    options =
      path: process.cwd()
      overrides: require './license-overrides'

    legalEagle options, (err, dependencyLicenses) ->
      if err?
        console.error(err)
        exit 1

      licenseText = getLicenseText(dependencyLicenses)
      if mode is 'save'
        targetPath = path.join(grunt.config.get('atom.appDir'), 'LICENSE')
        fs.writeFileSync(targetPath, licenseText)
      else
        console.log licenseText
      done()

getLicenseText = (dependencyLicenses) ->
  {keys} = require 'underscore-plus'
  text = """
    Copyright 2014 GitHub, Inc.

    This application bundles the following third-party packages in accordance
    with the following licenses:\n\n
  """
  names = keys(dependencyLicenses).sort()
  for name in names
    {license, source, sourceText} = dependencyLicenses[name]

    text += "-------------------------------------------------------------------------\n\n"
    text += "Package: #{name}\n"
    text += "License: #{license}\n"
    text += "License Source: #{source}\n" if source?
    if sourceText?
      text += "Source Text:\n\n"
      text += sourceText
    text += '\n'
  text

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

module.exports = (grunt) ->
  grunt.registerTask 'generate-license', 'Generate the license, including the licenses of all dependencies', (mode) ->
    legalEagle = require 'legal-eagle'
    done = @async()

    options =
      path: process.cwd()
      overrides: require './license-overrides'

    legalEagle options, (err, dependencyLicenses) ->
      if err?
        console.error(err)
        exit 1

      licenseText = getLicenseText(dependencyLicenses)
      if mode is 'save'
        targetPath = path.join(grunt.config.get('atom.appDir'), 'LICENSE.md')
        fs.writeFileSync(targetPath, licenseText)
      else
        console.log licenseText
      done()

getLicenseText = (dependencyLicenses) ->
  {keys} = require 'underscore-plus'
  text = """
    Copyright 2014 GitHub, Inc.

    This application bundles the following third-party packages in accordance
    with the following licenses:\n\n
  """
  names = keys(dependencyLicenses).sort()
  for name in names
    {license, source, sourceText} = dependencyLicenses[name]

    text += "-------------------------------------------------------------------------\n\n"
    text += "Package: #{name}\n"
    text += "License: #{license}\n"
    text += "License Source: #{source}\n" if source?
    if sourceText?
      text += "Source Text:\n\n"
      text += sourceText
    text += '\n'
  text

Add .md extension to generated license

Add .md extension to generated license


tryRequire = (dep) ->
  try
    require dep
  catch
    undefined

@window ||= {}

Q = @window.Q
_ = @window._

Q ||= tryRequire 'q'
_ ||= tryRequire 'lodash/dist/lodash.underscore'
_ ||= tryRequire 'underscore'

utils = require('./yayson/utils')(_, Q)

Adapter = require('./yayson/adapter')
adapters = require('./yayson/adapters')
presenterFactory = require('./yayson/presenter')

lookupAdapter = (nameOrAdapter) ->
  adapters[nameOrAdapter] || Adapter

presenter = (options = {}) ->
  adapter = lookupAdapter options.adapter
  presenterFactory(utils, adapter)

module.exports = ({adapter} = {}) ->
  Store: require('./yayson/store')(utils)
  Presenter: presenter({adapter})
  Adapter: Adapter

@window ||= {}

Q = @window.Q
_ = @window._

Q ||= (try require? 'q')
_ ||= (try require? 'lodash/dist/lodash.underscore')
_ ||= (try require? 'underscore')

utils = require('./yayson/utils')(_, Q)

Adapter = require('./yayson/adapter')
adapters = require('./yayson/adapters')
presenterFactory = require('./yayson/presenter')

lookupAdapter = (nameOrAdapter) ->
  adapters[nameOrAdapter] || Adapter

presenter = (options = {}) ->
  adapter = lookupAdapter options.adapter
  presenterFactory(utils, adapter)

module.exports = ({adapter} = {}) ->
  Store: require('./yayson/store')(utils)
  Presenter: presenter({adapter})
  Adapter: Adapter

Change optional require format to make webpack happier


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

{defer, makeElement, measureElement} = Trix

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

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

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

    [image]

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

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

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

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

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

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

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

{defer, makeElement, measureElement} = Trix

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

  createContentNodes: ->
    image = makeElement("img", src: "", "data-trix-mutable": true)
    caption = makeElement(tagName: "figcaption", textContent: @attachment.getFilename())
    @refresh(image)

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

    if filesize = @attachment.getFormattedFilesize()
      span = makeElement(tagName: "span", className: "size", textContent: filesize)
      caption.appendChild(span)

    [image, caption]

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

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

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

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

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

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

Add figcaptions to image attachments

Add figcaptions to image attachments


#global $, _
((NS) ->
  "use strict"

  # Filename: helpers/error_helper.js */
  NS = NS or {}
  isInBrowser = typeof module is 'undefined' and typeof window isnt 'undefined'
  # Exception class
  ###
   * Creates a new CustomException.
   * @class Exception class.
  ###
  class CustomException
    # @constructor
    constructor:(@name, @message,@options) ->
      @log()
    #Log the content of the exception.
    log: ->
      console.error("name", @name, "message", @message, "options", @options)
    # JSONify the content of the exception.
    toJSON:->
      return {"name": @name, "message": @message,  "options": @options}
  # Exception for a not implemented method.
  class NotImplementedException extends CustomException
    constructor:(message, options) ->
      super("NotImplementedException", message, options)
  # Exception class for an argument null exeption.
  class ArgumentNullException extends CustomException
    constructor:(message) ->
      super("ArgumentNull", message)
  # Exception for a invalid argument exeption
  class ArgumentInvalidException extends CustomException
    constructor:(message, options) ->
      super("ArgumentInvalidException", message, options)
  class DependencyException extends CustomException
    constructor:(message, options) ->
      super("DependencyException", message, options)
  mod = {
    CustomException: CustomException
    NotImplementedException: NotImplementedException
    ArgumentNullException: ArgumentNullException
    ArgumentInvalidException: ArgumentInvalidException
    DependencyException: DependencyException
  }
  if isInBrowser
    NS.Helpers = NS.Helpers or {}
    NS.Helpers.Exceptions = mod
  else
    module.exports = mod
)(if typeof module is 'undefined' and typeof window isnt 'undefined' then window.Fmk else module.exports)

#global $, _
  "use strict"
  # Filename: helpers/error_helper.js */
  # Exception class
  ###
   * Creates a new CustomException.
   * @class Exception class.
  ###
  class CustomException
    # @constructor
    constructor:(@name, @message,@options) ->
      @log()
    #Log the content of the exception.
    log: ->
      console.error("name", @name, "message", @message, "options", @options)
    # JSONify the content of the exception.
    toJSON:->
      return {"name": @name, "message": @message,  "options": @options}
  # Exception for a not implemented method.
  class NotImplementedException extends CustomException
    constructor:(message, options) ->
      super("NotImplementedException", message, options)
  # Exception class for an argument null exeption.
  class ArgumentNullException extends CustomException
    constructor:(message) ->
      super("ArgumentNull", message)
  # Exception for a invalid argument exeption
  class ArgumentInvalidException extends CustomException
    constructor:(message, options) ->
      super("ArgumentInvalidException", message, options)
  class DependencyException extends CustomException
    constructor:(message, options) ->
      super("DependencyException", message, options)
  mod = {
    CustomException: CustomException
    NotImplementedException: NotImplementedException
    ArgumentNullException: ArgumentNullException
    ArgumentInvalidException: ArgumentInvalidException
    DependencyException: DependencyException
  }
  module.exports = mod

Clean the custom exception module.

Clean the custom exception module.


###
A text region that can be clicked to edit its contents.
###

class window.EditableText extends Editable

  inherited:
    editClass: "TextBox"

  # True if the pressing Escape in edit mode cancels edit mode.
  # The default is true.
  cancelOnEscape: Control.property( null, true )

  editing: ( editing ) ->
    result = super editing
    # Switching to edit mode; put focus in the text box.
    @editControl().find( "input" ).andSelf().focus()  if editing
    result

  # True if the control should switch to editing mode when it's clicked.
  # Default is true.
  editOnClick: Control.property( null, true )

  initialize: ->
    @click =>
      @editing true if @editOnClick() and not @editing()

  # True if pressing the Enter key in edit mode saves changes and switches
  # back to read mode. The default is true.
  saveOnEnter: Control.property( null, true )

  _createEditControl: ->
    result = super()
    # Wire up events bound to input elements.
    @editControl().find( "input" ).andSelf().on
      blur: =>
        # Implicitly save when control loses focus.
        @save()  if @editing()
      keydown: ( event ) =>
        if @editing()
          switch event.which
            when 13 # Enter
              if @saveOnEnter()
                @save()
                event.preventDefault()
            when 27 # Escape
              @cancel()  if @cancelOnEscape()

    result

###
A text region that can be clicked to edit its contents.
###

class window.EditableText extends Editable

  inherited:
    editClass: "TextBox"

  # True if the pressing Escape in edit mode cancels edit mode.
  # The default is true.
  cancelOnEscape: Control.property( null, true )

  editing: ( editing ) ->
    result = super editing
    # Switching to edit mode; put focus in the text box.
    @editControl().find( "input" ).addBack().focus()  if editing
    result

  # True if the control should switch to editing mode when it's clicked.
  # Default is true.
  editOnClick: Control.property( null, true )

  initialize: ->
    @click =>
      @editing true if @editOnClick() and not @editing()

  # True if pressing the Enter key in edit mode saves changes and switches
  # back to read mode. The default is true.
  saveOnEnter: Control.property( null, true )

  _createEditControl: ->
    result = super()
    # Wire up events bound to input elements.
    @editControl().find( "input" ).addBack().on
      blur: =>
        # Implicitly save when control loses focus.
        @save()  if @editing()
      keydown: ( event ) =>
        if @editing()
          switch event.which
            when 13 # Enter
              if @saveOnEnter()
                @save()
                event.preventDefault()
            when 27 # Escape
              @cancel()  if @cancelOnEscape()

    result

Change $.andSelf() to $.addBack(), which is now preferred.


describe "RequireJS", ->
    it "check that the RequireJS object is present in the global namespace", ->
        expect(RequireJS).toEqual jasmine.any(Object)
        expect(window.RequireJS).toEqual jasmine.any(Object)

    it "check that requirejs(), require(), and define() are not in the global namespace", ->
        expect(requirejs).not.toBeDefined()
        expect(require).not.toBeDefined()
        expect(define).not.toBeDefined()
        expect(window.requirejs).not.toBeDefined()
        expect(window.require).not.toBeDefined()
        expect(window.define).not.toBeDefined()

describe "RequireJS", ->
  beforeEach ->
    @addMatchers requirejsTobeUndefined: ->
      typeof requirejs is "undefined"

  it "check that the RequireJS object is present in the global namespace", ->
    expect(RequireJS).toEqual jasmine.any(Object)
    expect(window.RequireJS).toEqual jasmine.any(Object)

  it "check that requirejs(), require(), and define() are not in the global namespace", ->
    expect({}).requirejsTobeUndefined()

    # expect(require).not.toBeDefined();
    # expect(define).not.toBeDefined();
    expect(window.requirejs).not.toBeDefined()
    expect(window.require).not.toBeDefined()
    expect(window.define).not.toBeDefined()

Work on RequireJS Jasmine test.

Work on RequireJS Jasmine test.