<commit_before>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple Inc. All rights reserved.
// License:   Licened under MIT license (see license.js)
// ==========================================================================

SC.json = {

  /**
    Encodes an object graph to a JSON output.  Beware that JSON cannot deal
    with circular references.  If you try to encode an object graph with
    references it could hang your browser.

    @param {Object} root object graph
    @returns {String} encode JSON
  */
  encode: function(root) {
    return JSON.stringify(root) ;
  },

  /**
    Decodes a JSON file in a safe way, returning the generated object graph.

    @param {String} encoded JSON
    @returns {Object} object graph or Error if there was a problem.
  */
  decode: function(root) {
    return JSON.parse(root) ;
  }

} ;

/*
    http://www.JSON.org/json2.js
    2008-11-19

    Public Domain.

    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

    See http://www.JSON.org/js.html

    This file creates a global JSON object containing two methods: stringify
    and parse.

        JSON.stringify(value, replacer, space)
            value       any JavaScript value, usually an object or array.

            replacer    an optional parameter that determines how object
                        values are stringified for objects. It can be a
                        function or an array of strings.

            space       an optional parameter that specifies the indentation
                        of nested structures. If it is omitted, the text will
                        be packed without extra whitespace. If it is a number,
                        it will specify the number of spaces to indent at each
                        level. If it is a string (such as '\t' or ' '),
                        it contains the characters used to indent at each level.

            This method produces a JSON text from a JavaScript value.

            When an object value is found, if the object contains a toJSON
            method, its toJSON method will be called and the result will be
            stringified. A toJSON method does not serialize: it returns the
            value represented by the name/value pair that should be serialized,
            or undefined if nothing should be serialized. The toJSON method
            will be passed the key associated with the value, and this will be
            bound to the object holding the key.

            For example, this would serialize Dates as ISO strings.

                Date.prototype.toJSON = function (key) {
                    function f(n) {
                        // Format integers to have at least two digits.
                        return n < 10 ? '0' + n : n;
                    }

                    return this.getUTCFullYear()   + '-' +
                         f(this.getUTCMonth() + 1) + '-' +
                         f(this.getUTCDate())      + 'T' +
                         f(this.getUTCHours())     + ':' +
                         f(this.getUTCMinutes())   + ':' +
                         f(this.getUTCSeconds())   + 'Z';
                };

            You can provide an optional replacer method. It will be passed the
            key and value of each member, with this bound to the containing
            object. The value that is returned from your method will be
            serialized. If your method returns undefined, then the member will
            be excluded from the serialization.

            If the replacer parameter is an array of strings, then it will be
            used to select the members to be serialized. It filters the results
            such that only members with keys listed in the replacer array are
            stringified.

            Values that do not have JSON representations, such as undefined or
            functions, will not be serialized. Such values in objects will be
            dropped; in arrays they will be replaced with null. You can use
            a replacer function to replace those with JSON values.
            JSON.stringify(undefined) returns undefined.

            The optional space parameter produces a stringification of the
            value that is filled with line breaks and indentation to make it
            easier to read.

            If the space parameter is a non-empty string, then that string will
            be used for indentation. If the space parameter is a number, then
            the indentation will be that many spaces.

            Example:

            text = JSON.stringify(['e', {pluribus: 'unum'}]);
            // text is '["e",{"pluribus":"unum"}]'

            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'

            text = JSON.stringify([new Date()], function (key, value) {
                return this[key] instanceof Date ?
                    'Date(' + this[key] + ')' : value;
            });
            // text is '["Date(---current time---)"]'

        JSON.parse(text, reviver)
            This method parses a JSON text to produce an object or array.
            It can throw a SyntaxError exception.

            The optional reviver parameter is a function that can filter and
            transform the results. It receives each of the keys and values,
            and its return value is used instead of the original value.
            If it returns what it received, then the structure is not modified.
            If it returns undefined then the member is deleted.

            Example:

            // Parse the text. Values that look like ISO date strings will
            // be converted to Date objects.

            myData = JSON.parse(text, function (key, value) {
                var a;
                if (typeof value === 'string') {
                    a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                    if (a) {
                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                            +a[5], +a[6]));
                    }
                }
                return value;
            });

            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
                var d;
                if (typeof value === 'string' &&
                        value.slice(0, 5) === 'Date(' &&
                        value.slice(-1) === ')') {
                    d = new Date(value.slice(5, -1));
                    if (d) {
                        return d;
                    }
                }
                return value;
            });

    This is a reference implementation. You are free to copy, modify, or
    redistribute.

    This code should be minified before deployment.
    See http://javascript.crockford.com/jsmin.html

    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.
*/

/*jslint evil: true */

/*global JSON */

/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
    lastIndex, length, parse, prototype, push, replace, slice, stringify,
    test, toJSON, toString, valueOf
*/

// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.

if (!this.JSON) {
    JSON = {};
}
(function () {

    function f(n) {
        // Format integers to have at least two digits.
        return n < 10 ? '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {

        Date.prototype.toJSON = function (key) {

            return this.getUTCFullYear()   + '-' +
                 f(this.getUTCMonth() + 1) + '-' +
                 f(this.getUTCDate())      + 'T' +
                 f(this.getUTCHours())     + ':' +
                 f(this.getUTCMinutes())   + ':' +
                 f(this.getUTCSeconds())   + 'Z';
        };

        String.prototype.toJSON =
        Number.prototype.toJSON =
        Boolean.prototype.toJSON = function (key) {
            return this.valueOf();
        };
    }

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        gap,
        indent,
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        rep;

    function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.

        escapable.lastIndex = 0;
        return escapable.test(string) ?
            '"' + string.replace(escapable, function (a) {
                var c = meta[a];
                return typeof c === 'string' ? c :
                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
            }) + '"' :
            '"' + string + '"';
    }

    function str(key, holder) {

// Produce a string from holder[key].

        var i,          // The loop counter.
            k,          // The member key.
            v,          // The member value.
            length,
            mind = gap,
            partial,
            value = holder[key];

// If the value has a toJSON method, call it to obtain a replacement value.

				/* FIXME: Prototype.js is creating an object.toJSON function which is not
					is not playing well with json2.js. Arrays are not being JSON.stringify
					correctly. Someone may want to check that this is correct.
				*/
        if (value && typeof value === 'object' &&
                typeof value.toJSON === 'function' &&
								Object.prototype.toString.apply(value) !== '[object Array]') {
            value = value.toJSON(key);
        }

// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.

        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }

// What happens next depends on the value's type.

        switch (typeof value) {
        case 'string':
            return quote(value);

        case 'number':

// JSON numbers must be finite. Encode non-finite numbers as null.

            return isFinite(value) ? String(value) : 'null';

        case 'boolean':
        case 'null':

// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.

            return String(value);

// If the type is 'object', we might be dealing with an object or an array or
// null.

        case 'object':

// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.

            if (!value) {
                return 'null';
            }

// Make an array to hold the partial results of stringifying this object value.

            gap += indent;
            partial = [];

// Is the value an array?

            if (Object.prototype.toString.apply(value) === '[object Array]') {

// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.

                length = value.length;
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value) || 'null';
                }

// Join all of the elements together, separated with commas, and wrap them in
// brackets.

                v = partial.length === 0 ? '[]' :
                    gap ? '[\n' + gap +
                            partial.join(',\n' + gap) + '\n' +
                                mind + ']' :
                          '[' + partial.join(',') + ']';
                gap = mind;
								return v;
            }

// If the replacer is an array, use it to select the members to be stringified.

            if (rep && typeof rep === 'object') {
                length = rep.length;
                for (i = 0; i < length; i += 1) {
                    k = rep[i];
                    if (typeof k === 'string') {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            } else {

// Otherwise, iterate through all of the keys in the object.

                for (k in value) {
                    if (Object.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            }

// Join all of the member texts together, separated with commas,
// and wrap them in braces.

            v = partial.length === 0 ? '{}' :
                gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
                        mind + '}' : '{' + partial.join(',') + '}';
            gap = mind;
            return v;
        }
    }

// If the JSON object does not yet have a stringify method, give it one.

    if (typeof JSON.stringify !== 'function') {
        JSON.stringify = function (value, replacer, space) {

// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.

            var i;
            gap = '';
            indent = '';

// If the space parameter is a number, make an indent string containing that
// many spaces.

            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }

// If the space parameter is a string, it will be used as the indent string.

            } else if (typeof space === 'string') {
                indent = space;
            }

// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.

            rep = replacer;
            if (replacer && typeof replacer !== 'function' &&
                    (typeof replacer !== 'object' ||
                     typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');
            }

// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.

            return str('', {'': value});
        };
    }

// If the JSON object does not yet have a parse method, give it one.

    if (typeof JSON.parse !== 'function') {
      JSON.parse = function(text) { return eval('('+text+')'); };
    }
})();<commit_msg>Revert "Revert "update to latest JSON2 with safer parsing""<commit_after>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple Inc. All rights reserved.
// License:   Licened under MIT license (see license.js)
// ==========================================================================

SC.json = {

  /**
    Encodes an object graph to a JSON output.  Beware that JSON cannot deal
    with circular references.  If you try to encode an object graph with
    references it could hang your browser.

    @param {Object} root object graph
    @returns {String} encode JSON
  */
  encode: function(root) {
    return JSON.stringify(root) ;
  },

  /**
    Decodes a JSON file in a safe way, returning the generated object graph.

    @param {String} encoded JSON
    @returns {Object} object graph or Error if there was a problem.
  */
  decode: function(root) {
    return JSON.parse(root) ;
  }

} ;

