<commit_before>/**
 * Created by keyvan on 8/16/16.
 */

import {v1 as neo4j} from 'neo4j-driver';
import fs from 'file-system';
import chalk from 'chalk';
import parser from 'parse-neo4j';
import {parseNeo4jInts} from './preprocess';

class Neo4jConnection {
    constructor({boltUrl, user, password} = {}) {
        this.queries = {};

        this.driver = neo4j.driver(boltUrl, neo4j.auth.basic(user, password));
        const session = this.driver.session();
        this.initialized = session.run('RETURN "Neo4j instance successfully connected."')
            .then((result) => {
                console.log(chalk.green(parser.parse(result)));
                session.close();
            })
            .catch(error => {
                console.error(
                    chalk.red('Error connecting to the Neo4j instance, check connection options'));
                console.log(error);
                throw error;
            });
    }

    addCypherQueryFile(cypherQueryFilePath) {
        this.queries[cypherQueryFilePath] = fs.readFileSync(cypherQueryFilePath, 'utf8');
    }

    executeCypher(cypherQueryFilePath, queryParams) {
        return new Promise((resolve, reject) => {
            if (!this.queries[cypherQueryFilePath])
                this.addCypherQueryFile(cypherQueryFilePath);

            const query = this.queries[cypherQueryFilePath];
            const session = this.driver.session();

            session.run(query, queryParams)
                .then(result => {
                    resolve(result);
                    session.close();
                })
                .catch(error => {
                    error = error.fields ? JSON.stringify(error.fields[0]) : String(error);
                    reject(`error while executing Cypher: ${error}`);
                });
        })
            .then(parser.parse);
    }
}

class Hook {
    constructor(functionOrArrayOfFunctions, procedureName, hookName) {
        this.timeout = 4000;
        this.name = hookName;
        this.procedureName = procedureName;
        if (!Array.isArray(functionOrArrayOfFunctions))
            if (typeof functionOrArrayOfFunctions === 'function')
                functionOrArrayOfFunctions = [functionOrArrayOfFunctions];
            else
                throw new Error('hook should be function or array of functions');
        this.phases = [];
        this.context = {};
        for (const func of functionOrArrayOfFunctions)
            if (typeof func === 'function')
                this.phases.push(this.asyncify(func));
            else
                throw new Error(`element ${func} in array passed as ${this.procedureName} ` +
                'lifecycle is not a function');

        this.execute = (...args) => {
            let next = Promise.resolve(this.phases[0](...args));
            for (let i =  1; i < this.phases.length; i++)
                next = Promise.all([this.phases[i], next])
                    .then(([phase, response]) => phase(response));
            return next;
        };
    }

    asyncify(func) {
        return (...args) => Promise.race([
            Promise.resolve(func.apply(this.context, args)),
            new Promise((resolve, reject) => setTimeout(() => reject('TimeOutError'), this.timeout))
        ])
            .catch((error) => {
                if (error === 'TimeOutError')
                    throw new Error(`${this.name} lifecycle of ${this.procedureName} timed out, ` +
                            'no response after 4 seconds');
                throw error;
            });
    }
}

const createProcedure = (neo4jConnection, {cypherQueryFile, check = (params, user) => true,
    preProcess = params => params, postProcess = result => result, postServe = result => result,
    name = 'createProcedure'} = {}) => {
    const checkHook = new Hook(check, name, 'check');
    const preProcessHook = new Hook(preProcess, name, 'preProcess');
    const postProcessHook = new Hook(postProcess, name, 'postProcess');
    const postServeHook = new Hook(postServe, name, 'postServe');

    return (params, ctx) => {
        const response = checkHook.execute(params, ctx)
            .then(checkPassed => {
                if (!checkPassed)
                    throw new Error('Check lifecycle hook did not pass');
                return [params, ctx];
            })
            .then(([params, ctx]) => Promise.all([
                preProcessHook.execute(params, ctx),
                ctx
            ]))
            .then(([params, ctx]) => Promise.all([
                parseNeo4jInts('id', 'skip', 'limit')(params),
                ctx
            ]))
            .then(([params, ctx]) => Promise.all([
                neo4jConnection.executeCypher(cypherQueryFile, params),
                params,
                ctx
            ]))
            .then(([result, params, ctx]) => Promise.all([
                postProcessHook.execute(result, params, ctx),
                params,
                ctx
            ]));

        response
            .then(([result, params, ctx]) => postServeHook.execute(result, params, ctx))
            .catch(error => { console.error(`Error in postServe : ${error}`); });
        return response.then(([result, params]) => result);
    };
};

class API {
    constructor(neo4jConnection, {method, route, allowedRoles = [], procedure,
        cypherQueryFile, check, preProcess, postProcess, postServe} = {}) {
        if (typeof procedure === 'function')
            this.invoke = procedure;
        else
            this.invoke = createProcedure(neo4jConnection,
                {cypherQueryFile, check, preProcess, postProcess, postServe, name: route});

        this.method = method;
        this.route = route;
        this.allowedRoles = allowedRoles;
        this.requiresJwtAuthentication = allowedRoles &&
            Array.isArray(allowedRoles) && allowedRoles.length > 0;
    }
}

export {Neo4jConnection, createProcedure, API};
<commit_msg>postProcess and postServe now have an optional third argument, ctx<commit_after>/**
 * Created by keyvan on 8/16/16.
 */

import {v1 as neo4j} from 'neo4j-driver';
import fs from 'file-system';
import chalk from 'chalk';
import parser from 'parse-neo4j';
import {parseNeo4jInts} from './preprocess';

class Neo4jConnection {
    constructor({boltUrl, user, password} = {}) {
        this.queries = {};

        this.driver = neo4j.driver(boltUrl, neo4j.auth.basic(user, password));
        const session = this.driver.session();
        this.initialized = session.run('RETURN "Neo4j instance successfully connected."')
            .then((result) => {
                console.log(chalk.green(parser.parse(result)));
                session.close();
            })
            .catch(error => {
                console.error(
                    chalk.red('Error connecting to the Neo4j instance, check connection options'));
                console.log(error);
                throw error;
            });
    }

    addCypherQueryFile(cypherQueryFilePath) {
        this.queries[cypherQueryFilePath] = fs.readFileSync(cypherQueryFilePath, 'utf8');
    }

    executeCypher(cypherQueryFilePath, queryParams) {
        return new Promise((resolve, reject) => {
            if (!this.queries[cypherQueryFilePath])
                this.addCypherQueryFile(cypherQueryFilePath);

            const query = this.queries[cypherQueryFilePath];
            const session = this.driver.session();

            session.run(query, queryParams)
                .then(result => {
                    resolve(result);
                    session.close();
                })
                .catch(error => {
                    error = error.fields ? JSON.stringify(error.fields[0]) : String(error);
                    reject(`error while executing Cypher: ${error}`);
                });
        })
            .then(parser.parse);
    }
}

class Hook {
    constructor(functionOrArrayOfFunctions, procedureName, hookName) {
        this.timeout = 4000;
        this.name = hookName;
        this.procedureName = procedureName;
        if (!Array.isArray(functionOrArrayOfFunctions))
            if (typeof functionOrArrayOfFunctions === 'function')
                functionOrArrayOfFunctions = [functionOrArrayOfFunctions];
            else
                throw new Error('hook should be function or array of functions');
        this.phases = [];
        this.context = {};
        for (const func of functionOrArrayOfFunctions)
            if (typeof func === 'function')
                this.phases.push(this.asyncify(func));
            else
                throw new Error(`element ${func} in array passed as ${this.procedureName} ` +
                'lifecycle is not a function');

        this.execute = (...args) => {
            let next = Promise.resolve(this.phases[0](...args));
            for (let i =  1; i < this.phases.length; i++)
                next = Promise.all([this.phases[i], next])
                    .then(([phase, response]) => phase(response));
            return next;
        };
    }

    asyncify(func) {
        return (...args) => Promise.race([
            Promise.resolve(func.apply(this.context, args)),
            new Promise((resolve, reject) => setTimeout(() => reject('TimeOutError'), this.timeout))
        ])
            .catch((error) => {
                if (error === 'TimeOutError')
                    throw new Error(`${this.name} lifecycle of ${this.procedureName} timed out, ` +
                            'no response after 4 seconds');
                throw error;
            });
    }
}

const createProcedure = (neo4jConnection, {cypherQueryFile, check = (params, user) => true,
    preProcess = params => params, postProcess = result => result, postServe = result => result,
    name = 'createProcedure'} = {}) => {
    const checkHook = new Hook(check, name, 'check');
    const preProcessHook = new Hook(preProcess, name, 'preProcess');
    const postProcessHook = new Hook(postProcess, name, 'postProcess');
    const postServeHook = new Hook(postServe, name, 'postServe');

    return (params, ctx) => {
        const response = checkHook.execute(params, ctx)
            .then(checkPassed => {
                if (!checkPassed)
                    throw new Error('Check lifecycle hook did not pass');
                return [params, ctx];
            })
            .then(([params, ctx]) => Promise.all([
                preProcessHook.execute(params, ctx),
                ctx
            ]))
            .then(([params, ctx]) => Promise.all([
                parseNeo4jInts('id', 'skip', 'limit')(params),
                ctx
            ]))
            .then(([params, ctx]) => Promise.all([
                neo4jConnection.executeCypher(cypherQueryFile, params),
                params,
                ctx
            ]))
            .then(([result, params, ctx]) => Promise.all([
                postProcessHook.execute(result, params, ctx),
                params,
                ctx
            ]));

        response
            .then(([result, params, ctx]) => postServeHook.execute(result, params, ctx))
            .catch(error => { console.error(`Error in postServe : ${error}`); });
        return response.then(([result, params, ctx]) => result);
    };
};

class API {
    constructor(neo4jConnection, {method, route, allowedRoles = [], procedure,
        cypherQueryFile, check, preProcess, postProcess, postServe} = {}) {
        if (typeof procedure === 'function')
            this.invoke = procedure;
        else
            this.invoke = createProcedure(neo4jConnection,
                {cypherQueryFile, check, preProcess, postProcess, postServe, name: route});

        this.method = method;
        this.route = route;
        this.allowedRoles = allowedRoles;
        this.requiresJwtAuthentication = allowedRoles &&
            Array.isArray(allowedRoles) && allowedRoles.length > 0;
    }
}

export {Neo4jConnection, createProcedure, API};
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const secretToken = require('../config').secretToken;
const User = require('../models/User');
const { log } = require('../log');
const validate = require('jsonschema').validate;
const { isTokenAuthorized, isUserAuthorized } = require('./userRoles');
const { getConnection } = require('../db');

/**
 * Middleware function to force a route to require authentication
 * Verifies the request's token against the server's secret token
 */
authMiddleware = (req, res, next) => {
	const token = req.headers.token || req.body.token || req.query.token;
	const validParams = {
		type: 'string'
	};

	if (!validate(token, validParams).valid) {
		res.status(403).json({ success: false, message: 'No token provided or JSON was invalid.' });
	} else if (token) {
		jwt.verify(token, secretToken, async (err, decoded) => {
			if (err) {
				res.status(401).json({ success: false, message: 'Failed to authenticate token.' });
			} else {
				req.decoded = decoded;
				try {
					const conn = getConnection();
					await User.getByID(decoded.data, conn); // checks if user exists in the database in case it was deleted
					next();
				} catch (error) {
					res.status(401).json({ success: false, message: 'User does not exist in database.' });
				}
			}
		});
	} else {
		res.status(403).send({ success: false, message: 'No token provided.' });
	}
};

function credentialsRequestValidationMiddleware(req, res, next) {
	const validParams = {
		type: 'object',
		required: ['email', 'password'],
		properties: {
			email: {
				type: 'string',
				minLength: 3,
				maxLength: 254
			},
			password: {
				type: 'string',
				minLength: 3
			}
		}
	};
	if (!validate(req.body, validParams).valid) {
		res.status(400).send('Invalid JSON. \n');
	} else {
		next();
	}
}

async function verifyCredentials(email, password, returnUser = false) {
	const conn = getConnection();
	const user = await User.getByEmail(email, conn);
	const isValid = await bcrypt.compare(password, user.passwordHash);
	return (returnUser ? isValid && user : isValid);
}

