# $(document).ready ->

# 	body = $('html, body')
# 	anchorClick = (link) ->
# 		linkSplit = link.split('/').pop()
# 		$.get 'pages/' + linkSplit, (data) ->
# 			$('#content').html data
# 			return
# 		return

# 	# Scroll on top when change page
# 	# $(body).scrollTop 0
# 	# Special function for lightbox
# 	# $('.magnific-image-link').magnificPopup type: 'image'
#  	# $('.magnific-video-link').magnificPopup type: 'iframe'

# 	$('#container').on 'click', '.changepage', (e) ->
# 		window.history.pushState(null, null, $(this).attr('href'))
# 		anchorClick($(this).attr('href'))
# 		e.preventDefault()
# 		return
# 	window.addEventListener 'popstate', (e) ->
# 		anchorClick(location.pathname)
# 		return
# 	return

$(document).ready(function() {

	function anchorClick(link) {
		var linkSplit = link.split('/').pop();
		$.get('pages/' + linkSplit, function(data) {
			$('#content').html(data);
		});
	}

	$('#container').on('click', 'a', function(e) {
		window.history.pushState(null, null, $(this).attr('href'));
		anchorClick($(this).attr('href'));
		e.preventDefault();
	});

	window.addEventListener('popstate', function(e) {
		anchorClick(location.pathname);
	});

});

$(document).ready ->

  anchorClick = (link) ->
    linkSplit = link.split('/').pop()
    $.get 'pages/' + linkSplit, (data) ->
      $('#content').html data
      return
    return

  $('#container').on 'click', 'a', (e) ->
    window.history.pushState null, null, $(this).attr('href')
    anchorClick $(this).attr('href')
    e.preventDefault()
    return
  window.addEventListener 'popstate', (e) ->
    anchorClick location.pathname
    return
  return

# $(document).ready(function() {

# 	function anchorClick(link) {
# 		var linkSplit = link.split('/').pop();
# 		$.get('pages/' + linkSplit, function(data) {
# 			$('#content').html(data);
# 		});
# 	}

# 	$('#container').on('click', 'a', function(e) {
# 		window.history.pushState(null, null, $(this).attr('href'));
# 		anchorClick($(this).attr('href'));
# 		e.preventDefault();
# 	});

# 	window.addEventListener('popstate', function(e) {
# 		anchorClick(location.pathname);
# 	});

# });

Test history api with coffee

Test history api with coffee


"*":
  core:
    audioBeep: false
    closeEmptyWindows: false
    disabledPackages: [
      "language-clojure"
      "language-go"
      "language-java"
      "language-perl"
      "language-objective-c"
      "language-property-list"
      "metrics"
      "open-on-github"
      "package-generator"
      "symbols-view"
      "language-toml"
      "spell-check"
    ]
    packagesWithKeymapsDisabled: [
      "refactor"
      "es-identifier-highlight"
      "sort-lines"
      "csslint"
    ]
    telemetryConsent: "limited"
  csslint:
    hideOnNoErrors: true
  editor:
    invisibles: {}
    showInvisibles: true
  "exception-reporting":
    userId: "2ab09d56-2ab2-2fc5-7065-f68aca373175"
  "find-and-replace": {}
  linter:
    lintOnChange: false
  "linter-jscs":
    configPath: ".jscsrc"
    onlyConfig: true
  "linter-jshint":
    disableWhenNoJshintrcFileInPath: true
  "linter-ui-default":
    showPanel: true
  "spell-check": {}
  tabs:
    enableVcsColoring: true
  "tree-view":
    hideIgnoredNames: true
    hideVcsIgnoredFiles: true
  welcome:
    showOnStartup: false
  whitespace:
    ignoreWhitespaceOnCurrentLine: false

"*":
  core:
    audioBeep: false
    closeEmptyWindows: false
    disabledPackages: [
      "language-clojure"
      "language-go"
      "language-java"
      "language-perl"
      "language-objective-c"
      "language-property-list"
      "metrics"
      "open-on-github"
      "package-generator"
      "symbols-view"
      "language-toml"
      "spell-check"
      "github"
    ]
    packagesWithKeymapsDisabled: [
      "refactor"
      "es-identifier-highlight"
      "sort-lines"
      "csslint"
    ]
    telemetryConsent: "limited"
  csslint:
    hideOnNoErrors: true
  editor:
    invisibles: {}
    showInvisibles: true
  "exception-reporting":
    userId: "2ab09d56-2ab2-2fc5-7065-f68aca373175"
  "find-and-replace": {}
  linter:
    lintOnChange: false
  "linter-jscs":
    configPath: ".jscsrc"
    onlyConfig: true
  "linter-jshint":
    disableWhenNoJshintrcFileInPath: true
  "linter-ui-default":
    showPanel: true
  "spell-check": {}
  tabs:
    enableVcsColoring: true
  "tree-view":
    hideIgnoredNames: true
    hideVcsIgnoredFiles: true
  welcome:
    showOnStartup: false
  whitespace:
    ignoreWhitespaceOnCurrentLine: false

Disable github package bundled with atom since 1.18.0

No, thank you @atom.


class MainChatPanel extends JView

  constructor:->
    super
      cssClass : 'main-chat-panel visible'

    @registerSingleton "chatPanel", @, yes

    @header = new MainChatHeader
    @conversationList = new ChatConversationListView
    @conversationListController = new ChatConversationListController
      view : @conversationList

  createConversation:(data)->
    # Data includes chatChannel and the conversation
    @conversationListController.addItem data

  viewAppended:->
    @addSubView @header
    @addSubView @conversationList
    @conversationListController.loadItems()

  show:->
    @setClass 'visible'
    @emit 'PanelVisibilityChanged', true

  hide:->
    @unsetClass 'visible'
    @emit 'PanelVisibilityChanged', false

  toggle:->
    @toggleClass 'visible'
    @emit 'PanelVisibilityChanged', @isVisible()

  isVisible:->
    @hasClass 'visible'

class MainChatPanel extends JView

  constructor:->
    super
      cssClass : 'main-chat-panel'

    @registerSingleton "chatPanel", @, yes

    @header = new MainChatHeader
    @conversationList = new ChatConversationListView
    @conversationListController = new ChatConversationListController
      view : @conversationList

    @on 'PanelVisibilityChanged', (visible)=>
      if visible
        @getSingleton('windowController').addLayer @
        @once 'ReceivedClickElsewhere', @bound 'hide'

  createConversation:(data)->
    # Data includes chatChannel and the conversation
    @conversationListController.addItem data

  viewAppended:->
    @addSubView @header
    @addSubView @conversationList
    @conversationListController.loadItems()
    @show()

  show:->
    @setClass 'visible'
    @emit 'PanelVisibilityChanged', true

  hide:->
    @unsetClass 'visible'
    @emit 'PanelVisibilityChanged', false

  toggle:->
    @toggleClass 'visible'
    @emit 'PanelVisibilityChanged', @isVisible()

  isVisible:->
    @hasClass 'visible'

Hide the panel when it looses focues

Hide the panel when it looses focues


async = require "async"
{assign} = require "lodash"

class PhantomTask

	constructor: (options) ->
		@jobs = []
		@scripts = []
		@options = assign {}, options
		@page = require('./webpage').create()

	add: (request, description = "Job ##{@jobs.length}", options = {}) ->

		task = require(request) options
		@jobs.push (done) =>
			console.log description
			task.apply @page, [done]
		@

	inject: (script) ->
		@scripts.push script
		@

	run: (url, callback) ->
		unless typeof callback is "function"
			callback = ->

		@page.open url, (status) =>
			unless status is "success"
				callback new Error "Failed to open page: #{src}"

			for script in [].concat(@scripts)
				@page.injectJs script

			method = if @options.parallel then "parallel" else "series"
			async[method] @jobs, (error) ->
				callback error
		@

module.exports = PhantomTask

async = require "async"
{assign} = require "lodash"

class PhantomTask

	constructor: (options) ->
		@jobs = []
		@scripts = []
		@options = assign {}, options
		@page = require('./webpage').create()

	add: (request, description = "Job ##{@jobs.length}", options = {}) ->

		task = require(request) options
		@jobs.push (done) =>
			console.log description
			task.apply @page, [done]
		@

	inject: (script) ->
		@scripts.push script
		@

	run: (url, callback) ->
		unless typeof callback is "function"
			callback = ->

		@page.open url, (status) =>
			unless status is "success"
				callback new Error "Failed to open page: #{url}"

			for script in [].concat(@scripts)
				@page.injectJs script

			method = if @options.parallel then "parallel" else "series"
			async[method] @jobs, (error) ->
				callback error
		@

module.exports = PhantomTask

Fix error message upon page load failure.


if Meteor.isServer
    @Sessions = new Meteor.Collection("session_timeouts")
    Meteor.methods( {
       session_heartbeat: ->
          user_id = Meteor.userId()
          return unless user_id
          old_session = Sessions.findOne({user_id: user_id})
          if old_session?
              Sessions.update({user_id: user_id}, {$set: {heartbeat: Date.now()}})
          else
              Sessions.insert({user_id: user_id, heartbeat: Date.now()})
    })

    interval = Meteor.settings.purgeInterval || 3000
    Meteor.setInterval(() ->
        timeout = Date.now()
        timeout -= Meteor.settings.inactivityTimeout || 300000
        users = _.pluck(Sessions.find({heartbeat: {$lt: timeout}}).fetch(), 'user_id')
        for id in users
            Meteor.users.update(id ,{$set: {'services.resume.loginTokens': []}})
            Sessions.remove({user_id: id})

    , interval)

if Meteor.isServer
    @Sessions = new Meteor.Collection("session_timeouts")
    Meteor.methods( {
       session_heartbeat: ->
          user_id = Meteor.userId()
          return unless user_id
          old_session = Sessions.findOne({user_id: user_id})
          if old_session?
              Sessions.update({user_id: user_id}, {$set: {heartbeat: Date.now()}})
          else
              Sessions.insert({user_id: user_id, heartbeat: Date.now()})
    })

    interval = Meteor.settings.purgeInterval || 3000
    Meteor.setInterval(() ->
        timeout = Date.now()
        timeout -= Meteor.settings.inactivityTimeout || 300000
        user_ids = _.pluck(Sessions.find({heartbeat: {$lt: timeout}}).fetch(), 'user_id')
        if user_ids.length
            Meteor.users.update({_id: {$in: user_ids}} ,{$set: {'services.resume.loginTokens': []}})
            Sessions.remove({user_id: {$in: user_ids}})

    , interval)

Optimize performance by reducing amount of DB requests


`import Em from "vendor/ember"`

Component = Em.Component.extend
    initializeValue: Em.on "init", ->
        prompt = @get "content.prompt"
        if prompt
            options = @get "content.options"
            if prompt isnt options[0].label
                options.unshift
                    label: prompt
                    value: ""
        else
            options = @get "content.options"
            if @get "content.is_optional"
                if options[0].label isnt "" and not @get "content.editable"
                    options.unshift
                        label: ""
                        value: ""

    initializeTypeahead: Em.on "didInsertElement", ->
        @$().find(".typeahead").typeahead
            source: @get("content.options").map (o) -> o.label

    label: ""
    updateValue: Em.observer "label", ->
        label = @get "label"
        values = (i.value for i in @get("content.options") when i.label is label)
        if values.length is 1
            @set "content.value", values[0]
        else
            @set "content.value", label

    sanitizeValue: Em.observer "content.options", ->
        options = (o.value for o in @get "content.options")
        value = @get "content.value"
        if value not in options
            @set "content.value", options[0]

    editing: true
    actions:
        toggleEdit: ->
            @toggleProperty "editing"

`export default Component`

`import Em from "vendor/ember"`

