jQuery.initializer '.edit_widget.map_search', ->
  oz = new OZ('oz_map_search')
  $form = $('form.widget_map_search')
  oz.api 'on_params_changed', (params) ->
    $('#widget_map_search_api_params').val(JSON.stringify(params))
    $.post $form.attr('action'), $form.serialize(), (data) ->
      $('textarea#snippet').val(data.snippet)
    , "json"

  this.on 'change', 'input[type="checkbox"], input[type="text"]', ->
    $form.submit()

jQuery.initializer '.edit_widget.direction', ->
  oz = new OZ('oz_direction')
  $form = $('form.widget_direction')
  oz.api 'on_params_changed', (params) ->
    $('#widget_direction_params').val(JSON.stringify(params))
    $.post $form.attr('action'), $form.serialize(), (data) ->
      $('textarea#snippet').val(data.snippet)
    , "json"

  this.on 'change', 'input[type="text"]', ->
    # TODO: use angular instead
    $this    = $(this)
    name     = $this.attr('name')
    value    = $this.val()
    $snippet = $('textarea#snippet')
    snippet  = $snippet.val()

    if name.match /width/
      $snippet.val(snippet.replace(/width='\d+'/, "width='#{value}'"))
    else if name.match /height/
      $snippet.val(snippet.replace(/height='\d+'/, "height='#{value}'"))

Update width/height in the snippet block if changed


{Disposable, CompositeDisposable} = require 'atom'

ViewURI = 'atom://deprecation-cop'
DeprecationCopView = null

module.exports =
  disposables: null

  activate: ->
    @disposables = new CompositeDisposable

    @disposables.add atom.workspace.addOpener (uri) =>
      @deserializeDeprecationCopView({uri}) if uri is ViewURI

    @disposables.add atom.commands.add 'atom-workspace', 'deprecation-cop:view', ->
      atom.workspace.open(ViewURI)

  deactivate: ->
    @disposables.dispose()
    if pane = atom.workspace.paneForURI(ViewURI)
      pane.destroyItem(pane.itemForURI(ViewURI))

  deserializeDeprecationCopView: (state) ->
    DeprecationCopView ?= require './deprecation-cop-view'
    new DeprecationCopView(state)

  consumeStatusBar: (statusBar) ->
    if atom.inDevMode()
      DeprecationCopStatusBarView = require './deprecation-cop-status-bar-view'
      statusBarView = new DeprecationCopStatusBarView()
      statusBarTile = statusBar.addRightTile(item: statusBarView, priority: 150)
      @disposables.add(new Disposable => statusBarView.destroy())
      @disposables.add(new Disposable => statusBarTile.destroy())

unless parseFloat(atom.getVersion()) >= 1.7
  atom.deserializers.add
    name: 'DeprecationCopView',
    deserialize: (state) -> module.exports.deserializeDeprecationCopView.bind(module.exports)

Add deserializers.add call for backwards compatibility


nconf = require("nconf")
nconf.env().argv()

# Add config file
nconf.file(file: nconf.get("config"))

Base = require('./src/base')
newsroom = new Base nconf.get("newsroom")

nconf = require("nconf")
nconf.env().argv()

# Add config file
nconf.file(file: nconf.get("config") || "config.json")

Base = require('./src/base')
newsroom = new Base nconf.get("newsroom")

Add config fallback for development

Add config fallback for development


_ = require 'lodash'
expect = chai.expect
React = require 'react/addons'
ReactTestUtils = React.addons.TestUtils
{Promise}      = require 'es6-promise'
{commonActions} = require './utilities'
sandbox = null

Wrapper = React.createClass

  render: ->
    React.createElement(@props._wrapped_component,
      _.extend(_.omit(@props, '_wrapped_component', 'children'), ref: 'element')
      @props.children
    )

Testing = {

  renderComponent: (component, options = {}) ->
    options.props ||= {}
    unmountAfter = options.unmountAfter or 1
    root = document.createElement('div')
    promise = new Promise( (resolve, reject) ->
      props = _.clone(options.props)
      props._wrapped_component = component
      wrapper = React.render( React.createElement(Wrapper, props), root )
      resolve({
        root,
        wrapper,
        element: wrapper.refs.element,
        dom: React.findDOMNode(wrapper.refs.element)
      })
    )
    # defer adding the then callback so it'll be called after whatever is attached after the return
    _.defer -> promise.then ->
      _.delay( ->
        React.unmountComponentAtNode(root)
      , unmountAfter )
      return arguments
    promise

  actions: commonActions

}

module.exports = {Testing, expect, sinon, React, _, ReactTestUtils}

_ = require 'underscore'
expect = chai.expect
React = require 'react/addons'
ReactTestUtils = React.addons.TestUtils
{Promise}      = require 'es6-promise'
{commonActions} = require './utilities'
sandbox = null

Wrapper = React.createClass

  render: ->
    React.createElement(@props._wrapped_component,
      _.extend(_.omit(@props, '_wrapped_component', 'children'), ref: 'element')
      @props.children
    )

Testing = {

  renderComponent: (component, options = {}) ->
    options.props ||= {}
    unmountAfter = options.unmountAfter or 1
    root = document.createElement('div')
    promise = new Promise( (resolve, reject) ->
      props = _.clone(options.props)
      props._wrapped_component = component
      wrapper = React.render( React.createElement(Wrapper, props), root )
      resolve({
        root,
        wrapper,
        element: wrapper.refs.element,
        dom: React.findDOMNode(wrapper.refs.element)
      })
    )
    # defer adding the then callback so it'll be called after whatever is attached after the return
    _.defer -> promise.then ->
      _.delay( ->
        React.unmountComponentAtNode(root)
      , unmountAfter )
      return arguments
    promise

  actions: commonActions

}

module.exports = {Testing, expect, sinon, React, _, ReactTestUtils}

Use underscore instead of lodash

Use underscore instead of lodash


define [
], () ->

	AUTOMATIC_REFRESH_PERIOD = 1000 * 60 * 10

	class LabelsManager
		constructor: (@ide, @$scope) ->
			@$scope.$root._labels = this

			@state =
				documents: {} # map of DocId => List[Label]

			@loadLabelsTimeout = null
			@periodicLoadInterval = null

			setTimeout(
				() =>
					# set up a regular re-load
					setTimeout(
						() =>
							@periodicLoadInterval = setInterval(
								() =>
									@loadLabelsFromOpenDoc()
								, AUTOMATIC_REFRESH_PERIOD
							)
						, AUTOMATIC_REFRESH_PERIOD
					)
					# listen for document open
					@$scope.$on 'document:opened', (e, doc) =>
						setTimeout(
							() =>
								@scheduleLoadLabelsFromOpenDoc()
							, 1000
						)
				, 0
			)

		loadLabelsFromOpenDoc: () ->
			docId = @ide.editorManager.getCurrentDocId()
			docText = @ide.editorManager.getCurrentDocValue()
			labels = []
			re = /\\label{(.*)}/g
			while labelMatch = re.exec(docText)
				if labelMatch[1]
					labels.push(labelMatch[1])
			@state.documents[docId] = labels

		scheduleLoadLabelsFromOpenDoc: () ->
			if @loadLabelsTimeout
				clearTimeout(@loadLabelsTimeout)
			@loadLabelsTimeout = setTimeout(
				() =>
					@loadLabelsFromOpenDoc()
				, 1000
				, this
			)

		getAllLabels: () ->
			_.flatten(labels for docId, labels of @state.documents)

define [
], () ->

	class LabelsManager
		constructor: (@ide, @$scope) ->
			@$scope.$root._labels = this

			@state =
				documents: {} # map of DocId => List[Label]

			@loadLabelsTimeout = null

			setTimeout(
				() =>
					# listen for document open
					@$scope.$on 'document:opened', (e, doc) =>
						setTimeout(
							() =>
								@scheduleLoadLabelsFromOpenDoc()
							, 0
						)
				, 0
			)

		loadLabelsFromOpenDoc: () ->
			docId = @ide.editorManager.getCurrentDocId()
			docText = @ide.editorManager.getCurrentDocValue()
			labels = []
			re = /\\label{(.*)}/g
			while labelMatch = re.exec(docText)
				if labelMatch[1]
					labels.push(labelMatch[1])
			@state.documents[docId] = labels

		scheduleLoadLabelsFromOpenDoc: () ->
			if @loadLabelsTimeout
				clearTimeout(@loadLabelsTimeout)
			@loadLabelsTimeout = setTimeout(
				() =>
					@loadLabelsFromOpenDoc()
				, 1000
				, this
			)

		getAllLabels: () ->
			_.flatten(labels for docId, labels of @state.documents)

Remove periodic polling of document for labels


CI.Browser or= {}

CI.Browser.scroll_to = (position) =>
  element = if jQuery.browser.webkit then "body" else "html"
  offset = if position == "top" then 0 else document.body.offsetHeight
  # Scrolling instantly is actually a smoother experience than
  # incorporating a delay. When the animation takes some time to run the
  # page jumps unpleasantly when new content is added.
  # Delays also fight the user if they try to scroll up at the same time
  # the animation is scrolling down.
  $(element).animate({scrollTop: offset}, 0)

CI.Browser or= {}

CI.Browser.scroll_to = (position) =>
  offset = if position == "top" then 0 else document.body.scrollHeight
  # Scrolling instantly is actually a smoother experience than
  # incorporating a delay. When the animation takes some time to run the
  # page jumps unpleasantly when new content is added.
  # Delays also fight the user if they try to scroll up at the same time
  # the animation is scrolling down.
  $("html, body").animate({scrollTop: offset}, 0)

Use document.body.scrollHeight, it's more correct


exports.config =

    paths:
        public: '../SingularityService/src/main/resources/static'

    files:

        javascripts:

            defaultExtension: 'coffee'

            joinTo:
                'static/js/app.js': /^app/
                'static/js/vendor.js': /^vendor/

            order:
                before: [
                    'vendor/scripts/log.coffee'
                    'vendor/scripts/parseDec.coffee'
                    'vendor/scripts/modernizr.custom-2.6.2.js'
                    'vendor/scripts/jquery-1.10.2.js'
                    'vendor/scripts/jquery.cookie-1.1.js'
                    'vendor/scripts/jquery.mousewheel-3.0.6.js'
                    'vendor/scripts/jquery.swipe-1.1.0.js'
                    'vendor/scripts/underscore-1.5.1.js'
                    'vendor/scripts/underscore.string-2.3.0.js'
                    'vendor/scripts/backbone-1.0.0.js'
                    'vendor/scripts/moment-2.1.0.js'
                ]

        stylesheets:
            defaultExtension: 'styl'
            joinTo: 'static/css/app.css'

        templates:
            defaultExtension: 'hbs'
            joinTo: 'static/js/app.js'

    server:
        base: '/singularity'

exports.config =

    paths:
        public: '../SingularityService/src/main/resources/static'

    files:

        javascripts:

            defaultExtension: 'coffee'

            joinTo:
                'static/js/app.js': /^app/
                'static/js/vendor.js': /^vendor/

            order:
                before: [
                    'vendor/scripts/log.coffee'
                    'vendor/scripts/parseDec.coffee'
                    'vendor/scripts/modernizr.custom-2.6.2.js'
                    'vendor/scripts/jquery-1.10.2.js'
                    'vendor/scripts/jquery.cookie-1.1.js'
                    'vendor/scripts/jquery.mousewheel-3.0.6.js'
                    'vendor/scripts/jquery.swipe-1.1.0.js'
                    'vendor/scripts/underscore-1.5.1.js'
                    'vendor/scripts/underscore.string-2.3.0.js'
                    'vendor/scripts/backbone-1.0.0.js'
                    'vendor/scripts/moment-2.1.0.js'
                ]

        stylesheets:
            defaultExtension: 'styl'
            joinTo: 'static/css/app.css'
            order:
                before: [
                    'vendor/styles/bootstrap.css'
                    'vendor/styles/bootstrap-responsive.css'
                    'vendor/styles/docs.css'
                ]

        templates:
            defaultExtension: 'hbs'
            joinTo: 'static/js/app.js'

    server:
        base: '/singularity'

Fix responsive styles (vendor stylesheet order was busted)


colors = require('colors')
url = require('url')
http = require('http')
Proxy = require('http-proxy')

