<commit_before>/**
 * jaylist v2
 * jaylist is a wrapper for javascript's built-in hash storage system.
 *
 * Copyright (C) 2011 by Ben Brooks Scholz
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * @constructor
 * List allows access to elements through a key (string of characters).
 */
var List = function () {
    this.table = {};
};

/**
 * List functions to create and manipulate a hashed list.
 *
 *  get(key)          -- Returns the value associated with key,
 *                       undefined if there is no values asso-
 *                       ciated with the key.
 *  add(key, value)   -- Insert an object into the list, over-
 *                       writing any value already assigned to the
 *                       key. Returns the value upon successful
 *                       addition.
 *  remove(key)       -- Removes the object from the list. Returns
 *                       false if no value is assigned to the key.
 *                       Upon successful removal, it returns the value
 *                       removed.
 *  keys()            -- Returns an array of the keys in the list.
 *  values()          -- Returns an array of the values in the list
 *                       with each value appearing only once.
 *  len()             -- Returns the number of elements in the list,
 *                       zero if empty.
 *  clear()           -- Removes the items from the list.
 *  hasKey(key)       -- Returns true if the list contains the key and
 *                       false if it does not.
 *  pop(key, default) -- Returns the value associated with the key and
 *                       removes it. If the value doesn't exist return
 *                       default. Default is an optional argument that
 *                       is set to undefined.
 */
List.prototype = {

    /**
     * get: Returns the value attached to the given key or undefined
     * if it isn't found.
     */
    get: function(key) {
        return this.table[key];
    },

    /**
     * add: Inserts an object into the list, assigning it to the given key.
     * It returns the value upon successful addition to the list. If a value
     * is inserted with a key that exists in the list already, the old value
     * is overwritten.
     */
    add: function (key, value) {
        this.table[key] = value;
        return this.table[key];
    },

    /**
     * remove: Removes an object from the list with the given key. It returns
     * false if no object with the given key exists in the list. Otherwise, it
     * returns the value removed.
     */
    remove: function (key) {
        var val;

        // if no value is assigned to the key
        if (this.table[key] === undefined)
            return false;

        // value associated with the key (for return)
        val = this.table[key];
        delete this.table[key];

        return val;
    },

    /**
     * keys: Returns an array of the keys in the List.
     */
    keys: function () {
        var key, keys, table;

        keys = [];
        table = this.table;

        // iterate throught the hash pairs in the table, pushing each key
        // to the keys array.
        for (key in table) {
            // filter inherited properties w/ for...in construct
            if (table.hasOwnProperty(key))
                keys.push(key);
        }

        return keys;
    },

    /**
     * values: Returns an array of the values in the list. Duplicate values
     * are only displayed once.
     */
    values: function () {
        var i, j, contains, keys, values;

        values = [];
        keys = this.keys();

        // iterate through the keys in the list
        for (i = 0; i < keys.length; i = i + 1) {
            // contains is false if the value does not already appear in the
            // values array and true if it is found.
            contains = false;
            for (j = 0; j < values.length; j = j + 1) {
                if (this.get(keys[i]) === values[j]) {
                    contains = true;
                    break;
                }
            }

            // if the value is not already in the values array, push the value
            if (!contains)
                values.push(this.get(keys[i]));
        }

        return values;
    },

    /**
     * len: Returns the number of items in the list. Returns zero if empty.
     */
    len: function () {
        var len, entry;
        len = 0;
        for (entry in this.table)
            if (this.table.hasOwnProperty(entry))
                len = len + 1;

        return len;
    },

    /**
     * clear: Removes the items from the list.
     */
    clear: function () {
        var i, keys;
        keys = this.keys();
        for (i = 0; i < keys.length; i = i + 1)
            delete this.table[keys[i]];
    },

    /**
     * hasKey: Returns true if the list contains the given key and false if
     * if does not.
     */
    hasKey: function(key) {
        if (this.get(key) !== undefined)
            return true;
        else
            return false;
    },

    /**
     * pop: Returns the value associated with the key and removes it. If there
     * is no value associated with the key, return default. Default is optional.
     */
    pop: function (key, def) {
        if (def === null)
            def = undefined;
        if (this.hasKey(key))
            return this.remove(key);
        else
            return def;
    }
};

// functions available to the user
window['List'] = List;
List.prototype['get'] = List.prototype.get;
List.prototype['add'] = List.prototype.add;
List.prototype['remove'] = List.prototype.remove;
List.prototype['keys'] = List.prototype.keys;
List.prototype['values'] = List.prototype.values;
List.prototype['len'] = List.prototype.len;
List.prototype['clear'] = List.prototype.clear;
List.prototype['hasKey'] = List.prototype.hasKey;
List.prototype['pop'] = List.prototype.pop;
<commit_msg>removed optional braces<commit_after>/**
 * jaylist v2
 * jaylist is a wrapper for javascript's built-in hash storage system.
 *
 * Copyright (C) 2011 by Ben Brooks Scholz
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * @constructor
 * List allows access to elements through a key (string of characters).
 */
var List = function () {
    this.table = {};
};

/**
 * List functions to create and manipulate a hashed list.
 *
 *  get(key)          -- Returns the value associated with key,
 *                       undefined if there is no values asso-
 *                       ciated with the key.
 *  add(key, value)   -- Insert an object into the list, over-
 *                       writing any value already assigned to the
 *                       key. Returns the value upon successful
 *                       addition.
 *  remove(key)       -- Removes the object from the list. Returns
 *                       false if no value is assigned to the key.
 *                       Upon successful removal, it returns the value
 *                       removed.
 *  keys()            -- Returns an array of the keys in the list.
 *  values()          -- Returns an array of the values in the list
 *                       with each value appearing only once.
 *  len()             -- Returns the number of elements in the list,
 *                       zero if empty.
 *  clear()           -- Removes the items from the list.
 *  hasKey(key)       -- Returns true if the list contains the key and
 *                       false if it does not.
 *  pop(key, default) -- Returns the value associated with the key and
 *                       removes it. If the value doesn't exist return
 *                       default. Default is an optional argument that
 *                       is set to undefined.
 */
List.prototype = {

    /**
     * get: Returns the value attached to the given key or undefined
     * if it isn't found.
     */
    get: function(key) {
        return this.table[key];
    },

    /**
     * add: Inserts an object into the list, assigning it to the given key.
     * It returns the value upon successful addition to the list. If a value
     * is inserted with a key that exists in the list already, the old value
     * is overwritten.
     */
    add: function (key, value) {
        this.table[key] = value;
        return this.table[key];
    },

    /**
     * remove: Removes an object from the list with the given key. It returns
     * false if no object with the given key exists in the list. Otherwise, it
     * returns the value removed.
     */
    remove: function (key) {
        var val;

        // if no value is assigned to the key
        if (this.table[key] === undefined)
            return false;

        // value associated with the key (for return)
        val = this.table[key];
        delete this.table[key];

        return val;
    },

    /**
     * keys: Returns an array of the keys in the List.
     */
    keys: function () {
        var key, keys, table;

        keys = [];
        table = this.table;

        // iterate throught the hash pairs in the table, pushing each key
        // to the keys array.
        for (key in table)
            // filter inherited properties w/ for...in construct
            if (table.hasOwnProperty(key))
                keys.push(key);

        return keys;
    },

    /**
     * values: Returns an array of the values in the list. Duplicate values
     * are only displayed once.
     */
    values: function () {
        var i, j, contains, keys, values;

        values = [];
        keys = this.keys();

        // iterate through the keys in the list
        for (i = 0; i < keys.length; i = i + 1) {
            // contains is false if the value does not already appear in the
            // values array and true if it is found.
            contains = false;
            for (j = 0; j < values.length; j = j + 1) {
                if (this.get(keys[i]) === values[j]) {
                    contains = true;
                    break;
                }
            }

            // if the value is not already in the values array, push the value
            if (!contains)
                values.push(this.get(keys[i]));
        }

        return values;
    },

    /**
     * len: Returns the number of items in the list. Returns zero if empty.
     */
    len: function () {
        var len, entry;
        len = 0;
        for (entry in this.table)
            if (this.table.hasOwnProperty(entry))
                len = len + 1;

        return len;
    },

    /**
     * clear: Removes the items from the list.
     */
    clear: function () {
        var i, keys;
        keys = this.keys();
        for (i = 0; i < keys.length; i = i + 1)
            delete this.table[keys[i]];
    },

    /**
     * hasKey: Returns true if the list contains the given key and false if
     * if does not.
     */
    hasKey: function(key) {
        if (this.get(key) !== undefined)
            return true;
        else
            return false;
    },

    /**
     * pop: Returns the value associated with the key and removes it. If there
     * is no value associated with the key, return default. Default is optional.
     */
    pop: function (key, def) {
        if (def === null)
            def = undefined;
        if (this.hasKey(key))
            return this.remove(key);
        else
            return def;
    }
};

// functions available to the user
window['List'] = List;
List.prototype['get'] = List.prototype.get;
List.prototype['add'] = List.prototype.add;
List.prototype['remove'] = List.prototype.remove;
List.prototype['keys'] = List.prototype.keys;
List.prototype['values'] = List.prototype.values;
List.prototype['len'] = List.prototype.len;
List.prototype['clear'] = List.prototype.clear;
List.prototype['hasKey'] = List.prototype.hasKey;
List.prototype['pop'] = List.prototype.pop;
<|endoftext|>


<commit_before>/**
 * jaylist is a wrapper for javascript's built-in hash storage system.
 * It provides functions to manipulate the list.
 *
 * Copyright (C) 2011 by Ben Brooks Scholz
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * List functions to create and manipulate a hashed list.
 *
 *  get(key)          -- Returns the value associated with key, un-
 *                       defined if there is no values associated
 *                       with the key.
 *  add(key, value)   -- Insert an object into the list, overwriting
 *                       any value already assigned to the key. Returns
 *                       the value upon successful addition.
 *  remove(item)      -- Removes the object from the list. Returns
 *                       undefined if no value is assigned to the key.
 *                       Upon successful removal, it returns the value
 *                       removed. A list or array of keys may also be
 *                       passed.
 *  keys()            -- Returns an array of the keys in the list.
 *  values()          -- Returns an array of the values in the list
 *                       with each value appearing only once.
 *  items()           -- Returns an array of key value pairs.
 *  len()             -- Returns the number of elements in the list,
 *                       zero if empty.
 *  clear()           -- Removes the items from the list.
 *  hasKey(key)       -- Returns true if the list contains the key and
 *                       false if it does not.
 *  pop(key, default) -- Returns the value associated with the key and
 *                       removes it. If the value doesn't exist return
 *                       default. Default is an optional argument that
 *                       is set to undefined.
 *  popItem()         -- Returns a random key value pair ( [key, value] )
 *                       and removes it. Like it's python counterpart,
 *                       you can use it to destructively iterate over
 *                       the list.
 *  update(list)      -- Updates the list with the entries of the input
 *                       list.
 *  copy()            -- Returns a deep copy of the list.
 *  each(callback)    -- Iterates over the entries in the list, passing
 *                       the parameter 'key'.
 *  next()            -- Iterates over the entries in the list returning
 *                       the key until the iteration is complete (calling
 *                       next() at this point will return undefined.
 *  object()          -- Returns the key value list as an object.
 *  isEqual(list)     -- Returns true if the lists are equivalent and false
 *                       otherwise.
 */

