<commit_before>'use strict';
const fs = require('fs.extra');
const electron = require('electron');
const tableify = require('tableify');
const {dialog} = require('electron');
const LineByLineReader = require('line-by-line');

const JSONParsed = [];
const app = electron.app;
let loadFile;
let win;
// adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')();
// prevent window being garbage collected
let mainWindow;
function createMainWindow() {
	win = new electron.BrowserWindow({
		width: 600,
		height: 400
	});

	win.on('closed', onClosed);

// menu functions be here
}
function onClosed() {
// dereference the window
// for multiple windows store them in an array
	mainWindow = null;
}
function funcLoad() {
	loadFile = dialog.showOpenDialog({properties: ['openFile']});
	if (/\.[log]+$/i.test(loadFile) === true) {
		fs.writeFile(`${process.resourcesPath}/index2.html`, '', err => {
			if (err) {
				return console.log(err);
			}
		});
		readLine();
		win.loadURL(`file:///${loadFile}`);
	} else {
		console.log('Please load a .log file.');
	}
}
function readLine() {
	const loadPls = loadFile;
	const lr = new LineByLineReader(loadPls[0]);

	lr.on('error', err => {
		return console.log(err);
	});

	lr.on('line', line => {
		const lineParse = JSON.parse(line);
		JSONParsed.push(lineParse);
// console.log(JSONParsed);
		const html = tableify(lineParse) + '
';
		fs.appendFile(`${process.resourcesPath}/index2.html`, html, err => {
			if (err) {
				return console.log(err);
			}
		});
	});
	fs.appendFile(`${process.resourcesPath}/index2.html`, '<link href="https://fonts.googleapis.com/css?family=Lato:400,400italic,700" rel="stylesheet" type="text/css">', err => {
		if (err) {
			return console.log(err);
		}
	});
	lr.on('end', () => {
		console.log('done!');
		console.log('The file was saved!');
		win.loadURL(`file://${process.resourcesPath}/index2.html`);
	});
	return win;
}

function funcSave() {
	dialog.showSaveDialog(fileName => {
		if (fileName === undefined) {
			console.log('You didn\'t save the file');
			return;
		}
// fileName is a string that contains the path and filename created in the save file dialog.
		fs.copy(`${process.resourcesPath}/index2.html`, fileName, err => {
			if (err) {
				console.log(err.message);
			}
		});
	}
);
}
function funcSaveJSON() {
	dialog.showSaveDialog(fileName => {
		if (fileName === undefined) {
			console.log('You didn\'t save the file');
			return;
		}
		const JSONParsedSave = JSON.stringify(JSONParsed);
		fs.writeFile(fileName, JSONParsedSave, err => {
			if (err) {
				console.log(err.message);
			}
		});
	});
}
app.on('window-all-closed', () => {
	if (process.platform !== 'darwin') {
		app.quit();
	}
	fs.writeFile(`${process.resourcesPath}/index2.html`, '', err => {
		if (err) {
			return console.log(err);
		}
	});
});
app.on('activate', () => {
	if (!mainWindow) {
		mainWindow = createMainWindow();
	}
});

app.on('ready', () => {
	mainWindow = createMainWindow();
});

const {Menu} = require('electron');

const template = [
	{
		label: 'File',
		submenu: [
	{label: 'Save as HTML', click: funcSave},
	{label: 'Save as JSON', click: funcSaveJSON},
	{label: 'Load', click: funcLoad}

		]
	},
	{
		label: 'Edit',
		submenu: [
			{
				role: 'selectall'
			}
		]
	},
	{
		label: 'View',
		submenu: [
			{
				label: 'Reload',
				accelerator: 'CmdOrCtrl+R',
				click(item, focusedWindow) {
					if (focusedWindow) {
						focusedWindow.reload();
					}
				}
			},
			{
				role: 'togglefullscreen'
			}
		]
	},
	{
		role: 'window',
		submenu: [
			{
				role: 'minimize'
			},
			{
				role: 'close'
			}
		]
	},
	{
		role: 'help',
		submenu: [
			{
				label: 'Learn More',
				click() {
					require('electron').shell.openExternal('http://electron.atom.io');
				}
			}
		]
	}
];

if (process.platform === 'darwin') {
	const name = require('electron').remote.app.getName();

	template.unshift({
		label: name,
		submenu: [
			{
				role: 'about'
			},
			{
				type: 'separator'
			},
			{
				role: 'services',
				submenu: []
			},
			{
				type: 'separator'
			},
			{
				role: 'hide'
			},
			{
				role: 'hideothers'
			},
			{
				role: 'unhide'
			},
			{
				type: 'separator'
			},
			{
				role: 'quit'
			}
		]
	});
// Edit menu.
	template[1].submenu.push(
		{
			type: 'separator'
		},
		{
			label: 'Speech',
			submenu: [
				{
					role: 'startspeaking'
				},
				{
					role: 'stopspeaking'
				}
			]
		}
);
// Window menu.
	template[3].submenu = [
		{
			label: 'Close',
			accelerator: 'CmdOrCtrl+W',
			role: 'close'
		},
		{
			label: 'Minimize',
			accelerator: 'CmdOrCtrl+M',
			role: 'minimize'
		},
		{
			label: 'Zoom',
			role: 'zoom'
		},
		{
			type: 'separator'
		},
		{
			label: 'Bring All to Front',
			role: 'front'
		}
	];
}

const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
<commit_msg>literally all the things have been done, check out the actual commit for what happened<commit_after>'use strict';
const path = require('path');
const os = require('os');
const fs = require('fs.extra');
const electron = require('electron');
const tableify = require('tableify');
const {dialog} = require('electron');
const LineByLineReader = require('line-by-line');

const JSONParsed = [];
const logPath = path.join(os.homedir(), 'Saved Games', 'Frontier Developments', 'Elite Dangerous');
const app = electron.app;
let loadFile;
let win; // eslint-disable-line no-var
let htmlDone; // eslint-disable-line no-unused-vars
const css = '<link href="https://fonts.googleapis.com/css?family=Lato:400,400italic,700" rel="stylesheet" type="text/css">';
// adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')();
// prevent window being garbage collected
let mainWindow;
function createMainWindow() {
	win = new electron.BrowserWindow({
		width: 600,
		height: 400
	});

	win.on('closed', onClosed);

// menu functions be here
}
function onClosed() {
// dereference the window
// for multiple windows store them in an array
	mainWindow = null;
}
function funcLoad() {
	loadFile = dialog.showOpenDialog({properties: ['openFile',
		{defaultPath: logPath}]});
	if (/\.[log]+$/i.test(loadFile) === true) {
		fs.writeFile(`${process.resourcesPath}/index2.html`, '', err => {
			if (err) {
				return console.log(err);
			}
		});
		readLine();
		win.loadURL(`file:///${loadFile}`);
	} else {
		console.log('Please load a .log file.');
	}
}
function readLine() {
	const loadPls = loadFile;
	const lr = new LineByLineReader(loadPls[0]);

	lr.on('error', err => {
		return console.log(err);
	});

	lr.on('line', line => {
		const lineParse = JSON.parse(line);
		JSONParsed.push(lineParse);
		const html = tableify(lineParse) + '
';
		fs.appendFile(`${process.resourcesPath}/index2.html`, html, err => {
			if (err) {
				return console.log(err);
			}
		});
	});
	fs.appendFile(`${process.resourcesPath}/index2.html`, '<link href="https://fonts.googleapis.com/css?family=Lato:400,400italic,700" rel="stylesheet" type="text/css">', err => {
		if (err) {
			return console.log(err);
		}
	});
	lr.on('end', () => {
		console.log('done!');
		console.log('The file was saved!');
		win.loadURL(`file://${process.resourcesPath}/index2.html`);
		// win.loadURL(`file://${process.resourcesPath}/index2.html`);
	});
	return win;
}
// function readLineMemory(converted) {
// 	// var html = '';
// 	loadFile = dialog.showOpenDialog({properties: ['openFile']});
// 	console.log(loadFile);
// 	var lr = new LineByLineReader(loadFile[0]);
// 	lr.on('error', err => {
// 		return console.log(err);
// 	});
// 	lr.on('line', function (line) {
// 		const lineParse = JSON.parse(line);
// 		JSONParsed.push(lineParse);
// 		var htmlTabled = tableify(lineParse) + '
';
// 		html = html + htmlTabled;
// 	});
// 	lr.on('end', function () {
// 		html = 'data:text/html,' + html;
// 	});
// 	converted = html;
// }
// function lineMem(converted) {
// 	var html;
// 	loadFile = dialog.showOpenDialog({properties: ['openFile']});
// 	// console.log(loadFile);
// 	var lr = new LineByLineReader(loadFile[0]);
// 	lr.on('error', err => {
// 		return console.log(err);
// 	});
// 	lr.on('line', function (line) {
// 		let lineParse = JSON.parse(line);
// 		JSONParsed.push(lineParse);
// 		let htmlTabled = tableify(lineParse) + '
';
// 		html = html + htmlTabled;
// 		process.htmlDone += html;
// 	});
// 	lr.on('end', function () {
// 		process.htmlDone = html;
// 	});
// }
// function test() {
// 	var willy = (lineMem(vampire));
// 	console.log(process.htmlDone);
// 	win.loadURL('data:text/html,' + encodeURIComponent(process.htmlDone));
// }
function funcSave() {
	dialog.showSaveDialog(fileName => {
		if (fileName === undefined) {
			console.log('You didn\'t save the file');
			return;
		}
// fileName is a string that contains the path and filename created in the save file dialog.
		fs.copy(`${process.resourcesPath}/index2.html`, fileName, err => {
			if (err) {
				console.log(err.message);
			}
		});
	}
);
}
function funcSaveJSON() {
	dialog.showSaveDialog(fileName => {
		if (fileName === undefined) {
			console.log('You didn\'t save the file');
			return;
		}
		const JSONParsedSave = JSON.stringify(JSONParsed);
		fs.writeFile(fileName, JSONParsedSave, err => {
			if (err) {
				console.log(err.message);
			}
		});
	});
}
app.on('window-all-closed', () => {
	if (process.platform !== 'darwin') {
		app.quit();
	}
	fs.writeFile(`${process.resourcesPath}/index2.html`, '', err => {
		if (err) {
			return console.log(err);
		}
	});
});
app.on('activate', () => {
	if (!mainWindow) {
		mainWindow = createMainWindow();
	}
});

app.on('ready', () => {
	mainWindow = createMainWindow();
});

const {Menu} = require('electron');