start = (config) ->
  match = (url, route) ->
    new RegExp(route).test(url)

  debug = (args...) ->
    if config.debug
      console.log args...

  getTarget = (req) ->
    debug "Proxying request to #{ req.url }"
    for path, dest of config.routes
      debug "Trying #{ path }"

      if match(req.url, path)
        debug "#{ path } matches, sending to #{ dest }".green
        return dest

    debug "No match!".red

  parseTarget = (dest) ->
    parts = url.parse(dest)

    return {
      host: parts.hostname
      port: parts.port
      path: parts.path
    }

  server = Proxy.createServer (req, res, proxy) ->
    target = getTarget(req)

    unless target
      res.writeHead(404)
      res.end("Proxying target not found")
      return

    target = parseTarget(target)

    unless target.path[target.path.length - 1] == '/'
      req.url = target.path

    proxy.proxyRequest req, res, target

  server.listen(config.port)

module.exports = {start}

colors = require('colors')
url = require('url')
http = require('http')
Proxy = require('http-proxy')

start = (config) ->
  match = (url, route) ->
    new RegExp(route).test(url)

  debug = (args...) ->
    if config.debug
      console.log args...

  getTarget = (req) ->
    debug "Proxying request to #{ req.url }"
    for path, dest of config.routes
      debug "Trying #{ path }"

      if match(req.url, path)
        debug "#{ path } matches, sending to #{ dest }".green
        return dest

    debug "No match!".red

  parseTarget = (dest) ->
    parts = url.parse(dest)

    return {
      host: parts.hostname
      port: parts.port or '80'
      path: parts.path
    }

  server = Proxy.createServer (req, res, proxy) ->
    target = getTarget(req)

    unless target
      res.writeHead(404)
      res.end("Proxying target not found")
      return

    target = parseTarget(target)

    unless target.path[target.path.length - 1] == '/'
      req.url = target.path

    proxy.proxyRequest req, res, target

  server.listen(config.port)

module.exports = {start}

Use port 80 by default

Use port 80 by default


path = require('path')
gulp = require('gulp')
mocha = require('gulp-mocha')
coffeelint = require('gulp-coffeelint')
mochaNotifierReporter = require('mocha-notifier-reporter')

OPTIONS =
	config:
		coffeelint: path.join(__dirname, 'coffeelint.json')
	files:
		coffee: [ 'lib/**/*.coffee', 'gulpfile.coffee' ]
		tests: 'lib/**/*.spec.coffee'

gulp.task 'test', ->
	gulp.src(OPTIONS.files.tests, read: false)
		.pipe(mocha({
			reporter: mochaNotifierReporter.decorate('list')
		}))

gulp.task 'lint', ->
	gulp.src(OPTIONS.files.coffee)
		.pipe(coffeelint({
			optFile: OPTIONS.config.coffeelint
		}))
		.pipe(coffeelint.reporter())

gulp.task 'watch', [ 'test', 'lint' ], ->
	gulp.watch(OPTIONS.files.tests, [ 'test' ])
	gulp.watch(OPTIONS.files.coffee, [ 'lint' ])

path = require('path')
gulp = require('gulp')
mocha = require('gulp-mocha')
coffeelint = require('gulp-coffeelint')
mochaNotifierReporter = require('mocha-notifier-reporter')

OPTIONS =
	config:
		coffeelint: path.join(__dirname, 'coffeelint.json')
	files:
		coffee: [ 'lib/**/*.coffee', 'gulpfile.coffee' ]
		tests: 'lib/**/*.spec.coffee'

gulp.task 'test', ->
	gulp.src(OPTIONS.files.tests, read: false)
		.pipe(mocha({
			reporter: mochaNotifierReporter.decorate('list')
		}))

gulp.task 'lint', ->
	gulp.src(OPTIONS.files.coffee)
		.pipe(coffeelint({
			optFile: OPTIONS.config.coffeelint
		}))
		.pipe(coffeelint.reporter())

gulp.task 'watch', [ 'test', 'lint' ], ->
	gulp.watch(OPTIONS.files.coffee, [ 'test', 'lint' ])

Watch all coffee files for running test

Watch all coffee files for running test


class @ProtectedAreaMap
  constructor: ($container) ->
    @map = L.map($container.attr('id'), {zoomControl: false, scrollWheelZoom: false})

    L.tileLayer('http://api.tiles.mapbox.com/v3/unepwcmc.ijh17499/{z}/{x}/{y}.png').addTo(@map)
    L.tileLayer('http://carbon-tool.cartodb.com/tiles/wdpa_poly_feb2014_0/{z}/{x}/{y}.png').addTo(@map)

  fitToBounds: (bounds, withPadding) ->
    opts = {}
    if withPadding?
      padding = @calculatePadding()
      opts.paddingTopLeft = padding.topLeft
      opts.paddingBottomRight = padding.bottomRight

    @map.fitBounds(bounds, opts)

  setZoomControl: (position) ->
    @map.addControl(L.control.zoom(position: position))

  locate: ->
    @map.locate(setView: true)

  calculatePadding: ->
    mapSize = @map.getSize()
    paddingLeft = mapSize.x/5
    {topLeft: [paddingLeft, 50], bottomRight: [0, 50]}

class @ProtectedAreaMap
  constructor: ($container) ->
    @map = L.map($container.attr('id'), {zoomControl: false, scrollWheelZoom: false})

    L.tileLayer('http://api.tiles.mapbox.com/v3/unepwcmc.ijh17499/{z}/{x}/{y}.png').addTo(@map)
    L.tileLayer('http://carbon-tool.cartodb.com/tiles/wdpapoly_july2014_0/{z}/{x}/{y}.png').addTo(@map)

  fitToBounds: (bounds, withPadding) ->
    opts = {}
    if withPadding?
      padding = @calculatePadding()
      opts.paddingTopLeft = padding.topLeft
      opts.paddingBottomRight = padding.bottomRight

    @map.fitBounds(bounds, opts)

  setZoomControl: (position) ->
    @map.addControl(L.control.zoom(position: position))

  locate: ->
    @map.locate(setView: true)

  calculatePadding: ->
    mapSize = @map.getSize()
    paddingLeft = mapSize.x/5
    {topLeft: [paddingLeft, 50], bottomRight: [0, 50]}

Update cartodb layer for july

Update cartodb layer for july


define [
	"base"
], (App) ->
	mathjaxConfig =
		messageStyle: "none"
		imageFont:null
		"HTML-CSS": { availableFonts: ["TeX"] },
		TeX:
			equationNumbers: { autoNumber: "AMS" },
			useLabelIDs: false
		tex2jax:
			inlineMath: [ ['$','$'], ["\\(","\\)"] ],
			displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
			processEscapes: true
		skipStartupTypeset: true

	MathJax?.Hub?.Config(mathjaxConfig);

	App.directive "mathjax", () ->
		return {
			link: (scope, element, attrs) ->
				setTimeout () ->
					MathJax?.Hub?.Queue(["Typeset", MathJax?.Hub, element.get(0)])
				, 0
		}

define [
	"base"
], (App) ->
	mathjaxConfig =
		extensions: ["Safe.js"]
		messageStyle: "none"
		imageFont:null
		"HTML-CSS": { availableFonts: ["TeX"] },
		TeX:
			equationNumbers: { autoNumber: "AMS" },
			useLabelIDs: false
		tex2jax:
			inlineMath: [ ['$','$'], ["\\(","\\)"] ],
			displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
			processEscapes: true
		skipStartupTypeset: true

	MathJax?.Hub?.Config(mathjaxConfig);

	App.directive "mathjax", () ->
		return {
			link: (scope, element, attrs) ->
				setTimeout () ->
					MathJax?.Hub?.Queue(["Typeset", MathJax?.Hub, element.get(0)])
				, 0
		}

Use the MathJax `Safe.js` extension to prevent XSS


fs            = require 'fs'
path          = require 'path'
CSON          = require 'cson'
postcss       = require 'postcss'

namespace = postcss.plugin 'postcss-namespace', (opts) ->
  if not opts?
    opts = {token: '-'}

  (css) ->
    ref = null

    css.walkRules (rule) ->
      if /^&/.test rule.selector
        rule.selector = rule.selector.replace /&/, ref
      else
        ref = rule.selector

module.exports = namespace

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

namespace = postcss.plugin 'postcss-namespace', (opts) ->
  if not opts?
    opts = {token: '-'}

  (css) ->
    ref = null

    css.walkRules (rule) ->
      if /^&/.test rule.selector
        rule.selector = rule.selector.replace /&/, ref
      else
        ref = rule.selector

module.exports = namespace

Remove CSON reference from coffee file

Remove CSON reference from coffee file


uploadcare.whenReady ->
  {
    jQuery: $
  } = uploadcare

  dataAttr = 'uploadcareWidget'

  uploadcare.initialize = (targets) ->
    for target in $(targets || '@uploadcare-uploader')
      el = $(target)
      initializeWidget(el)
    return

  initializeWidget = (el) ->
    widget = el.data(dataAttr)
    if !widget || el[0] != widget.element[0]
      cleanup(el)
      widget = new uploadcare.widget.Widget(el)
      el.data(dataAttr, widget)
      widget.template.content.data(dataAttr, widget.template)

    widget # FIXME Supposed to be API wrapper

  cleanup = (el) ->
    el.off('.uploadcare')
    el = el.next('.uploadcare-widget')
    template = el.data(dataAttr)
    if el.length && (!template || el[0] != template.content[0])
      el.remove()

  if uploadcare.defaults.live
    live = ->
      uploadcare.initialize()
      setTimeout(live, 100)
    $(live)
  else
    $ -> uploadcare.initialize()

uploadcare.whenReady ->
  {
    jQuery: $
  } = uploadcare

  dataAttr = 'uploadcareWidget'

  uploadcare.initialize = (targets) ->
    for target in $(targets || '@uploadcare-uploader')
      el = $(target)
      initializeWidget(el)
    return

  initializeWidget = (el) ->
    widget = el.data(dataAttr)
    if !widget || el[0] != widget.element[0]
      cleanup(el)
      widget = new uploadcare.widget.Widget(el)
      el.data(dataAttr, widget)
      widget.template.content.data(dataAttr, widget.template)

    widget # FIXME Supposed to be API wrapper

  cleanup = (el) ->
    el.off('.uploadcare')
    el = el.next('.uploadcare-widget')
    template = el.data(dataAttr)
    if el.length && (!template || el[0] != template.content[0])
      el.remove()

  live = -> uploadcare.initialize()
  if uploadcare.defaults.live
    $ -> setInterval(live, 100)
  else
    $(live)

Use interval instead of recreating timers in live


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

  constructor: ->
    super

    @once 'ready', =>
      setImmediate @bindEvents

    @render()

  context: (permissions = { public: true }) =>
    _.extend super,
      permissions: permissions

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

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

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

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

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

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

  hide: =>
    @visible = false
    @permissionsFieldsView()?.hide()
    #Marbles.DOM.setInnerText(@el, @text.visibility_toggle.show)

  show: (should_focus = true) =>
    @visible = true
    @permissionsFieldsView()?.show()
    #Marbles.DOM.setInnerText(@el, @text.visibility_toggle.hide)

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

  constructor: ->
    super

    @once 'ready', =>
      setImmediate @bindEvents

    @render()

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

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

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

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

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

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

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

  hide: =>
    @visible = false
    @permissionsFieldsView()?.hide()
    #Marbles.DOM.setInnerText(@el, @text.visibility_toggle.show)

  show: (should_focus = true) =>
    @visible = true
    @permissionsFieldsView()?.show()
    #Marbles.DOM.setInnerText(@el, @text.visibility_toggle.hide)

Fix permissions toggle for limited posts


cozydb = require 'cozydb'

module.exports = Contact = cozydb.getModel 'Contact',
    fn            : String
    n             : String
    datapoints    : [Object]
    revision      : String
    note          : String
    tags          : [String]
    accounts      : String
    title         : String
    org           : String
    bday          : String
    url           : String
    initials      : String
    sortedName    : String
    ref           : String
    _attachments  : Object

Contact::asNameAndEmails = ->
    name = @fn or @n?.split(';')[0..1].join ' '
    emails = @datapoints?.filter (dp) -> dp.name is 'email'

    # XXX What if several Cozy instances are linked to one user?
    cozy = dp.value for dp in @datapoints when (dp.name is 'other' and
        dp.type is 'COZY') or (dp.name is 'url' and
        dp.mediatype.search 'cozy' isnt -1)

    return simple =
        id         : @id
        name       : name or '?'
        emails     : emails or []
        hasPicture : @_attachments?.picture?
        cozy       : cozy or null

cozydb = require 'cozydb'

module.exports = Contact = cozydb.getModel 'Contact',
    fn            : String
    n             : String
    datapoints    : [Object]
    revision      : String
    note          : String
    tags          : [String]
    accounts      : String
    title         : String
    org           : String
    bday          : String
    url           : String
    initials      : String
    sortedName    : String
    ref           : String
    _attachments  : Object

