<commit_before>
openerp.web.formats = function(instance) {
var _t = instance.web._t;

/**
 * Intersperses ``separator`` in ``str`` at the positions indicated by
 * ``indices``.
 *
 * ``indices`` is an array of relative offsets (from the previous insertion
 * position, starting from the end of the string) at which to insert
 * ``separator``.
 *
 * There are two special values:
 *
 * ``-1``
 *   indicates the insertion should end now
 * ``0``
 *   indicates that the previous section pattern should be repeated (until all
 *   of ``str`` is consumed)
 *
 * @param {String} str
 * @param {Array<Number>} indices
 * @param {String} separator
 * @returns {String}
 */
instance.web.intersperse = function (str, indices, separator) {
    separator = separator || '';
    var result = [], last = str.length;

    for(var i=0; i<indices.length; ++i) {
        var section = indices[i];
        if (section === -1 || last <= 0) {
            // Done with string, or -1 (stops formatting string)
            break;
        } else if(section === 0 && i === 0) {
            // repeats previous section, which there is none => stop
            break;
        } else if (section === 0) {
            // repeat previous section forever
            //noinspection AssignmentToForLoopParameterJS
            section = indices[--i];
        }
        result.push(str.substring(last-section, last));
        last -= section;
    }

    var s = str.substring(0, last);
    if (s) { result.push(s); }
    return result.reverse().join(separator);
};
/**
 * Insert "thousands" separators in the provided number (which is actually
 * a string)
 *
 * @param {String} num
 * @returns {String}
 */
instance.web.insert_thousand_seps = function (num) {
    var negative = num[0] === '-';
    num = (negative ? num.slice(1) : num);
    return (negative ? '-' : '') + instance.web.intersperse(
        num, _t.database.parameters.grouping, _t.database.parameters.thousands_sep);
};

/**
 * removes literal (non-format) text from a date or time pattern, as datejs can
 * not deal with literal text in format strings (whatever the format), whereas
 * strftime allows for literal characters
 *
 * @param {String} value original format
 */
instance.web.strip_raw_chars = function (value) {
    var isletter = /[a-zA-Z]/, output = [];
    for(var index=0; index < value.length; ++index) {
        var character = value[index];
        if(isletter.test(character) && (index === 0 || value[index-1] !== '%')) {
            continue;
        }
        output.push(character);
    }
    return output.join('');
};
var normalize_format = function (format) {
    return Date.normalizeFormat(instance.web.strip_raw_chars(format));
};
/**
 * Formats a single atomic value based on a field descriptor
 *
 * @param {Object} value read from OpenERP
 * @param {Object} descriptor union of orm field and view field
 * @param {Object} [descriptor.widget] widget to use to display the value
 * @param {Object} descriptor.type fallback if no widget is provided, or if the provided widget is unknown
 * @param {Object} [descriptor.digits] used for the formatting of floats
 * @param {String} [value_if_empty=''] returned if the ``value`` argument is considered empty
 */
instance.web.format_value = function (value, descriptor, value_if_empty) {
    // If NaN value, display as with a `false` (empty cell)
    if (typeof value === 'number' && isNaN(value)) {
        value = false;
    }
    //noinspection FallthroughInSwitchStatementJS
    switch (value) {
        case '':
            if (descriptor.type === 'char') {
                return '';
            }
            console.warn('Field', descriptor, 'had an empty string as value, treating as false...');
        case false:
        case Infinity:
        case -Infinity:
            return value_if_empty === undefined ?  '' : value_if_empty;
    }
    var l10n = _t.database.parameters;
    switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) {
        case 'id':
            return value.toString();
        case 'integer':
            return instance.web.insert_thousand_seps(
                _.str.sprintf('%d', value));
        case 'float':
            var precision = descriptor.digits ? descriptor.digits[1] : 2;
            var formatted = _.str.sprintf('%.' + precision + 'f', value).split('.');
            formatted[0] = instance.web.insert_thousand_seps(formatted[0]);
            return formatted.join(l10n.decimal_point);
        case 'float_time':
            var pattern = '%02d:%02d';
            if (value < 0) {
                value = Math.abs(value);
                pattern = '-' + pattern;
            }
            return _.str.sprintf(pattern,
                    Math.floor(value),
                    Math.round((value % 1) * 60));
        case 'many2one':
            // name_get value format
            return value[1];
        case 'datetime':
            if (typeof(value) == "string")
                value = instance.web.auto_str_to_date(value);

            return value.toString(normalize_format(l10n.date_format)
                        + ' ' + normalize_format(l10n.time_format));
        case 'date':
            if (typeof(value) == "string")
                value = instance.web.auto_str_to_date(value);
            return value.toString(normalize_format(l10n.date_format));
        case 'time':
            if (typeof(value) == "string")
                value = instance.web.auto_str_to_date(value);
            return value.toString(normalize_format(l10n.time_format));
        case 'selection': case 'statusbar':
            // Each choice is [value, label]
            if(_.isArray(value)) {
                 value = value[0]
            }
            var result = _(descriptor.selection).detect(function (choice) {
                return choice[0] === value;
            });
            if (result) { return result[1]; }
            return;
        default:
            return value;
    }
};

instance.web.parse_value = function (value, descriptor, value_if_empty) {
    var date_pattern = normalize_format(_t.database.parameters.date_format),
        time_pattern = normalize_format(_t.database.parameters.time_format);
    switch (value) {
        case false:
        case "":
            return value_if_empty === undefined ?  false : value_if_empty;
    }
    switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) {
        case 'integer':
            var tmp;
            do {
                tmp = value;
                value = value.replace(instance.web._t.database.parameters.thousands_sep, "");
            } while(tmp !== value);
            tmp = Number(value);
            if (isNaN(tmp))
                throw new Error(value + " is not a correct integer");
            return tmp;
        case 'float':
            var tmp = Number(value);
            if (!isNaN(tmp))
                return tmp;

            var tmp2 = value;
            do {
                tmp = tmp2;
                tmp2 = tmp.replace(instance.web._t.database.parameters.thousands_sep, "");
            } while(tmp !== tmp2);
            var reformatted_value = tmp.replace(instance.web._t.database.parameters.decimal_point, ".");
            var parsed = Number(reformatted_value);
            if (isNaN(parsed))
                throw new Error(value + " is not a correct float");
            return parsed;
        case 'float_time':
            var factor = 1;
            if (value[0] === '-') {
                value = value.slice(1);
                factor = -1;
            }
            var float_time_pair = value.split(":");
            if (float_time_pair.length != 2)
                return factor * instance.web.parse_value(value, {type: "float"});
            var hours = instance.web.parse_value(float_time_pair[0], {type: "integer"});
            var minutes = instance.web.parse_value(float_time_pair[1], {type: "integer"});
            return factor * (hours + (minutes / 60));
        case 'progressbar':
            return instance.web.parse_value(value, {type: "float"});
        case 'datetime':
            var datetime = Date.parseExact(
                    value, (date_pattern + ' ' + time_pattern));
            if (datetime !== null)
                return instance.web.datetime_to_str(datetime);
            datetime = Date.parse(value);
            if (datetime !== null)
                return instance.web.datetime_to_str(datetime);
            throw new Error(value + " is not a valid datetime");
        case 'date':
            var date = Date.parseExact(value, date_pattern);
            if (date !== null)
                return instance.web.date_to_str(date);
            date = Date.parse(value);
            if (date !== null)
                return instance.web.date_to_str(date);
            throw new Error(value + " is not a valid date");
        case 'time':
            var time = Date.parseExact(value, time_pattern);
            if (time !== null)
                return instance.web.time_to_str(time);
            time = Date.parse(value);
            if (time !== null)
                return instance.web.time_to_str(time);
            throw new Error(value + " is not a valid time");
    }
    return value;
};

instance.web.auto_str_to_date = function(value, type) {
    try {
        return instance.web.str_to_datetime(value);
    } catch(e) {}
    try {
        return instance.web.str_to_date(value);
    } catch(e) {}
    try {
        return instance.web.str_to_time(value);
    } catch(e) {}
    throw new Error("'" + value + "' is not a valid date, datetime nor time");
};

instance.web.auto_date_to_str = function(value, type) {
    switch(type) {
        case 'datetime':
            return instance.web.datetime_to_str(value);
        case 'date':
            return instance.web.date_to_str(value);
        case 'time':
            return instance.web.time_to_str(value);
        default:
            throw new Error(type + " is not convertible to date, datetime nor time");
    }
};

/**
 * Formats a provided cell based on its field type. Most of the field types
 * return a correctly formatted value, but some tags and fields are
 * special-cased in their handling:
 *
 * * buttons will return an actual ``<button>`` tag with a bunch of error handling
 *
 * * boolean fields will return a checkbox input, potentially disabled
 *
 * * binary fields will return a link to download the binary data as a file
 *
 * @param {Object} row_data record whose values should be displayed in the cell
 * @param {Object} column column descriptor
 * @param {"button"|"field"} column.tag base control type
 * @param {String} column.type widget type for a field control
 * @param {String} [column.string] button label
 * @param {String} [column.icon] button icon
 * @param {Object} [options]
 * @param {String} [options.value_if_empty=''] what to display if the field's value is ``false``
 * @param {Boolean} [options.process_modifiers=true] should the modifiers be computed ?
 * @param {String} [options.model] current record's model
 * @param {Number} [options.id] current record's id
 *
 */
