module.exports = function(grunt) {

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    compress: {
      main: {
        options: {
          archive: 'Geocaching_Utils.zip'
        },
        files: [
          {
            src: ['source/**'],
            dest: ''
          }
        ]
      }
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        eqnull: true,
        browser: true,
        esnext: true,
        bitwise: true,
        globals: {
          jQuery: true
        },
        ignores: [
          'node_modules/**/*.js',
          'source/js/lib/**/*.js'
        ]
      },
      all: ['**/*.js']
     }
  });

  grunt.loadNpmTasks('grunt-contrib-compress');
  grunt.loadNpmTasks('grunt-contrib-jshint');

  grunt.registerTask('build', ['jshint']);
  grunt.registerTask('package', ['compress']);
  grunt.registerTask('default', ['build', 'package']);
};

module.exports = function(grunt) {

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    compress: {
      main: {
        options: {
          archive: 'GeocachingUtils_<%= pkg.version %>.zip'
        },
        files: [
          {
            src: ['source/**'],
            dest: ''
          }
        ]
      }
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        eqnull: true,
        browser: true,
        esnext: true,
        bitwise: true,
        globals: {
          jQuery: true
        },
        ignores: [
          'node_modules/**/*.js',
          'source/js/lib/**/*.js'
        ]
      },
      all: ['**/*.js']
     }
  });

  grunt.loadNpmTasks('grunt-contrib-compress');
  grunt.loadNpmTasks('grunt-contrib-jshint');

  grunt.registerTask('build', ['jshint']);
  grunt.registerTask('package', ['compress']);
  grunt.registerTask('default', ['build', 'package']);
};

Include version from package.json in build output file name


'use strict';

module.exports = function (grunt) {
  // Show elapsed time at the end
  require('time-grunt')(grunt);
  // Load all grunt tasks
  require('load-grunt-tasks')(grunt);

  // Project configuration.
  grunt.initConfig({
    mochacli: {
        src: ['test/*.js'],
        options: {
            globals: ['chai'],
            timeout: 6000,
            ignoreLeaks: false,
            ui: 'bdd',
            reporter: 'spec'
        }
    }
  });

  grunt.registerTask('test', ['mochacli']);

};

'use strict';

module.exports = function (grunt) {
  // Show elapsed time at the end
  require('time-grunt')(grunt);
  // Load all grunt tasks
  require('load-grunt-tasks')(grunt);

  // Project configuration.
  grunt.initConfig({
    mochaTest: {
      test: {
        src: ['test/*.js'],
        options: {
          globals: ['chai'],
          timeout: 6000,
          ignoreLeaks: false,
          ui: 'bdd',
          reporter: 'spec'
        }
      }
    },
    jshint: {
      all: ['lib/**/*.js'],
      options: {
        jshintrc: '.jshintrc'
      }
    },
    jscs: {
      src: 'lib/**/*.js',
      options: {
        config: '.jscsrc'
      }
    }
  });

  grunt.registerTask('test', ['mochaTest']);

};

Change test task and add code style tasks


// Made by Tim Caswell, https://gist.github.com/creationix/bb1474fd018076862c6b
module.exports = asyncMap;

// This will loop through an array calling fn(item, callback) for each item.
// It assumes that the callback will always be called eventually with (err) or (null, value)
// Once all the callbacks have been called, the outer callback will be called with (error, results)
// where `error` is the last error to occur (if any)
// and `results` is the mapped results of the initial array.
function asyncMap(array, fn, callback) {
  var left = array.length;
  var results = new Array(left);
  var error;
  // Handle case of empty array
  if (!left) return callback(error, results);
  // Run all commands in parallel and wait for results.
  array.forEach(function (item, i) {
    fn(item, function (err, result) {
      if (err) error = err;
      else results[i] = result;
      if (!--left) callback(error, results);
    });
  });
}

// Usage example and test, not part of library
asyncMap([1,2,3,4,5], function (num, callback) {
  setTimeout(function () {
    callback(null, num);
  }, Math.random() * 100);
}, function (err, results) {
  if (err) throw err;
  console.log(results);
});

// Made by Tim Caswell, https://gist.github.com/creationix/bb1474fd018076862c6b
module.exports = asyncMap;

// This will loop through an array calling fn(item, callback) for each item.
// It assumes that the callback will always be called eventually with (err) or (null, value)
// Once all the callbacks have been called, the outer callback will be called with (error, results)
// where `error` is the last error to occur (if any)
// and `results` is the mapped results of the initial array.
function asyncMap(array, fn, callback) {
  var left = array.length;
  var results = new Array(left);
  var error;
  // Handle case of empty array
  if (!left) return callback(error, results);
  // Run all commands in parallel and wait for results.
  array.forEach(function (item, i) {
    fn(item, function (err, result) {
      if (err) error = err;
      else results[i] = result;
      if (!--left) callback(error, results);
    });
  });
}

/*
// Usage example and test, not part of library
asyncMap([1,2,3,4,5], function (num, callback) {
  setTimeout(function () {
    callback(null, num);
  }, Math.random() * 100);
}, function (err, results) {
  if (err) throw err;
  console.log(results);
});
*/

Put example code in comment block.


var fs   = require("fs");
var path = require("path");
var _    = require("lodash");

var animals;
var adjectives;

module.exports = function () {
	if (animals && adjectives) {
		return { animals : animals, adjectives : adjectives };
	}

	adjectives = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "lists", "adjectives.json")));
	animals = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "lists", "animals.json")));

	_.each(adjectives, function (word, idx) { adjectives[idx] = word.toLowerCase(); });
	_.each(animals, function (word, idx) { animals[idx] = word.toLowerCase(); });

	return { adjectives : adjectives, animals : animals };
};

module.exports.NUM_ADJECTIVES = 1500;
module.exports.NUM_ANIMALS = 1750;

var fs   = require("fs");
var path = require("path");
var _    = require("lodash");

var animals;
var adjectives;

module.exports = function () {
	if (animals && adjectives) {
		return { animals : animals, adjectives : adjectives };
	}

	adjectives = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "lists", "adjectives.json")));
	animals = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "lists", "animals.json")));

	_.each(adjectives, function (word, idx) { adjectives[idx] = word.toLowerCase(); });
	_.each(animals, function (word, idx) { animals[idx] = word.toLowerCase(); });

	return { adjectives : adjectives, animals : animals };
};

module.exports.NUM_ADJECTIVES = 1501;
module.exports.NUM_ANIMALS = 1750;

Fix off-by-one for adjective list


/**
 * User: simon
 * Date: 30/08/2011
 * Time: 13:52
 * Desc: Loads test specific variables
 */

var _ = require('underscore');

// set environment specific variables
global.settings     = require(__dirname + '/../../config/settings');
global.environment  = require(__dirname + '/../../config/environments/test');
_.extend(global.settings, global.environment);
process.env['NODE_ENV'] = 'test';

Set NODE_ENV env variable to 'test' during testsuite


$(document).ready(function(){
  console.log("ready")

  $('form').on('click','.remove_fields', function(event){
    event.preventDefault();
    $(this).prev('input[type=hidden]').val('1');
    $(this).closest('fieldset').hide();
  });

  $('form').on('click','.add_fields', function(event){
    event.preventDefault();
    time = new Date().getTime();
    regexp = new RegExp($(this).data('id'), 'g');
    $(this).before($(this).data('fields').replace(regexp, time));
  });
  // $('#add-location').click(function(e){
  //   e.preventDefault();
  //   addLegForm();
  // })

$('body').on('click','.location',function(e){
  $(this).geocomplete();
});

$('#expenses_grid').on('click','#add-expense',function(e){
  console.log("clicked")
  $('#new-expense').show();
  $('#add-expense').hide();
});

$('#expenses_grid').on('submit','#new-expense',function(e){

  e.preventDefault();
  $.ajax ({
    url: $(e.target).attr('action'),
    type: 'POST',
    data: $(e.target).serialize()
  }).done(function(data){
    $('#expenses_grid').append(data);
    clearInputs();
  });

});
})

clearInputs = function(){
  $(':input').val("");
}

$(document).ready(function(){
  console.log("ready")

  $('form').on('click','.remove_fields', function(event){
    event.preventDefault();
    $(this).prev('input[type=hidden]').val('1');
    $(this).closest('fieldset').hide();
  });

  $('form').on('click','.add_fields', function(event){
    event.preventDefault();
    time = new Date().getTime();
    regexp = new RegExp($(this).data('id'), 'g');
    $(this).before($(this).data('fields').replace(regexp, time));
  });
  // $('#add-location').click(function(e){
  //   e.preventDefault();
  //   addLegForm();
  // })

$('body').on('click','.location',function(e){
  $(this).geocomplete();
});

$('#expenses_grid').on('click','#add-expense',function(e){
  console.log("clicked")
  $('#new-expense').show();
  $('#add-expense').hide();
});

$('#expenses_grid').on('submit','#new-expense',function(e){

  e.preventDefault();
  $.ajax ({
    url: $(e.target).attr('action'),
    type: 'POST',
    data: $(e.target).serialize()
  }).done(function(data){
    $('#expenses_grid').append(data);
    clearInputs();
  });

});
})

clearInputs = function(){
  $("input[name='expense[date]'").val("");
  $("input[name='expense[location_id]'").val("");
  $("input[name='expense[cost]'").val("");
  $("input[name='expense[category_id]'").val("");

}

Clear input fields properly after submitting form


angular.module('app', []).controller('AppCtrl', function ($scope, $http) {
	$scope.results = [];

	$scope.loadUsers = function() {
		$http.get('/elements')
			.success(function(data) {
				$scope.results = data;
			})
			.error(function(err) {
				$scope.results = err;
			});
	}

	$scope.clickElement = function (element) {
		var promiseElement = $http.put('/elements/' + element.id, {count: element.count + 1})
		promiseElement.then(function(elem) {
			element.count = elem.data.count;
		})
	};
});

angular.module('app', []).controller('AppCtrl', function ($scope, $http) {
	$scope.results = [];

	$scope.loadUsers = function() {
		$http.get('/elements')
			.success(function(data) {
				$scope.results = data;
			})
			.error(function(err) {
				$scope.results = err;
			});
	}

	$scope.clickElement = function (element) {
		var promiseElement = $http.put('/elements/' + element.id, {count: element.count + 1})
		promiseElement.success(function(elem) {
			element.count = elem.count;
		})
	};
});

Refactor put method for elements


module.exports = function(grunt) {
    'use strict';

    // Add the grunt-mocha-test tasks.
    grunt.loadNpmTasks('grunt-mocha-test');

    // Project configuration.
    grunt.initConfig({
        jshint: {
            all: ['Gruntfile.js', 'index.js', 'test/*.js'],
            options: {
                jshintrc: '.jshintrc'
            }
        },
        mochaTest: {
            test: {
                options: {
                    reporter: 'spec'
                },
                src: ['test/imap-client-unit.js', 'test/imap-client-integration-node.js']
            }
        }
    });

    // Load the plugin(s)
    grunt.loadNpmTasks('grunt-contrib-jshint');

    // Default task(s).
    grunt.registerTask('test', ['jshint', 'mochaTest']);
};

module.exports = function(grunt) {
    'use strict';

    // Project configuration.
    grunt.initConfig({
        jshint: {
            all: ['Gruntfile.js', 'index.js', 'test/*.js'],
            options: {
                jshintrc: '.jshintrc'
            }
        },
        mochaTest: {
            test: {
                options: {
                    reporter: 'spec'
                },
                src: ['test/imap-client-unit.js']
            }
        }
    });

    // Load the plugin(s)
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-mocha-test');

    // Default task(s).
    grunt.registerTask('test', ['jshint', 'mochaTest']);
};

