class AppRouter extends Backbone.Router

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

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

    flight.goTo "#panel-1"

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

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

class AppRouter extends Backbone.Router

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

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

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

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

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


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

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

Add save as HTML menu

Add save as HTML menu


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

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

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

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

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

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

Add i18n when env.coffee isn't required

Add i18n when env.coffee isn't required


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

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

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

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

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

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

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

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

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

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

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

Make cosmetic improvements to the output


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

{sync: resolve} = require 'resolve'

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

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

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

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

{sync: resolve} = require 'resolve'

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

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

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

Fix canonicalization of core modules

Fix canonicalization of core modules


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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Add source.litcoffee to default grammars

Closes #38


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

describe "Presenters", ->

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

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

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

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

    # describe "generateBody", ->

    # describe "respond", ->

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

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

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

    # describe "generateBody", ->

    # describe "respond", ->

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

describe "Presenters", ->

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

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

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

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

    # describe "generateBody", ->

    # describe "respond", ->

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

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

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

    # describe "generateBody", ->

    # describe "respond", ->

Fix method name in presenter spec

Fix method name in presenter spec


{View} = require 'space-pen'

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

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

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

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

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

  column: 80

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

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

{View} = require 'space-pen'

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

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

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

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

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

  column: 80

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

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

Use interpolated string for setting left offset


logger = new Logger("browserpolicy")

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

logger = new Logger("browserpolicy")

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

Allow images from any origin

Allow images from any origin


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

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

  userKeymapPath = atom.keymaps.getUserKeymapPath()

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

  userStyleSheetPath = atom.styles.getUserStyleSheetPath()

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

  linter.getDeprecations()

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

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

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

  userKeymapPath = atom.keymaps.getUserKeymapPath()

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

  userStyleSheetPath = atom.styles.getUserStyleSheetPath()

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

  linter.getDeprecations()

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

Use isFileSync instead of existsSync for checking file existence


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

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

module.exports = (robot) ->

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Remove ac node module, handle new data being sent


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

         $urlMatcherFactoryProvider.strictMode(false)

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

Remove trailing whitespace for jshint

Remove trailing whitespace for jshint


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

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

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

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


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

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

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

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

Remove modernizr from app asset precompilation


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

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

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

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

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

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

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

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

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

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

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

Remove references to ember dependencies

Remove references to ember dependencies


React = require 'react'

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

  constructor: (@props) ->

  render: =>

      {@_renderLogo()}

        {@_renderMenuItems()}

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

    else return

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

        {item.name}

module.exports = Header

React = require 'react'

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

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

  render: =>

      {@_renderLogo()}

        {@_renderMenuItems()}

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

    else return

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

        {item.name}

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

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

      menuItems: state.menuItems

module.exports = Header

Add ability to close tabs

Add ability to close tabs


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


AST = { }

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

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

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

  compile : ( context ) -> @content

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

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

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

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

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

  compile : ( context ) ->

    curr = context
    paths = @paths.concat( )

    while paths.length

      path = paths.shift( )

      curr = path.compile curr, context

    curr

module.exports = AST

AST = { }

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

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

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

  compile : ( context ) -> @content

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

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

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

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

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

  compile : ( context ) ->

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

module.exports = AST

Tidy up the PathNode compile method a bit


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

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

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

module.exports = config

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

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

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

module.exports = config

Fix typo in uuid generation

Fix typo in uuid generation


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

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

Make source maps work in Sentry.

Make source maps work in Sentry.

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


# # Kissmetrics Batch

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

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

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

    @queue.add data

  get: ->
    @queue.get()

  process: ->
    queue = @get()

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

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

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

    delete data.type

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

module.exports = BatchKissmetricsClient

# # Kissmetrics Batch

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

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

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

    @queue.add data

  get: ->
    @queue.get()

  process: ->
    queue = @get()

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

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

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

    delete data.type

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

module.exports = BatchKissmetricsClient

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


module.exports = [

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

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

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

]

module.exports = [

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

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

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

]

Update SockJS-client to 0.3.4 stable

Update SockJS-client to 0.3.4 stable


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

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

Add the toolbar to the menu

Add the toolbar to the menu


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

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

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

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

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

Switch data over to use new variation class


'use strict'

toggleGem = Reflux.createAction()

module.exports =
  toggleGem: toggleGem

'use strict'

actions = Reflux.createActions [
  'toggleGem'
]

module.exports = actions

Refactor using Reflux sugar functions

Refactor using Reflux sugar functions

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

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

Beautiful.


NProgress.configure(showSpinner: false)

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

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

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

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

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

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

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

    work(nextIndex)
  , delay)

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

NProgress.configure(showSpinner: false)

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

currentTimer = null
delay        = 150

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

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

stop = ->
  clearInterval(currentTimer)
  clearHighlights()

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

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

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

Restructure logo JS to use `setInterval`


NProgress.configure(showSpinner: false)

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

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

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

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

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

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

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

    work(nextIndex)
  , 200)

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

NProgress.configure(showSpinner: false)

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

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

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

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

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

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

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

    work(nextIndex)
  , delay)

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

Decrease the logo sweep delay

Decrease the logo sweep delay


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

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

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

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

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

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

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

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

Revert "Export ReactEditorView as EditorView"

This reverts commit be201485188cb8583bbfe0a2dd239a20efa8cbd9.


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Choose a random workflow and subject

Choose a random workflow and subject


SymbolsView = require './symbols-view'
TagGenerator = require './tag-generator'

module.exports =
class FileView extends SymbolsView
  constructor: (@stack) ->
    super
  initialize: ->
    super

    @cachedTags = {}

    @subscribe atom.project.eachBuffer (buffer) =>
      @subscribe buffer, 'reloaded saved destroyed path-changed', =>
        delete @cachedTags[buffer.getPath()]

      @subscribe buffer, 'destroyed', =>
        @unsubscribe(buffer)

    @subscribe atom.workspace.eachEditor (editor) =>
      @subscribe editor, 'grammar-changed', =>
        delete @cachedTags[editor.getPath()]

      @subscribe editor, 'destroyed', =>
        @unsubscribe(editor)

  toggle: ->
    if @hasParent()
      @cancel()
    else if filePath = @getPath()
      @populate(filePath)
      @attach()

  getPath: -> atom.workspace.getActiveEditor()?.getPath()

  getScopeName: -> atom.workspace.getActiveEditor()?.getGrammar()?.scopeName

  populate: (filePath) ->
    @list.empty()
    @setLoading('Generating symbols\u2026')
    if tags = @cachedTags[filePath]
      @maxItem = Infinity
      @setItems(tags)
    else
      @generateTags(filePath)

  generateTags: (filePath) ->
    new TagGenerator(filePath, @getScopeName()).generate().done (tags) =>
      @cachedTags[filePath] = tags
      @maxItem = Infinity
      @setItems(tags)

  afterTagOpen: (previous) ->
    @stack.push previous