/*
    http://www.JSON.org/json2.js
    2009-09-29

    Public Domain.

    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

    See http://www.JSON.org/js.html

    This file creates a global JSON object containing two methods: stringify
    and parse.

        JSON.stringify(value, replacer, space)
            value       any JavaScript value, usually an object or array.

            replacer    an optional parameter that determines how object
                        values are stringified for objects. It can be a
                        function or an array of strings.

            space       an optional parameter that specifies the indentation
                        of nested structures. If it is omitted, the text will
                        be packed without extra whitespace. If it is a number,
                        it will specify the number of spaces to indent at each
                        level. If it is a string (such as '\t' or ' '),
                        it contains the characters used to indent at each level.

            This method produces a JSON text from a JavaScript value.

            When an object value is found, if the object contains a toJSON
            method, its toJSON method will be called and the result will be
            stringified. A toJSON method does not serialize: it returns the
            value represented by the name/value pair that should be serialized,
            or undefined if nothing should be serialized. The toJSON method
            will be passed the key associated with the value, and this will be
            bound to the value

            For example, this would serialize Dates as ISO strings.

                Date.prototype.toJSON = function (key) {
                    function f(n) {
                        // Format integers to have at least two digits.
                        return n < 10 ? '0' + n : n;
                    }

                    return this.getUTCFullYear()   + '-' +
                         f(this.getUTCMonth() + 1) + '-' +
                         f(this.getUTCDate())      + 'T' +
                         f(this.getUTCHours())     + ':' +
                         f(this.getUTCMinutes())   + ':' +
                         f(this.getUTCSeconds())   + 'Z';
                };

            You can provide an optional replacer method. It will be passed the
            key and value of each member, with this bound to the containing
            object. The value that is returned from your method will be
            serialized. If your method returns undefined, then the member will
            be excluded from the serialization.

            If the replacer parameter is an array of strings, then it will be
            used to select the members to be serialized. It filters the results
            such that only members with keys listed in the replacer array are
            stringified.

            Values that do not have JSON representations, such as undefined or
            functions, will not be serialized. Such values in objects will be
            dropped; in arrays they will be replaced with null. You can use
            a replacer function to replace those with JSON values.
            JSON.stringify(undefined) returns undefined.

            The optional space parameter produces a stringification of the
            value that is filled with line breaks and indentation to make it
            easier to read.

            If the space parameter is a non-empty string, then that string will
            be used for indentation. If the space parameter is a number, then
            the indentation will be that many spaces.

            Example:

            text = JSON.stringify(['e', {pluribus: 'unum'}]);
            // text is '["e",{"pluribus":"unum"}]'

            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'

            text = JSON.stringify([new Date()], function (key, value) {
                return this[key] instanceof Date ?
                    'Date(' + this[key] + ')' : value;
            });
            // text is '["Date(---current time---)"]'

        JSON.parse(text, reviver)
            This method parses a JSON text to produce an object or array.
            It can throw a SyntaxError exception.

            The optional reviver parameter is a function that can filter and
            transform the results. It receives each of the keys and values,
            and its return value is used instead of the original value.
            If it returns what it received, then the structure is not modified.
            If it returns undefined then the member is deleted.

            Example:

            // Parse the text. Values that look like ISO date strings will
            // be converted to Date objects.

            myData = JSON.parse(text, function (key, value) {
                var a;
                if (typeof value === 'string') {
                    a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                    if (a) {
                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                            +a[5], +a[6]));
                    }
                }
                return value;
            });

            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
                var d;
                if (typeof value === 'string' &&
                        value.slice(0, 5) === 'Date(' &&
                        value.slice(-1) === ')') {
                    d = new Date(value.slice(5, -1));
                    if (d) {
                        return d;
                    }
                }
                return value;
            });

    This is a reference implementation. You are free to copy, modify, or
    redistribute.

    This code should be minified before deployment.
    See http://javascript.crockford.com/jsmin.html

    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.
*/

/*jslint evil: true, strict: false */

/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
    lastIndex, length, parse, prototype, push, replace, slice, stringify,
    test, toJSON, toString, valueOf
*/

// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.

if (!this.JSON) {
    this.JSON = {};
}

(function () {

    function f(n) {
        // Format integers to have at least two digits.
        return n < 10 ? '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {

        Date.prototype.toJSON = function (key) {

            return isFinite(this.valueOf()) ?
                   this.getUTCFullYear()   + '-' +
                 f(this.getUTCMonth() + 1) + '-' +
                 f(this.getUTCDate())      + 'T' +
                 f(this.getUTCHours())     + ':' +
                 f(this.getUTCMinutes())   + ':' +
                 f(this.getUTCSeconds())   + 'Z' : null;
        };

        String.prototype.toJSON =
        Number.prototype.toJSON =
        Boolean.prototype.toJSON = function (key) {
            return this.valueOf();
        };
    }

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        gap,
        indent,
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        rep;

    function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.

        escapable.lastIndex = 0;
        return escapable.test(string) ?
            '"' + string.replace(escapable, function (a) {
                var c = meta[a];
                return typeof c === 'string' ? c :
                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
            }) + '"' :
            '"' + string + '"';
    }

    function str(key, holder) {

// Produce a string from holder[key].

        var i,          // The loop counter.
            k,          // The member key.
            v,          // The member value.
            length,
            mind = gap,
            partial,
            value = holder[key];

// If the value has a toJSON method, call it to obtain a replacement value.

        if (value && typeof value === 'object' &&
                typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }

// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.

        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }

// What happens next depends on the value's type.

        switch (typeof value) {
        case 'string':
            return quote(value);

        case 'number':

// JSON numbers must be finite. Encode non-finite numbers as null.

            return isFinite(value) ? String(value) : 'null';

        case 'boolean':
        case 'null':

// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.

            return String(value);

// If the type is 'object', we might be dealing with an object or an array or
// null.

        case 'object':

// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.

            if (!value) {
                return 'null';
            }

// Make an array to hold the partial results of stringifying this object value.

            gap += indent;
            partial = [];

// Is the value an array?

            if (Object.prototype.toString.apply(value) === '[object Array]') {

// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.

                length = value.length;
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value) || 'null';
                }

// Join all of the elements together, separated with commas, and wrap them in
// brackets.

                v = partial.length === 0 ? '[]' :
                    gap ? '[\n' + gap +
                            partial.join(',\n' + gap) + '\n' +
                                mind + ']' :
                          '[' + partial.join(',') + ']';
                gap = mind;
                return v;
            }

// If the replacer is an array, use it to select the members to be stringified.

            if (rep && typeof rep === 'object') {
                length = rep.length;
                for (i = 0; i < length; i += 1) {
                    k = rep[i];
                    if (typeof k === 'string') {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            } else {

// Otherwise, iterate through all of the keys in the object.

                for (k in value) {
                    if (Object.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            }

// Join all of the member texts together, separated with commas,
// and wrap them in braces.

            v = partial.length === 0 ? '{}' :
                gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
                        mind + '}' : '{' + partial.join(',') + '}';
            gap = mind;
            return v;
        }
    }

// If the JSON object does not yet have a stringify method, give it one.

    if (typeof JSON.stringify !== 'function') {
        JSON.stringify = function (value, replacer, space) {

// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.

            var i;
            gap = '';
            indent = '';

// If the space parameter is a number, make an indent string containing that
// many spaces.

            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }

// If the space parameter is a string, it will be used as the indent string.

            } else if (typeof space === 'string') {
                indent = space;
            }

// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.

            rep = replacer;
            if (replacer && typeof replacer !== 'function' &&
                    (typeof replacer !== 'object' ||
                     typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');
            }

// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.

            return str('', {'': value});
        };
    }

// If the JSON object does not yet have a parse method, give it one.

    if (typeof JSON.parse !== 'function') {
        JSON.parse = function (text, reviver) {

// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.

            var j;

            function walk(holder, key) {

// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.

                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }

// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.

            cx.lastIndex = 0;
            if (cx.test(text)) {
                text = text.replace(cx, function (a) {
                    return '\\u' +
                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }

// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.

// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

            if (/^[\],:{}\s]*$/.
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                j = eval('(' + text + ')');

// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.

                return typeof reviver === 'function' ?
                    walk({'': j}, '') : j;
            }

// If the text is not JSON parseable, then a SyntaxError is thrown.

            throw new SyntaxError('JSON.parse');
        };
    }
}());
<|endoftext|>


<commit_before>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple, Inc. All rights reserved.
// License:   Licened under MIT license (see license.js)
// ==========================================================================

sc_require('views/view') ;
sc_require('mixins/control') ;
sc_require('mixins/validatable') ;

