<commit_before>/*
The MIT License (MIT)

Copyright (c) 2013-2014 CNRS

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/* The API controller for group's methods */

var async = require('async');

exports.exist = function(req, res, next) {
	Group.findById(req.params.id_group, function(error, group){
		if (error) res.status(400).json(error);
		else if (!group) res.status(400).json({"message":"id_group don't exists"});
		else next();
	});
}

//list all groups to which the connected user belong
exports.getAll = function (req, res) {
	Group.find({}, function (error, groups) {
		if (error) res.status(400).json(error);
		if (groups) res.status(200).json(groups);
		else return res.status(200).json([]);
	});
}

//retrieve a particular group (with id)
exports.getInfo = function(req, res){
	Group.findById(req.params.id_group, function(error, group){
		if (error) res.status(400).json(error);
		else  res.status(200).json(group);
	});
}

exports.create = function(req, res){
	var error=null;
	async.waterfall([
		function(callback) {
			if (req.body.name == undefined) error="the name is not define";
			if (req.body.name == "") 		error="empty string for name is not allow";
			callback(error);
		},
		function(callback) {
			Group.count({name: req.body.name}, function (error, count) {
				if ((!error) && (count != 0)) error = "the name is already used, choose another name";
		        callback(error);
		    });
		},
		function(callback) {
			var group = new Group({
				name: req.body.name,
				description: req.body.description,
				users_list: []
			}).save(function (error, newGroup) {
				if (newGroup) res.status(200).json(newGroup);
				callback(error);
			});
		}
	], function (error) {
		if (error) res.status(400).json({"message":error});
	});
};

//update information of a user
exports.update = function(req, res){
	var error=null;
	var update = {};
	async.waterfall([
		function(callback) {
			if (req.body.description == undefined) error="one or more data fields are not filled out properly";
			else update.description = req.body.description;
			callback(error, update);
		},
		function(update, callback) {
				Group.findByIdAndUpdate(req.params.id_group, update, function (error, group) {
				if (!error) res.status(200).json(group);
				callback(error);
			});
		}
	], function (error) {
		if (error) res.status(400).json({"message":error});
	});
}

// remove a given group ID
exports.remove = function (req, res) {
	var error;
	async.waterfall([
		function(callback) {
			Group.remove({_id : req.params.id_group}, function (error, group) {
				if (!error && group == 1) res.status(200).json({message:"The group as been delete"});
				callback(error);
			});
		}
		// delete group from corpus acl
		// delete group from layer acl
	], function (error) {
		if (error) res.status(400).json({"message":error});
	});
}

//add a user to a group
exports.addUser = function(req, res){
	Group.findById(req.params.id_group, function (error, group) {
		if (error) res.status(400).json({message:error});
		else if (group.users_list.indexOf(req.params.id_user) != -1) res.status(400).json({error:"This user is already in the group"})
		else {
			group.users_list.push(req.params.id_user);
			group.save(function(error3, dat){
				if (error3) res.status(400).json({error:"error", message:error3});
				else res.status(200).json(dat);
			});
		}
	});
};

/*

//retrieve a particular group (with id)
exports.listUserOfGroupId = function(req, res){
	if (req.params.id == undefined) return res.status(400).send({error:"the given ID is not correct"});//id of the group
	var connectedUser = req.session.user;
	Group.findById(req.params.id, function(error, data){
		if (error) res.status(400).json({error:"error", message:error});
		else if (data == null) res.json({error:"no such id!"})
		else {
			if (connectedUser.role == "admin")  res.json(data.usersList);
			else res.status(403).json({error:"You dont have enough right to access this resource"});
		}
	});
}

// add a group
exports.addGroup = function (req, res) {
	if (req.body.groupname == undefined) return res.status(400).json({error:"The groupname field has not been filled in"});
	Group.findOne({groupname : {$regex : new RegExp('^'+ req.body.groupname + '$', "i")}}, function(error, group) {
		if (error) res.status(400).json({error:"error", message:error});
		else if (group == null) {
			var groupItem = {
				groupname : req.body.groupname,
				description : req.body.description || "unknown",
				usersList : []
			};
			var g = new Group(groupItem);

			g.save(function(error2, data){
				if (error2) res.status(400).json({error:"error", message:error2});
				else res.send(200, data);
			});
		}
		else res.status(400).json({error:"This group already exists"});
	});
}

// update information of a group: put /group/:id
exports.update = function(req, res){
	if (req.params.id == undefined) return res.status(400).json({error:"one or more data fields are not filled out properly"});
	var update = {};
	if (req.body.groupname) update.groupname = req.body.groupname;
	if (req.body.description) update.description = req.body.description;
	Group.findByIdAndUpdate(req.params.id, update, function (error, data) {
		if (error) res.status(400).json({error:"error", message:error});
		else res.json(data);
	});
}
//remove a user from a group
exports.removeUserFromGroup  = function(req, res){
	if (req.params.id == undefined || req.params.username == undefined)
		return res.status(400).json({error:"one or more data fields are not filled out properly"});
	Group.findById(req.params.id, function (error, data) {
		if (error) res.status(400).json({error:"error", message:error});
		else {
			var index = data.usersList.indexOf(req.params.username);
			if (index > -1) {//not working on IE8 and below
				data.usersList.splice(index, 1);
				data.save(function(error2, dat){
					if (error) res.status(400).json({error:"error", message:error});
					else res.json(dat);
				});
			}
			else res.json(data);
		}
	});
}
*/
<commit_msg>add remove user from a group fit<commit_after>/*
The MIT License (MIT)

Copyright (c) 2013-2014 CNRS

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/* The API controller for group's methods */

var async = require('async');

exports.exist = function(req, res, next) {
	Group.findById(req.params.id_group, function(error, group){
		if (error) res.status(400).json(error);
		else if (!group) res.status(400).json({"message":"id_group don't exists"});
		else next();
	});
}

//list all groups to which the connected user belong
exports.getAll = function (req, res) {
	Group.find({}, function (error, groups) {
		if (error) res.status(400).json(error);
		if (groups) res.status(200).json(groups);
		else return res.status(200).json([]);
	});
}

//retrieve a particular group (with id)
exports.getInfo = function(req, res){
	Group.findById(req.params.id_group, function(error, group){
		if (error) res.status(400).json(error);
		else  res.status(200).json(group);
	});
}

//create a group
exports.create = function(req, res){
	var error=null;
	async.waterfall([
		function(callback) {
			if (req.body.name == undefined) error="the name is not define";
			if (req.body.name == "") 		error="empty string for name is not allow";
			callback(error);
		},
		function(callback) {
			Group.count({name: req.body.name}, function (error, count) {
				if ((!error) && (count != 0)) error = "the name is already used, choose another name";
		        callback(error);
		    });
		},
		function(callback) {
			var group = new Group({
				name: req.body.name,
				description: req.body.description,
				users_list: []
			}).save(function (error, newGroup) {
				if (newGroup) res.status(200).json(newGroup);
				callback(error);
			});
		}
	], function (error) {
		if (error) res.status(400).json({"message":error});
	});
};

//update information of a group
exports.update = function(req, res){
	var error=null;
	var update = {};
	async.waterfall([
		function(callback) {
			if (req.body.description == undefined) error="one or more data fields are not filled out properly";
			else update.description = req.body.description;
			callback(error, update);
		},
		function(update, callback) {
				Group.findByIdAndUpdate(req.params.id_group, update, function (error, group) {
				if (!error) res.status(200).json(group);
				callback(error);
			});
		}
	], function (error) {
		if (error) res.status(400).json({"message":error});
	});
}

// remove a given group ID
exports.remove = function (req, res) {
	var error;
	async.waterfall([
		function(callback) {
			Group.remove({_id : req.params.id_group}, function (error, group) {
				if (!error && group == 1) res.status(200).json({message:"The group as been delete"});
				callback(error);
			});
		}
		// delete group from corpus acl
		// delete group from layer acl
	], function (error) {
		if (error) res.status(400).json({"message":error});
	});
}

//add a user to a group
exports.addUser = function(req, res){
	Group.findById(req.params.id_group, function (error, group) {
		if (error) res.status(400).json(error);
		else if (group.users_list.indexOf(req.params.id_user) != -1) res.status(400).json({error:"This user is already in the group"})
		else {
			group.users_list.push(req.params.id_user);
			group.save(function(error3, dat){
				if (error3) res.status(400).json(error);
				else res.status(200).json(dat);
			});
		}
	});
};

//remove a user from a group
exports.removeUser  = function(req, res){
	Group.findById(req.params.id_group, function (error, group) {
		if (error) res.status(400).json(error);
		else {
			var index = group.users_list.indexOf(req.params.id_user);
			if (index > -1) {
				group.users_list.splice(index, 1);
				group.save(function(error2, dat){
					if (error) res.status(400).json(error);
					else res.json(dat);
				});
			}
			else res.status(400).json({message:"This user is not in the group"});
		}
	});
}

<|endoftext|>


<commit_before>import {PHPFunctionType, PHPSimpleType, PHPTypeUnion} from "./phptype"
import {Identifier, Class, ConstRef} from "./shadowtree"
import * as PHPError from "./php-error"
import {ClassContext, TraitContext} from "./class-context"
import {FileContext} from "./file-context"
import {GlobalContext} from "./global-context"

const fs = require("fs")
const path = require("path")

/** @type {boolean} If true, this will dump out type info */
const DEBUG_TYPES = false

/** @type {boolean} If true, invalid parent:: references will be ignored */
const IgnoreInvalidParent = true

/**
 * @type {string[]} From `print json_encode(array_keys(get_defined_constants()), JSON_PRETTY_PRINT);`
 */
const PHPConstants = JSON.parse(fs.readFileSync(__dirname + "/../../data/php-constants.json", "utf8"))

/**
 * @type {{[x: string]: boolean[]}}
 *
 * From:
 *
 * ```
 * print json_encode(array_combine(
 *     get_defined_functions()["internal"],
 *     array_map(function($n) {
 *         return array_map(
 *             function($p) {return $p->isPassedByReference();},
 *             (new ReflectionFunction($n))->getParameters()
 *         );
 *     }, get_defined_functions()["internal"])
 * ), JSON_PRETTY_PRINT);
 * ```
 */
