function done(){
	console.log('nailed that done');
	var userName=document.getElementById('userInput').value;
	var time=document.getElementById('timeInput').value;
	window.localStorage.setItem("name", userName);
	window.localStorage.setItem("time", time);
	window.localStorage.setItem("changeTime", true);
	window.location="index.html";
}

function cancel(){
	window.location="index.html";
}

var dButton = document.getElementById('doneButton');
if(dButton.addEventListener){
	dButton.addEventListener("click", done, false);
}else if(dButton.attachEvent){
	dButton.attachEvent('onclick', done);
}

var cButton = document.getElementById('cancelButton');
if(cButton.addEventListener){
	cButton.addEventListener("click", cancel, false);
}else if(cButton.attachEvent){
	cButton.attachEvent('onclick', cancel);
}

$('#timeInput').val(window.localStorage.getItem('time'));
$('#userInput').val(window.localStorage.getItem('name'));

Read in settings when loading settings page.


var matchdep = require('matchdep');
module.exports = function(grunt){

  matchdep.filterDev('grunt-*').forEach(grunt.loadNpmTasks);
  grunt.loadTasks('tasks');
  var config = require('load-grunt-config')(grunt, {
    configPath: __dirname + '/tasks/options',
    init: false
  });

  config.pkg = require('./package');
  config.env = process.env;

  grunt.initConfig(config);

  grunt.registerTask('buildPackages', [
    'clean',
    'transpile:amd',
    'concat:globals',
    'browser:dist',
    'jshint'
  ]);

  grunt.registerTask('buildTests', ['concat:tests']);
  grunt.registerTask('dev', [ 'connect', 'watch' ]);
  grunt.registerTask('default', ['buildPackages', 'buildTests', 'connect', 'qunit', 'uglify']);
};

var matchdep = require('matchdep');
module.exports = function(grunt){

  matchdep.filterDev('grunt-*').forEach(grunt.loadNpmTasks);
  grunt.loadTasks('tasks');
  var config = require('load-grunt-config')(grunt, {
    configPath: __dirname + '/tasks/options',
    init: false
  });

  config.pkg = require('./package');
  config.env = process.env;

  grunt.initConfig(config);

  grunt.registerTask('buildPackages', [
    'clean',
    'transpile:amd',
    'concat:globals',
    'browser:dist',
    'jshint'
  ]);

  grunt.registerTask('buildTests', ['concat:tests']);
  grunt.registerTask('dev', [ 'connect', 'watch' ]);
  grunt.registerTask('test', ['buildPackages', 'buildTests', 'connect', 'qunit', 'uglify']);
  grunt.registerTask('default', ['test']);
};

Add missing task `grunt test`


isic.models.StudyModel = girder.Model.extend({
    resourceName: 'study',

    /**
     * Add a user to the study.
     */
    addUser: function (userId) {
        girder.restRequest({
            path: this.resourceName + '/' + this.get('_id') + '/user',
            type: 'POST',
            data: {
                userId: userId
            }
        }).done(_.bind(function (resp) {
            this.trigger('g:addedUser');
        }, this)).error(_.bind(function (err) {
            this.trigger('g:error', err);
        }, this));
    }
});

isic.models.StudyModel = girder.Model.extend({
    resourceName: 'study',

    /**
     * Add a user to the study.
     */
    addUser: function (userId) {
        girder.restRequest({
            path: this.resourceName + '/' + this.get('_id') + '/user',
            type: 'POST',
            data: {
                userId: userId
            }
        }).done(_.bind(function (resp) {
            this.trigger('g:addedUser');
        }, this)).error(_.bind(function (err) {
            this.trigger('g:error', err);
        }, this));
    },

    /**
     * Check whether user is a a study administrator.
     *
     * Returns a promise that is resolved with a single boolean argument that
     * indicates whether the user is a study administrator.
     *
     */
    isAdministrator: function (user) {
        var deferred = $.Deferred();
        if (user) {
            var groups = new girder.collections.GroupCollection();
            groups.once('g:changed', function () {
                if (!groups.isEmpty()) {
                    var groupId = groups.first().id;
                    var userGroups = user.get('groups');
                    var studyAdmin = _.contains(userGroups, groupId);
                    deferred.resolve(studyAdmin);
                } else {
                    deferred.resolve(false);
                }
            }, this).once('g:error', function () {
                deferred.reject();
            }, this).fetch({
                text: 'Study Administrators',
                exact: true
            });
        } else {
            deferred.resolve(false);
        }
        return deferred.promise();
    }
});

Add method to check whether a user is a study administrator


// folder-create-menu.js