/** @class

  Base view for managing a view backed by an input element.  Since the web
  browser provides native support for editing input elements, this view
  provides basic support for listening to changes on these input elements and
  responding to them.

  Generally you will not work with a FieldView directly.  Instead, you should
  use one of the subclasses implemented by your target platform such as
  SC.CheckboxView, SC.RadioView, SC.TextFieldView, and so on.

  @extends SC.View
  @extends SC.Control
  @extends SC.Validatable
  @since SproutCore 1.0
*/
SC.FieldView = SC.View.extend(SC.Control, SC.Validatable,
/** @scope SC.FieldView.prototype */ {

  /**
    If YES then we use textarea instead of input.
  */
  isTextArea: NO,

  /**
    The raw value of the field itself.  This is computed from the 'value'
    property by passing it through any validator you might have set.  This is
    the value that will be set on the field itself when the view is updated.

    @property {String}
  */
  fieldValue: function() {
    var value = this.get('value');
    if (SC.typeOf(value) === SC.T_ERROR) value = value.get('value');
    return this.fieldValueForObject(value);
  }.property('value', 'validator').cacheable(),

  // ..........................................................
  // PRIMITIVES
  //

  /**
    Override to return an CoreQuery object that selects the input elements
    for the view.  If this method is defined, the field view will
    automatically edit the attrbutes of the input element to reflect the
    current isEnabled state among other things.
  */
  $field: function() {
    if(this.get('isTextArea')){
      return this.$('textarea').andSelf().filter('textarea');
    }else{
      return this.$('input');
    }
  },

  /**
    Override to set the actual value of the field.

    The default implementation will simple copy the newValue to the value
    attribute of any input tags in the receiver view.  You can override this
    method to provide specific functionality needed by your view.

    @param {Object} newValue the value to display.
    @returns {SC.FieldView} receiver
  */
  setFieldValue: function(newValue) {
    if (SC.none(newValue)) newValue = '' ;
    this.$field().val(newValue);
    return this ;
  },

  /**
    Override to retrieve the actual value of the field.

    The default implementation will simply retrieve the value attribute from
    the first input tag in the receiver view.

    @returns {String} value
  */
  getFieldValue: function() {
    return this.$field().val();
  },

  _field_fieldValueDidChange: function(evt) {
    SC.RunLoop.begin();
    this.fieldValueDidChange(NO);
    SC.RunLoop.end();
  },

  /**
    Your class should call this method anytime you think the value of the
    input element may have changed.  This will retrieve the value and update
    the value property of the view accordingly.

    If this is a partial change (i.e. the user is still editing the field and
    you expect the value to change further), then be sure to pass YES for the
    partialChange parameter.  This will change the kind of validation done on
    the value.  Otherwise, the validator may mark the field as having an error
    when the user is still in mid-edit.

    @param partialChange (optional) YES if this is a partial change.
    @returns {Boolean|SC.Error} result of validation.
  */
  fieldValueDidChange: function(partialChange) {
    // collect the field value and convert it back to a value
    var fieldValue = this.getFieldValue();
    var value = this.objectForFieldValue(fieldValue, partialChange);
    this.setIfChanged('value', value);

    // validate value if needed...

    // this.notifyPropertyChange('fieldValue');
    //
    // // get the field value and set it.
    // // if ret is an error, use that instead of the field value.
    // var ret = this.performValidate ? this.performValidate(partialChange) : YES;
    // if (ret === SC.VALIDATE_NO_CHANGE) return ret ;
    //
    // this.propertyWillChange('fieldValue');
    //
    // // if the validator says everything is OK, then in addition to posting
    // // out the value, go ahead and pass the value back through itself.
    // // This way if you have a formatter applied, it will reformat.
    // //
    // // Do this BEFORE we set the value so that the valueObserver will not
    // // overreact.
    // //
    // var ok = SC.$ok(ret);
    // var value = ok ? this._field_getFieldValue() : ret ;
    // if (!partialChange && ok) this._field_setFieldValue(value) ;
    // this.set('value',value) ;
    //
    // this.propertyDidChange('fieldValue');
    //
    // return ret ;
  },

  // ..........................................................
  // INTERNAL SUPPORT
  //

  /** @private
    invoked when the value property changes.  Sets the field value...
  */
  _field_valueDidChange: function() {
    this.setFieldValue(this.get('fieldValue'));
  }.observes('value'),

  /** @private
    after the layer is created, set the field value and observe events
  */
  didCreateLayer: function() {
    this.setFieldValue(this.get('fieldValue'));
    SC.Event.add(this.$field(), 'change', this, this._field_fieldValueDidChange) ;
  },

  willDestroyLayer: function() {
    SC.Event.remove(this.$field(), 'change', this, this._field_fieldValueDidChange);
  },

  /** @private
    when the layer is updated, go ahead and call render like normal.  this
    will allow normal CSS class + style updates.  by then also update field
    value manually.

    Most subclasses should not regenerate their contents unless necessary.
  */
  updateLayer: function() {
    sc_super();

    // only change field value if it has changed from the last time we
    // set it.  This allows the browser-native field value to change without
    // this method interfering with it.
    var fieldValue = this.get('fieldValue');
    this.setFieldValue(fieldValue);
  },

  // ACTIONS
  // You generally do not need to override these but they may be used.

  /**
    Called to perform validation on the field just before the form
    is submitted.  If you have a validator attached, this will get the
    validators.
  */
  // validateSubmit: function() {
  //   var ret = this.performValidateSubmit ? this.performValidateSubmit() : YES;
  //   // save the value if needed
  //   var value = SC.$ok(ret) ? this._field_getFieldValue() : ret ;
  //   if (value != this.get('value')) this.set('value', value) ;
  //   return ret ;
  // },

  // OVERRIDE IN YOUR SUBCLASS
  // Override these primitives in your subclass as required.

  /**
    Allow the browser to do its normal event handling for the mouse down
    event.  But first, set isActive to YES.
  */
  mouseDown: function(evt) {
    if (this.get('isEnabled')) {
      this.set('isActive', YES);
      this._field_isMouseDown = YES;
    }
    evt.allowDefault();
    return YES;
  },

  /** @private
    Remove the active class on mouseOut if mouse is down.
  */
  mouseOut: function(evt) {
    if (this._field_isMouseDown) this.set('isActive', NO);
    evt.allowDefault();
    return YES;
  },

  /** @private
    If mouse was down and we renter the button area, set the active state again.
  */
  mouseOver: function(evt) {
    this.set('isActive', this._field_isMouseDown);
    evt.allowDefault();
    return YES;
  },

  _field_isMouseDown: NO,

  /** @private
    on mouse up, remove the isActive class and then allow the browser to do
    its normal thing.
  */
  mouseUp: function(evt) {
    // track independently in case isEnabled has changed
    if (this._field_isMouseDown) this.set('isActive', NO);
    this._field_isMouseDown = false;
    evt.allowDefault();
    return YES ;
  },

  // called whenever the value is set on the object.  Will set the value
  // on the field if the value is changed.
  // valueDidChange: function() {
  //   var value = this.get('value') ;
  //   var isError = SC.typeOf(value) === SC.T_ERROR ;
  //   if (!isError && (value !== this._field_getFieldValue())) {
  //     this._field_setFieldValue(value) ;
  //   }
  // }.observes('value'),

  // these methods use the validator to convert the raw field value returned
  // by your subclass into an object and visa versa.
  _field_setFieldValue: function(newValue) {

    this.propertyWillChange('fieldValue');
    if (this.fieldValueForObject) {
      newValue = this.fieldValueForObject(newValue) ;
    }
    var ret = this.setFieldValue(newValue) ;
    this.propertyDidChange('fieldValue');
    return ret ;
  },

  _field_getFieldValue: function() {
    var ret = this.getFieldValue() ;
    if (this.objectForFieldValue) ret=this.objectForFieldValue(ret);
    return ret ;
  }

}) ;

<commit_msg>Fix regression in selectfield due to a change in field.js<commit_after>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple, Inc. All rights reserved.
// License:   Licened under MIT license (see license.js)
// ==========================================================================

sc_require('views/view') ;
sc_require('mixins/control') ;
sc_require('mixins/validatable') ;

