this.Element && function (ElementPrototype) {
    ElementPrototype.matches = ElementPrototype.matches ||
    ElementPrototype.matchesSelector ||
    ElementPrototype.mozMatchesSelector ||
    ElementPrototype.msMatchesSelector ||
    ElementPrototype.webkitMatchesSelector ||
    function (selector) {
        var node = this, nodes = (node.parentNode || node.document).querySelectorAll(selector), i = -1;
        while (nodes[++i] && nodes[i] != node);
        return !!nodes[i];
    }
} (Element.prototype);

this.Element && function (ElementPrototype) {
    ElementPrototype.closest =
    function (selector) {
        var node = this;
        while (node) {
            if (node == document) return undefined;
            if (node.matches(selector)) return node;
            node = node.parentNode;
        }
    }
} (Element.prototype);

/*jshint bitwise: true, curly: true, eqeqeq: true, forin: true, immed: true, indent: 4, latedef: true, newcap: true, noarg: true, noempty: true, nonew: true, quotmark: double, undef: true, unused: vars, strict: true, trailing: true, maxdepth: 3, devel: true, asi: true */
/*global HTMLElement: true */

//
// ELEMENT
//

// Closest
// Usage: element.closest(selector)
this.Element && function (ElementPrototype) {
    ElementPrototype.closest =
    function (selector) {
        var node = this;
        while (node) {
            if (node == document) return undefined;
            if (node.matches(selector)) return node;
            node = node.parentNode;
        }
    }
} (Element.prototype);

// Matches
// Usage: element.matches(selector)
this.Element && function (ElementPrototype) {
    ElementPrototype.matches = ElementPrototype.matches ||
    ElementPrototype.matchesSelector ||
    ElementPrototype.mozMatchesSelector ||
    ElementPrototype.msMatchesSelector ||
    ElementPrototype.webkitMatchesSelector ||
    function (selector) {
        var node = this, nodes = (node.parentNode || node.document).querySelectorAll(selector), i = -1;
        while (nodes[++i] && nodes[i] != node);
        return !!nodes[i];
    }
} (Element.prototype);

Add jshint options and comments.


import http from '../http';

export default class collections {

    static get(collectionID) {
        return http.get(`/zebedee/collectionDetails/${collectionID}`)
            .then(response => {
                return response;
            })
    }

    static getAll() {
        return http.get(`/zebedee/collections`)
            .then(response => {
                return response;
            })
    }

    static create(body) {
        return http.post(`/zebedee/collection`, body)
            .then(response => {
                return response;
            })
    }

    static approve(collectionID) {
        return http.post(`/zebedee/approve/${collectionID}`);
    }

    static delete(collectionID) {
        return http.delete(`/zebedee/collection/${collectionID}`);
    }

    static update(collectionID, body) {
        body.id = collectionID;
        return http.put(`/zebedee/collection/${collectionID}`, body);
    }

    static deletePage(collectionID, pageURI) {
        return http.delete(`/zebedee/content/${collectionID}?uri=${pageURI}`);
    }

    static cancelDelete(collectionID, pageURI) {
        return http.delete(`/zebedee/DeleteContent/${collectionID}?uri=${pageURI}`);
    }

}

import http from '../http';

export default class collections {

    static get(collectionID) {
        return http.get(`/zebedee/collectionDetails/${collectionID}`)
            .then(response => {
                return response;
            })
    }

    static getAll() {
        return http.get(`/zebedee/collections`)
            .then(response => {
                return response;
            })
    }

    static create(body) {
        return http.post(`/zebedee/collection`, body)
            .then(response => {
                return response;
            })
    }

    static approve(collectionID) {
        return http.post(`/zebedee/approve/${collectionID}`);
    }

    static delete(collectionID) {
        return http.delete(`/zebedee/collection/${collectionID}`);
    }

    static update(collectionID, body) {
        body.id = collectionID;
        return http.put(`/zebedee/collection/${collectionID}`, body);
    }

    static deletePage(collectionID, pageURI) {
        return http.delete(`/zebedee/content/${collectionID}?uri=${pageURI}`);
    }

    static cancelDelete(collectionID, pageURI) {
        return http.delete(`/zebedee/DeleteContent/${collectionID}?uri=${pageURI}`);
    }

    static async checkContentIsInCollection(pageURI) {
        return http.get(`/zebedee/checkcollectionsforuri?uri=${pageURI}`)
    }

}

Add method to check is content is in another collection


/**
 * Settings component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import { HashRouter } from 'react-router-dom';

/**
 * WordPress dependencies
 */
import domReady from '@wordpress/dom-ready';
import { render } from '@wordpress/element';

/**
 * Internal dependencies
 */
import './components/legacy-notifications';
import Root from './components/Root';
import SettingsApp from './components/settings/SettingsApp';
import './modules';

// Initialize the app once the DOM is ready.
domReady( () => {
	const renderTarget = document.getElementById( 'googlesitekit-settings-wrapper' );

	if ( renderTarget ) {
		render(
			<Root dataAPIContext="Settings">
				<HashRouter>
					<SettingsApp />
				</HashRouter>
			</Root>,
			renderTarget
		);
	}
} );

/**
 * Settings component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import { HashRouter } from 'react-router-dom';

/**
 * WordPress dependencies
 */
import domReady from '@wordpress/dom-ready';
import { render } from '@wordpress/element';

/**
 * Internal dependencies
 */
import './components/legacy-notifications';
import Root from './components/Root';
import SettingsApp from './components/settings/SettingsApp';

// Initialize the app once the DOM is ready.
domReady( () => {
	const renderTarget = document.getElementById( 'googlesitekit-settings-wrapper' );

	if ( renderTarget ) {
		render(
			<Root dataAPIContext="Settings">
				<HashRouter>
					<SettingsApp />
				</HashRouter>
			</Root>,
			renderTarget
		);
	}
} );

Remove import ref so builds.


import config from 'config';

export const originMiddleware = async (ctx, next) => {
  ctx.response.set('Access-Control-Allow-Origin', config.origin);
  ctx.response.set('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
  ctx.response.set('Access-Control-Allow-Headers', [
    'Origin',
    'X-Requested-With',
    'Content-Type',
    'Accept',
    'X-Authentication-Token',
    'Access-Control-Request-Method',
    'Authorization',
  ].join(', '));
  ctx.response.set('Access-Control-Expose-Headers', 'Date, X-Freefeed-Server');

  await next();
};

import config from 'config';

export const originMiddleware = async (ctx, next) => {
  ctx.response.set('Access-Control-Allow-Origin', config.origin);
  ctx.response.set('Access-Control-Allow-Methods', 'GET,PUT,POST,PATCH,DELETE,OPTIONS');
  ctx.response.set('Access-Control-Allow-Headers', [
    'Origin',
    'X-Requested-With',
    'Content-Type',
    'Accept',
    'X-Authentication-Token',
    'Access-Control-Request-Method',
    'Authorization',
  ].join(', '));
  ctx.response.set('Access-Control-Expose-Headers', 'Date, X-Freefeed-Server');

  await next();
};

Add PATCH to Access-Control-Allow-Methods header


/* jshint node:true */

module.exports = {
  afterInstall: function() {
    return this.addBowerPackageToProject('polyfills-pkg');
  },

  normalizeEntityName: function() {
  }
};

/* jshint node:true */

module.exports = {
  normalizeEntityName: function() {
  }
};

Stop requiring a polyfill that we don't need


/*
	Each Enyo-provided library will annotate this structure with its own
	version info. Why? In general, Enyo and its libraries are versioned
	and released together, but libraries may be versioned separately in
	the future. Also, since libraries are checked out and updated
	individually, a project may be using "mismatched" libraries at any
	given time (e.g., the last stable release of Enyo, but an
	unreleased checkout from the master branch of layout).

	Enyo uses semantic versioning. Official releases have version
	numbers	of the form "X.y.z". Prereleases are indicated by a suffix
	of the form "-pre.N" where N is incremented for each prerelease.
	Between releases, version numbers include an additional "-dev"
	suffix.
*/

enyo.version = {
	enyo: "2.3.0-pre.5-dev"
};

/*
	Each Enyo-provided library will annotate this structure with its own
	version info. Why? In general, Enyo and its libraries are versioned
	and released together, but libraries may be versioned separately in
	the future. Also, since libraries are checked out and updated
	individually, a project may be using "mismatched" libraries at any
	given time (e.g., the last stable release of Enyo, but an
	unreleased checkout from the master branch of layout).

	Enyo uses semantic versioning. Official releases have version
	numbers	of the form "X.y.z". Prereleases are indicated by a suffix
	of the form "-pre.N" where N is incremented for each prerelease.
	Between releases, version numbers include an additional "-dev"
	suffix.
*/

enyo.version = {
	enyo: "2.3.0-pre.5"
};

Remove -dev suffix for pilot-5 release.


var path = require('path'),
    fs = require('fs'),
    crypto = require('crypto');

describe("writeFile functionality", function() {
    var _this = this;
    require('./harness.js')(_this);
    it("creates a directory", function(done) {
        var fname = "testDir";
        var resolved = path.resolve(_this.tempdir, fname);
        crypto.pseudoRandomBytes(128 * 1024, function(err, data) {
            if (err) throw err;
            _this.wd.writeFile(fname, data, function(err) {
                expect(err).toBe(null);
                fs.readFile(resolved, function(err, rdata) {
                    if (err) throw err;
                    expect(rdata.toString()).toBe(data.toString());
                    done();
                });
            });
        });
    });
});

var path = require('path'),
    fs = require('fs'),
    crypto = require('crypto');

describe("writeFile functionality", function() {
    var _this = this;
    require('./harness.js')(_this);
    it("writes data to a file that doesn't exist", function(done) {
        var fname = "testDir";
        var resolved = path.resolve(_this.tempdir, fname);
        crypto.pseudoRandomBytes(128 * 1024, function(err, data) {
            if (err) throw err;
            _this.wd.writeFile(fname, data, function(err) {
                expect(err).toBe(null);
                fs.readFile(resolved, function(err, rdata) {
                    if (err) throw err;
                    expect(rdata.toString()).toBe(data.toString());
                    done();
                });
            });
        });
    });
});

Fix name of writeFile test


// Include The 'require.async' Module
require("require.async")(require);

/**
 * Tokenizes an input string.
 *
 * @param {String} Input
 *
 * @return {Array}
 */
function tokenize (input) {
    return input
            .replace(/[^a-zA-Z ]+/g, "")
            .replace("/ {2,}/", " ")
            .toLowerCase()
            .split(" ");
}

/**
 * Performs sentiment analysis on the provided input "term".
 *
 * @param {String} Input term
 *
 * @return {Object}
 */
module.exports = function (term, callback) {

	// Include the AFINN Dictionary JSON asynchronously
	require.async("./AFINN.json", function(afinn) {

        // Split line term to letters only words array
        var words = tokenize(term || "");
        var score = 0;
        var rate;
        var i = 0;

        function calculate(word) {
            // Get the word rate from the AFINN dictionary
            rate = afinn[word];
            if (rate) {
                // Add current word rate to the final calculated sentiment score
                score += rate;
            }

            // Defer next turn execution (Etheration)
            setImmediate(function() {
                // Use callback for completion
                if (i === (words.length - 1)) {
                    callback(null, score);
                }
                else {
                    // Invoke next turn
                    calculate(words[++i]);
                }
            });
        }

        // Start calculating
        calculate(i);
	});
};

// Include The 'require.async' Module
require("require.async")(require);

/**
 * Tokenizes an input string.
 *
 * @param {String} Input
 *
 * @return {Array}
 */
function tokenize (input) {
    return input
            .replace(/[^a-zA-Z ]+/g, "")
            .replace("/ {2,}/", " ")
            .toLowerCase()
            .split(" ");
}

/**
 * Performs sentiment analysis on the provided input "term".
 *
 * @param {String} Input term
 *
 * @return {Object}
 */
module.exports = function (term, callback) {

	// Include the AFINN Dictionary JSON asynchronously
	require.async("./AFINN.json", function(afinn) {

        // Split line term to letters only words array
        var words = tokenize(term || "");
        var score = 0;
        var rate;
        var i = 0;

        function calculate(word) {
            // Get the word rate from the AFINN dictionary
            rate = afinn[word];
            if (rate) {
                // Add current word rate to the final calculated sentiment score
                score += rate;
            }

            // Defer next turn execution (Etheration)
            setImmediate(function() {
                // Use callback for completion
                if (i === (words.length - 1)) {
                    callback(null, score);
                }
                else {
                    // Invoke next turn
                    calculate(words[++i]);
                }
            });
        }

        // Start calculating
        calculate(words[i]);
	});
};

Fix bug in sentiment calculation


import { createAction } from 'redux-actions';

export const REQUEST_LOGIN       = "REQUEST_LOGIN";
export const SUCCESS_LOGIN       = "SUCCESS_LOGIN";
export const FAILURE_LOGIN       = "FAILURE_LOGIN";
export const REQUEST_SUBMIT_SONG = "REQUEST_SUBMIT_SONG";
export const SUCCESS_SUBMIT_SONG = "SUCCESS_SUBMIT_SONG";
export const FAILURE_SUBMIT_SONG = "FAILURE_SUBMIT_SONG";
export const INPUT_QUERY         = "INPUT_QUERY";
export const REQUEST_SEARCH      = "REQUEST_SEARCH";
export const SUCCESS_SEARCH      = "SUCCESS_SEARCH";
export const FAILURE_SEARCH      = "FAILURE_SEARCH";
export const ADDED_SONG          = "ADDED_SONG";

export const RequestLogin      = createAction(REQUEST_LOGIN);
export const SuccessLogin      = createAction(SUCCESS_LOGIN);
export const FailureLogin      = createAction(FAILURE_LOGIN);
export const RequestSubmitSong = createAction(REQUEST_SUBMIT_SONG);
export const SuccessSubmitSong = createAction(SUCCESS_SUBMIT_SONG);
export const FailureSubmitSong = createAction(FAILURE_SUBMIT_SONG);
export const InputQuery        = createAction(INPUT_QUERY);
export const RequestSearch     = createAction(REQUEST_SEARCH);
export const SuccessSearch     = createAction(SUCCESS_SEARCH);
export const FailureSearch     = createAction(FAILURE_SEARCH);
export const AddedSong         = createAction(ADDED_SONG);

import { createAction } from 'redux-actions';

export createActions(
  "REQUEST_LOGIN",
  "SUCCESS_LOGIN",
  "FAILURE_LOGIN",
  "REQUEST_SUBMIT_SONG",
  "SUCCESS_SUBMIT_SONG",
  "FAILURE_SUBMIT_SONG",
  "INPUT_QUERY",
  "REQUEST_SEARCH",
  "SUCCESS_SEARCH",
  "FAILURE_SEARCH",
  "ADDED_SONG",
  "PLAYED_SONG"
);

Use createActions to create actioncreator


import { IsolatedInlineNodeComponent as SubstanceIsolatedInlineNodeComponent } from 'substance'

/*
  This is overriding Substance.IsolatedInlineNodeComponent to support Models.
*/
export default class IsolatedInlineNodeComponentNew extends SubstanceIsolatedInlineNodeComponent {
  // overriding AbstractIsolatedNodeComponent.didMount() because it uses deprecated EditorSession.onRender()
  didMount () {
    let appState = this.context.appState
    appState.addObserver(['selection'], this._onSelectionChanged, this, { stage: 'render' })
  }

  // overriding AbstractIsolatedNodeComponent.dispose() because it uses EditorSession.off() in a way which has been deprecated
  dispose () {
    this.context.appState.off(this)
  }
}

import { IsolatedInlineNodeComponent as SubstanceIsolatedInlineNodeComponent } from 'substance'

/*
  This is overriding Substance.IsolatedInlineNodeComponent to support Models.
*/
export default class IsolatedInlineNodeComponentNew extends SubstanceIsolatedInlineNodeComponent {
  // overriding AbstractIsolatedNodeComponent.didMount() because it uses deprecated EditorSession.onRender()
  didMount () {
    let appState = this.context.appState
    appState.addObserver(['selection'], this._onSelectionChanged, this, { stage: 'render' })
  }

  // overriding AbstractIsolatedNodeComponent.dispose() because it uses EditorSession.off() in a way which has been deprecated
  dispose () {
    this.context.appState.off(this)
  }

  render ($$) {
    let el = super.render($$)
    // HACK: substnace IsoloatedInlineNodeComponent does not listen on click, but IMO this should be the case.
    // TODO instead of this HACK fix the implementation in Substance Land
    if (!this.isDisabled()) {
      el.on('click', this.onClick)
    }
    return el
  }
}

Add a click hook to IsolatedInlineNodeComponent.


var nano = require('nano')('http://localhost:5984');
var db = nano.db.use('todo');

var todo = {};

module.exports = todo;

var nano = require('nano')('http://localhost:5984');
var db = nano.db.use('todo');

var todo = {};

todo.getAll = function() {
  var results = [];
  db.view('todos', 'all_todos', function(err, body) {
    for (var row of body.rows) {
      results.push(row.value);
    }
    return results;
  });
};

module.exports = todo;

Copy get all logic into a getAll function.


"use strict";

var debug = require('debug')('server');
var express = require('express');
var path = require('path');

var routes = require('./routes/index');

var app = express();

app.use('/', routes);

app.set('view engine', 'jade');
app.set('views', path.join(__dirname, 'views'));

var server = app.listen(process.env.PORT || 3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  debug('listening at http://%s:%s', host, port);
});