Component = Em.Component.extend
    initializeValue: Em.on "init", ->
        prompt = @get "content.prompt"
        if prompt
            options = @get "content.options"
            if prompt isnt options[0].label
                options.unshift
                    label: prompt
                    value: ""
        else
            options = @get "content.options"
            if @get "content.is_optional"
                if options[0]?.label isnt "" and not @get "content.editable"
                    options.unshift
                        label: ""
                        value: ""

    initializeTypeahead: Em.on "didInsertElement", ->
        @$().find(".typeahead").typeahead
            source: @get("content.options").map (o) -> o.label

    label: ""
    updateValue: Em.observer "label", ->
        label = @get "label"
        values = (i.value for i in @get("content.options") when i.label is label)
        if values.length is 1
            @set "content.value", values[0]
        else
            @set "content.value", label

    sanitizeValue: Em.observer "content.options", ->
        options = (o.value for o in @get "content.options")
        value = @get "content.value"
        if value not in options
            @set "content.value", options[0]

    editing: true
    actions:
        toggleEdit: ->
            @toggleProperty "editing"

`export default Component`

Fix initialization of empty selects.

Fix initialization of empty selects.


globals = require 'globals'

module.exports = (url) ->

  return url  if globals.config.environment is 'dev'
  return url  if /p.koding.com/.test url

  # let's use DOM for parsing the url
  parser = global.document.createElement('a')
  parser.href = url

  # build our new url, example:
  # old: http://54.164.174.218:3000/kite
  # new: https://koding.com/-/prodproxy/54.164.243.111/kite
  #           or
  #      http://localhost:8090/-/prodproxy/54.164.243.111/kite

  { protocol } = global.document.location

  proxy = if globals.config.environment is 'production'
  then 'prodproxy'
  else 'devproxy'

  subdomain = if globals.config.environment is 'production'
  then 'p'
  else 'dev-p'

  return "#{protocol}//#{subdomain}.koding.com/-/#{proxy}/#{parser.hostname}#{parser.pathname}"

globals = require 'globals'

module.exports = (url) ->

  return url  if globals.config.environment is 'dev'
  return url  if /p\.koding\.com/.test url

  # let's use DOM for parsing the url
  parser = global.document.createElement('a')
  parser.href = url

  # build our new url, example:
  # old: http://54.164.174.218:3000/kite
  # new: https://koding.com/-/prodproxy/54.164.243.111/kite
  #           or
  #      http://localhost:8090/-/prodproxy/54.164.243.111/kite

  { protocol } = global.document.location

  if /\.koding\.me$/.test parser.hostname
    proxy = 'devtunnel'
    if globals.config.environment is 'production'
      proxy = 'prodtunnel'
  else
    proxy = if globals.config.environment is 'production'
    then 'prodproxy'
    else 'devproxy'

  subdomain = if globals.config.environment is 'production'
  then 'p'
  else 'dev-p'

  return "#{protocol}//#{subdomain}.koding.com/-/#{proxy}/#{parser.hostname}#{parser.pathname}"

ProxifyUrl: Use {prod, dev}tunnel for tunnelled kites


#!/usr/bin/env coffee

express        = require 'express'
path           = require 'path'
favicon        = require 'serve-favicon'
logger         = require 'morgan'
methodOverride = require 'method-override'
session        = require 'express-session'
bodyParser     = require 'body-parser'
multer         = require 'multer'
errorHandler   = require 'errorhandler'

TemperatureController = require './controllers/temperature-controller'
temperatureController = new TemperatureController()

app = express()

app.set 'port', process.env.WEATHER_SERVICE_PORT || 3000
app.set 'views', path.join(__dirname, 'views')
app.set 'view engine', 'jade'
# app.use favicon(__dirname + '/public/favicon.ico'
app.use logger('dev')
app.use methodOverride()
app.use session(resave: true, saveUninitialized: true, secret: 'uwotm8')
app.use bodyParser.json()
app.use bodyParser.urlencoded(extended: true)
app.use multer()
app.use express.static(path.join(__dirname, 'public'))

app.use errorHandler()

app.get '/temperature/c', temperatureController.celsius
app.get '/temperature/celsius', temperatureController.celsius

app.get '/temperature/f', temperatureController.fahrenheit
app.get '/temperature/fahrenheit', temperatureController.fahrenheit

app.listen app.get('port'), ->
  console.log "Express server listening on port #{app.get('port')}"

#!/usr/bin/env coffee

express        = require 'express'
path           = require 'path'
favicon        = require 'serve-favicon'
logger         = require 'morgan'
methodOverride = require 'method-override'
session        = require 'express-session'
bodyParser     = require 'body-parser'
multer         = require 'multer'
errorHandler   = require 'errorhandler'

TemperatureController = require './controllers/temperature-controller'
temperatureController = new TemperatureController()

app = express()

app.set 'port', process.env?.WEATHER_SERVICE_PORT || process.env?.PORT || 3000
app.set 'views', path.join(__dirname, 'views')
app.set 'view engine', 'jade'
# app.use favicon(__dirname + '/public/favicon.ico'
app.use logger('dev')
app.use methodOverride()
app.use session(resave: true, saveUninitialized: true, secret: 'uwotm8')
app.use bodyParser.json()
app.use bodyParser.urlencoded(extended: true)
app.use multer()
app.use express.static(path.join(__dirname, 'public'))

app.use errorHandler()

app.get '/temperature/c', temperatureController.celsius
app.get '/temperature/celsius', temperatureController.celsius

app.get '/temperature/f', temperatureController.fahrenheit
app.get '/temperature/fahrenheit', temperatureController.fahrenheit

app.listen app.get('port'), ->
  console.log "Express server listening on port #{app.get('port')}"

Allow user to specify port

Allow user to specify port


###* @jsx React.DOM ###

React = require('react/addons')
ParserMixin = require './mixins/Parser'
DisableOnSubmitMixin = require('../controls/mixins/DisableOnSubmit')

ButtonToolbar = require('react-bootstrap/ButtonToolbar')
Button = require('react-bootstrap/Button')

Form = React.createClass(
  mixins: [
    ParserMixin,
    DisableOnSubmitMixin
  ]

  propTypes:
    formDef        : React.PropTypes.object
    formData       : React.PropTypes.object
    title          : React.PropTypes.string # Title can also be set in formDef
    onEnter        : React.PropTypes.func # Callback when hitting Enter on an input
    buttons        : React.PropTypes.object

  classes: ->
    React.addons.classSet
      "form-horizontal": true
      "component-submitting" : @props.submitting
      "component-not-submitting" : !@props.submitting

  buttons: ->
    _.map @props.buttons, (props, title) =>
      props.key = title
      props.disabled = @disabled()
      React.createFactory(Button) props, title

  render: ->
    `(
      <form role="form" className={this.classes()} onChange={this.onChange}>
        {this.constructFormFromDef(this.props.formDef)}
        <ButtonToolbar>{this.buttons()}</ButtonToolbar>
      </form>
    )`
)

module.exports = Form

###* @jsx React.DOM ###

React = require('react/addons')
ParserMixin = require './mixins/Parser'
DisableOnSubmitMixin = require('../controls/mixins/DisableOnSubmit')

{ButtonToolbar, Button} = require('react-bootstrap')

Form = React.createClass(
  mixins: [
    ParserMixin,
    DisableOnSubmitMixin
  ]

  propTypes:
    formDef        : React.PropTypes.object
    formData       : React.PropTypes.object
    title          : React.PropTypes.string # Title can also be set in formDef
    onEnter        : React.PropTypes.func # Callback when hitting Enter on an input
    buttons        : React.PropTypes.object

  classes: ->
    React.addons.classSet
      "form-horizontal": true
      "component-submitting" : @props.submitting
      "component-not-submitting" : !@props.submitting

  buttons: ->
    _.map @props.buttons, (props, title) =>
      props.key = title
      props.disabled = @disabled()
      React.createFactory(Button) props, title

  render: ->
    `(
      <form role="form" className={this.classes()} onChange={this.onChange}>
        {this.constructFormFromDef(this.props.formDef)}
        <ButtonToolbar>{this.buttons()}</ButtonToolbar>
      </form>
    )`
)

module.exports = Form

Use destructuring assignment as ReactBoostrap doesn't expose modules directly anymore


class Lanes.Access.Extension extends Lanes.Extensions.Base

    identifier: "lanes-access"

    setBootstrapData: (data)->
        Lanes.current_user = new Lanes.Models.User

        Lanes.Models.Roles.all = new Lanes.Models.Roles(
            _.map( data.roles, (role)->
                { id: role.toLowerCase(), name: role }
            )
        )
        if data.user
            Lanes.current_user.set(data.user)
        if data.access
            Lanes.current_user.access_data = data.access

    onAvailable: (view)->
        this.login_dialog = new Lanes.Access.LoginDialog({ parent: view })

        # screen=Lanes.Models.Screens.all.get("user-management")
        # screen.display(view.viewport)

class Lanes.Access.Extension extends Lanes.Extensions.Base

    identifier: "lanes-access"

    setBootstrapData: (data)->
        Lanes.current_user = new Lanes.Models.User

        Lanes.Models.Roles.all = new Lanes.Models.Roles(
            _.map( data.roles, (role)->
                { id: role.toLowerCase(), name: role }
            )
        )
        if data.user
            Lanes.current_user.set(data.user)
        if data.access
            Lanes.current_user.access_data = data.access

    onAvailable: (view)->
        Lanes.Access.createLoginDialog(view)

Move loginDialog into own creation function


counterpart = require 'counterpart'
React = require 'react'
TitleMixin = require '../lib/title-mixin'
apiClient = require '../api/client'
OwnedCardList = require '../components/owned-card-list'

counterpart.registerTranslations 'en',
  projectsPage:
    title: 'All Projects'
    countMessage: 'Showing %(pageStart)s-%(pageEnd)s of %(count)s found'
    button: 'Get Started'
    notFoundMessage: 'Sorry, no projects found'

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

  mixins: [TitleMixin]

  title: 'Projects'

  listProjects: ->
    query = {include: 'avatar'}

    if !apiClient.params.admin
      query.homepage = true

    apiClient.type('projects').get Object.assign {}, query, @props.location.query

  imagePromise: (project) ->
    Promise.resolve project.avatar_src or '/assets/simple-avatar.jpg'

  cardLink: (project) ->
    link = if !!project.redirect
      project.redirect
    else
      [owner, name] = project.slug.split('/')
      "/projects/#{owner}/#{name}"

    return link

  render: ->
    <OwnedCardList
      {...@props}
      translationObjectName="projectsPage"
      listPromise={@listProjects()}
      linkTo="projects"
      cardLink={@cardLink}
      heroClass="projects-hero"
      imagePromise={@imagePromise}
      skipOwner={true} />

counterpart = require 'counterpart'
React = require 'react'
TitleMixin = require '../lib/title-mixin'
apiClient = require '../api/client'
OwnedCardList = require '../components/owned-card-list'

counterpart.registerTranslations 'en',
  projectsPage:
    title: 'All Projects'
    countMessage: 'Showing %(pageStart)s-%(pageEnd)s of %(count)s found'
    button: 'Get Started'
    notFoundMessage: 'Sorry, no projects found'

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

  mixins: [TitleMixin]

  title: 'Projects'

  listProjects: ->
    query = {include: 'avatar'}

    if !apiClient.params.admin
      query.simple = true

    apiClient.type('projects').get Object.assign {}, query, @props.location.query

  imagePromise: (project) ->
    Promise.resolve project.avatar_src or '/assets/simple-avatar.jpg'

  cardLink: (project) ->
    link = if !!project.redirect
      project.redirect
    else
      [owner, name] = project.slug.split('/')
      "/projects/#{owner}/#{name}"

    return link

  render: ->
    <OwnedCardList
      {...@props}
      translationObjectName="projectsPage"
      listPromise={@listProjects()}
      linkTo="projects"
      cardLink={@cardLink}
      heroClass="projects-hero"
      imagePromise={@imagePromise}
      skipOwner={true} />

Rename the homepage param to simple for clarity


{_, $, View} = require 'atom'