Remove unreliable integration tests from automated testing


const Joi = require('joi');

const PARAMS = {
  name: Joi.string().required()
};

const PAYLOAD = {
  name: Joi.string().required(),
  maintainers: Joi.array(),
  description: Joi.string(),
  hasLicense: Joi.boolean(),
  hasLinter: Joi.boolean(),
  hasReadme: Joi.boolean(),
  engines: {
    npm: Joi.string(),
    node: Joi.string()
  }
};

exports.create = {
  payload: PAYLOAD
};

exports.delete = {
  params: PARAMS
};

exports.getOne = {
  params: PARAMS
};

exports.update = {
  params: PARAMS,
  payload: PAYLOAD
};

const Joi = require('joi');

const PARAMS = {
  name: Joi.string().required()
};

const PAYLOAD = {
  name: Joi.string().required(),
  maintainers: Joi.array(),
  description: Joi.string(),
  hasLicense: Joi.boolean(),
  hasLinter: Joi.boolean(),
  hasReadme: Joi.boolean(),
  engines: {
    npm: Joi.string(),
    node: Joi.string()
  }
};

const QUERY = {
  limit: Joi.number(),
  offset: Joi.number(),
  sort: Joi.string().allow('asc', 'ascending', 'desc', 'descending')
};

exports.create = {
  payload: PAYLOAD
};

exports.delete = {
  params: PARAMS
};

exports.getOne = {
  params: PARAMS
};

exports.getAll = {
  query: QUERY
};

exports.update = {
  params: PARAMS,
  payload: PAYLOAD
};

Add validation rules for limit, offset, and sorting


import hooks from 'htmlbars-runtime/hooks';
import render from 'htmlbars-runtime/render';
import { manualElement } from 'htmlbars-runtime/render';
import { visitChildren } from "../htmlbars-util/morph-utils";
import { blockFor, clearMorph } from "../htmlbars-util/template-utils";
import { validateChildMorphs } from "htmlbars-runtime/expression-visitor";
import {
  hostBlock,
  continueBlock,
  hostYieldWithShadowTemplate
} from 'htmlbars-runtime/hooks';

var internal = {
  blockFor: blockFor,
  manualElement: manualElement,
  hostBlock: hostBlock,
  continueBlock: continueBlock,
  hostYieldWithShadowTemplate: hostYieldWithShadowTemplate,
  visitChildren: visitChildren,
  validateChildMorphs: validateChildMorphs,
  clearMorph: clearMorph
};

export {
  hooks,
  render,
  internal
};

import hooks from './htmlbars-runtime/hooks';
import render from './htmlbars-runtime/render';
import { manualElement } from './htmlbars-runtime/render';
import { visitChildren } from "../htmlbars-util/morph-utils";
import { blockFor, clearMorph } from "../htmlbars-util/template-utils";
import { validateChildMorphs } from "./htmlbars-runtime/expression-visitor";
import {
  hostBlock,
  continueBlock,
  hostYieldWithShadowTemplate
} from 'htmlbars-runtime/hooks';

var internal = {
  blockFor: blockFor,
  manualElement: manualElement,
  hostBlock: hostBlock,
  continueBlock: continueBlock,
  hostYieldWithShadowTemplate: hostYieldWithShadowTemplate,
  visitChildren: visitChildren,
  validateChildMorphs: validateChildMorphs,
  clearMorph: clearMorph
};

export {
  hooks,
  render,
  internal
};

Use relative imports for node compatibility


//
// Reusable, domain-specific prop types
//
import PropTypes from "prop-types"

import STAGES from "../js/configs/stages"
import { CATEGORIES as startingCategories } from "../js/configs/retro_configs"

const { LOBBY, PRIME_DIRECTIVE, IDEA_GENERATION, VOTING, ACTION_ITEMS, CLOSED } = STAGES

export const alert = PropTypes.object

export const category = PropTypes.oneOf([
  ...startingCategories,
  "action-item",
])

export const presence = PropTypes.shape({
  given_name: PropTypes.string,
  online_at: PropTypes.number,
  is_facilitator: PropTypes.boolean,
})

export const presences = PropTypes.arrayOf(presence)

export const retroChannel = PropTypes.shape({
  on: PropTypes.func,
  push: PropTypes.func,
})

export const idea = PropTypes.shape({
  id: PropTypes.number,
  user: PropTypes.object,
  body: PropTypes.string,
  category,
})

export const stage = PropTypes.oneOf([
  LOBBY,
  PRIME_DIRECTIVE,
  IDEA_GENERATION,
  VOTING,
  ACTION_ITEMS,
  CLOSED,
])

export const categories = PropTypes.arrayOf(PropTypes.string)

export const votes = PropTypes.arrayOf(PropTypes.object)

export const ideas = PropTypes.arrayOf(idea)

//
// Reusable, domain-specific prop types
//
import PropTypes from "prop-types"

import STAGES from "../js/configs/stages"
import { CATEGORIES as startingCategories } from "../js/configs/retro_configs"

const { LOBBY, PRIME_DIRECTIVE, IDEA_GENERATION, VOTING, ACTION_ITEMS, CLOSED } = STAGES

export const alert = PropTypes.object

export const category = PropTypes.oneOf([
  ...startingCategories,
  "action-item",
])

export const presence = PropTypes.shape({
  given_name: PropTypes.string,
  online_at: PropTypes.number,
  is_facilitator: PropTypes.boolean,
})

export const presences = PropTypes.arrayOf(presence)

export const retroChannel = PropTypes.shape({
  on: PropTypes.func,
  push: PropTypes.func,
})

export const idea = PropTypes.shape({
  id: PropTypes.number,
  body: PropTypes.string,
  category,
})

export const stage = PropTypes.oneOf([
  LOBBY,
  PRIME_DIRECTIVE,
  IDEA_GENERATION,
  VOTING,
  ACTION_ITEMS,
  CLOSED,
])

export const categories = PropTypes.arrayOf(PropTypes.string)

export const votes = PropTypes.arrayOf(PropTypes.object)

export const ideas = PropTypes.arrayOf(idea)

Remove outdated (React) prop shape property; we no longer aggregate idea w/ user


import {jsdom} from 'jsdom';
// this adds the ability to change the dom size when testing components that render
// differently for different dom sizes
const documentHTML = '<!doctype html>

';
global.document = jsdom(documentHTML);
global.window = document.parentWindow;

global.window.resizeTo = (width, height) => {
    global.window.innerWidth = width || global.window.innerWidth;
    global.window.innerHeight = height || global.window.innerHeight;
    global.window.dispatchEvent(new Event('resize'));
};

Update old tests, add tests for utils and DataPackList


var pongular = require('../lib/pongular').pongular;

var ook = pongular.module('ook', []);
ook.constant('e', 1.7);

var pong = pongular.module('pong', ['ook']);
pong.constant('pi', 3.14);
pong.config(function(pi) {
  console.log('configging');
  console.log(pi);
});

var injector = pongular.injector(['pong']);

injector.invoke(['pi', 'e', function(pi, e) {
  console.log(pi);
  console.log(e);
}]);

var pongular = require('../../lib/pongular').pongular;

var ook = pongular.module('ook', []);
ook.constant('e', 1.7);

var pong = pongular.module('pong', ['ook']);
pong.constant('pi', 3.14);
pong.config(function(pi) {
  console.log('configging');
  console.log(pi);
});

var injector = pongular.injector(['pong']);

injector.invoke(['pi', 'e', function(pi, e) {
  console.log(pi);
  console.log(e);
}]);

Fix test after moving it


// Karma configuration file, see link for more information
// https://karma-runner.github.io/0.13/config/configuration-file.html
process.env.CHROME_BIN = require('puppeteer').executablePath()

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular/cli'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'),
      require('karma-coverage-istanbul-reporter'),
      require('@angular/cli/plugins/karma')
    ],
    client:{
      clearContext: false // leave Jasmine Spec Runner output visible in browser
    },
    coverageIstanbulReporter: {
      reports: [ 'html', 'lcovonly' ],
      fixWebpackSourcePaths: true
    },
    angularCli: {
      environment: 'dev'
    },
    reporters: ['progress', 'kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['ChromeHeadless'],
    singleRun: true
  });
};

// Karma configuration file, see link for more information
// https://karma-runner.github.io/0.13/config/configuration-file.html
// process.env.CHROME_BIN = require('puppeteer').executablePath()

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular/cli'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'),
      require('karma-coverage-istanbul-reporter'),
      require('@angular/cli/plugins/karma')
    ],
    client:{
      clearContext: false // leave Jasmine Spec Runner output visible in browser
    },
    coverageIstanbulReporter: {
      reports: [ 'html', 'lcovonly' ],
      fixWebpackSourcePaths: true
    },
    angularCli: {
      environment: 'dev'
    },
    reporters: ['progress', 'kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['ChromeHeadless'],
    singleRun: true
  });
};

Install chromium directly (not via puppeteer)


import inquirer from 'inquirer'

function deleteStack (cloudformation, argv, utils) {
  const stackName = argv._[1]

  inquirer.prompt([
    {
      type: 'confirm',
      name: 'ok',
      message: `Are you sure you want to delete ${stackName}?`
    }
  ], function (answers) {
    if (!answers.ok) {
      return process.exit()
    }

    const beforeDeleteDate = new Date()

    cloudformation.deleteStack({
      StackName: stackName
    }, function (err, response) {
      if (err) {
        throw new Error(err)
      }

      utils.pollEvents(stackName, 'Deleting...', [
        [ 'LogicalResourceId', stackName ],
        [ 'ResourceStatus', 'DELETE_COMPLETE' ]
      ], function (err) {
        if (err) {
          if (err.code !== 'ValidationError') {
            throw new Error(err)
          }
          process.exit()
        }

        process.exit()
      }, {
        startDate: beforeDeleteDate,
        ignoreMissing: true
      })
    })
  })
}

export default {
  name: 'delete',
  description: 'Deletes a stack',
  fn: deleteStack
}

import inquirer from 'inquirer'

function deleteStack (cloudformation, argv, utils) {
  const stackName = argv._[1]

  inquirer.prompt([
    {
      type: 'confirm',
      name: 'ok',
      message: `Are you sure you want to delete ${stackName}?`
    },
    {
      type: 'input',
      name: 'region',
      message: 'Just confirming, which region did you want to delete this stack in?'
    }
  ], function (answers) {
    if (!answers.ok) {
      return process.exit()
    }

    if (answers.region !== argv.region) {
      console.error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'.red)
      console.error('The region you entered was different from the one you previously selected.')
      console.error('Aborted.')
      process.exit(1)
    }

    const beforeDeleteDate = new Date()

    cloudformation.deleteStack({
      StackName: stackName
    }, function (err, response) {
      if (err) {
        throw new Error(err)
      }

      utils.pollEvents(stackName, 'Deleting...', [
        [ 'LogicalResourceId', stackName ],
        [ 'ResourceStatus', 'DELETE_COMPLETE' ]
      ], function (err) {
        if (err) {
          if (err.code !== 'ValidationError') {
            throw new Error(err)
          }
          process.exit()
        }

        process.exit()
      }, {
        startDate: beforeDeleteDate,
        ignoreMissing: true
      })
    })
  })
}

export default {
  name: 'delete',
  description: 'Deletes a stack',
  fn: deleteStack
}

Add region confirmation for delete command


import { createStore } from 'redux'
import reducer from '../reducers'

export default () => {
  const store = createStore(reducer)

  return store
}

import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import reducer from '../reducers'

