<commit_before>/*
** Module dependencies
*/
var _s = require('underscore.string');
var _ = require('lodash');
var ComputingError = require('./errors').ComputingError;

/*
** Entity
*/
function Entity(options) {
    this.id = options.id;
    this.situation = options.situation;
    this.userAttributes = {};
    this.computedAttributes = {};
}

/*
** Prototype
*/
Entity.prototype.setUserAttribute = function(name, value) {
    this.userAttributes[name] = value;
};

Entity.prototype.getUserAttribute = function(name) {
    return this.userAttributes[name];
};

Entity.prototype.hasUserAttribute = function(name) {
    return name in this.userAttributes;
};

Entity.prototype.setComputedAttribute = function(name, value) {
    this.computedAttributes[name] = value;
};

Entity.prototype.getComputedAttribute = function(name) {
    return this.computedAttributes[name];
};

Entity.prototype.hasComputedAttribute = function(name) {
    return name in this.computedAttributes;
};

Entity.prototype.set = function(name, value) {
    // Batch set
    if (_.isObject(name)) {
        _.forEach(name, function(value, name) {
            this.set(name, value);
        }, this);
        return this;
    }

    // Step 1: use build-in accessor
    var setterName = 'set' + _s.capitalize(name);
    if ((setterName in this) && _.isFunction(this[setterName])) this[setterName](value);
    // Step 2: set as user-defined attributes
    else this.setUserAttribute(name, value);
    return this;
};

Entity.prototype.get = function(name) {
    // Step 1: use user-defined attribute
    if (this.hasUserAttribute(name)) return this.getUserAttribute(name);
    // Step 2: use computed attribute
    if (this.hasComputedAttribute(name)) return this.getComputedAttribute(name);
    // Step 3: compute attribute
    var getterName = 'get' + _s.capitalize(name);
    if ((getterName in this) && _.isFunction(this[getterName])) {
        var result = this[getterName]();
        this.setComputedAttribute(name, result);
        return result;
    }
    // Step 4: throw an exception
    throw new ComputingError([name], this);
};

Entity.prototype.read = function(name) {
    try {
        return this.get(name);
    } catch (e) {
        return undefined;
    }
};

Entity.prototype.toJSON = function() {
    var json = { id: this.id };
    json.userAttributes = _.clone(this.userAttributes);
    json.computedAttributes = _.clone(this.computedAttributes);
    return json;
};

Entity.prototype.parse = function(data) {
    _.extend(this, data);
};

/*
** Exports
*/
module.exports = Entity;<commit_msg>Add claim method for Entity<commit_after>/*
** Module dependencies
*/
var _s = require('underscore.string');
var _ = require('lodash');
var ComputingError = require('./errors').ComputingError;

/*
** Entity
*/
function Entity(options) {
    this.id = options.id;
    this.situation = options.situation;
    this.userAttributes = {};
    this.computedAttributes = {};
}

/*
** Prototype
*/
Entity.prototype.setUserAttribute = function(name, value) {
    this.userAttributes[name] = value;
};

Entity.prototype.getUserAttribute = function(name) {
    return this.userAttributes[name];
};

Entity.prototype.hasUserAttribute = function(name) {
    return name in this.userAttributes;
};

Entity.prototype.setComputedAttribute = function(name, value) {
    this.computedAttributes[name] = value;
};

Entity.prototype.getComputedAttribute = function(name) {
    return this.computedAttributes[name];
};

Entity.prototype.hasComputedAttribute = function(name) {
    return name in this.computedAttributes;
};

Entity.prototype.set = function(name, value) {
    // Batch set
    if (_.isObject(name)) {
        _.forEach(name, function(value, name) {
            this.set(name, value);
        }, this);
        return this;
    }

    // Step 1: use build-in accessor
    var setterName = 'set' + _s.capitalize(name);
    if ((setterName in this) && _.isFunction(this[setterName])) this[setterName](value);
    // Step 2: set as user-defined attributes
    else this.setUserAttribute(name, value);
    return this;
};

Entity.prototype.get = function(name) {
    // Step 1: use user-defined attribute
    if (this.hasUserAttribute(name)) return this.getUserAttribute(name);
    // Step 2: use computed attribute
    if (this.hasComputedAttribute(name)) return this.getComputedAttribute(name);
    // Step 3: compute attribute
    var getterName = 'get' + _s.capitalize(name);
    if ((getterName in this) && _.isFunction(this[getterName])) {
        var result = this[getterName]();
        this.setComputedAttribute(name, result);
        return result;
    }
    // Step 4: throw an exception or return undefined
    if (this.situation.claiming) {
        throw new ComputingError([name], this);
    } else {
        return;
    }

};

Entity.prototype.claim = function(name) {
    try {
        this.situation.claiming = true;
        return this.get(name);
    } catch (e) {
        this.situation.claiming = false;
        throw e;
    }
};

Entity.prototype.read = function(name) {
    try {
        return this.get(name);
    } catch (e) {
        return;
    }
};

Entity.prototype.toJSON = function() {
    var json = { id: this.id };
    json.userAttributes = _.clone(this.userAttributes);
    json.computedAttributes = _.clone(this.computedAttributes);
    return json;
};

Entity.prototype.parse = function(data) {
    _.extend(this, data);
};

/*
** Exports
*/
module.exports = Entity;<|endoftext|>


<commit_before>/**
 * @license
 * DOM shortcut library
 *  version 0.0.1c
 *  copyright (c) 2012-2015, Nicolas JOYARD <joyard dot nicolas at gmail dot com>
 *  license: MIT
 */

/*jshint browser:true */
/*global define, require */

define([], function () {
	'use strict';

	var dom = {},
		addListener, remListener,
		querySelector, querySelectorAll;

	/**
	 * Execute a callback when DOM is ready
	 * Requires a 'domReady' plugin to be available
	 * Usage: dom.ready(<callback>)
	 */
	dom.ready = function(callback) {
		require(['domReady!'], callback);
	};

	querySelectorAll = function(e, s) {
		return [].slice.call(e.querySelectorAll(s));
	};

	querySelector = function(e, s) {
		return e.querySelector(s);
	};

	/**
	 * querySelector[All] aliases
	 */
	dom.$ = dom.get = function(element, selector) {
		if (typeof element === 'string') {
			selector = element;
			element = document;
		}

		if (!element) {
			throw new Error('No element specified');
		}

		return querySelector(element, selector);
	};

	dom.$$ = dom.all = function(element, selector) {
		if (typeof element === 'string') {
			selector = element;
			element = document;
		}

		if (!element) {
			throw new Error('No element specified');
		}

		return querySelectorAll(element, selector);
	};

	dom.$C = dom.children = function(element, selector) {
		return dom.all(element, selector).filter(function(elem) {
			return elem.parentNode === element;
		});
	};

	/**
	 * getElementById alias
	 */
	if (document.getElementById) {
		dom.gbid = function (id) {
			return document.getElementById(id);
		};
	} else if (document.all) {
		dom.gbid = function (id) {
			return document.all[id];
		};
	} else if (document.layers) {
		dom.gbid = function (id) {
			return document.layers[id];
		};
	} else {
		throw new Error('No getElementById alternative');
	}

	/**
	 * document.body alias
	 */
	dom.body = function () { return document.body; };

	/**
	 * document.createElement alias
	 */
	dom.elem = function(tag, doc) { return (doc || document).createElement(tag); };
	dom.text = function(text, doc) { return (doc || document).createTextNode(text); };
	dom.frag = function(nodes, doc) {
		var frag = (doc || document).createDocumentFragment();
		[].slice.call(nodes || []).forEach(function(n) {
			frag.appendChild(n);
		});
		return frag;
	};

	/**
	 * Empty an element (el can either be an element or a selector)
	 */
	dom.empty = function(el) {
		if (typeof el === 'string') {
			dom.all(el).forEach(dom.empty);
		} else {
			while (el.firstChild) {
				el.removeChild(el.firstChild);
			}
		}
	};

	/**
	 * Remove an element from the DOM tree
	 */
	dom.remove = function(el) {
		if (typeof el === 'string') {
			dom.all(el).forEach(dom.remove);
		} else {
			if (el.parentNode) {
				el.parentNode.removeChild(el);
			}
		}
	};

	/* Remove comment nodes and empty or whitespace-only text nodes */
	dom.clean = function(node) {
		[].slice.call(node.childNodes).forEach(function(child) {
			if (child.nodeType === 8 || (child.nodeType === 3 && !/\S/.test(child.nodeValue))) {
				node.removeChild(child);
			} else if (child.nodeType === 1) {
				dom.clean(child);
			}
		});

		return node;
	};

	/**
	 * Set style elements in 'style' on 'el' (element or selector)
	 */
	dom.style = function (el, style) {
		var p;

		if (typeof el === 'string') {
			dom.all(el).forEach(function(elem) {
				dom.style(elem, style);
			});
		} else {
			if (!el) {
				throw new Error('No element specified');
			}

			for (p in style) {
				if (style.hasOwnProperty(p)) {
					el.style[p] = style[p];
				}
			}
		}
	};

	// Cross browser event handling
	if (document.addEventListener) {
		addListener = function (el, evt, handler) {
			el.addEventListener(evt, handler, true);
		};

		remListener = function (el, evt, handler) {
			el.removeEventListener(evt, handler, true);
		};
	} else if (document.attachEvent) {
		addListener = function (el, evt, handler) {
			el.attachEvent('on' + evt, handler);
		};

		remListener = function (el, evt, handler) {
			el.detachEvent('on' + evt, handler);
		};
	} else {
		throw new Error('No addEventListener alternative');
	}

	/**
	 * Set handler 'handler' for event 'evt' on element (or selector) 'el'.
	 * 'handler' will receive the Event object as a parameter and 'el' as context.
	 */
	dom.addListener = function (el, evt, handler) {
		if (typeof el === 'string') {
			el = dom.get(el);
		}

		if (!el) {
			throw new Error('No element specified');
		}

		addListener(el, evt, handler);
	};

	dom.remListener = function(el, evt, handler) {
		if (typeof el === 'string') {
			el = dom.get(el);
		}

		if (!el) {
			throw new Error('No element specified');
		}

		remListener(el, evt, handler);
	};

	/**
	 * Get first parent element of 'element' matching 'selector'
	 * When 'includeMe' is true, returns 'element' if it matches.
	 */
	dom.$P = dom.parent = function(element, selector, includeMe) {
		var node = element;

		if (!includeMe) {
			node = node.parentNode;
		}

		while (node && node.parentNode) {
			if (dom.all(node.parentNode, selector).indexOf(node) !== -1) {
				return node;
			}

			node = node.parentNode;
		}

		return null;
	};

	return dom;
});
<commit_msg>Enable calling dom.cleanup with selectors<commit_after>/**
 * @license
 * DOM shortcut library
 *  version 0.0.1c
 *  copyright (c) 2012-2015, Nicolas JOYARD <joyard dot nicolas at gmail dot com>
 *  license: MIT
 */