module.exports =
class WrapGuideView extends View
  @activate: ->
    atom.workspaceView.eachEditorView (editorView) ->
      if editorView.attached and editorView.getPane()
        editorView.underlayer.append(new WrapGuideView(editorView))

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

  initialize: (@editorView) ->
    @observeConfig 'editor.fontSize', => @updateGuide()
    @subscribe @editorView, 'editor:path-changed', => @updateGuide()
    @subscribe @editorView, 'editor:min-width-changed', => @updateGuide()
    @subscribe $(window), 'resize', => @updateGuide()

  getDefaultColumn: ->
    atom.config.getPositiveInt('editor.preferredLineLength', 80)

  getGuideColumn: (path) ->
    customColumns = atom.config.get('wrap-guide.columns')
    return @getDefaultColumn() unless _.isArray(customColumns)
    for customColumn in customColumns when _.isObject(customColumn)
      {pattern, column} = customColumn
      return parseInt(column) if pattern and new RegExp(pattern).test(path)
    @getDefaultColumn()

  updateGuide: ->
    column = @getGuideColumn(@editorView.getPath())
    if column > 0
      columnWidth = @editorView.charWidth * column
      if columnWidth < @editorView.layerMinWidth or columnWidth < @editorView.width()
        @css('left', columnWidth).show()
      else
        @hide()
    else
      @hide()

{_, $, View} = require 'atom'

module.exports =
class WrapGuideView extends View
  @activate: ->
    atom.workspaceView.eachEditorView (editorView) ->
      if editorView.attached and editorView.getPane()
        editorView.underlayer.append(new WrapGuideView(editorView))

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

  initialize: (@editorView) ->
    @observeConfig 'editor.fontSize', => @updateGuide()
    @subscribe @editorView, 'editor:path-changed', => @updateGuide()
    @subscribe @editorView, 'editor:min-width-changed', => @updateGuide()
    @subscribe $(window), 'resize', => @updateGuide()

  getDefaultColumn: ->
    atom.config.getPositiveInt('editor.preferredLineLength', 80)

  getGuideColumn: (path) ->
    customColumns = atom.config.get('wrap-guide.columns')
    return @getDefaultColumn() unless _.isArray(customColumns)
    for customColumn in customColumns when _.isObject(customColumn)
      {pattern, column} = customColumn
      return parseInt(column) if pattern and new RegExp(pattern).test(path)
    @getDefaultColumn()

  updateGuide: ->
    column = @getGuideColumn(@editorView.getEditor().getPath())
    if column > 0
      columnWidth = @editorView.charWidth * column
      if columnWidth < @editorView.layerMinWidth or columnWidth < @editorView.width()
        @css('left', columnWidth).show()
      else
        @hide()
    else
      @hide()

Call getPath on Editor instead of EditorView


{View} = require 'space-pen'
$ = require 'jquery'
_ = require 'underscore'

module.exports =
class WrapGuideView extends View
  @activate: ->
    rootView.eachEditor (editor) =>
      @appendToEditorPane(rootView, editor) if editor.attached

  @appendToEditorPane: (rootView, editor) ->
    if underlayer = editor.find('.underlayer')
      underlayer.append(new WrapGuideView(editor))

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

  defaultColumn: 80

  initialize: (@editor) =>
    @observeConfig 'editor.fontSize', => @updateGuide()
    @subscribe @editor, 'editor:path-changed', => @updateGuide()
    @subscribe @editor, 'editor:min-width-changed', => @updateGuide()
    @subscribe $(window), 'resize', => @updateGuide()

  getGuideColumn: (path) ->
    customColumns = config.get('wrapGuide.columns')
    return @defaultColumn unless _.isArray(customColumns)
    for customColumn in customColumns
      continue unless _.isObject(customColumn)
      pattern = customColumn['pattern']
      continue unless pattern
      return parseInt(customColumn['column']) if new RegExp(pattern).test(path)
    @defaultColumn

  updateGuide: ->
    column = @getGuideColumn(@editor.getPath(), @defaultColumn)
    if column > 0
      columnWidth = @editor.charWidth * column
      if columnWidth < @editor.layerMinWidth or columnWidth < @editor.width()
        @css('left', columnWidth).show()
      else
        @hide()
    else
      @hide()

{View} = require 'space-pen'
$ = require 'jquery'
_ = require 'underscore'

module.exports =
class WrapGuideView extends View
  @activate: ->
    rootView.eachEditor (editor) =>
      editor.underlayer.append(new WrapGuideView(editor)) if editor.attached

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

  defaultColumn: 80

  initialize: (@editor) =>
    @observeConfig 'editor.fontSize', => @updateGuide()
    @subscribe @editor, 'editor:path-changed', => @updateGuide()
    @subscribe @editor, 'editor:min-width-changed', => @updateGuide()
    @subscribe $(window), 'resize', => @updateGuide()

  getGuideColumn: (path) ->
    customColumns = config.get('wrapGuide.columns')
    return @defaultColumn unless _.isArray(customColumns)
    for customColumn in customColumns
      continue unless _.isObject(customColumn)
      pattern = customColumn['pattern']
      continue unless pattern
      return parseInt(customColumn['column']) if new RegExp(pattern).test(path)
    @defaultColumn

  updateGuide: ->
    column = @getGuideColumn(@editor.getPath(), @defaultColumn)
    if column > 0
      columnWidth = @editor.charWidth * column
      if columnWidth < @editor.layerMinWidth or columnWidth < @editor.width()
        @css('left', columnWidth).show()
      else
        @hide()
    else
      @hide()

Use underlayer property on editor

Use underlayer property on editor

Removes unneeded call to find


module.exports = (grunt) ->

  require('time-grunt')(grunt)

  require('load-grunt-config')(grunt)

  grunt.registerTask 'default', ['clean', 'amd_tamer', 'uglify']

  grunt.registerTask 'test', ['jshint']

  grunt.registerTask 'doc', ['groc']

  grunt.registerTask 'pages', ['metalsmith', 'doc']

module.exports = (grunt) ->

  require('time-grunt')(grunt)

  require('load-grunt-config')(grunt)

  grunt.registerTask 'default', ['clean', 'amd_tamer', 'uglify']

  grunt.registerTask 'test', ['jshint']

  grunt.registerTask 'doc', ['groc']

  grunt.registerTask 'pages', ['metalsmith', 'doc', 'bowercopy']

Add bowercopy task for pages

Add bowercopy task for pages


dispatcher = require './dispatcher'
invariant = require './invariant'
Action = require './action'

_id = 0

class ActionInstance

	constructor: (@type, @payload) ->
		@actionID = _id++
		Object.freeze @

	valueOf: () ->
		@payload

	getActionID: () ->
		@actionID

module.exports = class ActionCreator

	###
	# Method for dispatching an action through the dispatcher
	#
	# @param {Action} action The action to dispatch
	# @param {mixed} payload Payload for the action
	###
	dispatch: (action, payload) ->
		actionInstance = @createActionInstance action, payload
		dispatcher.dispatch actionInstance
		return actionInstance

	createActionInstance: (action, payload) ->
		invariant action instanceof Action and action?.type?,
			"The action you dispatched does not seem to be an instance of capacitor.Action"
		new ActionInstance action.type, payload

dispatcher = require './dispatcher'
invariant = require './invariant'
Action = require './action'

_actionID = 0
_requestID = 0

class ActionInstance

	constructor: (@type, @payload) ->
		@actionID = _actionID++
		Object.freeze @

	valueOf: () ->
		@payload

	getActionID: () ->
		@actionID

module.exports = class ActionCreator

	###
	# Dispatches an action through the dispatcher
	#
	# @param {Action} action The action to dispatch
	# @param {mixed} payload Payload for the action
	###
	dispatch: (action, payload) ->
		actionInstance = @createActionInstance action, payload
		dispatcher.dispatch actionInstance
		return actionInstance

	###
	# Creates an action instance for dispatching
	#
	# @param {Action} action The action to dispatch
	# @param {mixed} payload Payload for the action
	###
	createActionInstance: (action, payload) ->
		invariant action instanceof Action and action?.type?,
			"The action you dispatched does not seem to be an instance of capacitor.Action"
		new ActionInstance action.type, payload

	###
	# Generates a request id. Useful for tracking specific requests in components.
	###
	generateRequestID: () ->
		return _requestID++

Add method on ActionCreator to generate a request id


{$} = require 'atom'
UIWatcher = require './ui-watcher'

module.exports =
  activate: (state) ->
    uiWatcher = null

    # HACK: I need an actvation event when the ui or packages are all loaded.
    # It cant watch all the packages until they are all loaded.
    createUIWatcher = ->
      uiWatcher = new UIWatcher
        themeManager: atom.themes
      $(window).off 'focus', createUIWatcher
    $(window).on 'focus', createUIWatcher

    rootView.command 'dev-live-reload:reload-all', ->
      console.log 'Reloading all styles!'
      uiWatcher.reloadAll()

{$} = require 'atom'
UIWatcher = require './ui-watcher'

module.exports =
  activate: (state) ->
    return unless atom.getLoadSettings().devMode

    console.log 'Enabling live reloader...'

    uiWatcher = null

    # HACK: I need an actvation event when the ui or packages are all loaded.
    # It cant watch all the packages until they are all loaded.
    createUIWatcher = ->
      uiWatcher = new UIWatcher
        themeManager: atom.themes
      $(window).off 'focus', createUIWatcher
    $(window).on 'focus', createUIWatcher

    rootView.command 'dev-live-reload:reload-all', ->
      console.log 'Reloading all styles!'
      uiWatcher.reloadAll()

Enable only in dev mode

Enable only in dev mode


# Your snippets
#
# Atom snippets allow you to enter a simple prefix in the editor and hit tab to
# expand the prefix into a larger code block with templated values.
#
# You can create a new snippet in this file by typing "snip" and then hitting
# tab.
#
# An example CoffeeScript snippet to expand log to console.log:
#
# '.source.coffee':
#   'Console log':
#     'prefix': 'log'
#     'body': 'console.log $1'
#
# This file uses CoffeeScript Object Notation (CSON).
# If you are unfamiliar with CSON, you can read more about it here:
# https://github.com/bevry/cson#what-is-cson

'.text.html':
  'Translation Method':
    'prefix': 'trans'
    'body': '<?php echo $this->__(\'\') ?>'
  'Get URL':
    'prefix': 'geturl'
    'body': '<?php echo $this->getUrl(\'\') ?>'
  'Get Child HTML':
    'prefix': 'chtml'
    'body': '<?php echo $this->getChildHtml(\'\') ?>'

Add snippet for Magento getChildHtml method


idCounter = 0

module.exports =
class SpellCheckTask
  @handler: null
  @callbacksById: {}

  constructor: (@task) ->
    @id = idCounter++

  terminate: ->
    delete @constructor.callbacksById[@id]

  start: (buffer) ->
    # Figure out the paths since we need that for checkers that are project-specific.
    projectPath = null
    relativePath = null
    if buffer?.file?.path
      [projectPath, relativePath] = atom.project.relativizePath(buffer.file.path)

    # Submit the spell check request to the background task.
    args = {
      id: @id,
      projectPath,
      relativePath,
      text: buffer.getText()
    }
    @task?.start args, @constructor.dispatchMisspellings

  onDidSpellCheck: (callback) ->
    @constructor.callbacksById[@id] = callback

  @dispatchMisspellings: (data) =>
    @callbacksById[data.id]?(data.misspellings)

idCounter = 0
log = console.log

module.exports =
class SpellCheckTask
  @handler: null
  @callbacksById: {}
  @isBusy: false
  @queue: []

  constructor: (@task) ->
    @id = idCounter++

  terminate: ->
    delete @constructor.callbacksById[@id]

  start: (buffer) ->
    # Figure out the paths since we need that for checkers that are project-specific.
    projectPath = null
    relativePath = null
    if buffer?.file?.path
      [projectPath, relativePath] = atom.project.relativizePath(buffer.file.path)

    # Submit the spell check request to the background task.
    entry = {
      task: @task,
      args: {
        id: @id,
        projectPath,
        relativePath,
        text: buffer.getText()
      }
    }

    log('Pushing ' + @id, entry)
    queue = @constructor.queue

    if (queue.length > 0)
      for i in [0..queue.length-1]
        if (queue[i].id is @id)
          log('Ejecting previous entry at ' + i)
          queue.splice(i, 1)
          break

    queue.push(entry)
    @constructor.sendNextMaybe()

  @sendNextMaybe: ->
    if not @isBusy and @queue.length > 0
      @isBusy = true
      entry = @queue.shift()
      log('Dispatching ' + entry.args.id + ' from queue of ' + (@queue.length + 1))
      entry.task?.start entry.args, @dispatchMisspellings

  onDidSpellCheck: (callback) ->
    @constructor.callbacksById[@id] = callback

  @dispatchMisspellings: (data) =>
    log('completed ' + data.id, data)
    @callbacksById[data.id]?(data.misspellings)
    @isBusy = false
    @sendNextMaybe()