instance.web.format_cell = function (row_data, column, options) {
    options = options || {};
    var attrs = {};
    if (options.process_modifiers !== false) {
        attrs = column.modifiers_for(row_data);
    }
    if (attrs.invisible) { return ''; }

    if (column.tag === 'button') {
        return _.template('<button type="button" title="<%-title%>" <%=additional_attributes%> >' +
            '<img src="<%-prefix%>/web/static/src/img/icons/<%-icon%>.png" alt="<%-alt%>"/>' +
            '</button>', {
                title: column.string || '',
                additional_attributes: isNaN(row_data["id"].value) && instance.web.BufferedDataSet.virtual_id_regex.test(row_data["id"].value) ?
                    'disabled="disabled" class="oe-listview-button-disabled"' : '',
                prefix: instance.connection.prefix,
                icon: column.icon,
                alt: column.string || ''
            });
    }
    if (!row_data[column.id]) {
        return options.value_if_empty === undefined ? '' : options.value_if_empty;
    }

    switch (column.widget || column.type) {
    case "boolean":
        return _.str.sprintf('<input type="checkbox" %s disabled="disabled"/>',
                 row_data[column.id].value ? 'checked="checked"' : '');
    case "binary":
        var text = _t("Download"),
            download_url = _.str.sprintf('/web/binary/saveas?session_id=%s&model=%s&field=%s&id=%d', instance.connection.session_id, options.model, column.id, options.id);
        if (column.filename) {
            download_url += '&filename_field=' + column.filename;
            if (row_data[column.filename]) {
                text = _.str.sprintf(_t("Download \"%s\""), instance.web.format_value(
                        row_data[column.filename].value, {type: 'char'}));
            }
        }
        return _.template('<a href="<%-href%>"><%-text%> (%<-size%>)', {
            text: text,
            href: download_url,
            size: row_data[column.id].value
        });
    case 'progressbar':
        return _.template(
            '<progress value="<%-value%>" max="100"><%-value%>%</progress>', {
                value: _.str.sprintf("%.0f", row_data[column.id].value || 0)
            });
    }

    return _.escape(instance.web.format_value(
            row_data[column.id].value, column, options.value_if_empty));
}

};
<commit_msg>[IMP] formatting of o2m and m2m fields in list views, courtesy of William Beltrán<commit_after>
openerp.web.formats = function(instance) {
var _t = instance.web._t;

/**
 * Intersperses ``separator`` in ``str`` at the positions indicated by
 * ``indices``.
 *
 * ``indices`` is an array of relative offsets (from the previous insertion
 * position, starting from the end of the string) at which to insert
 * ``separator``.
 *
 * There are two special values:
 *
 * ``-1``
 *   indicates the insertion should end now
 * ``0``
 *   indicates that the previous section pattern should be repeated (until all
 *   of ``str`` is consumed)
 *
 * @param {String} str
 * @param {Array<Number>} indices
 * @param {String} separator
 * @returns {String}
 */
instance.web.intersperse = function (str, indices, separator) {
    separator = separator || '';
    var result = [], last = str.length;

    for(var i=0; i<indices.length; ++i) {
        var section = indices[i];
        if (section === -1 || last <= 0) {
            // Done with string, or -1 (stops formatting string)
            break;
        } else if(section === 0 && i === 0) {
            // repeats previous section, which there is none => stop
            break;
        } else if (section === 0) {
            // repeat previous section forever
            //noinspection AssignmentToForLoopParameterJS
            section = indices[--i];
        }
        result.push(str.substring(last-section, last));
        last -= section;
    }

    var s = str.substring(0, last);
    if (s) { result.push(s); }
    return result.reverse().join(separator);
};
/**
 * Insert "thousands" separators in the provided number (which is actually
 * a string)
 *
 * @param {String} num
 * @returns {String}
 */
instance.web.insert_thousand_seps = function (num) {
    var negative = num[0] === '-';
    num = (negative ? num.slice(1) : num);
    return (negative ? '-' : '') + instance.web.intersperse(
        num, _t.database.parameters.grouping, _t.database.parameters.thousands_sep);
};

/**
 * removes literal (non-format) text from a date or time pattern, as datejs can
 * not deal with literal text in format strings (whatever the format), whereas
 * strftime allows for literal characters
 *
 * @param {String} value original format
 */
instance.web.strip_raw_chars = function (value) {
    var isletter = /[a-zA-Z]/, output = [];
    for(var index=0; index < value.length; ++index) {
        var character = value[index];
        if(isletter.test(character) && (index === 0 || value[index-1] !== '%')) {
            continue;
        }
        output.push(character);
    }
    return output.join('');
};
var normalize_format = function (format) {
    return Date.normalizeFormat(instance.web.strip_raw_chars(format));
};
/**
 * Formats a single atomic value based on a field descriptor
 *
 * @param {Object} value read from OpenERP
 * @param {Object} descriptor union of orm field and view field
 * @param {Object} [descriptor.widget] widget to use to display the value
 * @param {Object} descriptor.type fallback if no widget is provided, or if the provided widget is unknown
 * @param {Object} [descriptor.digits] used for the formatting of floats
 * @param {String} [value_if_empty=''] returned if the ``value`` argument is considered empty
 */
instance.web.format_value = function (value, descriptor, value_if_empty) {
    // If NaN value, display as with a `false` (empty cell)
    if (typeof value === 'number' && isNaN(value)) {
        value = false;
    }
    //noinspection FallthroughInSwitchStatementJS
    switch (value) {
        case '':
            if (descriptor.type === 'char') {
                return '';
            }
            console.warn('Field', descriptor, 'had an empty string as value, treating as false...');
        case false:
        case Infinity:
        case -Infinity:
            return value_if_empty === undefined ?  '' : value_if_empty;
    }
    var l10n = _t.database.parameters;
    switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) {
        case 'id':
            return value.toString();
        case 'integer':
            return instance.web.insert_thousand_seps(
                _.str.sprintf('%d', value));
        case 'float':
            var precision = descriptor.digits ? descriptor.digits[1] : 2;
            var formatted = _.str.sprintf('%.' + precision + 'f', value).split('.');
            formatted[0] = instance.web.insert_thousand_seps(formatted[0]);
            return formatted.join(l10n.decimal_point);
        case 'float_time':
            var pattern = '%02d:%02d';
            if (value < 0) {
                value = Math.abs(value);
                pattern = '-' + pattern;
            }
            return _.str.sprintf(pattern,
                    Math.floor(value),
                    Math.round((value % 1) * 60));
        case 'many2one':
            // name_get value format
            return value[1];
        case 'one2many':
        case 'many2many':
            return _.str.sprintf(_t("(%d records)"), value.length);
        case 'datetime':
            if (typeof(value) == "string")
                value = instance.web.auto_str_to_date(value);

            return value.toString(normalize_format(l10n.date_format)
                        + ' ' + normalize_format(l10n.time_format));
        case 'date':
            if (typeof(value) == "string")
                value = instance.web.auto_str_to_date(value);
            return value.toString(normalize_format(l10n.date_format));
        case 'time':
            if (typeof(value) == "string")
                value = instance.web.auto_str_to_date(value);
            return value.toString(normalize_format(l10n.time_format));
        case 'selection': case 'statusbar':
            // Each choice is [value, label]
            if(_.isArray(value)) {
                 value = value[0]
            }
            var result = _(descriptor.selection).detect(function (choice) {
                return choice[0] === value;
            });
            if (result) { return result[1]; }
            return;
        default:
            return value;
    }
};

instance.web.parse_value = function (value, descriptor, value_if_empty) {
    var date_pattern = normalize_format(_t.database.parameters.date_format),
        time_pattern = normalize_format(_t.database.parameters.time_format);
    switch (value) {
        case false:
        case "":
            return value_if_empty === undefined ?  false : value_if_empty;
    }
    switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) {
        case 'integer':
            var tmp;
            do {
                tmp = value;
                value = value.replace(instance.web._t.database.parameters.thousands_sep, "");
            } while(tmp !== value);
            tmp = Number(value);
            if (isNaN(tmp))
                throw new Error(value + " is not a correct integer");
            return tmp;
        case 'float':
            var tmp = Number(value);
            if (!isNaN(tmp))
                return tmp;

            var tmp2 = value;
            do {
                tmp = tmp2;
                tmp2 = tmp.replace(instance.web._t.database.parameters.thousands_sep, "");
            } while(tmp !== tmp2);
            var reformatted_value = tmp.replace(instance.web._t.database.parameters.decimal_point, ".");
            var parsed = Number(reformatted_value);
            if (isNaN(parsed))
                throw new Error(value + " is not a correct float");
            return parsed;
        case 'float_time':
            var factor = 1;
            if (value[0] === '-') {
                value = value.slice(1);
                factor = -1;
            }
            var float_time_pair = value.split(":");
            if (float_time_pair.length != 2)
                return factor * instance.web.parse_value(value, {type: "float"});
            var hours = instance.web.parse_value(float_time_pair[0], {type: "integer"});
            var minutes = instance.web.parse_value(float_time_pair[1], {type: "integer"});
            return factor * (hours + (minutes / 60));
        case 'progressbar':
            return instance.web.parse_value(value, {type: "float"});
        case 'datetime':
            var datetime = Date.parseExact(
                    value, (date_pattern + ' ' + time_pattern));
            if (datetime !== null)
                return instance.web.datetime_to_str(datetime);
            datetime = Date.parse(value);
            if (datetime !== null)
                return instance.web.datetime_to_str(datetime);
            throw new Error(value + " is not a valid datetime");
        case 'date':
            var date = Date.parseExact(value, date_pattern);
            if (date !== null)
                return instance.web.date_to_str(date);
            date = Date.parse(value);
            if (date !== null)
                return instance.web.date_to_str(date);
            throw new Error(value + " is not a valid date");
        case 'time':
            var time = Date.parseExact(value, time_pattern);
            if (time !== null)
                return instance.web.time_to_str(time);
            time = Date.parse(value);
            if (time !== null)
                return instance.web.time_to_str(time);
            throw new Error(value + " is not a valid time");
    }
    return value;
};

instance.web.auto_str_to_date = function(value, type) {
    try {
        return instance.web.str_to_datetime(value);
    } catch(e) {}
    try {
        return instance.web.str_to_date(value);
    } catch(e) {}
    try {
        return instance.web.str_to_time(value);
    } catch(e) {}
    throw new Error("'" + value + "' is not a valid date, datetime nor time");
};

instance.web.auto_date_to_str = function(value, type) {
    switch(type) {
        case 'datetime':
            return instance.web.datetime_to_str(value);
        case 'date':
            return instance.web.date_to_str(value);
        case 'time':
            return instance.web.time_to_str(value);
        default:
            throw new Error(type + " is not convertible to date, datetime nor time");
    }
};