/*jshint browser:true */
/*global define, require */

define([], function () {
	'use strict';

	var dom = {},
		addListener, remListener,
		querySelector, querySelectorAll;

	/**
	 * Execute a callback when DOM is ready
	 * Requires a 'domReady' plugin to be available
	 * Usage: dom.ready(<callback>)
	 */
	dom.ready = function(callback) {
		require(['domReady!'], callback);
	};

	querySelectorAll = function(e, s) {
		return [].slice.call(e.querySelectorAll(s));
	};

	querySelector = function(e, s) {
		return e.querySelector(s);
	};

	/**
	 * querySelector[All] aliases
	 */
	dom.$ = dom.get = function(element, selector) {
		if (typeof element === 'string') {
			selector = element;
			element = document;
		}

		if (!element) {
			throw new Error('No element specified');
		}

		return querySelector(element, selector);
	};

	dom.$$ = dom.all = function(element, selector) {
		if (typeof element === 'string') {
			selector = element;
			element = document;
		}

		if (!element) {
			throw new Error('No element specified');
		}

		return querySelectorAll(element, selector);
	};

	dom.$C = dom.children = function(element, selector) {
		return dom.all(element, selector).filter(function(elem) {
			return elem.parentNode === element;
		});
	};

	/**
	 * getElementById alias
	 */
	if (document.getElementById) {
		dom.gbid = function (id) {
			return document.getElementById(id);
		};
	} else if (document.all) {
		dom.gbid = function (id) {
			return document.all[id];
		};
	} else if (document.layers) {
		dom.gbid = function (id) {
			return document.layers[id];
		};
	} else {
		throw new Error('No getElementById alternative');
	}

	/**
	 * document.body alias
	 */
	dom.body = function () { return document.body; };

	/**
	 * document.createElement alias
	 */
	dom.elem = function(tag, doc) { return (doc || document).createElement(tag); };
	dom.text = function(text, doc) { return (doc || document).createTextNode(text); };
	dom.frag = function(nodes, doc) {
		var frag = (doc || document).createDocumentFragment();
		[].slice.call(nodes || []).forEach(function(n) {
			frag.appendChild(n);
		});
		return frag;
	};

	/**
	 * Empty an element (el can either be an element or a selector)
	 */
	dom.empty = function(el) {
		if (typeof el === 'string') {
			dom.all(el).forEach(dom.empty);
		} else {
			while (el.firstChild) {
				el.removeChild(el.firstChild);
			}
		}
	};

	/**
	 * Remove an element from the DOM tree
	 */
	dom.remove = function(el) {
		if (typeof el === 'string') {
			dom.all(el).forEach(dom.remove);
		} else {
			if (el.parentNode) {
				el.parentNode.removeChild(el);
			}
		}
	};

	/* Remove comment nodes and empty or whitespace-only text nodes */
	dom.clean = function(el) {
		if (typeof el === 'string') {
			dom.all(el).forEach(dom.clean);
		} else {
			[].slice.call(el.childNodes).forEach(function(child) {
				if (child.nodeType === 8 || (child.nodeType === 3 && !/\S/.test(child.nodeValue))) {
					el.removeChild(child);
				} else if (child.nodeType === 1) {
					dom.clean(child);
				}
			});
		}
	};

	/**
	 * Set style elements in 'style' on 'el' (element or selector)
	 */
	dom.style = function (el, style) {
		var p;

		if (typeof el === 'string') {
			dom.all(el).forEach(function(elem) {
				dom.style(elem, style);
			});
		} else {
			if (!el) {
				throw new Error('No element specified');
			}

			for (p in style) {
				if (style.hasOwnProperty(p)) {
					el.style[p] = style[p];
				}
			}
		}
	};

	// Cross browser event handling
	if (document.addEventListener) {
		addListener = function (el, evt, handler) {
			el.addEventListener(evt, handler, true);
		};

		remListener = function (el, evt, handler) {
			el.removeEventListener(evt, handler, true);
		};
	} else if (document.attachEvent) {
		addListener = function (el, evt, handler) {
			el.attachEvent('on' + evt, handler);
		};

		remListener = function (el, evt, handler) {
			el.detachEvent('on' + evt, handler);
		};
	} else {
		throw new Error('No addEventListener alternative');
	}

	/**
	 * Set handler 'handler' for event 'evt' on element (or selector) 'el'.
	 * 'handler' will receive the Event object as a parameter and 'el' as context.
	 */
	dom.addListener = function (el, evt, handler) {
		if (typeof el === 'string') {
			el = dom.get(el);
		}

		if (!el) {
			throw new Error('No element specified');
		}

		addListener(el, evt, handler);
	};

	dom.remListener = function(el, evt, handler) {
		if (typeof el === 'string') {
			el = dom.get(el);
		}

		if (!el) {
			throw new Error('No element specified');
		}

		remListener(el, evt, handler);
	};

	/**
	 * Get first parent element of 'element' matching 'selector'
	 * When 'includeMe' is true, returns 'element' if it matches.
	 */
	dom.$P = dom.parent = function(element, selector, includeMe) {
		var node = element;

		if (!includeMe) {
			node = node.parentNode;
		}

		while (node && node.parentNode) {
			if (dom.all(node.parentNode, selector).indexOf(node) !== -1) {
				return node;
			}

			node = node.parentNode;
		}

		return null;
	};

	return dom;
});
<|endoftext|>


<commit_before>/*
 *      This program is free software: you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation, either version 3 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *      Copyright 2011 Marc-Antoine Perennou <Marc-Antoine@Perennou.com>
 *
 *      This file is part of GPaste.
 *
 *      GPaste is free software: you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation, either version 3 of the License, or
 *      (at your option) any later version.
 *
 *      GPaste is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with GPaste.  If not, see <http://www.gnu.org/licenses/>.
 */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */

const StatusIconDispatcher = imports.ui.statusIconDispatcher;
const Panel = imports.ui.panel;
const DBus = imports.dbus;
const Lang = imports.lang;
const St = imports.gi.St;
const GLib = imports.gi.GLib;
const Pango = imports.gi.Pango;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const Gettext = imports.gettext;

const _ = Gettext.domain('GPaste').gettext;

const BUS_NAME = 'org.gnome.GPaste';
const OBJECT_PATH = '/org/gnome/GPaste';

let pkglibexecdir = null;

const GPasteInterface = {
    name: BUS_NAME,
    methods: [
        { name: 'GetHistory', inSignature: '', outSignature: 'as' },
        { name: 'Select', inSignature: 'u', outSignature: '' },
        { name: 'Delete', inSignature: 'u', outSignature: '' },
        { name: 'Empty', inSignature: '', outSignature: '' },
        { name: 'Launch', inSignature: '', outSignature: '' },
        { name: 'Stop', inSignature: '', outSignature: '' },
    ],
    signals: [
        { name: 'Changed', inSignature: '', outSignature: '' },
        { name: 'Start', inSignature: '', outSignature: '' },
        { name: 'Exit', inSignature: '', outSignature: '' },
    ],
    properties: [
        { name: 'Active', signature: 'b', access: 'readonly' },
    ]
};
let GPasteProxy = DBus.makeProxyClass(GPasteInterface);

function Indicator() {
    this._init.apply(this, arguments);
}

Indicator.prototype = {
    __proto__: PanelMenu.SystemStatusButton.prototype,

    _init: function() {
        PanelMenu.SystemStatusButton.prototype._init.call(this, 'edit-paste-symbolic');
        Util.spawn([pkglibexecdir + '/gpasted']);
        this._killSwitch = new PopupMenu.PopupSwitchMenuItem(_("Track clipboard changes"), true);
        this._killSwitch.connect('toggled', Lang.bind(this, this._toggleDaemon));
        this._proxy = new GPasteProxy(DBus.session, BUS_NAME, OBJECT_PATH);
        this._proxy.launchRemote();
        this._proxy.connect('Changed', Lang.bind(this, this._fillHistory));
        this._proxy.connect('Start', Lang.bind(this, this._started));
        this._proxy.connect('Exit', Lang.bind(this, this._exited));
        this._history = new PopupMenu.PopupMenuSection();
        this._fillMenu();
    },

    _select: function(index) {
        this._proxy.SelectRemote(index);
    },

    _delete: function(index) {
        this._proxy.DeleteRemote(index);
    },

    _empty: function() {
        this._proxy.EmptyRemote();
    },

    _started: function() {
        this._killSwitch.setToggleState(true);
    },

    _exited: function() {
        this._killSwitch.setToggleState(false);
    },

    _toggleDaemon: function() {
        if (this._killSwitch.state)
            this._proxy.LaunchRemote();
        else
            this._proxy.StopRemote();
    },

    _fillMenu: function() {
        this._proxy.GetRemote('Active', Lang.bind(this, function(active) {
            if (active != null)
                this._killSwitch.setToggleState(active);
            this.menu.addMenuItem(this._killSwitch);
            this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
            this.menu.addMenuItem(this._history);
            let prefsItem = new PopupMenu.PopupMenuItem(_("GPaste Settings"));
            prefsItem.connect('activate', function() {
                Util.spawn([pkglibexecdir + '/gpaste-settings']);
            });
            this.menu.addMenuItem(prefsItem);
            this._fillHistory();
        }));
    },

    _fillHistory: function(history) {
        this._proxy.GetHistoryRemote(Lang.bind(this, function(history) {
            this._history.removeAll();
            if (history.length == 0) {
                let emptyItem = new PopupMenu.PopupMenuItem(_("(Empty)"), { reactive: false });
                this._history.addMenuItem(emptyItem);
                this._history.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
            } else if (history != null) {
                let limit = (history.length > 20) ? 20 : history.length;
                for (let index = 0; index < limit; ++index)
                    this._addSelection(index, history[index]);
                this._history.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
                let emptyItem = new PopupMenu.PopupMenuItem(_("Empty history"));
                emptyItem.connect('activate', Lang.bind(this, this._empty));
                this._history.addMenuItem(emptyItem);
            }
        }));
    },

    _addSelection: function(index, element) {
        let displaystr = element.replace(/\n/g, ' ');
        let altdisplaystr = _("delete: %s").format(displaystr);
        let selection = new PopupMenu.PopupAlternatingMenuItem(displaystr, altdisplaystr);
        selection.actor.style_class = 'my-alternating-menu-item';
        selection.actor.add_style_class_name('popup-menu-item');
        let label = selection.label;
        label.clutter_text.max_length = 60;
        label.clutter_text.ellipsize = Pango.EllipsizeMode.END;
        selection.connect('activate', Lang.bind(this, function(actor, event) {
            if (selection.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
                this._select(index);
                return false;
            } else {
                this._delete(index);
                return true;
            }
        }));
        this._history.addMenuItem(selection);
    }
};