SymbolsView = require './symbols-view'
TagGenerator = require './tag-generator'

module.exports =
class FileView extends SymbolsView
  initialize: ->
    super

    @cachedTags = {}

    @subscribe atom.project.eachBuffer (buffer) =>
      @subscribe buffer, 'reloaded saved destroyed path-changed', =>
        delete @cachedTags[buffer.getPath()]

      @subscribe buffer, 'destroyed', =>
        @unsubscribe(buffer)

    @subscribe atom.workspace.eachEditor (editor) =>
      @subscribe editor, 'grammar-changed', =>
        delete @cachedTags[editor.getPath()]

      @subscribe editor, 'destroyed', =>
        @unsubscribe(editor)

  toggle: ->
    if @hasParent()
      @cancel()
    else if filePath = @getPath()
      @populate(filePath)
      @attach()

  getPath: -> atom.workspace.getActiveEditor()?.getPath()

  getScopeName: -> atom.workspace.getActiveEditor()?.getGrammar()?.scopeName

  populate: (filePath) ->
    @list.empty()
    @setLoading('Generating symbols\u2026')
    if tags = @cachedTags[filePath]
      @maxItem = Infinity
      @setItems(tags)
    else
      @generateTags(filePath)

  generateTags: (filePath) ->
    new TagGenerator(filePath, @getScopeName()).generate().done (tags) =>
      @cachedTags[filePath] = tags
      @maxItem = Infinity
      @setItems(tags)

  afterTagOpen: (previous) ->
    @stack.push previous

Remove ctor handled in superclass

Remove ctor handled in superclass


Meteor.subscribe 'authors';
Meteor.subscribe 'Posts';
Meteor.subscribe 'Comments';

Template['posts'].helpers
  'posts': -> Posts.find({}, sort: {createdAt: -1})

Template.post.helpers
  'comments': -> Comments.find({post_id: @post._id})

# Template['posts'].events

Template['new-post'].events
  'submit .new-post': (e) ->
    e.preventDefault()
    Posts.insert
      'title': e.target.title.value
      'content': e.target.content.value
      'author': Meteor.userId()
      'createdAt': new Date()

Template.new_comment.events
  'submit .new_comment': (e) ->
    e.preventDefault
    Comments.insert
      'title': e.target.title.value
      'content': e.target.content.value
      'author': e.target.author.value
      'post_id': e.target.post_id.value
      'createdAt': new Date()

Meteor.subscribe 'authors';
Meteor.subscribe 'Posts';
Meteor.subscribe 'Comments';

Template['posts'].helpers
  'posts': -> Posts.find({}, sort: {createdAt: -1})

Template.post.helpers
  'comments': -> Comments.find({post_id: @post._id})

# Template['posts'].events

Template['new-post'].events
  'submit .new-post': (e) ->
    e.preventDefault()
    Posts.insert
      'title': e.target.title.value
      'content': e.target.content.value
      'author': Meteor.userId()
      'createdAt': new Date()

Template.new_comment.events
  'submit .new_comment': (e) ->
    e.preventDefault()
    Comments.insert
      'title': e.target.title.value
      'content': e.target.content.value
      'author': e.target.author.value
      'post_id': e.target.post_id.value
      'createdAt': new Date()

Fix on preventDefault method call

Fix on preventDefault method call


Dialog = require './dialog'
Project = require './project'
projects = require './projects'
path = require 'path'
changeCase = require 'change-case'

module.exports =
class SaveDialog extends Dialog
  filePath: null

  constructor: () ->
    firstPath = atom.project.getPaths()[0]
    title = path.basename(firstPath)

    if atom.config.get('project-manager.prettifyTitle')
      title = changeCase.titleCase(title)

    super
      prompt: 'Enter name of project'
      input: title
      select: true
      iconClass: 'icon-arrow-right'

    projects.getCurrent (project) =>
      if project.props.paths[0] is firstPath
        @showError "This project is already saved as #{project.props.title}"

  onConfirm: (title) ->
    if title
      properties =
        title: title
        paths: atom.project.getPaths()

      project = new Project(properties)
      project.save()

      @close()
    else
      @showError('You need to specify a name for the project')

Dialog = require './dialog'
Project = require './project'
projects = require './projects'
path = require 'path'
changeCase = require 'change-case'

module.exports =
class SaveDialog extends Dialog
  filePath: null

  constructor: () ->
    firstPath = atom.project.getPaths()[0]
    title = path.basename(firstPath)

    if atom.config.get('project-manager.prettifyTitle')
      title = changeCase.titleCase(title)

    super
      prompt: 'Enter name of project'
      input: title
      select: true
      iconClass: 'icon-arrow-right'

    projects.getCurrent (project) =>
      if project.rootPAth is firstPath
        @showError "This project is already saved as #{project.props.title}"

  onConfirm: (title) ->
    if title
      properties =
        title: title
        paths: atom.project.getPaths()

      project = new Project(properties)
      project.save()

      @close()
    else
      @showError('You need to specify a name for the project')

Use method to check root path

Use method to check root path


# Argumenta instance
argumenta = require '../app/argumenta'

# Site index
exports.index = (req, res) ->
  argumenta.users.latest {limit: 10}, (err, users) ->
    argumenta.repos.latest {limit: 20}, (err, repos) ->
      res.reply 'index',
        latest_users: users
        latest_repos: repos

# Argumenta instance
argumenta = require '../app/argumenta'

# Site index
exports.index = (req, res) ->
  argumenta.users.latest {limit: 10}, (err, users) ->
    argumenta.repos.latest {limit: 20, metadata: true}, (err, repos) ->
      res.reply 'index',
        latest_users: users
        latest_repos: repos

Include metadata for repos on homepage

Include metadata for repos on homepage


AutoUpdater = process.atomBinding('auto_updater').AutoUpdater
EventEmitter = require('events').EventEmitter

AutoUpdater::__proto__ = EventEmitter.prototype

autoUpdater = new AutoUpdater
autoUpdater.on 'update-downloaded-raw', (args...) ->
  args[3] = new Date(args[3])  # releaseDate
  @emit 'update-downloaded', args..., => @quitAndInstall()