"use strict";

var debug = require('debug')('server');
var express = require('express');
var io = require('socket.io')();
var path = require('path');

var routes = require('./routes/index');

var app = express();

app.use('/', routes);

app.set('view engine', 'jade');
app.set('views', path.join(__dirname, 'views'));

var server = app.listen(process.env.PORT || 3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  debug('listening at http://%s:%s', host, port);
});

io.attach(server);

io.on('connection', function (socket) {
  debug('+1 socket connection');
  io.emit('test', { message: 'Hey, everyone! +1 connection' });
  socket.on('test', function (data) {
    debug('received: %s', data);
  });
  socket.on('disconnect', function () {
    debug('-1 socket connection');
  });
});

Integrate socket.io to the backend.


/*global isic:true*/

var isic = isic || {};

_.extend(isic, {
    models: {},
    collections: {},
    views: {},
    router: new Backbone.Router(),
    events: _.clone(Backbone.Events)
});

girder.router.enabled(false);

/*global isic:true*/

var isic = isic || {};

_.extend(isic, {
    models: {},
    collections: {},
    views: {},
    router: new Backbone.Router(),
    events: girder.events
});

girder.router.enabled(false);

Make isic.events an alias for girder.events


const Test = require('./include/runner');

const setUp = (context) => {
   return context.gitP(context.root).init();
};

describe('remote', () => {

   let context;
   let REMOTE_URL = 'https://github.com/steveukx/git-js.git';

   beforeEach(() => setUp(context = Test.createContext()));

   it('adds and removes named remotes', async () => {
      const {gitP, root} = context;
      await gitP(root).addRemote('remote-name', REMOTE_URL);

      expect(await gitP(root).getRemotes(true)).toEqual([
         { name: 'remote-name', refs: { fetch: REMOTE_URL, push: REMOTE_URL }},
      ]);

      await gitP(root).removeRemote('remote-name');
      expect(await gitP(root).getRemotes(true)).toEqual([]);
   });

})

const Test = require('./include/runner');

const setUp = (context) => {
   return context.gitP(context.root).init();
};

describe('remote', () => {

   let context;
   let REMOTE_URL_ROOT = 'https://github.com/steveukx';
   let REMOTE_URL = `${ REMOTE_URL_ROOT }/git-js.git`;

   beforeEach(() => setUp(context = Test.createContext()));

   it('adds and removes named remotes', async () => {
      const {gitP, root} = context;
      await gitP(root).addRemote('remote-name', REMOTE_URL);

      expect(await gitP(root).getRemotes(true)).toEqual([
         {name: 'remote-name', refs: {fetch: REMOTE_URL, push: REMOTE_URL}},
      ]);

      await gitP(root).removeRemote('remote-name');
      expect(await gitP(root).getRemotes(true)).toEqual([]);
   });

   it('allows setting the remote url', async () => {
      const {gitP, root} = context;
      const git = gitP(root);

      let repoName = 'origin';
      let initialRemoteRepo = `${REMOTE_URL_ROOT}/initial.git`;
      let updatedRemoteRepo = `${REMOTE_URL_ROOT}/updated.git`;

      await git.addRemote(repoName, initialRemoteRepo);
      expect(await git.getRemotes(true)).toEqual([
         {name: repoName, refs: {fetch: initialRemoteRepo, push: initialRemoteRepo}},
      ]);

      await git.remote(['set-url', repoName, updatedRemoteRepo]);
      expect(await git.getRemotes(true)).toEqual([
         {name: repoName, refs: {fetch: updatedRemoteRepo, push: updatedRemoteRepo}},
      ]);

   });

})

Add test for using `addRemote` and `remote(['set-url', ...])'`


module.exports = {
    Env: process.env.NODE_ENV || 'development',
    Permissions: {
        viewPage: 'viewPage'
    },
    boxWidth: 55,
    boxHeight: 30,
    Difficulties: {
        1: {
            name: 'Very Easy',
            percent: 10
        },
        2: {
            name: 'Easy',
            percent: 15
        },
        3: {
            name: 'Medium',
            percent: 20
        },
        4: {
            name: 'Hard',
            percent: 30
        },
        5: {
            name: 'Nightmare',
            percent: 60
        },
        6: {
            name: 'Impossibruuu!!',
            percent: 90
        }
    }
};

module.exports = {
    Env: process.env.NODE_ENV || 'development',
    Permissions: {
        viewPage: 'viewPage'
    },
    boxWidth: 40,
    boxHeight: 35,
    Difficulties: {
        1: {
            name: 'Very Easy',
            percent: 10
        },
        2: {
            name: 'Easy',
            percent: 15
        },
        3: {
            name: 'Medium',
            percent: 20
        },
        4: {
            name: 'Hard',
            percent: 30
        },
        5: {
            name: 'Nightmare',
            percent: 60
        },
        6: {
            name: 'Impossibruuu!!',
            percent: 90
        }
    }
};

Adjust dimensions of grid to be squarer


(function() {
  'use strict';

  var ripper = require('./Rip'),
    encoder = require('./Encode'),
    ui = require('bull-ui/app')({
      redis: {
        host: 'localhost',
        port: '6379'
      }
    }),
    Queue = require('bull');

  ui.listen(1337, function() {
    console.log('bull-ui started listening on port', this.address().port);
  });

  var ripQ = Queue('disc ripping');
  var encodeQ = Queue('video encoding');

  encodeQ.add({
    type: './HandBrakeCLI',
    options: '-Z "High Profile" -O -q 21 --main-feature --min-duration 2000 -i /mnt/temp/RIP -o',
    destination: '/mnt/temp'
  });

  ripQ.add({
    destination: '/mnt/temp'
  });

  encodeQ.process(function(job) {
    return encoder.encode(job);
  });

  ripQ.process(function(job) {
    return ripper.rip(job);
  });
}());