Implement a queuing system to avoid quadratic pipe reading time in node IPC.


passport = require 'passport'

exports.logInFirst = (req, res, next) ->
  if req.isAuthenticated()
    next()
  else
    res.redirect "/auth/login?next=#{req.path}"

exports.storeNext = (req, res, next) ->
  if req.query.next
    req.session.next = req.query.next

  next()

exports.login =
  passport.authenticate 'google',
    scope: ['profile', 'email']
    hd: 'andrew.cmu.edu'

exports.callback = passport.authenticate 'google'

exports.after = (req, res) ->
  if req.session.next
    next = req.session.next
    delete req.session
    res.redirect next
  else
    res.redirect '/'

exports.ensureAuthenticated = (req, res, next) ->
  if req.isAuthenticated()
    next()
  else
    res.status(401).send null

exports.ensureAdmin = (req, res, next) ->
  if req.user.isAdmin
    next()
  else
    err = new Error 'Forbidden: Admin'
    err.status 403
    err.type 'forbidden'
    next err

exports.logout = (req, res) ->
  req.logout()
  res.redirect '/'

passport = require 'passport'

exports.logInFirst = (req, res, next) ->
  if req.isAuthenticated()
    next()
  else
    res.redirect "/auth/login?next=#{req.path}"

exports.storeNext = (req, res, next) ->
  if req.query.next
    req.session.next = req.query.next

  next()

exports.login =
  passport.authenticate 'google',
    scope: ['profile', 'email']
    hd: 'andrew.cmu.edu'

exports.callback = passport.authenticate 'google'

exports.after = (req, res) ->
  if req.session.next
    next = req.session.next
    delete req.session
    res.redirect next
  else
    res.redirect '/'

exports.ensureAuthenticated = (req, res, next) ->
  if req.isAuthenticated()
    next()
  else
    res.status(401).send null

exports.ensureAdmin = (req, res, next) ->
  if req.user.isAdmin
    next()
  else
    err = new Error 'Forbidden: Admin'
    err.status = 403
    err.type = 'forbidden'
    next err

exports.logout = (req, res) ->
  req.logout()
  res.redirect '/'

Fix 'undefined is not a function' error

Fix 'undefined is not a function' error


is_page_visible = true
num_unseen_posts = 0

$(document).on 'page:change', ->
  if location.pathname == '/posts'
    App.posts = App.cable.subscriptions.create "PostsChannel",
      received: (data) ->
        $('table tbody').prepend(data['row'])

        unless is_page_visible
          num_unseen_posts++
          document.title = "(#{num_unseen_posts}*) Recent posts - metasmoke"
  else if /^\/post\/(\d*)(\/)?$/.test(location.pathname)
    App.posts = App.cable.subscriptions.create { channel: "PostsChannel", post_id: location.pathname.match(/^\/post\/(\d*)(\/)?$/)[1] },
      received: (data) ->
        $('strong.post-feedbacks').prepend(data['feedback'])
  else if App.posts
    App.posts.unsubscribe()
    App.posts = null

$(window).on 'blur', ->
  is_page_visible = false

$(window).on 'focus', ->
  if location.pathname == '/posts'
    is_page_visible = true
    num_unseen_posts = 0
    document.title = "Recent posts - metasmoke"

is_page_visible = true
num_unseen_posts = 0

$(document).on 'turbolinks:load', ->
  console.log "hi"
  if location.pathname == '/posts'
    App.posts = App.cable.subscriptions.create "PostsChannel",
      received: (data) ->
        $('table tbody').prepend(data['row'])

        unless is_page_visible
          num_unseen_posts++
          document.title = "(#{num_unseen_posts}*) Recent posts - metasmoke"
  else if /^\/post\/(\d*)(\/)?$/.test(location.pathname)
    console.log "oy"
    App.posts = App.cable.subscriptions.create { channel: "PostsChannel", post_id: location.pathname.match(/^\/post\/(\d*)(\/)?$/)[1] },
      received: (data) ->
        $('strong.post-feedbacks').prepend(data['feedback'])
  else if App.posts
    App.posts.unsubscribe()
    App.posts = null

$(window).on 'blur', ->
  is_page_visible = false

$(window).on 'focus', ->
  if location.pathname == '/posts'
    is_page_visible = true
    num_unseen_posts = 0
    document.title = "Recent posts - metasmoke"

Change websocket trigger to turbolinks:load; debugging


React = require 'react'
Router = require 'react-router'

ArticleList = require './views/article-list.cjsx'

DefaultRoute = Router.DefaultRoute
Route = Router.Route
RouteHandler = Router.RouteHandler
Link = Router.Link

App = React.createClass
	render: ->

<Link to="blog">Blog</Link>

			<RouteHandler/>

routes = <Route name="app" path="/" handler={ App }>
	<Route name="blog" path="/blog" handler={ ArticleList }/>
</Route>

Router.run routes, Router.HistoryLocation, (Handler) ->
	React.render(<Handler/>, document.body)

React = require 'react'
Router = require 'react-router'

ArticleList = require './views/article-list.cjsx'

DefaultRoute = Router.DefaultRoute
Route = Router.Route
RouteHandler = Router.RouteHandler
Link = Router.Link

App = React.createClass
	render: ->

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

			<RouteHandler/>

routes = <Route name="app" path="/" handler={ App }>
	<DefaultRoute handler={ ArticleList }/>
</Route>

Router.run routes, Router.HistoryLocation, (Handler) ->
	React.render(<Handler/>, document.body)

Set ArticleList as default route.

Set ArticleList as default route.


# Config and Start SyncedCron
logger = new Logger 'SyncedCron'

SyncedCron.config
	logger: (opts) ->
		logger[opts.level].call(logger, opts.message)
	collectionName: 'rocketchat_cron_history'

generateStatistics = ->
	statistics = RocketChat.statistics.save()
	statistics.host = Meteor.absoluteUrl()
	if RocketChat.settings.get 'Statistics_reporting'
		HTTP.post 'https://rocket.chat/stats',
			data: statistics
	return

Meteor.startup ->
	Meteor.defer ->
		generateStatistics()

		# Generate and save statistics every hour
		SyncedCron.add
			name: 'Generate and save statistics',
			schedule: (parser) -># parser is a later.parse object
				return parser.text 'every 1 hour'
			job: generateStatistics

		SyncedCron.start()

# Config and Start SyncedCron
logger = new Logger 'SyncedCron'

SyncedCron.config
	logger: (opts) ->
		logger[opts.level].call(logger, opts.message)
	collectionName: 'rocketchat_cron_history'

generateStatistics = ->
	statistics = RocketChat.statistics.save()
	statistics.host = Meteor.absoluteUrl()
	if RocketChat.settings.get 'Statistics_reporting'
		try
			HTTP.post 'https://rocket.chat/stats',
				data: statistics
		catch e
			logger.warn('Failed to send usage report')
	return

Meteor.startup ->
	Meteor.defer ->
		generateStatistics()

		# Generate and save statistics every hour
		SyncedCron.add
			name: 'Generate and save statistics',
			schedule: (parser) -># parser is a later.parse object
				return parser.text 'every 1 hour'
			job: generateStatistics

		SyncedCron.start()

Add error handling for stat server request


url = require 'url'
{$$} = require 'space-pen'
ScrollView = require 'scroll-view'
BuddyView = require './buddy-view'

module.exports =
class BuddyList extends ScrollView
  @content: ->
    @div class: 'buddy-list', tabindex: -1

  initialize: (@presence) ->
    super

    @presence.on 'person-added', -> @updateBuddies()
    @presence.on 'person-removed', -> @updateBuddies()
    @presence.on 'person-status-changed', -> @updateBuddies()

  toggle: ->
    if @hasParent()
      @detach()
    else
      @attach()

  attach: ->
    rootView.horizontal.append(this)
    @focus()
    @updateBuddies()

  updateBuddies: ->
    @empty()
    @append(new BuddyView(buddy)) for buddy in @presence.getPeople()

url = require 'url'
{$$} = require 'space-pen'
ScrollView = require 'scroll-view'
BuddyView = require './buddy-view'

module.exports =
class BuddyList extends ScrollView
  @content: ->
    @div class: 'buddy-list', tabindex: -1

  initialize: (@presence) ->
    super

    @presence.on 'person-added', => @updateBuddies()
    @presence.on 'person-removed', => @updateBuddies()
    @presence.on 'person-status-changed', => @updateBuddies()

  toggle: ->
    if @hasParent()
      @detach()
    else
      @attach()

  attach: ->
    rootView.horizontal.append(this)
    @focus()
    @updateBuddies()

  updateBuddies: ->
    @empty()
    @append(new BuddyView(buddy)) for buddy in @presence.getPeople()

Use fat arrow for callbacks

Use fat arrow for callbacks


window.StrutBuilder ||= {}

# [
#   { #slide 1
#     start: 0,
#     end: 2.5,
#     texts: [
#              {text: 'Hum', position: 1.2},
#              {text: 'bewafaa', position: 1.7}
#            ]
#   },
#   { #slide 2
#     start: 2.5,
#     end: 4.3,
#     texts: [
#              {text: 'Hargiz', position: 3.3},
#              {text: 'na they', position: 3.8}
#            ]
#   }
# ]
StrutBuilder.build = (data) ->
  slides = for slide, i  in data
    StrutBuilder.Slide.build(slide, i)
  {
    slides: slides,
    activeSlide: slides[0],
    fileName: 'presentation-unnamed',
    customStylesheet: '',
    deckVersion: '1.0',
    customBackgrounds: { bgs: [] }
  }

window.StrutBuilder ||= {}

# [
#   { #slide 1
#     start: 0,
#     end: 2.5,
#     texts: [
#              {text: 'Hum', position: 1.2},
#              {text: 'bewafaa', position: 1.7}
#            ]
#   },
#   { #slide 2
#     start: 2.5,
#     end: 4.3,
#     texts: [
#              {text: 'Hargiz', position: 3.3},
#              {text: 'na they', position: 3.8}
#            ]
#   }
# ]
StrutBuilder.build = (data) ->
  slidesdata = (slide for slide in data when slide.data.type == 'segment')
  itemdata = (item for item in data when item.data.type == 'segment_item')
  for slidedata in slidesdata
    items = for item in itemdata when (slidedata.start <= item.start and item.start < slidedata.end)
      text: item.data.note
      position: item.start
    slidedata.texts = items

  slides = for slide, i in slidesdata
    StrutBuilder.Slide.build(slide, i)
  {
    slides: slides,
    activeSlide: slides[0],
    fileName: 'presentation-unnamed',
    customStylesheet: '',
    deckVersion: '1.0',
    customBackgrounds: { bgs: [] }
  }

Convert segments and their text to words in the PPT slides


express = require 'express'
compress = require 'compression'
hbs = require 'hbs'

config = require '../config'
passport = require '../lib/auth'
User = require '../models/user'

module.exports = app = express()

hbs.registerHelper 'json', (context) ->
  new hbs.handlebars.SafeString JSON.stringify(context)

app.set 'views', "#{__dirname}/../views"
app.use compress()
app.use express.static '#{__dirname}/../public/'

# Special case for install
app.post '/login', passport.authenticate 'local',
  failureRedirect: "/#{config.buckets.adminSegment}/login"
  successRedirect: "/#{config.buckets.adminSegment}/"

app.get '/logout', (req, res) ->
  req.logout()
  res.redirect "/#{config.buckets.adminSegment}/"

