<commit_before>/* jslint node: true, esnext: true */

'use strict';

const address = require('network-address'),
	url = require('url'),
	route = require('koa-route'),
	endpoint = require('kronos-endpoint'),
	service = require('kronos-service'),
	ServiceConsumerMixin = require('kronos-service').ServiceConsumerMixin;

class ServiceConsul extends service.Service {
	static get name() {
		return 'consul';
	}

	get type() {
		return ServiceConsul.name;
	}

	get autostart() {
		return true;
	}

	constructor(config, owner) {
		super(config, owner);

		const nodesEndpoint = new endpoint.ReceiveEndpoint('nodes', this, {
			createOpposite: true
		});

		let watch;

		nodesEndpoint.receive = request => {
			if (request) {
				if (request.update && watch === undefined) {
					watch = this.consul.watch({
						method: this.consul.catalog.service.nodes,
						options: {
							service: this.serviceDefinition.name
						}
					});

					watch.on('change', (data, res) => {
						this.info(data);
						nodesEndpoint.opposite.receive(data);
					});

					watch.on('error', err => this.error(err));
				} else if (request.update === false && watch) {
					watch.end();
					watch = undefined;
				}
			}

			return this.kronosNodes();
		};

		this.addEndpoint(nodesEndpoint);
	}

	get configurationAttributes() {
		const co = this.consulOptions;

		function consulOptionSetter(value, attribute) {
			if (value !== undefined) {
				co[attribute.name] = value;
			}
		}

		return Object.assign({
			host: {
				description: 'consul host',
				default: 'localhost',
				type: 'string',
				setter: consulOptionSetter
			},
			port: {
				description: 'consul port',
				default: 8500,
				type: 'integer',
				setter: consulOptionSetter
			},
			secure: {
				default: false,
				type: 'boolean',
				setter: consulOptionSetter
			},
			ca: {
				setter: consulOptionSetter
			},
			id: {
				description: 'kronos service id',
				type: 'string',
				// id of our node in the consul cluster
				default: address()
			},
			checkPath: {
				description: 'url path used for the kronos check',
				type: 'string',
				default: '/check'
			},
			checkInterval: {
				description: 'interval the kronos check is called',
				default: 10,
				type: 'duration'
			},
			checkTimeout: {
				description: 'timeout for the kronos check interval',
				default: 5,
				type: 'duration'
			}
		}, super.configurationAttributes);
	}

	_configure(config) {
		if (this.consulOptions === undefined) {
			this.consulOptions = {
				promisify(fn) {
					return new Promise((resolve, reject) => {
						try {
							return fn((err, data, res) => {
								if (err) {
									err.res = res;
									return reject(err);
								}
								return resolve([data, res]);
							});
						} catch (err) {
							return reject(err);
						}
					});
				}
			};
		}

		const modified = super._configure(config);

		// TODO where does baseUrl come from ?
		delete this.consulOptions.baseUrl;

		this.consul = require('consul')(this.consulOptions);

		return modified;
	}

	get serviceDefinition() {
		function asSeconds(value) {
			return value instanceof String && value.matches(/s$/) ? value : `${value}s`;
		}

		return {
			name: 'kronos',
			id: this.id + ':' + this.listener.port, // TODO find a better way to get a unique service id
			port: this.listener.port,
			address: this.listener.hostname,
			tags: this.tags,
			check: {
				id: this.listener.url + this.checkPath,
				http: this.listener.url + this.checkPath,
				interval: asSeconds(this.checkInterval),
				timeout: asSeconds(this.checkTimeout)
			}
		};
	}

	updateTags() {
		this.tags = Object.keys(this.owner.steps).map(name => `step:${name}`);
	}

	timeoutForTransition(transition) {
		if (transition.name === 'start') {
			return 600000;
		}

		return super.timeoutForTransition(transition);
	}