(function() {
  'use strict';

  var ripper = require('./Rip'),
    fs = require('fs'),
    encoder = require('./Encode'),
    ui = require('bull-ui/app')({
      redis: {
        host: 'localhost',
        port: '6379'
      }
    }),
    Queue = require('bull');

  ui.listen(1337, function() {
    console.log('bull-ui started listening on port', this.address().port);
  });

  var ripQ = Queue('disc ripping');
  var encodeQ = Queue('video encoding');

  encodeQ.add({
    type: './HandBrakeCLI',
    options: '-Z "High Profile" -O -q 21 --main-feature --min-duration 2000 -i /mnt/temp/RIP -o',
    destination: '/mnt/temp'
  });

  ripQ.add({
    destination: '/mnt/temp'
  });

  encodeQ.process(function(job) {
    return encoder.encode(job);
  });

  if(fs.existsSync('/dev/sr0')) {
    //if a DVD device exists, then we can process the Ripping queue
    ripQ.process(function(job) {
      return ripper.rip(job);
    });
  }

}());

Check for DVD device for ripping queue processing


'use strict';

const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const routes = require('./controllers/routes');

let app = express();

// Configure view engine and views directory
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));

// Configure middleware
app.use(bodyParser.urlencoded({ extended: false }));

// Static file serving happens everywhere but in production
if (process.env.NODE_ENV !== 'production') {
  let staticPath = path.join(__dirname, '..', '..', 'public');
  app.use('/static', express.static(staticPath));
}

// Mount application routes
routes(app);

// Export Express webapp instance
module.exports = app;

'use strict';

const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const routes = require('./controllers/routes');

let app = express();

// Configure view engine and views directory
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.set('x-powered-by', false);

// Configure middleware
app.use(bodyParser.urlencoded({ extended: false }));

// Static file serving happens everywhere but in production
if (process.env.NODE_ENV !== 'production') {
  let staticPath = path.join(__dirname, '..', '..', 'public');
  app.use('/static', express.static(staticPath));
}

// Mount application routes
routes(app);

// Export Express webapp instance
module.exports = app;

Remove the 'X-Powered-By: Express' HTTP response header


var test = require('tape')
var names = require('../lib/imageref.js')

test('litmus', function (t) {
  t.plan(2)
  t.looseEqual(
    names(['1', '']),
    ['atom-h']
  )
  t.looseEqual(
    names(['1', 'gc']),
    ['bond-left', 'bond-right', 'atom-h']
  )
})

var test = require('tape')
var names = require('../lib/imagenames.js')

test('litmus', function (t) {
  t.plan(2)
  t.looseEqual(
    names(['1', '']),
    ['atom-h']
  )
  t.looseEqual(
    names(['1', 'gc']),
    ['bond-left', 'bond-right', 'atom-h']
  )
})

Fix last minute name chang bug.


var postcss = require('postcss');

