<commit_before>//Regex patterns
var ALPHA_NUMERIC_PLUS_UNDERSCORE_REGEX = "^[A-Za-z0-9_]+$";
var ALPHA_NUMERIC_PLUS_UNDERSCORE_REGEX_NOT_STARTING_WITH_NUMBER = "^[A-Za-z_][A-Za-z0-9_]+$";
var VERSION_REGEX = "^[A-Za-z0-9_.-]+$";

//Environment key validation
function validateEnvKey(envKey){
    var envKeyRegex = new RegExp(ALPHA_NUMERIC_PLUS_UNDERSCORE_REGEX_NOT_STARTING_WITH_NUMBER);
    var validator;
    if (!envKeyRegex.test(envKey)) {
        validator = {
            status: false,
            msg: "Only alphanumeric characters and underscore are allowed for Environmental Variable key. And cannot start with a number."
        }
    } else {
        validator = {
            status: true,
            msg: "Environment variable key is successfully added."
        }
    }
    return validator;
}

/**
 * Method to validate database name
 *
 * @param databaseName database name
 * @returns {if database name is valid or not}
 */
function validateDbName(databaseName) {
    var databaseNameRegex = new RegExp(ALPHA_NUMERIC_PLUS_UNDERSCORE_REGEX);
    var validator;
    if (!databaseNameRegex.test(databaseName)) {
        validator = {
            status: false,
            msg: "Only alphanumeric characters and underscore are allowed."
        }
    } else {
        validator = {
            status: true,
            msg: "Database name is valid."
        }
    }
    return validator;
}

//Validated the application version provided by user
function validateApplicationVersion(version) {
    var versionRegex = new RegExp(VERSION_REGEX);
    var validator;
    if (!versionRegex.test(version)) {
        validator = {
            status: false,
            msg: "Invalid characters found for application version. Valid char set [a-z, A-Z, 0-9, -, _, .]"
        }
    } else if (version.toLowerCase() == "ballerina-composer".toLowerCase())  {
        validator = {
            status: false,
            msg: "Version cannot be 'ballerina-composer'."
        }
    } else {
        validator = {
            status: true,
            msg: "Version validation is successful."
        }
    }
    return validator;
}

// validate the application name provided by user
function validateAlphaNumeric(value) {
    var validator;
    var NonAlphaNumRegex = new RegExp(ALPHA_NUMERIC_PLUS_UNDERSCORE_REGEX);
    if (value == null || value.trim().length == 0) {
        validator = {
            status: false,
            msg: "Application name cannot be empty'."
        }
    } else if (!isNaN(value)) {
        validator = {
            status: false,
            msg: "Non-alphanumeric characters are not allowed for Application Name"
        }
    } else if (!NonAlphaNumRegex.test(value)) {
        validator = {
            status: false,
            msg: "Non-alphanumeric characters are not allowed for Application Name"
        }
    } else {
        validator = {
            status: true,
        }
    }
    return validator;
}
<commit_msg>Updated Fixed 'create application starts evn the application name is invalid'<commit_after>//Regex patterns
var ALPHA_NUMERIC_PLUS_UNDERSCORE_REGEX = "^[A-Za-z0-9_]+$";
var ALPHA_NUMERIC_PLUS_UNDERSCORE_REGEX_NOT_STARTING_WITH_NUMBER = "^[A-Za-z_][A-Za-z0-9_]+$";
var VERSION_REGEX = "^[A-Za-z0-9_.-]+$";

//Environment key validation
function validateEnvKey(envKey){
    var envKeyRegex = new RegExp(ALPHA_NUMERIC_PLUS_UNDERSCORE_REGEX_NOT_STARTING_WITH_NUMBER);
    var validator;
    if (!envKeyRegex.test(envKey)) {
        validator = {
            status: false,
            msg: "Only alphanumeric characters and underscore are allowed for Environmental Variable key. And cannot start with a number."
        }
    } else {
        validator = {
            status: true,
            msg: "Environment variable key is successfully added."
        }
    }
    return validator;
}

/**
 * Method to validate database name
 *
 * @param databaseName database name
 * @returns {if database name is valid or not}
 */
function validateDbName(databaseName) {
    var databaseNameRegex = new RegExp(ALPHA_NUMERIC_PLUS_UNDERSCORE_REGEX);
    var validator;
    if (!databaseNameRegex.test(databaseName)) {
        validator = {
            status: false,
            msg: "Only alphanumeric characters and underscore are allowed."
        }
    } else {
        validator = {
            status: true,
            msg: "Database name is valid."
        }
    }
    return validator;
}

//Validated the application version provided by user
function validateApplicationVersion(version) {
    var versionRegex = new RegExp(VERSION_REGEX);
    var validator;
    if (!versionRegex.test(version)) {
        validator = {
            status: false,
            msg: "Invalid characters found for application version. Valid char set [a-z, A-Z, 0-9, -, _, .]"
        }
    } else if (version.toLowerCase() == "ballerina-composer".toLowerCase())  {
        validator = {
            status: false,
            msg: "Version cannot be 'ballerina-composer'."
        }
    } else {
        validator = {
            status: true,
            msg: "Version validation is successful."
        }
    }
    return validator;
}

// validate the application name provided by user
function validateAlphaNumeric(value) {
    var validator;
    var NonAlphaNumRegex = new RegExp(ALPHA_NUMERIC_PLUS_UNDERSCORE_REGEX);
    if (value == null || value.trim().length == 0) {
        validator = {
            status: false,
            msg: "Application name cannot be empty"
        }
    } else if (!isNaN(value)) {
        validator = {
            status: false,
            msg: "Non-alphanumeric characters are not allowed for Application Name"
        }
    } else if (!NonAlphaNumRegex.test(value)) {
        validator = {
            status: false,
            msg: "Non-alphanumeric characters are not allowed for Application Name"
        }
    } else {
        validator = {
            status: true,
        }
    }
    return validator;
}
<|endoftext|>


<commit_before>/* global config,  XMLHttpRequest, console, APP, JSON */

var TranscriptionService = require("./AbstractTranscriptionService");
var Word = require( "../word");
var audioRecorder = require("./../audioRecorder");

/**
 * Implements a TranscriptionService for a Sphinx4 http server
 */
var SphinxService = function() {
    //set the correct url
    this.url = getURL();
};

/**
 * Subclass of AbstractTranscriptionService
 */
SphinxService.prototype = Object.create(TranscriptionService.prototype);

/**
 * Set the right constructor
 */
SphinxService.constructor = SphinxService;

/**
 * Overrides the sendRequest method from AbstractTranscriptionService
 * it will send the audio stream the a Sphinx4 server to get the transcription
 *
 * @param audioFileBlob the recorder audio stream an a single Blob
 * @param callback the callback function retrieving the server response
 */
SphinxService.prototype.sendRequest = function(audioFileBlob, callback) {
    console.log("sending an audio file  to " + this.url);
    console.log("the audio file being sent: " + audioFileBlob);
    var request = new XMLHttpRequest();
    request.onreadystatechange = function() {
        if(request.readyState === XMLHttpRequest.DONE && request.status === 200)
        {
            callback(request.responseText);
        }
        else if (request.readyState === XMLHttpRequest.DONE) {
            throw new Error("unable to accept response from sphinx server." +
                "status: " + request.status);
        }
        //if not ready no point to throw an error
    };
    request.open("POST", this.url);
    request.setRequestHeader("Content-Type",
        audioRecorder.determineCorrectFileType());
    request.send(audioFileBlob);
    console.log("send " + audioFileBlob);
};

/**
 * Overrides the formatResponse method from AbstractTranscriptionService
 * It will parse the answer from the server in the expected format
 *
 * @param response the JSON body retrieved from the Sphinx4 server
 */
SphinxService.prototype.formatResponse = function(response) {
    var result = JSON.parse(response).objects;
    //make sure to delete the session id object, which is always
    //the first value in the JSON array
    result.shift();
    var array = [];
    result.forEach(function(word){
        if(!word.filler) {
            array.push(new Word(word.word, word.start, word.end));
        }
    });
    return array;
};

/**
 * checks wether the reply is empty, or doesn't contain a correct JSON object
 * @param response the server response
 * @return {boolean} whether the response is valid
 */
SphinxService.prototype.verify = function(response){
    console.log("response from server:" + response.toString());
    //test if server responded with a string object
    if(typeof(response) !== "string"){
        return false;
    }
    //test if the string can be parsed into valid JSON
    var json;
    try{
        json = JSON.parse(response);
    }
    catch (error){
        console.log(error);
        return false;
    }
    //check if the JSON has a "objects" value
    if(json.objects === undefined){
        return false;
    }
    //get the "objects" value and check for a session ID
    var array = json.objects;
    if(!(array[0] && array[0]["session-id"])){
        return false;
    }
    //everything seems to be in order
    return true;
};

/**
 * Gets the URL to the Sphinx4 server from the config file. If it's not there,
 * it will throw an error
 *
 * @returns {string} the URL to the sphinx4 server
 */
function getURL() {
    var message = "config does not contain an url to a " +
    "Sphinx4 https server";
    if(config.sphinxURL === undefined){
        throw new Error(message);
    }
    else {
        var toReturn = config.sphinxURL;
        if(toReturn.includes !== undefined && toReturn.includes("https://")){
            return toReturn;
        }
        else{
            throw new Error(message);
        }
    }
}

module.exports = SphinxService;<commit_msg>Sphinx now logs the error instead of throwing it<commit_after>/* global config,  XMLHttpRequest, console, APP, JSON */

var TranscriptionService = require("./AbstractTranscriptionService");
var Word = require( "../word");
var audioRecorder = require("./../audioRecorder");

/**
 * Implements a TranscriptionService for a Sphinx4 http server
 */
var SphinxService = function() {
    //set the correct url
    this.url = getURL();
};

/**
 * Subclass of AbstractTranscriptionService
 */
SphinxService.prototype = Object.create(TranscriptionService.prototype);

/**
 * Set the right constructor
 */
SphinxService.constructor = SphinxService;

/**
 * Overrides the sendRequest method from AbstractTranscriptionService
 * it will send the audio stream the a Sphinx4 server to get the transcription
 *
 * @param audioFileBlob the recorder audio stream an a single Blob
 * @param callback the callback function retrieving the server response
 */
SphinxService.prototype.sendRequest = function(audioFileBlob, callback) {
    console.log("sending an audio file  to " + this.url);
    console.log("the audio file being sent: " + audioFileBlob);
    var request = new XMLHttpRequest();
    request.onreadystatechange = function() {
        if(request.readyState === XMLHttpRequest.DONE && request.status === 200)
        {
            callback(request.responseText);
        }
        else if (request.readyState === XMLHttpRequest.DONE) {
            throw new Error("unable to accept response from sphinx server." +
                "status: " + request.status);
        }
        //if not ready no point to throw an error
    };
    request.open("POST", this.url);
    request.setRequestHeader("Content-Type",
        audioRecorder.determineCorrectFileType());
    request.send(audioFileBlob);
    console.log("send " + audioFileBlob);
};

/**
 * Overrides the formatResponse method from AbstractTranscriptionService
 * It will parse the answer from the server in the expected format
 *
 * @param response the JSON body retrieved from the Sphinx4 server
 */