export default () => {
  const store = createStore(
    reducer,
    applyMiddleware(thunk)
  )

  return store
}

Add thunk middleware to store


'use strict'

var pubsubangular = angular.module('pubsub.angular', []);
pubsubangular.factory('ps', function () {
    var ps = window.PubSub;
    if(!!ps===false){
        throw new Error('Pubsub-js is a required dependency.');
    }
    return ps;
});

pubsubangular
    .directive('psSubscribe', function (ps) {
        return {
            template: '<div ng-transclude></div>',
            transclude: true,
            link: function postLink(scope, element, attrs) {
                var attr = (attrs.psSubscribe || "").split('|');
                var context = {
                    event: 'broadcast',
                    data: 'data'
                };

                if (attr.length == 1) {
                    context.event = attr[0].trim();
                } else if (attr.length == 2) {
                    context.event = attr[0].trim();
                    context.container = attr[1].trim();
                }

                ps.subscribe(context.event, function (label, d) {
                    scope.label = label;
                    scope[context.data] = d;
                    scope.$digest();
                });
            }
        };
    });

'use strict'

var pubsubangular = angular.module('pubsub.angular', []);
pubsubangular.factory('ps', function () {
    var ps = window.PubSub;
    if(!!ps===false){
        throw new Error('Pubsub-js is a required dependency.');
    }
    return ps;
});

pubsubangular
    .directive('psSubscribe', function (ps) {
        return {
            template: '<div ng-transclude></div>',
            transclude: true,
            link: function postLink(scope, element, attrs) {
                var attr = (attrs.psSubscribe || "").split('|');
                var context = {
                    event: 'broadcast',
                    data: 'data'
                };

                if (attr.length == 1) {
                    context.event = attr[0].trim();
                } else if (attr.length == 2) {
                    context.event = attr[0].trim();
                    context.data = attr[1].trim();
                }

                ps.subscribe(context.event, function (label, d) {
                    scope.label = label;
                    scope[context.data] = d;
                    scope.$digest();
                });
            }
        };
    });

Correct container name to data


function Switch() {
	var self = Ti.UI.createWindow({});

	var view = Ti.UI.createView({
		left : '35%',
		top : '35%',
		layout : 'horizontal'
	});

	var titleLabel = Ti.UI.createLabel({
		text : 'On/Off'
	});

	// cannot use the keyword 'switch' because it is reserved in JS
	var onOffSwitch = Ti.UI.createSwitch({
		left : '10dp', // left from the titleLabel
		value : true, // can be true or false
		title : 'On off', // android only and with checkbox
		style : (Ti.Platform.osname === 'android' ?
				Titanium.UI.Android.SWITCH_STYLE_CHECKBOX : undefined) // android only
	});

	onOffSwitch.addEventListener('change', function(e) {
		alert(e.value);
	});

	if (Ti.Platform.osname === 'ipad' || Ti.Platform.osname === 'iphone') {
		view.add(titleLabel);
	}

	view.add(onOffSwitch);

	self.add(view);

	return self;
};

module.exports = Switch;

Complete lesson 15 - switch


import { DocumentNode, CHILD, CHILDREN, TEXT } from 'substance'
import { RICH_TEXT_ANNOS } from './modelConstants'

export default class Article extends DocumentNode {}
Article.schema = {
  type: 'article',
  metadata: CHILD('metadata'),
  title: TEXT(RICH_TEXT_ANNOS),
  abstract: CHILD('abstract'),
  body: CHILD('body'),
  references: CHILDREN('reference'),
  footnotes: CHILDREN('footnote'),
  // EXPERIMENTAL: a translation has a link to the original content property
  // e.g. a translation for the article abstract points to 'article.abstract'
  // and has the same 'targetTypes' as the source property
  // FIXME: implement a UI for translations
  translations: CHILDREN('translation')
}

import { DocumentNode, CHILD, CHILDREN, TEXT } from 'substance'
import { RICH_TEXT_ANNOS } from './modelConstants'

export default class Article extends DocumentNode {}
Article.schema = {
  type: 'article',
  metadata: CHILD('metadata'),
  title: TEXT(RICH_TEXT_ANNOS),
  subTitle: TEXT(RICH_TEXT_ANNOS),
  abstract: CHILD('abstract'),
  body: CHILD('body'),
  references: CHILDREN('reference'),
  footnotes: CHILDREN('footnote'),
  // EXPERIMENTAL: a translation has a link to the original content property
  // e.g. a translation for the article abstract points to 'article.abstract'
  // and has the same 'targetTypes' as the source property
  // FIXME: implement a UI for translations
  translations: CHILDREN('translation')
}

Extend article schema with subtitle.


'use strict';
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');

