<commit_before>"use strict";

// include core Park class
const Park = require("../park");
const Moment = require("moment-timezone");

// uuid generation lib
const uuid = require("uuid/v4");
// zip lib to extract data
const unzip = require("yauzl");

const s_apiKey = Symbol();
const s_apiBase = Symbol();
const s_calendarURLBase = Symbol();
const s_appVersion = Symbol();
const s_appBuild = Symbol();
const s_deviceID = Symbol();
const s_dataVersion = Symbol();

const s_deviceTokenCacheTime = Symbol();
const s_userIDCacheTime = Symbol();
const s_dataCacheTime = Symbol();

/**
 * Implements the Merlin Park API framework. Thorpe Park, Alton Towers, Chessington etc. use this API framework
 * @class
 * @extends Park
 */
class MerlinPark extends Park {
    /**
     * Create new Merlin Object.
     * This object should not be called directly, but rather extended for each of the individual Merlin parks
     * @param {Object} options
     * @param {String} options.api_key API key to access this park's API
     * @param {String} [options.api_base] API Base to use when accessing the API
     * @param {String} [options.app_build] Build version of the app (optional)
     * @param {String} [options.app_version] App version of the app (optional)
     * @param {String} [options.device_id] Device identifier for use against the API (optional)
     * @param {String} [options.initial_data_version] The initial version timestamp to fetch (optional)
     * @param {Number} [options.device_token_cachetime=86400000] Time to cache device token, in milliseconds (optional)
     * @param {Number} [options.user_id_cachetime=43200000] Time to cache user ID, in milliseconds (optional)
     * @param {Number} [options.data_cachetime=43200000] Time to ride data, in milliseconds (optional)
     */
    constructor(options = {}) {
        options.name = options.name || "Merlin Park";

        // hard-code UserAgent for these parks
        //  do this before calling super, so we don't get a randomly generated one
        options.useragent = "okhttp/3.2.0";

        // inherit from base class
        super(options);

        // custom API options
        if (!options.api_key) throw new Error("Merlin Parks require an API key");
        this[s_apiKey] = options.api_key;
        if (!options.initial_data_version) throw new Error("Merlin Parks require an initial data version to fetch ride names");
        this[s_dataVersion] = options.initial_data_version;

        // app version options (optionally overriden)
        this[s_appBuild] = options.app_build || "5";
        this[s_appVersion] = options.app_version || "1.0.1";
        this[s_deviceID] = options.device_id || "123";

        // default base API
        this[s_apiBase] = options.api_base || "https://api.attractions.io/v1/";
        this[s_calendarURLBase] = options.calendar_base || "https://www.thorpepark.com/";

        // cache times
        this[s_deviceTokenCacheTime] = options.device_token_cachetime || 86400000; // default: 24 hours
        this[s_userIDCacheTime] = options.user_id_cachetime || 43200000; // default: 12 hours
        this[s_dataCacheTime] = options.data_cachetime || 43200000; // default: 12 hours
    }

    /**
     * Get the API Base URL
     */
    get APIBase() {
        return this[s_apiBase];
    }

    FetchWaitTimes() {
        // first, make sure we have our park data (ride names etc.)
        return this.GetParkData().then((rideNames) => {
            // fetch wait times
            return this.MakeAPICall({
                url: `${this.APIBase}live-data`
            }).then((data) => {
                for (var i = 0, ride; ride = data.entities.Item.records[i++];) {
                    // apply each wait time data
                    var rideObject = this.GetRideObject({
                        id: ride._id,
                        name: rideNames[ride._id],
                    });

                    if (!rideObject) {
                        this.Log(`Failed to find ride with ID ${ride.id}`);
                    } else {
                        // update ride wait time (wait times are in seconds in this API!)
                        rideObject.WaitTime = ride.IsOpen ? (ride.QueueTime / 60) : -1;
                    }
                }

                return Promise.resolve();
            });
        });
    }

    /**
     * Get an API token from cache or through registering a new device
     */
    RegisterDevice() {
        // fetch new device token if we haven't already got one in our cache
        return this.Cache.Wrap("device_token", () => {
            // first, get (or generate) a new user ID
            return this.GenerateUserID().then((user_id) => {
                // request token for further API requests
                return this.HTTP({
                    url: `${this[s_apiBase]}installation`,
                    method: "POST",
                    data: {
                        user_identifier: user_id,
                        device_identifier: this[s_deviceID],
                        app_version: this[s_appVersion],
                        app_build: this[s_appBuild]
                    },
                    headers: {
                        "occasio-platform": "Android",
                        "occasio-platform-version": "6.0.1",
                        "occasio-app-build": this[s_appBuild],
                        "authorization": `Attractions-Io api-key "${this[s_apiKey]}"`,
                    }
                }).then((data) => {
                    if (data && data.token) {
                        return Promise.resolve(data.token);
                    }

                    return Promise.reject("No data returned");
                });
            });
        }, this[s_deviceTokenCacheTime]);
    }

    /**
     * Generate (or fetch a cached) user ID
     */
    GenerateUserID() {
        return this.Cache.Wrap("user_id", () => {
            // generate new UUID if cache hit fails
            const newUserID = uuid();

            this.Log(`Generated new UserID ${newUserID}`);

            return Promise.resolve(newUserID);
        }, this[s_userIDCacheTime]);
    }

    /**
     * Get (or fetch new) park data
     */
    GetParkData() {
        return this.Cache.Wrap("data", () => {
            // fetch fresh/updated data
            return this.FetchParkData(this.DataVersion).then((data) => {
                var rideData = {};
                for (var i = 0, item; item = data.Item[i++];) {
                    rideData[item._id] = item.Name;
                }
                return Promise.resolve(rideData);
            });
        }, this[s_dataCacheTime]);
    }

    /**
     * Get the latest data version timestamp
     */
    get DataVersion() {
        return this[s_dataVersion];
    }

    /**
     * Fetch/Sync park data
     * Warning: full sync is ~30MB
     */
    FetchParkData(version) {
        // this is a recursive function, and will keep fetching data until we get no more deltas to resolve
        //  note: we should attempt to periodically update the initialVersion to cut down on these requests

        // remember this as the latest version for next fetch
        this[s_dataVersion] = version;

        // Fetch data
        return this.MakeAPICall({
            url: `${this[s_apiBase]}data`,
            data: {
                version: version
            },
            // we want the full response to get the status code
            returnFullResponse: true,
        }).then((response) => {
            if (response.statusCode == 304) {
                // reject
                this.Log(`Reached status 304 accessing data version ${version}`);
                return Promise.reject();
            } else {
                this.Log(`Received data for version ${version}`);

                return new Promise((resolve, reject) => {
                    // unzip data
                    unzip.fromBuffer(response.body, {
                        lazyEntries: true
                    }, (err, zip) => {
                        var manifestData;
                        var recordsData;

                        this.Log("Parsing zip file");
                        if (err) {
                            return reject(err);
                        }

                        const GetNextEntry = () => {
                            if (manifestData && recordsData) {
                                // got both the files we need, stop reading the zip file

                                // fetch next data URL
                                if (manifestData.version) {
                                    this.FetchParkData(manifestData.version).catch(() => {
                                        // as soon as we hit an error, return the current level or records data
                                        return resolve(recordsData);
                                    });
                                } else {
                                    return resolve(recordsData);
                                }
                            } else {
                                // read next entry
                                zip.readEntry();
                            }
                        };

                        zip.on("entry", (file) => {
                            this.Log(`Got zip file ${file.fileName}`);

                            // look for the two files we want
                            if (file.fileName == "manifest.json") {
                                ReadZipFile(zip, file).then((data) => {
                                    manifestData = data;

                                    GetNextEntry();
                                });
                            } else if (file.fileName == "records.json") {
                                ReadZipFile(zip, file).then((data) => {
                                    recordsData = data;

                                    GetNextEntry();
                                });
                            } else {
                                GetNextEntry();
                            }
                        });

                        // start reading file...
                        zip.readEntry();
                    });
                });
            }
        });
    }

    /**
     * Generic API request function, will sort out API token and send auth headers
     * @param {*} options
     * @param {String} options.url URL to access
     * @param {String} [options.method=GET] method to use
     * @param {Object} [options.data={}] data/query string to use
     */
    MakeAPICall(options = {
        method: "GET",
        data: {}
    }) {
        // get token
        return this.RegisterDevice().then((token) => {
            // inject auth headers into request headers
            if (!options.headers) {
                options.headers = {};
            }
            options.headers["occasio-platform"] = "Android";
            options.headers["occasio-platform-version"] = "6.0.1";
            options.headers["occasio-app-build"] = this[s_appBuild];
            options.headers["authorization"] = `Attractions-Io api-key "${this[s_apiKey]}", installation-token="${token}"`;

            // make API call
            return this.HTTP(options);
        });
    }

    FetchOpeningTimes() {
        return new Promise((resolve, reject) => {
            this.HTTP({
                url: `${this[s_calendarURLBase]}Umbraco/Api/Calendar/GetAllOpeningTimes`,
                method: "GET",
                headers: {
                    "Referer": this[s_calendarURLBase],
                    "X-Requested-With": "XMLHttpRequest",
                },
                json: true
            }).then((calendarData) => {
                // find theme park dates from response
                //  it contains "WatterPark"[sic] times as well in a separate array
                var parkDates = null;
                if (calendarData[0] && calendarData[0].Type) {
                    // for resorts with multiple parks (Alton Towers)
                    for (var i = 0, times; times = calendarData[i++];) {
                        if (times.Type == "ThemePark") {
                            parkDates = times.OpeningHours;
                            break;
                        }
                    }
                } else if (calendarData[0].Open) {
                    // resorts with only 1 park (Thorpe Park)
                    parkDates = calendarData;
                } else {
                    return reject("Invalid/Unknown calendar data returned");
                }

                var result, timeRange;
                for (i = 0, timeRange; timeRange = parkDates[i++];) {
                    var range = {
                        startDate: Moment(timeRange.From, "YYYY-MM-DDTHH:mm:ss"),
                        endDate: Moment(timeRange.To, "YYYY-MM-DDTHH:mm:ss")
                    };

                    this.Log(`Processing ${range.startDate} => ${range.endDate}`);

                    // figure out opening times for this range
                    if (result = /([0-9:]+\s?[ap]m)\s*-\s*([0-9:]+\s?[ap]m)/gi.exec(timeRange.Open.replace(/\./g, ":"))) {
                        range.openingTime = Moment(result[1].replace(/ /g, ""), "HH:mma");
                        range.closingTime = Moment(result[2].replace(/ /g, ""), "HH:mma");
                    }
                    // try shorthand format too, in case someone entered the times in badly
                    else if (result = /([0-9]+)\s*-\s*([0-9]+)/gi.exec(timeRange.Open.replace(/\./g, ":"))) {
                        range.openingTime = Moment(result[1] + ":00am", "HH:mma");
                        range.closingTime = Moment(result[2] + ":00pm", "HH:mma");
                    } else {
                        this.Log(`Unable to understand hour format: ${timeRange.Open}`);
                        continue;
                    }

                    // apply this range
                    this.Schedule.SetRange(range);
                }

                resolve();
            }, reject);
        });
    }
}