/**
 * List allows access to elements through a key (string of characters).
 * _next is a placeholder for the next() iterator.
 */
var List = function () {
    this._table = {};
    this._next;
};

List.prototype = (function () {

    // an iternal array type checker. It returns true
    // if item is an array and false otherwise.
    var _isArray = function (item) {
        if (item && typeof item === 'object' && item.constructor === Array)
            return true;
        else if (Object.prototype.toString.call(item) == '[object Array]')
            return true;
        else
            return false;
    };

    // recursive function for equality checking
    var _deepEquals = function (a_obj, b_obj) {

        var i, key, atype = typeof a_obj, btype = typeof b_obj;

        // basic equality checks
        if (a_obj === b_obj)
            return true;
        if (atype !== btype)
            return false;

        // a_obj and b_obj are arrays; check their members
        if (_isArray(a_obj) && _isArray(b_obj)) {
            if (a_obj.length !== b_obj.length)
                return false;
            for (i = 0; i < a_obj.length; i += 1)
                if (a_obj[i] !== b_obj[i])
                    return false;
            return true;
        }

        // if a_obj and b_obj aren't objects, at this point, they aren't equal
        if (atype !== "object")
            return false;

        // check number of keys in object
        if (Object.keys(a_obj).length !== Object.keys(b_obj).length)
            return false;

        // equality of key-values and recursive call to deepEquals()
        for (key in a_obj) {
            if (!b_obj.hasOwnProperty(key))
                return false;
            if (a_obj.hasOwnProperty(key) && b_obj.hasOwnProperty(key))
                return _deepEquals(a_obj[key], b_obj[key]);
        }

        // if it has made it this far, a_obj and b_obj are equal
        return true;
    };

    // recursive function for deep copying a list
    var _deepCopy = function (obj) {
        var entry, copied = {};

        // object is an instance of List
        if (obj instanceof List)
            copied = new List();

        // object is an array
        else if (_isArray(obj))
            copied = [];

        // copy each member of the object
        for (entry in obj) {

            if (obj.hasOwnProperty(entry)) {
                if (typeof obj[entry] === 'string' ||
                    typeof obj[entry] === 'number' ||
                    typeof obj[entry] === 'boolean')
                    copied[entry] = obj[entry];

                // if member is object, recursively call deepCopy(obj)
                else if (typeof obj[entry] === 'object' || _isArray(obj))
                    copied[entry] = _deepCopy(obj[entry]);

            }
        }
        return copied;
    };

   /**
    * get: Returns the value attached to the given key or undefined
    * if it isn't found.
    */
    var get = function (key) {
        if (this._table.hasOwnProperty(key))
            return this._table[key];
        else
            return undefined;
    };

   /**
    * add: Inserts an object into the list, assigning it to the given key.
    * It returns the value upon successful addition to the list. If a value
    * is inserted with a key that exists in the list already, the old value
    * is overwritten.
    */
    var add = function (key, value) {
        return (this._table[key] = value);
    };

   /**
    * remove: Removes an object from the list with the given key. It returns
    * undefined if no object with the given key exists in the list. Otherwise,
    * it returns the value removed. A list or array of keys may also be passed.
    */
    var remove = function (item) {
        var nitem;

        // item is a list: remove all keys from parent object
        if (item instanceof List) {
            while ((nitem = item.next()))
                delete this._table[nitem];

        // item is an array: remove keys from parent object
        } else if (_isArray(item)) {
            while (item.length !== 0)
                delete this._table[item.pop()];

        // item is a single key: remove it and return its value (undefined is returned
        // if the key is not a member of the parent object).
        } else {
            var val = this._table[item];
            delete this._table[item];
            return val;
        }
    };

   /**
    * keys: Returns an array of the keys in the List.
    */
    var keys = function () {
        return Object.keys(this._table);
    };

   /**
    * values: Returns an array of the values in the list. Duplicate values
    * are only displayed once.
    */
    var values = function () {
        var i, contains, self = this, values = [];

        // iterate through the keys in the list
        this.each(function (key) {

            contains = false;
            i = values.length;

            // decrement the value for the length of values.
            // contains is false if the value does not already
            // appear in the values array and true if it is
            // found. when contains is true, break out of the loop.
            while (i-- && !contains)
                if (self.get(key) === values[i])
                    contains = true;

            // push the value if it is not in the values array
            if (!contains)
                values.push(self.get(key));
        });

        return values;
    };

   /**
    * items: Returns an array of key-value pairs: [[key, value]]
    */
    var items = function () {
        var itemlist = [], self = this;

        // push each key and value to itemlist
        this.each(function (key) {
            itemlist.push([key, self._table[key]]);
        });

        return itemlist;
    };

   /**
    * len: Returns the number of items in the list. Returns zero if empty.
    */
    var len = function () {
        var len = 0;

        // count the entries in the table
        this.each(function () {
            len = len + 1;
        });

        return len;
    };

   /**
    * clear: Removes the items from the list.
    */
    var clear = function () {
        this._table = {};
    };

   /**
    * hasKey: Returns true if the list contains the given key and false if
    * if does not.
    */
    var hasKey = function (key) {
        return (this.get(key) !== undefined);
    };

   /**
    * pop: Returns the value associated with the key and removes it. If there
    * is no value associated with the key, return undefined, & for that reason
    * def is optional.
    */
    var pop = function (key, def) {
        if (this.hasKey(key))
        	this.remove(key);
        else
        	return def;
    };

   /**
    * popItem: Returns a random key value pair ( [key, value] ) and removes it.
    */
    var popItem = function () {
        var pair, keys = this.keys();

        // make sure there are keys in the list
        if (keys.length === 0)
            return undefined;

        // pop a random key from the key list and push it to the pair
        pair = [keys[0]];

        // push the value to the pair and remove it
        pair.push(this.remove(pair[0]));

        return pair;
    };

   /**
    * update: Adds all the entries from the input list to the list.
    */
    var update = function (list) {
        var self = this;

        // iterate through the input list, push the entries to the list
        list.each(function (key) {
            self._table[key] = list.get(key);
        });
    };

   /**
    * copy: Returns a deep copy of the list.
    */
    var copy = function () {

        // create a new list and fill it with the result of deepCopy(obj)
        var copy = new List();
        copy.update(_deepCopy(this));

        return copy;
    };

   /**
    * each: Iterates over each entry in the list, calling the callback with the
    * parameter 'key'.
    */
    var each = function (callback) {
        for (var key in this._table)
            if (this._table.hasOwnProperty(key))
                callback(key);
    };

   /**
    * next: Iterates over the list, returning the key of next entry on each call.
    * Returns undefined when the iteration is complete.
    */
    var next = function () {
        // _next contains keys to iterate through
        if (this._next !== undefined && this._next.length !== 0)
            return this._next.pop();

        // _next is empty; fill it with keys and pop one
        else if (this._next === undefined) {
            this._next = this.keys();
            return this._next.pop();

        // iteration complete, reset _next
        } else if (this._next.length === 0) {
            this._next = undefined;
            return this._next;
        }
    };

   /**
    * object: Return the key-value list as an object.
    */
    var object = function () {
        return this._table;
    };

   /**
    * isEqual: Returns true if the lists are equivalent and false otherwise.
    */
    var isEqual = function (list) {

        // check if list argument is actually a list
        if (!(list instanceof List))
            return false;

        return _deepEquals(this._table, list._table);
    };

    return {
        _table: this._table,
        _next: this._next,
        get: get,
        add: add,
        remove: remove,
        keys: keys,
        values: values,
        items: items,
        len: len,
        clear: clear,
        hasKey: hasKey,
        pop: pop,
        popItem: popItem,
        update: update,
        copy: copy,
        each: each,
        next: next,
        object: object,
        isEqual: isEqual
    };
})();
<commit_msg>spacing changes<commit_after>/**
 * jaylist is a wrapper for javascript's built-in hash storage system.
 * It provides functions to manipulate the list.
 *
 * Copyright (C) 2011 by Ben Brooks Scholz
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * List functions to create and manipulate a hashed list.
 *
 *  get(key)          -- Returns the value associated with key, un-
 *                       defined if there is no values associated
 *                       with the key.
 *  add(key, value)   -- Insert an object into the list, overwriting
 *                       any value already assigned to the key. Returns
 *                       the value upon successful addition.
 *  remove(item)      -- Removes the object from the list. Returns
 *                       undefined if no value is assigned to the key.
 *                       Upon successful removal, it returns the value
 *                       removed. A list or array of keys may also be
 *                       passed.
 *  keys()            -- Returns an array of the keys in the list.
 *  values()          -- Returns an array of the values in the list
 *                       with each value appearing only once.
 *  items()           -- Returns an array of key value pairs.
 *  len()             -- Returns the number of elements in the list,
 *                       zero if empty.
 *  clear()           -- Removes the items from the list.
 *  hasKey(key)       -- Returns true if the list contains the key and
 *                       false if it does not.
 *  pop(key, default) -- Returns the value associated with the key and
 *                       removes it. If the value doesn't exist return
 *                       default. Default is an optional argument that
 *                       is set to undefined.
 *  popItem()         -- Returns a random key value pair ( [key, value] )
 *                       and removes it. Like it's python counterpart,
 *                       you can use it to destructively iterate over
 *                       the list.
 *  update(list)      -- Updates the list with the entries of the input
 *                       list.
 *  copy()            -- Returns a deep copy of the list.
 *  each(callback)    -- Iterates over the entries in the list, passing
 *                       the parameter 'key'.
 *  next()            -- Iterates over the entries in the list returning
 *                       the key until the iteration is complete (calling
 *                       next() at this point will return undefined.
 *  object()          -- Returns the key value list as an object.
 *  isEqual(list)     -- Returns true if the lists are equivalent and false
 *                       otherwise.
 */

/**
 * List allows access to elements through a key (string of characters).
 * _next is a placeholder for the next() iterator.
 */