SphinxService.prototype.formatResponse = function(response) {
    var result = JSON.parse(response).objects;
    //make sure to delete the session id object, which is always
    //the first value in the JSON array
    result.shift();
    var array = [];
    result.forEach(function(word){
        if(!word.filler) {
            array.push(new Word(word.word, word.start, word.end));
        }
    });
    return array;
};

/**
 * checks wether the reply is empty, or doesn't contain a correct JSON object
 * @param response the server response
 * @return {boolean} whether the response is valid
 */
SphinxService.prototype.verify = function(response){
    console.log("response from server:" + response.toString());
    //test if server responded with a string object
    if(typeof(response) !== "string"){
        return false;
    }
    //test if the string can be parsed into valid JSON
    var json;
    try{
        json = JSON.parse(response);
    }
    catch (error){
        console.log(error);
        return false;
    }
    //check if the JSON has a "objects" value
    if(json.objects === undefined){
        return false;
    }
    //get the "objects" value and check for a session ID
    var array = json.objects;
    if(!(array[0] && array[0]["session-id"])){
        return false;
    }
    //everything seems to be in order
    return true;
};

/**
 * Gets the URL to the Sphinx4 server from the config file. If it's not there,
 * it will throw an error
 *
 * @returns {string} the URL to the sphinx4 server
 */
function getURL() {
    var message = "config does not contain an url to a " +
    "Sphinx4 https server";
    if(config.sphinxURL === undefined){
        console.log(message);
    }
    else {
        var toReturn = config.sphinxURL;
        if(toReturn.includes !== undefined && toReturn.includes("https://")){
            return toReturn;
        }
        else{
            console.log(message);
        }
    }
}

module.exports = SphinxService;<|endoftext|>


<commit_before>function Component()
{
    // constructor
}

Component.prototype.isDefault = function()
{
    // select the component by default
    return true;
}

function createShortcuts()
{
    var windir = installer.environmentVariable("WINDIR");
    if (windir === "") {
        QMessageBox["warning"]( "Error" , "Error", "Could not find windows installation directory");
        return;
    }

    var cmdLocation = windir + "\\system32\\cmd.exe";
    component.addOperation( "CreateShortcut",
                            cmdLocation,
                            "@StartMenuDir@/MSYS2 Shell.lnk",
                            "/A /Q /K " + installer.value("TargetDir") + "\\msys2_shell.bat");

    component.addOperation( "CreateShortcut",
                            cmdLocation,
                            "@StartMenuDir@/MinGW-w64 Win32 Shell.lnk",
                            "/A /Q /K " + installer.value("TargetDir") + "\\mingw32_shell.bat");

    component.addOperation( "CreateShortcut",
                            cmdLocation,
                            "@StartMenuDir@/MinGW-w64 Win64 Shell.lnk",
                            "/A /Q /K " + installer.value("TargetDir") + "\\mingw64_shell.bat");

    if ("@BITNESS@bit" === "32bit") {
        component.addOperation( "Execute",
                               ["@TargetDir@\\autorebase.bat"]);
    }

    component.addOperation( "Execute",
                           ["@TargetDir@\\usr\\bin\\bash.exe", "--login", "-c", "exit"]);
}

Component.prototype.createOperations = function()
{
    component.createOperations();
    createShortcuts();
}
<commit_msg>Start Menu shortcuts: use proper cmd flags for launching shells<commit_after>function Component()
{
    // constructor
}

Component.prototype.isDefault = function()
{
    // select the component by default
    return true;
}

function createShortcuts()
{
    var windir = installer.environmentVariable("WINDIR");
    if (windir === "") {
        QMessageBox["warning"]( "Error" , "Error", "Could not find windows installation directory");
        return;
    }

    var cmdLocation = windir + "\\system32\\cmd.exe";
    component.addOperation( "CreateShortcut",
                            cmdLocation,
                            "@StartMenuDir@/MSYS2 Shell.lnk",
                            "/A /Q /C " + installer.value("TargetDir") + "\\msys2_shell.bat");

    component.addOperation( "CreateShortcut",
                            cmdLocation,
                            "@StartMenuDir@/MinGW-w64 Win32 Shell.lnk",
                            "/A /Q /C " + installer.value("TargetDir") + "\\mingw32_shell.bat");

    component.addOperation( "CreateShortcut",
                            cmdLocation,
                            "@StartMenuDir@/MinGW-w64 Win64 Shell.lnk",
                            "/A /Q /C " + installer.value("TargetDir") + "\\mingw64_shell.bat");

    if ("@BITNESS@bit" === "32bit") {
        component.addOperation( "Execute",
                               ["@TargetDir@\\autorebase.bat"]);
    }

    component.addOperation( "Execute",
                           ["@TargetDir@\\usr\\bin\\bash.exe", "--login", "-c", "exit"]);
}

Component.prototype.createOperations = function()
{
    component.createOperations();
    createShortcuts();
}
<|endoftext|>


<commit_before>var assert = require('assert');
var utils = require('./utils.js');

// Can swap out different backing stores
function TypedArrayBackingStore(ArrayType) {
	return {
		ArrayType: ArrayType,
		set: function(tgt, src, offset) {
			tgt.set(src, offset);
		}
	}
}
var ArrayBackingStore = {
	ArrayType: Array,
	set: function(tgt, src, offset) {;
		for (var i = 0; i < src.length; i++) {
			tgt[i+offset] = src[i];
		}
	}
};

// The actual backing store we're using
var BackingStore = TypedArrayBackingStore(Float64Array);

function Tensor(dims) {
	this.dims = dims;
	var size = 1;
	var n = dims.length;
	while (n--) size *= dims[n];
	this.length = size;
	this.data = new BackingStore.ArrayType(size);
	return this;
}

Object.defineProperties(Tensor.prototype, {
	rank: { get: function() { return this.dims.length; } },
});

Tensor.prototype.reshape = function(dims) {
	var size = 1;
	var n = dims.length;
	while (n--) size *= dims[n];
	assert(size === this.length, 'Tensor reshape invalid size');
	this.dims = dims;
}

Tensor.prototype.fill = function(val) {
	// TODO: Use TypedArray.fill, when it is more broadly supported
	var n = this.length;
	while (n--) this.data[n] = val;
	return this;
};

Tensor.prototype.zero = function() {
	return this.fill(0);
};

// Adapted from:
//    https://github.com/karpathy/convnetjs/blob/master/src/convnet_vol.js
Tensor.prototype.fillRandom = function() {
	var scale = 1/this.length;
	var n = this.length;
	while (n--) this.data[n] = utils.gaussianSample(0, scale);
	return this;
}

Tensor.prototype.copy = function(other, offset) {
	offset = offset || 0;
	BackingStore.set(this.data, other.data, offset);
	return this;
};

Tensor.prototype.clone = function() {
	var copy = new Tensor(this.dims);
	return copy.copy(this);
};

// These are slow; don't use them inside any hot loops (i.e. they're good for
//    debgugging/translating data to/from other formats, and not much else)
Tensor.prototype.get = function(coords) {
	var idx = 0;
	var n = this.dims.length;
	for (var i = 0; i < n; i++) {
		idx = idx * this.dims[i] + coords[i];
	}
	return this.data[idx];
};
Tensor.prototype.set = function(coords, val) {
	var idx = 0;
	var n = this.dims.length;
	for (var i = 0; i < n; i++) {
		idx = idx * this.dims[i] + coords[i];
	}
	this.data[idx] = val;
};
function toArrayRec(tensor, coords) {
	if (coords.length === tensor.rank) {
		return tensor.get(coords);
	} else {
		var dim = coords.length;
		var arr = [];
		for (var i = 0; i < tensor.dims[dim]; i++) {
			arr.push(toArrayRec(tensor, coords.concat([i])));
		}
		return arr;
	}
}
Tensor.prototype.toArray = function() {
	return toArrayRec(this, []);
};
function fromArrayRec(tensor, coords, x) {
	if (!(x instanceof Array)) {
		tensor.set(coords, x);
	} else {
		var dim = coords.length;
		for (var i = 0; i < tensor.dims[dim]; i++) {
			fromArrayRec(tensor, coords.concat([i]), x[i]);
		}
	}
}
Tensor.prototype.fromArray = function(arr) {
	fromArrayRec(this, [], arr);
	return this;
};

Tensor.prototype.toString = function() {
	return this.toArray();
};

Tensor.prototype.toFlatArray = function() {
	return Array.prototype.slice.call(this.data);
}
Tensor.prototype.fromFlatArray = function(arr) {
	BackingStore.set(this.data, arr, 0);
	return this;
}

function addUnaryMethod(name, fncode) {
	var fneq = new Function([
		'var n = this.data.length;',
		'while (n--) {',
		'	var x = this.data[n];',
		'	this.data[n] = ' + fncode + ';',
		'}',
		'return this;'
	].join('\n'));
	Tensor.prototype[name + 'eq'] = fneq;
	Tensor.prototype[name] = function() {
		var nt = this.clone();
		return fneq.call(nt);
	};
}

function addBinaryMethod(name, fncode) {
	var fneqS = new Function('s', [
		'var n = this.data.length;',
		'var b = s;',
		'while (n--) {',
		'	var a = this.data[n];',
		'	this.data[n] = ' + fncode + ';',
		'}',
		'return this;'
	].join('\n'));
	var fneqT = new Function('t', [
		'var n = this.data.length;',
		'while (n--) {',
		'	var a = this.data[n];',
		'	var b = t.data[n];',
		'	this.data[n] = ' + fncode + ';',
		'}',
		'return this;'
	].join('\n'));

	var fneq = function(x) {
		if (x.constructor === Tensor)
			return fneqT.call(this, x);
		else
			return fneqS.call(this, x);
	}
	Tensor.prototype[name + 'eq'] = fneq;
	Tensor.prototype[name] = function(x) {
		var nt = this.clone();
		return fneq.call(nt, x);
	};
}

function addReduction(name, initcode, fncode) {
	Tensor.prototype[name+'reduce'] = new Function([
		'var accum = ' + initcode + ';',
		'var n = this.data.length;',
		'while (n--) {',
		'	var x = this.data[n];',
		'	accum = ' + fncode + ';',
		'}',
		'return accum;'
	].join('\n'));
}

addUnaryMethod('neg', '-x');
addUnaryMethod('round', 'Math.round(x)');
addUnaryMethod('log', 'Math.log(x)');
addUnaryMethod('exp', 'Math.exp(x)');
addUnaryMethod('sqrt', 'Math.sqrt(x)');
addUnaryMethod('abs', 'Math.abs(x)');
addUnaryMethod('ceil', 'Math.ceil(x)');
addUnaryMethod('floor', 'Math.floor(x)');
addUnaryMethod('cos', 'Math.cos(x)');
addUnaryMethod('sin', 'Math.sin(x)');
addUnaryMethod('tan', 'Math.tan(x)');
addUnaryMethod('acos', 'Math.acos(x)');
addUnaryMethod('asin', 'Math.asin(x)');
addUnaryMethod('atan', 'Math.atan(x)');
addUnaryMethod('cosh', 'Math.cosh(x)');
addUnaryMethod('sinh', 'Math.sinh(x)');
addUnaryMethod('tanh', 'Math.tanh(x)');
addUnaryMethod('acosh', 'Math.acosh(x)');
addUnaryMethod('asinh', 'Math.asinh(x)');
addUnaryMethod('atanh', 'Math.atanh(x)');
addUnaryMethod('sigmoid', '1 / (1 + Math.exp(-x))');
addUnaryMethod('isFinite', 'isFinite(x)');
addUnaryMethod('isNaN', 'isNaN(x)');
addUnaryMethod('invert', '1/x');
addUnaryMethod('pseudoinvert', 'x === 0 ? 0 : 1/x');