/**
 * Creates middleware that verifies the requested token and only proceeds if the requestor is a particular user role or Admin.
 * @param {string} role
 * @param action
 */
function roleAuthMiddleware(role, action){
	return function (req, res, next) {
		this.authMiddleware(req, res, async () => {
			const token = req.headers.token || req.body.token || req.query.token;
			if (await isTokenAuthorized(token, role)) {
				next();
			} else {
				log.warn(`Got request to '${action}' with invalid credentials. ${role.toUpperCase()} role is required to '${action}'.`);
				res.status(401)
					.json({ message: `Invalid credentials supplied. Only admins can ${action}.` });
			}
		})
	}
}

/**
 * Returns middleware that verifies the requested token and only proceeds if the requestor is an  Admin.
 */
function adminAuthMiddleware(action) {
	return roleAuthMiddleware(User.role.ADMIN, action);
}

/**
 * Returns middleware that verifies the requested token and only proceeds if the requestor is an  Admin.
 */
function exportAuthMiddleware(action) {
	return roleAuthMiddleware(User.role.EXPORT, action);
}

/**
 * Returns middleware that only authenticates an Admin or Obvius user.
 * @param {string} action - is a phrase or word that can be prefixed by 'to' for the proper response and warning messages.
 */
function obviusEmailAndPasswordAuthMiddleware(action) {
	return function (req, res, next) {
		credentialsRequestValidationMiddleware(req, res, async () => {
			try {
				const user = await verifyCredentials(req.body.email, req.body.password, true);
				if (user) {
					if (isUserAuthorized(user, User.role.OBVIUS)) {
						next();
					} else {
						const message = `Got request to '${action}' with invalid authorization level. Obvius role is at least required to '${action}'.`;
						log.warn(message);
						res.status(401).send(message);
						return;
					}
				} else {
					const message = `Got request to '${action} with invalid credentials.`;
					log.warn(message);
					res.status(400).send(message);
					return;
				}
			} catch (error) {
				if (error.message === 'No data returned from the query.') {
					res.status(400).send(`No user corresponding to the email: ${req.body.email} was found. Please make a request with a valid email.`);
				} else {
					log.error('Internal Server Error for Obvius request.', error);
					res.status(500).send('Internal OED Server Error for Obvius request.');
				}
			}
		});
	}
}

/**
 * Middleware function to force a route to provide optional authentication
 * Verifies the request's token against the server's secret token
 * Sets the req field hasValidAuthToken to true or false
 */
optionalAuthMiddleware = (req, res, next) => {
	// Set auth token to false initially.
	req.hasValidAuthToken = false;

	const token = req.headers.token || req.body.token || req.query.token;
	const validParams = {
		type: 'string'
	};

	// If there is no token, there can be no valid token.
	if (!validate(token, validParams).valid) {
		next();
	} else if (token) {
		jwt.verify(token, secretToken, (err, decoded) => {
			if (err) {
				// do nothing. Could log here if need be
			} else {
				req.decoded = decoded;
				req.hasValidAuthToken = true;
			}
			next();
		});
	} else {
		next();
	}
};

module.exports = {
	adminAuthMiddleware,
	authMiddleware,
	exportAuthMiddleware,
	obviusEmailAndPasswordAuthMiddleware,
	optionalAuthMiddleware
};<commit_msg>Change error code to 403<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const secretToken = require('../config').secretToken;
const User = require('../models/User');
const { log } = require('../log');
const validate = require('jsonschema').validate;
const { isTokenAuthorized, isUserAuthorized } = require('./userRoles');
const { getConnection } = require('../db');

/**
 * Middleware function to force a route to require authentication
 * Verifies the request's token against the server's secret token
 */
authMiddleware = (req, res, next) => {
	const token = req.headers.token || req.body.token || req.query.token;
	const validParams = {
		type: 'string'
	};

	if (!validate(token, validParams).valid) {
		res.status(403).json({ success: false, message: 'No token provided or JSON was invalid.' });
	} else if (token) {
		jwt.verify(token, secretToken, async (err, decoded) => {
			if (err) {
				res.status(401).json({ success: false, message: 'Failed to authenticate token.' });
			} else {
				req.decoded = decoded;
				try {
					const conn = getConnection();
					await User.getByID(decoded.data, conn); // checks if user exists in the database in case it was deleted
					next();
				} catch (error) {
					res.status(401).json({ success: false, message: 'User does not exist in database.' });
				}
			}
		});
	} else {
		res.status(403).send({ success: false, message: 'No token provided.' });
	}
};

function credentialsRequestValidationMiddleware(req, res, next) {
	const validParams = {
		type: 'object',
		required: ['email', 'password'],
		properties: {
			email: {
				type: 'string',
				minLength: 3,
				maxLength: 254
			},
			password: {
				type: 'string',
				minLength: 3
			}
		}
	};
	if (!validate(req.body, validParams).valid) {
		res.status(400).send('Invalid JSON. \n');
	} else {
		next();
	}
}

async function verifyCredentials(email, password, returnUser = false) {
	const conn = getConnection();
	const user = await User.getByEmail(email, conn);
	const isValid = await bcrypt.compare(password, user.passwordHash);
	return (returnUser ? isValid && user : isValid);
}

/**
 * Creates middleware that verifies the requested token and only proceeds if the requestor is a particular user role or Admin.
 * @param {string} role
 * @param action
 */
function roleAuthMiddleware(role, action){
	return function (req, res, next) {
		this.authMiddleware(req, res, async () => {
			const token = req.headers.token || req.body.token || req.query.token;
			if (await isTokenAuthorized(token, role)) {
				next();
			} else {
				log.warn(`Got request to '${action}' with invalid credentials. ${role.toUpperCase()} role is required to '${action}'.`);
				res.status(403)
					.json({ message: `Invalid credentials supplied. Only ${role.toUpperCase()} can ${action}.` });
			}
		})
	}
}

/**
 * Returns middleware that verifies the requested token and only proceeds if the requestor is an  Admin.
 */
function adminAuthMiddleware(action) {
	return roleAuthMiddleware(User.role.ADMIN, action);
}

/**
 * Returns middleware that verifies the requested token and only proceeds if the requestor is an  Admin.
 */
function exportAuthMiddleware(action) {
	return roleAuthMiddleware(User.role.EXPORT, action);
}

/**
 * Returns middleware that only authenticates an Admin or Obvius user.
 * @param {string} action - is a phrase or word that can be prefixed by 'to' for the proper response and warning messages.
 */
function obviusEmailAndPasswordAuthMiddleware(action) {
	return function (req, res, next) {
		credentialsRequestValidationMiddleware(req, res, async () => {
			try {
				const user = await verifyCredentials(req.body.email, req.body.password, true);
				if (user) {
					if (isUserAuthorized(user, User.role.OBVIUS)) {
						next();
					} else {
						const message = `Got request to '${action}' with invalid authorization level. Obvius role is at least required to '${action}'.`;
						log.warn(message);
						res.status(401).send(message);
						return;
					}
				} else {
					const message = `Got request to '${action} with invalid credentials.`;
					log.warn(message);
					res.status(400).send(message);
					return;
				}
			} catch (error) {
				if (error.message === 'No data returned from the query.') {
					res.status(400).send(`No user corresponding to the email: ${req.body.email} was found. Please make a request with a valid email.`);
				} else {
					log.error('Internal Server Error for Obvius request.', error);
					res.status(500).send('Internal OED Server Error for Obvius request.');
				}
			}
		});
	}
}

/**
 * Middleware function to force a route to provide optional authentication
 * Verifies the request's token against the server's secret token
 * Sets the req field hasValidAuthToken to true or false
 */
optionalAuthMiddleware = (req, res, next) => {
	// Set auth token to false initially.
	req.hasValidAuthToken = false;

	const token = req.headers.token || req.body.token || req.query.token;
	const validParams = {
		type: 'string'
	};

	// If there is no token, there can be no valid token.
	if (!validate(token, validParams).valid) {
		next();
	} else if (token) {
		jwt.verify(token, secretToken, (err, decoded) => {
			if (err) {
				// do nothing. Could log here if need be
			} else {
				req.decoded = decoded;
				req.hasValidAuthToken = true;
			}
			next();
		});
	} else {
		next();
	}
};

module.exports = {
	adminAuthMiddleware,
	authMiddleware,
	exportAuthMiddleware,
	obviusEmailAndPasswordAuthMiddleware,
	optionalAuthMiddleware
};<|endoftext|>


<commit_before>/**
 * Created by keyvan on 8/16/16.
 */

import {v1 as neo4j} from 'neo4j-driver';
import fs from 'file-system';
import chalk from 'chalk';
import parser from 'parse-neo4j';
import {parseNeo4jInts} from './preprocess';
import {pipe, getArgs} from './util';

class Neo4jConnection {
    constructor({boltUrl, user, password} = {}) {
        this.queries = {};

        this.driver = neo4j.driver(boltUrl, neo4j.auth.basic(user, password));
        const session = this.driver.session();
        this.initialized = session.run('RETURN "Neo4j instance successfully connected."')
            .then((result) => {
                console.log(chalk.green(parser.parse(result)));
                session.close();
            })
            .catch(error => {
                console.error(
                    chalk.red('Error connecting to the Neo4j instance, check connection options'));
                console.log(error);
                throw error;
            });
    }

    addCypherQueryFile(cypherQueryFilePath) {
        this.queries[cypherQueryFilePath] = fs.readFileSync(cypherQueryFilePath, 'utf8');
    }

    executeCypher(cypherQueryFilePath, queryParams) {
        return new Promise((resolve, reject) => {
            if (!this.queries[cypherQueryFilePath])
                this.addCypherQueryFile(cypherQueryFilePath);

            const query = this.queries[cypherQueryFilePath];
            const session = this.driver.session();

            session.run(query, queryParams)
                .then(result => {
                    resolve(result);
                    session.close();
                })
                .catch(reject);
        })
            .then(parser.parse);
    }
}

class Hook {
    constructor(func, route, hookName) {
        this.name = hookName;
        this.route = route;
        const lastTwoArgs = getArgs(func).slice(-2);
        if (lastTwoArgs[0] === 'resolve' || lastTwoArgs[1] === 'resolve')
            this.constructAsync(func, lastTwoArgs[1] === 'reject');
        else
            this.constructSync(func);
    }

    constructAsync(func, rejectPresent) {
        this.execute = (...args) => Promise.race([
            new Promise((resolve, reject) => {
                args.push(resolve);
                if (rejectPresent)
                    args.push(reject);
                func.apply(this.context, args);
            }),
            new Promise(resolve => setTimeout(resolve, 4000))
                .then(() => 'no response after 4 seconds')
        ])
            .then(result => {
                if (result === 'no response after 4 seconds')
                    throw new Error(`${this.name} lifecycle of ${this.route} timed out, ${result}`);
                return result;
            });
    }

    constructSync(func) {
        this.execute = (...args) => Promise.resolve(func.apply(this.context, args));
    }
}

const createProcedure = (neo4jConnection, {cypherQueryFile, check = (params, user) => true,
    preProcess = params => params, postProcess = result => result,
    name = 'createProcedure'} = {}) => {
    const checkHook = new Hook(check, name, 'check');
    const preProcessHooh = new Hook(preProcess, name, 'preProcess');
    const postProcessHook = new Hook(postProcess, name, 'postProcess');

    return (params, user) => {
        return checkHook.execute(params, user)
            .then(checkPassed => {
                if (!checkPassed)
                    throw new Error('Check lifecycle hook did not pass');
                return params;
            })
            .then(pipe(parseNeo4jInts('id', 'skip', 'limit'), preProcessHooh.execute))
            .then(params => Promise.all([
                neo4jConnection.executeCypher(cypherQueryFile, params),
                Promise.resolve(params)
            ]))
            .then(([result, params]) => postProcessHook.execute(result, params));
    };
};

class API {
    constructor(neo4jConnection, {method, route, allowedRoles = [], procedure,
        cypherQueryFile, check, preProcess, postProcess} = {}) {
        if (typeof procedure === 'function')
            this.response = procedure;
        else
            this.response = createProcedure(neo4jConnection,
                {cypherQueryFile, check, preProcess, postProcess, name: route});

        this.method = method;
        this.route = route;
        this.allowedRoles = allowedRoles;
        this.requiresJwtAuthentication = allowedRoles &&
            Array.isArray(allowedRoles) && allowedRoles.length > 0;
    }
}