jQuery(function($) {
    $('#create-menu').one('click', function() {
        $.ajax({
            type: 'GET',
            url: $('#create-menu-json')[0].href + encodeURIComponent(calli.getUserIri()),
            xhrFields: calli.withCredentials,
            dataType: 'json',
            success: function(data) {
                var ul = $('#create-menu-more');
                var section;
                $(data.rows).each(function(){
                    if (section != this[4]) {
                        if (section) {
                            ul.append('

');
                        }
                        section = this[4];
                        var header = $('

');
                        header.text(section);
                        ul.append(header);
                    }
                    var li = $('

');
                    var a = $('');
                    a.attr('href', this[0]);
                    a.text(this[1]);
                    if (this[2]) {
                        a.attr('title', this[2]);
                    }
                    if (this[3]) {
                        var img = $('');
                        img.attr('src', this[3]);
                        a.prepend(' ');
                        a.prepend(img);
                    }
                    li.append(a);
                    ul.append(li);
                });
            }
        });
        return true;
    });
});

// folder-create-menu.js

jQuery(function($) {
    $('#create-menu').one('click', function() {
        var wait = calli.wait();
        $.ajax({
            type: 'GET',
            url: $('#create-menu-json')[0].href + encodeURIComponent(calli.getUserIri()),
            xhrFields: calli.withCredentials,
            dataType: 'json',
            success: function(data) {
                var ul = $('#create-menu-more');
                var section;
                $(data.rows).each(function(){
                    if (section != this[4]) {
                        if (section) {
                            ul.append('

');
                        }
                        section = this[4];
                        var header = $('

');
                        header.text(section);
                        ul.append(header);
                    }
                    var li = $('

');
                    var a = $('');
                    a.attr('href', this[0]);
                    a.text(this[1]);
                    if (this[2]) {
                        a.attr('title', this[2]);
                    }
                    if (this[3]) {
                        var img = $('');
                        img.attr('src', this[3]);
                        a.prepend(' ');
                        a.prepend(img);
                    }
                    li.append(a);
                    ul.append(li);
                });
                wait.over();
            }
        });
        return true;
    });
});

Add wait cursor when loading folder create menu


/*global module, require*/
module.exports = function(grunt){
  'use strict';

  var gruntConfig = {
    pkg: grunt.file.readJSON('package.json')
  };

  // lint
  grunt.loadNpmTasks('grunt-contrib-jshint');
  gruntConfig.jshint = {
    all: [
      'Gruntfile.js',
      'dice-roller.js'
    ],
    options: {
      jshintrc: true
    }
  };
  grunt.registerTask('lint', 'jshint');

  // test
  grunt.loadNpmTasks('grunt-contrib-jasmine');
  gruntConfig.jasmine = {
    src: {
      src: [
        'dice-roller.js'
      ],
      options: {
        helpers: 'tests/helpers/*.helper.js',
        specs: 'tests/*.test.js',
        junit: {
          path: 'output/testresults'
        }
      }
    }
  };
  grunt.registerTask('test', 'jasmine:src');

  // watch
  /*grunt.loadNpmTasks('grunt-contrib-watch');
  gruntConfig.watch = {
    scripts: {
      files: ['dice-roller.js'],
      tasks: ['lint', 'test']
    }
  };*/

  // grunt
  grunt.initConfig(gruntConfig);

  // convenience
  grunt.registerTask('default', ['lint', 'test']);
  grunt.registerTask('all', ['default']);

  // continuous integration
  grunt.registerTask('ci', ['lint', 'test']);
};

/*global module, require*/
module.exports = grunt => {
  'use strict';

  const gruntConfig = {
    pkg: grunt.file.readJSON('package.json')
  };

  // lint
  grunt.loadNpmTasks('grunt-contrib-jshint');
  gruntConfig.jshint = {
    all: [
      'Gruntfile.js',
      'dice-roller.js'
    ],
    options: {
      jshintrc: true
    }
  };
  grunt.registerTask('lint', 'jshint');

  // test
  grunt.loadNpmTasks('grunt-contrib-jasmine');
  gruntConfig.jasmine = {
    src: {
      src: [
        'dice-roller.js'
      ],
      options: {
        helpers: 'tests/helpers/*.helper.js',
        specs: 'tests/*.test.js',
        junit: {
          path: 'output/testresults'
        }
      }
    }
  };
  grunt.registerTask('test', 'jasmine:src');

  // watch
  /*grunt.loadNpmTasks('grunt-contrib-watch');
  gruntConfig.watch = {
    scripts: {
      files: ['dice-roller.js'],
      tasks: ['lint', 'test']
    }
  };*/

  // grunt
  grunt.initConfig(gruntConfig);

  // convenience
  grunt.registerTask('default', ['lint', 'test']);
  grunt.registerTask('all', ['default']);

  // continuous integration
  grunt.registerTask('ci', ['lint', 'test']);
};

Use ES6 bits in gruntfile


const express = require('express');
const fs = require('fs');
const app = express();
const port = 3000;
const gifFolder = './public/gifs';

let fileNames = [];

app.use(express.static('public'));

app.get('/', function(req, res) {
  res.sendFile(path.join(__dirname + '/public/index.html'));
});

fs.readdir(gifFolder, (err, files) => {
  files.forEach(file => {
    fileNames.push(files);
  });

  fs.writeFileSync('public/fileNames.json', JSON.stringify(fileNames));
});

app.listen(port, (err) => {
  if (err) console.log(`Error: ${err}`);

  console.log(`Server is running on port ${port}`);
});

const express = require('express');
const fs = require('fs');
const app = express();
const port = 3000;
const gifFolder = './public/gifs';

app.use(express.static('public'));

app.get('/', function(req, res) {
  res.sendFile(path.join(__dirname + '/public/index.html'));
});

fs.readdir(gifFolder, (err, files) => {
  fs.writeFileSync('public/fileNames.json', JSON.stringify(files));
});

app.listen(port, (err) => {
  if (err) console.log(`Error: ${err}`);

  console.log(`Server is running on port ${port}`);
});

Fix readdir -> writeFileSync to write filenames once


const path = require('path')
const express = require('express')

const app = express()

const port = process.env.PORT ? process.env.PORT : 8081
const dist = path.join(__dirname, 'public')

app.use(express.static(dist))
app.all('*', function (req, res, next) { // eslint-disable-line
  if (req.headers['x-forwarded-proto'] === 'https') {
    return next()
  }
  res.redirect(`https://${req.headers.host}`)
})

app.get('*', (req, res) => {
  res.sendFile(path.join(dist, 'index.html'))
})

app.listen(port, (error) => {
  if (error) {
    console.log(error) // eslint-disable-line no-console
  }
  console.info('Express is listening on port %s.', port) // eslint-disable-line no-console
})

const path = require('path')
const express = require('express')

const app = express()

const port = process.env.PORT ? process.env.PORT : 8081
const dist = path.join(__dirname, 'public')

function ensureSecure(req, res, next) { // eslint-disable-line
  if (req.secure) {
    return next()
  }

  res.redirect(`https://${req.hostname} ${req.url}`)
}

app.use(express.static(dist))
app.all('*', ensureSecure)

app.get('*', (req, res) => {
  res.sendFile(path.join(dist, 'index.html'))
})

app.listen(port, (error) => {
  if (error) {
    console.log(error) // eslint-disable-line no-console
  }
  console.info('Express is listening on port %s.', port) // eslint-disable-line no-console
})

Fix ensure secure connection middleware


// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .
$( document ).ready(function() {
  $(".show-if-accept").hide();
  $("#show-accept").click(function(){
    $(".hide-if-accept").hide();
    $(".show-if-accept").show();
  });
});

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .
$( document ).ready(function() {
  $(".show-if-accept").hide();
  $("#show-accept").click(function(){
    $(".hide-if-accept").hide();
    $(".show-if-accept").show();
  });
  $("#notes").focus(function(){
    $("#actions_notes").prop('checked', true);
  });
});

Mark notes as checkbox as checked if focus on textarea


// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require foundation
//= require turbolinks
//= require_tree
//= require d3

$(function(){ $(document).foundation(); });

var loader = document.getElementById('loader');
startLoading();
finishedLoading();
function startLoading() {
  loader.className = '';
}
function finishedLoading() {
  loader.className = 'done';
  setTimeout(function() {
    loader.className = 'hide';
  }, 5000);
}

$('a.close').click(function() {
   var qqq = $(this).closest('.modal');
   $(qqq).removeClass('active');
});

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require foundation
//= require turbolinks
//= require_tree
//= require d3

$(function(){ $(document).foundation(); });

var loader = document.getElementById('loader');
startLoading();
function startLoading() {
  loader.className = '';
}
function finishedLoading() {
  loader.className = 'done';
  setTimeout(function() {
    loader.className = 'hide';
  }, 500);
}

Change timeout time to 500, remove call for finishedLoading method


'use strict';

var _ = require('lodash');
var $ = require('jquery');

function render(container, options) {
  container = $(container);
  options = _.extend({
    items: []
  }, options);

  _.each(options.items, function(url) {
    var wrapper = $('<div>')
      .css({
        position: 'relative',
        paddingTop: '100%'
      })
      .append(
        $('<iframe>')
          .attr({
            width: '100%',
            height: '100%',
            border: '0',
            frameborder: '0',
            seamless: 'on',
            src: url
          })
          .css({
            border: 0,
            margin: 0,
            padding: 0,
            position: 'absolute',
            left: 0,
            top: 0,
            width: '100%',
            height: '100%'
          })
      );

    $('<div>').addClass('content-grid-item col-md-6')
      .append(wrapper).appendTo(container);
  });
}

module.exports.render = render;

'use strict';

var _ = require('lodash');
var $ = require('jquery');

function render(container, options) {
  container = $(container);
  options = _.extend({
    items: []
  }, options);

  _.each(options.items, function(url) {
    var wrapper = $('<div>')
      .css({
        position: 'relative',
        minHeight: '250vh'
      })
      .append(
        $('<iframe>')
          .attr({
            width: '100%',
            height: '100%',
            border: '0',
            frameborder: '0',
            seamless: 'on',
            src: url
          })
          .css({
            border: 0,
            margin: 0,
            padding: 0,
            position: 'absolute',
            left: 0,
            top: 0,
            width: '100%',
            height: '100%'
          })
      );

    $('<div>').addClass('content-grid-item')
      .append(wrapper).appendTo(container);
  });
}

module.exports.render = render;

Remove top padding from the iframe's wrapping div and set minimum height. Also, remove the .col-xs-12 class


module.exports = function(model) {
    return {
        mustExist: mustExist,
        mustNotExist: mustNotExist
    };

    function mustExist(what, modelName, done) {
        'use strict';
        model[modelName].get(what).then(function(value) {
            let error = null;
            if (!value) {
                error = {
                    rule: 'mustExist',
                    actual: what,
                    expected: 'did not find ' + what + ' in model'
                };
            }
            done(error);
        });
    }

    function mustNotExist(what, spec, done) {
        'use strict';

        let pieces = spec.split(':'),
            modelName = pieces[0],
            modelIndex = pieces[1];
        model[modelName].get(what, modelIndex).then(function(value) {
            let error = null;
            if (value) {
                // found a match, when we shouldn't have
                error = {
                    rule: 'mustNotExist',
                    actual: what,
                    expected: `found ${what} in model`
                };
            }
            done(error);
        });
    }
};

var _ = require('lodash');
module.exports = function(model) {
    'use strict';

    let propertyTypes = [
        'number',
        'string',
        'histogram',
        'composition'
    ];

    let propertyUnits = [
        'mm',
        'm',
        'c',
        'f'
    ];

    return {
        mustExist: mustExist,
        mustNotExist: mustNotExist,
        isValidPropertyType: isValidPropertyType,
        isValidUnit: isValidUnit
    };

    // mustExist looks up an entry in the named table by id. If
    // the entry doesn't exist it returns an error.
    function mustExist(what, modelName, done) {
        model[modelName].get(what).then(function(value) {
            let error = null;
            if (!value) {
                error = {
                    rule: 'mustExist',
                    actual: what,
                    expected: 'did not find ' + what + ' in model'
                };
            }
            done(error);
        });
    }

    // mustNotExist looks up an entry in the named table by the named
    // index. If the entry exists it returns an error.
    function mustNotExist(what, spec, done) {
        let pieces = spec.split(':'),
            modelName = pieces[0],
            modelIndex = pieces[1];
        model[modelName].get(what, modelIndex).then(function(value) {
            let error = null;
            if (value) {
                // found a match, when we shouldn't have
                error = {
                    rule: 'mustNotExist',
                    actual: what,
                    expected: `found ${what} in model`
                };
            }
            done(error);
        });
    }

    function isValidPropertyType(what, _ignore) {
        let invalid = {
            rule: 'isValidPropertyType',
            actual: what,
            expected: `type to be one of ${propertyTypes}`
        };
        return _.indexOf(propertyTypes, what) === -1 ? invalid : null;
    }

    function isValidUnit(what, _ignore) {
        let invalid = {
            rule: 'isValidUnit',
            actual: what,
            expected: `units to be one of ${propertyUnits}`
        };
        return _.indexOf(propertyUnits, what) === -1 ? invalid : null;
    }
};

Add rules for validating property schema _type and units.


module.exports = {
  "server": {
    baseDir: "./"
  },
  "files": [
    "assets/css/**/*.css"
  ],
  "browser": "default",
  "injectChanges": true,
  "online": false,
  "open": false,
  "port": 3000,
  "proxy": false,
  "notify": false,
  "watchTask": true
};

module.exports = {
  "server": {
    baseDir: "./"
  },
  "files": [
    "css/**/*.css"
  ],
  "browser": "default",
  "injectChanges": true,
  "online": false,
  "open": false,
  "port": 3000,
  "proxy": false,
  "notify": false,
  "watchTask": true
};

Update Browsersync to watch correct directory for CSS.


import React, {PropTypes} from 'react'
import FormBuilderPropTypes from '../FormBuilderPropTypes'
import DefaultTextField from 'component:@sanity/components/textfields/default'

export default class Num extends React.Component {
  static displayName = 'Number';

  static propTypes = {
    field: FormBuilderPropTypes.field,
    value: PropTypes.number,
    onChange: PropTypes.func,
    focus: PropTypes.bool
  };

  static defaultProps = {
    onChange() {}
  };

  constructor(props, context) {
    super(props, context)
    this.handleChange = this.handleChange.bind(this)
  }

  handleChange(e) {
    const val = e.target.value.trim()
    this.props.onChange({patch: {$set: val === '' ? undefined : Number(e.target.value)}})
  }

  render() {
    const {value, field, focus} = this.props
    return (
      <DefaultTextField
        label={field.title}
        type="number"
        placeholder={field.placeholder || 'Must be a number. Ex 1234'}
        onChange={this.handleChange}
        onKeyPress={this.handleKeyPress}
        value={value}
        focus={focus}
        ref={this.setInputElement}
      />
    )
  }
}

import React, {PropTypes} from 'react'
import FormBuilderPropTypes from '../FormBuilderPropTypes'
import DefaultTextField from 'component:@sanity/components/textfields/default'

export default class Num extends React.Component {
  static displayName = 'Number';

  static propTypes = {
    field: FormBuilderPropTypes.field,
    value: PropTypes.number,
    onChange: PropTypes.func,
    focus: PropTypes.bool
  };

  static defaultProps = {
    onChange() {}
  };

  constructor(props, context) {
    super(props, context)
    this.handleChange = this.handleChange.bind(this)
  }

  handleChange(e) {
    const val = e.target.value.trim()
    this.props.onChange({patch: {$set: val === '' ? undefined : Number(e.target.value)}})
  }

  render() {
    const {value, field, focus} = this.props
    return (
      <DefaultTextField
        label={field.title}
        type="number"
        placeholder={field.placeholder || 'Must be a number. Ex 1234'}
        onChange={this.handleChange}
        onKeyPress={this.handleKeyPress}
        value={String(value)}
        focus={focus}
        ref={this.setInputElement}
      />
    )
  }
}

Convert number value to string


// satisfy ag-grid HTMLElement dependency
HTMLElement = typeof HTMLElement === 'undefined' ? function () {} : HTMLElement;
HTMLSelectElement = typeof HTMLSelectElement === 'undefined' ? function () {} : HTMLSelectElement;
HTMLInputElement = typeof HTMLInputElement === 'undefined' ? function () {} : HTMLInputElement;
HTMLButtonElement = typeof HTMLButtonElement === 'undefined' ? function () {} : HTMLButtonElement;

require('./node_modules/reflect-metadata');

var {AgGridNg2} = require('./dist/agGridNg2');
var {ComponentUtil} = require("ag-grid/main");

var missingProperties = [];
ComponentUtil.ALL_PROPERTIES.forEach((property) => {
    if (!Reflect.getOwnMetadata('propMetadata', AgGridNg2).hasOwnProperty(property)) {
        missingProperties.push(`Grid property ${property} does not exist on AgGridNg2`)
    }
});

var missingEvents = [];
ComponentUtil.EVENTS.forEach((event) => {
    if (!Reflect.getOwnMetadata('propMetadata', AgGridNg2).hasOwnProperty(event)) {
        missingEvents.push(`Grid event ${event} does not exist on AgGridNg2`)
    }
});

if(missingProperties.length || missingEvents.length) {
    console.error("*************************** BUILD FAILED ***************************");
    missingProperties.concat(missingEvents).forEach((message) => console.error(message));
    console.error("*************************** BUILD FAILED ***************************");

    throw("Build Properties Check Failed");
} else {
    console.info("*************************** BUILD OK ***************************");
}

// satisfy ag-grid HTMLElement dependency
HTMLElement = typeof HTMLElement === 'undefined' ? function () {} : HTMLElement;
HTMLSelectElement = typeof HTMLSelectElement === 'undefined' ? function () {} : HTMLSelectElement;
HTMLInputElement = typeof HTMLInputElement === 'undefined' ? function () {} : HTMLInputElement;
HTMLButtonElement = typeof HTMLButtonElement === 'undefined' ? function () {} : HTMLButtonElement;

var {AgGridNg2} = require('./dist/agGridNg2');
var {ComponentUtil} = require("ag-grid/main");

var missingProperties = [];
ComponentUtil.ALL_PROPERTIES.forEach((property) => {
    if (!AgGridNg2.propDecorators.hasOwnProperty(property)) {
        missingProperties.push(`Grid property ${property} does not exist on AgGridNg2`)
    }
});

var missingEvents = [];
ComponentUtil.EVENTS.forEach((event) => {
    if (!AgGridNg2.propDecorators.hasOwnProperty(event)) {
        missingEvents.push(`Grid event ${event} does not exist on AgGridNg2`)
    }
});

if(missingProperties.length || missingEvents.length) {
    console.error("*************************** BUILD FAILED ***************************");
    missingProperties.concat(missingEvents).forEach((message) => console.error(message));
    console.error("*************************** BUILD FAILED ***************************");

    throw("Build Properties Check Failed");
} else {
    console.info("*************************** BUILD OK ***************************");
}

Fix regression - internal reflect lib changes!


// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

base.require('base.guid');
base.require('tracing.trace_model.event');

/**
 * @fileoverview Provides the TimedEvent class.
 */
base.exportTo('tracing.trace_model', function() {
  /**
   * A TimedEvent is the base type for any piece of data in the trace model with
   * a specific start and duration.
   *
   * @constructor
   */
  function TimedEvent(start) {
    tracing.trace_model.Event.call(this);
    this.guid_ = base.GUID.allocate();
    this.start = start;
    this.duration = 0;
  }

  TimedEvent.prototype = {
    __proto__: tracing.trace_model.Event.prototype,

    get end() {
      return this.start + this.duration;
    },

    addBoundsToRange: function(range) {
      range.addValue(this.start);
      range.addValue(this.end);
    }
  };

  return {
    TimedEvent: TimedEvent
  };
});

// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

base.require('base.guid');
base.require('tracing.trace_model.event');

/**
 * @fileoverview Provides the TimedEvent class.
 */
base.exportTo('tracing.trace_model', function() {
  /**
   * A TimedEvent is the base type for any piece of data in the trace model with
   * a specific start and duration.
   *
   * @constructor
   */
  function TimedEvent(start) {
    tracing.trace_model.Event.call(this);
    this.start = start;
    this.duration = 0;
  }

  TimedEvent.prototype = {
    __proto__: tracing.trace_model.Event.prototype,

    get end() {
      return this.start + this.duration;
    },

    addBoundsToRange: function(range) {
      range.addValue(this.start);
      range.addValue(this.end);
    }
  };

  return {
    TimedEvent: TimedEvent
  };
});

Fix TimedEvent sets GUID twice


/**
 * Execute a given function once the document has finished loading
 * @param  {Function} cb - Function to execute once the document has finished loading
 */
export default function domReady(once) {
  return (cb) => {
    if(typeof cb !== 'function') { return; }
    if(document.readyState === 'complete') { return cb(); }
    once(document, 'DOMContentLoaded', () => cb());
  };
}

import _once from './once';
import isFunction from './isFunction';

/**
 * Build a method that executes a given function once the document has finished loading
 * @param  {Function} once - The 'once' (single trigger event) method to use
 * @return {Function} - The 'domready' method using the given once method
 */
export function domReadyBuilder(once = _once) {
  if(!isFunction(once)) { return null; }

  return (cb) => {
    if(!isFunction(cb)) { return; }
    if(document.readyState === 'complete') { return cb(); }
    once(document, 'DOMContentLoaded', () => cb());
  }
}

/**
 * Execute a given function once the document has finished loading
 * @param  {Function} cb - Function to execute once the document has finished loading
 */
const domReady = domReadyBuilder();
export default domReady;

Create a 'domReadyBuilder' and imporve algorithm


/**
 * @providesModule ZeroProj.Redux.Store
 */

/* eslint-disable no-underscore-dangle */

import { applyMiddleware, createStore, compose } from 'redux';
import reducers from '../reducers';

const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

export default createStore(
  reducers,
  composeEnhancer(applyMiddleware(
    // Redux middleware
  ))
);

/* eslint-enable no-underscore-dangle */

/**
 * @providesModule ZeroProj.Redux.Store
 */

/* eslint-disable no-underscore-dangle */

import { applyMiddleware, createStore, compose } from 'redux';
import reducers from '../reducers';

/**
 * Configure to work with `redux-devtools-extensions` & `react-native-debugger`
 * https://github.com/jhen0409/react-native-debugger
 * https://github.com/zalmoxisus/redux-devtools-extension#12-advanced-store-setup
 */
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

export default createStore(
  reducers,
  composeEnhancer(applyMiddleware(
    // Redux middleware
  ))
);

/* eslint-enable no-underscore-dangle */

Configure Redux store to work with redux-devtools-extensions & react-native-debugger


var options = {
  dbname: 'yamb-test',
  storage: require('./storage')
};

if (process.env.yapi) {
  options.yapi = process.env.yapi;
}

module.exports = options;

var options = {
  storage: require('./storage')
};

if (process.env.yapi) {
  options.yapi = process.env.yapi;
}

module.exports = options;

Remove old option for tests


import registerListeners from './register-listeners';

export default ({ request, files, instance, progress }) =>
  new Promise(resolve => {
    const xhr = new XMLHttpRequest();
    instance(xhr);

    registerListeners({ xhr, resolve, progress });

    xhr.open(request.method || 'POST', request.url);
    xhr.withCredentials = request.withCredentials || false;

    if (request.headers) {
      Object.keys(request.headers).forEach(header =>
        xhr.setRequestHeader(header, request.headers[header]));
    }
    //send just the file if no fields or filename is set
    if (!request.fileName && !request.fields) return xhr.send(files[0]);

    var formData = new FormData();
    Array.from(files).forEach(file =>
      formData.append(request.fileName || 'file', file));

    if (request.fields) {
      Object.keys(request.fields).forEach(field =>
        formData.append(field, request.fields[field]));
    }

    xhr.send(formData);
  });

import registerListeners from './register-listeners';

export default ({ request, files, instance, progress }) =>
  new Promise(resolve => {
    const xhr = new XMLHttpRequest();
    instance(xhr);

    registerListeners({ xhr, resolve, progress });

    xhr.open(request.method || 'POST', request.url);
    xhr.withCredentials = request.withCredentials || false;

    if (request.headers) {
      Object.keys(request.headers).forEach(header =>
        xhr.setRequestHeader(header, request.headers[header]));
    }
    //send just the file if no fields or filename is set
    if (!request.fileName && !request.fields) return xhr.send(files[0]);

    var formData = new FormData();

    //append fields first, fixes https://github.com/expressjs/multer/issues/322
    if (request.fields) {
      Object.keys(request.fields).forEach(field =>
        formData.append(field, request.fields[field]));
    }

    Array.from(files).forEach(file =>
      formData.append(request.fileName || 'file', file));

    xhr.send(formData);
  });

Append fields before files in FormData of request


var baseUrl = "http://marihachi.php.xdomain.jp/crystal-resonance";
$(function() {
	// ログイン処理
	$('#login-form').submit(function(e) {
		e.preventDefault();
		$.ajax(baseUrl + "/api/account/login", {
			type: 'post',
			data: $('#login-form').serialize(),
			dataType: 'json',
		}).done(function() {
			location.reload();
		}).fail(function() {
			$('#log-message').text("ログインに失敗しました");
		});
	});

	// ログアウト処理
	$('#logout-form').submit(function(e) {
		e.preventDefault();
		$.ajax(baseUrl + "/api/account/logout", {
			type: 'get',
			dataType: 'json',
		}).done(function() {
			location.reload();
		}).fail(function() {
			$('#log-message').text("ログアウトに失敗しました");
		});
	});

	$('#signup-form').submit(function(e) {
		e.preventDefault();
		$.ajax(baseUrl + "/api/account/create", {
			type: 'post',
			data: $(this).serialize(),
			dataType: 'json',
		}).done(function() {
			location.href = "../";
		}).fail(function() {
			$('#log-message').text("サインアップに失敗しました");
		});
	});
});

var baseUrl = "http://marihachi.php.xdomain.jp/crystal-resonance";
$(function() {
	// ログイン処理
	$('#login-form').submit(function(e) {
		e.preventDefault();
		$.ajax(baseUrl + "/api/account/login", {
			type: 'post',
			data: $('#login-form').serialize(),
			dataType: 'json',
		}).done(function() {
			location.reload();
		}).fail(function() {
			$('#log-message').text("ログインに失敗しました");
		});
	});

	// ログアウト処理
	$('#logout-form').submit(function(e) {
		e.preventDefault();
		$.ajax(baseUrl + "/api/account/logout", {
			type: 'get',
			dataType: 'json',
		}).done(function() {
			location.reload();
		}).fail(function() {
			$('#log-message').text("ログアウトに失敗しました");
		});
	});

	$('#signup-form').submit(function(e) {
		e.preventDefault();
		$.ajax(baseUrl + "/api/account/create", {
			type: 'post',
			data: $(this).serialize(),
			dataType: 'json',
		}).done(function() {
			location.href = baseUrl;
		}).fail(function() {
			$('#log-message').text("サインアップに失敗しました");
		});
	});
});

Fix destination at create account


'use strict';

var fs      = require('fs');
var hljs    = require('../build');
var utility = require('./utility');

function testAutoDetection(language) {
  it('should be detected as ' + language, function() {
    var filename     = language + '.txt',
        languagePath = utility.buildPath('language', filename),
        content      = fs.readFileSync(languagePath, 'utf-8'),

        expected = language,
        actual   = hljs.highlightAuto(content).language;

    actual.should.equal(expected);
  });
}

describe('hljs', function() {
  describe('.highlightAuto', function() {
    var languages = utility.languagesList();

    languages.forEach(testAutoDetection);
  });
});

'use strict';

var fs      = require('fs');
var hljs    = require('../build');
var path    = require('path');
var utility = require('./utility');

function testAutoDetection(language) {
  it('should be detected as ' + language, function() {
    var languagePath = utility.buildPath('language', language),
        examples     = fs.readdirSync(languagePath);

    examples.forEach(function(example) {
      var filename = path.join(languagePath, example),
          content  = fs.readFileSync(filename, 'utf-8'),

          expected = language,
          actual   = hljs.highlightAuto(content).language;

      actual.should.equal(expected);
    });
  });
}

describe('hljs', function() {
  describe('.highlightAuto', function() {
    var languages = utility.languagesList();

    languages.forEach(testAutoDetection);
  });
});

Change testAutoDetection to handle multiple files


;
(function (d, n) {
  'use strict';
  var os = n.platform.match(/(Win|Mac|Linux)/);
  var x = n.userAgent.match(/x86_64|Win64|WOW64/) ||
    n.cpuClass === 'x64' ? 'x64' : 'x86';
  var db = d.getElementById('home-downloadbutton');
  if (!db) { return; }
  var version = db.dataset.version;
  var dlLocal = db.dataset.dlLocal;
  switch (os && os[1]) {
    case 'Mac':
      db.href += 'node-' + version + '.pkg';
      db.innerText = dlLocal + ' OS X (x64)';
      break;
    case 'Win':
      db.href += (version[0] == '0' && x == 'x64' ? x + '/' : '') + 'node-' + version + '-' + x + '.msi';
      db.innerText = dlLocal + ' Windows (' + x +')';
      break;
    case 'Linux':
      db.href += 'node-' + version + '-linux-' + x + '.tar.gz';
      db.innerText = dlLocal + ' Linux (' + x + ')';
      break;
  }
})(document, navigator);

;
(function (d, n) {
  'use strict';
  var os = n.platform.match(/(Win|Mac|Linux)/);
  var x = n.userAgent.match(/x86_64|Win64|WOW64/) ||
    n.cpuClass === 'x64' ? 'x64' : 'x86';
  var db = d.getElementById('home-downloadbutton');
  if (!db) { return; }
  var version = db.dataset.version;
  var dlLocal = db.dataset.dlLocal;
  switch (os && os[1]) {
    case 'Mac':
      db.href += 'node-' + version + '.pkg';
      db.innerText = dlLocal + ' OS X (x64)';
      break;
    case 'Win':
      // Windows 64-bit files for 0.x.x need to be prefixed with 'x64/'
      db.href += (version[1] == '0' && x == 'x64' ? x + '/' : '') + 'node-' + version + '-' + x + '.msi';
      db.innerText = dlLocal + ' Windows (' + x +')';
      break;
    case 'Linux':
      db.href += 'node-' + version + '-linux-' + x + '.tar.gz';
      db.innerText = dlLocal + ' Linux (' + x + ')';
      break;
  }
})(document, navigator);

Fix version check for win-x64


/*
  gulpfile.js
  ===========
  Each task has been broken out into its own file in build/tasks. Any file in that folder gets
  automatically required by the loop in ./gulp/index.js (required below).

  To add a new task, simply add a new task file to ./build/tasks.
*/

var gulp = require('gulp'),
    config = require('./gulp/config');

require('./gulp');

gulp.task('default', ['lint']);

gulp.task('dev', ['lint', 'test'], function() {
  gulp.watch(config.source.concat(['./test/**/*.js']), ['lint', 'test']);
});

/*
  gulpfile.js
  ===========
  Each task has been broken out into its own file in build/tasks. Any file in that folder gets
  automatically required by the loop in ./gulp/index.js (required below).

  To add a new task, simply add a new task file to ./build/tasks.
*/

var gulp = require('gulp'),
    config = require('./gulp/config');

var Pack = require('./gulp');

Pack.dev(['lint', 'test']);
gulp.task('default', ['dev']);

Use gulp dev helper for our own dev task


module.exports = {
  main: {
    files: [
      { expand: true, src: ["assets/images/**"], dest: "dist/" },
      { expand: true, src: ["assets/kss/**"], dest: "dist/" },
      { expand: true, src: ["assets/fonts/**"], dest: "dist/" },
      { expand: true, src: ["scss/**"], dest: "dist/" },
      { src: "README.md", dest: "dist/README.md" },
      { src: "LICENSE", dest: "dist/LICENSE" },
      { src: "bower.json", dest: "dist/bower.json" },
      { src: "package.json", dest: "dist/package.json" }
    ]
  }
}

module.exports = {
  main: {
    files: [
      { expand: true, src: ["assets/images/**"], dest: "dist/" },
      { expand: true, src: ["assets/kss/**"], dest: "dist/" },
      { expand: true, src: ["assets/fonts/**"], dest: "dist/" },
      { expand: true, src: ["scss/**"], dest: "dist/" },
      { expand: true, src: ["js/**"], dest: "dist/" },
      { src: "README.md", dest: "dist/README.md" },
      { src: "LICENSE", dest: "dist/LICENSE" },
      { src: "bower.json", dest: "dist/bower.json" },
      { src: "package.json", dest: "dist/package.json" }
    ]
  }
}

Include JS source in distribution build for direct consumption.


'use strict';

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var runSequence = require('run-sequence');
var del = require('del');

gulp.task('zip', function () {
  return gulp.src([
    'templates/*',
    'templates/app/**',
    '!**/.DS_Store'
  ], {dot: true})
  .pipe($.ignore.include({isFile: true}))
    .pipe($.zip('archive.zip'))
    .pipe(gulp.dest('dist'));
});

gulp.task('clean', del.bind(null, 'dist'));

gulp.task('default', function (callback) {
  runSequence('clean', 'zip', callback);
});

'use strict';

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var runSequence = require('run-sequence');
var del = require('del');

gulp.task('zip', function () {
  return gulp.src([
    'templates/*',
    'templates/app/**',
    '!**/.DS_Store'
  ], {base: 'templates', dot: true})
  .pipe($.ignore.include({isFile: true}))
    .pipe($.zip('archive.zip'))
    .pipe(gulp.dest('dist'));
});

gulp.task('clean', del.bind(null, 'dist'));

gulp.task('default', function (callback) {
  runSequence('clean', 'zip', callback);
});

Fix directory structure in zip archive


/*
Copyright 2017 Vector Creations Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import sdk from '../../../index';
import PropTypes from 'prop-types';

const StartChatButton = function(props) {
    const ActionButton = sdk.getComponent('elements.ActionButton');
    return (
        <ActionButton action="view_create_chat"
            label="Start chat"
            iconPath="img/icons-people.svg"
            size={props.size}
            tooltip={props.tooltip}
        />
    );
};

StartChatButton.propTypes = {
    size: PropTypes.string,
    tooltip: PropTypes.bool,
};

export default StartChatButton;

/*
Copyright 2017 Vector Creations Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import sdk from '../../../index';
import PropTypes from 'prop-types';

const StartChatButton = function(props) {
    const ActionButton = sdk.getComponent('elements.ActionButton');
    return (
        <ActionButton action="start_chat"
            label="Start chat"
            iconPath="img/icons-people.svg"
            size={props.size}
            tooltip={props.tooltip}
        />
    );
};

StartChatButton.propTypes = {
    size: PropTypes.string,
    tooltip: PropTypes.bool,
};

export default StartChatButton;

Revert "Fix 'start chat' button"


#!/usr/bin/env node

"use strict";

var path = require('path');

// this must be set before "server.js" is loaded
process.env.HARAKA = process.env.HARAKA || path.resolve('.');
try {
    require.paths.push(path.join(process.env.HARAKA, 'node_modules'));
}
catch(e) {
    process.env.NODE_PATH += ':' + path.join(process.env.HARAKA, 'node_modules');
}

var fs     = require('fs');
var logger = require('./logger');
var server = require('./server');

exports.version = JSON.parse(
        fs.readFileSync(path.join(__dirname, './package.json'), 'utf8')
    ).version;

process.on('uncaughtException', function (err) {
    if (err.stack) {
        err.stack.split("\n").forEach(function (line) {
            logger.logcrit(line);
        });
    }
    else {
        logger.logcrit('Caught exception: ' + err);
    }
    logger.dump_logs();
    process.exit(1);
});

logger.log("INFO", "Starting up Haraka version " + exports.version);

server.createServer();

#!/usr/bin/env node

"use strict";

var path = require('path');

// this must be set before "server.js" is loaded
process.env.HARAKA = process.env.HARAKA || path.resolve('.');
try {
    require.paths.push(path.join(process.env.HARAKA, 'node_modules'));
}
catch(e) {
    process.env.NODE_PATH = process.env.NODE_PATH ?
            (process.env.NODE_PATH + ':' + path.join(process.env.HARAKA, 'node_modules'))
            :
            (path.join(process.env.HARAKA, 'node_modules'));
    require('module')._initPaths(); // Horrible hack
}

var fs     = require('fs');
var logger = require('./logger');
var server = require('./server');

exports.version = JSON.parse(
        fs.readFileSync(path.join(__dirname, './package.json'), 'utf8')
    ).version;

process.on('uncaughtException', function (err) {
    if (err.stack) {
        err.stack.split("\n").forEach(function (line) {
            logger.logcrit(line);
        });
    }
    else {
        logger.logcrit('Caught exception: ' + err);
    }
    logger.dump_logs();
    process.exit(1);
});

logger.log("INFO", "Starting up Haraka version " + exports.version);

server.createServer();

Fix paths not working on node 0.6 (hack alert)


module.exports = function(config) {
  config.set({
    frameworks: ['mocha'],

    exclude: ['build/test/external.spec.js'],

    files: [
      'vendor/es5-shim.js',
      'vendor/es5-sham.js',
      'vendor/rsvp.js',
      'vendor/unexpected-magicpen.min.js',
      'build/test/promisePolyfill.js',
      'unexpected.js',
      'build/test/common.js',
      'build/test/**/*.spec.js'
    ],

    browsers: ['ChromeHeadlessNoSandbox', 'ie11'],

    browserDisconnectTimeout: '60000',
    browserNoActivityTimeout: '60000',

    client: {
      mocha: {
        reporter: 'html',
        timeout: 60000
      }
    },

    browserStack: {
      video: false,
      project:
        process.env.TRAVIS_BRANCH === 'master' ? 'unexpected' : 'unexpected-dev'
    },

    customLaunchers: {
      ChromeHeadlessNoSandbox: {
        base: 'ChromeHeadless',
        flags: ['--no-sandbox']
      },
      ie11: {
        base: 'BrowserStack',
        browser: 'IE',
        browser_version: '11',
        os: 'Windows',
        os_version: '7'
      }
    },

    reporters: ['dots', 'BrowserStack']
  });
};

module.exports = function(config) {
  config.set({
    frameworks: ['mocha'],

    exclude: ['build/test/external.spec.js'],

    files: [
      'vendor/es5-shim.js',
      'vendor/es5-sham.js',
      'vendor/rsvp.js',
      'vendor/unexpected-magicpen.min.js',
      'build/test/promisePolyfill.js',
      'unexpected.js',
      'build/test/common.js',
      'build/test/**/*.spec.js'
    ],

    browsers: ['ChromeHeadlessNoSandbox', 'ie11'],

    browserDisconnectTimeout: '60000',
    browserNoActivityTimeout: '60000',

    client: {
      mocha: {
        reporter: 'html',
        timeout: 60000
      }
    },

    browserStack: {
      video: false,
      project:
        process.env.TRAVIS_BRANCH === 'master' &&
        !process.env.TRAVIS_PULL_REQUEST_BRANCH // Catch Travis "PR" builds
          ? 'unexpected'
          : 'unexpected-dev'
    },

    customLaunchers: {
      ChromeHeadlessNoSandbox: {
        base: 'ChromeHeadless',
        flags: ['--no-sandbox']
      },
      ie11: {
        base: 'BrowserStack',
        browser: 'IE',
        browser_version: '11',
        os: 'Windows',
        os_version: '7'
      }
    },

    reporters: ['dots', 'BrowserStack']
  });
};

Use the unexpected-dev project on browserstack for Travis "PR" builds


'use babel';

import levelsConfig     from './levels-config';
import levelsServices   from './levels-services';
import workspaceManager from './workspace-manager';

export default {
  activate() {
    workspaceManager.setUpWorkspace();
    workspaceManager.activateEventHandlers();
    workspaceManager.activateCommandHandlers();
  },

  deactivate() {
    workspaceManager.cleanUpWorkspace();
    workspaceManager.deactivateEventHandlers();
    workspaceManager.deactivateCommandHandlers();
  },

  config: levelsConfig,

  provideLevels() {
    return levelsServices;
  },

  consumeStatusBar(statusBar) {
    workspaceManager.consumeStatusBar(statusBar);
  }
};

'use babel';

import languageRegistry from './language-registry';
import levelsConfig     from './levels-config';
import levelsServices   from './levels-services';
import workspace        from './workspace';
import workspaceManager from './workspace-manager';

export default {
  activate() {
    workspaceManager.setUpWorkspace();
    workspaceManager.activateEventHandlers();
    workspaceManager.activateCommandHandlers();
  },

  deactivate() {
    workspaceManager.cleanUpWorkspace();
    workspaceManager.deactivateEventHandlers();
    workspaceManager.deactivateCommandHandlers();
    workspace.destroy();
    languageRegistry.destroy();
  },

  config: levelsConfig,

  provideLevels() {
    return levelsServices;
  },

  consumeStatusBar(statusBar) {
    workspaceManager.consumeStatusBar(statusBar);
  }
};

Destroy language registry and workspace on package deactivation


var opener = require('opener')
var template = require('lodash.template')
var fs = require('fs')
var path = require('path')
var md = fs.readFileSync(path.join(__dirname, 'template.md'), 'utf8')
var message = template(md)
var endpoint = 'https://github.com/npm/support-cli/issues/new?body='

module.exports = function (answers) {
  var body = message(answers)
  opener(endpoint + body)
}

var opener = require('opener')
var template = require('lodash.template')
var fs = require('fs')
var path = require('path')
var md = fs.readFileSync(path.join(__dirname, 'template.md'), 'utf8')
var message = template(md)
var endpoint = 'https://github.com/npm/npm/issues/new?body='

module.exports = function (answers) {
  var body = message(answers)
  opener(endpoint + body)
}

Update the target url to npm/npm from npm/support-cli


'use strict';
angular.module('arethusa.core').directive('pluginSetting', [
  'userPreferences',
  function (userPreferences) {
    return {
      restrict: 'A',
      scope: true,
      link: function(scope, element, attrs) {
        scope.change = function() {
          var model = scope.setting.model;
          var value = scope.plugin[model];
          var change = scope.plugin[scope.setting.change];
          userPreferences.set(scope.plugin.name, model, value);
          if (change) change();
        };
      },
      templateUrl: 'templates/arethusa.core/plugin_setting.html'
    };
  }
]);

'use strict';
angular.module('arethusa.core').directive('pluginSetting', [
  'userPreferences',
  function (userPreferences) {
    return {
      restrict: 'A',
      scope: true,
      link: function(scope, element, attrs) {
        scope.change = function() {
          var model = scope.setting.model;
          var value = scope.plugin[model];
          var change = scope.setting.change;
          userPreferences.set(scope.plugin.name, model, value);
          if (angular.isFunction(change)) change();
        };
      },
      templateUrl: 'templates/arethusa.core/plugin_setting.html'
    };
  }
]);

Fix calling of change function


'use strict'

const TelegramBot = require('node-telegram-bot-api');

const config = require('../config');
const utils = require('./utils');
const Kinospartak = require('./Kinospartak/Kinospartak');

const bot = new TelegramBot(config.TOKEN);

const kinospartak = new Kinospartak();

/**
 * updateSchedule - update schedule and push updates to Telegram channel
 *
 * @return {Promise}
 */
function updateSchedule() {
  return kinospartak.getChanges()
    .then(changes =>
      changes.length
        ? utils.formatSchedule(changes)
        : undefined)
    .then(messages =>
      messages
        ? utils.sendInOrder(bot, config.CHANNEL, messages)
        : undefined)
    .then(() => kinospartak.commitChanges())
};

/**
 * updateNews - update news and push updates to Telegram channel
 *
 * @return {Promise}
 */
function updateNews() {
  return kinospartak.getLatestNews()
    .then(news =>
      news.length
        ? utils.formatNews(news)
        : undefined)
    .then(messages =>
      messages
        ? utils.sendInOrder(bot, config.CHANNEL, messages)
        : undefined)
    .then(() => kinospartak.setNewsOffset(new Date().toString()))
};

function update() {
  return Promise.all([
    updateSchedule,
    updateNews
  ]).catch((err) => {
    setTimeout(() => {
        update();
      }, 60 * 5);
  })
}

update();

'use strict'

const TelegramBot = require('node-telegram-bot-api');

const config = require('../config');
const utils = require('./utils');
const Kinospartak = require('./Kinospartak/Kinospartak');

const bot = new TelegramBot(config.TOKEN);

const kinospartak = new Kinospartak();

/**
 * updateSchedule - update schedule and push updates to Telegram channel
 *
 * @return {Promise}
 */
function updateSchedule() {
  return kinospartak.getChanges()
    .then(changes =>
      changes.length
        ? utils.formatSchedule(changes)
        : undefined)
    .then(messages =>
      messages
        ? utils.sendInOrder(bot, config.CHANNEL, messages)
        : undefined)
    .then(() => kinospartak.commitChanges())
};

/**
 * updateNews - update news and push updates to Telegram channel
 *
 * @return {Promise}
 */
function updateNews() {
  return kinospartak.getLatestNews()
    .then(news =>
      news.length
        ? utils.formatNews(news)
        : undefined)
    .then(messages =>
      messages
        ? utils.sendInOrder(bot, config.CHANNEL, messages)
        : undefined)
    .then(() => kinospartak.setNewsOffset(new Date().toString()))
};

function update() {
  return Promise.all([
    updateSchedule,
    updateNews
  ]).catch((err) => {
    setTimeout(() => {
        update();
    }, 1000 * 60 * 5);
  })
}

update();

Change channel update retry timeout


module.exports = client => async (key, get, { expire, invalidate } = {}) => {
  let value;
  if (client.getJSON) {
    value = await client.getJSON(key);
  } else {
    value = await client.get(key);
  }
  if (!value || (invalidate && invalidate(value))) {
    value = await get();
    if (client.setJSON) {
      await client.setJSON(key, value);
    } else {
      await client.set(key, value);
    }
    if (expire) {
      if (expire.second) {
        expire = expire.second();
      }
      await client.expire(key, expire);
    }
  }
  return value;
};

module.exports = client => async (key, get, { expire, invalidate } = {}) => {
  let value;
  if (client.getJSON) {
    value = await client.getJSON(key);
  } else {
    value = await client.get(key);
  }
  if (!value || (invalidate && invalidate(value))) {
    value = await get();
    if (client.setJSON) {
      await client.setJSON(key, value);
    } else {
      await client.set(key, value);
    }
    if (expire) {
      if (expire.seconds) {
        expire = expire.seconds();
      }
      await client.expire(key, expire);
    }
  }
  return value;
};

Use pluralizationed format function to support also moment.duration objects


'use strict';
let http = require('http');

exports.handler = function(event, context, callback) {
  var path = "", method = "POST";

  switch(event.result.metadata.intentName) {
    case "Transmitter Intent":
      path = '/transmitter'+
        '?device='+event.result.parameters['Device']+
        '&switch='+event.result.parameters['Switch'];
    break;
    case "TV Channel Intent":
      path = '/tv/channel'+
        '?channel='+event.result.parameters['TvChannel'];
    break;
    case "Temperature Intent":
      path = '/temperature'+
        '?sensor='+event.result.parameters['Sensor'];
      method = 'GET';
    break;
    case "TV Command Intent":
      path = '/tv/command'+
        '?command='+event.result.parameters['TvCommand'];
    break;
  }

  let options = {
        host: 'mydyndns.com',
        port: 9900,
        method: method,
        path: path,
        auth: 'apiai:XXX'
  };

  makeRequest(options, function( data, error) {
    let result = data.result[0];
    if (result) {
        callback(null, {"speech": result.result});
    }
    else {
        callback(null, {"speech": "I'm not sure!"});
    }
  });
};

function makeRequest(options, callback) {
    var request = http.request(options, function(response) {
        var responseString = '';
        response.on('data', function(data) {
            responseString += data;
        });
         response.on('end', function() {
            var responseJSON = JSON.parse(responseString);
            callback(responseJSON, null);
        });
    });
    request.end();
}

Add code being used from AWS Lambda.


import { CarouselCard, Carousel } from './carousel';

export default function init() {
  const projectsContainer = document.getElementsByClassName('projects-container')[0];
  const cardElems = [...projectsContainer.getElementsByClassName('carousel-card')];
  const cards = cardElems.map((c, i) => new CarouselCard(c, i));
  window.workCarousel = new Carousel(cards);
}

import { CarouselCard, Carousel } from './carousel';

export default function init() {
  const projectsContainer = document.getElementsByClassName('projects-container')[0];
  const cardElems = [...projectsContainer.getElementsByClassName('carousel-card')];
  const cards = cardElems.map(c => new CarouselCard(c));
  window.workCarousel = new Carousel(cards);
}

Fix bad argument to CarouselCard construction


module.exports = (function() {
  return function($record) {
    this.name = $record.find('.item-list__name').html();
    var _info = $record.children('div');
    this.salePrice = _info.eq(1).text().trim();
    this.buyer = _info.eq(2).text().trim();
    this.saleDate = eval(_info.eq(3).children('script').text().split(' = ')[1]);
  };
})();

module.exports = (function() {
  function buildDate(match, p1) {
    var d = new Date();
    var date = [
      d.getFullYear(),
      ('0' + (d.getMonth() + 1)).substr(-2),
      ('0' + d.getDate()).substr(-2)
    ].join('/');
    return [date, ' ', ('0'+p1).substr(-2), ':'].join('');
  }

  return function($record) {
    this.name = $record.find('.item-list__name').html();
    var _info = $record.children('div');
    this.salePrice = _info.eq(1).text().trim();
    this.buyer = _info.eq(2).text().trim();
    var _saleDate = eval(_info.eq(3).children('script').text().split(' = ')[1]);
    this.saleDate = _saleDate.replace(/本日 (\d+):/, buildDate);
  };
})();

Replace '本日' with date string


var express = require('express');
var router = express.Router();
var JsonDB = require('node-json-db');
var _ = require('lodash');

// Recipes listing
router.get('/', function (req, res, next) {
  var db = new JsonDB('db', false, false);
  var recipes = db.getData('/recipes');

  // Expand requested resources if they exist
  // Users and ingredients for the recipes are loaded
  if (!_.isUndefined(req.query._expand)) {
    var users = db.getData('/users');
    _(recipes)
      .forEach(function (recipe) {
        recipe.user = _(users).findWhere({ id: recipe.userId });
        delete recipe.userId;
      })
      .value();
  }

  res.json(recipes);
});

module.exports = router;

var express = require('express');
var router = express.Router();
var JsonDB = require('node-json-db');
var _ = require('lodash');

// Recipes listing
router.get('/', function (req, res, next) {
  var db = new JsonDB('db', false, false);
  var recipes = db.getData('/recipes');

  // Expand requested resources if they exist
  // The resource to expand is singular, e.g.
  // to expand 'users' we provide _expand=user
  var expand = req.query._expand;
  if (expand) {
    try {
      var relation = db.getData('/' + expand + 's');
      _(recipes)
        .forEach(function (recipe) {
          recipe.user = _(relation).findWhere({ id: recipe[expand + 'Id'] });
          delete recipe[expand + 'Id'];
        })
        .value();
    }
    catch(err) {
      console.log(err);
    }
  }

  res.json(recipes);
});

module.exports = router;

Prepare branch for section 2.2 tutorial


var Schema = require('./../Schema');

function BuildController(mongoose){

    var convert = function(build){
        return build
    };

    this.get = function (req, res) {
        var Build = mongoose.model('Build', Schema.buildSchema);
        Build.findOne({"blueprint.owner": req.params.owner, "blueprint.repo": req.params.repo}, {}, { sort: { 'created_at' : 1 } }, function(err, build){
            if(err || build === null) res.status(404).json({message: 'No build found'});
            else res.json(convert(build));
        });
    };
}

module.exports = BuildController;

var _ = require('underscore'),
    Schema = require('./../Schema'),
    CONFIG = require('config');

function BuildController(mongoose){

    var convert = function(build){

        var makeUrl = function(owner, repo, name, type){
            return CONFIG.url + '/file/' + owner + '/' + repo + '/' + name + '/' + type;
        };

        var documents = []

        _.each(build.documents, function (document) {
            var files = [];
            _.each(build.document.files, function(file){
                files.push({
                    type: file.type,
                    name: file.name,
                    url: makeUrl(build.blueprint.owner, build.blueprint.repo, build.documents.name, file.type)
                });
            });
            document.files = files;
            documents.push(document);
        });
        build.documents = documents;
        return build;
    };

    this.get = function (req, res) {
        var Build = mongoose.model('Build', Schema.buildSchema);
        Build.findOne({"blueprint.owner": req.params.owner, "blueprint.repo": req.params.repo}, {}, { sort: { 'created_at' : 1 } }, function(err, build){
            if(err || build === null) res.status(404).json({message: 'No build found'});
            else res.json(convert(build));
        });
    };
}

module.exports = BuildController;

Convert file paths to urls


import { Component } from 'react';
import h from 'react-hyperscript';

import Quote from './components/Quote';
import getRandomQuote from './utils/getRandomQuote';

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      text: 'Loading...',
      name: 'website',
    };
  }

  componentDidMount() {
    getRandomQuote()
      .then(quote => {
        const { text, name } = quote;
        this.setState({ text, name });
      })
      .catch(err => {
        this.setState({ text: err });
        console.error(err);
      });
  }

  render() {
    const { text, name } = this.state;
    return h(Quote, { text, name });
  }
}