// export the class
module.exports = MerlinPark;

// static functions
function ReadZipFile(zip, file) {
    return new Promise((resolve, reject) => {
        var data = "";
        zip.openReadStream(file, function(err, readStream) {
            if (err) {
                return reject(err);
            }

            readStream.on("data", function(chunk) {
                data += chunk;
            }).on("end", function() {
                // parse JSON data
                try {
                    data = JSON.parse(data);
                    return resolve(data);
                } catch (e) {
                    return reject(`JSON parse error extracting ${file.fileName}: ${e}`);
                }
            });
        });
    });
}<commit_msg>* Fixes MerlinParks FetchOpeningTimes<commit_after>"use strict";

// include core Park class
const Park = require("../park");
const Moment = require("moment-timezone");

// uuid generation lib
const uuid = require("uuid/v4");
// zip lib to extract data
const unzip = require("yauzl");

const s_apiKey = Symbol();
const s_apiBase = Symbol();
const s_calendarURLBase = Symbol();
const s_appVersion = Symbol();
const s_appBuild = Symbol();
const s_deviceID = Symbol();
const s_dataVersion = Symbol();

const s_deviceTokenCacheTime = Symbol();
const s_userIDCacheTime = Symbol();
const s_dataCacheTime = Symbol();

/**
 * Implements the Merlin Park API framework. Thorpe Park, Alton Towers, Chessington etc. use this API framework
 * @class
 * @extends Park
 */
class MerlinPark extends Park {
    /**
     * Create new Merlin Object.
     * This object should not be called directly, but rather extended for each of the individual Merlin parks
     * @param {Object} options
     * @param {String} options.api_key API key to access this park's API
     * @param {String} [options.api_base] API Base to use when accessing the API
     * @param {String} [options.app_build] Build version of the app (optional)
     * @param {String} [options.app_version] App version of the app (optional)
     * @param {String} [options.device_id] Device identifier for use against the API (optional)
     * @param {String} [options.initial_data_version] The initial version timestamp to fetch (optional)
     * @param {Number} [options.device_token_cachetime=86400000] Time to cache device token, in milliseconds (optional)
     * @param {Number} [options.user_id_cachetime=43200000] Time to cache user ID, in milliseconds (optional)
     * @param {Number} [options.data_cachetime=43200000] Time to ride data, in milliseconds (optional)
     */
    constructor(options = {}) {
        options.name = options.name || "Merlin Park";

        // hard-code UserAgent for these parks
        //  do this before calling super, so we don't get a randomly generated one
        options.useragent = "okhttp/3.2.0";

        // inherit from base class
        super(options);

        // custom API options
        if (!options.api_key) throw new Error("Merlin Parks require an API key");
        this[s_apiKey] = options.api_key;
        if (!options.initial_data_version) throw new Error("Merlin Parks require an initial data version to fetch ride names");
        this[s_dataVersion] = options.initial_data_version;

        // app version options (optionally overriden)
        this[s_appBuild] = options.app_build || "5";
        this[s_appVersion] = options.app_version || "1.0.1";
        this[s_deviceID] = options.device_id || "123";

        // default base API
        this[s_apiBase] = options.api_base || "https://api.attractions.io/v1/";
        this[s_calendarURLBase] = options.calendar_base || "https://www.thorpepark.com/";

        // cache times
        this[s_deviceTokenCacheTime] = options.device_token_cachetime || 86400000; // default: 24 hours
        this[s_userIDCacheTime] = options.user_id_cachetime || 43200000; // default: 12 hours
        this[s_dataCacheTime] = options.data_cachetime || 43200000; // default: 12 hours
    }

    /**
     * Get the API Base URL
     */
    get APIBase() {
        return this[s_apiBase];
    }

    FetchWaitTimes() {
        // first, make sure we have our park data (ride names etc.)
        return this.GetParkData().then((rideNames) => {
            // fetch wait times
            return this.MakeAPICall({
                url: `${this.APIBase}live-data`
            }).then((data) => {
                for (var i = 0, ride; ride = data.entities.Item.records[i++];) {
                    // apply each wait time data
                    var rideObject = this.GetRideObject({
                        id: ride._id,
                        name: rideNames[ride._id],
                    });

                    if (!rideObject) {
                        this.Log(`Failed to find ride with ID ${ride.id}`);
                    } else {
                        // update ride wait time (wait times are in seconds in this API!)
                        rideObject.WaitTime = ride.IsOpen ? (ride.QueueTime / 60) : -1;
                    }
                }

                return Promise.resolve();
            });
        });
    }

    /**
     * Get an API token from cache or through registering a new device
     */
    RegisterDevice() {
        // fetch new device token if we haven't already got one in our cache
        return this.Cache.Wrap("device_token", () => {
            // first, get (or generate) a new user ID
            return this.GenerateUserID().then((user_id) => {
                // request token for further API requests
                return this.HTTP({
                    url: `${this[s_apiBase]}installation`,
                    method: "POST",
                    data: {
                        user_identifier: user_id,
                        device_identifier: this[s_deviceID],
                        app_version: this[s_appVersion],
                        app_build: this[s_appBuild]
                    },
                    headers: {
                        "occasio-platform": "Android",
                        "occasio-platform-version": "6.0.1",
                        "occasio-app-build": this[s_appBuild],
                        "authorization": `Attractions-Io api-key "${this[s_apiKey]}"`,
                    }
                }).then((data) => {
                    if (data && data.token) {
                        return Promise.resolve(data.token);
                    }

                    return Promise.reject("No data returned");
                });
            });
        }, this[s_deviceTokenCacheTime]);
    }

    /**
     * Generate (or fetch a cached) user ID
     */
    GenerateUserID() {
        return this.Cache.Wrap("user_id", () => {
            // generate new UUID if cache hit fails
            const newUserID = uuid();

            this.Log(`Generated new UserID ${newUserID}`);

            return Promise.resolve(newUserID);
        }, this[s_userIDCacheTime]);
    }

    /**
     * Get (or fetch new) park data
     */
    GetParkData() {
        return this.Cache.Wrap("data", () => {
            // fetch fresh/updated data
            return this.FetchParkData(this.DataVersion).then((data) => {
                var rideData = {};
                for (var i = 0, item; item = data.Item[i++];) {
                    rideData[item._id] = item.Name;
                }
                return Promise.resolve(rideData);
            });
        }, this[s_dataCacheTime]);
    }

    /**
     * Get the latest data version timestamp
     */
    get DataVersion() {
        return this[s_dataVersion];
    }

    /**
     * Fetch/Sync park data
     * Warning: full sync is ~30MB
     */
    FetchParkData(version) {
        // this is a recursive function, and will keep fetching data until we get no more deltas to resolve
        //  note: we should attempt to periodically update the initialVersion to cut down on these requests

        // remember this as the latest version for next fetch
        this[s_dataVersion] = version;

        // Fetch data
        return this.MakeAPICall({
            url: `${this[s_apiBase]}data`,
            data: {
                version: version
            },
            // we want the full response to get the status code
            returnFullResponse: true,
        }).then((response) => {
            if (response.statusCode == 304) {
                // reject
                this.Log(`Reached status 304 accessing data version ${version}`);
                return Promise.reject();
            } else {
                this.Log(`Received data for version ${version}`);

                return new Promise((resolve, reject) => {
                    // unzip data
                    unzip.fromBuffer(response.body, {
                        lazyEntries: true
                    }, (err, zip) => {
                        var manifestData;
                        var recordsData;

                        this.Log("Parsing zip file");
                        if (err) {
                            return reject(err);
                        }

                        const GetNextEntry = () => {
                            if (manifestData && recordsData) {
                                // got both the files we need, stop reading the zip file

                                // fetch next data URL
                                if (manifestData.version) {
                                    this.FetchParkData(manifestData.version).catch(() => {
                                        // as soon as we hit an error, return the current level or records data
                                        return resolve(recordsData);
                                    });
                                } else {
                                    return resolve(recordsData);
                                }
                            } else {
                                // read next entry
                                zip.readEntry();
                            }
                        };

                        zip.on("entry", (file) => {
                            this.Log(`Got zip file ${file.fileName}`);

                            // look for the two files we want
                            if (file.fileName == "manifest.json") {
                                ReadZipFile(zip, file).then((data) => {
                                    manifestData = data;

                                    GetNextEntry();
                                });
                            } else if (file.fileName == "records.json") {
                                ReadZipFile(zip, file).then((data) => {
                                    recordsData = data;

                                    GetNextEntry();
                                });
                            } else {
                                GetNextEntry();
                            }
                        });

                        // start reading file...
                        zip.readEntry();
                    });
                });
            }
        });
    }

    /**
     * Generic API request function, will sort out API token and send auth headers
     * @param {*} options
     * @param {String} options.url URL to access
     * @param {String} [options.method=GET] method to use
     * @param {Object} [options.data={}] data/query string to use
     */
    MakeAPICall(options = {
        method: "GET",
        data: {}
    }) {
        // get token
        return this.RegisterDevice().then((token) => {
            // inject auth headers into request headers
            if (!options.headers) {
                options.headers = {};
            }
            options.headers["occasio-platform"] = "Android";
            options.headers["occasio-platform-version"] = "6.0.1";
            options.headers["occasio-app-build"] = this[s_appBuild];
            options.headers["authorization"] = `Attractions-Io api-key "${this[s_apiKey]}", installation-token="${token}"`;

            // make API call
            return this.HTTP(options);
        });
    }