app.all '*', (req, res) ->
  # This is kinda dumb, but whatever
  User.count({}).exec (err, userCount) ->
    res.send 500 if err

    res.render 'admin',
      user: req.user
      adminSegment: config.buckets.adminSegment
      needsInstall: userCount is 0

express = require 'express'
compress = require 'compression'
hbs = require 'hbs'

config = require '../config'
passport = require '../lib/auth'
User = require '../models/user'

module.exports = app = express()

hbs.registerHelper 'json', (context) ->
  new hbs.handlebars.SafeString JSON.stringify(context)

app.set 'views', "#{__dirname}/../views"
app.use compress()
app.use express.static '#{__dirname}/../public/', maxAge: 86400000 # One day

# Special case for install
app.post '/login', passport.authenticate 'local',
  failureRedirect: "/#{config.buckets.adminSegment}/login"
  successRedirect: "/#{config.buckets.adminSegment}/"

app.get '/logout', (req, res) ->
  req.logout()
  res.redirect "/#{config.buckets.adminSegment}/"

app.all '*', (req, res) ->
  # This is kinda dumb, but whatever
  User.count({}).exec (err, userCount) ->
    res.send 500 if err

    res.render 'admin',
      user: req.user
      adminSegment: config.buckets.adminSegment
      needsInstall: userCount is 0

Set cache headers for statics

Set cache headers for statics


CocoView = require 'views/kinds/CocoView'
template = require 'templates/play/level/tome/problem_alert'
{me} = require 'lib/auth'

module.exports = class ProblemAlertView extends CocoView
  className: 'problem-alert'
  template: template

  subscriptions: {}

  events:
    'click .close': 'onRemoveClicked'

  constructor: (options) ->
    super options
    @problem = options.problem

  getRenderData: (context={}) ->
    context = super context
    format = (s) -> s?.replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br>')
    message = @problem.aetherProblem.message
    age = @problem.aetherProblem.userInfo?.age
    if age?
      if /^Line \d+:/.test message
        message = message.replace /^(Line \d+)/, "$1, time #{age.toFixed(1)}"
      else
        message = "Time #{age.toFixed(1)}: #{message}"
    context.message = format message
    context.hint = format @problem.aetherProblem.hint
    context

  afterRender: ->
    super()
    @$el.addClass('alert').addClass("alert-#{@problem.aetherProblem.level}").hide().fadeIn('slow')
    @$el.addClass('no-hint') unless @problem.aetherProblem.hint
    Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'error_appear', volume: 1.0

  onRemoveClicked: ->
    @$el.remove()
    @destroy()
    #@problem.destroy()  # let's try leaving the annotations / marker ranges alone

CocoView = require 'views/kinds/CocoView'
template = require 'templates/play/level/tome/problem_alert'
{me} = require 'lib/auth'

module.exports = class ProblemAlertView extends CocoView
  className: 'problem-alert'
  template: template

  subscriptions: {}

  events:
    'click .close': 'onRemoveClicked'

  constructor: (options) ->
    super options
    @problem = options.problem

  getRenderData: (context={}) ->
    context = super context
    format = (s) -> s?.replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br>')
    context.message = format @problem.aetherProblem.message
    context.hint = format @problem.aetherProblem.hint
    context

  afterRender: ->
    super()
    @$el.addClass('alert').addClass("alert-#{@problem.aetherProblem.level}").hide().fadeIn('slow')
    @$el.addClass('no-hint') unless @problem.aetherProblem.hint
    Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'error_appear', volume: 1.0

  onRemoveClicked: ->
    @$el.remove()
    @destroy()
    #@problem.destroy()  # let's try leaving the annotations / marker ranges alone

Remove time from problem alert message

Remove time from problem alert message


@RailsAdmin ||= {}
@RailsAdmin.I18n = class Locale
  @init: (@locale, @translations)->
    moment.locale(@locale)

  @t:(key) ->
    humanize = key.charAt(0).toUpperCase() + key.replace(/_/g, " ").slice(1)
    @translations[key] || humanize

@RailsAdmin ||= {}
@RailsAdmin.I18n = class Locale
  @init: (@locale, @translations)->
    moment.locale(@locale)
    if typeof(@translations) == "string"
      @translations = JSON.parse(@translations)

  @t:(key) ->
    humanize = key.charAt(0).toUpperCase() + key.replace(/_/g, " ").slice(1)
    @translations[key] || humanize

Fix JS translations not be object but string


ETahi.MessageOverlayController = ETahi.TaskController.extend ETahi.ControllerParticipants,
  newCommentBody: ""

  message: true

  _clearNewMessage: ->
    @set('newCommentBody', "")

  commentSort: ['createdAt:asc']
  sortedComments: Ember.computed.sort('comments', 'commentSort')

  actions:
    clearMessageContent: ->
      @_clearNewMessage()

    postComment: ->
      commenter = @get('currentUser')
      commentFields =
        commenter: commenter
        messageTask: @get('model')
        body: @get('newCommentBody')
      newComment = @store.createRecord('comment', commentFields)
      newComment.save()
        .then(@_clearNewMessage.bind(@), newComment.deleteRecord)
        .then(@send('saveNewParticipant', commenter))

ETahi.MessageOverlayController = ETahi.TaskController.extend ETahi.ControllerParticipants,
  newCommentBody: ""

  message: true

  _clearNewMessage: ->
    @set('newCommentBody', "")

  commentSort: ['createdAt:asc']
  sortedComments: Ember.computed.sort('comments', 'commentSort')

  actions:
    clearMessageContent: ->
      @_clearNewMessage()

    postComment: ->
      commenter = @get('currentUser')
      commentFields =
        commenter: commenter
        messageTask: @get('model')
        body: @get('newCommentBody')
        createdAt: new Date()
      newComment = @store.createRecord('comment', commentFields)
      newComment.save()
        .then(@_clearNewMessage.bind(@), newComment.deleteRecord)
        .then(@send('saveNewParticipant', commenter))

Add initial createdAt date when saving comment.

Null dates sort differently than real ones.


describe 'HashParams', ->
    describe 'given foreground and background', ->
        params = null
        beforeEach ->
            params = new HashParams(
                new HashParams.scalar('foreground'),
                new HashParams.scalar('background'))
        it 'initializes values.foreground and .background', ->
            expect(params.values).toEqual {foreground: '', background: ''}
        describe 'setHash', ->
            it 'can set values.foreground', ->
                params.setHash '#foreground=blue'
                expect(params.values).toEqual {foreground: 'blue', background: ''}
            it 'can set values.background', ->
                params.setHash '#background=green'
                expect(params.values).toEqual {foreground: '', background: 'green'}
            it 'clears other values', ->
                params.values.foreground = 'magenta'
                params.setHash '#background=green'
                expect(params.values).toEqual {foreground: '', background: 'green'}
            it 'will not set values.foo', ->
                params.setHash '#foo=bar'
                expect(params.values).toEqual {foreground: '', background: ''}

describe 'HashParams', ->
    describe 'initial state', ->
        describe 'given foreground and background', ->
            params = null
            beforeEach ->
                params = new HashParams(
                    new HashParams.scalar('foreground'),
                    new HashParams.scalar('background'))
            it 'has empty strings for values.foreground and values.background', ->
                expect(params.values).toEqual {foreground: '', background: ''}
    describe '.setHash()', ->
        describe 'given foreground and background', ->
            params = null
            beforeEach ->
                params = new HashParams(
                    new HashParams.scalar('foreground'),
                    new HashParams.scalar('background'))
            it 'can set values.foreground', ->
                params.setHash '#foreground=blue'
                expect(params.values).toEqual {foreground: 'blue', background: ''}
            it 'can set values.background', ->
                params.setHash '#background=green'
                expect(params.values).toEqual {foreground: '', background: 'green'}
            it 'clears other values', ->
                params.values.foreground = 'magenta'
                params.setHash '#background=green'
                expect(params.values).toEqual {foreground: '', background: 'green'}
            it 'will not set values.foo', ->
                params.setHash '#foo=bar'
                expect(params.values).toEqual {foreground: '', background: ''}

Reorganize specs by public method.

Reorganize specs by public method.


Binary = require('./example');

describe 'binary', ->

  it '1 is decimal 1', ->
    expect(1).toEqual new Binary('1').toDecimal()

  xit '10 is decimal 2', ->
    expect(2).toEqual new Binary('10').toDecimal()

  xit '11 is decimal 3', ->
    expect(3).toEqual new Binary('11').toDecimal()

  xit '100 is decimal 4', ->
    expect(4).toEqual new Binary('100').toDecimal()

  xit '1001 is decimal 9', ->
    expect(9).toEqual new Binary('1001').toDecimal()

  xit '11010 is decimal 26', ->
    expect(26).toEqual new Binary('11010').toDecimal()

  xit '10001101000 is decimal 1128', ->
    expect(1128).toEqual new Binary('10001101000').toDecimal()

  xit 'carrot is decimal 0', ->
    expect(0).toEqual new Binary('carrot').toDecimal()

Binary = require('./binary');

describe 'binary', ->

  it '1 is decimal 1', ->
    expect(1).toEqual new Binary('1').toDecimal()

  xit '10 is decimal 2', ->
    expect(2).toEqual new Binary('10').toDecimal()

  xit '11 is decimal 3', ->
    expect(3).toEqual new Binary('11').toDecimal()

  xit '100 is decimal 4', ->
    expect(4).toEqual new Binary('100').toDecimal()

  xit '1001 is decimal 9', ->
    expect(9).toEqual new Binary('1001').toDecimal()

  xit '11010 is decimal 26', ->
    expect(26).toEqual new Binary('11010').toDecimal()

  xit '10001101000 is decimal 1128', ->
    expect(1128).toEqual new Binary('10001101000').toDecimal()

  xit 'carrot is decimal 0', ->
    expect(0).toEqual new Binary('carrot').toDecimal()

Fix require in binary test for coffeescript


Template.incidentTable.events
  'mouseover .incident-table tbody tr': (event, instance) ->
    if not instance.data.scrollToAnnotations
      return
    $annotation = $("span[data-incident-id=#{@_id}]")
    $("span[data-incident-id]").removeClass('viewing')
    appHeaderHeight = $('header nav.navbar').outerHeight()
    detailsHeaderHeight = $('.curator-source-details-header').outerHeight()
    headerOffset = appHeaderHeight + detailsHeaderHeight
    containerScrollTop = $('.curator-source-details-copy').scrollTop()
    annotationTopOffset = $annotation.offset().top
    countainerVerticalMidpoint = $('.curator-source-details-copy').height() / 2
    totalOffset = annotationTopOffset - headerOffset
    # Distance of scroll based on postition of text container, scroll position
    # within the text container and the container's midpoint (to position the
    # annotation in the center of the container)
    scrollDistance =  totalOffset + containerScrollTop - countainerVerticalMidpoint
    $('.curator-source-details-copy').stop().animate
      scrollTop: scrollDistance
    , 500, -> $annotation.addClass('viewing')

SCROLL_WAIT_TIME = 500

Template.incidentTable.onCreated ->
  @scrollToAnnotation = (id) =>
    intervalTime = 0
    @interval = setInterval =>
      if intervalTime >= SCROLL_WAIT_TIME
        @stopScrollingInterval()
        $annotation = $("span[data-incident-id=#{id}]")
        $("span[data-incident-id]").removeClass('viewing')
        appHeaderHeight = $('header nav.navbar').outerHeight()
        detailsHeaderHeight = $('.curator-source-details--header').outerHeight()
        headerOffset = appHeaderHeight + detailsHeaderHeight
        containerScrollTop = $('.curator-source-details--copy').scrollTop()
        annotationTopOffset = $annotation.offset().top
        countainerVerticalMidpoint = $('.curator-source-details--copy').height() / 2
        totalOffset = annotationTopOffset - headerOffset
        # Distance of scroll based on postition of text container, scroll position
        # within the text container and the container's midpoint (to position the
        # annotation in the center of the container)
        scrollDistance =  totalOffset + containerScrollTop - countainerVerticalMidpoint
        $('.curator-source-details--copy').stop().animate
          scrollTop: scrollDistance
        , 500, -> $annotation.addClass('viewing')
      intervalTime += 100
    , 100

  @stopScrollingInterval = ->
    clearInterval(@interval)