export {Neo4jConnection, createProcedure, API};
<commit_msg>fix for resolve and reject in postProcess async<commit_after>/**
 * Created by keyvan on 8/16/16.
 */

import {v1 as neo4j} from 'neo4j-driver';
import fs from 'file-system';
import chalk from 'chalk';
import parser from 'parse-neo4j';
import {parseNeo4jInts} from './preprocess';
import {pipe, getArgs} from './util';

class Neo4jConnection {
    constructor({boltUrl, user, password} = {}) {
        this.queries = {};

        this.driver = neo4j.driver(boltUrl, neo4j.auth.basic(user, password));
        const session = this.driver.session();
        this.initialized = session.run('RETURN "Neo4j instance successfully connected."')
            .then((result) => {
                console.log(chalk.green(parser.parse(result)));
                session.close();
            })
            .catch(error => {
                console.error(
                    chalk.red('Error connecting to the Neo4j instance, check connection options'));
                console.log(error);
                throw error;
            });
    }

    addCypherQueryFile(cypherQueryFilePath) {
        this.queries[cypherQueryFilePath] = fs.readFileSync(cypherQueryFilePath, 'utf8');
    }

    executeCypher(cypherQueryFilePath, queryParams) {
        return new Promise((resolve, reject) => {
            if (!this.queries[cypherQueryFilePath])
                this.addCypherQueryFile(cypherQueryFilePath);

            const query = this.queries[cypherQueryFilePath];
            const session = this.driver.session();

            session.run(query, queryParams)
                .then(result => {
                    resolve(result);
                    session.close();
                })
                .catch(reject);
        })
            .then(parser.parse);
    }
}

class Hook {
    constructor(func, route, hookName) {
        this.name = hookName;
        this.route = route;
        const lastTwoArgs = getArgs(func).slice(-2);
        if (lastTwoArgs[0] === 'resolve' || lastTwoArgs[1] === 'resolve')
            this.constructAsync(func, lastTwoArgs[1] === 'reject');
        else
            this.constructSync(func);
    }

    constructAsync(func, rejectPresent) {
        this.execute = (...args) => Promise.race([
            new Promise((resolve, reject) => {
                args.push(resolve);
                if (rejectPresent)
                    args.push(reject);
                func.apply(this.context, args);
            }),
            new Promise(resolve => setTimeout(resolve, 4000))
                .then(() => 'no response after 4 seconds')
        ])
            .then(result => {
                if (result === 'no response after 4 seconds')
                    throw new Error(`${this.name} lifecycle of ${this.route} timed out, ${result}`);
                return result;
            });
    }

    constructSync(func) {
        this.execute = (...args) => Promise.resolve(func.apply(this.context, args));
    }
}

const createProcedure = (neo4jConnection, {cypherQueryFile, check = (params, user) => true,
    preProcess = params => params, postProcess = result => result,
    name = 'createProcedure'} = {}) => {
    const checkHook = new Hook(check, name, 'check');
    const preProcessHooh = new Hook(preProcess, name, 'preProcess');
    const postProcessHook = new Hook(postProcess, name, 'postProcess');

    return (params, user) => {
        return checkHook.execute(params, user)
            .then(checkPassed => {
                if (!checkPassed)
                    throw new Error('Check lifecycle hook did not pass');
                return params;
            })
            .then(pipe(parseNeo4jInts('id', 'skip', 'limit'), preProcessHooh.execute))
            .then(params => Promise.all([
                neo4jConnection.executeCypher(cypherQueryFile, params),
                Promise.resolve(params)
            ]))
            .then(([result, params]) => {
                const args = getArgs(postProcess);
                let lastArg = args.slice(-1)[0];
                if (lastArg === 'reject') {
                    args.pop();
                    lastArg = args.slice(-1)[0];
                }
                if (lastArg === 'resolve')
                    args.pop();
                if (args.length === 1)
                    return postProcessHook.execute(result);
                return postProcessHook.execute(result, params);
            });
    };
};

class API {
    constructor(neo4jConnection, {method, route, allowedRoles = [], procedure,
        cypherQueryFile, check, preProcess, postProcess} = {}) {
        if (typeof procedure === 'function')
            this.response = procedure;
        else
            this.response = createProcedure(neo4jConnection,
                {cypherQueryFile, check, preProcess, postProcess, name: route});

        this.method = method;
        this.route = route;
        this.allowedRoles = allowedRoles;
        this.requiresJwtAuthentication = allowedRoles &&
            Array.isArray(allowedRoles) && allowedRoles.length > 0;
    }
}

export {Neo4jConnection, createProcedure, API};
<|endoftext|>


