<commit_before>/*
 * Copyright 2015 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of perseo-fe
 *
 * perseo-fe 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.
 *
 * perseo-fe 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 perseo-fe.
 * If not, see http://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::[contacto@tid.es]
 */
'use strict';

var util = require('util'),
    rules = require('./rules'),
    myutils = require('../myutils'),
    eplTemplate = 'select *,"${name}" as ruleName' +
        ' from pattern [every ev=iotEvent(${conditions})]',
    operatorMap = {
        'GREATER_THAN': ' > ',
        'EQUAL_TO': ' = ',
        'MINOR_THAN': ' < ',
        'DIFFERENT_TO': ' != ',
        'GREATER_OR_EQUAL_THAN': ' >= ',
        'MINOR_OR_EQUAL_THAN': ' <= ',
        'MATCH': ' regexp '
    },
    errors = {};

function errorOperator(op) {
    if (operatorMap[op] === undefined) {
        return new errors.UnknownOperator(op);
    }
    return null;
}

function castVar(str, isNumber) {
    str = util.format('cast(`%s`?, String)', str);
    if (isNumber === true) {
        str = util.format('cast(%s, float)', str);
    }
    return str;
}

function adaptExp(str, isNumber) {
    if (str.indexOf('${') !== 0) {
        if (isNumber !== true) {
            str = util.format('%j', str);
        }
        return str;
    }
    //Remove starting "${" and trailing "}"
    str = str.slice(2, -1);
    //Change dot to double underscore
    str = str.replace(/\./g, '__');
    return castVar(str, isNumber);
}

function makeUserPropCondition(exprL, op, exprR, isNumber) {
    exprL = adaptExp(exprL, isNumber);
    exprR = adaptExp(exprR, isNumber);
    return util.format('(%s %s %s)', exprL, operatorMap[op], exprR);
}
function makeObservationCondition(exprL, op, exprR, isNumber) {
    exprL = castVar(exprL, isNumber);
    exprR = adaptExp(exprR, isNumber);
    return util.format('(%s %s %s)', exprL, operatorMap[op], exprR);
}
function plainParams(p) {
    var i, obj = {};
    for (i = 0; i < p.length; i += 1) {
        obj[p[i].name] = p[i].value;
    }
    return obj;
}

function vr2rule(cardRule) {
    var r, i, card,
        conditions = [],
        action = {},
        noSignal, id, idRegexp, type,
        plain,
        checkInterval,
        errOp;
    try {
        r = {VR: cardRule, name: cardRule.name};
        for (i = 0; i < cardRule.cards.length; i += 1) {
            card = cardRule.cards[i];
            switch (card.type) {
            case 'SensorCard':
                switch (card.conditionList[0].scope) {
                case 'USER_PROP':
                    errOp = errorOperator(card.conditionList[0].operator);
                    if (errOp) {
                        return errOp;
                    }
                    conditions.push(makeUserPropCondition(card.conditionList[0].userProp,
                        card.conditionList[0].operator,
                        card.conditionList[0].parameterValue,
                        false));

                    break;
                case 'XPATH':
                    errOp = errorOperator(card.conditionList[0].operator);
                    if (errOp) {
                        return errOp;
                    }
                    conditions.push(makeObservationCondition(card.conditionList[0].parameterName,
                        card.conditionList[0].operator,
                        card.conditionList[0].parameterValue,
                        card.sensorData.dataType === 'Quantity'));
                    if (card.conditionList[0].parameterName === 'id') {
                        if (card.conditionList[0].operator === 'MATCH') {
                            idRegexp = card.conditionList[0].parameterValue;
                            //Just to check it is a valid regexp
                            new RegExp(idRegexp);
                        } else {
                            id = card.conditionList[0].parameterValue;
                        }
                    } else if (card.conditionList[0].parameterName === 'type') {
                        type = card.conditionList[0].parameterValue;
                    }
                    break;
                case 'OBSERVATION':
                    errOp = errorOperator(card.conditionList[0].operator);
                    if (errOp) {
                        return errOp;
                    }
                    if (card.sensorData.measureName === 'id') {
                        return new errors.IdAsAttribute('');
                    } else if (card.sensorData.measureName === 'type') {
                        return new errors.TypeAsAttribute('');
                    }
                    conditions.push(makeObservationCondition(card.sensorData.measureName,
                        card.conditionList[0].operator,
                        card.conditionList[0].parameterValue,
                        card.sensorData.dataType === 'Quantity'));
                    break;
                case 'LAST_MEASURE':
                    checkInterval = parseInt(card.timeData.interval, 10);
                    if (isNaN(checkInterval) || checkInterval < 1) {
                        return new errors.InvalidVisualRule('check interval ' + card.timeData.interval);
                    }
                    noSignal = {
                        checkInterval: card.timeData.interval,
                        attribute: card.sensorData.measureName,
                        reportInterval: card.conditionList[0].parameterValue
                    };
                    break;
                default:
                    return new errors.NotSupportedActionScope(card.conditionList[0].scope);
                }
                break;
            case 'ActionCard':
                switch (card.actionData.type) {
                case 'SendEmailAction':
                    plain = plainParams(card.actionData.userParams);
                    action.type = 'email';
                    action.template = plain['mail.message'];
                    action.parameters = {
                        to: plain['mail.to'],
                        from: plain['mail.from'],
                        subject: plain['mail.subject']
                    };
                    break;
                case 'SendSmsMibAction':
                    plain = plainParams(card.actionData.userParams);
                    action.type = 'sms';
                    action.template = plain['sms.message'];
                    action.parameters = {
                        to: plain['sms.to']
                    };
                    break;
                case 'updateAttribute':
                    action.type = 'update';
                    action.parameters = {
                        name: card.actionData.userParams.name,
                        value: card.actionData.userParams.value,
                        updateType: card.actionData.userParams.updateType
                    };
                    break;
                default:
                    return new errors.NotSupportedActionType(card.actionData.type);
                }
                break;

            case 'TimeCard':
                if (card.configData) {
                    switch (card.configData.timeType) {
                    case 'timeInterval': //No signal detection
                        // This is different from old DCA rules. No-signal cards are now of type
                        // SensorCard with a timeData field. https://jirapdi.tid.es/browse/PIOTP-855
                        return new errors.NotSupportedTimeCard(card.configData.timeType);
                        //break; not necessary with return
                    case 'timeElapsed': // Minimal interval for actions
                        action.interval = card.timeData.interval;
                        break;
                    }
                }
                else {
                    return new errors.MissingConfigDataInTimeCard(JSON.stringify(card));
                }

            }
        }

        r.action = action;
        r.subservice = cardRule.subservice;
        r.service = cardRule.service;
        if (noSignal) {
            r.nosignal = noSignal;
            r.nosignal.id = id;
            r.nosignal.idRegexp = idRegexp;
            r.nosignal.type = type;
        } else {
            r.text = myutils.expandVar(eplTemplate, {
                name: r.name,
                conditions: conditions.join(' AND '),
                service: r.service,
                subservice: r.subservice
            });
        }
    } catch (ex) { // SHOULD BE ex instanceof TypeError. Do not do anything else inside try
        // Also it can be instance of SyntaxError: Invalid regular expression
        return new errors.InvalidVisualRule(ex.toString());
    }
    return r;
}

module.exports = {
    FindAll: function FindAll(service, subservice, callback) {
        rules.FindAll(service, subservice, function(err, data) {
            if (err) {
                return callback(err, null);
            }
            var vrdata = [], i;
            for (i = 0; i < data.length; i += 1) {
                if (data[i].VR) {
                    vrdata.push(data[i].VR);
                }
            }
            return callback(err, vrdata);
        });
    },
    Find: function Find(rule, callback) {
        rules.Find(rule, function(err, data) {
            if (err) {
                return callback(err, null);
            }
            data = data || {};
            data.VR = data.VR || {};
            return callback(err, data.VR);
        });
    },
    Save: function Save(vrrule, callback) {
        var rule = vr2rule(vrrule);
        if (rule instanceof Error) {
            myutils.logErrorIf(rule);
            return callback(rule, null);
        }
        rules.Save(rule, function(err, data) {
            if (err) {
                return callback(err, null);
            }
            return callback(null, data[2].VR);
        });
    },
    Remove: function Remove(id, callback) {
        rules.Remove(id, callback);
    },
    Put: function(id, rule, callback) {
        rule = vr2rule(rule);
        if (rule instanceof Error) {
            myutils.logErrorIf(rule);
            return callback(rule, null);
        }
        rules.Put(id, rule, function(err, data) {
            if (err) {
                return callback(err, null);
            }
            callback(err, data[0].VR);
        });
    }
};
/**
 * Constructors for possible errors from this module
 *
 * @type {Object}
 */
module.exports.errors = errors;
// Only for testing, not intended for external use
module.exports.vr2rule = vr2rule;
module.exports.errorOperator = errorOperator;

(function() {

    errors.InvalidVisualRule = function InvalidVisualRule(msg) {
        this.name = 'INVALID_VISUAL_RULE';
        this.message = 'invalid visual rule format ' + msg;
        this.httpCode = 400;
    };
    errors.NotSupportedTimeCard = function NotSupportedTimeCard(msg) {
        this.message = 'TimeCard not supported ' + msg;
        this.httpCode = 400;
    };
    errors.NotSupportedActionType = function NotSupportedActionType(msg) {
        this.name = 'ACTION_TYPE_NOT_SUPPORTED';
        this.message = 'ActionType not supported ' + msg;
        this.httpCode = 400;
    };
    errors.NotSupportedActionScope = function NotSupportedActionScope(msg) {
        this.name = 'UNKNOWN_SCOPE_ACTION';
        this.message = 'Scope not supported ' + msg;
        this.httpCode = 400;
    };
    errors.MissingConfigDataInTimeCard = function MissingConfigDataInTimeCard(msg) {
        this.name = 'MISSING_CONFIGDATA_TIMECARD';
        this.message = 'Missing config data in time card' + msg;
        this.httpCode = 400;
    };
    errors.IdAsAttribute = function IdAsAttribute(msg) {
        this.name = 'ID_ATTRIBUTE';
        this.message = 'id as attribute ' + msg;
        this.httpCode = 400;
    };
    errors.TypeAsAttribute = function TypeAsAttribute(msg) {
        this.name = 'TYPE_ATTRIBUTE';
        this.message = 'type as attribute ' + msg;
        this.httpCode = 400;
    };
    errors.UnknownOperator = function UnknownOperator(msg) {
        this.name = 'UNKNOWN_OPERATOR';
        this.message = 'unknown operator ' + msg;
        this.httpCode = 400;
    };
    Object.keys(errors).forEach(function(element) {
        util.inherits(errors[element], Error);
    });
})();