var List = function () {
    this._table = {};
    this._next;
};

List.prototype = (function () {

    // an iternal array type checker. It returns true
    // if item is an array and false otherwise.
    var _isArray = function (item) {
        if (item && typeof item === 'object' && item.constructor === Array)
            return true;
        else if (Object.prototype.toString.call(item) == '[object Array]')
            return true;
        else
            return false;
    };

    // recursive function for equality checking
    var _deepEquals = function (a_obj, b_obj) {

        var i, key, atype = typeof a_obj, btype = typeof b_obj;

        // basic equality checks
        if (a_obj === b_obj)
            return true;
        if (atype !== btype)
            return false;

        // a_obj and b_obj are arrays; check their members
        if (_isArray(a_obj) && _isArray(b_obj)) {
            if (a_obj.length !== b_obj.length)
                return false;
            for (i = 0; i < a_obj.length; i += 1)
                if (a_obj[i] !== b_obj[i])
                    return false;
            return true;
        }

        // if a_obj and b_obj aren't objects, at this point, they aren't equal
        if (atype !== "object")
            return false;

        // check number of keys in object
        if (Object.keys(a_obj).length !== Object.keys(b_obj).length)
            return false;

        // equality of key-values and recursive call to deepEquals()
        for (key in a_obj) {
            if (!b_obj.hasOwnProperty(key))
                return false;
            if (a_obj.hasOwnProperty(key) && b_obj.hasOwnProperty(key))
                return _deepEquals(a_obj[key], b_obj[key]);
        }

        // if it has made it this far, a_obj and b_obj are equal
        return true;
    };

    // recursive function for deep copying a list
    var _deepCopy = function (obj) {
        var entry, copied = {};

        // object is an instance of List
        if (obj instanceof List)
            copied = new List();

        // object is an array
        else if (_isArray(obj))
            copied = [];

        // copy each member of the object
        for (entry in obj) {

            if (obj.hasOwnProperty(entry)) {
                if (typeof obj[entry] === 'string' ||
                    typeof obj[entry] === 'number' ||
                    typeof obj[entry] === 'boolean')
                    copied[entry] = obj[entry];

                // if member is object, recursively call deepCopy(obj)
                else if (typeof obj[entry] === 'object' || _isArray(obj))
                    copied[entry] = _deepCopy(obj[entry]);

            }
        }
        return copied;
    };

   /**
    * get: Returns the value attached to the given key or undefined
    * if it isn't found.
    */
    var get = function (key) {
        if (this._table.hasOwnProperty(key))
            return this._table[key];
        else
            return undefined;
    };

   /**
    * add: Inserts an object into the list, assigning it to the given key.
    * It returns the value upon successful addition to the list. If a value
    * is inserted with a key that exists in the list already, the old value
    * is overwritten.
    */
    var add = function (key, value) {
        return (this._table[key] = value);
    };

   /**
    * remove: Removes an object from the list with the given key. It returns
    * undefined if no object with the given key exists in the list. Otherwise,
    * it returns the value removed. A list or array of keys may also be passed.
    */
    var remove = function (item) {
        var nitem;

        // item is a list: remove all keys from parent object
        if (item instanceof List) {
            while ((nitem = item.next()))
                delete this._table[nitem];

        // item is an array: remove keys from parent object
        } else if (_isArray(item)) {
            while (item.length !== 0)
                delete this._table[item.pop()];

        // item is a single key: remove it and return its value (undefined is returned
        // if the key is not a member of the parent object).
        } else {
            var val = this._table[item];
            delete this._table[item];
            return val;
        }
    };

   /**
    * keys: Returns an array of the keys in the List.
    */
    var keys = function () {
        return Object.keys(this._table);
    };

   /**
    * values: Returns an array of the values in the list. Duplicate values
    * are only displayed once.
    */
    var values = function () {
        var i, contains, self = this, values = [];

        // iterate through the keys in the list
        this.each(function (key) {

            contains = false;
            i = values.length;

            // decrement the value for the length of values.
            // contains is false if the value does not already
            // appear in the values array and true if it is
            // found. when contains is true, break out of the loop.
            while (i-- && !contains)
                if (self.get(key) === values[i])
                    contains = true;

            // push the value if it is not in the values array
            if (!contains)
                values.push(self.get(key));
        });

        return values;
    };

   /**
    * items: Returns an array of key-value pairs: [[key, value]]
    */
    var items = function () {
        var itemlist = [], self = this;

        // push each key and value to itemlist
        this.each(function (key) {
            itemlist.push([key, self._table[key]]);
        });

        return itemlist;
    };

   /**
    * len: Returns the number of items in the list. Returns zero if empty.
    */
    var len = function () {
        var len = 0;

        // count the entries in the table
        this.each(function () {
            len = len + 1;
        });

        return len;
    };

   /**
    * clear: Removes the items from the list.
    */
    var clear = function () {
        this._table = {};
    };

   /**
    * hasKey: Returns true if the list contains the given key and false if
    * if does not.
    */
    var hasKey = function (key) {
        return (this.get(key) !== undefined);
    };

   /**
    * pop: Returns the value associated with the key and removes it. If there
    * is no value associated with the key, return undefined, & for that reason
    * def is optional.
    */
    var pop = function (key, def) {
        if (this.hasKey(key))
        	this.remove(key);
        else
        	return def;
    };

   /**
    * popItem: Returns a random key value pair ( [key, value] ) and removes it.
    */
    var popItem = function () {
        var pair, keys = this.keys();

        // make sure there are keys in the list
        if (keys.length === 0)
            return undefined;

        // pop a random key from the key list and push it to the pair
        pair = [keys[0]];

        // push the value to the pair and remove it
        pair.push(this.remove(pair[0]));

        return pair;
    };

   /**
    * update: Adds all the entries from the input list to the list.
    */
    var update = function (list) {
        var self = this;

        // iterate through the input list, push the entries to the list
        list.each(function (key) {
            self._table[key] = list.get(key);
        });
    };

   /**
    * copy: Returns a deep copy of the list.
    */
    var copy = function () {
        // create a new list and fill it with the result of deepCopy(obj)
        var copy = new List();
        copy.update(_deepCopy(this));

        return copy;
    };

   /**
    * each: Iterates over each entry in the list, calling the callback with the
    * parameter 'key'.
    */
    var each = function (callback) {
        for (var key in this._table)
            if (this._table.hasOwnProperty(key))
                callback(key);
    };

   /**
    * next: Iterates over the list, returning the key of next entry on each call.
    * Returns undefined when the iteration is complete.
    */
    var next = function () {
        // _next contains keys to iterate through
        if (this._next !== undefined && this._next.length !== 0)
            return this._next.pop();

        // _next is empty; fill it with keys and pop one
        else if (this._next === undefined) {
            this._next = this.keys();
            return this._next.pop();

        // iteration complete, reset _next
        } else if (this._next.length === 0) {
            this._next = undefined;
            return this._next;
        }
    };

   /**
    * object: Return the key-value list as an object.
    */
    var object = function () {
        return this._table;
    };

   /**
    * isEqual: Returns true if the lists are equivalent and false otherwise.
    */
    var isEqual = function (list) {
        // check if list argument is actually a list
        if (!(list instanceof List))
            return false;

        return _deepEquals(this._table, list._table);
    };

    return {
        _table: this._table,
        _next: this._next,
        get: get,
        add: add,
        remove: remove,
        keys: keys,
        values: values,
        items: items,
        len: len,
        clear: clear,
        hasKey: hasKey,
        pop: pop,
        popItem: popItem,
        update: update,
        copy: copy,
        each: each,
        next: next,
        object: object,
        isEqual: isEqual
    };
})();
<|endoftext|>


<commit_before>/**
 * Remove all undefined values from an array
 */

module.exports = function compact (...items) {
  return [].concat.apply([], items).filter(i => i !== void 0)
}
<commit_msg>[remove] unused compact.js<commit_after><|endoftext|>


<commit_before>////
//// A forward-looking branch of TermDetails.js
//// A lot of the commented out stuff in the other completely gone here.
//// Will dev on this one until I replace the other.
////

// Logger.
var logger = new bbop.logger();
logger.DEBUG = true;
function ll(str){ logger.kvetch('TD: ' + str); }
// AmiGO helper.
var amigo = new bbop.amigo();
var gm = new bbop.amigo.go_meta();

//
function TermDetailsInit(){

    ll('');
    ll('TermDetailsBeta.js');
    ll('TermDetailsInit start...');

    // var prev_source_count = 0;
    // var prev_species_count = 0;

    // Bring in meta information.
    var species_data = gm.species();
    var source_data = gm.sources();

    ///
    /// Tabify the layout if we can (may be in a non-tabby version).
    ///

    var dtabs = jQuery("#display-tabs");
    if( dtabs ){
	ll('Apply tabs...');
	jQuery("#display-tabs").tabs();
	//dtabs.tabs();
	jQuery("#display-tabs").tabs('select', 0);
    }

    ///
    /// Ready the configuration that we'll use.
    ///

    var gconf = new bbop.golr.conf(bbop.golr.golr_meta);
    var cclass = gconf.get_class('bbop_ann');
    var filter_order = cclass.field_order_by_weight('filter');

    ///
    /// Manager and callbacks.
    ///

    var solr_server = gm.golr_base();

    // TODO: new to replace the below.
    var gm_ann = new bbop.golr.manager(solr_server, gconf);
    gm_ann.set_personality('bbop_ann'); // profile in gconf
    gm_ann.sticky_filters('document_category', 'annotation');
    gm_ann.sticky_filters('isa_partof_closure', global_acc);

    var ui_ann = new GOlrUIBeta({'interface_id': 'display-associations',
				 'class_conf': cclass});

    ///
    /// Setup and bind them together.
    ///

    // Class/term init.
    // gm_ann.register('reset', 'control_init_q',
    // 		    ui_ann.make_filter_controls_frame, 0);
    // Setup the gross frames for the filters and results.
    ui_ann.setup_filters();
    ui_ann.setup_results();
    ui_ann.setup_meta(); // meta is nested inside something created
			 // for results, so it comes after.

    // Things to do on every reset event.
    //gm_ann.register('reset', 'results_init', ui_ann.make_results_frame, -2);
    //gm_ann.register('reset', 'filters_set', ui_ann.set_static_filters);
    gm_ann.register('reset', 'filters_first', ui_ann.draw_filters, -1);
    gm_ann.register('reset', 'meta_first', ui_ann.draw_meta, -1);
    gm_ann.register('reset', 'results_first', ui_ann.draw_results, -1);
    // gm_ann.register('reset', 'results_init_after', _peg_q, -4);

    // Things to do on every search event.
    gm_ann.register('search', 'controls_usual', ui_ann.draw_filters);
    gm_ann.register('search', 'meta_usual', ui_ann.draw_meta);
    gm_ann.register('search', 'results_usual', ui_ann.draw_results);

    // Whenever there is a user interface actions, trigger a model
    // search.
    ui_ann.register('action', 'ui_action', gm_ann.search);

    // Start the ball with a reset.
    gm_ann.reset();

    //
    ll('TermDetailsInit done.');
}
<commit_msg>added richer fq path and API to manager; fixed bugs in tests and core; more core utils; tests, documentation and docs<commit_after>////
//// A forward-looking branch of TermDetails.js
//// A lot of the commented out stuff in the other completely gone here.
//// Will dev on this one until I replace the other.
////