autoUpdater.quitAndInstall = ->
  # Do the restart after all windows have been closed.
  app = require 'app'
  app.removeAllListeners 'window-all-closed'
  app.once 'window-all-closed', AutoUpdater::quitAndInstall.bind(this)

  # Tell all windows to remove beforeunload handler and then close itself.
  ipc = require 'ipc'
  BrowserWindow = require 'browser-window'
  ipc.sendChannel win.getProcessId(), win.getRoutingId(), 'ATOM_SHELL_SILENT_CLOSE' for win in BrowserWindow.getAllWindows()

module.exports = autoUpdater

AutoUpdater = process.atomBinding('auto_updater').AutoUpdater
EventEmitter = require('events').EventEmitter

AutoUpdater::__proto__ = EventEmitter.prototype

autoUpdater = new AutoUpdater
autoUpdater.on 'update-downloaded-raw', (args...) ->
  args[3] = new Date(args[3])  # releaseDate
  @emit 'update-downloaded', args..., => @quitAndInstall()

autoUpdater.quitAndInstall = ->
  # If we don't have any window then quitAndInstall immediately.
  BrowserWindow = require 'browser-window'
  windows = BrowserWindow.getAllWindows()
  if windows.length is 0
    AutoUpdater::quitAndInstall.call this
    return

  # Do the restart after all windows have been closed.
  app = require 'app'
  app.removeAllListeners 'window-all-closed'
  app.once 'window-all-closed', AutoUpdater::quitAndInstall.bind(this)

  # Tell all windows to remove beforeunload handler and then close itself.
  ipc = require 'ipc'
  ipc.sendChannel win.getProcessId(), win.getRoutingId(), 'ATOM_SHELL_SILENT_CLOSE' for win in windows

module.exports = autoUpdater

Fix quitAndInstall when there is no window.


Emmet = require '../lib/emmet'

describe "Emmet", ->
  it "has one valid test", ->
    true

Emmet = require 'emmet/lib/emmet'
RootView = require 'root-view'
Buffer = require 'text-buffer'
Editor = require 'editor'

describe "Emmet", ->
  [buffer, editor, editSession] = []
  keymap = null

  beforeEach ->
    window.rootView = new RootView
    rootView.open('sample.js')

    editor = rootView.getActiveView()
    editSession = rootView.getActivePaneItem()
    buffer = editor.getBuffer()

    atom.activatePackage("emmet")

    rootView.simulateDomAttachment()
    rootView.enableKeymap()

  describe "emmet:expand-abbreviation", ->
    htmlSolution = null

    beforeEach ->
      buffer.setText('')
      editor.insertText "#header>ul#nav>li*4>a"
      htmlSolution = '
\n
\n

\n

\n

\n

\n
\n
'

    it "expands HTML abbreviations via commands", ->
      editor.trigger "emmet:expand-abbreviation"
      expect(editor.getText()).toBe htmlSolution

    it "expands HTML abbreviations via keybindings", ->
      editor.trigger keydownEvent('e', shiftKey: true, metaKey: true, target: editor[0])
      expect(editor.getText()).toBe htmlSolution

Write a test for expand-abbreviation

Write a test for expand-abbreviation


params = (options) ->
  url: "https://stream.twitter.com/1.1/statuses/filter.json"
  oauth: options.oauth
  form:
    include_entities: true
    track: options.words.join ','

request = require 'request'

makeRequest = (validate, beautify, fn) ->
  req = request.post params, (error, response, body) ->
    fn error, false if error

  req.on 'end', () ->
    req = makeRequest validate, beautify, fn

  req.on 'data', (buffer) ->
    try
      tweet = JSON.parse buffer.toString()
      if tweet.disconnect
        req = makeRequest validate, beautify, fn
    catch error
      tweet = false

    if tweet and validate tweet
      tweet = beautify tweet, false if beautify

      fn null, tweet

  req

module.exports = (options) ->
  params = params options

  (validate, beautify, fn) ->
    req = makeRequest validate, beautify, fn

params = (options) ->
  url: "https://stream.twitter.com/1.1/statuses/filter.json"
  oauth: options.oauth
  form:
    include_entities: true
    track: options.words.join ','

request = require 'request'

makeRequest = (validate, beautify, fn) ->
  stream = request.post params, (error, response, body) ->
    fn error, false if error

  stream.on 'end', ->
    makeRequest validate, beautify, fn
    return

  stream.on 'data', (buffer) ->
    try
      tweet = JSON.parse buffer.toString()
      if tweet and tweet.disconnect
        makeRequest validate, beautify, fn
        return
    catch error
      tweet = false

    if tweet and validate tweet
      tweet = beautify tweet, false if beautify

      fn null, tweet
      return
  return

module.exports = (options) ->
  params = params options

  (validate, beautify, fn) ->
    makeRequest validate, beautify, fn
    return

Add more control on return

Add more control on return


# Tool to query and render GUID conversions via REST API

delay = (ms, func) -> setTimeout func, ms

class window.GuidTool
    # Initialize on page load
    @init: =>
        $('#guid').select()

        delay 2000, =>
            $('.nav, #footer').fadeIn()

        $('#submit').click (event) =>
            event.preventDefault()
            GuidTool.query $('#guid').val()
            $('#guid').val('').focus()

    # Query the server for a given GUID
    @query: (guid) =>
        $.ajax
            url: '/'
            type: 'post'
            data:
                guid: guid
            success: (data, status, xhr) =>
                # Check for success and show conversions or error
                if data.status is 'success'
                    html = '
Int:' + data.int + '
Hex:' + data.hex + '
B64:' + data.b64 + '
'
                else
                    guid = "no input given" if guid is ''
                    html = '
Invalid input: ' + guid + '
'

                $('#results').prepend(html)

# Tool to query and render GUID conversions via REST API

delay = (ms, func) -> setTimeout func, ms

class window.GuidTool
    # Initialize on page load
    @init: =>
        $('#guid').select()

        delay 2000, =>
            $('.nav, #footer').fadeIn()

        $('#submit').click (event) =>
            event.preventDefault()
            GuidTool.query $('#guid').val()
            $('#guid').val('').focus()

    # RFC 4122 Section 4.4 GUID generation from pseudo-random numbers
    @generate: =>
        'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace /[xy]/g, (c) =>
            r = Math.random() * 16 | 0
            v = if c is 'x' then r else r & 0x3 | 0x8
            return v.toString 16

    # Query the server for a given GUID
    @query: (guid) =>
        $.ajax
            url: '/'
            type: 'post'
            data:
                guid: guid
            success: (data, status, xhr) =>
                # Check for success and show conversions or error
                if data.status is 'success'
                    html = '
Int:' + data.int + '
Hex:' + data.hex + '
B64:' + data.b64 + '
'
                else
                    guid = "no input given" if guid is ''
                    html = '