const template = [
	{
		label: 'File',
		submenu: [
	{label: 'Save as HTML', click: funcSave},
	{label: 'Save as JSON', click: funcSaveJSON},
	{label: 'Load', click: funcLoad},
	{label: 'Load log(alternate)', click() {
		let html;
		loadFile = dialog.showOpenDialog({properties: ['openFile']});
	// console.log(loadFile);
		const lr = new LineByLineReader(loadFile[0]);
		lr.on('error', err => {
			return console.log(err);
		});
		lr.on('line', function (line) { // eslint-disable-line prefer-arrow-callback
			let lineParse = JSON.parse(line); // eslint-disable-line prefer-const
			JSONParsed.push(lineParse);
			let htmlTabled = tableify(lineParse) + '
';  // eslint-disable-line prefer-const
			html += htmlTabled;
		});
		lr.on('end', err => {
			if (err) {
				console.log(err.message);
			}
			process.htmlDone = html;
			win.loadURL('data:text/html,' + css + process.htmlDone);
		});
	}}

		]
	},
	{
		label: 'Edit',
		submenu: [
			{
				role: 'selectall'
			}
		]
	},
	{
		label: 'View',
		submenu: [
			{
				label: 'Reload',
				accelerator: 'CmdOrCtrl+R',
				click(item, focusedWindow) {
					if (focusedWindow) {
						focusedWindow.reload();
					}
				}
			},
			{
				role: 'togglefullscreen'
			}
		]
	},
	{
		role: 'window',
		submenu: [
			{
				role: 'minimize'
			},
			{
				role: 'close'
			}
		]
	},
	{
		role: 'help',
		submenu: [
			{
				label: 'Learn More',
				click() {
					require('electron').shell.openExternal('http://electron.atom.io');
				}
			}
		]
	}
];

if (process.platform === 'darwin') {
	const name = require('electron').remote.app.getName();

	template.unshift({
		label: name,
		submenu: [
			{
				role: 'about'
			},
			{
				type: 'separator'
			},
			{
				role: 'services',
				submenu: []
			},
			{
				type: 'separator'
			},
			{
				role: 'hide'
			},
			{
				role: 'hideothers'
			},
			{
				role: 'unhide'
			},
			{
				type: 'separator'
			},
			{
				role: 'quit'
			}
		]
	});
// Edit menu.
	template[1].submenu.push(
		{
			type: 'separator'
		},
		{
			label: 'Speech',
			submenu: [
				{
					role: 'startspeaking'
				},
				{
					role: 'stopspeaking'
				}
			]
		}
);
// Window menu.
	template[3].submenu = [
		{
			label: 'Close',
			accelerator: 'CmdOrCtrl+W',
			role: 'close'
		},
		{
			label: 'Minimize',
			accelerator: 'CmdOrCtrl+M',
			role: 'minimize'
		},
		{
			label: 'Zoom',
			role: 'zoom'
		},
		{
			type: 'separator'
		},
		{
			label: 'Bring All to Front',
			role: 'front'
		}
	];
}

const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
<|endoftext|>


<commit_before>"use strict";

// require('sterno')('http://assets.mysite.com', ['/app.js', '/app.css']);
var LocalFileSystem = LocalFileSystem || {},
    cordova = cordova || {};

// Async helper.  Like async.parallel.  Calls done on first non null error
// or when all tasks completed.
function parallel(tasks, done){
    var remaining = tasks.length,
        resolved = false;

    tasks.map(function(task){
        task(function(err, res){
            if(!resolved){
                if(err){
                    resolved = true;
                    return done(err);
                }
                remaining--;
                if(remaining === 0){
                    done();
                }
            }
        });
    });
}

// XHR fetch asset.
function fetch(url, done){
    if(!process.env || process.env.environment === 'development'){
        url += '?bust' + Math.random();
    }

    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onload = function(e) {
        if (e.target.status !== 200) {
            return done(new Error('wtf?: ' + e.target.status));
        }
        return done(null, e);
    };
    xhr.onerror = function(){
        done(new Error('XHR error'));
    };
    xhr.send();
}

// Usage:
// require('bootstrap-loader')(process.env.url, {'js': '/app.js'});
module.exports = function(url, assets, done){
    return new Loader(url, assets).load(done);
};

//Map of assetType to function to drop it on the dom.
var append = {
    'js': function(src){
        var el = document.createElement('script');
        el.type = 'text/javascript';
        if(src.indexOf('file://') === 0){
            el.src = src;
        }
        else {
            el.innerHTML = src; // Blob
        }
        document.head.appendChild(el);
        return el;
    },
    'css': function(src){
        var el;
        if(src.indexOf('file://') === 0){
            el = document.createElement('link');
            el.rel = 'stylesheet';
            el.type = 'text/css';
            el.href = src;
        }
        else {
            el = document.createElement('style');
            el.type = 'text/css';
            el.innerHTML = src; // Blob
        }
        document.head.appendChild(el);
        return el;
    }
};

// url: The base url for assets
// assets: map of {js: [], 'css': []}
// bootstrapPath: Where bootstrap data can be found.
function Loader(url, assets, bootstrapPath){
    this.url = url;
    this.assets = assets;
    this.bootstrapPath = (bootstrapPath ? url + bootstrapPath : url + '/sterno-bootstrap.json');
    this.versions = {};
    this.appVersion = localStorage.getItem('appVersion');

    this.localVersions = {}; // Gets lazy loaded from localstorage

    this.incomingVersion = {};
    this.version = {};
    if(this.appVersion){
        this.version = this.parseVersion(this.appVersion);
    }

}

Loader.prototype.hasChanged = function(src){
    if(!this.localVersions[src]){
        this.localVersions[src] = localStorage.getItem('versions_' + src);
    }

    if(!this.localVersions[src]){
        return true;
    }

    return this.versions[src] !== this.localVersions[src];
};

Loader.prototype.shouldUpgradeAsset = function(src){
    if(!navigator.onLine || !this.hasChanged(src)){
        return false;
    }

    return (this.incomingVersion.major === this.version.major && this.incomingVersion.minor === this.version.minor);
};

Loader.prototype.parseVersion = function(v){
    var matches = /(\d+)\.(\d+)\.(\d+)/.exec(v);
    return {
        'major': matches[1],
        'minor': matches[2],
        'patch': matches[3]
    };
};

Loader.prototype.insert = function(done){
    var self = this;
    parallel(this.assets.map(function(src){
        var assetType = /.*\.(js|css)/.exec(src)[1];
        return function(callback){
            // Can we use this version and are we online?
            if(self.shouldUpgradeAsset(src)){
                // Yes -> download, add to dom, next tick save to disk
                fetch(self.url + src, function(err, event){
                    if(err){
                        return callback(err);
                    }

                    append[assetType](event.target.response);

                    self.write(src, event.target.response, function(err){
                        if(err){
                            return callback(err);
                        }
                        localStorage.setItem('versions_' + src,  self.versions[src]);
                        callback();
                    });
                });
            }
            else {
                // No -> check FS. not in fs, set to local URI
                self.read(src, function(err, blob){
                    if(err){ // Doesn't exist or no FS.
                        return append[assetType]('file://' + src);
                    }
                    append[assetType](blob);
                });
            }
        };
    }), function(err){
        done(err);
    });
};

Loader.prototype.read = function(src, done){
    if(!this.fs){
        return done(new Error('Filesystem not available?'));
    }

    this.fs.root.getFile(src, {}, function(entry){
        entry.file(function(file){
            var reader;
            if(cordova){
                reader = new cordova.require('cordova/plugin/FileReader')();
            }
            else {
                reader = window.FileReader();
            }

            reader.onloadend = function(e){
                done(null, e.target.result);
            };
            reader.readAsText(file);
        }, done);
    });
};

Loader.prototype.write = function(dest, blob, done){
    var self = this;
    this.fs.root.getFile(dest, {'create': true, 'exclusive': false}, function(entry){
        entry.createWriter(function(writer){
            writer.onwriteend = function(e){
                done();
            };
            writer.write(blob);
        }, done);
    }, done);
};

Loader.prototype.load = function(done){
    var self = this;
    window.addEventListener('load', function(){
        if(navigator.vendor === 'Google Inc.'){
            return self.deviceReady(done);
        }
        document.addEventListener('deviceready', function(){
            self.deviceReady(done);
        });
    });
    return this;
};

Loader.prototype.deviceReady = function(done){
    done = done || function(){};
    var self = this;
    parallel([
        function getFS(callback){
            (window.requestFileSystem || window.webkitRequestFileSystem)(LocalFileSystem.PERSISTENT || window.PERSISTENT, 50 * 1024 * 1024, function(fs){
                self.fs = fs;
                callback();
            }, callback);
        },
        function getBootstrap(callback){
            fetch(self.bootstrapPath, function(err, event){
                if(err){
                    return callback(err);
                }
                self.versions = JSON.parse(event.target.response);

                // If we haven't bootstrapped yet, default to whats there now.
                if(!self.appVersion){
                    self.appVersion = self.versions.version;
                    self.version = self.parseVersion(self.appVersion);
                }
                self.incomingVersion = self.parseVersion(self.versions.version);
                callback();
            });
        }
    ], function(err){
        self.insert(done);
    });
};

<commit_msg>Adding lots of docs<commit_after>"use strict";

var LocalFileSystem = LocalFileSystem || {},
    cordova = cordova || {};

// Usage:
// require('sterno')(process.env.url, ['/app.js']);
//
// on load / device ready:
//
// # get local file system for reading / writing file caches
// # load bootstrap json from remote
// # insert assets to the dom, and cache locally if need be
module.exports = function(url, assets, done){
    return new Loader(url, assets).load(done);
};

// Async helper.  Like async.parallel.  Calls done on first non null error
// or when all tasks completed.
function parallel(tasks, done){
    var remaining = tasks.length,
        resolved = false;

    tasks.map(function(task){
        task(function(err, res){
            if(!resolved){
                if(err){
                    resolved = true;
                    return done(err);
                }
                remaining--;
                if(remaining === 0){
                    done();
                }
            }
        });
    });
}

// XHR fetch asset.
function fetch(url, done){
    if(!process.env || process.env.environment === 'development'){
        url += '?bust' + Math.random();
    }

    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onload = function(e) {
        if (e.target.status !== 200) {
            return done(new Error('wtf?: ' + e.target.status));
        }
        return done(null, e);
    };
    xhr.onerror = function(){
        done(new Error('XHR error'));
    };
    xhr.send();
}

//Map of assetType to function to drop it on the DOM.
var append = {
    'js': function(src){
        var el = document.createElement('script');
        el.type = 'text/javascript';
        if(src.indexOf('file://') === 0){
            el.src = src;
        }
        else {
            el.innerHTML = src; // Blob
        }
        document.head.appendChild(el);
        return el;
    },
    'css': function(src){
        var el;
        if(src.indexOf('file://') === 0){
            el = document.createElement('link');
            el.rel = 'stylesheet';
            el.type = 'text/css';
            el.href = src;
        }
        else {
            el = document.createElement('style');
            el.type = 'text/css';
            el.innerHTML = src; // Blob
        }
        document.head.appendChild(el);
        return el;
    }
};

// Loader instance handles everything for you.
//
// @param {String} url The base url for assets
// @param {Array} assets just a list of assets to manage, ie /app.css, /app.js, etc.
// @param {String} bootstrapPath optionally where bootstrap data can be found
function Loader(url, assets, bootstrapPath){
    this.url = url;
    this.assets = assets;
    this.bootstrapPath = (bootstrapPath ? url + bootstrapPath : url + '/sterno-bootstrap.json');
    this.versions = {};
    this.appVersion = localStorage.getItem('appVersion');

    // Hashes of files we've already seen.
    // Gets lazy loaded from localstorage
    this.localVersions = {};

    this.incomingVersion = {};
    this.version = {};
    if(this.appVersion){
        this.version = this.parseVersion(this.appVersion);
    }

}