// Logger.
var logger = new bbop.logger();
logger.DEBUG = true;
function ll(str){ logger.kvetch('TD: ' + str); }
// AmiGO helper.
var amigo = new bbop.amigo();
var gm = new bbop.amigo.go_meta();

//
function TermDetailsInit(){

    ll('');
    ll('TermDetailsBeta.js');
    ll('TermDetailsInit start...');

    // var prev_source_count = 0;
    // var prev_species_count = 0;

    // Bring in meta information.
    var species_data = gm.species();
    var source_data = gm.sources();

    ///
    /// Tabify the layout if we can (may be in a non-tabby version).
    ///

    var dtabs = jQuery("#display-tabs");
    if( dtabs ){
	ll('Apply tabs...');
	jQuery("#display-tabs").tabs();
	//dtabs.tabs();
	jQuery("#display-tabs").tabs('select', 0);
    }

    ///
    /// Ready the configuration that we'll use.
    ///

    var gconf = new bbop.golr.conf(bbop.golr.golr_meta);
    var cclass = gconf.get_class('bbop_ann');
    var filter_order = cclass.field_order_by_weight('filter');

    ///
    /// Manager and callbacks.
    ///

    var solr_server = gm.golr_base();

    // TODO: new to replace the below.
    var gm_ann = new bbop.golr.manager(solr_server, gconf);
    gm_ann.set_personality('bbop_ann'); // profile in gconf
    // Make these two base filters sticky in this case.
    gm_ann.add_query_filter('document_category', 'annotation', ['*']);
    gm_ann.add_query_filter('isa_partof_closure', global_acc, ['*']);

    var ui_ann = new GOlrUIBeta({'interface_id': 'display-associations',
				 'class_conf': cclass});

    ///
    /// Setup and bind them together.
    ///

    // Class/term init.
    // gm_ann.register('reset', 'control_init_q',
    // 		    ui_ann.make_filter_controls_frame, 0);
    // Setup the gross frames for the filters and results.
    ui_ann.setup_filters();
    ui_ann.setup_results();
    ui_ann.setup_meta(); // meta is nested inside something created
			 // for results, so it comes after.

    // Things to do on every reset event.
    //gm_ann.register('reset', 'results_init', ui_ann.make_results_frame, -2);
    //gm_ann.register('reset', 'filters_set', ui_ann.set_static_filters);
    gm_ann.register('reset', 'filters_first', ui_ann.draw_filters, -1);
    gm_ann.register('reset', 'meta_first', ui_ann.draw_meta, -1);
    gm_ann.register('reset', 'results_first', ui_ann.draw_results, -1);
    // gm_ann.register('reset', 'results_init_after', _peg_q, -4);

    // Things to do on every search event.
    gm_ann.register('search', 'controls_usual', ui_ann.draw_filters);
    gm_ann.register('search', 'meta_usual', ui_ann.draw_meta);
    gm_ann.register('search', 'results_usual', ui_ann.draw_results);

    // Whenever there is a user interface actions, trigger a model
    // search.
    ui_ann.register('action', 'ui_action', gm_ann.search);

    // Start the ball with a reset.
    gm_ann.reset();

    //
    ll('TermDetailsInit done.');
}
<|endoftext|>


<commit_before>/**
 * DashboardCoreSiteAlerts Component Stories.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Internal dependencies
 */
import WithRegistrySetup from '../../../../tests/js/WithRegistrySetup';
import DashboardCoreSiteAlerts from './DashboardCoreSiteAlerts';
import { CORE_SITE } from '../../googlesitekit/datastore/site/constants';
import { CORE_USER } from '../../googlesitekit/datastore/user/constants';

const Template = ( { setupRegistry } ) => (
	<WithRegistrySetup func={ setupRegistry }>
		<DashboardCoreSiteAlerts />
	</WithRegistrySetup>
);

const notification1 = {
	id: 'test-notification',
	title: 'Google Analytics 5 Beta',
	content: 'Upgrade to the latest and greatest version of Analytics!',
	ctaURL: '#ga5-upgrade',
	ctaLabel: 'Upgrade to GA5!',
	ctaTarget: '_blank',
	learnMoreURL: '#learn-more',
	learnMoreLabel: 'Learn more',
	dismissible: true,
	dismissLabel: 'Dismiss this message',
};

export const NotificationCTA = Template.bind( {} );
NotificationCTA.storyName = 'Has Notifications - Displayed';
NotificationCTA.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( CORE_SITE ).receiveGetNotifications( [ notification1 ], {} );
	},
};

export const NoNotifications = Template.bind( {} );
NoNotifications.storyName = 'Has No Notifications - Not Displayed';
NoNotifications.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( CORE_SITE ).receiveGetNotifications( [], {} );
	},
};

export const NotificationCTAWithSurvey = Template.bind( {} );
NotificationCTAWithSurvey.storyName = 'Has Notifications, and Survey - Not Displayed';
NotificationCTAWithSurvey.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( CORE_SITE ).receiveGetNotifications( [ notification1 ], {} );
		registry.dispatch( CORE_USER ).receiveTriggerSurvey( { survey_payload: { ab2: true }, session: {} }, { triggerID: 'storybook' } );
	},
};

export const NotificationCTAWithSurveyShortDelay = Template.bind( {} );
NotificationCTAWithSurveyShortDelay.storyName = 'Has Notifications, with Survey in three seconds - Not Displayed';
NotificationCTAWithSurveyShortDelay.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( CORE_SITE ).receiveGetNotifications( [ notification1 ], {} );
		setTimeout( () => {
			// Remote triggered survey arrives after three seconds, so the notification WILL NOT be displayed.
			registry.dispatch( CORE_USER ).receiveTriggerSurvey( { survey_payload: { ab2: true }, session: {} }, { triggerID: 'storybook' } );
		}, 3 * 1000 );
	},
};

export const NotificationCTAWithSurveyLongerDelay = Template.bind( {} );
NotificationCTAWithSurveyLongerDelay.storyName = 'Has Notifications, with Survey in six seconds - Displayed';
NotificationCTAWithSurveyLongerDelay.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( CORE_SITE ).receiveGetNotifications( [ notification1 ], {} );
		setTimeout( () => {
			// Remote triggered survey arrives after the five second window, so the notification WILL be displayed.
			registry.dispatch( CORE_USER ).receiveTriggerSurvey( { survey_payload: { ab2: true }, session: {} }, { triggerID: 'storybook' } );
		}, 6 * 1000 );
	},
};

export default {
	title: 'Components/DashboardCoreSiteAlerts',
	decorators: [
		( Story ) => (

					<Story />

		),
		( Story, { args } ) => {
			const setupRegistry = ( registry ) => {
				// Call story-specific setup.
				args.setupRegistry( registry );
			};

			return (
				<WithRegistrySetup func={ setupRegistry }>
					<Story />
				</WithRegistrySetup>
			);
		},
	],
};
<commit_msg>Update assets/js/components/legacy-notifications/DashboardCoreSiteAlerts.stories.js<commit_after>/**
 * DashboardCoreSiteAlerts Component Stories.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Internal dependencies
 */
import WithRegistrySetup from '../../../../tests/js/WithRegistrySetup';
import DashboardCoreSiteAlerts from './DashboardCoreSiteAlerts';
import { CORE_SITE } from '../../googlesitekit/datastore/site/constants';
import { CORE_USER } from '../../googlesitekit/datastore/user/constants';

const Template = ( { setupRegistry } ) => (
	<WithRegistrySetup func={ setupRegistry }>
		<DashboardCoreSiteAlerts />
	</WithRegistrySetup>
);

const notification1 = {
	id: 'test-notification',
	title: 'Google Analytics 5 Beta',
	content: 'Upgrade to the latest and greatest version of Analytics!',
	ctaURL: '#ga5-upgrade',
	ctaLabel: 'Upgrade to GA5!',
	ctaTarget: '_blank',
	learnMoreURL: '#learn-more',
	learnMoreLabel: 'Learn more',
	dismissible: true,
	dismissLabel: 'Dismiss this message',
};

export const NotificationCTA = Template.bind( {} );
NotificationCTA.storyName = 'Has Notifications - Displayed';
NotificationCTA.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( CORE_SITE ).receiveGetNotifications( [ notification1 ], {} );
	},
};

export const NoNotifications = Template.bind( {} );
NoNotifications.storyName = 'Has No Notifications - Not Displayed';
NoNotifications.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( CORE_SITE ).receiveGetNotifications( [], {} );
	},
};

export const NotificationCTAWithSurvey = Template.bind( {} );
NotificationCTAWithSurvey.storyName = 'Has Notifications, and Survey - Not Displayed';
NotificationCTAWithSurvey.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( CORE_SITE ).receiveGetNotifications( [ notification1 ], {} );
		registry.dispatch( CORE_USER ).receiveTriggerSurvey( { survey_payload: { ab2: true }, session: {} }, { triggerID: 'storybook' } );
	},
};

export const NotificationCTAWithSurveyShortDelay = Template.bind( {} );
NotificationCTAWithSurveyShortDelay.storyName = 'Has Notifications, with Survey in three seconds - Not Displayed';
NotificationCTAWithSurveyShortDelay.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( CORE_SITE ).receiveGetNotifications( [ notification1 ], {} );
		setTimeout( () => {
			// Remote triggered survey arrives in three seconds, so the notification WILL NOT be displayed.
			registry.dispatch( CORE_USER ).receiveTriggerSurvey( { survey_payload: { ab2: true }, session: {} }, { triggerID: 'storybook' } );
		}, 3 * 1000 );
	},
};