function main(metadata) {
    Gettext.bindtextdomain('gpaste', metadata.localedir);
    pkglibexecdir = metadata.pkglibexecdir;
    StatusIconDispatcher.STANDARD_TRAY_ICON_IMPLEMENTATIONS['gpaste-applet'] = 'gpaste';
    Panel.STANDARD_TRAY_ICON_ORDER.unshift('gpaste');
    Panel.STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION['gpaste'] = Indicator;
}
<commit_msg>typso<commit_after>/*
 *      This program is free software: you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation, either version 3 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *      Copyright 2011 Marc-Antoine Perennou <Marc-Antoine@Perennou.com>
 *
 *      This file is part of GPaste.
 *
 *      GPaste is free software: you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation, either version 3 of the License, or
 *      (at your option) any later version.
 *
 *      GPaste is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with GPaste.  If not, see <http://www.gnu.org/licenses/>.
 */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */

const StatusIconDispatcher = imports.ui.statusIconDispatcher;
const Panel = imports.ui.panel;
const DBus = imports.dbus;
const Lang = imports.lang;
const St = imports.gi.St;
const GLib = imports.gi.GLib;
const Pango = imports.gi.Pango;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const Gettext = imports.gettext;

const _ = Gettext.domain('GPaste').gettext;

const BUS_NAME = 'org.gnome.GPaste';
const OBJECT_PATH = '/org/gnome/GPaste';

let pkglibexecdir = null;

const GPasteInterface = {
    name: BUS_NAME,
    methods: [
        { name: 'GetHistory', inSignature: '', outSignature: 'as' },
        { name: 'Select', inSignature: 'u', outSignature: '' },
        { name: 'Delete', inSignature: 'u', outSignature: '' },
        { name: 'Empty', inSignature: '', outSignature: '' },
        { name: 'Launch', inSignature: '', outSignature: '' },
        { name: 'Stop', inSignature: '', outSignature: '' },
    ],
    signals: [
        { name: 'Changed', inSignature: '', outSignature: '' },
        { name: 'Start', inSignature: '', outSignature: '' },
        { name: 'Exit', inSignature: '', outSignature: '' },
    ],
    properties: [
        { name: 'Active', signature: 'b', access: 'readonly' },
    ]
};
let GPasteProxy = DBus.makeProxyClass(GPasteInterface);

function Indicator() {
    this._init.apply(this, arguments);
}

Indicator.prototype = {
    __proto__: PanelMenu.SystemStatusButton.prototype,

    _init: function() {
        PanelMenu.SystemStatusButton.prototype._init.call(this, 'edit-paste-symbolic');
        Util.spawn([pkglibexecdir + '/gpasted']);
        this._killSwitch = new PopupMenu.PopupSwitchMenuItem(_("Track clipboard changes"), true);
        this._killSwitch.connect('toggled', Lang.bind(this, this._toggleDaemon));
        this._proxy = new GPasteProxy(DBus.session, BUS_NAME, OBJECT_PATH);
        this._proxy.LaunchRemote();
        this._proxy.connect('Changed', Lang.bind(this, this._fillHistory));
        this._proxy.connect('Start', Lang.bind(this, this._started));
        this._proxy.connect('Exit', Lang.bind(this, this._exited));
        this._history = new PopupMenu.PopupMenuSection();
        this._fillMenu();
    },

    _select: function(index) {
        this._proxy.SelectRemote(index);
    },

    _delete: function(index) {
        this._proxy.DeleteRemote(index);
    },

    _empty: function() {
        this._proxy.EmptyRemote();
    },

    _started: function() {
        this._killSwitch.setToggleState(true);
    },

    _exited: function() {
        this._killSwitch.setToggleState(false);
    },

    _toggleDaemon: function() {
        if (this._killSwitch.state)
            this._proxy.LaunchRemote();
        else
            this._proxy.StopRemote();
    },

    _fillMenu: function() {
        this._proxy.GetRemote('Active', Lang.bind(this, function(active) {
            if (active != null)
                this._killSwitch.setToggleState(active);
            this.menu.addMenuItem(this._killSwitch);
            this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
            this.menu.addMenuItem(this._history);
            let prefsItem = new PopupMenu.PopupMenuItem(_("GPaste Settings"));
            prefsItem.connect('activate', function() {
                Util.spawn([pkglibexecdir + '/gpaste-settings']);
            });
            this.menu.addMenuItem(prefsItem);
            this._fillHistory();
        }));
    },

    _fillHistory: function(history) {
        this._proxy.GetHistoryRemote(Lang.bind(this, function(history) {
            this._history.removeAll();
            if (history.length == 0) {
                let emptyItem = new PopupMenu.PopupMenuItem(_("(Empty)"), { reactive: false });
                this._history.addMenuItem(emptyItem);
                this._history.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
            } else if (history != null) {
                let limit = (history.length > 20) ? 20 : history.length;
                for (let index = 0; index < limit; ++index)
                    this._addSelection(index, history[index]);
                this._history.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
                let emptyItem = new PopupMenu.PopupMenuItem(_("Empty history"));
                emptyItem.connect('activate', Lang.bind(this, this._empty));
                this._history.addMenuItem(emptyItem);
            }
        }));
    },

    _addSelection: function(index, element) {
        let displaystr = element.replace(/\n/g, ' ');
        let altdisplaystr = _("delete: %s").format(displaystr);
        let selection = new PopupMenu.PopupAlternatingMenuItem(displaystr, altdisplaystr);
        selection.actor.style_class = 'my-alternating-menu-item';
        selection.actor.add_style_class_name('popup-menu-item');
        let label = selection.label;
        label.clutter_text.max_length = 60;
        label.clutter_text.ellipsize = Pango.EllipsizeMode.END;
        selection.connect('activate', Lang.bind(this, function(actor, event) {
            if (selection.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
                this._select(index);
                return false;
            } else {
                this._delete(index);
                return true;
            }
        }));
        this._history.addMenuItem(selection);
    }
};

function main(metadata) {
    Gettext.bindtextdomain('gpaste', metadata.localedir);
    pkglibexecdir = metadata.pkglibexecdir;
    StatusIconDispatcher.STANDARD_TRAY_ICON_IMPLEMENTATIONS['gpaste-applet'] = 'gpaste';
    Panel.STANDARD_TRAY_ICON_ORDER.unshift('gpaste');
    Panel.STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION['gpaste'] = Indicator;
}
<|endoftext|>


<commit_before>/**
 * 取自thinkjs
 */

var net = require('net');

var Valid = {

	/**
	 * 长度限定
	 * @param  {String} value 字符串
	 * @param  {Int} min   最小长度
	 * @param  {Int} max   最大长度
	 * @return {Boolean}
	 */
	length: function(value, min, max) {
		'use strict';
		min = min | 0;
		var length = ((value || '') + '').length;
		if (length < min) {
			return false;
		}
		if (max && length > max) {
			return false;
		}
		return true;
	},

	/**
	 * 必填
	 * @return {[type]} [description]
	 */
	required: function(value) {
		'use strict';
		return ((value || '') + '').length > 0;
	},

	/**
	 * 自定义正则校验
	 * @param  {[type]} reg [description]
	 * @return {[type]}     [description]
	 */
	regexp: function(value, reg) {
		'use strict';
		return reg.test(value);
	},
	/**
	 * 邮箱
	 * @return {[type]} [description]
	 */
	email: function(value) {
		'use strict';
		var reg = /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/;
		return this.regexp(value, reg);
	},
	/**
	 * 时间戳
	 * @return {[type]} [description]
	 */
	time: function(value) {
		'use strict';
		var reg = /^[1-5]\d{12}$/;
		return this.regexp(value, reg);
	},
	/**
	 * 中文名
	 * @return {[type]} [description]
	 */
	cnname: function(value) {
		'use strict';
		var reg = /^[\u4e00-\u9fa5\u3002\u2022]{2,32}$/;
		return this.regexp(value, reg);
	},
	/**
	 * 身份证号码
	 * @return {[type]} [description]
	 */
	idnumber: function(value) {
		'use strict';
		if (/^\d{15}$/.test(value)) {
			return true;
		}
		if ((/^\d{17}[0-9xX]$/).test(value)) {
			var vs = '1,0,x,9,8,7,6,5,4,3,2'.split(','),
				ps = '7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2'.split(','),
				ss = value.toLowerCase().split(''),
				r = 0;
			for (var i = 0; i < 17; i++) {
				r += ps[i] * ss[i];
			}
			var isOk = (vs[r % 11] === ss[17]);
			return isOk;
		}
		return false;
	},
	/**
	 * 手机号
	 * @return {[type]} [description]
	 */
	mobile: function(value) {
		'use strict';
		var reg = /^(13|15|18|14|17)\d{9}$/;
		return this.regexp(value, reg);
	},
	/**
	 * 邮编
	 * @return {[type]} [description]
	 */
	zipcode: function(value) {
		'use strict';
		var reg = /^\d{6}$/;
		return this.regexp(value, reg);
	},
	/**
	 * 2次值是否一致
	 * @param  {[type]} field [description]
	 * @return {[type]}       [description]
	 */
	confirm: function(value, cvalue) {
		'use strict';
		return value === cvalue;
	},
	/**
	 * url
	 * @return {[type]} [description]
	 */
	url: function(value) {
		'use strict';
		var reg = /^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/;
		return this.regexp(value, reg);
	},
	/**
	 * 整数
	 * @param  {[type]} o [description]
	 * @return {[type]}   [description]
	 */
	int: function(value) {
		'use strict';
		var val = parseInt(value, 10);
		if (isNaN(val)) {
			return false;
		}
		return (val + '').length === value.length;
	},
	/**
	 * 浮点数
	 * @return {[type]} [description]
	 */
	float: function(value) {
		'use strict';
		return isNumberString(value);
	},
	/**
	 * 整数范围
	 * @param  {[type]} min [description]
	 * @param  {[type]} max [description]
	 * @return {[type]}     [description]
	 */
	range: function(value, min, max) {
		'use strict';
		value = parseInt(value, 10);
		min = min | 0;
		if (isNaN(value) || value < min) {
			return false;
		}
		if (max && value > max) {
			return false;
		}
		return true;
	},
	/**
	 * ip4校验
	 * @return {[type]} [description]
	 */
	ip4: function(value) {
		'use strict';
		return net.isIPv4(value);
	},
	/**
	 * ip6校验
	 * @return {[type]} [description]
	 */
	ip6: function(value) {
		'use strict';
		return net.isIPv6(value);
	},
	/**
	 * ip校验
	 * @return {[type]} [description]
	 */
	ip: function(value) {
		'use strict';
		return net.isIP(value);
	},
	/**
	 * 日期校验
	 * @return {[type]} [description]
	 */
	date: function(value) {
		'use strict';
		var reg = /^\d{4}-\d{1,2}-\d{1,2}$/;
		return this.regexp(value, reg);
	},
	/**
	 * 在一个范围内
	 * @param  {[type]} value [description]
	 * @param  {[type]} arr   [description]
	 * @return {[type]}       [description]
	 */
	in : function(value, arr) {
		'use strict';
		return arr.indexOf(value) > -1;
	}
};