/** @class

  Base view for managing a view backed by an input element.  Since the web
  browser provides native support for editing input elements, this view
  provides basic support for listening to changes on these input elements and
  responding to them.

  Generally you will not work with a FieldView directly.  Instead, you should
  use one of the subclasses implemented by your target platform such as
  SC.CheckboxView, SC.RadioView, SC.TextFieldView, and so on.

  @extends SC.View
  @extends SC.Control
  @extends SC.Validatable
  @since SproutCore 1.0
*/
SC.FieldView = SC.View.extend(SC.Control, SC.Validatable,
/** @scope SC.FieldView.prototype */ {

  /**
    If YES then we use textarea instead of input.
  */
  isTextArea: NO,

  /**
    The raw value of the field itself.  This is computed from the 'value'
    property by passing it through any validator you might have set.  This is
    the value that will be set on the field itself when the view is updated.

    @property {String}
  */
  fieldValue: function() {
    var value = this.get('value');
    if (SC.typeOf(value) === SC.T_ERROR) value = value.get('value');
    return this.fieldValueForObject(value);
  }.property('value', 'validator').cacheable(),

  // ..........................................................
  // PRIMITIVES
  //

  /**
    Override to return an CoreQuery object that selects the input elements
    for the view.  If this method is defined, the field view will
    automatically edit the attrbutes of the input element to reflect the
    current isEnabled state among other things.
  */
  $input: function() {
    if(this.get('isTextArea')){
      return this.$('textarea').andSelf().filter('textarea');
    }else{
      return this.$('input').andSelf().filter('input');
    }
  },

  /**
    Override to set the actual value of the field.

    The default implementation will simple copy the newValue to the value
    attribute of any input tags in the receiver view.  You can override this
    method to provide specific functionality needed by your view.

    @param {Object} newValue the value to display.
    @returns {SC.FieldView} receiver
  */
  setFieldValue: function(newValue) {
    if (SC.none(newValue)) newValue = '' ;
    this.$input().val(newValue);
    return this ;
  },

  /**
    Override to retrieve the actual value of the field.

    The default implementation will simply retrieve the value attribute from
    the first input tag in the receiver view.

    @returns {String} value
  */
  getFieldValue: function() {
    return this.$input().val();
  },

  _field_fieldValueDidChange: function(evt) {
    SC.RunLoop.begin();
    this.fieldValueDidChange(NO);
    SC.RunLoop.end();
  },

  /**
    Your class should call this method anytime you think the value of the
    input element may have changed.  This will retrieve the value and update
    the value property of the view accordingly.

    If this is a partial change (i.e. the user is still editing the field and
    you expect the value to change further), then be sure to pass YES for the
    partialChange parameter.  This will change the kind of validation done on
    the value.  Otherwise, the validator may mark the field as having an error
    when the user is still in mid-edit.

    @param partialChange (optional) YES if this is a partial change.
    @returns {Boolean|SC.Error} result of validation.
  */
  fieldValueDidChange: function(partialChange) {
    // collect the field value and convert it back to a value
    var fieldValue = this.getFieldValue();
    var value = this.objectForFieldValue(fieldValue, partialChange);
    this.setIfChanged('value', value);

    // validate value if needed...

    // this.notifyPropertyChange('fieldValue');
    //
    // // get the field value and set it.
    // // if ret is an error, use that instead of the field value.
    // var ret = this.performValidate ? this.performValidate(partialChange) : YES;
    // if (ret === SC.VALIDATE_NO_CHANGE) return ret ;
    //
    // this.propertyWillChange('fieldValue');
    //
    // // if the validator says everything is OK, then in addition to posting
    // // out the value, go ahead and pass the value back through itself.
    // // This way if you have a formatter applied, it will reformat.
    // //
    // // Do this BEFORE we set the value so that the valueObserver will not
    // // overreact.
    // //
    // var ok = SC.$ok(ret);
    // var value = ok ? this._field_getFieldValue() : ret ;
    // if (!partialChange && ok) this._field_setFieldValue(value) ;
    // this.set('value',value) ;
    //
    // this.propertyDidChange('fieldValue');
    //
    // return ret ;
  },

  // ..........................................................
  // INTERNAL SUPPORT
  //

  /** @private
    invoked when the value property changes.  Sets the field value...
  */
  _field_valueDidChange: function() {
    this.setFieldValue(this.get('fieldValue'));
  }.observes('value'),

  /** @private
    after the layer is created, set the field value and observe events
  */
  didCreateLayer: function() {
    this.setFieldValue(this.get('fieldValue'));
    SC.Event.add(this.$input(), 'change', this, this._field_fieldValueDidChange) ;
  },

  willDestroyLayer: function() {
    SC.Event.remove(this.$input(), 'change', this, this._field_fieldValueDidChange);
  },

  /** @private
    when the layer is updated, go ahead and call render like normal.  this
    will allow normal CSS class + style updates.  by then also update field
    value manually.

    Most subclasses should not regenerate their contents unless necessary.
  */
  updateLayer: function() {
    sc_super();

    // only change field value if it has changed from the last time we
    // set it.  This allows the browser-native field value to change without
    // this method interfering with it.
    var fieldValue = this.get('fieldValue');
    this.setFieldValue(fieldValue);
  },

  // ACTIONS
  // You generally do not need to override these but they may be used.

  /**
    Called to perform validation on the field just before the form
    is submitted.  If you have a validator attached, this will get the
    validators.
  */
  // validateSubmit: function() {
  //   var ret = this.performValidateSubmit ? this.performValidateSubmit() : YES;
  //   // save the value if needed
  //   var value = SC.$ok(ret) ? this._field_getFieldValue() : ret ;
  //   if (value != this.get('value')) this.set('value', value) ;
  //   return ret ;
  // },

  // OVERRIDE IN YOUR SUBCLASS
  // Override these primitives in your subclass as required.

  /**
    Allow the browser to do its normal event handling for the mouse down
    event.  But first, set isActive to YES.
  */
  mouseDown: function(evt) {
    if (this.get('isEnabled')) {
      this.set('isActive', YES);
      this._field_isMouseDown = YES;
    }
    evt.allowDefault();
    return YES;
  },

  /** @private
    Remove the active class on mouseOut if mouse is down.
  */
  mouseOut: function(evt) {
    if (this._field_isMouseDown) this.set('isActive', NO);
    evt.allowDefault();
    return YES;
  },

  /** @private
    If mouse was down and we renter the button area, set the active state again.
  */
  mouseOver: function(evt) {
    this.set('isActive', this._field_isMouseDown);
    evt.allowDefault();
    return YES;
  },

  _field_isMouseDown: NO,

  /** @private
    on mouse up, remove the isActive class and then allow the browser to do
    its normal thing.
  */
  mouseUp: function(evt) {
    // track independently in case isEnabled has changed
    if (this._field_isMouseDown) this.set('isActive', NO);
    this._field_isMouseDown = false;
    evt.allowDefault();
    return YES ;
  },

  // called whenever the value is set on the object.  Will set the value
  // on the field if the value is changed.
  // valueDidChange: function() {
  //   var value = this.get('value') ;
  //   var isError = SC.typeOf(value) === SC.T_ERROR ;
  //   if (!isError && (value !== this._field_getFieldValue())) {
  //     this._field_setFieldValue(value) ;
  //   }
  // }.observes('value'),

  // these methods use the validator to convert the raw field value returned
  // by your subclass into an object and visa versa.
  _field_setFieldValue: function(newValue) {

    this.propertyWillChange('fieldValue');
    if (this.fieldValueForObject) {
      newValue = this.fieldValueForObject(newValue) ;
    }
    var ret = this.setFieldValue(newValue) ;
    this.propertyDidChange('fieldValue');
    return ret ;
  },

  _field_getFieldValue: function() {
    var ret = this.getFieldValue() ;
    if (this.objectForFieldValue) ret=this.objectForFieldValue(ret);
    return ret ;
  }

}) ;

<|endoftext|>