addBinaryMethod('add', 'a + b');
addBinaryMethod('sub', 'a - b');
addBinaryMethod('mul', 'a * b');
addBinaryMethod('div', 'a / b');
addBinaryMethod('mod', 'a % b');
addBinaryMethod('min', 'Math.min(a, b)');
addBinaryMethod('max', 'Math.max(a, b)');
addBinaryMethod('pow', 'Math.pow(a, b)');
addBinaryMethod('atan2', 'Math.atan2(a, b)');
addBinaryMethod('eq', 'a === b');
addBinaryMethod('neq', 'a !== b');
addBinaryMethod('gt', 'a > b');
addBinaryMethod('ge', 'a >= b');
addBinaryMethod('lt', 'a < b');
addBinaryMethod('le', 'a <= b');

addReduction('sum', '0', 'accum + x');
addReduction('min', 'Infinity', 'Math.min(accum, x)');
addReduction('max', '-Infinity', 'Math.max(accum, x)');
addReduction('all', 'true', 'accum && (x !== 0)');
addReduction('any', 'false', 'accum || (x !== 0)');

module.exports = Tensor;

<commit_msg>Fix bug where tensor Array backing store didn't initialize to all zeros.<commit_after>var assert = require('assert');
var utils = require('./utils.js');

// Can swap out different backing stores
function TypedArrayBackingStore(ArrayType) {
	return {
		new: function(n) { return new ArrayType(n); },
		set: function(tgt, src, offset) {
			tgt.set(src, offset);
		}
	}
}
var ArrayBackingStore = {
	ArrayType: Array,
	new: function(n) {
		var a = new Array(n);
		while (n--) { a[n] = 0; }
		return a;
	},
	set: function(tgt, src, offset) {;
		for (var i = 0; i < src.length; i++) {
			tgt[i+offset] = src[i];
		}
	}
};

// The actual backing store we're using
var BackingStore = TypedArrayBackingStore(Float64Array);

function Tensor(dims) {
	this.dims = dims;
	var size = 1;
	var n = dims.length;
	while (n--) size *= dims[n];
	this.length = size;
	this.data = BackingStore.new(size);
	return this;
}

Object.defineProperties(Tensor.prototype, {
	rank: { get: function() { return this.dims.length; } },
});

Tensor.prototype.reshape = function(dims) {
	var size = 1;
	var n = dims.length;
	while (n--) size *= dims[n];
	assert(size === this.length, 'Tensor reshape invalid size');
	this.dims = dims;
}

Tensor.prototype.fill = function(val) {
	// TODO: Use TypedArray.fill, when it is more broadly supported
	var n = this.length;
	while (n--) this.data[n] = val;
	return this;
};

Tensor.prototype.zero = function() {
	return this.fill(0);
};

// Adapted from:
//    https://github.com/karpathy/convnetjs/blob/master/src/convnet_vol.js
Tensor.prototype.fillRandom = function() {
	var scale = 1/this.length;
	var n = this.length;
	while (n--) this.data[n] = utils.gaussianSample(0, scale);
	return this;
}

Tensor.prototype.copy = function(other, offset) {
	offset = offset || 0;
	BackingStore.set(this.data, other.data, offset);
	return this;
};

Tensor.prototype.clone = function() {
	var copy = new Tensor(this.dims);
	return copy.copy(this);
};

// These are slow; don't use them inside any hot loops (i.e. they're good for
//    debgugging/translating data to/from other formats, and not much else)
Tensor.prototype.get = function(coords) {
	var idx = 0;
	var n = this.dims.length;
	for (var i = 0; i < n; i++) {
		idx = idx * this.dims[i] + coords[i];
	}
	return this.data[idx];
};
Tensor.prototype.set = function(coords, val) {
	var idx = 0;
	var n = this.dims.length;
	for (var i = 0; i < n; i++) {
		idx = idx * this.dims[i] + coords[i];
	}
	this.data[idx] = val;
};
function toArrayRec(tensor, coords) {
	if (coords.length === tensor.rank) {
		return tensor.get(coords);
	} else {
		var dim = coords.length;
		var arr = [];
		for (var i = 0; i < tensor.dims[dim]; i++) {
			arr.push(toArrayRec(tensor, coords.concat([i])));
		}
		return arr;
	}
}
Tensor.prototype.toArray = function() {
	return toArrayRec(this, []);
};
function fromArrayRec(tensor, coords, x) {
	if (!(x instanceof Array)) {
		tensor.set(coords, x);
	} else {
		var dim = coords.length;
		for (var i = 0; i < tensor.dims[dim]; i++) {
			fromArrayRec(tensor, coords.concat([i]), x[i]);
		}
	}
}
Tensor.prototype.fromArray = function(arr) {
	fromArrayRec(this, [], arr);
	return this;
};

Tensor.prototype.toString = function() {
	return this.toArray();
};

Tensor.prototype.toFlatArray = function() {
	return Array.prototype.slice.call(this.data);
}
Tensor.prototype.fromFlatArray = function(arr) {
	BackingStore.set(this.data, arr, 0);
	return this;
}

function addUnaryMethod(name, fncode) {
	var fneq = new Function([
		'var n = this.data.length;',
		'while (n--) {',
		'	var x = this.data[n];',
		'	this.data[n] = ' + fncode + ';',
		'}',
		'return this;'
	].join('\n'));
	Tensor.prototype[name + 'eq'] = fneq;
	Tensor.prototype[name] = function() {
		var nt = this.clone();
		return fneq.call(nt);
	};
}

function addBinaryMethod(name, fncode) {
	var fneqS = new Function('s', [
		'var n = this.data.length;',
		'var b = s;',
		'while (n--) {',
		'	var a = this.data[n];',
		'	this.data[n] = ' + fncode + ';',
		'}',
		'return this;'
	].join('\n'));
	var fneqT = new Function('t', [
		'var n = this.data.length;',
		'while (n--) {',
		'	var a = this.data[n];',
		'	var b = t.data[n];',
		'	this.data[n] = ' + fncode + ';',
		'}',
		'return this;'
	].join('\n'));

	var fneq = function(x) {
		if (x.constructor === Tensor)
			return fneqT.call(this, x);
		else
			return fneqS.call(this, x);
	}
	Tensor.prototype[name + 'eq'] = fneq;
	Tensor.prototype[name] = function(x) {
		var nt = this.clone();
		return fneq.call(nt, x);
	};
}

function addReduction(name, initcode, fncode) {
	Tensor.prototype[name+'reduce'] = new Function([
		'var accum = ' + initcode + ';',
		'var n = this.data.length;',
		'while (n--) {',
		'	var x = this.data[n];',
		'	accum = ' + fncode + ';',
		'}',
		'return accum;'
	].join('\n'));
}

addUnaryMethod('neg', '-x');
addUnaryMethod('round', 'Math.round(x)');
addUnaryMethod('log', 'Math.log(x)');
addUnaryMethod('exp', 'Math.exp(x)');
addUnaryMethod('sqrt', 'Math.sqrt(x)');
addUnaryMethod('abs', 'Math.abs(x)');
addUnaryMethod('ceil', 'Math.ceil(x)');
addUnaryMethod('floor', 'Math.floor(x)');
addUnaryMethod('cos', 'Math.cos(x)');
addUnaryMethod('sin', 'Math.sin(x)');
addUnaryMethod('tan', 'Math.tan(x)');
addUnaryMethod('acos', 'Math.acos(x)');
addUnaryMethod('asin', 'Math.asin(x)');
addUnaryMethod('atan', 'Math.atan(x)');
addUnaryMethod('cosh', 'Math.cosh(x)');
addUnaryMethod('sinh', 'Math.sinh(x)');
addUnaryMethod('tanh', 'Math.tanh(x)');
addUnaryMethod('acosh', 'Math.acosh(x)');
addUnaryMethod('asinh', 'Math.asinh(x)');
addUnaryMethod('atanh', 'Math.atanh(x)');
addUnaryMethod('sigmoid', '1 / (1 + Math.exp(-x))');
addUnaryMethod('isFinite', 'isFinite(x)');
addUnaryMethod('isNaN', 'isNaN(x)');
addUnaryMethod('invert', '1/x');
addUnaryMethod('pseudoinvert', 'x === 0 ? 0 : 1/x');

addBinaryMethod('add', 'a + b');
addBinaryMethod('sub', 'a - b');
addBinaryMethod('mul', 'a * b');
addBinaryMethod('div', 'a / b');
addBinaryMethod('mod', 'a % b');
addBinaryMethod('min', 'Math.min(a, b)');
addBinaryMethod('max', 'Math.max(a, b)');
addBinaryMethod('pow', 'Math.pow(a, b)');
addBinaryMethod('atan2', 'Math.atan2(a, b)');
addBinaryMethod('eq', 'a === b');
addBinaryMethod('neq', 'a !== b');
addBinaryMethod('gt', 'a > b');
addBinaryMethod('ge', 'a >= b');
addBinaryMethod('lt', 'a < b');
addBinaryMethod('le', 'a <= b');

addReduction('sum', '0', 'accum + x');
addReduction('min', 'Infinity', 'Math.min(accum, x)');
addReduction('max', '-Infinity', 'Math.max(accum, x)');
addReduction('all', 'true', 'accum && (x !== 0)');
addReduction('any', 'false', 'accum || (x !== 0)');

module.exports = Tensor;

<|endoftext|>


<commit_before>//Global Functions and Stuff

var SVR_ADDRESS = "http://sshh12.com:8338/";
//var SVR_ADDRESS = "http://10.0.0.2:8338/";

function createDocElement(name, bodytext) { //Magical HTML Parser Object
	var page = document.implementation.createHTMLDocument(name);
	var pagebody = page.createElement("body");
	pagebody.innerHTML = bodytext;
	return pagebody;
}

function isUndefined(value) {
    return typeof value === 'undefined';
}

function encodeToURL(str) {
  return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
    return '%' + c.charCodeAt(0).toString(16);
  });
}

function reduceString(string){
	return string.toLowerCase().replace(",", "").replace(" ", "");
}

function parseXSS(string){
	return string.replace(/;/g, ";")
							 .replace(/=/g, "=")
							 .replace(/</g, "<")
							 .replace(/>/g, ">")
							 .replace(/"/g, """)
							 .replace(/&/g, "&")
							 .replace(/!/g, "!")
							 .replace(/\$/g, "$");
}

function timeout(ms, promise) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      reject(new Error("Connection Timed Out"))
    }, ms)
    promise.then(resolve, reject)
  })
}

function getFromAPI(method){
	return fetch(SVR_ADDRESS + method);
}