export const NotificationCTAWithSurveyLongerDelay = Template.bind( {} );
NotificationCTAWithSurveyLongerDelay.storyName = 'Has Notifications, with Survey in six seconds - Displayed';
NotificationCTAWithSurveyLongerDelay.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( CORE_SITE ).receiveGetNotifications( [ notification1 ], {} );
		setTimeout( () => {
			// Remote triggered survey arrives after the five second window, so the notification WILL be displayed.
			registry.dispatch( CORE_USER ).receiveTriggerSurvey( { survey_payload: { ab2: true }, session: {} }, { triggerID: 'storybook' } );
		}, 6 * 1000 );
	},
};

export default {
	title: 'Components/DashboardCoreSiteAlerts',
	decorators: [
		( Story ) => (

					<Story />

		),
		( Story, { args } ) => {
			const setupRegistry = ( registry ) => {
				// Call story-specific setup.
				args.setupRegistry( registry );
			};

			return (
				<WithRegistrySetup func={ setupRegistry }>
					<Story />
				</WithRegistrySetup>
			);
		},
	],
};
<|endoftext|>


<commit_before>import {Container, inject} from 'aurelia-dependency-injection';
import {TaskQueue} from 'aurelia-task-queue';
import {
  CompositionEngine, ViewSlot, ViewResources,
  customElement, bindable, noView, View
} from 'aurelia-templating';
import {DOM} from 'aurelia-pal';

/**
* Used to compose a new view / view-model template or bind to an existing instance.
*/
@customElement('compose')
@noView
@inject(DOM.Element, Container, CompositionEngine, ViewSlot, ViewResources, TaskQueue)
export class Compose {
  /**
  * Model to bind the custom element to.
  *
  * @property model
  * @type {CustomElement}
  */
  @bindable model
  /**
  * View to bind the custom element to.
  *
  * @property view
  * @type {HtmlElement}
  */
  @bindable view
  /**
  * View-model to bind the custom element's template to.
  *
  * @property viewModel
  * @type {Class}
  */
  @bindable viewModel

  /**
  * Creates an instance of Compose.
  * @param element The Compose element.
  * @param container The dependency injection container instance.
  * @param compositionEngine CompositionEngine instance to compose the element.
  * @param viewSlot The slot the view is injected in to.
  * @param viewResources Collection of resources used to compile the the view.
  * @param taskQueue The TaskQueue instance.
  */
  constructor(element, container, compositionEngine, viewSlot, viewResources, taskQueue) {
    this.element = element;
    this.container = container;
    this.compositionEngine = compositionEngine;
    this.viewSlot = viewSlot;
    this.viewResources = viewResources;
    this.taskQueue = taskQueue;
    this.currentController = null;
    this.currentViewModel = null;
  }

  /**
  * Invoked when the component has been created.
  *
  * @param owningView The view that this component was created inside of.
  */
  created(owningView: View) {
    this.owningView = owningView;
  }

  /**
  * Used to set the bindingContext.
  *
  * @param bindingContext The context in which the view model is executed in.
  * @param overrideContext The context in which the view model is executed in.
  */
  bind(bindingContext, overrideContext) {
    this.bindingContext = bindingContext;
    this.overrideContext = overrideContext;
    processInstruction(this, createInstruction(this, {
      view: this.view,
      viewModel: this.viewModel,
      model: this.model
    }));
  }

  /**
  * Unbinds the Compose.
  */
  unbind(bindingContext, overrideContext) {
    this.bindingContext = null;
    this.overrideContext = null;
    let returnToCache = true;
    let skipAnimation = true;
    this.viewSlot.removeAll(returnToCache, skipAnimation);
  }

  /**
  * Invoked everytime the bound model changes.
  * @param newValue The new value.
  * @param oldValue The old value.
  */
  modelChanged(newValue, oldValue) {
    if (this.currentInstruction) {
      this.currentInstruction.model = newValue;
      return;
    }

    this.taskQueue.queueMicroTask(() => {
      if (this.currentInstruction) {
        this.currentInstruction.model = newValue;
        return;
      }

      let vm = this.currentViewModel;

      if (vm && typeof vm.activate === 'function') {
        vm.activate(newValue);
      }
    });
  }

  /**
  * Invoked everytime the bound view changes.
  * @param newValue The new value.
  * @param oldValue The old value.
  */
  viewChanged(newValue, oldValue) {
    let instruction = createInstruction(this, {
      view: newValue,
      viewModel: this.currentViewModel || this.viewModel,
      model: this.model
    });

    if (this.currentInstruction) {
      this.currentInstruction = instruction;
      return;
    }

    this.currentInstruction = instruction;
    this.taskQueue.queueMicroTask(() => processInstruction(this, this.currentInstruction));
  }

  /**
    * Invoked everytime the bound view model changes.
    * @param newValue The new value.
    * @param oldValue The old value.
    */
  viewModelChanged(newValue, oldValue) {
    let instruction = createInstruction(this, {
      viewModel: newValue,
      view: this.view,
      model: this.model
    });

    if (this.currentInstruction) {
      this.currentInstruction = instruction;
      return;
    }

    this.currentInstruction = instruction;
    this.taskQueue.queueMicroTask(() => processInstruction(this, this.currentInstruction));
  }
}

function createInstruction(composer, instruction) {
  return Object.assign(instruction, {
    bindingContext: composer.bindingContext,
    overrideContext: composer.overrideContext,
    owningView: composer.owningView,
    container: composer.container,
    viewSlot: composer.viewSlot,
    viewResources: composer.viewResources,
    currentController: composer.currentController,
    host: composer.element
  });
}

function processInstruction(composer, instruction) {
  composer.currentInstruction = null;
  composer.compositionEngine.compose(instruction).then(controller => {
    composer.currentController = controller;
    composer.currentViewModel = controller ? controller.viewModel : null;
  });
}
<commit_msg>feat(swapOrder): add swaporder property for concurrent enter/leave transitions<commit_after>import {Container, inject} from 'aurelia-dependency-injection';
import {TaskQueue} from 'aurelia-task-queue';
import {
  CompositionEngine, ViewSlot, ViewResources,
  customElement, bindable, noView, View
} from 'aurelia-templating';
import {DOM} from 'aurelia-pal';

/**
* Used to compose a new view / view-model template or bind to an existing instance.
*/
@customElement('compose')
@noView
@inject(DOM.Element, Container, CompositionEngine, ViewSlot, ViewResources, TaskQueue)
export class Compose {
  /**
  * Model to bind the custom element to.
  *
  * @property model
  * @type {CustomElement}
  */
  @bindable model
  /**
  * View to bind the custom element to.
  *
  * @property view
  * @type {HtmlElement}
  */
  @bindable view
  /**
  * View-model to bind the custom element's template to.
  *
  * @property viewModel
  * @type {Class}
  */
  @bindable viewModel

  /**
   * SwapOrder to control the swaping order of the custom element's view.
   *
   * @property view
   * @type {String}
   */
  @bindable swapOrder;

  /**
  * Creates an instance of Compose.
  * @param element The Compose element.
  * @param container The dependency injection container instance.
  * @param compositionEngine CompositionEngine instance to compose the element.
  * @param viewSlot The slot the view is injected in to.
  * @param viewResources Collection of resources used to compile the the view.
  * @param taskQueue The TaskQueue instance.
  */
  constructor(element, container, compositionEngine, viewSlot, viewResources, taskQueue) {
    this.element = element;
    this.container = container;
    this.compositionEngine = compositionEngine;
    this.viewSlot = viewSlot;
    this.viewResources = viewResources;
    this.taskQueue = taskQueue;
    this.currentController = null;
    this.currentViewModel = null;
  }

  /**
  * Invoked when the component has been created.
  *
  * @param owningView The view that this component was created inside of.
  */
  created(owningView: View) {
    this.owningView = owningView;
  }

  /**
  * Used to set the bindingContext.
  *
  * @param bindingContext The context in which the view model is executed in.
  * @param overrideContext The context in which the view model is executed in.
  */
  bind(bindingContext, overrideContext) {
    this.bindingContext = bindingContext;
    this.overrideContext = overrideContext;
    processInstruction(this, createInstruction(this, {
      view: this.view,
      viewModel: this.viewModel,
      model: this.model
    }));
  }

  /**
  * Unbinds the Compose.
  */
  unbind(bindingContext, overrideContext) {
    this.bindingContext = null;
    this.overrideContext = null;
    let returnToCache = true;
    let skipAnimation = true;
    this.viewSlot.removeAll(returnToCache, skipAnimation);
  }

  /**
  * Invoked everytime the bound model changes.
  * @param newValue The new value.
  * @param oldValue The old value.
  */
  modelChanged(newValue, oldValue) {
    if (this.currentInstruction) {
      this.currentInstruction.model = newValue;
      return;
    }

    this.taskQueue.queueMicroTask(() => {
      if (this.currentInstruction) {
        this.currentInstruction.model = newValue;
        return;
      }

      let vm = this.currentViewModel;

      if (vm && typeof vm.activate === 'function') {
        vm.activate(newValue);
      }
    });
  }

  /**
  * Invoked everytime the bound view changes.
  * @param newValue The new value.
  * @param oldValue The old value.
  */
  viewChanged(newValue, oldValue) {
    let instruction = createInstruction(this, {
      view: newValue,
      viewModel: this.currentViewModel || this.viewModel,
      model: this.model
    });

    if (this.currentInstruction) {
      this.currentInstruction = instruction;
      return;
    }

    this.currentInstruction = instruction;
    this.taskQueue.queueMicroTask(() => processInstruction(this, this.currentInstruction));
  }

  /**
    * Invoked everytime the bound view model changes.
    * @param newValue The new value.
    * @param oldValue The old value.
    */
  viewModelChanged(newValue, oldValue) {
    let instruction = createInstruction(this, {
      viewModel: newValue,
      view: this.view,
      model: this.model
    });

    if (this.currentInstruction) {
      this.currentInstruction = instruction;
      return;
    }

    this.currentInstruction = instruction;
    this.taskQueue.queueMicroTask(() => processInstruction(this, this.currentInstruction));
  }
}

function createInstruction(composer, instruction) {
  return Object.assign(instruction, {
    bindingContext: composer.bindingContext,
    overrideContext: composer.overrideContext,
    owningView: composer.owningView,
    container: composer.container,
    viewSlot: composer.viewSlot,
    viewResources: composer.viewResources,
    currentController: composer.currentController,
    host: composer.element,
    swapOrder: composer.swapOrder
  });
}

function processInstruction(composer, instruction) {
  composer.currentInstruction = null;
  composer.compositionEngine.compose(instruction).then(controller => {
    composer.currentController = controller;
    composer.currentViewModel = controller ? controller.viewModel : null;
  });
}
<|endoftext|>