    FetchOpeningTimes() {
        return new Promise((resolve, reject) => {
            this.HTTP({
                url: `${this[s_calendarURLBase]}Umbraco/Api/Calendar/GetAllOpeningTimes`,
                method: "GET",
                headers: {
                    "Referer": this[s_calendarURLBase],
                    "X-Requested-With": "XMLHttpRequest",
                }
            }).then((calendarData) => {
                // find theme park dates from response
                //  it contains "WatterPark"[sic] times as well in a separate array
                var parkDates = null;
                if (calendarData[0] && calendarData[0].Type) {
                    // for resorts with multiple parks (Alton Towers)
                    for (var i = 0, times; times = calendarData[i++];) {
                        if (times.Type == "ThemePark") {
                            parkDates = times.OpeningHours;
                            break;
                        }
                    }
                } else if (calendarData[0].Open) {
                    // resorts with only 1 park (Thorpe Park)
                    parkDates = calendarData;
                } else {
                    return reject("Invalid/Unknown calendar data returned");
                }

                var result, timeRange;
                for (i = 0, timeRange; timeRange = parkDates[i++];) {
                    var range = {
                        startDate: Moment(timeRange.From, "YYYY-MM-DDTHH:mm:ss"),
                        endDate: Moment(timeRange.To, "YYYY-MM-DDTHH:mm:ss")
                    };

                    this.Log(`Processing ${range.startDate} => ${range.endDate}`);

                    // figure out opening times for this range
                    if (result = /([0-9:]+\s?[ap]m)\s*-\s*([0-9:]+\s?[ap]m)/gi.exec(timeRange.Open.replace(/\./g, ":"))) {
                        range.openingTime = Moment(result[1].replace(/ /g, ""), "HH:mma");
                        range.closingTime = Moment(result[2].replace(/ /g, ""), "HH:mma");
                    }
                    // try shorthand format too, in case someone entered the times in badly
                    else if (result = /([0-9]+)\s*-\s*([0-9]+)/gi.exec(timeRange.Open.replace(/\./g, ":"))) {
                        range.openingTime = Moment(result[1] + ":00am", "HH:mma");
                        range.closingTime = Moment(result[2] + ":00pm", "HH:mma");
                    } else {
                        this.Log(`Unable to understand hour format: ${timeRange.Open}`);
                        continue;
                    }

                    // apply this range
                    this.Schedule.SetRange(range);
                }

                resolve();
            }, reject);
        });
    }
}

// export the class
module.exports = MerlinPark;

// static functions
function ReadZipFile(zip, file) {
    return new Promise((resolve, reject) => {
        var data = "";
        zip.openReadStream(file, function (err, readStream) {
            if (err) {
                return reject(err);
            }

            readStream.on("data", function (chunk) {
                data += chunk;
            }).on("end", function () {
                // parse JSON data
                try {
                    data = JSON.parse(data);
                    return resolve(data);
                } catch (e) {
                    return reject(`JSON parse error extracting ${file.fileName}: ${e}`);
                }
            });
        });
    });
}<|endoftext|>


<commit_before>define([
	'goo/fsmpack/statemachine/actions/Action',
	'goo/math/Vector3'
], function (
	Action,
	Vector3
) {
	'use strict';

	function MoveAction(/*id, settings*/) {
		Action.apply(this, arguments);
	}

	MoveAction.prototype = Object.create(Action.prototype);
	MoveAction.prototype.constructor = MoveAction;

	MoveAction.external = {
		name: 'Move',
		type: 'animation',
		description: 'Moves the entity',
		parameters: [{
			name: 'Translation',
			key: 'translation',
			type: 'position',
			description: 'Move',
			'default': [0, 0, 0]
		}, {
			name: 'Oriented',
			key: 'oriented',
			type: 'boolean',
			description: 'If true translate with rotation',
			'default': true
		}, {
			name: 'Relative',
			key: 'relative',
			type: 'boolean',
			description: 'If true add to current translation',
			'default': true
		}, {
			name: 'On every frame',
			key: 'everyFrame',
			type: 'boolean',
			description: 'Repeat this action every frame',
			'default': true
		}],
		transitions: []
	};

	MoveAction.prototype._setup = function (fsm) {
		var entity = fsm.getOwnerEntity();
		var transform = entity.transformComponent.transform;
		this.forward = Vector3.fromArray(this.translation);
		var orientation = transform.rotation;
		orientation.applyPost(this.forward);
	};

	MoveAction.prototype._run = function (fsm) {
		var entity = fsm.getOwnerEntity();
		var transform = entity.transformComponent.transform;
		var translation = transform.translation;

		if (this.oriented) {
			if (this.relative) {
				var forward = Vector3.fromArray(this.translation);
				var orientation = transform.rotation;
				orientation.applyPost(forward);

				if (this.everyFrame) {
					forward.scale(fsm.getTpf() * 10);
					translation.add(forward);
				} else {
					translation.add(forward);
				}
			} else {
				translation.set(this.forward);
			}
		} else {
			if (this.relative) {
				if (this.everyFrame) {
					var tpf = fsm.getTpf() * 10;
					translation.addDirect(this.translation[0], this.translation[1], this.translation[2])
						.scale(tpf);
				} else {
					translation.addDirect(this.translation[0], this.translation[1], this.translation[2]);
				}
			} else {
				translation.setDirect(this.translation[0], this.translation[1], this.translation[2]);
			}
		}

		entity.transformComponent.setUpdated();
	};

	return MoveAction;
});<commit_msg>not use deprecated applyPost in MoveAction<commit_after>define([
	'goo/fsmpack/statemachine/actions/Action',
	'goo/math/Vector3'
], function (
	Action,
	Vector3
) {
	'use strict';

	function MoveAction(/*id, settings*/) {
		Action.apply(this, arguments);
	}

	MoveAction.prototype = Object.create(Action.prototype);
	MoveAction.prototype.constructor = MoveAction;

	MoveAction.external = {
		name: 'Move',
		type: 'animation',
		description: 'Moves the entity',
		parameters: [{
			name: 'Translation',
			key: 'translation',
			type: 'position',
			description: 'Move',
			'default': [0, 0, 0]
		}, {
			name: 'Oriented',
			key: 'oriented',
			type: 'boolean',
			description: 'If true translate with rotation',
			'default': true
		}, {
			name: 'Relative',
			key: 'relative',
			type: 'boolean',
			description: 'If true add to current translation',
			'default': true
		}, {
			name: 'On every frame',
			key: 'everyFrame',
			type: 'boolean',
			description: 'Repeat this action every frame',
			'default': true
		}],
		transitions: []
	};

	MoveAction.prototype._setup = function (fsm) {
		var entity = fsm.getOwnerEntity();
		var transform = entity.transformComponent.transform;
		this.forward = Vector3.fromArray(this.translation);
		var orientation = transform.rotation;
		this.forward.applyPost(orientation);
	};

	MoveAction.prototype._run = function (fsm) {
		var entity = fsm.getOwnerEntity();
		var transform = entity.transformComponent.transform;
		var translation = transform.translation;

		if (this.oriented) {
			if (this.relative) {
				var forward = Vector3.fromArray(this.translation);
				var orientation = transform.rotation;
				forward.applyPost(orientation);

				if (this.everyFrame) {
					forward.scale(fsm.getTpf() * 10);
					translation.add(forward);
				} else {
					translation.add(forward);
				}
			} else {
				translation.set(this.forward);
			}
		} else {
			if (this.relative) {
				if (this.everyFrame) {
					var tpf = fsm.getTpf() * 10;
					translation.addDirect(this.translation[0], this.translation[1], this.translation[2])
						.scale(tpf);
				} else {
					translation.addDirect(this.translation[0], this.translation[1], this.translation[2]);
				}
			} else {
				translation.setDirect(this.translation[0], this.translation[1], this.translation[2]);
			}
		}

		entity.transformComponent.setUpdated();
	};

	return MoveAction;
});<|endoftext|>