function getFromSite(method){
	var xmlHttp = new XMLHttpRequest();
  xmlHttp.open("GET", SVR_ADDRESS + method, false);
  xmlHttp.send( null );
	return xmlHttp.responseText;
}

function AppAlert(title, text){
	navigator.notification.alert(text, function(){ return false; }, title, 'Dismiss');
}
<commit_msg>Now Works with Migrated Backend<commit_after>//Global Functions and Stuff

var SVR_ADDRESS = "https://cfisdapi.herokuapp.com/";
//var SVR_ADDRESS = "http://10.0.0.2:8338/";

function createDocElement(name, bodytext) { //Magical HTML Parser Object
	var page = document.implementation.createHTMLDocument(name);
	var pagebody = page.createElement("body");
	pagebody.innerHTML = bodytext;
	return pagebody;
}

function isUndefined(value) {
    return typeof value === 'undefined';
}

function encodeToURL(str) {
  return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
    return '%' + c.charCodeAt(0).toString(16);
  });
}

function reduceString(string){
	return string.toLowerCase().replace(",", "").replace(" ", "");
}

function parseXSS(string){
	return string.replace(/;/g, ";")
							 .replace(/=/g, "=")
							 .replace(/</g, "<")
							 .replace(/>/g, ">")
							 .replace(/"/g, """)
							 .replace(/&/g, "&")
							 .replace(/!/g, "!")
							 .replace(/\$/g, "$");
}

function timeout(ms, promise) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      reject(new Error("Connection Timed Out"))
    }, ms)
    promise.then(resolve, reject)
  })
}

function getFromAPI(method){
	return fetch(SVR_ADDRESS + method);
}

function getFromSite(method){
	var xmlHttp = new XMLHttpRequest();
  xmlHttp.open("GET", SVR_ADDRESS + method, false);
  xmlHttp.send( null );
	return xmlHttp.responseText;
}

function AppAlert(title, text){
	navigator.notification.alert(text, function(){ return false; }, title, 'Dismiss');
}
<|endoftext|>


<commit_before>//Global Functions and Stuff

var SVR_ADDRESS = "http://sshh12.com:8338/";
//var SVR_ADDRESS = "http://10.0.0.2:8338/";

function createDocElement(name, bodytext) {
	var page = document.implementation.createHTMLDocument(name);
	var pagebody = page.createElement("body");
	pagebody.innerHTML = bodytext;
	return pagebody;
}

function isUndefined(value) {
    return typeof value === 'undefined';
}

function encodeToURL(str) {
  return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
    return '%' + c.charCodeAt(0).toString(16);
  });
}

function reduceString(string){
	return string.toLowerCase().replace(",", "").replace(" ", "");
}

function parseXSS(string){
	return string.replace(/;/g, ";").replace(/=/g, "=").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/&/g, "&").replace(/!/g, "!").replace(/\$/g, "$");
}

function timeout(ms, promise) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      reject(new Error("Connection Timed Out"))
    }, ms)
    promise.then(resolve, reject)
  })
}

function getFromAPI(method){
	return fetch(SVR_ADDRESS + method);
}

function getFromSite(method){
	var xmlHttp = new XMLHttpRequest();
  xmlHttp.open("GET", SVR_ADDRESS + method, false);
  xmlHttp.send( null );
	return xmlHttp.responseText;
}

function AppAlert(title, text){
	navigator.notification.alert(text, function(){ return false; }, title, 'Dismiss');
}
<commit_msg>Minor Changes<commit_after>//Global Functions and Stuff

var SVR_ADDRESS = "http://sshh12.com:8338/";
//var SVR_ADDRESS = "http://10.0.0.2:8338/";

function createDocElement(name, bodytext) { //Magical HTML Parser Object
	var page = document.implementation.createHTMLDocument(name);
	var pagebody = page.createElement("body");
	pagebody.innerHTML = bodytext;
	return pagebody;
}

function isUndefined(value) {
    return typeof value === 'undefined';
}

function encodeToURL(str) {
  return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
    return '%' + c.charCodeAt(0).toString(16);
  });
}

function reduceString(string){
	return string.toLowerCase().replace(",", "").replace(" ", "");
}

function parseXSS(string){
	return string.replace(/;/g, ";")
							 .replace(/=/g, "=")
							 .replace(/</g, "<")
							 .replace(/>/g, ">")
							 .replace(/"/g, """)
							 .replace(/&/g, "&")
							 .replace(/!/g, "!")
							 .replace(/\$/g, "$");
}

function timeout(ms, promise) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      reject(new Error("Connection Timed Out"))
    }, ms)
    promise.then(resolve, reject)
  })
}

function getFromAPI(method){
	return fetch(SVR_ADDRESS + method);
}

function getFromSite(method){
	var xmlHttp = new XMLHttpRequest();
  xmlHttp.open("GET", SVR_ADDRESS + method, false);
  xmlHttp.send( null );
	return xmlHttp.responseText;
}

function AppAlert(title, text){
	navigator.notification.alert(text, function(){ return false; }, title, 'Dismiss');
}
<|endoftext|>


<commit_before>/**
 * Created by Doron Sinai on 23/10/2014.
 */
var mongoose = require('mongoose');
var request = require('request');
var xml2js = require('xml2js');
var moment = require('moment');
var Agenda = require('agenda');
var async = require('async');
var fs = require('fs');
var _ = require('lodash');
var jsdom = require("jsdom").jsdom;
var config = require('config');
var Q = require('q');
var downloadFolder = config.get('downloadFolder');
var winston = require('winston');
require('./winston-config.js');
require("./db.js");
var mailer = require('./mailer.js');
var updater = require('./updater.js');
var debugLogger = winston.loggers.get('all');
var errorLogger = winston.loggers.get('terror');
var parser = xml2js.Parser({
    explicitArray: false,
    normalizeTags: true
});
var apiKey = config.get("apiKey"); //API key for the tv db
var User = mongoose.model('User');
var Show = mongoose.model('Show');
var Episode = mongoose.model('Episode');

function checkAndCreateFolder(folder){
    if(fs.existsSync(folder)){
        return true;
    }
    else{
        fs.mkdirSync(folder);
        if(fs.existsSync(folder)){
            return true;
        }
        return false;
    }
}

function downloadFile(url, folder, defer){
    var ret = [];
    var len = 0;
    var zlib = require("zlib");
    debugLogger.info('Going to download from the following URL: ' + url);
    debugLogger.info('and save it in this folder: ' + folder);
    request({
        url:url,
        gzip:true,
        headers: {
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
        }
    }).on('response', function(res){
        var path = res.request.uri.path.split('/');
        var fileName = path[path.length-1];
        debugLogger.info('Giving it this filename: ' + fileName);

        res.on('data', function (data) {
            ret.push(data);
            len += data.length;
        });

        res.on('end', function(){
            var buffer = Buffer.concat(ret, len);
            var encoding = res.headers['content-encoding'];
            var folderName = downloadFolder + folder + '/';
            if(!checkAndCreateFolder(folderName)){
                errorLogger.error('Can not create folders');
                defer.reject("Error creating folders");
                return;
            }
            var wstream = fs.createWriteStream(folderName + fileName);
            if (encoding == 'gzip') {
                zlib.gunzip(buffer, function(err, decoded) {
                    wstream.write(decoded);
                    wstream.end();
                });
            } else if (encoding == 'deflate') {
                zlib.inflate(buffer, function(err, decoded) {
                    wstream.write(decoded);
                    wstream.end();
                })
            } else {
                wstream.write(buffer.toString());
                wstream.end();
            }
            defer.resolve({
                status:"sucess",
                filename:fileName
            })
        });
    }).on('error', function(err) {
        errorLogger.error('Error while trying to save file ' + err);
        defer.reject("Error downloading file");
    });;
}

function requestSeriesPage(url){
    var debugMessagePrefix = '[' + url.name + ' S' + url.season + 'E' + url.number + '] ';
    var finishedRequest = Q.defer();
    var finishedRequestPromise = finishedRequest.promise;
    debugLogger.info(debugMessagePrefix + 'Going to request the page');

    request({
        url: url.url,
        gzip:true
    },  function(error, response, body) {
        debugLogger.info(debugMessagePrefix + 'Got a response back with status: ' + response.statusCode);
        if (!error && response.statusCode == 200) {
            debugLogger.info(debugMessagePrefix + 'About to parse the dom');
            jsdom.env(
                body,
                ["./jquery-2.1.1.min.js"],
                function (errors, window) {
                    if(errors) {
                        errorLogger.error(errors);
                        finishedRequest.reject("JSDOM error - see logs");
                        return;
                    }
                    if(url.number < 10){
                        url.number = '0' + url.number;
                    }
                    var node = window.$(window.$.find('h3:contains("Season 0' + url.season + '")')).next('div').find('span:contains("Episode ' + url.number + '")').parent().attr("onClick");
                    if(node && node.length > 1){
                        var episodeUrlTorrent = node.split('\'')[1];
                        if(episodeUrlTorrent){
                            debugLogger.info(debugMessagePrefix + 'Found the following episode number: ' + episodeUrlTorrent);
                            finishedRequest.resolve('' + episodeUrlTorrent);
                        }
                    }
                    else{
                        finishedRequest.reject("Did not find season in page");
                    }
                }
            );
        }
        else{
            errorLogger.error(error);
            finishedRequest.reject();
        }
    });

    //do it next
    finishedRequestPromise.then(function(episodeNumber){
        requestEpisodeSegment({episodeNumber: episodeNumber, debugMessagePrefix:debugMessagePrefix, name:url.name, deferred:url.deferred});
    }, function(reason){
        errorLogger.error(reason);
        url.deferred.reject(reason);
    }, function(){});  //.then(onFulfilled, onRejected, onProgress)
}

function requestEpisodeSegment(episode){
    var debugMessagePrefix = episode.debugMessagePrefix;
    var url = 'https://kickass.to/media/getepisode/' + episode.episodeNumber + '/';
    var finishedRequest = Q.defer();
    var finishedRequestPromise = finishedRequest.promise;

    debugLogger.info(debugMessagePrefix + 'Getting segment from: ' + url);

    request({
        url: url,
        gzip:true
    },  function(error, response, body) {
        if (!error && response.statusCode == 200) {
            jsdom.env(
                body,
                ["./jquery-2.1.1.min.js"],
                function (errors, window) {
                    if(errors) {
                        errorLogger.error("requestEpisodeSegment - jsdom - " + errors);
                        finishedRequest.reject("JSDOM error - see logs");
                        return;
                    }
                    debugLogger.info(debugMessagePrefix + "Look for x264 files in segment");
                    var node = window.$(window.$.find('tr:contains("x264")')).find(('a[title="Download torrent file"]'));
                    if (node.length < 1){
                        node = window.$.find('a[title="Download torrent file"]');
                        debugLogger.info(debugMessagePrefix + "No x264 torrents found in page");
                        if(node.length < 1){
                            debugLogger.info(debugMessagePrefix + "No torrents found - rejecting defer obj");
                            finishedRequest.reject("No torrents found");
                            return;
                        }
                    }
                    var nodeUrl = node[0].href;
                    finishedRequest.resolve(nodeUrl);
                }
            );
        }
        else{
            errorLogger.error("requestEpisodeSegment - request - " + error);
            finishedRequest.reject();
        }
    });

    //do it next
    finishedRequestPromise.then(function(nodeUrl){
        debugLogger.info(debugMessagePrefix + "Download file from: " + nodeUrl);
        downloadFile(nodeUrl, episode.name, episode.deferred);
    }, function(reason){
        errorLogger.error(reason);
        episode.deferred.reject(reason);
    }, function(){});  //.then(onFulfilled, onRejected, onProgress)
}