const PHPFunctions = JSON.parse(fs.readFileSync(__dirname + "/../../data/php-functions.json", "utf8"))

/** @type {{[x: string]: string}} From `print json_encode(array_map("gettype", get_defined_vars()), JSON_PRETTY_PRINT);` */
const PHPSuperglobals = {
    "_ENV": "array",
    "_GET": "array",
    "_POST": "array",
    "_COOKIE": "array",
    "_FILES": "array",
    "argv": "array",
    "argc": "integer",
    "_SERVER": "array",
    "_SESSION": "array",
    "GLOBALS": "array",
}

/**
 * This defines the entire context applying to the current node.
 */
export default class Context {
    /**
     * @type {{[x: string]: PHPTypeUnion}} A map of names to types for the
     * "always global" core PHP variables and functions.
     */
    static get superGlobals() {
        if(!this._superGlobals) {
            this._superGlobals = {}
            Object.keys(PHPSuperglobals).forEach(
                name => this._superGlobals["$" + name] = PHPSimpleType.named(PHPSuperglobals[name])
            )
            Object.keys(PHPFunctions).forEach(
                name => this._superGlobals[name] = new PHPTypeUnion(new PHPFunctionType(
                    PHPFunctions[name].map(arg => PHPSimpleType.coreTypes.mixed),
                    name == "array_keys" ? PHPSimpleType.named("string[]") : PHPSimpleType.coreTypes.mixed,
                    PHPFunctions[name]
                ))
            )
            PHPConstants.forEach(
                name => this._superGlobals[name] = PHPSimpleType.coreTypes.mixed
            )
            Object.freeze(this._superGlobals)
        }
        return this._superGlobals
    }

    /**
     * Builds the object
     * @param {FileContext} file_context
     * @param {?GlobalContext} global_context
     * @param {?ClassContext} [class_context]
     * @param {?{[x: string]: PHPTypeUnion}} [ns]
     * @param {number} [depth]
     */
    constructor(file_context, global_context, class_context = null, ns = null, depth = 0) {
        this.classContext = class_context
        this.depth = depth
        this.globalContext = global_context || new GlobalContext()
        this.fileContext = file_context
        /** @type {?PHPTypeUnion} */
        this.assigningType = null
        this.ns = ns || {}
    }

    /**
     * @type {string[]} All the variable names in the namespace
     */
    get definedVariables() {
        return Object.keys(this.ns).filter(
            name => name.match(/^[$]/)
        ).concat(
            Object.keys(Context.superGlobals).filter(
                name => name.match(/^[$]/)
            )
        )
    }

    /**
     * @type {string}
     */
    get directory() {
        return this.globalContext.workingDirectory
    }

    set directory(v) {
        this.globalContext.workingDirectory = v
    }

    /**
     * @type {?FileContext}
     */
    get fileContext() {
        return this._fileContext
    }

    set fileContext(v) {
        this._fileContext = v
        if(v && !this.directory) {
            let file_directory = v.directory
            let composer_path = this.globalContext.findComposerConfig(file_directory)
            if(composer_path) {
                this.directory = path.dirname(composer_path)
            } else {
                this.directory = file_directory
            }
        }
    }

    /**
     * Adds a name to the namespace list.
     * @param {string} name eg. "$foo"
     * @param {PHPTypeUnion} types
     * @returns {PHPTypeUnion} The original types
     */
    addName(name, types) {
        if(!this.ns[name]) {
            this.ns[name] = Context.superGlobals[name] || PHPTypeUnion.empty
        }
        this.ns[name] = this.ns[name].addTypesFrom(types)
        if(DEBUG_TYPES) {
            console.log(`Types for ${name} are: ${this.ns[name]}`)
        }
        return types
    }

    /**
     * Updates which directory the context will work from. Generally only makes
     * sense at the very start of a file.
     *
     * @param {string} directory
     */
    chdir(directory) {
        this.directory = path.resolve(this.directory, directory)
    }

    /**
     * Checks a PHP script
     * @param {string} filename
     * @param {boolean} [with_warnings]
     */
    checkFile(filename, with_warnings = true) {
        let full_filename = path.resolve(this.directory, filename)
        try {
            this.globalContext.checkFile(full_filename, this.depth + 1)
        } catch(e) {
            if(e.errno == -2) {
                if(with_warnings) {
                    console.log(`${full_filename} missing, not installed?`)
                }
            } else {
                throw e
            }
        }
    }

    /**
     * Returns a new context which inherits from this one.
     * @param {boolean} keep_ns If this is true, the same namespace will be linked.
     * @returns {Context}
     */
    childContext(keep_ns = false) {
        return new Context(
            this.fileContext,
            this.globalContext,
            this.classContext,
            keep_ns ? this.ns : null,
            this.depth
        )
    }

    /**
     * Finds the class context with the given name
     * @param {string} name Fully qualified only
     * @returns {?ClassContext}
     */
    findClass(name) {
        if(name == "self") {
            return this.classContext
        } else if(name != "mixed" && name != "object" && PHPSimpleType.coreTypes[name]) {
            console.log(`Attempt to access core type ${name} as class`)
            return null
        } else {
            return this.globalContext.findClass(name, this.fileContext, this.depth)
        }
    }

    /**
     * If the name is in the namespace, returns its possible types. This only
     * finds variables and functions.
     *
     * @param {string} name eg "$bar"
     * @returns {PHPTypeUnion}
     */
    findName(name) {
        var types = this.ns[name] || Context.superGlobals[name]
        return types
    }

    /**
     * Copies the namespace from one context to another. The existing namespace
     * will still be retained.
     * @param {Context} context
     */
    importNamespaceFrom(context) {
        Object.keys(context.ns).forEach(
            name => {
                if(this.ns[name]) {
                    this.ns[name] = this.ns[name].addTypesFrom(context.ns[name])
                } else {
                    this.ns[name] = context.ns[name]
                }
            }
        )
    }

    /**
     * Resolves a given name, eg, for "Foo::$bar" this would resolve "Foo". This
     * does not handle multi-node lookups.
     *
     * Variable names are not handled here as they do not require resolution.
     *
     * @param {string} name
     * @param {string} [resolution] eg. "uqn"
     * @returns {string}
     */
    resolveName(name, resolution = "uqn") {
        let md
        switch(resolution) {
            case "fqn":
                if(
                    (md = name.match(/^\u005c(.+)/)) &&
                    PHPSimpleType.coreTypes[md[1]]
                ) {
                    return md[1]
                } else {
                    return name
                }
            case "uqn":
                if(name == "self" && this.classContext && !(this.classContext instanceof TraitContext)) {
                    return this.classContext.name
                } else if(PHPSimpleType.coreTypes[name]) {
                    return name
                } else if(this.classContext) {
                    let class_name
                    try {
                        class_name = this.classContext.resolveName(name)
                    } catch(e) {
                        if(e instanceof PHPError.Error && IgnoreInvalidParent) {
                            class_name = this.globalContext.addUnknownClass().name
                        } else {
                            throw e
                        }
                    }
                    if(class_name) {
                        return class_name
                    }
                }
                return this.fileContext.resolveName(name)
            case "qn":
                md = name.match(/^(.*)\\(.*)/)
                return `${this.resolveName(md[1])}\\${md[2]}`
            default:
                console.log(name)
                throw new Error(`TODO don't know how to resolve ${resolution}`)
        }
    }

    /**
     * Given that the node has a name, returns its fully resolved form.
     *
     * @param {Identifier|Class|ConstRef} node
     * @returns {string}
     */
    resolveNodeName(node) {
        if(node.name instanceof Identifier) {
            return this.resolveNodeName(node.name)
        } else if(node instanceof Identifier) {
            return this.resolveName(node.name, node.resolution)
        } else if(typeof node.name == "string") {
            return this.resolveName(node.name)
        } else {
            throw new Error(`Unable to resolve node name for ${node}`)
        }
    }

    /**
     * Sets the type(s) for a name. This overwrites any types already assigned
     * to the name.
     * @param {string} name
     * @param {PHPTypeUnion} types
     * @returns {PHPTypeUnion}
     */
    setName(name, types) {
        this.ns[name] = types
        return types
    }

    /**
     * Sets $this in the scope.
     * @returns {PHPTypeUnion}
     */
    setThis() {
        this.ns["$this"] = PHPSimpleType.coreTypes.self
        return PHPSimpleType.coreTypes.self
    }
}<commit_msg>Decode "self" for "$this" ASAP<commit_after>import {PHPFunctionType, PHPSimpleType, PHPTypeUnion} from "./phptype"
import {Identifier, Class, ConstRef} from "./shadowtree"
import * as PHPError from "./php-error"
import {ClassContext, TraitContext} from "./class-context"
import {FileContext} from "./file-context"
import {GlobalContext} from "./global-context"

const fs = require("fs")
const path = require("path")

/** @type {boolean} If true, this will dump out type info */
const DEBUG_TYPES = false

/** @type {boolean} If true, invalid parent:: references will be ignored */
const IgnoreInvalidParent = true

/**
 * @type {string[]} From `print json_encode(array_keys(get_defined_constants()), JSON_PRETTY_PRINT);`
 */
const PHPConstants = JSON.parse(fs.readFileSync(__dirname + "/../../data/php-constants.json", "utf8"))

/**
 * @type {{[x: string]: boolean[]}}
 *
 * From:
 *
 * ```
 * print json_encode(array_combine(
 *     get_defined_functions()["internal"],
 *     array_map(function($n) {
 *         return array_map(
 *             function($p) {return $p->isPassedByReference();},
 *             (new ReflectionFunction($n))->getParameters()
 *         );
 *     }, get_defined_functions()["internal"])
 * ), JSON_PRETTY_PRINT);
 * ```
 */
const PHPFunctions = JSON.parse(fs.readFileSync(__dirname + "/../../data/php-functions.json", "utf8"))