export default App;

import { Component } from 'react';
import h from 'react-hyperscript';

import Quote from './components/Quote';
import getRandomQuote from './utils/getRandomQuote';

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      text: 'Loading...',
      name: 'website',
    };
  }

  componentDidMount() {
    getRandomQuote()
      .then(quote => {
        const { text, name } = quote;
        this.setState({ text, name });
      })
      .catch(err => {
        this.setState({
          text: err,
          name: 'website',
        });
        console.error(err);
      });
  }

  render() {
    const { text, name } = this.state;
    return h(Quote, { text, name });
  }
}

export default App;

Revert to name 'website' on error


var Router = require('routes');
var router = new Router();
var st = require('st');
var fs = require('fs');

var mount = st({
  path: __dirname + '/static/', // resolved against the process cwd
  url: 'boot/', // defaults to '/'

  // indexing options
  index: 'index', // auto-index, the default

  dot: false // default: return 403 for any url with a dot-file part

});

router.addRoute('/chain', function(req, res, params, splats) {
  console.log("Got a CHAIN request");
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end("#!ipxe\n\necho Attempting to boot into the chain... \nchain http://${next-server}/boot/${mac}\n");
});

router.addRoute('/boot/:macaddr', function boot(req, res, params, splats) {
  console.log("Got a BOOT request");
  console.log("Just got word that "+params.params.macaddr+" just booted");

  try {
    var stat = fs.statSync(__dirname + '/static/' + params.params.macaddr);
  } catch (error){
    if(error.code != 'ENOENT')
      throw error;
  }

  if(stat && stat.isDirectory()){
    mount(req, res);
  } else {
    req.url = '/boot/default';
    mount(req, res);
  }
});