var AppengineGenerator = module.exports = function AppengineGenerator(args, options, config) {
  yeoman.generators.Base.apply(this, arguments);
  this.args = args;
  this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(AppengineGenerator, yeoman.generators.Base);

AppengineGenerator.prototype.askFor = function askFor() {
  var cb = this.async();

  this.appId = this.args[0] || undefined;

  var prompts = [];

  if (this.args[0] === undefined) {
    prompts.push({
      name: 'appId',
      message: 'What is the application ID?',
      default: 'new-application'
    })
  } else {
    this.appId = this.args[0];
  }

  this.prompt(prompts, function (props) {
    for (var prop in props) {
      this[prop] = props[prop];
    }

    cb();
  }.bind(this));
};

AppengineGenerator.prototype.projectfiles = function projectfiles() {
  this.copy('editorconfig', '.editorconfig');
};

AppengineGenerator.prototype.AppEngineFiles = function AppEngineFiles() {
  this.template('app.yaml');
  this.copy('index.yaml');
};

AppengineGenerator.prototype.StaticFiles = function StaticFiles() {
  this.mkdir('assets');
  this.directory('assets');
};

'use strict';
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');

var AppengineGenerator = module.exports = function AppengineGenerator(args, options, config) {
  yeoman.generators.Base.apply(this, arguments);
  this.args = args;
  this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(AppengineGenerator, yeoman.generators.Base);

AppengineGenerator.prototype.askFor = function askFor() {
  var cb = this.async();

  this.appId = this.args[0] || undefined;

  var prompts = [];

  if (this.args[0] === undefined) {
    prompts.push({
      name: 'appId',
      message: 'What is the application ID?',
      default: path.basename(process.cwd())
    })
  } else {
    this.appId = this.args[0];
  }

  this.prompt(prompts, function (props) {
    for (var prop in props) {
      this[prop] = props[prop];
    }

    cb();
  }.bind(this));
};

AppengineGenerator.prototype.projectfiles = function projectfiles() {
  this.copy('editorconfig', '.editorconfig');
};

AppengineGenerator.prototype.AppEngineFiles = function AppEngineFiles() {
  this.template('app.yaml');
  this.copy('index.yaml');
};

AppengineGenerator.prototype.StaticFiles = function StaticFiles() {
  this.mkdir('assets');
  this.directory('assets');
};

Set default application name to folder name


import {
  moduleForModel,
  test
} from 'ember-qunit';

moduleForModel('instructor-group', 'InstructorGroup', {
  // Specify the other units that are required for this test.
  needs: [
    'model:school',
    'model:user',
    'model:program',
    'model:program-year',
    'model:offering',
    'model:session',
  ]
});

test('it exists', function() {
  var model = this.subject();
  // var store = this.store();
  ok(!!model);
});

import {
  moduleForModel,
  test
} from 'ember-qunit';
import Ember from 'ember';

moduleForModel('instructor-group', 'InstructorGroup', {
  // Specify the other units that are required for this test.
  needs: [
    'model:school',
    'model:user',
    'model:program',
    'model:program-year',
    'model:offering',
    'model:session',
    'model:course',
  ]
});

test('it exists', function() {
  var model = this.subject();
  // var store = this.store();
  ok(!!model);
});

test('list courses', function() {
  expect(3);
  var model = this.subject();
  var store = model.store;
  Ember.run(function(){

    var course1 = store.createRecord('course', {title:'course1'});
    var course2 = store.createRecord('course', {title:'course2'});
    var session1 = store.createRecord('session', {course: course1});
    var session2 = store.createRecord('session', {course: course1});
    var session3 = store.createRecord('session', {course: course2});
    model.get('offerings').then(function(offerings){
      offerings.pushObject(store.createRecord('offering', {session: session1}));
      offerings.pushObject(store.createRecord('offering', {session: session1}));
      offerings.pushObject(store.createRecord('offering', {session: session1}));
      offerings.pushObject(store.createRecord('offering', {session: session2}));
      offerings.pushObject(store.createRecord('offering', {session: session2}));
      offerings.pushObject(store.createRecord('offering', {session: session3}));
    });
  });

  Ember.run(function(){
    var courses = model.get('courses');
    equal(courses.length, 2);
    equal(courses.objectAt(0).get('title'), 'course1');
    equal(courses.objectAt(1).get('title'), 'course2');
  });

});

Test the courses property on the instructor-group model


(function () {
  'use strict';

  var mod = angular.module('components.utils', []);

  mod.factory('Utils', ['$window', function Utils($window) {

    function stringify(obj, prefix) {
      var str = [];

      for(var p in obj) {
        var k = prefix ? prefix + '[' + p + ']' : p, v = obj[p];
        str.push(typeof v == 'object' ?
          stringify(v, k) :
          encodeURIComponent(k) + '=' + encodeURIComponent(v));
      }

      return str.join('&');
    }

    function objectToFormData(data) {
      var formData  = new $window.FormData();

      for(var i in data) {
        if(_.isObject(data[i])) {

          for(var j in data[i]) {
            formData.append(i + '[' + j + ']', data[i][j]);
          }

        } else if(_.isArray(data[i])) {

          for(var k in data[i]) {
            formData.append(i + '[]', data[i][k]);
          }

        } else {
          formData.append(i, data[i]);
        }
      }

      return formData;
    }

    return {
      stringify: stringify,
      objectToFormData: objectToFormData
    };
  }]);

}());

(function () {
  'use strict';

  var mod = angular.module('components.utils', []);

  mod.factory('Utils', ['$window', function Utils($window) {

    function stringify(obj, prefix) {
      var str = [];

      for(var p in obj) {
        var k = prefix ? prefix + '[' + p + ']' : p, v = obj[p];
        str.push(typeof v == 'object' ?
          stringify(v, k) :
          encodeURIComponent(k) + '=' + encodeURIComponent(v));
      }

      return str.join('&');
    }

    function objectToFormData(data) {
      var formData  = new $window.FormData();

      for(var i in data) {
        if(_.isArray(data[i])) {

          for(var k in data[i]) {
            formData.append(i + '[]', data[i][k]);
          }

        } else if(_.isObject(data[i])) {

          for(var j in data[i]) {
            formData.append(i + '[' + j + ']', data[i][j]);
          }

        } else {
          formData.append(i, data[i]);
        }
      }

      return formData;
    }

    return {
      stringify: stringify,
      objectToFormData: objectToFormData
    };
  }]);

}());

Fix checking type of data (array is recognized as an object)


var controller = null;
var speed = 30;
var life = 3000;

function start()
{
	controller = Game.getFromScene("Background").ControllerScript;
}

function update(time)
{
	if(controller.paused)
		return;

    var addX = speed*(time/1000)

    GameObject.translate(0,-addX, 0);

    life -= time;
    if(life <= 0)
        GameObject.destroy();
}

var speed = 30;
var life = 3000;

function start()
{
}

function update(time)
{
    var addX = speed*(time/1000)

    GameObject.translate(0,-addX, 0);

    life -= time;
    if(life <= 0)
        GameObject.destroy();
}

Allow bullets to finish travelling - otherwise it looks all silly ;)


'use strict';

var net    = require('net'),
    utils  = require('radiodan-client').utils,
    logger = utils.logger(__filename);

function create(port, socket) {
  var deferred = utils.promise.defer(),
      retries  = 0,
      timeout  = 1000;

  socket = socket || new net.Socket();

  socket.setTimeout(2500);

  function addHandlers() {
    socket.on('connect', handleConnect);
    socket.on('error', handleError);
  }

  function handleConnect() {
    logger.debug('Connected to', port);
    deferred.resolve(port);
  }

  function handleError() {
    logger.warn('Cannot connect, attempt #' + retries++);

    setTimeout(function () {
      socket.connect(port);
    }, timeout);
  }

  function connect() {
    logger.debug('Connecting to port', port);
    addHandlers();
    socket.connect(port);
    return deferred.promise;
  }

  return {
    _addHandlers: addHandlers,
    connect: connect
  };
}

module.exports = {
  create: create
};

'use strict';

var net    = require('net'),
    utils  = require('radiodan-client').utils,
    logger = utils.logger(__filename);

function create(port, socket) {
  var deferred = utils.promise.defer(),
      retries  = 0,
      timeout  = 1000;

  socket = socket || new net.Socket();

  socket.setTimeout(2500);

  function addHandlers() {
    socket.on('connect', handleConnect);
    socket.on('error', handleError);
  }

  function handleConnect() {
    logger.debug('Connected to', port);
    deferred.resolve(port);
  }

  function handleError() {
    logger.warn('Cannot connect, attempt #' + ++retries);

    setTimeout(function () {
      socket.connect(port);
    }, timeout);
  }

  function connect() {
    logger.debug('Connecting to port', port);
    addHandlers();
    socket.connect(port);
    return deferred.promise;
  }

  return {
    _addHandlers: addHandlers,
    connect: connect
  };
}

module.exports = {
  create: create
};

Increment retries before printing log


var fs = require('fs');
var path = require('path');
var each = require('async').each;
var debug = require('debug')('metalsmith-mtime');

/**
 * Expose `plugin`.
 */

module.exports = plugin;

/**
 * A Metalsmith plugin that adds files mtimes to their metadata.
 *
 * @return {Function}
 */
function plugin() {
  return addAllMtimes;
}

function addAllMtimes(files, metalsmith, done) {

  // File system will be accessed for each element so iterate in parallel.
  each(Object.keys(files), getAddMtime, done);

  function getAddMtime(file, done) {
    fs.stat(path.join(metalsmith.source(), file), addMtime);

    function addMtime(err, stats) {
      if (err) {
        return done(err);
      }

      debug('mtime of file %s is %s', file, stats.mtime);
      files[file].mtime = stats.mtime;
      done();
    }
  }
}

var fs = require('fs');
var path = require('path');
var each = require('async').each;
var debug = require('debug')('metalsmith-mtime');

/**
 * Expose `plugin`.
 */

module.exports = plugin;

/**
 * A Metalsmith plugin that adds files mtimes to their metadata.
 *
 * @return {Function}
 */
function plugin() {
  return addAllMtimes;
}

function addAllMtimes(files, metalsmith, done) {

  // File system will be accessed for each element so iterate in parallel.
  each(Object.keys(files), getAddMtime, done);

  function getAddMtime(file, done) {
    fs.stat(path.join(metalsmith.source(), file), addMtime);

    function addMtime(err, stats) {
      if (err) {
        // Skip elements of `files` that don't point to existing files.
        // This can happen if some other Metalsmith plugin does something
        // strange with `files`.
        if (err.code === 'ENOENT') {
          debug('file %s not found', file);
          return done();
        }
        return done(err);
      }

      debug('mtime of file %s is %s', file, stats.mtime);
      files[file].mtime = stats.mtime;
      done();
    }
  }
}

Implement skipping of non-existing files


Object.defineProperty(exports, 'lock', {
	get() {
		return require('./lock');
	}
});

Object.defineProperty(exports, 'tag', {
	get() {
		return require('./tag');
	}
});

Object.defineProperty(exports, 'vary', {
	get() {
		return require('./vary');
	}
});

Object.defineProperty(exports, 'map', {
	get() {
		return require('./map');
	}
});

Object.defineProperty(exports, 'lock', {
	get() {
		return require('./lock');
	}
});

Object.defineProperty(exports, 'tag', {
	get() {
		return require('./tag');
	}
});

Object.defineProperty(exports, 'map', {
	get() {
		return require('./map');
	}
});

Drop vary from js module


/**
 * Dependencies
 * --------------------------------------------------------------------------*/

var Promise = require('bluebird'),
    _       = require('underscore');

/**
 * Returns a promise of a document's save operation
 */

function saveP(doc) {
  return Promise.promisify(doc.save, doc)()
    .then(_.first);
}

/**
 * Returns a promise of a document's remove operation
 */

function removeP(doc) {
  return Promise.promisify(doc.remove, doc)()
    .then(_.first);
}

/**
 * Returns a promise of a Model's findOne operation, with an optional not found
 * error message
 */

function findOneP(model, query, not_found_msg) {
  var findOne = model.findOneAsync || Promise.promisify(model.findOne, model),
      docP = findOne(query);

  if(not_found_msg) {
    return docP.then(function(doc) {
      if(!doc) throw _.extend(new Error(not_found_msg), { status: 404 });
      else     return doc;
    });
  } else return docP;
}

function findByIdP(model, id, not_found_msg) {
  return findOneP(model, {_id: id}, not_found_msg);
}

module.exports = {
  saveP:     saveP,
  removeP:   removeP,
  findOneP:  findOneP,
  findByIdP: findByIdP
};

/**
 * Dependencies
 * --------------------------------------------------------------------------*/

var Promise = require('bluebird'),
    _       = require('underscore');

/**
 * Invokes a promisified version of method on an object
 */

function invokeP(obj, method_name, args) {
  return Promise.promisify(obj[method_name], obj).apply(obj, args);
}

/**
 * Returns a promise of a document's save operation
 */

function saveP(doc) {
  return invokeP(doc, 'save').then(_.first);
}

/**
 * Returns a promise of a document's remove operation
 */

function removeP(doc) {
  return invokeP(doc, 'remove').then(_.first);
}

/**
 * Returns a promise of a Model's findOne operation, with an optional not found
 * error message
 */

function findOneP(model, query, not_found_msg) {
  var findOne = model.findOneAsync || Promise.promisify(model.findOne, model),
      docP = findOne(query);

  if(not_found_msg) {
    return docP.then(function(doc) {
      if(!doc) throw _.extend(new Error(not_found_msg), { status: 404 });
      else     return doc;
    });
  } else return docP;
}

function findByIdP(model, id, not_found_msg) {
  return findOneP(model, {_id: id}, not_found_msg);
}

module.exports = {
  invokeP:   invokeP,
  saveP:     saveP,
  removeP:   removeP,
  findOneP:  findOneP,
  findByIdP: findByIdP
};

Add an invokeP function and use it internally


/**
 * Module dependencies
 */

var generate = require('./generate')
	, reportback = require('reportback')();

/**
 * Generate module(s)
 *
 * @param  {Object}   scope [description]
 * @param  {Function} cb    [description]
 * @return {[type]}         [description]
 */
module.exports = function (scope, cb) {
	cb = reportback.extend(cb);

	if (!scope.generatorType) {
		return cb.error('Sorry, `scope.generatorType` must be defined.');
	}

	// Use configured module name for this generatorType if applicable.
	var module = (scope.modules && scope.modules[scope.generatorType])
		|| 'sails-generate-' + scope.generatorType;

	// Try to load the generator module
	var Generator;
	try {
		Generator = require(module);
	}
	catch (e) { return cb.log.error(e); }

	generate (Generator, scope, {
		error: cb.error,
		success: function (output) { cb.log.info('ok!'); },
		notSailsApp: function () { cb.log.error('Not a sails app.'); },
		alreadyExists: function () {
			console.log('1111');
			return cb.error();
		}
	});

};

/**
 * Module dependencies
 */

var generate = require('./generate')
	, reportback = require('reportback')();

/**
 * Generate module(s)
 *
 * @param  {Object}   scope [description]
 * @param  {Function} cb    [description]
 * @return {[type]}         [description]
 */
module.exports = function (scope, cb) {
	cb = reportback.extend(cb, {
		error: cb.error,
		success: function (output) { cb.log.info('ok!'); },
		notSailsApp: function () { cb.log.error('Not a sails app.'); },
		alreadyExists: function () {
			console.log('1111');
			return cb.error();
		}
	});

	if (!scope.generatorType) {
		return cb.error('Sorry, `scope.generatorType` must be defined.');
	}

	// Use configured module name for this generatorType if applicable.
	var module = (scope.modules && scope.modules[scope.generatorType])
		|| 'sails-generate-' + scope.generatorType;

	// Try to load the generator module
	var Generator;
	try {
		Generator = require(module);
	}
	catch (e) { return cb.log.error(e); }

	generate (Generator, scope, cb);

};

Allow override of all callbacks for sails-generate


/* See license.txt for terms of usage */

/**
 * xxxHonza: TODO docs
 */
window.addEventListener("click", function(event) {
  var target = event.target;
  if (target.id == "start") {
    console.log("from content " + target.id)
    self.port.emit("start");
  }
})

/* See license.txt for terms of usage */

/**
 * Content script for notification panel. It's only purpose is registering
 * a listener for 'click' event and sending a message to the chrome scope
 * if the user clicks on 'Start Pixel Perfect' link.
 */
window.addEventListener("click", function(event) {
  var target = event.target;
  if (target.id == "start") {
    self.port.emit("start");
  }
})

Update JS docs for notification content script


'use strict';
/*global window: false, document: false, $:false, d3:false, toggle_overview_btn, checkIfUsingChromeLocally, addData*/

$(document).ready(function() {
  toggle_overview_btn(); // write overview to overview section
  initTableSorter();
  $("[data-toggle='tooltip']").tooltip(); //ToolTip
  checkIfUsingChromeLocally();
});

$( document ).on( "click", "td, .plot_btn", function( event ) {
    if ($(this).hasClass('success') || $(this).hasClass('danger')){
      var title = $(this).attr('title');
      var val = title.replace(/[ \/]/g, '');
      addData(this, val);
    } else if ($(this).hasClass('plot_btn')){
      addData(this, 'all');
    }
});

function initTableSorter() {
  $.tablesorter.addParser({
    id: 'star_scores', // called later when init the tablesorter
    is: function() {
      return false; // return false so this parser is not auto detected
    },
    format: function(s, table, cell, cellIndex) {
      var $cell = $(cell);
      if (cellIndex === 1) {
        return $cell.attr('data-score') || s;
      }
      return s;
    },
    parsed: false,
    type: 'numeric' // Setting type of data...
  });
  $('table').tablesorter({
    headers: {
      1 : { sorter: 'star_scores' } // Telling it to use custom parser...
    },
    sortList: [[0,0]],
  });
}

'use strict';
/*global window: false, document: false, $:false, d3:false, toggle_overview_btn, checkIfUsingChromeLocally, addData*/

$(document).ready(function() {
  checkIfUsingChromeLocally();
  toggle_overview_btn(); // write overview to overview section
  initTableSorter();
  $("[data-toggle='tooltip']").tooltip(); //ToolTip
});

$( document ).on( "click", "td, .plot_btn", function( event ) {
    if ($(this).hasClass('success') || $(this).hasClass('danger')){
      var title = $(this).attr('title');
      var val = title.replace(/[ \/]/g, '');
      addData(this, val);
    } else if ($(this).hasClass('plot_btn')){
      addData(this, 'all');
    }
});

function initTableSorter() {
  $.tablesorter.addParser({
    id: 'star_scores', // called later when init the tablesorter
    is: function() {
      return false; // return false so this parser is not auto detected
    },
    format: function(s, table, cell, cellIndex) {
      var $cell = $(cell);
      if (cellIndex === 1) {
        return $cell.attr('data-score') || s;
      }
      return s;
    },
    parsed: false,
    type: 'numeric' // Setting type of data...
  });
  $('table').tablesorter({
    headers: {
      1 : { sorter: 'star_scores' } // Telling it to use custom parser...
    },
    sortList: [[0,0]],
  });
}

Check if using chrome first


const got = require('got');

const cache = require('../utils/cache.js');
const time = require('../utils/time.js');

// Get trips for stop.
async function getTrips(id) {

	const now = time.getSeconds();

	return (await cache.use('elron-trips', id, async () => {

		const data = JSON.parse((await got(`http://elron.ee/api/v1/stop?stop=${encodeURIComponent(id)}`)).body).data;

		if (!data) throw new Error("Provider 'Elron' is not returning data");
		if (data.text) throw new Error(data.text);

		return data.map((trip) => ({
			time: time.toSeconds(trip.plaaniline_aeg),
			countdown: time.toSeconds(trip.plaaniline_aeg) - now,
			name: trip.reis,
			destination: trip.liin,
			type: 'train',
			live: false,
			provider: 'elron'
		}));

	})).filter((trip) => trip.time > now).slice(0, 15);

}

module.exports = {
	getTrips
};

const got = require('got');

const cache = require('../utils/cache.js');
const time = require('../utils/time.js');

// Get trips for stop.
async function getTrips(id) {

	const now = time.getSeconds();
	const trips = JSON.parse((await got(`http://elron.ee/api/v1/stop?stop=${encodeURIComponent(id)}`)).body).data;

	if (!trips) throw new Error("Provider 'Elron' is not returning data");
	if (trips.text) throw new Error(trips.text);

	// Show not arrived trips until 30 minutes of being late.
	return trips.filter((trip) => !trip.tegelik_aeg).map((trip) => ({
		time: time.toSeconds(trip.plaaniline_aeg),
		countdown: time.toSeconds(trip.plaaniline_aeg) - now,
		name: trip.reis,
		destination: trip.liin,
		type: 'train',
		live: false,
		provider: 'elron'
	})).filter((trip) => now - trip.time < 1800).slice(0, 15);

}

module.exports = {
	getTrips
};

Make Elron provider count live time (api)


var artistController = require('../controllers/artist-controller');
var genreController = require('../controllers/genre-controller');

module.exports = function(app, passport) {
  app.get('/auth/facebook', passport.authenticate('facebook', { scope : 'email' }));

  app.get('/auth/facebook/callback',
  passport.authenticate('facebook', {
    failureRedirect : '/'
  }), function(req, res) {
    return res.status(200).send(req.user);
  });

  app.get('/profile', function(req, res) {
    return res.send(200);
  });

  app.post('/api/artist/:id/like', artistController.likeArtist);
  app.get('/api/artist/recommendation', artistController.getArtistRecommendations);

  app.get('/api/genre', genreController.getGenres);
  app.get('/api/genre/artists', genreController.getArtistsByGenre);
};

var artistController = require('../controllers/artist-controller');
var genreController = require('../controllers/genre-controller');

module.exports = function(app, passport) {
  app.get('/auth/facebook', passport.authenticate('facebook', { scope : 'email' }));

  app.get('/auth/facebook/callback',
  passport.authenticate('facebook', {
    failureRedirect : '/'
  }), function(req, res) {
    return res.status(200).send(req.user);
  });

  app.get('/profile', function(req, res) {
    return res.send(200);
  });

  app.post('/api/artist/:id/like', artistController.likeArtist);
  app.get('/api/artist/recommendation', artistController.getArtistRecommendations);

  app.get('/api/genre', genreController.getGenres);
  app.get('/api/genre/artists', genreController.getArtistsByGenre);

  app.get('*', function(req, res) {
    return res.render('index.html');
  });
};

Add catchall route for serving Angular application


var express = require('express');
var router = express.Router();
var visitsHelper = require('../src/helpers/visits');
var parser = require('../src/helpers/parser.js');

var url = process.env.ENDPOINT_URL;

/* GET visits listing. */
router.get('/', function(req, res) {
  var token = parser.parse(req.headers);

  // FIXME(gfestari):This call simply takes too long for promises to complete.
  // visitsHelper.getVisits(url + '/visits', token, function(err, data) {
  //   if (err) { return; }
  //   res.json(data);
  // });

  visitsHelper.queryApi(url + '/visits', token, 1, function(data) {
    res.json(data.body);
  });

});

module.exports = router;

var express = require('express');
var router = express.Router();
var visitsHelper = require('../src/helpers/visits');
var parser = require('../src/helpers/parser.js');

var url = process.env.ENDPOINT_URL;

/* GET visits listing. */
router.get('/', function(req, res) {
  var token = parser.parse(req.headers);
  // FIXME(gfestari):This call simply takes too damn long
  visitsHelper.getVisits(url + '/visits', token, function(err, data) {
    if (err) { return; }
    res.json({ visits: data });
  });
});

module.exports = router;

Enable full recursive visit search


Meteor.startup(function () {
  // Reset Database only in environment dev
  if (process.env.NODE_ENV === 'development') {
    KSessions.remove({});
    Books.remove({});
    datas = Fixtures; // Specific datas for dev environment
  }
  else if (process.env.NODE_ENV === 'production') {
    datas = Datas; // Specific datas for prod environment
  }

  // Specific insert for Books
  datas.books.forEach(function(record) {
    if (Books.findOne(record._id)) {
      Books.update(record._id, record);
    }
    else {
      Books.insert(record);
    }
  });

  Meteor.publish("all_books", function() {
    return Books.find();
  });

  // Specific insert for KSessions
  datas.ksessions.forEach(function(record) {
    if (KSessions.findOne(record._id)) {
      KSessions.update(record._id, record);
    }
    else {
      KSessions.insert(record);
    }
  });

  Meteor.publish("all_ksessions", function() {
    return KSessions.find();
  });

  // Specific insert for users
  datas.users.forEach(function(user) {
    if (! Meteor.users.findOne({username: user.username})) {
      Accounts.createUser(user);
    }
  });
});

Meteor.startup(function () {
  // Reset Database only in environment dev
  if (process.env.NODE_ENV === 'development') {
    KSessions.remove({});
    Books.remove({});

    // Specific insert for Books
    Fixtures.books.forEach(function(rec) {
      if (Books.findOne(rec._id)) {
        Books.update(rec._id, rec);
      }
      else {
        Books.insert(rec);
      }
    });

    Meteor.publish("all_books", function() {
      return Books.find();
    });

    // Specific insert for KSessions
    Fixtures.ksessions.forEach(function(rec) {
      if (KSessions.findOne(rec._id)) {
        KSessions.update(rec._id, rec);
      }
      else {
        KSessions.insert(rec);
      }
    });

    Meteor.publish("all_ksessions", function() {
      return KSessions.find();
    });

    // Specific insert for users
    Fixtures.users.forEach(function(user) {
      if (! Meteor.users.findOne({username: user.username})) {
        Accounts.createUser(user);
      }

    });
  }
});

Disable data change in prod and pre-prod environment


/* global sauce, jQuery */

sauce.ns('profile', ns => {
    'use strict';

    const idMatch = location.pathname.match(/\/(?:athletes|pros)\/([0-9]+)/);
    const athleteId = idMatch ? Number(idMatch[1]) : null;

    async function load() {
        if (sauce.patronLevel && sauce.patronLevel >= 10) {
            const $name = jQuery('.profile-heading .athlete-name');
            const name = $name.text().trim();
            const $btn = await sauce.sync.createSyncButton(athleteId, {name});
            const $buttonBox = $name.siblings('.follow-action');
            if ($buttonBox.length) {
                // Peer
                $buttonBox.prepend($btn);
            } else {
                // Self
                $name.parent().append($btn);
            }
        }
    }

    if (['interactive', 'complete'].indexOf(document.readyState) === -1) {
        addEventListener('DOMContentLoaded', () => load().catch(sauce.report.error));
    } else {
        load().catch(sauce.report.error);
    }
});

/* global sauce, jQuery */

sauce.ns('profile', ns => {
    'use strict';

    const idMatch = location.pathname.match(/\/(?:athletes|pros)\/([0-9]+)/);
    const athleteId = idMatch ? Number(idMatch[1]) : null;

    async function load() {
        if (sauce.patronLevel && sauce.patronLevel >= 10 && currentAthlete.isLoggedIn()) {
            const $name = jQuery('.profile-heading .athlete-name');
            const name = $name.text().trim();
            const $btn = await sauce.sync.createSyncButton(athleteId, {name});
            const $buttonBox = $name.siblings('.follow-action');
            if ($buttonBox.length) {
                // Peer
                $buttonBox.prepend($btn);
            } else {
                // Self
                $name.parent().append($btn);
            }
        }
    }

    if (['interactive', 'complete'].indexOf(document.readyState) === -1) {
        addEventListener('DOMContentLoaded', () => load().catch(sauce.report.error));
    } else {
        load().catch(sauce.report.error);
    }
});

Fix issue with trying to show sync icon when logged out.


import React from 'react';
import { shallow } from 'enzyme'; // eslint-disable-line
import Array from '../types/Array';

describe('Array', () => {
  it('should subscribe to setKnobs event of channel', () => {
    const onChange = jest.fn();
    const wrapper = shallow(
      <Array
        onChange={onChange}
        knob={{ name: 'passions', value: ['Fishing', 'Skiing'], separator: ',' }}
      />
    );

    wrapper.simulate('change', { target: { value: 'Fhishing,Skiing,Dancing' } });
    expect(onChange).toHaveBeenCalledWith(['Fhishing', 'Skiing', 'Dancing']);
  });
});

import React from 'react';
import { shallow } from 'enzyme'; // eslint-disable-line
import ArrayType from '../types/Array';

describe('Array', () => {
  it('should subscribe to setKnobs event of channel', () => {
    const onChange = jest.fn();
    const wrapper = shallow(
      <ArrayType
        onChange={onChange}
        knob={{ name: 'passions', value: ['Fishing', 'Skiing'], separator: ',' }}
      />
    );

    wrapper.simulate('change', { target: { value: 'Fhishing,Skiing,Dancing' } });
    expect(onChange).toHaveBeenCalledWith(['Fhishing', 'Skiing', 'Dancing']);
  });
});

Rename import to avoid naming conflict


//= require_self
//= require ./string
//= require_tree .
/* global Data:true */

Data = Ember.Namespace.create({

  ajax: function (settings) {
    return $.ajax(settings);
  }
});

//= require_self
//= require ./string
//= require_tree .
/* global Data:true */

Ember.$.support.cors = true;

Data = Ember.Namespace.create({

  ajax: function (settings) {
    return Ember.$.ajax(settings);
  }
});

Add support for IE (CORS)


import Vue from 'vue';
import UiIcon from '../src/UiIcon.vue';

describe('UiIcon.vue', function() {
    it('should initialize with correct data/props', function() {
        const vm = new Vue({
            template: '
<ui-icon icon="mail" :disable-text="true" v-ref:icon></ui-icon>
',
            components: {
                UiIcon
            }
        }).$mount();

        expect(vm.$refs.icon.icon).toBe('mail');
        expect(vm.$refs.icon.disableText).toBe(true);
    });

    it('should add icon prop as a class', function() {
        const vm = new Vue({
            template: '
<ui-icon icon="mail" v-ref:icon></ui-icon>
',
            components: {
                UiIcon
            }
        }).$mount();

        expect(vm.$refs.icon.$el.className).toMatch(/mail/);
    });

    it('should render icon prop as inner text', function() {
        const vm = new Vue({
            template: '
<ui-icon icon="mail" v-ref:icon></ui-icon>
',
            components: {
                UiIcon
            }
        }).$mount();

        expect(vm.$refs.icon.$el.textContent).toBe('mail');
    });

    it('should not render icon prop as inner text when disableText prop is true', function() {
        const vm = new Vue({
            template: '
<ui-icon icon="mail" :disable-text="true" v-ref:icon></ui-icon>
',
            components: {
                UiIcon
            }
        }).$mount();

        expect(vm.$refs.icon.$el.textContent).toBe('');
    });
});

import Vue from 'vue';
import UiIcon from '../src/UiIcon.vue';

describe('UiIcon.vue', function() {
    it('should initialize with correct data/props', function() {
        const vm = new Vue({
            template: '
<ui-icon icon="mail" :remove-text="true" v-ref:icon></ui-icon>
',
            components: {
                UiIcon
            }
        }).$mount();

        expect(vm.$refs.icon.icon).toBe('mail');
        expect(vm.$refs.icon.removeText).toBe(true);
    });

    it('should add icon prop as a class', function() {
        const vm = new Vue({
            template: '
<ui-icon icon="mail" v-ref:icon></ui-icon>
',
            components: {
                UiIcon
            }
        }).$mount();

        expect(vm.$refs.icon.$el.className).toMatch(/mail/);
    });

    it('should render icon prop as inner text', function() {
        const vm = new Vue({
            template: '
<ui-icon icon="mail" v-ref:icon></ui-icon>
',
            components: {
                UiIcon
            }
        }).$mount();

        expect(vm.$refs.icon.$el.textContent).toBe('mail');
    });

    it('should not render icon prop as inner text when removeText prop is true', function() {
        const vm = new Vue({
            template: '
<ui-icon icon="mail" :remove-text="true" v-ref:icon></ui-icon>
',
            components: {
                UiIcon
            }
        }).$mount();

        expect(vm.$refs.icon.$el.textContent).toBe('');
    });
});

Rename disableText prop to removeText in UiIcon test


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

// A simple event is an event which does not contain data associated with it, and
// instead just records "it happened", the count field incrementing with each hit.
// For many events this is viable enough, and can be optimized to be way faster.

var simpleEventSchema = new Schema({
    project   : String,
    category  : String,
    action    : String,
    count     : {type: Number, default: 0}
});

var SimpleEvent = mongoose.model('SimpleEvent', simpleEventSchema);

module.exports = SimpleEvent;

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

// A simple event is an event which does not contain data associated with it, and
// instead just records "it happened", the count field incrementing with each hit.
// For many events this is viable enough, and can be optimized to be way faster.

var simpleEventSchema = new Schema({
    project   : String,
    category  : String,
    action    : String,
    count     : {type: Number, default: 0, index: true}
});

// Compound index because these fields are treated like namespaces.
simpleEventSchema.index({project: 1, category: 1, unique: 1});

var SimpleEvent = mongoose.model('SimpleEvent', simpleEventSchema);

module.exports = SimpleEvent;

Set up indexing for simple events.


var GtfsEditor = GtfsEditor || {};

(function(G, $, ich) {
  G.Router = Backbone.Router.extend({
    routes: {
      '': 'showStep',
      ':step': 'showStep'
    },

    initialize: function () {
      var router = this;
      $('#route-nav').on('click', 'a', function (evt) {
        evt.preventDefault();
        router.navigate($(this).attr('href'), {trigger: true});
      });
    },

    showStep: function (step) {
      if (!step) {
        step = '1';
        this.navigate(step);
      }

      $('#route-step-content').html('This is step ' + step);
    }
  });

})(GtfsEditor, jQuery, ich);

var router;
$(function(){
  router = new GtfsEditor.Router();
  Backbone.history.start({pushState: true, root: '/route/'});
});

var GtfsEditor = GtfsEditor || {};

(function(G, $, ich) {
  G.Router = Backbone.Router.extend({
    routes: {
      '': 'showStep',
      ':step': 'showStep'
    },

    initialize: function () {
      var router = this;
      $('#route-nav').on('click', 'a', function (evt) {
        evt.preventDefault();
        router.navigate($(this).attr('href'), {trigger: true});
      });
    },

    showStep: function (step) {
      if (!step) {
        step = '1';
        this.navigate(step);
      }

      $('#route-nav li').removeClass('active').find('a[href="'+step+'"]').parent().addClass('active');
      $('#route-step-content').html('This is step ' + step);
    }
  });

})(GtfsEditor, jQuery, ich);

var router;
$(function(){
  router = new GtfsEditor.Router();
  Backbone.history.start({pushState: true, root: '/route/'});
});

Update the active class for the current step


'use strict';

var elements = document.querySelectorAll('.record');
if (elements.length) {
  var line = Array.prototype.filter.call(elements,function(record) {
    return record.textContent.indexOf('文章網址') !== -1;
  })[0].textContent;
  var matched = line.match(/(https*:\/\/[\w\.\/]+)/);
  if (matched) {
    window.location.href = matched[1];
  }
}

'use strict';

var selector = document.location.pathname.startsWith('/m/') ? '.fgG0' : '.record';
var elements = document.querySelectorAll(selector);
if (elements.length) {
  var line = Array.prototype.filter.call(elements,function(record) {
    return record.textContent.indexOf('文章網址') !== -1;
  })[0].textContent;
  var matched = line.match(/(https*:\/\/[\w\.\/]+)/);
  if (matched) {
    window.location.href = matched[1];
  }
}

Use different selector for disp.cc mobile version


if (Meteor.isClient) {

  Accounts.ui.config({
     passwordSignupFields: 'USERNAME_ONLY'
  });

  Template.messages.helpers({
      messages: function() {
          return Messages.find({}, { sort: { time: -1}});
      }
  });

  Template.input.events = {
    'keydown input#message' : function (event) {
      if (event.which == 13) { // 13 is the enter key event
        if (Meteor.user())
          var name = Meteor.user().username;
        else
          var name = 'Anonymous';
        var message = document.getElementById('message');

        if (message.value != '') {
          Messages.insert({
            name: name,
            message: message.value,
            time: Date.now(),
          });

          document.getElementById('message').value = '';
          message.value = '';
        }
      }
    }
  };

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup
  });
}
}