/** @type {{[x: string]: string}} From `print json_encode(array_map("gettype", get_defined_vars()), JSON_PRETTY_PRINT);` */
const PHPSuperglobals = {
    "_ENV": "array",
    "_GET": "array",
    "_POST": "array",
    "_COOKIE": "array",
    "_FILES": "array",
    "argv": "array",
    "argc": "integer",
    "_SERVER": "array",
    "_SESSION": "array",
    "GLOBALS": "array",
}

/**
 * This defines the entire context applying to the current node.
 */
export default class Context {
    /**
     * @type {{[x: string]: PHPTypeUnion}} A map of names to types for the
     * "always global" core PHP variables and functions.
     */
    static get superGlobals() {
        if(!this._superGlobals) {
            this._superGlobals = {}
            Object.keys(PHPSuperglobals).forEach(
                name => this._superGlobals["$" + name] = PHPSimpleType.named(PHPSuperglobals[name])
            )
            Object.keys(PHPFunctions).forEach(
                name => this._superGlobals[name] = new PHPTypeUnion(new PHPFunctionType(
                    PHPFunctions[name].map(arg => PHPSimpleType.coreTypes.mixed),
                    name == "array_keys" ? PHPSimpleType.named("string[]") : PHPSimpleType.coreTypes.mixed,
                    PHPFunctions[name]
                ))
            )
            PHPConstants.forEach(
                name => this._superGlobals[name] = PHPSimpleType.coreTypes.mixed
            )
            Object.freeze(this._superGlobals)
        }
        return this._superGlobals
    }

    /**
     * Builds the object
     * @param {FileContext} file_context
     * @param {?GlobalContext} global_context
     * @param {?ClassContext} [class_context]
     * @param {?{[x: string]: PHPTypeUnion}} [ns]
     * @param {number} [depth]
     */
    constructor(file_context, global_context, class_context = null, ns = null, depth = 0) {
        this.classContext = class_context
        this.depth = depth
        this.globalContext = global_context || new GlobalContext()
        this.fileContext = file_context
        /** @type {?PHPTypeUnion} */
        this.assigningType = null
        this.ns = ns || {}
    }

    /**
     * @type {string[]} All the variable names in the namespace
     */
    get definedVariables() {
        return Object.keys(this.ns).filter(
            name => name.match(/^[$]/)
        ).concat(
            Object.keys(Context.superGlobals).filter(
                name => name.match(/^[$]/)
            )
        )
    }

    /**
     * @type {string}
     */
    get directory() {
        return this.globalContext.workingDirectory
    }

    set directory(v) {
        this.globalContext.workingDirectory = v
    }

    /**
     * @type {?FileContext}
     */
    get fileContext() {
        return this._fileContext
    }

    set fileContext(v) {
        this._fileContext = v
        if(v && !this.directory) {
            let file_directory = v.directory
            let composer_path = this.globalContext.findComposerConfig(file_directory)
            if(composer_path) {
                this.directory = path.dirname(composer_path)
            } else {
                this.directory = file_directory
            }
        }
    }

    /**
     * Adds a name to the namespace list.
     * @param {string} name eg. "$foo"
     * @param {PHPTypeUnion} types
     * @returns {PHPTypeUnion} The original types
     */
    addName(name, types) {
        if(!this.ns[name]) {
            this.ns[name] = Context.superGlobals[name] || PHPTypeUnion.empty
        }
        this.ns[name] = this.ns[name].addTypesFrom(types)
        if(DEBUG_TYPES) {
            console.log(`Types for ${name} are: ${this.ns[name]}`)
        }
        return types
    }

    /**
     * Updates which directory the context will work from. Generally only makes
     * sense at the very start of a file.
     *
     * @param {string} directory
     */
    chdir(directory) {
        this.directory = path.resolve(this.directory, directory)
    }

    /**
     * Checks a PHP script
     * @param {string} filename
     * @param {boolean} [with_warnings]
     */
    checkFile(filename, with_warnings = true) {
        let full_filename = path.resolve(this.directory, filename)
        try {
            this.globalContext.checkFile(full_filename, this.depth + 1)
        } catch(e) {
            if(e.errno == -2) {
                if(with_warnings) {
                    console.log(`${full_filename} missing, not installed?`)
                }
            } else {
                throw e
            }
        }
    }

    /**
     * Returns a new context which inherits from this one.
     * @param {boolean} keep_ns If this is true, the same namespace will be linked.
     * @returns {Context}
     */
    childContext(keep_ns = false) {
        return new Context(
            this.fileContext,
            this.globalContext,
            this.classContext,
            keep_ns ? this.ns : null,
            this.depth
        )
    }

    /**
     * Finds the class context with the given name
     * @param {string} name Fully qualified only
     * @returns {?ClassContext}
     */
    findClass(name) {
        if(name == "self") {
            return this.classContext
        } else if(name != "mixed" && name != "object" && PHPSimpleType.coreTypes[name]) {
            console.log(`Attempt to access core type ${name} as class`)
            return null
        } else {
            return this.globalContext.findClass(name, this.fileContext, this.depth)
        }
    }

    /**
     * If the name is in the namespace, returns its possible types. This only
     * finds variables and functions.
     *
     * @param {string} name eg "$bar"
     * @returns {PHPTypeUnion}
     */
    findName(name) {
        var types = this.ns[name] || Context.superGlobals[name]
        return types
    }

    /**
     * Copies the namespace from one context to another. The existing namespace
     * will still be retained.
     * @param {Context} context
     */
    importNamespaceFrom(context) {
        Object.keys(context.ns).forEach(
            name => {
                if(this.ns[name]) {
                    this.ns[name] = this.ns[name].addTypesFrom(context.ns[name])
                } else {
                    this.ns[name] = context.ns[name]
                }
            }
        )
    }

    /**
     * Resolves a given name, eg, for "Foo::$bar" this would resolve "Foo". This
     * does not handle multi-node lookups.
     *
     * Variable names are not handled here as they do not require resolution.
     *
     * @param {string} name
     * @param {string} [resolution] eg. "uqn"
     * @returns {string}
     */
    resolveName(name, resolution = "uqn") {
        let md
        switch(resolution) {
            case "fqn":
                if(
                    (md = name.match(/^\u005c(.+)/)) &&
                    PHPSimpleType.coreTypes[md[1]]
                ) {
                    return md[1]
                } else {
                    return name
                }
            case "uqn":
                if(name == "self" && this.classContext && !(this.classContext instanceof TraitContext)) {
                    return this.classContext.name
                } else if(PHPSimpleType.coreTypes[name]) {
                    return name
                } else if(this.classContext) {
                    let class_name
                    try {
                        class_name = this.classContext.resolveName(name)
                    } catch(e) {
                        if(e instanceof PHPError.Error && IgnoreInvalidParent) {
                            class_name = this.globalContext.addUnknownClass().name
                        } else {
                            throw e
                        }
                    }
                    if(class_name) {
                        return class_name
                    }
                }
                return this.fileContext.resolveName(name)
            case "qn":
                md = name.match(/^(.*)\\(.*)/)
                return `${this.resolveName(md[1])}\\${md[2]}`
            default:
                console.log(name)
                throw new Error(`TODO don't know how to resolve ${resolution}`)
        }
    }

    /**
     * Given that the node has a name, returns its fully resolved form.
     *
     * @param {Identifier|Class|ConstRef} node
     * @returns {string}
     */
    resolveNodeName(node) {
        if(node.name instanceof Identifier) {
            return this.resolveNodeName(node.name)
        } else if(node instanceof Identifier) {
            return this.resolveName(node.name, node.resolution)
        } else if(typeof node.name == "string") {
            return this.resolveName(node.name)
        } else {
            throw new Error(`Unable to resolve node name for ${node}`)
        }
    }

    /**
     * Sets the type(s) for a name. This overwrites any types already assigned
     * to the name.
     * @param {string} name
     * @param {PHPTypeUnion} types
     * @returns {PHPTypeUnion}
     */
    setName(name, types) {
        this.ns[name] = types
        return types
    }

    /**
     * Sets $this in the scope.
     * @returns {PHPTypeUnion}
     */
    setThis() {
        if(this.classContext && !(this.classContext instanceof TraitContext)) {
            this.ns["$this"] = PHPSimpleType.named(this.classContext.name)
        } else {
            this.ns["$this"] = PHPSimpleType.coreTypes.self
        }
        return this.ns["$this"]
    }
}<|endoftext|>