<commit_before>(function() {

  this.Player = function() {
    var defaults = {
        width: 600,
        height: 400,
        playerId: 'video-player',
        videoId: null,
    };

    if (arguments[0] && typeof arguments[0] === 'object') {
      this.options = extendDefaults(defaults, arguments[0]);
    }
  };

  Player.prototype.init = function() {

    var this_ = this;
    var callback = function() {

      this_.player = new YT.Player(this_.options.playerId, {
        videoId: this_.options.videoId,
        }
      });

    };

    // Test if the youtube api is loaded
    if ("YT" in window) {
      callback();
    } else {
      var tag = document.createElement('script');

      tag.src = "https://www.youtube.com/iframe_api";
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

      tag.onload = function() {
        YT.ready(callback);
      };
    }

  };
  Player.prototype._onReady = function() {
  };
  // Private Methods

  // Utility method to extend defaults with user options
  function extendDefaults( source, properties ) {
    var property;
    for ( property in properties ) {
      if ( properties.hasOwnProperty(property) ) {
        source[property] = properties[property];
      }
    }
    return source;
  }

})();<commit_msg>Added events<commit_after>(function() {

  this.Player = function() {
    var defaults = {
        width: 600,
        height: 400,
        playerId: 'video-player',
        videoId: null,
    };

    if (arguments[0] && typeof arguments[0] === 'object') {
      this.options = extendDefaults(defaults, arguments[0]);
    }
  };

  Player.prototype.init = function() {

    var this_ = this;
    var callback = function() {

      this_.player = new YT.Player(this_.options.playerId, {
        videoId: this_.options.videoId,
        events: {
        }
      });

    };

    // Test if the youtube api is loaded
    if ("YT" in window) {
      callback();
    } else {
      var tag = document.createElement('script');

      tag.src = "https://www.youtube.com/iframe_api";
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

      tag.onload = function() {
        YT.ready(callback);
      };
    }

  };
  Player.prototype._onReady = function() {
  };
  // Private Methods

  // Utility method to extend defaults with user options
  function extendDefaults( source, properties ) {
    var property;
    for ( property in properties ) {
      if ( properties.hasOwnProperty(property) ) {
        source[property] = properties[property];
      }
    }
    return source;
  }

})();<|endoftext|>


<commit_before>// generated from index.cfm/Fiddles/dbTypes?format=js on {ts '2012-07-11 00:37:10'}
$(function () {
	window.dbTypes.reset([{"id":3,"className":"net.sourceforge.jtds.jdbc.Driver","context":"host","sample_fragment":"","simple_name":"SQL Server","notes":"SQL Server supports multiple statements in a batch separated by semicolons. Separate statement batches with a line consisting of a single GO command, as needed.","full_name":"MS SQL Server 2008 R2"},{"id":2,"className":"org.gjt.mm.mysql.Driver","context":"host","sample_fragment":"","simple_name":"MySQL","notes":"Separate multiple statements in MySQL by terminating each one with a semicolon.","full_name":"MySQL 5.5.20"},{"id":4,"className":"oracle.jdbc.OracleDriver","context":"host","sample_fragment":"","simple_name":"Oracle","notes":"Oracle does not support multiple statements in batch.  Separate each statement with a line consisting of a single \/, and do not terminate statements with semicolons.","full_name":"Oracle 11g R2"},{"id":1,"className":"org.postgresql.Driver","context":"host","sample_fragment":"1\/c55ab\/1","simple_name":"PostgreSQL","notes":"Separate multiple statements in PostgreSQL by terminating each one with a semicolon.","full_name":"PostgreSQL 9.1.2"},{"id":6,"className":"sqljs","context":"browser","sample_fragment":"6\/59124\/4","simple_name":"SQLite","notes":"","full_name":"SQLite (SQL.js)"},{"id":7,"className":"websql","context":"browser","sample_fragment":"7\/8b248\/2","simple_name":"SQLite","notes":"","full_name":"SQLite (WebSQL)"}]);
});

<commit_msg>Untracking the cached js file<commit_after>// generated from index.cfm/Fiddles/dbTypes?format=js on {ts '2012-07-11 00:40:49'}
$(function () {
	window.dbTypes.reset([{"id":3,"className":"net.sourceforge.jtds.jdbc.Driver","context":"host","sample_fragment":"","simple_name":"SQL Server","notes":"SQL Server supports multiple statements in a batch separated by semicolons. Separate statement batches with a line consisting of a single GO command, as needed.","full_name":"MS SQL Server 2008 R2"},{"id":2,"className":"org.gjt.mm.mysql.Driver","context":"host","sample_fragment":"","simple_name":"MySQL","notes":"Separate multiple statements in MySQL by terminating each one with a semicolon.","full_name":"MySQL 5.5.20"},{"id":4,"className":"oracle.jdbc.OracleDriver","context":"host","sample_fragment":"","simple_name":"Oracle","notes":"Oracle does not support multiple statements in batch.  Separate each statement with a line consisting of a single \/, and do not terminate statements with semicolons.","full_name":"Oracle 11g R2"},{"id":1,"className":"org.postgresql.Driver","context":"host","sample_fragment":"1\/c55ab\/1","simple_name":"PostgreSQL","notes":"Separate multiple statements in PostgreSQL by terminating each one with a semicolon.","full_name":"PostgreSQL 9.1.2"},{"id":6,"className":"sqljs","context":"browser","sample_fragment":"6\/59124\/4","simple_name":"SQLite","notes":"","full_name":"SQLite (SQL.js)"},{"id":7,"className":"websql","context":"browser","sample_fragment":"7\/8b248\/2","simple_name":"SQLite","notes":"","full_name":"SQLite (WebSQL)"}]);
});

<|endoftext|>


<commit_before>// Copyright 2018, University of Colorado Boulder

/**
 * Displays the axis of symmetry for a quadratic.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( require => {
  'use strict';

  // modules
  const GQColors = require( 'GRAPHING_QUADRATICS/common/GQColors' );
  const GQConstants = require( 'GRAPHING_QUADRATICS/common/GQConstants' );
  const GQEquationFactory = require( 'GRAPHING_QUADRATICS/common/view/GQEquationFactory' );
  const graphingQuadratics = require( 'GRAPHING_QUADRATICS/graphingQuadratics' );
  const Line = require( 'SCENERY/nodes/Line' );
  const Node = require( 'SCENERY/nodes/Node' );
  const Property = require( 'AXON/Property' );

  class AxisOfSymmetryNode extends Node {

    /**
     * @param {Property.<Quadratic>} quadraticProperty - the interactive quadratic
     * @param {Range} yRange - range of the graph's y axis
     * @param {ModelViewTransform2} modelViewTransform
     * @param {BooleanProperty} axisOfSymmetryVisibleProperty
     * @param {BooleanProperty} equationsVisibleProperty
     */
    constructor( quadraticProperty, yRange, modelViewTransform,
                 axisOfSymmetryVisibleProperty, equationsVisibleProperty ) {

      super();

      // the line
      const lineNode = new Line( 0, 0, 0, 1, {
        stroke: GQColors.AXIS_OF_SYMMETRY,
        lineWidth: GQConstants.AXIS_OF_SYMMETRY_LINE_WIDTH,
        lineDash: GQConstants.AXIS_OF_SYMMETRY_LINE_DASH
      } );
      this.addChild( lineNode );

      // equation on the line, created below
      let equationNode = null;

      const minY = modelViewTransform.modelToViewY( yRange.max );
      const maxY = modelViewTransform.modelToViewY( yRange.min );

      quadraticProperty.link( quadratic => {

        if ( quadratic.axisOfSymmetry !== undefined ) {
          assert && assert( quadratic.vertex, 'expected vertex: ' + quadratic.vertex );

          // update the line
          const x = modelViewTransform.modelToViewX( quadratic.axisOfSymmetry );
          lineNode.setLine( x, minY, x, maxY );

          // update the equation
          equationNode && this.removeChild( equationNode );
          equationNode = GQEquationFactory.createAxisOfSymmetry( quadratic.axisOfSymmetry );
          equationNode.maxHeight = 100; // maxHeight because equation is rotated, determined empirically
          this.addChild( equationNode );

          // position the equation to avoid overlapping vertex and y axis
          if ( quadratic.axisOfSymmetry > yRange.max - GQConstants.EQUATION_Y_MARGIN ) {

            // axis is at far right of graph, so put equation on left of axis
            equationNode.right = lineNode.left - GQConstants.EQUATION_SPACING;
          }
          else if ( quadratic.axisOfSymmetry < yRange.min + GQConstants.EQUATION_Y_MARGIN ) {

            // axis is at far left of graph, so put equation on right of axis
            equationNode.left = lineNode.right + GQConstants.EQUATION_SPACING;
          }
          else if ( quadratic.axisOfSymmetry >= 0 ) {

            // axis is at or to right of origin, so put equation on left of axis
            equationNode.left = lineNode.right + GQConstants.EQUATION_SPACING;
          }
          else {

            // axis is to left of origin, os put equation on right of axis
            equationNode.right = lineNode.left - GQConstants.EQUATION_SPACING;
          }

          // space between the equation and axis
          if ( quadratic.vertex.y >= 0 ) {
            equationNode.bottom = modelViewTransform.modelToViewY( yRange.min + 1 );
          }
          else {
            equationNode.top = modelViewTransform.modelToViewY( yRange.max - 1 );
          }
        }
      } );

      Property.multilink( [ axisOfSymmetryVisibleProperty, quadraticProperty ],
        ( axisOfSymmetryVisible, quadratic ) => {
          this.visible = !!( axisOfSymmetryVisible &&
                             quadratic.axisOfSymmetry !== undefined &&
                             yRange.contains( quadratic.axisOfSymmetry ) );
        } );

      equationsVisibleProperty.link( visible => { equationNode.visible = visible; } );
    }
  }

  return graphingQuadratics.register( 'AxisOfSymmetryNode', AxisOfSymmetryNode );
} );<commit_msg>doc<commit_after>// Copyright 2018, University of Colorado Boulder