Invalid input: ' + guid + '
'

                $('#results').prepend(html)

Add method to generate UUID from javascript


_ = require 'underscore'

exports.throttle = (getIdentifier, timeout = 1000) ->
  cache = {}
  throttleInner = (req, resp, next) ->
    identifier = getIdentifier(arguments)

    unless identifier of cache
       cache[identifier] = _.throttle(next, timeout, {trailing: false})

    cache[identifier]()

  return throttleInner

_ = require 'underscore'

callNext = (next) ->
  next()

exports.throttle = (getIdentifier, timeout = 1000) ->
  cache = {}
  throttleInner = (req, resp, next) ->
    identifier = getIdentifier(arguments)

    unless identifier of cache
       cache[identifier] = _.throttle(callNext, timeout, {trailing: false})

    cache[identifier](next)

  return throttleInner

Add indirection so that correct next is called.


webpackConfig = require('./webpack.config.coffee')
webpackConfig.entry = {}

module.exports = (config)  ->
  config.set
    frameworks: ['jasmine']
    browsers: ['Chrome']

    files: [
      './spec/**/*.coffee'
    ]

    preprocessors:
      './spec/helpers/**/*': ['webpack']
      './spec/**/*': ['webpack']

    webpack: webpackConfig

    webpackMiddleware:
      noInfo: true

webpackConfig = require('./webpack.config.coffee')
webpackConfig.entry = {}
webpackConfig.plugins = []

module.exports = (config)  ->
  config.set
    frameworks: ['jasmine']
    browsers: ['Chrome']

    files: [
      './spec/**/*.coffee'
    ]

    preprocessors:
      './spec/helpers/**/*': ['webpack']
      './spec/**/*': ['webpack']

    webpack: webpackConfig

    webpackMiddleware:
      noInfo: true

Remove common chunks plugin when testing


gulp       = require 'gulp'
del        = require 'del'
haml       = require 'gulp-haml'
sourcemaps = require 'gulp-sourcemaps'
coffee     = require 'gulp-coffee'
serve      = require './serve.coffee'
bower      = require 'main-bower-files'

SRC = 'src'
DEST = 'out'
HAML_PATH = "#{SRC}/haml/**/*.haml"
COFFEE_PATH = "#{SRC}/coffee/**/*.coffee"

gulp.task 'default', ['haml', 'coffee', 'bower']

gulp.task 'haml', ->
  gulp.src HAML_PATH
    .pipe haml()
    .pipe gulp.dest DEST

gulp.task 'coffee', ->
  gulp.src COFFEE_PATH
    .pipe sourcemaps.init()
    .pipe coffee()
    .pipe sourcemaps.write()
    .pipe gulp.dest "#{DEST}/scripts"

gulp.task 'bower', ->
  gulp.src bower()
    .pipe gulp.dest "#{DEST}/external"

gulp.task 'clean', (callback) ->
  del DEST, callback

gulp.task 'watch', ['haml', 'coffee'], ->
  gulp.watch HAML_PATH, ['haml']
  gulp.watch COFFEE_PATH, ['coffee']
  return

gulp.task 'serve', ->
  serve DEST

gulp       = require 'gulp'
del        = require 'del'
haml       = require 'gulp-haml'
sourcemaps = require 'gulp-sourcemaps'
coffee     = require 'gulp-coffee'
serve      = require './serve.coffee'
bower      = require 'main-bower-files'

SRC = 'src'
DEST = 'out'
HAML_PATH = "#{SRC}/haml/**/*.haml"
COFFEE_PATH = "#{SRC}/coffee/**/*.coffee"

gulp.task 'build', ['haml', 'coffee', 'bower']

gulp.task 'haml', ->
  gulp.src HAML_PATH
    .pipe haml()
    .pipe gulp.dest DEST

gulp.task 'coffee', ->
  gulp.src COFFEE_PATH
    .pipe sourcemaps.init()
    .pipe coffee()
    .pipe sourcemaps.write()
    .pipe gulp.dest "#{DEST}/scripts"

gulp.task 'bower', ->
  gulp.src bower()
    .pipe gulp.dest "#{DEST}/external"

gulp.task 'clean', (callback) ->
  del DEST, callback

gulp.task 'watch', ['build'], ->
  gulp.watch HAML_PATH, ['haml']
  gulp.watch COFFEE_PATH, ['coffee']
  return

gulp.task 'serve', ->
  serve DEST

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

Watch & Serve by Default

Watch & Serve by Default

The old default task is now "build".


".text.html":
  "polymer element":
    "prefix": "pe"
    "body": """
    <link rel="import" href="${1:../bower_components}/polymer/polymer.html">

    <dom-module id="$2">
      <style>
        :host {
          display: block;
        }
      </style>
      <template>
        $4
      </template>
    </dom-module>

    <script>
      Polymer({
        is: '$2',
        $3
      });
    </script>
    """
  "polymer element no template":
    "prefix": "pen"
    "body": """
    <link rel="import" href="${1:../bower_components}/polymer/polymer.html">

    <script>
      Polymer({
        is: '$2',
        $3
      });
    </script>
    """

".text.html":
  "polymer element":
    "prefix": "pe"
    "body": """
    <link rel="import" href="${1:../bower_components}/polymer/polymer.html">

    <dom-module id="$2">
      <style>
        :host {
          $5
        }
      </style>
      <template>
        $4
      </template>
      <script>
        Polymer({
          is: '$2',
          $3
        });
      </script>
    </dom-module>
    """
  "polymer element no template":
    "prefix": "pen"
    "body": """
    <link rel="import" href="${1:../bower_components}/polymer/polymer.html">

    <script>
      Polymer({
        is: '$2',
        $3
      });
    </script>
    """

Remove opinion about element display style

This one is give or take.


request = require 'request'

module.exports =
  class Reporter
    constructor: ->
      @request = request

    send: (eventType, data) ->
      params =
        timestamp: new Date().getTime() / 1000
        dimensions: data

      requestOptions =
        method: 'POST'
        url: "https://collector.githubapp.com/atom/#{eventType}"
        headers:
          'Content-Type' : 'application/vnd.github-octolytics+json'
        body: JSON.stringify(params)

      @request requestOptions, -> # Callback prevents errors from going to the console

request = require 'request'

module.exports =
  class Reporter
    constructor: ->
      @request = request

    send: (eventType, data) ->
      params =
        timestamp: new Date().getTime() / 1000
        context: data

      requestOptions =
        method: 'POST'
        url: "https://collector.githubapp.com/atom/#{eventType}"
        headers:
          'Content-Type' : 'application/vnd.github-octolytics+json'
        body: JSON.stringify(params)

      @request requestOptions, -> # Callback prevents errors from going to the console