<commit_before>/* Generated from cs.po at Fri Jan 30 08:28:42 2009 */
window.ui_strings || ( window.ui_strings  = {} )
window.ui_strings.lang_code = "cs";
ui_strings.S_SWITCH_SHOW_TAB_ALL="Zobrazit list Vše";
ui_strings.S_SWITCH_SHOW_TAB_SCRIPT="Zobrazit list Skript";
ui_strings.S_SWITCH_SHOW_TAB_JAVA="Zobrazit list Java";
ui_strings.S_SWITCH_SHOW_TAB_M2="Zobrazit list Pošta";
ui_strings.S_SWITCH_SHOW_TAB_NETWORK="Zobrazit list Připojení";
ui_strings.S_SWITCH_SHOW_TAB_XML="Zobrazit list XML";
ui_strings.S_SWITCH_SHOW_TAB_HTML="Zobrazit list HTML";
ui_strings.S_SWITCH_SHOW_TAB_CSS="Zobrazit list CSS";
ui_strings.S_SWITCH_SHOW_TAB_XSLT="Zobrazit list XSLT";
ui_strings.S_SWITCH_SHOW_TAB_SVG="Zobrazit list SVG";
ui_strings.S_SWITCH_SHOW_TAB_BITTORRENT="Zobrazit list BitTorrent";
ui_strings.S_SWITCH_SHOW_TAB_VOICE="Zobrazit list Hlasový modul";
ui_strings.S_SWITCH_SHOW_TAB_WIDGET="Zobrazit list Pomůcky";
ui_strings.S_SWITCH_SHOW_TAB_DRAGONFLY="Zobrazit list Opera Dragonfly";
ui_strings.S_SWITCH_UPDATE_GLOBAL_SCOPE="Automaticky aktualizovat v celém rozsahu";
ui_strings.S_SWITCH_FIND_ELEMENT_BY_CLICKING="Klepnutím vyhledat prvek";
ui_strings.S_SWITCH_HIGHLIGHT_BY_MOUSE_OVER="Zvýraznit při najetí myší";
ui_strings.S_SWITCH_UPDATE_DOM_ON_NODE_REMOVE="Při odstranění uzlu aktualizovat DOM";
ui_strings.S_SWITCH_USE_LOWER_CASE_TAG_NAMES="Použít malá písmena pro jména tagů";
ui_strings.S_SWITCH_SHOW_COMMENT_NODES="Zobrazit uzly s komentáři";
ui_strings.S_SWITCH_SHOW_ATTRIBUTES="Zobrazit atributy";
ui_strings.S_SWITCH_SHOW_WHITE_SPACE_NODES="Zobrazit uzly s bílými znaky";
ui_strings.S_SWITCH_SHOW_DOM_INTREE_VIEW="Zobrazit stromovou strukturu DOM";
ui_strings.S_SWITCH_USE_SHORTHAND_PROPERTIES="Použít zkrácený zápis vlastností";
ui_strings.S_SWITCH_HIDE_INITIAL_VALUES="Skrýt počáteční hodnoty v počítaných stylech";
ui_strings.S_SWITCH_HIDE_SHORTHANDS="Skrýt zkrácený zápis v počítaných stylech";
ui_strings.S_SWITCH_HIDE_EMPTY_STRINGS="Skrýt prázdné řetězce a nulové hodnoty";
ui_strings.S_SWITCH_REMOTE_DEBUG="Vzdálené ladění";
ui_strings.S_SWITCH_SHOW_VIEWS_MENU="Zobrazit menu Zobrazení";
ui_strings.S_SWITCH_RELOAD_SCRIPTS_AUTOMATICALLY="Při výběru okna automaticky znovu načíst dokumenty";
ui_strings.S_SWITCH_ATTACH_WINDOW="Připojit do hlavního okna";
ui_strings.S_SWITCH_SHOW_INITIAL_VALUES="Skrýt počáteční hodnoty v počítaných stylech";
ui_strings.S_SWITCH_SHOW_SHORTHANDS="Skrýt zkrácený zápis v zobrazení počítaných stylů";
ui_strings.S_SWITCH_CREATE_SHORTHANDS="Použít zkrácený zápis vlastností";
ui_strings.S_BUTTON_LABEL_CONTINUE="Pokračovat (F8)";
ui_strings.S_BUTTON_LABEL_STEP_OVER="Přejít (F10)";
ui_strings.S_BUTTON_LABEL_STEP_INTO="Vstoupit (F11)";
ui_strings.S_BUTTON_LABEL_STEP_OUT="Vystoupit (Shift F11)";
ui_strings.S_BUTTON_LABEL_STOP_AT_THREAD="Zastavit u dalšího skriptu";
ui_strings.S_BUTTON_LABEL_AT_EXCEPTION="Zastavit při výskytu výjimky";
ui_strings.S_BUTTON_LABEL_AT_ERROR="Zastavit při výskytu chyby";
ui_strings.S_BUTTON_LABEL_AT_ABORT="Zastavit při selhání";
ui_strings.S_BUTTON_LABEL_RELOAD_HOST="Načíst znovu vybrané okno v prohlížeči";
ui_strings.S_BUTTON_LABEL_SELECT_WINDOW="Výběr okna";
ui_strings.S_BUTTON_LABEL_GET_THE_WOHLE_TREE="Rozbalit strom DOM";
ui_strings.S_BUTTON_LABEL_EXPORT_DOM="Exportovat stávající zobrazení DOM";
ui_strings.S_BUTTON_LABEL_HIDE_DEFAULT_PROPS_IN_GLOBAL_SCOPE="Skrýt výchozí vlastnosti v celém rozsahu";
ui_strings.S_BUTTON_LABEL_LOG_THREADS="Zaznamenávat vlákna";
ui_strings.S_BUTTON_LABEL_CLEAR_THREAD_LOG="Vymazat záznam vlákna";
ui_strings.S_BUTTON_LABEL_EXPORT_LOG="Exportovat záznam vlákna";
ui_strings.S_BUTTON_LABEL_SETTINGS="Nastavení";
ui_strings.S_BUTTON_LABEL_CLEAR_LOG="Vymazat záznam";
ui_strings.S_BUTTON_LABEL_CLOSE_WINDOW="Zavřít okno";
ui_strings.S_BUTTON_TEXT_APPLY="Použít";
ui_strings.S_BUTTON_CLEAR_REQUEST_LOG="Vymazat záznam požadavků";
ui_strings.S_LABEL_STATUS_INDICATOR="Stavový indikátor prohlížeče a ladícího nástroje";
ui_strings.S_LABEL_PORT="Port";
ui_strings.S_INPUT_DEFAULT_TEXT_SEARCH="Hledat";
ui_strings.S_INPUT_DEFAULT_TEXT_FILTER="Vyhledat";
ui_strings.S_INFO_RELOAD_FOR_SCRIPT="Po klepnutí na tlačítko pro opětovné načtení umístěné výše budou načteny skripty vybraného okna";
ui_strings.S_INFO_RUNTIME_HAS_NO_SCRIPTS="Tento dokument neobsahuje skripty";
ui_strings.S_INFO_DOCUMNENT_LOADING="Načítá se Opera Dragonfly ...";
ui_strings.S_INFO_SERVICE_NOT_AVAILABLE="Služba není dostupná: %s";
ui_strings.S_INFO_NO_RUNTIME_SELECTED="Výběr běhového prostředí";
ui_strings.S_TEXT_CALL_STACK_FRAME_LINE="%(FUNCTION_NAME)s: Řádek %(LINE_NUMBER)s (Script ID %(SCRIPT_ID)s)";
ui_strings.S_TEXT_ENVIRONMENT_PROTOCOL_VERSION="Verze protokolu";
ui_strings.S_TEXT_ENVIRONMENT_OPERATING_SYSTEM="Operační systém";
ui_strings.S_TEXT_ENVIRONMENT_PLATFORM="Platforma";
ui_strings.S_TEXT_ENVIRONMENT_USER_AGENT="Identifikační řetězec";
ui_strings.S_TEXT_ENVIRONMENT_DRAGONFLY_VERSION="Verze Opera Dragonfly";
ui_strings.S_TEXT_ENVIRONMENT_REVISION_NUMBER="Číslo revize";
ui_strings.S_TEXT_ECMA_SCRIPT_TYPE_INLINE="Vřazený";
ui_strings.S_TEXT_ECMA_SCRIPT_TYPE_LINKED="Odkazovaný";
ui_strings.S_TEXT_ECMA_SCRIPT_TYPE_UNKNOWN="Neznámý";
ui_strings.S_TEXT_ECMA_SCRIPT_SCRIPT_ID="Skript ID";
ui_strings.S_TEXT_STATUS_SEARCH="Výskyty výrazu %(SEARCH_TERM)s: Výskyt č. %(SEARCH_COUNT_INDEX)s z %(SEARCH_COUNT_TOTAL)s";
ui_strings.S_TEXT_NO_REQUEST_SELECTED="Není vybrán žádný požadavek.";
ui_strings.S_SWITCH_DETACH_WINDOW="Odpojit do vlastního okna";
ui_strings.S_SWITCH_SHOW_SIBLINGS_IN_BREAD_CRUMB="Zobrazit v navigačním řetězci sourozence";
ui_strings.S_SWITCH_SHOW_ID_AND_CLASSES_IN_BREAD_CRUMB="Zobrazit v navigačním řetězci identity a třídy";
ui_strings.S_BUTTON_LABEL_HELP="Nápověda";
ui_strings.S_SELECT_WINDOW_EMPTY="Vybrat okno";
ui_strings.S_INFO_WRONG_START="Tímto způsobem nelze nástroj Opera Dragonfly používat.\nZadejte stávající adresu na stránce Editoru nastavení do\n\n   opera:config > Developer Tools > Developer Tools URL\n\nnebo nastavte prostředí ladícího nástroje pomocí proxy a serveru.";
ui_strings.S_INFO_WAITING_FOR_CONNECTION="Opera Dragonfly čeká na připojení na portu %s.\nPro připojení zadejte "opera:debug" do adresního řádku Vašeho zařízení.";
ui_strings.M_VIEW_LABEL_COMPOSITE_SCRIPTS="Skripty";
ui_strings.M_VIEW_LABEL_COMPOSITE_DOM="DOM";
ui_strings.M_VIEW_LABEL_COMPOSITE_ERROR_CONSOLE="Chybová konzole";
ui_strings.M_VIEW_LABEL_COMPOSITE_EXPORTS="Export";
ui_strings.M_VIEW_LABEL_NETWORK="Připojení";
ui_strings.M_VIEW_LABEL_SCRIPTS="Skripty";
ui_strings.M_VIEW_LABEL_ENVIRONMENT="Prostředí";
ui_strings.M_VIEW_LABEL_SOURCE="Zdroj";
ui_strings.M_VIEW_LABEL_COMMAND_LINE="Příkazový řádek";
ui_strings.M_VIEW_LABEL_CALLSTACK="Souhrn volání";
ui_strings.M_VIEW_LABEL_THREAD_LOG="Záznam vlákna";
ui_strings.M_VIEW_LABEL_FRAME_INSPECTION="Prohlížení";
ui_strings.M_VIEW_LABEL_OBJECT_INSPECTION="Prohlížení objektu";
ui_strings.M_VIEW_LABEL_DOCUMENTS="Dokumenty";
ui_strings.M_VIEW_LABEL_STYLESHEETS="Kaskádové styly";
ui_strings.M_VIEW_LABEL_DOM="DOM";
ui_strings.M_VIEW_LABEL_STYLESHEET="Kaskádový styl";
ui_strings.M_VIEW_LABEL_STYLES="Styly";
ui_strings.M_VIEW_LABEL_DOM_ATTR="Vlastnosti";
ui_strings.M_VIEW_LABEL_LAYOUT="Rozvržení";
ui_strings.M_VIEW_LABEL_ERROR_ALL="Vše";
ui_strings.M_VIEW_LABEL_ERROR_SCRIPT="JavaScript";
ui_strings.M_VIEW_LABEL_ERROR_JAVA="Java";
ui_strings.M_VIEW_LABEL_ERROR_M2="Pošta";
ui_strings.M_VIEW_LABEL_ERROR_NETWORK="Připojení";
ui_strings.M_VIEW_LABEL_ERROR_XML="XML";
ui_strings.M_VIEW_LABEL_ERROR_HTML="HTML";
ui_strings.M_VIEW_LABEL_ERROR_CSS="CSS";
ui_strings.M_VIEW_LABEL_ERROR_XSLT="XSLT";
ui_strings.M_VIEW_LABEL_ERROR_SVG="SVG";
ui_strings.M_VIEW_LABEL_ERROR_BITTORRENT="BitTorrent";
ui_strings.M_VIEW_LABEL_ERROR_VOICE="Hlasový modul";
ui_strings.M_VIEW_LABEL_ERROR_WIDGET="Pomůcky";
ui_strings.M_VIEW_LABEL_ERROR_DRAGONFLY="Opera Dragonfly";
ui_strings.M_VIEW_LABEL_COMPUTED_STYLE="Počítaný styl";
ui_strings.M_VIEW_LABEL_CONSOLE="Konzole";
ui_strings.M_VIEW_LABEL_EXPORT="Export";
ui_strings.M_VIEW_LABEL_REQUEST_LOG="Záznam požadavků";
ui_strings.M_VIEW_LABEL_RAW_REQUEST_INFO="Neupravovaný požadavek";
ui_strings.M_VIEW_LABEL_RAW_RESPONSE_INFO="Neupravovaná odezva";
ui_strings.M_VIEW_LABEL_REQUEST_HEADERS="Hlavička požadavku";
ui_strings.M_VIEW_LABEL_RESPONSE_HEADERS="Hlavička odezvy";
ui_strings.M_VIEW_LABEL_REQUEST_INFO="Info o požadavku";
ui_strings.M_VIEW_LABEL_RESPONSE_BODY="Tělo odezvy";
ui_strings.M_VIEW_LABEL_VIEWS="Zobrazení";
ui_strings.M_VIEW_SUB_LABEL_METRICS="Metrika";
ui_strings.M_VIEW_SUB_LABEL_PARENT_OFFSETS="Nadřazené offsety";
ui_strings.M_VIEW_SUB_LABEL_OFFSET_VALUES="Hodnoty offsetu";
ui_strings.M_SETTING_LABEL_GENERAL="Základní";<commit_msg>Fixed some unescaped quotes in the cs translation<commit_after>/* Generated from cs.po at Fri Jan 30 08:28:42 2009 */
window.ui_strings || ( window.ui_strings  = {} )
window.ui_strings.lang_code = "cs";
ui_strings.S_SWITCH_SHOW_TAB_ALL="Zobrazit list Vše";
ui_strings.S_SWITCH_SHOW_TAB_SCRIPT="Zobrazit list Skript";
ui_strings.S_SWITCH_SHOW_TAB_JAVA="Zobrazit list Java";
ui_strings.S_SWITCH_SHOW_TAB_M2="Zobrazit list Pošta";
ui_strings.S_SWITCH_SHOW_TAB_NETWORK="Zobrazit list Připojení";
ui_strings.S_SWITCH_SHOW_TAB_XML="Zobrazit list XML";
ui_strings.S_SWITCH_SHOW_TAB_HTML="Zobrazit list HTML";
ui_strings.S_SWITCH_SHOW_TAB_CSS="Zobrazit list CSS";
ui_strings.S_SWITCH_SHOW_TAB_XSLT="Zobrazit list XSLT";
ui_strings.S_SWITCH_SHOW_TAB_SVG="Zobrazit list SVG";
ui_strings.S_SWITCH_SHOW_TAB_BITTORRENT="Zobrazit list BitTorrent";
ui_strings.S_SWITCH_SHOW_TAB_VOICE="Zobrazit list Hlasový modul";
ui_strings.S_SWITCH_SHOW_TAB_WIDGET="Zobrazit list Pomůcky";
ui_strings.S_SWITCH_SHOW_TAB_DRAGONFLY="Zobrazit list Opera Dragonfly";
ui_strings.S_SWITCH_UPDATE_GLOBAL_SCOPE="Automaticky aktualizovat v celém rozsahu";
ui_strings.S_SWITCH_FIND_ELEMENT_BY_CLICKING="Klepnutím vyhledat prvek";
ui_strings.S_SWITCH_HIGHLIGHT_BY_MOUSE_OVER="Zvýraznit při najetí myší";
ui_strings.S_SWITCH_UPDATE_DOM_ON_NODE_REMOVE="Při odstranění uzlu aktualizovat DOM";
ui_strings.S_SWITCH_USE_LOWER_CASE_TAG_NAMES="Použít malá písmena pro jména tagů";
ui_strings.S_SWITCH_SHOW_COMMENT_NODES="Zobrazit uzly s komentáři";
ui_strings.S_SWITCH_SHOW_ATTRIBUTES="Zobrazit atributy";
ui_strings.S_SWITCH_SHOW_WHITE_SPACE_NODES="Zobrazit uzly s bílými znaky";
ui_strings.S_SWITCH_SHOW_DOM_INTREE_VIEW="Zobrazit stromovou strukturu DOM";
ui_strings.S_SWITCH_USE_SHORTHAND_PROPERTIES="Použít zkrácený zápis vlastností";
ui_strings.S_SWITCH_HIDE_INITIAL_VALUES="Skrýt počáteční hodnoty v počítaných stylech";
ui_strings.S_SWITCH_HIDE_SHORTHANDS="Skrýt zkrácený zápis v počítaných stylech";
ui_strings.S_SWITCH_HIDE_EMPTY_STRINGS="Skrýt prázdné řetězce a nulové hodnoty";
ui_strings.S_SWITCH_REMOTE_DEBUG="Vzdálené ladění";
ui_strings.S_SWITCH_SHOW_VIEWS_MENU="Zobrazit menu Zobrazení";
ui_strings.S_SWITCH_RELOAD_SCRIPTS_AUTOMATICALLY="Při výběru okna automaticky znovu načíst dokumenty";
ui_strings.S_SWITCH_ATTACH_WINDOW="Připojit do hlavního okna";
ui_strings.S_SWITCH_SHOW_INITIAL_VALUES="Skrýt počáteční hodnoty v počítaných stylech";
ui_strings.S_SWITCH_SHOW_SHORTHANDS="Skrýt zkrácený zápis v zobrazení počítaných stylů";
ui_strings.S_SWITCH_CREATE_SHORTHANDS="Použít zkrácený zápis vlastností";
ui_strings.S_BUTTON_LABEL_CONTINUE="Pokračovat (F8)";
ui_strings.S_BUTTON_LABEL_STEP_OVER="Přejít (F10)";
ui_strings.S_BUTTON_LABEL_STEP_INTO="Vstoupit (F11)";
ui_strings.S_BUTTON_LABEL_STEP_OUT="Vystoupit (Shift F11)";
ui_strings.S_BUTTON_LABEL_STOP_AT_THREAD="Zastavit u dalšího skriptu";
ui_strings.S_BUTTON_LABEL_AT_EXCEPTION="Zastavit při výskytu výjimky";
ui_strings.S_BUTTON_LABEL_AT_ERROR="Zastavit při výskytu chyby";
ui_strings.S_BUTTON_LABEL_AT_ABORT="Zastavit při selhání";
ui_strings.S_BUTTON_LABEL_RELOAD_HOST="Načíst znovu vybrané okno v prohlížeči";
ui_strings.S_BUTTON_LABEL_SELECT_WINDOW="Výběr okna";
ui_strings.S_BUTTON_LABEL_GET_THE_WOHLE_TREE="Rozbalit strom DOM";
ui_strings.S_BUTTON_LABEL_EXPORT_DOM="Exportovat stávající zobrazení DOM";
ui_strings.S_BUTTON_LABEL_HIDE_DEFAULT_PROPS_IN_GLOBAL_SCOPE="Skrýt výchozí vlastnosti v celém rozsahu";
ui_strings.S_BUTTON_LABEL_LOG_THREADS="Zaznamenávat vlákna";
ui_strings.S_BUTTON_LABEL_CLEAR_THREAD_LOG="Vymazat záznam vlákna";
ui_strings.S_BUTTON_LABEL_EXPORT_LOG="Exportovat záznam vlákna";
ui_strings.S_BUTTON_LABEL_SETTINGS="Nastavení";
ui_strings.S_BUTTON_LABEL_CLEAR_LOG="Vymazat záznam";
ui_strings.S_BUTTON_LABEL_CLOSE_WINDOW="Zavřít okno";
ui_strings.S_BUTTON_TEXT_APPLY="Použít";
ui_strings.S_BUTTON_CLEAR_REQUEST_LOG="Vymazat záznam požadavků";
ui_strings.S_LABEL_STATUS_INDICATOR="Stavový indikátor prohlížeče a ladícího nástroje";
ui_strings.S_LABEL_PORT="Port";
ui_strings.S_INPUT_DEFAULT_TEXT_SEARCH="Hledat";
ui_strings.S_INPUT_DEFAULT_TEXT_FILTER="Vyhledat";
ui_strings.S_INFO_RELOAD_FOR_SCRIPT="Po klepnutí na tlačítko pro opětovné načtení umístěné výše budou načteny skripty vybraného okna";
ui_strings.S_INFO_RUNTIME_HAS_NO_SCRIPTS="Tento dokument neobsahuje skripty";
ui_strings.S_INFO_DOCUMNENT_LOADING="Načítá se Opera Dragonfly ...";
ui_strings.S_INFO_SERVICE_NOT_AVAILABLE="Služba není dostupná: %s";
ui_strings.S_INFO_NO_RUNTIME_SELECTED="Výběr běhového prostředí";
ui_strings.S_TEXT_CALL_STACK_FRAME_LINE="%(FUNCTION_NAME)s: Řádek %(LINE_NUMBER)s (Script ID %(SCRIPT_ID)s)";
ui_strings.S_TEXT_ENVIRONMENT_PROTOCOL_VERSION="Verze protokolu";
ui_strings.S_TEXT_ENVIRONMENT_OPERATING_SYSTEM="Operační systém";
ui_strings.S_TEXT_ENVIRONMENT_PLATFORM="Platforma";
ui_strings.S_TEXT_ENVIRONMENT_USER_AGENT="Identifikační řetězec";
ui_strings.S_TEXT_ENVIRONMENT_DRAGONFLY_VERSION="Verze Opera Dragonfly";
ui_strings.S_TEXT_ENVIRONMENT_REVISION_NUMBER="Číslo revize";
ui_strings.S_TEXT_ECMA_SCRIPT_TYPE_INLINE="Vřazený";
ui_strings.S_TEXT_ECMA_SCRIPT_TYPE_LINKED="Odkazovaný";
ui_strings.S_TEXT_ECMA_SCRIPT_TYPE_UNKNOWN="Neznámý";
ui_strings.S_TEXT_ECMA_SCRIPT_SCRIPT_ID="Skript ID";
ui_strings.S_TEXT_STATUS_SEARCH="Výskyty výrazu %(SEARCH_TERM)s: Výskyt č. %(SEARCH_COUNT_INDEX)s z %(SEARCH_COUNT_TOTAL)s";
ui_strings.S_TEXT_NO_REQUEST_SELECTED="Není vybrán žádný požadavek.";
ui_strings.S_SWITCH_DETACH_WINDOW="Odpojit do vlastního okna";
ui_strings.S_SWITCH_SHOW_SIBLINGS_IN_BREAD_CRUMB="Zobrazit v navigačním řetězci sourozence";
ui_strings.S_SWITCH_SHOW_ID_AND_CLASSES_IN_BREAD_CRUMB="Zobrazit v navigačním řetězci identity a třídy";
ui_strings.S_BUTTON_LABEL_HELP="Nápověda";
ui_strings.S_SELECT_WINDOW_EMPTY="Vybrat okno";
ui_strings.S_INFO_WRONG_START="Tímto způsobem nelze nástroj Opera Dragonfly používat.\nZadejte stávající adresu na stránce Editoru nastavení do\n\n   opera:config > Developer Tools > Developer Tools URL\n\nnebo nastavte prostředí ladícího nástroje pomocí proxy a serveru.";
ui_strings.S_INFO_WAITING_FOR_CONNECTION="Opera Dragonfly čeká na připojení na portu %s.\nPro připojení zadejte \"opera:debug\" do adresního řádku Vašeho zařízení.";
ui_strings.M_VIEW_LABEL_COMPOSITE_SCRIPTS="Skripty";
ui_strings.M_VIEW_LABEL_COMPOSITE_DOM="DOM";
ui_strings.M_VIEW_LABEL_COMPOSITE_ERROR_CONSOLE="Chybová konzole";
ui_strings.M_VIEW_LABEL_COMPOSITE_EXPORTS="Export";
ui_strings.M_VIEW_LABEL_NETWORK="Připojení";
ui_strings.M_VIEW_LABEL_SCRIPTS="Skripty";
ui_strings.M_VIEW_LABEL_ENVIRONMENT="Prostředí";
ui_strings.M_VIEW_LABEL_SOURCE="Zdroj";
ui_strings.M_VIEW_LABEL_COMMAND_LINE="Příkazový řádek";
ui_strings.M_VIEW_LABEL_CALLSTACK="Souhrn volání";
ui_strings.M_VIEW_LABEL_THREAD_LOG="Záznam vlákna";
ui_strings.M_VIEW_LABEL_FRAME_INSPECTION="Prohlížení";
ui_strings.M_VIEW_LABEL_OBJECT_INSPECTION="Prohlížení objektu";
ui_strings.M_VIEW_LABEL_DOCUMENTS="Dokumenty";
ui_strings.M_VIEW_LABEL_STYLESHEETS="Kaskádové styly";
ui_strings.M_VIEW_LABEL_DOM="DOM";
ui_strings.M_VIEW_LABEL_STYLESHEET="Kaskádový styl";
ui_strings.M_VIEW_LABEL_STYLES="Styly";
ui_strings.M_VIEW_LABEL_DOM_ATTR="Vlastnosti";
ui_strings.M_VIEW_LABEL_LAYOUT="Rozvržení";
ui_strings.M_VIEW_LABEL_ERROR_ALL="Vše";
ui_strings.M_VIEW_LABEL_ERROR_SCRIPT="JavaScript";
ui_strings.M_VIEW_LABEL_ERROR_JAVA="Java";
ui_strings.M_VIEW_LABEL_ERROR_M2="Pošta";
ui_strings.M_VIEW_LABEL_ERROR_NETWORK="Připojení";
ui_strings.M_VIEW_LABEL_ERROR_XML="XML";
ui_strings.M_VIEW_LABEL_ERROR_HTML="HTML";
ui_strings.M_VIEW_LABEL_ERROR_CSS="CSS";
ui_strings.M_VIEW_LABEL_ERROR_XSLT="XSLT";
ui_strings.M_VIEW_LABEL_ERROR_SVG="SVG";
ui_strings.M_VIEW_LABEL_ERROR_BITTORRENT="BitTorrent";
ui_strings.M_VIEW_LABEL_ERROR_VOICE="Hlasový modul";
ui_strings.M_VIEW_LABEL_ERROR_WIDGET="Pomůcky";
ui_strings.M_VIEW_LABEL_ERROR_DRAGONFLY="Opera Dragonfly";
ui_strings.M_VIEW_LABEL_COMPUTED_STYLE="Počítaný styl";
ui_strings.M_VIEW_LABEL_CONSOLE="Konzole";
ui_strings.M_VIEW_LABEL_EXPORT="Export";
ui_strings.M_VIEW_LABEL_REQUEST_LOG="Záznam požadavků";
ui_strings.M_VIEW_LABEL_RAW_REQUEST_INFO="Neupravovaný požadavek";
ui_strings.M_VIEW_LABEL_RAW_RESPONSE_INFO="Neupravovaná odezva";
ui_strings.M_VIEW_LABEL_REQUEST_HEADERS="Hlavička požadavku";
ui_strings.M_VIEW_LABEL_RESPONSE_HEADERS="Hlavička odezvy";
ui_strings.M_VIEW_LABEL_REQUEST_INFO="Info o požadavku";
ui_strings.M_VIEW_LABEL_RESPONSE_BODY="Tělo odezvy";
ui_strings.M_VIEW_LABEL_VIEWS="Zobrazení";
ui_strings.M_VIEW_SUB_LABEL_METRICS="Metrika";
ui_strings.M_VIEW_SUB_LABEL_PARENT_OFFSETS="Nadřazené offsety";
ui_strings.M_VIEW_SUB_LABEL_OFFSET_VALUES="Hodnoty offsetu";
ui_strings.M_SETTING_LABEL_GENERAL="Základní";<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const secretToken = require('../config').secretToken;
const User = require('../models/User');
const { log } = require('../log');
const validate = require('jsonschema').validate;
const { isTokenAuthorized, isUserAuthorized } = require('./userRoles');
const { getConnection } = require('../db');