<commit_before>(function() {
    "use strict";

    // TODO to stylesheet
    var context = {
        canvasId: "canvas-nine-dots-puzzle",
        colourBackround: 'white',
        colourNeutral: "blue",
        colourSuccess: "green",
        colourFail: "red",
        dotRadius: 5,
        lineColor: "green",
        lineWidth: 3
    };

    function Coordinate(parent, x, y) {
        this.raster = parent;
        this.x = x;
        this.y = y;
        this.covered = false;
        this.isDot = false;
        this.radius = context.dotRadius;
        this.colour = context.colourNeutral;
        this.animationId = - 1;
    }

    Coordinate.prototype._blinkInterval = 300; // ms
    Coordinate.prototype.animationDuration = 2400; // ms

    Coordinate.prototype.draw = function() {
        if (this.isDot) {
            var canvas = this.raster.canvasWrapper.canvas;
            var canvasContext = canvas.getContext("2d");

            canvasContext.fillStyle = this.colour;
            canvasContext.strokeStyle = this.colour;
            canvasContext.lineWidth = 1;
            canvasContext.beginPath();
            canvasContext.arc(this.getPositionX(), this.getPositionY(), this.radius, 0, 2 * Math.PI);
            canvasContext.fill();
            canvasContext.stroke();
        }
    };

    Coordinate.prototype.cover = function() {
        this.covered = true;
        this.colour = context.colourSuccess;
    }

    Coordinate.prototype.blink = function() {
        this.animationId = this._blink();

        setTimeout(function() {
            clearInterval(this.animationId);
        }.bind(this), Coordinate.prototype.animationDuration);
    };

    Coordinate.prototype._blink = function() {
        return setInterval(function() {
            this.colour = this.colour === context.colourFail ? context.colourNeutral : context.colourFail;
            this.draw();
        }.bind(this), Coordinate.prototype._blinkInterval);
    };

    Coordinate.prototype.expand = function() {
        this.animationId = requestAnimationFrame(function() {
            this._expand();
        }.bind(this));

        setTimeout(function() {
            cancelAnimationFrame(this.animationId);
        }.bind(this), Coordinate.prototype.animationDuration);
    }

    Coordinate.prototype._expand = function() {
        if (!this._scalingFactor) {
            var rStart = this.radius;
            var rTarget = Math.min(this.raster.canvasWrapper.height, this.raster.canvasWrapper.width) / 2;
            var exponent = (this.animationDuration / 1000) * 60 // 60 frames per second

            this._scalingFactor = Math.pow(rTarget / rStart, 1 / exponent);
        }

        this.radius *= this._scalingFactor;
        this.draw();

        this.animationId = requestAnimationFrame(function() {
            this._expand();
        }.bind(this));
    };

    Coordinate.prototype.getPositionX = function() {
        return this._getPosition(true);
    };

    Coordinate.prototype.getPositionY = function() {
        return this._getPosition(false);
    };

    Coordinate.prototype._getPosition = function(horizontal) {
        var canvas = this.raster.canvasWrapper.canvas;
        var canvasSize = canvas.width;
        var rasterSpacing = canvasSize / (Raster.prototype.size + 1);
        var padding = rasterSpacing;

        return horizontal ? padding + this.x * rasterSpacing : padding + this.y * rasterSpacing;
    };

    Coordinate.prototype.equals = function(other) {
        return other && other.x === this.x && other.y === this.y;
    }

    function Raster(parent) {
        var x, y, dot;
        this.canvasWrapper = parent;
        this.coordinates = new Array(Raster.prototype.size);

        for (x = 0; x < Raster.prototype.size; ++x) {
            this.coordinates[x] = new Array(Raster.prototype.size);

            for (y = 0; y < Raster.prototype.size; ++y) {
                this.coordinates[x][y] = new Coordinate(this, x, y);
            }
        }

        for (dot of this.getDots()) {
            dot.isDot = true;
        }
    }

    Raster.prototype.size = 9;
    Raster.prototype.dotSpacing = 2;

    Raster.prototype.getDots = function() {
        var dotCount = 9;
        var dots = new Array(dotCount);
        var d = 0, i, j;
        var indentation = 2;
        var dotSpacing = Raster.prototype.dotSpacing;

        for (i = 0; i < 3; ++i) {
            for (j = 0; j < 3; ++j) {
                dots[d] = this.coordinates[indentation + i * dotSpacing][indentation + j * dotSpacing];
                ++d;
            }
        }

        return dots;
    };

    Raster.prototype.draw = function() {
        var row;
        var coordinate;

        for (row of this.coordinates) {
            for (coordinate of row) {
                coordinate.draw();
            }
        }
    };

    Raster.prototype._getGridIndex = function(clickPosition) {
        var canvasSize = this.canvasWrapper.width;
        var rasterSpacing = canvasSize / (Raster.prototype.size + 1);
        var padding = rasterSpacing;
        var gridIndex = Math.round((clickPosition - padding) / rasterSpacing);

        if (gridIndex < 0) {
            gridIndex = 0;
        }
        if (gridIndex >= Raster.prototype.size) {
            gridIndex = Raster.prototype.size - 1;
        }

        return gridIndex;
    };

    Raster.prototype.getCoordinate = function(clickX, clickY) {
        return this.coordinates[this._getGridIndex(clickX)][this._getGridIndex(clickY)];
    };

    Raster.prototype._updateCoveredState = function(startNode, targetNode) {
        if (startNode.x == targetNode.x) { // Vertical line
            if (startNode.y > targetNode.y) {
                var swap = targetNode;
                targetNode = startNode;
                startNode = swap;
            }

            var y;
            var x = startNode.x;

            for (y = startNode.y; y <= targetNode.y; ++y) {
                this.coordinates[x][y].cover();
            }
        } else {
            if (startNode.x > targetNode.x) {
                var swap = targetNode;
                targetNode = startNode;
                startNode = swap;
            }

            var slope = (targetNode.y - startNode.y) / (targetNode.x - startNode.x);
            var y = startNode.y;
            var x;
            var epsilon = 0.0001;

            for (x = startNode.x; x <= targetNode.x; ++x) {
                if (Math.abs(Math.floor(y) - y) < epsilon) {
                    this.coordinates[x][Math.floor(y)].cover();
                }

                y += slope;
            }
        }
    };

    Raster.prototype.updateCoveredState = function(polyline) {
        if (polyline.nodeCount == 1) {
            this._updateCoveredState(polyline.nodes[0], polyline.nodes[0]);
        } else {
            this._updateCoveredState(polyline.nodes[polyline.nodeCount - 2], polyline.nodes[polyline.nodeCount - 1]);
        }
    };

    Raster.prototype.covered = function() {
        return this.getDots().every(dot => dot.covered);
    };

    function CanvasWrapper() {
        // TODO remove coupling: insert canvas to DOM programmatically
        this.canvas = document.getElementById(context.canvasId);
        this.height = this.canvas.height;
        this.width = this.canvas.width;
        this.canvas.addEventListener("click", this.onClick.bind(this));
        this.canvas.addEventListener("mousemove", this.onMouseMove.bind(this));

        this.canvas.style.cursor = 'crosshair';
    }

    CanvasWrapper.prototype.draw = function() {
        var canvasContext = this.canvas.getContext("2d");

        canvasContext.fillStyle = context.colourBackround;
        canvasContext.fillRect(0, 0, this.width, this.height);

        this.raster.draw();

        if (this.polyline)
            this.polyline.draw();
    };

    CanvasWrapper.prototype.drawFace = function(happy) {
        var canvasContext = this.canvas.getContext("2d");
        var centre = Math.min(this.width, this.height) / 2;
        var headRadius = centre * 0.8;
        var eyeRadius = centre * 0.05;
        var eyesOffsetX = centre * 0.25;
        var eyesOffsetY = centre * 0.3;

        canvasContext.strokeStyle = 'black';
        canvasContext.lineWidth = 3;

        // Background
        canvasContext.fillStyle = happy ? context.colourSuccess : context.colourFail;
        canvasContext.fillRect(0, 0, this.width, this.height);

        // Head
        canvasContext.fillStyle = 'yellow';
        canvasContext.beginPath();
        canvasContext.arc(centre, centre, headRadius, 0, Math.PI * 2, true);
        canvasContext.fill();
        canvasContext.stroke();

        // Mouth
        if (happy) {
            var mouthRadius = centre * 0.5;

            canvasContext.fillStyle = 'white';
            canvasContext.beginPath();
            canvasContext.arc(centre, centre, mouthRadius, 0, Math.PI, false);
            canvasContext.lineTo(centre + mouthRadius, centre);
            canvasContext.fill();
            canvasContext.stroke();
        } else {
            var leftCornerOfMouthX = centre - headRadius * 0.6;
            var leftCornerOfMouthY = centre + headRadius * 0.1;
            var rightCornerOfMouthX = centre + headRadius * 0.55;
            var rightCornerOfMouthY = centre + headRadius * 0.4;

            canvasContext.lineWidth = 4;
            canvasContext.beginPath();
            canvasContext.moveTo(leftCornerOfMouthX, leftCornerOfMouthY);
            canvasContext.lineTo(rightCornerOfMouthX, rightCornerOfMouthY);
            canvasContext.stroke();
        }

        // Eyes
        canvasContext.fillStyle = 'black';
        canvasContext.beginPath();
        canvasContext.arc(centre - eyesOffsetX, centre - eyesOffsetY, eyeRadius, 0, Math.PI * 2, true);
        canvasContext.fill();
        canvasContext.stroke();
        canvasContext.beginPath();
        canvasContext.arc(centre + eyesOffsetX, centre - eyesOffsetY, eyeRadius, 0, Math.PI * 2, true);
        canvasContext.fill();
        canvasContext.stroke();
    }

    CanvasWrapper.prototype.showResult = function(puzzleSolved) {
        if (puzzleSolved) {
            this.raster.getDots().forEach(function(dot) {
                dot.expand();
            })
        } else {
            this.raster.getDots().forEach(function(dot) {
                if (!dot.covered) {
                    dot.blink();
                }
            })
        }

        setTimeout(function() {
            this.drawFace(puzzleSolved);
            this.faceDisplayed = true;
        }.bind(this), Coordinate.prototype.animationDuration);
    };

    CanvasWrapper.prototype.startGame = function() {
        this.raster = new Raster(this);
        this.polyline = new Polyline(this);
        this.hasGameEnded = false;
        this.faceDisplayed = false;
        this.draw();
    };

    CanvasWrapper.prototype.onClick = function(event) {
        if (this.hasGameEnded) {
            if (this.faceDisplayed)
                this.startGame();
        } else {
            var node = this.raster.getCoordinate(event.layerX, event.layerY);

            this.polyline.addNode(node);
            this.raster.updateCoveredState(this.polyline);
            this.draw();

            if (this.polyline.isComplete()) {
                this.hasGameEnded = true;
                this.showResult(this.raster.covered());
            }
        }
    };

    CanvasWrapper.prototype.onMouseMove = function(event) {
        var node = this.raster.getCoordinate(event.layerX, event.layerY);

        if (this.polyline.nodeCount === 0) {

        } else {

        }
    };

    function Polyline(parent) {
        this.canvasWrapper = parent;
        this.nodes = new Array(this.maxNodeCount);
        this.nodeCount = 0;
    }

    Polyline.prototype.maxNodeCount = 5;

    Polyline.prototype.isComplete = function() {
        return this.nodeCount == Polyline.prototype.maxNodeCount;
    };

    Polyline.prototype.addNode = function(newNode) {
        console.assert(this.nodeCount < this.maxNodeCount, "Illegal state: Maximum number of polyline nodes exceeded.");

        if (this.nodeCount === 0 || !this.nodes[this.nodeCount - 1].equals(newNode)) {
            this.nodes[this.nodeCount] = newNode;
            ++this.nodeCount;
        }
    };

    Polyline.prototype.draw = function() {
        if (this.nodeCount > 0) {
            var canvas = this.canvasWrapper.canvas;
            var canvasContext = canvas.getContext("2d");
            var i;

            canvasContext.strokeStyle = context.lineColor;
            canvasContext.lineWidth = context.lineWidth;
            canvasContext.lineCap = "round";
            canvasContext.beginPath();

            for (i = 0; i < this.nodeCount; ++i) {
                var x = this.nodes[i].getPositionX();
                var y = this.nodes[i].getPositionY();

                if (i == 0)
                    canvasContext.moveTo(x, y);
                else
                    canvasContext.lineTo(x, y);
            }

            canvasContext.stroke();
        }
    };

    Polyline.prototype.toString = function() {
        var stringRepresentation = "Polyline(";
        var i;

        for (i = 0; i < this.nodeCount; ++i) {
            stringRepresentation += "(" + this.nodes[i].x + "," + this.nodes[i].y + ")";

            if (i < this.nodeCount - 1) {
                stringRepresentation += ", ";
            }
        }
        stringRepresentation += ")";
        return stringRepresentation;
    };

    (function() {
        (new CanvasWrapper()).startGame();
    })();
})();
<commit_msg>Preview (part 1)<commit_after>(function() {
    "use strict";

    // TODO to stylesheet
    var context = {
        canvasId: "canvas-nine-dots-puzzle",
        colourBackround: 'white',
        colourNeutral: "blue",
        colourSuccess: "green",
        colourFail: "red",
        dotRadius: 5,
        lineColor: "green",
        lineWidth: 3
    };

    function Coordinate(parent, x, y) {
        this.raster = parent;
        this.x = x;
        this.y = y;
        this.covered = false;
        this.isDot = false;
        this.radius = context.dotRadius;
        this.colour = context.colourNeutral;
        this.animationId = - 1;
    }

    Coordinate.prototype._blinkInterval = 300; // ms
    Coordinate.prototype.animationDuration = 2400; // ms

    Coordinate.prototype.draw = function() {
        if (this.isDot) {
            var canvas = this.raster.canvasWrapper.canvas;
            var canvasContext = canvas.getContext("2d");

            canvasContext.fillStyle = this.colour;
            canvasContext.strokeStyle = this.colour;
            canvasContext.lineWidth = 1;
            canvasContext.beginPath();
            canvasContext.arc(this.getPositionX(), this.getPositionY(), this.radius, 0, 2 * Math.PI);
            canvasContext.fill();
            canvasContext.stroke();
        }
    };

    Coordinate.prototype.updateState = function(covered) {
        this.covered = covered;
        this.colour = this.covered ? context.colourSuccess : context.colourNeutral;
    }

    Coordinate.prototype.blink = function() {
        this.animationId = this._blink();

        setTimeout(function() {
            clearInterval(this.animationId);
        }.bind(this), Coordinate.prototype.animationDuration);
    };

    Coordinate.prototype._blink = function() {
        return setInterval(function() {
            this.colour = this.colour === context.colourFail ? context.colourNeutral : context.colourFail;
            this.draw();
        }.bind(this), Coordinate.prototype._blinkInterval);
    };

    Coordinate.prototype.expand = function() {
        this.animationId = requestAnimationFrame(function() {
            this._expand();
        }.bind(this));

        setTimeout(function() {
            cancelAnimationFrame(this.animationId);
        }.bind(this), Coordinate.prototype.animationDuration);
    };

    Coordinate.prototype._expand = function() {
        if (!this._scalingFactor) {
            var rStart = this.radius;
            var rTarget = Math.min(this.raster.canvasWrapper.height, this.raster.canvasWrapper.width) / 2;
            var exponent = (this.animationDuration / 1000) * 60 // 60 frames per second

            this._scalingFactor = Math.pow(rTarget / rStart, 1 / exponent);
        }

        this.radius *= this._scalingFactor;
        this.draw();

        this.animationId = requestAnimationFrame(function() {
            this._expand();
        }.bind(this));
    };

    Coordinate.prototype.getPositionX = function() {
        return this._getPosition(true);
    };

    Coordinate.prototype.getPositionY = function() {
        return this._getPosition(false);
    };

    Coordinate.prototype._getPosition = function(horizontal) {
        var canvas = this.raster.canvasWrapper.canvas;
        var canvasSize = canvas.width;
        var rasterSpacing = canvasSize / (Raster.prototype.size + 1);
        var padding = rasterSpacing;

        return horizontal ? padding + this.x * rasterSpacing : padding + this.y * rasterSpacing;
    };

    Coordinate.prototype.equals = function(other) {
        return other && other.x === this.x && other.y === this.y;
    };

    function Raster(parent) {
        var x, y, dot;
        this.canvasWrapper = parent;
        this.coordinates = new Array(Raster.prototype.size);

        for (x = 0; x < Raster.prototype.size; ++x) {
            this.coordinates[x] = new Array(Raster.prototype.size);

            for (y = 0; y < Raster.prototype.size; ++y) {
                this.coordinates[x][y] = new Coordinate(this, x, y);
            }
        }

        for (dot of this.getDots()) {
            dot.isDot = true;
        }
    }

    Raster.prototype.size = 9;
    Raster.prototype.dotSpacing = 2;

    Raster.prototype.getDots = function() {
        var dotCount = 9;
        var dots = new Array(dotCount);
        var d = 0, i, j;
        var indentation = 2;
        var dotSpacing = Raster.prototype.dotSpacing;

        for (i = 0; i < 3; ++i) {
            for (j = 0; j < 3; ++j) {
                dots[d] = this.coordinates[indentation + i * dotSpacing][indentation + j * dotSpacing];
                ++d;
            }
        }

        return dots;
    };

    Raster.prototype.draw = function() {
        var row;
        var coordinate;

        for (row of this.coordinates) {
            for (coordinate of row) {
                coordinate.draw();
            }
        }
    };

    Raster.prototype._getGridIndex = function(clickPosition) {
        var canvasSize = this.canvasWrapper.width;
        var rasterSpacing = canvasSize / (Raster.prototype.size + 1);
        var padding = rasterSpacing;
        var gridIndex = Math.round((clickPosition - padding) / rasterSpacing);

        if (gridIndex < 0) {
            gridIndex = 0;
        }
        if (gridIndex >= Raster.prototype.size) {
            gridIndex = Raster.prototype.size - 1;
        }

        return gridIndex;
    };

    Raster.prototype.getCoordinate = function(clickX, clickY) {
        return this.coordinates[this._getGridIndex(clickX)][this._getGridIndex(clickY)];
    };

    Raster.prototype._updateState = function(startNode, targetNode) {
        if (startNode.x == targetNode.x) { // Vertical line
            if (startNode.y > targetNode.y) {
                var swap = targetNode;
                targetNode = startNode;
                startNode = swap;
            }

            var y;
            var x = startNode.x;

            for (y = startNode.y; y <= targetNode.y; ++y) {
                this.coordinates[x][y].updateState(true);
            }
        } else {
            if (startNode.x > targetNode.x) {
                var swap = targetNode;
                targetNode = startNode;
                startNode = swap;
            }

            var slope = (targetNode.y - startNode.y) / (targetNode.x - startNode.x);
            var y = startNode.y;
            var x;
            var epsilon = 0.0001;

            for (x = startNode.x; x <= targetNode.x; ++x) {
                if (Math.abs(Math.floor(y) - y) < epsilon) {
                    this.coordinates[x][Math.floor(y)].updateState(true);
                }

                y += slope;
            }
        }
    };

    Raster.prototype.updateState = function(polyline) {
        this.getDots().forEach(dot => dot.updateState(false));

        if (polyline.nodeCount == 0) {
            polyline.previewNode.updateState(true);
        } else {
            var i;

            for (i = 0; i < polyline.nodeCount - 1; ++i) {
                this._updateState(polyline.nodes[i], polyline.nodes[i + 1]);
            }

            this._updateState(polyline.nodes[polyline.nodeCount - 1], polyline.previewNode);
        }
    };

    Raster.prototype.covered = function() {
        return this.getDots().every(dot => dot.covered);
    };

    function CanvasWrapper() {
        // TODO remove coupling: insert canvas to DOM programmatically
        this.canvas = document.getElementById(context.canvasId);
        this.height = this.canvas.height;
        this.width = this.canvas.width;
        this.canvas.addEventListener("click", this.onClick.bind(this));
        this.canvas.addEventListener("mousemove", this.onMouseMove.bind(this));
        this.canvas.style.cursor = 'crosshair';
    }

    CanvasWrapper.prototype.draw = function() {
        var canvasContext = this.canvas.getContext("2d");

        canvasContext.fillStyle = context.colourBackround;
        canvasContext.fillRect(0, 0, this.width, this.height);

        this.raster.draw();

        if (this.polyline)
            this.polyline.draw();
    };

    CanvasWrapper.prototype.drawFace = function(happy) {
        var canvasContext = this.canvas.getContext("2d");
        var centre = Math.min(this.width, this.height) / 2;
        var headRadius = centre * 0.8;
        var eyeRadius = centre * 0.05;
        var eyesOffsetX = centre * 0.25;
        var eyesOffsetY = centre * 0.3;

        canvasContext.strokeStyle = 'black';
        canvasContext.lineWidth = 3;

        // Background
        canvasContext.fillStyle = happy ? context.colourSuccess : context.colourFail;
        canvasContext.fillRect(0, 0, this.width, this.height);

        // Head
        canvasContext.fillStyle = 'yellow';
        canvasContext.beginPath();
        canvasContext.arc(centre, centre, headRadius, 0, Math.PI * 2, true);
        canvasContext.fill();
        canvasContext.stroke();

        // Mouth
        if (happy) {
            var mouthRadius = centre * 0.5;

            canvasContext.fillStyle = 'white';
            canvasContext.beginPath();
            canvasContext.arc(centre, centre, mouthRadius, 0, Math.PI, false);
            canvasContext.lineTo(centre + mouthRadius, centre);
            canvasContext.fill();
            canvasContext.stroke();
        } else {
            var leftCornerOfMouthX = centre - headRadius * 0.6;
            var leftCornerOfMouthY = centre + headRadius * 0.1;
            var rightCornerOfMouthX = centre + headRadius * 0.55;
            var rightCornerOfMouthY = centre + headRadius * 0.4;

            canvasContext.lineWidth = 4;
            canvasContext.beginPath();
            canvasContext.moveTo(leftCornerOfMouthX, leftCornerOfMouthY);
            canvasContext.lineTo(rightCornerOfMouthX, rightCornerOfMouthY);
            canvasContext.stroke();
        }

        // Eyes
        canvasContext.fillStyle = 'black';
        canvasContext.beginPath();
        canvasContext.arc(centre - eyesOffsetX, centre - eyesOffsetY, eyeRadius, 0, Math.PI * 2, true);
        canvasContext.fill();
        canvasContext.stroke();
        canvasContext.beginPath();
        canvasContext.arc(centre + eyesOffsetX, centre - eyesOffsetY, eyeRadius, 0, Math.PI * 2, true);
        canvasContext.fill();
        canvasContext.stroke();
    };

    CanvasWrapper.prototype.showResult = function(puzzleSolved) {
        if (puzzleSolved) {
            this.raster.getDots().forEach(function(dot) {
                dot.expand();
            })
        } else {
            this.raster.getDots().forEach(function(dot) {
                if (!dot.covered) {
                    dot.blink();
                }
            })
        }

        setTimeout(function() {
            this.drawFace(puzzleSolved);
            this.faceDisplayed = true;
        }.bind(this), Coordinate.prototype.animationDuration);
    };

    CanvasWrapper.prototype.startGame = function() {
        this.raster = new Raster(this);
        this.polyline = new Polyline(this);
        this.hasGameEnded = false;
        this.faceDisplayed = false;
        this.draw();
    };

    CanvasWrapper.prototype.onClick = function(event) {
        if (this.hasGameEnded) {
            if (this.faceDisplayed)
                this.startGame();
        } else {
            var node = this.raster.getCoordinate(event.layerX, event.layerY);

            this.polyline.addNode(node);
            this.raster.updateState(this.polyline);
            this.draw();

            if (this.polyline.isComplete()) {
                this.hasGameEnded = true;
                this.showResult(this.raster.covered());
            }
        }
    };

    CanvasWrapper.prototype.onMouseMove = function(event) {
        if (!this.hasGameEnded) {
            var node = this.raster.getCoordinate(event.layerX, event.layerY);

            this.polyline.addNode(node, true);
            this.raster.updateState(this.polyline);
            this.draw();
        }
    };

    function Polyline(parent) {
        this.canvasWrapper = parent;
        this.nodes = new Array(this.maxNodeCount);
        this.nodeCount = 0;
        this.previewNode = null;
    }

    Polyline.prototype.maxNodeCount = 5;

    Polyline.prototype.isComplete = function() {
        return this.nodeCount == Polyline.prototype.maxNodeCount;
    };

    Polyline.prototype.addNode = function(newNode, isPreviewNode) {
        console.assert(this.nodeCount < this.maxNodeCount, "Illegal state: Maximum number of polyline nodes exceeded.");

        if (this.nodeCount === 0 || !this.nodes[this.nodeCount - 1].equals(newNode)) {
            if (isPreviewNode) {
                this.previewNode = newNode;
            } else {
                this.nodes[this.nodeCount] = newNode;
                ++this.nodeCount;
            }
        }
    };

    Polyline.prototype.draw = function() {
        if (this.nodeCount > 0) {
            var canvas = this.canvasWrapper.canvas;
            var canvasContext = canvas.getContext("2d");
            var i;

            canvasContext.strokeStyle = context.lineColor;
            canvasContext.lineWidth = context.lineWidth;
            canvasContext.lineCap = "round";
            canvasContext.beginPath();

            for (i = 0; i < this.nodeCount; ++i) {
                var x = this.nodes[i].getPositionX();
                var y = this.nodes[i].getPositionY();

                if (i == 0)
                    canvasContext.moveTo(x, y);
                else
                    canvasContext.lineTo(x, y);
            }

            canvasContext.stroke();
        }
    };

    Polyline.prototype.toString = function() {
        var stringRepresentation = "Polyline(";
        var i;

        for (i = 0; i < this.nodeCount; ++i) {
            stringRepresentation += "(" + this.nodes[i].x + "," + this.nodes[i].y + ")";

            if (i < this.nodeCount - 1) {
                stringRepresentation += ", ";
            }
        }
        stringRepresentation += ")";
        return stringRepresentation;
    };

    (function() {
        (new CanvasWrapper()).startGame();
    })();
})();
<|endoftext|>