// Use data from the bootstrap to check if a file is different from our
// local copy.
//
// @param {String} src Source of the file, ie /app.js
Loader.prototype.hasChanged = function(src){
    if(!this.localVersions[src]){
        this.localVersions[src] = localStorage.getItem('versions_' + src);
    }

    if(!this.localVersions[src]){
        return true;
    }

    return this.versions[src] !== this.localVersions[src];
};

// Use our decision tree to check if we should actually pull down a nwe version
// of an asset.  Check that we're online, the file has changed and the version
// in the bootstrap is actually one we can use.
//
// @param {String} src Source of the file, ie /app.js
Loader.prototype.shouldUpgradeAsset = function(src){
    if(!navigator.onLine || !this.hasChanged(src)){
        return false;
    }

    return (this.incomingVersion.major === this.version.major && this.incomingVersion.minor === this.version.minor);
};

// Just blow up a version string into a map of major, minor and patch.
//
// @param {String} v any version string, ie 0.1.1
Loader.prototype.parseVersion = function(v){
    var matches = /(\d+)\.(\d+)\.(\d+)/.exec(v);
    return {
        'major': matches[1],
        'minor': matches[2],
        'patch': matches[3]
    };
};

// Insert all of our assets into the DOM.
// Takes care of managing all the versions and fall backs.
//
// @param {Function} done
Loader.prototype.insert = function(done){
    var self = this;
    parallel(this.assets.map(function(src){
        var assetType = /.*\.(js|css)/.exec(src)[1];
        return function(callback){
            // Can we use this version and are we online?
            if(self.shouldUpgradeAsset(src)){
                // Yes -> download, add to dom, next tick save to disk
                fetch(self.url + src, function(err, event){
                    if(err){
                        return callback(err);
                    }

                    append[assetType](event.target.response);

                    self.write(src, event.target.response, function(err){
                        if(err){
                            return callback(err);
                        }
                        localStorage.setItem('versions_' + src,  self.versions[src]);
                        callback();
                    });
                });
            }
            else {
                // No -> check FS. not in fs, set to local URI
                self.read(src, function(err, blob){
                    if(err){ // Doesn't exist or no FS.
                        return append[assetType]('file://' + src);
                    }
                    append[assetType](blob);
                });
            }
        };
    }), function(err){
        done(err);
    });
};

// Cleaner API for reading from the local fs and handing back contents.
//
// @param {String} src
// @param {Function} done
Loader.prototype.read = function(src, done){
    if(!this.fs){
        return done(new Error('Filesystem not available?'));
    }

    this.fs.root.getFile(src, {}, function(entry){
        entry.file(function(file){
            var reader;
            if(cordova){
                reader = new cordova.require('cordova/plugin/FileReader')();
            }
            else {
                reader = window.FileReader();
            }

            reader.onloadend = function(e){
                done(null, e.target.result);
            };
            reader.readAsText(file);
        }, done);
    });
};

// Cleaner API for writing to local fs.
//
// @param {String} dest
// @param {String} blob
// @param {Function} done
Loader.prototype.write = function(dest, blob, done){
    var self = this;
    this.fs.root.getFile(dest, {'create': true, 'exclusive': false}, function(entry){
        entry.createWriter(function(writer){
            writer.onwriteend = function(e){
                done();
            };
            writer.write(blob);
        }, done);
    }, done);
};

// Kicks everything off.
// If we're in chrome, on window load, call device ready.
// If we're in cordova land, wait for device ready to actually fire.
//
// @param {Function} done
Loader.prototype.load = function(done){
    var self = this;
    window.addEventListener('load', function(){
        if(navigator.vendor === 'Google Inc.'){
            return self.deviceReady(done);
        }
        document.addEventListener('deviceready', function(){
            self.deviceReady(done);
        });
    });
    return this;
};

// Called by window load or device ready depeneding on where we're running.
// Tries to get permissions for local filesystem and gets bootstrapping JSON
// data from the remote.  After it gets all that, does some version parsing to
// set up the data used to determine if an asset should be upgraded.
// When thats all good, calls `insert` to start loading our assets into the DOM.
Loader.prototype.deviceReady = function(done){
    done = done || function(){};
    var self = this;
    parallel([
        function getFS(callback){
            (window.requestFileSystem || window.webkitRequestFileSystem)(LocalFileSystem.PERSISTENT || window.PERSISTENT, 50 * 1024 * 1024, function(fs){
                self.fs = fs;
                callback();
            }, callback);
        },
        function getBootstrap(callback){
            fetch(self.bootstrapPath, function(err, event){
                if(err){
                    return callback(err);
                }
                self.versions = JSON.parse(event.target.response);

                // If we haven't bootstrapped yet, default to whats there now.
                if(!self.appVersion){
                    self.appVersion = self.versions.version;
                    self.version = self.parseVersion(self.appVersion);
                }
                self.incomingVersion = self.parseVersion(self.versions.version);
                callback();
            });
        }
    ], function(err){
        self.insert(done);
    });
};

<|endoftext|>


<commit_before> /**
 * @author Chenzhyc
 * @description 分站express引用
 */

const crypto = require('crypto');
const request = require('request');

/**
 * MD5 hash
 * @param  {string} str [string to be hashed]
 * @return {string}     [hashed string with hex]
 */
function md5(str) {
    const hash = crypto.createHash('md5');
    return hash.update(str).digest('hex');
}

/**
 * check if a string is format of JSON
 * @param  {string}  str [description]
 * @return {Boolean}     [description]
 */
function isJsonString(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return true;
}

/**
 * decode base64 string
 * @param  {string} str [string with base64 encoded]
 * @return {string}     [original string]
 */
function base64Decode(str) {
    if (typeof str !== 'string') {
        return null;
    }

    return new Buffer(str, 'base64').toString();
}

/**
 * 校验sessionId
 * @param  {string} ssoUrl  [单点认证中心url]
 * @param  {string} siteUrl [分站url]
 * @param  {string} webserviceUrl [java api url]
 * @return {function}         [在express中使用]
 */
exports.checkSid = function(ssoUrl, siteUrl, webserviceUrl) {
    return function(req, res, next) {
        //如果不存在ycsid，则需重新登录
        if (!req.cookies.ycsid) {
            res.redirect(`${ssoUrl}?redirectUrl=${siteUrl}&errorMsg=NoSID`);
            return;
        }else if (!req.cookies.userId){ // 如果cookie中不存在userId，则也需要重新登录
            res.redirect(`${ssoUrl}?redirectUrl=${siteUrl}&errorMsg=NoUserId`);
            return;
        }else {
            //校验ycsid合法性
            const params = {
                userName: req.cookies.userName,
                password: '',
                sessionId: req.cookies.ycsid,
                ips: [ req.cookies.deviceId ],
                expiresIn: 30 * 24 * 60 * 60,
                country: req.cookies[md5('country')] ? base64Decode(req.cookies[md5('country')]) : '',
                province: '',
                city: req.cookies[md5('city')] ? base64Decode(req.cookies[md5('city')]) : '',
                lat: req.cookies[md5('lat')] ? base64Decode(req.cookies[md5('lat')]) : '',
                lon: req.cookies[md5('lon')] ? base64Decode(req.cookies[md5('lon')]) : '',
                district: req.cookies[md5('city')] ? base64Decode(req.cookies[md5('city')]) : '',
                userAgent: req.get('User-Agent'),
                redirectUrl: siteUrl,
                captchaId: '',
                captcha: ''
            }

            const reqBody = {
                header: {
                    deviceId: req.cookies.deviceId ? req.cookies.deviceId : '',
                    clientType: req.cookies.clientType ? req.cookies.clientType : 'web',
                    clientVersion: req.cookies.clientVersion ? req.cookies.clientVersion : '',
                    clientId: req.cookies.clientId ? req.cookies.clientId : ''
                },
                body: {
                    action: 'getTicket',
                    requestParam: params
                }
            };

            request.post({ url: webserviceUrl, form: JSON.stringify(reqBody) }, function(err, response, body){
                console.log('reqBody = ', reqBody, '\n\n\n\nresponse = ', body);
                if (isJsonString(body) == false) {
                    res.json({
                        code: -1,
                        status: 500,
                        msg:'接口请求失败，请检查请求路径和参数，返回非json文本',
                        resbody: body,
                        err: err
                    });
                    return;
                }
                const ret = JSON.parse(body);
                //如果校验成功，则继续
                if (ret.code == 0) {
                    next();
                }else {
                    //校验失败需重新登录
                    res.redirect(`${ssoUrl}?redirectUrl=${siteUrl}&errorMsg=${body}`);
                    return;
                }
            });
        }
    }
};

/**
 * 通用转发中间件
 * @param  {string} webserviceUrl Java Api url
 * @return {function}              used in express
 */
exports.forwardMiddleWare = function (webserviceUrl) {
    return function(req, res, next) {
        //将ycsid替换为userToken
        const b = {};
        Object.assign(b, req.body);
        b.body.requestParam.userToken = req.cookies.ycsid;

        request.post({ url: webserviceUrl , form: JSON.stringify(b) }, function(err, response, body){

            if (isJsonString(body) == false) {
                res.json({
                    code: -1,
                    status: 500,
                    msg:'接口请求失败，请检查请求路径和参数，返回非json文本',
                    resbody: body,
                    err: err
                });
                return;
            }

            res.status(200).send(body);
            return;
        });
    }
};

/**
 * 通过授权码即ticket 换取共享的sessionId
 * @param  {string} webserviceUrl [Java Api url of sso]
 * @param  {number} maxAge  [cookie中的maxAge]
 * @return {function}               [used in express]
 */
exports.checkTicket = function(webserviceUrl, maxAge, siteUrl) {
    return function(req, res, next) {
        //如果没有传ticket
        if (!req.query.ticket || !req.query.deviceId) {
            res.json({
                code: -1,
                msg:'参数错误',
            });
            return;
        }

        const params = {
            ticket: req.query.ticket,
            ips: [ req.query.deviceId ],
            expiresIn: 30 * 24 * 60 * 60,
            country: base64Decode(req.cookies[md5('country')] ? req.cookies[md5('country')] : ''),
            province: '',
            city: base64Decode(req.cookies[md5('city')] ? req.cookies[md5('city')] : ''),
            lat: base64Decode(req.cookies[md5('lat')] ? req.cookies[md5('lat')] : ''),
            lon: base64Decode(req.cookies[md5('lon')] ? req.cookies[md5('lon')] : ''),
            district: base64Decode(req.cookies[md5('city')] ? req.cookies[md5('city')] : ''),
            userAgent: req.get('User-Agent'),
            redirectUrl: siteUrl
        };

        const reqBody = {
            header: {
                deviceId: req.cookies.deviceId ? req.cookies.deviceId : req.query.deviceId,
                clientType: req.cookies.clientType ? req.cookies.clientType : 'web',
                clientVersion: req.cookies.clientVersion ? req.cookies.clientVersion : '',
                clientId: req.cookies.clientId ? req.cookies.clientId : req.query.deviceId
            },
            body: {
                action: 'getSid',
                requestParam: params
            }
        };

        request.post({ url: webserviceUrl, form: JSON.stringify(reqBody) }, function(err, response, body){
            console.log('reqBody = ', reqBody, '\n\n\n\nresponse = ', body);
            if (isJsonString(body) == false) {
                res.json({
                    code: -1,
                    status: 500,
                    msg:'接口请求失败，请检查请求路径和参数，返回非json文本',
                    resbody: body,
                    err: err
                });
                return;
            }

            const ret = JSON.parse(body);

            if (ret.code == 0 && ret.sessionId) {
                //如果存在remember，则将sid存储时效为一个月，否则只存在于session中
                if (req.query.remember === 'true') {
                    res.cookie('ycsid', ret.sessionId, { maxAge: maxAge, httpOnly: true });
                }else{
                    res.cookie('ycsid', ret.sessionId, { httpOnly: true });
                }
                res.cookie('userId', ret.userId, { maxAge: maxAge });
                res.cookie('userName', ret.userName, { maxAge: maxAge });
                res.cookie('userType', ret.userType, { maxAge: maxAge });
                res.cookie('imgLink', ret.imgLink, { maxAge: maxAge });
                res.cookie('remember', req.query.remember, { maxAge: maxAge });
                res.status(200).send('ok');
                return;
            }else {
                //换票失败需重新登录
                res.json({
                    code: ret.code,
                    msg: ret.msg,
                });

                return;
            }
        });
    }
};
<commit_msg>debug<commit_after> /**
 * @author Chenzhyc
 * @description 分站express引用
 */