/********************Set some tasks for later *******************/
var agenda = new Agenda({db: { address: 'localhost:27017/agendaJobs'}});

agenda.define('today shows',function(job,done){
    var downloadDays = config.get('downloadDays');
    if(!downloadDays || isNaN(parseInt(downloadDays))){
        downloadDays = 1;
    }
    debugLogger.info('Number of days back to look for: ' +downloadDays);
    async.waterfall([
        // find relevant episode in the db
        function(callback){
            var start = moment().subtract(downloadDays, 'days').hour(0).minute(0).toDate();
            var end = moment().hour(0).minute(0).toDate();
            debugLogger.info('Look for episode in range: ' + start + ' - ' + end);
            Episode.find({firstAired:{$gte:start, $lt:end}},function(err, results){
                _.each(results, function(r){
                    debugLogger.info('Found the following: ', r.episodeId + ':' + r.episodeName);
                })

                if(err) callback(err);
                if(results.length < 1) {
                    debugLogger.info('No episode found for that date range');
                    callback(111);
                }
                callback(null,results);
            });
        },
        //extract the urls of each show to kickass torrents
        function(episodes, callback){
            var urls = [];
            var showsNumbers = {}
            Show.find({},function(err,shows){
                if(err) callback(err);

                for(var i=0; i <shows.length; i++){
                    var o = {}
                    o.url = shows[i].url;
                    o.name = shows[i].name;
                    showsNumbers[shows[i]._id] = o;
                }

                _.each(episodes,function(episode){
                    var u = {};
                    u.season = episode.season;
                    u.number = episode.episodeNumber;
                    u.url = showsNumbers[episode.showId]["url"];
                    u.name = showsNumbers[episode.showId]["name"];
                    if(u.url && (u.url !== "")){
                        urls.push(u);
                    }

                });
                if(urls.length ===0) callback(222);
                callback(null, urls)
            })
        },
        //go get the torrent files urls
        function(urls, callback){
            var promises = [];
            _.each(urls,function(url){
                console.log(url);
                var deferred = Q.defer();
                promises.push(deferred.promise);
                url.deferred = deferred;
                requestSeriesPage(url);
            });

            Q.allSettled(promises).spread(function(){
                var args = arguments;
                var sucessFiles = [];
                var failoureFiles = [];
                var mailSubject = "";
                var mailBody = "";
                var successString = "Success: \n";
                var failureString = "Failure: \n";
                for(var i=0; i<args.length; i++){
                    var promise = args[i];
                    if(promise.state === "fulfilled"){
                        sucessFiles.push(promise.value.filename);
                        successString += promise.value.filename + "\n"
                    }
                    else{
                        failoureFiles.push(promise.value);
                        failureString += promise.value + "\n";
                    }
                }
                if(failoureFiles.length === 0){
                    mailSubject = sucessFiles.length + " New episodes were downloaded successfully";
                }
                else{
                    mailSubject = sucessFiles.length + " New episodes were downloaded successfully and " + failoureFiles.length + " files had errors";
                }
                mailBody = successString + failureString;
                debugLogger.info('Going to send email: ', mailSubject ,mailBody)
                agenda.now('send mail',{
                    mailBody: mailBody,
                    mailSubject:mailSubject
                });

            }).done();

            callback(null);
        }
    ], function (err, result) {
        if(err){
            if(err === 111){
                debugLogger.info('No episodes were found for today');
            }
            else if(err === 222){
                debugLogger.info('No links found in db');
            }
            else{
                errorLogger.error(err)
            }
        }
        done();
    });
})
mailer(agenda);
updater(agenda);
agenda.start();
agenda.every('24 hours', 'today shows');
agenda.every('24 hours', 'update db');

/********************Set some tasks for later*******************/<commit_msg>fix 0 in season number bug<commit_after>/**
 * Created by Doron Sinai on 23/10/2014.
 */
var mongoose = require('mongoose');
var request = require('request');
var xml2js = require('xml2js');
var moment = require('moment');
var Agenda = require('agenda');
var async = require('async');
var fs = require('fs');
var _ = require('lodash');
var jsdom = require("jsdom").jsdom;
var config = require('config');
var Q = require('q');
var downloadFolder = config.get('downloadFolder');
var winston = require('winston');
require('./winston-config.js');
require("./db.js");
var mailer = require('./mailer.js');
var updater = require('./updater.js');
var debugLogger = winston.loggers.get('all');
var errorLogger = winston.loggers.get('terror');
var parser = xml2js.Parser({
    explicitArray: false,
    normalizeTags: true
});
var apiKey = config.get("apiKey"); //API key for the tv db
var User = mongoose.model('User');
var Show = mongoose.model('Show');
var Episode = mongoose.model('Episode');

function checkAndCreateFolder(folder){
    if(fs.existsSync(folder)){
        return true;
    }
    else{
        fs.mkdirSync(folder);
        if(fs.existsSync(folder)){
            return true;
        }
        return false;
    }
}

function downloadFile(url, folder, defer){
    var ret = [];
    var len = 0;
    var zlib = require("zlib");
    debugLogger.info('Going to download from the following URL: ' + url);
    debugLogger.info('and save it in this folder: ' + folder);
    request({
        url:url,
        gzip:true,
        headers: {
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
        }
    }).on('response', function(res){
        var path = res.request.uri.path.split('/');
        var fileName = path[path.length-1];
        debugLogger.info('Giving it this filename: ' + fileName);

        res.on('data', function (data) {
            ret.push(data);
            len += data.length;
        });

        res.on('end', function(){
            var buffer = Buffer.concat(ret, len);
            var encoding = res.headers['content-encoding'];
            var folderName = downloadFolder + folder + '/';
            if(!checkAndCreateFolder(folderName)){
                errorLogger.error('Can not create folders');
                defer.reject("Error creating folders");
                return;
            }
            var wstream = fs.createWriteStream(folderName + fileName);
            if (encoding == 'gzip') {
                zlib.gunzip(buffer, function(err, decoded) {
                    wstream.write(decoded);
                    wstream.end();
                });
            } else if (encoding == 'deflate') {
                zlib.inflate(buffer, function(err, decoded) {
                    wstream.write(decoded);
                    wstream.end();
                })
            } else {
                wstream.write(buffer.toString());
                wstream.end();
            }
            defer.resolve({
                status:"sucess",
                filename:fileName
            })
        });
    }).on('error', function(err) {
        errorLogger.error('Error while trying to save file ' + err);
        defer.reject("Error downloading file");
    });;
}

function requestSeriesPage(url){
    var debugMessagePrefix = '[' + url.name + ' S' + url.season + 'E' + url.number + '] ';
    var finishedRequest = Q.defer();
    var finishedRequestPromise = finishedRequest.promise;
    debugLogger.info(debugMessagePrefix + 'Going to request the page');

    request({
        url: url.url,
        gzip:true
    },  function(error, response, body) {
        debugLogger.info(debugMessagePrefix + 'Got a response back with status: ' + response.statusCode);
        if (!error && response.statusCode == 200) {
            debugLogger.info(debugMessagePrefix + 'About to parse the dom');
            jsdom.env(
                body,
                ["./jquery-2.1.1.min.js"],
                function (errors, window) {
                    if(errors) {
                        errorLogger.error(errors);
                        finishedRequest.reject("JSDOM error - see logs");
                        return;
                    }
                    if(url.number < 10){
                        url.number = '0' + url.number;
                    }
                    if(url.season < 10){
                        url.season = '0' + url.season;
                    }
                    var node = window.$(window.$.find('h3:contains("Season ' + url.season + '")')).next('div').find('span:contains("Episode ' + url.number + '")').parent().attr("onClick");
                    if(node && node.length > 1){
                        var episodeUrlTorrent = node.split('\'')[1];
                        if(episodeUrlTorrent){
                            debugLogger.info(debugMessagePrefix + 'Found the following episode number: ' + episodeUrlTorrent);
                            finishedRequest.resolve('' + episodeUrlTorrent);
                        }
                    }
                    else{
                        finishedRequest.reject("Did not find season in page");
                    }
                }
            );
        }
        else{
            errorLogger.error(error);
            finishedRequest.reject();
        }
    });

    //do it next
    finishedRequestPromise.then(function(episodeNumber){
        requestEpisodeSegment({episodeNumber: episodeNumber, debugMessagePrefix:debugMessagePrefix, name:url.name, deferred:url.deferred});
    }, function(reason){
        errorLogger.error(reason);
        url.deferred.reject(reason);
    }, function(){});  //.then(onFulfilled, onRejected, onProgress)
}

function requestEpisodeSegment(episode){
    var debugMessagePrefix = episode.debugMessagePrefix;
    var url = 'https://kickass.to/media/getepisode/' + episode.episodeNumber + '/';
    var finishedRequest = Q.defer();
    var finishedRequestPromise = finishedRequest.promise;

    debugLogger.info(debugMessagePrefix + 'Getting segment from: ' + url);

    request({
        url: url,
        gzip:true
    },  function(error, response, body) {
        if (!error && response.statusCode == 200) {
            jsdom.env(
                body,
                ["./jquery-2.1.1.min.js"],
                function (errors, window) {
                    if(errors) {
                        errorLogger.error("requestEpisodeSegment - jsdom - " + errors);
                        finishedRequest.reject("JSDOM error - see logs");
                        return;
                    }
                    debugLogger.info(debugMessagePrefix + "Look for x264 files in segment");
                    var node = window.$(window.$.find('tr:contains("x264")')).find(('a[title="Download torrent file"]'));
                    if (node.length < 1){
                        node = window.$.find('a[title="Download torrent file"]');
                        debugLogger.info(debugMessagePrefix + "No x264 torrents found in page");
                        if(node.length < 1){
                            debugLogger.info(debugMessagePrefix + "No torrents found - rejecting defer obj");
                            finishedRequest.reject("No torrents found");
                            return;
                        }
                    }
                    var nodeUrl = node[0].href;
                    finishedRequest.resolve(nodeUrl);
                }
            );
        }
        else{
            errorLogger.error("requestEpisodeSegment - request - " + error);
            finishedRequest.reject();
        }
    });

    //do it next
    finishedRequestPromise.then(function(nodeUrl){
        debugLogger.info(debugMessagePrefix + "Download file from: " + nodeUrl);
        downloadFile(nodeUrl, episode.name, episode.deferred);
    }, function(reason){
        errorLogger.error(reason);
        episode.deferred.reject(reason);
    }, function(){});  //.then(onFulfilled, onRejected, onProgress)
}

/********************Set some tasks for later *******************/
var agenda = new Agenda({db: { address: 'localhost:27017/agendaJobs'}});