Store data in context instead of dimensions


class Aggregate

  constructor: (@_context, @_eventric, @_name, Root) ->
    @_domainEvents = []

    if !Root
      @root = {}
    else
      @root = new Root

    @root.$emitDomainEvent = @emitDomainEvent

  emitDomainEvent: (domainEventName, domainEventPayload) =>
    DomainEventClass = @_context.getDomainEvent domainEventName
    if !DomainEventClass
      err = "Tried to emitDomainEvent '#{domainEventName}' which is not defined"
      @_eventric.log.error err
      throw new Error err

    aggregate =
      id: @id
      name: @_name
    domainEvent = @_context.createDomainEvent domainEventName, DomainEventClass, domainEventPayload, aggregate
    @_domainEvents.push domainEvent

    @_handleDomainEvent domainEventName, domainEvent
    @_eventric.log.debug "Created and Handled DomainEvent in Aggregate", domainEvent
    # TODO: do a rollback if something goes wrong inside the handle function

  _handleDomainEvent: (domainEventName, domainEvent) ->
    if @root["handle#{domainEventName}"]
      @root["handle#{domainEventName}"] domainEvent, ->

    else
      @_eventric.log.debug "Tried to handle the DomainEvent '#{domainEventName}' without a matching handle method"

  getDomainEvents: =>
    @_domainEvents

  applyDomainEvents: (domainEvents) ->
    @_applyDomainEvent domainEvent for domainEvent in domainEvents

  _applyDomainEvent: (domainEvent) ->
    @_handleDomainEvent domainEvent.name, domainEvent

module.exports = Aggregate

class Aggregate

  constructor: (@_context, @_eventric, @_name, AggregateClass) ->
    @_domainEvents = []
    @instance = new AggregateClass
    @instance.$emitDomainEvent = @emitDomainEvent

  emitDomainEvent: (domainEventName, domainEventPayload) =>
    DomainEventClass = @_context.getDomainEvent domainEventName
    if !DomainEventClass
      throw new Error "Tried to emitDomainEvent '#{domainEventName}' which is not defined"

    aggregate =
      id: @id
      name: @_name
    domainEvent = @_context.createDomainEvent domainEventName, DomainEventClass, domainEventPayload, aggregate
    @_domainEvents.push domainEvent

    @_handleDomainEvent domainEventName, domainEvent
    @_eventric.log.debug "Created and Handled DomainEvent in Aggregate", domainEvent

  _handleDomainEvent: (domainEventName, domainEvent) ->
    if @instance["handle#{domainEventName}"]
      @instance["handle#{domainEventName}"] domainEvent
    else
      @_eventric.log.debug "Tried to handle the DomainEvent '#{domainEventName}' without a matching handle method"

  getDomainEvents: =>
    @_domainEvents

  applyDomainEvents: (domainEvents) ->
    @_applyDomainEvent domainEvent for domainEvent in domainEvents

  _applyDomainEvent: (domainEvent) ->
    @_handleDomainEvent domainEvent.name, domainEvent

module.exports = Aggregate

Aggregate: Rename plain object member variable from "root" to "instance" in order to not conflict with DDD terminology


I18n = (args...) ->
  m = chrome.i18n.getMessage(args...)
  return escapeHtml(m) if m != ""
  m = id.replace(/(.)([A-Z][a-z])/g, (m, p1, p2) -> "#{p1} #{p2.toLowerCase()}")
  m = m.replace(/_/g, ' ')
  escapeHtml(m)

$(->
  pat = /__MSG_([A-Za-z0-9]+)__/
  $("a,button").each((i, v) ->
    e = $(v)
    title = e.attr?("title")
    if title
      newTitle = title.replace(pat, (m, p1) -> I18n(p1))
      e.attr("title", newTitle) if title != newTitle
    html = e.html()
    return true unless html
    newHtml = html.replace(pat, (m, p1) -> I18n(p1))
    e.html(newHtml) if html != newHtml
  )
)

I18n = (args...) ->
  m = chrome.i18n.getMessage(args...)
  return escapeHtml(m) if m != ""
  m = args[0].replace(/(.)([A-Z][a-z])/g, (m, p1, p2) -> "#{p1} #{p2.toLowerCase()}")
  m = m.replace(/_/g, ' ')
  escapeHtml(m)

$(->
  pat = /__MSG_([A-Za-z0-9]+)__/
  $("a,button").each((i, v) ->
    e = $(v)
    title = e.attr?("title")
    if title
      newTitle = title.replace(pat, (m, p1) -> I18n(p1))
      e.attr("title", newTitle) if title != newTitle
    html = e.html()
    return true unless html
    newHtml = html.replace(pat, (m, p1) -> I18n(p1))
    e.html(newHtml) if html != newHtml
  )
)

Fix I18n error when ID not defined in messages.json


class Component

    constructor: ->

    update: ->

    stringify: ->
        JSON.stringify(@spec)