module.exports = postcss.plugin('postcss-prefixer-font-face', function (opts) {
    opts = opts || {};

    var prefix = opts.prefix || '';

    var usedFonts = [];

    return function (css, result) {

        /* Font Faces */
        css.walkAtRules(/font-face$/, function (font) {
            font.walkDecls(/font-family/, function (decl) {
                var fontName = decl.value.replace(/['"]+/g, '');
                usedFonts.push(fontName);
                decl.value = '\''+String(prefix+fontName)+'\'';
            });
        });

        css.walkDecls(/font-family/, function (decl) {
            var fontName = decl.value.replace(/['"]+/g, '');
            if (usedFonts.indexOf(fontName) > -1) {
                decl.value = '\''+String(prefix+fontName)+'\'';
            }
        });
    };
});

var postcss = require('postcss');

module.exports = postcss.plugin('postcss-prefixer-font-face', function (opts) {
    opts = opts || {};

    var prefix = opts.prefix || '';

    var usedFonts = [];

    return function (css, result) {

        /* Font Faces */
        css.walkAtRules(/font-face$/, function (font) {
            font.walkDecls(/font-family/, function (decl) {
                var fontName = decl.value.replace(/['"]+/g, '');
                usedFonts.push(fontName);
                decl.value = String(prefix + fontName);
            });
        });

        css.walkDecls(/font-family/, function (decl) {
            var fontNames = decl.value.replace(/['"]+/g, '').split(',');
            for (var i = 0; i < fontNames.length; i++) {
                var fontName = fontNames[i].trim();
                if (usedFonts.indexOf(fontName) > -1) {
                    fontNames[i] = String(prefix + fontName);
                }
            }
            decl.value = fontNames.join(',');
        });
    };
});

Support prefix if multiple font families are used


'use strict';

var async = require("async");

function capitalize(string) {
  return string.charAt(0).toUpperCase() + string.slice(1);
}

module.exports = function seeder(seedObject, mongoose, logger, cb) {
  if(!cb) {
    cb = logger;
    logger = console.log;
  }

  var ObjectId = mongoose.Types.ObjectId;

  async.each(Object.keys(seedObject), function(mongoModel, cb) {
    var documents = seedObject[mongoModel];
    var mongoModelName = capitalize(mongoModel);
    var Model = mongoose.model(mongoModelName);

    async.each(Object.keys(documents), function(_id, cb) {
      // Fake an upsert call, to keep the hooks
      Model.findById(_id, function(err, mongoDocument) {
        if(err) {
          return cb(err);
        }
        if(!mongoDocument) {
          mongoDocument = new Model({_id: new ObjectId(_id)});
        }

        var document = documents[_id];
        for(var key in document) {
          mongoDocument[key] = document[key];
          mongoDocument.markModified(key);
        }

        logger(mongoModelName, _id);
        mongoDocument.save(cb);
      });
    }, cb);
  }, cb);
};

'use strict';

var async = require("async");

function capitalize(string) {
  return string.charAt(0).toUpperCase() + string.slice(1);
}

module.exports = function seeder(seedObject, mongoose, logger, cb) {
  if(!cb) {
    cb = logger;
    logger = console.log;
  }

  var ObjectId = mongoose.Types.ObjectId;

  async.each(Object.keys(seedObject), function(mongoModel, cb) {
    var documents = seedObject[mongoModel];
    var mongoModelName = capitalize(mongoModel);
    var Model = mongoose.model(mongoModelName);

    async.each(Object.keys(documents), function(_id, cb) {
      var document = documents[_id];

      if(document._id) {
        _id = document._id;
      }

      // Fake an upsert call, to keep the hooks
      Model.findById(_id, function(err, mongoDocument) {
        if(err) {
          return cb(err);
        }
        if(!mongoDocument) {
          mongoDocument = new Model({_id: new ObjectId(_id)});
        }

        for(var key in document) {
          mongoDocument[key] = document[key];
          mongoDocument.markModified(key);
        }

        logger(mongoModelName, _id);
        mongoDocument.save(cb);
      });
    }, cb);
  }, cb);
};

Add managing of _id field


const { expect } = require('chai');
const Plexacious = require('../lib/Plexacious');
const config = {
  "hostname": process.env.PLEX_SERVER_HOST,
  "port": process.env.PLEX_SERVER_PORT,
  "https": process.env.PLEX_SERVER_HTTPS,
  "token": process.env.PLEX_AUTH_TOKEN
};

const plex = new Plexacious(config);

describe('Plexacious:', () => {
  describe('Event attaching:', () => {
    it('should instantiate with no events', () => {
      expect(plex.events()).to.deep.equal({});
      expect(typeof plex.events('test')).to.equal('undefined');
    });

    it('should attach a callback to an event', () => {
      plex.on('test', () => {});
      expect(Object.keys(plex.events()).length).to.equal(1);
      expect(typeof plex.events('test')).to.equal('function');
    });
  });

  describe('Recently Added:', () => {

  });
});

const { expect } = require('chai');
const Plexacious = require('../lib/Plexacious');
const env = require('node-env-file');
env('./.env');
const config = {
  "hostname": process.env.PLEX_SERVER_HOST,
  "port": process.env.PLEX_SERVER_PORT,
  "https": process.env.PLEX_SERVER_HTTPS,
  "token": process.env.PLEX_AUTH_TOKEN
};

const plex = new Plexacious(config);

describe('Plexacious:', () => {
  describe('Event attaching:', () => {
    it('should instantiate with no events', () => {
      expect(plex.eventFunctions()).to.deep.equal({});
      expect(typeof plex.eventFunctions('test')).to.equal('undefined');
    });

    it('should attach a callback to an event', () => {
      plex.on('test', () => {});
      expect(Object.keys(plex.eventFunctions()).length).to.equal(1);
      expect(typeof plex.eventFunctions('test')).to.equal('function');
    });
  });

  describe('Recently Added:', () => {

  });
});

Fix events() call to match renamed function eventFunctions()


function hide_covers() {
    // Remove covers
    $(".mix_element div.cover").remove()
    // Add class so cards can be restyled
    $(".mix_card.half_card").addClass("ext-coverless_card")

    // Remove covers on track page
    $("#cover_art").remove()
    // Remove covers in the sidebar of a track page
    $(".card.sidebar_mix .cover").remove()
    $(".card.sidebar_mix").addClass("ext-coverless_card")

    // Remove covers in "suggested collections"
    $(".suggested_collection .covers").remove()
    $(".suggested_collection").addClass("ext-coverless_card")
}

function filter() {
    chrome.storage.local.get("state", function(result) {
        if(result["state"] == "on") {
            hide_covers()
        }
    });
}
// Make sure that when we navigate the site (which doesn't refresh the page), the filter is still run
var observer = new MutationObserver(filter)
observer.observe(document.getElementById("main"), {childList: true, subtree: true})
filter();

function hide_covers() {
    // Remove covers
    $(".mix_element div.cover").remove()
    // Add class so cards can be restyled
    $(".mix_card.half_card").addClass("ext-coverless_card")

    // Remove covers on track page
    $("#cover_art").remove()
    // Remove covers in the sidebar of a track page
    $(".card.sidebar_mix .cover").remove()
    $(".card.sidebar_mix").addClass("ext-coverless_card")

    // Remove covers in "suggested collections"
    $(".suggested_collection .covers").remove()
    $(".suggested_collection").addClass("ext-coverless_card")

    // Remove mini covers ("Because you liked ____")
    // Replace with 8tracks icon
    $(".card img.mini-cover")
        .replaceWith("")
}

function filter() {
    chrome.storage.local.get("state", function(result) {
        if(result["state"] == "on") {
            hide_covers()
        }
    });
}
// Make sure that when we navigate the site (which doesn't refresh the page), the filter is still run
var observer = new MutationObserver(filter)
observer.observe(document.getElementById("main"), {childList: true, subtree: true})
filter();

Replace mini covers with 8tracks icon


var cookie = require('cookie');

var _cookies = cookie.parse((typeof document !== 'undefined') ? document.cookie : '');

for (var key in _cookies) {
  try {
    _cookies[key] = JSON.parse(_cookies[key]);
  } catch(e) {
    // Not serialized object
  }
}

function load(name) {
  return _cookies[name];
}

function save(name, val, opt) {
  _cookies[name] = val;

  // Cookies only work in the browser
  if (typeof document === 'undefined') return;

  document.cookie = cookie.serialize(name, val, opt);
}

var reactCookie = {
  load: load,
  save: save
};

if (typeof module !== 'undefined') {
  module.exports = reactCookie
}

if (typeof window !== 'undefined') {
  window['reactCookie'] = reactCookie;
}

var cookie = require('cookie');

var _cookies = cookie.parse((typeof document !== 'undefined') ? document.cookie : '');

for (var key in _cookies) {
  try {
    _cookies[key] = JSON.parse(_cookies[key]);
  } catch(e) {
    // Not serialized object
  }
}

function load(name) {
  return _cookies[name];
}

function save(name, val, opt) {
  _cookies[name] = val;

  // Cookies only work in the browser
  if (typeof document === 'undefined') return;

  // allow you to work with cookies as objects.
  if (typeof val === 'object') val = JSON.stringify(val);

  document.cookie = cookie.serialize(name, val, opt);
}

var reactCookie = {
  load: load,
  save: save
};

if (typeof module !== 'undefined') {
  module.exports = reactCookie
}

if (typeof window !== 'undefined') {
  window['reactCookie'] = reactCookie;
}

Fix cookie not being parsed on load.


#!/usr/bin/env node

'use strict';

const moment = require("moment");
const sugar = require("sugar");
const chalk = require("chalk");
const exec = require("child_process").exec;

process.argv.splice(0, 2);
if (process.argv.length > 0) {

  // Attempt to parse the date
  let date = process.argv.join(" ");
  let parsedDate = new sugar.Date.create(date);

  if (parsedDate != "Invalid Date") {

    // Date could be parsed, parse the date to git date format
    let dateString = moment(parsedDate).format("ddd MMM DD HH:mm:ss YYYY ZZ");

    // Actually modify the dates
    let command = "GIT_COMMITTER_DATE=\"" + dateString + "\" git commit --amend --date=\"" + dateString + "\" --no-edit";
    exec(command, (err, stdout, stderr) => {
      if (err) {
        console.log("fatal: Could not change the previous commit");
      } else {
        console.log("\nModified previous commit:\n\tAUTHOR_DATE " + chalk.grey(dateString) + "\n\tCOMMITTER_DATE " + chalk.grey(dateString) + "\n\nCommand executed:\n\t" + chalk.bgWhite.black(command) + "\n");
      }
    });

  } else {
    console.log("fatal: Could not parse \"" + date + "\" into a valid date");
  }

} else {
  console.log("fatal: No date string given");
}

#!/usr/bin/env node

"use strict";

const moment = require("moment");
const sugar = require("sugar");
const chalk = require("chalk");
const exec = require("child_process").exec;

process.argv.splice(0, 2);
if (process.argv.length > 0) {

  // Attempt to parse the date
  let date = process.argv.join(" ");
  let parsedDate = new sugar.Date.create(date);

  if (parsedDate != "Invalid Date") {

    // Date could be parsed, parse the date to git date format
    let dateString = moment(parsedDate).format("ddd MMM DD HH:mm:ss YYYY ZZ");

    // Actually modify the dates
    let command = "GIT_COMMITTER_DATE=\"" + dateString + "\" git commit --amend --date=\"" + dateString + "\" --no-edit";
    exec(command, (err, stdout, stderr) => {
      if (err) {
        console.log("fatal: Could not change the previous commit");
      } else {
        console.log("\nModified previous commit:\n\tAUTHOR_DATE " + chalk.grey(dateString) + "\n\tCOMMITTER_DATE " + chalk.grey(dateString) + "\n\nCommand executed:\n\t" + chalk.bgWhite.black(command) + "\n");
      }
    });

  } else {
    console.log("fatal: Could not parse \"" + date + "\" into a valid date");
  }

} else {
  console.log("fatal: No date string given");
}

Use double quotes on "use strict"


var child_process = require('child_process');
var byline = require('./byline');

exports.handler = function(event, context) {
  var proc = child_process.spawn('./main', [JSON.stringify(event)], { stdio: [process.stdin, 'pipe', 'pipe'] });

  proc.stdout.on('data', function(line){
    var msg = JSON.parse(line);
    context.succeed(msg);
  })

  proc.stderr.on('data', function(line){
    var msg = new Error(line)
    context.fail(msg);
  })

  proc.on('exit', function(code){
    console.error('exit blabla: %s', code)
    context.fail("No results")
  })
}

var child_process = require('child_process');

exports.handler = function(event, context) {
  var proc = child_process.spawn('./main', [JSON.stringify(event)], { stdio: [process.stdin, 'pipe', 'pipe'] });

  proc.stdout.on('data', function(line){
    var msg = JSON.parse(line);
    context.succeed(msg);
  })

  proc.stderr.on('data', function(line){
    var msg = new Error(line)
    context.fail(msg);
  })

  proc.on('exit', function(code){
    console.error('exit blabla: %s', code)
    context.fail("No results")
  })
}

Remove unused dependency from JS wrapper


'use strict';

class Mutex {
  constructor() {
    // Item at index 0 is the caller with the lock:
    // [ <has the lock>, <waiting>, <waiting>, <waiting> ... ]
    this.queue = [];
  }

  acquire({ timeout = 60000 } = {}) {
    const queue = this.queue;

    return new Promise((resolve, reject) => {
      setTimeout(() => {
        const index = queue.indexOf(resolve);

        if (index > 0) { // Still waiting in the queue
          queue.splice(index, 1);
          reject('Queue timeout');
        }
      }, timeout);

      if (queue.push(resolve) === 1) {
        // Queue was empty, resolve the promise immediately. Caller is kept in the queue and
        // blocks it until it caller calls release()
        resolve({ release: function release() {
          queue.shift();

          if (queue.length > 0) {
            queue[0]({ release }); // give the lock to the next in line by resolving the promise
          }
        }});
      }
    });
  }
}

module.exports = Mutex;

'use strict';

class Mutex {
  constructor() {
    // Item at index 0 is the caller with the lock:
    // [ <has the lock>, <waiting>, <waiting>, <waiting> ... ]
    this.queue = [];
  }

  acquire({ timeout = false } = {}) {
    const queue = this.queue;

    return new Promise((resolve, reject) => {
      if (timeout !== false) {
        setTimeout(() => {
          const index = queue.indexOf(resolve);

          if (index > 0) { // Still waiting in the queue
            queue.splice(index, 1);
            reject('Queue timeout');
          }
        }, timeout);
      }

      if (queue.push(resolve) === 1) {
        // Queue was empty, resolve this promise immediately. Caller is kept in the queue until
        // it calls release()
        resolve({
          release: function release() {
            queue.shift();

            if (queue.length > 0) {
              queue[0]({ release }); // give the lock to the next in line by resolving the promise
            }
          }
        });
      }
    });
  }
}

module.exports = Mutex;

Make timeout disabled by default


'use strict';

var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');

var api = require('./nestor/api');

var app = express();

app.use(bodyParser.json());

var router = express.Router();

router.route('/')
    .get(function (req, res) {

        api.rtm.start();
    });

app.use('/', router);

app.set('port', process.env.PORT || 3000);

var server = app.listen(app.get('port'), function () {
    console.log('Nestor listening on port ' + server.address().port);
});

'use strict';

var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');

var api = require('./nestor/api');

var app = express();

app.use(bodyParser.json());

var router = express.Router();

app.set('port', process.env.PORT || 3000);

var server = app.listen(app.get('port'), function () {
    api.rtm.start();

    console.log('Nestor listening on port ' + server.address().port);
});

Connect to RTM right away


'use strict';

var fs = require('fs');

function reset() {
    exports.out = [];
    exports.xmlEmitter = null;
    exports.opts = {};
} reset();

/**
 * Load a formatter
 * @param  {String} formatterPath
 * @return
 */
function loadFormatter(formatterPath) {
    return require('./lib/' + formatterPath + '_emitter');
}

/**
 * Write out a XML file for the encountered results
 */
exports.reporter = function (results, data, opts) {
    console.log(arguments);
    console.log('\n\n\n\n');
    opts = opts || {};
    opts.format = opts.format || 'checkstyle';
    opts.filePath = opts.filePath || 'jshint.xml';
    exports.opts = opts;
    exports.xmlEmitter = loadFormatter(opts.format);
    exports.out.push(exports.xmlEmitter.formatContent(results));
};

exports.writeFile = function () {
    var outStream = fs.createWriteStream(exports.opts.filePath);
    outStream.write(exports.xmlEmitter.getHeader());
    outStream.write(exports.out.join('\n'));
    outStream.write(exports.xmlEmitter.getFooter());
    reset();
};

'use strict';

var fs = require('fs');

function reset() {
    exports.out = [];
    exports.xmlEmitter = null;
    exports.opts = {};
} reset();

/**
 * Load a formatter
 * @param  {String} formatterPath
 * @return
 */
function loadFormatter(formatterPath) {
    return require('./lib/' + formatterPath + '_emitter');
}

/**
 * Write out a XML file for the encountered results
 * @param  {Array}  results
 * @param  {Array}  data
 * @param  {Object} opts
 */
exports.reporter = function (results) {
    exports.out.push(results);
};

exports.writeFile = function (opts) {
    opts = opts || {};
    opts.filePath = opts.filePath || 'jshint.xml';
    opts.format = opts.format || 'checkstyle';
    exports.xmlEmitter = loadFormatter(opts.format);
    return function () {
        if (!exports.out.length) {
            reset();
            return;
        }
        var outStream = fs.createWriteStream(opts.filePath);
        outStream.write(exports.xmlEmitter.getHeader());
        exports.out.forEach(function (item) {
            outStream.write(exports.xmlEmitter.formatContent(item));
        });
        outStream.write(exports.out.join('\n'));
        outStream.write(exports.xmlEmitter.getFooter());
        reset();
    };
};

Restructure things to handle all-ok cases


'use strict';

var minimatch = require('minimatch');

var anymatch = function(criteria, string, returnIndex, startIndex, endIndex) {
  if (!Array.isArray(criteria)) { criteria = [criteria]; }
  if (arguments.length === 1) { return anymatch.bind(null, criteria); }
  if (startIndex == null) { startIndex = 0; }
  var matchIndex = -1;
  function testCriteria (criterion, index) {
    var result;
    switch (toString.call(criterion)) {
    case '[object String]':
      result = string === criterion || minimatch(string, criterion);
      break;
    case '[object RegExp]':
      result = criterion.test(string);
      break;
    case '[object Function]':
      result = criterion(string);
      break;
    default:
      result = false;
    }
    if (result) { matchIndex = index + startIndex; }
    return result;
  }
  var matched = criteria.slice(startIndex, endIndex).some(testCriteria);
  return returnIndex === true ? matchIndex : matched;
};

module.exports = anymatch;

'use strict';

var minimatch = require('minimatch');

var anymatch = function(criteria, value, returnIndex, startIndex, endIndex) {
  if (!Array.isArray(criteria)) { criteria = [criteria]; }
  var string = Array.isArray(value) ? value[0] : value;
  if (arguments.length === 1) { return anymatch.bind(null, criteria); }
  if (startIndex == null) { startIndex = 0; }
  var matchIndex = -1;
  function testCriteria (criterion, index) {
    var result;
    switch (toString.call(criterion)) {
    case '[object String]':
      result = string === criterion || minimatch(string, criterion);
      break;
    case '[object RegExp]':
      result = criterion.test(string);
      break;
    case '[object Function]':
      result = criterion.apply(null, Array.isArray(value) ? value : [value]);
      break;
    default:
      result = false;
    }
    if (result) { matchIndex = index + startIndex; }
    return result;
  }
  var matched = criteria.slice(startIndex, endIndex).some(testCriteria);
  return returnIndex === true ? matchIndex : matched;
};

module.exports = anymatch;

Allow passing extra args to function matchers


/**
 * Dispatcher prototype
 */

var dispatcher = Dispatcher.prototype;

/**
 * Exports
 */

module.exports = Dispatcher;

/**
 * Dispatcher
 *
 * @return {Object}
 * @api public
 */

function Dispatcher() {
  if (!(this instanceof Dispatcher)) return new Dispatcher;
  this.callbacks = [];
};

/**
 * Register a new store.
 *
 *   dispatcher.register('update_course', callbackFunction);
 *
 * @param {String} action
 * @param {Function} callback
 * @api public
 */

dispatcher.register = function(action, callback) {
  this.callbacks.push({
    action: action,
    callback: callback
  });
};

/**
 * Dispatch event to stores.
 *
 *   dispatcher.dispatch('update_course', {id: 123, title: 'Tobi'});
 *
 * @param {String} action
 * @param {Object | Object[]} data
 * @return {Function[]}
 * @api public
 */

dispatcher.dispatch = function(action, data) {
  this.getCallbacks(action)
    .map(function(callback) {
      return callback.call(callback, data);
    });
};

/**
 * Return registered callbacks.
 *
 * @param {String} action
 * @return {Function[]}
 * @api private
 */

dispatcher.getCallbacks = function(action) {
  return this.callbacks
    .filter(function(callback) {
      return callback.action === action;
    })
    .map(function(callback) {
      return callback.callback;
    });
};

/**
 * Exports
 */

module.exports = Dispatcher;

/**
 * Dispatcher prototype
 */

var dispatcher = Dispatcher.prototype;

/**
 * Dispatcher
 *
 * @return {Object}
 * @api public
 */

function Dispatcher() {
  if (!(this instanceof Dispatcher)) return new Dispatcher;
  this.callbacks = [];
};

/**
 * Register a new store.
 *
 *   dispatcher.register('update_course', callbackFunction);
 *
 * @param {String} action
 * @param {Function} callback
 * @api public
 */

dispatcher.register = function(action, callback) {
  this.callbacks.push({
    action: action,
    callback: callback
  });
};

/**
 * Dispatch event to stores.
 *
 *   dispatcher.dispatch('update_course', {id: 123, title: 'Tobi'});
 *
 * @param {String} action
 * @param {Object | Object[]} data
 * @return {Function[]}
 * @api public
 */

dispatcher.dispatch = function(action, data) {
  this.getCallbacks(action)
    .forEach(function(callback) {
      callback.call(callback, data);
    });
};

/**
 * Return registered callbacks.
 *
 * @param {String} action
 * @return {Function[]}
 * @api private
 */

dispatcher.getCallbacks = function(action) {
  return this.callbacks
    .filter(function(callback) {
      return callback.action === action;
    })
    .map(function(callback) {
      return callback.callback;
    });
};

Remove last reference to array returns


var util = require('util');

GeometryBounds = function(bounds) {
  this.xKey = "x";
  this.yKey = "y";

  this.bounds = [];
  if(!bounds || !bounds[0]) return;

  this.xKey = Object.keys(bounds[0])[0];
  this.yKey = Object.keys(bounds[0])[1];

  for(var b1 in bounds) {
    var constructedBound = [];
    var bound = bounds[b1];
    for(var b2 in bound)  {
      var constructedPoint = [];
      var point = bound[b2];

      constructedPoint.push(parseFloat(point[this.xKey]));
      constructedPoint.push(parseFloat(point[this.yKey]));
    }
  }

}

GeometryBounds.prototype.contains = function contains(dot)  {
  if(dot == null || !(this.xKey in dot) || !(this.yKey in dot)) {
    return false;
  }

  var x = parseFloat(dot[this.xKey]);
  var y = parseFloat(dot[this.yKey]);

  for(var index in this.bounds) {

    if(testInPolygon(this.bounds[index], x, y)) return true;
  }

  return false;
}

function testInPolygon(bound, x, y) {
  var c = false;
  for(i = 0, j = 1; i < bound.length; i++)  {
  }
}

exports.GeometryBounds = GeometryBounds;

var util = require('util');

GeometryBounds = function(bounds) {
  this.xKey = "x";
  this.yKey = "y";

  this.bounds = [];
  if(!bounds || !bounds[0] || !bounds[0][0]) return;

  this.xKey = Object.keys(bounds[0][0])[0];
  this.yKey = Object.keys(bounds[0][0])[1];

  for(var b1 in bounds) {
    var constructedBound = [];
    var bound = bounds[b1];
    for(var b2 in bound)  {
      var constructedPoint = [];
      var point = bound[b2];

      constructedPoint.push(parseFloat(point[this.xKey]));
      constructedPoint.push(parseFloat(point[this.yKey]));
    }
  }

}

GeometryBounds.prototype.contains = function contains(dot)  {
  if(dot == null || !(this.xKey in dot) || !(this.yKey in dot)) {
    return false;
  }

  var x = parseFloat(dot[this.xKey]);
  var y = parseFloat(dot[this.yKey]);

  console.log(this.bounds);
  for(var index in this.bounds) {

    if(testInPolygon(this.bounds[index], x, y)) return true;
  }

  return false;
}

function testInPolygon(bound, x, y) {
  var c = false;
  console.log(bound);
  for(i = 0, j = bound.length - 1; i < bound.length; j = i++)  {
    console.log(util.format("i = %d, j = %d", i, j));
  }
}

exports.GeometryBounds = GeometryBounds;

Fix in defining keys for x,y


/**
 * @class CM_FormField_Text
 * @extends CM_FormField_Abstract
 */
var CM_FormField_Text = CM_FormField_Abstract.extend({
	_class: 'CM_FormField_Text',

	/** @type Boolean */
	_skipTriggerChange: false,

	events: {
		'blur input': function() {
			this.trigger('blur');
		},
		'focus input': function() {
			this.trigger('focus');
		}
	},

	/**
	 * @param {String} value
	 */
	setValue: function(value) {
		this._skipTriggerChange = true;
		this.$('input').val(value);
		this._skipTriggerChange = false;
	},

	setFocus: function() {
		this.$('input').focus();
	},

	enableTriggerChange: function() {
		var self = this;
		var $input = this.$('input');
		var valueLast = $input.val();
		var callback = function() {
			var value = this.value;
			if (value != valueLast) {
				valueLast = value;
				if (!self._skipTriggerChange) {
					self.trigger('change');
				}
			}
		};
		// `propertychange` and `keyup` needed for IE9
		$input.on('input propertychange keyup', callback);
	}
});

/**
 * @class CM_FormField_Text
 * @extends CM_FormField_Abstract
 */
var CM_FormField_Text = CM_FormField_Abstract.extend({
	_class: 'CM_FormField_Text',

	/** @type Boolean */
	_skipTriggerChange: false,

	events: {
		'blur input': function() {
			this.trigger('blur');
		},
		'focus input': function() {
			this.trigger('focus');
		}
	},

	/**
	 * @param {String} value
	 */
	setValue: function(value) {
		this._skipTriggerChange = true;
		this.$('input').val(value);
		this._skipTriggerChange = false;
	},

	setFocus: function() {
		this.$('input').focus();
	},

	/**
	 * @return {Boolean}
	 */
	hasFocus: function() {
		return this.$('input').is(':focus');
	},

	enableTriggerChange: function() {
		var self = this;
		var $input = this.$('input');
		var valueLast = $input.val();
		var callback = function() {
			var value = this.value;
			if (value != valueLast) {
				valueLast = value;
				if (!self._skipTriggerChange) {
					self.trigger('change');
				}
			}
		};
		// `propertychange` and `keyup` needed for IE9
		$input.on('input propertychange keyup', callback);
	}
});

Add hasFocus() for text formField


/**
 * Builder.js
 *
 * @author: Harish Anchu <harishanchu@gmail.com>
 * @copyright Copyright (c) 2015-2016, QuorraJS.
 * @license See LICENSE.txt
 */

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

function Builder() {

    /**
     * Stores middleware classes
     *
     * @type {Array}
     * @protected
     */
    this.__specs = [];

}

Builder.prototype.push = function(spec) {

    if (typeof spec != 'function') {
        throw new Error("Spec error");
    }

    this.__specs.push(spec);

    return this;

};

Builder.prototype.resolve = function(app)
{
    var next = app;
    var middlewares = [app];
    var key;
    var spec;

    for(key = this.__specs.length -1; key >= 0; key--) {
        spec = this.__specs[key];

        next = new spec(app, next);

        middlewares.unshift(next);
    }

    return new StackedHttpKernel(next, middlewares);
};

module.exports = Builder;

/**
 * Builder.js
 *
 * @author: Harish Anchu <harishanchu@gmail.com>
 * @copyright Copyright (c) 2015-2016, QuorraJS.
 * @license See LICENSE.txt
 */

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

function Builder() {

    /**
     * Stores middleware classes
     *
     * @type {Array}
     * @protected
     */
    this.__specs = [];

}

Builder.prototype.push = function(spec) {

    if (typeof spec != 'function') {
        throw new Error("Spec error");
    }

    this.__specs.push(spec);

    return this;

};

Builder.prototype.resolve = function(app)
{
    var next = app;
    var key;
    var spec;

    for(key = this.__specs.length -1; key >= 0; key--) {
        spec = this.__specs[key];

        next = new spec(app, next);
    }

    return new StackedHttpKernel(next);
};

module.exports = Builder;

Stop passing middlewares array to stack


#!/usr/bin/env node
'use strict';

/**
 * Binary to run a pg server.
 * (C) 2015 Alex Fernández.
 */

// requires
var stdio = require('stdio');
var server = require('../lib/server.js');
var packageJson = require(__dirname + '/../package.json');

// constants
var PORT = 5433;

// init
var options = stdio.getopt({
	version: {key: 'v', description: 'Display version and quit'},
	port: {key: 'p', args: 1, description: 'Port to connect to', default: PORT},
	host: {key: 'h', args: 1, description: 'Host to connect to'},
	quiet: {description: 'Do not log any messages'},
	debug: {description: 'Show debug messages'},
});
if (options.version)
{
	console.log('Loadtest version: %s', packageJson.version);
	process.exit(0);
}
if (options.args && options.args.length > 0)
{
	console.error('Too many arguments: %s', options.args);
	options.printHelp();
	process.exit(1);
}
server.start(options, function(error)
{
	if (error)
	{
		return console.error('Could not start server on port %s: %s', options.port, error);
	}
	console.log('Pooled PostgreSQL server started on port %s', options.port);
});

#!/usr/bin/env node
'use strict';

/**
 * Binary to run a pg server.
 * (C) 2015 Alex Fernández.
 */

// requires
var Log = require('log');
var stdio = require('stdio');
var server = require('../lib/server.js');
var packageJson = require(__dirname + '/../package.json');

// globals
var log = new Log('info');

// constants
var PORT = 5433;

// init
var options = stdio.getopt({
	version: {key: 'v', description: 'Display version and quit'},
	port: {key: 'p', args: 1, description: 'Port to connect to', default: PORT},
	host: {key: 'h', args: 1, description: 'Host to connect to'},
	quiet: {key: 'q', description: 'Do not log any messages'},
	debug: {key: 'd', description: 'Show debug messages'},
});
if (options.version)
{
	console.log('Loadtest version: %s', packageJson.version);
	process.exit(0);
}
if (options.args && options.args.length > 0)
{
	console.error('Too many arguments: %s', options.args);
	options.printHelp();
	process.exit(1);
}
server.start(options, function(error)
{
	if (error)
	{
		return console.error('Could not start server on port %s: %s', options.port, error);
	}
	log.info('Pooled PostgreSQL server started on port %s', options.port);
});

Debug and quiet have short keys.


'use strict';

require.config({
    baseUrl: '../lib',
    paths: {
        'test': '..',
        'forge': 'forge.min'
    },
    shim: {
        sinon: {
            exports: 'sinon',
        }
    }
});

// add function.bind polyfill
if (!Function.prototype.bind) {
    Function.prototype.bind = function(oThis) {
        if (typeof this !== "function") {
            // closest thing possible to the ECMAScript 5 internal IsCallable function
            throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
        }

        var aArgs = Array.prototype.slice.call(arguments, 1),
            fToBind = this,
            FNOP = function() {},
            fBound = function() {
                return fToBind.apply(this instanceof FNOP && oThis ? this : oThis,
                    aArgs.concat(Array.prototype.slice.call(arguments)));
            };

        FNOP.prototype = this.prototype;
        fBound.prototype = new FNOP();

        return fBound;
    };
}

mocha.setup('bdd');
require(['test/unit/browserbox-test', 'test/unit/browserbox-imap-test'], function() {
    (window.mochaPhantomJS || window.mocha).run();
});

'use strict';

require.config({
    baseUrl: '../lib',
    paths: {
        'test': '..',
        'forge': 'forge.min'
    }
});

// add function.bind polyfill
if (!Function.prototype.bind) {
    Function.prototype.bind = function(oThis) {
        if (typeof this !== "function") {
            // closest thing possible to the ECMAScript 5 internal IsCallable function
            throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
        }

        var aArgs = Array.prototype.slice.call(arguments, 1),
            fToBind = this,
            FNOP = function() {},
            fBound = function() {
                return fToBind.apply(this instanceof FNOP && oThis ? this : oThis,
                    aArgs.concat(Array.prototype.slice.call(arguments)));
            };

        FNOP.prototype = this.prototype;
        fBound.prototype = new FNOP();

        return fBound;
    };
}

mocha.setup('bdd');
require(['test/unit/browserbox-test', 'test/unit/browserbox-imap-test'], function() {
    (window.mochaPhantomJS || window.mocha).run();
});

Remove useless sinon require shim


describe('getFolders()', function() {
  it('should return the correct list of folders', function() {
    var objects = [
      { Key: '/' },
      { Key: 'test/' },
      { Key: 'test/test/' },
      { Key: 'test/a/b' },
      { Key: 'test' },
    ];
    chai.expect(dodgercms.utils.getFolders(objects)).to.have.members(['/', 'test/', 'test/test/', 'test/a/']);
  });

  it('should return the root folder if the array is empty', function() {
    var objects = [];
    chai.expect(dodgercms.utils.getFolders(objects)).to.have.members(['/']);
  });
});

describe('newFolder()', function() {
  before(function(done) {
    sinon
      .stub(dodgercms.s3, 'putObject')
      .yields(null, 'index');
    done();
  });

  after(function(done) {
    dodgercms.s3.putObject.restore();
    done();
  });

  it('should match the given key', function(done) {
    dodgercms.utils.newFolder('index', 'dataBucket','siteBucket', function(err, key) {
      if (err) {
        return done(err);
      }
      chai.assert(key === 'index');
      done();
    });
  });
});

describe('isFolder()', function() {
  it('should return true for root', function() {
    chai.assert(dodgercms.utils.isFolder('/'));
  });
  it('should return true for folder', function() {
    chai.assert(dodgercms.utils.isFolder('/folder/'));
  });
  it('should return true for nested folder', function() {
    chai.assert(dodgercms.utils.isFolder('/folder/test/folder/'));
  });
});

Add test cases for the utils


Package.describe({
  summary: "Run tests interactively in the browser",
  version: '1.0.5-pre.2'
});

Package.on_use(function (api) {
  // XXX this should go away, and there should be a clean interface
  // that tinytest and the driver both implement?
  api.use('tinytest');
  api.use('bootstrap');
  api.use('underscore');

  api.use('session');
  api.use('reload');

  api.use(['blaze', 'templating', 'spacebars',
           'ddp', 'tracker'], 'client');

  api.add_files('diff_match_patch_uncompressed.js', 'client');

  api.add_files('diff_match_patch_uncompressed.js', 'client');

  api.add_files([
    'driver.css',
    'driver.html',
    'driver.js'
  ], "client");

  api.use('autoupdate', 'server', {weak: true});
  api.use('random', 'server');
  api.add_files('autoupdate.js', 'server');
});

Package.describe({
  summary: "Run tests interactively in the browser",
  version: '1.0.5-pre.2'
});

Package.on_use(function (api) {
  // XXX this should go away, and there should be a clean interface
  // that tinytest and the driver both implement?
  api.use('tinytest');
  api.use('bootstrap@1.0.1');
  api.use('underscore');

  api.use('session');
  api.use('reload');

  api.use(['blaze', 'templating', 'spacebars',
           'ddp', 'tracker'], 'client');

  api.add_files('diff_match_patch_uncompressed.js', 'client');

  api.add_files('diff_match_patch_uncompressed.js', 'client');

  api.add_files([
    'driver.css',
    'driver.html',
    'driver.js'
  ], "client");

  api.use('autoupdate', 'server', {weak: true});
  api.use('random', 'server');
  api.add_files('autoupdate.js', 'server');
});

Add version constraing to bootstrap use


import React from 'react';
import { NavLink } from 'react-router-dom';

import './style.css';

const Header = props => {
  const { isAdmin, loggedIn } = props;
  return (

          <NavLink to="/">

          </NavLink>
          <NavLink
            activeClassName="selected"
            className="navbar-item"
            to="/jobs"
          >
            Explore Jobs
          </NavLink>
          {isAdmin && (
            <NavLink
              activeClassName="selected"
              className="navbar-item"
              to="/admin"
            >
              Admin Panel
            </NavLink>
          )}
          {!loggedIn && (
            <NavLink
              activeClassName="selected"
              className="navbar-item"
              to="/login"
            >
              Log in
            </NavLink>
          )}
          {!loggedIn && (
            <NavLink
              activeClassName="selected"
              className="navbar-item"
              to="/join"
            >
              Join
            </NavLink>
          )}

  );
};

export default Header;

import React from 'react';
import { NavLink } from 'react-router-dom';

import './style.css';

const Header = props => {
  const { isAdmin, loggedIn } = props;
  return (

          <NavLink to="/">

          </NavLink>
          <NavLink
            activeClassName="selected"
            className="navbar-item"
            to="/jobs"
          >
            Explore Jobs
          </NavLink>
          {isAdmin && (
            <NavLink
              activeClassName="selected"
              className="navbar-item"
              to="/admin"
            >
              Admin Panel
            </NavLink>
          )}
          {!loggedIn && (
            <NavLink
              activeClassName="selected"
              className="navbar-item"
              to="/login"
            >
              Log in
            </NavLink>
          )}
          {!loggedIn && (
            <NavLink
              activeClassName="selected"
              className="navbar-item"
              to="/join"
            >
              Join
            </NavLink>
          )}
          {loggedIn && (
            <NavLink
              activeClassName="selected"
              className="navbar-item"
              to="/bookmarks"
            >
              My saved jobs
            </NavLink>
          )}

  );
};

export default Header;

Add navbar link to /bookmarks


var log4js = require('log4js');

log4js.configure({
  appenders: [
    {
        'type': 'file',
        'filename': 'logs/mymap.log',
        'category': ['mymap', 'console'],
        'maxLogSize': 5242880,
        'backups': 10
    },
    {
        type: 'console'
    }
  ],
  replaceConsole: true
});

exports.getLogger = function() {
    return log4js.getLogger('mymap');
}

var log4js = require('log4js'),
    fs = require('fs');

configure();

exports.getLogger = function() {
    return log4js.getLogger('mymap');
}

function configure() {
    if(!fs.existsSync('logs')) {
        fs.mkdirSync('logs');
    }

    log4js.configure({
      appenders: [
        {
            'type': 'file',
            'filename': 'logs/mymap.log',
            'category': ['mymap', 'console'],
            'maxLogSize': 5242880,
            'backups': 10
        },
        {
            type: 'console'
        }
      ],
      replaceConsole: true
    });
}

Create logs dir if necessary


const MySql = require("./MySql.js");

class Meet{
  constructor(obj){
    Object.keys(obj).forEach(k=>this[k]=obj[k]);
  }

  asMarkdown(){
    return `*${this.post_title}* ${this.meet_start_time}\n_${this.guid}_`;
  }

}
Meet.fromObjArray = function(objArray){
  return objArray.map(o=>new Meet(o));
};

function getAllMeets(){
  return MySql.query(`SELECT * FROM wp_posts WHERE post_type = 'meet'`)
    .then(results=>Meet.fromObjArray(results.results));
}

function getUpcomingMeets(){
  return MySql.query(`
    SELECT meta_value AS meet_start_time, wp_posts.*
    FROM wp_postmeta LEFT JOIN wp_posts ON post_id=ID
    WHERE meta_key = 'meet_start_time' AND CAST(meta_value AS DATE) > CURDATE()
  `).then(results=>Meet.fromObjArray(results.results));
}

module.exports = {getAllMeets,getUpcomingMeets};

const MySql = require("./MySql.js");
const entities = require("entities");

class Meet{
  constructor(obj){
    Object.keys(obj).forEach(k=>this[k]=entities.decodeHTML(obj[k]));
  }

  asMarkdown(){
    return `*${this.post_title}* ${this.meet_start_time}\n${this.guid}`;
  }

}
Meet.fromObjArray = function(objArray){
  return objArray.map(o=>new Meet(o));
};

function getAllMeets(){
  return MySql.query(`SELECT * FROM wp_posts WHERE post_type = 'meet'`)
    .then(results=>Meet.fromObjArray(results.results));
}

function getUpcomingMeets(){
  return MySql.query(`
    SELECT CAST(meta_value AS DATE) AS meet_start_time, wp_posts.*
    FROM wp_postmeta LEFT JOIN wp_posts ON post_id=ID
    WHERE meta_key = 'meet_start_time' AND CAST(meta_value AS DATE) > CURDATE()
  `).then(results=>Meet.fromObjArray(results.results));
}

module.exports = {getAllMeets,getUpcomingMeets};

FIX broken markdown and entities


module.exports = exports = MC

function MC () {
  this._loading = 0
  this.models = {}
}

var modelLoaders = {}
MC.model = function (name, loader) {
  modelLoaders[name] = loader
  return MC
}

MC.prototype.load = function (name) {
  if (!modelLoaders[name]) {
    throw new Error('Unknown model: ' + name)
  }
  if (this.error) return
  var a = new Array(arguments.length)
  for (var i = 1; i < arguments.length; i ++) {
    a[i-1] = arguments[i]
  }
  a[i-1] = next.bind(this)
  this._loading ++
  modelLoaders[name].apply(this, a)
  function next (er, data) {
    if (this.error) return
    this.error = er
    this.models[name] = data

    this._loading --
    if (er || this._loading === 0) {
      this.ondone(this.error, this.models)
    }
  }
}

MC.prototype.end = function (cb) {
  this.ondone = cb
  if (this._loading === 0) this.ondone(this.error, this.models)
}

module.exports = exports = MC

function MC () {
  this.loading = 0
  this.models = {}
  this.ondone = function () {}
}

var modelLoaders = {}
MC.model = function (name, loader) {
  if (MC.prototype.hasOwnProperty(name) ||
      name === 'loading' ||
      name === 'ondone' ||
      name === 'error' ||
      name === 'models') {
    throw new Error('invalid model name: ' + name)
  }
  modelLoaders[name] = loader
  return MC
}

MC.prototype.load = function (name) {
  if (!modelLoaders[name]) {
    throw new Error('Unknown model: ' + name)
  }
  if (this.error) return
  var a = new Array(arguments.length)
  for (var i = 1; i < arguments.length; i ++) {
    a[i-1] = arguments[i]
  }
  a[i-1] = next.bind(this)
  this.loading ++
  modelLoaders[name].apply(this, a)
  function next (er, data) {
    if (this.error) return
    this.error = er
    this[name] = this.models[name] = data

    this.loading --
    if ((er || this.loading === 0) && this.ondone) {
      this.ondone(this.error, this.models)
    }
  }
}

MC.prototype.end = function (cb) {
  this.ondone = cb
  if (this.loading === 0 || this.error) {
    this.ondone(this.error, this.models)
  }
}

Put the model results right on the MC object


const fs = require('fs');
const path = require('path');

const exec = require('child_process').exec;
// this is from the env of npm, not node
const nodePath = process.env.NODE;
const version = process.versions.v8;
const tmpfile = path.join(__dirname, version+'.flags.json');

if (!fs.existsSync(tmpfile)) {
  exec('"'+nodePath+'" --v8-options', function (execErr, result) {
    var flags;
    if (execErr) {
      throw new Error(execErr);
    } else {
      flags = result.match(/\s\s--(\w+)/gm).map(function (match) {
        return match.substring(2);
      });
      fs.writeFile(tmpfile, JSON.stringify(flags), { encoding:'utf8' },
        function (writeErr) {
          if (writeErr) {
            throw new Error(writeErr);
          } else {
            console.log('flags for v8 '+version+' cached.');
          }
        }
      );
    }
  });
}

module.exports = require.bind(null, tmpfile);

const fs = require('fs');
const path = require('path');

const exec = require('child_process').exec;
const nodePath = process.execPath;
const version = process.versions.v8;
const tmpfile = path.join(__dirname, version+'.flags.json');

if (!fs.existsSync(tmpfile)) {
  exec('"'+nodePath+'" --v8-options', function (execErr, result) {
    var flags;
    if (execErr) {
      throw new Error(execErr);
    } else {
      flags = result.match(/\s\s--(\w+)/gm).map(function (match) {
        return match.substring(2);
      });
      fs.writeFile(tmpfile, JSON.stringify(flags), { encoding:'utf8' },
        function (writeErr) {
          if (writeErr) {
            throw new Error(writeErr);
          } else {
            console.log('flags for v8 '+version+' cached.');
          }
        }
      );
    }
  });
}

module.exports = require.bind(null, tmpfile);

Use process.execPath to find node executable on Windows


const {
    assemble,
    writeFile,
    unicodeVersion
} = require('./utils.js');

const properties = [
    'ASCII',
    'Alphabetic',
    'Any',
    'Default_Ignorable_Code_Point',
    'Lowercase',
    'Noncharacter_Code_Point',
    'Uppercase',
    'White_Space'
];

const result = [];
for (const property of properties) {
    const codePoints = require(`${unicodeVersion}/Binary_Property/${property}/code-points.js`);
    result.push(assemble({
        name: property,
        codePoints
    }));
}
writeFile('properties.js', result);

const {
    assemble,
    writeFile,
    unicodeVersion
} = require('./utils.js');

// This intentially includes only the binary properties required by UTS 18 Level 1 RL1.2 for Unicode
// regex support, minus `Assigned` which has special handling since it is the inverse of Unicode
// category `Unassigned` (`Cn`). To include all binary properties, change this to:
// `const properties = require(`${unicodeVersion}`).Binary_Property;`
const properties = [
    'ASCII',
    'Alphabetic',
    'Any',
    'Default_Ignorable_Code_Point',
    'Lowercase',
    'Noncharacter_Code_Point',
    'Uppercase',
    'White_Space'
];

const result = [];
for (const property of properties) {
    const codePoints = require(`${unicodeVersion}/Binary_Property/${property}/code-points.js`);
    result.push(assemble({
        name: property,
        codePoints
    }));
}
writeFile('properties.js', result);

Add comment about level 1 Unicode properties


/**
 * Module dependencies.
 */

var express       = require('express'),
    expressHogan  = require('express-hogan.js'),
    mongoose      = require('mongoose'),
    nodemailer    = require('nodemailer');

// Connect to the default database
mongoose.connect('mongodb://localhost/all');

var app = module.exports = express.createServer();

// Configuration

app.configure(function(){
  app.set('views', __dirname + '/views');
  app.register('.txt',  expressHogan);
  app.register('.html', expressHogan);
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
  app.use(express.logger({ format: ':method :status :url' }));
});

app.configure('production', function(){
  app.use(express.errorHandler());
});

app.nodemailer_transport = nodemailer.createTransport("Sendmail");

// Routes
require('./routes').route(app);

app.listen(3000);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);

/**
 * Module dependencies.
 */

var express       = require('express'),
    expressHogan  = require('express-hogan.js'),
    mongoose      = require('mongoose'),
    nodemailer    = require('nodemailer');

// Connect to the default database
mongoose.connect('mongodb://localhost/all');

var app = module.exports = express.createServer();

// Configuration

app.configure(function(){
  app.use(express.logger('dev'));
  app.set('views', __dirname + '/views');
  app.register('.txt',  expressHogan);
  app.register('.html', expressHogan);
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  app.use(express.errorHandler());
});

app.nodemailer_transport = nodemailer.createTransport("Sendmail");

// Routes
require('./routes').route(app);

app.listen(3000);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);

Add logging to all requests (needed to be at start of configure, perhaps a template rendering issue?)


var pagination = require('hexo-pagination');
var _ = require('lodash');

hexo.extend.generator.register('category', function(locals){
  var config = this.config;
  var categories = locals.data.categories;
  if (config.category_generator) {
    var perPage = config.category_generator.per_page;
  } else {
    var perPage = 10;
  }
  var paginationDir = config.pagination_dir || 'page';
  var result = [];

  _.each(categories, function(data, title) {
    _.each(data, function(data, lang) {
      result = result.concat(
        pagination(lang + '/' + data.slug, getCategoryByName(locals.categories, data.category).posts, {
          perPage: perPage,
          layout: ['category', 'archive', 'index'],
          format: paginationDir + '/%d/',
          data: {
            lang: lang,
            title: data.name,
            category: data.category
          }
        })
      );
    });
  });

  return result;
});

function getCategoryByName(categories, name) {
  return categories.toArray().filter(function(category){
    return category.name == name;
  })[0];
}

var pagination = require('hexo-pagination');
var _ = require('lodash');

hexo.extend.generator.register('category', function(locals){
  var config = this.config;
  var categories = locals.data.categories;
  if (config.category_generator) {
    var perPage = config.category_generator.per_page;
  } else {
    var perPage = 10;
  }
  var paginationDir = config.pagination_dir || 'page';
  var result = [];

  _.each(categories, function(category, title) {
    _.each(category, function(data, lang) {
      result = result.concat(
        pagination(lang + '/' + data.slug, getCategoryByName(locals.categories, data.category).posts, {
          perPage: perPage,
          layout: ['category', 'archive', 'index'],
          format: paginationDir + '/%d/',
          data: {
            lang: lang,
            title: data.name,
            category: data.category,
            alternates: getAlternateLangs(category, lang)
          }
        })
      );
    });
  });

  return result;
});

function getCategoryByName(categories, name) {
  return categories.toArray().filter(function(category){
    return category.name == name;
  })[0];
}

function getAlternateLangs(category, currentLang) {
  var result = [];
  _.each(category, function(data, lang) {
    if (currentLang != lang) {
      result.push({
        lang: lang,
        path: lang + '/' + data.slug
      });
    }
  });
  return result;
}

Add alternate language categories in generator


/**
 * DefaultKeystoneConfiguration contains the default settings for keystone.
 * @class DefaultKeystoneConfiguration
 * @param {Theme} theme
 * @constructor
 *
 */
module.exports = function DefaultKeystoneConfiguration(theme) {

	return {

		'name': process.env.DOMAIN || 'Estore',
		'brand': process.env.DOMAIN || 'Estore',
		'auto update': process.env.KEYSTONE_AUTO_UPDATE || true,
		'session': true,
		'session store': 'mongo',
		'auth': true,
		'cookie secret': process.env.COOKIE_SECRET,
		'view engine': 'html',
		'views': theme.getTemplatePath(),
		'static': theme.getStaticPath(),
		'emails': theme.getEmailPath(),
		'port': process.env.PORT || 3000,
		'mongo': process.env.MONGO_URI,
	};

};

/**
 * DefaultKeystoneConfiguration contains the default settings for keystone.
 * @class DefaultKeystoneConfiguration
 * @param {Theme} theme
 * @constructor
 *
 */
module.exports = function DefaultKeystoneConfiguration(theme) {
	return {

		'name': process.env.DOMAIN || 'Estore',
		'brand': process.env.DOMAIN || 'Estore',
		'auto update': (process.env.KEYSTONE_AUTO_UPDATE === true) ? true : false,
		'session': true,
		'session store': 'mongo',
		'auth': true,
		'cookie secret': process.env.COOKIE_SECRET,
		'view engine': 'html',
		'views': theme.getTemplatePath(),
		'static': theme.getStaticPath(),
		'emails': theme.getEmailPath(),
		'port': process.env.PORT || 3000,
		'mongo': process.env.MONGO_URI,
	};

};

Use an explicit check for auto update override.


global.Promise = require('bluebird')
global.Promise.onPossiblyUnhandledRejection((e) => { throw e; });

global.Promise.config({
  // Enable warnings.
  warnings: false,
  // Enable long stack traces.
  longStackTraces: true,
  // Enable cancellation.
  cancellation: true
});

// First require your DOM emulation file (see below)
require('./emulateDom.js');

import db_config from '../knexfile';

let exec_env = process.env.DB_ENV || 'test';
global.$dbConfig = db_config[exec_env];

process.env.NODE_ENV = 'test';

Use bluebird for debuggable promises in tests


'use strict';

var request = require('request');

var opts = {
    uri: 'https://api.github.com' + '/users/' + parseParams(process.argv[2]) + '/events',
    json: true,
    method: 'GET',
    headers: {
        'User-Agent': 'nodejs script'
    }
}

request(opts, function (err, res, body) {
    if (err) throw new Error(err);

    var format = '[%s]: %s %s %s %s';

    for (var i = 0; i < body.length; i++) {
        /*
         * TODO return something like this as JSON
         * for caller consumption (useful for servers).
         */
        console.log(format
            , body[i].created_at
            , body[i].type
            , body[i].actor.login
            , body[i].repo.name);
    }
});

function parseParams(params) {
    if (! params) {
        console.log('Usage: nodejs gevents.js <user-name>');
        process.exit(0);
    }
    return params;
}

'use strict';

var request = require('request');

var opts = {
    uri: 'https://api.github.com' + '/users/' + parseParams(process.argv[2]) + '/events',
    json: true,
    method: 'GET',
    headers: {
        'User-Agent': 'nodejs script'
    }
}

request(opts, function (err, res, body) {
    if (err) throw new Error(err);

    var format = '[%s]: %s %s %s %s';

    for (var i = 0; i < body.length; i++) {
        /*
         * TODO return something like this as JSON
         * for caller consumption (useful for servers).
         */
        console.log(format
            , body[i].created_at
            , body[i].type
            , body[i].actor.login
            , body[i].repo.name);
    }
});

/*
 * Verify param is present, and just return it.
 * TODO
 *   Check for multiple params, and check validity
 *   as well as presence.
 */
function parseParams(params) {
    if (! params) {
        console.log('Usage: nodejs gevents.js <user-name>');
        process.exit(0);
    }
    return params;
}

Add explanatory and TODO notes


'use strict';

var _        = require('lodash');
var bluebird = require('bluebird');
var fs       = bluebird.promisifyAll(require('fs'));
var glob     = require('glob');
var hljs     = require('../../build');
var path     = require('path');
var utility  = require('../utility');

function testLanguage(language) {
  describe(language, function() {
    var filePath  = utility.buildPath('markup', language, '*.expect.txt'),
        filenames = glob.sync(filePath);

    _.each(filenames, function(filename) {
      var testName   = path.basename(filename, '.expect.txt'),
          sourceName = filename.replace(/\.expect/, '');

      it(`should markup ${testName}`, function(done) {
        var sourceFile   = fs.readFileAsync(sourceName, 'utf-8'),
            expectedFile = fs.readFileAsync(filename, 'utf-8');

        bluebird.join(sourceFile, expectedFile, function(source, expected) {
          var actual = hljs.highlight(language, source).value;

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

describe('hljs.highlight()', function() {
  var languages = fs.readdirSync(utility.buildPath('markup'));

  _.each(languages, testLanguage, this);
});

'use strict';

var _        = require('lodash');
var bluebird = require('bluebird');
var fs       = bluebird.promisifyAll(require('fs'));
var glob     = require('glob');
var hljs     = require('../../build');
var path     = require('path');
var utility  = require('../utility');

function testLanguage(language) {
  describe(language, function() {
    var filePath  = utility.buildPath('markup', language, '*.expect.txt'),
        filenames = glob.sync(filePath);

    _.each(filenames, function(filename) {
      var testName   = path.basename(filename, '.expect.txt'),
          sourceName = filename.replace(/\.expect/, '');

      it(`should markup ${testName}`, function(done) {
        var sourceFile   = fs.readFileAsync(sourceName, 'utf-8'),
            expectedFile = fs.readFileAsync(filename, 'utf-8');

        bluebird.join(sourceFile, expectedFile, function(source, expected) {
          var actual = hljs.highlight(language, source).value;

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

describe('hljs.highlight()', function() {
  var markupPath = utility.buildPath('markup');

  return fs.readdirAsync(markupPath).each(testLanguage);
});

Change synchronous readdir to a promise


var assert = buster.referee.assert;

buster.testCase("Call onerror", {

  setUp: function () {
    $ = {};
    $.post = this.spy();

    initErrorHandler("/error", "localhost");
  },

  "exception within the system": function () {
    window.onerror('error message', 'http://localhost/test.js', 11);
    assert.isTrue($.post.called);
  },

  "error within the system": function (done) {

    setTimeout(function() {
      // throw some real-life exception
      not_defined.not_defined();
    }, 10);

    setTimeout(function() {
      assert.isTrue($.post.called);
      done();
    }, 100);
  },

  "error outside the system": function() {
    window.onerror('error message', 'http://example.com/test.js', 11);
    assert.isFalse($.post.called);
  },

  "error from unknown source": function() {
    window.onerror('error message', 'http://localhost/foo', 11);
    assert.isFalse($.post.called);
  }
});

var assert = buster.referee.assert;
var hostname = location.hostname;

buster.testCase("Call onerror", {

  setUp: function () {
    $ = {};
    $.post = this.spy();

    initErrorHandler("/error", hostname);
  },

  "exception within the system": function () {
    window.onerror('error message', 'http://' + hostname + '/test.js', 11);
    assert.isTrue($.post.called);
  },

  "error within the system": function (done) {

    setTimeout(function() {
      // throw some real-life exception
      not_defined.not_defined();
    }, 10);

    setTimeout(function() {
      assert.isTrue($.post.called);
      done();
    }, 100);
  },

  "error outside the system": function() {
    window.onerror('error message', 'http://example.com/test.js', 11);
    assert.isFalse($.post.called);
  },

  "error from unknown source": function() {
    window.onerror('error message', 'http://' + hostname + '/foo', 11);
    assert.isFalse($.post.called);
  }
});

Make the tests work for remote test clients.


console.log(this) //contexto global
console.log(this === window) //true

var developer = {
  name : 'Erik',
  lastName : 'Ochoa',
  isAdult : true,
  completeName: function(){
    return this.name + this.lastName
  }
}

console.log(developer.name) // Erik
console.log(developer.lastName) // Ochoa
console.log(developer.isAdult) // true
//We call a function that is stored as a property of an object becoming a method
console.log(developer.completeName()) // ErikOchoa

console.log(this) //contexto global
console.log(this === window) //true

var developer = {
  name : 'Erik',
  lastName : 'Ochoa',
  isAdult : true,
  get completeName() {
    return this.name + this.lastName
  }
}

console.log(developer.name) // Erik
console.log(developer.lastName) // Ochoa
console.log(developer.isAdult) // true
console.log(developer.completeName) // ErikOchoa

Use getter to call completeName as a property


describe('Prerequisites', () => {
  describe('Call the same resource with both http client and iframe', () => {
      it('http headers should be less or equal than iframe ones', () => {
        browser.url('/');
        browser.leftClick('.httpCall');
        browser.waitForExist('.detail_headers');
        browser.waitForExist('.detail_body');

        const httpHeadersCount = Object.keys(browser.elements('.detail_headers').value).length;
        const httpBodyCount = Object.keys(browser.elements('.detail_body').value).length;

        browser.leftClick('.iframeCall');
        browser.waitForExist('.detail_headers');
        browser.waitForExist('.detail_body');

        const iframeHeadersCount = Object.keys(browser.elements('.detail_headers').value).length;
        const iframeBodyCount = Object.keys(browser.elements('.detail_body').value).length;

        expect(iframeHeadersCount).toBeGreaterThanOrEqual(httpHeadersCount);
        expect(iframeBodyCount).toBeGreaterThanOrEqual(httpBodyCount);

      });
  })
});

describe('Prerequisites', () => {
  describe('Call the same resource with both http client and iframe', () => {
      it('http headers should be less or equal than iframe ones', () => {
        browser.url('/');
        browser.leftClick('.httpCall');
        browser.waitForExist('.detail_headers');
        browser.waitForExist('.detail_body');

        const httpHeadersCount = Object.keys(browser.elements('.detail_headers').value).length;
        const httpBodyCount = Object.keys(browser.elements('.detail_body').value).length;

        browser.refresh();
        browser.leftClick('.iframeCall');
        browser.waitForExist('.detail_headers');
        browser.waitForExist('.detail_body');

        const iframeHeadersCount = Object.keys(browser.elements('.detail_headers').value).length;
        const iframeBodyCount = Object.keys(browser.elements('.detail_body').value).length;

        expect(iframeHeadersCount).toBeGreaterThanOrEqual(httpHeadersCount);
        expect(iframeBodyCount).toBeGreaterThanOrEqual(httpBodyCount);

      });
  })
});

Refresh the page between a test and another


const Alfred = require('../index');
const Builder = Alfred.Builder;

const bot = new Alfred();

bot.login('username', 'password')
    .then(() => bot.send('servernotifyregister', { 'event': 'server' }))
    .then(() => bot.send('servernotifyregister', { 'event': 'textprivate' }))
    .then(() => console.log('Connected with clid', bot.get('clid')))
    .catch(console.error);

bot.use(Alfred.User);

bot.on('cliententerview', data => console.log(data.user.get('name'), 'connected', '[db:' + data.user.get('dbid') + ']'));

bot.on('clientleftview', data => console.log(data.user.get('name'), 'disconnected'));

bot.on('textmessage', data => {
    let msg = "" + data.msg;
    console.log(JSON.stringify(data));
    if (msg.startsWith("!exit")) {
        bot.disconnect();
        console.log("disconnected");
    }
    if (msg.startsWith("!kickserver")) {
        data.user.serverKick(Builder.underline("Bye from the server!"));
    }
    if (msg.startsWith("!kickchannel")) {
        data.user.channelKick(Builder.italic("bye have great day!"));
    }
});

Add new line at the end of test files


/*
 * Command to handle APS events
 */
Ape.registerCmd("event", true, function(params, info) {

	if(params.multi){
		var recipient = Ape.getChannelByPubid(params.pipe);
	}else{
		var recipient = Ape.getUserByPubid(params.pipe);
	}

	if(recipient){

		if(!!params.sync){
			info.sendResponse("SYNC", {
				data: params.data,
				event: params.event,
				chanid: params.pipe
			});
		}

		delete params.sync;

		recipient.sendEvent(params, {from: info.user.pipe});
	}

	return 1;
});

/*
 * Command to handle APS events
 */
Ape.registerCmd("event", true, function(params, info) {

	if(params.multi){
		var recipient = Ape.getChannelByPubid(params.pipe);
	}else{
		var recipient = Ape.getUserByPubid(params.pipe);
	}

	if(recipient){

		if(!!params.sync){
			info.sendResponse("SYNC", {
				data: params.data,
				event: params.event,
				chanid: params.pipe
			});
		}

		delete params.sync;

		recipient.sendEvent(params, {from: info.user.pipe});

		return 1;
	}

	return ["425", "UNKNOWN_RECIPIENT"];

});

Send error 425 if the recipient of an event is not found


const logger = require('../logging');
const passport = require('passport');
const { setupOIDC } = require('./oidc');

const getUserById = require('../models/user.accessors').getUserById;

require('./providers/ow4.js');

module.exports = async (app) => {
  passport.serializeUser((user, done) => {
    logger.silly('Serializing user', { userId: user.id });
    done(null, user.id);
  });

  passport.deserializeUser((id, done) => {
    logger.silly('Deserializing user', { userId: id });
    done(null, () => getUserById(id));
  });
  app.use(passport.initialize());
  app.use(passport.session());
  app.get('/login', passport.authenticate('oauth2', { successReturnToOrRedirect: '/' }));
  app.get('/logout', (req, res) => {
    req.logout();
    res.redirect('/');
  });
  app.get('/auth', passport.authenticate('oauth2', { callback: true }), (req, res) => {
    res.redirect('/');
  });
  if (process.env.SDF_OIDC && process.env.SDF_OIDC.toLowerCase() === 'true') {
    const success = await setupOIDC();
    if (success) {
      app.get('/openid-login', passport.authenticate('oidc'));
      app.get('/openid-auth', passport.authenticate('oidc', { successRedirect: '/', failureRedirect: '/openid-login' }));
    }
    return app;
  }
  return app;
};

const logger = require('../logging');
const passport = require('passport');
const { setupOIDC } = require('./oidc');

const getUserById = require('../models/user.accessors').getUserById;

require('./providers/ow4.js');

module.exports = async (app) => {
  await setupOIDC();

  passport.serializeUser((user, done) => {
    logger.silly('Serializing user', { userId: user.id });
    done(null, user.id);
  });

  passport.deserializeUser((id, done) => {
    logger.silly('Deserializing user', { userId: id });
    done(null, () => getUserById(id));
  });
  app.use(passport.initialize());
  app.use(passport.session());
  app.get('/login', passport.authenticate('oidc'));
  app.get('/logout', (req, res) => {
    req.logout();
    res.redirect('/');
  });
  app.get('/auth', passport.authenticate('oidc', { successRedirect: '/', failureRedirect: '/openid-login' }));
  return app;
};

Make OIDC be default auth mechanism


exports.AgGridAurelia = require('./lib/agGridAurelia').AgGridAurelia;
exports.AgGridColumn = require('./lib/agGridColumn').AgGridColumn;
exports.AgCellTemplate = require('./lib/agTemplate').AgCellTemplate;
exports.AgEditorTemplate = require('./lib/agTemplate').AgEditorTemplate;
exports.AgFilterTemplate = require('./lib/agTemplate').AgFilterTemplate;
exports.AureliaCellRendererComponent = require('./lib/aureliaCellRendererComponent').AureliaCellRendererComponent;
exports.AureliaComponentFactory = require('./lib/aureliaComponentFactory').AureliaComponentFactory;
exports.AureliaFrameworkFactory = require('./lib/aureliaFrameworkFactory').AureliaFrameworkFactory;
exports.BaseAureliaEditor = require('./lib/editorViewModels').BaseAureliaEditor;

function configure(config) {
    config.globalResources(
      './lib/agGridAurelia',
      './lib/agGridColumn',
      './lib/agTemplate'
    );
}

exports.configure = configure;

exports.AgGridAurelia = require('./lib/agGridAurelia').AgGridAurelia;
exports.AgGridColumn = require('./lib/agGridColumn').AgGridColumn;
exports.AgCellTemplate = require('./lib/agTemplate').AgCellTemplate;
exports.AgEditorTemplate = require('./lib/agTemplate').AgEditorTemplate;
exports.AgFullWidthRowTemplate = require('./lib/agTemplate').AgFullWidthRowTemplate;
exports.AgFilterTemplate = require('./lib/agTemplate').AgFilterTemplate;
exports.AureliaCellRendererComponent = require('./lib/aureliaCellRendererComponent').AureliaCellRendererComponent;
exports.AureliaComponentFactory = require('./lib/aureliaComponentFactory').AureliaComponentFactory;
exports.AureliaFrameworkFactory = require('./lib/aureliaFrameworkFactory').AureliaFrameworkFactory;
exports.BaseAureliaEditor = require('./lib/editorViewModels').BaseAureliaEditor;

function configure(config) {
    config.globalResources(
      './lib/agGridAurelia',
      './lib/agGridColumn',
      './lib/agTemplate'
    );
}

exports.configure = configure;

Add FullWidth row template to exports