/**
 * data格式
 * [{
 *     value: xxx,
 *     name: '',
 *     valid: ['required', 'range'],
 *     range_args: [],
 *     msg:{
 *         required: '',
 *         range: ''
 *     }
 * },{
 *     value: xxx,
 *     name: '',
 *     valid: ['required', 'range'],
 *     range_args: [],
 *     msg:{
 *         required: '',
 *         range: ''
 *     }
 * }]
 * @param  {[type]} data [description]
 * @return {[type]}      [description]
 */
module.exports = function(data) {

};<commit_msg>更新校验模块，增加校验函数。<commit_after>/**
 * 取自thinkjs
 */

var Promise = require('bluebird'),
    _       = require('lodash'),
    path    = require('path'),
    net 	= require('net'),
    errors  = require('../errors');

var Valid = {

	/**
	 * 必填
	 * @return {[type]} [description]
	 */
	required: function(value) {
		'use strict';
		return ((value || '') + '').length > 0;
	},

	/**
	 * 邮箱
	 * @return {[type]} [description]
	 */
	email: function(value) {
		'use strict';
		var reg = /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/;
		return this.regexp(value, reg);
	},
	/**
	 * 时间戳
	 * @return {[type]} [description]
	 */
	time: function(value) {
		'use strict';
		var reg = /^[1-5]\d{12}$/;
		return this.regexp(value, reg);
	},
	/**
	 * 中文名
	 * @return {[type]} [description]
	 */
	cnname: function(value) {
		'use strict';
		var reg = /^[\u4e00-\u9fa5\u3002\u2022]{2,32}$/;
		return this.regexp(value, reg);
	},
	/**
	 * 身份证号码
	 * @return {[type]} [description]
	 */
	idnumber: function(value) {
		'use strict';
		if (/^\d{15}$/.test(value)) {
			return true;
		}
		if ((/^\d{17}[0-9xX]$/).test(value)) {
			var vs = '1,0,x,9,8,7,6,5,4,3,2'.split(','),
				ps = '7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2'.split(','),
				ss = value.toLowerCase().split(''),
				r = 0;
			for (var i = 0; i < 17; i++) {
				r += ps[i] * ss[i];
			}
			var isOk = (vs[r % 11] === ss[17]);
			return isOk;
		}
		return false;
	},
	/**
	 * 手机号
	 * @return {[type]} [description]
	 */
	mobile: function(value) {
		'use strict';
		var reg = /^(13|15|18|14|17)\d{9}$/;
		return this.regexp(value, reg);
	},
	/**
	 * 邮编
	 * @return {[type]} [description]
	 */
	zipcode: function(value) {
		'use strict';
		var reg = /^\d{6}$/;
		return this.regexp(value, reg);
	},

	/**
	 * url
	 * @return {[type]} [description]
	 */
	url: function(value) {
		'use strict';
		var reg = /^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/;
		return this.regexp(value, reg);
	},
	/**
	 * 整数
	 * @param  {[type]} o [description]
	 * @return {[type]}   [description]
	 */
	int: function(value) {
		'use strict';
		var val = parseInt(value, 10);
		if (isNaN(val)) {
			return false;
		}
		return (val + '').length === value.length;
	},
	/**
	 * 浮点数
	 * @return {[type]} [description]
	 */
	float: function(value) {
		'use strict';
		return isNumberString(value);
	},

	/**
	 * ip4校验
	 * @return {[type]} [description]
	 */
	ip4: function(value) {
		'use strict';
		return net.isIPv4(value);
	},
	/**
	 * ip6校验
	 * @return {[type]} [description]
	 */
	ip6: function(value) {
		'use strict';
		return net.isIPv6(value);
	},
	/**
	 * ip校验
	 * @return {[type]} [description]
	 */
	ip: function(value) {
		'use strict';
		return net.isIP(value);
	},
	/**
	 * 日期校验
	 * @return {[type]} [description]
	 */
	date: function(value) {
		'use strict';
		var reg = /^\d{4}-\d{1,2}-\d{1,2}$/;
		return this.regexp(value, reg);
	},

	/**
	 * 长度限定
	 * @param  {String} value 字符串
	 * @param  {Int} min   最小长度
	 * @param  {Int} max   最大长度
	 * @return {Boolean}
	 */
	length: function(value, min, max) {
		'use strict';
		min = min | 0;
		var length = ((value || '') + '').length;
		if (length < min) {
			return false;
		}
		if (max && length > max) {
			return false;
		}
		return true;
	},

	/**
	 * 自定义正则校验
	 * @param  {[type]} reg [description]
	 * @return {[type]}     [description]
	 */
	regexp: function(value, reg) {
		'use strict';
		return reg.test(value);
	},

	/**
	 * 2次值是否一致
	 * @param  {[type]} field [description]
	 * @return {[type]}       [description]
	 */
	confirm: function(value, cvalue) {
		'use strict';
		return value === cvalue;
	},

	/**
	 * 整数范围
	 * @param  {[type]} min [description]
	 * @param  {[type]} max [description]
	 * @return {[type]}     [description]
	 */
	range: function(value, min, max) {
		'use strict';
		value = parseInt(value, 10);
		min = min | 0;
		if (isNaN(value) || value < min) {
			return false;
		}
		if (max && value > max) {
			return false;
		}
		return true;
	},

	/**
	 * 在一个范围内
	 * @param  {[type]} value [description]
	 * @param  {[type]} arr   [description]
	 * @return {[type]}       [description]
	 */
	in : function(value, arr) {
		'use strict';
		return arr.indexOf(value) > -1;
	}
};

/**
 * data格式
 * [{
 *     value: xxx,
 *     name: '',
 *     valids: ['required', 'range'],
 *     range_args: [],
 *     msg:{
 *         required: '',
 *         range: ''
 *     }
 * },{
 *     value: xxx,
 *     name: '',
 *     valids: ['required', 'range'],
 *     range_args: [],
 * }]
 * @param  {[type]} data [description]
 * @return {[type]}      [description]
 */

//带参函数
var arg_funs = {
	length: true,
	regexp: true,
	confirm: true,
	range: true,
	in: true
};
module.exports = function(data) {

	var res, cv, args, validationErrors = [];

	_.forEach(data, function(field) {

		if(!(field.valids && _.isArray(field.valids) && valids.length > 0)) {
			return true;
		}

		_.forEach(field.valids, function(validItem) {

			res = false;

			//调用参数
			args = [field.value];
			if(arg_funs[validItem]) {

				cv = field[validItem + '_args'] || [];
				if(!_.isArray(cv)) {
					cv = [cv];
				}

				args = args.concat(cv);
			}

			//调用
			if(_.isFunction(Valid[validItem])) {
				res = Valid[validItem].apply(Valid, args);
				if(res === false) {
					validationErrors.push(new errors.ValidationError('校验 (' + field.name + ') 失败，该值不符合要求： ' + field.value, field.value));
				}
			} else {
				validationErrors.push(new errors.ValidationError('校验 (' + field.name + ') 失败，没有该校验函数：', arg_funs[validItem]));
			}
		});
	});

	if (_.isEmpty(validationErrors)) {
	    return Promise.resolve(options);
	}

	return errors.logAndRejectError(validationErrors[0]);
};<|endoftext|>