agenda.define('today shows',function(job,done){
    var downloadDays = config.get('downloadDays');
    if(!downloadDays || isNaN(parseInt(downloadDays))){
        downloadDays = 1;
    }
    debugLogger.info('Number of days back to look for: ' +downloadDays);
    async.waterfall([
        // find relevant episode in the db
        function(callback){
            var start = moment().subtract(downloadDays, 'days').hour(0).minute(0).toDate();
            var end = moment().hour(0).minute(0).toDate();
            debugLogger.info('Look for episode in range: ' + start + ' - ' + end);
            Episode.find({firstAired:{$gte:start, $lt:end}},function(err, results){
                _.each(results, function(r){
                    debugLogger.info('Found the following: ', r.episodeId + ':' + r.episodeName);
                })

                if(err) callback(err);
                if(results.length < 1) {
                    debugLogger.info('No episode found for that date range');
                    callback(111);
                }
                callback(null,results);
            });
        },
        //extract the urls of each show to kickass torrents
        function(episodes, callback){
            var urls = [];
            var showsNumbers = {}
            Show.find({},function(err,shows){
                if(err) callback(err);

                for(var i=0; i <shows.length; i++){
                    var o = {}
                    o.url = shows[i].url;
                    o.name = shows[i].name;
                    showsNumbers[shows[i]._id] = o;
                }

                _.each(episodes,function(episode){
                    var u = {};
                    u.season = episode.season;
                    u.number = episode.episodeNumber;
                    u.url = showsNumbers[episode.showId]["url"];
                    u.name = showsNumbers[episode.showId]["name"];
                    if(u.url && (u.url !== "")){
                        urls.push(u);
                    }

                });
                if(urls.length ===0) callback(222);
                callback(null, urls)
            })
        },
        //go get the torrent files urls
        function(urls, callback){
            var promises = [];
            _.each(urls,function(url){
                console.log(url);
                var deferred = Q.defer();
                promises.push(deferred.promise);
                url.deferred = deferred;
                requestSeriesPage(url);
            });

            Q.allSettled(promises).spread(function(){
                var args = arguments;
                var sucessFiles = [];
                var failoureFiles = [];
                var mailSubject = "";
                var mailBody = "";
                var successString = "Success: \n";
                var failureString = "Failure: \n";
                for(var i=0; i<args.length; i++){
                    var promise = args[i];
                    if(promise.state === "fulfilled"){
                        sucessFiles.push(promise.value.filename);
                        successString += promise.value.filename + "\n"
                    }
                    else{
                        failoureFiles.push(promise.value);
                        failureString += promise.value + "\n";
                    }
                }
                if(failoureFiles.length === 0){
                    mailSubject = sucessFiles.length + " New episodes were downloaded successfully";
                }
                else{
                    mailSubject = sucessFiles.length + " New episodes were downloaded successfully and " + failoureFiles.length + " files had errors";
                }
                mailBody = successString + failureString;
                debugLogger.info('Going to send email: ', mailSubject ,mailBody)
                agenda.now('send mail',{
                    mailBody: mailBody,
                    mailSubject:mailSubject
                });

            }).done();

            callback(null);
        }
    ], function (err, result) {
        if(err){
            if(err === 111){
                debugLogger.info('No episodes were found for today');
            }
            else if(err === 222){
                debugLogger.info('No links found in db');
            }
            else{
                errorLogger.error(err)
            }
        }
        done();
    });
})
mailer(agenda);
updater(agenda);
agenda.start();
agenda.every('24 hours', 'today shows');
agenda.every('24 hours', 'update db');

/********************Set some tasks for later*******************/<|endoftext|>


<commit_before>/* eslint-disable no-unused-expressions */
import React from 'react'
import { shallow } from 'enzyme'
import { expect } from 'chai'

import { PageTabLayout } from 'mobilizations/components'

describe('client/mobilizations/components/page-tab-layout', () => {
  let wrapper
  const props = {
    mobilization: { id: 1 },
    location: { pathname: 'foo/bar' }
  }

  beforeAll(() => {
    wrapper = shallow(<PageTabLayout {...props} />)
  })

  describe('#render', () => {
    it('should render without crash', () => {
      expect(wrapper).to.be.ok
    })
  })
})
<commit_msg>fix(admin): page-tab-layout console.error<commit_after>/* eslint-disable no-unused-expressions */
import React from 'react'
import { shallow } from 'enzyme'
import { expect } from 'chai'

import { PageTabLayout } from 'mobilizations/components'

describe('client/mobilizations/components/page-tab-layout', () => {
  let wrapper
  const props = {
    mobilization: { id: 1 },
    location: { pathname: 'foo/bar' }
  }

  beforeAll(() => {
    wrapper = shallow(<PageTabLayout {...props} children={<div />} />)
  })

  describe('#render', () => {
    it('should render without crash', () => {
      expect(wrapper).to.be.ok
    })
  })
})
<|endoftext|>


<commit_before>/**
 * Container Generator
 */

const path = require('path');

// Plugin identifier based on the package.json `name` value
const pluginPkg = require(path.resolve(process.cwd(), 'package.json'));
const pluginId = pluginPkg.name.replace(
  /^strapi-plugin-/i,
  ''
);

const componentExists = require('../utils/componentExists');

module.exports = {
  description: 'Add a container component',
  prompts: [{
    type: 'input',
    name: 'name',
    message: 'What should it be called?',
    default: 'Form',
    validate: (value) => {
      if ((/.+/).test(value)) {
        return componentExists(value) ? 'A component or container with this name already exists' : true;
      }

      return 'The name is required';
    },
  }, {
    type: 'confirm',
    name: 'wantHeaders',
    default: false,
    message: 'Do you want headers?',
  }, {
    type: 'confirm',
    name: 'wantCSS',
    default: false,
    message: 'Does it have styling?',
  }, {
    type: 'confirm',
    name: 'wantActionsAndReducer',
    default: true,
    message: 'Do you want an actions/constants/selectors/reducer tupel for this container?',
  }, {
    type: 'confirm',
    name: 'wantSagas',
    default: true,
    message: 'Do you want sagas for asynchronous flows? (e.g. fetching data)',
  }],
  actions: (data) => {
    // Expose `pluginId` value
    data.pluginId = pluginId;

    // Generate index.js and index.test.js
    const actions = [{
      type: 'add',
      path: '../../../../../admin/src/containers/{{properCase name}}/index.js',
      templateFile: './container/index.js.hbs',
      abortOnFail: true,
    }, {
      type: 'add',
      path: '../../../../../admin/src/containers/{{properCase name}}/tests/index.test.js',
      templateFile: './container/test.js.hbs',
      abortOnFail: true,
    }];

    // If they want a SCSS file, add styles.scss
    if (data.wantCSS) {
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/styles.scss',
        templateFile: './container/styles.scss.hbs',
        abortOnFail: true,
      });
    }

    // If component wants messages
    if (data.wantMessages) {
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/messages.js',
        templateFile: './container/messages.js.hbs',
        abortOnFail: true,
      });
    }

    // If they want actions and a reducer, generate actions.js, constants.js,
    // reducer.js and the corresponding tests for actions and the reducer
    if (data.wantActionsAndReducer) {
      // Actions
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/actions.js',
        templateFile: './container/actions.js.hbs',
        abortOnFail: true,
      });
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/tests/actions.test.js',
        templateFile: './container/actions.test.js.hbs',
        abortOnFail: true,
      });

      // Constants
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/constants.js',
        templateFile: './container/constants.js.hbs',
        abortOnFail: true,
      });

      // Selectors
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/selectors.js',
        templateFile: './container/selectors.js.hbs',
        abortOnFail: true,
      });
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/tests/selectors.test.js',
        templateFile: './container/selectors.test.js.hbs',
        abortOnFail: true,
      });

      // Reducer
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/reducer.js',
        templateFile: './container/reducer.js.hbs',
        abortOnFail: true,
      });
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/tests/reducer.test.js',
        templateFile: './container/reducer.test.js.hbs',
        abortOnFail: true,
      });
    }

    // Sagas
    if (data.wantSagas) {
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/sagas.js',
        templateFile: './container/sagas.js.hbs',
        abortOnFail: true,
      });
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/tests/sagas.test.js',
        templateFile: './container/sagas.test.js.hbs',
        abortOnFail: true,
      });
    }

    return actions;
  },
};
<commit_msg>Make strapi-helper-plugin tests passing<commit_after>/**
 * Container Generator
 */

const path = require('path');

// Plugin identifier based on the package.json `name` value
const pluginPkg = require(path.resolve(process.cwd(), 'package.json'));
const pluginId = pluginPkg.name.replace(
  /^strapi-plugin-/i,
  ''
);

const componentExists = require('../utils/componentExists');

module.exports = {
  description: 'Add a container component',
  prompts: [{
    type: 'input',
    name: 'name',
    message: 'What should it be called?',
    default: 'Form',
    validate: (value) => {
      if ((/.+/).test(value)) {
        return componentExists(value) ? 'A component or container with this name already exists' : true;
      }

      return 'The name is required';
    },
  }, {
    type: 'confirm',
    name: 'wantHeaders',
    default: false,
    message: 'Do you want headers?',
  }, {
    type: 'confirm',
    name: 'wantCSS',
    default: false,
    message: 'Does it have styling?',
  }, {
    type: 'confirm',
    name: 'wantActionsAndReducer',
    default: true,
    message: 'Do you want an actions/constants/selectors/reducer tupel for this container?',
  }, {
    type: 'confirm',
    name: 'wantSagas',
    default: true,
    message: 'Do you want sagas for asynchronous flows? (e.g. fetching data)',
  }],
  actions: (data) => {
    const dataFormatted = data;

    // Expose `pluginId` value
    dataFormatted.pluginId = pluginId;

    // Generate index.js and index.test.js
    const actions = [{
      type: 'add',
      path: '../../../../../admin/src/containers/{{properCase name}}/index.js',
      templateFile: './container/index.js.hbs',
      abortOnFail: true,
    }, {
      type: 'add',
      path: '../../../../../admin/src/containers/{{properCase name}}/tests/index.test.js',
      templateFile: './container/test.js.hbs',
      abortOnFail: true,
    }];

    // If they want a SCSS file, add styles.scss
    if (dataFormatted.wantCSS) {
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/styles.scss',
        templateFile: './container/styles.scss.hbs',
        abortOnFail: true,
      });
    }

    // If component wants messages
    if (dataFormatted.wantMessages) {
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/messages.js',
        templateFile: './container/messages.js.hbs',
        abortOnFail: true,
      });
    }

    // If they want actions and a reducer, generate actions.js, constants.js,
    // reducer.js and the corresponding tests for actions and the reducer
    if (dataFormatted.wantActionsAndReducer) {
      // Actions
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/actions.js',
        templateFile: './container/actions.js.hbs',
        abortOnFail: true,
      });
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/tests/actions.test.js',
        templateFile: './container/actions.test.js.hbs',
        abortOnFail: true,
      });

      // Constants
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/constants.js',
        templateFile: './container/constants.js.hbs',
        abortOnFail: true,
      });

      // Selectors
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/selectors.js',
        templateFile: './container/selectors.js.hbs',
        abortOnFail: true,
      });
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/tests/selectors.test.js',
        templateFile: './container/selectors.test.js.hbs',
        abortOnFail: true,
      });

      // Reducer
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/reducer.js',
        templateFile: './container/reducer.js.hbs',
        abortOnFail: true,
      });
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/tests/reducer.test.js',
        templateFile: './container/reducer.test.js.hbs',
        abortOnFail: true,
      });
    }

    // Sagas
    if (dataFormatted.wantSagas) {
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/sagas.js',
        templateFile: './container/sagas.js.hbs',
        abortOnFail: true,
      });
      actions.push({
        type: 'add',
        path: '../../../../../admin/src/containers/{{properCase name}}/tests/sagas.test.js',
        templateFile: './container/sagas.test.js.hbs',
        abortOnFail: true,
      });
    }

    return actions;
  },
};
<|endoftext|>