/**
 * Middleware function to force a route to require authentication
 * Verifies the request's token against the server's secret token
 */
authMiddleware = (req, res, next) => {
	const token = req.headers.token || req.body.token || req.query.token;
	const validParams = {
		type: 'string'
	};

	if (!validate(token, validParams).valid) {
		res.status(403).json({ success: false, message: 'No token provided or JSON was invalid.' });
	} else if (token) {
		jwt.verify(token, secretToken, (err, decoded) => {
			if (err) {
				res.status(401).json({ success: false, message: 'Failed to authenticate token.' });
			} else {
				req.decoded = decoded;
				next();
			}
		});
	} else {
		res.status(403).send({ success: false, message: 'No token provided.' });
	}
};

function credentialsRequestValidationMiddleware(req, res, next) {
	const validParams = {
		type: 'object',
		required: ['email', 'password'],
		properties: {
			email: {
				type: 'string',
				minLength: 3,
				maxLength: 254
			},
			password: {
				type: 'string',
				minLength: 3
			}
		}
	};
	if (!validate(req.body, validParams).valid) {
		res.status(400).send('Invalid JSON. \n');
	} else {
		next();
	}
}

async function verifyCredentials(email, password, returnUser = false) {
	const conn = getConnection();
	const user = await User.getByEmail(email, conn);
	const isValid = await bcrypt.compare(password, user.passwordHash);
	return (returnUser ? isValid && user : isValid);
}

/**
 * Returns middleware that verifies the requested token and only proceeds if the requestor is an  Admin.
 */
function adminAuthMiddleware(action) {
	return function (req, res, next) {
		this.authMiddleware(req, res, async () => {
			const token = req.headers.token || req.body.token || req.query.token;
			if (await isTokenAuthorized(token, User.role.ADMIN)) {
				next();
			} else {
				log.warn(`Got request to '${action}' with invalid credentials. Admin role is required to '${action}'.`);
				res.status(401)
					.json({ message: `Invalid credentials supplied. Only admins can ${action}.` });
			}
		})
	}
}

/**
 * Returns middleware that only authenticates an Admin or Obvius user.
 * @param {string} action - is a phrase or word that can be prefixed by 'to' for the proper response and warning messages.
 */
function obviusEmailAndPasswordAuthMiddleware(action) {
	return function (req, res, next) {
		credentialsRequestValidationMiddleware(req, res, async () => {
			try {
				const user = await verifyCredentials(req.email, req.password, true);
				if (user) {
					if (isUserAuthorized(user, User.role.OBVIUS)) {
						next();
					} else {
						const message = `Got request to '${action}' with invalid authorization level. Obvius role is at least required to '${action}'.`;
						log.warn(message);
						res.status(400)
							.text(message);
					}
				} else {
					const message = `Got request to '${action} with invalid credentials.`;
					log.warn(message);
					res.status(400)
						.text(message);
				}
			} catch (error) {
				if (error.message === 'No data returned from the query.') {
					res.status(400).text(`No user corresponding to the email: ${req.email} was found. Please make a request with a valid email.`);
				} else {
					log.error('Internal Server Error for Obvius request.', error);
					res.status(400).text('Internal OED Server Error for Obvius request.');
				}
			}
		});
	}
}