	/**
	 * Register the kronos service in consul
	 * @return {Promise} that fullfills on succesfull startup
	 */
	_start() {
		return super._start().then(() => {
			this.updateTags();

			// wait until health-check and koa services are present
			return ServiceConsumerMixin.defineServiceConsumerProperties(this, {
				listener: {
					name: 'koa-admin',
					type: 'koa'
				},
				hcs: {
					name: 'health-check',
					type: 'health-check'
				}
			}, this.owner, true).then(() =>
				this.listener.start().then(() =>
					this.consul.agent.service.register(this.serviceDefinition).then(f => {
						this.consul.status.leader().then(leader => this.info(level =>
							`Consul raft leader is ${Object.keys(leader).join(',')}`));
						this.consul.status.peers().then(peers => this.trace(level =>
							`Consul raft peers are ${peers.map(p => p.body)}`));
						this.kronosNodes().then(nodes => this.info(level =>
							`Kronos nodes are ${nodes.map( n => n.ServiceID)}`));

						this._stepRegisteredListener = step => {
							this.updateTags();
							this.update(5000);
						};

						this.owner.addListener('stepRegistered', this._stepRegisteredListener);

						this.listener.koa.use(route.get(this.checkPath, ctx =>
							this.hcs.endpoints.state.receive({}).then(r => {
								this.info({
									'health': r
								});
								this.status = r ? 200 : 300;
								ctx.body = r ? 'OK' : 'ERROR';
							})
						));

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

	/**
	 * deregister the service from consul
	 * @return {Promise} that fullfills when the deregitering has finished
	 */
	_stop() {
		return this.consul.agent.service.deregister(this.serviceDefinition.id).then(f => {
			if (this._stepRegisteredListener) {
				this.owner.removeListener('stepRegistered', this._stepRegisteredListener);
				this._stepRegisteredListener = undefined;
			}
			return Promise.resolve();
		});
	}

	/**
	 * Update service definition in consul
	 * @param {Number} delay time to wait before doing the unregister/register action
	 */
	update(delay) {
		const reregister = () =>
			this.consul.agent.service.deregister(this.serviceDefinition.id)
			.then(() => this.consul.agent.service.register(this.serviceDefinition));

		if (this._updateTimer) {
			clearTimeout(this._updateTimer);
		}

		if (delay) {
			this._updateTimer = setTimeout(reregister, delay);
		} else {
			return reregister();
		}
	}

	kronosNodes() {
		return this.consul.catalog.service.nodes({
			service: this.serviceDefinition.name
		}).then(response => response[0]);
	}

	registerService(name, options) {
		this.info({
			message: 'registerService',
			name: name,
			options: options
		});

		const u = url.parse(options.url);

		/*
				const watch = this.consul.watch({
					method: this.consul.kv.get,
					options: {
						key: `services/${name}/${this.id}/url`
					}
				});

				watch.on('change', (data, res) => {
					console.log('change data:', data);
				});

				watch.on('error', err => console.log('error:', err));
		*/

		return this.consul.kv.set({
			key: `services/${name}/${this.id}/url`,
			value: options.url
		});

		/*
				const serviceDefinition = {
					name: name,
					id: u.href,
					address: u.hostname,
					port: parseInt(u.port, 10),
					tags: options.tags
				};

				return consul.agent.service.register(serviceDefinition).then(f => {
					//this.info(`registered: ${JSON.stringify(f)}`);
					return Promise.resolve();
				});
				*/
	}

	unregisterService(name) {
		this.info({
			message: 'unregisterService',
			name: name
		});

		return this.consul.kv.del({
			key: `services/${name}/${this.id}`,
			recurse: true
		});

		//return consul.agent.service.deregister(name);
	}

	* serviceURLs(name) {
		let si = [];

		let firstPromise = this.consul.kv.get({
				key: `services/${name}`,
				recurse: true
			})
			.then(data => {
				si = data[0].map(d => d.Value);
				firstPromise = undefined;
				return si.length === 0 ? Promise.reject() : Promise.resolve(si[0]);
			});

		while (firstPromise) {
			yield firstPromise;
			//console.log(`size: ${si.length} ${firstPromise}`);
		}

		if (si.length) {
			for (let i = 1;; i++) {
				if (i >= si.length) {
					i = 0;
				}
				//console.log(`yield: ${i} ${si.length}`);
				yield Promise.resolve(si[i]);
			}
		}
		return undefined;
	}
}

module.exports.registerWithManager = manager =>
	manager.registerServiceFactory(ServiceConsul).then(sf =>
		manager.declareService({
			'type': sf.name,
			'name': 'registry'
		}));
<commit_msg>fix(service): service.id is the complete id<commit_after>/* jslint node: true, esnext: true */

'use strict';

const address = require('network-address'),
	url = require('url'),
	route = require('koa-route'),
	endpoint = require('kronos-endpoint'),
	service = require('kronos-service'),
	ServiceConsumerMixin = require('kronos-service').ServiceConsumerMixin;

class ServiceConsul extends service.Service {
	static get name() {
		return 'consul';
	}

	get type() {
		return ServiceConsul.name;
	}

	get autostart() {
		return true;
	}

	constructor(config, owner) {
		super(config, owner);

		const nodesEndpoint = new endpoint.ReceiveEndpoint('nodes', this, {
			createOpposite: true
		});

		let watch;

		nodesEndpoint.receive = request => {
			if (request) {
				if (request.update && watch === undefined) {
					watch = this.consul.watch({
						method: this.consul.catalog.service.nodes,
						options: {
							service: this.serviceDefinition.name
						}
					});

					watch.on('change', (data, res) => {
						this.info(data);
						nodesEndpoint.opposite.receive(data);
					});

					watch.on('error', err => this.error(err));
				} else if (request.update === false && watch) {
					watch.end();
					watch = undefined;
				}
			}

			return this.kronosNodes();
		};

		this.addEndpoint(nodesEndpoint);
	}

	get configurationAttributes() {
		const co = this.consulOptions;

		function consulOptionSetter(value, attribute) {
			if (value !== undefined) {
				co[attribute.name] = value;
			}
		}

		return Object.assign({
			host: {
				description: 'consul host',
				default: 'localhost',
				type: 'string',
				setter: consulOptionSetter
			},
			port: {
				description: 'consul port',
				default: 8500,
				type: 'integer',
				setter: consulOptionSetter
			},
			secure: {
				default: false,
				type: 'boolean',
				setter: consulOptionSetter
			},
			ca: {
				setter: consulOptionSetter
			},
			id: {
				description: 'kronos service id',
				type: 'string',
				// id of our node in the consul cluster
				default: address()
			},
			checkPath: {
				description: 'url path used for the kronos check',
				type: 'string',
				default: '/check'
			},
			checkInterval: {
				description: 'interval the kronos check is called',
				default: 10,
				type: 'duration'
			},
			checkTimeout: {
				description: 'timeout for the kronos check interval',
				default: 5,
				type: 'duration'
			}
		}, super.configurationAttributes);
	}

	_configure(config) {
		if (this.consulOptions === undefined) {
			this.consulOptions = {
				promisify(fn) {
					return new Promise((resolve, reject) => {
						try {
							return fn((err, data, res) => {
								if (err) {
									err.res = res;
									return reject(err);
								}
								return resolve([data, res]);
							});
						} catch (err) {
							return reject(err);
						}
					});
				}
			};
		}

		const modified = super._configure(config);

		// TODO where does baseUrl come from ?
		delete this.consulOptions.baseUrl;

		this.consul = require('consul')(this.consulOptions);

		return modified;
	}

	get serviceDefinition() {
		function asSeconds(value) {
			return value instanceof String && value.matches(/s$/) ? value : `${value}s`;
		}

		return {
			name: 'kronos',
			id: this.id,
			port: this.listener.port,
			address: this.listener.hostname,
			tags: this.tags,
			check: {
				id: this.listener.url + this.checkPath,
				http: this.listener.url + this.checkPath,
				interval: asSeconds(this.checkInterval),
				timeout: asSeconds(this.checkTimeout)
			}
		};
	}

	updateTags() {
		this.tags = Object.keys(this.owner.steps).map(name => `step:${name}`);
	}

	timeoutForTransition(transition) {
		if (transition.name === 'start') {
			return 600000;
		}

		return super.timeoutForTransition(transition);
	}

	/**
	 * Register the kronos service in consul
	 * @return {Promise} that fullfills on succesfull startup
	 */
	_start() {
		return super._start().then(() => {
			this.updateTags();

			// wait until health-check and koa services are present
			return ServiceConsumerMixin.defineServiceConsumerProperties(this, {
				listener: {
					name: 'koa-admin',
					type: 'koa'
				},
				hcs: {
					name: 'health-check',
					type: 'health-check'
				}
			}, this.owner, true).then(() =>
				this.listener.start().then(() =>
					this.consul.agent.service.register(this.serviceDefinition).then(f => {
						this.consul.status.leader().then(leader => this.info(level =>
							`Consul raft leader is ${Object.keys(leader).join(',')}`));
						this.consul.status.peers().then(peers => this.trace(level =>
							`Consul raft peers are ${peers.map(p => p.body)}`));
						this.kronosNodes().then(nodes => this.info(level =>
							`Kronos nodes are ${nodes.map( n => n.ServiceID)}`));

						this._stepRegisteredListener = step => {
							this.updateTags();
							this.update(5000);
						};

						this.owner.addListener('stepRegistered', this._stepRegisteredListener);

						this.listener.koa.use(route.get(this.checkPath, ctx =>
							this.hcs.endpoints.state.receive({}).then(r => {
								this.info({
									'health': r
								});
								this.status = r ? 200 : 300;
								ctx.body = r ? 'OK' : 'ERROR';
							})
						));

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

	/**
	 * deregister the service from consul
	 * @return {Promise} that fullfills when the deregitering has finished
	 */
	_stop() {
		return this.consul.agent.service.deregister(this.serviceDefinition.id).then(f => {
			if (this._stepRegisteredListener) {
				this.owner.removeListener('stepRegistered', this._stepRegisteredListener);
				this._stepRegisteredListener = undefined;
			}
			return Promise.resolve();
		});
	}

	/**
	 * Update service definition in consul
	 * @param {Number} delay time to wait before doing the unregister/register action
	 */
	update(delay) {
		const reregister = () =>
			this.consul.agent.service.deregister(this.serviceDefinition.id)
			.then(() => this.consul.agent.service.register(this.serviceDefinition));

		if (this._updateTimer) {
			clearTimeout(this._updateTimer);
		}

		if (delay) {
			this._updateTimer = setTimeout(reregister, delay);
		} else {
			return reregister();
		}
	}

	kronosNodes() {
		return this.consul.catalog.service.nodes({
			service: this.serviceDefinition.name
		}).then(response => response[0]);
	}

	registerService(name, options) {
		this.info({
			message: 'registerService',
			name: name,
			options: options
		});

		const u = url.parse(options.url);

		/*
				const watch = this.consul.watch({
					method: this.consul.kv.get,
					options: {
						key: `services/${name}/${this.id}/url`
					}
				});

				watch.on('change', (data, res) => {
					console.log('change data:', data);
				});

				watch.on('error', err => console.log('error:', err));
		*/

		return this.consul.kv.set({
			key: `services/${name}/${this.id}/url`,
			value: options.url
		});

		/*
				const serviceDefinition = {
					name: name,
					id: u.href,
					address: u.hostname,
					port: parseInt(u.port, 10),
					tags: options.tags
				};

				return consul.agent.service.register(serviceDefinition).then(f => {
					//this.info(`registered: ${JSON.stringify(f)}`);
					return Promise.resolve();
				});
				*/
	}

	unregisterService(name) {
		this.info({
			message: 'unregisterService',
			name: name
		});

		return this.consul.kv.del({
			key: `services/${name}/${this.id}`,
			recurse: true
		});

		//return consul.agent.service.deregister(name);
	}

	* serviceURLs(name) {
		let si = [];

		let firstPromise = this.consul.kv.get({
				key: `services/${name}`,
				recurse: true
			})
			.then(data => {
				si = data[0].map(d => d.Value);
				firstPromise = undefined;
				return si.length === 0 ? Promise.reject() : Promise.resolve(si[0]);
			});

		while (firstPromise) {
			yield firstPromise;
			//console.log(`size: ${si.length} ${firstPromise}`);
		}

		if (si.length) {
			for (let i = 1;; i++) {
				if (i >= si.length) {
					i = 0;
				}
				//console.log(`yield: ${i} ${si.length}`);
				yield Promise.resolve(si[i]);
			}
		}
		return undefined;
	}
}

module.exports.registerWithManager = manager =>
	manager.registerServiceFactory(ServiceConsul).then(sf =>
		manager.declareService({
			'type': sf.name,
			'name': 'registry'
		}));
<|endoftext|>


<commit_before>(function (global, undefined) {
	'use strict';
	var setAsap = (function () {
		var callbacks = [], timeout, hiddenDiv, scriptEl, timeoutFn;
		// Modern browsers, fastest async
		if (global.MutationObserver) {
			hiddenDiv = document.createElement("div");
			(new MutationObserver(executeCallbacks)).observe(hiddenDiv, { attributes: true });
			return function (callback) {
				if (!callbacks.length) {
					hiddenDiv.setAttribute('yes', 'no');
				}
				callbacks.push(callback);
			};
		// Browsers that support postMessage
		} else if (!global.setImmediate && global.postMessage && !global.importScripts && global.addEventListener) {
			var MESSAGE_PREFIX = "com.setImmediate" + Math.random(), hasPostMessage = false;

			var onGlobalMessage = function (event) {
				if (event.source === global && event.data === MESSAGE_PREFIX) {
					hasPostMessage = false;
					executeCallbacks();
				}
			};

			global.addEventListener("message", onGlobalMessage, false);

			return function (fn) {
				callbacks.push(fn);

				if (!hasPostMessage) {
					hasPostMessage = true;
					global.postMessage(MESSAGE_PREFIX, "*");
				}
			};
		// IE browsers without postMessage
		} else if (!global.setImmediate && global.document && 'onreadystatechange' in document.createElement('script')) {
			return function (callback) {
				callbacks.push(callback);
				if (!scriptEl) {
					scriptEl = document.createElement("script");
					scriptEl.onreadystatechange = function () {
						scriptEl.onreadystatechange = null;
						scriptEl.parentNode.removeChild(scriptEl);
						scriptEl = null;
						executeCallbacks();
					};
					document.body.appendChild(scriptEl);
				}
			};
		// All other browsers and node
		} else {
			timeoutFn = global.setImmediate || (global.process && global.process.nextTick) || setTimeout;
			return function (callback) {
				callbacks.push(callback);
				if (!timeout) {
					timeout = timeoutFn(function () {
						timeout = undefined;
						executeCallbacks();
					}, 0);
				}
			};
		}

		function executeCallbacks() {
			var cbList = callbacks;
			callbacks = [];
			for (var i = 0, len = cbList.length; i < len; i++) {
				cbList[i]();
			}
		}
	})();

	if (typeof module !== 'undefined' && module.exports) {
		module.exports = setAsap;
	} else if (typeof require !== 'undefined' && require.amd) {
		define(function () {
			return setAsap;
		});
	} else {
		global.setAsap = setAsap;
	}

})(this, void 0);
<commit_msg>Renamed global variable to work with Browserify<commit_after>(function (main, undefined) {
	'use strict';
	var setAsap = (function () {
		var callbacks = [], timeout, hiddenDiv, scriptEl, timeoutFn;
		// Modern browsers, fastest async
		if (main.MutationObserver) {
			hiddenDiv = document.createElement("div");
			(new MutationObserver(executeCallbacks)).observe(hiddenDiv, { attributes: true });
			return function (callback) {
				if (!callbacks.length) {
					hiddenDiv.setAttribute('yes', 'no');
				}
				callbacks.push(callback);
			};
		// Browsers that support postMessage
		} else if (!main.setImmediate && main.postMessage && !main.importScripts && main.addEventListener) {
			var MESSAGE_PREFIX = "com.setImmediate" + Math.random(), hasPostMessage = false;

			var onGlobalMessage = function (event) {
				if (event.source === main && event.data === MESSAGE_PREFIX) {
					hasPostMessage = false;
					executeCallbacks();
				}
			};

			main.addEventListener("message", onGlobalMessage, false);

			return function (fn) {
				callbacks.push(fn);

				if (!hasPostMessage) {
					hasPostMessage = true;
					main.postMessage(MESSAGE_PREFIX, "*");
				}
			};
		// IE browsers without postMessage
		} else if (!main.setImmediate && main.document && 'onreadystatechange' in document.createElement('script')) {
			return function (callback) {
				callbacks.push(callback);
				if (!scriptEl) {
					scriptEl = document.createElement("script");
					scriptEl.onreadystatechange = function () {
						scriptEl.onreadystatechange = null;
						scriptEl.parentNode.removeChild(scriptEl);
						scriptEl = null;
						executeCallbacks();
					};
					document.body.appendChild(scriptEl);
				}
			};
		// All other browsers and node
		} else {
			timeoutFn = main.setImmediate || (main.process && main.process.nextTick) || setTimeout;
			return function (callback) {
				callbacks.push(callback);
				if (!timeout) {
					timeout = timeoutFn(function () {
						timeout = undefined;
						executeCallbacks();
					}, 0);
				}
			};
		}

		function executeCallbacks() {
			var cbList = callbacks;
			callbacks = [];
			for (var i = 0, len = cbList.length; i < len; i++) {
				cbList[i]();
			}
		}
	})();

	if (typeof module !== 'undefined' && module.exports) {
		module.exports = setAsap;
	} else if (typeof require !== 'undefined' && require.amd) {
		define(function () {
			return setAsap;
		});
	} else {
		main.setAsap = setAsap;
	}

})(this);
<|endoftext|>


<commit_before>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved.
//            (c) 2011 panacoda GmbH. All rights reserved.
// Creator:   Sebastian
// Date:      15.11.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

m_require('core/datastore/data_provider.js');

/**
 * @class
 *
 * Encapsulates access to LocalStorage (in-browser key value store).
 * LocalStorage is an in-browser key-value store to persist data.
 * This data provider persists model records as JSON strings with their name and id as key.
 * When fetching these strings from storage, their automatically converted in their corresponding model records.
 *
 * Operates synchronous.
 *
 * @extends M.DataProvider
 */
M.DataProviderLocalStorage = M.DataProvider.extend(
    /** @scope M.DataProviderLocalStorage.prototype */ {

    /**
     * The type of this object.
     * @type String
     */
    type:'M.DataProviderLocalStorage',

    /**
     * Saves a model record to the local storage
     * The key is the model record's name combined with id, value is stringified object
     * e.g.
     * Note_123 => '{ text: 'buy some food' }'
     *
     * @param {Object} that (is a model).
     * @returns {Boolean} Boolean indicating whether save was successful (YES|true) or not (NO|false).
     */
    save:function (obj) {
        try {
            //console.log(obj);
            /* add m_id to saved object */
            /*var a = JSON.stringify(obj.model.record).split('{', 2);
             a[2] = a[1];
             a[1] = '"m_id":' + obj.model.m_id + ',';
             a[0] = '{';
             var value = a.join('');*/
            var value = JSON.stringify(obj.model.record);
            localStorage.setItem(M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_' + obj.model.m_id, value);
            return YES;
        } catch (e) {
            M.Logger.log(M.WARN, 'Error saving ' + obj.model.record + ' to localStorage with key: ' + M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_' + this.m_id);
            return NO;
        }

    },

    /**
     * deletes a model from the local storage
     * key defines which one to delete
     * e.g. key: 'Note_123'
     *
     * @param {Object} obj The param obj, includes model
     * @returns {Boolean} Boolean indicating whether save was successful (YES|true) or not (NO|false).
     */
    del:function (obj) {
        try {
            if (localStorage.getItem(M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_' + obj.model.m_id)) { // check if key-value pair exists
                localStorage.removeItem(M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_' + obj.model.m_id);
                obj.model.recordManager.remove(obj.model.m_id);
                return YES;
            }
            return NO;
        } catch (e) {
            M.Logger.log(M.WARN, 'Error removing key: ' + M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_' + obj.model.m_id + ' from localStorage');
            return NO;
        }
    },

    /**
     * Finds all models of type defined by modelName that match a key or a simple query.
     * A simple query example: 'price < 2.21'
     * Right now, no AND or OR joins possible, just one query constraint.
     *
     * If no query is passed, all models are returned by calling findAll()
     * @param {Object} The param object containing e.g. the query or the key.
     * @returns {Object|Boolean} Returns an object if find is done with a key, an array of objects when a query is given or no parameter passed.
     * @throws Exception when query tries to compare two different data types
     */
    find:function (obj) {
        if (obj.key) {
            var record = this.findByKey(obj);
            if (!record) {
                return NO;
            }
            /*construct new model record with the saved id*/
            var reg = new RegExp('^' + M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_([0-9a-zA-Z]+)$').exec(obj.key);
            var m_id = reg && reg[1] ? reg[1] : null;
            if (!m_id) {
                M.Logger.log('retrieved model has no valid key: ' + obj.key, M.ERR);
                return NO;
            }
            var m = obj.model.createRecord($.extend(record, {m_id:m_id, state:M.STATE_VALID}));
            return m;
        }

        if (obj.query) {
            var q = obj.query;
            var missing = [];
            if (!q.identifier) {
                missing.push('identifier');
            }
            if (!q.operator) {
                missing.push('operator');
            }
            if (q.value === undefined) {
                missing.push('value');
            }

            if (missing.length > 0) {
                M.Logger.log('Wrong query format:', missing.join(', '), ' is/are missing.', M.WARN);
                return [];
            }

            var ident = q.identifier;
            var op = q.operator;
            var val = q.value;

            var res = this.findAll(obj);

            // check if query is correct in respect of data types
            if(res && res.length > 0) {
                var o = res[0];
                if (typeof(o.record[ident]) != o.__meta[ident].dataType.toLowerCase()) {
                    throw 'Query: "' + ident + op + val + '" tries to compare ' + typeof(o.record[ident]) + ' with ' + o.__meta[ident].dataType.toLowerCase() + '.';
                }
            }

            switch (op) {
                case '=':

                    res = _.select(res, function (o) {
                        return o.record[ident] === val;
                    });
                    break;

                case '~=': // => includes (works only on strings)

                    if(obj.model.__meta[ident].dataType.toLowerCase() !== 'string') {
                        throw 'Query: Operator "~=" only works on string properties. Property "' + ident + '" is of type ' + obj.model.__meta[ident].dataType.toLowerCase() + '.';
                    }
                    // escape all meta regex meta characters: \, *, +, ?, |, {, [, (,), ^, $,., # and space
                    var metaChars = ['\\\\', '\\*', '\\+', '\\?', '\\|', '\\{', '\\}', '\\[', '\\]', '\\(', '\\)', '\\^', '\\$', '\\.', '\\#'];

                    for(var i in metaChars) {
                        val = val.replace(new RegExp(metaChars[i], 'g'), '\\' + metaChars[i].substring(1,2));
                    }

                    // replace whitespaces with regex equivalent
                    val = val.replace(/\s/g, '\\s');

                    var regex = new RegExp(val);

                    res = _.select(res, function(o) {
                        return regex.test(o.record[ident]);
                    });

                    break;

                case '!=':
                    res = _.select(res, function (o) {
                        return o.record[ident] !== val;
                    });
                    break;
                case '<':
                    res = _.select(res, function (o) {
                        return o.record[ident] < val;
                    });
                    break;
                case '>':
                    res = _.select(res, function (o) {
                        return o.record[ident] > val;
                    });
                    break;
                case '<=':
                    res = _.select(res, function (o) {
                        return o.record[ident] <= val;
                    });
                    break;
                case '>=':
                    res = _.select(res, function (o) {
                        return o.record[ident] >= val;
                    });
                    break;
                default:
                    M.Logger.log('Query has unknown operator: ' + op, M.WARN);
                    res = [];
                    break;

            }

            return res;

        } else { /* if no query is passed, all models for modelName shall be returned */
            return this.findAll(obj);
        }
    },

    /**
     * Finds a record identified by the key.
     *
     * @param {Object} The param object containing e.g. the query or the key.
     * @returns {Object|Boolean} Returns an object identified by key, correctly built as a model record by calling
     * or a boolean (NO|false) if no key is given or the key does not exist in LocalStorage.
     * parameter passed.
     */
    findByKey:function (obj) {
        if (obj.key) {

            var reg = new RegExp('^' + M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX);
            /* assume that if key starts with local storage prefix, correct key is given, other wise construct it and key might be m_id */
            obj.key = reg.test(obj.key) ? obj.key : M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_' + obj.key;

            if (localStorage.getItem(obj.key)) { // if key is available
                return this.buildRecord(obj.key, obj)
            } else {
                return NO;
            }
        }
        M.Logger.log("Please provide a key.", M.WARN);
        return NO;
    },

    /**
     * Returns all models defined by modelName.
     *
     * Models are saved with key: Modelname_ID, e.g. Note_123
     *
     * @param {Object} obj The param obj, includes model
     * @returns {Object} The array of fetched objects/model records. If no records the array is empty.
     */
    findAll:function (obj) {
        var result = [];
        for (var i = 0; i < localStorage.length; i++) {
            var k = localStorage.key(i);
            regexResult = new RegExp('^' + M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_').exec(k);
            if (regexResult) {
                var record = this.buildRecord(k, obj);//JSON.parse(localStorage.getItem(k));

                /*construct new model record with the saved m_id*/
                var reg = new RegExp('^' + M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_([0-9a-zA-Z]+)$').exec(k);
                var m_id = reg && reg[1] ? reg[1] : null;
                if (!m_id) {
                    M.Logger.log('Model Record m_id not correct: ' + m_id, M.ERR);
                    continue; // if m_id does not exist, continue with next record element
                }
                var m = obj.model.createRecord($.extend(record, {m_id:m_id, state:M.STATE_VALID}));

                result.push(m);
            }
        }
        return result;
    },

    /**
     * Fetches a record from LocalStorage and checks whether automatic parsing by JSON.parse set the elements right.
     * Means: check whether resulting object's properties have the data type define by their model attribute object.
     * E.g. String containing a date is automatically transfered into a M.Date object when the model attribute has the data type
     * 'Date' set for this property.
     *
     * @param {String} key The key to fetch the element from LocalStorage
     * @param {Object} obj The param object, includes model
     * @returns {Object} record The record object. Includes all model record properties with correctly set data types.
     */
    buildRecord:function (key, obj) {
        var record = JSON.parse(localStorage.getItem(key));
        for (var i in record) {
            if (obj.model.__meta[i] && typeof(record[i]) !== obj.model.__meta[i].dataType.toLowerCase()) {
                switch (obj.model.__meta[i].dataType) {
                    case 'Date':
                        record[i] = M.Date.create(record[i]);
                        break;
                }
            }
        }
        return record;
    },

    /**
     * Returns all keys for model defined by modelName.
     *
     * @param {Object} obj The param obj, includes model
     * @returns {Object} keys All keys for model records in LocalStorage for a certain model identified by the model's name.
     */
    allKeys:function (obj) {
        var keys = [];
        for (var i = 0; i < localStorage.length; i++) {
            var k = localStorage.key(i)
            regexResult = new RegExp('^' + M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_').exec(k);
            if (regexResult) {
                keys.push(k);
            }
        }
        return keys;
    }

});
<commit_msg>Adding check for null as well<commit_after>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved.
//            (c) 2011 panacoda GmbH. All rights reserved.
// Creator:   Sebastian
// Date:      15.11.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

m_require('core/datastore/data_provider.js');

/**
 * @class
 *
 * Encapsulates access to LocalStorage (in-browser key value store).
 * LocalStorage is an in-browser key-value store to persist data.
 * This data provider persists model records as JSON strings with their name and id as key.
 * When fetching these strings from storage, their automatically converted in their corresponding model records.
 *
 * Operates synchronous.
 *
 * @extends M.DataProvider
 */
M.DataProviderLocalStorage = M.DataProvider.extend(
    /** @scope M.DataProviderLocalStorage.prototype */ {

    /**
     * The type of this object.
     * @type String
     */
    type:'M.DataProviderLocalStorage',

    /**
     * Saves a model record to the local storage
     * The key is the model record's name combined with id, value is stringified object
     * e.g.
     * Note_123 => '{ text: 'buy some food' }'
     *
     * @param {Object} that (is a model).
     * @returns {Boolean} Boolean indicating whether save was successful (YES|true) or not (NO|false).
     */
    save:function (obj) {
        try {
            //console.log(obj);
            /* add m_id to saved object */
            /*var a = JSON.stringify(obj.model.record).split('{', 2);
             a[2] = a[1];
             a[1] = '"m_id":' + obj.model.m_id + ',';
             a[0] = '{';
             var value = a.join('');*/
            var value = JSON.stringify(obj.model.record);
            localStorage.setItem(M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_' + obj.model.m_id, value);
            return YES;
        } catch (e) {
            M.Logger.log(M.WARN, 'Error saving ' + obj.model.record + ' to localStorage with key: ' + M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_' + this.m_id);
            return NO;
        }

    },

    /**
     * deletes a model from the local storage
     * key defines which one to delete
     * e.g. key: 'Note_123'
     *
     * @param {Object} obj The param obj, includes model
     * @returns {Boolean} Boolean indicating whether save was successful (YES|true) or not (NO|false).
     */
    del:function (obj) {
        try {
            if (localStorage.getItem(M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_' + obj.model.m_id)) { // check if key-value pair exists
                localStorage.removeItem(M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_' + obj.model.m_id);
                obj.model.recordManager.remove(obj.model.m_id);
                return YES;
            }
            return NO;
        } catch (e) {
            M.Logger.log(M.WARN, 'Error removing key: ' + M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_' + obj.model.m_id + ' from localStorage');
            return NO;
        }
    },

    /**
     * Finds all models of type defined by modelName that match a key or a simple query.
     * A simple query example: 'price < 2.21'
     * Right now, no AND or OR joins possible, just one query constraint.
     *
     * If no query is passed, all models are returned by calling findAll()
     * @param {Object} The param object containing e.g. the query or the key.
     * @returns {Object|Boolean} Returns an object if find is done with a key, an array of objects when a query is given or no parameter passed.
     * @throws Exception when query tries to compare two different data types
     */
    find:function (obj) {
        if (obj.key) {
            var record = this.findByKey(obj);
            if (!record) {
                return NO;
            }
            /*construct new model record with the saved id*/
            var reg = new RegExp('^' + M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_([0-9a-zA-Z]+)$').exec(obj.key);
            var m_id = reg && reg[1] ? reg[1] : null;
            if (!m_id) {
                M.Logger.log('retrieved model has no valid key: ' + obj.key, M.ERR);
                return NO;
            }
            var m = obj.model.createRecord($.extend(record, {m_id:m_id, state:M.STATE_VALID}));
            return m;
        }

        if (obj.query) {
            var q = obj.query;
            var missing = [];
            if (!q.identifier) {
                missing.push('identifier');
            }
            if (!q.operator) {
                missing.push('operator');
            }
            if (q.value === undefined || q.value === null) {
                missing.push('value');
            }

            if (missing.length > 0) {
                M.Logger.log('Wrong query format:', missing.join(', '), ' is/are missing.', M.WARN);
                return [];
            }

            var ident = q.identifier;
            var op = q.operator;
            var val = q.value;

            var res = this.findAll(obj);

            // check if query is correct in respect of data types
            if(res && res.length > 0) {
                var o = res[0];
                if (typeof(o.record[ident]) != o.__meta[ident].dataType.toLowerCase()) {
                    throw 'Query: "' + ident + op + val + '" tries to compare ' + typeof(o.record[ident]) + ' with ' + o.__meta[ident].dataType.toLowerCase() + '.';
                }
            }

            switch (op) {
                case '=':

                    res = _.select(res, function (o) {
                        return o.record[ident] === val;
                    });
                    break;

                case '~=': // => includes (works only on strings)

                    if(obj.model.__meta[ident].dataType.toLowerCase() !== 'string') {
                        throw 'Query: Operator "~=" only works on string properties. Property "' + ident + '" is of type ' + obj.model.__meta[ident].dataType.toLowerCase() + '.';
                    }
                    // escape all meta regex meta characters: \, *, +, ?, |, {, [, (,), ^, $,., # and space
                    var metaChars = ['\\\\', '\\*', '\\+', '\\?', '\\|', '\\{', '\\}', '\\[', '\\]', '\\(', '\\)', '\\^', '\\$', '\\.', '\\#'];

                    for(var i in metaChars) {
                        val = val.replace(new RegExp(metaChars[i], 'g'), '\\' + metaChars[i].substring(1,2));
                    }

                    // replace whitespaces with regex equivalent
                    val = val.replace(/\s/g, '\\s');

                    var regex = new RegExp(val);

                    res = _.select(res, function(o) {
                        return regex.test(o.record[ident]);
                    });

                    break;

                case '!=':
                    res = _.select(res, function (o) {
                        return o.record[ident] !== val;
                    });
                    break;
                case '<':
                    res = _.select(res, function (o) {
                        return o.record[ident] < val;
                    });
                    break;
                case '>':
                    res = _.select(res, function (o) {
                        return o.record[ident] > val;
                    });
                    break;
                case '<=':
                    res = _.select(res, function (o) {
                        return o.record[ident] <= val;
                    });
                    break;
                case '>=':
                    res = _.select(res, function (o) {
                        return o.record[ident] >= val;
                    });
                    break;
                default:
                    M.Logger.log('Query has unknown operator: ' + op, M.WARN);
                    res = [];
                    break;

            }

            return res;

        } else { /* if no query is passed, all models for modelName shall be returned */
            return this.findAll(obj);
        }
    },

    /**
     * Finds a record identified by the key.
     *
     * @param {Object} The param object containing e.g. the query or the key.
     * @returns {Object|Boolean} Returns an object identified by key, correctly built as a model record by calling
     * or a boolean (NO|false) if no key is given or the key does not exist in LocalStorage.
     * parameter passed.
     */
    findByKey:function (obj) {
        if (obj.key) {

            var reg = new RegExp('^' + M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX);
            /* assume that if key starts with local storage prefix, correct key is given, other wise construct it and key might be m_id */
            obj.key = reg.test(obj.key) ? obj.key : M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_' + obj.key;

            if (localStorage.getItem(obj.key)) { // if key is available
                return this.buildRecord(obj.key, obj)
            } else {
                return NO;
            }
        }
        M.Logger.log("Please provide a key.", M.WARN);
        return NO;
    },

    /**
     * Returns all models defined by modelName.
     *
     * Models are saved with key: Modelname_ID, e.g. Note_123
     *
     * @param {Object} obj The param obj, includes model
     * @returns {Object} The array of fetched objects/model records. If no records the array is empty.
     */
    findAll:function (obj) {
        var result = [];
        for (var i = 0; i < localStorage.length; i++) {
            var k = localStorage.key(i);
            regexResult = new RegExp('^' + M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_').exec(k);
            if (regexResult) {
                var record = this.buildRecord(k, obj);//JSON.parse(localStorage.getItem(k));

                /*construct new model record with the saved m_id*/
                var reg = new RegExp('^' + M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_([0-9a-zA-Z]+)$').exec(k);
                var m_id = reg && reg[1] ? reg[1] : null;
                if (!m_id) {
                    M.Logger.log('Model Record m_id not correct: ' + m_id, M.ERR);
                    continue; // if m_id does not exist, continue with next record element
                }
                var m = obj.model.createRecord($.extend(record, {m_id:m_id, state:M.STATE_VALID}));

                result.push(m);
            }
        }
        return result;
    },

    /**
     * Fetches a record from LocalStorage and checks whether automatic parsing by JSON.parse set the elements right.
     * Means: check whether resulting object's properties have the data type define by their model attribute object.
     * E.g. String containing a date is automatically transfered into a M.Date object when the model attribute has the data type
     * 'Date' set for this property.
     *
     * @param {String} key The key to fetch the element from LocalStorage
     * @param {Object} obj The param object, includes model
     * @returns {Object} record The record object. Includes all model record properties with correctly set data types.
     */
    buildRecord:function (key, obj) {
        var record = JSON.parse(localStorage.getItem(key));
        for (var i in record) {
            if (obj.model.__meta[i] && typeof(record[i]) !== obj.model.__meta[i].dataType.toLowerCase()) {
                switch (obj.model.__meta[i].dataType) {
                    case 'Date':
                        record[i] = M.Date.create(record[i]);
                        break;
                }
            }
        }
        return record;
    },

    /**
     * Returns all keys for model defined by modelName.
     *
     * @param {Object} obj The param obj, includes model
     * @returns {Object} keys All keys for model records in LocalStorage for a certain model identified by the model's name.
     */
    allKeys:function (obj) {
        var keys = [];
        for (var i = 0; i < localStorage.length; i++) {
            var k = localStorage.key(i)
            regexResult = new RegExp('^' + M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + obj.model.name + '_').exec(k);
            if (regexResult) {
                keys.push(k);
            }
        }
        return keys;
    }

});
<|endoftext|>


<commit_before>import { ASSEMBLER_INSTANCE_PROPERTY_NAME } from './core'

export class TargetAssembler {
    /**
     * Create the assembler instance and assemble the specified object
     * Initializes the object by all passed init arguments
     * @param {*} [init]
     * @param {*} [rest]
     */
    constructor(init, ...rest) {
        this.assemble(init)
        if(rest.length) {
            rest.forEach(init => this.init(init))
        }
    }

    /**
     * Instantiate and initialize the specified object
     * @param {*} [init] initializing dictionary
     * @returns {Object|*}
     */
    assemble(init) {
        const target = this.create(init)
        this.setInstance(target)
        this.init(init)
        return target
    }

    /**
     * Create the specified object
     * @param {*} [init] initializing dictionary
     * @returns {init}
     */
    create(init) {
        return init && init.constructor === Object?
            this.constructor.create(init) :
            this.constructor.create()
    }

    /**
     * Initialize the object with the defined properties
     * @param {*} init initializing dictionary
     * @returns {Object|*} initialized node
     */
    init(init) {
        const target = this._target
        if(init) {
            const constructor = this.constructor
            for(let prop in init) {
                const value = init[prop]
                if(value !== undefined) {
                    if(prop in this) this[prop] = value
                    else if(prop in constructor) void null
                    else if(prop in target) target[prop] = value
                    else this._onMismatch(prop, value)
                }
            }
        }
    }

    /**
     * @param {Object|*} target
     */
    setInstance(target) {
        this._target = target
        target[ASSEMBLER_INSTANCE_PROPERTY_NAME] = this
    }

    /**
     * @param {Object|*} target
     * @returns {TargetAssembler|*}
     */
    getInstance(target) {
        return target? this.constructor.getInstance(target) : null
    }

    /**
     * The init mismatch handler
     * @param {String} prop mismatched property name
     * @param {*} value mismatched property value
     */
    _onMismatch(prop, value) {
        const propval = prop + `="${ value }"`
        const name = this.name
        const message = `The property ${ propval } is not found on the ${ name } instance:`
        console.warn(message, this)
    }

    /**
     * Stub for extension
     */
    static create() {
        throw Error(`Could not create an abstract ${ this.name } instance!`)
    }

    /**
     * @param {Object|*} target
     * @returns {TargetAssembler|*|null}
     */
    static getInstance(target) {
        return target[ASSEMBLER_INSTANCE_PROPERTY_NAME] || null
    }
}

Object.defineProperty(
    TargetAssembler.prototype,
    '_target',
    {
        writable : true,
        value : null
    })
<commit_msg>TargetAssembler: _init private method<commit_after>import { ASSEMBLER_INSTANCE_PROPERTY_NAME } from './core'

export class TargetAssembler {
    /**
     * Create the assembler instance and assemble the specified object
     * Initializes the object by all passed init arguments
     * @param {*} [init]
     * @param {*} [rest]
     */
    constructor(init, ...rest) {
        this.assemble(init)
        if(rest.length) {
            rest.forEach(init => this._init(init))
        }
    }

    /**
     * Instantiate and initialize the specified object
     * @param {*} [init] initializing dictionary
     * @returns {Object|*}
     */
    assemble(init) {
        const target = this.create(init)
        this.setInstance(target)
        this.init(init)
        return target
    }

    /**
     * Create the specified object
     * @param {*} [init] initializing dictionary
     * @returns {init}
     */
    create(init) {
        return init && init.constructor === Object?
            this.constructor.create(init) :
            this.constructor.create()
    }

    /**
     * Initialize the object with the defined properties
     * @param {*} init initializing dictionary
     * @returns {Object|*} initialized node
     */
    init(init) {
        this._init(init)
    }

    _init(init) {
        const target = this._target
        if(init) {
            const constructor = this.constructor
            for(let prop in init) {
                const value = init[prop]
                if(value !== undefined) {
                    if(prop in this) this[prop] = value
                    else if(prop in constructor) void null
                    else if(prop in target) target[prop] = value
                    else this._onMismatch(prop, value)
                }
            }
        }
    }

    /**
     * @param {Object|*} target
     */
    setInstance(target) {
        this._target = target
        target[ASSEMBLER_INSTANCE_PROPERTY_NAME] = this
    }

    /**
     * @param {Object|*} target
     * @returns {TargetAssembler|*}
     */
    getInstance(target) {
        return target? this.constructor.getInstance(target) : null
    }

    /**
     * The init mismatch handler
     * @param {String} prop mismatched property name
     * @param {*} value mismatched property value
     */
    _onMismatch(prop, value) {
        const propval = prop + `="${ value }"`
        const name = this.name
        const message = `The property ${ propval } is not found on the ${ name } instance:`
        console.warn(message, this)
    }

    /**
     * Stub for extension
     */
    static create() {
        throw Error(`Could not create an abstract ${ this.name } instance!`)
    }

    /**
     * @param {Object|*} target
     * @returns {TargetAssembler|*|null}
     */
    static getInstance(target) {
        return target[ASSEMBLER_INSTANCE_PROPERTY_NAME] || null
    }
}

Object.defineProperty(
    TargetAssembler.prototype,
    '_target',
    {
        writable : true,
        value : null
    })
<|endoftext|>


<commit_before>module.exports = testla

//+ @type TestResult = {name: String, time: Number, passed: Array, failed: Array, skipped: Array}
//+ @type Dependencies = Object
//+ @type Tests = {Function} | Function
//+ @type Promise = {fork: Function}
//+ @type DI = {register: Function, inject: Function}
var assert = require('asserts')
var fn = require('fn')
var DI = require('dependency-injector')
var Observer = require('Observer')
var Promise = require('fantasy-promises')

var INCOMPLETE = {}
var PASSED = 1
var FAILED = 2
var SKIPPED = 3

//+ prepareTests :: DI, Tests -> { run: Function }
function prepareTests(instance, tests) {
  var mapOfTests = typeof tests === 'function'
    ? instance.inject(tests).call()
    : tests

  return { run: fn.curry(runAllTests, mapOfTests) }
}

//+ foldPromises :: Function, [Promise], Any -> Promise
function foldPromises(f, arr, acc) {
  return fn.foldl(arr, function (a, b) {
    return fn.lift2(f, a, b)
  }, Promise.of(acc))
}

//+ runAllTests :: Tests, Function, Function -> Promise
function runAllTests(tests, runner, formatter) {
  var promisedTests = fn.pairs(tests).map(runner)
  var accumulator = { passed: [], failed: [], skipped: [], time: 0 }
  var reduce = function (a, b) { return fn.foldl([a, b], formatter) }

  return foldPromises(reduce, promisedTests, accumulator)
}

//+ computeResult :: String, Number, Any -> TestResult
function computeResult(name, startTime, result) {
  var test = {
    name: name,
    time: Date.now() - startTime
  }
  var report = fn.mergeInto({}, test)

  test.failed = []
  test.passed = []
  test.skipped = []

  if (result instanceof Error) {
    report.status = FAILED
    test.failed.push(report)
  } else if (result === INCOMPLETE) {
    report.status = SKIPPED
    test.skipped.push(report)
  } else {
    report.status = PASSED
    test.passed.push(report)
  }

  report.result = result

  return test
}

//- runTest :: DI, [String, Function] -> Promise TestResult
//+ runTest :: DI, [String, Function] -> Promise
function runTest(instance, testPair) {
  var name = testPair[0]
  var test_fn = testPair[1]

  // skip tests that begin with an underscore
  if (name[0] === '_') {
    return Promise.of(computeResult(name, Date.now(), INCOMPLETE))
  }

  return new Promise(function (resolve, reject) {
    var startTime = Date.now()
    var doResolve = fn.comp(resolve, function (value) {
      return computeResult(name, startTime, value)
    })
    var promise = { resolve: doResolve, reject: reject }

    try {
      var result = instance.inject(test_fn, {
        promise: promise,
        spy: new Observer()
      }).call()

      return result === promise ? null : doResolve(result)
    } catch (e) {
      if (e.name === 'AssertionError') {
        return doResolve(e)
      }
      console.error(name)
      return reject(e)
    }
  })
}

//+ getFormatter :: String -> Function -> Object, Object -> TestResult
function getFormatter(name) {
  return function (a, b) {
    return {
      name: name,
      time: a.time + b.time,
      passed: a.passed.concat(b.passed),
      failed: a.failed.concat(b.failed),
      skipped: a.skipped.concat(b.skipped)
    }
  }
}

//+ testla :: String, Tests, Dependencies -> Promise
function testla(name, tests, dependencies) {
  var instance = new DI(fn.mergeInto({ assert: assert }, dependencies))
  var runner = fn.curry(runTest, instance)

  return prepareTests(instance, tests).run(runner, getFormatter(name))
}
<commit_msg>Fix for node v0.6<commit_after>module.exports = testla

//+ @type TestResult = {name: String, time: Number, passed: Array, failed: Array, skipped: Array}
//+ @type Dependencies = Object
//+ @type Tests = {Function} | Function
//+ @type Promise = {fork: Function}
//+ @type DI = {register: Function, inject: Function}
var assert = require('asserts')
var fn = require('fn')
var DI = require('dependency-injector')
var Observer = require('observer')
var Promise = require('fantasy-promises')

var INCOMPLETE = {}
var PASSED = 1
var FAILED = 2
var SKIPPED = 3

//+ prepareTests :: DI, Tests -> { run: Function }
function prepareTests(instance, tests) {
  var mapOfTests = typeof tests === 'function'
    ? instance.inject(tests).call()
    : tests

  return { run: fn.curry(runAllTests, mapOfTests) }
}

//+ foldPromises :: Function, [Promise], Any -> Promise
function foldPromises(f, arr, acc) {
  return fn.foldl(arr, function (a, b) {
    return fn.lift2(f, a, b)
  }, Promise.of(acc))
}

//+ runAllTests :: Tests, Function, Function -> Promise
function runAllTests(tests, runner, formatter) {
  var promisedTests = fn.pairs(tests).map(runner)
  var accumulator = { passed: [], failed: [], skipped: [], time: 0 }
  var reduce = function (a, b) { return fn.foldl([a, b], formatter) }

  return foldPromises(reduce, promisedTests, accumulator)
}

//+ computeResult :: String, Number, Any -> TestResult
function computeResult(name, startTime, result) {
  var test = {
    name: name,
    time: Date.now() - startTime
  }
  var report = fn.mergeInto({}, test)

  test.failed = []
  test.passed = []
  test.skipped = []

  if (result instanceof Error) {
    report.status = FAILED
    test.failed.push(report)
  } else if (result === INCOMPLETE) {
    report.status = SKIPPED
    test.skipped.push(report)
  } else {
    report.status = PASSED
    test.passed.push(report)
  }

  report.result = result

  return test
}

//- runTest :: DI, [String, Function] -> Promise TestResult
//+ runTest :: DI, [String, Function] -> Promise
function runTest(instance, testPair) {
  var name = testPair[0]
  var test_fn = testPair[1]

  // skip tests that begin with an underscore
  if (name[0] === '_') {
    return Promise.of(computeResult(name, Date.now(), INCOMPLETE))
  }

  return new Promise(function (resolve, reject) {
    var startTime = Date.now()
    var doResolve = fn.comp(resolve, function (value) {
      return computeResult(name, startTime, value)
    })
    var promise = { resolve: doResolve, reject: reject }

    try {
      var result = instance.inject(test_fn, {
        promise: promise,
        spy: new Observer()
      }).call()

      return result === promise ? null : doResolve(result)
    } catch (e) {
      if (e.name === 'AssertionError') {
        return doResolve(e)
      }
      console.error(name)
      return reject(e)
    }
  })
}

//+ getFormatter :: String -> Function -> Object, Object -> TestResult
function getFormatter(name) {
  return function (a, b) {
    return {
      name: name,
      time: a.time + b.time,
      passed: a.passed.concat(b.passed),
      failed: a.failed.concat(b.failed),
      skipped: a.skipped.concat(b.skipped)
    }
  }
}

//+ testla :: String, Tests, Dependencies -> Promise
function testla(name, tests, dependencies) {
  var instance = new DI(fn.mergeInto({ assert: assert }, dependencies))
  var runner = fn.curry(runTest, instance)

  return prepareTests(instance, tests).run(runner, getFormatter(name))
}
<|endoftext|>


<commit_before>

// var markers = [];
// var map;
// var brownUniversity = new google.maps.LatLng(41.8262, -71.4032);

// var MY_MAPTYPE_ID = 'style';

// function initialize() {

//      // This event listener will call addMarker() when the map is clicked.
//      google.maps.event.addListener(map, 'click', function(event) {
//        addMarker(event.:atLng);
//      });

//   var mapOptions = {
//     zoom: 14,
//     center: brownUniversity,
//     mapTypeControlOptions: {
//       mapTypeIds: [google.maps.MapTypeId.ROADMAP, MY_MAPTYPE_ID]
//     },
//     mapTypeId: MY_MAPTYPE_ID
//   };

//   map = new google.maps.Map(document.getElementById('center'),
//       mapOptions);

//   var styledMapOptions = {
//     name: 'Style'
//   };

//   var customMapType = new google.maps.StyledMapType(featureOpts, styledMapOptions);

//   map.mapTypes.set(MY_MAPTYPE_ID, customMapType);

//   addMarker(brownUniversity);
// }

//   // Add a marker to the map and push to the array.

//      function addMarker(location) {
//        var marker = new google.maps.Marker({
//          position: location,
//          map: map
//        });
//        markers.push(marker);
//      }

//      // Sets the map on all markers in the array.
//      function setAllMap(map) {
//        for (var i = 0; i < markers.length; i++) {
//          markers[i].setMap(map);
//        }
//      }

//      // Removes the markers from the map, but keeps them in the array.
//      function clearMarkers() {
//        setAllMap(null);
//      }
//      // Shows any markers currently in the array.
//      function showMarkers() {
//        setAllMap(map);
//      }

//      // Deletes all markers in the array by removing references to them.
//      function deleteMarkers() {
//        clearMarkers();
//        markers = [];
//      }

// google.maps.event.addDomListener(window, 'load', initialize);

var map;
var markers = [];
var MY_MAPTYPE_ID = 'style';

function initialize() {
	var featureOpts = [
	  {
	    stylers: [
	      { hue: '#555555' },
	    	{ lightness: 50},
	      { visibility: 'simplified' },
	      {gamma: 0.5},
	      { weight: 0.5 }
	    ]
	  },
	  {
	    elementType: 'labels',
	    stylers: [
	      { visibility: 'on' }
	    ]
	  },
	    ];
  var brownUniversity = new google.maps.LatLng(41.8262, -71.4032);
  var mapOptions = {
    zoom: 12,
    center: brownUniversity,
    mapTypeId: google.maps.MapTypeId.TERRAIN
  };
  map = new google.maps.Map(document.getElementById('center'),
      mapOptions);

  // This event listener will call addMarker() when the map is clicked.
  google.maps.event.addListener(map, 'click', function(event) {
    addMarker(event.latLng);
  });
}

// Add a marker to the map and push to the array.
function addMarker(location) {
  var marker = new google.maps.Marker({
    position: location,
    map: map
  });
  markers.push(marker);
}

// Sets the map on all markers in the array.
function setAllMap(map) {
  for (var i = 0; i < markers.length; i++) {
    markers[i].setMap(map);
  }
}

// Removes the markers from the map, but keeps them in the array.
function clearMarkers() {
  setAllMap(null);
}

// Shows any markers currently in the array.
function showMarkers() {
  setAllMap(map);
}

// Deletes all markers in the array by removing references to them.
function deleteMarkers() {
  clearMarkers();
  markers = [];
}

google.maps.event.addDomListener(window, 'load', initialize);<commit_msg>GEOLOCATION BITCH<commit_after>var map;
var brownUniversity = new google.maps.LatLng(41.8262, -71.4032);
var markers = [];
var MY_MAPTYPE_ID = 'style';

function initialize() {

  var featureOpts = [
    {
      stylers: [
        { hue: '#555555' },
      	{ lightness: 50},
        { visibility: 'simplified' },
        {gamma: 0.5},
        { weight: 0.5 }
      ]
    },
    {
      elementType: 'labels',
      stylers: [
        { visibility: 'on' }
      ]
    },
      ];

  var mapOptions = {
    zoom: 14,
    center: brownUniversity,
    mapTypeControlOptions: {
      mapTypeIds: [google.maps.MapTypeId.ROADMAP, MY_MAPTYPE_ID]
    },
    mapTypeId: MY_MAPTYPE_ID
  };

  map = new google.maps.Map(document.getElementById('center'),
      mapOptions);

  var styledMapOptions = {
    name: 'Style'
  };

  var customMapType = new google.maps.StyledMapType(featureOpts, styledMapOptions);

  map.mapTypes.set(MY_MAPTYPE_ID, customMapType);
  google.maps.event.addListener(map, 'click', function(event) {
    addMarker(event.latLng);
  });
}

// Add a marker to the map and push to the array.
function addMarker(location) {
  var marker = new google.maps.Marker({
    position: location,
    map: map
  });
  markers.push(marker);
}

// Sets the map on all markers in the array.
function setAllMap(map) {
  for (var i = 0; i < markers.length; i++) {
    markers[i].setMap(map);
  }
}

// Removes the markers from the map, but keeps them in the array.
function clearMarkers() {
  setAllMap(null);
}

// Shows any markers currently in the array.
function showMarkers() {
  setAllMap(map);
}

// Deletes all markers in the array by removing references to them.
function deleteMarkers() {
  clearMarkers();
  markers = [];
}

google.maps.event.addDomListener(window, 'load', initialize);

////////////////////////////////////////////////////////////////////////////////////////////////////

// var map;

// var MY_MAPTYPE_ID = 'style';
// var brownUniversity = new google.maps.LatLng(41.8262, -71.4032);

// function initialize() {
// 	var featureOpts = [
// 	  {
// 	    stylers: [
// 	      { hue: '#555555' },
// 	    	{ lightness: 50},
// 	      { visibility: 'simplified' },
// 	      {gamma: 0.5},
// 	      { weight: 0.5 }
// 	    ]
// 	  },
// 	  {
// 	    elementType: 'labels',
// 	    stylers: [
// 	      { visibility: 'on' }
// 	    ]
// 	  },
// 	    ];

//   var mapOptions = {
//     zoom: 12,
//     center: brownUniversity,
//     mapTypeIds: [google.maps.MapTypeId.ROADMAP, MY_MAPTYPE_ID]
//   };
//     mapTypeId: MY_MAPTYPE_ID
//   	map = new google.maps.Map(document.getElementById('center'),
//       mapOptions);

//   var customMapType = new google.maps.StyledMapType(featureOpts, styledMapOptions);

//   map.mapTypes.set(MY_MAPTYPE_ID, customMapType);

//   var styledMapOptions = {
//     name: 'style'
//   };

//   // This event listener will call addMarker() when the map is clicked.
//   google.maps.event.addListener(map, 'click', function(event) {
//     addMarker(event.latLng);
//   });
// }

// google.maps.event.addDomListener(window, 'load', initialize);<|endoftext|>


<commit_before><commit_msg>Introduce inject HOC to inect app().xxx domains etc<commit_after><|endoftext|>


<commit_before><commit_msg>changing timeit syntax<commit_after><|endoftext|>


<commit_before><commit_msg>Made maplegend optional<commit_after><|endoftext|>


<commit_before><commit_msg>“user state known” directives<commit_after><|endoftext|>


<commit_before><commit_msg>Authorize additional post request.<commit_after><|endoftext|>


<commit_before><commit_msg>remove baby-legs endpoint from server side<commit_after><|endoftext|>


<commit_before><commit_msg>Added Simple.GenerateArray() function.<commit_after><|endoftext|>


<commit_before>
Seed({
		name : "Mold.Lib.Template",
		dna : "class",
		version : "0.0.3",
		include : [
			"Mold.Lib.Tree",
			"Mold.Lib.TreeFactory",
			"Mold.Lib.Event",
			"Mold.Lib.TemplateFilter",
			"Mold.Lib.Sanitize"
		],
		browserInclude : [
			"Mold.Lib.Directive",
			"Mold.Defaults.TemplateDirectives"
		],
		nodeInclude : [
			"Mold.Lib.Document"
		],
		test : "Mold.Test.Lib.Template"
	},
	function(content, config){

		var that = this,
			_config = config || {},
			_templateContent = "",
			_shadowTemplate = false,
			_compiledTemplate = false,
			_container = false,
			_viewModel = {},
			_snatched = {},
			_contentType = false,
			_doc = false,
			_testMode = false,
			_target = false,
			_tid = Mold.getId(),
			undefined;

		Mold.mixin(this, new Mold.Lib.Event(this));

		if(Mold.isNodeJS || _testMode){
			_doc = new Mold.Lib.Document();
		}else{
			_doc = document;
		}

		var _hideTemplate = function(element){

			Mold.each(element, function(element){
				if(element.childs && element.childs[0]){
					_hideTemplate(element.childs[0]);
				}
				element.hide();
			});

		}

		var _parseTemplate = function(templateContent){
			_applyToDom(templateContent);
			Mold.Lib.TreeFactory.preParseTemplate(_shadowTemplate);
			var tree = _buildTree();
			if(!Mold.isNodeJS){
				that.on("after.init", function(){
					var addDirectives = function(scope){
						Mold.each(Mold.Defaults.TemplateDirectives, function(directive){
							directive._id = directive.name +"_"+that._eid;
							Mold.Lib.Directive.add(
								directive,
								scope,
								that
							);
						});

					}

					addDirectives(_shadowTemplate);
				});
			}
			return tree;
		}

		var _parseElement = function(templateElement){
			_shadowTemplate = templateElement;
			Mold.Lib.TreeFactory.preParseTemplate(_shadowTemplate);
			var tree = _buildTree();
			return tree;
		}

		var _copyNodesToElements = function(target, node){
			while (node.hasChildNodes()) {
  				target.appendChild(node.removeChild(node.firstChild))
			}
		}

		var _applyToDom = function(template){
			_shadowTemplate =  _doc.createElement("div"); //_doc.createDocumentFragment();
			if(!_config.disableSanitizer){
				var sanitizer =  new Mold.Lib.Sanitize();
				_shadowTemplate.innerHTML = sanitizer.html(template);
			}else{
				_shadowTemplate.innerHTML = template;
			}
			_shadowTemplate.moldTemplate = that;
			_target = _shadowTemplate;
		}

		var _firstElement = function(){
			var next = _target.firstChild;
			var selected = false;
			while (next) {
				if(next.nodeType === 1){
					selected = next;
				}
  				next = next.nextSibling;
			}
			return selected;
		}

		var _appendTo = function(target){

			var addDirectives = function(){
				Mold.each(Mold.Defaults.TemplateDirectives, function(directive){
					Mold.Lib.Directive.add(
						directive,
						target,
						that
					);
				});
			}
			target.moldTemplate = _shadowTemplate.moldTemplate;
			while(_shadowTemplate.hasChildNodes()){
				var targetObserver = new Mold.Lib.Event(_shadowTemplate.firstChild);
				targetObserver.on("DOMNodeInserted", addDirectives);
				target.appendChild(_shadowTemplate.removeChild(_shadowTemplate.firstChild));

			}
			_target = target;
		}

		var _buildTree = function(){
			var tree = Mold.Lib.TreeFactory.parseDomTree(_shadowTemplate, new Mold.Lib.Tree("root", false, false, false, that), that);
			return tree;
		}

		var _triggerEvent = function(name, e){
			var data = _viewModel;
			if(_snatched[name]){
				var result = _snatched[name].call(this, data);
				if(result === false){
					return false;
				}
			}
			Mold.mixin(data, e);
			this.trigger(name.split("@")[1], data)
		}

		var _hasVar = function(name, tree){
			name = name.replace("{{", "").replace("}}", "");
			var output = false;
			Mold.each(tree, function(treeValue, treeName){
				if(name === treeName){
					 output = true;
					 return "break";
				}else{
					if(treeValue.childs.length){
						Mold.each(treeValue.childs, function(child){
							output = (_hasVar(name, child)) ? true : output
						})

					}
				}

			});
			return output;
		}

		var _viewModelObject = {
			set : function(model, name, value){
				_viewModel[model] = _viewModel[model] || {};
				_viewModel[model][name] = value;
				that.trigger("viewmodel.change", { model : _viewModel, modelname : model, name : name, value : value })
				return _viewModel[model][name];
			},
			get : function(model, name){
				if(!model && !name){
					return _viewModel;
				}
				if(_viewModel[model] && _viewModel[model][name]){
					return _viewModel[model][name];
				}
				return false;
			},
			remove : function(model, name){
				if(_viewModel[model] && _viewModel[model][name]){
					delete _viewModel[model][name];
					return true;
				}
				return false;
			}
		}

		var _addData = function(template, data, bind){

				Mold.each(template, function(element, name){
					if(data[name] != undefined){

						if(Mold.isArray(data[name])){
							if(bind){
								data[name].on("list.item.add", function(e){

									var filterResult = true;

									if(element.filter && element.filter.length){
										//_applyFilter(element);
									}

									//if(filterResult){
										if(!element.childs[e.data.index]){
											element.add();
										}else{
											element.show();
										}

										_addData(element.childs[e.data.index], e.data.value, bind);
									//}

								}).on("list.item.remove", function(e){
									element.remove(e.data.index);
								}).on("list.item.change", function(e){
									_addData(element.childs[e.data.index], e.data.value, bind)
								});
							}
							Mold.each(data[name], function(selectedData, index){
								if(!element.childs[index]){
									element.add();
								}else{
									element.show();
								}
								_addData(element.childs[index], selectedData, bind);
							})
						}else{
							element.setValue(data[name])

							if(bind){
								data.on("property.change."+name, function(e){
									element.setValue(e.data.value)
								});
							}
						}

					}

				});
		}

		var _each = function(element, callback){

			if(element.childs && element.childs.length){
				Mold.each(element.childs, function(childElement){

					Mold.each(childElement, function(selected, name){
						callback.call(this, selected, name);
						_each(selected, callback);
					});
				});
			}
		}

		var _visibility = function(element, callback){
			var rowcount = -1;
			if(element.childs && element.childs.length){
				var i = 0,
					len = element.childs.length;

				for(; i < len; i++){
					var selected = element.childs[i];
					rowcount++;
					if(
						Mold.some(selected, function(selectedChild, name){
							var output = callback.call(this, selectedChild, rowcount);
							if(output === "exit"){
								i = len;
								return false;
							}
							return output;
						})
					){
						element.show(false, i);
					}else{
						element.hide(i);
					}
				}
			}
		}

		var _applyFilter = function(element){

			if(element.filter && element.filter.length){
				Mold.each(element.filter, function(filterName){
					var filterParts = filterName.split(":");
					filterName =  filterParts[0];
					var filterParameter = (filterParts[1]) ? filterParts[1] : false;

					var filter = Mold.Lib.TemplateFilter.get(filterName);
					if(filter){
						switch (filter.select){
							case "child":
								switch (filter.type){
									case "visibility" :
										_visibility(element, function(child, rowcount){
											return filter.action.call(this, that, {
												child : child,
												viewModel : _viewModel,
												element : element,
												rowcount : rowcount,
												parameter : filterParameter
											});
										});
										break;
									default:
										break;
								}
								break;
							default:
								break;
						}
					}
				});
			}
		}

		var _refresh = function(){

			switch(_contentType){
				case "string":
					_compiledTemplate = _parseTemplate(_templateContent);
					break;
				case "node":
					_compiledTemplate = _parseElement(_templateContent);
					break;
				default:
					break;
			}
		}

		if(_config.parseAsString){
			_shadowTemplate = {}
			_compiledTemplate = Mold.Lib.TreeFactory.parseString(_shadowTemplate, content);
			this.trigger("ready");
		}else{
			if(typeof content === "function"){

				_templateContent = content.toString().replace(/(^function\s*\(\)\s*\{\s*\/\*\|)([\s\S]*)(\|\*\/\s*\})$/g, function(){
					return arguments[2];
				});

				//Safari Bugfix
				_templateContent = _templateContent.replace(/^function\s*\(\)\s*\{\s*\/\*\|/g, '');
				_templateContent = _templateContent.replace(/\|\*\/\s*\}$/g, '');

				_templateContent = _templateContent.replace(/ style=/g, ' mold-style=');

				_contentType = "string";
				_compiledTemplate = _parseTemplate(_templateContent);
				this.trigger("ready");
			}else if(Mold.isNode(content)){
				_templateContent = content;
				_contentType = "node"
				_compiledTemplate = _parseElement(_templateContent);
			}else{
				console.log("is nothing")
			}
		}

		this.publics = {
			viewModel : _viewModelObject,
			triggerEvent : _triggerEvent,
			applyFilter : _applyFilter,
			visibility : _visibility,
			each : function(callback){
				_each(_compiledTemplate, callback);
			},
			refresh : function(){
				_refresh();
			},
			snatch : function(data){
				Mold.each(data, function(callback, name){
					_snatched[name] = callback;
				});
				return this;
			},
/**
* @namespace Mold.Lib.Template
* @methode bind
* @desc  bind a Mold model to the Template
* @public
* @return (Object)  returns this;
* @param (model) object - the modelt
**/
			bind : function(model){
				if(!_compiledTemplate){
					throw "Template not compiled!";
				}
				if(model){
					_addData(_compiledTemplate.childs[0], model.data, true);
				}
				return that;
			},
/**
* @namespace Mold.Lib.Template
* @methode unbind
* @desc  unbind a Mold model from the Template
* @public
* @return (Object)  returns this;
* @param (model) object - the modelt
**/
			unbind : function(model){

				return this;
			},
/**
* @namespace Mold.Lib.Template
* @methode append
* @desc  append a Mold model to the Template, without bindings
* @public
* @return (Object)  returns this;
* @param (model) object - the model
**/
			append : function(model){
				if(!_compiledTemplate){
					throw "Template not compiled!";
				}
				if(model.className && model.className === "Mold.Lib.Model"){
					_addData(_compiledTemplate.childs[0], model.data, false);
				}else{
					_addData(_compiledTemplate.childs[0], model, false);
				}
				return this;
			},
/**
* @namespace Mold.Lib.Template
* @methode tree
* @desc  returns the template-tree
* @public
* @return (Object)  the template-tree;
**/
			tree : function(){
				return _compiledTemplate;
			},

			hasVar : function(name){
				return _hasVar(name, _compiledTemplate.childs[0]);
			},

/**
* @namespace Mold.Lib.Template
* @methode get
* @desc  returns the parsed templates main dom node
* @public
* @return (node)  returns the parsed Template
**/
			get : function(){
				if(_config.parseAsString){
					return _shadowTemplate.nodeValue;
				}
				if(Mold.isNodeJS){
					return _shadowTemplate.innerHTML;
				}else{
					return _shadowTemplate;
				}
			},
			getFirst : function(){
				return _firstElement();
			},
			appendTo : function(target){
				return _appendTo(target);
			},
/**
* @namespace Mold.Lib.Template
* @methode getInner
* @desc  returns the parsed template dom nodes without main node
* @public
* @return (node)  returns the parsed Tempalte inner nodes
**/
			getInner : function(){
				return _shadowTemplate.childNodes;
			}

		}

	}
);<commit_msg>performance added<commit_after>
Seed({
		name : "Mold.Lib.Template",
		dna : "class",
		version : "0.0.3",
		include : [
			"Mold.Lib.Tree",
			"Mold.Lib.TreeFactory",
			"Mold.Lib.Event",
			"Mold.Lib.TemplateFilter",
			"Mold.Lib.Sanitize"
		],
		browserInclude : [
			"Mold.Lib.Directive",
			"Mold.Defaults.TemplateDirectives"
		],
		nodeInclude : [
			"Mold.Lib.Document"
		],
		test : "Mold.Test.Lib.Template"
	},
	function(content, config){

		var that = this,
			_config = config || {},
			_templateContent = "",
			_shadowTemplate = false,
			_compiledTemplate = false,
			_container = false,
			_viewModel = {},
			_snatched = {},
			_contentType = false,
			_doc = false,
			_testMode = false,
			_target = false,
			_tid = Mold.getId(),
			undefined;

		Mold.mixin(this, new Mold.Lib.Event(this));

		if(Mold.isNodeJS || _testMode){
			_doc = new Mold.Lib.Document();
		}else{
			_doc = document;
		}

		var _hideTemplate = function(element){

			Mold.each(element, function(element){
				if(element.childs && element.childs[0]){
					_hideTemplate(element.childs[0]);
				}
				element.hide();
			});

		}

		var _parseTemplate = function(templateContent){
			_applyToDom(templateContent);
			Mold.Lib.TreeFactory.preParseTemplate(_shadowTemplate);
			var tree = _buildTree();
			if(!Mold.isNodeJS){
				that.on("after.init", function(){
					var addDirectives = function(scope){
						Mold.each(Mold.Defaults.TemplateDirectives, function(directive){
							directive._id = directive.name +"_"+that._eid;
							Mold.Lib.Directive.add(
								directive,
								scope,
								that
							);
						});

					}

					addDirectives(_shadowTemplate);
				});
			}
			return tree;
		}

		var _parseElement = function(templateElement){
			_shadowTemplate = templateElement;
			Mold.Lib.TreeFactory.preParseTemplate(_shadowTemplate);
			var tree = _buildTree();
			return tree;
		}

		var _copyNodesToElements = function(target, node){
			while (node.hasChildNodes()) {
  				target.appendChild(node.removeChild(node.firstChild))
			}
		}

		var _applyToDom = function(template){
			_shadowTemplate =  _doc.createElement("div"); //_doc.createDocumentFragment();
			if(!_config.disableSanitizer){
				var sanitizer =  new Mold.Lib.Sanitize();
				_shadowTemplate.innerHTML = sanitizer.html(template);
			}else{
				_shadowTemplate.innerHTML = template;
			}
			_shadowTemplate.moldTemplate = that;
			_target = _shadowTemplate;
		}

		var _firstElement = function(){
			var next = _target.firstChild;
			var selected = false;
			while (next) {
				if(next.nodeType === 1){
					selected = next;
				}
  				next = next.nextSibling;
			}
			return selected;
		}

		var _appendTo = function(target){

			var addDirectives = function(){
				Mold.each(Mold.Defaults.TemplateDirectives, function(directive){
					Mold.Lib.Directive.add(
						directive,
						target,
						that
					);
				});
			}
			target.moldTemplate = _shadowTemplate.moldTemplate;
			while(_shadowTemplate.hasChildNodes()){
				var targetObserver = new Mold.Lib.Event(_shadowTemplate.firstChild);
				targetObserver.on("DOMNodeInserted", addDirectives);
				target.appendChild(_shadowTemplate.removeChild(_shadowTemplate.firstChild));

			}
			_target = target;
		}

		var _buildTree = function(){
			var tree = Mold.Lib.TreeFactory.parseDomTree(_shadowTemplate, new Mold.Lib.Tree("root", false, false, false, that), that);
			return tree;
		}

		var _triggerEvent = function(name, e){
			var data = _viewModel;
			if(_snatched[name]){
				var result = _snatched[name].call(this, data);
				if(result === false){
					return false;
				}
			}
			Mold.mixin(data, e);
			this.trigger(name.split("@")[1], data)
		}

		var _hasVar = function(name, tree){
			name = name.replace("{{", "").replace("}}", "");
			var output = false;
			Mold.each(tree, function(treeValue, treeName){
				if(name === treeName){
					 output = true;
					 return "break";
				}else{
					if(treeValue.childs.length){
						Mold.each(treeValue.childs, function(child){
							output = (_hasVar(name, child)) ? true : output
						})

					}
				}

			});
			return output;
		}

		var _viewModelObject = {
			set : function(model, name, value){
				_viewModel[model] = _viewModel[model] || {};
				_viewModel[model][name] = value;
				that.trigger("viewmodel.change", { model : _viewModel, modelname : model, name : name, value : value })
				return _viewModel[model][name];
			},
			get : function(model, name){
				if(!model && !name){
					return _viewModel;
				}
				if(_viewModel[model] && _viewModel[model][name]){
					return _viewModel[model][name];
				}
				return false;
			},
			remove : function(model, name){
				if(_viewModel[model] && _viewModel[model][name]){
					delete _viewModel[model][name];
					return true;
				}
				return false;
			}
		}

		var countAddData = 0;
		var addTime = 0;
		var _addData = function(template, data, bind){
				countAddData++;

				Mold.each(template, function(element, name){
					if(data[name] != undefined){

						if(Mold.isArray(data[name])){
							if(bind){
								data[name].on("list.item.add", function(e){

									var filterResult = true;

									if(element.filter && element.filter.length){
										//_applyFilter(element);
									}

									//if(filterResult){
										if(!element.childs[e.data.index]){
											element.add();

										}else{
											element.show();
										}

										_addData(element.childs[e.data.index], e.data.value, bind);
									//}

								}).on("list.item.remove", function(e){
									element.remove(e.data.index);
								}).on("list.item.change", function(e){
									_addData(element.childs[e.data.index], e.data.value, bind);

								});
							}
							Mold.each(data[name], function(selectedData, index){
								if(!element.childs[index]){
									element.add();
								}else{
									element.show();
								}
								_addData(element.childs[index], selectedData, bind);
							})
						}else{

							element.setValue(data[name]);

							if(bind){
								data.on("property.change."+name, function(e){
									element.setValue(e.data.value)
								});
							}
						}

					}

				});

		}

		var _each = function(element, callback){

			if(element.childs && element.childs.length){
				Mold.each(element.childs, function(childElement){

					Mold.each(childElement, function(selected, name){
						callback.call(this, selected, name);
						_each(selected, callback);
					});
				});
			}
		}

		var _visibility = function(element, callback){
			var rowcount = -1;
			if(element.childs && element.childs.length){
				var i = 0,
					len = element.childs.length;

				for(; i < len; i++){
					var selected = element.childs[i];
					rowcount++;
					if(
						Mold.some(selected, function(selectedChild, name){
							var output = callback.call(this, selectedChild, rowcount);
							if(output === "exit"){
								i = len;
								return false;
							}
							return output;
						})
					){
						element.show(false, i);
					}else{
						element.hide(i);
					}
				}
			}
		}

		var _applyFilter = function(element){

			if(element.filter && element.filter.length){
				Mold.each(element.filter, function(filterName){
					var filterParts = filterName.split(":");
					filterName =  filterParts[0];
					var filterParameter = (filterParts[1]) ? filterParts[1] : false;

					var filter = Mold.Lib.TemplateFilter.get(filterName);
					if(filter){
						switch (filter.select){
							case "child":
								switch (filter.type){
									case "visibility" :
										_visibility(element, function(child, rowcount){
											return filter.action.call(this, that, {
												child : child,
												viewModel : _viewModel,
												element : element,
												rowcount : rowcount,
												parameter : filterParameter
											});
										});
										break;
									default:
										break;
								}
								break;
							default:
								break;
						}
					}
				});
			}
		}

		var _refresh = function(){

			switch(_contentType){
				case "string":
					_compiledTemplate = _parseTemplate(_templateContent);
					break;
				case "node":
					_compiledTemplate = _parseElement(_templateContent);
					break;
				default:
					break;
			}
		}

		if(_config.parseAsString){
			_shadowTemplate = {}
			_compiledTemplate = Mold.Lib.TreeFactory.parseString(_shadowTemplate, content);
			this.trigger("ready");
		}else{
			if(typeof content === "function"){

				_templateContent = content.toString().replace(/(^function\s*\(\)\s*\{\s*\/\*\|)([\s\S]*)(\|\*\/\s*\})$/g, function(){
					return arguments[2];
				});

				//Safari Bugfix
				_templateContent = _templateContent.replace(/^function\s*\(\)\s*\{\s*\/\*\|/g, '');
				_templateContent = _templateContent.replace(/\|\*\/\s*\}$/g, '');

				_templateContent = _templateContent.replace(/ style=/g, ' mold-style=');

				_contentType = "string";
				_compiledTemplate = _parseTemplate(_templateContent);
				this.trigger("ready");
			}else if(Mold.isNode(content)){
				_templateContent = content;
				_contentType = "node"
				_compiledTemplate = _parseElement(_templateContent);
			}else{
				console.log("is nothing")
			}
		}

		this.publics = {
			viewModel : _viewModelObject,
			triggerEvent : _triggerEvent,
			applyFilter : _applyFilter,
			visibility : _visibility,
			each : function(callback){
				_each(_compiledTemplate, callback);
			},
			refresh : function(){
				_refresh();
			},
			snatch : function(data){
				Mold.each(data, function(callback, name){
					_snatched[name] = callback;
				});
				return this;
			},
/**
* @namespace Mold.Lib.Template
* @methode bind
* @desc  bind a Mold model to the Template
* @public
* @return (Object)  returns this;
* @param (model) object - the modelt
**/
			bind : function(model){
				if(!_compiledTemplate){
					throw "Template not compiled!";
				}
				if(model){
					_addData(_compiledTemplate.childs[0], model.data, true);
				}
				return that;
			},
/**
* @namespace Mold.Lib.Template
* @methode unbind
* @desc  unbind a Mold model from the Template
* @public
* @return (Object)  returns this;
* @param (model) object - the modelt
**/
			unbind : function(model){

				return this;
			},
/**
* @namespace Mold.Lib.Template
* @methode append
* @desc  append a Mold model to the Template, without bindings
* @public
* @return (Object)  returns this;
* @param (model) object - the model
**/
			append : function(model){
				if(!_compiledTemplate){
					throw "Template not compiled!";
				}

				if(model.className && model.className === "Mold.Lib.Model"){
					_addData(_compiledTemplate.childs[0], model.data, false);
				}else{
					_addData(_compiledTemplate.childs[0], model, false);
				}
				return this;
			},
/**
* @namespace Mold.Lib.Template
* @methode tree
* @desc  returns the template-tree
* @public
* @return (Object)  the template-tree;
**/
			tree : function(){
				return _compiledTemplate;
			},

			hasVar : function(name){
				return _hasVar(name, _compiledTemplate.childs[0]);
			},

/**
* @namespace Mold.Lib.Template
* @methode get
* @desc  returns the parsed templates main dom node
* @public
* @return (node)  returns the parsed Template
**/
			get : function(){
				if(_config.parseAsString){
					return _shadowTemplate.nodeValue;
				}
				if(Mold.isNodeJS){
					var html = _shadowTemplate.innerHTML;
					return html;
				}else{
					return _shadowTemplate;
				}
			},
			getFirst : function(){
				return _firstElement();
			},
			appendTo : function(target){
				return _appendTo(target);
			},
/**
* @namespace Mold.Lib.Template
* @methode getInner
* @desc  returns the parsed template dom nodes without main node
* @public
* @return (node)  returns the parsed Tempalte inner nodes
**/
			getInner : function(){
				return _shadowTemplate.childNodes;
			}

		}

	}
);<|endoftext|>


<commit_before><commit_msg>Removed chacebusting in prod build. Needs redesign, should make use of cache manifest<commit_after><|endoftext|>


<commit_before>function getTarget(binding) {
  return binding.value ??
    Object.entries(binding.modifiers).filter(([_, b]) => b)[0][0];
}

export default function(Vue, _) {
  Vue.directive('uw-collapse', {
    bind: (el, binding) => {
      let target = getTarget(binding);

      // set the attributes required by bootstrap
      el.setAttribute('data-bs-toggle', 'collapse');
      el.setAttribute('data-bs-target', `#${CSS.escape(target)}`);
      el.setAttribute('aria-expanded', 'false');
      el.setAttribute('aria-controls', target);
      el.setAttribute('role', 'button');
    },
  });

  Vue.directive('uw-modal', {
    bind: (el, binding) => {
      let target = getTarget(binding);

      // set the attributes required by bootstrap
      el.setAttribute('data-bs-toggle', 'modal');
      el.setAttribute('data-bs-target', `#${CSS.escape(target)}`);
      el.setAttribute('role', 'button');
    },
  });
}<commit_msg>bs-target now updated on update<commit_after>function getTarget(binding) {
  return binding.value ??
    Object.entries(binding.modifiers).filter(([_, b]) => b)[0][0];
}

export default function(Vue, _) {
  Vue.directive('uw-collapse', {
    bind: (el, binding) => {
      let target = getTarget(binding);

      // set the attributes required by bootstrap
      el.setAttribute('data-bs-toggle', 'collapse');
      el.setAttribute('data-bs-target', `#${CSS.escape(target)}`);
      el.setAttribute('aria-expanded', 'false');
      el.setAttribute('aria-controls', target);
      el.setAttribute('role', 'button');
    },
    update: (el, binding) => {
      let target = getTarget(binding);

      // update the target attributes
      el.setAttribute('data-bs-target', `#${CSS.escape(target)}`);
      el.setAttribute('aria-controls', target);
    },
  });

  Vue.directive('uw-modal', {
    bind: (el, binding) => {
      let target = getTarget(binding);

      // set the attributes required by bootstrap
      el.setAttribute('data-bs-toggle', 'modal');
      el.setAttribute('data-bs-target', `#${CSS.escape(target)}`);
      el.setAttribute('role', 'button');
    },

    update: (el, binding) => {
      let target = getTarget(binding);

      // update the target attributes
      el.setAttribute('data-bs-target', `#${CSS.escape(target)}`);
    },
  });
}<|endoftext|>


<commit_before><commit_msg>chore(tests): cleanup, trigger build<commit_after><|endoftext|>


<commit_before><commit_msg>Fix test broken by introduction of #__PURE__ comment.<commit_after><|endoftext|>


<commit_before><commit_msg>Fixed tests for getMemoryInfo() function<commit_after><|endoftext|>


<commit_before>// @flow

import type { ThreadInfo } from 'lib/types/thread-types';

export type SidebarListModalParams = {|
  +threadInfo: ThreadInfo,
|};

function SidebarListModal() {
  return null;
}

export default SidebarListModal;
<commit_msg>[native] FlatList and search logic for SidebarListModal<commit_after>// @flow

import type { ThreadInfo, SidebarInfo } from 'lib/types/thread-types';
import type { RootNavigationProp } from '../navigation/root-navigator.react';
import type { NavigationRoute } from '../navigation/route-names';

import * as React from 'react';
import { TextInput, FlatList, StyleSheet } from 'react-native';

import { sidebarInfoSelector } from 'lib/selectors/thread-selectors';
import SearchIndex from 'lib/shared/search-index';
import { threadSearchText } from 'lib/shared/thread-utils';
import sleep from 'lib/utils/sleep';

import { useSelector } from '../redux/redux-utils';
import Modal from '../components/modal.react';
import Search from '../components/search.react';
import { useIndicatorStyle } from '../themes/colors';

export type SidebarListModalParams = {|
  +threadInfo: ThreadInfo,
|};

function keyExtractor(sidebarInfo: SidebarInfo) {
  return sidebarInfo.threadInfo.id;
}
function getItemLayout(data: ?$ReadOnlyArray<SidebarInfo>, index: number) {
  return { length: 24, offset: 24 * index, index };
}

type Props = {|
  +navigation: RootNavigationProp<'SidebarListModal'>,
  +route: NavigationRoute<'SidebarListModal'>,
|};
function SidebarListModal(props: Props) {
  const threadID = props.route.params.threadInfo.id;
  const sidebarInfos = useSelector(
    (state) => sidebarInfoSelector(state)[threadID] ?? [],
  );

  const [searchState, setSearchState] = React.useState({
    text: '',
    results: new Set<string>(),
  });

  const listData = React.useMemo(() => {
    if (!searchState.text) {
      return sidebarInfos;
    }
    return sidebarInfos.filter(({ threadInfo }) =>
      searchState.results.has(threadInfo.id),
    );
  }, [sidebarInfos, searchState]);

  const userInfos = useSelector((state) => state.userStore.userInfos);
  const searchIndex = React.useMemo(() => {
    const index = new SearchIndex();
    for (const sidebarInfo of sidebarInfos) {
      const { threadInfo } = sidebarInfo;
      index.addEntry(threadInfo.id, threadSearchText(threadInfo, userInfos));
    }
    return index;
  }, [sidebarInfos, userInfos]);
  React.useEffect(() => {
    setSearchState((curState) => ({
      ...curState,
      results: new Set(searchIndex.getSearchResults(curState.text)),
    }));
  }, [searchIndex]);

  const onChangeSearchText = React.useCallback(
    (searchText: string) =>
      setSearchState({
        text: searchText,
        results: new Set(searchIndex.getSearchResults(searchText)),
      }),
    [searchIndex],
  );

  const searchTextInputRef = React.useRef();
  const setSearchTextInputRef = React.useCallback(
    async (textInput: ?React.ElementRef<typeof TextInput>) => {
      searchTextInputRef.current = textInput;
      if (!textInput) {
        return;
      }
      await sleep(50);
      if (searchTextInputRef.current) {
        searchTextInputRef.current.focus();
      }
    },
    [],
  );

  const renderItem = React.useCallback(() => {
    return null;
  }, []);

  const { navigation } = props;
  const indicatorStyle = useIndicatorStyle();
  return (
    <Modal navigation={navigation}>
      <Search
        searchText={searchState.text}
        onChangeText={onChangeSearchText}
        containerStyle={styles.search}
        placeholder="Search sidebars"
        ref={setSearchTextInputRef}
      />
      <FlatList
        data={listData}
        renderItem={renderItem}
        keyExtractor={keyExtractor}
        getItemLayout={getItemLayout}
        keyboardShouldPersistTaps="handled"
        initialNumToRender={20}
        indicatorStyle={indicatorStyle}
      />
    </Modal>
  );
}

const styles = StyleSheet.create({
  search: {
    marginBottom: 8,
  },
});

export default SidebarListModal;
<|endoftext|>