<commit_msg>replace updateType to actionType<commit_after>/*
 * Copyright 2015 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of perseo-fe
 *
 * perseo-fe 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.
 *
 * perseo-fe 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 perseo-fe.
 * If not, see http://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::[contacto@tid.es]
 */
'use strict';

var util = require('util'),
    rules = require('./rules'),
    myutils = require('../myutils'),
    eplTemplate = 'select *,"${name}" as ruleName' +
        ' from pattern [every ev=iotEvent(${conditions})]',
    operatorMap = {
        'GREATER_THAN': ' > ',
        'EQUAL_TO': ' = ',
        'MINOR_THAN': ' < ',
        'DIFFERENT_TO': ' != ',
        'GREATER_OR_EQUAL_THAN': ' >= ',
        'MINOR_OR_EQUAL_THAN': ' <= ',
        'MATCH': ' regexp '
    },
    errors = {};

function errorOperator(op) {
    if (operatorMap[op] === undefined) {
        return new errors.UnknownOperator(op);
    }
    return null;
}

function castVar(str, isNumber) {
    str = util.format('cast(`%s`?, String)', str);
    if (isNumber === true) {
        str = util.format('cast(%s, float)', str);
    }
    return str;
}

function adaptExp(str, isNumber) {
    if (str.indexOf('${') !== 0) {
        if (isNumber !== true) {
            str = util.format('%j', str);
        }
        return str;
    }
    //Remove starting "${" and trailing "}"
    str = str.slice(2, -1);
    //Change dot to double underscore
    str = str.replace(/\./g, '__');
    return castVar(str, isNumber);
}

function makeUserPropCondition(exprL, op, exprR, isNumber) {
    exprL = adaptExp(exprL, isNumber);
    exprR = adaptExp(exprR, isNumber);
    return util.format('(%s %s %s)', exprL, operatorMap[op], exprR);
}
function makeObservationCondition(exprL, op, exprR, isNumber) {
    exprL = castVar(exprL, isNumber);
    exprR = adaptExp(exprR, isNumber);
    return util.format('(%s %s %s)', exprL, operatorMap[op], exprR);
}
function plainParams(p) {
    var i, obj = {};
    for (i = 0; i < p.length; i += 1) {
        obj[p[i].name] = p[i].value;
    }
    return obj;
}

function vr2rule(cardRule) {
    var r, i, card,
        conditions = [],
        action = {},
        noSignal, id, idRegexp, type,
        plain,
        checkInterval,
        errOp;
    try {
        r = {VR: cardRule, name: cardRule.name};
        for (i = 0; i < cardRule.cards.length; i += 1) {
            card = cardRule.cards[i];
            switch (card.type) {
            case 'SensorCard':
                switch (card.conditionList[0].scope) {
                case 'USER_PROP':
                    errOp = errorOperator(card.conditionList[0].operator);
                    if (errOp) {
                        return errOp;
                    }
                    conditions.push(makeUserPropCondition(card.conditionList[0].userProp,
                        card.conditionList[0].operator,
                        card.conditionList[0].parameterValue,
                        false));

                    break;
                case 'XPATH':
                    errOp = errorOperator(card.conditionList[0].operator);
                    if (errOp) {
                        return errOp;
                    }
                    conditions.push(makeObservationCondition(card.conditionList[0].parameterName,
                        card.conditionList[0].operator,
                        card.conditionList[0].parameterValue,
                        card.sensorData.dataType === 'Quantity'));
                    if (card.conditionList[0].parameterName === 'id') {
                        if (card.conditionList[0].operator === 'MATCH') {
                            idRegexp = card.conditionList[0].parameterValue;
                            //Just to check it is a valid regexp
                            new RegExp(idRegexp);
                        } else {
                            id = card.conditionList[0].parameterValue;
                        }
                    } else if (card.conditionList[0].parameterName === 'type') {
                        type = card.conditionList[0].parameterValue;
                    }
                    break;
                case 'OBSERVATION':
                    errOp = errorOperator(card.conditionList[0].operator);
                    if (errOp) {
                        return errOp;
                    }
                    if (card.sensorData.measureName === 'id') {
                        return new errors.IdAsAttribute('');
                    } else if (card.sensorData.measureName === 'type') {
                        return new errors.TypeAsAttribute('');
                    }
                    conditions.push(makeObservationCondition(card.sensorData.measureName,
                        card.conditionList[0].operator,
                        card.conditionList[0].parameterValue,
                        card.sensorData.dataType === 'Quantity'));
                    break;
                case 'LAST_MEASURE':
                    checkInterval = parseInt(card.timeData.interval, 10);
                    if (isNaN(checkInterval) || checkInterval < 1) {
                        return new errors.InvalidVisualRule('check interval ' + card.timeData.interval);
                    }
                    noSignal = {
                        checkInterval: card.timeData.interval,
                        attribute: card.sensorData.measureName,
                        reportInterval: card.conditionList[0].parameterValue
                    };
                    break;
                default:
                    return new errors.NotSupportedActionScope(card.conditionList[0].scope);
                }
                break;
            case 'ActionCard':
                switch (card.actionData.type) {
                case 'SendEmailAction':
                    plain = plainParams(card.actionData.userParams);
                    action.type = 'email';
                    action.template = plain['mail.message'];
                    action.parameters = {
                        to: plain['mail.to'],
                        from: plain['mail.from'],
                        subject: plain['mail.subject']
                    };
                    break;
                case 'SendSmsMibAction':
                    plain = plainParams(card.actionData.userParams);
                    action.type = 'sms';
                    action.template = plain['sms.message'];
                    action.parameters = {
                        to: plain['sms.to']
                    };
                    break;
                case 'updateAttribute':
                    action.type = 'update';
                    action.parameters = {
                        name: card.actionData.userParams.name,
                        value: card.actionData.userParams.value,
                        actionType: card.actionData.userParams.actionType
                    };
                    break;
                default:
                    return new errors.NotSupportedActionType(card.actionData.type);
                }
                break;

            case 'TimeCard':
                if (card.configData) {
                    switch (card.configData.timeType) {
                    case 'timeInterval': //No signal detection
                        // This is different from old DCA rules. No-signal cards are now of type
                        // SensorCard with a timeData field. https://jirapdi.tid.es/browse/PIOTP-855
                        return new errors.NotSupportedTimeCard(card.configData.timeType);
                        //break; not necessary with return
                    case 'timeElapsed': // Minimal interval for actions
                        action.interval = card.timeData.interval;
                        break;
                    }
                }
                else {
                    return new errors.MissingConfigDataInTimeCard(JSON.stringify(card));
                }

            }
        }

        r.action = action;
        r.subservice = cardRule.subservice;
        r.service = cardRule.service;
        if (noSignal) {
            r.nosignal = noSignal;
            r.nosignal.id = id;
            r.nosignal.idRegexp = idRegexp;
            r.nosignal.type = type;
        } else {
            r.text = myutils.expandVar(eplTemplate, {
                name: r.name,
                conditions: conditions.join(' AND '),
                service: r.service,
                subservice: r.subservice
            });
        }
    } catch (ex) { // SHOULD BE ex instanceof TypeError. Do not do anything else inside try
        // Also it can be instance of SyntaxError: Invalid regular expression
        return new errors.InvalidVisualRule(ex.toString());
    }
    return r;
}

module.exports = {
    FindAll: function FindAll(service, subservice, callback) {
        rules.FindAll(service, subservice, function(err, data) {
            if (err) {
                return callback(err, null);
            }
            var vrdata = [], i;
            for (i = 0; i < data.length; i += 1) {
                if (data[i].VR) {
                    vrdata.push(data[i].VR);
                }
            }
            return callback(err, vrdata);
        });
    },
    Find: function Find(rule, callback) {
        rules.Find(rule, function(err, data) {
            if (err) {
                return callback(err, null);
            }
            data = data || {};
            data.VR = data.VR || {};
            return callback(err, data.VR);
        });
    },
    Save: function Save(vrrule, callback) {
        var rule = vr2rule(vrrule);
        if (rule instanceof Error) {
            myutils.logErrorIf(rule);
            return callback(rule, null);
        }
        rules.Save(rule, function(err, data) {
            if (err) {
                return callback(err, null);
            }
            return callback(null, data[2].VR);
        });
    },
    Remove: function Remove(id, callback) {
        rules.Remove(id, callback);
    },
    Put: function(id, rule, callback) {
        rule = vr2rule(rule);
        if (rule instanceof Error) {
            myutils.logErrorIf(rule);
            return callback(rule, null);
        }
        rules.Put(id, rule, function(err, data) {
            if (err) {
                return callback(err, null);
            }
            callback(err, data[0].VR);
        });
    }
};
/**
 * Constructors for possible errors from this module
 *
 * @type {Object}
 */
module.exports.errors = errors;
// Only for testing, not intended for external use
module.exports.vr2rule = vr2rule;
module.exports.errorOperator = errorOperator;