if (Meteor.isClient) {

  Accounts.ui.config({
     passwordSignupFields: 'USERNAME_ONLY'
  });

  Template.messages.helpers({
      messages: function() {
          return Messages.find({}, { sort: { time: 1}});
      }
  });

  Template.input.events = {
    'keydown input#message' : function (event) {
      if (event.which == 13) { // 13 is the enter key event
        if (Meteor.user())
          var name = Meteor.user().username;
        else
          var name = 'Anonymous';
        var message = document.getElementById('message');

        if (message.value != '') {
          Messages.insert({
            name: name,
            message: message.value,
            time: Date.now(),
          });

          document.getElementById('message').value = '';
          message.value = '';
        }
      }
    }
  };

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup
  });
}
}

Change message sort order to top to bottom


/**
 * Creates a JS Error object from an NSException pointer.
 */
var id = require('./id')
  , Err = require('vm').runInNewContext('Error')

var proto = exports.proto = Err.prototype
// Make the Error objects inherit from our id class
proto.__proto__ = id.proto

exports.wrap = function wrap (pointer) {
  var w = id.wrap(pointer)
  w.__proto__ = proto
  w.name = String(w('name'))
  w.message = String(w('reason'))
  Err.captureStackTrace(w, exports.wrap)
  return w
}