<commit_before>/**
 * Rainbow.js
 *
 * @package This file is part of the Rainbow Guestbook
 * @author  Michael Pratt <pratt@hablarmierda.net>
 * @link http://www.michael-pratt.com/
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
var Rainbow = {
    // Sets things up
    init : function () {
        var t = this;

        $('#create').click(function () {
            t.createForm();
            return false;
        });

        $('#new').click(function () {
            t.list('actions.php?do=getAll&token=' + token);

            $('#header ul li').removeClass('current');
            $(this).parent('li').addClass('current');
            return false;
        });

        $('#modified').click(function () {
            t.list('actions.php?do=getActive&token=' + token);

            $('#header ul li').removeClass('current');
            $(this).parent('li').addClass('current');
            return false;
        });

        $('#favorite').click(function () {
            t.list('actions.php?do=getFavorite&token=' + token);

            $('#header ul li').removeClass('current');
            $(this).parent('li').addClass('current');
            return false;
        });

        $('#mine').click(function () {
            t.viewColor(myColor);

            $('#header ul li').removeClass('current');
            $(this).parent('li').addClass('current');
            return false;
        });

        $('#help').click(function () {
            $(this).nextAll('div').toggle();

            $('#header ul li').removeClass('current');
            $(this).parent('li').addClass('current');
            return false;
        });

        $('#help').mouseover(function () { $('#help').click(); });
        $('#help').mouseout(function () { $(this).nextAll('div').hide(); });

        $('#avatar').css({'background-color' : '#' + myColor,
                          'width' : '25px',
                          'text-align' : 'center'});

        // Trigger the action we want to do
        if (request.view)
            t.viewReplies('actions.php?do=view&token=' + token + '&id=' + request.view, request.view, true);
        else if (request.color)
            t.viewColor(request.color);
        else if (request.modified == '')
            $('#modified').click();
        else if (request.favorite == '')
            $('#favorite').click();
        else if (request.mine == '')
            $('#mine').click();
        else
            $('#new').click();
    },

    // Reads all the messages from a url
    list : function(url) {
        var t = this;
        $('#bubbles').empty();
        $.ajax({url: url,
            method:   'GET',
            dataType: 'json',
            beforeSend:  function() { $('#avatar').html(''); },
            success: function(response) {
                $('#avatar').empty();
                if ($.isEmptyObject(response))
                {
                    $('
', {'class' : 'anounce-bubbles', 'text' : rainbowLang.empty}).appendTo('#bubbles');
                    return false;
                }

                $.each(response, function(index, value) {
                    t.draw(value.id, value.text, value.replies, value.date, value.color);
                });
            }
        });
    },

    // Fetches and draws all the replies from an id
    viewReplies: function(viewUrl, id, fatalError) {
        var t = this;
        $('.inline-reply').remove();
        $('#create-form').remove();
        $.ajax({url: viewUrl,
            method:   'GET',
            dataType: 'json',
            beforeSend: function() { $('#avatar').html(' '); },
            success: function(response) {
                $('#avatar').empty();

                if (fatalError && $.isEmptyObject(response))
                {
                    $('
', {'class' : 'anounce-bubbles', 'text' : rainbowLang.empty}).appendTo('#bubbles');
                    return false;
                }

                var container = $('
', {'class' : 'inline-reply'}).appendTo('#bubbles');
                $('#bubble-' + id).after(container);

                if (!$.isEmptyObject(response)) {
                    $.each(response, function(index, value) {
                        var reply = $('
', {'class' : 'bubble'});
                        reply.css({'background-color' : '#' + value.color});
                        reply.html(t.autoEmbed(value.text));
                        reply.appendTo(container).fadeIn(1000);
                    });
                }

                var form = t.createReplyForm(id);
                form.appendTo(container);
            }
        });
    },

    // shows messages that were sent by a color
    viewColor : function (color) {
        $('#bubbles').empty();
        $.ajax({url: 'actions.php?do=getColor&token=' + token + '&color=' + color,
                method:   'GET',
                dataType: 'json',
                beforeSend:  function() { $('#avatar').html(' '); },
                success: function(response) {
                    $('#avatar').empty();
                    if ($.isEmptyObject(response))
                    {
                        $('
', {'class' : 'anounce-bubbles', 'text' : rainbowLang.empty}).appendTo('#bubbles');
                        return false;
                    }

                    $.each(response, function(index, value) {
                        var newBubble = $('
', {'class' : 'bubble', 'text' : value.text, 'id' : 'bubble-' + value.id});
                        newBubble.css({'background-color' : '#' + color,
                                       'text-align' : 'left',
                                       'opacity' : 0.7});

                        newBubble.appendTo('#bubbles');
                    });

                }
        });
    },

    // Creates a reply Form to a message
    createReplyForm : function (parentId) {
        var formContainer = $('
', {'class' : 'bubble'});
        formContainer.css({'background-color' : '#B3AAAA'});

        var form = $('<form />', {'action' : 'actions.php?do=reply&token=' + token, 'method' : 'post'});
        var textInput = $('<textarea />', {'name' : 'reply', 'type' : 'text', 'value' : ''});

        textInput.keyup(function() {
            if ($(this).val().length > 1000){
                $(this).val($(this).val().substr(0, 1000));
            }
        });

        var idInput = $('<input />', {'name' : 'id', 'type' : 'hidden', 'value' : parentId});
        var submitButton = $('<input />', {'type' : 'submit', 'value' : rainbowLang.reply});
        var clearfix = $('
', {'class' : 'clearfix'});

        textInput.appendTo(form);
        idInput.appendTo(form);
        submitButton.appendTo(form);
        clearfix.appendTo(form);

        var viewLink = $('', {'href' : 'index.php?view=' + parentId, 'text' : rainbowLang.view});
        var deleteLink = $('', {'href' : 'actions.php?do=delete&token=' + token + '&id=' + parentId, 'text' : rainbowLang.deleteShow});
        deleteLink.click(function(){ return confirm(rainbowLang.deleteConfirm); });

        if (document.cookie.indexOf('i%3A' + parentId + '%3B') != -1) {
            var favorite = $('', {'href' : 'actions.php?do=favorite&token=' + token + '&subaction=remove&id=' + parentId,
                                       'text' : rainbowLang.removeFavorite});
        }
        else {
            var favorite = $('', {'href' : 'actions.php?do=favorite&token=' + token + '&subaction=add&id=' + parentId,
                                       'text' : rainbowLang.addFavorite});
        }

        favorite.click(function(){
            $(this).remove();
        });

        viewLink.appendTo(form);
        $('', {'text' : '  |  '}).appendTo(form);
        favorite.appendTo(form);
        $('', {'text' : '  |  '}).appendTo(form);
        deleteLink.appendTo(form);
        form.appendTo(formContainer);

        return formContainer;
    },

    // Creates a form for new messages
    createForm : function () {
        $('#create-form').remove();
        $('.inline-reply').remove();
        var formContainer = $('
', {'class' : 'bubble', 'id' : 'create-form'});
        formContainer.css({'background-color' : '#B3AAAA'});

        var form = $('<form />', {'action' : 'actions.php?do=create&token=' + token, 'method' : 'post'});
        var textInput = $('<textarea />', {'name' : 'quote', 'type' : 'text', 'value' : rainbowLang.createDesc});
        textInput.focus(function() { $(this).val(''); });

        textInput.keyup(function() {
            if ($(this).val().length > 1000){
                $(this).val($(this).val().substr(0, 1000));
            }
        });

        var submitButton = $('<input />', {'type' : 'submit', 'value' : rainbowLang.create});
        var clearfix = $('
', {'class' : 'clearfix'});

        textInput.appendTo(form);
        submitButton.appendTo(form);
        clearfix.appendTo(form);
        form.appendTo(formContainer);
        formContainer.prependTo('#bubbles');
    },

    // This is the main mehtod that draws messages
    draw : function (id, text, replies, date, color) {
        var t = this;
        var repliesCounter =  $('
', {'text' : replies + ' ' + rainbowLang.replies, 'class' : 'reply-counter'});
        var textLink  = $('', {'text' : text, 'href' : 'index.php?view=' + id});
        var newBubble = $('
', {'class' : 'bubble', 'id' : 'bubble-' + id});
        newBubble.css({'background-color' : '#' + color,
                       'cursor' : 'pointer',
                       'text-align' : 'left',
                       'opacity' : 0.7});

        newBubble.click(function(){
            $(this).prependTo('#bubbles');

            $('iframe').each(function(){
                var src = $(this).attr('src');
                $(this).replaceWith(src);
            });

            $(this).html(t.autoEmbed($(this).html()));
            t.viewReplies('actions.php?do=view&token=' + token + '&id=' + id + '&shift=1', id, false);
            $('html,body').animate({scrollTop: $('#bubble-' + id).offset().top},'slow');
            return false;
        });

        repliesCounter.appendTo(newBubble);
        textLink.appendTo(newBubble);
        newBubble.appendTo('#bubbles').fadeIn(1000);
    },

    // Embeds videos
    autoEmbed : function(text) {
        var re = /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w]*(?:['"][^<>]*>|<\/a>))[?=&+%\w]*/ig;
        return text.replace(re, '

');
    }
};