<commit_before>'use strict';
var path = require('path');
var assert = require('yeoman-assert');
var helpers = require('yeoman-test');

describe('node:eslint', function () {
  before(function (done) {
    helpers.run(path.join(__dirname, '../generators/eslint'))
      .on('end', done);
  });

  it('fill package.json', function () {
    assert.fileContent('package.json', /"eslint-config-xo-space":/);
    assert.jsonFileContent('package.json', {
      eslintConfig: {
        extends: 'xo-space',
        env: {
          mocha: true
        }
      }
    });
  });

  describe('--es2015', function () {
    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/eslint'))
        .withOptions({es2015: true})
        .on('end', done);
    });

    it('fill package.json for ES2015', function () {
      assert.fileContent('package.json', /"babel-eslint":/);
      assert.fileContent('package.json', /"eslint-plugin-babel":/);
      assert.jsonFileContent('package.json', {
        eslintConfig: {
          extends: 'xo-space/esnext'
        }
      });
    });
  });

  describe('--generate-into', function () {
    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/eslint'))
        .withOptions({generateInto: 'other/'})
        .on('end', done);
    });

    it('fill env .eslintrc with generate-into option', function () {
      assert.fileContent('other/package.json', /"eslint-config-xo-space":/);
      assert.jsonFileContent('other/package.json', {
        eslintConfig: {
          extends: 'xo-space'
        }
      });
    });
  });
});
<commit_msg>Fix test<commit_after>'use strict';
var path = require('path');
var assert = require('yeoman-assert');
var helpers = require('yeoman-test');