/**
 * Creates a JS Error object from an NSException pointer.
 */
var id = require('./id')
  , Err = require('vm').runInNewContext('Error')

var proto = exports.proto = Err.prototype
// Make the Error objects inherit from our id class
proto.__proto__ = id.proto

exports.wrap = function wrap (pointer) {
  var w = id.wrap(pointer)
  w.__proto__ = proto
  // We have to do a little workaround to get a nice 'stack' property, since
  // the 'name' property on the id wraps is non-configurable
  var stacker = new Error(String(w('reason')))
  stacker.name = String(w('name'))
  Err.captureStackTrace(stacker, exports.wrap)
  Object.defineProperty(w, 'stack', Object.getOwnPropertyDescriptor(stacker, 'stack'))
  return w
}

Put in place a little workaround to get a nice 'name' on the NSException wrap's 'stack' property.


import { newSignal, signalStep } from './signal';

// Euler integration
// integrate :: (a -> b -> dt -> a) -> a -> Signal t b -> Signal t a
export default (integral, a, s) => runInteg(integral, a, s, 0);

const runInteg = (integral, a0, s, t0) =>
    newSignal(t => stepInteg(integral, a0, s.runSignal(t), t, t0));

const stepInteg = (integral, a0, sv, t, t0) => {
    const a = integral(a0, sv.value, t - t0);
    return signalStep(a, runInteg(integral, a, sv.next, t));
};

import { newSignal, signalStep } from './signal';

// Euler integration
// integrate :: (a -> b -> dt -> a) -> a -> Signal t b -> Signal t a
export default (integral, a, s) =>
    newSignal(t => signalStep(a, runInteg(integral, a, s, t)));

const runInteg = (integral, a0, s, t0) =>
    newSignal(t => stepInteg(integral, a0, s.runSignal(t), t, t0));

const stepInteg = (integral, a0, sv, t, t0) => {
    const a = integral(a0, sv.value, t - t0);
    return signalStep(a, runInteg(integral, a, sv.next, t));
};

Fix cheating on first integral step


var fs = require('fs');

var Settings = {};

Settings.init = function (){};

Settings.get = function (key){
  var tokenFileName = process.env.HOME + '/.unidisk/' + key;
  var value;
  try {
    var stats = fs.statSync(tokenFileName);
    value = stats.isFile() ? fs.readFileSync( tokenFileName ) : null;
  } catch (e) {
    value = null;
  }
  return value;
};

Settings.set = function (key, value){

};

module.exports = Settings;

var fs = require('fs');

var Settings = {};

Settings.init = function (){};

Settings.get = function (key){
  if (this.table) {
    return this.table[key];
  }

  var settingsFileName = process.env.HOME + '/.unidisk/' + 'settings.json';
  try {
    var stats = fs.statSync(settingsFileName);
    var value = stats.isFile() ? fs.readFileSync( settingsFileName ) : {};
    this.table = JSON.parse(value);
  } catch (e) {
    console.error('failed to load settings');
    this.table = {};
  }
  return this.table[key];
};

Settings.set = function (key, value){

};

module.exports = Settings;

Integrate all settings into settings.json file.


function queryString (name) {
    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
        results = regex.exec(location.search);
    return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}

if (queryString("site"))
$("iframe").attr("src", queryString("site"));

function queryString (name) {
    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
        results = regex.exec(location.search);
    return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}

$("iframe").attr("src", "http://fiddle.jshell.net/B5T6N/9/show/");

Set the iframe url on the JS side


/* angular-file-saver
*
* A AngularJS service that implements the HTML5 W3C saveAs() in browsers that
* do not natively support it
*
* (c) 2015 Philipp Alferov
* License: MIT
*
*/