module.exports = router;

var Router = require('routes');
var router = new Router();
var st = require('st');
var fs = require('fs');

var mount = st({
  path: __dirname + '/../static/', // resolved against the process cwd
  url: 'boot/', // defaults to '/'

  // indexing options
  index: 'index', // auto-index, the default

  dot: false // default: return 403 for any url with a dot-file part

});

router.addRoute('/chain', function(req, res, params, splats) {
  console.log("Got a CHAIN request");
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end("#!ipxe\n\necho Attempting to boot into the chain... \nchain http://${next-server}/boot/${mac}\n");
});

router.addRoute('/boot/:macaddr', function boot(req, res, params, splats) {
  console.log("Got a BOOT request");
  console.log("Just got word that "+params.params.macaddr+" just booted");

  fs.stat(__dirname + '/../static/' + params.params.macaddr, function(err,stat){
    if(stat && stat.isDirectory()){
      mount(req, res);
    } else {
      req.url = '/boot/default';
      mount(req, res);
    }
  })
});

module.exports = router;

Check bootdir async and fix static path


import LocalStorageStore from 'ember-simple-auth/session-stores/local-storage';

export default LocalStorageStore.extend({
    key: 'ghost:session'
});

import AdaptiveStore from 'ember-simple-auth/session-stores/adaptive';