Contact::asNameAndEmails = ->
    name = @fn or @n?.split(';')[0..1].join ' '
    emails = @datapoints?.filter (dp) -> dp.name is 'email'

    # XXX What if several Cozy instances are linked to one user?
    cozy = dp.value for dp in @datapoints when (dp.name is 'other' and
        dp.type is 'COZY') or (dp.name is 'url' and
        dp.mediatype?.search 'cozy' isnt -1)

    return simple =
        id         : @id
        name       : name or '?'
        emails     : emails or []
        hasPicture : @_attachments?.picture?
        cozy       : cozy or null

Fix error due to mediatype being undefined


Player    = require './Player'
TextInput = require './TextInput'

class Game
  constructor: (game) ->
    @textBox = new TextInput(game)
    @player  = new Player(game)

    window.Game = @

    @socket = io.connect('http://localhost:8080', {secure: true})
    @socket.emit 'new player', 'name'

    @socket.on 'snap', (data) =>
      # update appropriate word for snap
      @player.addPoints(data.d_score)
      console.log data.d_score
      console.log "total points: #{@player.points}"
      $.notify "Snap! on #{data.word}"
      $.notify "You have #{@player.points} points", "info"

  create: ->

  sendWord: (word) ->
    console.log word
    @socket.emit 'new word', word

module.exports = Game

Player    = require './Player'
TextInput = require './TextInput'

class Game
  constructor: (game) ->
    @textBox = new TextInput(game)
    @player  = new Player(game)

    window.Game = @

    @socket = io.connect('https://snapgame.herokuapp.com', {secure: true})
    @socket.emit 'new player', 'name'

    @socket.on 'snap', (data) =>
      # update appropriate word for snap
      @player.addPoints(data.d_score)
      console.log data.d_score
      console.log "total points: #{@player.points}"
      $.notify "Snap! on #{data.word}"
      $.notify "You have #{@player.points} points", "info"

  create: ->

  sendWord: (word) ->
    console.log word
    @socket.emit 'new word', word

module.exports = Game

Use heroku app as backend

Use heroku app as backend


[
	{
		title: "@Atom Theme"
		paths: [
			"/Users/johngardner/Labs/Atom-PhoenixTheme"
		]
		devMode: true
	}
	{
		title: ".files"
		paths: [
			"/Users/johngardner/.files"
		]
		devMode: true
	}
	{
		title: "language-roff"
		paths: [
			"/Users/johngardner/Labs/language-roff"
		]
		devMode: true
	}
	{
		title: "file-icons"
		paths: [
			"/Users/johngardner/Labs/file-icons"
		]
		devMode: true
	}
	{
		title: "Atom-FS"
		paths: [
			"/Users/johngardner/Labs/Atom-FS"
			"/Users/johngardner/Labs/Utils"
		]
		devMode: true
	}
	{
		title: "Utils"
		paths: [
			"/Users/johngardner/Labs/Utils"
		]
		devMode: true
	}
	{
		title: "GNU Groff"
		paths: [
			"/Users/johngardner/Mirrors/GNU-Groff"
			"/usr/local/share/groff/current/font"
		]
		devMode: true
	}
]

[
	{
		title: ".atom"
		paths: [
			"~/.atom"
		]
		devMode: true
	}
	{
		title: ".files"
		paths: [
			"~/.files"
		]
		devMode: true
	}
	{
		title: "language-roff"
		paths: [
			"~/Labs/language-roff"
		]
		devMode: true
	}
	{
		title: "file-icons"
		paths: [
			"~/Labs/file-icons"
		]
		devMode: true
	}
	{
		title: "Atom-FS"
		paths: [
			"~/Labs/Atom-FS"
			"~/Labs/Utils"
		]
		devMode: true
	}
	{
		title: "Utils"
		paths: [
			"~/Labs/Utils"
		]
		devMode: true
	}
	{
		title: "GNU Groff"
		paths: [
			"~/Mirrors/GNU-Groff"
			"/usr/local/share/groff/current/font"
		]
		devMode: true
	}
]

Fix broken project paths from old macOS installation


window.ReactFeedSelection = React.createClass
  displayName: 'ReactFeedSelection'
  mixins: [UpdateOnSignInOrOutMixin]

  getInitialState: ->
    feedChoice: 'global'
    feeds:
      global: new GlobalFeedActivities
      personal: new PersonalFeedActivities

  _handleFeedChoiceChange: (e) ->
    if(e.target.checked)
      @setState
        feedChoice: e.target.value

  render: ->
    _div [],
      if currentSession.signedIn()
        _div ['feed-selection-row'],
          _input [ 'radio-toggle-button', type: 'radio', name: 'FeedChoice', value: 'global', id: 'FeedChoice_Global', onChange: @_handleFeedChoiceChange, checked: @state.feedChoice=='global'  ]
          _label [ htmlFor: 'FeedChoice_Global' ],
            'Global'

          _input [ 'radio-toggle-button', type: 'radio', name: 'FeedChoice', value: 'personal', id: 'FeedChoice_Personal', onChange: @_handleFeedChoiceChange, checked: @state.feedChoice=='personal' ]
          _label [ htmlFor: 'FeedChoice_Personal' ],
            'Personal'

          _div ['feed-selection-install-extension-button'],
            ReactInstallExtensionOrBookmarklet()

      ReactFeedActivitiesAutoLoading
        model: @state.feeds[@state.feedChoice]
        key: @state.feedChoice

window.ReactFeedSelection = React.createClass
  displayName: 'ReactFeedSelection'
  mixins: [UpdateOnSignInOrOutMixin]

  getInitialState: ->
    feedChoice: 'global'
    feeds:
      global: new GlobalFeedActivities
      personal: new PersonalFeedActivities
      discussions: new DiscussionsFeedActivities

  _handleFeedChoiceChange: (e) ->
    if(e.target.checked)
      @setState
        feedChoice: e.target.value

  render: ->
    _div [],
      if currentSession.signedIn()
        _div ['feed-selection-row'],
          _input [ 'radio-toggle-button', type: 'radio', name: 'FeedChoice', value: 'global', id: 'FeedChoice_Global', onChange: @_handleFeedChoiceChange, checked: @state.feedChoice=='global'  ]
          _label [ htmlFor: 'FeedChoice_Global' ],
            'Global'

          _input [ 'radio-toggle-button', type: 'radio', name: 'FeedChoice', value: 'personal', id: 'FeedChoice_Personal', onChange: @_handleFeedChoiceChange, checked: @state.feedChoice=='personal' ]
          _label [ htmlFor: 'FeedChoice_Personal' ],
            'Personal'
          _input [ 'radio-toggle-button', type: 'radio', name: 'FeedChoice', value: 'discussions', id: 'FeedChoice_Discussions', onChange: @_handleFeedChoiceChange, checked: @state.feedChoice=='discussions' ]
          _label [ htmlFor: 'FeedChoice_Discussions' ],
            'Discussions'

          _div ['feed-selection-install-extension-button'],
            ReactInstallExtensionOrBookmarklet()

      ReactFeedActivitiesAutoLoading
        model: @state.feeds[@state.feedChoice]
        key: @state.feedChoice

Allow selecting "Discussions" as a feed

Allow selecting "Discussions" as a feed


React = require 'react'
ReactDOM = {render} = require 'react-dom'
{Router, Route, Link} = require 'react-router'
{useBasename} = require 'history'
createBrowserHistory = require 'history/lib/createBrowserHistory'
routes = require './router'

# IE, oh my god:
location.origin ?= location.protocol + "//" + location.hostname + if location.port then ':' + location.port else ''
document.baseURI ?= location.origin + document.querySelector('base').getAttribute('href')

if location?.hash?.indexOf('/') is 1
  location.replace location.hash.slice 1

basename = document.baseURI.slice(location.origin.length)
history = useBasename(createBrowserHistory)({basename})

history.listen ->
  window.dispatchEvent new CustomEvent 'locationchange'

render <Router history={history}>{routes}</Router>,
  document.getElementById('panoptes-main-container')

logDeployedCommit = require './lib/log-deployed-commit'
logDeployedCommit()

# For console access:
window?.zooAPI = require 'panoptes-client/lib/api-client'

React = require 'react'
ReactDOM = {render} = require 'react-dom'
{Router, Route, Link} = require 'react-router'
{useBasename} = require 'history'
createBrowserHistory = require 'history/lib/createBrowserHistory'
routes = require './router'
apiClient = require 'panoptes-client/lib/api-client'

# IE, oh my god:
location.origin ?= location.protocol + "//" + location.hostname + if location.port then ':' + location.port else ''
document.baseURI ?= location.origin + document.querySelector('base').getAttribute('href')

if location?.hash?.indexOf('/') is 1
  location.replace location.hash.slice 1

basename = document.baseURI.slice(location.origin.length)
history = useBasename(createBrowserHistory)({basename})

history.listen ->
  window.dispatchEvent new CustomEvent 'locationchange'

render <Router history={history}>{routes}</Router>,
  document.getElementById('panoptes-main-container')

logDeployedCommit = require './lib/log-deployed-commit'
logDeployedCommit()

# For console access:
window?.zooAPI = apiClient

Set window object to variable

Set window object to variable


#= require routes/map.route

Wheelmap.PopupRoute = Wheelmap.MapRoute.extend
  model: (params)->
    @get('store').find('node', params.node_id)

  setupController: (controller, model, queryParams)->
    @_super(controller, model, queryParams)

    @controllerFor('map').set('poppingNode', controller)

  renderTemplate: (controller, model)->
    @render 'node-popup',
      outlet: 'popup',
      controller: controller

#= require routes/map.route

Wheelmap.PopupRoute = Wheelmap.MapRoute.extend
  model: (params, queryParams)->
    self = @

    @get('store').find('node', params.node_id).then(null, ()->
      # if node was not found
      self.transitionTo('index')
    )

  setupController: (controller, model, queryParams)->
    @_super(controller, model, queryParams)

    @controllerFor('map').set('poppingNode', controller)

  renderTemplate: (controller, model)->
    @render 'node-popup',
      outlet: 'popup',
      controller: controller

Fix blank page if node by id was not found.


{View} = require 'atom'

# View to show the grammar name in the status bar.
module.exports =
class GrammarStatusView extends View
  @content: ->
    @div class: 'grammar-status', =>
      @a href: '#', class: 'inline-block', outlet: 'grammarLink'

  initialize: (@statusBar) ->
    @subscribe @statusBar, 'active-buffer-changed', =>
      @updateGrammarText()

    @subscribe atom.workspace.eachEditor (editor) =>
      @subscribe editor, 'grammar-changed', =>
        @updateGrammarText() if editor is atom.workspace.getActiveEditor()

    atom.config.observe 'grammar-selector.showOnRightSideOfStatusBar', =>
      @attach()

    @subscribe this, 'click', ->
      atom.workspaceView.trigger('grammar-selector:show')
      false

  attach: ->
    if atom.config.get 'grammar-selector.showOnRightSideOfStatusBar'
      @statusBar.prependRight(this)
    else
      @statusBar.appendLeft(this)

  afterAttach: ->
    @updateGrammarText()

  updateGrammarText: ->
    grammar = atom.workspace.getActiveEditor()?.getGrammar?()
    if grammar?
      if grammar is atom.syntax.nullGrammar
        grammarName = 'Plain Text'
      else
        grammarName = grammar.name ? grammar.scopeName
      @grammarLink.element.textContent = grammarName
      @grammarLink.element.dataset.grammar = grammarName
      @element.style.display = ''
    else
      @element.style.display = 'none'

{View} = require 'atom'

# View to show the grammar name in the status bar.
module.exports =
class GrammarStatusView extends View
  @content: ->
    @div class: 'grammar-status inline-block', =>
      @a href: '#', class: 'inline-block', outlet: 'grammarLink'

  initialize: (@statusBar) ->
    @subscribe @statusBar, 'active-buffer-changed', =>
      @updateGrammarText()

    @subscribe atom.workspace.eachEditor (editor) =>
      @subscribe editor, 'grammar-changed', =>
        @updateGrammarText() if editor is atom.workspace.getActiveEditor()

    atom.config.observe 'grammar-selector.showOnRightSideOfStatusBar', =>
      @attach()

    @subscribe this, 'click', ->
      atom.workspaceView.trigger('grammar-selector:show')
      false

  attach: ->
    if atom.config.get 'grammar-selector.showOnRightSideOfStatusBar'
      @statusBar.prependRight(this)
    else
      @statusBar.appendLeft(this)

  afterAttach: ->
    @updateGrammarText()

  updateGrammarText: ->
    grammar = atom.workspace.getActiveEditor()?.getGrammar?()
    if grammar?
      if grammar is atom.syntax.nullGrammar
        grammarName = 'Plain Text'
      else
        grammarName = grammar.name ? grammar.scopeName
      @grammarLink.element.textContent = grammarName
      @grammarLink.element.dataset.grammar = grammarName
      @element.style.display = ''
    else
      @element.style.display = 'none'