describe('node:eslint', function () {
  before(function (done) {
    helpers.run(path.join(__dirname, '../generators/eslint'))
      .on('end', done);
  });

  it('fill package.json', function () {
    assert.fileContent('package.json', /"eslint-config-xo-space":/);
    assert.jsonFileContent('package.json', {
      eslintConfig: {
        extends: 'xo-space',
        env: {
          mocha: true
        }
      }
    });
  });

  describe('--es2015', function () {
    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/eslint'))
        .withOptions({es2015: true})
        .on('end', done);
    });

    it('fill package.json for ES2015', function () {
      assert.fileContent('package.json', /"babel-eslint":/);
      assert.fileContent('package.json', /"eslint-plugin-babel":/);
    });
  });

  describe('--generate-into', function () {
    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/eslint'))
        .withOptions({generateInto: 'other/'})
        .on('end', done);
    });

    it('fill env .eslintrc with generate-into option', function () {
      assert.fileContent('other/package.json', /"eslint-config-xo-space":/);
      assert.jsonFileContent('other/package.json', {
        eslintConfig: {
          extends: 'xo-space'
        }
      });
    });
  });
});
<|endoftext|>


<commit_before>import DS from "ember-data";

import ENV from '../config/environment';

export default DS.RESTAdapter.extend({
  host: ENV.APP.API_HOST,
  namespace: 'api'
});
<commit_msg>Add comment<commit_after>import DS from "ember-data";

import ENV from '../config/environment';

export default DS.RESTAdapter.extend({
  // host: "http://localhost:8888",
  host: ENV.APP.API_HOST,
  namespace: 'api'
});
<|endoftext|>


<commit_before>'use strict';

var net = require('net');

/**
 * Create new HA proxy mock server.
 *
 * @param {Object} options
 * @api public
 */
exports.createServer = function createServer(options) {
  return new Hamock(options || {});
};

/**
 * A HAProxy unix-socket mockup server.
 *
 * @constructor
 * @param {Object} options
 * @api private
 */
function Hamock(options) {
  this.server = options.server || net.createServer();
  this.server.on('connection', this.handle.bind(this));
  this.commands = options.commands || require('./fixtures');
  this.sockets = [];
}

/**
 * Handles requests.
 *
 * @param {Socket} socket TCP socket of the connection.
 * @api private
 */
Hamock.prototype.handle = function handle(socket) {
  this.sockets.push(socket);

  var command = '';
  socket.setEncoding('utf-8');

  socket.on('data', function data(buffer) {
    command += buffer;
  }).on('end', function end() {
    var handler = command.trim()
      , data = this.commands[handler];

    socket.end(data || 'Unkown command');
  }.bind(this));

  socket.once('close', function close() {
    this.sockets.splice(this.sockets.indexOf(socket), 1);
  }.bind(this));
};

/**
 * Start listening on a something. Accepts what ever a plain net.Server accepts.
 *
 * @param {String} path Location of the socket;
 * @param {Function} fn Callback function
 * @api public
 */
Hamock.prototype.listen = function listen(path, fn) {
  if ('function' === typeof path) {
    fn = path;
    path = null;
  }

  this.server(path || '/tmp/haproxy.sock', fn);
  return this;
};

/**
 * Closes the server and kills all the connections.
 *
 * @param {Function} fn Callback when everthing is cleaned.
 * @api public
 */
Hamock.prototype.close = function close(fn) {
  this.sockets.forEach(function each(socket) {
    socket.end();

    if (socket.unref) socket.unref();
  });

  this.server.close(fn);
  return this;
};
<commit_msg>[fix] Automatically unlink the socket or we will EADDRINSUE [fix] Allow half open sockets.<commit_after>'use strict';

var net = require('net')
  , fs = require('fs');

/**
 * Create new HA proxy mock server.
 *
 * @param {Object} options
 * @api public
 */
exports.createServer = function createServer(options) {
  return new Hamock(options || {});
};

/**
 * A HAProxy unix-socket mockup server.
 *
 * @constructor
 * @param {Object} options
 * @api private
 */
function Hamock(options) {
  this.server = options.server || net.createServer({ allowHalfOpen: true });
  this.server.on('connection', this.handle.bind(this));
  this.commands = options.commands || require('./fixtures');
  this.socket = '/tmp/haproxy.sock';
  this.sockets = [];
}

/**
 * Handles requests.
 *
 * @param {Socket} socket TCP socket of the connection.
 * @api private
 */
Hamock.prototype.handle = function handle(socket) {
  this.sockets.push(socket);

  var command = '';
  socket.setEncoding('utf-8');

  socket.on('data', function data(buffer) {
    command += buffer;
  }).on('end', function end() {
    var handler = command.trim()
      , data = this.commands[handler];

    socket.end(data || 'Unkown command');
  }.bind(this));

  socket.once('close', function close() {
    this.sockets.splice(this.sockets.indexOf(socket), 1);
  }.bind(this));
};

/**
 * Start listening on a something. Accepts what ever a plain net.Server accepts.
 *
 * @param {String} path Location of the socket;
 * @param {Function} fn Callback function
 * @api public
 */
Hamock.prototype.listen = function listen(path, fn) {
  if ('function' === typeof path) {
    fn = path;
    path = null;
  }

  if (path) this.socket = path;

  fs.unlinkSync(this.socket);
  this.server.listen(this.socket, fn);
  return this;
};

/**
 * Closes the server and kills all the connections.
 *
 * @param {Function} fn Callback when everthing is cleaned.
 * @api public
 */
Hamock.prototype.close = function close(fn) {
  this.sockets.forEach(function each(socket) {
    socket.end();

    if (socket.unref) socket.unref();
  });

  this.server.close(function closed() {
    fs.unlinkSync(this.socket);

    if (fn) fn.apply(fn, arguments);
  }.bind(this));

  return this;
};
<|endoftext|>