(function() {
  'use strict';

  angular
    .module('fileSaver', [])
    .factory('SaveAs', SaveAs);

    function SaveAs() {

      function isBlobInstance (data) {
        return data instanceof Blob;
      }

      function save(blob, filename) {
        try {
          saveAs(blob, filename);
        } catch(err) {
          console.error(err.message);
        }
      }

      return {

        /**
        * saveFile - Immediately starts saving a file, returns undefined.
        *
        * @param  {array|Blob} data Represented as an array or a Blob object
        * @param  {string} filename
        * @param  {object} options Set of Blob constructor options.
        * Optional parameter, if Blob object is passed as first argument
        * @return {undefined}
        */

        download: function (data, filename, options) {
          var blob;
          data = data instanceof Array ? data : [data];

          if (isBlobInstance(data)) {
            save(data, filename);
          }

          blob = new Blob(data, options);
          save(blob, filename);
        }
      };
    }

})();

'use strict';

/* angular-file-saver
*
* A AngularJS service that implements the HTML5 W3C saveAs() in browsers that
* do not natively support it
*
* (c) 2015 Philipp Alferov
* License: MIT
*
*/

angular
  .module('fileSaver', [])
  .factory('SaveAs', SaveAs);

  function SaveAs() {

    function isBlobInstance (data) {
      return data instanceof Blob;
    }

    function save(blob, filename) {
      try {
        saveAs(blob, filename);
      } catch(err) {
        console.error(err.message);
      }
    }

    return {

      /**
      * saveFile - Immediately starts saving a file, returns undefined.
      *
      * @param  {array|Blob} data Represented as an array or a Blob object
      * @param  {string} filename
      * @param  {object} options Set of Blob constructor options.
      * Optional parameter, if Blob object is passed as first argument
      * @return {undefined}
      */

      download: function (data, filename, options) {
        var blob;
        data = data instanceof Array ? data : [data];

        if (isBlobInstance(data)) {
          save(data, filename);
        }

        blob = new Blob(data, options);
        save(blob, filename);
      }
    };
  }

Remove IIFE as browserify adds one


var _create = global.document.createNodeIterator;

export function createNodeIterator(root, whatToShow, filter = null) {
  var iter = _create.call(global.document, root, whatToShow, filter, false);
  return typeof(iter.referenceNode) === 'undefined' ? shim(iter, root) : iter;
}

export function install() {
  global.document.createNodeIterator = createNodeIterator;
}

function shim(iter, root) {
  var _referenceNode = root;
  var _pointerBeforeReferenceNode = true;

  return Object.create(NodeIterator.prototype, {
    root: {
      get: function () {
        return iter.root;
      }
    },

    whatToShow: {
      get: function () {
        return iter.whatToShow;
      }
    },

    filter: {
      get: function () {
        return iter.filter;
      }
    },

    referenceNode: {
      get: function () {
        return _referenceNode;
      }
    },

    pointerBeforeReferenceNode: {
      get: function () {
        return _pointerBeforeReferenceNode;
      }
    },

    nextNode: {
      value: function () {
        _referenceNode = iter.nextNode();
        _pointerBeforeReferenceNode = false;
        return _referenceNode;
      }
    },

    previousNode: {
      value: function () {
        _referenceNode = iter.previousNode();
        _pointerBeforeReferenceNode = true;
        return _referenceNode;
      }
    }
  });
}

var _create = global.document.createNodeIterator;

export function createNodeIterator(root, whatToShow, filter = null) {
  var iter = _create.call(global.document, root, whatToShow, filter, false);
  return typeof(iter.referenceNode) === 'undefined' ? shim(iter, root) : iter;
}

export function install() {
  global.document.createNodeIterator = createNodeIterator;
}

function shim(iter, root) {
  var _referenceNode = root;
  var _pointerBeforeReferenceNode = true;

  return Object.create(NodeIterator.prototype, {
    root: {
      get: function () {
        return iter.root;
      }
    },

    whatToShow: {
      get: function () {
        return iter.whatToShow;
      }
    },

    filter: {
      get: function () {
        return iter.filter;
      }
    },

    referenceNode: {
      get: function () {
        return _referenceNode;
      }
    },

    pointerBeforeReferenceNode: {
      get: function () {
        return _pointerBeforeReferenceNode;
      }
    },

    nextNode: {
      value: function () {
        let result = iter.nextNode();
        if (result !== null) {
          _referenceNode = iter.nextNode();
        }
        _pointerBeforeReferenceNode = false;
        return _referenceNode;
      }
    },

    previousNode: {
      value: function () {
        let result = iter.previousNode();
        if (result !== null) {
          _referenceNode = iter.previousNode();
        }
        _pointerBeforeReferenceNode = true;
        return _referenceNode;
      }
    }
  });
}

Normalize for nulling out on IE at the ends


'use strict';

const assert = require('assert');

const api = {

  configureStaticApi(apiServerCreator, port) {
    assert(typeof apiServerCreator === 'function', 'apiServerCreator has to be function to create static api');
    assert(port, 'Port has to be specified');

    let server;

    before(() => {
      return apiServerCreator({ port: port }).then(created_server => {
        server = created_server;
        return server.start();
      });
    });

    after(() => {
      return server.stop();
    });
  },

};

// exported in a way that is compatible with both `require` and `import`
module.exports = api;
module.exports.default = api;
Object.defineProperty(module.exports, '__esModule', { value: true });

Add missing "use strict" to api tester


var Anagram = require('./anagram');

describe('Anagram', function() {

  it("no matches",function() {
    var detector = new Anagram("diaper");
    var matches = detector.match([ "hello", "world", "zombies", "pants"]);
    expect(matches).toEqual([]);
  });

  xit("detects simple anagram",function() {
    var detector = new Anagram("ba");
    var matches = detector.match(['ab', 'abc', 'bac']);
    expect(matches).toEqual(['ab']);
  });

  xit("detects multiple anagrams",function() {
    var detector = new Anagram("abc");
    var matches = detector.match(['ab', 'abc', 'bac']);
    expect(matches).toEqual(['abc', 'bac']);
  });

  xit("detects anagram",function() {
    var detector = new Anagram("listen");
    var matches = detector.match(['enlists', 'google', 'inlets', 'banana']);
    expect(matches).toEqual(['inlets']);
  });

  xit("detects multiple anagrams",function() {
    var detector = new Anagram("allergy");
    var matches = detector.match(['gallery', 'ballerina', 'regally', 'clergy', 'largely', 'leading']);
    expect(matches).toEqual(['gallery', 'regally', 'largely']);
  });
});

var Anagram = require('./anagram');

describe('Anagram', function() {

  it("no matches",function() {
    var detector = new Anagram("diaper");
    var matches = detector.match([ "hello", "world", "zombies", "pants"]);
    expect(matches).toEqual([]);
  });

  xit("detects simple anagram",function() {
    var detector = new Anagram("ba");
    var matches = detector.match(['ab', 'abc', 'bac']);
    expect(matches).toEqual(['ab']);
  });

  xit("does not detect false positives",function() {
    var detector = new Anagram("bba");
    var matches = detector.match(["aab"]);
    expect(matches).toEqual([]);
  });

  xit("detects multiple anagrams",function() {
    var detector = new Anagram("abc");
    var matches = detector.match(['ab', 'abc', 'bac']);
    expect(matches).toEqual(['abc', 'bac']);
  });

  xit("detects anagram",function() {
    var detector = new Anagram("listen");
    var matches = detector.match(['enlists', 'google', 'inlets', 'banana']);
    expect(matches).toEqual(['inlets']);
  });

  xit("detects multiple anagrams",function() {
    var detector = new Anagram("allergy");
    var matches = detector.match(['gallery', 'ballerina', 'regally', 'clergy', 'largely', 'leading']);
    expect(matches).toEqual(['gallery', 'regally', 'largely']);
  });
});

Add test for same length, same letters, different letter instance counts


var path = require('path');
var _ = require('underscore')._;

module.exports = function(app, settings) {
  var providers = {};
  for (var p in settings.providers) {
      // TODO :express better
      providers[p] = require('./' + path.join(p, 'index'))(app, settings);
  }
  app.get('/provider', function(req, res) {
      res.send({
          status: true,
          provider: _.keys(settings.providers)
      });
  });
  app.get('/provider/:provider', function(req, res) {
      providers[req.params.provider].objects(function(objects) {
          res.send({
              status: true,
              name: providers[req.params.provider].name,
              datasources: objects
          });
      });
  });
};

var path = require('path');
var _ = require('underscore')._;

module.exports = function(app, settings) {
  var providers = {};
  for (var p in settings.providers) {
      // TODO :express better
      providers[p] = require('./' + path.join(p, 'index'))(app, settings);
  }
  app.get('/provider', function(req, res) {
      res.send({
          status: true,
          provider: _.keys(settings.providers)
      });
  });
  app.get('/provider/:provider', function(req, res) {
      providers[req.params.provider].objects(function(objects) {
          res.send(objects);
      });
  });
};

Send list of objects for backbone compatibility.


import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';

import { Link } from 'react-router';

import { createPureComponent } from 'utils/createPureComponent';

export default createPureComponent({

  displayName: 'App',

  renderLink() {
    const isEditing = this.props.location.pathname === '/editor';
    const to = isEditing ? '/' : '/editor';
    const text = isEditing ? 'Play this level' : 'Edit this level';
    return (<Link to={to}>{text}</Link>);
  },

  render() {
    return (

        {this.props.children}

            {this.renderLink()}

    );
  }

});

import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';

import { Link } from 'react-router';

import { createPureComponent } from 'utils/createPureComponent';

export default createPureComponent({

  displayName: 'App',

  renderLink() {
    const isEditing = this.props.location.pathname === '/editor';
    const to = isEditing ? '/' : '/editor';
    const text = isEditing ? 'Play this level' : 'Edit this level';
    return (<Link to={to}>{text}</Link>);
  },

  render() {
    return (
      <div className="app">
        {this.props.children}
      </div>
    );
  }

});

Revert "Revert "Revert "Revert "Revert "Revert "Revert "Revert "kein editor""""""""