(function() {

    errors.InvalidVisualRule = function InvalidVisualRule(msg) {
        this.name = 'INVALID_VISUAL_RULE';
        this.message = 'invalid visual rule format ' + msg;
        this.httpCode = 400;
    };
    errors.NotSupportedTimeCard = function NotSupportedTimeCard(msg) {
        this.message = 'TimeCard not supported ' + msg;
        this.httpCode = 400;
    };
    errors.NotSupportedActionType = function NotSupportedActionType(msg) {
        this.name = 'ACTION_TYPE_NOT_SUPPORTED';
        this.message = 'ActionType not supported ' + msg;
        this.httpCode = 400;
    };
    errors.NotSupportedActionScope = function NotSupportedActionScope(msg) {
        this.name = 'UNKNOWN_SCOPE_ACTION';
        this.message = 'Scope not supported ' + msg;
        this.httpCode = 400;
    };
    errors.MissingConfigDataInTimeCard = function MissingConfigDataInTimeCard(msg) {
        this.name = 'MISSING_CONFIGDATA_TIMECARD';
        this.message = 'Missing config data in time card' + msg;
        this.httpCode = 400;
    };
    errors.IdAsAttribute = function IdAsAttribute(msg) {
        this.name = 'ID_ATTRIBUTE';
        this.message = 'id as attribute ' + msg;
        this.httpCode = 400;
    };
    errors.TypeAsAttribute = function TypeAsAttribute(msg) {
        this.name = 'TYPE_ATTRIBUTE';
        this.message = 'type as attribute ' + msg;
        this.httpCode = 400;
    };
    errors.UnknownOperator = function UnknownOperator(msg) {
        this.name = 'UNKNOWN_OPERATOR';
        this.message = 'unknown operator ' + msg;
        this.httpCode = 400;
    };
    Object.keys(errors).forEach(function(element) {
        util.inherits(errors[element], Error);
    });
})();

<|endoftext|>


<commit_before>// Copyright 2014-2015, University of Colorado Boulder

/**
 * A node that represents a 2D surface on which energy chunks reside.  The
 * surface contains z-dimension information, and can thus be used to create an
 * effect of layering in order to get a bit of a 3D appearance.
 *
 * @author John Blanco
 */