$(function() { Rainbow.init(); });<commit_msg>- Arreglado un bug que no dejaba que los formularios de envio funcionaran en Opera.<commit_after>/**
 * Rainbow.js
 *
 * @package This file is part of the Rainbow Guestbook
 * @author  Michael Pratt <pratt@hablarmierda.net>
 * @link http://www.michael-pratt.com/
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
var Rainbow = {
    // Sets things up
    init : function () {
        var t = this;

        $('#create').click(function () {
            t.createForm();
            return false;
        });

        $('#new').click(function () {
            t.list('actions.php?do=getAll&token=' + token);

            $('#header ul li').removeClass('current');
            $(this).parent('li').addClass('current');
            return false;
        });

        $('#modified').click(function () {
            t.list('actions.php?do=getActive&token=' + token);

            $('#header ul li').removeClass('current');
            $(this).parent('li').addClass('current');
            return false;
        });

        $('#favorite').click(function () {
            t.list('actions.php?do=getFavorite&token=' + token);

            $('#header ul li').removeClass('current');
            $(this).parent('li').addClass('current');
            return false;
        });

        $('#mine').click(function () {
            t.viewColor(myColor);

            $('#header ul li').removeClass('current');
            $(this).parent('li').addClass('current');
            return false;
        });

        $('#help').click(function () {
            $(this).nextAll('div').toggle();

            $('#header ul li').removeClass('current');
            $(this).parent('li').addClass('current');
            return false;
        });

        $('#help').mouseover(function () { $('#help').click(); });
        $('#help').mouseout(function () { $(this).nextAll('div').hide(); });

        $('#avatar').css({'background-color' : '#' + myColor,
                          'width' : '25px',
                          'text-align' : 'center'});

        // Trigger the action we want to do
        if (request.view)
            t.viewReplies('actions.php?do=view&token=' + token + '&id=' + request.view, request.view, true);
        else if (request.color)
            t.viewColor(request.color);
        else if (request.modified == '')
            $('#modified').click();
        else if (request.favorite == '')
            $('#favorite').click();
        else if (request.mine == '')
            $('#mine').click();
        else
            $('#new').click();
    },

    // Reads all the messages from a url
    list : function(url) {
        var t = this;
        $('#bubbles').empty();
        $.ajax({url: url,
            method:   'GET',
            dataType: 'json',
            beforeSend:  function() { $('#avatar').html(''); },
            success: function(response) {
                $('#avatar').empty();
                if ($.isEmptyObject(response))
                {
                    $('
', {'class' : 'anounce-bubbles', 'text' : rainbowLang.empty}).appendTo('#bubbles');
                    return false;
                }

                $.each(response, function(index, value) {
                    t.draw(value.id, value.text, value.replies, value.date, value.color);
                });
            }
        });
    },

    // Fetches and draws all the replies from an id
    viewReplies: function(viewUrl, id, fatalError) {
        var t = this;
        $('.inline-reply').remove();
        $('#create-form').remove();
        $.ajax({url: viewUrl,
            method:   'GET',
            dataType: 'json',
            beforeSend: function() { $('#avatar').html(' '); },
            success: function(response) {
                $('#avatar').empty();

                if (fatalError && $.isEmptyObject(response))
                {
                    $('
', {'class' : 'anounce-bubbles', 'text' : rainbowLang.empty}).appendTo('#bubbles');
                    return false;
                }

                var container = $('
', {'class' : 'inline-reply'}).appendTo('#bubbles');
                $('#bubble-' + id).after(container);

                if (!$.isEmptyObject(response)) {
                    $.each(response, function(index, value) {
                        var reply = $('
', {'class' : 'bubble'});
                        reply.css({'background-color' : '#' + value.color});
                        reply.html(t.autoEmbed(value.text));
                        reply.appendTo(container).fadeIn(1000);
                    });
                }

                var form = t.createReplyForm(id);
                form.appendTo(container);
            }
        });
    },

    // shows messages that were sent by a color
    viewColor : function (color) {
        $('#bubbles').empty();
        $.ajax({url: 'actions.php?do=getColor&token=' + token + '&color=' + color,
                method:   'GET',
                dataType: 'json',
                beforeSend:  function() { $('#avatar').html(' '); },
                success: function(response) {
                    $('#avatar').empty();
                    if ($.isEmptyObject(response))
                    {
                        $('
', {'class' : 'anounce-bubbles', 'text' : rainbowLang.empty}).appendTo('#bubbles');
                        return false;
                    }

                    $.each(response, function(index, value) {
                        var newBubble = $('
', {'class' : 'bubble', 'text' : value.text, 'id' : 'bubble-' + value.id});
                        newBubble.css({'background-color' : '#' + color,
                                       'text-align' : 'left',
                                       'opacity' : 0.7});

                        newBubble.appendTo('#bubbles');
                    });

                }
        });
    },

    // Creates a reply Form to a message
    createReplyForm : function (parentId) {
        var formContainer = $('
', {'class' : 'bubble'});
        formContainer.css({'background-color' : '#B3AAAA'});

        var form = $('<form />', {'action' : 'actions.php?do=reply&token=' + token, 'method' : 'post'});
        var textInput = $('<textarea />', {'name' : 'reply', 'value' : ''});

        textInput.keyup(function() {
            if ($(this).val().length > 1000){
                $(this).val($(this).val().substr(0, 1000));
            }
        });

        var idInput = $('<input />', {'name' : 'id', 'type' : 'hidden', 'value' : parentId});
        var submitButton = $('<input />', {'type' : 'submit', 'value' : rainbowLang.reply});
        var clearfix = $('
', {'class' : 'clearfix'});

        textInput.appendTo(form);
        idInput.appendTo(form);
        submitButton.appendTo(form);
        clearfix.appendTo(form);

        var viewLink = $('', {'href' : 'index.php?view=' + parentId, 'text' : rainbowLang.view});
        var deleteLink = $('', {'href' : 'actions.php?do=delete&token=' + token + '&id=' + parentId, 'text' : rainbowLang.deleteShow});
        deleteLink.click(function(){ return confirm(rainbowLang.deleteConfirm); });

        if (document.cookie.indexOf('i%3A' + parentId + '%3B') != -1) {
            var favorite = $('', {'href' : 'actions.php?do=favorite&token=' + token + '&subaction=remove&id=' + parentId,
                                       'text' : rainbowLang.removeFavorite});
        }
        else {
            var favorite = $('', {'href' : 'actions.php?do=favorite&token=' + token + '&subaction=add&id=' + parentId,
                                       'text' : rainbowLang.addFavorite});
        }

        favorite.click(function(){
            $(this).remove();
        });

        viewLink.appendTo(form);
        $('', {'text' : '  |  '}).appendTo(form);
        favorite.appendTo(form);
        $('', {'text' : '  |  '}).appendTo(form);
        deleteLink.appendTo(form);
        form.appendTo(formContainer);

        return formContainer;
    },

    // Creates a form for new messages
    createForm : function () {
        $('#create-form').remove();
        $('.inline-reply').remove();
        var formContainer = $('
', {'class' : 'bubble', 'id' : 'create-form'});
        formContainer.css({'background-color' : '#B3AAAA'});

        var form = $('<form />', {'action' : 'actions.php?do=create&token=' + token, 'method' : 'post'});
        var textInput = $('<textarea />', {'name' : 'quote', 'value' : rainbowLang.createDesc});
        textInput.focus(function() { $(this).val(''); });

        textInput.keyup(function() {
            if ($(this).val().length > 1000){
                $(this).val($(this).val().substr(0, 1000));
            }
        });

        var submitButton = $('<input />', {'type' : 'submit', 'value' : rainbowLang.create});
        var clearfix = $('
', {'class' : 'clearfix'});

        textInput.appendTo(form);
        submitButton.appendTo(form);
        clearfix.appendTo(form);
        form.appendTo(formContainer);
        formContainer.prependTo('#bubbles');
    },

    // This is the main mehtod that draws messages
    draw : function (id, text, replies, date, color) {
        var t = this;
        var repliesCounter =  $('
', {'text' : replies + ' ' + rainbowLang.replies, 'class' : 'reply-counter'});
        var textLink  = $('', {'text' : text, 'href' : 'index.php?view=' + id});
        var newBubble = $('
', {'class' : 'bubble', 'id' : 'bubble-' + id});
        newBubble.css({'background-color' : '#' + color,
                       'cursor' : 'pointer',
                       'text-align' : 'left',
                       'opacity' : 0.7});

        newBubble.click(function(){
            $(this).prependTo('#bubbles');

            $('iframe').each(function(){
                var src = $(this).attr('src');
                $(this).replaceWith(src);
            });

            $(this).html(t.autoEmbed($(this).html()));
            t.viewReplies('actions.php?do=view&token=' + token + '&id=' + id + '&shift=1', id, false);
            $('html,body').animate({scrollTop: $('#bubble-' + id).offset().top},'slow');
            return false;
        });

        repliesCounter.appendTo(newBubble);
        textLink.appendTo(newBubble);
        newBubble.appendTo('#bubbles').fadeIn(1000);
    },

    // Embeds videos
    autoEmbed : function(text) {
        var re = /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w]*(?:['"][^<>]*>|<\/a>))[?=&+%\w]*/ig;
        return text.replace(re, '

');
    }
};

$(function() { Rainbow.init(); });<|endoftext|>


<commit_before>// adt.js
// ------
// Algebraic data types and immutable structures in Javascript
//
// version : 0.6.2
// author  : Nathan Faubion <nathan@n-son.com>
// license : MIT