<commit_before>// ==UserScript==
// @name        YouTube: Remove Autoplay
// @namespace   youtubeRemoveAutoplay
// @description Disables the autoplay function
// @version     1.0
// @include     http://*youtube.com/*
// @include     https://*youtube.com/*
// @exclude     https://*.youtube.com/embed*
// @grant       none
// ==/UserScript==

document.addEventListener('spfdone', function() {
	document.getElementById('autoplay-checkbox').parentElement.remove();
});

document.getElementById('autoplay-checkbox').parentElement.remove();
<commit_msg>Delete YouTube_Stop_Autoplay.user.js<commit_after><|endoftext|>


<commit_before>/* @flow */
"use strict";

/*globals cordova*/
import Emitter from "yasmf-emitter";

// private properties -- we need some symbols
let _selectors = Symbol();
let _useSmoothScrolling = Symbol();
let _smoothScrollDuration = Symbol();
let _showElementUnderKeyboard = Symbol();

/**
 * given a selector string, return matching elements in an Array
 * @param {string} selectorString
 * @return Array<Node>
 */
function getScrollContainers(selectorString/*: string*/)/*: Array<Node>*/ {
    return Array.from(document.querySelectorAll(selectorString));
}

/**
 * Given an element, returns an array representing the start and end of
 * the current selection.
 * @param {Node} focusedElement
 * @return Array<number>
 */
function getElementSelection(focusedElement/*: Node*/)/*: Array<number>*/ {
    return [focusedElement.selectionStart, focusedElement.selectionEnd];
}

/**
 * Given an element and a tuple representing the start and end of the selection,
 * set the selection on the element.
 * @param {Node} focusedElement
 * @param {number} selectionStart the start of the selection
 * @param {number} selectionEnd   the end of the selection
 */
function setElementSelection(focusedElement/*: Node*/, [selectionStart/*: number*/, selectionEnd/*: number*/] = [0, 0])/*: void*/ {
    focusedElement.selectionStart = selectionStart;
    focusedElement.selectionEnd = selectionEnd;
}

function showElementUnderKeyboard(keyboardHeight/*: number*/) {
    let e = document.createElement("div");
    e.className = "sk-element-under-keyboard";
    e.style.position = "absolute";
    e.style.bottom = "0";
    e.style.left = "0";
    e.style.right = "0";
    e.style.zIndex = "9999999999999";
    e.style.height = `${keyboardHeight}px`;
    document.body.appendChild(e);
}

function hideElementUnderKeyboard()/*: void*/ {
    let els = Array.from(document.querySelectorAll(".sk-element-under-keyboard"));
    els.forEach((el) => document.body.removeChild(el));
}

/**
 * Saves the element's current text selection, then resets it to 0. After a tick, it
 * restores the element's saved text selection.
 * This is to fix iOS's buggy behavior regarding cursor positioning after the scrolling
 * of an element.
 *
 * @param {Node} focusedElement
 */
function handleTextSelection(focusedElement/*: Node*/)/*: void*/ {
    setTimeout(() => {
        // save the selection
        let selection = getElementSelection(focusedElement);

        // reset the selection to 0,0
        setElementSelection(focusedElement);

        // after a short delay, restore the selection
        setTimeout(() => setElementSelection(focusedElement, selection), 33);
    }, 0);
}

/**
 * Provides methods for avoiding the soft keyboard. This tries to be automatic,
 * but you will need to supply scrollable selectors.
 */
export default class SoftKeyboard extends Emitter {

    /**
     * Construct an instance of the SoftKeyboard
     *
     * @return SoftKeyboard
     */
    constructor(options) {
        super(options);
    }

    /**
     * Initialize a SoftKeyboard. Will be called automatically during construction
     * @param {Array<string>} [selectors]       defaults to an empty array
     * @param {boolean} [useSmoothScrolling]    defaults to true
     * @param {number} [smoothScrollDuration]   defaults to 100
     * @param {boolean} [showElementUnderKeyboard]   defaults to false
     */
    init({selectors=[], useSmoothScrolling = true, smoothScrollDuration = 100,
          showElementUnderKeyboard = false} = {}) {
        // selectors: Array, useSmoothScrolling: boolean, smoothScrollDuration: number
        if (typeof cordova !== "undefined" ) {
            if (cordova.plugins && cordova.plugins.Keyboard) {
                cordova.plugins.Keyboard.disableScroll(true);
                window.addEventListener("native.keyboardshow", this.keyboardShown.bind(this));
                window.addEventListener("native.keyboardhide", this.keyboardHidden.bind(this));
            }
        }
        this[_selectors] = new Set();
        selectors.forEach( sel => this.addSelector(sel) );
        this[_useSmoothScrolling] = useSmoothScrolling;
        this[_smoothScrollDuration] = smoothScrollDuration;
        this[_showElementUnderKeyboard] = showElementUnderKeyboard;
    }

    /**
     * Adds a selector
     * @param {string} selector    A CSS selector that identifies a scrolling container
     * @return {SoftKeyboard}
     */
    addSelector(selector/*: string*/)/*: SoftKeyboard*/ {
        this[_selectors].add(selector);
        return this;
    }

    /**
     * Removes a selector
     * @param {string} selector    A CSS selector that identifies a scrolling container
     * @return {SoftKeyboard}
     */
    removeSelector(selector/*: string*/)/*: SoftKeyboard*/ {
        this[_selectors].delete(selector);
        return this;
    }

    get selectors()/*: Array*/ {
        return Array.from(this[_selectors]);
    }

    get selectorString()/*: string*/ {
        return this.selectors.join(", ");
    }

    get useSmoothScrolling()/*: boolean*/ {
        return this[_useSmoothScrolling];
    }
    set useSmoothScrolling(b/*: boolean*/)/*: void*/ {
        this[_useSmoothScrolling] = b;
    }

    get smoothScrollDuration()/*: number*/ {
        return this[_smoothScrollDuration];
    }
    set smoothScrollDuration(d/*: number*/)/*: void*/ {
        this[_smoothScrollDuration] = d;
    }

    get showElementUnderKeyboard()/*: boolean*/ {
        return this[_showElementUnderKeyboard];
    }
    set showElementUnderKeyboard(b/*: boolean*/)/*: void*/ {
        this[_showElementUnderKeyboard] = b;
    }

    /**
     * Shows the keyboard, if possible
     */
    showKeyboard(force/*: boolean*/ = false)/*: void*/ {
        if (typeof cordova !== "undefined") {
            if (cordova.plugins && cordova.plugins.Keyboard) {
                cordova.plugins.Keyboard.show();
                return;
            }
        }
        if (force) {
            this.keyboardShown({keyboardHeight:240});
        }
    }

    /**
     * Hide the keyboard, if possible
     */
    hideKeyboard(force/*: boolean*/ = false)/*: void*/ {
        if (typeof cordova !== "undefined") {
            if (cordova.plugins && cordova.plugins.Keyboard) {
                cordova.plugins.Keyboard.hide();
                return;
            }
        }
        if (force) {
            this.keyboardHidden({});
        }
    }

    /**
     * Triggered when the soft keyboard is displayed
     * @param {{keyboardHeight: number}} e    the event triggered from the keyboard plugin
     */
    keyboardShown(e)/*: void*/ {
        this.emit("keyboardShown", e);
        this.emit("willResize", e);
        setTimeout(() => {
            let screenHeight = window.innerHeight; //(document.body.clientWidth === window.screen.height ? window.screen.width : window.screen.height);
            let scrollContainers = getScrollContainers(this.selectorString);
            let keyboardHeight = e.keyboardHeight;

            if (this.showElementUnderKeyboard) {
                showElementUnderKeyboard(keyboardHeight);
            }

            // for each scroll container in the DOM, we need to calculate the
            // the height it should be to fit in the reduced view
            scrollContainers.forEach((sc) => {
                let scTop = sc.getBoundingClientRect().top;
                // now that we know the top of the scroll container, the height of the
                // the screen, and the height of the keyboard, we can calculate the
                // appropriate max-height for the container.
                sc.style.maxHeight = "" + (screenHeight - keyboardHeight - scTop) + "px";
            });
            this.emit("didResize", e);
            // changing the height isn't sufficient: we need to scroll any focused
            // element into view.
            setTimeout(() => {
                let focusedElement = document.querySelector(":focus");
                if (focusedElement) {
                    if (!this.useSmoothScrolling || !window.requestAnimationFrame) {
                        // scroll the element into view, but only if we have to
                        if (focusedElement.scrollIntoViewIfNeeded) {
                            focusedElement.scrollIntoViewIfNeeded();
                        } else {
                            // aim for the bottom of the viewport
                            focusedElement.scrollIntoView(false);
                        }
                        // iOS doesn't always position the cursor correctly after
                        // a scroll operation. Clear the selection so that iOS is
                        // forced to recompute where the cursor should appear.
                        handleTextSelection(focusedElement);
                    } else {
                        // to scroll the element smoothly into view, things become a little
                        // more difficult.
                        let fElTop = focusedElement.getBoundingClientRect().top,
                            sc = focusedElement, scTop, scBottom,
                            selectorString = this.selectorString;
                        // find the containing scroll container if we can
                        while (sc && !sc.matches(selectorString)) {
                            sc = sc.parentElement;
                        }
                        if (sc) {
                            scTop = sc.getBoundingClientRect().top;
                            scBottom = sc.getBoundingClientRect().bottom;
                            if (fElTop < scTop || fElTop > (((scBottom - scTop) / 2) + scTop)) {
                                // the element isn't above the keyboard (or is too far above),
                                // scroll it into view smoothly
                                let targetTop = ((scBottom - scTop) / 2) + scTop,
                                    deltaTop = fElTop - targetTop,
                                    origScrollTop = sc.scrollTop,
                                    startTimestamp = null;
                                // animate our scroll
                                let scrollStep;
                                window.requestAnimationFrame(scrollStep = (timestamp) => {
                                    if (!startTimestamp) {
                                        startTimestamp = timestamp;
                                    }
                                    var progressDelta = timestamp - startTimestamp,
                                        pct = progressDelta / this.smoothScrollDuration;
                                    sc.scrollTop = origScrollTop + (deltaTop * pct);
                                    if (progressDelta < this.smoothScrollDuration) {
                                        window.requestAnimationFrame(scrollStep);
                                    } else {
                                        // set the scroll to the final desired position, just in case
                                        // we didn't actually get there (or overshot)
                                        sc.scrollTop = origScrollTop + deltaTop;
                                        handleTextSelection(focusedElement);
                                    }
                                });
                            }
                        }
                    }
                }
            }, 0);
        }, 0);
    }