Template.incidentTable.events
  'mouseover .incident-table tbody tr': (event, instance) ->
    if not instance.data.scrollToAnnotations
      return
    instance.scrollToAnnotation(@_id)

  'mouseout .incident-table tbody tr': (event, instance) ->
    if not instance.data.scrollToAnnotations
      return
    instance.stopScrollingInterval()

Add wait time for scrolling to annotations on hover


_ = require 'lodash'
typeOf = require 'type-of'

err = require './errors'
{ availableKeys, availableFormats } = require './api_config'

RealtimeInformation    = require './services/realtime'
LocationLookup         = require './services/location'
TripPlanner            = require './services/trip'
TrafficSituation       = require './services/traffic'
DisturbanceInformation = require './services/disturbance'

checkIfKeyIsSupplied = (keys) ->
  throw new err.NoKeySuppliedError unless keys?

checkIfKeyIsObject = (keys) ->
  type = typeOf keys
  unless type is 'object' then throw new err.InvalidKeyFormatSupplied type

checkKeyNames = (keys) ->
  for key, val of keys
    if key not in availableKeys
      throw new err.InvalidKeyNameSuppliedError key

checkSuppliedFormat = (format) ->
  if format and format.toUpperCase() not in availableFormats
    throw new err.InvalidResponseFormatSuppliedError format

class SL
  constructor: (@keys, @format) ->
    checkIfKeyIsSupplied @keys
    checkIfKeyIsObject @keys
    checkKeyNames @keys
    checkSuppliedFormat @format
    @createServices()

  createServices: ->
    @realtimeInformation = new RealtimeInformation @
    @locationLookup = new LocationLookup @
    @disturbanceInformation = new DisturbanceInformation @
    @trafficSituation = new TrafficSituation @
    @tripPlanner = new TripPlanner @

module.exports = SL

_ = require 'lodash'
typeOf = require 'type-of'

err = require './errors'
{ availableKeys, availableFormats } = require './api_config'

RealtimeInformation    = require './services/realtime'
LocationLookup         = require './services/location'
TripPlanner            = require './services/trip'
TrafficSituation       = require './services/traffic'
DisturbanceInformation = require './services/disturbance'

checkIfKeyIsSupplied = (keys) ->
  throw new err.NoKeySuppliedError unless keys?

checkIfKeyIsObject = (keys) ->
  type = typeOf keys
  unless type is 'object' then throw new err.InvalidKeyFormatSupplied type

checkKeyNames = (keys) ->
  for key, val of keys
    if key not in availableKeys
      throw new err.InvalidKeyNameSuppliedError key

checkSuppliedFormat = (format) ->
  if format
    if not _(format).isString() or format.toUpperCase() not in availableFormats
      throw new err.InvalidResponseFormatSuppliedError format

class SL
  constructor: (@keys, @format) ->
    checkIfKeyIsSupplied @keys
    checkIfKeyIsObject @keys
    checkKeyNames @keys
    checkSuppliedFormat @format
    @createServices()

  createServices: ->
    @realtimeInformation = new RealtimeInformation @
    @locationLookup = new LocationLookup @
    @disturbanceInformation = new DisturbanceInformation @
    @trafficSituation = new TrafficSituation @
    @tripPlanner = new TripPlanner @

module.exports = SL

Throw error if format option is not string

Throws InvalidResponseFormatSuppliedError if the supplied format option
is not a string of either 'json' or 'xml'


# react-controllables
# ===================

invariant = require 'react/lib/invariant'

getControllableValue = (name, state, props) -> props[name] ? state[name]
capFirst = (str) -> "#{ str[...1].toUpperCase() }#{ str[1...] }"
callbackName = (prop) -> "on#{ capFirst prop }Change"

ControllablesMixin =
  getInitialState: ->
    invariant(
      !!@controllables,
      'Components that use ControllablesMixin must define a controllables array'
    )
    state = {}
    for name in @controllables
      defaultValue = @props["default#{ capFirst name }"]
      if defaultValue? then state[name] = defaultValue
    state
  getControllableValue: (name) -> getControllableValue name, @state, @props
  componentDidUpdate: (prevProps, prevState) ->
    for name in @controllables
      invariant(
        not @props[callbackName name]? or not @props[name]?,
        "It doesn't make sense to add change callbacks for controlled properties. Either remove the callback or let it manage its own state. (#{ name })"
      )
      newValue = @state[name]
      oldValue = getControllableValue name, prevState, prevProps
      if newValue isnt oldValue
        @props[callbackName name]? newValue, oldValue
    return

module.exports = ControllablesMixin

# react-controllables
# ===================

invariant = require 'react/lib/invariant'

getControllableValue = (name, state, props) -> props[name] ? state[name]
capFirst = (str) -> "#{ str[...1].toUpperCase() }#{ str[1...] }"
callbackName = (prop) -> "on#{ capFirst prop }Change"

ControllablesMixin =
  getInitialState: ->
    invariant(
      !!@controllables,
      'Components that use ControllablesMixin must define a controllables array'
    )
    state = {}
    for name in @controllables
      defaultValue = @props["default#{ capFirst name }"]
      if defaultValue? then state[name] = defaultValue
    state
  getControllableValue: (name) -> getControllableValue name, @state, @props
  componentDidUpdate: (prevProps, prevState) ->
    for name in @controllables
      newValue = @state[name]
      oldValue = getControllableValue name, prevState, prevProps
      if newValue isnt oldValue
        @props[callbackName name]? newValue, oldValue
    return

module.exports = ControllablesMixin

Remove invariant check for callbacks on controlled components

I don’t remember why I added this. React’s form components don’t do
this /:


class @WalletSendPreparingDialogViewController extends @DialogViewController

  view:
    spinnerContainer: '#spinner_container'

  onAfterRender: ->
    super
    @view.spinner = ledger.spinners.createLargeSpinner(@view.spinnerContainer[0])
    account = Account.find(index: 0).first()

    # fetch amount
    ledger.wallet.transaction.createAndPrepareTransaction @params.amount, 10000, @params.address, account, account, (transaction, error) =>
      return if not @isShown()
      @once 'dismiss', =>
        if error?
          reason = switch error.code
            when ledger.errors.NetworkError then 'network_no_response'
            when ledger.errors.NotEnoughFunds then 'unsufficient_balance'
          dialog = new WalletSendErrorDialogViewController reason: reason
          dialog.show()
        else
          dialog = new WalletSendValidationDialogViewController transaction: transaction
          dialog.show()
      @dismiss()

class @WalletSendPreparingDialogViewController extends @DialogViewController

  view:
    spinnerContainer: '#spinner_container'

  onAfterRender: ->
    super
    @view.spinner = ledger.spinners.createLargeSpinner(@view.spinnerContainer[0])
    account = Account.find(index: 0).first()

    # fetch amount
    ledger.wallet.transaction.createAndPrepareTransaction @params.amount, 10000, @params.address, account, account, (transaction, error) =>
      return if not @isShown()
      if error?
        reason = switch error.code
          when ledger.errors.NetworkError then 'network_no_response'
          when ledger.errors.NotEnoughFunds then 'unsufficient_balance'
        @once 'dismiss', =>
          dialog = new WalletSendErrorDialogViewController reason: reason
          dialog.show()
        @dismiss()
      else
        invertModes = _.invert(ledger.wallet.transaction.Transaction.ValidationModes)
        l "[PreparingTxDialog]", invertModes[transaction.getValidationMode()], transaction
        switch transaction.getValidationMode()
          when ledger.wallet.transaction.Transaction.ValidationModes.KEYCARD
            @once 'dismiss', =>
              dialog = new WalletSendValidationDialogViewController transaction: transaction
              dialog.show()
            @dismiss()
          when ledger.wallet.transaction.Transaction.ValidationModes.SECURE_SCREEN
            l "%c[M2FA] Secure screen dialog in preparation", "#888888"
            @_requestValidation(transaction)

  _requestValidation: (tx) ->
    ledger.m2fa.validateTxOnAll(tx).fail( (error) =>
      # return if not @isShown()
      @once 'dismiss', =>
        dialog = new WalletSendErrorDialogViewController(reason: error)
        dialog.show()
      @dismiss()
    ).then( () =>
      # return if not @isShown()
      @once 'dismiss', =>
        dialog = new WalletSendSuccessDialogViewController()
        dialog.show()
      @dismiss()
    ).done()

Modify dialogs when waiting for secure screen validation


Helpers = require '../lib/helpers'

describe "The Results Validation Helper", ->
  it "should throw an exception when nothing is passed.", ->
    expect( -> Helpers.validateResults()).toThrow()
  it "should throw an exception when a String is passed.", ->
    expect( -> Helpers.validateResults('String')).toThrow()

describe "The Linter Validation Helper", ->
  it "should throw an exception when nothing is passed.", ->
    expect( -> Helpers.validateLinter()).toThrow()
  it "should throw an exception when a String is passed.", ->
    expect( -> Helpers.validateLinter('String')).toThrow()

Add the same test for Linter validation.


Grim = require 'grim'
if Grim.includeDeprecations
  module.exports = require('theorist').Model
  return

PropertyAccessors = require 'property-accessors'

nextInstanceId = 1

module.exports =
class Model
  PropertyAccessors.includeInto(this)

  @resetNextInstanceId: -> nextInstanceId = 1

  constructor: (params) ->
    @assignId(params?.id)

  assignId: (id) ->
    @id ?= id ? nextInstanceId++

  @::advisedAccessor 'id',
    set: (id) -> nextInstanceId = id + 1 if id >= nextInstanceId

  destroy: ->
    return unless @isAlive()
    @alive = false
    @destroyed?()

  isAlive: -> @alive

  isDestroyed: -> not @isAlive()

Grim = require 'grim'
if Grim.includeDeprecations
  module.exports = require('theorist').Model
  return

PropertyAccessors = require 'property-accessors'

nextInstanceId = 1

module.exports =
class Model
  PropertyAccessors.includeInto(this)

  @resetNextInstanceId: -> nextInstanceId = 1

  alive: true

  constructor: (params) ->
    @assignId(params?.id)

  assignId: (id) ->
    @id ?= id ? nextInstanceId++

  @::advisedAccessor 'id',
    set: (id) -> nextInstanceId = id + 1 if id >= nextInstanceId

  destroy: ->
    return unless @isAlive()
    @alive = false
    @destroyed?()

  isAlive: -> @alive

  isDestroyed: -> not @isAlive()

Add alive ivar to light Model

Add alive ivar to light Model


SpellChecker = require 'spellchecker'