Make root div inline-block as well

Make root div inline-block as well


module.exports = (grunt) ->

    grunt.initConfig

        pkg: grunt.file.readJSON('package.json')

        meta:
            banner: '/*! <%= pkg.name %> <%= pkg.version %> | (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %> | <%= pkg.license %> License */\n'

        coffee:
            compile:
                expand: true
                cwd: 'coffee/'
                src: ['**/*.coffee']
                dest: 'js/'
                ext: '.js'

        uglify:
            options:
                banner: '<%= meta.banner %>'
            dist:
                files:
                    'js/uTip.min.js': ['js/uTip.js']

        watch:
            files: 'src/**/*.coffee'
            tasks: ['compile']

    grunt.loadNpmTasks 'grunt-contrib-coffee'
    grunt.loadNpmTasks 'grunt-contrib-uglify'
    grunt.loadNpmTasks 'grunt-contrib-watch'

    grunt.registerTask 'compile', ['coffee', 'uglify']
    grunt.registerTask 'default', ['compile', 'watch']

module.exports = (grunt) ->

    grunt.initConfig

        pkg: grunt.file.readJSON('package.json')

        meta:
            banner: '/*! <%= pkg.name %> <%= pkg.version %> | (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %> | <%= pkg.license %> License */\n'

        coffee:
            compile:
                expand: true
                cwd: 'coffee/'
                src: ['**/*.coffee']
                dest: 'js/'
                ext: '.js'

        uglify:
            options:
                banner: '<%= meta.banner %>'
            dist:
                files:
                    'js/uTip.min.js': ['js/uTip.js']

        watch:
            files: 'coffee/**/*.coffee'
            tasks: ['compile']

    grunt.loadNpmTasks 'grunt-contrib-coffee'
    grunt.loadNpmTasks 'grunt-contrib-uglify'
    grunt.loadNpmTasks 'grunt-contrib-watch'

    grunt.registerTask 'compile', ['coffee', 'uglify']
    grunt.registerTask 'default', ['compile', 'watch']

Fix incorrect watch path in grunt task

Fix incorrect watch path in grunt task


Backbone = require 'backbone'
Promise = require 'bluebird-q'
{ API_URL } = require('sharify').data
Channel = require '../../../../models/channel.coffee'
mediator = require '../../../../lib/mediator.coffee'

module.exports = class ConnectCreateView extends Backbone.View
  className: 'Connect__create'

  events:
    click: 'create'

  initialize: ({ @connectable, @state }) ->
    @listenTo @state, 'change:query', @render

  create: (e) ->
    e.preventDefault()
    e.stopPropagation()

    @$el.text 'Creating'

    title = @state.get 'query'

    channel = new Channel
      title: title
      status: 'private'

    channel.url = "#{API_URL}/channels"

    Promise(channel.save())
      .then =>
        @$el.text 'Connecting'
        @connect channel

      .then =>
        @render()
        channel.set "selected:#{@connectable.get 'base_class'}:#{@connectable.id}", true
        @collection.unshift channel

      .catch =>
        @$el.text 'Error'

  connect: (channel) ->
    Promise $.ajax
      type: 'POST'
      url: "#{API_URL}/channels/#{channel.id}/connections"
      data:
        connectable_id: @connectable.id
        connectable_type: @connectable.get('base_class')

    .then =>
      mediator.shared.recent_connections.shove channel
      mediator.trigger "connection:added:#{@connectable.id}", channel
      mediator.trigger 'connection:added', channel

  render: ->
    @$el.text "+ New private channel “#{@state.get('query')}”"
    this

Backbone = require 'backbone'
Promise = require 'bluebird-q'
{ API_URL } = require('sharify').data
Channel = require '../../../../models/channel.coffee'
mediator = require '../../../../lib/mediator.coffee'

module.exports = class ConnectCreateView extends Backbone.View
  className: 'Connect__create'

  events:
    click: 'create'

  initialize: ({ @connectable, @state }) ->
    @listenTo @state, 'change:query', @render

  create: (e) ->
    e.preventDefault()
    e.stopPropagation()

    @$el.text 'Creating'

    title = @state.get 'query'

    channel = new Channel
      title: title
      status: 'private'

    channel.url = "#{API_URL}/channels"
    channel.set "selected:#{@connectable.get 'base_class'}:#{@connectable.id}", true

    Promise(channel.save())
      .then =>
        @$el.text 'Connecting'
        @connect channel

      .then =>
        @render()
        @collection.unshift channel

      .catch =>
        @$el.text 'Error'

  connect: (channel) ->
    Promise $.ajax
      type: 'POST'
      url: "#{API_URL}/channels/#{channel.id}/connections"
      data:
        connectable_id: @connectable.id
        connectable_type: @connectable.get('base_class')

    .then =>
      mediator.shared.recent_connections.shove channel
      mediator.trigger "connection:added:#{@connectable.id}", channel
      mediator.trigger 'connection:added', channel

  render: ->
    @$el.text "+ New private channel “#{@state.get('query')}”"
    this

Set attribute before doing anything with it


"*":
  core:
    themes: [
      "one-light-ui"
      "solarized-dark-syntax"
    ]
  editor:
    fontSize: 15
  "exception-reporting":
    userId: "76d6bd0a-16fd-42b8-0163-bce5c8c7e379"
  welcome:
    showOnStartup: false

"*":
  core:
    themes: [
      "one-light-ui"
      "solarized-dark-syntax"
    ]
  editor:
    fontSize: 16
  "exception-reporting":
    userId: "76d6bd0a-16fd-42b8-0163-bce5c8c7e379"
  welcome:
    showOnStartup: false

Change Atom editor font size

Change Atom editor font size


#= require_self
#= require_tree .

window.Neighborly =
  configs:
    turbolinks: true
    pjax: false
    respond_with:
      'Create': 'New'
      'Update': 'Edit'

  modules: -> []

  initPage: ->
    that = this
    unless window.Turbolinks is undefined
      $(document).bind "page:fetch", ->
        that.Loading.show()

      $(document).bind "page:restore", ->
        that.Loading.hide()

      $(document).bind "page:change", ->
        $(window).scrollTop(0)

        try
          FB.XFBML.parse()
        try
          twttr.widgets.load()

  init: ->
    $(document).foundation('reveal', {animation: 'fadeAndPop', animationSpeed: 100})
    $(document).foundation()

    $.pjax.defaults.scrollTo = false if $.pjax.defaults?
    $.pjax.defaults.timeout = false if $.pjax.defaults?

    $('.button.disabled').click ->
      return false

    $('.top-bar .search-button').click ->
      if $('.discover-form-input').val() != ''
        $('form.discover-form').submit()
      else
        $('.discover-form-input').toggleClass('show').focus()

      return false

  Loading:
    show: ->
      $('#loading').addClass('show')
    hide: ->
      $('#loading').removeClass('show')

#= require_self
#= require_tree .

window.Neighborly =
  configs:
    turbolinks: true
    pjax: false
    respond_with:
      'Create': 'New'
      'Update': 'Edit'

  modules: -> []

  initPage: ->
    unless window.Turbolinks is undefined
      $(document).bind "page:fetch", =>
        this.Loading.show()

      $(document).bind "page:restore", =>
        this.Loading.hide()

      $(document).bind "page:change", =>
        clearTimeout(this.flash_time_out)
        $(window).scrollTop(0)

        try
          FB.XFBML.parse()
        try
          twttr.widgets.load()

  init: ->
    $(document).foundation('reveal', {animation: 'fadeAndPop', animationSpeed: 100})
    $(document).foundation()

    $.pjax.defaults.scrollTo = false if $.pjax.defaults?
    $.pjax.defaults.timeout = false if $.pjax.defaults?

    this.flash()

    $('.button.disabled').click ->
      return false

    $('.top-bar .search-button').click ->
      if $('.discover-form-input').val() != ''
        $('form.discover-form').submit()
      else
        $('.discover-form-input').toggleClass('show').focus()

      return false

  Loading:
    show: ->
      $('#loading').addClass('show')
    hide: ->
      $('#loading').removeClass('show')

  flash: ->
    if $(".flash").length > 0
      this.flash_time_out = setTimeout this.closeFlash, 5000
      $(".flash a.close").click(this.closeFlash)

  closeFlash: ->
    $('.flash .alert-box').fadeOut('fast')
    setTimeout (->
      $('.flash').slideUp('slow')
    ), 100

Make flash messages auto dismissible

Make flash messages auto dismissible


goog.provide 'app.Facebook'

class app.Facebook

  ###*
    @param {app.user.Store} userStore
    @constructor
  ###
  constructor: (@userStore) ->

  ###*
    @type {Object}
    @private
  ###
  fb_: null

  ###*
    Enable Facebook api.
  ###
  init: ->
    window.fbAsyncInit = =>
      @fb_ = window.FB
      @fb_.init
        'appId': '1458272837757905'
        'cookie': true
        'version': 'v2.1'
        'xfbml': false

    # Load the SDK asynchronously.
    ((d, s, id) ->
      fjs = d.getElementsByTagName(s)[0]
      return if d.getElementById id
      js = d.createElement s
      js.id = id
      js.src = '//connect.facebook.net/en_US/sdk.js'
      fjs.parentNode.insertBefore js, fjs
      return
    ) document, 'script', 'facebook-jssdk'

  login: ->
    if !@fb_
      alert 'Facebook API not ready yet. Click again please.'
      return
    @fb_.getLoginStatus (response) =>
      if response.status == 'connected'
        @onConnected_()
      else if response.status == 'not_authorized'
        alert 'Please log into this app.'
      else
        alert 'Please log into Facebook.'

  ###*
    @private
  ###
  onConnected_: ->
    @fb_.api '/me', (response) =>
      @userStore.loginFacebookUser response

  logout: ->
    # The FB.logout log the person out of Facebook, which is not we want.
    @userStore.logout()

goog.provide 'app.Facebook'

class app.Facebook

  ###*
    @param {app.user.Store} userStore
    @constructor
  ###
  constructor: (@userStore) ->

  ###*
    @type {Object}
    @private
  ###
  fb_: null

  ###*
    Load Facebook api async.
  ###
  init: ->
    window.fbAsyncInit = =>
      @fb_ = window.FB
      @fb_.init
        'appId': '1458272837757905'
        'cookie': true
        'version': 'v2.1'
        'xfbml': false

    # Load the SDK asynchronously.
    ((d, s, id) ->
      fjs = d.getElementsByTagName(s)[0]
      return if d.getElementById id
      js = d.createElement s
      js.id = id
      js.src = '//connect.facebook.net/en_US/sdk.js'
      fjs.parentNode.insertBefore js, fjs
      return
    ) document, 'script', 'facebook-jssdk'

  login: ->
    if !@fb_
      alert 'Facebook API not ready yet. Click again please.'
      return
    @fb_.getLoginStatus (response) =>
      if response.status == 'connected'
        @onConnected_()
      else if response.status == 'not_authorized'
        alert 'Please log into this app.'
      else
        alert 'Please log into Facebook.'

  ###*
    @private
  ###
  onConnected_: ->
    @fb_.api '/me', (response) =>
      @userStore.loginFacebookUser response

  logout: ->
    # The FB.logout log the person out of Facebook, which is not we want.
    # @userStore.logout()

Comment some code in app.Facebook.

Comment some code in app.Facebook.


module.exports = (grunt) ->

# =============================== Load plugins =============================== #
  grunt.loadNpmTasks 'grunt-eslint'
  grunt.loadNpmTasks 'grunt-travis-lint'
  grunt.loadNpmTasks 'grunt-jsonlint'
  grunt.loadNpmTasks 'grunt-coffeelint'
  grunt.loadNpmTasks 'grunt-mdlint'

# ================================= Settings ================================= #
  # Force use of Unix newlines
  grunt.util.linefeed = '\n'

  # Project configuration
  # =====================
  grunt.initConfig

    # Load external configurations
    pkg: grunt.file.readJSON 'package.json'