export default AdaptiveStore.extend({
    localStorageKey: 'ghost:session',
    cookieName: 'ghost:session'
});

Use AdaptiveStore for cookie fallback if local storage is unavailable


// ==UserScript==
// @name                Selfish Youtube
// @version             2013-05-06
// @namespace           https://github.com/ASzc/selfish-youtube
// @description         On the watch page, remove the share panel.
// @include             http://youtube.com/watch*
// @include             http://*.youtube.com/watch*
// @include             https://youtube.com/watch*
// @include             https://*.youtube.com/watch*
// @grant               none
// ==/UserScript==

var panelName = "action-panel-share";

// Remove panel
var actionPanelShare = document.getElementById(panelName);
actionPanelShare.parentNode.removeChild(actionPanelShare);

// Remove buttons targeting the panel
var buttons = document.body.getElementsByTagName("button");
if (buttons != null && buttons instanceof NodeList) {
    for (var i = 0; i < buttons.length; i++) {
        var button = buttons[i];
        var buttonDTF = button.getAttribute("data-trigger-for");
        if (buttonDTF != null && buttonDTF == panelName) {
            button.parentNode.removeChild(button);
        }
    }
}

// ==UserScript==
// @name                Selfish Youtube
// @version             2013-05-06
// @namespace           https://github.com/ASzc/selfish-youtube
// @description         On the watch page, remove the share panel.
// @include             http://youtube.com/watch*
// @include             http://*.youtube.com/watch*
// @include             https://youtube.com/watch*
// @include             https://*.youtube.com/watch*
// @grant               none
// ==/UserScript==