/**
 * Displays the axis of symmetry for a quadratic.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( require => {
  'use strict';

  // modules
  const GQColors = require( 'GRAPHING_QUADRATICS/common/GQColors' );
  const GQConstants = require( 'GRAPHING_QUADRATICS/common/GQConstants' );
  const GQEquationFactory = require( 'GRAPHING_QUADRATICS/common/view/GQEquationFactory' );
  const graphingQuadratics = require( 'GRAPHING_QUADRATICS/graphingQuadratics' );
  const Line = require( 'SCENERY/nodes/Line' );
  const Node = require( 'SCENERY/nodes/Node' );
  const Property = require( 'AXON/Property' );

  class AxisOfSymmetryNode extends Node {

    /**
     * @param {Property.<Quadratic>} quadraticProperty - the interactive quadratic
     * @param {Range} yRange - range of the graph's y axis
     * @param {ModelViewTransform2} modelViewTransform
     * @param {BooleanProperty} axisOfSymmetryVisibleProperty
     * @param {BooleanProperty} equationsVisibleProperty
     */
    constructor( quadraticProperty, yRange, modelViewTransform,
                 axisOfSymmetryVisibleProperty, equationsVisibleProperty ) {

      super();

      // the line
      const lineNode = new Line( 0, 0, 0, 1, {
        stroke: GQColors.AXIS_OF_SYMMETRY,
        lineWidth: GQConstants.AXIS_OF_SYMMETRY_LINE_WIDTH,
        lineDash: GQConstants.AXIS_OF_SYMMETRY_LINE_DASH
      } );
      this.addChild( lineNode );

      // equation on the line, created below
      let equationNode = null;

      // to improve readability
      const minY = modelViewTransform.modelToViewY( yRange.max );
      const maxY = modelViewTransform.modelToViewY( yRange.min );

      quadraticProperty.link( quadratic => {

        if ( quadratic.axisOfSymmetry !== undefined ) {
          assert && assert( quadratic.vertex, 'expected vertex: ' + quadratic.vertex );

          // update the line
          const x = modelViewTransform.modelToViewX( quadratic.axisOfSymmetry );
          lineNode.setLine( x, minY, x, maxY );

          // update the equation
          equationNode && this.removeChild( equationNode );
          equationNode = GQEquationFactory.createAxisOfSymmetry( quadratic.axisOfSymmetry );
          equationNode.maxHeight = 100; // maxHeight because equation is rotated, determined empirically
          this.addChild( equationNode );

          // position the equation to avoid overlapping vertex and y axis
          if ( quadratic.axisOfSymmetry > yRange.max - GQConstants.EQUATION_Y_MARGIN ) {

            // axis is at far right of graph, so put equation on left of axis
            equationNode.right = lineNode.left - GQConstants.EQUATION_SPACING;
          }
          else if ( quadratic.axisOfSymmetry < yRange.min + GQConstants.EQUATION_Y_MARGIN ) {

            // axis is at far left of graph, so put equation on right of axis
            equationNode.left = lineNode.right + GQConstants.EQUATION_SPACING;
          }
          else if ( quadratic.axisOfSymmetry >= 0 ) {

            // axis is at or to right of origin, so put equation on left of axis
            equationNode.left = lineNode.right + GQConstants.EQUATION_SPACING;
          }
          else {

            // axis is to left of origin, os put equation on right of axis
            equationNode.right = lineNode.left - GQConstants.EQUATION_SPACING;
          }

          // space between the equation and axis
          if ( quadratic.vertex.y >= 0 ) {
            equationNode.bottom = modelViewTransform.modelToViewY( yRange.min + 1 );
          }
          else {
            equationNode.top = modelViewTransform.modelToViewY( yRange.max - 1 );
          }
        }
      } );

      Property.multilink( [ axisOfSymmetryVisibleProperty, quadraticProperty ],
        ( axisOfSymmetryVisible, quadratic ) => {
          this.visible = !!( axisOfSymmetryVisible &&
                             quadratic.axisOfSymmetry !== undefined &&
                             yRange.contains( quadratic.axisOfSymmetry ) );
        } );

      equationsVisibleProperty.link( visible => { equationNode.visible = visible; } );
    }
  }

  return graphingQuadratics.register( 'AxisOfSymmetryNode', AxisOfSymmetryNode );
} );<|endoftext|>


<commit_before>App.QuestionPreviewComponent = Ember.Component.extend({
  answersCount: function() {
    return this.get('question.answers.length');
  }.property('question.answers.length')
});<commit_msg>Chapter 11: Shorthand expression for bound properties<commit_after>App.QuestionPreviewComponent = Ember.Component.extend({
  answersCount: Ember.computed.alias('question.answers.length')
});<|endoftext|>