/**
 * Formats a provided cell based on its field type. Most of the field types
 * return a correctly formatted value, but some tags and fields are
 * special-cased in their handling:
 *
 * * buttons will return an actual ``<button>`` tag with a bunch of error handling
 *
 * * boolean fields will return a checkbox input, potentially disabled
 *
 * * binary fields will return a link to download the binary data as a file
 *
 * @param {Object} row_data record whose values should be displayed in the cell
 * @param {Object} column column descriptor
 * @param {"button"|"field"} column.tag base control type
 * @param {String} column.type widget type for a field control
 * @param {String} [column.string] button label
 * @param {String} [column.icon] button icon
 * @param {Object} [options]
 * @param {String} [options.value_if_empty=''] what to display if the field's value is ``false``
 * @param {Boolean} [options.process_modifiers=true] should the modifiers be computed ?
 * @param {String} [options.model] current record's model
 * @param {Number} [options.id] current record's id
 *
 */
instance.web.format_cell = function (row_data, column, options) {
    options = options || {};
    var attrs = {};
    if (options.process_modifiers !== false) {
        attrs = column.modifiers_for(row_data);
    }
    if (attrs.invisible) { return ''; }

    if (column.tag === 'button') {
        return _.template('<button type="button" title="<%-title%>" <%=additional_attributes%> >' +
            '<img src="<%-prefix%>/web/static/src/img/icons/<%-icon%>.png" alt="<%-alt%>"/>' +
            '</button>', {
                title: column.string || '',
                additional_attributes: isNaN(row_data["id"].value) && instance.web.BufferedDataSet.virtual_id_regex.test(row_data["id"].value) ?
                    'disabled="disabled" class="oe-listview-button-disabled"' : '',
                prefix: instance.connection.prefix,
                icon: column.icon,
                alt: column.string || ''
            });
    }
    if (!row_data[column.id]) {
        return options.value_if_empty === undefined ? '' : options.value_if_empty;
    }

    switch (column.widget || column.type) {
    case "boolean":
        return _.str.sprintf('<input type="checkbox" %s disabled="disabled"/>',
                 row_data[column.id].value ? 'checked="checked"' : '');
    case "binary":
        var text = _t("Download"),
            download_url = _.str.sprintf('/web/binary/saveas?session_id=%s&model=%s&field=%s&id=%d', instance.connection.session_id, options.model, column.id, options.id);
        if (column.filename) {
            download_url += '&filename_field=' + column.filename;
            if (row_data[column.filename]) {
                text = _.str.sprintf(_t("Download \"%s\""), instance.web.format_value(
                        row_data[column.filename].value, {type: 'char'}));
            }
        }
        return _.template('<a href="<%-href%>"><%-text%> (%<-size%>)', {
            text: text,
            href: download_url,
            size: row_data[column.id].value
        });
    case 'progressbar':
        return _.template(
            '<progress value="<%-value%>" max="100"><%-value%>%</progress>', {
                value: _.str.sprintf("%.0f", row_data[column.id].value || 0)
            });
    }

    return _.escape(instance.web.format_value(
            row_data[column.id].value, column, options.value_if_empty));
}

};
<|endoftext|>


<commit_before>// uglify-save-license.js v0.2.3
// Copyright (c) 2013 - 2014 Shinnosuke Watanabe
// Licensed uder the MIT license

'use strict';

// regexp to determine whether the comment looks like license text.
var licenseRegexp = /^\!|^@preserve|^@cc_on|\bMIT\b|\bMPL\b|\bGPL\b|\bBSD\b|\(c\)|License|Copyright/mi;

// number of line where license comment appeared last
var prevCommentLine = 0;
// name of the file minified last
var prevFile = '';

module.exports = function saveLicense(node, comment) {
  if (comment.file !== prevFile) {
    prevCommentLine = 0;
  }

  // check if the comment contains license text
  var result = licenseRegexp.test(comment.value) ||
               comment.line === 1 ||
               comment.line === prevCommentLine + 1;

  if (result) {
    // if the comment contains license, save line number
    prevCommentLine = comment.line;
  } else {
    // if the comment doesn't contain license, reset line number
    prevCommentLine = 0;
  }

  // save current filename
  prevFile = comment.file;

  return result;
};
<commit_msg>support ISC license<commit_after>// uglify-save-license.js v0.3.0
// Copyright (c) 2013 - 2014 Shinnosuke Watanabe
// Licensed uder the MIT license

'use strict';

// regexp to determine whether the comment looks like license text.
var licenseRegexp = /^\!|^@preserve|^@cc_on|\bMIT\b|\bMPL\b|\bGPL\b|\bBSD\b|\bISCL\b|\(c\)|License|Copyright/mi;

// number of line where license comment appeared last
var prevCommentLine = 0;
// name of the file minified last
var prevFile = '';

module.exports = function saveLicense(node, comment) {
  if (comment.file !== prevFile) {
    prevCommentLine = 0;
  }

  // check if the comment contains license text
  var result = licenseRegexp.test(comment.value) ||
               comment.line === 1 ||
               comment.line === prevCommentLine + 1;

  if (result) {
    // if the comment contains license, save line number
    prevCommentLine = comment.line;
  } else {
    // if the comment doesn't contain license, reset line number
    prevCommentLine = 0;
  }

  // save current filename
  prevFile = comment.file;

  return result;
};
<|endoftext|>