# =================================== Task =================================== #

    # Linters
    # ------

    # JS
    eslint:
      options:
        configFile: '.eslintrc.json'
      target: ['*.js']

    # JSON
    jsonlint:
      default:
        src: [
          "*.json"
          ".coffeelintrc"
          ".jshintrc"
        ]

    # Coffee
    coffeelint:
      default: [
        '*.coffee'
      ]
      options:
        configFile: '.coffeelintrc'

    # MarkDown
    mdlint:
      default: [
        '*.md'
      ]

# ============================== Callable tasks ============================== #
  grunt.registerTask 'travis', [
    'lint'
  ]

  grunt.registerTask 'lint', [
    'eslint',
    'jsonlint',
    'coffeelint'
    'mdlint'
    'travis-lint'
  ]

  # Alias
  grunt.registerTask 'default', 'travis'

module.exports = (grunt) ->

# =============================== Load plugins =============================== #
  grunt.loadNpmTasks 'grunt-eslint'
  grunt.loadNpmTasks 'grunt-travis-lint'
  grunt.loadNpmTasks 'grunt-jsonlint'
  grunt.loadNpmTasks 'grunt-coffeelint'
  grunt.loadNpmTasks 'grunt-mdlint'

# ================================= Settings ================================= #
  # Force use of Unix newlines
  grunt.util.linefeed = '\n'

  # Project configuration
  # =====================
  grunt.initConfig

    # Load external configurations
    pkg: grunt.file.readJSON 'package.json'

# =================================== Task =================================== #

    # Linters
    # ------

    # JS
    eslint:
      options:
        configFile: '.eslintrc.json'
      target: ['*.js']

    # JSON
    jsonlint:
      default:
        src: [
          "*.json"
          ".coffeelintrc"
          ".jshintrc"
        ]

    # Coffee
    coffeelint:
      default: [
        '*.coffee'
      ]
      options:
        configFile: '.coffeelintrc'

    # MarkDown
    mdlint:
      default: [
        '*.md'
      ]

# ============================== Callable tasks ============================== #
  grunt.registerTask 'travis', [
    'eslint',
    'jsonlint',
    'coffeelint'
    'travis-lint'
  ]

  grunt.registerTask 'lint', [
    'eslint',
    'jsonlint',
    'coffeelint'
    'mdlint'
    'travis-lint'
  ]

  # Alias
  grunt.registerTask 'default', 'lint'

Fix mdlint VS NodeJS >= 5 for Travis

Fix mdlint VS NodeJS >= 5 for Travis


#= require jquery
#= require jquery_ujs

#= require jquery-fileupload/basic
#= require jquery-fileupload/vendor/tmpl
#= require attachments
#= require dropzone_effects

#= require bootstrap-sprockets

#= require moment
#= require moment/de
#= require bootstrap-datetimepicker

#= require marked.min
# http://github.com/toopay/bootstrap-markdown
#= require bootstrap-markdown

# NOTE: requires api controller to render markdown preview.
#       see echo-live for code
# require markdown_setup

#= require flyout
#= require cocoon

# NOTE: gem's not getting loaded for unknown reason
# require editable/bootstrap-editable
# require editable/rails

#= require jquery.autogrow
#= require clndr
#= require json3
#= require underscore

$ ->
  $('.datepicker').datetimepicker
    language: 'de'
    pick12HourFormat: false
    minuteStepping: 15

  $('textarea').autoGrow()

  $(document).on "click", ".panel-toggle-btn", ->
    $(this).closest(".panel").toggleClass "closed"

#= require jquery
#= require jquery_ujs

#= require jquery-fileupload/basic
#= require jquery-fileupload/vendor/tmpl
#= require attachments
#= require dropzone_effects

#= require bootstrap-sprockets

#= require moment
#= require moment/de
#= require bootstrap-datetimepicker

#= require marked.min
# http://github.com/toopay/bootstrap-markdown
#= require bootstrap-markdown

# NOTE: requires api controller to render markdown preview.
#       see echo-live for code
# require markdown_setup

#= require flyout
#= require cocoon

# NOTE: gem's not getting loaded for unknown reason
# require editable/bootstrap-editable
# require editable/rails

#= require jquery.autogrow
#= require clndr
#= require json3
#= require underscore

$ ->
  $('.datepicker').datetimepicker
    locale: 'de'
    pick12HourFormat: false
    minuteStepping: 15

  $('textarea').autoGrow()

  $(document).on "click", ".panel-toggle-btn", ->
    $(this).closest(".panel").toggleClass "closed"

Fix datetimepicker call after plugin update


# TODO: API for load missing content or binding to page events
$ ->
  setup_listener()
  load_missing_content()

setup_listener = ->
  $(document).on 'progressive_render:end', load_missing_content
  $(document).on 'ajax:end', load_missing_content
  $(document).on 'turbolinks:load', load_missing_content if window.Turbolinks

load_missing_content = ->
  $('[data-progressive-render-placeholder=true]').each ->
    $this = $(this)
    # Don't re-process div's we've already seen
    return if $this.data('progressive-render-setup')
    $this.data('progressive-render-setup', true)

    # Start the load
    $.ajax url: $this.data('progressive-render-path'), cache: false, success: (response) ->
      $this.html(response);
      $(document).trigger('progressive_render:end')

# TODO: API for load missing content or binding to page events
$ ->
  setup_listener()
  load_missing_content()

setup_listener = ->
  $(document).on 'progressive_render:end', load_missing_content
  $(document).on 'ajax:end', load_missing_content
  $(document).on 'turbolinks:load', load_missing_content if window.Turbolinks

load_missing_content = ->
  $('[data-progressive-render-placeholder=true]').each ->
    $this = $(this)
    # Remove the designation on this partial from the DOM so we don't attempt to re-load it later.
    $this.attr('data-progressive-render-placeholder', false)

    # Start the load
    $.ajax url: $this.data('progressive-render-path'), cache: false, success: (response) ->
      $this.html(response);
      $(document).trigger('progressive_render:end')

Modify the DOM instead of setting the 'data' prop via jQuery to mark a section as 'progressive-loaded'

Defect:
This was exposed as an issue by another bug which was loading the entire page on partial load and re-loading the javascript.
The result was an infinite loop of reloading the content.

Fix:
Modifying the DOM of the element we don't replace (the main placeholder) ensure we don't run into this class of issues.


class InteractorEmptyView extends Backbone.Marionette.ItemView
  tagName: 'span'
  template: "fact_relations/interactor_empty"

class InteractorView extends Backbone.Marionette.Layout
  tagName: 'span'
  className: 'separator-list-item'
  template: "fact_relations/interactor"

class window.InteractorsView extends Backbone.Marionette.CompositeView
  template: "fact_relations/interactors"
  emptyView: InteractorEmptyView
  itemView: InteractorView
  itemViewContainer: ".js-interactors-collection"
  events:
    'click a.showAll' : 'showAll'

  initialize: (options) ->
    @model = new Backbone.Model
    @fetch()

  fetch: ->
    @collection.fetch success: =>
      @model.set
        numberNotDisplayed: @collection.totalRecords - @collection.length
        multipleNotDisplayed: (@collection.totalRecords - @collection.length)>1
      @render()

  templateHelpers: =>
    multiplicity = if @collection.totalRecords > 1 then 'plural' else 'singular'
    translation = "fact_#{@collection.type}_past_#{multiplicity}_action"

    past_action: Factlink.Global.t[translation]

  showAll: (e) ->
    e.stopPropagation()
    e.preventDefault()
    @collection.howManyPer(1000000)
    @fetch()

class InteractorEmptyView extends Backbone.Marionette.ItemView
  tagName: 'span'
  template: "fact_relations/interactor_empty"

class InteractorView extends Backbone.Marionette.Layout
  tagName: 'span'
  className: 'separator-list-item'
  template: "fact_relations/interactor"

class window.InteractorsView extends Backbone.Marionette.CompositeView
  template: "fact_relations/interactors"
  emptyView: InteractorEmptyView
  itemView: InteractorView
  itemViewContainer: ".js-interactors-collection"
  events:
    'click a.showAll' : 'showAll'

  initialize: (options) ->
    @model = new Backbone.Model
    @fetch()

  fetch: ->
    @collection.fetch success: =>
      @model.set
        numberNotDisplayed: @collection.totalRecords - @collection.length
        multipleNotDisplayed: (@collection.totalRecords - @collection.length)>1
      @render()

  singularType: ->
    switch @collection.type
      when 'believes' then 'believe'
      when 'disbelieves' then 'disbelieve'
      when 'doubts' then 'doubt'

  templateHelpers: =>
    multiplicity = if @collection.totalRecords > 1 then 'plural' else 'singular'
    translation = "fact_#{@singularType()}_past_#{multiplicity}_action"

    past_action: Factlink.Global.t[translation]

  showAll: (e) ->
    e.stopPropagation()
    e.preventDefault()
    @collection.howManyPer(1000000)
    @fetch()

Use singular type in InteractorsView

Use singular type in InteractorsView


window.Backbone ||= {}
window.Backbone.Views ||= {}

class Backbone.Views.ReportEditVisualisationView extends Backbone.Diorama.NestingView
  className: 'modal report-edit-visualisation'
  template: Handlebars.templates['report_edit_visualisation.hbs']

  events:
    "click .close": "close"
    "click .save": "save"
    "change select[name='visualisation']": 'updateVisualisationType'

  initialize: (options) ->
    @visualisation = options.visualisation
    @listenTo @visualisation, 'change', @render
    @render()

  render: =>
    @closeSubViews()
    @$el.html(@template(
      thisView: @
      indicator: @visualisation.get('indicator').toJSON()
      visualisation: @visualisation
      visualisationType: @visualisation.get('type')
      visualisationViewName: @visualisation.get('type') + "View"
      visualisationTypes: Backbone.Models.Visualisation.visualisationTypes
    ))
    @renderSubViews()
    $('body').addClass('stop-scrolling')

    return @

  save: ->
    @visualisation.save()

  onClose: ->
    $('body').removeClass('stop-scrolling')
    @trigger('close')
    @closeSubViews()
    @stopListening()

  updateVisualisationType: =>
    type = @$el.find("select[name='visualisation']").val()
    @visualisation.set('type', type)

window.Backbone ||= {}
window.Backbone.Views ||= {}

class Backbone.Views.ReportEditVisualisationView extends Backbone.Diorama.NestingView
  className: 'modal report-edit-visualisation'
  template: Handlebars.templates['report_edit_visualisation.hbs']

  events:
    "click .close": "closeModal"
    "click .save": "save"
    "change select[name='visualisation']": 'updateVisualisationType'

  initialize: (options) ->
    @visualisation = options.visualisation
    @listenTo @visualisation, 'change', @render
    @render()

  render: =>
    @closeSubViews()
    @$el.html(@template(
      thisView: @
      indicator: @visualisation.get('indicator').toJSON()
      visualisation: @visualisation
      visualisationType: @visualisation.get('type')
      visualisationViewName: @visualisation.get('type') + "View"
      visualisationTypes: Backbone.Models.Visualisation.visualisationTypes
    ))
    @renderSubViews()
    $('body').addClass('stop-scrolling')

    return @

  save: ->
    @visualisation.save()

  closeModal: ->
    @trigger('close')
    @close()

  onClose: ->
    $('body').removeClass('stop-scrolling')
    @closeSubViews()
    @stopListening()

  updateVisualisationType: =>
    type = @$el.find("select[name='visualisation']").val()
    @visualisation.set('type', type)

Revert removal of closeModal function, _events get cleared before onClose


App.AdvancedSearch =

  advanced_search_terms: ->
    $('#js-advanced-search').data('advanced-search-terms')

  toggle_form: (event) ->
    event.preventDefault()
    $('#js-advanced-search').slideToggle()

  toggle_date_options: ->
    if $('#js-advanced-search-date-min').val() == 'custom'
      $('#js-custom-date').show()
      $( ".js-calendar" ).datepicker( "option", "disabled", false )
    else
      $('#js-custom-date').hide()
      $( ".js-calendar" ).datepicker( "option", "disabled", true )

  init_calendar: ->
    locale = $('#js-locale').data('current-locale')
    if locale == 'en'
      locale = ''

    $('.js-calendar').datepicker
      regional: locale
      maxDate:  "+0d"
    $('.js-calendar-full').datepicker
      regional: locale

  initialize: ->
    App.AdvancedSearch.init_calendar()

    if App.AdvancedSearch.advanced_search_terms()
      $('#js-advanced-search').show()
      App.AdvancedSearch.toggle_date_options()

    $('#js-advanced-search-title').on
      click: (event) ->
        App.AdvancedSearch.toggle_form(event)

    $('#js-advanced-search-date-min').on
      change: ->
        App.AdvancedSearch.toggle_date_options()