var panelName = "action-panel-share";

// Remove panel
var actionPanelShare = document.getElementById(panelName);
actionPanelShare.parentNode.removeChild(actionPanelShare);

// Remove buttons targeting the panel
var buttons = document.body.getElementsByTagName("button");
if (buttons != null) {
    for (var i = 0; i < buttons.length; i++) {
        var button = buttons[i];
        var buttonDTF = button.getAttribute("data-trigger-for");
        if (buttonDTF != null && buttonDTF == panelName) {
            button.parentNode.removeChild(button);
        }
    }
}

Remove instanceof check for button list


"use strict";
var EventEmitter = require("events");
var util = require("util");
var instance = null;

function MockAppService() {
    EventEmitter.call(this);
}
util.inherits(MockAppService, EventEmitter);

MockAppService.prototype.listen = function(port) {
    // NOP
};

MockAppService.prototype._trigger = function(eventType, content) {
    var listeners = instance.listeners(eventType);
    var promises = listeners.map(function(l) {
        return l(content);
    });
    if (promises.length === 1) {
        return promises[0];
    }
    return Promise.all(promises);
};

MockAppService.prototype._queryAlias = function(alias) {
    if (!this.onAliasQuery) {
        throw new Error("IRC AS hasn't hooked into onAliasQuery yet.");
    }
    return this.onAliasQuery(alias);
};

MockAppService.prototype._queryUser = function(user) {
    if (!this.onUserQuery) {
        throw new Error("IRC AS hasn't hooked into onUserQuery yet.");
    }
    return this.onUserQuery(user);
};

function MockAppServiceProxy() {
    if (!instance) {
        instance = new MockAppService();
    }
    return instance;
}
MockAppServiceProxy.instance = function() {
    instance = new MockAppService();
    return instance;
};
MockAppServiceProxy.resetInstance = function() {
    if (instance) {
        instance.removeAllListeners();
    }
    instance = null;
};

module.exports = MockAppServiceProxy;

"use strict";
var EventEmitter = require("events");
var util = require("util");
var instance = null;

function MockAppService() {
    EventEmitter.call(this);
}
util.inherits(MockAppService, EventEmitter);

MockAppService.prototype.listen = function(port) {
    // NOP
};

MockAppService.prototype._trigger = function(eventType, content) {
    var listeners = instance.listeners(eventType);
    var promises = listeners.map(function(l) {
        return l(content);
    });
    if (promises.length === 1) {
        return promises[0];
    }
    return Promise.all(promises);
};

MockAppService.prototype._queryAlias = function(alias) {
    if (!this.onAliasQuery) {
        throw new Error("IRC AS hasn't hooked into onAliasQuery yet.");
    }
    return this.onAliasQuery(alias);
};

MockAppService.prototype._queryUser = function(user) {
    if (!this.onUserQuery) {
        throw new Error("IRC AS hasn't hooked into onUserQuery yet.");
    }
    return this.onUserQuery(user);
};

function MockAppServiceProxy() {
    if (!instance) {
        instance = new MockAppService();
    }
    return instance;
}

MockAppServiceProxy.instance = function() {
    if (!instance) {
        instance = new MockAppService();
    }
    return instance;
};

MockAppServiceProxy.resetInstance = function() {
    if (instance) {
        instance.removeAllListeners();
    }
    instance = null;
};

module.exports = MockAppServiceProxy;

Make instance() not create new singletons


const getStorage  = () => {
  const data = window.localStorage.getItem('__chrome.storage.sync__')
  if (data != null) {
    return JSON.parse(data)
  } else {
    return {}
  }
}

const setStorage = (storage) => {
  const json = JSON.stringify(storage)
  window.localStorage.setItem('__chrome.storage.sync__', json)
}

module.exports = {
  sync: {
    get (keys, callback) {
      const storage = getStorage()

      if (keys === {} || keys === []) return {}
      if (keys === null) return storage

      if (typeof keys === 'string') keys = [keys]

      let items = {}
      // ['foo'] or ['foo', 'bar'] or [{foo: 'bar'}]
      keys.forEach(function (key) {
        if (typeof key === 'string') {
          items[key] = storage[key]
        }
        else {
          const objKey = Object.keys(key)
          if (!storage[objKey] || storage[objKey] === '') {
            items[objKey] = key[objKey]
          } else {
            items[objKey] = storage[objKey]
          }
        }
      })

      setTimeout(function () {
        callback(items)
      })
    },

    set (items, callback) {
      const storage = getStorage()

      Object.keys(items).forEach(function (name) {
        storage[name] = items[name]
      })

      setStorage(storage)

      setTimeout(callback)
    }
  }
}

const getStorage  = () => {
  const data = window.localStorage.getItem('__chrome.storage.sync__')
  if (data != null) {
    return JSON.parse(data)
  } else {
    return {}
  }
}

const setStorage = (storage) => {
  const json = JSON.stringify(storage)
  window.localStorage.setItem('__chrome.storage.sync__', json)
}

module.exports = {
  sync: {
    get (keys, callback) {
      const storage = getStorage()
      if (keys == null) return storage

      let defaults = {}
      switch (typeof keys) {
        case 'string':
          keys = [keys]
          break
        case 'object':
          if (!Array.isArray(keys)) {
            defaults = keys
            keys = Object.keys(keys)
          }
          break;
      }
      if (keys.length === 0 ) return {}

      let items = {}
      keys.forEach(function (key) {
        var value = storage[key]
        if (value == null) value = defaults[key]
        items[key] = value
      })

      setTimeout(function () {
        callback(items)
      })
    },

    set (items, callback) {
      const storage = getStorage()

      Object.keys(items).forEach(function (name) {
        storage[name] = items[name]
      })

      setStorage(storage)

      setTimeout(callback)
    }
  }
}