define( function( require ) {
  'use strict';

  // modules

  var EnergyChunkNode = require( 'ENERGY_FORMS_AND_CHANGES/common/view/EnergyChunkNode' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Path = require( 'SCENERY/nodes/Path' );

  // constants
  var ALWAYS_SHOW_OUTLINE = true;

  /**
   * *
   * @param {EnergyChunkContainerSlice} energyChunkContainerSlice
   * @param {ModelViewTransform2} modelViewTransform
   * @constructor
   */
  function EnergyChunkContainerSliceNode( energyChunkContainerSlice, modelViewTransform ) {

    var self = this;
    this.modelViewTransform = modelViewTransform;
    this.energyChunkContainerSlice = energyChunkContainerSlice;
    Node.call( this );

    // Add the initial energy chunks.
    this.addInitialEnergyChunks();

    energyChunkContainerSlice.energyChunkList.addItemAddedListener( function( addedEnergyChunk ) {
      var energyChunkNode = new EnergyChunkNode( addedEnergyChunk, modelViewTransform );
      self.addChild( energyChunkNode );
      energyChunkContainerSlice.energyChunkList.addItemRemovedListener( function removalListener( removedEnergyChunk ) {
        if ( removedEnergyChunk === addedEnergyChunk ) {
          self.removeChild( energyChunkNode );
          energyChunkContainerSlice.energyChunkList.removeItemRemovedListener( removalListener );
        }
      } );
    } );

    // For debug.
    if ( ALWAYS_SHOW_OUTLINE ) {
      this.addChild( new Path( modelViewTransform.modelToViewShape( energyChunkContainerSlice.shape ), {
        lineWidth: 1,
        stroke: 'red'
      } ) );
    }
  }

  return inherit( Node, EnergyChunkContainerSliceNode, {

    addInitialEnergyChunks: function() {
      var thisNode = this;
      this.energyChunkContainerSlice.energyChunkList.forEach( function( energyChunk ) {
        thisNode.addChild( new EnergyChunkNode( energyChunk, thisNode.modelViewTransform ) );
      } );
    }
  } );

} );<commit_msg>Disable slice outlines<commit_after>// Copyright 2014-2015, University of Colorado Boulder

/**
 * A node that represents a 2D surface on which energy chunks reside.  The
 * surface contains z-dimension information, and can thus be used to create an
 * effect of layering in order to get a bit of a 3D appearance.
 *
 * @author John Blanco
 */

define( function( require ) {
  'use strict';

  // modules

  var EnergyChunkNode = require( 'ENERGY_FORMS_AND_CHANGES/common/view/EnergyChunkNode' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Path = require( 'SCENERY/nodes/Path' );

  // constants
  var ALWAYS_SHOW_OUTLINE = false;

  /**
   * *
   * @param {EnergyChunkContainerSlice} energyChunkContainerSlice
   * @param {ModelViewTransform2} modelViewTransform
   * @constructor
   */
  function EnergyChunkContainerSliceNode( energyChunkContainerSlice, modelViewTransform ) {

    var self = this;
    this.modelViewTransform = modelViewTransform;
    this.energyChunkContainerSlice = energyChunkContainerSlice;
    Node.call( this );

    // Add the initial energy chunks.
    this.addInitialEnergyChunks();

    energyChunkContainerSlice.energyChunkList.addItemAddedListener( function( addedEnergyChunk ) {
      var energyChunkNode = new EnergyChunkNode( addedEnergyChunk, modelViewTransform );
      self.addChild( energyChunkNode );
      energyChunkContainerSlice.energyChunkList.addItemRemovedListener( function removalListener( removedEnergyChunk ) {
        if ( removedEnergyChunk === addedEnergyChunk ) {
          self.removeChild( energyChunkNode );
          energyChunkContainerSlice.energyChunkList.removeItemRemovedListener( removalListener );
        }
      } );
    } );

    // For debug.
    if ( ALWAYS_SHOW_OUTLINE ) {
      this.addChild( new Path( modelViewTransform.modelToViewShape( energyChunkContainerSlice.shape ), {
        lineWidth: 1,
        stroke: 'red'
      } ) );
    }
  }

  return inherit( Node, EnergyChunkContainerSliceNode, {

    addInitialEnergyChunks: function() {
      var thisNode = this;
      this.energyChunkContainerSlice.energyChunkList.forEach( function( energyChunk ) {
        thisNode.addChild( new EnergyChunkNode( energyChunk, thisNode.modelViewTransform ) );
      } );
    }
  } );

} );<|endoftext|>


<commit_before>var fs = require('fs'),
    readability = require('readability'),
    natural = require('natural'),
    request = require('request'),
    S = require('string'),
    tfidf = require('./tfidf'),
    shortener = {};

function getFrequencyMap(words) {
    var frequencyMap = {};
    var totalTermCount = 0;

    for (var i = 0; i < words.length; i++) {
        if(frequencyMap[words[i]] === undefined) {
            frequencyMap[words[i]] = 1;
        } else {
            frequencyMap[words[i]] += 1;
        }
    }

    return {
        frequencyMap: frequencyMap,
            totalTermCount: words.length
    };
}

function getSortedScoreMap(scoreMap) {
    var sortable = [];
    for (var key in scoreMap) {
        if (scoreMap.hasOwnProperty(key)) {
            sortable.push([key, scoreMap[key]]);
        }
    }
    sortable.sort(function(a, b) {
        return b[1] - a[1];
    });
    return sortable;
}

// Get the first N most 'important' words and place them in 'mostImportantWords' array
function getImportantTerms(sortedScoreMap) {
    var sortedScoreSubset = sortedScoreMap.splice(1,7);
    var importantTerms = [];
    for (var i = 0; i < sortedScoreSubset.length; i++) {
        importantTerms.push(sortedScoreSubset[i][0]);
    }
    return importantTerms;
}

// @TODO - make this awesomer
shortener.create = function (sortedScoreMap) {
    var importantTerms = getImportantTerms(sortedScoreMap);
    return importantTerms.join('-');
};

shortener.shorten = function (url, cb) {
    if (!url) {
        cb.call(this, undefined, 'invalid url');
    }

    shortener.extract(url, function (article) {
        shortener.filter(article.s, function(words) {
            shortener.tfidf(words, function (sortedScoreMap) {
                cb.call(this, shortener.create(sortedScoreMap), undefined);
            });
        });
    });
};

shortener.extract = function (url, cb) {
    var content = request(url, function (err, res, body) {
        var tagRegex = /(<([^>]+)>)/ig;
        article = body.replace(tagRegex, "<>");
        var textRegex = /[a-zA-Z]+?[^<>/()\n\r]+?([a-zA-Z]+\s){3}[^<>/()\n\r]+/g;
        article = article.match(textRegex).join(" ");
        article = article.replace(/[^-_a-zA-Z0-9\']+?/g, " ");
        article = article.replace(/[ ]+/g, " ");
        cb.call(this, article);
    });
};

// Filter the plaintext content of the article
shortener.filter = function (content, cb) {
    var tokenizer = new natural.WordTokenizer();
    var terms = tokenizer.tokenize(content);
    cb.call(this, terms);
};

// Perform TFIDF on terms (list of words)
shortener.tfidf = function (words, cb) {
    var freqMapObject = getFrequencyMap(words);
    tfidf.getScoreMap(freqMapObject.frequencyMap,
            freqMapObject.totalTermCount, function(scoreMap) {
                cb.call(this, getSortedScoreMap(scoreMap));
            });
};
exports.shorten = shortener.shorten;
<commit_msg>Fix bug, new tfdif works very well<commit_after>var fs = require('fs'),
    readability = require('readability'),
    natural = require('natural'),
    request = require('request'),
    S = require('string'),
    tfidf = require('./tfidf'),
    shortener = {};

function getFrequencyMap(words) {
    var frequencyMap = {};
    var totalTermCount = 0;

    for (var i = 0; i < words.length; i++) {
        if(frequencyMap[words[i]] === undefined) {
            frequencyMap[words[i]] = 1;
        } else {
            frequencyMap[words[i]] += 1;
        }
    }

    return {
        frequencyMap: frequencyMap,
            totalTermCount: words.length
    };
}

function getSortedScoreMap(scoreMap) {
    var sortable = [];
    for (var key in scoreMap) {
        if (scoreMap.hasOwnProperty(key)) {
            sortable.push([key, scoreMap[key]]);
        }
    }
    sortable.sort(function(a, b) {
        return b[1] - a[1];
    });
    return sortable;
}

// Get the first N most 'important' words and place them in 'mostImportantWords' array
function getImportantTerms(sortedScoreMap) {
    var sortedScoreSubset = sortedScoreMap.splice(1,7);
    var importantTerms = [];
    for (var i = 0; i < sortedScoreSubset.length; i++) {
        importantTerms.push(sortedScoreSubset[i][0]);
    }
    return importantTerms;
}

// @TODO - make this awesomer
shortener.create = function (sortedScoreMap) {
    var importantTerms = getImportantTerms(sortedScoreMap);
    return importantTerms.join('-');
};

shortener.shorten = function (url, cb) {
    if (!url) {
        cb.call(this, undefined, 'invalid url');
    }

    shortener.extract(url, function (article) {
        shortener.filter(article, function(words) {
            shortener.tfidf(words, function (sortedScoreMap) {
                cb.call(this, shortener.create(sortedScoreMap), undefined);
            });
        });
    });
};

shortener.extract = function (url, cb) {
    var content = request(url, function (err, res, body) {
        var tagRegex = /(<([^>]+)>)/ig;
        var article = body.replace(tagRegex, "<>");
        var textRegex = /[a-zA-Z]+?[^<>/()\n\r]+?([a-zA-Z]+\s){3}[^<>/()\n\r]+/g;
        article = article.match(textRegex).join(" ");
        article = article.replace(/[^-_a-zA-Z0-9\']+?/g, " ");
        article = article.replace(/[ ]+/g, " ");
        cb.call(this, article);
    });
};

// Filter the plaintext content of the article
shortener.filter = function (content, cb) {
    var tokenizer = new natural.WordTokenizer();
    var terms = tokenizer.tokenize(content);
    cb.call(this, terms);
};

// Perform TFIDF on terms (list of words)
shortener.tfidf = function (words, cb) {
    var freqMapObject = getFrequencyMap(words);
    tfidf.getScoreMap(freqMapObject.frequencyMap,
            freqMapObject.totalTermCount, function(scoreMap) {
                cb.call(this, getSortedScoreMap(scoreMap));
            });
};
exports.shorten = shortener.shorten;
<|endoftext|>


<commit_before>function Sounds() {
	Sounds.names = [];
	Sounds.durations = [];
	Sounds.loadNames();
}

Sounds.loadNames=function(){
	var request = "sound/names";
	var callback = function(response) {
		Sounds.names = response.split("\n")
		Sounds.loadDurations();
	};
	HtmlServer.sendRequestWithCallback(request, callback);
};

Sounds.loadDurations=function(){
	var callback = function(index, duration) {
		Sounds.durations[index] = duration;
	}
	for (var i = 0; i < Sound.names.length; i++) {
		var request = "sound/duration/" + Sounds.getSoundName(i);
		var callback = function(duration) {
			Sounds.durations[i] = duration;
		}
		HtmlServer.sendRequestWithCallback(request,callback);
	}
}

Sounds.getSoundDuration=function(index){
	return Sounds.durations[index];
};

Sounds.getSoundName=function(index){
	return Sounds.names[index];
};
Sounds.getSoundCount=function(){
	return Sounds.names.length;
};
Sounds.indexFromName=function(soundName){
	return Sounds.names.indexOf(soundId);
};
Sounds.checkNameIsValid=function(soundName){
	return Sounds.indexFromName(soundName)>=0;
};
<commit_msg>Update Sounds.js<commit_after>function Sounds() {
	Sounds.names = [];
	Sounds.durations = [];
	Sounds.loadNames();
}

Sounds.loadNames=function(){
	var request = "sound/names";
	var callback = function(response) {
		Sounds.names = response.split("\n")
		Sounds.loadDurations();
	};
	HtmlServer.sendRequestWithCallback(request, callback);
};

Sounds.loadDurations=function(){
	var callback = function(index, duration) {
		Sounds.durations[index] = duration;
	}
	for (var i = 0; i < Sound.names.length; i++) {
		var request = "sound/duration/" + Sounds.getSoundName(i);
		var callback = function(duration) {
			Sounds.durations[i] = duration;
		}
		HtmlServer.sendRequestWithCallback(request,callback);
	}
}

Sounds.getSoundDuration=function(index){
	return Sounds.durations[index];
};

Sounds.getSoundName=function(index){
	return Sounds.names[index];
};
Sounds.getSoundCount=function(){
	return Sounds.names.length;
};
Sounds.indexFromName=function(soundName){
	return Sounds.names.indexOf(soundName);
};
Sounds.checkNameIsValid=function(soundName){
	return Sounds.indexFromName(soundName)>=0;
};
<|endoftext|>


<commit_before><commit_msg>updated config with jspm clean<commit_after><|endoftext|>


<commit_before>/**
 * @ngdoc module
 * @name material.core.ripple
 * @description
 * Ripple
 */
angular.module('material.core')
    .factory('$mdInkRipple', InkRippleService)
    .directive('mdInkRipple', InkRippleDirective)
    .directive('mdNoInk', attrNoDirective)
    .directive('mdNoBar', attrNoDirective)
    .directive('mdNoStretch', attrNoDirective);

var DURATION = 450;

/**
 * @ngdoc directive
 * @name mdInkRipple
 * @module material.core.ripple
 *
 * @description
 * The `md-ink-ripple` directive allows you to specify the ripple color or id a ripple is allowed.
 *
 * @param {string|boolean} md-ink-ripple A color string `#FF0000` or boolean (`false` or `0`) for preventing ripple
 *
 * @usage
 * ### String values
 * <hljs lang="html">
 *   <ANY md-ink-ripple="#FF0000">
 *     Ripples in red
 *   </ANY>
 *
 *   <ANY md-ink-ripple="false">
 *     Not rippling
 *   </ANY>
 * </hljs>
 *
 * ### Interpolated values
 * <hljs lang="html">
 *   <ANY md-ink-ripple="{{ randomColor() }}">
 *     Ripples with the return value of 'randomColor' function
 *   </ANY>
 *
 *   <ANY md-ink-ripple="{{ canRipple() }}">
 *     Ripples if 'canRipple' function return value is not 'false' or '0'
 *   </ANY>
 * </hljs>
 */
function InkRippleDirective ($mdButtonInkRipple, $mdCheckboxInkRipple) {
  return {
    controller: angular.noop,
    link:       function (scope, element, attr) {
      attr.hasOwnProperty('mdInkRippleCheckbox')
          ? $mdCheckboxInkRipple.attach(scope, element)
          : $mdButtonInkRipple.attach(scope, element);
    }
  };
}

/**
 * @ngdoc service
 * @name $mdInkRipple
 * @module material.core.ripple
 *
 * @description
 * `$mdInkRipple` is a service for adding ripples to any element
 *
 * @usage
 * <hljs lang="js">
 * app.factory('$myElementInkRipple', function($mdInkRipple) {
 *   return {
 *     attach: function (scope, element, options) {
 *       return $mdInkRipple.attach(scope, element, angular.extend({
 *         center: false,
 *         dimBackground: true
 *       }, options));
 *     }
 *   };
 * });
 *
 * app.controller('myController', function ($scope, $element, $myElementInkRipple) {
 *   $scope.onClick = function (ev) {
 *     $myElementInkRipple.attach($scope, angular.element(ev.target), { center: true });
 *   }
 * });
 * </hljs>
 */

/**
 * @ngdoc method
 * @name $mdInkRipple#attach
 *
 * @description
 * Attaching given scope, element and options to inkRipple controller
 *
 * @param {object=} scope Scope within the current context
 * @param {object=} element The element the ripple effect should be applied to
 * @param {object=} options (Optional) Configuration options to override the defaultRipple configuration
 * * `center` -  Whether the ripple should start from the center of the container element
 * * `dimBackground` - Whether the background should be dimmed with the ripple color
 * * `colorElement` - The element the ripple should take its color from, defined by css property `color`
 * * `fitRipple` - Whether the ripple should fill the element
 */
function InkRippleService ($injector) {
  return { attach: attach };
  function attach (scope, element, options) {
    if (element.controller('mdNoInk')) return angular.noop;
    return $injector.instantiate(InkRippleCtrl, {
      $scope:        scope,
      $element:      element,
      rippleOptions: options
    });
  }
}

/**
 * Controller used by the ripple service in order to apply ripples
 * @ngInject
 */
function InkRippleCtrl ($scope, $element, rippleOptions, $window, $timeout, $mdUtil) {
  this.$window    = $window;
  this.$timeout   = $timeout;
  this.$mdUtil    = $mdUtil;
  this.$scope     = $scope;
  this.$element   = $element;
  this.options    = rippleOptions;
  this.mousedown  = false;
  this.ripples    = [];
  this.timeout    = null; // Stores a reference to the most-recent ripple timeout
  this.lastRipple = null;

  $mdUtil.valueOnUse(this, 'container', this.createContainer);

  this.$element.addClass('md-ink-ripple');

  // attach method for unit tests
  ($element.controller('mdInkRipple') || {}).createRipple = angular.bind(this, this.createRipple);
  ($element.controller('mdInkRipple') || {}).setColor = angular.bind(this, this.color);

  this.bindEvents();
}

/**
 * Either remove or unlock any remaining ripples when the user mouses off of the element (either by
 * mouseup or mouseleave event)
 */
function autoCleanup (self, cleanupFn) {

  if ( self.mousedown || self.lastRipple ) {
    self.mousedown = false;
    self.$mdUtil.nextTick( angular.bind(self, cleanupFn), false);
  }

}

/**
 * Returns the color that the ripple should be (either based on CSS or hard-coded)
 * @returns {string}
 */
InkRippleCtrl.prototype.color = function (value) {
  var self = this;

  // If assigning a color value, apply it to background and the ripple color
  if (angular.isDefined(value)) {
    self._color = self._parseColor(value);
  }

  // If color lookup, use assigned, defined, or inherited
  return self._color || self._parseColor( self.inkRipple() ) || self._parseColor( getElementColor() );

  /**
   * Finds the color element and returns its text color for use as default ripple color
   * @returns {string}
   */
  function getElementColor () {
    var items = self.options && self.options.colorElement ? self.options.colorElement : [];
    var elem =  items.length ? items[ 0 ] : self.$element[ 0 ];

    return elem ? self.$window.getComputedStyle(elem).color : 'rgb(0,0,0)';
  }
};

/**
 * Updating the ripple colors based on the current inkRipple value
 * or the element's computed style color
 */
InkRippleCtrl.prototype.calculateColor = function () {
  return this.color();
};

/**
 * Takes a string color and converts it to RGBA format
 * @param color {string}
 * @param [multiplier] {int}
 * @returns {string}
 */

InkRippleCtrl.prototype._parseColor = function parseColor (color, multiplier) {
  multiplier = multiplier || 1;

  if (!color) return;
  if (color.indexOf('rgba') === 0) return color.replace(/\d?\.?\d*\s*\)\s*$/, (0.1 * multiplier).toString() + ')');
  if (color.indexOf('rgb') === 0) return rgbToRGBA(color);
  if (color.indexOf('#') === 0) return hexToRGBA(color);

  /**
   * Converts hex value to RGBA string
   * @param color {string}
   * @returns {string}
   */
  function hexToRGBA (color) {
    var hex   = color[ 0 ] === '#' ? color.substr(1) : color,
      dig   = hex.length / 3,
      red   = hex.substr(0, dig),
      green = hex.substr(dig, dig),
      blue  = hex.substr(dig * 2);
    if (dig === 1) {
      red += red;
      green += green;
      blue += blue;
    }
    return 'rgba(' + parseInt(red, 16) + ',' + parseInt(green, 16) + ',' + parseInt(blue, 16) + ',0.1)';
  }

  /**
   * Converts an RGB color to RGBA
   * @param color {string}
   * @returns {string}
   */
  function rgbToRGBA (color) {
    return color.replace(')', ', 0.1)').replace('(', 'a(');
  }

};

/**
 * Binds events to the root element for
 */
InkRippleCtrl.prototype.bindEvents = function () {
  this.$element.on('mousedown', angular.bind(this, this.handleMousedown));
  this.$element.on('mouseup touchend', angular.bind(this, this.handleMouseup));
  this.$element.on('mouseleave', angular.bind(this, this.handleMouseup));
  this.$element.on('touchmove', angular.bind(this, this.handleTouchmove));
};

/**
 * Create a new ripple on every mousedown event from the root element
 * @param event {MouseEvent}
 */
InkRippleCtrl.prototype.handleMousedown = function (event) {
  if ( this.mousedown ) return;

  // When jQuery is loaded, we have to get the original event
  if (event.hasOwnProperty('originalEvent')) event = event.originalEvent;
  this.mousedown = true;
  if (this.options.center) {
    this.createRipple(this.container.prop('clientWidth') / 2, this.container.prop('clientWidth') / 2);
  } else {
    this.createRipple(event.offsetX, event.offsetY);
  }
};

/**
 * Either remove or unlock any remaining ripples when the user mouses off of the element (either by
 * mouseup, touchend or mouseleave event)
 */
InkRippleCtrl.prototype.handleMouseup = function () {
  autoCleanup(this, this.clearRipples);
};

/**
 * Either remove or unlock any remaining ripples when the user mouses off of the element (by
 * touchmove)
 */
InkRippleCtrl.prototype.handleTouchmove = function () {
  autoCleanup(this, this.deleteRipples);
};

/**
 * Cycles through all ripples and attempts to remove them.
 */
InkRippleCtrl.prototype.deleteRipples = function () {
  for (var i = 0; i < this.ripples.length; i++) {
    this.ripples[ i ].remove();
  }
};

/**
 * Cycles through all ripples and attempts to remove them with fade.
 * Depending on logic within `fadeInComplete`, some removals will be postponed.
 */
InkRippleCtrl.prototype.clearRipples = function () {
  for (var i = 0; i < this.ripples.length; i++) {
    this.fadeInComplete(this.ripples[ i ]);
  }
};

/**
 * Creates the ripple container element
 * @returns {*}
 */
InkRippleCtrl.prototype.createContainer = function () {
  var container = angular.element('

');
  this.$element.append(container);
  return container;
};

InkRippleCtrl.prototype.clearTimeout = function () {
  if (this.timeout) {
    this.$timeout.cancel(this.timeout);
    this.timeout = null;
  }
};

InkRippleCtrl.prototype.isRippleAllowed = function () {
  var element = this.$element[0];
  do {
    if (!element.tagName || element.tagName === 'BODY') break;

    if (element && angular.isFunction(element.hasAttribute)) {
      if (element.hasAttribute('disabled')) return false;
      if (this.inkRipple() === 'false' || this.inkRipple() === '0') return false;
    }

  } while (element = element.parentNode);
  return true;
};

/**
 * The attribute `md-ink-ripple` may be a static or interpolated
 * color value OR a boolean indicator (used to disable ripples)
 */
InkRippleCtrl.prototype.inkRipple = function () {
  return this.$element.attr('md-ink-ripple');
};

/**
 * Creates a new ripple and adds it to the container.  Also tracks ripple in `this.ripples`.
 * @param left
 * @param top
 */
InkRippleCtrl.prototype.createRipple = function (left, top) {
  if (!this.isRippleAllowed()) return;

  var ctrl        = this;
  var ripple      = angular.element('

');
  var width       = this.$element.prop('clientWidth');
  var height      = this.$element.prop('clientHeight');
  var x           = Math.max(Math.abs(width - left), left) * 2;
  var y           = Math.max(Math.abs(height - top), top) * 2;
  var size        = getSize(this.options.fitRipple, x, y);
  var color       = this.calculateColor();

  ripple.css({
    left:            left + 'px',
    top:             top + 'px',
    background:      'black',
    width:           size + 'px',
    height:          size + 'px',
    backgroundColor: rgbaToRGB(color),
    borderColor:     rgbaToRGB(color)
  });
  this.lastRipple = ripple;

  // we only want one timeout to be running at a time
  this.clearTimeout();
  this.timeout    = this.$timeout(function () {
    ctrl.clearTimeout();
    if (!ctrl.mousedown) ctrl.fadeInComplete(ripple);
  }, DURATION * 0.35, false);

  if (this.options.dimBackground) this.container.css({ backgroundColor: color });
  this.container.append(ripple);
  this.ripples.push(ripple);
  ripple.addClass('md-ripple-placed');

  this.$mdUtil.nextTick(function () {

    ripple.addClass('md-ripple-scaled md-ripple-active');
    ctrl.$timeout(function () {
      ctrl.clearRipples();
    }, DURATION, false);

  }, false);

  function rgbaToRGB (color) {
    return color
        ? color.replace('rgba', 'rgb').replace(/,[^\),]+\)/, ')')
        : 'rgb(0,0,0)';
  }

  function getSize (fit, x, y) {
    return fit
        ? Math.max(x, y)
        : Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
  }
};

/**
 * After fadeIn finishes, either kicks off the fade-out animation or queues the element for removal on mouseup
 * @param ripple
 */
InkRippleCtrl.prototype.fadeInComplete = function (ripple) {
  if (this.lastRipple === ripple) {
    if (!this.timeout && !this.mousedown) {
      this.removeRipple(ripple);
    }
  } else {
    this.removeRipple(ripple);
  }
};

/**
 * Kicks off the animation for removing a ripple
 * @param ripple {Element}
 */
InkRippleCtrl.prototype.removeRipple = function (ripple) {
  var ctrl  = this;
  var index = this.ripples.indexOf(ripple);
  if (index < 0) return;
  this.ripples.splice(this.ripples.indexOf(ripple), 1);
  ripple.removeClass('md-ripple-active');
  if (this.ripples.length === 0) this.container.css({ backgroundColor: '' });
  // use a 2-second timeout in order to allow for the animation to finish
  // we don't actually care how long the animation takes
  this.$timeout(function () {
    ctrl.fadeOutComplete(ripple);
  }, DURATION, false);
};

/**
 * Removes the provided ripple from the DOM
 * @param ripple
 */
InkRippleCtrl.prototype.fadeOutComplete = function (ripple) {
  ripple.remove();
  this.lastRipple = null;
};

/**
 * Used to create an empty directive.  This is used to track flag-directives whose children may have
 * functionality based on them.
 *
 * Example: `md-no-ink` will potentially be used by all child directives.
 */
function attrNoDirective () {
  return { controller: angular.noop };
}
<commit_msg>fix(ripple): calculate relative coordinates from ripple target.<commit_after>/**
 * @ngdoc module
 * @name material.core.ripple
 * @description
 * Ripple
 */
angular.module('material.core')
    .factory('$mdInkRipple', InkRippleService)
    .directive('mdInkRipple', InkRippleDirective)
    .directive('mdNoInk', attrNoDirective)
    .directive('mdNoBar', attrNoDirective)
    .directive('mdNoStretch', attrNoDirective);

var DURATION = 450;

/**
 * @ngdoc directive
 * @name mdInkRipple
 * @module material.core.ripple
 *
 * @description
 * The `md-ink-ripple` directive allows you to specify the ripple color or id a ripple is allowed.
 *
 * @param {string|boolean} md-ink-ripple A color string `#FF0000` or boolean (`false` or `0`) for preventing ripple
 *
 * @usage
 * ### String values
 * <hljs lang="html">
 *   <ANY md-ink-ripple="#FF0000">
 *     Ripples in red
 *   </ANY>
 *
 *   <ANY md-ink-ripple="false">
 *     Not rippling
 *   </ANY>
 * </hljs>
 *
 * ### Interpolated values
 * <hljs lang="html">
 *   <ANY md-ink-ripple="{{ randomColor() }}">
 *     Ripples with the return value of 'randomColor' function
 *   </ANY>
 *
 *   <ANY md-ink-ripple="{{ canRipple() }}">
 *     Ripples if 'canRipple' function return value is not 'false' or '0'
 *   </ANY>
 * </hljs>
 */
function InkRippleDirective ($mdButtonInkRipple, $mdCheckboxInkRipple) {
  return {
    controller: angular.noop,
    link:       function (scope, element, attr) {
      attr.hasOwnProperty('mdInkRippleCheckbox')
          ? $mdCheckboxInkRipple.attach(scope, element)
          : $mdButtonInkRipple.attach(scope, element);
    }
  };
}

/**
 * @ngdoc service
 * @name $mdInkRipple
 * @module material.core.ripple
 *
 * @description
 * `$mdInkRipple` is a service for adding ripples to any element
 *
 * @usage
 * <hljs lang="js">
 * app.factory('$myElementInkRipple', function($mdInkRipple) {
 *   return {
 *     attach: function (scope, element, options) {
 *       return $mdInkRipple.attach(scope, element, angular.extend({
 *         center: false,
 *         dimBackground: true
 *       }, options));
 *     }
 *   };
 * });
 *
 * app.controller('myController', function ($scope, $element, $myElementInkRipple) {
 *   $scope.onClick = function (ev) {
 *     $myElementInkRipple.attach($scope, angular.element(ev.target), { center: true });
 *   }
 * });
 * </hljs>
 */

/**
 * @ngdoc method
 * @name $mdInkRipple#attach
 *
 * @description
 * Attaching given scope, element and options to inkRipple controller
 *
 * @param {object=} scope Scope within the current context
 * @param {object=} element The element the ripple effect should be applied to
 * @param {object=} options (Optional) Configuration options to override the defaultRipple configuration
 * * `center` -  Whether the ripple should start from the center of the container element
 * * `dimBackground` - Whether the background should be dimmed with the ripple color
 * * `colorElement` - The element the ripple should take its color from, defined by css property `color`
 * * `fitRipple` - Whether the ripple should fill the element
 */
function InkRippleService ($injector) {
  return { attach: attach };
  function attach (scope, element, options) {
    if (element.controller('mdNoInk')) return angular.noop;
    return $injector.instantiate(InkRippleCtrl, {
      $scope:        scope,
      $element:      element,
      rippleOptions: options
    });
  }
}

/**
 * Controller used by the ripple service in order to apply ripples
 * @ngInject
 */
function InkRippleCtrl ($scope, $element, rippleOptions, $window, $timeout, $mdUtil) {
  this.$window    = $window;
  this.$timeout   = $timeout;
  this.$mdUtil    = $mdUtil;
  this.$scope     = $scope;
  this.$element   = $element;
  this.options    = rippleOptions;
  this.mousedown  = false;
  this.ripples    = [];
  this.timeout    = null; // Stores a reference to the most-recent ripple timeout
  this.lastRipple = null;

  $mdUtil.valueOnUse(this, 'container', this.createContainer);

  this.$element.addClass('md-ink-ripple');

  // attach method for unit tests
  ($element.controller('mdInkRipple') || {}).createRipple = angular.bind(this, this.createRipple);
  ($element.controller('mdInkRipple') || {}).setColor = angular.bind(this, this.color);

  this.bindEvents();
}

/**
 * Either remove or unlock any remaining ripples when the user mouses off of the element (either by
 * mouseup or mouseleave event)
 */
function autoCleanup (self, cleanupFn) {

  if ( self.mousedown || self.lastRipple ) {
    self.mousedown = false;
    self.$mdUtil.nextTick( angular.bind(self, cleanupFn), false);
  }

}

/**
 * Returns the color that the ripple should be (either based on CSS or hard-coded)
 * @returns {string}
 */
InkRippleCtrl.prototype.color = function (value) {
  var self = this;

  // If assigning a color value, apply it to background and the ripple color
  if (angular.isDefined(value)) {
    self._color = self._parseColor(value);
  }

  // If color lookup, use assigned, defined, or inherited
  return self._color || self._parseColor( self.inkRipple() ) || self._parseColor( getElementColor() );

  /**
   * Finds the color element and returns its text color for use as default ripple color
   * @returns {string}
   */
  function getElementColor () {
    var items = self.options && self.options.colorElement ? self.options.colorElement : [];
    var elem =  items.length ? items[ 0 ] : self.$element[ 0 ];

    return elem ? self.$window.getComputedStyle(elem).color : 'rgb(0,0,0)';
  }
};

/**
 * Updating the ripple colors based on the current inkRipple value
 * or the element's computed style color
 */
InkRippleCtrl.prototype.calculateColor = function () {
  return this.color();
};

/**
 * Takes a string color and converts it to RGBA format
 * @param color {string}
 * @param [multiplier] {int}
 * @returns {string}
 */

InkRippleCtrl.prototype._parseColor = function parseColor (color, multiplier) {
  multiplier = multiplier || 1;

  if (!color) return;
  if (color.indexOf('rgba') === 0) return color.replace(/\d?\.?\d*\s*\)\s*$/, (0.1 * multiplier).toString() + ')');
  if (color.indexOf('rgb') === 0) return rgbToRGBA(color);
  if (color.indexOf('#') === 0) return hexToRGBA(color);

  /**
   * Converts hex value to RGBA string
   * @param color {string}
   * @returns {string}
   */
  function hexToRGBA (color) {
    var hex   = color[ 0 ] === '#' ? color.substr(1) : color,
      dig   = hex.length / 3,
      red   = hex.substr(0, dig),
      green = hex.substr(dig, dig),
      blue  = hex.substr(dig * 2);
    if (dig === 1) {
      red += red;
      green += green;
      blue += blue;
    }
    return 'rgba(' + parseInt(red, 16) + ',' + parseInt(green, 16) + ',' + parseInt(blue, 16) + ',0.1)';
  }

  /**
   * Converts an RGB color to RGBA
   * @param color {string}
   * @returns {string}
   */
  function rgbToRGBA (color) {
    return color.replace(')', ', 0.1)').replace('(', 'a(');
  }

};

/**
 * Binds events to the root element for
 */
InkRippleCtrl.prototype.bindEvents = function () {
  this.$element.on('mousedown', angular.bind(this, this.handleMousedown));
  this.$element.on('mouseup touchend', angular.bind(this, this.handleMouseup));
  this.$element.on('mouseleave', angular.bind(this, this.handleMouseup));
  this.$element.on('touchmove', angular.bind(this, this.handleTouchmove));
};

/**
 * Create a new ripple on every mousedown event from the root element
 * @param event {MouseEvent}
 */
InkRippleCtrl.prototype.handleMousedown = function (event) {
  if ( this.mousedown ) return;

  // When jQuery is loaded, we have to get the original event
  if (event.hasOwnProperty('originalEvent')) event = event.originalEvent;
  this.mousedown = true;
  if (this.options.center) {
    this.createRipple(this.container.prop('clientWidth') / 2, this.container.prop('clientWidth') / 2);
  } else {

    // We need to calculate the relative coordinates if the target is a sublayer of the ripple element
    if (event.srcElement !== this.$element[0]) {
      var layerRect = this.$element[0].getBoundingClientRect();
      var layerX = event.clientX - layerRect.left;
      var layerY = event.clientY - layerRect.top;

      this.createRipple(layerX, layerY);
    } else {
      this.createRipple(event.offsetX, event.offsetY);
    }
  }
};

/**
 * Either remove or unlock any remaining ripples when the user mouses off of the element (either by
 * mouseup, touchend or mouseleave event)
 */
InkRippleCtrl.prototype.handleMouseup = function () {
  autoCleanup(this, this.clearRipples);
};

/**
 * Either remove or unlock any remaining ripples when the user mouses off of the element (by
 * touchmove)
 */
InkRippleCtrl.prototype.handleTouchmove = function () {
  autoCleanup(this, this.deleteRipples);
};

/**
 * Cycles through all ripples and attempts to remove them.
 */
InkRippleCtrl.prototype.deleteRipples = function () {
  for (var i = 0; i < this.ripples.length; i++) {
    this.ripples[ i ].remove();
  }
};

/**
 * Cycles through all ripples and attempts to remove them with fade.
 * Depending on logic within `fadeInComplete`, some removals will be postponed.
 */
InkRippleCtrl.prototype.clearRipples = function () {
  for (var i = 0; i < this.ripples.length; i++) {
    this.fadeInComplete(this.ripples[ i ]);
  }
};

/**
 * Creates the ripple container element
 * @returns {*}
 */
InkRippleCtrl.prototype.createContainer = function () {
  var container = angular.element('

');
  this.$element.append(container);
  return container;
};

InkRippleCtrl.prototype.clearTimeout = function () {
  if (this.timeout) {
    this.$timeout.cancel(this.timeout);
    this.timeout = null;
  }
};

InkRippleCtrl.prototype.isRippleAllowed = function () {
  var element = this.$element[0];
  do {
    if (!element.tagName || element.tagName === 'BODY') break;

    if (element && angular.isFunction(element.hasAttribute)) {
      if (element.hasAttribute('disabled')) return false;
      if (this.inkRipple() === 'false' || this.inkRipple() === '0') return false;
    }

  } while (element = element.parentNode);
  return true;
};

/**
 * The attribute `md-ink-ripple` may be a static or interpolated
 * color value OR a boolean indicator (used to disable ripples)
 */
InkRippleCtrl.prototype.inkRipple = function () {
  return this.$element.attr('md-ink-ripple');
};

/**
 * Creates a new ripple and adds it to the container.  Also tracks ripple in `this.ripples`.
 * @param left
 * @param top
 */
InkRippleCtrl.prototype.createRipple = function (left, top) {
  if (!this.isRippleAllowed()) return;

  var ctrl        = this;
  var ripple      = angular.element('

');
  var width       = this.$element.prop('clientWidth');
  var height      = this.$element.prop('clientHeight');
  var x           = Math.max(Math.abs(width - left), left) * 2;
  var y           = Math.max(Math.abs(height - top), top) * 2;
  var size        = getSize(this.options.fitRipple, x, y);
  var color       = this.calculateColor();

  ripple.css({
    left:            left + 'px',
    top:             top + 'px',
    background:      'black',
    width:           size + 'px',
    height:          size + 'px',
    backgroundColor: rgbaToRGB(color),
    borderColor:     rgbaToRGB(color)
  });
  this.lastRipple = ripple;

  // we only want one timeout to be running at a time
  this.clearTimeout();
  this.timeout    = this.$timeout(function () {
    ctrl.clearTimeout();
    if (!ctrl.mousedown) ctrl.fadeInComplete(ripple);
  }, DURATION * 0.35, false);

  if (this.options.dimBackground) this.container.css({ backgroundColor: color });
  this.container.append(ripple);
  this.ripples.push(ripple);
  ripple.addClass('md-ripple-placed');

  this.$mdUtil.nextTick(function () {

    ripple.addClass('md-ripple-scaled md-ripple-active');
    ctrl.$timeout(function () {
      ctrl.clearRipples();
    }, DURATION, false);

  }, false);

  function rgbaToRGB (color) {
    return color
        ? color.replace('rgba', 'rgb').replace(/,[^\),]+\)/, ')')
        : 'rgb(0,0,0)';
  }

  function getSize (fit, x, y) {
    return fit
        ? Math.max(x, y)
        : Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
  }
};

/**
 * After fadeIn finishes, either kicks off the fade-out animation or queues the element for removal on mouseup
 * @param ripple
 */
InkRippleCtrl.prototype.fadeInComplete = function (ripple) {
  if (this.lastRipple === ripple) {
    if (!this.timeout && !this.mousedown) {
      this.removeRipple(ripple);
    }
  } else {
    this.removeRipple(ripple);
  }
};

/**
 * Kicks off the animation for removing a ripple
 * @param ripple {Element}
 */
InkRippleCtrl.prototype.removeRipple = function (ripple) {
  var ctrl  = this;
  var index = this.ripples.indexOf(ripple);
  if (index < 0) return;
  this.ripples.splice(this.ripples.indexOf(ripple), 1);
  ripple.removeClass('md-ripple-active');
  if (this.ripples.length === 0) this.container.css({ backgroundColor: '' });
  // use a 2-second timeout in order to allow for the animation to finish
  // we don't actually care how long the animation takes
  this.$timeout(function () {
    ctrl.fadeOutComplete(ripple);
  }, DURATION, false);
};

/**
 * Removes the provided ripple from the DOM
 * @param ripple
 */
InkRippleCtrl.prototype.fadeOutComplete = function (ripple) {
  ripple.remove();
  this.lastRipple = null;
};

/**
 * Used to create an empty directive.  This is used to track flag-directives whose children may have
 * functionality based on them.
 *
 * Example: `md-no-ink` will potentially be used by all child directives.
 */
function attrNoDirective () {
  return { controller: angular.noop };
}
<|endoftext|>


<commit_before>var listSequences = require('./list-sequences');
var shouldIgnoreRule = require('./should-ignore-rule');
var shouldIgnoreSelector = require('./should-ignore-selector');
var toInterpoloatedRegexp = require('./to-interpolated-regexp');
var resolveNestedSelector = require('postcss-resolve-nested-selector');

function isTopLevel(node) {
  return node.type === 'root';
}

function isNestedRule(node) {
  return /(?:at)?rule/.test(node.parent.type)
}

function hasNoDeclarations(node) {
  return node.nodes.length && node.every(function(child) {
    return child.type !== 'decl';
  });
}

function getComponentRootRule(node) {
  while (!isTopLevel(node.parent)) {
    node = node.parent;
  }
  return node;
}

function unWrapSelectors(parent, rule) {
  var selectors = [];
  parent.walkRules(function(node) {
    // Only unwrap as far as the current rule being linted
    if (node.selector !== rule.selector) {return;}
    node.selectors.forEach(function(selector) {
      selectors = selectors.concat(resolveNestedSelector(selector, node));
    });
  });
  return selectors;
}

function getSelectors(rule) {
  // Skip validation on parent rules with no declarations
  // as these don't exist after rules have been unwrapped
  if (isTopLevel(rule.parent) && hasNoDeclarations(rule)) {
    return null;
  }

  if (isNestedRule(rule)) {
    var componentRootRule = getComponentRootRule(rule);
    var nestedSelectors = unWrapSelectors(componentRootRule, rule);
    return nestedSelectors;
  }

  return rule.selectors;
}

/**
 * @param {Object} config
 * @param {Rule} config.rule - PostCSS Rule
 * @param {String} config.componentName
 * @param {Boolean} config.weakMode
 * @param {Object} config.selectorPattern
 * @param {Object} config.selectorPatternOptions
 * @param {RegExp} config.ignorePattern
 * @param {Result} config.result - PostCSS Result, for registering warnings
 */
module.exports = function(config) {
  if (shouldIgnoreRule(config.rule)) return;
  var rule = config.rule;

  var initialPattern = (config.selectorPattern.initial)
    ? toInterpoloatedRegexp(config.selectorPattern.initial)(config.componentName, config.selectorPatternOptions)
    : toInterpoloatedRegexp(config.selectorPattern)(config.componentName, config.selectorPatternOptions);
  var combinedPattern = (config.selectorPattern.combined)
    ? toInterpoloatedRegexp(config.selectorPattern.combined)(config.componentName, config.selectorPatternOptions)
    : toInterpoloatedRegexp(initialPattern);
  var selectors = getSelectors(rule);

  if (!selectors) {return;}

  selectors.forEach(function(selector) {
    // Don't bother with :root
    if (selector === ':root') return;

    var allSequences = listSequences(selector);
    var sequence;
    for (var i = 0, l = allSequences.length; i < l; i++) {
      if (config.weakMode && i !== 0) return;
      sequence = allSequences[i];
      if (config.ignorePattern && shouldIgnoreSelector(sequence, config.ignorePattern)) continue;
      if (i === 0 && initialPattern.test(sequence)) continue;
      if (i !== 0 && combinedPattern.test(sequence)) continue;

      config.result.warn(
        'Invalid component selector "' + selector + '"',
        {
          node: rule,
          word: selector,
        }
      );
      return;
    }
  });
}
<commit_msg>Skip checking a rule if it has no declarations<commit_after>var listSequences = require('./list-sequences');
var shouldIgnoreRule = require('./should-ignore-rule');
var shouldIgnoreSelector = require('./should-ignore-selector');
var toInterpoloatedRegexp = require('./to-interpolated-regexp');
var resolveNestedSelector = require('postcss-resolve-nested-selector');

function isTopLevel(node) {
  return node.type === 'root';
}

function isNestedRule(node) {
  return /(?:at)?rule/.test(node.parent.type)
}

function hasNoDeclarations(node) {
  return node.nodes.length && node.every(function(child) {
    return child.type !== 'decl';
  });
}

function getComponentRootRule(node) {
  while (!isTopLevel(node.parent)) {
    node = node.parent;
  }
  return node;
}

function unWrapSelectors(parent, rule) {
  var selectors = [];
  parent.walkRules(function(node) {
    // Only unwrap as far as the current rule being linted
    if (node.selector !== rule.selector) {return;}
    node.selectors.forEach(function(selector) {
      selectors = selectors.concat(resolveNestedSelector(selector, node));
    });
  });
  return selectors;
}

function getSelectors(rule) {
  // Skip validation on rules with no declarations
  // as these don't exist after rules have been unwrapped
  if (hasNoDeclarations(rule)) {
    return null;
  }

  if (isNestedRule(rule)) {
    var componentRootRule = getComponentRootRule(rule);
    var nestedSelectors = unWrapSelectors(componentRootRule, rule);
    return nestedSelectors;
  }

  return rule.selectors;
}

/**
 * @param {Object} config
 * @param {Rule} config.rule - PostCSS Rule
 * @param {String} config.componentName
 * @param {Boolean} config.weakMode
 * @param {Object} config.selectorPattern
 * @param {Object} config.selectorPatternOptions
 * @param {RegExp} config.ignorePattern
 * @param {Result} config.result - PostCSS Result, for registering warnings
 */
module.exports = function(config) {
  if (shouldIgnoreRule(config.rule)) return;
  var rule = config.rule;

  var initialPattern = (config.selectorPattern.initial)
    ? toInterpoloatedRegexp(config.selectorPattern.initial)(config.componentName, config.selectorPatternOptions)
    : toInterpoloatedRegexp(config.selectorPattern)(config.componentName, config.selectorPatternOptions);
  var combinedPattern = (config.selectorPattern.combined)
    ? toInterpoloatedRegexp(config.selectorPattern.combined)(config.componentName, config.selectorPatternOptions)
    : toInterpoloatedRegexp(initialPattern);
  var selectors = getSelectors(rule);

  if (!selectors) {return;}

  selectors.forEach(function(selector) {
    // Don't bother with :root
    if (selector === ':root') return;

    var allSequences = listSequences(selector);
    var sequence;
    for (var i = 0, l = allSequences.length; i < l; i++) {
      if (config.weakMode && i !== 0) return;
      sequence = allSequences[i];
      if (config.ignorePattern && shouldIgnoreSelector(sequence, config.ignorePattern)) continue;
      if (i === 0 && initialPattern.test(sequence)) continue;
      if (i !== 0 && combinedPattern.test(sequence)) continue;

      config.result.warn(
        'Invalid component selector "' + selector + '"',
        {
          node: rule,
          word: selector,
        }
      );
      return;
    }
  });
}
<|endoftext|>


<commit_before>var mongoose = require("mongoose");

var childSchema = new mongoose.Schema({
	firstname: String,
	lastname: String,
	age: Number,
	student: Boolean,
	type: String
});

module.exports = mongoose.model("Child", childSchema);<commit_msg>Updated child schema<commit_after>var mongoose = require("mongoose");

var childSchema = new mongoose.Schema({
	firstname: String,
	lastname: String,
	age: Number,
	student: Boolean,
	ethnicity: String,
	race: String,
	type: String
});

module.exports = mongoose.model("Child", childSchema);<|endoftext|>


<commit_before>"use strict";

/*global process*/

const
    ESLINT = "../node_modules/eslint/",
    RULES = ESLINT + "lib/rules",
    CONFIGURATION = "../.eslintrc",

    fs = require("fs"),
    path = require("path"),

    levels = [
        "ignore",
        "warning",
        "error",
        "-"
    ],

    gpfConfiguration = JSON.parse(fs.readFileSync(path.join(__dirname, CONFIGURATION)).toString()),
    ruleFilenames = fs.readdirSync(path.join(__dirname, RULES)),
    orderOfCategories = [
        "Possible Errors",
        "Best Practices",
        "Strict Mode",
        "Variables",
        "Node.js and CommonJS",
        "Stylistic Issues",
        "ECMAScript 6"
    ]
;

ruleFilenames
    .map(ruleFilename => {
        const
            name = path.basename(ruleFilename, ".js"),
            rule = require(path.join(__dirname, "../node_modules/eslint/lib/rules", ruleFilename)),
            docs = rule.meta.docs,
            category = docs.category,
            description = docs.description,
            recommended = docs.recommended,
            hasProperties = rule.meta.schema.length ? rule.meta.schema[0].properties : false,
            config = gpfConfiguration.rules[name];
        let
            level = levels.length - 1,
            hasPropertiesSet = false;
        if (Array.isArray(config)) {
            level = config[0];
        } else if (undefined !== config) {
            level = config;
        }
        return {
            name,
            category,
            description,
            recommended,
            hasProperties,
            config,
            level,
            hasPropertiesSet
        };
    })
    .sort((rule1, rule2) => {
        const
            rule1CategoryOrder = orderOfCategories.indexOf(rule1.category),
            rule2CategoryOrder = orderOfCategories.indexOf(rule2.category);
        if (rule1CategoryOrder !== rule2CategoryOrder) {
            return rule1CategoryOrder - rule2CategoryOrder;
        }
        return rule1.name.localeCompare(rule2.name);
    })
    .forEach((rule, index, rules) => {
        const flag = (value, mark) => value ? mark : " ";
        if (0 === index || rules[index - 1].category !== rule.category) {
            console.log(rule.category);
        }
        if (rule.hasPropertiesSet && !rule.hasProperties) {
            console.error(`Unexpected parameters for ${rule.name}`);
        }
        console.log(
            "\t",
            rule.name.padEnd(40, " "),
            flag(rule.recommended, "R"),
            levels[rule.level].padEnd(7),
            flag(rule.hasPropertiesSet, "C")
        );
    });
<commit_msg>Detecting unsupported (obsolete?) keys (#280)<commit_after>"use strict";

/*global process*/

const
    ESLINT = "../node_modules/eslint/",
    RULES = ESLINT + "lib/rules",
    CONFIGURATION = "../.eslintrc",

    fs = require("fs"),
    path = require("path"),

    levels = [
        "ignore",
        "warning",
        "error",
        "-"
    ],

    gpfConfiguration = JSON.parse(fs.readFileSync(path.join(__dirname, CONFIGURATION)).toString()),
    ruleFilenames = fs.readdirSync(path.join(__dirname, RULES)),
    orderOfCategories = [
        "Possible Errors",
        "Best Practices",
        "Strict Mode",
        "Variables",
        "Node.js and CommonJS",
        "Stylistic Issues",
        "ECMAScript 6"
    ]
;

// Assess that all rules specified in the .eslintrc actually exists !
Object.keys(gpfConfiguration.rules)
    .filter(name => !ruleFilenames.includes(`${name}.js`))
    .forEach(name => {
        console.error(`Unknown rule name: ${name}`)
    });

ruleFilenames
    .map(ruleFilename => {
        const
            name = path.basename(ruleFilename, ".js"),
            rule = require(path.join(__dirname, "../node_modules/eslint/lib/rules", ruleFilename)),
            docs = rule.meta.docs,
            category = docs.category,
            description = docs.description,
            recommended = docs.recommended,
            hasProperties = rule.meta.schema.length ? rule.meta.schema[0].properties : false,
            config = gpfConfiguration.rules[name];
        let
            level = levels.length - 1,
            hasPropertiesSet = false;
        if (Array.isArray(config)) {
            level = config[0];
        } else if (undefined !== config) {
            level = config;
        }
        return {
            name,
            category,
            description,
            recommended,
            hasProperties,
            config,
            level,
            hasPropertiesSet
        };
    })
    .sort((rule1, rule2) => {
        const
            rule1CategoryOrder = orderOfCategories.indexOf(rule1.category),
            rule2CategoryOrder = orderOfCategories.indexOf(rule2.category);
        if (rule1CategoryOrder !== rule2CategoryOrder) {
            return rule1CategoryOrder - rule2CategoryOrder;
        }
        return rule1.name.localeCompare(rule2.name);
    })
    .forEach((rule, index, rules) => {
        const flag = (value, mark) => value ? mark : " ";
        if (0 === index || rules[index - 1].category !== rule.category) {
            console.log(rule.category);
        }
        if (rule.hasPropertiesSet && !rule.hasProperties) {
            console.error(`Unexpected parameters for ${rule.name}`);
        }
        console.log(
            "\t",
            rule.name.padEnd(40, " "),
            flag(rule.recommended, "R"),
            levels[rule.level].padEnd(7),
            flag(rule.hasPropertiesSet, "C")
        );
    });
<|endoftext|>


<commit_before>var gm = require("gm"),
	events = require("events"),
	util = require("util"),
	spawn = require("child_process").spawn,
	fs = require("fs"),
	exec = require('child_process').exec;

// flag to tell if a process is running
var PROCESS_RUNNING_FLAG = false;

// the process id of the process spawned to take photos/video
var child_process = null;

// Exit strategy to kill child process
// (eg. for timelapse) on parent process exit
process.on('exit', function() {
	if(PROCESS_RUNNING_FLAG){
		child_process.kill();
	}
});

function cowboy() {

}

util.inherits( cowboy, events.EventEmitter );

cowboy.prototype.mask = function(depth_imagepath, rgb_imagepath, destination_path, imagename, threshold){
	// depth_imagepath and rgb_imagepath include full paths
	// destination_path has trailing slash
	// threshold: "can be given as a percentage or as an absolute integer value corresponding to the desired channel value."
	// See: http://www.imagemagick.org/script/command-line-options.php#threshold
	//
	var self = this;

	var gmcommand = "convert";
	var gmargs = depth_imagepath + " -colorspace Gray -write mpr:mask +delete mpr:mask -fill white -opaque black -write mpr:mask +delete mpr:mask -threshold " + threshold + " -write mpr:mask +delete mpr:mask -negate -write mpr:mask +delete " + rgb_imagepath + " mpr:mask -alpha Off -compose CopyOpacity -composite " + destination_path + imagename;
	//get rid of double spaces
	gmargs = gmargs.replace(/ +(?= )/g,'');
	gmargs = gmargs.split(" ");

	this.child_process = spawn(gmcommand, gmargs);
	child_process = this.child_process;
	PROCESS_RUNNING_FLAG = true;

	this.child_process.stdout.on('data', function (data) {
		console.log('stdout: ' + data);
		dout = data;
	});

	this.child_process.stderr.on('data', function (data) {
		console.log('stderr: ' + data);
		derr = data;
	});

	this.child_process.on('close', function (code) {
		//emit exit signal for process chaining over time
		self.emit( "exit", destination_path + imagename);

		PROCESS_RUNNING_FLAG = false;
		self.child_process = null;
		child_process = null;
	});

};

module.exports = cowboy;
<commit_msg>commit<commit_after>	var events = require("events"),
	util = require("util"),
	spawn = require("child_process").spawn,
	fs = require("fs"),
	exec = require('child_process').exec;

// flag to tell if a process is running
var PROCESS_RUNNING_FLAG = false;

// the process id of the process spawned to take photos/video
var child_process = null;

// Exit strategy to kill child process
// (eg. for timelapse) on parent process exit
process.on('exit', function() {
	if(PROCESS_RUNNING_FLAG){
		child_process.kill();
	}
});

function cowboy() {

}

util.inherits( cowboy, events.EventEmitter );

cowboy.prototype.mask = function(depth_imagepath, rgb_imagepath, destination_path, imagename, threshold){
	// depth_imagepath and rgb_imagepath include full paths
	// destination_path has trailing slash
	// threshold: "can be given as a percentage or as an absolute integer value corresponding to the desired channel value."
	// See: http://www.imagemagick.org/script/command-line-options.php#threshold
	//
	var self = this;

	var gmcommand = "convert";
	var gmargs = depth_imagepath + " -colorspace Gray -write mpr:mask +delete mpr:mask -fill white -opaque black -write mpr:mask +delete mpr:mask -threshold " + threshold + " -write mpr:mask +delete mpr:mask -negate -write mpr:mask +delete " + rgb_imagepath + " mpr:mask -alpha Off -compose CopyOpacity -composite " + destination_path + imagename;
	//get rid of double spaces
	gmargs = gmargs.replace(/ +(?= )/g,'');
	gmargs = gmargs.split(" ");

	this.child_process = spawn(gmcommand, gmargs);
	child_process = this.child_process;
	PROCESS_RUNNING_FLAG = true;

	this.child_process.stdout.on('data', function (data) {
		console.log('stdout: ' + data);
		dout = data;
	});

	this.child_process.stderr.on('data', function (data) {
		console.log('stderr: ' + data);
		derr = data;
	});

	this.child_process.on('close', function (code) {
		//emit exit signal for process chaining over time
		self.emit( "exit", destination_path + imagename);

		PROCESS_RUNNING_FLAG = false;
		self.child_process = null;
		child_process = null;
	});

};

module.exports = cowboy;
<|endoftext|>