/**
 * Middleware function to force a route to provide optional authentication
 * Verifies the request's token against the server's secret token
 * Sets the req field hasValidAuthToken to true or false
 */
optionalAuthMiddleware = (req, res, next) => {
	// Set auth token to false initially.
	req.hasValidAuthToken = false;

	const token = req.headers.token || req.body.token || req.query.token;
	const validParams = {
		type: 'string'
	};

	// If there is no token, there can be no valid token.
	if (!validate(token, validParams).valid) {
		next();
	} else if (token) {
		jwt.verify(token, secretToken, (err, decoded) => {
			if (err) {
				// do nothing. Could log here if need be
			} else {
				req.decoded = decoded;
				req.hasValidAuthToken = true;
			}
			next();
		});
	} else {
		next();
	}
};

module.exports = {
	adminAuthMiddleware,
	authMiddleware,
	obviusEmailAndPasswordAuthMiddleware,
	optionalAuthMiddleware
};<commit_msg>Fix bugs with obvius authentication<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const secretToken = require('../config').secretToken;
const User = require('../models/User');
const { log } = require('../log');
const validate = require('jsonschema').validate;
const { isTokenAuthorized, isUserAuthorized } = require('./userRoles');
const { getConnection } = require('../db');

/**
 * Middleware function to force a route to require authentication
 * Verifies the request's token against the server's secret token
 */
authMiddleware = (req, res, next) => {
	const token = req.headers.token || req.body.token || req.query.token;
	const validParams = {
		type: 'string'
	};

	if (!validate(token, validParams).valid) {
		res.status(403).json({ success: false, message: 'No token provided or JSON was invalid.' });
	} else if (token) {
		jwt.verify(token, secretToken, (err, decoded) => {
			if (err) {
				res.status(401).json({ success: false, message: 'Failed to authenticate token.' });
			} else {
				req.decoded = decoded;
				next();
			}
		});
	} else {
		res.status(403).send({ success: false, message: 'No token provided.' });
	}
};

function credentialsRequestValidationMiddleware(req, res, next) {
	const validParams = {
		type: 'object',
		required: ['email', 'password'],
		properties: {
			email: {
				type: 'string',
				minLength: 3,
				maxLength: 254
			},
			password: {
				type: 'string',
				minLength: 3
			}
		}
	};
	if (!validate(req.body, validParams).valid) {
		res.status(400).send('Invalid JSON. \n');
	} else {
		next();
	}
}

async function verifyCredentials(email, password, returnUser = false) {
	const conn = getConnection();
	const user = await User.getByEmail(email, conn);
	const isValid = await bcrypt.compare(password, user.passwordHash);
	return (returnUser ? isValid && user : isValid);
}

/**
 * Returns middleware that verifies the requested token and only proceeds if the requestor is an  Admin.
 */
function adminAuthMiddleware(action) {
	return function (req, res, next) {
		this.authMiddleware(req, res, async () => {
			const token = req.headers.token || req.body.token || req.query.token;
			if (await isTokenAuthorized(token, User.role.ADMIN)) {
				next();
			} else {
				log.warn(`Got request to '${action}' with invalid credentials. Admin role is required to '${action}'.`);
				res.status(401)
					.json({ message: `Invalid credentials supplied. Only admins can ${action}.` });
			}
		})
	}
}

/**
 * Returns middleware that only authenticates an Admin or Obvius user.
 * @param {string} action - is a phrase or word that can be prefixed by 'to' for the proper response and warning messages.
 */
function obviusEmailAndPasswordAuthMiddleware(action) {
	return function (req, res, next) {
		credentialsRequestValidationMiddleware(req, res, async () => {
			try {
				const user = await verifyCredentials(req.body.email, req.body.password, true);
				if (user) {
					if (isUserAuthorized(user, User.role.OBVIUS)) {
						next();
					} else {
						const message = `Got request to '${action}' with invalid authorization level. Obvius role is at least required to '${action}'.`;
						log.warn(message);
						res.status(401).send(message);
						return;
					}
				} else {
					const message = `Got request to '${action} with invalid credentials.`;
					log.warn(message);
					res.status(400).send(message);
					return;
				}
			} catch (error) {
				if (error.message === 'No data returned from the query.') {
					res.status(400).send(`No user corresponding to the email: ${req.body.email} was found. Please make a request with a valid email.`);
				} else {
					log.error('Internal Server Error for Obvius request.', error);
					res.status(500).send('Internal OED Server Error for Obvius request.');
				}
			}
		});
	}
}

/**
 * Middleware function to force a route to provide optional authentication
 * Verifies the request's token against the server's secret token
 * Sets the req field hasValidAuthToken to true or false
 */
optionalAuthMiddleware = (req, res, next) => {
	// Set auth token to false initially.
	req.hasValidAuthToken = false;

	const token = req.headers.token || req.body.token || req.query.token;
	const validParams = {
		type: 'string'
	};

	// If there is no token, there can be no valid token.
	if (!validate(token, validParams).valid) {
		next();
	} else if (token) {
		jwt.verify(token, secretToken, (err, decoded) => {
			if (err) {
				// do nothing. Could log here if need be
			} else {
				req.decoded = decoded;
				req.hasValidAuthToken = true;
			}
			next();
		});
	} else {
		next();
	}
};

module.exports = {
	adminAuthMiddleware,
	authMiddleware,
	obviusEmailAndPasswordAuthMiddleware,
	optionalAuthMiddleware
};<|endoftext|>


<commit_before>// this includes endpoints at data.nba.com

const getJson = require("./get-json");
const { interpolate } = require("./util/string");

const scoreboardURL = interpolate("http://data.nba.com/data/5s/json/cms/noseason/scoreboard/__date__/games.json");
const boxScoreURL = interpolate("http://data.nba.com/data/5s/json/cms/noseason/game/__date__/__gameId__/boxscore.json");
const playByPlayURL = interpolate("http://data.nba.com/data/5s/json/cms/noseason/game/__date__/__gameId__/pbp_all.json");

// NOTE: the 'date' argument should be a string in format like "20181008" (which indicates Oct 8 2018)
// You *can* pass a Date object but beware of timezone weirdness!

const scoreboard = date => getJson(scoreboardURL({ date: dateToYYYYMMDD(date) }));
scoreboard.defaults = { date: null };

const boxScore = (date, gameId) => getJson(boxScoreURL({ date: dateToYYYYMMDD(date), gameId }));
boxScore.defaults = { date: null, gameId: null };

const playByPlay = (date, gameId) => getJson(playByPlayURL({ date: dateToYYYYMMDD(date), gameId }));
playByPlay.defaults = { date: null, gameId: null };

function dateToYYYYMMDD (date) {
  if (date instanceof Date) {
    return [
      date.getFullYear(),
      String(date.getMonth() + 1).padStart(2, 0),
      String(date.getDate()).padStart(2, 0),
    ].join("");
  }

  // TODO: better checking here?

  return date;
}