<commit_before>var data = {
	portfolio: [
		{
			imgPath: "project-1",
			link: "http://denistrator.esy.es/mountains",
			titleEN: "Mountains",
			titleRU: "Mountains",
			githubLink: "https://github.com/denistrator/training-01-mountains",
			mod: ""
		},
		{
			imgPath: "project-6",
			link: "http://gorcons.apanshin-dev.ru/",
			titleRU: "Горконс",
			titleEN: "Gorcons",
			githubLink: "",
			mod: "",
			commercial: true,
			alternateImg: true
		},
		{
			imgPath: "project-2",
			link: "http://denistrator.esy.es/modest",
			titleEN: "Modest",
			titleRU: "Modest",
			githubLink: "https://github.com/denistrator/spalah-lessons--lesson-8",
			mod: ""
		},
		{
			imgPath: "project-3",
			link: "http://denistrator.esy.es/tajam",
			titleEN: "Tajam",
			titleRU: "Tajam",
			githubLink: "https://github.com/denistrator/spalah-lessons--lesson-7",
			mod: "portfolio-collapse-pos",
			alternateImg: true
		},
		{
			imgPath: "project-4",
			link: "http://denistrator.esy.es/yellow_moon",
			titleEN: "Yellow Moon",
			titleRU: "Yellow Moon",
			githubLink: "https://github.com/denistrator/spalah-lessons--lesson-6",
			mod: ""
		},
		{
			imgPath: "project-no-image",
			link: "http://denistrator.esy.es/cosmetologylife",
			titleRU: "Косметология Жизни",
			titleEN: "Cosmetology Life",
			githubLink: "",
			mod: "",
			commercial: true,
			alternateImg: true
		},
		{
			imgPath: "project-5",
			link: "http://denistrator.esy.es/Freebie_Page_Atech/",
			titleEN: "Atech",
			titleRU: "Atech",
			githubLink: "",
			mod: "old",
			alternateImg: true
		},
		{
			imgPath: "project-no-image",
			link: "http://denistrator.esy.es/naturetour/",
			titleEN: "Naturetour",
			titleRU: "Naturetour",
			githubLink: "",
			mod: "old",
			alternateImg: true
		},
		{
			imgPath: "project-no-image",
			link: "http://denistrator.esy.es/extended/",
			titleEN: "Extended",
			titleRU: "Extended",
			githubLink: "",
			mod: "old",
			alternateImg: true
		}
	]
};<commit_msg>add new work<commit_after>var data = {
	portfolio: [
		{
			imgPath: "project-1",
			link: "http://denistrator.esy.es/mountains",
			titleEN: "Mountains",
			titleRU: "Mountains",
			githubLink: "https://github.com/denistrator/training-01-mountains",
			mod: ""
		},
		{
			imgPath: "project-6",
			link: "http://gorcons.apanshin-dev.ru/",
			titleRU: "Горконс",
			titleEN: "Gorcons",
			githubLink: "",
			mod: "",
			commercial: true,
			alternateImg: true
		},
		{
			imgPath: "project-2",
			link: "http://denistrator.esy.es/modest",
			titleEN: "Modest",
			titleRU: "Modest",
			githubLink: "https://github.com/denistrator/spalah-lessons--lesson-8",
			mod: ""
		},
		{
			imgPath: "project-no-image",
			link: "http://denistrator.esy.es/counter/",
			titleEN: "Counter",
			titleRU: "Счётчик",
			githubLink: "https://github.com/denistrator/counter",
			mod: ""
		},
		{
			imgPath: "project-3",
			link: "http://denistrator.esy.es/tajam",
			titleEN: "Tajam",
			titleRU: "Tajam",
			githubLink: "https://github.com/denistrator/spalah-lessons--lesson-7",
			mod: "portfolio-collapse-pos",
			alternateImg: true
		},
		{
			imgPath: "project-4",
			link: "http://denistrator.esy.es/yellow_moon",
			titleEN: "Yellow Moon",
			titleRU: "Yellow Moon",
			githubLink: "https://github.com/denistrator/spalah-lessons--lesson-6",
			mod: ""
		},
		{
			imgPath: "project-no-image",
			link: "http://denistrator.esy.es/cosmetologylife",
			titleRU: "Косметология Жизни",
			titleEN: "Cosmetology Life",
			githubLink: "",
			mod: "old",
			commercial: true,
			alternateImg: true
		},
		{
			imgPath: "project-5",
			link: "http://denistrator.esy.es/Freebie_Page_Atech/",
			titleEN: "Atech",
			titleRU: "Atech",
			githubLink: "",
			mod: "old",
			alternateImg: true
		},
		{
			imgPath: "project-no-image",
			link: "http://denistrator.esy.es/naturetour/",
			titleEN: "Naturetour",
			titleRU: "Naturetour",
			githubLink: "",
			mod: "old",
			alternateImg: true
		},
		{
			imgPath: "project-no-image",
			link: "http://denistrator.esy.es/extended/",
			titleEN: "Extended",
			titleRU: "Extended",
			githubLink: "",
			mod: "old",
			alternateImg: true
		}
	]
};<|endoftext|>


<commit_before>"use strict";

var fs = require("fs");
var path = require("path");
var request = require("request-promise-native");
var yauzl = require("yauzl");
var mkdirp = require("mkdirp");
const util = require("util");
const rimraf = require("rimraf");

/**
 * need source repo url
 * call https://developer.github.com/v3/repos/releases/#get-the-latest-release
 * check published_at
 * if it's after stored value, download it!
 */