<commit_before>(function(tree) {

tree.Ruleset = function(selectors, rules) {
    this.selectors = selectors;
    this.rules = rules;
    this._lookups = {};
};
tree.Ruleset.prototype = {
    eval: function(env) {
        var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0));

        ruleset.root = this.root;

        // push the current ruleset to the frames stack
        env.frames.unshift(ruleset);

        // Evaluate imports
        if (ruleset.root) {
            for (var i = 0; i < ruleset.rules.length; i++) {
                if (ruleset.rules[i] instanceof tree.Import) {
                    Array.prototype.splice
                         .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
                }
            }
        }

        // Store the frames around mixin definitions,
        // so they can be evaluated like closures when the time comes.
        for (var i = 0; i < ruleset.rules.length; i++) {
            if (ruleset.rules[i] instanceof tree.mixin.Definition) {
                ruleset.rules[i].frames = env.frames.slice(0);
            }
        }

        // Evaluate mixin calls.
        for (var i = 0; i < ruleset.rules.length; i++) {
            if (ruleset.rules[i] instanceof tree.mixin.Call) {
                Array.prototype.splice
                     .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
            }
        }

        // Evaluate everything else
        for (var i = 0, rule; i < ruleset.rules.length; i++) {
            rule = ruleset.rules[i];

            if (! (rule instanceof tree.mixin.Definition)) {
                ruleset.rules[i] = rule.eval ? rule.eval(env) : rule;
            }
        }

        // Pop the stack
        env.frames.shift();

        return ruleset;
    },
    match: function(args) {
        return !args || args.length === 0;
    },
    variables: function() {
        if (this._variables) { return this._variables }
        else {
            return this._variables = this.rules.reduce(function(hash, r) {
                if (r instanceof tree.Rule && r.variable === true) {
                    hash[r.name] = r;
                }
                return hash;
            }, {});
        }
    },
    variable: function(name) {
        return this.variables()[name];
    },
    rulesets: function() {
        if (this._rulesets) { return this._rulesets }
        else {
            return this._rulesets = this.rules.filter(function(r) {
                return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
            });
        }
    },
    find: function(selector, self) {
        self = self || this;
        var rules = [], rule, match,
            key = selector.toCSS();

        if (key in this._lookups) { return this._lookups[key] }

        this.rulesets().forEach(function(rule) {
            if (rule !== self) {
                for (var j = 0; j < rule.selectors.length; j++) {
                    if (match = selector.match(rule.selectors[j])) {
                        if (selector.elements.length > 1) {
                            Array.prototype.push.apply(rules, rule.find(
                                new(tree.Selector)(selector.elements.slice(1)), self));
                        } else {
                            rules.push(rule);
                        }
                        break;
                    }
                }
            }
        });
        return this._lookups[key] = rules;
    },
    //
    // Entry point for code generation
    //
    //     `context` holds an array of arrays.
    //
    toCSS: function(context, env) {
        var css = [],      // The CSS output
            rules = [],    // node.Rule instances
            rulesets = [], // node.Ruleset instances
            paths = [],    // Current selectors
            selector,      // The fully rendered selector
            symbolizers = {},
            rule;

        if (! this.root) {
            if (context.length === 0) {
                paths = this.selectors.map(function(s) { return [s] });
            } else {
                for (var s = 0; s < this.selectors.length; s++) {
                    for (var c = 0; c < context.length; c++) {
                        paths.push(context[c].concat([this.selectors[s]]));
                    }
                }
            }
        }

        // Compile rules and rulesets
        for (var i = 0; i < this.rules.length; i++) {
            rule = this.rules[i];

            if (rule.rules || (rule instanceof tree.Directive)) {
                rulesets.push(rule.toCSS(paths, env));
            } else if (rule instanceof tree.Comment) {
                if (!rule.silent) {
                    if (this.root) {
                        rulesets.push(rule.toCSS(env));
                    } else {
                        rules.push(rule.toCSS(env));
                    }
                }
            } else {
                if (rule.toCSS && !rule.variable) {
                    if (!symbolizers[rule.symbolizer]) {
                        symbolizers[rule.symbolizer] = {};
                    }
                    symbolizers[rule.symbolizer][rule.name] = rule.toCSS(env);
                    rules.push(rule.toCSS(env));
                } else if (rule.value && !rule.variable) {
                    rules.push(rule.value.toString());
                }
            }
        }

        rulesets = rulesets.join('');

        // If this is the root node, we don't render
        // a selector, or {}.
        // Otherwise, only output if this ruleset has rules.
        if (this.root) {
            css.push(rules.join(env.compress ? '' : '\n'));
        } else {
            if (rules.length > 0) {
                selector = paths.map(function(p) {
                    return p.map(function(s) {
                        return s.toCSS(env);
                    }).join('').trim();
                }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', '));

                filters = (function(paths) {
                    var out = [];
                    paths.forEach(function(path) {
                        path.forEach(function(selector) {
                            selector.filters.forEach(function(filter) {
                                out.push(filter.toCSS());
                            });
                        });
                    });
                    return out;
                })(paths);

                if (symbolizers) {
                    rules = (function(symbolizers) {
                        var out = [];
                        for (i in symbolizers) {
                            if (i.indexOf('-') > 0) {
                                var splitat = i.indexOf('-');
                                var symname = i.charAt(0).toUpperCase() +
                                    i.slice(1,splitat) +
                                    i.charAt(splitat+1).toUpperCase() +
                                    i.slice(splitat+2) + 'Symbolizer';
                            } else {
                                var symname = i.charAt(0).toUpperCase() +
                                    i.slice(1) + 'Symbolizer';
                            }
                           // TODO: replace with _.values when underscore is included
                           sym = [];
                           prop_names = [];
                           for (j in symbolizers[i]) {
                               sym.push(symbolizers[i][j]);
                               prop_names.push(j);
                           }
                           if (err = tree.Reference.requiredProperties(i, prop_names)) {
                                throw {
                                    message: err
                                };
                           }

                           out.push('      <' +
                               symname + ' ' +
                               sym.join('\n       ') +
                               '/>');
                        }
                        return out;
                    })(symbolizers);
                }
                if (this.selectors[0].elements[0].value !== 'Map') {
                      css.push('\n  <Style name="' +
                            selector +
                            '">\n    <Rule>\n      ' +
                            filters.join('\n') + '\n' +
                            rules.join('\n') +
                            '\n    </Rule>\n' +
                            '  </Style>\n');
                }
            }
        }
        css.push(rulesets);

        return css.join('') + (env.compress ? '\n' : '');
    }
};
})(require('mess/tree'));
<commit_msg>Coalesce symbol-shorthand-to-symbolizer functionality<commit_after>(function(tree) {

tree.Ruleset = function(selectors, rules) {
    this.selectors = selectors;
    this.rules = rules;
    this._lookups = {};
};
tree.Ruleset.prototype = {
    eval: function(env) {
        var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0));

        ruleset.root = this.root;

        // push the current ruleset to the frames stack
        env.frames.unshift(ruleset);

        // Evaluate imports
        if (ruleset.root) {
            for (var i = 0; i < ruleset.rules.length; i++) {
                if (ruleset.rules[i] instanceof tree.Import) {
                    Array.prototype.splice
                         .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
                }
            }
        }

        // Store the frames around mixin definitions,
        // so they can be evaluated like closures when the time comes.
        for (var i = 0; i < ruleset.rules.length; i++) {
            if (ruleset.rules[i] instanceof tree.mixin.Definition) {
                ruleset.rules[i].frames = env.frames.slice(0);
            }
        }

        // Evaluate mixin calls.
        for (var i = 0; i < ruleset.rules.length; i++) {
            if (ruleset.rules[i] instanceof tree.mixin.Call) {
                Array.prototype.splice
                     .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
            }
        }

        // Evaluate everything else
        for (var i = 0, rule; i < ruleset.rules.length; i++) {
            rule = ruleset.rules[i];

            if (! (rule instanceof tree.mixin.Definition)) {
                ruleset.rules[i] = rule.eval ? rule.eval(env) : rule;
            }
        }

        // Pop the stack
        env.frames.shift();

        return ruleset;
    },
    match: function(args) {
        return !args || args.length === 0;
    },
    variables: function() {
        if (this._variables) { return this._variables }
        else {
            return this._variables = this.rules.reduce(function(hash, r) {
                if (r instanceof tree.Rule && r.variable === true) {
                    hash[r.name] = r;
                }
                return hash;
            }, {});
        }
    },
    variable: function(name) {
        return this.variables()[name];
    },
    rulesets: function() {
        if (this._rulesets) { return this._rulesets }
        else {
            return this._rulesets = this.rules.filter(function(r) {
                return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
            });
        }
    },
    find: function(selector, self) {
        self = self || this;
        var rules = [], rule, match,
            key = selector.toCSS();

        if (key in this._lookups) { return this._lookups[key] }

        this.rulesets().forEach(function(rule) {
            if (rule !== self) {
                for (var j = 0; j < rule.selectors.length; j++) {
                    if (match = selector.match(rule.selectors[j])) {
                        if (selector.elements.length > 1) {
                            Array.prototype.push.apply(rules, rule.find(
                                new(tree.Selector)(selector.elements.slice(1)), self));
                        } else {
                            rules.push(rule);
                        }
                        break;
                    }
                }
            }
        });
        return this._lookups[key] = rules;
    },
    //
    // Entry point for code generation
    //
    //     `context` holds an array of arrays.
    //
    toCSS: function(context, env) {
        var css = [],      // The CSS output
            rules = [],    // node.Rule instances
            rulesets = [], // node.Ruleset instances
            paths = [],    // Current selectors
            selector,      // The fully rendered selector
            symbolizers = {},
            rule;

        if (! this.root) {
            if (context.length === 0) {
                paths = this.selectors.map(function(s) { return [s] });
            } else {
                for (var s = 0; s < this.selectors.length; s++) {
                    for (var c = 0; c < context.length; c++) {
                        paths.push(context[c].concat([this.selectors[s]]));
                    }
                }
            }
        }

        // Compile rules and rulesets
        for (var i = 0; i < this.rules.length; i++) {
            rule = this.rules[i];

            if (rule.rules || (rule instanceof tree.Directive)) {
                rulesets.push(rule.toCSS(paths, env));
            } else if (rule instanceof tree.Comment) {
                if (!rule.silent) {
                    if (this.root) {
                        rulesets.push(rule.toCSS(env));
                    } else {
                        rules.push(rule.toCSS(env));
                    }
                }
            } else {
                if (rule.toCSS && !rule.variable) {
                    if (!symbolizers[rule.symbolizer]) {
                        symbolizers[rule.symbolizer] = {};
                    }
                    symbolizers[rule.symbolizer][rule.name] = rule.toCSS(env);
                    rules.push(rule.toCSS(env));
                } else if (rule.value && !rule.variable) {
                    rules.push(rule.value.toString());
                }
            }
        }

        rulesets = rulesets.join('');

        // If this is the root node, we don't render
        // a selector, or {}.
        // Otherwise, only output if this ruleset has rules.
        if (this.root) {
            css.push(rules.join(env.compress ? '' : '\n'));
        } else {
            if (rules.length > 0) {
                selector = paths.map(function(p) {
                    return p.map(function(s) {
                        return s.toCSS(env);
                    }).join('').trim();
                }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', '));

                filters = (function(paths) {
                    var out = [];
                    paths.forEach(function(path) {
                        path.forEach(function(selector) {
                            selector.filters.forEach(function(filter) {
                                out.push(filter.toCSS());
                            });
                        });
                    });
                    return out;
                })(paths);

                if (symbolizers) {
                    rules = (function(symbolizers) {
                        var out = [];
                        for (i in symbolizers) {
                           var symname = i.charAt(0).toUpperCase()
                               + i.slice(1).replace(/\-./, function(str) {
                               return str[1].toUpperCase();
                           }) + 'Symbolizer';
                           // TODO: replace with _.values when underscore is included
                           sym = [];
                           prop_names = [];
                           for (j in symbolizers[i]) {
                               sym.push(symbolizers[i][j]);
                               prop_names.push(j);
                           }
                           if (err = tree.Reference.requiredProperties(i, prop_names)) {
                                throw {
                                    message: err
                                };
                           }

                           out.push('      <' +
                               symname + ' ' +
                               sym.join('\n       ') +
                               '/>');
                        }
                        return out;
                    })(symbolizers);
                }
                if (this.selectors[0].elements[0].value !== 'Map') {
                      css.push('\n  <Style name="' +
                            selector +
                            '">\n    <Rule>\n      ' +
                            filters.join('\n') + '\n' +
                            rules.join('\n') +
                            '\n    </Rule>\n' +
                            '  </Style>\n');
                }
            }
        }
        css.push(rulesets);

        return css.join('') + (env.compress ? '\n' : '');
    }
};
})(require('mess/tree'));
<|endoftext|>


<commit_before>$(document).ready(function(){

  $('#tmpltzr').width( window.innerWidth - 400 );

  $(".owl-carousel").owlCarousel({
    items : 3,
    slideSpeed : 1000,
    autoPlay : true,
    stopOnHover : true,
    responsive: true,
    responsiveRefreshRate : 200,
    responsiveBaseWidth: 800

  });

});
<commit_msg>basewidth<commit_after>$(document).ready(function(){

  $('#tmpltzr').width( window.innerWidth - 400 );

  $(".owl-carousel").owlCarousel({
    items : 3,
    slideSpeed : 1000,
    autoPlay : true,
    stopOnHover : true,
    responsive: true,
    responsiveRefreshRate : 200,
    responsiveBaseWidth: window

  });

});
<|endoftext|>