Handle the three get cases


/* global BackboneWizard, Marionette, Backbone, $ */

window.BackboneWizard = {};

var app = new Marionette.Application();

app.addRegions({
    wizard: '#wizard'
});

app.addInitializer(function () {
    BackboneWizard.itemList = new app.Collections.ItemList();
    BackboneWizard.transaction = new app.Models.Transaction();
    BackboneWizard.state = 'index';

    $.get('./appData.json').done(function (data) {
        BackboneWizard.transaction.set(data);
    });

    $.get('./itemData.json').done(function (data) {
        BackboneWizard.itemList.add(data, { merge: true });
    });

    BackboneWizard.wizardController = new app.Controllers.WizardController();

    BackboneWizard.wizardRouter = new app.Routers.WizardRouter({
        controller: BackboneWizard.wizardController
    });

    Backbone.history.start();
});

/* global BackboneWizard, Marionette, Backbone, $ */

window.BackboneWizard = {};

var app = new Marionette.Application();

app.addRegions({
    wizard: '#wizard'
});

app.addInitializer(function () {
    var wizardController = new app.Controllers.WizardController();

    BackboneWizard.itemList = new app.Collections.ItemList();
    BackboneWizard.transaction = new app.Models.Transaction();
    BackboneWizard.state = 'index';

    $.get('./appData.json').done(function (data) {
        BackboneWizard.transaction.set(data);
    });

    $.get('./itemData.json').done(function (data) {
        BackboneWizard.itemList.add(data, { merge: true });
    });

    BackboneWizard.wizardRouter = new app.Routers.WizardRouter({
        controller: wizardController
    });

    Backbone.history.start();
});

Remove controller from the global namespace.


// Client side resources to be injected for gData extension

// Add items to the exporter menu
MenuBar.insertBefore(
        [ "core/project", "core/export", "core/export-templating" ],
        [
            {
                "label":"Google Spreadsheet",
                "click": function() {}
            },
            {
                "label":"Google Data",
                "click": function() {}
            },
            {} // separator
        ]
);

var gdataExtension = {};

// Client side resources to be injected for gData extension

// Add items to the exporter menu
//ExportManager.MenuItems.append(
//        [ "core/project", "core/export", "core/export-templating" ],
//        [
//            {
//                "label":"Google Spreadsheet",
//                "click": function() {}
//            },
//            {
//                "label":"Google Data",
//                "click": function() {}
//            },
//            {} // separator
//        ]
//);

var gdataExtension = {};

Comment out unused exporter injection. Target has moved anyway


import { applyMiddleware, createStore } from 'redux'
import reducer from '../../src/reducer'

export default ({ middleware, initialState = {} }) =>
  createStore(reducer, initialState, applyMiddleware(middleware))

import { applyMiddleware, combineReducers, createStore } from 'redux'
import reducer from '../../src/reducer'

export default ({ middleware, initialState = {} }) =>
  createStore(
    combineReducers({ session: reducer }),
    initialState,
    applyMiddleware(middleware)
  )

Use combine reducers in test store


var marked   = require('marked');
var nunjucks = require('nunjucks');
var path     = require('path');

module.exports = function(options) {

  options || (options = {});
  options.path || (options.path = 'template');

  var env = new nunjucks.Environment(
    new nunjucks.FileSystemLoader(options.path),
    {noCache: true}
  );
  env.addFilter('markdown', function(str) {
    return new nunjucks.runtime.SafeString(marked(str));
  });

  return function(tmplName, tmplData) {
    return env.render(tmplName, tmplData);
  };
};

var marked   = require('marked');
var nunjucks = require('nunjucks');
var path     = require('path');

module.exports = function(options) {

  options || (options = {});
  options.path || (options.path = 'template');

  var env = new nunjucks.Environment(
    new nunjucks.FileSystemLoader(options.path),
    {noCache: true}
  );
  env.addFilter('markdown', function(str) {
    if (!str) {
      return str;
    }
    return new nunjucks.runtime.SafeString(marked(str));
  });

  return function(tmplName, tmplData) {
    return env.render(tmplName, tmplData);
  };
};

Make markdown filter not to throw error for null or undefined


/**
 * The default template based URL, used as it by the template cache.
 * @type {string}
 */
ngeo.baseTemplateUrl = '../src/directives/partials';

/**
 * The default template based URL, used as-is by the template cache.
 * @type {string}
 */
ngeo.baseTemplateUrl = '../src/directives/partials';

/**
 * The default modules template based URL, used as-is by the template cache.
 * @type {string}
 */
ngeo.baseModuleTemplateUrl = '../src/modules';

Fix examples using module templates


(function(UI) {

  /** section: scripty2 ui
   *  class S2.UI.Base
   *  includes S2.UI.Mixin.Configurable
  **/
  UI.Base = Class.create(UI.Mixin.Configurable, {
    NAME: "S2.UI.Base",

    /**
     *  S2.UI.Base#addObservers() -> undefined
    **/
    addObservers:    Function.ABSTRACT,

    /**
     *  S2.UI.Base#removeObservers() -> undefined
    **/
    removeObservers: Function.ABSTRACT,

    /**
     *  S2.UI.Base#destroy() -> undefined
    **/
    destroy: function() {
      this.removeObservers();
    },

    /**
     *  S2.UI.Base#toElement() -> Element
     *
     *  Returns the DOM element corresponding to this control.
    **/
    toElement: function() {
      return this.element;
    },

    /**
     *  S2.UI.Base#inspect() -> String
    **/
    inspect: function() {
      return "#<#{NAME}>".interpolate(this);
    }
  });

})(S2.UI);

(function(UI) {

  /** section: scripty2 ui
   *  class S2.UI.Base
   *  includes S2.UI.Mixin.Configurable
   *
   *  A base class for all UI widgets.
  **/
  UI.Base = Class.create(UI.Mixin.Configurable, {
    NAME: "S2.UI.Base",

    initialize:      Function.ABSTRACT,

    /**
     *  S2.UI.Base#addObservers() -> undefined
    **/
    addObservers:    Function.ABSTRACT,

    /**
     *  S2.UI.Base#removeObservers() -> undefined
    **/
    removeObservers: function() {
      if (this.__observers) {
        this.__observers.invoke('stop');
        this.__observers = null;
      }
    },

    /**
     *  S2.UI.Base#destroy() -> undefined
    **/
    destroy: function() {
      this.removeObservers();
    },

    /**
     *  S2.UI.Base#toElement() -> Element | null
     *
     *  Returns the DOM element corresponding to this control.
     *
     *  By default, this returns the instance's `element` property, but
     *  widgets can override this behavior.
    **/
    toElement: function() {
      return this.element || null;
    },

    /**
     *  S2.UI.Base#inspect() -> String
     *
     *  Returns a debug-friendly string representation of the widget.
    **/
    inspect: function() {
      return "#<#{NAME}>".interpolate(this);
    }
  });

})(S2.UI);

Add some documentation to the abstract `S2.UI.Base` class.


module.exports = {
	package: {
		src: [ '<%= paths.tmp %>' ]
	},
	wpcom: {
		src: [
			'<%= paths.wpcom %>/*',
			'!<%= paths.wpcom %>/.svn',
			'!<%= paths.wpcom %>/inc',
			'!<%= paths.wpcom %>/includes',
			'<%= paths.wpcom %>/includes/*',
			'!<%= paths.wpcom %>/includes/wpcom',
			'!<%= paths.wpcom %>/languages'
		]
	}
};

module.exports = {
	package: {
		src: [ '<%= paths.tmp %>' ]
	},
	wpcom: {
		src: [
			'<%= paths.wpcom %>/*',
			'!<%= paths.wpcom %>/.svn',
			'!<%= paths.wpcom %>/inc',
			'!<%= paths.wpcom %>/includes',
			'<%= paths.wpcom %>/includes/*',
			'!<%= paths.wpcom %>/includes/plugins',
			'<%= paths.wpcom %>/includes/plugins/*',
			'!<%= paths.wpcom %>/includes/plugins/jetpack-pro',
			'!<%= paths.wpcom %>/languages'
		]
	}
};