$(document).ready(function () {

  $(".new-question").click(function() {
    $(this).addClass("hidden");
    $("#new-question").removeClass("hidden");
  });

  $("#new-question").submit(function(event) {
    event.preventDefault();

    var ajaxRequest = $.ajax({
      url: '/questions',
      method: 'POST',
      data: $(this).serialize()
    });

    ajaxRequest.done(function(response) {
      $("ul.questions").prepend(response);
      $("form#new-question")[0].reset();
      $(".new-question").removeClass("hidden");
      $("form#new-question").addClass("hidden");

  $('#answer-form').on('submit', function(event){
    event.preventDefault();
    var route = $(this).attr("action");
    var answerData = $(this).find("textarea").serialize();
    // debugger;
    $.ajax({
      url: route,
      method: "post",
      data: answerData
    }).done(function(serverResponse) {
      // debugger;
      $(".answer-box").find(".answers").append(serverResponse)

    });
  });

});

$(document).ready(function () {

  $(".new-question").click(function() {
    $(this).addClass("hidden");
    $("#new-question").removeClass("hidden");
  });

  $("#new-question").submit(function(event) {
    event.preventDefault();
    var ajaxRequest = $.ajax({
      url: '/questions',
      method: 'POST',
      data: $(this).serialize()
    });
    ajaxRequest.done(function(response) {
      $("ul.questions").prepend(response);
      $("form#new-question")[0].reset();
      $(".new-question").removeClass("hidden");
      $("form#new-question").addClass("hidden");
    });
  });

  $('#answer-form').on('submit', function(event){
    event.preventDefault();
    var route = $(this).attr("action");
    var answerData = $(this).find("textarea").serialize();
    $.ajax({
      url: route,
      method: "post",
      data: answerData
    }).done(function(serverResponse) {
      $(".answer-box").find(".answers").append(serverResponse)
      $('#answer-form').find('textarea').val('')
    });
  });

});

Fix JS issue to let users post questions and answers


/**
 * FCViz
 * Payload script for loan requests page
 */

$("#watch_form").find("a.mediumText").each(function(){$(this).before(
  $(document.createElement("a")).html("+").attr("class","seemore").attr("style", "cursor: pointer")
)});

$(".seemore").before("[").after("] ");

window.fcVizObserver.disconnect();

/**
 * FCViz
 * Payload script for loan requests page
 */

//We don't need this mutation observer since we are in the requests page
window.fcVizObserver.disconnect();

var prependLinkToCell = function(){$(this).before(
  $(document.createElement("a")).html("+").attr("class","seemore").attr("style", "cursor: pointer")
)};

$("#watch_form").find("a.mediumText").each(prependLinkToCell);

$(".seemore").before("[").after("] ");

Rearrange code a bit for clarity


// @flow
import type { LayerType } from './layer';
import type { TilesetType } from './tileset';

export type MapType = {
  layers: Array<LayerType>;
  tileSets: Array<TilesetType>;
}

// TODO: https://github.com/andrewrk/node-tmx-parser/blob/master/index.js#L811

Add link to tmx-parser type definitions


(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
      (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
      m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
      })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

      ga('create', 'UA-24717231-5', 'auto');
      ga('send', 'pageview');

(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

// Tell Google who we are
ga('create', 'UA-24717231-5', 'auto');
// Trigger a pageview event
ga('send', 'pageview');

// Some listeners to track events
$('.data').click(function() {
  ga('send', 'event', 'user_upload', 'left-menu-btn', 'click on left menu add your data button');
});
$('.config').click(function() {
  ga('send', 'event', 'configure_page', 'left-menu-btn', 'click on left menu configure this page button');
});
$('.export').click(function() {
  ga('send', 'event', 'export_data', 'left-menu-btn', 'click on left menu export data button');
});

Add some Google Analytics Events for testing


'use strict';
const getConfig = require('./utils').getConfig;
const getTestRoot = require('./utils').getTestRoot;
const deepMerge = require('./utils').deepMerge;
const fileExists = require('../utils').fileExists;
const path = require('path');
const mkdirp = require('mkdirp');
const Config = require('../config');
const Codecept = require('../codecept');
const output = require('../output');

module.exports = function (test, options) {
  // registering options globally to use in config
  process.profile = options.profile;
  let configFile = options.config;
  let codecept, outputDir;

  let testRoot = getTestRoot(configFile);
  let config = getConfig(configFile);
  if (options.override) {
    config = Config.append(JSON.parse(options.override));
  }

  if (!fileExists(outputDir = path.join(testRoot, config.output))) {
    output.print('creating output directory: ' + outputDir);
    mkdirp.sync(outputDir);
  }

  try {
    codecept = new Codecept(config, options);
    codecept.init(testRoot, function (err) {
      if (err) throw new Error('Error while running bootstrap file :' + err);
      codecept.loadTests();
      codecept.run(test);
    });
  } catch (err) {
    output.print('');
    output.error(err.message);
    output.print('');
    output.print(output.colors.grey(err.stack.replace(err.message, '')));
    process.exit(1);
  }
};

'use strict';
const getConfig = require('./utils').getConfig;
const getTestRoot = require('./utils').getTestRoot;
const deepMerge = require('./utils').deepMerge;
const fileExists = require('../utils').fileExists;
const path = require('path');
const mkdirp = require('mkdirp');
const Config = require('../config');
const Codecept = require('../codecept');
const output = require('../output');

module.exports = function (test, options) {
  // registering options globally to use in config
  process.profile = options.profile;
  let configFile = options.config;
  let codecept, outputDir;

  let testRoot = getTestRoot(configFile);
  let config = getConfig(configFile);
  if (options.override) {
    config = Config.append(JSON.parse(options.override));
  }

  if (config.output.startsWith('/') || config.output.startsWith('\\')) outputDir = config.output
  else outputDir = path.join(testRoot, config.output)

  if (!fileExists(outputDir)) {
    output.print('creating output directory: ' + outputDir);
    mkdirp.sync(outputDir);
  }

  try {
    codecept = new Codecept(config, options);
    codecept.init(testRoot, function (err) {
      if (err) throw new Error('Error while running bootstrap file :' + err);
      codecept.loadTests();
      codecept.run(test);
    });
  } catch (err) {
    output.print('');
    output.error(err.message);
    output.print('');
    output.print(output.colors.grey(err.stack.replace(err.message, '')));
    process.exit(1);
  }
};

Fix absolute path in output


const argParser = require('minimist')
const escodegen = require('escodegen')
const fs = require('fs')
const parser = require('./parser')
const childProcess = require('child_process')

const argv = argParser(process.argv.slice(2))
const infile = argv._[0]
const outfile = infile.replace(/\.cl$/, '.js')
const src = fs.readFileSync(infile, 'utf8').toString()
const tree = parser({'str': src, 'line': 1, 'column': 1, 'indent': 0})
const out = escodegen.generate(tree)
fs.writeFileSync(outfile, out, 'utf8')
childProcess.execSync('node ' + outfile, {stdio: 'inherit'})

const argParser = require('minimist')
const escodegen = require('escodegen')
const fs = require('fs')
const parser = require('./parser')
const childProcess = require('child_process')

const argv = argParser(process.argv.slice(2))
const infile = argv._[0]
const outfile = infile.replace(/\.cl$/, '.js')
const src = fs.readFileSync(infile, 'utf8').toString()
const tree = parser({'str': src, 'line': 1, 'column': 1, 'indent': 0})
const out = escodegen.generate(tree, {comment: true})
fs.writeFileSync(outfile, out, 'utf8')
childProcess.execSync('node ' + outfile, {stdio: 'inherit'})

Update `out` to include comments in js file


var fs = require('fs');
var middleware = [];

fs.readdirSync(__dirname + '/middleware').forEach(function (filename) {
    if (/\.js$/.test(filename)) {
        var name = filename.substr(0, filename.lastIndexOf('.'));
        middleware.push(name);
        exports.__defineGetter__(name, function () {
            return require('./middleware/' + name);
        });
    }
});

exports.defaults = function (app, overrides) {
    if (typeof app.use !== 'function') {
        overrides = app;
        try {   // make sub-app, in likeliest framework(s)
            app = require('express')();
        } catch (e) {
            app = require('connect')();
        }
    }
    overrides = overrides || {csp: false};
    middleware.forEach(function _eachMiddleware(m) {
        if (overrides[m] !== false) {
            app.use(require('./middleware/' + m)());
        }
    });
    return app;
};

var fs = require('fs');
var middleware = [];

fs.readdirSync(__dirname + '/middleware').forEach(function (filename) {
    if (/\.js$/.test(filename)) {
        var name = filename.substr(0, filename.lastIndexOf('.'));
        middleware.push(name);
        exports.__defineGetter__(name, function () {
            return require('./middleware/' + name);
        });
    }
});

exports.defaults = function (app, overrides) {
    if (!app || typeof app.use !== 'function') {
        overrides = app;
        try {   // make sub-app, in likeliest framework(s)
            app = require('express')();
        } catch (e) {
            app = require('connect')();
        }
    }
    overrides = overrides || {csp: false};
    middleware.forEach(function _eachMiddleware(m) {
        if (overrides[m] !== false) {
            app.use(require('./middleware/' + m)());
        }
    });
    return app;
};

Fix defaults-only middleware case, i.e. no args


// Dependencies
var Exec = require("child_process").exec
  , OArgv = require("oargv")
  , ElectronPath = require("electron-prebuilt")
  ;

/**
 * Electroner
 *
 * @name Electroner
 * @function
 * @param {Object} options The path to the main script or an object interpreted
 * by [`oargv`](https://github.com/IonicaBizau/node-oargv) and optional fields:
 *
 *  - `cwd` (String): An optional key representing directory where the electron
 *    process should be executed.
 *
 * @param {Function} callback The callback function.
 * @return {Process} The Electron process.
 */
var Electroner = module.exports = function (path, options, callback) {

    callback = callback || function (err) {
        if (err) {
            throw err;
        };
    };

    if (!path) {
        return callback(new Error("The path argument is mandatory."));
    }

    if (typeof options === "function") {
        callback = options;
        options = null;
    }

    options = options || {};
    options._ = [path];

    var cwd = options.cwd || (process && process.cwd()) || __dirname;
    delete options.cwd;

    // Run the command
    return Exec(OArgv(options, ElectronPath), { cwd: cwd }, callback);
};

"use strict";

// Dependencies
const spawn = require("spawno")
    , oArgv = require("oargv")
    , electronPath = require("electron-prebuilt")
    ;

/**
 * electroner
 * Starts the Electron process.
 *
 * @name electroner
 * @function
 * @param {Object} options The path to the main script or an object interpreted
 * by [`oargv`](https://github.com/IonicaBizau/node-oargv) and optional fields:
 *
 *  - `cwd` (String): An optional key representing directory where the electron
 *    process should be executed.
 *
 * @param {Function} callback The callback function.
 * @return {Process} The Electron process.
 */
module.exports = function electroner (path, options, callback) {

    if (!path) {
        return callback(new Error("The path argument is mandatory."));
    }

    if (typeof options === "function") {
        callback = options;
        options = null;
    }

    options = options || {};
    options._ = [path];

    let cwd = options.cwd || (process && process.cwd()) || __dirname;
    delete options.cwd;

    // Run the command
    return spawn(electronPath, oArgv(options), { cwd: cwd, _showOutput: true }, callback);
};

Use spawno instead of exec


var _ = require('lodash'),
    request = require('request'),
    savePage = require('./save').page;

function getPageFromServer(params, pageResult) {
  request.get(params, function (error, response, body) {
    pageResult(error || (response.statusCode !== 200 || !body), arguments);
  });
}

function getMain(params, callback) {
  var tmpParams = _.extend({}, params.main, params.request);
  getPageFromServer(tmpParams, function (err, res) {
    // Save to cache
    var body = res[2];
    if (!err && params.save) savePage(tmpParams, params.save, body);

    callback(err, res);
  });
}

function getCache(params, callback) {
  if (params.cache) {
    var tmpParams = _.extend({}, params.cache, params.request);
    getPageFromServer(tmpParams, function (err, res) {
      callback(err, res);
    });
  }
  else {
    callback(true);
  }
}

exports = {
  main: getMain,
  cache: getCache
};

var _ = require('lodash'),
    request = require('request'),
    savePage = require('./save').page;

function getPageFromServer(params, pageResult) {
  request.get(params, function (error, response, body) {
    pageResult(error || (response.statusCode !== 200 || !body), arguments);
  });
}

function getMain(params, callback) {
  var tmpParams = _.extend({}, params.request, params.main);
  getPageFromServer(tmpParams, function (err, reqRes) {
    // Save to cache
    var body = reqRes[2];
    if (!err && params.save) savePage(tmpParams, params.save, body);

    callback(err, reqRes);
  });
}

function getCache(params, callback) {
  if (params.cache) {
    var tmpParams = _.extend({}, params.request, params.cache);
    getPageFromServer(tmpParams, function (err, reqRes) {
      callback(err, reqRes);
    });
  }
  else {
    callback(true);
  }
}

exports = {
  main: getMain,
  cache: getCache
};

Extend params in correct order