class $blab.Table extends Component

    constructor: (@spec, sheet) ->

        randPos = (range, offset)->
            "#{Math.round((Math.random()*range+offset)*100)}%"
        @spec.x ?= randPos(0.8, 0.1)
        @spec.y ?= randPos(0.8, 0.1)

        @sheet = sheet[@spec.id]

        container = $("##{@spec.id}")
        container.append("

")
        container.css("position", "absolute")
        container.css("left", @spec.x)
        container.css("top", @spec.y)

        hot = $("##{@spec.id} .hot")
        @defaults =
            data: @sheet.spec.data
            afterChange: (change, source) =>
                $blab.compute() if source is "edit" and @sheet.spec.compute
            columns: ({type: 'numeric'} for k in [1..@sheet.spec.data[0].length])
            rowHeaders: @sheet.spec.rowHeaders
            colHeaders: @sheet.spec.colHeaders
            contextMenu: false
        @table = new Handsontable hot[0], $.extend({}, @defaults, @spec)

    update: ->
        @table.loadData @sheet.spec.data
        @table.render()

class $blab.Table extends $blab.Component

    constructor: (@spec, sheet, file) ->

        @sheet = sheet[@spec.id]

        container = $("##{@spec.containerId}")
        container.append("

")

        hot = $("#Table-#{@spec.id}")
        hot.css("position", "absolute")
        hot.css("left", @spec.x)
        hot.css("top", @spec.y)

        defaults =
            data: @sheet.data
            afterChange: (change, source) =>
                $blab.compute() if source is "edit" and @spec.compute
            columns: ({type: 'numeric'} for k in [1..@sheet.data[0].length])
            rowHeaders: @sheet.rowHeaders
            colHeaders: @sheet.colHeaders
            contextMenu: false

        @table = new Handsontable hot[0], $.extend({}, defaults, @spec)

    update: ->
        @table.loadData @sheet.data
        @table.render()

Remove local Component class. Refactor.

Remove local Component class. Refactor.


angular.module 'ws.helper', []

  .factory 'WebSocketOptions', ->
    options = {}
    return options

  .factory 'UserWebSocket', [
    '$timeout'
    'WebSocketOptions'
    ($timeout, options) ->
      class UserWebSocket

        constructor: (url) ->
          @url = url
          @handlers = {}
          @connect() if options.autoConnect ? true

        register: (handlers...) ->
          @handlers[handler.protocol] = handler for handler in handlers
          return

        connect: =>
          @socket = new WebSocket @url
          @socket.onmessage = (event) =>
            msg = JSON.parse(event.data)
            handler = @handlers[msg.protocol]
            handler.onmessage(msg) if handler?
            return

          @socket.onclose = (event) =>
            $timeout @connect, 10000
            return

          return

        send: (msg) ->
          @socket.send JSON.stringify(msg) if @readyState() is WebSocket.OPEN
          return

        readyState: ->
          @socket?.readyState ? WebSocket.CLOSED

      return new UserWebSocket options.url
    ]

angular.module 'ws.helper', []

  .factory 'WebSocketOptions', ->
    options = {}
    return options

  .factory 'UserWebSocket', [
    '$timeout'
    'WebSocketOptions'
    ($timeout, options) ->
      class UserWebSocket

        constructor: (url) ->
          @url = url
          @handlers = {}
          $timeout @connect, 2000 if options.autoConnect ? true

        register: (handlers...) ->
          @handlers[handler.protocol] = handler for handler in handlers
          return

        connect: =>
          @socket = new WebSocket @url
          @socket.onmessage = (event) =>
            msg = JSON.parse(event.data)
            handler = @handlers[msg.protocol]
            handler.onmessage(msg) if handler?
            return

          @socket.onclose = (event) =>
            $timeout @connect, 10000
            return

          return

        send: (msg) ->
          @socket.send JSON.stringify(msg) if @readyState() is WebSocket.OPEN
          return

        readyState: ->
          @socket?.readyState ? WebSocket.CLOSED

      return new UserWebSocket options.url
    ]

Put a 2-second delay before websocket connecting


# Your Adapter should define:
# * QueryDefaults - an object of defaults to send as query parameters

class Embeditor.Adapter
    className: "Adapter"

    constructor: (@element, @options={}) ->
        @adapter        = Embeditor.Adapters[@className]
        @href           = @element.attr('href')
        @dataOptions    = @_extractData()
        @queryParams    = @_buildParams(@dataOptions, options)

    swap: ->
        return

    embed: (html) ->
        @wrapper = $("<div />", class: @options.wrapperClass)
        @wrapper.html(html)
        @element.after @wrapper

    _extractData: ->
        dataOptions = {}

        for key,val of @element.data()
            # Make sure we care about this attribute
            if @adapter.QueryDefaults?[key]
                dataOptions[key] = val

        dataOptions

    # We're combining a few things (in order of precedence):
    # 1. The `data-attributes` of the placeholder,
    # 2. The adapter-specific options specified at Embeditor
    #    initialization,
    # 3. The global options specified at Embeditor initialization,
    # 4. This adapter's default options (fallback options).
    _buildParams: (dataOptions, options) ->
        _.defaults(dataOptions,
            @adapter.query,
            options['query'],
            @adapter.QueryDefaults
        )

# Your Adapter SHOULD define:
# * @QueryDefaults - The default parameters if no others are passed in.

class Embeditor.Adapter
    className: "Adapter"

    @QueryDefaults = {}

    constructor: (@element, @options={}) ->
        @adapter        = Embeditor.Adapters[@className]
        @href           = @element.attr('href')
        @dataOptions    = @_extractData()
        @queryParams    = @_buildParams(@dataOptions, options)

    swap: ->
        return

    embed: (html) ->
        @wrapper = $("<div />", class: @options.wrapperClass)
        @wrapper.html(html)
        @element.after @wrapper

    _extractData: ->
        dataOptions = {}

        for key,val of @element.data()
            # Make sure we care about this attribute
            if @adapter.QueryDefaults?[key]
                dataOptions[key] = val

        dataOptions

    # We're combining a few things (in order of precedence):
    # 1. The `data-attributes` of the placeholder,
    # 2. The adapter-specific options specified at Embeditor
    #    initialization,
    # 3. The global options specified at Embeditor initialization,
    # 4. This adapter's default options (fallback options).
    _buildParams: (dataOptions, options) ->
        _.defaults(dataOptions,
            @adapter.query,
            options['query'],
            @adapter.QueryDefaults
        )

Add some documentatio and blank QueryDefaults object in Adapter


HighlightedAreaView = require './highlighted-area-view'

module.exports =
  activate: (state) ->
    @areas = []
    atom.workspaceView.eachEditorView (editorView) =>
      area = new HighlightedAreaView(editorView)
      area.attach()
      @areas.push = area

  deactivate: =>
    for area in @areas
      area.destroy()

HighlightedAreaView = require './highlighted-area-view'
areas = []

module.exports =
  activate: (state) ->
    atom.workspaceView.eachEditorView (editorView) ->
      area = new HighlightedAreaView(editorView)
      area.attach()
      areas.push = area

  deactivate: ->
    for area in areas
      area.destroy()

Fix being able to uninstall package

Fix being able to uninstall package


Guid = require 'guid'
Reporter = require './reporter'

module.exports =
  activate: ({sessionLength}) ->
    atom.config.set('metrics.userId', Guid.raw()) unless atom.config.get('metrics.userId')
    @sessionStart = Date.now()

    Reporter.sendEvent('ended', sessionLength) if sessionLength
    Reporter.sendEvent('started')
    Reporter.sendTiming('core-load', atom.getWindowLoadTime())
    Reporter.sendTiming('shell-load', atom.getLoadSettings().shellLoadTime)
    atom.workspaceView.on 'editor:attached', (event, editorView) ->
      Reporter.sendView('EditorView')

  serialize: ->
    sessionLength: Date.now() - @sessionStart

Guid = require 'guid'
Reporter = require './reporter'

module.exports =
  activate: ({sessionLength}) ->
    atom.config.set('metrics.userId', Guid.raw()) unless atom.config.get('metrics.userId')
    @sessionStart = Date.now()

    Reporter.sendEvent('ended', sessionLength) if sessionLength
    Reporter.sendEvent('started')
    Reporter.sendTiming('core-load', atom.getWindowLoadTime())
    Reporter.sendTiming('shell-load', atom.getLoadSettings().shellLoadTime)
     atom.workspaceView.on 'pane:item-added', (event, item) ->
        name = item.getViewClass?().name ? item.constructor.name
        Reporter.sendView(name)

  serialize: ->
    sessionLength: Date.now() - @sessionStart

Use pane:item-added instead of editor:attached

Now there is info about what pane item is added. Also we don't get
events for mini-editors being attached.


flat = (obj, newObj = {}, path = '') ->
	for key, value of obj
		if _.isObject value
			flat value, newObj, key + '.'
		else
			newObj[path + key] = value

	return newObj

Meteor.startup ->
	l = {}
	errors = []

	for lang, value of TAPi18next.options.resStore
		l[lang] = flat value

	for lang, value of l
		for subLang, subValue of l when subLang isnt lang
			for key, translation of subValue
				if not value[key]?
					errors.push "#{lang}: no value found for key #{key} from #{subLang}"

	if errors.length > 0
		len = 0
		for error in errors
			if error.length > len
				len = error.length

		console.log s.rpad('', len + 4, '=').red
		for error in errors
			console.log "| #{error} |".red
		console.log s.rpad('', len + 4, '=').red

flat = (obj, newObj = {}, path = '') ->
	for key, value of obj
		if _.isObject value
			flat value, newObj, key + '.'
		else
			newObj[path + key] = value

	return newObj

Meteor.startup ->
	l = {}
	errors = []

	for lang, value of TAPi18next.options.resStore
		l[lang] = flat value

	for lang, value of l
		for subLang, subValue of l when subLang isnt lang
			for key, translation of subValue
				if not value[key]?
					errors.push "#{lang}: no value found for key #{key} from #{subLang}"

	if errors.length > 0
		len = 0
		for error in errors
			if error.length > len
				len = error.length

		console.log s.rpad('', len + 4, '=').red
		for error in errors
			console.log "|".red, s.rpad("#{error}", len).red,  "|".red
		console.log s.rpad('', len + 4, '=').red

Fix log of language validation

Fix log of language validation


class Visualization extends Backbone.Model
  paramRoot: 'visualization'
  defaults:
    parameters: null

module.exports = Visualization

class Visualization extends Backbone.Model
  paramRoot: 'visualization'
  urlRoot: '/api/visualizations'
  defaults:
    parameters: null

module.exports = Visualization

Add urlRoot parameter to Visualization model in order to update model parameters via api


{Disposable, CompositeDisposable} = require 'event-kit'

ContentsByMode =
  insert:  ["status-bar-vim-mode-insert", "Insert"]
  command: ["status-bar-vim-mode-command", "Command"]
  visual:  ["status-bar-vim-mode-visual", "Visual"]

module.exports =
class StatusBarManager
  constructor: ->
    @element = document.createElement("div")
    @element.id = "status-bar-vim-mode"
    @element.classList.add("inline-block")

  initialize: ->
    @disposables = new CompositeDisposable
    unless @attach()
      @disposables.add atom.packages.onDidActivateAll => @attach()
    @disposables

  update: (currentMode) ->
    for mode, [klass, html] of ContentsByMode
      if mode is currentMode
        @element.classList.add(klass)
        @element.innerHTML = html
      else
        @element.classList.remove(klass)

  # Private

  attach: ->
    statusBar = atom.workspaceView?.statusBar
    if statusBar?
      statusBar.prependRight(@element)
      @disposables.add =>
        @element.parentNode?.removeChild(@element)
      true
    else
      false

{Disposable, CompositeDisposable} = require 'event-kit'

ContentsByMode =
  insert:  ["status-bar-vim-mode-insert", "Insert"]
  command: ["status-bar-vim-mode-command", "Command"]
  visual:  ["status-bar-vim-mode-visual", "Visual"]

module.exports =
class StatusBarManager
  constructor: ->
    @element = document.createElement("div")
    @element.id = "status-bar-vim-mode"
    @element.classList.add("inline-block")

  initialize: ->
    @disposables = new CompositeDisposable
    unless @attach()
      @disposables.add atom.packages.onDidActivateAll => @attach()
    @disposables

  update: (currentMode) ->
    for mode, [klass, html] of ContentsByMode
      if mode is currentMode
        @element.classList.add(klass)
        @element.innerHTML = html
      else
        @element.classList.remove(klass)

  # Private

  attach: ->
    statusBar = atom.workspaceView?.statusBar
    if statusBar?
      statusBar.prependRight(@element)
      @disposables.add new Disposable =>
        @element.parentNode?.removeChild(@element)
      true
    else
      false

Fix error when deactivating package

Fix error when deactivating package


Spine = require('spine')

class Actions extends Spine.Controller

  elements:
    '.deal': 'deal_button'
    '.continue': 'continue_button'
    '.surrender': 'surrender_button'
    '.bet': 'bet_buttons'
    '.action': 'action_buttons'

  events:
    'click .deal': 'deal'

  constructor: ->
    super
    @html require('views/actions')()
    Spine.bind 'result', @finished
    @setup()

  setup: =>
    show @bet_buttons
    hide @action_buttons
    hide @continue_button

  deal: =>
    hide @bet_buttons
    hide @deal_button
    show @action_buttons

  finished: =>
    hide @action_buttons
    show @continue_button

  # Private

  hide = (selection) ->
    selection.hide()

  show = (selection) ->
    enable selection.show()

  disable = (selection) ->
    selection.attr('disabled', true)

  enable = (selection) ->
    selection.removeAttr('disabled')

module.exports = Actions

Spine = require('spine')
Player = require('models/player')
$ = Spine.$

class Actions extends Spine.Controller

  elements:
    '.deal': 'deal_button'
    '.continue': 'continue_button'
    '.surrender': 'surrender_button'
    '.bet': 'bet_buttons'
    '.action': 'action_buttons'

  events:
    'click .deal': 'deal'

  constructor: ->
    super
    @html require('views/actions')()
    Spine.bind 'result', @finished
    Player.bind 'change', @bank_check
    @setup()

  setup: =>
    show @bet_buttons
    hide @action_buttons
    hide @continue_button

  deal: =>
    hide @bet_buttons
    hide @deal_button
    show @action_buttons

  finished: =>
    hide @action_buttons
    show @continue_button

  bank_check: (player) =>
    for el in @bet_buttons.find('button')
      bet_button = $(el)
      (disable bet_button) if bet_button.data('amount') > player.pot.size

  # Private

  hide = (selection) ->
    selection.hide()

  show = (selection) ->
    enable selection.show()

  disable = (selection) ->
    selection.attr('disabled', true)

  enable = (selection) ->
    selection.removeAttr('disabled')

module.exports = Actions

Disable bet buttons when you don't have that much to bet


'.platform-darwin .editor':
  'cmd-r': 'symbols-view:toggle-file-symbols'
  'cmd-alt-down': 'symbols-view:go-to-declaration'
  'cmd-alt-up': 'symbols-view:return-from-declaration'

'.platform-win32 .editor':
  'ctrl-r': 'symbols-view:toggle-file-symbols'

'.platform-linux .editor':
  'ctrl-r': 'symbols-view:toggle-file-symbols'
  'ctrl-alt-down': 'symbols-view:go-to-declaration'
  'ctrl-alt-up': 'symbols-view:return-from-declaration'

'.platform-darwin':
  'cmd-R': 'symbols-view:toggle-project-symbols'

'.platform-win32, .platform-linux':
  'ctrl-R': 'symbols-view:toggle-project-symbols'

'.platform-darwin atom-text-editor':
  'cmd-r': 'symbols-view:toggle-file-symbols'
  'cmd-alt-down': 'symbols-view:go-to-declaration'
  'cmd-alt-up': 'symbols-view:return-from-declaration'

'.platform-win32 atom-text-editor':
  'ctrl-r': 'symbols-view:toggle-file-symbols'

'.platform-linux atom-text-editor':
  'ctrl-r': 'symbols-view:toggle-file-symbols'
  'ctrl-alt-down': 'symbols-view:go-to-declaration'
  'ctrl-alt-up': 'symbols-view:return-from-declaration'

'.platform-darwin':
  'cmd-R': 'symbols-view:toggle-project-symbols'

'.platform-win32, .platform-linux':
  'ctrl-R': 'symbols-view:toggle-project-symbols'

Replace .editor -> atom-text-editor in keymap


$ = window.$ = require("jquery")
Bacon = window.Bacon = require("baconjs")
_ = require("lodash")
$.fn.asEventStream = Bacon.$.asEventStream
examples = require("./examples.coffee")

$code = $("#code #editor")
$run = $(".run")

runBus = new Bacon.Bus()

codeMirror = CodeMirror.fromTextArea $code.get(0), {
  lineNumbers: true
  mode: "javascript"
  theme: "solarized dark",
  extraKeys: {
    "Ctrl-Enter": -> runBus.push()
  }
}
initialCode = localStorage.code || examples.first
codeMirror.setValue(initialCode)
codeP = Bacon.fromEventTarget(codeMirror, "change")
  .map(".getValue")
  .toProperty(initialCode)
enabledP = Bacon.constant(true)

codeP.onValue (code) ->
  localStorage.code = code

evalE = codeP.filter(enabledP).sampledBy($run.asEventStream("click").doAction(".preventDefault").merge(runBus))

evalCode = (code) ->
  window.frameLoaded = (frame) ->
    scriptElem = frame.document.createElement "script"
    scriptElem.type = "text/javascript"
    scriptElem.text = code
    frame.document.body.appendChild scriptElem
  $("#game").attr("src", "game.html")

evalE.onValue(evalCode)

codeMirror.focus()
$("body").css("opacity", 1)

$ = window.$ = require("jquery")
Bacon = window.Bacon = require("baconjs")
_ = require("lodash")
$.fn.asEventStream = Bacon.$.asEventStream
examples = require("./examples.coffee")

$code = $("#code #editor")
$run = $(".run")

runBus = new Bacon.Bus()

codeMirror = CodeMirror.fromTextArea $code.get(0), {
  lineNumbers: true
  mode: "javascript"
  theme: "solarized dark",
  extraKeys: {
    "Ctrl-Enter": -> runBus.push()
  }
}
initialCode = localStorage.code || examples.first
codeMirror.setValue(initialCode)
codeP = Bacon.fromEventTarget(codeMirror, "change")
  .map(".getValue")
  .toProperty(initialCode)
enabledP = Bacon.constant(true)

codeP.onValue (code) ->
  localStorage.code = code

evalE = codeP.filter(enabledP).sampledBy($run.asEventStream("click").doAction(".preventDefault").merge(runBus))

evalCode = (code) ->
  window.frameLoaded = (frame) ->
    frame.eval(code)
  $("#game").attr("src", "game.html")

evalE.onValue(evalCode)

codeMirror.focus()
$("body").css("opacity", 1)

Revert "use script elem instead of eval"

This reverts commit c6e6adf9eb37da77fa01b0c856ead2e426463530.


class Creator

  update: (el) =>
    model = el.getAttribute(ObserveJS.attributeName)
    if model?
      @create(el, model)
    else
      @destroy(el)

  create: (el) =>
    model = el.getAttribute(ObserveJS.attributeName)
    if ObserveJS.cache[model]?
      if el.instance?
        el.instance.loaded()
        return

      el.instance = new ObserveJS.cache[model](el)

      el.instance.element = ->
        el

      el.instance.on = (event, target, callback) ->
        if callback?
          el.instance.on.events.push([event, target, callback])
        else
          callback = target
          target = el
        target.addEventListener(event, callback)

      el.instance.on.events = []

      if el.instance.loaded?
        el.instance.loaded()

    else
      throw "error: #{model} is not registered. Add your model with ObserveJS.Models.add(#{model})"

  destroy: (el) =>
    el.instance.on.events?.forEach (event) ->
      event[1].removeEventListener(event[0], event[2])

@ObserveJS.Creator = new Creator()

class Creator

  update: (el) =>
    model = el.getAttribute(ObserveJS.attributeName)
    if model?
      @create(el, model)
    else
      @destroy(el)

  create: (el) =>
    model = el.getAttribute(ObserveJS.attributeName)
    if ObserveJS.cache[model]?
      if el.instance?
        el.instance.loaded()
        return

      el.instance = new ObserveJS.cache[model](el)

      el.instance.element = ->
        el

      el.instance.on = (event, target, callback) ->
        if callback?
          el.instance.on.events.push([event, target, callback])
        else
          callback = target
          target = el
        target.addEventListener(event, callback)

      el.instance.on.events = []

      if el.instance.loaded?
        el.instance.loaded()

    else
      throw "error: #{model} is not registered. Add your model with ObserveJS.Models.add(#{model})"

  destroy: (el) =>
    el.instance.on.events?.forEach (event) ->
      event[1].removeEventListener(event[0], event[2])

    delete el.instance

@ObserveJS.Creator = new Creator()

Delete object to avoid leakage

Delete object to avoid leakage