wordRegex = /(?:^|[\s\[\]"'])([a-zA-Z]+([a-zA-Z']+[a-zA-Z])?)(?=[\s\.\[\]:,"']|$)/g

module.exports = ({id, text}) ->
  row = 0
  misspellings = []
  for line in text.split('\n')
    while matches = wordRegex.exec(line)
      word = matches[1]
      continue if word in ['GitHub', 'github']
      continue unless SpellChecker.isMisspelled(word)

      startColumn = matches.index + matches[0].length - word.length
      endColumn = startColumn + word.length
      misspellings.push([[row, startColumn], [row, endColumn]])
    row++
  {id, misspellings}

SpellChecker = require 'spellchecker'

module.exports = ({id, text}) ->
  misspelledCharacterRanges = SpellChecker.checkSpelling(text)

  row = 0
  rangeIndex = 0
  characterIndex = 0
  misspellings = []
  while characterIndex < text.length and rangeIndex < misspelledCharacterRanges.length
    lineBreakIndex = text.indexOf('\n', characterIndex)
    if lineBreakIndex is -1
      lineBreakIndex = Infinity

    loop
      range = misspelledCharacterRanges[rangeIndex]
      if range and range.start < lineBreakIndex
        misspellings.push([
          [row, range.start - characterIndex],
          [row, range.end - characterIndex]
        ])
        rangeIndex++
      else
        break

    characterIndex = lineBreakIndex + 1
    row++

  {id, misspellings}

Use new bulk spell-checking method in task handler


# a number of jasmine-jquery helpers / extensions
# it totally used to do this natively, but now doesn't...

jasmine.getFixtures().findContainer = ->
  $(document.body).find("##{@containerId}")

jasmine.getFixtures().getContainer = ->
  cont = @findContainer()
  if cont.length == 0
    @createContainer_("")
    cont = @findContainer()
  cont

window.f = (html="")->
  cont = jasmine.getFixtures().getContainer();
  if html.length > 0
    cont.html(html)
  cont

#beforeEach ->
#  @addMatchers(
#    toInclude: (value)->
#      _(@).find((it)-> it == value)
#  )

# a number of jasmine-jquery helpers / extensions
# it totally used to do this natively, but now doesn't...

jasmine.getFixtures().findContainer = ->
  $(document.body).find("##{@containerId}")

jasmine.getFixtures().getContainer = ->
  cont = @findContainer()
  if cont.length == 0
    @createContainer_("")
    cont = @findContainer()
  cont

window.f = (html="")->
  cont = jasmine.getFixtures().getContainer();
  if html.length > 0
    cont.html(html)
  cont

beforeEach ->
  @addMatchers(
    toBeInstanceOf: (type)->
      @message = ->
        "Expected #{@actual} to be an instance of #{type.name}"
      @actual instanceof type
    toBeEqualTo: (other)->
      @message = ->
        "Expected #{@actual}.isEqual(#{type}) to be true"
      @actual.isEqual(other)
  )

Refactor of most of the math library pulling components out


module.exports =

  config:
    undefinedDisplay:
      type: 'string'
      default: ''

  activate: (state) ->
    atom.workspaceView.command 'table-edit:demo', => @openDemo()
    @openDemo()

  deactivate: ->

  serialize: ->

  openDemo: ->
    Table = require './table'
    TableView = require './table-view'

    table = new Table
    table.addColumn 'key'
    table.addColumn 'value', align: 'right'
    table.addColumn 'foo', align: 'right'

    for i in [0...100]
      table.addRow [
        "row#{i}"
        i * 100
        if i % 2 is 0 then 'yes' else 'no'
      ]

    tableView = new TableView(table)
    tableView.setRowHeight 30
    tableView.setRowOverdraw 4

    tableView.addClass('demo overlay from-top').height(300)
    atom.workspaceView.append(tableView)

    tableView.on 'core:cancel', -> tableView.destroy()

    tableView.focus()

module.exports =

  config:
    undefinedDisplay:
      type: 'string'
      default: ''

  activate: (state) ->
    atom.workspaceView.command 'table-edit:demo', => @openDemo()
    @openDemo()

  deactivate: ->

  serialize: ->

  openDemo: ->
    Table = require './table'
    TableView = require './table-view'

    table = new Table
    table.addColumn 'key'
    table.addColumn 'value', align: 'right'
    table.addColumn 'foo', align: 'right'

    for i in [0...100]
      table.addRow [
        "row#{i}"
        i * 100
        if i % 2 is 0 then 'yes' else 'no'
      ]

    table.clearUndoStack()

    tableView = new TableView(table)
    tableView.setRowHeight 30
    tableView.setRowOverdraw 4

    tableView.addClass('demo overlay from-top').height(300)
    atom.workspaceView.append(tableView)

    tableView.on 'core:cancel', -> tableView.destroy()

    tableView.focus()

Clear undo stack of the demo after creation


define (require) ->
  settings = require('settings')
  FooterTabView = require('cs!../inherits/tab/tab')
  template = require('hbs!./metadata-template')
  require('less!./metadata')

  return class MetadataView extends FooterTabView
    template: template
    templateHelpers: () ->
      model = super()
      model.languages = settings.languages
      model.languageName = settings.languages[model.language]
      return model

    editable:
      '.js-metadata-language-select':
        value: () -> if @media is 'book' then return 'language' else return 'currentPage.language'
        type: 'select2'
        select2:
          width: 300

    initialize: () ->
      super()
      @listenTo(@model, 'change:editable', @render)

define (require) ->
  settings = require('settings')
  FooterTabView = require('cs!../inherits/tab/tab')
  template = require('hbs!./metadata-template')
  require('less!./metadata')

  return class MetadataView extends FooterTabView
    template: template
    templateHelpers: () ->
      model = super()
      model.languages = settings.languages
      model.languageName = settings.languages[model.language]
      return model

    editable:
      '.metadata-language-select':
        value: () -> if @media is 'book' then return 'language' else return 'currentPage.language'
        type: 'select2'
        select2:
          width: 300

    initialize: () ->
      super()
      @listenTo(@model, 'change:editable', @render)

Update language select class name

Update language select class name


{Range} = require 'atom'
_ = require 'underscore-plus'
fs = require 'fs-plus'

module.exports =
class GocovParser
  constructor: (dispatch) ->
    @dispatch = dispatch

  setDataFile: (file) ->
    @dataFile = file

  # TODO disgusting - fix this parsing, regex
  rangesForFile: (file) ->
    # TODO Ensure we have a data file and it exists
    data = fs.readFileSync @dataFile, {encoding: "utf8"}

    ranges = []

    for line in data.split("\n")
      line = line.trim()
      continue if line == "mode: set" || line == ""
      [fileLinesCols, statements, count] = line.split(" ")
      [filePath, linesCols] = fileLinesCols.split(":")
      if _.endsWith(file, filePath)
        [start, end] = linesCols.split(",")
        [startRow, startCol] = start.split(".")
        [endRow, endCol] = end.split(".")

        range = new Range([parseInt(startRow)-1, parseInt(startCol)-1], [parseInt(endRow)-1, parseInt(endCol)-1])
        ranges.push range: range, count: parseInt(count)

    ranges

{Range} = require 'atom'
_ = require 'underscore-plus'
fs = require 'fs-plus'

module.exports =
class GocovParser
  constructor: (dispatch) ->
    @dispatch = dispatch

  setDataFile: (file) ->
    @dataFile = file

  # TODO disgusting - fix this parsing, regex
  rangesForFile: (file) ->
    try
      data = fs.readFileSync @dataFile, {encoding: "utf8"}
    catch error
      return []

    ranges = []

    for line in data.split("\n")
      line = line.trim()
      continue if line == "mode: set" || line == ""
      [fileLinesCols, statements, count] = line.split(" ")
      [filePath, linesCols] = fileLinesCols.split(":")
      if _.endsWith(file, filePath)
        [start, end] = linesCols.split(",")
        [startRow, startCol] = start.split(".")
        [endRow, endCol] = end.split(".")

        range = new Range([parseInt(startRow)-1, parseInt(startCol)-1], [parseInt(endRow)-1, parseInt(endCol)-1])
        ranges.push range: range, count: parseInt(count)

    ranges

Handle the error when the coverage report is not generated


express = require 'express'
passport = require 'passport'
_ = require 'underscore'
authentication = require './authentication'
info = require './package'
http = require 'http'

require 'express-namespace'

users = require './routes/users'
projects = require './routes/projects'
time_entries = require './routes/time_entries'
not_found_handler = require './not_found_handler'

done = null

#setup authentication
auth_strategy_name = authentication passport

app = express()

app.use express.logger() if not process.env.TESTING
app.use express.bodyParser()
app.use '/api', passport.authenticate(auth_strategy_name, session: no)

app.get '/', (req, res)-> res.send version:info.version

_.each [users, projects, time_entries], (s) ->
  app.namespace '/api', ->
    s app

app.use app.router
app.use not_found_handler

port = process.env.PORT || 3000

server = http.createServer app

server.listen port, ->
  console.log "Listening on #{port}"
  done() if done?

module.exports = (ready) -> done = ready

express = require 'express'
passport = require 'passport'
_ = require 'underscore'
authentication = require './authentication'
info = require './package'
http = require 'http'

require 'express-namespace'

users = require './routes/users'
projects = require './routes/projects'
time_entries = require './routes/time_entries'
not_found_handler = require './not_found_handler'

done = null

#setup authentication
auth_strategy_name = authentication passport

app = express()

app.use express.logger() if not process.env.TESTING
app.use express.bodyParser()
#app.use '/api', passport.authenticate(auth_strategy_name, session: no)

app.get '/', (req, res)-> res.send version:info.version

_.each [users, projects, time_entries], (s) ->
  app.namespace '/api', ->
    s app

app.use app.router
app.use not_found_handler

port = process.env.PORT || 3000

server = http.createServer app

server.listen port, ->
  console.log "Listening on #{port}"
  done() if done?

module.exports = (ready) -> done = ready

Disable hawk auth for now

Disable hawk auth for now


class AsciiIo.Brush
  @cache: {}

  @clearCache: ->
    @cache = {}

  @hash: (brush) ->
    "#{brush.fg}_#{brush.bg}_#{brush.bright}_#{brush.underline}_#{brush.italic}_#{brush.blink}"

  @create: (options = {}) ->
    key = @hash(options)
    brush = @cache[key]

    if not brush
      brush = new AsciiIo.Brush(options)
      @cache[key] = brush

    brush

  @normal: ->
    @_normal ||= @create()

  constructor: (options) ->
    @fg        = options.fg
    @bg        = options.bg
    @blink     = options.blink
    @bright    = options.bright
    @italic    = options.italic
    @underline = options.underline

  hash: ->
    AsciiIo.Brush.hash(this)

  fgColor: ->
    color = @fg || 7
    color += 8 if color < 8 and @bright
    color

  bgColor: ->
    color = @bg || 0
    color += 8 if color < 8 and @blink
    color

class AsciiIo.Brush
  @cache: {}

  @clearCache: ->
    @cache = {}

  @hash: (brush) ->
    "#{brush.fg}_#{brush.bg}_#{brush.bright}_#{brush.underline}_#{brush.italic}_#{brush.blink}"

  @create: (options = {}) ->
    key = @hash(options)
    brush = @cache[key]

    if not brush
      brush = new AsciiIo.Brush(options)
      @cache[key] = brush

    brush

  @normal: ->
    @_normal ||= @create()

  constructor: (options) ->
    @fg        = options.fg
    @bg        = options.bg
    @blink     = options.blink
    @bright    = options.bright
    @italic    = options.italic
    @underline = options.underline

  hash: ->
    AsciiIo.Brush.hash(this)

  fgColor: ->
    color = @fg || 0
    color += 8 if color < 8 and @bright
    color

  bgColor: ->
    color = @bg || 0
    color += 8 if color < 8 and @blink
    color

Use color 0 as default fg color

Use color 0 as default fg color


@app.factory 'fileUpload', [
  '$q', '$rootScope', '$http', 'formData',
  ($q,   $rootScope,   $http,   formData) ->

    fileUpload = (options) ->
      xhr = null
      deferred = $q.defer()

      lastProgressApply = 0
      progressHandler = (event) ->
        return unless event.lengthComputable
        now = Date.now()
        return if now - lastProgressApply < 500
        lastProgressApply = now
        $rootScope.$applyAsync -> deferred.notify(loaded: event.loaded, total: event.total)

      $q.when($.ajax
        url: options.url
        type: options.type || 'POST'
        data: options.data
        headers: _.pick($http.defaults.headers.common, [ 'X-CSRF-Token', 'X-Call-Token' ])
        cache: false
        xhr: ->
          xhr = $.ajaxSettings.xhr()
          xhr.upload?.addEventListener('progress', progressHandler, false)
          xhr
        xhrFields:
          withCredentials: true
        contentType: false
        processData: false
      ).then(
        deferred.resolve,
        ((xhr) ->
          # transform $.ajax error response to something more like what $http would return
          deferred.reject
            status: xhr.status
            statusText: xhr.statusText
            data: xhr.responseJSON
        )
      )

      deferred.promise.abort = ->
        xhr.upload?.removeEventListener('progress', progressHandler) # prevents double $apply error
        xhr.abort()
        null

      deferred.promise

    fileUpload.extendResource = (resourceCls, options) ->
      methodName = "upload#{options.field.camelize()}"

      resourceCls::[methodName] = (fileOrBlob, fileName, params = {}) ->
        fileUpload(
          url: @url()
          type: 'PUT'
          data: formData().add(params).add(options.field, fileOrBlob, fileName).build()
        ).then((data) =>
          angular.extend @, data
        )

      resourceCls[methodName] = (fileOrBlob, fileName, params) ->
        params = angular.copy params

        fileUpload(
          url: (new resourceCls(params)).url()
          data: formData().add(params).add(options.field, fileOrBlob, fileName).build()
        ).then((data) ->
          new resourceCls data
        )

    fileUpload
]

@app.factory 'fileUpload', [
  '$q', '$rootScope', '$http', 'formData',
  ($q,   $rootScope,   $http,   formData) ->

    (options) ->
      deferred = $q.defer()
      timeout = $q.defer()

      options.method ?= options.type ? 'POST'
      options.data = formData.build(options.data)
      options.headers ?= {}
      options.headers['Content-Type'] = undefined # browser auto-fills with correct type and boundary
      options.withCredentials = true
      options.uploadEventHandlers =
        progress: (e) ->
          deferred.notify(loaded: e.loaded, total: e.total) if e.lengthComputable
      options.timeout = timeout.promise

      $http(options).then(
        ((response) -> deferred.resolve(response.data)),
        deferred.reject,
        deferred.notify)

      deferred.promise.abort = timeout.resolve
      deferred.promise
]

Use $http for file upload

Use $http for file upload


validator = require "./validator"

module.exports = HtmlValidation =
    config:
        validateOnSave:
            type: "boolean"
            default: no
            title: "Validate on save"
            description: "Make a validation each time you save an HTML file."
        validateOnChange:
            type: "boolean"
            default: no
            title: "Validate on change"
            description: "Make a validation each time you change an HTML file."
        hideOnNoErrors:
            type: "boolean"
            default: no
            title: "Hide on no errors"
            description: "Hide the panel if there was no errors."
        useFoldModeAsDefault:
            type: "boolean"
            default: no
            title: "Use fold mode as default"
            description: "Fold the panel by default."

    activate: ->
        atom.commands.add "atom-text-editor", "html-validation:validate": validator

        atom.config.observe "html-validation.validateOnSave", ( bValue ) ->
            atom.workspace.eachEditor ( oEditor ) ->
                oEditor.buffer[ if bValue then "on" else "off" ] "saved", validator

        atom.config.observe "html-validation.validateOnChange", ( bValue ) ->
            atom.workspace.eachEditor ( oEditor ) ->
                oEditor.buffer[ if bValue then "on" else "off" ] "contents-modified", validator

validator = require "./validator"

module.exports = HtmlValidation =
    config:
        validateOnSave:
            type: "boolean"
            default: yes
            title: "Validate on save"
            description: "Make a validation each time you save an HTML file."
        validateOnChange:
            type: "boolean"
            default: no
            title: "Validate on change"
            description: "Make a validation each time you change an HTML file."
        hideOnNoErrors:
            type: "boolean"
            default: no
            title: "Hide on no errors"
            description: "Hide the panel if there was no errors."
        useFoldModeAsDefault:
            type: "boolean"
            default: no
            title: "Use fold mode as default"
            description: "Fold the panel by default."

    activate: ->
        atom.commands.add "atom-text-editor", "html-validation:validate": validator

        atom.config.observe "html-validation.validateOnSave", ( bValue ) ->
            atom.workspace.eachEditor ( oEditor ) ->
                oEditor.buffer[ if bValue then "on" else "off" ] "saved", validator

        atom.config.observe "html-validation.validateOnChange", ( bValue ) ->
            atom.workspace.eachEditor ( oEditor ) ->
                oEditor.buffer[ if bValue then "on" else "off" ] "contents-modified", validator

Change default value for validateOnSave

Change default value for validateOnSave


_ = require 'underscore'
__ = require 'highland'
fs = require 'fs'
csv = require 'csv'
transform = require 'stream-transform'
ImportMapping = require './importmapping'
Streaming = require '../streaming'
Promise = require 'bluebird'

class Importer

  constructor: (@logger, options = {}) ->
    @streaming = new Streaming @logger, options

  run: (fileName) ->
    rowCount = 2
    new Promise (resolve, reject) =>
      input = fs.createReadStream fileName
      input.on 'error', (error) ->
        reject error

      parser = csv.parse
        delimiter: ','
        columns: (rawHeader) =>
          @mapping = new ImportMapping rawHeader
          errors = @mapping.validate()
          throw { errors } if _.size errors
          rawHeader
      parser.on 'error', (error) ->
        reject error
      parser.on 'finish', ->
        resolve 'Import done.'

      transformer = transform (row, callback) =>
        category = @createCategory row
        callback null, category
      , {parallel: 10}

      __(input).pipe(parser).pipe(transformer).pipe(
        transform (chunk, cb) =>
          console.log "Process row: " + rowCount
          @logger.debug 'chunk: ', chunk, {}
          @streaming.processStream [ chunk ], cb # TODO: better passing of chunk
          rowCount++
        , {parallel: 1})

      console.log @streaming.summaryReport

  createCategory: (row) ->
    @logger.debug 'create JSON category for row: ', row
    json = @mapping.toJSON row
    @logger.debug 'generated JSON category: ', json
    json

module.exports = Importer

_ = require 'underscore'
__ = require 'highland'
fs = require 'fs'
csv = require 'csv'
transform = require 'stream-transform'
ImportMapping = require './importmapping'
Streaming = require '../streaming'
Promise = require 'bluebird'

class Importer

  constructor: (@logger, options = {}) ->
    @streaming = new Streaming @logger, options

  run: (fileName) ->
    rowCount = 2
    new Promise (resolve, reject) =>
      input = fs.createReadStream fileName
      input.on 'error', (error) ->
        reject error

      parser = csv.parse
        delimiter: ','
        columns: (rawHeader) =>
          @mapping = new ImportMapping rawHeader
          errors = @mapping.validate()
          throw { errors } if _.size errors
          rawHeader
      parser.on 'error', (error) ->
        reject error
      parser.on 'finish', ->
        resolve 'Import done.'

      transformer = transform (row, callback) =>
        category = @createCategory row
        callback null, category
      , {parallel: 10}

      __(input).pipe(parser).pipe(transformer).pipe(
        transform (chunk, cb) =>
          chunkSize = 1
          console.log "Process row: " + rowCount
          @logger.debug 'chunk: ', chunk, {}
          @streaming.processStream [ chunk ], cb # TODO: better passing of chunk
          rowCount = rowCount + chunkSize
        , {parallel: chunkSize})

      console.log @streaming.summaryReport

  createCategory: (row) ->
    @logger.debug 'create JSON category for row: ', row
    json = @mapping.toJSON row
    @logger.debug 'generated JSON category: ', json
    json

module.exports = Importer

Adjust row counter to also work with bigger chunks.


{CompositeDisposable} = require 'atom'

module.exports =
  config:
    executablePath:
      type: 'string'
      title: 'PHP Executable Path'
      default: 'php' # Let OS's $PATH handle the rest

  activate: ->
    @subscriptions = new CompositeDisposable
    @subscriptions.add atom.config.observe 'linter-php.executablePath',
      (executablePath) =>
        @executablePath = executablePath

  deactivate: ->
    @subscriptions.dispose()

  provideLinter: ->
    helpers = require('atom-linter')
    provider =
      grammarScopes: ['text.html.php', 'source.php']
      scope: 'file'
      lintOnFly: true
      lint: (textEditor) =>
        filePath = textEditor.getPath()
        command = @executablePath
        parameters = []
        parameters.push('--syntax-check')
        parameters.push('--no-php-ini')
        parameters.push('--define', 'display_errors=On')
        parameters.push('--define', 'log_errors=Off')
        text = textEditor.getText()
        return helpers.exec(command, parameters, {stdin: text}).then (output) ->
          regex = /error:\s+(.*?) on line (\d+)/g
          messages = []
          while((match = regex.exec(output)) isnt null)
            messages.push
              type: "Error"
              filePath: filePath
              range: [[match[2] - 1 , 1], [match[2] - 1, 2]]
              text: match[1]
          return messages

{CompositeDisposable} = require 'atom'

module.exports =
  config:
    executablePath:
      type: 'string'
      title: 'PHP Executable Path'
      default: 'php' # Let OS's $PATH handle the rest

  activate: ->
    @subscriptions = new CompositeDisposable
    @subscriptions.add atom.config.observe 'linter-php.executablePath',
      (executablePath) =>
        @executablePath = executablePath

  deactivate: ->
    @subscriptions.dispose()

  provideLinter: ->
    helpers = require('atom-linter')
    provider =
      grammarScopes: ['text.html.php', 'source.php']
      scope: 'file'
      lintOnFly: true
      lint: (textEditor) =>
        filePath = textEditor.getPath()
        command = @executablePath
        parameters = []
        parameters.push('--syntax-check')
        parameters.push('--no-php-ini')
        parameters.push('--define', 'display_errors=On')
        parameters.push('--define', 'log_errors=Off')
        text = textEditor.getText()
        return helpers.exec(command, parameters, {stdin: text}).then (output) ->
          regex = /error:\s+(.*?) on line (\d+)/g
          messages = []
          while((match = regex.exec(output)) isnt null)
            messages.push
              type: "Error"
              filePath: filePath
              range: helpers.rangeFromLineNumber(textEditor, match[2] - 1)
              text: match[1]
          return messages

:new: Use new helper method for generating range


class ProductComponent
	bindProductEvent: (name, handler, productIdIndex = 0) =>
		$(window).on name, (evt, args...) =>
			return unless @productId is args[productIdIndex]
			handler(evt, args...)

root = window || exports
root.ProductComponent = ProductComponent

class ProductComponent
	bindProductEvent: (name, handler, productIdIndex = 0) =>
		$(window).on name, (evt, args...) =>
			return unless @productId is args[productIdIndex]
			handler(evt, args...)

	generateSelectors: (selectors) =>
		for k, v of selectors
			@["find#{k}"] = do(v) => => @element.find(v)
			@["show#{k}"] = do(k) => => @["find#{k}"]().show()
			@["hide#{k}"] = do(k) => => @["find#{k}"]().hide()

root = window || exports
root.ProductComponent = ProductComponent

Add selector generation to Product Component


---
---

dl = require('datalib')
evalexpr = require('expr-eval')

{% include coffee/essential.coffee %}
{% include coffee/main.coffee %}
{% include coffee/vega_extra.coffee %}
{% include coffee/simulation.coffee %}
{% include coffee/uploads.coffee %}
{% include coffee/benchmark_table.coffee %}
{% include coffee/result_comparison.coffee %}
{% include coffee/test.coffee %}

---
---

# dl = require('datalib')
# evalexpr = require('expr-eval')

{% include coffee/essential.coffee %}
{% include coffee/main.coffee %}
{% include coffee/vega_extra.coffee %}
{% include coffee/simulation.coffee %}
{% include coffee/uploads.coffee %}
{% include coffee/benchmark_table.coffee %}
{% include coffee/result_comparison.coffee %}
{% include coffee/test.coffee %}

Comment imports for broken backend libs on Travis

Address #709

Libraries commented out are broken on Travis CI so can't use them


describe 'Pending', ->
    it 'Should test skipHeader option'
    it 'Should test initWith option'
    it 'Should embed plain JS files'
    it 'Should allow setting the source path'
    it 'Should allow setting the lib path'
    it 'Should allow setting the tmp path'
    it 'Should allow setting the out path'

Add three more pending tests.

Add three more pending tests.


editorModule "Installation process", template: "editor_html"

editorTest "element.editorController", ->
  ok getEditorController() instanceof Trix.EditorController

editorTest "creates a contenteditable element", ->
  ok getDocumentElement()

editorTest "loads the initial document", ->
  equal getDocumentElement().textContent, "Hello world"

editorTest "sets value attribute", (done) ->
  defer ->
    equal getEditorElement().getAttribute("value"), "
Hello world
"
    done()

editorModule "Installation process", template: "editor_json"

editorTest "loads the initial document from input with JSON", ->
  equal getDocumentElement().textContent, "Hello JSON"

Remove expected block comment from test

Remove expected block comment from test