<commit_before>/**
 * messageformat.js
 *
 * ICU PluralFormat + SelectFormat for JavaScript
 *
 * @author Alex Sexton - @SlexAxton
 * @version 0.1.7
 * @license WTFPL
 * @contributor_license Dojo CLA
*/
(function ( root ) {

  // Create the contructor function
  function MessageFormat ( locale, pluralFunc ) {
    var fallbackLocale;

    if ( locale && pluralFunc ) {
      MessageFormat.locale[ locale ] = pluralFunc;
    }

    // Defaults
    fallbackLocale = locale = locale || "en";
    pluralFunc = pluralFunc || MessageFormat.locale[ fallbackLocale = MessageFormat.Utils.getFallbackLocale( locale ) ];

    if ( ! pluralFunc ) {
      throw new Error( "Plural Function not found for locale: " + locale );
    }

    // Own Properties
    this.pluralFunc = pluralFunc;
    this.locale = locale;
    this.fallbackLocale = fallbackLocale;
  }

  // methods in common with the generated MessageFormat
  MessageFormat.check_d = function(d){
    if(!d){throw new Error("MessageFormat: No data passed to function.")}
  };
  MessageFormat.num = function(x, key){
    if(isNaN(x)){throw new Error("MessageFormat: `"+key+"` isnt a number.")}
    return x;
  };
  MessageFormat.plural = function(p, k, o, d, l){
    return (p[k+""] || p[MessageFormat.locale[l](k-o)] || p["other"])(d);
  };

  // Set up the locales object. Add in english by default
  MessageFormat.locale = {
    "en" : function ( n ) {
      if ( n === 1 ) {
        return "one";
      }
      return "other";
    }
  };

  // Build out our basic SafeString type
  // more or less stolen from Handlebars by @wycats
  MessageFormat.SafeString = function( string ) {
    this.string = string;
  };

  MessageFormat.SafeString.prototype.toString = function () {
    return this.string.toString();
  };

  MessageFormat.Utils = {
    numSub : function ( string, key, depth ) {
      // make sure that it's not an escaped octothorpe
      return string.replace( /^#|[^\\]#/g, function (m) {
        var prefix = m && m.length === 2 ? m.charAt(0) : '';
        return prefix + '" + MessageFormat.num(' + key + ',lastkey_' + depth + ') + "';
      });
    },
    escapeExpression : function (string) {
      var escape = {
            "\n": "\\n",
            "\"": '\\"'
          },
          badChars = /[\n"]/g,
          possible = /[\n"]/,
          escapeChar = function(chr) {
            return escape[chr] || "&";
          };

      // Don't escape SafeStrings, since they're already safe
      if ( string instanceof MessageFormat.SafeString ) {
        return string.toString();
      }
      else if ( string === null || string === false ) {
        return "";
      }

      if ( ! possible.test( string ) ) {
        return string;
      }
      return string.replace( badChars, escapeChar );
    },
    getFallbackLocale: function( locale ) {
      var tagSeparator = locale.indexOf("-") >= 0 ? "-" : "_";

      // Lets just be friends, fallback through the language tags
      while ( ! MessageFormat.locale.hasOwnProperty( locale ) ) {
        locale = locale.substring(0, locale.lastIndexOf( tagSeparator ));
        if (locale.length === 0) {
          return null;
        }
      }

      return locale;
    }
  };

  var mparser = require( './message_parser' );

  MessageFormat.prototype.parse = function () {
    // Bind to itself so error handling works
    return mparser.parse.apply( mparser, arguments );
  };

  MessageFormat.prototype.precompile = function ( ast ) {
    var self = this,
        needOther = false;

    function interpMFP ( ast, data ) {
      // Set some default data
      data = data || {};
      var s = '', i, tmp, lastkeyname;

      switch ( ast.type ) {
        case 'program':
          return interpMFP( ast.program );
        case 'messageFormatPattern':
          for ( i = 0; i < ast.statements.length; ++i ) {
            s += interpMFP( ast.statements[i], data );
          }
          if ( /^r \+=/.test(s) ) {
            tmp = /^(r \+= (.+)\n)?$/.exec(s);
            if ( tmp ) {
              s = 'return ' + (tmp[2] || '"";');
            } else {
              s = s.replace(/^r \+=/, 'var r =') + 'return r;\n';
            }
          } else {
            s = s ? 'var r = "";\n' + s + 'return r;\n' : 'return "";';
          }
          if ( data.check_d && !data.pf_count ) {
            s = 'MessageFormat.check_d(d);\n' + s;
            data.check_d = false;
          }
          return 'function(d){' + (s.indexOf('\n') !== -1 ? '\n' : '') + s + '}';
        case 'messageFormatPatternRight':
          for ( i = 0; i < ast.statements.length; ++i ) {
            s += interpMFP( ast.statements[i], data );
          }
          return s;
        case 'messageFormatElement':
          data.pf_count = data.pf_count || 0;
          if ( ast.output ) {
            s += 'r += d["' + ast.argumentIndex + '"];\n';
          }
          else {
            lastkeyname = 'lastkey_'+(data.pf_count+1);
            s += 'var '+lastkeyname+' = "'+ast.argumentIndex+'";\n';
            s += 'var k_'+(data.pf_count+1)+'=d['+lastkeyname+'];\n';
            s += interpMFP( ast.elementFormat, data );
          }
          data.check_d = true;
          return s;
        case 'elementFormat':
          if ( ast.key === 'select' ) {
            s += interpMFP( ast.val, data );
            s += 'r += (pf_' +
                 data.pf_count +
                 '[ k_' + (data.pf_count+1) + ' ] || pf_'+data.pf_count+'[ "other" ])( d );\n';
          }
          else if ( ast.key === 'plural' ) {
            s += interpMFP( ast.val, data );
            s += 'r += MessageFormat.plural(pf_' + data.pf_count + ',k_' + (data.pf_count+1)
              + ',off_' + data.pf_count + ',d,"' + self.fallbackLocale + '");\n';
          }
          return s;
        /* // Unreachable cases.
        case 'pluralStyle':
        case 'selectStyle':*/
        case 'pluralFormatPattern':
          data.pf_count = data.pf_count || 0;
          s += 'var off_'+data.pf_count+' = '+ast.offset+';\n';
          s += 'var pf_' + data.pf_count + ' = { \n';
          needOther = true;
          // We're going to simultaneously check to make sure we hit the required 'other' option.

          for ( i = 0; i < ast.pluralForms.length; ++i ) {
            if ( ast.pluralForms[ i ].key === 'other' ) {
              needOther = false;
            }
            if ( tmp ) {
              s += ',\n';
            }
            else{
              tmp = 1;
            }
            s += '"' + ast.pluralForms[ i ].key + '" : ' + interpMFP( ast.pluralForms[ i ].val,
          (function(){ var res = JSON.parse(JSON.stringify(data)); res.pf_count++; return res; })() );
          }
          s += '\n};\n';
          if ( needOther ) {
            throw new Error("No 'other' form found in pluralFormatPattern " + data.pf_count);
          }
          return s;
        case 'selectFormatPattern':

          data.pf_count = data.pf_count || 0;
          s += 'var off_'+data.pf_count+' = 0;\n';
          s += 'var pf_' + data.pf_count + ' = { \n';
          needOther = true;

          for ( i = 0; i < ast.pluralForms.length; ++i ) {
            if ( ast.pluralForms[ i ].key === 'other' ) {
              needOther = false;
            }
            if ( tmp ) {
              s += ',\n';
            }
            else{
              tmp = 1;
            }
            s += '"' + ast.pluralForms[ i ].key + '" : ' + interpMFP( ast.pluralForms[ i ].val,
              (function(){
                var res = JSON.parse( JSON.stringify( data ) );
                res.pf_count++;
                return res;
              })()
            );
          }
          s += '\n};\n';
          if ( needOther ) {
            throw new Error("No 'other' form found in selectFormatPattern " + data.pf_count);
          }
          return s;
        /* // Unreachable
        case 'pluralForms':
        */
        case 'string':
          tmp = MessageFormat.Utils.escapeExpression( ast.val );
          if ( data.pf_count ) {
            tmp = MessageFormat.Utils.numSub( tmp,
              'k_' + data.pf_count + ' - off_' + ( data.pf_count - 1 ),
              data.pf_count
            );
          }
          return 'r += "' + tmp + '";\n';
        default:
          throw new Error( 'Bad AST type: ' + ast.type );
      }
    }
    return interpMFP( ast );
  };

  MessageFormat.prototype.compile = function ( message ) {
    return (new Function( 'MessageFormat',
      'return ' +
        this.precompile(
          this.parse( message )
        )
    ))(MessageFormat);
  };

  if (typeof exports !== 'undefined') {
    if (typeof module !== 'undefined' && module.exports) {
      exports = module.exports = MessageFormat;
    }
    exports.MessageFormat = MessageFormat;
  }
  else if (typeof define === 'function' && define.amd) {
    define(function() {
      return MessageFormat;
    });
  }
  else {
    root['MessageFormat'] = MessageFormat;
  }

})( this );
<commit_msg>got rid of lastkey_# in output, using new data.key<commit_after>/**
 * messageformat.js
 *
 * ICU PluralFormat + SelectFormat for JavaScript
 *
 * @author Alex Sexton - @SlexAxton
 * @version 0.1.7
 * @license WTFPL
 * @contributor_license Dojo CLA
*/
(function ( root ) {

  // Create the contructor function
  function MessageFormat ( locale, pluralFunc ) {
    var fallbackLocale;

    if ( locale && pluralFunc ) {
      MessageFormat.locale[ locale ] = pluralFunc;
    }

    // Defaults
    fallbackLocale = locale = locale || "en";
    pluralFunc = pluralFunc || MessageFormat.locale[ fallbackLocale = MessageFormat.Utils.getFallbackLocale( locale ) ];

    if ( ! pluralFunc ) {
      throw new Error( "Plural Function not found for locale: " + locale );
    }

    // Own Properties
    this.pluralFunc = pluralFunc;
    this.locale = locale;
    this.fallbackLocale = fallbackLocale;
  }

  // methods in common with the generated MessageFormat
  MessageFormat.check_d = function(d){
    if(!d){throw new Error("MessageFormat: No data passed to function.")}
  };
  MessageFormat.num = function(x, key){
    if(isNaN(x)){throw new Error("MessageFormat: `"+key+"` isnt a number.")}
    return x;
  };
  MessageFormat.plural = function(p, k, o, d, l){
    return (p[k+""] || p[MessageFormat.locale[l](k-o)] || p["other"])(d);
  };

  // Set up the locales object. Add in english by default
  MessageFormat.locale = {
    "en" : function ( n ) {
      if ( n === 1 ) {
        return "one";
      }
      return "other";
    }
  };

  // Build out our basic SafeString type
  // more or less stolen from Handlebars by @wycats
  MessageFormat.SafeString = function( string ) {
    this.string = string;
  };

  MessageFormat.SafeString.prototype.toString = function () {
    return this.string.toString();
  };

  MessageFormat.Utils = {
    numSub : function ( string, key, name ) {
      // make sure that it's not an escaped octothorpe
      return string.replace( /^#|[^\\]#/g, function (m) {
        var prefix = m && m.length === 2 ? m.charAt(0) : '';
        return prefix + '" + MessageFormat.num(' + key + ',' + name + ') + "';
      });
    },
    escapeExpression : function (string) {
      var escape = {
            "\n": "\\n",
            "\"": '\\"'
          },
          badChars = /[\n"]/g,
          possible = /[\n"]/,
          escapeChar = function(chr) {
            return escape[chr] || "&";
          };

      // Don't escape SafeStrings, since they're already safe
      if ( string instanceof MessageFormat.SafeString ) {
        return string.toString();
      }
      else if ( string === null || string === false ) {
        return "";
      }

      if ( ! possible.test( string ) ) {
        return string;
      }
      return string.replace( badChars, escapeChar );
    },
    getFallbackLocale: function( locale ) {
      var tagSeparator = locale.indexOf("-") >= 0 ? "-" : "_";

      // Lets just be friends, fallback through the language tags
      while ( ! MessageFormat.locale.hasOwnProperty( locale ) ) {
        locale = locale.substring(0, locale.lastIndexOf( tagSeparator ));
        if (locale.length === 0) {
          return null;
        }
      }

      return locale;
    }
  };

  var mparser = require( './message_parser' );

  MessageFormat.prototype.parse = function () {
    // Bind to itself so error handling works
    return mparser.parse.apply( mparser, arguments );
  };

  MessageFormat.prototype.precompile = function ( ast ) {
    var self = this,
        needOther = false;

    function interpMFP ( ast, data ) {
      // Set some default data
      data = data || {};
      var s = '', i, tmp;

      switch ( ast.type ) {
        case 'program':
          return interpMFP( ast.program );
        case 'messageFormatPattern':
          for ( i = 0; i < ast.statements.length; ++i ) {
            s += interpMFP( ast.statements[i], data );
          }
          if ( /^r \+=/.test(s) ) {
            tmp = /^(r \+= (.+)\n)?$/.exec(s);
            if ( tmp ) {
              s = 'return ' + (tmp[2] || '"";');
            } else {
              s = s.replace(/^r \+=/, 'var r =') + 'return r;\n';
            }
          } else {
            s = s ? 'var r = "";\n' + s + 'return r;\n' : 'return "";';
          }
          if ( data.check_d && !data.pf_count ) {
            s = 'MessageFormat.check_d(d);\n' + s;
            data.check_d = false;
          }
          return 'function(d){' + (s.indexOf('\n') !== -1 ? '\n' : '') + s + '}';
        case 'messageFormatPatternRight':
          for ( i = 0; i < ast.statements.length; ++i ) {
            s += interpMFP( ast.statements[i], data );
          }
          return s;
        case 'messageFormatElement':
          data.pf_count = data.pf_count || 0;
          if ( ast.output ) {
            s += 'r += d["' + ast.argumentIndex + '"];\n';
          }
          else {
            data.key = '"' + ast.argumentIndex + '"';
            s += 'var k_'+(data.pf_count+1)+'=d['+data.key+'];\n';
            s += interpMFP( ast.elementFormat, data );
          }
          data.check_d = true;
          return s;
        case 'elementFormat':
          if ( ast.key === 'select' ) {
            s += interpMFP( ast.val, data );
            s += 'r += (pf_' +
                 data.pf_count +
                 '[ k_' + (data.pf_count+1) + ' ] || pf_'+data.pf_count+'[ "other" ])( d );\n';
          }
          else if ( ast.key === 'plural' ) {
            s += interpMFP( ast.val, data );
            s += 'r += MessageFormat.plural(pf_' + data.pf_count + ',k_' + (data.pf_count+1)
              + ',off_' + data.pf_count + ',d,"' + self.fallbackLocale + '");\n';
          }
          return s;
        /* // Unreachable cases.
        case 'pluralStyle':
        case 'selectStyle':*/
        case 'pluralFormatPattern':
          data.pf_count = data.pf_count || 0;
          s += 'var off_'+data.pf_count+' = '+ast.offset+';\n';
          s += 'var pf_' + data.pf_count + ' = { \n';
          needOther = true;
          // We're going to simultaneously check to make sure we hit the required 'other' option.

          for ( i = 0; i < ast.pluralForms.length; ++i ) {
            if ( ast.pluralForms[ i ].key === 'other' ) {
              needOther = false;
            }
            if ( tmp ) {
              s += ',\n';
            }
            else{
              tmp = 1;
            }
            s += '"' + ast.pluralForms[ i ].key + '" : ' + interpMFP( ast.pluralForms[ i ].val,
          (function(){ var res = JSON.parse(JSON.stringify(data)); res.pf_count++; return res; })() );
          }
          s += '\n};\n';
          if ( needOther ) {
            throw new Error("No 'other' form found in pluralFormatPattern " + data.pf_count);
          }
          return s;
        case 'selectFormatPattern':

          data.pf_count = data.pf_count || 0;
          s += 'var off_'+data.pf_count+' = 0;\n';
          s += 'var pf_' + data.pf_count + ' = { \n';
          needOther = true;

          for ( i = 0; i < ast.pluralForms.length; ++i ) {
            if ( ast.pluralForms[ i ].key === 'other' ) {
              needOther = false;
            }
            if ( tmp ) {
              s += ',\n';
            }
            else{
              tmp = 1;
            }
            s += '"' + ast.pluralForms[ i ].key + '" : ' + interpMFP( ast.pluralForms[ i ].val,
              (function(){
                var res = JSON.parse( JSON.stringify( data ) );
                res.pf_count++;
                return res;
              })()
            );
          }
          s += '\n};\n';
          if ( needOther ) {
            throw new Error("No 'other' form found in selectFormatPattern " + data.pf_count);
          }
          return s;
        /* // Unreachable
        case 'pluralForms':
        */
        case 'string':
          tmp = MessageFormat.Utils.escapeExpression( ast.val );
          if ( data.pf_count ) {
            tmp = MessageFormat.Utils.numSub( tmp,
              'k_' + data.pf_count + ' - off_' + ( data.pf_count - 1 ),
              data.key
            );
          }
          return 'r += "' + tmp + '";\n';
        default:
          throw new Error( 'Bad AST type: ' + ast.type );
      }
    }
    return interpMFP( ast );
  };

  MessageFormat.prototype.compile = function ( message ) {
    return (new Function( 'MessageFormat',
      'return ' +
        this.precompile(
          this.parse( message )
        )
    ))(MessageFormat);
  };

  if (typeof exports !== 'undefined') {
    if (typeof module !== 'undefined' && module.exports) {
      exports = module.exports = MessageFormat;
    }
    exports.MessageFormat = MessageFormat;
  }
  else if (typeof define === 'function' && define.amd) {
    define(function() {
      return MessageFormat;
    });
  }
  else {
    root['MessageFormat'] = MessageFormat;
  }

})( this );
<|endoftext|>


<commit_before>
/*!
 * Connect - logger
 * Copyright(c) 2010 Sencha Inc.
 * Copyright(c) 2011 TJ Holowaychuk
 * MIT Licensed
 */

/**
 * Log buffer.
 */

var buf = [];

/**
 * Default log buffer duration.
 */

var defaultBufferDuration = 1000;

/**
 * Log requests with the given `options` or a `format` string.
 *
 * Options:
 *
 *   - `format`  Format string, see below for tokens
 *   - `stream`  Output stream, defaults to _stdout_
 *   - `buffer`  Buffer duration, defaults to 1000ms when _true_
 *
 * Tokens:
 *
 *   - `:req[header]` ex: `:req[Accept]`
 *   - `:res[header]` ex: `:res[Content-Length]`
 *   - `:http-version`
 *   - `:response-time`
 *   - `:remote-addr`
 *   - `:date`
 *   - `:method`
 *   - `:url`
 *   - `:referrer`
 *   - `:user-agent`
 *   - `:status`
 *
 * Formats:
 *
 *   Pre-defined formats that ship with connect:
 *
 *    - `default` ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'
 *    - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'
 *    - `tiny`  ':method :url :status :res[content-length] - :response-time ms'
 *    - `dev` concise output colored by response status for development use
 *
 * Examples:
 *
 *      connect.logger() // default
 *      connect.logger('short')
 *      connect.logger('tiny')
 *      connect.logger('dev')
 *      connect.logger(':method :url - :referrer')
 *      connect.logger(':req[content-type] -> :res[content-type]')
 *      connect.logger(function(req, res){ return 'some format string' })
 *
 * Defining Tokens:
 *
 *   To define a token, simply invoke `connect.logger.token()` with the
 *   name and a callback function. The value returned is then available
 *   as ":type" in this case.
 *
 *      connect.logger.token('type', function(req, res){ return req.headers['content-type']; })
 *
 * Defining Formats:
 *
 *   All default formats are defined this way, however it's public API as well:
 *
 *       connect.logger.format('name', 'string or function')
 *
 * @param {String|Function|Object} format or options
 * @return {Function}
 * @api public
 */

exports = module.exports = function logger(options) {
  if ('object' == typeof options) {
    options = options || {};
  } else if (options) {
    options = { format: options };
  } else {
    options = {};
  }

  // format name
  var fmt = exports[options.format] || options.format || exports.default;

  // compile format
  if ('function' != typeof fmt) fmt = compile(fmt);

  // options
  var stream = options.stream || process.stdout
    , buffer = options.buffer;

  // buffering support
  if (buffer) {
    var realStream = stream
      , interval = 'number' == typeof buffer
        ? buffer
        : defaultBufferDuration;

    // flush interval
    setInterval(function(){
      if (buf.length) {
        realStream.write(buf.join(''), 'ascii');
        buf.length = 0;
      }
    }, interval);

    // swap the stream
    stream = {
      write: function(str){
        buf.push(str);
      }
    };
  }

  return function logger(req, res, next) {
    req._startTime = new Date;

    // mount safety
    if (req._logging) return next();

    // flag as logging
    req._logging = true;

    // proxy end to output loggging
    var end = res.end;
    res.end = function(chunk, encoding){
      res.end = end;
      res.end(chunk, encoding);
      stream.write(fmt(exports, req, res) + '\n', 'ascii');
    };

    next();
  };
};

/**
 * Compile `fmt` into a function.
 *
 * @param {String} fmt
 * @return {Function}
 * @api private
 */

function compile(fmt) {
  fmt = fmt.replace(/"/g, '\\"');
  var js = '  return "' + fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, function(_, name, arg){
    return '"\n    + (tokens["' + name + '"](req, res, "' + arg + '") || "-") + "';
  }) + '";'
  return new Function('tokens, req, res', js);
};

/**
 * Define a token function with the given `name`,
 * and callback `fn(req, res)`.
 *
 * @param {String} name
 * @param {Function} fn
 * @return {Object} exports for chaining
 * @api public
 */

exports.token = function(name, fn) {
  exports[name] = fn;
  return this;
};

/**
 * Define a `fmt` with the given `name`.
 *
 * @param {String} name
 * @param {String|Function} fmt
 * @return {Object} exports for chaining
 * @api public
 */

exports.format = function(name, str){
  exports[name] = str;
  return this;
};

// default format

exports.format('default', ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"');

// short format

exports.format('short', ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms');

// tiny format

exports.format('tiny', ':method :url :status :res[content-length] - :response-time ms');

// dev (colored)

exports.format('dev', function(tokens, req, res){
  var status = res.statusCode
    , color = 32;

  if (status >= 500) color = 31
  else if (status >= 400) color = 33
  else if (status >= 300) color = 36;

  return '\033[90m' + req.method
    + ' ' + req.originalUrl + ' '
    + '\033[' + color + 'm' + res.statusCode
    + ' \033[90m'
    + (new Date - req._startTime)
    + 'ms\033[0m';
});

// request url

exports.token('url', function(req){
  return req.originalUrl;
});

// request method

exports.token('method', function(req){
  return req.method;
});

// response time in milliseconds

exports.token('response-time', function(req){
  return new Date - req._startTime;
});

// UTC date

exports.token('date', function(){
  return new Date().toUTCString();
});

// response status code

exports.token('status', function(req, res){
  return res.statusCode;
});

// normalized referrer

exports.token('referrer', function(req){
  return req.headers['referer'] || req.headers['referrer'];
});

// remote address

exports.token('remote-addr', function(req){
  return req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress));
});

// HTTP version

exports.token('http-version', function(req){
  return req.httpVersionMajor + '.' + req.httpVersionMinor;
});

// UA string

exports.token('user-agent', function(req){
  return req.headers['user-agent'];
});

// request header

exports.token('req', function(req, res, field){
  return req.headers[field.toLowerCase()];
});

// response header

exports.token('res', function(req, res, field){
  return (res._headers || {})[field.toLowerCase()];
});

<commit_msg>Allow retval `== null` from logger callback<commit_after>
/*!
 * Connect - logger
 * Copyright(c) 2010 Sencha Inc.
 * Copyright(c) 2011 TJ Holowaychuk
 * MIT Licensed
 */

/**
 * Log buffer.
 */

var buf = [];

/**
 * Default log buffer duration.
 */

var defaultBufferDuration = 1000;

/**
 * Log requests with the given `options` or a `format` string.
 *
 * Options:
 *
 *   - `format`  Format string, see below for tokens
 *   - `stream`  Output stream, defaults to _stdout_
 *   - `buffer`  Buffer duration, defaults to 1000ms when _true_
 *
 * Tokens:
 *
 *   - `:req[header]` ex: `:req[Accept]`
 *   - `:res[header]` ex: `:res[Content-Length]`
 *   - `:http-version`
 *   - `:response-time`
 *   - `:remote-addr`
 *   - `:date`
 *   - `:method`
 *   - `:url`
 *   - `:referrer`
 *   - `:user-agent`
 *   - `:status`
 *
 * Formats:
 *
 *   Pre-defined formats that ship with connect:
 *
 *    - `default` ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'
 *    - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'
 *    - `tiny`  ':method :url :status :res[content-length] - :response-time ms'
 *    - `dev` concise output colored by response status for development use
 *
 * Examples:
 *
 *      connect.logger() // default
 *      connect.logger('short')
 *      connect.logger('tiny')
 *      connect.logger('dev')
 *      connect.logger(':method :url - :referrer')
 *      connect.logger(':req[content-type] -> :res[content-type]')
 *      connect.logger(function(req, res){ return 'some format string' })
 *
 * Defining Tokens:
 *
 *   To define a token, simply invoke `connect.logger.token()` with the
 *   name and a callback function. The value returned is then available
 *   as ":type" in this case.
 *
 *      connect.logger.token('type', function(req, res){ return req.headers['content-type']; })
 *
 * Defining Formats:
 *
 *   All default formats are defined this way, however it's public API as well:
 *
 *       connect.logger.format('name', 'string or function')
 *
 * @param {String|Function|Object} format or options
 * @return {Function}
 * @api public
 */

exports = module.exports = function logger(options) {
  if ('object' == typeof options) {
    options = options || {};
  } else if (options) {
    options = { format: options };
  } else {
    options = {};
  }

  // format name
  var fmt = exports[options.format] || options.format || exports.default;

  // compile format
  if ('function' != typeof fmt) fmt = compile(fmt);

  // options
  var stream = options.stream || process.stdout
    , buffer = options.buffer;

  // buffering support
  if (buffer) {
    var realStream = stream
      , interval = 'number' == typeof buffer
        ? buffer
        : defaultBufferDuration;

    // flush interval
    setInterval(function(){
      if (buf.length) {
        realStream.write(buf.join(''), 'ascii');
        buf.length = 0;
      }
    }, interval);

    // swap the stream
    stream = {
      write: function(str){
        buf.push(str);
      }
    };
  }

  return function logger(req, res, next) {
    req._startTime = new Date;

    // mount safety
    if (req._logging) return next();

    // flag as logging
    req._logging = true;

    // proxy end to output loggging
    var end = res.end;
    res.end = function(chunk, encoding){
      res.end = end;
      res.end(chunk, encoding);
      var line = fmt(exports, req, res);
      if (null == line) return;
      stream.write(line + '\n', 'ascii');
    };

    next();
  };
};

/**
 * Compile `fmt` into a function.
 *
 * @param {String} fmt
 * @return {Function}
 * @api private
 */

function compile(fmt) {
  fmt = fmt.replace(/"/g, '\\"');
  var js = '  return "' + fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, function(_, name, arg){
    return '"\n    + (tokens["' + name + '"](req, res, "' + arg + '") || "-") + "';
  }) + '";'
  return new Function('tokens, req, res', js);
};

/**
 * Define a token function with the given `name`,
 * and callback `fn(req, res)`.
 *
 * @param {String} name
 * @param {Function} fn
 * @return {Object} exports for chaining
 * @api public
 */

exports.token = function(name, fn) {
  exports[name] = fn;
  return this;
};

/**
 * Define a `fmt` with the given `name`.
 *
 * @param {String} name
 * @param {String|Function} fmt
 * @return {Object} exports for chaining
 * @api public
 */

exports.format = function(name, str){
  exports[name] = str;
  return this;
};

// default format

exports.format('default', ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"');

// short format

exports.format('short', ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms');

// tiny format

exports.format('tiny', ':method :url :status :res[content-length] - :response-time ms');

// dev (colored)

exports.format('dev', function(tokens, req, res){
  var status = res.statusCode
    , color = 32;

  if (status >= 500) color = 31
  else if (status >= 400) color = 33
  else if (status >= 300) color = 36;

  return '\033[90m' + req.method
    + ' ' + req.originalUrl + ' '
    + '\033[' + color + 'm' + res.statusCode
    + ' \033[90m'
    + (new Date - req._startTime)
    + 'ms\033[0m';
});

// request url

exports.token('url', function(req){
  return req.originalUrl;
});

// request method

exports.token('method', function(req){
  return req.method;
});

// response time in milliseconds

exports.token('response-time', function(req){
  return new Date - req._startTime;
});

// UTC date

exports.token('date', function(){
  return new Date().toUTCString();
});

// response status code

exports.token('status', function(req, res){
  return res.statusCode;
});

// normalized referrer

exports.token('referrer', function(req){
  return req.headers['referer'] || req.headers['referrer'];
});

// remote address

exports.token('remote-addr', function(req){
  return req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress));
});

// HTTP version

exports.token('http-version', function(req){
  return req.httpVersionMajor + '.' + req.httpVersionMinor;
});

// UA string

exports.token('user-agent', function(req){
  return req.headers['user-agent'];
});

// request header

exports.token('req', function(req, res, field){
  return req.headers[field.toLowerCase()];
});

// response header

exports.token('res', function(req, res, field){
  return (res._headers || {})[field.toLowerCase()];
});

<|endoftext|>


<commit_before>
/* global jQuery, require, module */

var DOMUtils = {};

if (typeof require === 'function' && typeof module === 'object') {
  var jQuery = require('jquery');

  module.exports = DOMUtils;
}

(function ($) {
  function listContains (list, element, compareFunc, context) {
    for (var i = 0; i < list.length; i++)
      if (compareFunc.call(context, element, list[i])) return true;

    return false;
  }

  function toArray (list) {
    var array = [];
    for (var i = 0; i < list.length; i++)
      array[i] = list[i];

    return array;
  }

  DOMUtils.tagsMatch = function (left, right) {
    if (! left || ! right) return false;

    if (left.tagName && right.tagName) return (left.tagName === right.tagName);
    else return left.isEqualNode(right);
  };

  DOMUtils.updateDOMElement = function (left, right) {
    if (left[0].isEqualNode(right[0])) return;
    if (right[0].childNodes.length === 0 || ! this.tagsMatch(left[0], right[0])) {
      left.replaceWith(right);
      return;
    }

    var added = [], removed = [];

    for (var i = 0; i < right[0].childNodes.length; i++)
      if (! listContains(left[0].childNodes, right[0].childNodes[i], this.tagsMatch, this))
        added.push($(right[0].childNodes[i]).clone(true, true));

    for (var j = 0; j < left[0].childNodes.length; j++)
      if (! listContains(right[0].childNodes, left[0].childNodes[j], this.tagsMatch, this))
        removed.push($(left[0].childNodes[j]));

    for (var k = 0; k < right[0].childNodes.length; k++)
      if (listContains(left[0].childNodes, right[0].childNodes[k], this.tagsMatch, this)) {
        var filterCallback = function (element) {
          if (element[0]) return DOMUtils.tagsMatch(right[0].childNodes[k], element[0]);
          else return DOMUtils.tagsMatch(right[0].childNodes[k], element);
        };

        var leftInstances = toArray(left[0].childNodes).filter(filterCallback);
        var rightInstances = toArray(right[0].childNodes).filter(filterCallback);
        var addedInstances = added.filter(filterCallback);
        var removedInstances = removed.filter(filterCallback);

        if (rightInstances.length > leftInstances.length) {
          var difference = rightInstances.length - leftInstances.length;
          if (difference > addedInstances.length) added.push($(right[0].childNodes[k]).clone(true, true));
        } else if (leftInstances.length > rightInstances.length) {
          difference = leftInstances.length - rightInstances.length;
          if (difference > removedInstances.length) removed.push($(leftInstances[0]));
        }
      }

    for (var l = added.length - 1; l >= 0; l--) {
      if (! added[l].nextSibling) left.append(added[l]);
      else left[0].insertBefore(added[l][0], left.children(added[l][0].nextSibling)[0]);
    }

    for (var m = 0; m < removed.length; m++)
      removed[m].remove();

    if (left[0].attributes && right[0].attributes) {
      for (var n = 0; n < right[0].attributes.length; n++) {
        var attrName = right[0].attributes[n].name;
        left.attr(attrName, right.attr(attrName));
      }

      for (var o = 0; o < left[0].attributes.length; o++) {
        attrName = left[0].attributes[o].name;
        if (! right.attr(attrName)) left.removeAttr(attrName);
      }
    }

    for (var p = 0; p < left[0].childNodes.length; p++)
      this.updateDOMElement($(left[0].childNodes[p]), $(right[0].childNodes[p]).clone(true, true));
  };
})(jQuery);
<commit_msg>Make DOMUtils work with non-jQuery objects<commit_after>
/* global jQuery, require, module */

var DOMUtils = {};

if (typeof require === 'function' && typeof module === 'object') {
  var jQuery = require('jquery');

  module.exports = DOMUtils;
}

(function ($) {
  function listContains (list, element, compareFunc, context) {
    for (var i = 0; i < list.length; i++)
      if (compareFunc.call(context, element, list[i])) return true;

    return false;
  }

  function toArray (list) {
    var array = [];
    for (var i = 0; i < list.length; i++)
      array[i] = list[i];

    return array;
  }

  DOMUtils.tagsMatch = function (left, right) {
    if (! left || ! right) return false;

    if (left.tagName && right.tagName) return (left.tagName === right.tagName);
    else return left.isEqualNode(right);
  };

  DOMUtils.updateDOMElement = function (left, right) {
    left = $(left);
    right = $(right);

    if (left[0].isEqualNode(right[0])) return;
    if (right[0].childNodes.length === 0 || ! this.tagsMatch(left[0], right[0])) {
      left.replaceWith(right);
      return;
    }

    var added = [], removed = [];

    for (var i = 0; i < right[0].childNodes.length; i++)
      if (! listContains(left[0].childNodes, right[0].childNodes[i], this.tagsMatch, this))
        added.push($(right[0].childNodes[i]).clone(true, true));

    for (var j = 0; j < left[0].childNodes.length; j++)
      if (! listContains(right[0].childNodes, left[0].childNodes[j], this.tagsMatch, this))
        removed.push($(left[0].childNodes[j]));

    for (var k = 0; k < right[0].childNodes.length; k++)
      if (listContains(left[0].childNodes, right[0].childNodes[k], this.tagsMatch, this)) {
        var filterCallback = function (element) {
          if (element[0]) return DOMUtils.tagsMatch(right[0].childNodes[k], element[0]);
          else return DOMUtils.tagsMatch(right[0].childNodes[k], element);
        };

        var leftInstances = toArray(left[0].childNodes).filter(filterCallback);
        var rightInstances = toArray(right[0].childNodes).filter(filterCallback);
        var addedInstances = added.filter(filterCallback);
        var removedInstances = removed.filter(filterCallback);

        if (rightInstances.length > leftInstances.length) {
          var difference = rightInstances.length - leftInstances.length;
          if (difference > addedInstances.length) added.push($(right[0].childNodes[k]).clone(true, true));
        } else if (leftInstances.length > rightInstances.length) {
          difference = leftInstances.length - rightInstances.length;
          if (difference > removedInstances.length) removed.push($(leftInstances[0]));
        }
      }

    for (var l = added.length - 1; l >= 0; l--) {
      if (! added[l].nextSibling) left.append(added[l]);
      else left[0].insertBefore(added[l][0], left.children(added[l][0].nextSibling)[0]);
    }

    for (var m = 0; m < removed.length; m++)
      removed[m].remove();

    if (left[0].attributes && right[0].attributes) {
      for (var n = 0; n < right[0].attributes.length; n++) {
        var attrName = right[0].attributes[n].name;
        left.attr(attrName, right.attr(attrName));
      }

      for (var o = 0; o < left[0].attributes.length; o++) {
        attrName = left[0].attributes[o].name;
        if (! right.attr(attrName)) left.removeAttr(attrName);
      }
    }

    for (var p = 0; p < left[0].childNodes.length; p++)
      this.updateDOMElement($(left[0].childNodes[p]), $(right[0].childNodes[p]).clone(true, true));
  };
})(jQuery);
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */
var errors = require('../errors')
  , utils = require('../utils');

/**
 * Secures a route requiring a valid access_token.
 * optionally also laods the client and/or user reflected by the token.
 *
 * If a token is present the client_id and user_id are placed in req.a2
 *
 * Options:
 *  `server`            Required, the server that is used for decrypting tokens and loading clients/users.
 *  `load_client`       Load the client reflected by client_id and validates the client_id, default: false
 *  `load_user`         Loads the user reflected by user_id in access_token. Enables require_token., default: false
 *  `require_token`     Requires a valid access_token
 *  `store`             The to be used, see store dir. defalts to server's store.
 *
 * @param options {Object}
 *
 */
function secure(options) {
  var server = options.server;
  var loadClient = options.load_client || options.require_client || false;
  var loadUser = options.load_user || options.require_user || false;
  var requireToken = options.require_token || false;
  if(loadUser) {
    requireToken = true;
  }

  return function(req, res, next) {
    req.a2 = req.a2 || {};
    req.a2.server = server;
    var self = this;
    if(req.query.client_id) {
      req.a2.client_id = req.query.client_id;
    }

    if(req.query.state || (req.body && req.body.state)) {
      req.a2.state = req.query.state;
    }
    if(req.query.response_type) {
      req.a2.response_type = req.query.response_type;
    }

    utils.getTokenFromRequest(req, res, function(err, tokenData) {
      if(err) {
        console.error("invalid token");
        return errors.resource.invalid_token(req, res);
      } else if((!err && !tokenData) && requireToken) {
        // No access_token was present, loadUser impossible.
        console.error("no token data available.");
        return errors.resource.access_denied(req, res);
      }

      if(tokenData) {
        server.tokenService.validateToken(tokenData, 'access_token', function(err, valid) {
          if(err || !valid) {
            return errors.resource.invalid_token(req, res);
          }
          req.a2.access_token = tokenData;
          req.a2.user_id = tokenData.user_id;
          req.a2.client_id = tokenData.client_id;
          var clientId = tokenData.client_id;
          var userId = tokenData.user_id;
          if(loadClient) {
            server.clientService.load(clientId, function(err, client) {
              if(err) {
                return next(err);
              }
              if(!client) {
                return errors.resource.invalid_token(req, res);
              }
              req.a2.client = client;
              if(!loadUser || (loadUser && req.a2.user)) {
                return next();
              }
            });
          }

          if(loadUser) {
            server.userService.load(tokenData.user_id, function(err, user) {
              if(err) {
                return next(err);
              }
              if(!user) {
                return errors.resource.invalid_token(req, res);
              }
              req.a2.user = user;
              if(!loadClient || (loadClient && req.a2.client)) {
                return next();
              }
            });
          }
        });
      } else {
        if(loadClient && req.query.client_id) {
          server.clientService.load(req.query.client_id, function(err, client) {
            if(err || !client) {
              return errors.resource.access_denied(req, res);
            }
            req.a2.client = client;
            return next();
          });
        } else if(loadClient && !req.query.client_id) {
          return errors.resource.access_denied(req, res);
        } else if(requireToken || (loadClient && !req.query.client_id)) {
          console.log("need token but no token or need client and no client_id");
          return errors.resource.access_denied(req, res);
        } else {
          if(loadClient && !req.query.client_id) {
            console.log("loadClient without client_id");
            return errors.resource.access_denied(req, res);
          }
          return next();
        }
      }
    });
  }
}

/**
 * expose middleware
 */
module.exports = secure;<commit_msg>a2 secure bugfix<commit_after>/**
 * Module dependencies
 */
var errors = require('../errors')
  , utils = require('../utils');

/**
 * Secures a route requiring a valid access_token.
 * optionally also laods the client and/or user reflected by the token.
 *
 * If a token is present the client_id and user_id are placed in req.a2
 *
 * Options:
 *  `server`            Required, the server that is used for decrypting tokens and loading clients/users.
 *  `load_client`       Load the client reflected by client_id and validates the client_id, default: false
 *  `load_user`         Loads the user reflected by user_id in access_token. Enables require_token., default: false
 *  `require_token`     Requires a valid access_token
 *  `store`             The to be used, see store dir. defalts to server's store.
 *
 * @param options {Object}
 *
 */
function secure(options) {
  var server = options.server;
  var loadClient = options.load_client || options.require_client || false;
  var loadUser = options.load_user || options.require_user || false;
  var requireToken = options.require_token || false;
  if(loadUser) {
    requireToken = true;
  }

  return function(req, res, next) {
    req.a2 = req.a2 || {};
    req.a2.server = server || req.app.a2.server;
    var self = this;
    if(req.query.client_id) {
      req.a2.client_id = req.query.client_id;
    }

    if(req.query.state || (req.body && req.body.state)) {
      req.a2.state = req.query.state;
    }
    if(req.query.response_type) {
      req.a2.response_type = req.query.response_type;
    }

    utils.getTokenFromRequest(req, res, function(err, tokenData) {
      if(err) {
        console.error("invalid token");
        return errors.resource.invalid_token(req, res);
      } else if((!err && !tokenData) && requireToken) {
        // No access_token was present, loadUser impossible.
        console.error("no token data available.");
        return errors.resource.access_denied(req, res);
      }

      if(tokenData) {
        server.tokenService.validateToken(tokenData, 'access_token', function(err, valid) {
          if(err || !valid) {
            console.error(err, valid);
            return errors.resource.invalid_token(req, res);
          }
          req.a2.access_token = tokenData;
          req.a2.user_id = tokenData.user_id;
          req.a2.client_id = tokenData.client_id;
          var clientId = tokenData.client_id;
          var userId = tokenData.user_id;

          if(loadClient) {
            server.clientService.load(clientId, function(err, client) {
              if(err) {
                return next(err);
              }
              if(!client) {
                return errors.resource.invalid_token(req, res);
              }
              req.a2.client = client;
              if(!loadUser || (loadUser && req.a2.user)) {
                return next();
              }
            });
          }

          if(loadUser) {
            server.userService.load(tokenData.user_id, function(err, user) {
              if(err) {
                return next(err);
              }
              if(!user) {
                return errors.resource.invalid_token(req, res);
              }
              req.a2.user = user;
              if(!loadClient || (loadClient && req.a2.client)) {
                return next();
              }
            });
          }

          if(!loadClient && !loadUser) {
            return next();
          }
        });
      } else {
        if(loadClient && req.query.client_id) {
          server.clientService.load(req.query.client_id, function(err, client) {
            if(err || !client) {
              return errors.resource.access_denied(req, res);
            }
            req.a2.client = client;
            return next();
          });
        } else if(loadClient && !req.query.client_id) {
          return errors.resource.access_denied(req, res);
        } else if(requireToken || (loadClient && !req.query.client_id)) {
          console.log("need token but no token or need client and no client_id");
          return errors.resource.access_denied(req, res);
        } else {
          if(loadClient && !req.query.client_id) {
            console.log("loadClient without client_id");
            return errors.resource.access_denied(req, res);
          }
          return next();
        }
      }
    });
  }
}

/**
 * expose middleware
 */
module.exports = secure;<|endoftext|>