    /**
     * Triggered when the soft keyboard is hidden
     * @param {*} e
     */
    keyboardHidden(e)/*: void*/ {
        setTimeout(() => {
            this.emit("keyboardHidden", e);
            this.emit("willResize", e);
            let scrollContainers = getScrollContainers(this.selectorString);
            scrollContainers.forEach(el => el.style.maxHeight = "");
            hideElementUnderKeyboard();
            this.emit("didResize", e);
        }, 0);
    }
}

export function createSoftKeyboard(...args) {
    return new SoftKeyboard(...args);
}
<commit_msg>guess to see if my thought process is right<commit_after>/* @flow */
"use strict";

/*globals cordova*/
import Emitter from "yasmf-emitter";

// private properties -- we need some symbols
let _selectors = Symbol();
let _useSmoothScrolling = Symbol();
let _smoothScrollDuration = Symbol();
let _showElementUnderKeyboard = Symbol();

/**
 * given a selector string, return matching elements in an Array
 * @param {string} selectorString
 * @return Array<Node>
 */
function getScrollContainers(selectorString/*: string*/)/*: Array<Node>*/ {
    return Array.from(document.querySelectorAll(selectorString));
}

/**
 * Given an element, returns an array representing the start and end of
 * the current selection.
 * @param {Node} focusedElement
 * @return Array<number>
 */
function getElementSelection(focusedElement/*: Node*/)/*: Array<number>*/ {
    return [focusedElement.selectionStart, focusedElement.selectionEnd];
}

/**
 * Given an element and a tuple representing the start and end of the selection,
 * set the selection on the element.
 * @param {Node} focusedElement
 * @param {number} selectionStart the start of the selection
 * @param {number} selectionEnd   the end of the selection
 */
function setElementSelection(focusedElement/*: Node*/, [selectionStart/*: number*/, selectionEnd/*: number*/] = [0, 0])/*: void*/ {
    focusedElement.selectionStart = selectionStart;
    focusedElement.selectionEnd = selectionEnd;
}

function showElementUnderKeyboard(keyboardHeight/*: number*/) {
    let e = document.createElement("div");
    e.className = "sk-element-under-keyboard";
    e.style.position = "absolute";
    e.style.bottom = "0";
    e.style.left = "0";
    e.style.right = "0";
    e.style.zIndex = "9999999999999";
    e.style.height = `${keyboardHeight}px`;
    document.body.appendChild(e);
}

function hideElementUnderKeyboard()/*: void*/ {
    let els = Array.from(document.querySelectorAll(".sk-element-under-keyboard"));
    els.forEach((el) => document.body.removeChild(el));
}

/**
 * Saves the element's current text selection, then resets it to 0. After a tick, it
 * restores the element's saved text selection.
 * This is to fix iOS's buggy behavior regarding cursor positioning after the scrolling
 * of an element.
 *
 * @param {Node} focusedElement
 */
function handleTextSelection(focusedElement/*: Node*/)/*: void*/ {
    setTimeout(() => {
        // save the selection
        let selection = getElementSelection(focusedElement);

        // reset the selection to 0,0
        setElementSelection(focusedElement);

        // after a short delay, restore the selection
        setTimeout(() => setElementSelection(focusedElement, selection), 33);
    }, 0);
}

/**
 * Provides methods for avoiding the soft keyboard. This tries to be automatic,
 * but you will need to supply scrollable selectors.
 */
export default class SoftKeyboard extends Emitter {

    /**
     * Construct an instance of the SoftKeyboard
     *
     * @return SoftKeyboard
     */
    constructor(options) {
        super(options);
    }

    /**
     * Initialize a SoftKeyboard. Will be called automatically during construction
     * @param {Array<string>} [selectors]       defaults to an empty array
     * @param {boolean} [useSmoothScrolling]    defaults to true
     * @param {number} [smoothScrollDuration]   defaults to 100
     * @param {boolean} [showElementUnderKeyboard]   defaults to false
     */
    init({selectors=[], useSmoothScrolling = true, smoothScrollDuration = 100,
          showElementUnderKeyboard = false} = {}) {
        // selectors: Array, useSmoothScrolling: boolean, smoothScrollDuration: number
        if (typeof cordova !== "undefined" ) {
            if (cordova.plugins && cordova.plugins.Keyboard) {
                cordova.plugins.Keyboard.disableScroll(true);
                window.addEventListener("native.keyboardshow", this.keyboardShown.bind(this));
                window.addEventListener("native.keyboardhide", this.keyboardHidden.bind(this));
            }
        }
        this[_selectors] = new Set();
        selectors.forEach( sel => this.addSelector(sel) );
        this[_useSmoothScrolling] = useSmoothScrolling;
        this[_smoothScrollDuration] = smoothScrollDuration;
        this[_showElementUnderKeyboard] = showElementUnderKeyboard;
    }

    /**
     * Adds a selector
     * @param {string} selector    A CSS selector that identifies a scrolling container
     * @return {SoftKeyboard}
     */
    addSelector(selector/*: string*/)/*: SoftKeyboard*/ {
        this[_selectors].add(selector);
        return this;
    }

    /**
     * Removes a selector
     * @param {string} selector    A CSS selector that identifies a scrolling container
     * @return {SoftKeyboard}
     */
    removeSelector(selector/*: string*/)/*: SoftKeyboard*/ {
        this[_selectors].delete(selector);
        return this;
    }

    get selectors()/*: Array*/ {
        return Array.from(this[_selectors]);
    }

    get selectorString()/*: string*/ {
        return this.selectors.join(", ");
    }

    get useSmoothScrolling()/*: boolean*/ {
        return this[_useSmoothScrolling];
    }
    set useSmoothScrolling(b/*: boolean*/)/*: void*/ {
        this[_useSmoothScrolling] = b;
    }

    get smoothScrollDuration()/*: number*/ {
        return this[_smoothScrollDuration];
    }
    set smoothScrollDuration(d/*: number*/)/*: void*/ {
        this[_smoothScrollDuration] = d;
    }

    get showElementUnderKeyboard()/*: boolean*/ {
        return this[_showElementUnderKeyboard];
    }
    set showElementUnderKeyboard(b/*: boolean*/)/*: void*/ {
        this[_showElementUnderKeyboard] = b;
    }

    /**
     * Shows the keyboard, if possible
     */
    showKeyboard(force/*: boolean*/ = false)/*: void*/ {
        if (typeof cordova !== "undefined") {
            if (cordova.plugins && cordova.plugins.Keyboard) {
                cordova.plugins.Keyboard.show();
                return;
            }
        }
        if (force) {
            this.keyboardShown({keyboardHeight:240});
        }
    }

    /**
     * Hide the keyboard, if possible
     */
    hideKeyboard(force/*: boolean*/ = false)/*: void*/ {
        if (typeof cordova !== "undefined") {
            if (cordova.plugins && cordova.plugins.Keyboard) {
                cordova.plugins.Keyboard.hide();
                return;
            }
        }
        if (force) {
            this.keyboardHidden({});
        }
    }

    /**
     * Triggered when the soft keyboard is displayed
     * @param {{keyboardHeight: number}} e    the event triggered from the keyboard plugin
     */
    keyboardShown(e)/*: void*/ {
        this.emit("keyboardShown", e);
        this.emit("willResize", e);
        setTimeout(() => {
            let screenHeight = window.innerHeight; //(document.body.clientWidth === window.screen.height ? window.screen.width : window.screen.height);
            let scrollContainers = getScrollContainers(this.selectorString);
            let keyboardHeight = e.keyboardHeight / devicePixelRatio;

            if (this.showElementUnderKeyboard) {
                showElementUnderKeyboard(keyboardHeight);
            }

            // for each scroll container in the DOM, we need to calculate the
            // the height it should be to fit in the reduced view
            scrollContainers.forEach((sc) => {
                let scTop = sc.getBoundingClientRect().top;
                // now that we know the top of the scroll container, the height of the
                // the screen, and the height of the keyboard, we can calculate the
                // appropriate max-height for the container.
                sc.style.maxHeight = "" + (screenHeight - keyboardHeight - scTop) + "px";
            });
            this.emit("didResize", e);
            // changing the height isn't sufficient: we need to scroll any focused
            // element into view.
            setTimeout(() => {
                let focusedElement = document.querySelector(":focus");
                if (focusedElement) {
                    if (!this.useSmoothScrolling || !window.requestAnimationFrame) {
                        // scroll the element into view, but only if we have to
                        if (focusedElement.scrollIntoViewIfNeeded) {
                            focusedElement.scrollIntoViewIfNeeded();
                        } else {
                            // aim for the bottom of the viewport
                            focusedElement.scrollIntoView(false);
                        }
                        // iOS doesn't always position the cursor correctly after
                        // a scroll operation. Clear the selection so that iOS is
                        // forced to recompute where the cursor should appear.
                        handleTextSelection(focusedElement);
                    } else {
                        // to scroll the element smoothly into view, things become a little
                        // more difficult.
                        let fElTop = focusedElement.getBoundingClientRect().top,
                            sc = focusedElement, scTop, scBottom,
                            selectorString = this.selectorString;
                        // find the containing scroll container if we can
                        while (sc && !sc.matches(selectorString)) {
                            sc = sc.parentElement;
                        }
                        if (sc) {
                            scTop = sc.getBoundingClientRect().top;
                            scBottom = sc.getBoundingClientRect().bottom;
                            if (fElTop < scTop || fElTop > (((scBottom - scTop) / 2) + scTop)) {
                                // the element isn't above the keyboard (or is too far above),
                                // scroll it into view smoothly
                                let targetTop = ((scBottom - scTop) / 2) + scTop,
                                    deltaTop = fElTop - targetTop,
                                    origScrollTop = sc.scrollTop,
                                    startTimestamp = null;
                                // animate our scroll
                                let scrollStep;
                                window.requestAnimationFrame(scrollStep = (timestamp) => {
                                    if (!startTimestamp) {
                                        startTimestamp = timestamp;
                                    }
                                    var progressDelta = timestamp - startTimestamp,
                                        pct = progressDelta / this.smoothScrollDuration;
                                    sc.scrollTop = origScrollTop + (deltaTop * pct);
                                    if (progressDelta < this.smoothScrollDuration) {
                                        window.requestAnimationFrame(scrollStep);
                                    } else {
                                        // set the scroll to the final desired position, just in case
                                        // we didn't actually get there (or overshot)
                                        sc.scrollTop = origScrollTop + deltaTop;
                                        handleTextSelection(focusedElement);
                                    }
                                });
                            }
                        }
                    }
                }
            }, 0);
        }, 0);
    }

    /**
     * Triggered when the soft keyboard is hidden
     * @param {*} e
     */
    keyboardHidden(e)/*: void*/ {
        setTimeout(() => {
            this.emit("keyboardHidden", e);
            this.emit("willResize", e);
            let scrollContainers = getScrollContainers(this.selectorString);
            scrollContainers.forEach(el => el.style.maxHeight = "");
            hideElementUnderKeyboard();
            this.emit("didResize", e);
        }, 0);
    }
}

export function createSoftKeyboard(...args) {
    return new SoftKeyboard(...args);
}
<|endoftext|>