Remove unnecesary space on coffeescript file


ETahi.PaperIndexView = Ember.View.extend
  setBackgroundColor:(->
    $('html').addClass('matte')
  ).on('didInsertElement')

  resetBackgroundColor:(->
    $('html').removeClass('matte')
  ).on('willDestroyElement')

  setupScrollFixing: (->
    $('.control-bar').scrollToFixed()
    $('#tahi-container > main > aside > div').scrollToFixed
      marginTop: $('.control-bar').outerHeight(true)
      unfixed: ->
        $(this).css('top', '0px')
  ).on('didInsertElement')

Add scrollToFix for content bar in paper show page

[Fixes #69382112]


class Motion
  constructor: (@editor) ->
  isComplete: -> true

class MoveLeft extends Motion
  execute: ->
    {column, row} = @editor.getCursorScreenPosition()
    @editor.moveCursorLeft() if column > 0

  select: ->
    {column, row} = @editor.getCursorScreenPosition()

    if column > 0
      @editor.selectLeft()
      true
    else
      false

class MoveRight extends Motion
  execute: ->
    # FIXME: Don't run off the end
    {column, row} = @editor.getCursorScreenPosition()
    @editor.moveCursorRight()

class MoveUp extends Motion
  execute: ->
    @editor.moveCursorUp()

class MoveDown extends Motion
  execute: ->
    @editor.moveCursorDown()

class MoveToPreviousWord extends Motion
  execute: ->
    @editor.moveCursorToBeginningOfWord()

  select: ->
    @editor.selectToBeginningOfWord()
    true

class MoveToNextWord extends Motion
  execute: ->
    @editor.moveCursorToBeginningOfNextWord()

  select: ->
    @editor.selectToBeginningOfNextWord()
    true

class MoveToNextParagraph extends Motion
  execute: ->
    @editor.setCursorScreenPosition(@nextPosition())

  select: ->
    @editor.selectToPosition(@nextPosition())
    true

  nextPosition: ->
    @editor.getCurrentParagraphBufferRange().end

module.exports = { Motion, MoveLeft, MoveRight, MoveUp, MoveDown, MoveToNextWord, MoveToPreviousWord, MoveToNextParagraph }

class Motion
  constructor: (@editor) ->
  isComplete: -> true

class MoveLeft extends Motion
  execute: ->
    {column, row} = @editor.getCursorScreenPosition()
    @editor.moveCursorLeft() if column > 0

  select: ->
    {column, row} = @editor.getCursorScreenPosition()

    if column > 0
      @editor.selectLeft()
      true
    else
      false

class MoveRight extends Motion
  execute: ->
    # FIXME: Don't run off the end
    {column, row} = @editor.getCursorScreenPosition()
    @editor.moveCursorRight()

class MoveUp extends Motion
  execute: ->
    @editor.moveCursorUp()

class MoveDown extends Motion
  execute: ->
    {column, row} = @editor.getCursorScreenPosition()
    @editor.moveCursorDown() if row < (@editor.getBuffer().getLineCount() - 1)

class MoveToPreviousWord extends Motion
  execute: ->
    @editor.moveCursorToBeginningOfWord()

  select: ->
    @editor.selectToBeginningOfWord()
    true

class MoveToNextWord extends Motion
  execute: ->
    @editor.moveCursorToBeginningOfNextWord()

  select: ->
    @editor.selectToBeginningOfNextWord()
    true

class MoveToNextParagraph extends Motion
  execute: ->
    @editor.setCursorScreenPosition(@nextPosition())

  select: ->
    @editor.selectToPosition(@nextPosition())
    true

  nextPosition: ->
    @editor.getCurrentParagraphBufferRange().end

module.exports = { Motion, MoveLeft, MoveRight, MoveUp, MoveDown, MoveToNextWord, MoveToPreviousWord, MoveToNextParagraph }

Fix the down motion to stop on last line


SHARED_DATA = null
SHARED_COLLECTION = null

class Skr.Models.Location extends Skr.Models.Base

    cacheDuration: [1, 'day']

    mixins: [ 'FileSupport', 'HasCodeField' ]

    props:
        id:            {type:"integer"}
        code:          {type:"code"}
        name:          {type:"string"}
        address_id:    {type:"integer"}
        is_active:     {type:"boolean", "default":true}
        gl_branch_code:{type:"string", "default":"01"}
        logo:     "file"
        options:  "any"

    associations:
        address:  { model: "Address" }
        sku_locs: { collection: "SkuLoc" }

    @initialize: (data) ->
        SHARED_DATA = data.locations

Object.defineProperties Skr.Models.Location, {
    all:
        get: ->
            SHARED_COLLECTION ||= new Skr.Models.Location.Collection( SHARED_DATA )
    default:
        get: ->
            @all.findWhere(code: 'DEFAULT') || @all.first()
}

SHARED_DATA = null
SHARED_COLLECTION = null

class Skr.Models.Location extends Skr.Models.Base

    cacheDuration: [1, 'day']

    mixins: [ 'FileSupport', 'HasCodeField' ]

    props:
        id:            {type:"integer"}
        code:          {type:"code"}
        name:          {type:"string"}
        address_id:    {type:"integer"}
        is_active:     {type:"boolean", "default":true}
        gl_branch_code:{type:"string", "default":"01"}
        logo:     "file"
        options:  "any"

    associations:
        address:  { model: "Address" }
        sku_locs: { collection: "SkuLoc" }

    @initialize: (data) ->
        SHARED_DATA = data.locations

    addChangeSet: (change) ->
        if change.update.logo
            change.update.logo[1] = change.update.logo[1].logo
        super

Object.defineProperties Skr.Models.Location, {
    all:
        get: ->
            SHARED_COLLECTION ||= new Skr.Models.Location.Collection( SHARED_DATA )
    default:
        get: ->
            @all.findWhere(code: 'DEFAULT') || @all.first()
}

Adjust logo property on change

Adjust logo property on change

Since the onchange does slightly wrong thing


geyser = do ->
  parse = (spec) ->
    dotIndex = spec.indexOf '.'
    switch dotIndex
      when -1
        tag: spec
      when 0
        tag: 'div'
        classes: split (spec.substr 1), '.'
      else
        tokens = split spec, '.'
        tag: tokens.shift()
        classes: tokens

  generate = (arg) ->
    console.assert (isString arg) or (isArray arg)
    specs = if isString arg then words arg else arg
    map specs, (spec) ->
      el = parse spec
      (content) ->
        el: el
        content: content

  renderOne = (el, content) ->
    classes = if el.classes then ' class="' + (join el.classes, ' ') + '"' else ''
    "<#{el.tag}#{classes}>#{content}</#{el.tag}>"

  render = (html) ->
    if isArray html.content
      renderOne html.el, (join (map html.content, render), '')
    else
      renderOne html.el, html.content

  generate: generate
  render: render

geyser = do ->

  _cache = {}

  parse = (spec) ->
    dotIndex = spec.indexOf '.'
    switch dotIndex
      when -1
        tag: spec
      when 0
        tag: 'div'
        classes: split (spec.substr 1), '.'
      else
        tokens = split spec, '.'
        tag: tokens.shift()
        classes: tokens

  getElement = (spec) ->
    if el = _cache[spec]
      el
    else
      _cache[spec] = parse spec

  generate = (arg) ->
    console.assert (isString arg) or (isArray arg)
    specs = if isString arg then words arg else arg
    map specs, (spec) ->
      el = getElement spec
      (content) ->
        el: el
        content: content

  renderOne = (el, content) ->
    classes = if el.classes then ' class="' + (join el.classes, ' ') + '"' else ''
    "<#{el.tag}#{classes}>#{content}</#{el.tag}>"

  render = (html) ->
    if isArray html.content
      renderOne html.el, (join (map html.content, render), '')
    else
      renderOne html.el, html.content

  generate: generate
  render: render

Speed up geyser by caching known element types.
[PP-10]


React = require "react/addons"
classNames = require 'classnames'
{RetinaImg} = require 'nylas-component-kit'
{Actions, FocusedContentStore} = require "nylas-exports"

class DraftDeleteButton extends React.Component
  @displayName: 'DraftDeleteButton'
  @containerRequired: false

  @propTypes:
    selection: React.PropTypes.object.isRequired

  render: ->
    <button style={order:-100}
            className="btn btn-toolbar"
            title="Delete"
            onClick={@_destroySelected}>
      <RetinaImg name="icon-composer-trash.png" mode={RetinaImg.Mode.ContentIsMask} />
    </button>

  _destroySelected: =>
    for item in @props.selection.items()
      Actions.queueTask(new DestroyDraftTask(draftClientId: item.clientId))
    @props.selection.clear()

module.exports = {DraftDeleteButton}

React = require "react/addons"
classNames = require 'classnames'
{RetinaImg} = require 'nylas-component-kit'
{Actions, FocusedContentStore, DestroyDraftTask} = require "nylas-exports"

class DraftDeleteButton extends React.Component
  @displayName: 'DraftDeleteButton'
  @containerRequired: false

  @propTypes:
    selection: React.PropTypes.object.isRequired

  render: ->
    <button style={order:-100}
            className="btn btn-toolbar"
            title="Delete"
            onClick={@_destroySelected}>
      <RetinaImg name="icon-composer-trash.png" mode={RetinaImg.Mode.ContentIsMask} />
    </button>

  _destroySelected: =>
    for item in @props.selection.items()
      Actions.queueTask(new DestroyDraftTask(draftClientId: item.clientId))
    @props.selection.clear()

module.exports = {DraftDeleteButton}

fix(drafts): Fix missing import, resolves Sentry 4041


express            = require 'express'
bodyParser         = require 'body-parser'
errorHandler       = require 'errorhandler'
meshbluHealthcheck = require 'express-meshblu-healthcheck'
morgan             = require 'morgan'
MessagesController = require './src/controllers/messages-controller'

messagesController = new MessagesController

PORT  = process.env.PORT ? 80

app = express()
app.use morgan('combined', immediate: false)
app.use bodyParser.json({limit: '50mb'})
app.use errorHandler()
app.use meshbluHealthcheck()

app.post '/messages', messagesController.create

server = app.listen PORT, ->
  host = server.address().address
  port = server.address().port

  console.log "Server running on #{host}:#{port}"

bodyParser         = require 'body-parser'
errorHandler       = require 'errorhandler'
express            = require 'express'
meshbluHealthcheck = require 'express-meshblu-healthcheck'
morgan             = require 'morgan'
AuthenticateController = require './src/controllers/authenticate-controller'
MessagesController     = require './src/controllers/messages-controller'

authenticateController = new AuthenticateController
messagesController     = new MessagesController

PORT  = process.env.PORT ? 80

app = express()
app.use morgan('combined', immediate: false)
app.use bodyParser.json({limit: '50mb'})
app.use errorHandler()
app.use meshbluHealthcheck()

app.post '/authenticate', authenticateController.authenticate
app.post '/messages', messagesController.create

server = app.listen PORT, ->
  host = server.address().address
  port = server.address().port

  console.log "Server running on #{host}:#{port}"

Add authentication controller to routes

Add authentication controller to routes


{expect} = require "chai"
utils = require "../../utils"

{Collections} = utils.require "base"

describe "step_interpolator_transform module", ->
  source = {start: 0, end: 10}
  target = {start: 20, end: 80}

  generate_jitter = ->
    Collections("Jitter").create
      width: 1
      center: 0
      distribution: 'uniform'

  describe "Jitter with uniform", ->
    transform = generate_jitter()
    transform.set('distribution', 'uniform')

    it "should average the fixed values", ->
      N = 1000
      vals =  Array.apply(null, Array(N)).map ->
                5
      rets = transform.v_compute(vals)

      add(a, b) ->
        return a+b

      thesum = rets.reduce(add, 0)
      thediff = (thesum/N) - 5
      expect(thediff).to.be.below 0.01

  describe "Jitter with normal", ->
    transform = generate_jitter()
    transform.set('distribution', 'normal')

    it "should average the fixed values", ->
      N = 1000
      vals =  Array.apply(null, Array(N)).map ->
                5
      rets = transform.v_compute(vals)

      add(a, b) ->
        return a+b

      thesum = rets.reduce(add, 0)
      thediff = (thesum/N) - 5
      expect(thediff).to.be.below 0.01

{expect} = require "chai"
utils = require "../../utils"

{Collections} = utils.require "base"
Jitter = utils.require("models/transforms/jitter_transform").Model

describe "step_interpolator_transform module", ->
  source = {start: 0, end: 10}
  target = {start: 20, end: 80}

  generate_jitter = ->
    new Jitter({
      width: 1,
      center: 0,
      distribution: 'uniform'
    })

  describe "Jitter with uniform", ->
    transform = generate_jitter()
    transform.set('distribution', 'uniform')

    it "should average the fixed values", ->
      N = 1000
      vals =  Array.apply(null, Array(N)).map ->
                5
      rets = transform.v_compute(vals)

      add(a, b) ->
        return a+b

      thesum = rets.reduce(add, 0)
      thediff = (thesum/N) - 5
      expect(thediff).to.be.below 0.01

  describe "Jitter with normal", ->
    transform = generate_jitter()
    transform.set('distribution', 'normal')

    it "should average the fixed values", ->
      N = 1000
      vals =  Array.apply(null, Array(N)).map ->
                5
      rets = transform.v_compute(vals)

      add(a, b) ->
        return a+b

      thesum = rets.reduce(add, 0)
      thediff = (thesum/N) - 5
      expect(thediff).to.be.below 0.01

Convert to the newer unit test methodology.


_ = require 'underscore'

module.exports =
  projectPaths: null
  fuzzyFinderView: null
  loadPathsTask: null

  activate: (state) ->
    rootView.command 'fuzzy-finder:toggle-file-finder', =>
      @createView().toggleFileFinder()
    rootView.command 'fuzzy-finder:toggle-buffer-finder', =>
      @createView().toggleBufferFinder()
    rootView.command 'fuzzy-finder:find-under-cursor', =>
      @createView().findUnderCursor()

    if rootView.project.getPath()?
      LoadPathsTask = require 'fuzzy-finder/lib/load-paths-task'
      @loadPathsTask = new LoadPathsTask((paths) => @projectPaths = paths)
      @loadPathsTask.start()

    for path, lastOpened of state
      session = _.detect rootView.project.getEditSessions(), (editSession) ->
        editSession.getPath() is path
      session?.lastOpened = lastOpened

  deactivate: ->
    @loadPathsTask?.terminate()
    @loadPathsTask = null
    @fuzzyFinderView?.cancel()
    @fuzzyFinderView = null
    @projectPaths = null

  serialize: ->
    @fuzzyFinderView?.getOpenedPaths()

  createView:  ->
    unless @fuzzyFinderView
      FuzzyFinderView  = require 'fuzzy-finder/lib/fuzzy-finder-view'
      @fuzzyFinderView = new FuzzyFinderView()
      if @projectPaths? and not @fuzzyFinderView.projectPaths?
        @fuzzyFinderView.projectPaths = @projectPaths
        @fuzzyFinderView.reloadProjectPaths = false
    @fuzzyFinderView

_ = require 'underscore'

module.exports =
  projectPaths: null
  fuzzyFinderView: null
  loadPathsTask: null

  activate: (state) ->
    rootView.command 'fuzzy-finder:toggle-file-finder', =>
      @createView().toggleFileFinder()
    rootView.command 'fuzzy-finder:toggle-buffer-finder', =>
      @createView().toggleBufferFinder()
    rootView.command 'fuzzy-finder:find-under-cursor', =>
      @createView().findUnderCursor()

    if rootView.project.getPath()?
      LoadPathsTask = require 'fuzzy-finder/lib/load-paths-task'
      @loadPathsTask = new LoadPathsTask((paths) => @projectPaths = paths)
      @loadPathsTask.start()

    for editSession in rootView.project.getEditSessions()
      editSession.lastOpened = state[editSession.getPath()]

  deactivate: ->
    @loadPathsTask?.terminate()
    @loadPathsTask = null
    @fuzzyFinderView?.cancel()
    @fuzzyFinderView = null
    @projectPaths = null

  serialize: ->
    @fuzzyFinderView?.getOpenedPaths()

  createView:  ->
    unless @fuzzyFinderView
      FuzzyFinderView  = require 'fuzzy-finder/lib/fuzzy-finder-view'
      @fuzzyFinderView = new FuzzyFinderView()
      if @projectPaths? and not @fuzzyFinderView.projectPaths?
        @fuzzyFinderView.projectPaths = @projectPaths
        @fuzzyFinderView.reloadProjectPaths = false
    @fuzzyFinderView

Simplify setting lastOpened serialized value

Iterate over the project's edit sessions instead of
the stored paths in the serialized state.


"*":
  "atom-beautify":
    general:
      _analyticsUserId: "016f8b6e-eda5-4d72-acc8-57bcde20fdff"
  core:
    autoHideMenuBar: true
    disabledPackages: [
      "exception-reporting"
      "linter-perl"
      "perltidy"
    ]
    projectHome: "/home/caramelomartins/Projects"
    themes: [
      "nucleus-dark-ui"
      "atom-material-syntax"
    ]
  editor:
    invisibles: {}
    showIndentGuide: true
    tabLength: 4
  linter: {}
  "linter-htmlhint": {}
  "linter-jshint": {}
  "linter-shellcheck":
    enableNotice: true
  "markdown-preview":
    useGitHubStyle: true
  "one-dark-ui": {}
  "travis-ci-status": {}
  welcome:
    showOnStartup: false

"*":
  "atom-beautify":
    general:
      _analyticsUserId: "016f8b6e-eda5-4d72-acc8-57bcde20fdff"
  core:
    autoHideMenuBar: true
    disabledPackages: [
      "exception-reporting"
      "linter-perl"
      "perltidy"
    ]
    projectHome: "/home/caramelomartins/Projects"
    themes: [
      "nucleus-dark-ui"
      "atom-material-syntax"
    ]
  editor:
    fontSize: 12
    invisibles: {}
    showIndentGuide: true
    tabLength: 4
  linter: {}
  "linter-htmlhint": {}
  "linter-jshint": {}
  "linter-shellcheck":
    enableNotice: true
  "markdown-preview":
    useGitHubStyle: true
  "one-dark-ui": {}
  "travis-ci-status": {}
  welcome:
    showOnStartup: false

Change font size in atom

Change font size in atom


define [
], () ->
	class LabelsMaster
		constructor: (@ide, @$scope) ->

			@_state = {
				documents: {}
			}

			@$scope.$on 'doc:labels:updated', (e, data) =>
				if data.docId and data.labels
					@_state.documents[data.docId] = data.labels

			@$scope.$on 'entity:deleted', (e, entity) =>
				if entity.type == 'doc'
					delete @_state.documents[entity.id]

			@$scope.$on 'file:upload:complete', (e, upload) =>
				if upload.entity_type == 'doc'
					@loadDocLabelsFromServer(upload.entity_id)

			# load project labels now
			@loadProjectLabelsFromServer()

		getAllLabels: () ->
			_.flatten(labels for docId, labels of @_state.documents)

		## Loaders
		loadProjectLabelsFromServer: () ->
			$.get(
				"/project/#{window.project_id}/labels"
				, (data) =>
					if data.projectLabels
						for docId, docLabels of data.projectLabels
							@_state.documents[docId] = docLabels
			)

		loadDocLabelsFromServer: (docId) ->
			$.get(
				"/project/#{window.project_id}/#{docId}/labels"
				, (data) =>
					if data.docId and data.labels
						@_state.documents[data.docId] = data.labels
			)

define [
], () ->
	class LabelsMaster
		constructor: (@ide, @$scope) ->

			@_state = {
				documents: {}
			}

			@$scope.$on 'doc:labels:updated', (e, data) =>
				if data.docId and data.labels
					@_state.documents[data.docId] = data.labels

			@$scope.$on 'entity:deleted', (e, entity) =>
				if entity.type == 'doc'
					delete @_state.documents[entity.id]

			@$scope.$on 'file:upload:complete', (e, upload) =>
				if upload.entity_type == 'doc'
					@loadDocLabelsFromServer(upload.entity_id)

			# load project labels now
			@loadProjectLabelsFromServer()

		getAllLabels: () ->
			_.flatten(labels for docId, labels of @_state.documents)

		## Loaders
		loadProjectLabelsFromServer: () ->
			@ide.$http
				.get("/project/#{window.project_id}/labels")
				.success (data) =>
					if data.projectLabels
						for docId, docLabels of data.projectLabels
							@_state.documents[docId] = docLabels

		loadDocLabelsFromServer: (docId) ->
			@ide.$http
				.get("/project/#{window.project_id}/#{docId}/labels")
				.success (data) =>
					if data.docId and data.labels
						@_state.documents[data.docId] = data.labels

Use ide.$http, rather than jquery

Use ide.$http, rather than jquery


window.collectionDifference = (args...) ->
  utils = new CollectionUtils()
  utils.difference args...

window.collectionMap = (args...) ->
  utils = new CollectionUtils()
  utils.map(args...)

class window.CollectionUtils
  constructor: (eventAggregator)->
    @eventAggregator = eventAggregator || new Backbone.Marionette.EventAggregator

  listenTo: (args...)=>
    @eventAggregator.listenTo args...

  difference: (resultCollection, onField, collection1, collections...) =>
    reset = ->
     forbidden_fields = _.union(( for col in collections
        if col.pluck
          col.pluck(onField)
        else
          _.pluck(col,onField)
     )...)
     diffmodels = collection1.reject (model) => model.get(onField) in forbidden_fields
     resultCollection.reset diffmodels

    @listenTo collection1, 'add reset remove change', reset
    for collection in collections
      if collection.on?
        @listenTo collection, 'add reset remove change', reset

    reset()
    resultCollection

  union: (resultCollection, collections...)->
    reset = ->
      resultCollection.reset(_.union (col.models for col in collections)...)

    for collection in collections
      if collection.on
        @listenTo collection, 'add reset remove change', reset

    reset()
    resultCollection

  updatedClone: (resultCollection, collection)->
    @difference(resultCollection, null, collection)

  map: (resultCollection, collection, mapFunction) =>
    reset = ->
      resultCollection.reset()
      for model in collection.models
        resultCollection.add mapFunction(model)

    @listenTo collection, 'add remove reset change', reset
    reset()
    resultCollection

window.collectionDifference = (args...) ->
  utils = new CollectionUtils()
  utils.difference args...

window.collectionMap = (args...) ->
  utils = new CollectionUtils()
  utils.map(args...)

class window.CollectionUtils
  constructor: (eventAggregator)->
    @eventAggregator = eventAggregator || new Backbone.Wreqr.EventAggregator

  listenTo: (args...)=>
    @eventAggregator.listenTo args...

  difference: (resultCollection, onField, collection1, collections...) =>
    reset = ->
     forbidden_fields = _.union(( for col in collections
        if col.pluck
          col.pluck(onField)
        else
          _.pluck(col,onField)
     )...)
     diffmodels = collection1.reject (model) => model.get(onField) in forbidden_fields
     resultCollection.reset diffmodels

    @listenTo collection1, 'add reset remove change', reset
    for collection in collections
      if collection.on?
        @listenTo collection, 'add reset remove change', reset

    reset()
    resultCollection

  union: (resultCollection, collections...)->
    reset = ->
      resultCollection.reset(_.union (col.models for col in collections)...)

    for collection in collections
      if collection.on
        @listenTo collection, 'add reset remove change', reset

    reset()
    resultCollection

  updatedClone: (resultCollection, collection)->
    @difference(resultCollection, null, collection)

  map: (resultCollection, collection, mapFunction) =>
    reset = ->
      resultCollection.reset()
      for model in collection.models
        resultCollection.add mapFunction(model)

    @listenTo collection, 'add remove reset change', reset
    reset()
    resultCollection

Use Backbone.Wreqr.EventAggregator instead of Marionette's version


".text.roff":
	editor:
		commentStart: ".\\\" "

".source.pic":
	editor:
		commentStart: "# "

".text.runoff":
	editor:
		commentStart: ".! "

".text.roff":
	editor:
		commentStart: ".\\\" "

".source.pic":
	editor:
		commentStart: "# "
		increaseIndentPattern: "[\\[({:]\\s*$"
		decreaseIndentPattern: "^\\s*[\\])}]"

".text.runoff":
	editor:
		commentStart: ".! "

Add indentation settings for Pic

Add indentation settings for Pic


Settings = require 'settings-sharelatex'

module.exports = Features =
	externalAuthenticationSystemUsed: ->
		Settings.ldap? or Settings.saml? or Settings.overleaf?.oauth?

	hasFeature: (feature) ->
		switch feature
			when 'registration'
				return not Features.externalAuthenticationSystemUsed()
			when 'github-sync'
				return not Settings.disableGithubSync
			else
				throw new Error("unknown feature: #{feature}")

Settings = require 'settings-sharelatex'

module.exports = Features =
	externalAuthenticationSystemUsed: ->
		Settings.ldap? or Settings.saml? or Settings.overleaf?.oauth?

	hasFeature: (feature) ->
		switch feature
			when 'registration'
				return not Features.externalAuthenticationSystemUsed()
			when 'github-sync'
				return Settings.enableGithubSync
			else
				throw new Error("unknown feature: #{feature}")

Change to an 'enableGithubSync' setting

Change to an 'enableGithubSync' setting


class window.ExtendedFactTitleView extends Backbone.Marionette.Layout
  tagName: "header"
  id: "single-factlink-header"

  template: "facts/_extended_fact_title"

  events:
    "click .back-to-profile": "navigateToProfile"

  regions:
    creatorProfileRegion: ".created_by_region"

  onRender: ->
    @creatorProfileRegion.show new UserWithAuthorityBox(model: @model)

  navigateToProfile: (e) ->
    e.preventDefault()
    e.stopImmediatePropagation()
    Backbone.history.navigate @model.get('created_by').url, true

class window.ExtendedFactTitleView extends Backbone.Marionette.Layout
  tagName: "header"
  id: "single-factlink-header"

  template: "facts/extended_fact_title"

  events:
    "click .back-to-profile": "navigateToProfile"

  regions:
    creatorProfileRegion: ".created_by_region"

  onRender: ->
    @creatorProfileRegion.show new UserWithAuthorityBox(model: @model)

  navigateToProfile: (e) ->
    e.preventDefault()
    e.stopImmediatePropagation()
    Backbone.history.navigate @model.get('created_by').url, true

Use our correct template syntax

Use our correct template syntax


blacklist = require '../../lib/blacklist.coffee'
{ TEAM_BLOGS } = require('sharify').data

module.exports =
  patterns: [
    '^/personalize'
    '^/artsy-primer'
    '^/collect-art'
    '^/consign'
    '^/consign2'
    '^/signup'
    '^/login'
    '^/user/edit'
    '^/sale/.*'
    '^/auction/.*'
    '^/dev$'
    '^/inquiry/.*'
    '^/artwork/.*/checkout'
    '^/artwork/.*/thank-you'
    '^/jobs'
    '^/job/.*'
    TEAM_BLOGS or '^/test'
    '^/2016-year-in-art'
    '^/artist/.*'
    '^/venice-biennale.*'
    '^/gallery-partnerships.*'
    '^/article/.*'
  ]

  check: ->
    blacklist(@patterns).check()

blacklist = require '../../lib/blacklist.coffee'
{ TEAM_BLOGS } = require('sharify').data

module.exports =
  patterns: [
    '^/personalize'
    '^/artsy-primer'
    '^/collect-art'
    '^/consign'
    '^/consign2'
    '^/signup'
    '^/login'
    '^/user/edit'
    '^/sale/.*'
    '^/auction/.*'
    '^/dev$'
    '^/inquiry/.*'
    '^/artwork/.*/checkout'
    '^/artwork/.*/thank-you'
    '^/jobs'
    '^/job/.*'
    TEAM_BLOGS or '^/test'
    '^/2016-year-in-art'
    '^/artist/.*'
    '^/venice-biennale.*'
    '^/gallery-partnerships.*'
    '^/article/.*'
    '^/miami-fair-week'
  ]

  check: ->
    blacklist(@patterns).check()

Disable auction reminders on the Miami Fair Week page


TentStatus.Views.PostReplyForm = class PostReplyFormView extends TentStatus.Views.NewPostForm
  @template_name: '_post_reply_form'
  @view_name: 'post_reply_form'

  is_reply_form: true

  constructor: ->
    super

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

  hide: =>
    @visible = false
    DOM.hide(@el)

  show: =>
    @visible = true
    setImmediate =>
      @constructor.instances.all[@_child_views.MentionsAutoCompleteTextarea?[0]]?.textarea_view?.focus()
    if @ready
      DOM.show(@el)
    else
      @render()

  post: =>
    TentStatus.Models.Post.instances.all[@parent_view.post_cid]

  context: =>
    post = @post()
    _.extend {}, super,
      max_chars: TentStatus.config.MAX_LENGTH
      id: post.id
      entity: post.entity
      formatted:
        reply_to_entities: (_.map post.postMentions(), (m) => m.entity)

TentStatus.Views.PostReplyForm = class PostReplyFormView extends TentStatus.Views.NewPostForm
  @template_name: '_post_reply_form'
  @view_name: 'post_reply_form'

  is_reply_form: true

  constructor: ->
    super

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

  hide: =>
    @visible = false
    DOM.hide(@el)

  show: =>
    @visible = true
    setImmediate =>
      @constructor.instances.all[@_child_views.MentionsAutoCompleteTextarea?[0]]?.textarea_view?.focus()
    if @ready
      DOM.show(@el)
    else
      @render()

  post: =>
    TentStatus.Models.Post.instances.all[@parent_view.post_cid]

  context: =>
    post = @post()
    reply_to_entities = (_.map post.postMentions(), (m) => m.entity)
    reply_to_entities.push(post.entity) unless TentStatus.Helpers.isCurrentUserEntity(post.entity)
    _.extend {}, super,
      max_chars: TentStatus.config.MAX_LENGTH
      id: post.id
      entity: post.entity
      formatted:
        reply_to_entities: reply_to_entities

Add post author to prepopulated reply mentions


init = ->
  $("[data-provider='summernote']").summernote
    height: 300
    maximumImageFileSize: 262144 # 256KB

$(document).ready(init)

init = ->
  $("[data-provider='summernote']").summernote
    height: 300
    maximumImageFileSize: 262144 # 256KB
    toolbar: [
      ['style', ['style']],
      ['font', ['bold', 'italic', 'underline', 'clear']],
      ['fontname', ['fontname']],
      ['color', ['color']],
      ['para', ['ul', 'ol', 'paragraph']],
      ['table', ['table']],
      ['insert', ['link', 'picture', 'video']],
      ['view', ['fullscreen', 'codeview', 'help']],
    ]

$(document).ready(init)

Add italic to html container editor

Add italic to html container editor


_ = require 'lodash'

game = require '../game'
log = require '../log'
prompts = game.prompts

direction = require '../direction'
vectorMath = require '../vector-math'
calc = require '../calc'

Skill = class exports.Skill
	name: 'skill'
	# symbol: 'skill' # allow symbols for skills (to show in list maybe)

class exports.TentacleWhip extends Skill
	name: 'tentacle whip'

	askParams: (creature) ->
		# only called for player, to populate params to pass to #use()

		params = {}

		prompts.position 'Whip towards where?', default: creature
		.then (pos) -> params.position = pos

		.then -> params

	use: (creature, params) ->
		console.log 'whip:', params
		12

class exports.SenseLasagna extends Skill
	name: 'sense lasagna'

	use: (creature) ->
		game.message "
			You feel no presence of any lasagna aura in your vicinity. Disappointing.
		"

_ = require 'lodash'
Promise = require 'bluebird'

game = require '../game'
log = require '../log'
prompts = game.prompts

direction = require '../direction'
vectorMath = require '../vector-math'
calc = require '../calc'

Skill = class exports.Skill
	name: 'skill'
	# symbol: 'skill' # allow symbols for skills (to show in list maybe)

class exports.TentacleWhip extends Skill
	name: 'tentacle whip'

	askParams: (creature) ->
		# only called for player, to populate params to pass to #use()

		Promise.all [
			prompts.position 'Whip towards where?', default: creature
		]

		.then ([position]) -> {position}

	use: (creature, params) ->
		console.log 'whip:', params
		12

class exports.SenseLasagna extends Skill
	name: 'sense lasagna'

	use: (creature) ->
		game.message "
			You feel no presence of any lasagna aura in your vicinity. Disappointing.
		"

Tweak askParams of TentacleWhip skill

Tweak askParams of TentacleWhip skill


StepView = require './step.coffee'
Form = require '../../form/index.coffee'
LocationSearch = require '../../location_search/index.coffee'
template = -> require('../templates/basic_info.jade') arguments...

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

  __events__:
    'click button': 'serialize'

  serialize: (e) ->
    form = new Form model: @user, $form: @$('form')
    return unless form.start()
    e.preventDefault()
    form.state 'loading'

    @user.set form.data()

    # Temporary hack around API bug surrounding valid hash fields...
    collectorProfile = @user.related().collectorProfile
    id = collectorProfile.id
    collectorProfile.clear()
    collectorProfile.set _.extend id: id, @user.pick(collectorProfile.validHashFields)

    $.when.apply(null, [
      @user.save()
      collectorProfile.save()
    ])
      .always => @next()

  postRender: ->
    @locationSearch = new LocationSearch
      el: @$('.js-location-search')
      autofocus: false
      required: !@user.get('prequalified')

    @locationSearch.render @user.location()?.cityStateCountry()

    @listenTo @locationSearch, 'location:update', (location) ->
      @user.setLocation location

  remove: ->
    @locationSearch?.remove()
    super

StepView = require './step.coffee'
Form = require '../../form/index.coffee'
LocationSearch = require '../../location_search/index.coffee'
template = -> require('../templates/basic_info.jade') arguments...

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

  __events__:
    'click button': 'serialize'

  serialize: (e) ->
    form = new Form model: @user, $form: @$('form')
    return unless form.start()
    e.preventDefault()
    form.state 'loading'

    @user.set form.data()
    @user.related().collectorProfile.setWithValidAttributes @user.attributes

    $.when.apply(null, [
      @user.save()
      @user.related().collectorProfile.save()
    ])
      .always => @next()

  postRender: ->
    @locationSearch = new LocationSearch
      el: @$('.js-location-search')
      autofocus: false
      required: !@user.get('prequalified')

    @locationSearch.render @user.location()?.cityStateCountry()

    @listenTo @locationSearch, 'location:update', (location) ->
      @user.setLocation location

  remove: ->
    @locationSearch?.remove()
    super

Use hack for valid hash attr

Use hack for valid hash attr


vm = require 'vm'

exports.allowUnsafeEval = (fn) ->
  previousEval = global.eval
  try
    global.eval = (source) -> vm.runInThisContext(source)
    fn()
  finally
    global.eval = previousEval

exports.allowUnsafeNewFunction = (fn) ->
  previousFunction = global.Function
  try
    global.Function = exports.Function
    fn()
  finally
    global.Function = previousFunction

exports.Function = (paramLists..., body) ->
  params = []
  for paramList in paramLists
    params.push(paramList.split(/\s*,\s*/)...)

  vm.runInThisContext """
    (function(#{params.join(', ')}) {
      #{body}
    })
  """

vm = require 'vm'

exports.allowUnsafeEval = (fn) ->
  previousEval = global.eval
  try
    global.eval = (source) -> vm.runInThisContext(source)
    fn()
  finally
    global.eval = previousEval

exports.allowUnsafeNewFunction = (fn) ->
  previousFunction = global.Function
  try
    global.Function = exports.Function
    fn()
  finally
    global.Function = previousFunction

exports.Function = (paramLists..., body) ->
  params = []
  for paramList in paramLists
    if typeof paramList is 'string'
      paramList = paramList.split(/\s*,\s*/)
    params.push(paramList...)

  vm.runInThisContext """
    (function(#{params.join(', ')}) {
      #{body}
    })
  """

Allow arrays as param lists in

Allow arrays as param lists in


module.exports = (config) ->
  config.set
    basePath: ''
    frameworks: [ 'jasmine' ]
    files: [
      'public/vendor/zepto-1.1.4.js'
      'public/site.js'
      'spec/**/*.coffee'
    ]
    exclude: []
    preprocessors: {
      '**/*.coffee': ['coffee']
    }
    reporters: [ 'progress' ]
    port: 9876
    colors: true
    logLevel: config.LOG_INFO
    autoWatch: true
    browsers: [
      'Chrome'
    ]
    singleRun: false

module.exports = (config) ->
  config.set
    basePath: ''
    frameworks: [ 'jasmine' ]
    files: [
      'public/vendor/zepto-1.1.4.js'
      'spec/**/*.coffee'
    ]
    exclude: []
    preprocessors: {
      '**/*.coffee': ['coffee']
    }
    reporters: [ 'progress' ]
    port: 9876
    colors: true
    logLevel: config.LOG_INFO
    autoWatch: true
    browsers: [
      'Chrome'
    ]
    singleRun: false

Revert "re-run tests on changes in site.js"

This reverts commit 89e3a3d26be72fc3d49a89fc8cbc75abf73999ce.