<commit_before>
import Scalar     from "./Scalar.jsx";
import Table      from "./Table.jsx";
import LineChart  from "./LineChart.jsx";
import BarChart   from "./BarChart.jsx";
import PieChart   from "./PieChart.jsx";
import AreaChart  from "./AreaChart.jsx";
import USStateMap from "./USStateMap.jsx";
import WorldMap   from "./WorldMap.jsx";
import PinMap     from "./PinMap.jsx";

class MapDefault extends Map {
    constructor(_default, ...args) {
        super(...args);
        this._default = _default;
    }
    get(key) {
        if (this.has(key)) {
            return super.get(key);
        } else {
            return this._default;
        }
    }
}

const visualizations = new MapDefault(Table);

export function registerVisualization(visualization) {
    let identifier = visualization.identifier;
    if (identifier == null) {
        throw new Error("Visualization must define an 'identifier' static variable: " + visualization.name);
    }
    if (visualizations.has(identifier)) {
        throw new Error("Visualization with that identifier is already registered: " + visualization.name);
    }
    visualizations.set(identifier, visualization);
}

registerVisualization(Scalar);
registerVisualization(Table);
registerVisualization(LineChart);
registerVisualization(BarChart);
registerVisualization(PieChart);
registerVisualization(AreaChart);
registerVisualization(USStateMap);
registerVisualization(WorldMap);
registerVisualization(PinMap);

export default visualizations;
<commit_msg>Fix Safari<commit_after>
import Scalar     from "./Scalar.jsx";
import Table      from "./Table.jsx";
import LineChart  from "./LineChart.jsx";
import BarChart   from "./BarChart.jsx";
import PieChart   from "./PieChart.jsx";
import AreaChart  from "./AreaChart.jsx";
import USStateMap from "./USStateMap.jsx";
import WorldMap   from "./WorldMap.jsx";
import PinMap     from "./PinMap.jsx";

const visualizations = new Map();
visualizations.get = function(key) {
    return Map.prototype.get.call(this, key) || Table;
}

export function registerVisualization(visualization) {
    let identifier = visualization.identifier;
    if (identifier == null) {
        throw new Error("Visualization must define an 'identifier' static variable: " + visualization.name);
    }
    if (visualizations.has(identifier)) {
        throw new Error("Visualization with that identifier is already registered: " + visualization.name);
    }
    visualizations.set(identifier, visualization);
}

registerVisualization(Scalar);
registerVisualization(Table);
registerVisualization(LineChart);
registerVisualization(BarChart);
registerVisualization(PieChart);
registerVisualization(AreaChart);
registerVisualization(USStateMap);
registerVisualization(WorldMap);
registerVisualization(PinMap);

export default visualizations;
<|endoftext|>


<commit_before>var base        = require('taskcluster-base');
var data        = require('../hooks/data');
var taskcluster = require('taskcluster-client');
var taskcreator = require('../hooks/taskcreator');
var v1          = require('../routes/v1');
var load        = require('../bin/main');
var config      = require('typed-env-config');
var _           = require('lodash');

var loadOptions = {profile: 'test', process: 'test-helper'};
var cfg = config({profile: 'test'});

var defaultClients = [
  {
    // Loaded from config so we can authenticated against the real queue
    // Note that we still use a mock auth server to avoid having the scope
    // hooks:* assigned to our test client
    clientId:     cfg.taskcluster.credentials.clientId,
    accessToken:  cfg.taskcluster.credentials.accessToken,
    scopes:       ['hooks:*', 'auth:*'],
    expires:      new Date(3000, 0, 0, 0, 0, 0, 0)
  }, {
    clientId:     'test-client',  // Used in default Hooks client creation
    accessToken:  'none',
    scopes:       ['*'],
    expires:      new Date(3000, 0, 0, 0, 0, 0, 0)
  }
];

var helper = module.exports = {};

helper.hasTcCredentials = cfg.taskcluster.credentials.accessToken;

// Call this in suites or tests that make API calls; it will set up
// what's required to respond to those calls.  But note that this
// requires credentials (taskcluster-hooks.conf.json); returns false
// if those credentials are not available.
helper.setupApi = function() {
  if (!helper.hasTcCredentials) {
    return false;
  }

  // Hold reference to authServer
  var authServer = null;
  var webServer = null;

  // Setup before tests
  suiteSetup(async () => {
    // Create mock authentication server
    authServer = await base.testing.createMockAuthServer({
      port: 60407,
      clients:  defaultClients,
      credentials: cfg.taskcluster.credentials
    });

    // Create Hooks table
    helper.Hook = await load('Hook', loadOptions);

    // Remove all entities before each test
    await helper.Hook.scan({}, {handler: hook => hook.remove()});

    helper.creator = new taskcreator.MockTaskCreator()
    webServer = await load('server', _.defaults({
      Hook: helper.Hook,
      taskcreator: helper.creator,
    }, loadOptions));

    // Create client for working with API
    helper.baseUrl = 'http://localhost:' + webServer.address().port + '/v1';
    var reference = v1.reference({baseUrl: helper.baseUrl});
    helper.Hooks = taskcluster.createClient(reference);
    // Utility to create an Hooks instance with limited scopes
    helper.scopes = (...scopes) => {
      helper.hooks = new helper.Hooks({
        // Ensure that we use global agent, to avoid problems with keepAlive
        // preventing tests from exiting
        agent:            require('http').globalAgent,
        baseUrl:          helper.baseUrl,
        credentials: {
          clientId:       'test-client',
          accessToken:    'none'
        },
        //authBaseUrl: cfg.get('taskcluster:authBaseUrl'),
        authorizedScopes: (scopes.length > 0 ? scopes : undefined)
      });
    };

    // Initialize queue client
    helper.scopes();
  });

  // Setup before each test
  setup(async () => {
    // Remove all entities before each test
    await helper.Hook.scan({}, {handler: hook => hook.remove()});

    // reset the list of fired tasks
    helper.creator.fireCalls = [];

    // Setup client with all scopes
    helper.scopes();
  });

  // Cleanup after tests
  suiteTeardown(async () => {
    // Kill webServer
    await webServer.terminate();
    await authServer.terminate();
  });

  return true;
};

<commit_msg>Small fix for intermittent timeout bug (in testing)<commit_after>var base        = require('taskcluster-base');
var data        = require('../hooks/data');
var taskcluster = require('taskcluster-client');
var taskcreator = require('../hooks/taskcreator');
var v1          = require('../routes/v1');
var load        = require('../bin/main');
var config      = require('typed-env-config');
var _           = require('lodash');

var loadOptions = {profile: 'test', process: 'test-helper'};
var cfg = config({profile: 'test'});

var defaultClients = [
  {
    // Loaded from config so we can authenticated against the real queue
    // Note that we still use a mock auth server to avoid having the scope
    // hooks:* assigned to our test client
    clientId:     cfg.taskcluster.credentials.clientId,
    accessToken:  cfg.taskcluster.credentials.accessToken,
    scopes:       ['hooks:*', 'auth:*'],
    expires:      new Date(3000, 0, 0, 0, 0, 0, 0)
  }, {
    clientId:     'test-client',  // Used in default Hooks client creation
    accessToken:  'none',
    scopes:       ['*'],
    expires:      new Date(3000, 0, 0, 0, 0, 0, 0)
  }
];

var helper = module.exports = {};

helper.hasTcCredentials = cfg.taskcluster.credentials.accessToken;

// Call this in suites or tests that make API calls; it will set up
// what's required to respond to those calls.  But note that this
// requires credentials (taskcluster-hooks.conf.json); returns false
// if those credentials are not available.
helper.setupApi = function() {
  if (!helper.hasTcCredentials) {
    return false;
  }

  // Hold reference to authServer
  var authServer = null;
  var webServer = null;

  // Setup before tests
  suiteSetup(async () => {
    // Create mock authentication server
    authServer = await base.testing.createMockAuthServer({
      port: 60407,
      clients:  defaultClients,
      credentials: cfg.taskcluster.credentials
    });
    // 500ms as coded into tc-base doesn't work, this need to live here until we
    // land a fix in tc-base (currently not brave enough to upgrade tc-base)
    authServer.setTimeout(30 * 1000);

    // Create Hooks table
    helper.Hook = await load('Hook', loadOptions);

    // Remove all entities before each test
    await helper.Hook.scan({}, {handler: hook => hook.remove()});

    helper.creator = new taskcreator.MockTaskCreator()
    webServer = await load('server', _.defaults({
      Hook: helper.Hook,
      taskcreator: helper.creator,
    }, loadOptions));

    // Create client for working with API
    helper.baseUrl = 'http://localhost:' + webServer.address().port + '/v1';
    var reference = v1.reference({baseUrl: helper.baseUrl});
    helper.Hooks = taskcluster.createClient(reference);
    // Utility to create an Hooks instance with limited scopes
    helper.scopes = (...scopes) => {
      helper.hooks = new helper.Hooks({
        // Ensure that we use global agent, to avoid problems with keepAlive
        // preventing tests from exiting
        agent:            require('http').globalAgent,
        baseUrl:          helper.baseUrl,
        credentials: {
          clientId:       'test-client',
          accessToken:    'none'
        },
        //authBaseUrl: cfg.get('taskcluster:authBaseUrl'),
        authorizedScopes: (scopes.length > 0 ? scopes : undefined)
      });
    };

    // Initialize queue client
    helper.scopes();
  });

  // Setup before each test
  setup(async () => {
    // Remove all entities before each test
    await helper.Hook.scan({}, {handler: hook => hook.remove()});

    // reset the list of fired tasks
    helper.creator.fireCalls = [];

    // Setup client with all scopes
    helper.scopes();
  });

  // Cleanup after tests
  suiteTeardown(async () => {
    // Kill webServer
    await webServer.terminate();
    await authServer.terminate();
  });

  return true;
};

<|endoftext|>