<commit_before>"use strict"
let Chart = {
  a: 'array',
  b: 'boolean',                               // Done
  C: 'object-serializable',
  d: 'double',                                // Done
  i: 'integer',                               // Done
  N: 'null',                                  // Done
  o: 'deprecated way to encode objects',
  O: 'object + class',                        // Done
  r: 'reference',
  R: 'pointer reference',
  s: 'string'                                 // Done
}
let Assert = require('assert')
let Regex = {
  i: /i:(.*?);/,
  d: /d:(.*?);/,
  O: /O:\d+:".*?":(\d+):\{(.*)\}/
}
class Serialize{
  static serialize(){

  }
  static unserialize(Item, Scope){
    if(typeof Scope !== 'object') Scope = {}
    Assert.equal(typeof Item, 'string', "Serialize.unserialize expects parameter one to be string")
    return Serialize.__unserializeItem(Item, Scope)
  }
  // Note: Trailing semi-colons are removed by the indexes
  static __unserializeItem(Item, Scope){
    let Type = Item.substr(0, 1)
    let Length
    let Value
    if(Type === 'i'){
      Value = Regex.i.exec(Item)
      Assert(Value, "Syntax Error")
      return {
        Index: Value.index + Value[0].length,
        Value: parseInt(Value[1])
      }
    } else if(Type === 's'){
      Length = parseInt(Item.substr(2, 1))
      Assert(Length === Length, "Syntax Error") // NaN !== NaN
      Item = Item.substr(4, Length + 2)
      return {
        Index: Length + Length.toString().length + 6,
        Value: Item.substr(1, Item.length - 2).replace(/\\"/g, '"') // 2 quotes
      }
    } else if(Type === 'b'){
      return {
        Value: Boolean(Item.substr(2, 1)),
        Index: 4
      }
    } else if(Type === 'N'){
      return {
        Value: null,
        Index: 2
      }
    } else if(Type === 'd'){
      Value = Regex.d.exec(Item)
      Assert(Value, "Syntax Error")
      return {
        Index: Value.index + Value[0].length,
        Value: parseFloat(Value[1])
      }
    } else if(Type === 'O'){
      let Container = {} // Create  container object
      let RegexVal = Regex.O.exec(Item)
      Assert(RegexVal, "Syntax Error")
      Length = parseInt(RegexVal[1]) * 2
      Value = RegexVal[2]
      Container = Serialize.__unserializeObject(Length, Value, {})
      return {
        Value: Container,
        Index: RegexVal.index + RegexVal[0].length
      }
      // key1,value1,key2,value2
    }
    return Type
  }
  static __unserializeObject(Length, Value, Container){
    let Temp = {Key: "", Value: ""}
    for(let I = 0; I < Length; ++I){
      let Entry = Serialize.__unserializeItem(Value, Scope)
      if(Temp.Key.length){
        Temp.Value = Entry.Value
        Container[Temp.Key] = Temp.Value
        Temp = {Key: "", Value: ""}
      } else Temp.Key = Entry.Value
      Value = Value.substr(Entry.Index)
    }
    return Container
  }
}

<commit_msg>:new: Implement Array parsing<commit_after>"use strict"
let Chart = {
  a: 'array',                                 // Done
  b: 'boolean',                               // Done
  C: 'object-serializable',
  d: 'double',                                // Done
  i: 'integer',                               // Done
  N: 'null',                                  // Done
  o: 'deprecated way to encode objects',
  O: 'object + class',                        // Done
  r: 'reference',
  R: 'pointer reference',
  s: 'string'                                 // Done
}
let Assert = require('assert')
let Regex = {
  i: /i:(.*?);/,
  d: /d:(.*?);/,
  O: /O:\d+:".*?":(\d+):\{(.*)\}/,
  a: /a:(\d+):\{(.*)\}/
}
class Serialize{
  static serialize(){

  }
  static unserialize(Item, Scope){
    if(typeof Scope !== 'object') Scope = {}
    Assert.equal(typeof Item, 'string', "Serialize.unserialize expects parameter one to be string")
    return Serialize.__unserializeItem(Item, Scope)
  }
  // Note: Trailing semi-colons are removed by the indexes
  static __unserializeItem(Item, Scope){
    let Type = Item.substr(0, 1)
    let Length
    let Value
    if(Type === 'i'){
      Value = Regex.i.exec(Item)
      Assert(Value, "Syntax Error")
      return {
        Index: Value.index + Value[0].length,
        Value: parseInt(Value[1])
      }
    } else if(Type === 's'){
      Length = parseInt(Item.substr(2, 1))
      Assert(Length === Length, "Syntax Error") // NaN !== NaN
      Item = Item.substr(4, Length + 2)
      return {
        Index: Length + Length.toString().length + 6,
        Value: Item.substr(1, Item.length - 2).replace(/\\"/g, '"') // 2 quotes
      }
    } else if(Type === 'b'){
      return {
        Value: Boolean(Item.substr(2, 1)),
        Index: 4
      }
    } else if(Type === 'N'){
      return {
        Value: null,
        Index: 2
      }
    } else if(Type === 'd'){
      Value = Regex.d.exec(Item)
      Assert(Value, "Syntax Error")
      return {
        Index: Value.index + Value[0].length,
        Value: parseFloat(Value[1])
      }
    } else if(Type === 'O'){
      let RegexVal = Regex.O.exec(Item)
      Assert(RegexVal, "Syntax Error")
      Length = parseInt(RegexVal[1]) * 2
      Value = RegexVal[2]
      return {
        Value: Serialize.__unserializeObject(Length, Value, {}),
        Index: RegexVal.index + RegexVal[0].length
      }
    } else if(Type === 'a'){
      let RegexVal = Regex.a.exec(Item)
      Assert(RegexVal, "Syntax Error")
      Length = parseInt(RegexVal[1]) * 2
      Value = RegexVal[2]
      return {
        Value: Serialize.__unserializeObject(Length, Value, []),
        Index: RegexVal.index + RegexVal[0].length
      }
    }
    return Type
  }
  static __unserializeObject(Length, Value, Container){
    let Temp = {Key: "", Value: ""}
    for(let I = 0; I < Length; ++I){
      let Entry = Serialize.__unserializeItem(Value, Scope)
      if(Temp.Key){
        Temp.Value = Entry.Value
        Container[Temp.Key] = Temp.Value
        Temp = {Key: "", Value: ""}
      } else Temp.Key = Entry.Value
      Value = Value.substr(Entry.Index)
    }
    return Container
  }
}
<|endoftext|>


<commit_before>var nodespec = require('./common');

var eg = require('../lib/example_group');

nodespec.describe("Nodespec", function() {
    this.subject("nodespec", function() {
        return nodespec("fresh nodespec to test");
    });
    this.after(function() {
        this.nodespec.abandon();
    });
    this.describe("assert", function() {
        this.example("defaults to stdlib assert module", function() {
            this.assert.strictEqual(this.nodespec.assert, require('assert'));
        });
        this.example("can be replaced with custom object", function() {
            var replacement_assert = new Object;
            this.nodespec.assert = replacement_assert;

            this.assert.strictEqual(this.nodespec.assert, replacement_assert);
        });
    });
    this.describe("describe", function() {
        this.subject("definition", function() { return function(){} });
        this.before(function() {
            this.eg_cls = this.sinon.stub(eg, "ExampleGroup");
        });
        this.example("factory for ExampleGroup", function() {
            var group = this.nodespec.describe("a set of tests",
                                               this.definition);

            this.sinon.assert.calledOnce(this.eg_cls);
            var call = this.eg_cls.getCall(0);

            // Called as constructor
            this.assert.ok(call.calledOn(group));
            // Arg 1 = description
            this.assert.equal(call.args[0], "a set of tests");
            // Arg 2 = options object
            this.assert.equal(typeof call.args[1], 'object');
            // options.parent is nodespec
            this.assert.strictEqual(call.args[1].parent, this.nodespec);
            // Arg 3 = definition function
            this.assert.equal(call.args[2], this.definition);
        });
        this.example("appends new instance to collection", function() {
            var group = this.nodespec.describe("a set of tests",
                                               this.definition);
            this.assert.strictEqual(this.nodespec.example_groups.length, 1);
            this.assert.strictEqual(this.nodespec.example_groups[0], group);
        })
    });
});
nodespec.exec();
<commit_msg>Tests for nodespec copies, and use them in module specs<commit_after>var nodespec = require('./common');

var eg = require('../lib/example_group');

nodespec.describe("Nodespec", function() {
    this.describe("sandboxing nodespecs", function() {
        this.example("calling nodespec gives a new copy", function() {
            var new_nodespec = nodespec("new copy");
            this.assert.notStrictEqual(new_nodespec, nodespec);
            var another = nodespec("another");
            this.assert.notStrictEqual(another, nodespec);
            this.assert.notStrictEqual(another, new_nodespec);
            // Cleanup, test below proves it works!
            new_nodespec.abandon(); another.abandon();
        });
        this.example("same name gives the same copy", function() {
            var one_nodespec = nodespec("new copy");
            var two_nodespec = nodespec("new copy");
            this.assert.strictEqual(one_nodespec, two_nodespec);
            // Cleanup, test below proves it works!
            one_nodespec.abandon();
        });
        this.example("abandon() can discard copy", function() {
            var one_nodespec = nodespec("new copy");
            one_nodespec.abandon();
            var two_nodespec = nodespec("new copy");
            this.assert.notStrictEqual(one_nodespec, two_nodespec);
            // Don't leave two_nodespec lying around
            two_nodespec.abandon();
        });
    });
    this.context("sandboxed nodespec module", function() {
        this.subject("nodespec", function() {
            return nodespec("fresh nodespec to test");
        });
        this.after(function() {
            this.nodespec.abandon();
        });
        this.describe("assert", function() {
            this.example("defaults to stdlib assert module", function() {
                this.assert.strictEqual(this.nodespec.assert, require('assert'));
            });
            this.example("can be replaced with custom object", function() {
                var replacement_assert = new Object;
                this.nodespec.assert = replacement_assert;

                this.assert.strictEqual(this.nodespec.assert, replacement_assert);
            });
        });
        this.describe("describe", function() {
            this.subject("definition", function() { return function(){} });
            this.before(function() {
                this.eg_cls = this.sinon.stub(eg, "ExampleGroup");
            });
            this.example("factory for ExampleGroup", function() {
                var group = this.nodespec.describe("a set of tests",
                                                   this.definition);

                this.sinon.assert.calledOnce(this.eg_cls);
                var call = this.eg_cls.getCall(0);

                // Called as constructor
                this.assert.ok(call.calledOn(group));
                // Arg 1 = description
                this.assert.equal(call.args[0], "a set of tests");
                // Arg 2 = options object
                this.assert.equal(typeof call.args[1], 'object');
                // options.parent is nodespec
                this.assert.strictEqual(call.args[1].parent, this.nodespec);
                // Arg 3 = definition function
                this.assert.equal(call.args[2], this.definition);
            });
            this.example("can pass explicit options", function() {
                var options = {};
                var group = this.nodespec.describe("a set of tests",
                                                   options, this.definition);

                this.sinon.assert.calledOnce(this.eg_cls);
                var call = this.eg_cls.getCall(0);

                // Arg 2 = options object
                this.assert.strictEqual(call.args[1], options);
                // options.parent is still set to nodespec
                this.assert.strictEqual(options.parent, this.nodespec);

            });
            this.example("appends new instance to collection", function() {
                var group = this.nodespec.describe("a set of tests",
                                                   this.definition);
                this.assert.strictEqual(this.nodespec.example_groups.length, 1);
                this.assert.strictEqual(this.nodespec.example_groups[0], group);
            })
        });
    });
});
nodespec.exec();
<|endoftext|>


<commit_before>var _ = require('underscore');
var parley = require('parley');
var async = require('async');
var util = require('sails-util');
var config = require('./config');
var normalize = require('./normalize');

var Deferred = require('./deferredObject');

var Collection = module.exports = function(definition) {
		var self = this;

		// ********************************************************************
		// Configure collection-specific configuration
		// Copy over only the methods from the adapter that you need, and modify if necessary
		// ********************************************************************
		// Pass up options from adapter  (defaults to global options)
		definition.migrate = definition.migrate || definition.adapter.config.migrate || config.migrate;
		definition.globalize = !_.isUndefined(definition.globalize) ? definition.globalize : !_.isUndefined(definition.adapter.config.globalize) ? definition.adapter.config.globalize : config.globalize;

		// Pass down appropriate configuration items to adapter
		_.each(['defaultPK', 'updatedAt', 'createdAt'], function(key) {
			if(!_.isUndefined(definition[key])) {
				definition.adapter.config[key] = definition[key];
			}
		});

		// Set behavior in adapter depending on migrate option
		if(definition.migrate === 'drop') {
			definition.sync = _.bind(definition.adapter.sync.drop, definition.adapter, definition);
		} else if(definition.migrate === 'alter') {
			definition.sync = _.bind(definition.adapter.sync.alter, definition.adapter, definition);
		} else if(definition.migrate === 'safe') {
			definition.sync = _.bind(definition.adapter.sync.safe, definition.adapter, definition);
		}

		// Absorb definition methods
		_.extend(this, definition);

		// if configured as such, make each collection globally accessible
		if(definition.globalize) {
			var globalName = _.str.capitalize(this.identity);
			global[globalName] = this;
		}

		//////////////////////////////////////////
		// Dynamic finders
		//////////////////////////////////////////
		// Query the collection using the name of the attribute directly
		// find or findAll will take care of callback
		// (with deferred object or the appropriate error)
		// So no need to worry about that
		this.generateDynamicFinder = function(attrName, method) {

			// Figure out actual dynamic method name by injecting attribute name
			var actualMethodName = method.replace(/\*/g, _.str.capitalize(attrName));

			// Assign this finder to the collection
			this[actualMethodName] = function dynamicMethod(value, options, cb) {
				if(_.isFunction(options)) {
					cb = options;
					options = null;
				}
				options = options || {};

				var usage = _.str.capitalize(this.identity) + '.' + actualMethodName + '(someValue,[options],callback)';
				if(_.isUndefined(value)) usageError('No value specified!', usage);
				if(options.where) usageError('Cannot specify `where` option in a dynamic ' + method + '*() query!', usage);

				// Build criteria query and submit it
				options.where = {};
				options.where[attrName] = value;

				// Make modifications based on method as necessary
				if (method === 'findBy*' || method === 'findBy*In') {
					return self.find(options, cb);
				} else if(method === 'findBy*Like') {
					return self.find(_.extend(options, {
						where: {
							like: options.where
						}
					}), cb);
				}

				// Aggregate finders
				else if(method === 'findAllBy*' || method === 'findAllBy*In') {
					return self.findAll(options, cb);
				} else if(method === 'findAllBy*Like') {
					return self.findAll(_.extend(options, {
						where: {
							like: options.where
						}
					}), cb);
				}

				// Count finders
				else if(method === 'countBy*' || method === 'countBy*In') {
					return self.count(options, cb);
				} else if(method === 'countBy*Like') {
					return self.count(_.extend(options, {
						where: {
							like: options.where
						}
					}), cb);
				}
			};
		};

		// Clone attributes and augment with id, createdAt, updatedAt, etc. if necessary
		var attributes = _.clone(this.attributes) || {};
		attributes = require('./augmentAttributes')(attributes, _.extend({}, config, this.config));

		// For each defined attribute, create a dynamic finder function
		_.each(attributes, function(attrDef, attrName) {

			this.generateDynamicFinder(attrName, 'findBy*');
			this.generateDynamicFinder(attrName, 'findBy*In');
			this.generateDynamicFinder(attrName, 'findBy*Like');

			this.generateDynamicFinder(attrName, 'findAllBy*');
			this.generateDynamicFinder(attrName, 'findAllBy*In');
			this.generateDynamicFinder(attrName, 'findAllBy*Like');

			this.generateDynamicFinder(attrName, 'countBy*');
			this.generateDynamicFinder(attrName, 'countBy*In');
			this.generateDynamicFinder(attrName, 'countBy*Like');
		}, this);

		//////////////////////////////////////////
		// Join
		//////////////////////////////////////////
		// Join with another collection
		// (use optimized join in adapter if one was provided)
		this.join = function (collection, fk, pk, cb) {
			// If no callback specified, return deferred object
			if(!_.isFunction(cb)) {
				return new Deferred({
					method: 'join',
					collection: this,
					args: {
						collection: collection,
						fk: fk,
						pk: pk
					},
					argsKeys: ['collection','fk','pk']
				});
			}
			else return this.adapter.join(this.identity, collection, fk, pk, cb);
		};

		// =============================

		//////////////////////////////////////////
		// Core CRUD
		//////////////////////////////////////////
		this.create = function(values, cb) {
			// =============================
			// TODO: (for a later release)
			// =============================
			/*

			if (this._isDeferredObject) {
				if (this.terminated) {
					throw new Error("The callback was already triggered!");
				}

				// If this was called from a deferred object,
				// instead of doing the normal operation, pop it on a queue for later

				if (cb) {
					// If a callback is specified, terminate the deferred object
				}
			}
			else {
				// Do the normal stuff
			}

			if (!cb) {
				// No callback specified
				// Initialize and return a deferred object
			}
		*/
			// =============================
			if(_.isFunction(values)) {
				cb = values;
				values = null;
			}
			var usage = _.str.capitalize(this.identity) + '.create({someAttr: "someValue"},callback)';
			if(!_.isFunction(cb)) usageError('Invalid callback specified!', usage);

			return this.adapter.create(this.identity, values, cb);
		};

		// Call find method in adapter
		this.find = function(criteria, cb) {
			var usage = _.str.capitalize(this.identity) + '.find([criteria],callback)';

			if (_.isFunction(criteria)) {
				cb = criteria;
				criteria = null;
			}

			// If no callback specified, return deferred object
			if(!_.isFunction(cb)) {
				return new Deferred({
					method: 'find',
					collection: this,
					args: { criteria: criteria },
					argsKeys: ['criteria']
				});
			}
			else return this.adapter.find(this.identity, criteria, cb);
		};

		this.findAll = function(criteria, options, cb) {
			var usage = _.str.capitalize(this.identity) + '.findAll([criteria],[options],callback)';
			if(_.isFunction(criteria)) {
				cb = criteria;
				criteria = null;
				options = null;
			} else if(_.isFunction(options)) {
				cb = options;
				options = null;
			}

			// Normalize criteria and fold in options
			criteria = normalize.criteria(criteria);
			if(_.isObject(options) && _.isObject(criteria)) {
				criteria = _.extend({}, criteria, options);
			}

			if (_.isFunction(criteria) || _.isFunction(options)) {
				return usageError('Invalid options specified!', usage);
			}

			// If no callback specified, return deferred object
			if(!_.isFunction(cb)) {
				return new Deferred({
					method: 'findAll',
					collection: this,
					args: {
						criteria: criteria
					},
					argsKeys: ['criteria']
				});
			}
			else return this.adapter.findAll(this.identity, criteria, cb);
		};
		this.where = this.findAll;
		this.select = this.findAll;

		this.findLike = function (criteria, options, cb) {
			var usage = _.str.capitalize(this.identity) + '.findLike([criteria],[options],callback)';
			if (criteria = normalizeLikeCriteria(criteria)) {
				return this.find(criteria, options, cb);
			}
			else usageError('Criteria must be string or object!',usage);
		};

		this.findAllLike = function (criteria, options, cb) {
			var usage = _.str.capitalize(this.identity) + '.findAllLike([criteria],[options],callback)';
			if (criteria = normalizeLikeCriteria(criteria)) {
				return this.findAll(criteria, options, cb);
			}
			else usageError('Criteria must be string or object!',usage);
		};

		this.count = function (criteria, options, cb) {
			var usage = _.str.capitalize(this.identity) + '.count([criteria],[options],callback)';
			if(_.isFunction(criteria)) {
				cb = criteria;
				criteria = null;
				options = null;
			} else if(_.isFunction(options)) {
				cb = options;
				options = null;
			} else if(_.isObject(options)) {
				criteria = _.extend({}, criteria, options);
			} else usageError('Invalid options specified!', usage);

			if(!_.isFunction(cb)) usageError('Invalid callback specified!', usage);

			return this.adapter.count(this.identity, criteria, cb);
		};
		this.countAll = this.count;

		// Call update method in adapter
		this.update = function(options, newValues, cb) {
			if(_.isFunction(options)) {
				cb = options;
				options = null;
			}
			var usage = _.str.capitalize(this.identity) + '.update(criteria, newValues, callback)';
			if(!newValues) usageError('No updated values specified!', usage);
			if(!_.isFunction(cb)) usageError('Invalid callback specified!', usage);

			return this.adapter.update(this.identity, options, newValues, cb);
		};
		this.updateWhere = this.update;
		this.updateAll = this.update;

		// Call destroy method in adapter
		this.destroy = function(options, cb) {
			if(_.isFunction(options)) {
				cb = options;
				options = null;
			}
			var usage = _.str.capitalize(this.identity) + '.destroy([options], callback)';
			if(!_.isFunction(cb)) usageError('Invalid callback specified!', usage);
			return this.adapter.destroy(this.identity, options, cb);
		};
		this.destroyWhere = this.destroy;
		this.destroyAll = this.destroy;

		//////////////////////////////////////////
		// Composite
		//////////////////////////////////////////
		this.findOrCreate = function(criteria, values, cb) {
			if(_.isFunction(values)) {
				cb = values;
				values = null;
			}
			var usage = _.str.capitalize(this.identity) + '.findOrCreate(criteria, values, callback)';
			if(!criteria) usageError('No criteria option specified!', usage);
			if(!_.isFunction(cb)) usageError('Invalid callback specified!', usage);

			return this.adapter.findOrCreate(this.identity, criteria, values, cb);
		};

		//////////////////////////////////////////
		// Aggregate methods
		//////////////////////////////////////////
		this.createEach = function(valuesList, cb) {
			var usage = _.str.capitalize(this.identity) + '.createEach(valuesList, callback)';
			if(!valuesList) usageError('No valuesList specified!', usage);
			if(!_.isArray(valuesList)) usageError('Invalid valuesList specified (should be an array!)', usage);
			if(!_.isFunction(cb)) usageError('Invalid callback specified!', usage);
			this.adapter.createEach(this.identity, valuesList, cb);
		};

		// Iterate through a list of objects, trying to find each one
		// For any that don't exist, create them
		this.findOrCreateEach = function(valuesList, cb) {
			var usage = _.str.capitalize(this.identity) + '.findOrCreateEach(valuesList, callback)';
			if(!valuesList) usageError('No valuesList specified!', usage);
			if(!_.isArray(valuesList)) usageError('Invalid valuesList specified (should be an array!)', usage);
			if(!_.isFunction(cb)) usageError('Invalid callback specified!', usage);
			this.adapter.findOrCreateEach(this.identity, valuesList, cb);
		};

		//////////////////////////////////////////
		// Special methods
		//////////////////////////////////////////
		this.transaction = function(transactionName, atomicLogic, afterUnlock) {
			var usage = _.str.capitalize(this.identity) + '.transaction(transactionName, atomicLogicFunction, afterUnlockFunction)';
			if(!atomicLogic) {
				return usageError('Missing required parameter: atomicLogicFunction!', usage);
			} else if(!_.isFunction(atomicLogic)) {
				return usageError('Invalid atomicLogicFunction!  Not a function: ' + atomicLogic, usage);
			} else if(afterUnlock && !_.isFunction(afterUnlock)) {
				return usageError('Invalid afterUnlockFunction!  Not a function: ' + afterUnlock, usage);
			} else return this.adapter.transaction(this.identity + '.' + transactionName, atomicLogic, afterUnlock);
		};

		//////////////////////////////////////////
		// Utility methods
		//////////////////////////////////////////
		// Return a trimmed set of the specified attributes
		// with only the attributes which actually exist in the server-side model
		this.filter = function(params) {
			var trimmedParams = util.objFilter(params, function(value, name) {
				return _.contains(_.keys(this.attributes), name);
			}, this);
			return trimmedParams;
		};
		this.trimParams = this.filter;

		// Bind instance methods to collection
		_.bindAll(definition);
		_.bindAll(this);

		// Returns false if criteria is invalid,
		// otherwise returns normalized criteria obj.
		// (inside as a closure in order to get access to attributes object)
		function normalizeLikeCriteria (criteria) {
			if (_.isObject(criteria)) {
				if (!criteria.where) criteria = {where: criteria};
				criteria.where = {like: criteria.where};
			}
			// If string criteria is specified, check each attribute for a match
			else if (_.isString(criteria)) {
				var searchTerm = criteria;
				criteria = {where: {or: []}};
				_.each(attributes,function (val, attrName) {
					var obj = {like: {}};
					obj.like[attrName] = searchTerm;
					criteria.where.or.push(obj);
				});
			}
			else return false;

			return criteria;
		}
	};

function usageError(err, usage) {
	console.error("\n\n");
	throw new Error(err + '\n==============================================\nProper usage :: \n' + usage + '\n==============================================\n');
}<commit_msg>Dealt with no-attributes-defined case.<commit_after>var _ = require('underscore');
var parley = require('parley');
var async = require('async');
var util = require('sails-util');
var config = require('./config');
var normalize = require('./normalize');

var Deferred = require('./deferredObject');

var Collection = module.exports = function(definition) {
		var self = this;

		// ********************************************************************
		// Configure collection-specific configuration
		// Copy over only the methods from the adapter that you need, and modify if necessary
		// ********************************************************************
		// Pass up options from adapter  (defaults to global options)
		definition.migrate = definition.migrate || definition.adapter.config.migrate || config.migrate;
		definition.globalize = !_.isUndefined(definition.globalize) ? definition.globalize : !_.isUndefined(definition.adapter.config.globalize) ? definition.adapter.config.globalize : config.globalize;

		// Pass down appropriate configuration items to adapter
		_.each(['defaultPK', 'updatedAt', 'createdAt'], function(key) {
			if(!_.isUndefined(definition[key])) {
				definition.adapter.config[key] = definition[key];
			}
		});

		// Set behavior in adapter depending on migrate option
		if(definition.migrate === 'drop') {
			definition.sync = _.bind(definition.adapter.sync.drop, definition.adapter, definition);
		} else if(definition.migrate === 'alter') {
			definition.sync = _.bind(definition.adapter.sync.alter, definition.adapter, definition);
		} else if(definition.migrate === 'safe') {
			definition.sync = _.bind(definition.adapter.sync.safe, definition.adapter, definition);
		}

		// Absorb definition methods
		_.extend(this, definition);

		// if configured as such, make each collection globally accessible
		if(definition.globalize) {
			var globalName = _.str.capitalize(this.identity);
			global[globalName] = this;
		}

		//////////////////////////////////////////
		// Dynamic finders
		//////////////////////////////////////////
		// Query the collection using the name of the attribute directly
		// find or findAll will take care of callback
		// (with deferred object or the appropriate error)
		// So no need to worry about that
		this.generateDynamicFinder = function(attrName, method) {

			// Figure out actual dynamic method name by injecting attribute name
			var actualMethodName = method.replace(/\*/g, _.str.capitalize(attrName));

			// Assign this finder to the collection
			this[actualMethodName] = function dynamicMethod(value, options, cb) {
				if(_.isFunction(options)) {
					cb = options;
					options = null;
				}
				options = options || {};

				var usage = _.str.capitalize(this.identity) + '.' + actualMethodName + '(someValue,[options],callback)';
				if(_.isUndefined(value)) usageError('No value specified!', usage);
				if(options.where) usageError('Cannot specify `where` option in a dynamic ' + method + '*() query!', usage);

				// Build criteria query and submit it
				options.where = {};
				options.where[attrName] = value;

				// Make modifications based on method as necessary
				if (method === 'findBy*' || method === 'findBy*In') {
					return self.find(options, cb);
				} else if(method === 'findBy*Like') {
					return self.find(_.extend(options, {
						where: {
							like: options.where
						}
					}), cb);
				}

				// Aggregate finders
				else if(method === 'findAllBy*' || method === 'findAllBy*In') {
					return self.findAll(options, cb);
				} else if(method === 'findAllBy*Like') {
					return self.findAll(_.extend(options, {
						where: {
							like: options.where
						}
					}), cb);
				}

				// Count finders
				else if(method === 'countBy*' || method === 'countBy*In') {
					return self.count(options, cb);
				} else if(method === 'countBy*Like') {
					return self.count(_.extend(options, {
						where: {
							like: options.where
						}
					}), cb);
				}
			};
		};

		// Clone attributes and augment with id, createdAt, updatedAt, etc. if necessary
		var attributes = _.clone(this.attributes) || {};
		attributes = require('./augmentAttributes')(attributes, _.extend({}, config, this.config));

		// For each defined attribute, create a dynamic finder function
		_.each(attributes, function(attrDef, attrName) {

			this.generateDynamicFinder(attrName, 'findBy*');
			this.generateDynamicFinder(attrName, 'findBy*In');
			this.generateDynamicFinder(attrName, 'findBy*Like');

			this.generateDynamicFinder(attrName, 'findAllBy*');
			this.generateDynamicFinder(attrName, 'findAllBy*In');
			this.generateDynamicFinder(attrName, 'findAllBy*Like');

			this.generateDynamicFinder(attrName, 'countBy*');
			this.generateDynamicFinder(attrName, 'countBy*In');
			this.generateDynamicFinder(attrName, 'countBy*Like');
		}, this);

		//////////////////////////////////////////
		// Join
		//////////////////////////////////////////
		// Join with another collection
		// (use optimized join in adapter if one was provided)
		this.join = function (collection, fk, pk, cb) {
			// If no callback specified, return deferred object
			if(!_.isFunction(cb)) {
				return new Deferred({
					method: 'join',
					collection: this,
					args: {
						collection: collection,
						fk: fk,
						pk: pk
					},
					argsKeys: ['collection','fk','pk']
				});
			}
			else return this.adapter.join(this.identity, collection, fk, pk, cb);
		};

		// =============================

		//////////////////////////////////////////
		// Core CRUD
		//////////////////////////////////////////
		this.create = function(values, cb) {
			// =============================
			// TODO: (for a later release)
			// =============================
			/*

			if (this._isDeferredObject) {
				if (this.terminated) {
					throw new Error("The callback was already triggered!");
				}

				// If this was called from a deferred object,
				// instead of doing the normal operation, pop it on a queue for later

				if (cb) {
					// If a callback is specified, terminate the deferred object
				}
			}
			else {
				// Do the normal stuff
			}

			if (!cb) {
				// No callback specified
				// Initialize and return a deferred object
			}
		*/
			// =============================
			if(_.isFunction(values)) {
				cb = values;
				values = null;
			}
			var usage = _.str.capitalize(this.identity) + '.create({someAttr: "someValue"},callback)';
			if(!_.isFunction(cb)) usageError('Invalid callback specified!', usage);

			return this.adapter.create(this.identity, values, cb);
		};

		// Call find method in adapter
		this.find = function(criteria, cb) {
			var usage = _.str.capitalize(this.identity) + '.find([criteria],callback)';

			if (_.isFunction(criteria)) {
				cb = criteria;
				criteria = null;
			}

			// If no callback specified, return deferred object
			if(!_.isFunction(cb)) {
				return new Deferred({
					method: 'find',
					collection: this,
					args: { criteria: criteria },
					argsKeys: ['criteria']
				});
			}
			else return this.adapter.find(this.identity, criteria, cb);
		};

		this.findAll = function(criteria, options, cb) {
			var usage = _.str.capitalize(this.identity) + '.findAll([criteria],[options],callback)';
			if(_.isFunction(criteria)) {
				cb = criteria;
				criteria = null;
				options = null;
			} else if(_.isFunction(options)) {
				cb = options;
				options = null;
			}

			// Normalize criteria and fold in options
			criteria = normalize.criteria(criteria);
			if(_.isObject(options) && _.isObject(criteria)) {
				criteria = _.extend({}, criteria, options);
			}

			if (_.isFunction(criteria) || _.isFunction(options)) {
				return usageError('Invalid options specified!', usage);
			}

			// If no callback specified, return deferred object
			if(!_.isFunction(cb)) {
				return new Deferred({
					method: 'findAll',
					collection: this,
					args: {
						criteria: criteria
					},
					argsKeys: ['criteria']
				});
			}
			else return this.adapter.findAll(this.identity, criteria, cb);
		};
		this.where = this.findAll;
		this.select = this.findAll;

		this.findLike = function (criteria, options, cb) {
			var usage = _.str.capitalize(this.identity) + '.findLike([criteria],[options],callback)';
			if (criteria = normalizeLikeCriteria(criteria)) {
				return this.find(criteria, options, cb);
			}
			else usageError('Criteria must be string or object!',usage);
		};

		this.findAllLike = function (criteria, options, cb) {
			var usage = _.str.capitalize(this.identity) + '.findAllLike([criteria],[options],callback)';
			if (criteria = normalizeLikeCriteria(criteria)) {
				return this.findAll(criteria, options, cb);
			}
			else usageError('Criteria must be string or object!',usage);
		};

		this.count = function (criteria, options, cb) {
			var usage = _.str.capitalize(this.identity) + '.count([criteria],[options],callback)';
			if(_.isFunction(criteria)) {
				cb = criteria;
				criteria = null;
				options = null;
			} else if(_.isFunction(options)) {
				cb = options;
				options = null;
			} else if(_.isObject(options)) {
				criteria = _.extend({}, criteria, options);
			} else usageError('Invalid options specified!', usage);

			if(!_.isFunction(cb)) usageError('Invalid callback specified!', usage);

			return this.adapter.count(this.identity, criteria, cb);
		};
		this.countAll = this.count;

		// Call update method in adapter
		this.update = function(options, newValues, cb) {
			if(_.isFunction(options)) {
				cb = options;
				options = null;
			}
			var usage = _.str.capitalize(this.identity) + '.update(criteria, newValues, callback)';
			if(!newValues) usageError('No updated values specified!', usage);
			if(!_.isFunction(cb)) usageError('Invalid callback specified!', usage);

			return this.adapter.update(this.identity, options, newValues, cb);
		};
		this.updateWhere = this.update;
		this.updateAll = this.update;

		// Call destroy method in adapter
		this.destroy = function(options, cb) {
			if(_.isFunction(options)) {
				cb = options;
				options = null;
			}
			var usage = _.str.capitalize(this.identity) + '.destroy([options], callback)';
			if(!_.isFunction(cb)) usageError('Invalid callback specified!', usage);
			return this.adapter.destroy(this.identity, options, cb);
		};
		this.destroyWhere = this.destroy;
		this.destroyAll = this.destroy;

		//////////////////////////////////////////
		// Composite
		//////////////////////////////////////////
		this.findOrCreate = function(criteria, values, cb) {
			if(_.isFunction(values)) {
				cb = values;
				values = null;
			}
			var usage = _.str.capitalize(this.identity) + '.findOrCreate(criteria, values, callback)';
			if(!criteria) usageError('No criteria option specified!', usage);
			if(!_.isFunction(cb)) usageError('Invalid callback specified!', usage);

			return this.adapter.findOrCreate(this.identity, criteria, values, cb);
		};

		//////////////////////////////////////////
		// Aggregate methods
		//////////////////////////////////////////
		this.createEach = function(valuesList, cb) {
			var usage = _.str.capitalize(this.identity) + '.createEach(valuesList, callback)';
			if(!valuesList) usageError('No valuesList specified!', usage);
			if(!_.isArray(valuesList)) usageError('Invalid valuesList specified (should be an array!)', usage);
			if(!_.isFunction(cb)) usageError('Invalid callback specified!', usage);
			this.adapter.createEach(this.identity, valuesList, cb);
		};

		// Iterate through a list of objects, trying to find each one
		// For any that don't exist, create them
		this.findOrCreateEach = function(valuesList, cb) {
			var usage = _.str.capitalize(this.identity) + '.findOrCreateEach(valuesList, callback)';
			if(!valuesList) usageError('No valuesList specified!', usage);
			if(!_.isArray(valuesList)) usageError('Invalid valuesList specified (should be an array!)', usage);
			if(!_.isFunction(cb)) usageError('Invalid callback specified!', usage);
			this.adapter.findOrCreateEach(this.identity, valuesList, cb);
		};

		//////////////////////////////////////////
		// Special methods
		//////////////////////////////////////////
		this.transaction = function(transactionName, atomicLogic, afterUnlock) {
			var usage = _.str.capitalize(this.identity) + '.transaction(transactionName, atomicLogicFunction, afterUnlockFunction)';
			if(!atomicLogic) {
				return usageError('Missing required parameter: atomicLogicFunction!', usage);
			} else if(!_.isFunction(atomicLogic)) {
				return usageError('Invalid atomicLogicFunction!  Not a function: ' + atomicLogic, usage);
			} else if(afterUnlock && !_.isFunction(afterUnlock)) {
				return usageError('Invalid afterUnlockFunction!  Not a function: ' + afterUnlock, usage);
			} else return this.adapter.transaction(this.identity + '.' + transactionName, atomicLogic, afterUnlock);
		};

		//////////////////////////////////////////
		// Utility methods
		//////////////////////////////////////////
		// Return a trimmed set of the specified attributes
		// with only the attributes which actually exist in the server-side model
		this.filter = function(params) {
			// If attributes aren't defined, send back
			if (!this.attributes) return {};

			var trimmedParams = util.objFilter(params, function(value, name) {
				return _.contains(_.keys(this.attributes), name);
			}, this);
			return trimmedParams;
		};
		this.trimParams = this.filter;

		// Bind instance methods to collection
		_.bindAll(definition);
		_.bindAll(this);

		// Returns false if criteria is invalid,
		// otherwise returns normalized criteria obj.
		// (inside as a closure in order to get access to attributes object)
		function normalizeLikeCriteria (criteria) {
			if (_.isObject(criteria)) {
				if (!criteria.where) criteria = {where: criteria};
				criteria.where = {like: criteria.where};
			}
			// If string criteria is specified, check each attribute for a match
			else if (_.isString(criteria)) {
				var searchTerm = criteria;
				criteria = {where: {or: []}};
				_.each(attributes,function (val, attrName) {
					var obj = {like: {}};
					obj.like[attrName] = searchTerm;
					criteria.where.or.push(obj);
				});
			}
			else return false;

			return criteria;
		}
	};

function usageError(err, usage) {
	console.error("\n\n");
	throw new Error(err + '\n==============================================\nProper usage :: \n' + usage + '\n==============================================\n');
}<|endoftext|>


<commit_before>// Universal Subtitles, universalsubtitles.org
//
// Copyright (C) 2010 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

goog.provide('mirosubs.widget.SubtitleController');

/**
 * @constructor
 */
mirosubs.widget.SubtitleController = function(
    videoID, videoURL, playController, videoTab, dropDown)
{
    this.videoID_ = videoID;
    this.videoURL_ = videoURL;
    this.videoTab_ = videoTab;
    this.dropDown_ = dropDown;
    this.playController_ = playController;
    this.playController_.setSubtitleController(this);
    this.handler_ = new goog.events.EventHandler(this);
    this.dialogOpener_ = new mirosubs.widget.SubtitleDialogOpener(
        videoID, videoURL, this.playController_.getVideoSource(),
        function(loading) {
            if (loading)
                videoTab.showLoading();
            else
                videoTab.stopLoading();
        },
        goog.bind(playController.stopForDialog, playController));
    this.handler_.listenOnce(
        this.dialogOpener_,
        goog.ui.Dialog.EventType.AFTER_HIDE,
        this.subtitleDialogClosed_);
    var s = mirosubs.widget.DropDown.Selection;
    this.handler_.
        listen(
            dropDown,
            s.ADD_LANGUAGE,
            this.openNewLanguageDialog).
        listen(
            dropDown,
            s.IMPROVE_SUBTITLES,
            this.openSubtitleDialog).
        listen(
            videoTab.getAnchorElem(), 'click',
            this.videoAnchorClicked_
        );
};

mirosubs.widget.SubtitleController.prototype.videoAnchorClicked_ =
    function(e)
{
    mirosubs.Tracker.getInstance().track('videoTabClicked');
    if (!this.dropDown_.hasSubtitles())
        this.openSubtitleDialog();
    else
        this.dropDown_.toggleShow();
    e.preventDefault();
};

/**
 * Corresponds to "Add new subs" or "Improve these subs" in menu.
 * @param type {string} opt_intitial_lang= When on Improve these subs,
 *  we should now which lang to default to on the started dialog
 */
mirosubs.widget.SubtitleController.prototype.openSubtitleDialog =
    function(e)
{
     this.openNewLanguageDialog(this.playController_.getSubtitleState().LANGUAGE);
};

mirosubs.widget.SubtitleController.prototype.openNewLanguageDialog =
    function(opt_intitialLang)
{
    this.dialogOpener_.showStartDialog(
        this.playController_.getVideoSource().getVideoURL(), opt_intitialLang);
};

mirosubs.widget.SubtitleController.prototype.subtitleDialogClosed_ = function(e) {
    var dropDownContents = e.target.getDropDownContents();
    this.playController_.dialogClosed();
    this.videoTab_.showContent(
        this.dropDown_.hasSubtitles(),
        this.playController_.getSubtitleState());
    this.dropDown_.setCurrentSubtitleState(
        this.playController_.getSubtitleState());
    if (dropDownContents != null) {
        this.dropDown_.updateContents(dropDownContents);
    }
};
<commit_msg>Fixed passing if current lang for not subtitled video (where subtitle state is null)<commit_after>// Universal Subtitles, universalsubtitles.org
//
// Copyright (C) 2010 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

goog.provide('mirosubs.widget.SubtitleController');

/**
 * @constructor
 */
mirosubs.widget.SubtitleController = function(
    videoID, videoURL, playController, videoTab, dropDown)
{
    this.videoID_ = videoID;
    this.videoURL_ = videoURL;
    this.videoTab_ = videoTab;
    this.dropDown_ = dropDown;
    this.playController_ = playController;
    this.playController_.setSubtitleController(this);
    this.handler_ = new goog.events.EventHandler(this);
    this.dialogOpener_ = new mirosubs.widget.SubtitleDialogOpener(
        videoID, videoURL, this.playController_.getVideoSource(),
        function(loading) {
            if (loading)
                videoTab.showLoading();
            else
                videoTab.stopLoading();
        },
        goog.bind(playController.stopForDialog, playController));
    this.handler_.listenOnce(
        this.dialogOpener_,
        goog.ui.Dialog.EventType.AFTER_HIDE,
        this.subtitleDialogClosed_);
    var s = mirosubs.widget.DropDown.Selection;
    this.handler_.
        listen(
            dropDown,
            s.ADD_LANGUAGE,
            this.openNewLanguageDialog).
        listen(
            dropDown,
            s.IMPROVE_SUBTITLES,
            this.openSubtitleDialog).
        listen(
            videoTab.getAnchorElem(), 'click',
            this.videoAnchorClicked_
        );
};

mirosubs.widget.SubtitleController.prototype.videoAnchorClicked_ =
    function(e)
{
    mirosubs.Tracker.getInstance().track('videoTabClicked');
    if (!this.dropDown_.hasSubtitles())
        this.openSubtitleDialog();
    else
        this.dropDown_.toggleShow();
    e.preventDefault();
};

/**
 * Corresponds to "Add new subs" or "Improve these subs" in menu.
 * @param type {string} opt_intitial_lang= When on Improve these subs,
 *  we should now which lang to default to on the started dialog
 */
mirosubs.widget.SubtitleController.prototype.openSubtitleDialog =
    function(e)
{
    var state  = this.playController_.getSubtitleState();
    this.openNewLanguageDialog(state && state.LANGUAGE);
};

mirosubs.widget.SubtitleController.prototype.openNewLanguageDialog =
    function(opt_intitialLang)
{
    this.dialogOpener_.showStartDialog(
        this.playController_.getVideoSource().getVideoURL(), opt_intitialLang);
};

mirosubs.widget.SubtitleController.prototype.subtitleDialogClosed_ = function(e) {
    var dropDownContents = e.target.getDropDownContents();
    this.playController_.dialogClosed();
    this.videoTab_.showContent(
        this.dropDown_.hasSubtitles(),
        this.playController_.getSubtitleState());
    this.dropDown_.setCurrentSubtitleState(
        this.playController_.getSubtitleState());
    if (dropDownContents != null) {
        this.dropDown_.updateContents(dropDownContents);
    }
};
<|endoftext|>


<commit_before>var tinynlp=function(){function l(a){this.lhsToRhsList={};for(var b in a){var c=a[b].split("->"),d=c[0].trim(),c=c[1].trim().split("|");this.lhsToRhsList[d]||(this.lhsToRhsList[d]=[]);for(var e in c)this.lhsToRhsList[d].push(c[e].trim().split(" "))}}function h(a){this.idToState={};this.currentId=0;this.chart=[];for(var b=0;b<a.length+1;b++)this.chart[b]=[]}function f(a,b,c,d,e){this.lhs=a;this.rhs=b;this.dot=c;this.left=d;this.right=e;this.id=-1;this.ref=[];for(a=0;a<b.length;a++)this.ref[a]={}}function m(a,
b,c,d){if(b==a.length)d.push(c.slice());else for(var e in a[b])c.push(a[b][e]),m(a,b+1,c,d),c.pop()}l.prototype.terminalSymbols=function(a){return[]};l.prototype.getRightHandSides=function(a){return(a=this.lhsToRhsList[a])?a:null};loggingOn=!1;h.prototype.addToChart=function(a,b){a.setId(this.currentId);var c=this.chart[b],d;for(d in c){var e=c[d];if(a.equals(e)){e.appendRefsToChidStates(a.getRefsToChidStates());return}}c.push(a);this.idToState[this.currentId]=a;this.currentId++};h.prototype.getStatesInColumn=
function(a){return this.chart[a]};h.prototype.countStatesInColumn=function(a){return this.chart[a].length};h.prototype.getState=function(a){return this.idToState[a]};h.prototype.getFinishedRoot=function(a){var b=this.chart[this.chart.length-1],c;for(c in b){var d=b[c];if(d.complete()&&d.getLeftHandSide()==a)return d}return null};h.prototype.log=function(a){if(loggingOn){console.log("-------------------");console.log("Column: "+a);console.log("-------------------");for(var b in this.chart[a])console.log(this.chart[a][b].toString())}};
f.prototype.complete=function(){return this.dot>=this.rhs.length};f.prototype.toString=function(){var a=[];a.push("(id: "+this.id+")");a.push(this.lhs);a.push("\u2192");for(var b=0;b<this.rhs.length;b++)b==this.dot&&a.push("\u2022"),a.push(this.rhs[b]);this.complete()&&a.push("\u2022");a.push("["+this.left+", "+this.right+"]");a.push(JSON.stringify(this.ref));return a.join(" ")};f.prototype.expectedNonTerminal=function(a){return null!==a.getRightHandSides(this.rhs[this.dot])?!0:!1};f.prototype.setId=
function(a){this.id=a};f.prototype.getId=function(){return this.id};f.prototype.equals=function(a){return this.lhs===a.lhs&&this.dot===a.dot&&this.left===a.left&&this.right===a.right&&JSON.stringify(this.rhs)===JSON.stringify(a.rhs)?!0:!1};f.prototype.getRefsToChidStates=function(){return this.ref};f.prototype.appendRefsToChidStates=function(a){for(var b=0;b<a.length;b++)if(a[b])for(var c in a[b])this.ref[b][c]=a[b][c]};f.prototype.predictor=function(a,b){var c=this.rhs[this.dot],d=a.getRightHandSides(c),
e;for(e in d){var g=new f(c,d[e],0,this.right,this.right);b.addToChart(g,this.right)}};f.prototype.scanner=function(a,b,c){var d=this.rhs[this.dot];(a=c?a.terminalSymbols(c):[])||(a=[]);a.push(c);for(var e in a)if(d==a[e]){c=new f(d,[c],1,this.right,this.right+1);b.addToChart(c,this.right+1);break}};f.prototype.completer=function(a){var b=a.getStatesInColumn(this.left),c;for(c in b){var d=b[c];if(d.rhs[d.dot]==this.lhs){var e=new f(d.lhs,d.rhs,d.dot+1,d.left,this.right);e.appendRefsToChidStates(d.ref);
var g=Array(d.rhs.length);g[d.dot]={};g[d.dot][this.id]=this;e.appendRefsToChidStates(g);a.addToChart(e,this.right)}}};f.prototype.traverse=function(){if(1==this.ref.length&&0==Object.keys(this.ref[0]).length){var a=[];this.lhs!=this.rhs&&a.push({root:this.rhs});return[{root:this.lhs,subtrees:a}]}for(var b=[],a=0;a<this.ref.length;a++){b[a]=[];for(var c in this.ref[a])b[a]=b[a].concat(this.ref[a][c].traverse())}c=[];m(b,0,[],c);b=[];for(a in c)b.push({root:this.lhs,subtrees:c[a]});return b};f.prototype.getLeftHandSide=
function(){return this.lhs};var k={};k.Grammar=l;k.State=f;k.Chart=h;k.parse=function(a,b,c){var d=new h(a),e=b.getRightHandSides(c),g;for(g in e){var k=new f(c,e[g],0,0,0);d.addToChart(k,0)}for(g=0;g<a.length+1;g++){for(j=0;j<d.countStatesInColumn(g);)c=d.getStatesInColumn(g)[j],c.complete()?c.completer(d):c.expectedNonTerminal(b)?c.predictor(b,d):c.scanner(b,d,a[g]),j++;d.log(g)}return d};k.logging=function(a){loggingOn=a};return k}();<commit_msg>Updated minified version<commit_after>var tinynlp=function(){function l(a){this.lhsToRhsList={};for(var b in a){var c=a[b].split("->"),d=c[0].trim(),c=c[1].trim().split("|");this.lhsToRhsList[d]||(this.lhsToRhsList[d]=[]);for(var e in c)this.lhsToRhsList[d].push(c[e].trim().split(" "))}}function h(a){this.idToState={};this.currentId=0;this.chart=[];for(var b=0;b<a.length+1;b++)this.chart[b]=[]}function f(a,b,c,d,e){this.lhs=a;this.rhs=b;this.dot=c;this.left=d;this.right=e;this.id=-1;this.ref=[];for(a=0;a<b.length;a++)this.ref[a]={}}function m(a,
b,c,d){if(b==a.length)d.push(c.slice());else for(var e in a[b])if(0==c.length||c[c.length-1].right==a[b][e].left)c.push(a[b][e]),m(a,b+1,c,d),c.pop()}l.prototype.terminalSymbols=function(a){return[]};l.prototype.getRightHandSides=function(a){return(a=this.lhsToRhsList[a])?a:null};loggingOn=!1;h.prototype.addToChart=function(a,b){a.setId(this.currentId);var c=this.chart[b],d;for(d in c){var e=c[d];if(a.equals(e)){e.appendRefsToChidStates(a.getRefsToChidStates());return}}c.push(a);this.idToState[this.currentId]=
a;this.currentId++};h.prototype.getStatesInColumn=function(a){return this.chart[a]};h.prototype.countStatesInColumn=function(a){return this.chart[a].length};h.prototype.getState=function(a){return this.idToState[a]};h.prototype.getFinishedRoot=function(a){var b=this.chart[this.chart.length-1],c;for(c in b){var d=b[c];if(d.complete()&&d.getLeftHandSide()==a)return d}return null};h.prototype.log=function(a){if(loggingOn){console.log("-------------------");console.log("Column: "+a);console.log("-------------------");
for(var b in this.chart[a])console.log(this.chart[a][b].toString())}};f.prototype.complete=function(){return this.dot>=this.rhs.length};f.prototype.toString=function(){var a=[];a.push("(id: "+this.id+")");a.push(this.lhs);a.push("\u2192");for(var b=0;b<this.rhs.length;b++)b==this.dot&&a.push("\u2022"),a.push(this.rhs[b]);this.complete()&&a.push("\u2022");a.push("["+this.left+", "+this.right+"]");a.push(JSON.stringify(this.ref));return a.join(" ")};f.prototype.expectedNonTerminal=function(a){return null!==
a.getRightHandSides(this.rhs[this.dot])?!0:!1};f.prototype.setId=function(a){this.id=a};f.prototype.getId=function(){return this.id};f.prototype.equals=function(a){return this.lhs===a.lhs&&this.dot===a.dot&&this.left===a.left&&this.right===a.right&&JSON.stringify(this.rhs)===JSON.stringify(a.rhs)?!0:!1};f.prototype.getRefsToChidStates=function(){return this.ref};f.prototype.appendRefsToChidStates=function(a){for(var b=0;b<a.length;b++)if(a[b])for(var c in a[b])this.ref[b][c]=a[b][c]};f.prototype.predictor=
function(a,b){var c=this.rhs[this.dot],d=a.getRightHandSides(c),e;for(e in d){var g=new f(c,d[e],0,this.right,this.right);b.addToChart(g,this.right)}};f.prototype.scanner=function(a,b,c){var d=this.rhs[this.dot];(a=c?a.terminalSymbols(c):[])||(a=[]);a.push(c);for(var e in a)if(d==a[e]){c=new f(d,[c],1,this.right,this.right+1);b.addToChart(c,this.right+1);break}};f.prototype.completer=function(a){var b=a.getStatesInColumn(this.left),c;for(c in b){var d=b[c];if(d.rhs[d.dot]==this.lhs){var e=new f(d.lhs,
d.rhs,d.dot+1,d.left,this.right);e.appendRefsToChidStates(d.ref);var g=Array(d.rhs.length);g[d.dot]={};g[d.dot][this.id]=this;e.appendRefsToChidStates(g);a.addToChart(e,this.right)}}};f.prototype.traverse=function(){if(1==this.ref.length&&0==Object.keys(this.ref[0]).length){var a=[];this.lhs!=this.rhs&&a.push({root:this.rhs,left:this.left,right:this.right});return[{root:this.lhs,left:this.left,right:this.right,subtrees:a}]}for(var b=[],a=0;a<this.ref.length;a++){b[a]=[];for(var c in this.ref[a])b[a]=
b[a].concat(this.ref[a][c].traverse())}c=[];m(b,0,[],c);b=[];for(a in c)b.push({root:this.lhs,left:this.left,right:this.right,subtrees:c[a]});return b};f.prototype.getLeftHandSide=function(){return this.lhs};var k={};k.Grammar=l;k.State=f;k.Chart=h;k.parse=function(a,b,c){var d=new h(a),e=b.getRightHandSides(c),g;for(g in e){var k=new f(c,e[g],0,0,0);d.addToChart(k,0)}for(g=0;g<a.length+1;g++){for(j=0;j<d.countStatesInColumn(g);)c=d.getStatesInColumn(g)[j],c.complete()?c.completer(d):c.expectedNonTerminal(b)?
c.predictor(b,d):c.scanner(b,d,a[g]),j++;d.log(g)}return d};k.logging=function(a){loggingOn=a};return k}();<|endoftext|>