Move WP.com support to /includes/plugins/jetpack-pro/*.


import Ember from 'ember';
import config from './config/environment';

var Router = Ember.Router.extend({
  location: config.locationType
});

Router.map(function () {
  this.route('cabins', {path: '/hytter', resetNamespace: true}, function () {
    this.route('edit', {path: '/:id'});
  });

  this.route('session.login', {path: '/logg-inn'});
  this.route('session.logout', {path: '/logg-ut'});
});

export default Router;

import Ember from 'ember';
import config from './config/environment';

var Router = Ember.Router.extend({
  location: config.locationType
});

Router.map(function () {
  this.route('cabins', {path: '/hytter', resetNamespace: true}, function () {
    this.route('edit', {path: '/:id'});
    this.route('new', {path: '/ny'});
  });

  this.route('session.login', {path: '/logg-inn'});
  this.route('session.logout', {path: '/logg-ut'});
});

export default Router;

Add route for adding new cabin


var TradeOfferManager = require('./index.js');

var EResult = require('../resources/EResult.js');

TradeOfferManager.prototype._apiCall = function(httpMethod, method, version, input, callback) {
	var iface = 'IEconService';
	if(typeof method === 'object') {
		iface = method.iface;
		method = method.method;
	}

	var options = {
		"uri": "https://api.steampowered.com/" + iface + "/" + method + "/v" + version + "/",
		"json": true,
		"method": httpMethod
	};

	input = input || {};
	input.key = this.apiKey;
	options[httpMethod == 'GET' ? 'qs' : 'form'] = input;

	this._request(options, function(err, response, body) {
		if(err || response.statusCode != 200) {
			callback(err || new Error("HTTP error " + response.statusCode));
			return;
		}

		var eresult = response.headers['x-eresult'];
		if(typeof eresult !== 'undefined' && eresult != 1) {
			callback(new Error(EResult[eresult]));
			return;
		}

		if(!body || typeof body != 'object') {
			callback(new Error("Invalid API response"));
			return;
		}

		callback(null, body);
	});
};

var TradeOfferManager = require('./index.js');

var EResult = require('../resources/EResult.js');

TradeOfferManager.prototype._apiCall = function(httpMethod, method, version, input, callback) {
	var iface = 'IEconService';
	if(typeof method === 'object') {
		iface = method.iface;
		method = method.method;
	}

	var options = {
		"uri": "https://api.steampowered.com/" + iface + "/" + method + "/v" + version + "/",
		"json": true,
		"method": httpMethod
	};

	input = input || {};
	input.key = this.apiKey;
	options[httpMethod == 'GET' ? 'qs' : 'form'] = input;

	this._request(options, function(err, response, body) {
		if(err || response.statusCode != 200) {
			callback(err || new Error("HTTP error " + response.statusCode));
			return;
		}

		var eresult = response.headers['x-eresult'];
		if(typeof eresult !== 'undefined' && eresult != 1) {
			var error = new Error(EResult.getName(eresult));
			error.eresult = eresult;
			callback(error);
			return;
		}

		if(!body || typeof body != 'object') {
			callback(new Error("Invalid API response"));
			return;
		}

		callback(null, body);
	});
};

Include eresult property in WebAPI errors


export const DEFAULT_QUERY = 'instrument note';
export const DEFAULT_MAX_RESULTS = 60;
export const DEFAULT_DESCRIPTOR = 'lowlevel.mfcc.mean';
export const DEFAULT_FILTER = 'duration:[0%20TO%202]';

export const DEFAULT_MESSAGE_DURATION = 4000;

export const MIN_ZOOM = 0.2;
export const MAX_ZOOM = 15;
export const MAP_SCALE_FACTOR = 20;
export const DEFAULT_RADIUS = 30;
export const DEFAULT_STROKE_WIDTH = 2;
export const DEFAULT_FILL_OPACITY = 0.7;
export const DEFAULT_STROKE_OPACITY = 0.9;

export const MAX_TSNE_ITERATIONS = 250;
export const TSNE_CONFIG = {
  epsilon: 10,
  perplexity: 10,
  dim: 2,
};

export const DEFAULT_QUERY = 'instrument note';
export const DEFAULT_MAX_RESULTS = 60;
export const DEFAULT_DESCRIPTOR = 'lowlevel.mfcc.mean';
export const DEFAULT_FILTER = 'duration:[0%20TO%205]';

export const DEFAULT_MESSAGE_DURATION = 4000;

export const MIN_ZOOM = 0.2;
export const MAX_ZOOM = 15;
export const MAP_SCALE_FACTOR = 20;
export const DEFAULT_RADIUS = 30;
export const DEFAULT_STROKE_WIDTH = 2;
export const DEFAULT_FILL_OPACITY = 0.7;
export const DEFAULT_STROKE_OPACITY = 0.9;

export const MAX_TSNE_ITERATIONS = 250;
export const TSNE_CONFIG = {
  epsilon: 10,
  perplexity: 10,
  dim: 2,
};

Set default filter to duration 5s


// ----------------------------------------------------------------
// Popover Class

class PopoverModel extends CommonModel {
  constructor({
    name = 'Popover',
    selector = null,
    help = 'popover',
    trigger = 'hover'
  } = {})
  {
    super({
      name: name
    });

    this.NAME = name;
    this.SELECTOR = selector;
    this.HELP = help;
    this.TRIGGER = trigger;
  }
}

class PopoverView extends CommonView {
  constructor(_model = new PopoverModel()) {
    super(_model);

    this.setPopover();
  }

  setPopover() {
    if (this.model.SELECTOR != null) {
      $(this.model.SELECTOR).attr('data-toggle', 'popover');
      $(this.model.SELECTOR).attr('data-content', this.model.HELP);
      $(this.model.SELECTOR).attr('data-trigger', this.model.TRIGGER);
      $(this.model.SELECTOR).popover();
    }
  }
}

// ----------------------------------------------------------------
// Controllers

class PopoverController extends CommonController {
  constructor(_obj) {
    super({
      name: 'Popover Controller'
    });

    this.model = new PopoverModel(_obj);
    this.view = new PopoverView(this.model);
  }
}

// ----------------------------------------------------------------
// Popover Class

class PopoverModel extends CommonModel {
  constructor({
    name = 'Popover',
    selector = null,
    help = 'popover',
    trigger = 'hover'
  } = {})
  {
    super({
      name: name,
      echoPermission: false
    });

    this.NAME = name;
    this.SELECTOR = selector;
    this.HELP = help;
    this.TRIGGER = trigger;
  }
}

class PopoverView extends CommonView {
  constructor(_model = new PopoverModel()) {
    super(_model);

    this.setPopover();
  }

  setPopover() {
    if (this.model.SELECTOR != null) {
      $(this.model.SELECTOR).attr('data-toggle', 'popover');
      $(this.model.SELECTOR).attr('data-content', this.model.HELP);
      $(this.model.SELECTOR).attr('data-trigger', this.model.TRIGGER);
      $(this.model.SELECTOR).popover();
    }
  }
}

// ----------------------------------------------------------------
// Controllers

class PopoverController extends CommonController {
  constructor(_obj) {
    super({
      name: 'Popover Controller'
    });

    this.model = new PopoverModel(_obj);
    this.view = new PopoverView(this.model);
  }
}

Add echoPermission option in PopoverModel


var React = require('react'),
	DOM = React.DOM;

module.exports = React.createClass({

	propTypes: {
		version: React.PropTypes.string,
		year: React.PropTypes.number,
		author: React.PropTypes.string,
		email: React.PropTypes.string,
		githubUrl: React.PropTypes.string
	},

	getDefaultProps: function () {
		return {
			year: new Date().getFullYear(),
			author: 'YourNameHere',
			email: 'your@email.com',
			githubUrl: null
		};
	},

	render: function () {
		return DOM.footer(null, [

			DOM.hr(null, null),

			DOM.div({ className: 'row' }, DOM.div({ className: 'col-xs-12 text-center' }, [
				DOM.small({ dangerouslySetInnerHTML: { __html: '© ' + this.props.year + ' ' }}),
				DOM.a({ className: 'footer__author', href: 'mailto:' + this.props.email }, this.props.author),
				DOM.small(null, ' v' + this.props.version)
			])),

			DOM.div({ className: 'row' },
				DOM.div({ className: 'col-xs-12 text-center' },
					DOM.small(null,
						DOM.a({ className: '', href: this.props.githubUrl }, 'View sourcecode on github')
					)
				)
			)

		]);
	}

});

var React = require('react'),
	DOM = React.DOM;

module.exports = React.createClass({

	propTypes: {
		version: React.PropTypes.string,
		year: React.PropTypes.number,
		author: React.PropTypes.string,
		email: React.PropTypes.string,
		githubUrl: React.PropTypes.string
	},

	getDefaultProps: function () {
		return {
			year: new Date().getFullYear(),
			author: 'YourNameHere',
			email: 'your@email.com',
			githubUrl: null
		};
	},

	render: function () {
		return DOM.footer(null, [

			DOM.hr(null, null),

			DOM.div({ className: 'row' }, DOM.div({ className: 'col-xs-12 text-center' }, [
				DOM.small({ dangerouslySetInnerHTML: { __html: '© ' + this.props.year + ' ' }}),
				DOM.a({ className: 'footer__author', href: 'mailto:' + this.props.email }, this.props.author),
				DOM.small({ className: 'footer__version'}, ' v' + this.props.version)
			])),

			DOM.div({ className: 'row' },
				DOM.div({ className: 'col-xs-12 text-center' },
					DOM.small(null,
						DOM.a({ className: 'footer__url', href: this.props.githubUrl }, 'View sourcecode on github')
					)
				)
			)

		]);
	}

});

Update component to pass tests.


const _ = require('lodash/fp')
const fs = require('fs')
const dsl = require('./dsl')
const vm = require('vm')

module.exports = function (file) {
  return vm.runInNewContext(fs.readFileSync(file),
                            _.assign(dsl, { module }),
                            { filename: file })
}

const fs = require('fs')
const dsl = require('./dsl')
const vm = require('vm')

module.exports = function (file) {
  return vm.runInNewContext(fs.readFileSync(file),
                            Object.assign({ module, require }, global, dsl),
                            { filename: file })
}

Fix missing globals in PureSpec modules


const pp        = require('./ppublish');
const pt        = require('./ptalk');
const utils     = require('../common/utils');
const fs        = require('fs');
const commander = require('commander');
const path      = require('path');

commander
    .option('-m --module <file>', 'specify a pjs file')
    .option('-s --server <String>', 'specify the server address')
    .parse(process.argv);

if (commander.module && commander.server) {
    console.log(commander.module, commander.server)
    fs.readFile(commander.module, function (err, data) {
        if (err) throw err;

        utils.rndPort().then((port) => {
            var addr = "tcp://127.0.0.1:" + port;
            data = JSON.parse(data);
            data.port = addr;

            pp.announce(data, commander.server);

            const dirname = path.dirname(commander.module);

            const imported = require(path.resolve(path.join(dirname, data.name)));

            pt(addr, function (name, params) {
                return imported[name](params);
            });

        }).catch((err) => {
            console.log(err)
        });
    });
}

const pp        = require('./ppublish');
const pt        = require('./ptalk');
const utils     = require('../common/utils');
const fs        = require('fs');
const commander = require('commander');
const path      = require('path');
const { exec }  = require('child_process');

commander
    .option('-m --module <file>', 'specify a pjs file')
    .option('-s --server <String>', 'specify the server address')
    .parse(process.argv);

function findFiles(folder, extension, cb){
    folder = path.resolve(folder);

    var command = "";

    if(/^win/.test(process.platform)){
        command = `dir /B ${folder}\\*."${extension}`;
    } else{
        command = `ls -1 ${folder}/*.${extension}`;
    }

    exec(command, (err, stdout, stderr) => {
        if(err) return cb(err, null);
        //get rid of \r from windows
        stdout = stdout.replace(/\r/g,"");
        var files = stdout.split("\n");
        //remove last entry because it is empty
        files.splice(-1, 1);
        cb(err, files);
    });
}

if (commander.module && commander.server) {
    findFiles(commander.module, 'pjs', (err, files) => {
        fs.readFile(files[0], (err, data) => {
            if (err) throw err;

            utils.rndPort().then((port) => {
                var addr = "tcp://127.0.0.1:" + port;
                data = JSON.parse(data);
                data.port = addr;

                pp.announce(data, commander.server);

                const imported = require(path.resolve(path.join(commander.module, data.name)));

                pt(addr, function (name, params) {
                    return imported[name](params);
                });

            }).catch((err) => {
                console.log(err)
            });
        });
    });
}

Add automatic pjs module search


$(document).ready(function() {
  // Set title preview
  $("#title").on('keyup', function(e) {
    $("#title-preview").text($("#title").val());
    $("#title-preview").attr("href", $("#url").val());
  })
  // Set image preview
  $("#url").on('keyup', function(e) {
    $("#img-preview").attr("src", $("#url").val());
  })
  // Replace broken images
  $("#img-preview").error(function() {
    $(this).attr("src", "http://dummyimage.com/800x600&text=Pinternet");
  });
  // Show grid
  var $grid = $('.grid').masonry({
    itemSelector: '.grid-item',
    fitWidth: true,
    transitionDuration: '0.8s',
    columnWidth: 5
  });
  // Set layout so no image overlap on image load
  $grid.imagesLoaded().progress( function() {
    $grid.masonry('layout');
  });
});

$(document).ready(function() {
  // Set title preview
  $("#title").on('keyup', function(e) {
    $("#title-preview").text($("#title").val());
    $("#title-preview").attr("href", $("#url").val());
  })
  // Set image preview
  $("#url").on('keyup', function(e) {
    $("#img-preview").attr("src", $(this).val());
  })
  // Replace broken images
  $(".grid-img").error(function() {
    $(this).attr("src", "http://dummyimage.com/800x600&text=Pinternet");
  });
  // Show grid
  var $grid = $('.grid').masonry({
    itemSelector: '.grid-item',
    fitWidth: true,
    transitionDuration: '0.8s',
    columnWidth: 5
  });
  // Set layout so no image overlap on image load
  $grid.imagesLoaded().progress( function() {
    $grid.masonry('layout');
  });
});

Replace all broken image links in js


import * as tt from 'typescript-definition-tester'

describe('TypeScript definitions', () => {
  it('should compile against index.d.ts', (done) => {
    tt.compileDirectory(
      __dirname + '/typescript',
      fileName => fileName.match(/\.ts$/),
      () => done()
    )
  })
})

import * as tt from 'typescript-definition-tester'

describe('TypeScript definitions', function() {
  this.timeout(0)

  it('should compile against index.d.ts', (done) => {
    tt.compileDirectory(
      __dirname + '/typescript',
      fileName => fileName.match(/\.ts$/),
      () => done()
    )
  })
})

Disable timeout for TypeScript definitions tests