const crypto = require('crypto');
const request = require('request');

/**
 * MD5 hash
 * @param  {string} str [string to be hashed]
 * @return {string}     [hashed string with hex]
 */
function md5(str) {
    const hash = crypto.createHash('md5');
    return hash.update(str).digest('hex');
}

/**
 * check if a string is format of JSON
 * @param  {string}  str [description]
 * @return {Boolean}     [description]
 */
function isJsonString(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return true;
}

/**
 * decode base64 string
 * @param  {string} str [string with base64 encoded]
 * @return {string}     [original string]
 */
function base64Decode(str) {
    if (typeof str !== 'string') {
        return null;
    }

    return new Buffer(str, 'base64').toString();
}

/**
 * 校验sessionId
 * @param  {string} ssoUrl  [单点认证中心url]
 * @param  {string} siteUrl [分站url]
 * @param  {string} webserviceUrl [java api url]
 * @return {function}         [在express中使用]
 */
exports.checkSid = function(ssoUrl, siteUrl, webserviceUrl) {
    return function(req, res, next) {
        //如果不存在ycsid，则需重新登录
        if (!req.cookies.ycsid) {
            res.redirect(`${ssoUrl}?redirectUrl=${siteUrl}&errorMsg=NoSID`);
            return;
        }else if (!req.cookies.userId){ // 如果cookie中不存在userId，则也需要重新登录
            res.redirect(`${ssoUrl}?redirectUrl=${siteUrl}&errorMsg=NoUserId`);
            return;
        }else {
            //校验ycsid合法性
            const params = {
                userName: req.cookies.userName,
                password: '',
                sessionId: req.cookies.ycsid,
                ips: [ req.cookies.deviceId ],
                expiresIn: 30 * 24 * 60 * 60,
                country: req.cookies[md5('country')] ? base64Decode(req.cookies[md5('country')]) : '',
                province: '',
                city: req.cookies[md5('city')] ? base64Decode(req.cookies[md5('city')]) : '',
                lat: req.cookies[md5('lat')] ? base64Decode(req.cookies[md5('lat')]) : '',
                lon: req.cookies[md5('lon')] ? base64Decode(req.cookies[md5('lon')]) : '',
                district: req.cookies[md5('city')] ? base64Decode(req.cookies[md5('city')]) : '',
                userAgent: req.get('User-Agent'),
                redirectUrl: siteUrl,
                captchaId: '',
                captcha: ''
            }

            const reqBody = {
                header: {
                    deviceId: req.cookies.deviceId ? req.cookies.deviceId : '',
                    clientType: req.cookies.clientType ? req.cookies.clientType : 'web',
                    clientVersion: req.cookies.clientVersion ? req.cookies.clientVersion : '',
                    clientId: req.cookies.clientId ? req.cookies.clientId : ''
                },
                body: {
                    action: 'getTicket',
                    requestParam: params
                }
            };

            request.post({ url: webserviceUrl, form: JSON.stringify(reqBody) }, function(err, response, body){
                console.log('reqBody = ', reqBody, '\n\n\n\nresponse = ', body);
                if (isJsonString(body) == false) {
                    res.json({
                        code: -1,
                        status: 500,
                        msg:'接口请求失败，请检查请求路径和参数，返回非json文本',
                        resbody: body,
                        err: err
                    });
                    return;
                }
                const ret = JSON.parse(body);
                //如果校验成功，则继续
                if (ret.code == 0) {
                    next();
                }else {
                    //校验失败需重新登录
                    res.redirect(`${ssoUrl}?redirectUrl=${siteUrl}&errorMsg=${body}`);
                    return;
                }
            });
        }
    }
};

/**
 * 通用转发中间件
 * @param  {string} webserviceUrl Java Api url
 * @return {function}              used in express
 */
exports.forwardMiddleWare = function (webserviceUrl) {
    return function(req, res, next) {
        //将ycsid替换为userToken
        const b = {};
        Object.assign(b, req.body);
        b.body.requestParam.userToken = req.cookies.ycsid;

        request.post({ url: webserviceUrl , form: JSON.stringify(b) }, function(err, response, body){

            if (isJsonString(body) == false) {
                res.json({
                    code: -1,
                    status: 500,
                    msg:'接口请求失败，请检查请求路径和参数，返回非json文本',
                    resbody: body,
                    err: err
                });
                return;
            }

            res.status(200).send(body);
            return;
        });
    }
};

/**
 * 通过授权码即ticket 换取共享的sessionId
 * @param  {string} webserviceUrl [Java Api url of sso]
 * @param  {number} maxAge  [cookie中的maxAge]
 * @return {function}               [used in express]
 */
exports.checkTicket = function(webserviceUrl, maxAge, siteUrl) {
    return function(req, res, next) {
        //如果没有传ticket
        if (!req.query.ticket || !req.query.deviceId) {
            res.json({
                code: -1,
                msg:'参数错误',
            });
            return;
        }

        const params = {
            ticket: req.query.ticket,
            ips: [ req.query.deviceId ],
            expiresIn: 30 * 24 * 60 * 60,
            country: base64Decode(req.cookies[md5('country')] ? req.cookies[md5('country')] : ''),
            province: '',
            city: base64Decode(req.cookies[md5('city')] ? req.cookies[md5('city')] : ''),
            lat: base64Decode(req.cookies[md5('lat')] ? req.cookies[md5('lat')] : ''),
            lon: base64Decode(req.cookies[md5('lon')] ? req.cookies[md5('lon')] : ''),
            district: base64Decode(req.cookies[md5('city')] ? req.cookies[md5('city')] : ''),
            userAgent: req.get('User-Agent'),
            redirectUrl: siteUrl
        };

        const reqBody = {
            header: {
                deviceId: req.cookies.deviceId ? req.cookies.deviceId : req.query.deviceId,
                clientType: req.cookies.clientType ? req.cookies.clientType : 'web',
                clientVersion: req.cookies.clientVersion ? req.cookies.clientVersion : '',
                clientId: req.cookies.clientId ? req.cookies.clientId : req.query.deviceId
            },
            body: {
                action: 'getSid',
                requestParam: params
            }
        };

        request.post({ url: webserviceUrl, form: JSON.stringify(reqBody) }, function(err, response, body){
            console.log('reqBody = ', reqBody, '\n\n\n\body = ', body);
            console.log('err = ', err, '\n\n\n\nresponse = ', response);
            if (isJsonString(body) == false) {
                res.json({
                    code: -1,
                    status: 500,
                    msg:'接口请求失败，请检查请求路径和参数，返回非json文本',
                    resbody: body,
                    err: err
                });
                return;
            }

            const ret = JSON.parse(body);

            if (ret.code == 0 && ret.sessionId) {
                //如果存在remember，则将sid存储时效为一个月，否则只存在于session中
                if (req.query.remember === 'true') {
                    res.cookie('ycsid', ret.sessionId, { maxAge: maxAge, httpOnly: true });
                }else{
                    res.cookie('ycsid', ret.sessionId, { httpOnly: true });
                }
                res.cookie('userId', ret.userId, { maxAge: maxAge });
                res.cookie('userName', ret.userName, { maxAge: maxAge });
                res.cookie('userType', ret.userType, { maxAge: maxAge });
                res.cookie('imgLink', ret.imgLink, { maxAge: maxAge });
                res.cookie('remember', req.query.remember, { maxAge: maxAge });
                res.status(200).send('ok');
                return;
            }else {
                //换票失败需重新登录
                res.json({
                    code: ret.code,
                    msg: ret.msg,
                });

                return;
            }
        });
    }
};
<|endoftext|>


<commit_before>var exec = require('child_process').exec;
var path = require('path');

const DBUS_COMMAND = "bash "+__dirname+"/dbus.sh ";
const DBUS_DEST_DEFAULT = 'org.mpris.MediaPlayer2.omxplayer';

class OmxInstance {

	constructor(options) {
		this.options = options;

		if (options && options.layer) {
			this.dbusDest = DBUS_DEST_DEFAULT + '_layer' + options.layer;
			this.layer = options.layer;
			console.log('setup for layered mode');
		} else {
			this.dbusDest = DBUS_DEST_DEFAULT;
			this.layer = 1;
			console.log('not layered mode');
		}
		console.log('dbus name will be', this.dbusDest);

		exec('mkfifo omxpipe'+this.layer);

		this.defaults = null;
		this.progressHandler = null;

	}

	getLayer() {
		return this.layer;
	}

	cancelProgressHandlerIfActive() {
		if (this.progressHandler) {
			clearInterval(this.progressHandler);
			console.log('progressHandler cancelled');
		}
	}

	dbusCommand (command)  {
		let merge = "bash " +__dirname+"/dbus.sh " + this.dbusDest + " " + command;
		if (command != 'getplaystatus' && command !='getvolume' && command != 'getposition') { console.log('merge:', merge); }
		return merge;
	}

	resume () {
		exec(this.dbusCommand('getplaystatus'), (error, stdout, stderr) => {
			// Ignore if already playing
			if (stdout.indexOf("Paused")>-1) {
				this.togglePlay();
			}
		});
	}

	pause () {
		exec(this.dbusCommand('getplaystatus'), (error, stdout, stderr) => {
			// Ignore if already paused
			if (stdout.indexOf("Playing")>-1) {
				this.togglePlay();
			}
		});
	}

	stop () {
		exec(this.dbusCommand('stop'), (error, stdout, stderr) => {
			this.cancelProgressHandlerIfActive();
		});
	}

	quit () {
		exec(this.dbusCommand('quit'), (error, stdout, stderr) => {
			this.cancelProgressHandlerIfActive();
	  });
	}

	togglePlay () {
		exec(this.dbusCommand('toggleplay'), (error, stdout, stderr) => {});
	}