;(function (adt) {
  'use strict';

  // ADT Class Generation
  // --------------------

  // Base class from which all adt.js classes inherit.
  adt.__Base__ = function () {};

  adt.data = function () {
    var targ0 = typeof arguments[0];

    // adt.data(...names: String)
    if (targ0 === 'string') {
      var names = arguments;
      return adt.data(function (type) {
        var i = 0, len = names.length;
        for (; i < len; i++) type(names[i]);
      });
    }

    // adt.data(types: Object)
    if (targ0 === 'object') {
      var types = arguments[0];
      return adt.data(function (type) {
        for (var name in types) {
          if (types.hasOwnProperty(name)) type(name, types[name]);
        }
      });
    }

    // adt.data(configure: Function)
    var callback = arguments[0] || noop;
    var names = [];

    // Create a new parent class.
    // This class should never be created using `new`. You obviously can,
    // but it won't be of much use. You can however override the apply method
    // to create default instances.
    var D = inherit(adt.__Base__, function () {
      if (!(this instanceof D) && D.apply !== Function.prototype.apply) {
        return D.apply(this, arguments);
      }
    });

    // Adds a new type to the ADT.
    D.type = function (name, tmpl) {
      if (typeof name !== 'string') {
        tmpl = name;
        name = uniqueId('Anonymous');
      }

      // Create a new template if not provided with one
      var isSingle = typeCheck([String, Boolean, Number, Date, null, void 0], tmpl);
      if (isSingle) tmpl = adt.single(tmpl);
      else if (typeof tmpl !== 'function') tmpl = adt.record(tmpl);

      // Add typechecking attributes for this type. Everything starts out as
      // false by default. Each individual class should overrides its own.
      D.prototype['is' + name] = false;

      // Call the template to build our type and export it on the parent type.
      D[name] = tmpl(D, name);
      names.push(name);
      return D[name];
    };

    // Call the callback with the constructor as the context.
    var types = callback.call(D, D.type, D);

    // If an object was returned in the callback, assume it's a mapping of
    // more types to add.
    if (typeof types === 'object' && !(types instanceof adt.__Base__)) {
      for (var name in types) {
        if (types.hasOwnProperty(name)) D.type(name, types[name]);
      }
    }

    // Keep the type function around because it allows for nice type
    // declarations, but give the option to seal it. This will call `seal`
    // on any sub types to.
    D.seal = function () {
      var i = 0, n, name;
      for (; n = names[i]; i++) if (this[n].seal) this[n].seal();
      delete D.type;
      delete D.seal;
      return D;
    };

    // Export names as a meta object
    D.__names__ = names;
    D.prototype.__adtClass__ = D;
    return D;
  };

  // Singleton Class Generation
  // --------------------------

  // Create a single empty class instance. You can pass in a value that the
  // class will use during JSON serialization.
  adt.single = function (val) {
    var ctr = function () {};
    ctr.__value__ = val === void 0 ? null : val;

    return function (parent, name) {
      inherit(parent, ctr);
      extend(ctr.prototype, adt.single.__methods__);

      ctr.className = name;
      ctr.prototype['is' + name] = true;

      return new ctr();
    };
  }

  // Singleton Methods
  // -----------------

  adt.single.__methods__ = {
    toString: function () {
      return this.constructor.className;
    },

    toJSON: function () {
      return this.constructor.__value__;
    },

    clone: function () {
      return this;
    },

    equals: function (that) {
      return this === that;
    }
  };

  // Record Class Generation
  // -----------------------

  adt.record = function () {
    var targ0 = typeof arguments[0];

    // adt.record(...names: String)
    if (targ0 === 'string') {
      var names = arguments;
      return adt.record(function (field) {
        var i = 0, len = names.length;
        for (; i < len; i++) field(names[i], adt.any);
      });
    }

    // adt.record(fields: Object)
    else if (targ0 === 'object') {
      var fields = arguments[0];
      return adt.record(function (field) {
        for (var name in fields) {
          if (fields.hasOwnProperty(name)) field(name, fields[name]);
        }
      });
    }

    // adt.record(template: Function)
    var callback = arguments[0] || noop;
    var names = [];
    var constraints = {};

    // A record's constructor can be called without `new` and will also throw
    // an error if called with the wrong number of arguments. Its arguments can
    // be curried as long as it isn't called with the `new` keyword.
    var ctr = function () {
      var args = arguments;
      var len = names.length;
      if (this instanceof ctr) {
        if (args.length < len) throw new Error('Too few arguments');
        if (args.length > len) throw new Error('Too many arguments');
        var i = 0, n;
        for (; n = names[i]; i++) this[n] = constraints[n](args[i]);
      } else {
        return args.length < len
        ? partial(ctr, toArray(args))
        : ctrApply(ctr, args);
      }
    };

    return function (parent, name) {
      inherit(parent, ctr);
      extend(ctr, adt.record.__classMethods__);
      extend(ctr.prototype, adt.record.__methods__);

      ctr.className = name;
      ctr.prototype['is' + name] = true;

      // Declares a field as part of the type.
      ctr.field = function (name, constraint) {
        if (!constraint) constraint = adt.any;
        if (typeof constraint !== 'function') {
          throw new TypeError('Constraints must be functions')
        }
        names.push(name);
        constraints[name] = constraint;
        return ctr;
      };

      // Call the callback with the contructor as the context.
      var fields = callback.call(ctr, ctr.field, ctr);

      // If an object was returned in the callback, assume it's a mapping of
      // more fields to add.
      if (typeof fields === 'object' && fields !== ctr) {
        for (var name in fields) {
          if (fields.hasOwnProperty(name)) ctr.field(name, fields[name]);
        }
      }

      // Export names and constraints as meta attributes.
      ctr.__names__ = names;
      ctr.__constraints__ = constraints;
      return ctr;
    };
  };

  // Record Methods
  // --------------

  adt.record.__methods__ = {
    toString: function () {
      var ctr = this.constructor;
      var vals = ctr.unapply(this);
      return ctr.className + (vals.length ? '(' + vals.join(', ') + ')' : '');
    },

    toJSON: function () {
      return this.constructor.unapplyObj(this, toJSONValue);
    },

    // Clones any value that is an adt.js type, delegating other JS values
    // to `adt.nativeClone`.
    clone: function () {
      var ctr = this.constructor;
      var names = ctr.__names__;
      var args = [], i = 0, n, val;
      for (; n = names[i]; i++) {
        val = this[n];
        args[i] = val instanceof adt.__Base__
          ? val.clone()
          : adt.nativeClone(val);
      }
      return ctr.apply(null, args);
    },

    // Recursively compares all adt.js types, delegating other JS values
    // to `adt.nativeEquals`.
    equals: function (that) {
      var ctr = this.constructor;
      if (this === that) return true;
      if (!(that instanceof ctr)) return false;
      var names = ctr.__names__;
      var i = 0, len = names.length;
      var vala, valb, n;
      for (; i < len; i++) {
        n = names[i];
        vala = this[n];
        valb = that[n];
        if (vala instanceof adt.__Base__) {
          if (!vala.equals(valb)) return false;
        } else if (!adt.nativeEquals(vala, valb)) return false;
      }
      return true;
    },

    // Overloaded to take either strings or numbers. Throws an error if the
    // key can't be found.
    get: function (field) {
      var ctr = this.constructor;
      var names = ctr.__names__;
      var constraints = ctr.__constraints__;
      if (typeof field === 'number') {
        if (field < 0 || field > names.length - 1) {
          throw new Error('Field index out of range: ' + field);
        }
        field = names[field];
      } else {
        if (!constraints.hasOwnProperty(field)) {
          throw new Error('Field name does not exist: ' + field);
        }
      }
      return this[field];
    },

    // Creates a new instance with the specified values changed.
    set: function (vals) {
      var ctr = this.constructor;
      var names = ctr.__names__;
      var args = [], i = 0, n;
      for (; n = names[i]; i++) args[i] = n in vals ? vals[n] : this[n];
      return ctr.apply(null, args);
    }
  };

  adt.record.__classMethods__ = {
    create: function (vals) {
      var args = [];
      var names = this.__names__;
      var i = 0, len = names.length, n;
      for (; i < len; i++) {
        n = names[i];
        if (!(n in vals)) throw new Error('Could not find field in arguments: ' + n);
        args[i] = vals[n];
      }
      return this.apply(null, args);
    },

    unapply: function (inst) {
      var names = this.__names__;
      var vals = [], i = 0, n;
      for (; n = names[i]; i++) vals[i] = inst[n];
      return vals;
    },

    unapplyObj: function (inst, fn) {
      var names = this.__names__;
      var vals = {}, i = 0, n;
      for (; n = names[i]; i++) vals[n] = fn ? fn(inst[n], n) : inst[n];
      return vals;
    },

    seal: function () {
      delete this.field;
      delete this.seal;
      return this;
    }
  };

  // Enum Class Generation
  // ---------------------

  adt.enumeration = function () {
    var E = adt.data.apply(null, arguments);
    var order = 0;

    // Helper to add the order meta attribute to a type.
    function addOrder (that) {
      if (that.constructor) that = that.constructor;
      that.__order__ = order++;
      return that;
    }

    // Iterate through the created types, applying the order meta attribute.
    for (var i = 0, n; n = E.__names__[i]; i++) addOrder(E[n]);

    // Patch the type function to add an order to any types created later.
    var __type = E.type;
    E.type = function () {
      return addOrder(__type.apply(E, arguments));
    };

    extend(E.prototype, adt.enumeration.__methods__);
    return E;
  };

  adt['enum'] = adt.enumeration;

  // Enum Methods
  // ------------

  function assertADT (a, b) {
    if (b instanceof a.__adtClass__) return true;
    throw new TypeError('Unexpected type');
  }

  function orderOf (that) {
    return that.constructor.__order__;
  }

  adt.enumeration.__methods__ = {
    lt: function (that) {
      return assertADT(this, that) && orderOf(this) < orderOf(that);
    },

    lte: function (that) {
      return assertADT(this, that) && orderOf(this) <= orderOf(that);
    },

    gt: function (that) {
      return assertADT(this, that) && orderOf(this) > orderOf(that);
    },

    gte: function (that) {
      return assertADT(this, that) && orderOf(this) >= orderOf(that);
    },

    eq: function (that) {
      return assertADT(this, that) && orderOf(this) === orderOf(that);
    },

    neq: function (that) {
      return assertADT(this, that) && orderOf(this) !== orderOf(that);
    },
  };

  // Public Helpers
  // --------------

  // Cloning for native JS types just returns a reference.
  adt.nativeClone = function (x) { return x; };

  // Equality for native JS types is just strict comparison.
  adt.nativeEquals = function (a, b) { return a === b; };

  // Shortcut for creating an ADT with only one type.
  adt.newtype = function () {
    var args = toArray(arguments);
    var data = adt.data();
    return data.type.apply(data, args);
  };

  // A contraint function that will accept any value.
  adt.any = function (x) { return x; };

  // A constraint generator that will perform instanceof checks on the value
  // to make sure it is of the correct type.
  adt.only = function () {
    var args = arguments;
    return function (x) {
      if (typeCheck(args, x)) return x;
      throw new TypeError('Unexpected type');
    };
  };

  // Utility Functions
  // -----------------

  function toArray (a, start) {
    var dest = [], i = start || 0, len = a.length;
    for (; i < len; i++) dest.push(a[i]);
    return dest;
  }

  function ctrApply (ctr, args) {
    var C = function () {};
    C.prototype = ctr.prototype;
    var inst = new C();
    var ret = ctr.apply(inst, args);
    return Object(ret) === ret ? ret : inst;
  }

  function inherit (sup, sub) {
    var C = function () {};
    C.prototype = sup.prototype;
    sub.prototype = new C();
    sub.prototype.constructor = sub;
    return sub;
  }

  function partial (func, args) {
    return function () {
      return func.apply(this, args.concat(toArray(arguments)));
    };
  }

  function extend (dest /*, ...sources*/) {
    var args = toArray(arguments, 1);
    var i = 0, len = args.length, k;
    for (; i < len; i++) {
      for (k in args[i]) {
        if (args[i].hasOwnProperty(k)) dest[k] = args[i][k];
      }
    }
    return dest;
  };

  function typeCheck (types, x) {
    var i = 0, len = types.length, type;
    for (; i < len; i++) {
      type = types[i];
      if (type instanceof Function) {
        if (x instanceof type
        || type === Number && typeof x === 'number'
        || type === String && typeof x === 'string'
        || type === Boolean && typeof x === 'boolean') return true;
      } else {
        if (type instanceof adt.__Base__ && type.equals(x)
        || type === x) return true;
      }
    }
    return false;
  }

  function toJSONValue (x) {
    return x && typeof x === 'object' && x.toJSON ? x.toJSON() : x;
  }

  var id = 0;
  function uniqueId (pre) {
    return (pre || '') + id++;
  }

  function noop () {}

})(exports !== void 0 ? exports : (this.adt = {}));
<commit_msg>Better error message for argument length errors in constructors<commit_after>// adt.js
// ------
// Algebraic data types and immutable structures in Javascript
//
// version : 0.6.2
// author  : Nathan Faubion <nathan@n-son.com>
// license : MIT