<commit_before>module.exports = {
    add: {
        dependencies: ['number'],
        code: 'function $add(a, b) { return $number(a) + $number(b); }'
    },
    array: {
        dependencies: ['slice'],
        code: [
            'function $array() { ',
            '   return Object.freeze($slice(arguments, 0));',
            '}'
        ].join("\n")
    },
    bool: {
        dependencies: [],
        code: [
            'function $bool(x) {',
            '    if (typeof x !== "boolean") {',
            '        throw new Error("not a boolean: " + x);',
            '    }',
            '    return x;',
            '}'
        ].join("\n")
    },
    concat: {
        dependencies: [],
        code: [
            'function $concat(a, b) {' +
            '    if (Array.isArray(a) && Array.isArray(b)) {' +
            '        return a.concat(b);' +
            '    }' +
            '    throw new Error("incorrect argument types for ++");' +
            '}'
        ].join("\n")
    },
    strcat: {
        dependencies: ['isObject'],
        code: [
            'function $strcat(a, b) {' +
            '    if ($isObject(a) || $isObject(b)) {' +
            '        throw new Error("incorrect argument types for ..");' +
            '    }' +
            '    return "" + a + b;' +
            '}'
        ].join("\n")
    },
    divide: {
        dependencies: ['number'],
        code: 'function $divide(a, b) { return $number(a) / $number(b); }'
    },
    eq: {
        dependencies: ['isObject'],
        code: [
            'function $eq(a, b) {',
            '    if (a === b) {',
            '        return true;',
            '    } else if (Array.isArray(a) && Array.isArray(b)) {',
            '        var n = a.length;',
            '        var m = b.length;',
            '        if (n !== m) {',
            '            return false;',
            '        } else {',
            '            for (var i = 0; i < n; i++) {',
            '                if (!$eq(a[i], b[i])) {',
            '                    return false;',
            '                }',
            '            }',
            '            return true;',
            '        }',
            '    } else if ($isObject(a) && $isObject(b)) {',
            '        // TODO: Remove duplicates.',
            '        var ks = Object.keys(a).concat(Object.keys(b)).sort();',
            '        return ks.every(function(k) {',
            '            return k in a && k in b && $eq(a[k], b[k]);',
            '        });',
            '    } else {',
            '        return false;',
            '    }',
            '}'
        ].join("\n")
    },
    get: {
        dependencies: ['has'],
        code: [
            'function $get(obj, key) {',
            '    if ($has(obj, key)) { return obj[key]; }',
            '    throw new Error(obj + " does not have key " + key);',
            '}'
        ].join("\n")
    },
    global: {
        dependencies: [],
        code: 'var $global = (1, eval)("this");'
    },
    gt: {
        // TODO: Make it work on strings too
        dependencies: ['number'],
        code: 'function $gt(a, b) { return $number(a) > $number(b); }'
    },
    gte: {
        dependencies: ['gt', 'eq'],
        code: 'function $gte(a, b) { return $gt(a, b) || $eq(a, b); }'
    },
    has: {
        dependencies: [],
        code: [
            'function $has(obj, key) {',
            '    if (obj === null || obj === undefined) {',
            '        throw new Error(obj + " cannot have keys");',
            '    }',
            '    if (typeof key === "string" ||',
            '        typeof key === "number" && key % 1 === 0) {',
            '        return obj[key] !== undefined;',
            '    }',
            '    throw new Error("Key must be a string or integer" +',
            '                    ", got " + typeof key);',
            '}'
        ].join("\n")
    },
    is: {
        dependencies: [],
        code: [
            'function $is(x, y) {',
            '    if (x === y) {',
            '        return x !== 0 || 1 / x === 1 / y;',
            '    } else {',
            '        return x !== x && y !== y;',
            '    }',
            '}'
        ].join("\n")
    },
    isObject: {
        dependencies: [],
        code: 'function $isObject(x) { return x && typeof x === "object"; }'
    },
    lt: {
        // TODO: Make it work on strings too
        dependencies: ['number'],
        code: 'function $lt(a, b) { return $number(a) < $number(b); }'
    },
    lte: {
        dependencies: ['lt', 'eq'],
        code: 'function $lte(a, b) { return $lt(a, b) || $eq(a, b); }'
    },
    method: {
        dependencies: [],
        code: 'function $method(obj, method) { return obj[method].bind(obj); }'
    },
    multiply: {
        dependencies: ['number'],
        code: 'function $multiply(a, b) { return $number(a) * $number(b); }'
    },
    negate: {
        dependencies: ['number'],
        code: 'function $negate(x) { return -$number(x); }'
    },
    neq: {
        dependencies: ['eq'],
        code: 'function $neq(a, b) { return !$eq(a, b); }'
    },
    not: {
        dependencies: ['bool'],
        code: 'function $not(x) { return !$bool(x); }'
    },
    number: {
        dependencies: [],
        code: [
            'function $number(x) {',
            '    if (typeof x !== "number") {',
            '        throw new Error("not a number: " + x);',
            '    }',
            '    return x;',
            '}'
        ].join("\n")
    },
    object: {
        dependencies: [],
        code: [
'function $object() {',
'    if (arguments.length % 2 !== 0) {',
'        throw new Error("objects must have an even number of items");',
'    }',
'    var obj = {};',
'    var i = 0;',
'    var n = arguments.length - 1;',
'    while (i < n) {',
'        if (typeof arguments[i] !== "string") {',
'            throw new Error("object keys must be strings: " + arguments[i]);',
'        }',
'        obj[arguments[i]] = arguments[i + 1];',
'        i += 2;',
'    }',
'    return Object.freeze(obj);',
'}'
].join("\n")
    },
    ref: {
        dependencies: ['undef'],
        code:
            'function $ref(x, name) {' +
            '    if (x === $undef) {' +
            '        throw new ReferenceError(' +
            'name + " used before initialization");' +
            '    }' +
            '    return x;' +
            '}'
    },
    set: {
        dependencies: [],
        code:
// TODO: Expose this in the language.
'function $set(obj, k, v) {' +
'    if (obj === null || typeof obj !== "object") {' +
'        throw new Error("cannot set " + k + " on " + obj);' +
'    }' +
'    if (Object.isFrozen(obj)) {' +
'        throw new Error("cannot set " + k + " on frozen object");' +
'    }' +
'    obj[k] = v;' +
'    return obj;' +
'}'
    },
    slice: {
        dependencies: [],
        code: 'function $slice(xs, i) { ' +
            'return Object.freeze(Array.prototype.slice.call(xs, i)); }'
    },
    subtract: {
        dependencies: ['number'],
        code: 'function $subtract(a, b) { return $number(a) - $number(b); }'
    },
    type: {
        dependencies: [],
        code:
            // TODO: Expose this in the language.
            'function $type(x) {' +
            '    if (x === null) {' +
            '        return "null"' +
            '    }' +
            '    if (Array.isArray(x)) {' +
            '        return "array";' +
            '    }' +
            '    return typeof x;' +
            '}'
    },
    undef: {
        dependencies: [],
        code: 'var $undef = {_: "SQUIGGLE_TEMPORAL_DEADZONE_VALUE"};'
    },
    update: {
        dependencies: [],
        code:
            'function $update(a, b) {' +
            '    var c = Object.create(Object.getPrototypeOf(a));' +
            '    Object.keys(a).forEach(function(k) { c[k] = a[k]; });' +
            '    Object.keys(b).forEach(function(k) { c[k] = b[k]; });' +
            '    return Object.freeze(c);' +
            '}'
    }
};
<commit_msg>Fixes #124 makes == throw on non-value types<commit_after>module.exports = {
    add: {
        dependencies: ['number'],
        code: 'function $add(a, b) { return $number(a) + $number(b); }'
    },
    array: {
        dependencies: ['slice'],
        code: [
            'function $array() { ',
            '   return Object.freeze($slice(arguments, 0));',
            '}'
        ].join("\n")
    },
    bool: {
        dependencies: [],
        code: [
            'function $bool(x) {',
            '    if (typeof x !== "boolean") {',
            '        throw new Error("not a boolean: " + x);',
            '    }',
            '    return x;',
            '}'
        ].join("\n")
    },
    concat: {
        dependencies: [],
        code: [
            'function $concat(a, b) {' +
            '    if (Array.isArray(a) && Array.isArray(b)) {' +
            '        return a.concat(b);' +
            '    }' +
            '    throw new Error("incorrect argument types for ++");' +
            '}'
        ].join("\n")
    },
    strcat: {
        dependencies: ['isObject'],
        code: [
            'function $strcat(a, b) {' +
            '    if ($isObject(a) || $isObject(b)) {' +
            '        throw new Error("incorrect argument types for ..");' +
            '    }' +
            '    return "" + a + b;' +
            '}'
        ].join("\n")
    },
    divide: {
        dependencies: ['number'],
        code: 'function $divide(a, b) { return $number(a) / $number(b); }'
    },
    eq: {
        dependencies: ['isValueType'],
        code: [
            'function $eq(a, b) {',
            '    if ($isValueType(a) && $isValueType(b)) {',
            '        return a === b;',
            '    } else {',
            '        throw new Error(' +
            '"cannot check equality of ' +
            'reference types, use operator \'is\' instead");',
            '    }',
            '}'
        ].join("\n")
    },
    isValueType: {
        dependencies: [],
        code: [
            'function $isValueType(a) {',
            '   return ' +
            'a === undefined || ' +
            'a === null || ' +
            'typeof a === "boolean" || ' +
            'typeof a === "string" || ' +
            'typeof a === "number";',
            '}'
        ].join("\n")
    },
    get: {
        dependencies: ['has'],
        code: [
            'function $get(obj, key) {',
            '    if ($has(obj, key)) { return obj[key]; }',
            '    throw new Error(obj + " does not have key " + key);',
            '}'
        ].join("\n")
    },
    global: {
        dependencies: [],
        code: 'var $global = (1, eval)("this");'
    },
    gt: {
        // TODO: Make it work on strings too
        dependencies: ['number'],
        code: 'function $gt(a, b) { return $number(a) > $number(b); }'
    },
    gte: {
        dependencies: ['gt', 'eq'],
        code: 'function $gte(a, b) { return $gt(a, b) || $eq(a, b); }'
    },
    has: {
        dependencies: [],
        code: [
            'function $has(obj, key) {',
            '    if (obj === null || obj === undefined) {',
            '        throw new Error(obj + " cannot have keys");',
            '    }',
            '    if (typeof key === "string" ||',
            '        typeof key === "number" && key % 1 === 0) {',
            '        return obj[key] !== undefined;',
            '    }',
            '    throw new Error("Key must be a string or integer" +',
            '                    ", got " + typeof key);',
            '}'
        ].join("\n")
    },
    is: {
        dependencies: [],
        code: [
            'function $is(x, y) {',
            '    if (x === y) {',
            '        return x !== 0 || 1 / x === 1 / y;',
            '    } else {',
            '        return x !== x && y !== y;',
            '    }',
            '}'
        ].join("\n")
    },
    isObject: {
        dependencies: [],
        code: 'function $isObject(x) { return x && typeof x === "object"; }'
    },
    lt: {
        // TODO: Make it work on strings too
        dependencies: ['number'],
        code: 'function $lt(a, b) { return $number(a) < $number(b); }'
    },
    lte: {
        dependencies: ['lt', 'eq'],
        code: 'function $lte(a, b) { return $lt(a, b) || $eq(a, b); }'
    },
    method: {
        dependencies: [],
        code: 'function $method(obj, method) { return obj[method].bind(obj); }'
    },
    multiply: {
        dependencies: ['number'],
        code: 'function $multiply(a, b) { return $number(a) * $number(b); }'
    },
    negate: {
        dependencies: ['number'],
        code: 'function $negate(x) { return -$number(x); }'
    },
    neq: {
        dependencies: ['eq'],
        code: 'function $neq(a, b) { return !$eq(a, b); }'
    },
    not: {
        dependencies: ['bool'],
        code: 'function $not(x) { return !$bool(x); }'
    },
    number: {
        dependencies: [],
        code: [
            'function $number(x) {',
            '    if (typeof x !== "number") {',
            '        throw new Error("not a number: " + x);',
            '    }',
            '    return x;',
            '}'
        ].join("\n")
    },
    object: {
        dependencies: [],
        code: [
'function $object() {',
'    if (arguments.length % 2 !== 0) {',
'        throw new Error("objects must have an even number of items");',
'    }',
'    var obj = {};',
'    var i = 0;',
'    var n = arguments.length - 1;',
'    while (i < n) {',
'        if (typeof arguments[i] !== "string") {',
'            throw new Error("object keys must be strings: " + arguments[i]);',
'        }',
'        obj[arguments[i]] = arguments[i + 1];',
'        i += 2;',
'    }',
'    return Object.freeze(obj);',
'}'
].join("\n")
    },
    ref: {
        dependencies: ['undef'],
        code:
            'function $ref(x, name) {' +
            '    if (x === $undef) {' +
            '        throw new ReferenceError(' +
            'name + " used before initialization");' +
            '    }' +
            '    return x;' +
            '}'
    },
    set: {
        dependencies: [],
        code:
// TODO: Expose this in the language.
'function $set(obj, k, v) {' +
'    if (obj === null || typeof obj !== "object") {' +
'        throw new Error("cannot set " + k + " on " + obj);' +
'    }' +
'    if (Object.isFrozen(obj)) {' +
'        throw new Error("cannot set " + k + " on frozen object");' +
'    }' +
'    obj[k] = v;' +
'    return obj;' +
'}'
    },
    slice: {
        dependencies: [],
        code: 'function $slice(xs, i) { ' +
            'return Object.freeze(Array.prototype.slice.call(xs, i)); }'
    },
    subtract: {
        dependencies: ['number'],
        code: 'function $subtract(a, b) { return $number(a) - $number(b); }'
    },
    type: {
        dependencies: [],
        code:
            // TODO: Expose this in the language.
            'function $type(x) {' +
            '    if (x === null) {' +
            '        return "null"' +
            '    }' +
            '    if (Array.isArray(x)) {' +
            '        return "array";' +
            '    }' +
            '    return typeof x;' +
            '}'
    },
    undef: {
        dependencies: [],
        code: 'var $undef = {_: "SQUIGGLE_TEMPORAL_DEADZONE_VALUE"};'
    },
    update: {
        dependencies: [],
        code:
            'function $update(a, b) {' +
            '    var c = Object.create(Object.getPrototypeOf(a));' +
            '    Object.keys(a).forEach(function(k) { c[k] = a[k]; });' +
            '    Object.keys(b).forEach(function(k) { c[k] = b[k]; });' +
            '    return Object.freeze(c);' +
            '}'
    }
};
<|endoftext|>


<commit_before>/**
 * Dependencies
 */
var Http = require('http');

/**
 * Connect
 */
var Connect = function Contructor(conf) {
	this.host = conf.host || 'localhost';
	this.port = conf.port || 4200;
	this.user = conf.user || null;
	this.pass = conf.pass || null;

	//TODO test connection method
}

/**
 * Send a query POST
 */
Connect.prototype.send = function POST(query, statements, callback) {
	//I really hope this query is sanatized!
	var request = Http.request({
		method: 'POST',
		host:   this.host,
		port:   this.port,
		path:   '/_sql'
	});

	var data = {
		stmt: query
	}

	if(statements.length > 0) {
		data.args = statements;
	}

	request.write( JSON.stringify(data) );
	request.end();

	if(typeof callback === 'function') {
		request.on('response', function(res) {
			var buf = '';

			res.on('data', function(data) {
				buf += data;
			});

			res.on('end', function() {
				callback(JSON.parse(buf));
			});
		});
	}
}

/**
 * Exports
 */
module.exports = Connect;
<commit_msg>prototype of load balancing, this is not the final design!<commit_after>/**
 * Dependencies
 */
var Http = require('http');

/**
 * Connect
 */
var Connect = function Contructor(conf) {
	this.host = conf.host || 'localhost';
	this.port = conf.port || 4200;
	this.user = conf.user || null;
	this.pass = conf.pass || null;

    if(this.cluster && this.cluster.length > 0) { //They sent an array with the host/port of each cluster
        this.load_balance = 'rr'; //Round-Robin
        this.rr_count = 0;
        this.lb_get = function() {
            if(this.rr_count >= this.cluster.length) {
                this.rr_count = 0;
            }

            return this.cluster[ this.rr_count++ ];
        }
    }

	//TODO test connection method
}

/**
 * Send a query POST
 */
Connect.prototype.send = function POST(query, statements, callback) {
    var options = {
		method: 'POST',
		path:   '/_sql'
        //No need to specify Keep-Alive, node will use the default global agent
    }

    if(this.load_balance === 'rr') {
        var node = this.lb_get();

        this.host = node.host || 'localhost';
        this.port = node.port || 4200;
    }

	var request = Http.request(options);

    //I really hope this query is sanatized!
	var data = {
		stmt: query
	}

	if(statements.length > 0) {
		data.args = statements;
	}

	request.write( JSON.stringify(data) );
	request.end();

	if(typeof callback === 'function') {
		request.on('response', function(res) {
			var buf = '';

			res.on('data', function(data) {
				buf += data;
			});

			res.on('end', function() {
				callback(JSON.parse(buf));
			});
		});
	}
}

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