	seek (offset) {
		//seek offset in seconds; relative from current position; negative values will cause a jump back;
		exec(this.dbusCommand('seek ' +Math.round(offset*1000000)), (error, stdout, stderr) => {});
	}

	setPosition (position) {
		//position in seconds from start; //positions larger than the duration will stop the player;
		exec(this.dbusCommand('setposition '+Math.round(position*1000000)), (error, stdout, stderr) => {});
	}

	setVolume (volume) {
		// volume range [0.0, 1.0];
		if (volume > 0 && volume < 1.0) {
			exec(this.dbusCommand('setvolume '+volume), (error, stdout, stderr) => {});
		}
	}

	setVisibility (visible) {
		let command = visible ? 'unhidevideo' : 'hidevideo';
		exec(this.dbusCommand(command), (err, stdout, stderr) => {});
	}

	setAlpha (alpha) {
		exec(this.dbusCommand('setalpha ' + alpha), (err, stdout, stderr) => {});
	}

	getCurrentPosition () {
		console.log('getCurrentPosition');
		return new Promise( (resolve, reject) => {
			exec(this.dbusCommand('getposition'), (error, stdout, stderr) => {
				console.log('getposition error, stdout, stderr:', error, stdout, stderr);
				if (error) reject();

				let position = parseInt(stdout);
				console.log('currentPosition:', position, 'or in seconds:', position / 1000);
				resolve(position);
			});
		});
	}

	getIsPlaying () {
		console.log('getIsPlaying');
		return new Promise( (resolve, reject) => {
			exec(this.dbusCommand('getplaystatus'), (error, stdout, stderr) => {
				console.log('getplaystatus error, stdout, stderr:', error, stdout, stderr);
				if (error) {
					console.error('error getting play status:', err);
					reject();
				}
				if (stdout === 'Playing') {
					resolve(true);
				} else {
					resolve(false);
				}
			});
		});
	}

	getDuration () {
		return new Promise( (resolve, reject) => {
			if (this.duration) {
				resolve(this.duration);
			} else {
				exec( this.dbusCommand('getduration'), (error, stdout, stderr) => {
					if (error) reject();

					let duration = parseInt(stdout);
					console.log('getDuration:', duration, 'or in seconds:', duration / 1000);
					resolve(duration);
					this.duration = duration; // cache last known duration
				});
			}
		});
	}

	getVolume () {
		exec(this.dbusCommand('getvolume'), (error, stdout, stderr) => {
			if (error) return null;
			let volume = parseFloat(stdout);
			console.log('getVolume:', volume);
		});	}

	onProgress (callback) {
		console.log('add new progress handler for layer', this.layer);
		this.progressHandler = setInterval( () => {
			this.getIsPlaying()
				 .then( (isPlaying) => {
					 console.log('isPlaying?', isPlaying);
					 if (isPlaying) {
						 this.getCurrentPosition()
						 	.then( (position) => {
								this.getDuration()
									.then( (duration) => {
										callback({ 'position': position, 'duration': duration });
									});
							});
					 } else {
						 callback({ 'playing': false });
					 }
				 })
				 .catch( () => {
					 console.error('error getting isPlaying status');
					 callback({ 'status': 'error', 'playing': false });
				 });
		}, 1000);
	}

	onStart (callback) {
		console.log('onStart event');
		if (callback) {
			callback();
		}
	}

	waitTillPlaying (callback) {
		console.log('waitTillPlaying');
		let countAttempts = 0;
		let interval;
		interval = setInterval( () => {
			countAttempts++;
			exec(this.dbusCommand('getplaystatus'), (error, stdout, stderr) => {
				if (error) {
					console.log('error on getplaystus:', error);
				} else {
					console.log('getplaystatus result after', countAttempts, ':', stdout);
					clearInterval(interval);
					callback();
				}
			});
		}, 1000);
	}

	open (path, doneCallback, holdMode) {
		console.log('OmxInstance open() for layer #', this.layer, 'holdMode?', holdMode);
		let settings = this.options || {};
		let args = [];
		let command = 'omxplayer';

		args.push('"'+path+'"');

		if (['hdmi','local','both'].indexOf(settings.audioOutput) != -1) {
			args.push('-o');
			args.push(settings.audioOutput);
		}

		if (settings.blackBackground !== false) { // defaults to true
			args.push('-b');
		}

		if (settings.disableKeys === true) { //defaults to  false
			args.push('--no-keys')
		}

		if (settings.disableOnScreenDisplay === true) { //defaults to  false
			args.push('--no-osd')
		}

		if (settings.disableGhostbox === true) { //defaults to  false
			args.push('--no-ghost-box');
		}

		if (settings.loop === true) { // defaults to false
			args.push('--loop');
		}

		if (settings.subtitlePath && settings.subtitlePath != "" ){
			args.push('--subtitles');
			args.push('"'+settings.subtitlePath+'"');
		}

		if (settings.startAt){
			args.push('--pos');
			args.push(''+settings.startAt+'');
		}

		if (settings.layer) {
			args.push('--layer');
			args.push(settings.layer);
		}

		if (holdMode) {
			args.push('--alpha');
			args.push(0);
		}

		args.push('--dbus_name');
		args.push(this.dbusDest);

		let finalOpenCommand = command+' '+args.join(' ')+' < omxpipe'+this.layer;
		console.log('finalOpenCommand:', finalOpenCommand);

	  exec(finalOpenCommand, (error, stdout, stderr) => {
			doneCallback();
			console.log('omxpipe done for layer', this.layer);
  		this.cancelProgressHandlerIfActive();
	  	console.log(stdout);
	  });
	  exec(' . > omxpipe'+this.layer, (error, stdout, stderr) => {
			this.waitTillPlaying( () => {
				console.log('started ok');
				this.onStart();
				if (holdMode) {
					console.log('holdMode ON, so immediately pause and hide');
					this.pause();
					this.setVisibility(false);
				}
			});
		});

	}

}

module.exports = OmxInstance;
<commit_msg>less strict check for isPlaying?<commit_after>var exec = require('child_process').exec;
var path = require('path');

const DBUS_COMMAND = "bash "+__dirname+"/dbus.sh ";
const DBUS_DEST_DEFAULT = 'org.mpris.MediaPlayer2.omxplayer';

class OmxInstance {

	constructor(options) {
		this.options = options;

		if (options && options.layer) {
			this.dbusDest = DBUS_DEST_DEFAULT + '_layer' + options.layer;
			this.layer = options.layer;
			console.log('setup for layered mode');
		} else {
			this.dbusDest = DBUS_DEST_DEFAULT;
			this.layer = 1;
			console.log('not layered mode');
		}
		console.log('dbus name will be', this.dbusDest);

		exec('mkfifo omxpipe'+this.layer);

		this.defaults = null;
		this.progressHandler = null;

	}

	getLayer() {
		return this.layer;
	}

	cancelProgressHandlerIfActive() {
		if (this.progressHandler) {
			clearInterval(this.progressHandler);
			console.log('progressHandler cancelled');
		}
	}

	dbusCommand (command)  {
		let merge = "bash " +__dirname+"/dbus.sh " + this.dbusDest + " " + command;
		if (command != 'getplaystatus' && command !='getvolume' && command != 'getposition') { console.log('merge:', merge); }
		return merge;
	}

	resume () {
		exec(this.dbusCommand('getplaystatus'), (error, stdout, stderr) => {
			// Ignore if already playing
			if (stdout.indexOf("Paused")>-1) {
				this.togglePlay();
			}
		});
	}

	pause () {
		exec(this.dbusCommand('getplaystatus'), (error, stdout, stderr) => {
			// Ignore if already paused
			if (stdout.indexOf("Playing")>-1) {
				this.togglePlay();
			}
		});
	}

	stop () {
		exec(this.dbusCommand('stop'), (error, stdout, stderr) => {
			this.cancelProgressHandlerIfActive();
		});
	}

	quit () {
		exec(this.dbusCommand('quit'), (error, stdout, stderr) => {
			this.cancelProgressHandlerIfActive();
	  });
	}

	togglePlay () {
		exec(this.dbusCommand('toggleplay'), (error, stdout, stderr) => {});
	}

	seek (offset) {
		//seek offset in seconds; relative from current position; negative values will cause a jump back;
		exec(this.dbusCommand('seek ' +Math.round(offset*1000000)), (error, stdout, stderr) => {});
	}

	setPosition (position) {
		//position in seconds from start; //positions larger than the duration will stop the player;
		exec(this.dbusCommand('setposition '+Math.round(position*1000000)), (error, stdout, stderr) => {});
	}

	setVolume (volume) {
		// volume range [0.0, 1.0];
		if (volume > 0 && volume < 1.0) {
			exec(this.dbusCommand('setvolume '+volume), (error, stdout, stderr) => {});
		}
	}

	setVisibility (visible) {
		let command = visible ? 'unhidevideo' : 'hidevideo';
		exec(this.dbusCommand(command), (err, stdout, stderr) => {});
	}

	setAlpha (alpha) {
		exec(this.dbusCommand('setalpha ' + alpha), (err, stdout, stderr) => {});
	}

	getCurrentPosition () {
		console.log('getCurrentPosition');
		return new Promise( (resolve, reject) => {
			exec(this.dbusCommand('getposition'), (error, stdout, stderr) => {
				console.log('getposition error, stdout, stderr:', error, stdout, stderr);
				if (error) reject();

				let position = parseInt(stdout);
				console.log('currentPosition:', position, 'or in seconds:', position / 1000);
				resolve(position);
			});
		});
	}

	getIsPlaying () {
		console.log('getIsPlaying');
		return new Promise( (resolve, reject) => {
			exec(this.dbusCommand('getplaystatus'), (error, stdout, stderr) => {
				console.log('getplaystatus error, stdout, stderr:', error, stdout, stderr);
				if (error) {
					console.error('error getting play status:', err);
					reject();
				}
				if (stdout == 'Playing') {
					resolve(true);
				} else {
					resolve(false);
				}
			});
		});
	}

	getDuration () {
		return new Promise( (resolve, reject) => {
			if (this.duration) {
				resolve(this.duration);
			} else {
				exec( this.dbusCommand('getduration'), (error, stdout, stderr) => {
					if (error) reject();

					let duration = parseInt(stdout);
					console.log('getDuration:', duration, 'or in seconds:', duration / 1000);
					resolve(duration);
					this.duration = duration; // cache last known duration
				});
			}
		});
	}

	getVolume () {
		exec(this.dbusCommand('getvolume'), (error, stdout, stderr) => {
			if (error) return null;
			let volume = parseFloat(stdout);
			console.log('getVolume:', volume);
		});	}

	onProgress (callback) {
		console.log('add new progress handler for layer', this.layer);
		this.progressHandler = setInterval( () => {
			this.getIsPlaying()
				 .then( (isPlaying) => {
					 console.log('isPlaying?', isPlaying);
					 if (isPlaying) {
						 this.getCurrentPosition()
						 	.then( (position) => {
								this.getDuration()
									.then( (duration) => {
										callback({ 'position': position, 'duration': duration });
									});
							});
					 } else {
						 callback({ 'playing': false });
					 }
				 })
				 .catch( () => {
					 console.error('error getting isPlaying status');
					 callback({ 'status': 'error', 'playing': false });
				 });
		}, 1000);
	}