module.exports = {
  scoreboard,
  boxScore,
  playByPlay,
};<commit_msg>added schedule endpoint (#67)<commit_after>// this includes endpoints at data.nba.com

const getJson = require("./get-json");
const { interpolate } = require("./util/string");

const scoreboardURL = interpolate("http://data.nba.com/data/5s/json/cms/noseason/scoreboard/__date__/games.json");
const boxScoreURL = interpolate("http://data.nba.com/data/5s/json/cms/noseason/game/__date__/__gameId__/boxscore.json");
const playByPlayURL = interpolate("http://data.nba.com/data/5s/json/cms/noseason/game/__date__/__gameId__/pbp_all.json");
const scheduleURL = interpolate("http://data.nba.com/data/10s/v2015/json/mobile_teams/nba/__season__/league/00_full_schedule.json");

// NOTE: the 'date' argument should be a string in format like "20181008" (which indicates Oct 8 2018)
// You *can* pass a Date object but beware of timezone weirdness!

const scoreboard = date => getJson(scoreboardURL({ date: dateToYYYYMMDD(date) }));
scoreboard.defaults = { date: null };

const boxScore = (date, gameId) => getJson(boxScoreURL({ date: dateToYYYYMMDD(date), gameId }));
boxScore.defaults = { date: null, gameId: null };

const playByPlay = (date, gameId) => getJson(playByPlayURL({ date: dateToYYYYMMDD(date), gameId }));
playByPlay.defaults = { date: null, gameId: null };

// NOTE: the 'season' argument is the first year of the NBA season e.g. "2018" for the 2018-19 season
// 2015 is the first valid season

const schedule = (season) => getJson(scheduleURL({ season }));
schedule.defaults = { season: null };

function dateToYYYYMMDD (date) {
  if (date instanceof Date) {
    return [
      date.getFullYear(),
      String(date.getMonth() + 1).padStart(2, 0),
      String(date.getDate()).padStart(2, 0),
    ].join("");
  }

  // TODO: better checking here?

  return date;
}

module.exports = {
  scoreboard,
  boxScore,
  playByPlay,
  schedule
};<|endoftext|>


<commit_before>function MakePlayer() {
        this.seen = { rock: 0, paper: 0, scissors: 0, spock: 0, lizard: 0};
        this.maxHold = 10;
        this.lastXMoves = [];
}

MakePlayer.prototype.keys = ['rock', 'paper', 'scissors', 'spock', 'lizard'];

MakePlayer.prototype.counters = {
    'rock': ['paper', 'spock'],
    'paper': ['scissors', 'lizard'],
    'scissors': ['rock', 'spock'],
    'spock': ['paper', 'lizard'],
    'lizard': ['rock', 'scissors']
};

MakePlayer.prototype.reset = function () {
    var that = this;

    // reset the seen values.
    $.each(Object.keys(this.seen), function (i, k) {
        that.seen[k] = 0;
    });
};

MakePlayer.prototype.getMostUsed = function () {
    var mostUsed,
        that = this,
        currentMax = -1;

    $.each(this.keys, function (i, k) {
        var localMax = that.seen[k];

        if (localMax > currentMax) {
            mostUsed = [k];
            currentMax = localMax;
        } else if (localMax === currentMax) {
            mostUsed.push(k);
        }
    });

    return mostUsed;
};

MakePlayer.prototype.recordOpponentMove = function (move) {
    this.seen[move]++;

    this.lastXMoves.push(move);

    if (this.lastXMoves.length === this.maxHold) {
        this.lastXMoves = this.lastXMoves.slice(1);
    }
};

MakePlayer.prototype.getMovePool = function (moves) {
        var that = this,
            movePool = [];

        $.each(moves, function (i, m) {
            $.each(that.counters[m], function (j, c) {
                if (moves.indexOf(c) === -1 && movePool.indexOf(c) === -1) {
                    movePool.push(c);
                }
            });
        });

        return movePool;
    };

MakePlayer.prototype.randomMove = function (moveArray) {
        var keys = moveArray || this.keys;

        console.log("Random");

        return keys[Math.floor(Math.random() * keys.length)];
    };

MakePlayer.prototype.smartMove = function () {
        var movePool = this.getMovePool(this.getMostUsed());

        console.log("Smart");

        return this.randomMove(movePool.length > 0 ? movePool : undefined);
    };

MakePlayer.prototype.smarterMove = function () {

        var mostUsed = this.getMostUsed(),
            i = this.lastXMoves.length - 1,
            lastMove = this.lastXMoves[i--],
            currentChain = 1,
            tmp,
            movePool,
            that = this;

        console.log("Smarter");

        // Look for a long chain for the last moves.
        for(; i >= 0; i--) {
            tmp = this.lastXMoves[i];

            if (tmp === lastMove) {
                currentChain++;
            } else {
                break;
            }
        }

        // We had the same thing appear three or more times in a row.
        // Let's counter that.
        if (currentChain >= 3) {
            movePool = this.getMovePool([lastMove]);
        } else { // Add in the latest move
            if (lastMove && mostUsed.indexOf(lastMove) === -1) {
                mostUsed.push(lastMove);
            }

            movePool = this.getMovePool(mostUsed)
        }

        return this.randomMove(movePool.length > 0 ? movePool : undefined);
    };

var R = {
    stats: { player: 0, comp: 0, ties: 0, total: 0 },

    relations: {
        'rock': {'scissors': 'crushes', 'lizard': 'crushes'},
        'paper': {'rock': 'covers', 'spock': 'disproves'},
        'scissors': {'paper': 'cut', 'lizard': 'decapitate'},
        'spock': {'rock': 'vaporizes', 'scissors': 'smashes'},
        'lizard': {'spock': 'poison', 'paper': 'eat'}
    },

    reset: function () {
        $.each(this.stats, function (i, k) {
            stats[k] = 0;
        });
    },

    prettyPercent: function (num) {
        if (this.stats.total !== 0) {
            return parseFloat(Math.round(num / this.stats.total + 'e+4') + 'e-2');
        } else {
            return 0.0;
        }
    },

    determineWinner: function (p1, p2, cb) {
        var outcomes,
            relations = this.relations,
            stats = this.stats;

        ++stats.total;

        if (p1 === p2) {
            ++stats.ties;

            cb("No one wins. It's a tie!");
        } else {
            outcomes = relations[p1];

            if (p2 in outcomes) {
                ++stats.player;

                cb(p1 + ' ' + outcomes[p2] + ' ' + p2 + '. Player 1 wins!');
            } else {
                ++stats.comp;

                outcomes = relations[p2];
                cb(p2 + ' ' + outcomes[p1] + ' ' + p1 + '. Player 2 wins!');
            }
        }
    }
};
<commit_msg>Remove console statements.<commit_after>function MakePlayer() {
        this.seen = { rock: 0, paper: 0, scissors: 0, spock: 0, lizard: 0};
        this.maxHold = 10;
        this.lastXMoves = [];
}

MakePlayer.prototype.keys = ['rock', 'paper', 'scissors', 'spock', 'lizard'];

MakePlayer.prototype.counters = {
    'rock': ['paper', 'spock'],
    'paper': ['scissors', 'lizard'],
    'scissors': ['rock', 'spock'],
    'spock': ['paper', 'lizard'],
    'lizard': ['rock', 'scissors']
};

MakePlayer.prototype.reset = function () {
    var that = this;

    // reset the seen values.
    $.each(Object.keys(this.seen), function (i, k) {
        that.seen[k] = 0;
    });
};

MakePlayer.prototype.getMostUsed = function () {
    var mostUsed,
        that = this,
        currentMax = -1;

    $.each(this.keys, function (i, k) {
        var localMax = that.seen[k];

        if (localMax > currentMax) {
            mostUsed = [k];
            currentMax = localMax;
        } else if (localMax === currentMax) {
            mostUsed.push(k);
        }
    });

    return mostUsed;
};

MakePlayer.prototype.recordOpponentMove = function (move) {
    this.seen[move]++;

    this.lastXMoves.push(move);

    if (this.lastXMoves.length === this.maxHold) {
        this.lastXMoves = this.lastXMoves.slice(1);
    }
};

MakePlayer.prototype.getMovePool = function (moves) {
        var that = this,
            movePool = [];

        $.each(moves, function (i, m) {
            $.each(that.counters[m], function (j, c) {
                if (moves.indexOf(c) === -1 && movePool.indexOf(c) === -1) {
                    movePool.push(c);
                }
            });
        });

        return movePool;
    };

MakePlayer.prototype.randomMove = function (moveArray) {
        var keys = moveArray || this.keys;

        return keys[Math.floor(Math.random() * keys.length)];
    };

MakePlayer.prototype.smartMove = function () {
        var movePool = this.getMovePool(this.getMostUsed());

        return this.randomMove(movePool.length > 0 ? movePool : undefined);
    };

MakePlayer.prototype.smarterMove = function () {

        var mostUsed = this.getMostUsed(),
            i = this.lastXMoves.length - 1,
            lastMove = this.lastXMoves[i--],
            currentChain = 1,
            tmp,
            movePool,
            that = this;

        // Look for a long chain for the last moves.
        for(; i >= 0; i--) {
            tmp = this.lastXMoves[i];

            if (tmp === lastMove) {
                currentChain++;
            } else {
                break;
            }
        }

        // We had the same thing appear three or more times in a row.
        // Let's counter that.
        if (currentChain >= 3) {
            movePool = this.getMovePool([lastMove]);
        } else { // Add in the latest move
            if (lastMove && mostUsed.indexOf(lastMove) === -1) {
                mostUsed.push(lastMove);
            }

            movePool = this.getMovePool(mostUsed)
        }

        return this.randomMove(movePool.length > 0 ? movePool : undefined);
    };

var R = {
    stats: { player: 0, comp: 0, ties: 0, total: 0 },

    relations: {
        'rock': {'scissors': 'crushes', 'lizard': 'crushes'},
        'paper': {'rock': 'covers', 'spock': 'disproves'},
        'scissors': {'paper': 'cut', 'lizard': 'decapitate'},
        'spock': {'rock': 'vaporizes', 'scissors': 'smashes'},
        'lizard': {'spock': 'poison', 'paper': 'eat'}
    },

    reset: function () {
        $.each(this.stats, function (i, k) {
            stats[k] = 0;
        });
    },

    prettyPercent: function (num) {
        if (this.stats.total !== 0) {
            return parseFloat(Math.round(num / this.stats.total + 'e+4') + 'e-2');
        } else {
            return 0.0;
        }
    },

    determineWinner: function (p1, p2, cb) {
        var outcomes,
            relations = this.relations,
            stats = this.stats;

        ++stats.total;

        if (p1 === p2) {
            ++stats.ties;

            cb("No one wins. It's a tie!");
        } else {
            outcomes = relations[p1];

            if (p2 in outcomes) {
                ++stats.player;

                cb(p1 + ' ' + outcomes[p2] + ' ' + p2 + '. Player 1 wins!');
            } else {
                ++stats.comp;

                outcomes = relations[p2];
                cb(p2 + ' ' + outcomes[p1] + ' ' + p1 + '. Player 2 wins!');
            }
        }
    }
};
<|endoftext|>


<commit_before>/*global angular */
/*
 jQuery UI Datepicker plugin wrapper

 @note If ≤ IE8 make sure you have a polyfill for Date.toISOString()
 @param [ui-date] {object} Options to pass to $.fn.datepicker() merged onto uiDateConfig
 */

angular.module('ui.date', [])

.constant('uiDateConfig', {})

.directive('uiDate', ['uiDateConfig', 'uiDateConverter', function (uiDateConfig, uiDateConverter) {
  'use strict';
  var options;
  options = {};
  angular.extend(options, uiDateConfig);
  return {
    require:'?ngModel',
    link:function (scope, element, attrs, controller) {
      var getOptions = function () {
        return angular.extend({}, uiDateConfig, scope.$eval(attrs.uiDate));
      };
      var initDateWidget = function () {
        var showing = false;
        var opts = getOptions();

        // If we have a controller (i.e. ngModelController) then wire it up
        if (controller) {

          // Set the view value in a $apply block when users selects
          // (calling directive user's function too if provided)
          var _onSelect = opts.onSelect || angular.noop;
          opts.onSelect = function (value, picker) {
            scope.$apply(function() {
              showing = true;
              controller.$setViewValue(element.datepicker("getDate"));
              _onSelect(value, picker);
              //element.blur();
            });
          };
          opts.beforeShow = function() {
            showing = true;
          };
          opts.onClose = function(value, picker) {
            showing = false;
          };
          element.off('blur.datepicker').on('blur.datepicker', function() {
            if ( !showing ) {
              scope.$apply(function() {
                element.datepicker("setDate", element.datepicker("getDate"));
                controller.$setViewValue(element.datepicker("getDate"));
              });
            }
          });

          // Update the date picker when the model changes
          controller.$render = function () {
            var date = controller.$modelValue;
            if ( angular.isDefined(date) && date !== null && !angular.isDate(date) ) {
                if ( angular.isString(controller.$modelValue) ) {
                    date = uiDateConverter.stringToDate(attrs.uiDateFormat, controller.$modelValue);
                } else {
                    throw new Error('ng-Model value must be a Date, or a String object with a date formatter - currently it is a ' + typeof date + ' - use ui-date-format to convert it from a string');
                }
            }
            element.datepicker("setDate", date);
          };
        }
        // If we don't destroy the old one it doesn't update properly when the config changes
        element.datepicker('destroy');
        // Create the new datepicker widget
        element.datepicker(opts);
        if ( controller ) {
          // Force a render to override whatever is in the input text box
          controller.$render();
        }
      };
      // Watch for changes to the directives options
      scope.$watch(getOptions, initDateWidget, true);
    }
  };
}
])
.service('uiDateConverter', ['uiDateFormatConfig', function(uiDateFormatConfig){

    function dateToString(dateFormat, value){
        if (value) {
            if ( dateFormat || uiDateFormatConfig) {
                return jQuery.datepicker.formatDate(dateFormat, value);
            }
            return value.toISOString();
        } else {
            return null;
        }
    }

    function stringToDate(dateFormat, value) {
        if ( angular.isString(value) ) {
            if ( dateFormat || uiDateFormatConfig) {
                return jQuery.datepicker.parseDate(dateFormat, value);
            }

            var isoDate = new Date(value);
            return isNaN(isoDate.getTime()) ? null : isoDate;
        }
        return null;
    }

    return {
        stringToDate: stringToDate,
        dateToString: dateToString
    };

}])
.constant('uiDateFormatConfig', '')
.directive('uiDateFormat', ['uiDateConverter', function(uiDateConverter) {
  var directive = {
    require:'ngModel',
    link: function(scope, element, attrs, modelCtrl) {
        var dateFormat = attrs.uiDateFormat;

        // Use the datepicker with the attribute value as the dateFormat string to convert to and from a string
        modelCtrl.$formatters.unshift(function(value) {
            return uiDateConverter.stringToDate(dateFormat, value);
        });

        modelCtrl.$parsers.push(function(value){
            return uiDateConverter.dateToString(dateFormat, value);
        });

    }
  };

  return directive;
}]);
<commit_msg>fix(date.js) service can be a factory<commit_after>/*global angular */
/*
 jQuery UI Datepicker plugin wrapper

 @note If ≤ IE8 make sure you have a polyfill for Date.toISOString()
 @param [ui-date] {object} Options to pass to $.fn.datepicker() merged onto uiDateConfig
 */

angular.module('ui.date', [])

.constant('uiDateConfig', {})

.directive('uiDate', ['uiDateConfig', 'uiDateConverter', function (uiDateConfig, uiDateConverter) {
  'use strict';
  var options;
  options = {};
  angular.extend(options, uiDateConfig);
  return {
    require:'?ngModel',
    link:function (scope, element, attrs, controller) {
      var getOptions = function () {
        return angular.extend({}, uiDateConfig, scope.$eval(attrs.uiDate));
      };
      var initDateWidget = function () {
        var showing = false;
        var opts = getOptions();

        // If we have a controller (i.e. ngModelController) then wire it up
        if (controller) {

          // Set the view value in a $apply block when users selects
          // (calling directive user's function too if provided)
          var _onSelect = opts.onSelect || angular.noop;
          opts.onSelect = function (value, picker) {
            scope.$apply(function() {
              showing = true;
              controller.$setViewValue(element.datepicker("getDate"));
              _onSelect(value, picker);
              //element.blur();
            });
          };
          opts.beforeShow = function() {
            showing = true;
          };
          opts.onClose = function(value, picker) {
            showing = false;
          };
          element.off('blur.datepicker').on('blur.datepicker', function() {
            if ( !showing ) {
              scope.$apply(function() {
                element.datepicker("setDate", element.datepicker("getDate"));
                controller.$setViewValue(element.datepicker("getDate"));
              });
            }
          });

          // Update the date picker when the model changes
          controller.$render = function () {
            var date = controller.$modelValue;
            if ( angular.isDefined(date) && date !== null && !angular.isDate(date) ) {
                if ( angular.isString(controller.$modelValue) ) {
                    date = uiDateConverter.stringToDate(attrs.uiDateFormat, controller.$modelValue);
                } else {
                    throw new Error('ng-Model value must be a Date, or a String object with a date formatter - currently it is a ' + typeof date + ' - use ui-date-format to convert it from a string');
                }
            }
            element.datepicker("setDate", date);
          };
        }
        // If we don't destroy the old one it doesn't update properly when the config changes
        element.datepicker('destroy');
        // Create the new datepicker widget
        element.datepicker(opts);
        if ( controller ) {
          // Force a render to override whatever is in the input text box
          controller.$render();
        }
      };
      // Watch for changes to the directives options
      scope.$watch(getOptions, initDateWidget, true);
    }
  };
}
])
.factory('uiDateConverter', ['uiDateFormatConfig', function(uiDateFormatConfig){

    function dateToString(dateFormat, value){
        if (value) {
            if ( dateFormat || uiDateFormatConfig) {
                return jQuery.datepicker.formatDate(dateFormat, value);
            }
            return value.toISOString();
        } else {
            return null;
        }
    }

    function stringToDate(dateFormat, value) {
        if ( angular.isString(value) ) {
            if ( dateFormat || uiDateFormatConfig) {
                return jQuery.datepicker.parseDate(dateFormat, value);
            }

            var isoDate = new Date(value);
            return isNaN(isoDate.getTime()) ? null : isoDate;
        }
        return null;
    }

    return {
        stringToDate: stringToDate,
        dateToString: dateToString
    };

}])
.constant('uiDateFormatConfig', '')
.directive('uiDateFormat', ['uiDateConverter', function(uiDateConverter) {
  var directive = {
    require:'ngModel',
    link: function(scope, element, attrs, modelCtrl) {
        var dateFormat = attrs.uiDateFormat;

        // Use the datepicker with the attribute value as the dateFormat string to convert to and from a string
        modelCtrl.$formatters.unshift(function(value) {
            return uiDateConverter.stringToDate(dateFormat, value);
        });

        modelCtrl.$parsers.push(function(value){
            return uiDateConverter.dateToString(dateFormat, value);
        });

    }
  };

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


<commit_before><commit_msg>feat(consulta): adicionar js de comportamento da pagina de consulta-ecletica.<commit_after><|endoftext|>


<commit_before>/**
 * greetings.js - Manage greetings for servers
 * @author Ovyerus
 */

/* eslint-env node */

const Eris = require('eris');

exports.commands = [
    'greetings'
];

exports.greetings = {
    desc: 'Manage server greetings.',
    longDesc: 'Show current greeting settings for the server, and manage them if you have the correct permission.',
    main(bot, ctx) {
        return new Promise((resolve, reject) => {
            if (ctx.args.length === 0) {
                ctx.createMessage({embed: greetingBlock(ctx.settings)}).then(resolve).catch(reject);
            } else if (ctx.args[0] === 'enable') {
                if (!ctx.member.permission.has('manageGuild')) {
                    ctx.createMessage(localeManager.t('user-noPerm', ctx.settings.locale, {perm: 'Manage Server'})).then(resolve).catch(reject);
                } else {
                    bot.getGuildSettings(ctx.guild.id).then(res => {
                        let settings = res;
                        settings.greeting.enabled = true;
                        return bot.setGuildSettings(res.id, settings);
                    }).then(() => {
                        return ctx.createMessage(localeManager.t('greetings-enable', ctx.settings.locale));
                    }).then(resolve).catch(reject);
                }
            }  else if (ctx.args[0] === 'disable') {
                if (!ctx.member.permission.has('manageGuild')) {
                    ctx.createMessage(localeManager.t('user-noPerm', ctx.settings.locale, {perm: 'Manage Server'})).then(resolve).catch(reject);
                } else {
                    bot.getGuildSettings(ctx.guild.id).then(res => {
                        let settings = res;
                        settings.greeting.enabled = false;
                        return bot.setGuildSettings(res.id, settings);
                    }).then(() => {
                        return ctx.createMessage(localeManager.t('greetings-disable', ctx.settings.locale));
                    }).then(resolve).catch(reject);
                }
            } else if (ctx.args[0] === 'channel' && ctx.args.length >= 2) {
                if (!ctx.member.permission.has('manageGuild')) {
                    ctx.createMessage(localeManager.t('user-noPerm', ctx.settings.locale, {perm: 'Manage Server'})).then(resolve).catch(reject);
                } else {
                    bot.getGuildSettings(ctx.guild.id).then(res => {
                        let settings = res;

                        if (ctx.channelMentions.length > 0) {
                            settings.greeting.channelID = ctx.channelMentions[0];
                            return bot.setGuildSettings(res.id, settings);
                        } else {
                            let meme = ctx.suffix.split(' ');
                            meme.shift();
                            let chans = ctx.guild.channels.filter(c => c.name.toLowerCase().includes(meme.join(' ')));

                            if (chans.length === 0) {
                                return ctx.createMessage(localeManager.t('greetings-noChan', ctx.settings.locale, {name: meme.join(' ')}));
                            } else {
                                settings.greeting.channelID = chans[0].id;
                                return bot.setGuildSettings(res.id, settings);
                            }
                        }
                    }).then(res => {
                        if (res instanceof Eris.Message) {
                            return null;
                        } else {
                            return bot.getGuildSettings(ctx.guild.id);
                        }
                    }).then(res => {
                        if (!res) {
                            return null;
                        } else {
                            console.log(res);
                            return ctx.createMessage(localeManager.t('greetings-setChan', ctx.settings.locale, {id: res.greeting.channelID}));
                        }
                    }).then(resolve).catch(reject);
                }
            } else if (ctx.args[0] === 'text' && ctx.args.length >= 2) {
                bot.getGuildSettings(ctx.guild.id).then(res => {
                    let settings = res;
                    let message = ctx.suffix.split(' ');
                    message.shift();
                    message = message.join(' ');

                    settings.greeting.message = message;

                    return bot.setGuildSettings(res.id, settings);
                }).then(() => {
                    return ctx.createMessage(localeManager.t('greetings-setMsg', ctx.settings.locale));
                }).then(resolve).catch(reject);
            } else {
                ctx.createMessage({embed: greetingBlock(ctx.settings)}).then(resolve).catch(reject);
            }
        });
    }
};

function greetingBlock(settings) {
    return {
        title: 'Greeting Management',
        description: `**${localeManager.t('greetings-enabled', settings.locale)}:** ${settings.guild.greeting.enabled ? localeManager.t('yes', settings.locale) : localeManager.t('no', settings.locale)}\n**${localeManager.t('greetings-channel')}:** ${settings.guild.greeting.channelID ? `<#${settings.guild.greeting.channelID}>` : localeManager.t('none', settings.locale)}\n**${localeManager.t('greetings-message')}:** ${settings.guild.greeting.message || localeManager.t('none', settings.locale)}`,
        fields: [{
            name: 'Example Usage',
            value: '`greetings enable`\n'
            + localeManager.t('greetings-example1', settings.locale)
            + '`greetings channel general`\n'
            + localeManager.t('greeting-example2', settings.locale)
            + '`greetings text Welcome to our server {{user}}`\n'
            + localeManager.t('greetings-example3', settings.locale)
        }]
    };
}<commit_msg>use JSDoc spec for this file<commit_after>/**
 * @file greetings.js
 * @description Manage greetings for servers
 * @author Ovyerus
 */

/* eslint-env node */

const Eris = require('eris');

exports.commands = [
    'greetings'
];

exports.greetings = {
    desc: 'Manage server greetings.',
    longDesc: 'Show current greeting settings for the server, and manage them if you have the correct permission.',
    main(bot, ctx) {
        return new Promise((resolve, reject) => {
            if (ctx.args.length === 0) {
                ctx.createMessage({embed: greetingBlock(ctx.settings)}).then(resolve).catch(reject);
            } else if (ctx.args[0] === 'enable') {
                if (!ctx.member.permission.has('manageGuild')) {
                    ctx.createMessage(localeManager.t('user-noPerm', ctx.settings.locale, {perm: 'Manage Server'})).then(resolve).catch(reject);
                } else {
                    bot.getGuildSettings(ctx.guild.id).then(res => {
                        let settings = res;
                        settings.greeting.enabled = true;
                        return bot.setGuildSettings(res.id, settings);
                    }).then(() => {
                        return ctx.createMessage(localeManager.t('greetings-enable', ctx.settings.locale));
                    }).then(resolve).catch(reject);
                }
            }  else if (ctx.args[0] === 'disable') {
                if (!ctx.member.permission.has('manageGuild')) {
                    ctx.createMessage(localeManager.t('user-noPerm', ctx.settings.locale, {perm: 'Manage Server'})).then(resolve).catch(reject);
                } else {
                    bot.getGuildSettings(ctx.guild.id).then(res => {
                        let settings = res;
                        settings.greeting.enabled = false;
                        return bot.setGuildSettings(res.id, settings);
                    }).then(() => {
                        return ctx.createMessage(localeManager.t('greetings-disable', ctx.settings.locale));
                    }).then(resolve).catch(reject);
                }
            } else if (ctx.args[0] === 'channel' && ctx.args.length >= 2) {
                if (!ctx.member.permission.has('manageGuild')) {
                    ctx.createMessage(localeManager.t('user-noPerm', ctx.settings.locale, {perm: 'Manage Server'})).then(resolve).catch(reject);
                } else {
                    bot.getGuildSettings(ctx.guild.id).then(res => {
                        let settings = res;

                        if (ctx.channelMentions.length > 0) {
                            settings.greeting.channelID = ctx.channelMentions[0];
                            return bot.setGuildSettings(res.id, settings);
                        } else {
                            let meme = ctx.suffix.split(' ');
                            meme.shift();
                            let chans = ctx.guild.channels.filter(c => c.name.toLowerCase().includes(meme.join(' ')));

                            if (chans.length === 0) {
                                return ctx.createMessage(localeManager.t('greetings-noChan', ctx.settings.locale, {name: meme.join(' ')}));
                            } else {
                                settings.greeting.channelID = chans[0].id;
                                return bot.setGuildSettings(res.id, settings);
                            }
                        }
                    }).then(res => {
                        if (res instanceof Eris.Message) {
                            return null;
                        } else {
                            return bot.getGuildSettings(ctx.guild.id);
                        }
                    }).then(res => {
                        if (!res) {
                            return null;
                        } else {
                            console.log(res);
                            return ctx.createMessage(localeManager.t('greetings-setChan', ctx.settings.locale, {id: res.greeting.channelID}));
                        }
                    }).then(resolve).catch(reject);
                }
            } else if (ctx.args[0] === 'text' && ctx.args.length >= 2) {
                bot.getGuildSettings(ctx.guild.id).then(res => {
                    let settings = res;
                    let message = ctx.suffix.split(' ');
                    message.shift();
                    message = message.join(' ');

                    settings.greeting.message = message;

                    return bot.setGuildSettings(res.id, settings);
                }).then(() => {
                    return ctx.createMessage(localeManager.t('greetings-setMsg', ctx.settings.locale));
                }).then(resolve).catch(reject);
            } else {
                ctx.createMessage({embed: greetingBlock(ctx.settings)}).then(resolve).catch(reject);
            }
        });
    }
};

function greetingBlock(settings) {
    return {
        title: 'Greeting Management',
        description: `**${localeManager.t('greetings-enabled', settings.locale)}:** ${settings.guild.greeting.enabled ? localeManager.t('yes', settings.locale) : localeManager.t('no', settings.locale)}\n**${localeManager.t('greetings-channel')}:** ${settings.guild.greeting.channelID ? `<#${settings.guild.greeting.channelID}>` : localeManager.t('none', settings.locale)}\n**${localeManager.t('greetings-message')}:** ${settings.guild.greeting.message || localeManager.t('none', settings.locale)}`,
        fields: [{
            name: 'Example Usage',
            value: '`greetings enable`\n'
            + localeManager.t('greetings-example1', settings.locale)
            + '`greetings channel general`\n'
            + localeManager.t('greeting-example2', settings.locale)
            + '`greetings text Welcome to our server {{user}}`\n'
            + localeManager.t('greetings-example3', settings.locale)
        }]
    };
}<|endoftext|>