;(function (adt) {
  'use strict';

  // ADT Class Generation
  // --------------------

  // Base class from which all adt.js classes inherit.
  adt.__Base__ = function () {};

  adt.data = function () {
    var targ0 = typeof arguments[0];

    // adt.data(...names: String)
    if (targ0 === 'string') {
      var names = arguments;
      return adt.data(function (type) {
        var i = 0, len = names.length;
        for (; i < len; i++) type(names[i]);
      });
    }

    // adt.data(types: Object)
    if (targ0 === 'object') {
      var types = arguments[0];
      return adt.data(function (type) {
        for (var name in types) {
          if (types.hasOwnProperty(name)) type(name, types[name]);
        }
      });
    }

    // adt.data(configure: Function)
    var callback = arguments[0] || noop;
    var names = [];

    // Create a new parent class.
    // This class should never be created using `new`. You obviously can,
    // but it won't be of much use. You can however override the apply method
    // to create default instances.
    var D = inherit(adt.__Base__, function () {
      if (!(this instanceof D) && D.apply !== Function.prototype.apply) {
        return D.apply(this, arguments);
      }
    });

    // Adds a new type to the ADT.
    D.type = function (name, tmpl) {
      if (typeof name !== 'string') {
        tmpl = name;
        name = uniqueId('Anonymous');
      }

      // Create a new template if not provided with one
      var isSingle = typeCheck([String, Boolean, Number, Date, null, void 0], tmpl);
      if (isSingle) tmpl = adt.single(tmpl);
      else if (typeof tmpl !== 'function') tmpl = adt.record(tmpl);

      // Add typechecking attributes for this type. Everything starts out as
      // false by default. Each individual class should overrides its own.
      D.prototype['is' + name] = false;

      // Call the template to build our type and export it on the parent type.
      D[name] = tmpl(D, name);
      names.push(name);
      return D[name];
    };

    // Call the callback with the constructor as the context.
    var types = callback.call(D, D.type, D);

    // If an object was returned in the callback, assume it's a mapping of
    // more types to add.
    if (typeof types === 'object' && !(types instanceof adt.__Base__)) {
      for (var name in types) {
        if (types.hasOwnProperty(name)) D.type(name, types[name]);
      }
    }

    // Keep the type function around because it allows for nice type
    // declarations, but give the option to seal it. This will call `seal`
    // on any sub types to.
    D.seal = function () {
      var i = 0, n, name;
      for (; n = names[i]; i++) if (this[n].seal) this[n].seal();
      delete D.type;
      delete D.seal;
      return D;
    };

    // Export names as a meta object
    D.__names__ = names;
    D.prototype.__adtClass__ = D;
    return D;
  };

  // Singleton Class Generation
  // --------------------------

  // Create a single empty class instance. You can pass in a value that the
  // class will use during JSON serialization.
  adt.single = function (val) {
    var ctr = function () {};
    ctr.__value__ = val === void 0 ? null : val;

    return function (parent, name) {
      inherit(parent, ctr);
      extend(ctr.prototype, adt.single.__methods__);

      ctr.className = name;
      ctr.prototype['is' + name] = true;

      return new ctr();
    };
  }

  // Singleton Methods
  // -----------------

  adt.single.__methods__ = {
    toString: function () {
      return this.constructor.className;
    },

    toJSON: function () {
      return this.constructor.__value__;
    },

    clone: function () {
      return this;
    },

    equals: function (that) {
      return this === that;
    }
  };

  // Record Class Generation
  // -----------------------

  adt.record = function () {
    var targ0 = typeof arguments[0];

    // adt.record(...names: String)
    if (targ0 === 'string') {
      var names = arguments;
      return adt.record(function (field) {
        var i = 0, len = names.length;
        for (; i < len; i++) field(names[i], adt.any);
      });
    }

    // adt.record(fields: Object)
    else if (targ0 === 'object') {
      var fields = arguments[0];
      return adt.record(function (field) {
        for (var name in fields) {
          if (fields.hasOwnProperty(name)) field(name, fields[name]);
        }
      });
    }

    // adt.record(template: Function)
    var callback = arguments[0] || noop;
    var names = [];
    var constraints = {};

    // A record's constructor can be called without `new` and will also throw
    // an error if called with the wrong number of arguments. Its arguments can
    // be curried as long as it isn't called with the `new` keyword.
    var ctr = function () {
      var args = arguments;
      var len = names.length;
      if (this instanceof ctr) {
        if (args.length !== len) {
          throw new Error(
            'Unexpected number of arguments for ' + ctr.className + ': ' +
            'got ' + args.length + ', but need ' + len + '.'
          );
        }
        var i = 0, n;
        for (; n = names[i]; i++) this[n] = constraints[n](args[i]);
      } else {
        return args.length < len
          ? partial(ctr, toArray(args))
          : ctrApply(ctr, args);
      }
    };

    return function (parent, name) {
      inherit(parent, ctr);
      extend(ctr, adt.record.__classMethods__);
      extend(ctr.prototype, adt.record.__methods__);

      ctr.className = name;
      ctr.prototype['is' + name] = true;

      // Declares a field as part of the type.
      ctr.field = function (name, constraint) {
        if (!constraint) constraint = adt.any;
        if (typeof constraint !== 'function') {
          throw new TypeError('Constraints must be functions')
        }
        names.push(name);
        constraints[name] = constraint;
        return ctr;
      };

      // Call the callback with the contructor as the context.
      var fields = callback.call(ctr, ctr.field, ctr);

      // If an object was returned in the callback, assume it's a mapping of
      // more fields to add.
      if (typeof fields === 'object' && fields !== ctr) {
        for (var name in fields) {
          if (fields.hasOwnProperty(name)) ctr.field(name, fields[name]);
        }
      }

      // Export names and constraints as meta attributes.
      ctr.__names__ = names;
      ctr.__constraints__ = constraints;
      return ctr;
    };
  };

  // Record Methods
  // --------------

  adt.record.__methods__ = {
    toString: function () {
      var ctr = this.constructor;
      var vals = ctr.unapply(this);
      return ctr.className + (vals.length ? '(' + vals.join(', ') + ')' : '');
    },

    toJSON: function () {
      return this.constructor.unapplyObj(this, toJSONValue);
    },

    // Clones any value that is an adt.js type, delegating other JS values
    // to `adt.nativeClone`.
    clone: function () {
      var ctr = this.constructor;
      var names = ctr.__names__;
      var args = [], i = 0, n, val;
      for (; n = names[i]; i++) {
        val = this[n];
        args[i] = val instanceof adt.__Base__
          ? val.clone()
          : adt.nativeClone(val);
      }
      return ctr.apply(null, args);
    },

    // Recursively compares all adt.js types, delegating other JS values
    // to `adt.nativeEquals`.
    equals: function (that) {
      var ctr = this.constructor;
      if (this === that) return true;
      if (!(that instanceof ctr)) return false;
      var names = ctr.__names__;
      var i = 0, len = names.length;
      var vala, valb, n;
      for (; i < len; i++) {
        n = names[i];
        vala = this[n];
        valb = that[n];
        if (vala instanceof adt.__Base__) {
          if (!vala.equals(valb)) return false;
        } else if (!adt.nativeEquals(vala, valb)) return false;
      }
      return true;
    },

    // Overloaded to take either strings or numbers. Throws an error if the
    // key can't be found.
    get: function (field) {
      var ctr = this.constructor;
      var names = ctr.__names__;
      var constraints = ctr.__constraints__;
      if (typeof field === 'number') {
        if (field < 0 || field > names.length - 1) {
          throw new Error('Field index out of range: ' + field);
        }
        field = names[field];
      } else {
        if (!constraints.hasOwnProperty(field)) {
          throw new Error('Field name does not exist: ' + field);
        }
      }
      return this[field];
    },

    // Creates a new instance with the specified values changed.
    set: function (vals) {
      var ctr = this.constructor;
      var names = ctr.__names__;
      var args = [], i = 0, n;
      for (; n = names[i]; i++) args[i] = n in vals ? vals[n] : this[n];
      return ctr.apply(null, args);
    }
  };

  adt.record.__classMethods__ = {
    create: function (vals) {
      var args = [];
      var names = this.__names__;
      var i = 0, len = names.length, n;
      for (; i < len; i++) {
        n = names[i];
        if (!(n in vals)) throw new Error('Could not find field in arguments: ' + n);
        args[i] = vals[n];
      }
      return this.apply(null, args);
    },

    unapply: function (inst) {
      var names = this.__names__;
      var vals = [], i = 0, n;
      for (; n = names[i]; i++) vals[i] = inst[n];
      return vals;
    },

    unapplyObj: function (inst, fn) {
      var names = this.__names__;
      var vals = {}, i = 0, n;
      for (; n = names[i]; i++) vals[n] = fn ? fn(inst[n], n) : inst[n];
      return vals;
    },

    seal: function () {
      delete this.field;
      delete this.seal;
      return this;
    }
  };

  // Enum Class Generation
  // ---------------------

  adt.enumeration = function () {
    var E = adt.data.apply(null, arguments);
    var order = 0;

    // Helper to add the order meta attribute to a type.
    function addOrder (that) {
      if (that.constructor) that = that.constructor;
      that.__order__ = order++;
      return that;
    }

    // Iterate through the created types, applying the order meta attribute.
    for (var i = 0, n; n = E.__names__[i]; i++) addOrder(E[n]);

    // Patch the type function to add an order to any types created later.
    var __type = E.type;
    E.type = function () {
      return addOrder(__type.apply(E, arguments));
    };

    extend(E.prototype, adt.enumeration.__methods__);
    return E;
  };

  adt['enum'] = adt.enumeration;

  // Enum Methods
  // ------------

  function assertADT (a, b) {
    if (b instanceof a.__adtClass__) return true;
    throw new TypeError('Unexpected type');
  }

  function orderOf (that) {
    return that.constructor.__order__;
  }

  adt.enumeration.__methods__ = {
    lt: function (that) {
      return assertADT(this, that) && orderOf(this) < orderOf(that);
    },

    lte: function (that) {
      return assertADT(this, that) && orderOf(this) <= orderOf(that);
    },

    gt: function (that) {
      return assertADT(this, that) && orderOf(this) > orderOf(that);
    },

    gte: function (that) {
      return assertADT(this, that) && orderOf(this) >= orderOf(that);
    },

    eq: function (that) {
      return assertADT(this, that) && orderOf(this) === orderOf(that);
    },

    neq: function (that) {
      return assertADT(this, that) && orderOf(this) !== orderOf(that);
    },
  };

  // Public Helpers
  // --------------

  // Cloning for native JS types just returns a reference.
  adt.nativeClone = function (x) { return x; };

  // Equality for native JS types is just strict comparison.
  adt.nativeEquals = function (a, b) { return a === b; };

  // Shortcut for creating an ADT with only one type.
  adt.newtype = function () {
    var args = toArray(arguments);
    var data = adt.data();
    return data.type.apply(data, args);
  };

  // A contraint function that will accept any value.
  adt.any = function (x) { return x; };

  // A constraint generator that will perform instanceof checks on the value
  // to make sure it is of the correct type.
  adt.only = function () {
    var args = arguments;
    return function (x) {
      if (typeCheck(args, x)) return x;
      throw new TypeError('Unexpected type');
    };
  };

  // Utility Functions
  // -----------------

  function toArray (a, start) {
    var dest = [], i = start || 0, len = a.length;
    for (; i < len; i++) dest.push(a[i]);
    return dest;
  }

  function ctrApply (ctr, args) {
    var C = function () {};
    C.prototype = ctr.prototype;
    var inst = new C();
    var ret = ctr.apply(inst, args);
    return Object(ret) === ret ? ret : inst;
  }

  function inherit (sup, sub) {
    var C = function () {};
    C.prototype = sup.prototype;
    sub.prototype = new C();
    sub.prototype.constructor = sub;
    return sub;
  }

  function partial (func, args) {
    return function () {
      return func.apply(this, args.concat(toArray(arguments)));
    };
  }

  function extend (dest /*, ...sources*/) {
    var args = toArray(arguments, 1);
    var i = 0, len = args.length, k;
    for (; i < len; i++) {
      for (k in args[i]) {
        if (args[i].hasOwnProperty(k)) dest[k] = args[i][k];
      }
    }
    return dest;
  };

  function typeCheck (types, x) {
    var i = 0, len = types.length, type;
    for (; i < len; i++) {
      type = types[i];
      if (type instanceof Function) {
        if (x instanceof type
        || type === Number && typeof x === 'number'
        || type === String && typeof x === 'string'
        || type === Boolean && typeof x === 'boolean') return true;
      } else {
        if (type instanceof adt.__Base__ && type.equals(x)
        || type === x) return true;
      }
    }
    return false;
  }

  function toJSONValue (x) {
    return x && typeof x === 'object' && x.toJSON ? x.toJSON() : x;
  }

  var id = 0;
  function uniqueId (pre) {
    return (pre || '') + id++;
  }

  function noop () {}

})(exports !== void 0 ? exports : (this.adt = {}));
<|endoftext|>


<commit_before><commit_msg>Update project i18next to 2.0.15<commit_after><|endoftext|>