	onStart (callback) {
		console.log('onStart event');
		if (callback) {
			callback();
		}
	}

	waitTillPlaying (callback) {
		console.log('waitTillPlaying');
		let countAttempts = 0;
		let interval;
		interval = setInterval( () => {
			countAttempts++;
			exec(this.dbusCommand('getplaystatus'), (error, stdout, stderr) => {
				if (error) {
					console.log('error on getplaystus:', error);
				} else {
					console.log('getplaystatus result after', countAttempts, ':', stdout);
					clearInterval(interval);
					callback();
				}
			});
		}, 1000);
	}

	open (path, doneCallback, holdMode) {
		console.log('OmxInstance open() for layer #', this.layer, 'holdMode?', holdMode);
		let settings = this.options || {};
		let args = [];
		let command = 'omxplayer';

		args.push('"'+path+'"');

		if (['hdmi','local','both'].indexOf(settings.audioOutput) != -1) {
			args.push('-o');
			args.push(settings.audioOutput);
		}

		if (settings.blackBackground !== false) { // defaults to true
			args.push('-b');
		}

		if (settings.disableKeys === true) { //defaults to  false
			args.push('--no-keys')
		}

		if (settings.disableOnScreenDisplay === true) { //defaults to  false
			args.push('--no-osd')
		}

		if (settings.disableGhostbox === true) { //defaults to  false
			args.push('--no-ghost-box');
		}

		if (settings.loop === true) { // defaults to false
			args.push('--loop');
		}

		if (settings.subtitlePath && settings.subtitlePath != "" ){
			args.push('--subtitles');
			args.push('"'+settings.subtitlePath+'"');
		}

		if (settings.startAt){
			args.push('--pos');
			args.push(''+settings.startAt+'');
		}

		if (settings.layer) {
			args.push('--layer');
			args.push(settings.layer);
		}

		if (holdMode) {
			args.push('--alpha');
			args.push(0);
		}

		args.push('--dbus_name');
		args.push(this.dbusDest);

		let finalOpenCommand = command+' '+args.join(' ')+' < omxpipe'+this.layer;
		console.log('finalOpenCommand:', finalOpenCommand);

	  exec(finalOpenCommand, (error, stdout, stderr) => {
			doneCallback();
			console.log('omxpipe done for layer', this.layer);
  		this.cancelProgressHandlerIfActive();
	  	console.log(stdout);
	  });
	  exec(' . > omxpipe'+this.layer, (error, stdout, stderr) => {
			this.waitTillPlaying( () => {
				console.log('started ok');
				this.onStart();
				if (holdMode) {
					console.log('holdMode ON, so immediately pause and hide');
					this.pause();
					this.setVisibility(false);
				}
			});
		});

	}

}

module.exports = OmxInstance;
<|endoftext|>


<commit_before>#!/usr/bin/env node

const editor = require('editor')
const fs = require('fs')
const walk = require('walk')
const moment = require('moment')
const _ = require('underscore')
const path = require('path')
const mkdirp = require('mkdirp')
const opn = require('opn')
const cli = require('meow')([`
  Usage
    $ journall <input>

  Options
    -t, --title    A title you want as a heading
    -p, --program  The program to open with
    -e, --editor   Open using $EDITOR
    --path         The path to the folder (Can be specifed with $JOURNALL)

  Examples
    $ get-github-user -t 'Test'
    # Will open a document with test
`], {
  alias: {
    t: 'title',
    p: 'program',
    e: 'editor'
  }
})

if (!cli.flags.path && !process.env['JOURNALL']) {
  console.log('ERROR: You must either specify --path or set $JOURNALL to a path.')
  cli.showHelp(1)
}

const journalFolder = cli.flags.path || path.resolve(process.env['JOURNALL'])
const files = []
const filename = moment().format('YYYY.MM.DD') + '.md'
const fullPath = path.resolve(journalFolder + '/' + filename)
const program = cli.flags.program || process.env['JOURNALL_PROGRAM']
const title = cli.flags.title || cli.input
const walker = walk.walk(journalFolder, { followLinks: false })

function openFile (text) {
  console.log(`${text} Opening page.`)
  if (cli.flags.editor) {
    editor(fullPath, function () {
      process.exit(0)
    })
  } else {
    opn(fullPath, {app: program, wait: false})
    process.exit(0)
  }
}

function wrapTitle (title) {
  return `\n## ${title}\n`
}

walker.on('file', function (root, stat, next) {
  files.push(stat.name)
  next()
})

walker.on('end', function () {
  var header = `# ${moment().format('YYYY MMMM Do')}\n\n`

  if (!_.contains(files, filename)) {
    // Add the date and an optional title to the header
    if (title && title.length !== 0) {
      header += wrapTitle(title)
    }

    // Create the directory if it doesn't exist
    mkdirp.sync(journalFolder)

    // Create file with simple header
    fs.writeFile(fullPath, header, function (err) {
      if (err) {
        throw new Error(err)
      }
      openFile('Log entered.')
    })
  } else if (title) {
    // Add the optional title at the end of the file
    fs.appendFile(fullPath, wrapTitle(title), function (err) {
      if (err) {
        throw new Error('Writing the new header did not work', err)
      }
      openFile('Date already exists.')
    })
  } else {
    openFile('Date already exists.')
  }
})
<commit_msg>Added h alias<commit_after>#!/usr/bin/env node

const editor = require('editor')
const fs = require('fs')
const walk = require('walk')
const moment = require('moment')
const _ = require('underscore')
const path = require('path')
const mkdirp = require('mkdirp')
const opn = require('opn')
const cli = require('meow')([`
  Usage
    $ journall <input>

  Options
    -t, --title    A title you want as a heading
    -p, --program  The program to open with
    -e, --editor   Open using $EDITOR
    --path         The path to the folder (Can be specifed with $JOURNALL)

  Examples
    $ get-github-user -t 'Test'
    # Will open a document with test
`], {
  alias: {
    h: 'help',
    t: 'title',
    p: 'program',
    e: 'editor'
  }
})

if (!cli.flags.path && !process.env['JOURNALL']) {
  console.log('ERROR: You must either specify --path or set $JOURNALL to a path.')
  cli.showHelp(1)
}

const journalFolder = cli.flags.path || path.resolve(process.env['JOURNALL'])
const files = []
const filename = moment().format('YYYY.MM.DD') + '.md'
const fullPath = path.resolve(journalFolder + '/' + filename)
const program = cli.flags.program || process.env['JOURNALL_PROGRAM']
const title = cli.flags.title || cli.input
const walker = walk.walk(journalFolder, { followLinks: false })

function openFile (text) {
  console.log(`${text} Opening page.`)
  if (cli.flags.editor) {
    editor(fullPath, function () {
      process.exit(0)
    })
  } else {
    opn(fullPath, {app: program, wait: false})
    process.exit(0)
  }
}

function wrapTitle (title) {
  return `\n## ${title}\n`
}

walker.on('file', function (root, stat, next) {
  files.push(stat.name)
  next()
})

walker.on('end', function () {
  var header = `# ${moment().format('YYYY MMMM Do')}\n\n`

  if (!_.contains(files, filename)) {
    // Add the date and an optional title to the header
    if (title && title.length !== 0) {
      header += wrapTitle(title)
    }

    // Create the directory if it doesn't exist
    mkdirp.sync(journalFolder)

    // Create file with simple header
    fs.writeFile(fullPath, header, function (err) {
      if (err) {
        throw new Error(err)
      }
      openFile('Log entered.')
    })
  } else if (title) {
    // Add the optional title at the end of the file
    fs.appendFile(fullPath, wrapTitle(title), function (err) {
      if (err) {
        throw new Error('Writing the new header did not work', err)
      }
      openFile('Date already exists.')
    })
  } else {
    openFile('Date already exists.')
  }
})
<|endoftext|>


<commit_before>
var initId = 0;

module.exports = function makeColumn(rootCol, fraction) {
  rootCol = rootCol || {K: 1, G: 0, depth: 0, children: {}};

  var col = {
    depth: rootCol.depth + 1,
    children: {}
  };

  var id = initId++;
  var rawf, f;

  col.setWidth = function (fraction) {
    fraction = fraction || '1/1';

    if (fraction === rawf) return;
    rawf = fraction;

    f = fractionToArray(fraction);
    col.updateWidth();

    if (col.children.length) {
      var child;
      for (child in col.children) {
        col.children[child].updateWidth();
      }
    }
  }

  col.updateWidth = function () {
    col.K = rootCol.K * f[0] / f[1];
    col.G = (rootCol.G * f[0] / f[1]) + (f[0] / f[1]) - 1;
  }

  col.getFraction = function () {
    return f;
  }

  col.getId = function() {
    return id;
  }

  col.getWidth = function (viewport, gutter) {
    return (viewport * col.K) + (gutter * col.G);
  }

  col.detach = function () {
    delete rootCol.children[id];
  }

  col.setWidth(fraction);
  rootCol.children[id] = col;

  return col;
}

function fractionToArray(f) {
  f = f.split('/');
  f[0] = parseInt(f[0]);
  f[1] = parseInt(f[1]);
  return f;
}
<commit_msg>spacing<commit_after>var initId = 0;

module.exports = function makeColumn(rootCol, fraction) {
  rootCol = rootCol || {K: 1, G: 0, depth: 0, children: {}};

  var col = {
    depth: rootCol.depth + 1,
    children: {}
  };

  var id = initId++;
  var rawf, f;

  col.setWidth = function (fraction) {
    fraction = fraction || '1/1';

    if (fraction === rawf) return;
    rawf = fraction;

    f = fractionToArray(fraction);
    col.updateWidth();

    if (col.children.length) {
      var child;
      for (child in col.children) {
        col.children[child].updateWidth();
      }
    }
  }

  col.updateWidth = function () {
    col.K = rootCol.K * f[0] / f[1];
    col.G = (rootCol.G * f[0] / f[1]) + (f[0] / f[1]) - 1;
  }

  col.getFraction = function () {
    return f;
  }

  col.getId = function() {
    return id;
  }

  col.getWidth = function (viewport, gutter) {
    return (viewport * col.K) + (gutter * col.G);
  }

  col.detach = function () {
    delete rootCol.children[id];
  }

  col.setWidth(fraction);
  rootCol.children[id] = col;

  return col;
}

function fractionToArray(f) {
  f = f.split('/');
  f[0] = parseInt(f[0]);
  f[1] = parseInt(f[1]);
  return f;
}<|endoftext|>