module.exports = function Package(_attrs) {
  var self = this;

  this.repo = _attrs.repo;
  this.dest = _attrs.dest;
  this.updated_at = _attrs.updated_at;
  this.downloaded = false;
  this.url = "https://api.github.com/repos/" + self.repo + "/releases/latest";

  if ( typeof(this.updated_at) === "undefined" ) {
    this.updated_at = new Date(0);
  }

  if ( typeof(_attrs.log) === "undefined" ) {
    _attrs.log = console.log;
  }

  this.log = _attrs.log;

  this.defaultHeaders = {
    "User-Agent": "Before Dawn"
  };

  this.attrs = function() {
    return {
      dest: this.dest,
      updated_at: this.updated_at,
      downloaded: this.downloaded
    };
  };

  this.getReleaseInfo = async function() {
    let self = this;
    this.data = await request.get({
      url: this.url,
      json: true,
      headers: this.defaultHeaders
    }).catch(function(err) {

      self.log(err);

      if ( typeof(self.data) !== "undefined" ) {
        return self.data;
      }
      else {
        return {};
      }
    });

    return this.data;
  };

  this.setReleaseInfo = function(d) {
    this.data = d;
  };

  this.checkLatestRelease = async function(cb) {
    let data = await this.getReleaseInfo();
    if ( data && data.published_at && new Date(data.published_at) > new Date(self.updated_at) ) {
      this.downloadFile(data.zipball_url, function() {
        self.updated_at = data.published_at;
        cb(self.attrs());
      });
    }
    else {
      cb(self.attrs());
    }
  };

  this.checkLocalRelease = async function(dataSrc, zipSrc, cb) {
    let rf = util.promisify(fs.readFile);
    let data = await rf(dataSrc);
    data = JSON.parse(data);

    if ( new Date(data.published_at) > (self.updated_at) ) {
      self.updated_at = data.published_at;
      this.zipToSavers(zipSrc, cb);
    }
    else {
      //console.log("we're good!");
      cb(self.attrs());
    }
  };

  this.downloadFile = function(url, cb) {
    var temp = require("temp");
    var os = require("os");
    var tempName = temp.path({dir: os.tmpdir(), suffix: ".zip"});

    var _resp;
    var opts = {
      url:url,
      headers:this.defaultHeaders
    };

    request(opts).on("error", function(err) {
      console.log(err);
      cb(err);
    }).on("response", function(r) {
      _resp = r;
    }).on("end", function() {
      self.downloaded = true;
      self.zipToSavers(tempName, cb);

    }).pipe(fs.createWriteStream(tempName));
  };

  this.zipToSavers = function(tempName, cb) {
    //
    // clean out existing files
    //
    try {
      //console.log("remove stuff from " + self.dest);
      rimraf.sync(self.dest);
    }
    catch (err) {
      console.error(err);
    }

    yauzl.open(tempName, {lazyEntries: true}, function(err, zipfile) {
      if (err) {
        throw err;
      }

      zipfile.readEntry();
      zipfile.on("entry", function(entry) {
        var fullPath = entry.fileName;

        // the incoming zip filename will have on extra directory on it
        // projectName/dir/etc/file
        //
        // example: muffinista-before-dawn-screensavers-d388377/starfield/index.html
        //
        // let's get rid of the projectName
        //
        var parts = fullPath.split(/\//);
        parts.shift();

        fullPath = path.join(self.dest, path.join(...parts));
        //console.log(self.dest + " -> " + fullPath);

        if (/\/$/.test(entry.fileName)) {
          // directory file names end with '/'
          mkdirp(fullPath, function(err) {
            //if (err) {throw err;}
            zipfile.readEntry();
          });
        }
        else {
          // file entry
          zipfile.openReadStream(entry, function(err, readStream) {
            if (err) {throw err;}
            // ensure parent directory exists
            mkdirp(path.dirname(fullPath), function(err) {
              //if (err) {throw err;}
              readStream.pipe(fs.createWriteStream(fullPath));
              readStream.on("end", function() {
                zipfile.readEntry();
              });
            });
          });
        }
      });

      zipfile.on("end", function() {
        cb(self.attrs());
      });

    });
  }
};
<commit_msg>Cleanup logging output<commit_after>"use strict";

var fs = require("fs");
var path = require("path");
var request = require("request-promise-native");
var yauzl = require("yauzl");
var mkdirp = require("mkdirp");
const util = require("util");
const rimraf = require("rimraf");

/**
 * need source repo url
 * call https://developer.github.com/v3/repos/releases/#get-the-latest-release
 * check published_at
 * if it's after stored value, download it!
 */

module.exports = function Package(_attrs) {
  var self = this;

  this.repo = _attrs.repo;
  this.dest = _attrs.dest;
  this.updated_at = _attrs.updated_at;
  this.downloaded = false;
  this.url = "https://api.github.com/repos/" + self.repo + "/releases/latest";

  if ( typeof(this.updated_at) === "undefined" ) {
    this.updated_at = new Date(0);
  }

  if ( typeof(_attrs.log) === "undefined" ) {
    _attrs.log = console.log;
  }

  this.logger = _attrs.log;

  this.defaultHeaders = {
    "User-Agent": "Before Dawn"
  };

  this.attrs = function() {
    return {
      dest: this.dest,
      updated_at: this.updated_at,
      downloaded: this.downloaded
    };
  };

  this.getReleaseInfo = async function() {
    let self = this;
    this.data = await request.get({
      url: this.url,
      json: true,
      headers: this.defaultHeaders
    }).catch(function(err) {

      self.logger(err);

      if ( typeof(self.data) !== "undefined" ) {
        return self.data;
      }
      else {
        return {};
      }
    });

    return this.data;
  };

  this.setReleaseInfo = function(d) {
    this.data = d;
  };

  this.checkLatestRelease = async function(cb) {
    let data = await this.getReleaseInfo();
    if ( data && data.published_at && new Date(data.published_at) > new Date(self.updated_at) ) {
      this.downloadFile(data.zipball_url, function() {
        self.updated_at = data.published_at;
        cb(self.attrs());
      });
    }
    else {
      cb(self.attrs());
    }
  };

  this.checkLocalRelease = async function(dataSrc, zipSrc, cb) {
    let rf = util.promisify(fs.readFile);
    let data = await rf(dataSrc);
    data = JSON.parse(data);

    if ( new Date(data.published_at) > (self.updated_at) ) {
      self.updated_at = data.published_at;
      this.zipToSavers(zipSrc, cb);
    }
    else {
      self.logger("Local release is up to date");
      cb(self.attrs());
    }
  };

  this.downloadFile = function(url, cb) {
    var temp = require("temp");
    var os = require("os");
    var tempName = temp.path({dir: os.tmpdir(), suffix: ".zip"});

    var _resp;
    var opts = {
      url:url,
      headers:this.defaultHeaders
    };

    request(opts).on("error", function(err) {
      this.logger(err);
      cb(err);
    }).on("response", function(r) {
      _resp = r;
    }).on("end", function() {
      self.downloaded = true;
      self.zipToSavers(tempName, cb);

    }).pipe(fs.createWriteStream(tempName));
  };

  this.zipToSavers = function(tempName, cb) {
    //
    // clean out existing files
    //
    try {
      this.logger("remove stuff from " + self.dest);
      rimraf.sync(self.dest);
    }
    catch (err) {
      this.logger(err);
    }

    yauzl.open(tempName, {lazyEntries: true}, function(err, zipfile) {
      if (err) {
        throw err;
      }

      zipfile.readEntry();
      zipfile.on("entry", function(entry) {
        var fullPath = entry.fileName;

        // the incoming zip filename will have on extra directory on it
        // projectName/dir/etc/file
        //
        // example: muffinista-before-dawn-screensavers-d388377/starfield/index.html
        //
        // let's get rid of the projectName
        //
        var parts = fullPath.split(/\//);
        parts.shift();

        fullPath = path.join(self.dest, path.join(...parts));
        //console.log(self.dest + " -> " + fullPath);

        if (/\/$/.test(entry.fileName)) {
          // directory file names end with '/'
          mkdirp(fullPath, function(err) {
            //if (err) {throw err;}
            zipfile.readEntry();
          });
        }
        else {
          // file entry
          zipfile.openReadStream(entry, function(err, readStream) {
            if (err) {throw err;}
            // ensure parent directory exists
            mkdirp(path.dirname(fullPath), function(err) {
              //if (err) {throw err;}
              readStream.pipe(fs.createWriteStream(fullPath));
              readStream.on("end", function() {
                zipfile.readEntry();
              });
            });
          });
        }
      });

      zipfile.on("end", function() {
        cb(self.attrs());
      });

    });
  }
};
<|endoftext|>


<commit_before>'use strict';

exports.check = check;

var stringfy = require('string');

function check(message, trigger) {
   return new Trigger('$').with(normalize(trigger)).accept(normalize(message));
}

class Trigger {
   constructor(placeholder) {
      this.placeholder = placeholder;
   }

   with(trigger) {
      this.trigger = trigger;
      this.params = new TriggerParams(this.trigger, this.placeholder);
      return this;
   }

   accept(message) {
      if (this.params.has()) {
         return this.acceptWithParams(message);
      }

      return this.acceptWithoutParams(message);
   }

   acceptWithParams(message) {
      var count = this.params.count();
      var params = this.params.capture(message);
      return { ok: params.length === count, params: params }
   }

   acceptWithoutParams(message) {
      return { ok: this.trigger === message, params: [] };
   }
}

class TriggerParams {
   constructor(trigger, placeholder) {
      this.trigger = trigger;
      this.placeholder = placeholder;
   }

   has() {
      return this.trigger.includes(this.placeholder) && !this.trigger.startsWith(this.placeholder);
   }

   count() {
      return this.trigger.match(new RegExp('\\' + this.placeholder, 'g')).length;
   }

   capture(message) {
      // get $ to $  >  ['get ', ' to ']
      var triggerParts = this.trigger.split(this.placeholder).filter(s => s);

      if (triggerParts.length == 1) {
         return [message.replace(triggerParts[0], '')];
      }

      // get alpha to beta  >  'alpha$beta'
      triggerParts.reduce((previous, next) => {
         message = message.replace(previous, this.placeholder);
         message = message.replace(next, this.placeholder);
      });

      // 'alpha$beta'  >  ['alpha', 'beta']
      return message.split(this.placeholder).filter(s => s);
   }
}

function normalize(text) {
   return stringfy(text).trim().latinise().s.toLowerCase();
}<commit_msg>Validation for all trigger parts<commit_after>'use strict';

exports.check = check;

var stringfy = require('string');

function check(message, trigger) {
   return new Trigger('$').with(normalize(trigger)).accept(normalize(message));
}

class Trigger {
   constructor(placeholder) {
      this.placeholder = placeholder;
   }

   with(trigger) {
      this.trigger = trigger;
      this.params = new TriggerParams(this.trigger, this.placeholder);
      return this;
   }

   accept(message) {
      if (this.params.has()) {
         return this.acceptWithParams(message);
      }

      return this.acceptWithoutParams(message);
   }

   acceptWithParams(message) {
      var count = this.params.count();
      var params = this.params.capture(message);
      return { ok: params.length === count, params: params }
   }

   acceptWithoutParams(message) {
      return { ok: this.trigger === message, params: [] };
   }
}

class TriggerParams {
   constructor(trigger, placeholder) {
      this.trigger = trigger;
      this.placeholder = placeholder;
   }

   has() {
      return this.trigger.includes(this.placeholder) && !this.trigger.startsWith(this.placeholder);
   }

   count() {
      return this.trigger.match(new RegExp('\\' + this.placeholder, 'g')).length;
   }

   capture(message) {
      // get $ to $  >  ['get ', ' to ']
      var triggerParts = this.trigger.split(this.placeholder).filter(s => s);

      // message must includes all trigger parts
      if (triggerParts.find(t => !message.includes(t))) {
         return [];
      }

      // reduce works only for array with more than one item
      if (triggerParts.length == 1) {
         return [message.replace(triggerParts[0], '')];
      }

      // get alpha to beta  >  'alpha$beta'
      triggerParts.reduce((previous, next) => {
         message = message.replace(previous, this.placeholder);
         message = message.replace(next, this.placeholder);
      });

      // 'alpha$beta'  >  ['alpha', 'beta']
      return message.split(this.placeholder).filter(s => s);
   }
}

function normalize(text) {
   return stringfy(text).trim().latinise().s.toLowerCase();
}<|endoftext|>


<commit_before>import React from 'react';
import { connect } from 'react-redux';
import { EDITOR_FACEBOOK_GROUP } from '../constants/urls';
import Link from 'next/link';
import { showDialog, logout } from '../redux/auth';

function AppHeader({ user, onLoginClick, onLogoutClick }) {
  return (

      <Link href="/">
真的假的
</Link>

        <Link href="/">文章</Link>
        <Link href="/replies">回應</Link>

        編輯求助區

      {user
        ?

            <Link href="/replies?mine=1">

                {user.get('name')}

            </Link>
            <button type="button" onClick={onLogoutClick}>Logout</button>

        : <button type="button" onClick={onLoginClick}>Login</button>}

  );
}

function mapStateToProps({ auth }) {
  return {
    user: auth.get('user'),
  };
}

function mapDispatchToProps(dispatch) {
  return {
    onLoginClick() {
      dispatch(showDialog());
    },
    onLogoutClick() {
      dispatch(logout());
    },
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(AppHeader);
<commit_msg>Fix linting.<commit_after>import React from 'react';
import { connect } from 'react-redux';
import { EDITOR_FACEBOOK_GROUP } from '../constants/urls';
import Link from 'next/link';
import { showDialog, logout } from '../redux/auth';

function AppHeader({ user, onLoginClick, onLogoutClick }) {
  return (

      <Link href="/">
真的假的
</Link>

        <Link href="/">文章</Link>
        <Link href="/replies">回應</Link>

        編輯求助區

      {user
        ?

            <Link href="/replies?mine=1">

                {user.get('name')}

            </Link>
            <button type="button" onClick={onLogoutClick}>Logout</button>

        : <button type="button" onClick={onLoginClick}>Login</button>}

  );
}

function mapStateToProps({ auth }) {
  return {
    user: auth.get('user'),
  };
}

function mapDispatchToProps(dispatch) {
  return {
    onLoginClick() {
      dispatch(showDialog());
    },
    onLogoutClick() {
      dispatch(logout());
    },
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(AppHeader);
<|endoftext|>


<commit_before>const pg = require("pg");
const { readFile } = require("fs");
const pgConnectionString = require("pg-connection-string");

// This test suite can be flaky. Increase it’s timeout.
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 20;

function readFilePromise(filename, encoding) {
  return new Promise((resolve, reject) => {
    readFile(filename, encoding, (err, res) => {
      if (err) reject(err);
      else resolve(res);
    });
  });
}

const withPgClient = async (url, fn) => {
  if (!fn) {
    fn = url;
    url = process.env.TEST_DATABASE_URL;
  }
  const pgPool = new pg.Pool(pgConnectionString.parse(url));
  let client;
  try {
    client = await pgPool.connect();
    await client.query("begin");
    await client.query("set local timezone to '+04:00'");
    const result = await fn(client);
    await client.query("rollback");
    return result;
  } finally {
    try {
      await client.release();
    } catch (e) {
      console.error("Error releasing pgClient", e);
    }
    await pgPool.end();
  }
};

const withDbFromUrl = async (url, fn) => {
  return withPgClient(url, async client => {
    try {
      await client.query("BEGIN ISOLATION LEVEL SERIALIZABLE;");
      return fn(client);
    } finally {
      await client.query("COMMIT;");
    }
  });
};

const withRootDb = fn => withDbFromUrl(process.env.TEST_DATABASE_URL, fn);

let prepopulatedDBKeepalive;

const populateDatabase = async client => {
  await client.query(
    await readFilePromise(`${__dirname}/p-data.sql`, "utf8")
  );
  return {};
};

const withPrepopulatedDb = async fn => {
  if (!prepopulatedDBKeepalive) {
    throw new Error("You must call setup and teardown to use this");
  }
  const { client, vars } = prepopulatedDBKeepalive;
  if (!vars) {
    throw new Error("No prepopulated vars");
  }
  let err;
  try {
    await fn(client, vars);
  } catch (e) {
    err = e;
  }
  try {
    await client.query("ROLLBACK TO SAVEPOINT pristine;");
  } catch (e) {
    err = err || e;
    console.error("ERROR ROLLING BACK", e.message); // eslint-disable-line no-console
  }
  if (err) {
    throw err;
  }
};

withPrepopulatedDb.setup = done => {
  if (prepopulatedDBKeepalive) {
    throw new Error("There's already a prepopulated DB running");
  }
  let res;
  let rej;
  prepopulatedDBKeepalive = new Promise((resolve, reject) => {
    res = resolve;
    rej = reject;
  });
  prepopulatedDBKeepalive.resolve = res;
  prepopulatedDBKeepalive.reject = rej;
  withRootDb(async client => {
    prepopulatedDBKeepalive.client = client;
    try {
      prepopulatedDBKeepalive.vars = await populateDatabase(client);
    } catch (e) {
      console.error("FAILED TO PREPOPULATE DB!", e.message); // eslint-disable-line no-console
      return done(e);
    }
    await client.query("SAVEPOINT pristine;");
    done();
    return prepopulatedDBKeepalive;
  });
};

withPrepopulatedDb.teardown = () => {
  if (!prepopulatedDBKeepalive) {
    throw new Error("Cannot tear down null!");
  }
  prepopulatedDBKeepalive.resolve(); // Release DB transaction
  prepopulatedDBKeepalive = null;
};

exports.withRootDb = withRootDb;
exports.withPrepopulatedDb = withPrepopulatedDb;
exports.withPgClient = withPgClient;
<commit_msg>prettier<commit_after>const pg = require("pg");
const { readFile } = require("fs");
const pgConnectionString = require("pg-connection-string");

// This test suite can be flaky. Increase it’s timeout.
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 20;

function readFilePromise(filename, encoding) {
  return new Promise((resolve, reject) => {
    readFile(filename, encoding, (err, res) => {
      if (err) reject(err);
      else resolve(res);
    });
  });
}

const withPgClient = async (url, fn) => {
  if (!fn) {
    fn = url;
    url = process.env.TEST_DATABASE_URL;
  }
  const pgPool = new pg.Pool(pgConnectionString.parse(url));
  let client;
  try {
    client = await pgPool.connect();
    await client.query("begin");
    await client.query("set local timezone to '+04:00'");
    const result = await fn(client);
    await client.query("rollback");
    return result;
  } finally {
    try {
      await client.release();
    } catch (e) {
      console.error("Error releasing pgClient", e);
    }
    await pgPool.end();
  }
};

const withDbFromUrl = async (url, fn) => {
  return withPgClient(url, async client => {
    try {
      await client.query("BEGIN ISOLATION LEVEL SERIALIZABLE;");
      return fn(client);
    } finally {
      await client.query("COMMIT;");
    }
  });
};

const withRootDb = fn => withDbFromUrl(process.env.TEST_DATABASE_URL, fn);

let prepopulatedDBKeepalive;

const populateDatabase = async client => {
  await client.query(await readFilePromise(`${__dirname}/p-data.sql`, "utf8"));
  return {};
};

const withPrepopulatedDb = async fn => {
  if (!prepopulatedDBKeepalive) {
    throw new Error("You must call setup and teardown to use this");
  }
  const { client, vars } = prepopulatedDBKeepalive;
  if (!vars) {
    throw new Error("No prepopulated vars");
  }
  let err;
  try {
    await fn(client, vars);
  } catch (e) {
    err = e;
  }
  try {
    await client.query("ROLLBACK TO SAVEPOINT pristine;");
  } catch (e) {
    err = err || e;
    console.error("ERROR ROLLING BACK", e.message); // eslint-disable-line no-console
  }
  if (err) {
    throw err;
  }
};

withPrepopulatedDb.setup = done => {
  if (prepopulatedDBKeepalive) {
    throw new Error("There's already a prepopulated DB running");
  }
  let res;
  let rej;
  prepopulatedDBKeepalive = new Promise((resolve, reject) => {
    res = resolve;
    rej = reject;
  });
  prepopulatedDBKeepalive.resolve = res;
  prepopulatedDBKeepalive.reject = rej;
  withRootDb(async client => {
    prepopulatedDBKeepalive.client = client;
    try {
      prepopulatedDBKeepalive.vars = await populateDatabase(client);
    } catch (e) {
      console.error("FAILED TO PREPOPULATE DB!", e.message); // eslint-disable-line no-console
      return done(e);
    }
    await client.query("SAVEPOINT pristine;");
    done();
    return prepopulatedDBKeepalive;
  });
};

withPrepopulatedDb.teardown = () => {
  if (!prepopulatedDBKeepalive) {
    throw new Error("Cannot tear down null!");
  }
  prepopulatedDBKeepalive.resolve(); // Release DB transaction
  prepopulatedDBKeepalive = null;
};

exports.withRootDb = withRootDb;
exports.withPrepopulatedDb = withPrepopulatedDb;
exports.withPgClient = withPgClient;
<|endoftext|>


<commit_before>import React from 'react'

import { Grid, Row, Col, Button, Table, Input, Panel } from 'react-bootstrap'
import { Link } from 'react-router'

import ManagerNavbar from '../containers/ManagerNavbar'
import CurrentStatusMessage from '../containers/CurrentStatusMessage'
import EditableTextField from './EditableTextField'

export default class ProjectsList extends React.Component {

  constructor (props) {
    super(props)
  }

  componentWillMount () {
    this.props.onComponentMount(this.props.routeParams.projectId)
  }

  render () {
    return (

        <ManagerNavbar />
        <Grid>
          <Row>
            <Col xs={12}>

{this.props.project.name}

            </Col>
          </Row>

          <Panel
            header={(Project Settings)}
            collapsible
          >
            <Row>
              <Col xs={12}>
                Settings
              </Col>
            </Row>
          </Panel>

          <Panel
            header={(Feed Sources)}
            collapsible
            defaultExpanded={true}
          >
            <Row>
              <Col xs={4}>
                <Input
                  type="text"
                  placeholder="Search by Feed Source Name"
                  onChange={evt => this.props.searchTextChanged(evt.target.value)}
                />
              </Col>
              <Col xs={8}>
                <Button
                  bsStyle="primary"
                  className="pull-right"
                  onClick={() => this.props.onNewFeedSourceClick()}
                >
                  New Feed Source
                </Button>
              </Col>
            </Row>
            <Row>
              <Col xs={12}>

                      Name
                      Public?
                      Retrieval Method
                      Last Updated
                      Error
Count
                      Valid Range

                    {this.props.project.feedSources
                      ? this.props.project.feedSources.map((feedSource) => {
                          return <FeedSourceTableRow
                            feedSource={feedSource}
                            newFeedSourceNamed={this.props.newFeedSourceNamed}
                            feedSourceNameChanged={this.props.feedSourceNameChanged}
                            key={feedSource.id}
                          />
                        })
                      : null
                    }

              </Col>
            </Row>
          </Panel>
        </Grid>
        <CurrentStatusMessage />

    )
  }
}

class FeedSourceTableRow extends React.Component {

  constructor (props) {
    super(props)
  }

  render () {
    const fs = this.props.feedSource
    return (

            <EditableTextField
              isEditing={(fs.isCreating === true)}
              value={fs.name}
              onChange={(value) => {
                if(fs.isCreating) this.props.newFeedSourceNamed(value)
                else this.props.feedSourceNameChanged(fs, value)
              }}
              link={`/feed/${fs.id}`}
            />

    )
  }
}
<commit_msg>Breadcrumbs on project viewer<commit_after>import React from 'react'

import { Grid, Row, Col, Button, Table, Input, Panel } from 'react-bootstrap'
import { Link } from 'react-router'

import ManagerNavbar from '../containers/ManagerNavbar'
import CurrentStatusMessage from '../containers/CurrentStatusMessage'
import EditableTextField from './EditableTextField'

export default class ProjectsList extends React.Component {

  constructor (props) {
    super(props)
  }

  componentWillMount () {
    this.props.onComponentMount(this.props.routeParams.projectId)
  }

  render () {
    return (

        <ManagerNavbar />
        <Grid>
          <Row>
            <Col xs={12}>

<Link to='/'>Projects</Link>

{this.props.project.name}

            </Col>
          </Row>
          <Row>
            <Col xs={12}>

{this.props.project.name}

            </Col>
          </Row>

          <Panel
            header={(Project Settings)}
            collapsible
          >
            <Row>
              <Col xs={12}>
                Settings
              </Col>
            </Row>
          </Panel>

          <Panel
            header={(Feed Sources)}
            collapsible
            defaultExpanded={true}
          >
            <Row>
              <Col xs={4}>
                <Input
                  type="text"
                  placeholder="Search by Feed Source Name"
                  onChange={evt => this.props.searchTextChanged(evt.target.value)}
                />
              </Col>
              <Col xs={8}>
                <Button
                  bsStyle="primary"
                  className="pull-right"
                  onClick={() => this.props.onNewFeedSourceClick()}
                >
                  New Feed Source
                </Button>
              </Col>
            </Row>
            <Row>
              <Col xs={12}>

                      Name
                      Public?
                      Retrieval Method
                      Last Updated
                      Error
Count
                      Valid Range

                    {this.props.project.feedSources
                      ? this.props.project.feedSources.map((feedSource) => {
                          return <FeedSourceTableRow
                            feedSource={feedSource}
                            newFeedSourceNamed={this.props.newFeedSourceNamed}
                            feedSourceNameChanged={this.props.feedSourceNameChanged}
                            key={feedSource.id}
                          />
                        })
                      : null
                    }

              </Col>
            </Row>
          </Panel>
        </Grid>
        <CurrentStatusMessage />

    )
  }
}

class FeedSourceTableRow extends React.Component {

  constructor (props) {
    super(props)
  }

  render () {
    const fs = this.props.feedSource
    return (

            <EditableTextField
              isEditing={(fs.isCreating === true)}
              value={fs.name}
              onChange={(value) => {
                if(fs.isCreating) this.props.newFeedSourceNamed(value)
                else this.props.feedSourceNameChanged(fs, value)
              }}
              link={`/feed/${fs.id}`}
            />

    )
  }
}
<|endoftext|>


<commit_before>var React = require('react-native');

window.React = React;

var {
  AppRegistry,
  NavigatorIOS,
  StyleSheet,
} = React;

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

var MoviesApp = React.createClass({
  render: function() {
    return (
      <NavigatorIOS
        style={styles.container}
        initialRoute={{
          title: 'Movies',
          component: MovieList,
        }}
      />
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
});

AppRegistry.registerComponent('MoviesApp', () => MoviesApp);

module.exports = MoviesApp;
<commit_msg>+parse for cloud data<commit_after>var React = require('react-native');
var Parse = require('parse').Parse;

// Make react and parse global
window.React = React;
window.Parse = Parse;

var {
  AppRegistry,
  NavigatorIOS,
  StyleSheet,
} = React;

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

var MoviesApp = React.createClass({
  render: function() {
    return (
      <NavigatorIOS
        style={styles.container}
        initialRoute={{
          title: 'Movies',
          component: MovieList,
        }}
      />
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
});

AppRegistry.registerComponent('MoviesApp', () => MoviesApp);

module.exports = MoviesApp;
<|endoftext|>


<commit_before>var mongoose = require('mongoose');
//连接数据库 mongodb://IP/数据库名 数据库不需要事先创建，直接使用即可
//因为使用时候mongodb如果发现此数据库不存会自动帮你创建
mongoose.connect('mongodb://127.0.0.1/201608db');
// 1. schema定义了一个集合的名称，里面文档记录的字段名称和字段类型
// 如果字段名称或类型不匹配，则存储失败
//不能操作数据库
var personSchema = new mongoose.Schema({
  name:String,//人的姓名
  birthday:Date,//出生日期
  email:String //邮箱
},{collection:'person'});//指定集合的名称

//2 model是真正用来操作数据库的。
//1参数是模型的名称 2参数是schema实例
//二个参数表示定义一个模型，一个参数表示获取一个模型
var User = mongoose.model('User',personSchema);
/**
 * 保存的时候会拿字段名称和schema定义一一匹配，如果匹配不上，则忽略此字段
 * 如果类型不匹配，则会尝试类型转换，如果转换不成功，是报错保存失败
 */
var userObj = {name:'张三',birthday:new Date(),email:'888@126.com',home:'北京'};
User.create(userObj,function(err,doc){
    if(err){
        console.error(err);
    }else{
        console.log(doc);
    }
});

/**
 * 切换到指定的数据库
 * > use 201608db
     switched to db 201608db

   查看当前是哪个数据库
 > db
   201608db
   查看帮助，了解数据库有哪些方法
    db.help();
   查看当前数据库下面的有哪些集合
 >  db.getCollectionNames();
 [ "person", "system.indexes" ]
 > show collections;
    person
   system.indexes

 如何 查看集合中的文档
  db.集合名称.find();
  db.person.find();
 */

<commit_msg>cookie的原理<commit_after>var mongoose = require('mongoose');
//使用自己写的promise库 使用es6 promise库
mongoose.Promise = Promise;
//连接数据库 mongodb://IP/数据库名 数据库不需要事先创建，直接使用即可
//因为使用时候mongodb如果发现此数据库不存会自动帮你创建
mongoose.connect('mongodb://127.0.0.1/201608db');
// 1. schema定义了一个集合的名称，里面文档记录的字段名称和字段类型
// 如果字段名称或类型不匹配，则存储失败
//不能操作数据库
var personSchema = new mongoose.Schema({
  name:String,//人的姓名
  birthday:Date,//出生日期
  email:String, //邮箱
  count:Number
},{collection:'person'});//指定集合的名称

//2 model是真正用来操作数据库的。
//1参数是模型的名称 2参数是schema实例
//二个参数表示定义一个模型，一个参数表示获取一个模型
var User = mongoose.model('User',personSchema);
/**
 * 保存的时候会拿字段名称和schema定义一一匹配，如果匹配不上，则忽略此字段
 * 如果类型不匹配，则会尝试类型转换，如果转换不成功，是报错保存失败
 */
var userObj = {name:'张三',birthday:new Date(),email:'888@126.com',home:'北京'};
/*User.create(userObj,function(err,doc){
    if(err){
        console.error(err);
    }else{
        console.log(doc);
    }

});*/

/**
 * 切换到指定的数据库
 * > use 201608db
     switched to db 201608db

   查看当前是哪个数据库
 > db
   201608db
   查看帮助，了解数据库有哪些方法
    db.help();
   查看当前数据库下面的有哪些集合
 >  db.getCollectionNames();
 [ "person", "system.indexes" ]
 > show collections;
    person
   system.indexes

 如何 查看集合中的文档
  db.集合名称.find();
  db.person.find();
 */

//User.find({name:'张三4'},function(err,docs){
//    if(err){
//        console.error(err);
//    }else{
//        console.log(docs.length);
//    }
//});

/*
User.find({name:'张三4'}).then(function(docs){
    console.log(docs);
},function(err){
    console.log(err);
});*/
/**
 * 如果你想用更新对象整体全部覆盖原对象对象的话
 * $set 表示更新哪些字段
 * $inc = increment increase
 * multi 表示如果匹配到多条记录，则全部更新，默认只更新区配到的第一条
 */
/*User.update({name:'张三'},{$set:{name:'张三6'}},{multi:true},function(err,doc){
    console.log(doc);
});*/
/*User.update({name:'张三'},{$inc:{count:5}},{multi:true},function(err,doc){
    console.log(doc);
});*/
//默认情况下，remove会删除掉所有匹配的记录
User.remove({name:'张三'},function(err,result){
    console.log(result.result);
});<|endoftext|>


<commit_before>
/**
 *  Map templates
 *
 *  It will display all the possibilities to select
 *  any of your current datasets or connect a new dataset.
 *
 */

module.exports = [
  {
    name: 'Animate Your Data',
    short_name: 'Animate Your Data',
    description: 'Learn to animate your data by date using historic United States tornado data.',
    short_description: 'Learn how yo create a map that shows events in time',
    icon: 'Snake',
    color: '#CB3F29',
    video: {
      id: '122308083',
      steps: []
    },
    map: {
      url: 'http://examples.cartodb.com/viz/960736aa-cd8c-11e4-a309-0e6e1df11cbf/embed_map',
      source: [
        'http://examples.cartodb.com/api/v2/sql?q=SELECT%20*%20FROM%20tornado_centroids&filename=tornados&format=geojson'
      ]
    }
  },
  {
    name: 'Animate the life of a cat',
    short_name: 'Animate point',
    description: 'Let\'s take a look at one week of movement data for a cat named Spencer. Using GPS collected data, we can animate Spencer over time to see his patterns of exploration in his neighborhood.',
    short_description: 'Mapping your GPS data was never so easy!',
    icon: 'Points',
    color: '#AC638B',
    video: {
      id: '122308076',
      steps: []
    },
    map: {
      url: 'http://examples.cartodb.com/viz/00c8701c-c121-11e4-b828-0e4fddd5de28/embed_map',
      source: [
        'http://examples.cartodb.com/api/v2/sql?q=SELECT%20*%20FROM%20spencer_the_cat&filename=spencer_the_cat&format=geojson'
      ]
    }
  },
  {
    name: 'Create your own data in the CartoDB editor',
    short_name: 'Create your own data',
    description: 'Learn to create your own point, line, and polygon data directly in the CartoDB editor',
    short_description: ' Add features in a map: points, polygons or lines!',
    icon: 'Notes',
    color: '#F2C000',
    video: {
      id: '122308073',
      steps: []
    },
    map: {
      url: 'http://examples.cartodb.com/viz/eaa226aa-cd8e-11e4-893e-0e0c41326911/embed_map'
    }
  },
  {
    name: 'Map your local world',
    short_name: 'Map your local world',
    description: "We will use a publically available set of buildings to map Nantucket Island. Then we will use CartoDB's annotation tools to highlight our point of interest.",
    short_description: 'Learn to create and style a map of your city',
    icon: 'Mountain',
    color: '#EA703D',
    video: {
      id: '122308081',
      steps: []
    },
    map: {
      url: 'http://examples.cartodb.com/viz/b8847e3e-c1f4-11e4-8c09-0e853d047bba/embed_map',
      source: [
        'http://examples.cartodb.com/api/v2/sql?q=SELECT%20*%20FROM%20structures_poly_197&filename=buildings_nantucket&format=geojson'
      ]
    }
  },
  {
    name: 'Create your first choropleth using Table Join',
    short_name: 'Create your first choropleth',
    description: 'Create your first choropleth map by joining historic tornado data with United States polygons',
    short_description: 'Build your first choropleth map from sample data',
    icon: 'Rectangles',
    color: '#86B765',
    video: {
      id: '122308079',
      steps: []
    },
    map: {
      url: 'http://examples.cartodb.com/viz/339c7670-cd90-11e4-ab8c-0e018d66dc29/embed_map',
      source: [
        'http://examples.cartodb.com/api/v2/sql?q=SELECT%20*%20FROM%20tornado_centroids&filename=tornados&format=geojson',
        'http://examples.cartodb.com/api/v2/sql?q=SELECT%20*%20FROM%20tornados_in_us&filename=tornados_us&format=geojson'
      ]
    }
  }
]
<commit_msg>texts revert<commit_after>
/**
 *  Map templates
 *
 *  It will display all the possibilities to select
 *  any of your current datasets or connect a new dataset.
 *
 */

module.exports = [
  {
    name: 'Create animated maps',
    short_name: 'Create animated maps',
    description: 'Learn how to animate your data, by using historic United States tornado data.',
    short_description: 'Create maps for showing events over time',
    icon: 'Snake',
    color: '#CB3F29',
    video: {
      id: '122308083',
      steps: []
    },
    map: {
      url: 'http://examples.cartodb.com/viz/960736aa-cd8c-11e4-a309-0e6e1df11cbf/embed_map',
      source: [
        'http://examples.cartodb.com/api/v2/sql?q=SELECT%20*%20FROM%20tornado_centroids&filename=tornados&format=geojson'
      ]
    }
  },
  {
    name: 'Animate the life of a cat',
    short_name: 'Create GPS Data maps',
    description: 'Let\'s take a look at one week of movements for a cat named Spencer. Using GPS collected data, we can animate Spencer over time to see his patterns of exploration in his neighborhood.',
    short_description: 'Mapping your GPS data was never so easy!',
    icon: 'Points',
    color: '#AC638B',
    video: {
      id: '122308076',
      steps: []
    },
    map: {
      url: 'http://examples.cartodb.com/viz/00c8701c-c121-11e4-b828-0e4fddd5de28/embed_map',
      source: [
        'http://examples.cartodb.com/api/v2/sql?q=SELECT%20*%20FROM%20spencer_the_cat&filename=spencer_the_cat&format=geojson'
      ]
    }
  },
  {
    name: 'Create your own data using the UI',
    short_name: 'Create your own datasets',
    description: 'Learn to create your own point, line, or polygon dataset directly in the CartoDB editor.',
    short_description: ' Add and style features in a map using the CartoDB UI.',
    icon: 'Notes',
    color: '#F2C000',
    video: {
      id: '122308073',
      steps: []
    },
    map: {
      url: 'http://examples.cartodb.com/viz/eaa226aa-cd8e-11e4-893e-0e0c41326911/embed_map'
    }
  },
  {
    name: 'Map your local world',
    short_name: 'Map your local world',
    description: "We will use a publically available set of buildings to map Nantucket Island. Then we will use CartoDB's annotation tools to highlight our point of interest.",
    short_description: 'Learn to create and style a map of your city',
    icon: 'Mountain',
    color: '#EA703D',
    video: {
      id: '122308081',
      steps: []
    },
    map: {
      url: 'http://examples.cartodb.com/viz/b8847e3e-c1f4-11e4-8c09-0e853d047bba/embed_map',
      source: [
        'http://examples.cartodb.com/api/v2/sql?q=SELECT%20*%20FROM%20structures_poly_197&filename=buildings_nantucket&format=geojson'
      ]
    }
  },
  {
    name: 'Create your first choropleth map using Table Join',
    short_name: 'Join Datasets',
    description: 'Create your first choropleth map by joining historic tornado data with United States polygons',
    short_description: 'Build your first choropleth map by joining two datasets',
    icon: 'Rectangles',
    color: '#86B765',
    video: {
      id: '122308079',
      steps: []
    },
    map: {
      url: 'http://examples.cartodb.com/viz/339c7670-cd90-11e4-ab8c-0e018d66dc29/embed_map',
      source: [
        'http://examples.cartodb.com/api/v2/sql?q=SELECT%20*%20FROM%20tornado_centroids&filename=tornados&format=geojson',
        'http://examples.cartodb.com/api/v2/sql?q=SELECT%20*%20FROM%20tornados_in_us&filename=tornados_us&format=geojson'
      ]
    }
  }
]
<|endoftext|>


<commit_before>import _ from 'lodash';
import React from 'react';
import { BackAndroid, Navigator, Platform, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import Button from 'react-native-button';
import { connect } from 'react-redux'

import Icon from './Icon';

let _navigator;
if (Platform.OS === 'android') {
  // FIXME: Uses NavigatorExperimental when it's ready.
  BackAndroid.addEventListener('hardwareBackPress', () => {
    if (_navigator && _navigator.getCurrentRoutes().length > 1) {
      _navigator.pop();
      return true;
    }
    return false;
  });
}

export default connect()(React.createClass({
  configureScene(route) {
    return route.props.sceneConfig || Navigator.SceneConfigs.PushFromRight;
  },
  renderScene(route, navigator) {
    if (Platform.OS === 'android') {
      _navigator = navigator;
    }
    return (
      <View style={styles.scene}>
        <route.component {...route.props} {...this.props.childProps} push={navigator.push} pop={navigator.pop} />
      </View>
    );
  },
  routeMapper() {
    const { dispatch } = this.props;
    return {
      LeftButton(route, navigator, index, navState) {
        const { component } = route;
        const leftButton = component.leftButton || _.get(component, 'WrappedComponent.leftButton');
        if (leftButton) {
          return (
            <View style={styles.navBarButton}>
              {leftButton(navigator, route)}
            </View>
          );
        }

        // default back button.
        if (index === 0) {
          return null;
        }
        return (
          <Button onPress={() => navigator.pop()} containerStyle={styles.navBarButton}>
            <View style={{ padding: 5 }}>
              <Icon name='arrow-back' size={23} color='white' />
            </View>
          </Button>
        );
      },
      RightButton(route, navigator, index, navState) {
        const { component, props } = route;
        const rightButton = props.rightButton || component.rightButton || _.get(component, 'WrappedComponent.rightButton');
        if (rightButton) {
          return (
            <View style={styles.navBarButton}>
              {rightButton(route, navigator, index, navState)}
            </View>
          );
        }
      },
      Title(route, navigator, index, navState) {
        const { title, component } = route;
        if (_.isNil(title)) {
          const componentTitle = component.title || _.get(component, 'WrappedComponent.title');
          if (componentTitle) return componentTitle(dispatch);
        } else {
          return (
            <Text style={styles.navBarTitleText}>
              {title}
            </Text>
          );
        }
      },
    };
  },
  render() {
    const { showTabBar } = this.props;
    return (
      <Navigator
        initialRoute={this.props.initialRoute}
        navigationBar={
          <Navigator.NavigationBar
            routeMapper={this.routeMapper()}
            style={styles.navBar}
            navigationStyles={Navigator.NavigationBar.StylesIOS}
          />
        }
        configureScene={this.configureScene}
        renderScene={this.renderScene}
        style={styles.container}
        onDidFocus={({component, props}) => {
          showTabBar && showTabBar(props.showTabBar !== false);
          const onDidFocus = component.onDidFocus || _.get(component, 'WrappedComponent.onDidFocus');
          if (onDidFocus) onDidFocus(props, this.props.dispatch);
        }}
      />
    );
  }
}));

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
  scene: {
    flex: 1,
    paddingTop: Platform.OS === 'ios' ? 64 : 56, // NavigationBar
    backgroundColor: 'white',
  },
  navBar: {
    backgroundColor: '#1F3A4A',
  },
  navBarTitleText: {
    color: 'white',
    fontWeight: 'bold',
    fontSize: 16,
    marginVertical: Platform.OS === 'ios' ? 9 : null,
  },
  navBarButton: {
    marginTop: Platform.OS === 'ios' ? 4 : -5,
    paddingLeft: 5,
    paddingRight: 5,
  },
});
<commit_msg>move show/hide tabbar to onWillFocus.<commit_after>import _ from 'lodash';
import React from 'react';
import { BackAndroid, Navigator, Platform, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import Button from 'react-native-button';
import { connect } from 'react-redux'

import Icon from './Icon';

let _navigator;
if (Platform.OS === 'android') {
  // FIXME: Uses NavigatorExperimental when it's ready.
  BackAndroid.addEventListener('hardwareBackPress', () => {
    if (_navigator && _navigator.getCurrentRoutes().length > 1) {
      _navigator.pop();
      return true;
    }
    return false;
  });
}

export default connect()(React.createClass({
  configureScene(route) {
    return route.props.sceneConfig || Navigator.SceneConfigs.PushFromRight;
  },
  renderScene(route, navigator) {
    if (Platform.OS === 'android') {
      _navigator = navigator;
    }
    return (
      <View style={styles.scene}>
        <route.component {...route.props} {...this.props.childProps} push={navigator.push} pop={navigator.pop} />
      </View>
    );
  },
  routeMapper() {
    const { dispatch } = this.props;
    return {
      LeftButton(route, navigator, index, navState) {
        const { component } = route;
        const leftButton = component.leftButton || _.get(component, 'WrappedComponent.leftButton');
        if (leftButton) {
          return (
            <View style={styles.navBarButton}>
              {leftButton(navigator, route)}
            </View>
          );
        }

        // default back button.
        if (index === 0) {
          return null;
        }
        return (
          <Button onPress={() => navigator.pop()} containerStyle={styles.navBarButton}>
            <View style={{ padding: 5 }}>
              <Icon name='arrow-back' size={23} color='white' />
            </View>
          </Button>
        );
      },
      RightButton(route, navigator, index, navState) {
        const { component, props } = route;
        const rightButton = props.rightButton || component.rightButton || _.get(component, 'WrappedComponent.rightButton');
        if (rightButton) {
          return (
            <View style={styles.navBarButton}>
              {rightButton(route, navigator, index, navState)}
            </View>
          );
        }
      },
      Title(route, navigator, index, navState) {
        const { title, component } = route;
        if (_.isNil(title)) {
          const componentTitle = component.title || _.get(component, 'WrappedComponent.title');
          if (componentTitle) return componentTitle(dispatch);
        } else {
          return (
            <Text style={styles.navBarTitleText}>
              {title}
            </Text>
          );
        }
      },
    };
  },
  render() {
    const { showTabBar } = this.props;
    return (
      <Navigator
        initialRoute={this.props.initialRoute}
        navigationBar={
          <Navigator.NavigationBar
            routeMapper={this.routeMapper()}
            style={styles.navBar}
            navigationStyles={Navigator.NavigationBar.StylesIOS}
          />
        }
        configureScene={this.configureScene}
        renderScene={this.renderScene}
        style={styles.container}
        onWillFocus={({props}) => {
          showTabBar && showTabBar(props.showTabBar !== false);
        }}
        onDidFocus={({component, props}) => {
          const onDidFocus = component.onDidFocus || _.get(component, 'WrappedComponent.onDidFocus');
          if (onDidFocus) onDidFocus(props, this.props.dispatch);
        }}
      />
    );
  }
}));

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
  scene: {
    flex: 1,
    paddingTop: Platform.OS === 'ios' ? 64 : 56, // NavigationBar
    backgroundColor: 'white',
  },
  navBar: {
    backgroundColor: '#1F3A4A',
  },
  navBarTitleText: {
    color: 'white',
    fontWeight: 'bold',
    fontSize: 16,
    marginVertical: Platform.OS === 'ios' ? 9 : null,
  },
  navBarButton: {
    marginTop: Platform.OS === 'ios' ? 4 : -5,
    paddingLeft: 5,
    paddingRight: 5,
  },
});
<|endoftext|>