<commit_before>//     jovial
//
//     Copyright (c) 2015, 2016 Simon Y. Blackwell, AnyWhichWay
//     MIT License - http://opensource.org/licenses/mit-license.php
(function() {
	"use strict";
	// soundex from https://gist.github.com/shawndumas/1262659
	function soundex(s) {
	    var a = s.toLowerCase().split(''),
	    f = a.shift(),
	    r = '',
	    codes = {
	        a: '', e: '', i: '', o: '', u: '',
	        b: 1, f: 1, p: 1, v: 1,
	        c: 2, g: 2, j: 2, k: 2, q: 2, s: 2, x: 2, z: 2,
	        d: 3, t: 3,
	        l: 4,
	        m: 5, n: 5,
	        r: 6
	    };

		r = f +
		    a
		    .map(function (v) { return codes[v] })
		    .filter(function (v, i, a) {
		        return ((i === 0) ? v !== codes[f] : v !== a[i - 1]);
		    })
		    .join('');

		return (r + '000').slice(0, 4).toUpperCase();
	}
	var ProxyConstructor;
	function Validator(config) {
		var me = this;
		if(config) {
			var keys = Object.keys(config);
			keys.forEach(function(key) {
				me[key] = config[key];
				me[key].name = key;
			});
		}
	}
	if(typeof(Proxy)==="undefined"  && typeof(require)==="function") {
		var ProxyConstructor = require('chrome-proxy');
		if(this!==window) {
			Proxy = Constructor;
		}
	}
	Validator.prototype.bind = function(constructorOrObject,onerror,name) {
		function validate(target,property,value,proxy,skipset,skiponerror,error) {
			var validation = validator[property], keys, error;
			if(validation) {
				keys = Object.keys(validation);
				try {
					value = (validation.transform ? Validator.validation.transform(validation.transform,value) : value);
				} catch(e) {
					error = (error ? error : new Validator.ValidationError(target));
					error.errors[property] = (error.errors[property] ? error.errors[property] : {});
					error.errors[property].value = (value===undefined ? null : value);
					error.errors[property].validation = (error.errors[property].validation ? error.errors[property].validation : {});
					error.errors[property].validation.transform = {constraint: validation.transform};
					error.errors[property].validation.transform.error = e;
				}
				keys.forEach(function(key) {
					if(typeof(Validator.validation[key])==="function" && key!=="transform") {
						var result = Validator.validation[key](validation[key],value);
						if(!result) {
							error = (error ? error : new Validator.ValidationError(target));
							error.errors[property] = (error.errors[property] ? error.errors[property] : {});
							error.errors[property].value = (value===undefined ? null : value);
							error.errors[property].validation = (error.errors[property].validation ? error.errors[property].validation : {});
							error.errors[property].validation[key] = {constraint: validation[key]};
							var msg = property + ":" + (typeof(value)==="string" ? "\"" + value + "\"" : (value instanceof Object ? JSON.stringify(value) : value)) + " failed validation {\"" + key + "\":" + JSON.stringify(error.errors[property].validation[key]) + "}";
							Validator.validation.type.onError = TypeError;
							var propertyerror = new (Validator.validation[key].onError ? Validator.validation[key].onError : Error)(msg);
							error.errors[property].validation[key].error = propertyerror;
						}
					}
				});
			}
			if(error) {
				if(!skiponerror && onerror) {
					onerror(error)
				} else {
					throw error;
				}
			} else  {
				if(!skipset) {
					target[property] = value;
				}
				return true;
			}
		}
		function validateInstance(trap) {
			var me = this, keys = Object.keys(me), error;
			keys.forEach(function(key) {
				var value = me[key];
				if(typeof(value)!=="function") {
					try {
						validate(me,key,value,undefined,true,true,error);
					} catch(e) {
						error = e;
					}
				}
			});
			if(trap) {
				return error;
			}
			if(onerror) {
				if(error) {
					onerror(error);
				}
			} else if(error) {
				throw error;
			}
		}
		name = (name ? name : (constructorOrObject.name ? constructorOrObject.name : "anonymous"));
		var validator = this, cons;
		var handler = {
			deleteProperty: function(target,property,proxy) {
				var validation = validator[property];
				if(Validator.validation.required(validation.required,undefined)) {
					delete target[property];
					return true;
				}
				handler.set(target,property,undefined,proxy,true);
			},
			defineProperty: function(target, property, descriptor, proxy) {
				if(handler.set(target, property, descriptor.value, proxy, true)) {
					Object.defineProperty(target, property, descriptor);
				}
			},
			set: validate
		};
		if(constructorOrObject instanceof Function) {
			cons = Function("cons","hndlr","prxy","return function " + name + "() { cons.apply(this,arguments); return new prxy(this,hndlr);  }")(constructorOrObject,handler,Proxy);
			cons.prototype = Object.create(constructorOrObject.prototype);
			cons.prototype.__kind__ = name;
			cons.prototype.constructor = cons;
			cons.prototype.validate = validateInstance;
			return cons;
		} else {
			constructorOrObject.validate = validateInstance;
		}
		return new Proxy(constructorOrObject,handler);
	}
	Validator.ValidationError = function(object) {
		this.object = object;
		this.errors = {};
	}
	Validator.ValidationError.prototype = Object.create(Error.prototype);
	Validator.ValidationError.prototype.constructor = Validator.ValidationError;
	Validator.validation = {};

	Validator.validation.transform = function(f,value) {
		return f(value);
	}
	Validator.validation.transform.onError = TypeError;

	Validator.validation.between = function(between,value) {
		between.sort(function(a,b) { return a - b; });
		var min = between[0];
		var max = between[between.length-1];
		return value>=min && value<=max;
	}
	Validator.validation.between.onError = RangeError;

	Validator.validation.echoes = function(echoes,value) {
		return soundex(echoes)===soundex(value);
	}
	Validator.validation.echoes.onError = RangeError;

	Validator.validation.in = function(values,value) {
		return values.indexOf(value)>=0;
	}
	Validator.validation.in.onError = RangeError;

	Validator.validation.length = function(length,value) {
		if(length instanceof Array) {
			length.sort(function(a,b) { return a - b; });
			var min = length[0];
			var max = length[length.length-1];
			return (value && (value.length>=min && value.length<=max) || (value.count>=min && value.count<=max));
		}
		return value && (value.length===length || value.count===length);
	}
	Validator.validation.length.onError = RangeError;

	Validator.validation.matches = function(regex,value) {
		return new RegExp(regex).test(value);
	}
	Validator.validation.matches.onError = RangeError;

	Validator.validation.max = function(max,value) {
		return value<=max;
	}
	Validator.validation.max.onError = RangeError;

	Validator.validation.min = function(min,value) {
		return value>=min;
	}
	Validator.validation.min.onError = RangeError;

	Validator.validation.required = function(required,value) {
		return (required ? value!==undefined : true);
	}
	Validator.validation.required.onError = TypeError;

	Validator.validation.satisfies = function(satisfies,value) {
		return satisfies(value);
	}
	Validator.validation.satisfies.onError = RangeError;

	Validator.validation.type = function(type,value) {
		var tel = {
				us: /^[01]?[- .]?\(?[2-9]\d{2}\)?[- .]?\d{3}[- .]?\d{4}$/
		};
		if(typeof(value)===type) {
			return true;
		}
		if(typeof(type)==="function") {
			return value instanceof type;
		}
		if(type==="SSN") {
			return /^\d{3}-\d{2}-\d{4}$/.test(value);
		}
		if(type==="latlon") {
			// David Jacobs via http://www.regexlib.com/
			return /(-?(90[ :°d]*00[ :\'\'m]*00(\.0+)?|[0-8][0-9][ :°d]*[0-5][0-9][ :\'\'m]*[0-5][0-9](\.\d+)?)[ :\?\"s]*(N|n|S|s)?)[ ,]*(-?(180[ :°d]*00[ :\'\'m]*00(\.0+)?|(1[0-7][0-9]|0[0-9][0-9])[ :°d]*[0-5][0-9][ :\'\'m]*[0-5][0-9](\.\d+)?)[ :\?\"s]*(E|e|W|w)?)/.test(value);
		}
		if(type.indexOf("tel")===0) {
			var split = type.split(".");
			split.shift();
			if(split.length===0) {
				split.push("us");
			}
			return split.some(function(country) {
				if(tel[country]) {
					return tel[country].test(value);
				}
			});
		}
		return false;
	}
	Validator.validation.type.onError = TypeError;

	if (this.exports) {
		this.exports  = Validator;
	} else if (typeof define === 'function' && define.amd) {
		// Publish as AMD module
		define(function() {return Proxy;});
	} else {
		this.Validator = Validator;
	}
}).call((typeof(window)!=='undefined' ? window : (typeof(module)!=='undefined' ? module : null)));<commit_msg>further server adjustements for Proxy<commit_after>//     jovial
//
//     Copyright (c) 2015, 2016 Simon Y. Blackwell, AnyWhichWay
//     MIT License - http://opensource.org/licenses/mit-license.php
(function() {
	"use strict";
	// soundex from https://gist.github.com/shawndumas/1262659
	function soundex(s) {
	    var a = s.toLowerCase().split(''),
	    f = a.shift(),
	    r = '',
	    codes = {
	        a: '', e: '', i: '', o: '', u: '',
	        b: 1, f: 1, p: 1, v: 1,
	        c: 2, g: 2, j: 2, k: 2, q: 2, s: 2, x: 2, z: 2,
	        d: 3, t: 3,
	        l: 4,
	        m: 5, n: 5,
	        r: 6
	    };

		r = f +
		    a
		    .map(function (v) { return codes[v] })
		    .filter(function (v, i, a) {
		        return ((i === 0) ? v !== codes[f] : v !== a[i - 1]);
		    })
		    .join('');

		return (r + '000').slice(0, 4).toUpperCase();
	}
	var ProxyConstructor;
	function Validator(config) {
		var me = this;
		if(config) {
			var keys = Object.keys(config);
			keys.forEach(function(key) {
				me[key] = config[key];
				me[key].name = key;
			});
		}
	}
	if(typeof(Proxy)==="undefined"  && typeof(require)==="function") {
		var ProxyConstructor = require('chrome-proxy');
		if(typeof(ProxyConstructor)==="function") {
			var Proxy = ProxyConstructor;
		}
	}
	Validator.prototype.bind = function(constructorOrObject,onerror,name) {
		function validate(target,property,value,proxy,skipset,skiponerror,error) {
			var validation = validator[property], keys, error;
			if(validation) {
				keys = Object.keys(validation);
				try {
					value = (validation.transform ? Validator.validation.transform(validation.transform,value) : value);
				} catch(e) {
					error = (error ? error : new Validator.ValidationError(target));
					error.errors[property] = (error.errors[property] ? error.errors[property] : {});
					error.errors[property].value = (value===undefined ? null : value);
					error.errors[property].validation = (error.errors[property].validation ? error.errors[property].validation : {});
					error.errors[property].validation.transform = {constraint: validation.transform};
					error.errors[property].validation.transform.error = e;
				}
				keys.forEach(function(key) {
					if(typeof(Validator.validation[key])==="function" && key!=="transform") {
						var result = Validator.validation[key](validation[key],value);
						if(!result) {
							error = (error ? error : new Validator.ValidationError(target));
							error.errors[property] = (error.errors[property] ? error.errors[property] : {});
							error.errors[property].value = (value===undefined ? null : value);
							error.errors[property].validation = (error.errors[property].validation ? error.errors[property].validation : {});
							error.errors[property].validation[key] = {constraint: validation[key]};
							var msg = property + ":" + (typeof(value)==="string" ? "\"" + value + "\"" : (value instanceof Object ? JSON.stringify(value) : value)) + " failed validation {\"" + key + "\":" + JSON.stringify(error.errors[property].validation[key]) + "}";
							Validator.validation.type.onError = TypeError;
							var propertyerror = new (Validator.validation[key].onError ? Validator.validation[key].onError : Error)(msg);
							error.errors[property].validation[key].error = propertyerror;
						}
					}
				});
			}
			if(error) {
				if(!skiponerror && onerror) {
					onerror(error)
				} else {
					throw error;
				}
			} else  {
				if(!skipset) {
					target[property] = value;
				}
				return true;
			}
		}
		function validateInstance(trap) {
			var me = this, keys = Object.keys(me), error;
			keys.forEach(function(key) {
				var value = me[key];
				if(typeof(value)!=="function") {
					try {
						validate(me,key,value,undefined,true,true,error);
					} catch(e) {
						error = e;
					}
				}
			});
			if(trap) {
				return error;
			}
			if(onerror) {
				if(error) {
					onerror(error);
				}
			} else if(error) {
				throw error;
			}
		}
		name = (name ? name : (constructorOrObject.name ? constructorOrObject.name : "anonymous"));
		var validator = this, cons;
		var handler = {
			deleteProperty: function(target,property,proxy) {
				var validation = validator[property];
				if(Validator.validation.required(validation.required,undefined)) {
					delete target[property];
					return true;
				}
				handler.set(target,property,undefined,proxy,true);
			},
			defineProperty: function(target, property, descriptor, proxy) {
				if(handler.set(target, property, descriptor.value, proxy, true)) {
					Object.defineProperty(target, property, descriptor);
				}
			},
			set: validate
		};
		if(constructorOrObject instanceof Function) {
			cons = Function("cons","hndlr","prxy","return function " + name + "() { cons.apply(this,arguments); return new prxy(this,hndlr);  }")(constructorOrObject,handler,Proxy);
			cons.prototype = Object.create(constructorOrObject.prototype);
			cons.prototype.__kind__ = name;
			cons.prototype.constructor = cons;
			cons.prototype.validate = validateInstance;
			return cons;
		} else {
			constructorOrObject.validate = validateInstance;
		}
		return new Proxy(constructorOrObject,handler);
	}
	Validator.ValidationError = function(object) {
		this.object = object;
		this.errors = {};
	}
	Validator.ValidationError.prototype = Object.create(Error.prototype);
	Validator.ValidationError.prototype.constructor = Validator.ValidationError;
	Validator.validation = {};

	Validator.validation.transform = function(f,value) {
		return f(value);
	}
	Validator.validation.transform.onError = TypeError;

	Validator.validation.between = function(between,value) {
		between.sort(function(a,b) { return a - b; });
		var min = between[0];
		var max = between[between.length-1];
		return value>=min && value<=max;
	}
	Validator.validation.between.onError = RangeError;

	Validator.validation.echoes = function(echoes,value) {
		return soundex(echoes)===soundex(value);
	}
	Validator.validation.echoes.onError = RangeError;

	Validator.validation.in = function(values,value) {
		return values.indexOf(value)>=0;
	}
	Validator.validation.in.onError = RangeError;

	Validator.validation.length = function(length,value) {
		if(length instanceof Array) {
			length.sort(function(a,b) { return a - b; });
			var min = length[0];
			var max = length[length.length-1];
			return (value && (value.length>=min && value.length<=max) || (value.count>=min && value.count<=max));
		}
		return value && (value.length===length || value.count===length);
	}
	Validator.validation.length.onError = RangeError;

	Validator.validation.matches = function(regex,value) {
		return new RegExp(regex).test(value);
	}
	Validator.validation.matches.onError = RangeError;

	Validator.validation.max = function(max,value) {
		return value<=max;
	}
	Validator.validation.max.onError = RangeError;

	Validator.validation.min = function(min,value) {
		return value>=min;
	}
	Validator.validation.min.onError = RangeError;

	Validator.validation.required = function(required,value) {
		return (required ? value!==undefined : true);
	}
	Validator.validation.required.onError = TypeError;

	Validator.validation.satisfies = function(satisfies,value) {
		return satisfies(value);
	}
	Validator.validation.satisfies.onError = RangeError;

	Validator.validation.type = function(type,value) {
		var tel = {
				us: /^[01]?[- .]?\(?[2-9]\d{2}\)?[- .]?\d{3}[- .]?\d{4}$/
		};
		if(typeof(value)===type) {
			return true;
		}
		if(typeof(type)==="function") {
			return value instanceof type;
		}
		if(type==="SSN") {
			return /^\d{3}-\d{2}-\d{4}$/.test(value);
		}
		if(type==="latlon") {
			// David Jacobs via http://www.regexlib.com/
			return /(-?(90[ :°d]*00[ :\'\'m]*00(\.0+)?|[0-8][0-9][ :°d]*[0-5][0-9][ :\'\'m]*[0-5][0-9](\.\d+)?)[ :\?\"s]*(N|n|S|s)?)[ ,]*(-?(180[ :°d]*00[ :\'\'m]*00(\.0+)?|(1[0-7][0-9]|0[0-9][0-9])[ :°d]*[0-5][0-9][ :\'\'m]*[0-5][0-9](\.\d+)?)[ :\?\"s]*(E|e|W|w)?)/.test(value);
		}
		if(type.indexOf("tel")===0) {
			var split = type.split(".");
			split.shift();
			if(split.length===0) {
				split.push("us");
			}
			return split.some(function(country) {
				if(tel[country]) {
					return tel[country].test(value);
				}
			});
		}
		return false;
	}
	Validator.validation.type.onError = TypeError;

	if (this.exports) {
		this.exports  = Validator;
	} else if (typeof define === 'function' && define.amd) {
		// Publish as AMD module
		define(function() {return Proxy;});
	} else {
		this.Validator = Validator;
	}
}).call((typeof(window)!=='undefined' ? window : (typeof(module)!=='undefined' ? module : null)));<|endoftext|>


<commit_before>var telegram = require('telegram-bot-api');
var _ = require('lodash');
var fs = require('fs');

(function() {
	var Game = function() {
		this.process = function(message) {
			if(message.text !== '/game') {
				return;
			}

			var sender = resolveSender(message);

			if(settings.timedOut) {
				api.sendMessage({
					chat_id: sender.id,
					text: 'A game invite was recently sent out, please wait before sending out another.'
				});

				return;
			}

			if(sender.muted) {
				api.sendMessage({
					chat_id: sender.id,
					text: 'You cannot send out game invites while muted.'
				});

				return;
			}

			_.each(users, function(user) {
				if(user.id !== sender.id && !user.muted) {
					api.sendMessage({
						chat_id: user.id,
						text: sender.name + ' has sent out a game invite.'
					});
				}
			});

			timeout(60);
		}
	};

	var Start = function() {
		this.process = function(message) {
			if(message.text !== '/start' && message.text !== '/unmute') {
				return;
			}

			var sender = resolveSender(message);

			if(sender.muted) {
				sender.muted = false;
				saveUsers();
			}
		}
	};

	var Mute = function() {
		this.process = function(message) {
			if(message.text !== '/mute') {
				return;
			}

			var sender = resolveSender(message);

			if(!sender.muted) {
				sender.muted = true;
				saveUsers();
			}
		}
	};

	var keys = require('./keys.json');

	var api = new telegram({
		token: keys.token,
		updates: {
			enabled: true
		}
	});

	var settings = {
		targetChatId: keys.gameInvitesChat,
		usersFile: './users.json',
		commands: [
			new Game(),
			new Start(),
			new Mute()
		],
		timeoutDuration: 300,
		timedOut: false
	};

	var users = require(settings.usersFile);

	function registerUser(userDto) {
		var found = _.find(users, function(user) {
			return user.id === userDto.id;
		});

		if(_.isUndefined(found)) {
			users.push({
				id: userDto.id,
				name: userDto.first_name,
				muted: false
			});

			saveUsers();
		}
	}

	function saveUsers() {
		fs.writeFile(settings.usersFile, JSON.stringify(users), function(error) {
			if(error) {
				console.log('Errored');
			}
		});
	}

	function timeout(seconds) {
		settings.timedOut = true;

		setTimeout(function() {
			this.timedOut = false;
		}, seconds);
	}

	function resolveSender(message) {
		return _.find(users, function(user) {
			return message.from.id === user.id;
		});
	}

	api.on('message', function(message) {
		if(message.chat.id !== settings.targetChatId) {
			return;
		}

		registerUser(message.from);

		_.each(settings.commands, function(cmd) {
			cmd.process(message);
		});
	});
}());<commit_msg>Convert tabs to spaces.<commit_after>var telegram = require('telegram-bot-api');
var _ = require('lodash');
var fs = require('fs');

(function() {
    var Game = function() {
        this.process = function(message) {
            if(message.text !== '/game') {
                return;
            }

            var sender = resolveSender(message);

            if(settings.timedOut) {
                api.sendMessage({
                    chat_id: sender.id,
                    text: 'A game invite was recently sent out, please wait before sending out another.'
                });

                return;
            }

            if(sender.muted) {
                api.sendMessage({
                    chat_id: sender.id,
                    text: 'You cannot send out game invites while muted.'
                });

                return;
            }

            _.each(users, function(user) {
                if(user.id !== sender.id && !user.muted) {
                    api.sendMessage({
                        chat_id: user.id,
                        text: sender.name + ' has sent out a game invite.'
                    });
                }
            });

            timeout(60);
        }
    };

    var Start = function() {
        this.process = function(message) {
            if(message.text !== '/start' && message.text !== '/unmute') {
                return;
            }

            var sender = resolveSender(message);

            if(sender.muted) {
                sender.muted = false;
                saveUsers();
            }
        }
    };

    var Mute = function() {
        this.process = function(message) {
            if(message.text !== '/mute') {
                return;
            }

            var sender = resolveSender(message);

            if(!sender.muted) {
                sender.muted = true;
                saveUsers();
            }
        }
    };

    var keys = require('./keys.json');

    var api = new telegram({
        token: keys.token,
        updates: {
            enabled: true
        }
    });

    var settings = {
        targetChatId: keys.gameInvitesChat,
        usersFile: './users.json',
        commands: [
            new Game(),
            new Start(),
            new Mute()
        ],
        timeoutDuration: 300,
        timedOut: false
    };

    var users = require(settings.usersFile);

    function registerUser(userDto) {
        var found = _.find(users, function(user) {
            return user.id === userDto.id;
        });

        if(_.isUndefined(found)) {
            users.push({
                id: userDto.id,
                name: userDto.first_name,
                muted: false
            });

            saveUsers();
        }
    }

    function saveUsers() {
        fs.writeFile(settings.usersFile, JSON.stringify(users), function(error) {
            if(error) {
                console.log('Errored');
            }
        });
    }

    function timeout(seconds) {
        settings.timedOut = true;

        setTimeout(function() {
            this.timedOut = false;
        }, seconds);
    }

    function resolveSender(message) {
        return _.find(users, function(user) {
            return message.from.id === user.id;
        });
    }

    api.on('message', function(message) {
        if(message.chat.id !== settings.targetChatId) {
            return;
        }

        registerUser(message.from);

        _.each(settings.commands, function(cmd) {
            cmd.process(message);
        });
    });
}());<|endoftext|>