<commit_before>define([
  'angular',
  'lodash',
  'moment',
  './query_ctrl',
  './directives',
],
function (angular, _) {
  'use strict';

  var module = angular.module('grafana.services');

  module.factory('CloudWatchDatasource', function($q, backendSrv, templateSrv) {

    function CloudWatchDatasource(datasource) {
      this.type = 'cloudwatch';
      this.name = datasource.name;
      this.supportMetrics = true;
      this.proxyUrl = datasource.url;
      this.defaultRegion = datasource.jsonData.defaultRegion;
    }

    CloudWatchDatasource.prototype.query = function(options) {
      var start = convertToCloudWatchTime(options.range.from);
      var end = convertToCloudWatchTime(options.range.to);

      var queries = [];
      _.each(options.targets, _.bind(function(target) {
        if (target.hide || !target.namespace || !target.metricName || _.isEmpty(target.statistics)) {
          return;
        }

        var query = {};
        query.region = templateSrv.replace(target.region, options.scopedVars);
        query.namespace = templateSrv.replace(target.namespace, options.scopedVars);
        query.metricName = templateSrv.replace(target.metricName, options.scopedVars);
        query.dimensions = convertDimensionFormat(target.dimensions, options.scopedVars);
        query.statistics = target.statistics;

        var range = end - start;
        query.period = parseInt(target.period, 10) || 60;

        if (range / query.period >= 1440) {
          query.period = Math.ceil(range / 1440 / 60) * 60;
        }

        queries.push(query);
      }, this));

      // No valid targets, return the empty result to save a round trip.
      if (_.isEmpty(queries)) {
        var d = $q.defer();
        d.resolve({ data: [] });
        return d.promise;
      }

      var allQueryPromise = _.map(queries, function(query) {
        return this.performTimeSeriesQuery(query, start, end);
      }, this);

      return $q.all(allQueryPromise).then(function(allResponse) {
        var result = [];

        _.each(allResponse, function(response, index) {
          var metrics = transformMetricData(response, options.targets[index]);
          result = result.concat(metrics);
        });

        return { data: result };
      });
    };

    CloudWatchDatasource.prototype.performTimeSeriesQuery = function(query, start, end) {
      return this.awsRequest({
        region: query.region,
        action: 'GetMetricStatistics',
        parameters:  {
          namespace: query.namespace,
          metricName: query.metricName,
          dimensions: query.dimensions,
          statistics: query.statistics,
          startTime: start,
          endTime: end,
          period: query.period
        }
      });
    };

    CloudWatchDatasource.prototype.getRegions = function() {
      return this.awsRequest({action: '__GetRegions'});
    };

    CloudWatchDatasource.prototype.getNamespaces = function() {
      return this.awsRequest({action: '__GetNamespaces'});
    };

    CloudWatchDatasource.prototype.getMetrics = function(namespace) {
      return this.awsRequest({
        action: '__GetMetrics',
        parameters: {
          namespace: templateSrv.replace(namespace)
        }
      });
    };

    CloudWatchDatasource.prototype.getDimensionKeys = function(namespace) {
      return this.awsRequest({
        action: '__GetDimensions',
        parameters: {
          namespace: templateSrv.replace(namespace)
        }
      });
    };

    CloudWatchDatasource.prototype.getDimensionValues = function(region, namespace, metricName, dimensions) {
      var request = {
        region: templateSrv.replace(region),
        action: 'ListMetrics',
        parameters: {
          namespace: templateSrv.replace(namespace),
          metricName: templateSrv.replace(metricName),
          dimensions: convertDimensionFormat(dimensions, {}),
        }
      };

      return this.awsRequest(request).then(function(result) {
        return _.chain(result.Metrics).map(function(metric) {
          return _.pluck(metric.Dimensions, 'Value');
        }).flatten().uniq().sortBy(function(name) {
          return name;
        }).map(function(value) {
          return {value: value, text: value};
        }).value();
      });
    };

    CloudWatchDatasource.prototype.performEC2DescribeInstances = function(region, filters, instanceIds) {
      return this.awsRequest({
        region: region,
        action: 'DescribeInstances',
        parameters: { filter: filters, instanceIds: instanceIds }
      });
    };

    CloudWatchDatasource.prototype.metricFindQuery = function(query) {
      var region;
      var namespace;
      var metricName;

      var transformSuggestData = function(suggestData) {
        return _.map(suggestData, function(v) {
          return { text: v };
        });
      };

      var regionQuery = query.match(/^regions\(\)/);
      if (regionQuery) {
        return this.getRegions();
      }

      var namespaceQuery = query.match(/^namespaces\(\)/);
      if (namespaceQuery) {
        return this.getNamespaces();
      }

      var metricNameQuery = query.match(/^metrics\(([^\)]+?)\)/);
      if (metricNameQuery) {
        return this.getMetrics(metricNameQuery[1]);
      }

      var dimensionKeysQuery = query.match(/^dimension_keys\(([^\)]+?)\)/);
      if (dimensionKeysQuery) {
        return this.getDimensionKeys(dimensionKeysQuery[1]);
      }

      var dimensionValuesQuery = query.match(/^dimension_values\(([^,]+?),\s?([^,]+?),\s?([^,]+?)(,\s?([^)]*))?\)/);
      if (dimensionValuesQuery) {
        region = templateSrv.replace(dimensionValuesQuery[1]);
        namespace = templateSrv.replace(dimensionValuesQuery[2]);
        metricName = templateSrv.replace(dimensionValuesQuery[3]);
        var dimensionPart = templateSrv.replace(dimensionValuesQuery[5]);

        var dimensions = {};
        if (!_.isEmpty(dimensionPart)) {
          _.each(dimensionPart.split(','), function(v) {
            var t = v.split('=');
            if (t.length !== 2) {
              throw new Error('Invalid query format');
            }
            dimensions[t[0]] = t[1];
          });
        }

        return this.getDimensionValues(region, namespace, metricName, dimensions);
      }

      var ebsVolumeIdsQuery = query.match(/^ebs_volume_ids\(([^,]+?),\s?([^,]+?)\)/);
      if (ebsVolumeIdsQuery) {
        region = templateSrv.replace(ebsVolumeIdsQuery[1]);
        var instanceId = templateSrv.replace(ebsVolumeIdsQuery[2]);
        var instanceIds = [
          instanceId
        ];

        return this.performEC2DescribeInstances(region, [], instanceIds).then(function(result) {
          var volumeIds = _.map(result.Reservations[0].Instances[0].BlockDeviceMappings, function(mapping) {
            return mapping.EBS.VolumeID;
          });

          return transformSuggestData(volumeIds);
        });
      }

      return $q.when([]);
    };

    CloudWatchDatasource.prototype.testDatasource = function() {
      /* use billing metrics for test */
      var region = 'us-east-1';
      var namespace = 'AWS/Billing';
      var metricName = 'EstimatedCharges';
      var dimensions = {};

      return this.getDimensionValues(region, namespace, metricName, dimensions).then(function () {
        return { status: 'success', message: 'Data source is working', title: 'Success' };
      });
    };

    CloudWatchDatasource.prototype.awsRequest = function(data) {
      var options = {
        method: 'POST',
        url: this.proxyUrl,
        data: data
      };

      return backendSrv.datasourceRequest(options).then(function(result) {
        return result.data;
      });
    };

    CloudWatchDatasource.prototype.getDefaultRegion = function() {
      return this.defaultRegion;
    };

    function transformMetricData(md, options) {
      var aliasRegex = /\{\{(.+?)\}\}/g;
      var aliasPattern = options.alias || '{{metric}}_{{stat}}';
      var aliasData = {
        region: templateSrv.replace(options.region),
        namespace: templateSrv.replace(options.namespace),
        metric: templateSrv.replace(options.metricName),
      };
      _.extend(aliasData, options.dimensions);

      return _.map(options.statistics, function(stat) {
        var dps = _.chain(md.Datapoints).map(function(dp) {
          return [dp[stat], new Date(dp.Timestamp).getTime()];
        })
        .sortBy(function(dp) {
          return dp[1];
        }).value();

        aliasData.stat = stat;
        var seriesName = aliasPattern.replace(aliasRegex, function(match, g1) {
          if (aliasData[g1]) {
            return aliasData[g1];
          }
          return g1;
        });

        return {target: seriesName, datapoints: dps};
      });
    }

    function convertToCloudWatchTime(date) {
      return Math.round(date.valueOf() / 1000);
    }

    function convertDimensionFormat(dimensions, scopedVars) {
      return _.map(dimensions, function(value, key) {
        return {
          Name: templateSrv.replace(key, scopedVars),
          Value: templateSrv.replace(value, scopedVars)
        };
      });
    }

    return CloudWatchDatasource;
  });

});
<commit_msg>Check specified AWS Region and not us-east-1<commit_after>define([
  'angular',
  'lodash',
  'moment',
  './query_ctrl',
  './directives',
],
function (angular, _) {
  'use strict';

  var module = angular.module('grafana.services');

  module.factory('CloudWatchDatasource', function($q, backendSrv, templateSrv) {

    function CloudWatchDatasource(datasource) {
      this.type = 'cloudwatch';
      this.name = datasource.name;
      this.supportMetrics = true;
      this.proxyUrl = datasource.url;
      this.defaultRegion = datasource.jsonData.defaultRegion;
    }

    CloudWatchDatasource.prototype.query = function(options) {
      var start = convertToCloudWatchTime(options.range.from);
      var end = convertToCloudWatchTime(options.range.to);

      var queries = [];
      _.each(options.targets, _.bind(function(target) {
        if (target.hide || !target.namespace || !target.metricName || _.isEmpty(target.statistics)) {
          return;
        }

        var query = {};
        query.region = templateSrv.replace(target.region, options.scopedVars);
        query.namespace = templateSrv.replace(target.namespace, options.scopedVars);
        query.metricName = templateSrv.replace(target.metricName, options.scopedVars);
        query.dimensions = convertDimensionFormat(target.dimensions, options.scopedVars);
        query.statistics = target.statistics;

        var range = end - start;
        query.period = parseInt(target.period, 10) || 60;

        if (range / query.period >= 1440) {
          query.period = Math.ceil(range / 1440 / 60) * 60;
        }

        queries.push(query);
      }, this));

      // No valid targets, return the empty result to save a round trip.
      if (_.isEmpty(queries)) {
        var d = $q.defer();
        d.resolve({ data: [] });
        return d.promise;
      }

      var allQueryPromise = _.map(queries, function(query) {
        return this.performTimeSeriesQuery(query, start, end);
      }, this);

      return $q.all(allQueryPromise).then(function(allResponse) {
        var result = [];

        _.each(allResponse, function(response, index) {
          var metrics = transformMetricData(response, options.targets[index]);
          result = result.concat(metrics);
        });

        return { data: result };
      });
    };

    CloudWatchDatasource.prototype.performTimeSeriesQuery = function(query, start, end) {
      return this.awsRequest({
        region: query.region,
        action: 'GetMetricStatistics',
        parameters:  {
          namespace: query.namespace,
          metricName: query.metricName,
          dimensions: query.dimensions,
          statistics: query.statistics,
          startTime: start,
          endTime: end,
          period: query.period
        }
      });
    };

    CloudWatchDatasource.prototype.getRegions = function() {
      return this.awsRequest({action: '__GetRegions'});
    };

    CloudWatchDatasource.prototype.getNamespaces = function() {
      return this.awsRequest({action: '__GetNamespaces'});
    };

    CloudWatchDatasource.prototype.getMetrics = function(namespace) {
      return this.awsRequest({
        action: '__GetMetrics',
        parameters: {
          namespace: templateSrv.replace(namespace)
        }
      });
    };

    CloudWatchDatasource.prototype.getDimensionKeys = function(namespace) {
      return this.awsRequest({
        action: '__GetDimensions',
        parameters: {
          namespace: templateSrv.replace(namespace)
        }
      });
    };

    CloudWatchDatasource.prototype.getDimensionValues = function(region, namespace, metricName, dimensions) {
      var request = {
        region: templateSrv.replace(region),
        action: 'ListMetrics',
        parameters: {
          namespace: templateSrv.replace(namespace),
          metricName: templateSrv.replace(metricName),
          dimensions: convertDimensionFormat(dimensions, {}),
        }
      };

      return this.awsRequest(request).then(function(result) {
        return _.chain(result.Metrics).map(function(metric) {
          return _.pluck(metric.Dimensions, 'Value');
        }).flatten().uniq().sortBy(function(name) {
          return name;
        }).map(function(value) {
          return {value: value, text: value};
        }).value();
      });
    };

    CloudWatchDatasource.prototype.performEC2DescribeInstances = function(region, filters, instanceIds) {
      return this.awsRequest({
        region: region,
        action: 'DescribeInstances',
        parameters: { filter: filters, instanceIds: instanceIds }
      });
    };

    CloudWatchDatasource.prototype.metricFindQuery = function(query) {
      var region;
      var namespace;
      var metricName;

      var transformSuggestData = function(suggestData) {
        return _.map(suggestData, function(v) {
          return { text: v };
        });
      };

      var regionQuery = query.match(/^regions\(\)/);
      if (regionQuery) {
        return this.getRegions();
      }

      var namespaceQuery = query.match(/^namespaces\(\)/);
      if (namespaceQuery) {
        return this.getNamespaces();
      }

      var metricNameQuery = query.match(/^metrics\(([^\)]+?)\)/);
      if (metricNameQuery) {
        return this.getMetrics(metricNameQuery[1]);
      }

      var dimensionKeysQuery = query.match(/^dimension_keys\(([^\)]+?)\)/);
      if (dimensionKeysQuery) {
        return this.getDimensionKeys(dimensionKeysQuery[1]);
      }

      var dimensionValuesQuery = query.match(/^dimension_values\(([^,]+?),\s?([^,]+?),\s?([^,]+?)(,\s?([^)]*))?\)/);
      if (dimensionValuesQuery) {
        region = templateSrv.replace(dimensionValuesQuery[1]);
        namespace = templateSrv.replace(dimensionValuesQuery[2]);
        metricName = templateSrv.replace(dimensionValuesQuery[3]);
        var dimensionPart = templateSrv.replace(dimensionValuesQuery[5]);

        var dimensions = {};
        if (!_.isEmpty(dimensionPart)) {
          _.each(dimensionPart.split(','), function(v) {
            var t = v.split('=');
            if (t.length !== 2) {
              throw new Error('Invalid query format');
            }
            dimensions[t[0]] = t[1];
          });
        }

        return this.getDimensionValues(region, namespace, metricName, dimensions);
      }

      var ebsVolumeIdsQuery = query.match(/^ebs_volume_ids\(([^,]+?),\s?([^,]+?)\)/);
      if (ebsVolumeIdsQuery) {
        region = templateSrv.replace(ebsVolumeIdsQuery[1]);
        var instanceId = templateSrv.replace(ebsVolumeIdsQuery[2]);
        var instanceIds = [
          instanceId
        ];

        return this.performEC2DescribeInstances(region, [], instanceIds).then(function(result) {
          var volumeIds = _.map(result.Reservations[0].Instances[0].BlockDeviceMappings, function(mapping) {
            return mapping.EBS.VolumeID;
          });

          return transformSuggestData(volumeIds);
        });
      }

      return $q.when([]);
    };

    CloudWatchDatasource.prototype.testDatasource = function() {
      /* use billing metrics for test */
      var region = this.defaultRegion;
      var namespace = 'AWS/Billing';
      var metricName = 'EstimatedCharges';
      var dimensions = {};

      return this.getDimensionValues(region, namespace, metricName, dimensions).then(function () {
        return { status: 'success', message: 'Data source is working', title: 'Success' };
      });
    };

    CloudWatchDatasource.prototype.awsRequest = function(data) {
      var options = {
        method: 'POST',
        url: this.proxyUrl,
        data: data
      };

      return backendSrv.datasourceRequest(options).then(function(result) {
        return result.data;
      });
    };

    CloudWatchDatasource.prototype.getDefaultRegion = function() {
      return this.defaultRegion;
    };

    function transformMetricData(md, options) {
      var aliasRegex = /\{\{(.+?)\}\}/g;
      var aliasPattern = options.alias || '{{metric}}_{{stat}}';
      var aliasData = {
        region: templateSrv.replace(options.region),
        namespace: templateSrv.replace(options.namespace),
        metric: templateSrv.replace(options.metricName),
      };
      _.extend(aliasData, options.dimensions);

      return _.map(options.statistics, function(stat) {
        var dps = _.chain(md.Datapoints).map(function(dp) {
          return [dp[stat], new Date(dp.Timestamp).getTime()];
        })
        .sortBy(function(dp) {
          return dp[1];
        }).value();

        aliasData.stat = stat;
        var seriesName = aliasPattern.replace(aliasRegex, function(match, g1) {
          if (aliasData[g1]) {
            return aliasData[g1];
          }
          return g1;
        });

        return {target: seriesName, datapoints: dps};
      });
    }

    function convertToCloudWatchTime(date) {
      return Math.round(date.valueOf() / 1000);
    }

    function convertDimensionFormat(dimensions, scopedVars) {
      return _.map(dimensions, function(value, key) {
        return {
          Name: templateSrv.replace(key, scopedVars),
          Value: templateSrv.replace(value, scopedVars)
        };
      });
    }

    return CloudWatchDatasource;
  });

});
<|endoftext|>


<commit_before>'use strict';
module.exports = (sequelize, DataTypes)=> {
    var Log = sequelize.define('log', {
            id: {
                type: DataTypes.INTEGER.UNSIGNED,
                autoIncrement: true,
                primaryKey: true
            },
            downloadedTimetables: {
                type: DataTypes.INTEGER.UNSIGNED,
                allowNull: true,
                set: (val)=> {
                    this.setDataValue('exceptiopnsExtracted', val);
                    this.setDataValue('exceptiopnsExtractedAt', new Date());
                }
            },
            downloadedTimetablesAt: {
                type: DataTypes.DATE,
                allowNull: true
            },
            exceptionsExtracted: {
                type: DataTypes.INTEGER.UNSIGNED,
                allowNull: true,
                set: (val)=> {
                    this.setDataValue('exceptionsExtracted', val);
                    this.setDataValue('exceptionsExtractedAt', new Date());
                }
            },
            exceptionsExtractedAt: {
                type: DataTypes.DATE,
                allowNull: true
            },
            eventsExtracted: {
                type: DataTypes.INTEGER.UNSIGNED,
                allowNull: true,
                set: (val)=> {
                    this.setDataValue('eventsExtracted', val);
                    this.setDataValue('eventsExtractedAt', new Date());
                }
            },
            eventsExtractedAt: {
                type: DataTypes.DATE,
                allowNull: true
            },
            eventtempsInserted: {
                type: DataTypes.INTEGER.UNSIGNED,
                allowNull: true,
                set: (val)=> {
                    this.setDataValue('eventtempsInserted', val);
                    this.setDataValue('eventtempsInsertedAt', new Date());
                }
            },
            eventtempsInsertedAt: {
                type: DataTypes.DATE,
                allowNull: true
            },
            eventsInserted: {
                type: DataTypes.INTEGER.UNSIGNED,
                allowNull: true,
                set: (val)=> {
                    this.setDataValue('eventsInserted', val);
                    this.setDataValue('eventsInsertedAt', new Date());
                }
            },
            eventsInsertedAt: {
                type: DataTypes.DATE,
                allowNull: true
            },
            eventsDeleted: {
                type: DataTypes.INTEGER.UNSIGNED,
                allowNull: true,
                set: (val)=> {
                    this.setDataValue('eventsDeleted', val);
                    this.setDataValue('eventsDeletedAt', new Date());
                }
            },
            eventsDeletedAt: {
                type: DataTypes.DATE,
                allowNull: true
            },
            eventsUpdated: {
                type: DataTypes.INTEGER.UNSIGNED,
                allowNull: true,
                set: (val)=> {
                    this.setDataValue('eventsUpdated', val);
                    this.setDataValue('eventsUpdatedAt', new Date());
                }
            },
            eventsUpdatedAt: {
                type: DataTypes.DATE,
                allowNull: true
            }
        },
        {
            timestamps: true
        });
    return Log;
};<commit_msg>Fix - typ<commit_after>'use strict';
module.exports = (sequelize, DataTypes)=> {
    var Log = sequelize.define('log', {
            id: {
                type: DataTypes.INTEGER.UNSIGNED,
                autoIncrement: true,
                primaryKey: true
            },
            downloadedTimetables: {
                type: DataTypes.INTEGER.UNSIGNED,
                allowNull: true,
                set: (val)=> {
                    this.setDataValue('downloadedTimetables', val);
                    this.setDataValue('downloadedTimetablesAt', new Date());
                }
            },
            downloadedTimetablesAt: {
                type: DataTypes.DATE,
                allowNull: true
            },
            exceptionsExtracted: {
                type: DataTypes.INTEGER.UNSIGNED,
                allowNull: true,
                set: (val)=> {
                    this.setDataValue('exceptionsExtracted', val);
                    this.setDataValue('exceptionsExtractedAt', new Date());
                }
            },
            exceptionsExtractedAt: {
                type: DataTypes.DATE,
                allowNull: true
            },
            eventsExtracted: {
                type: DataTypes.INTEGER.UNSIGNED,
                allowNull: true,
                set: (val)=> {
                    this.setDataValue('eventsExtracted', val);
                    this.setDataValue('eventsExtractedAt', new Date());
                }
            },
            eventsExtractedAt: {
                type: DataTypes.DATE,
                allowNull: true
            },
            eventtempsInserted: {
                type: DataTypes.INTEGER.UNSIGNED,
                allowNull: true,
                set: (val)=> {
                    this.setDataValue('eventtempsInserted', val);
                    this.setDataValue('eventtempsInsertedAt', new Date());
                }
            },
            eventtempsInsertedAt: {
                type: DataTypes.DATE,
                allowNull: true
            },
            eventsInserted: {
                type: DataTypes.INTEGER.UNSIGNED,
                allowNull: true,
                set: (val)=> {
                    this.setDataValue('eventsInserted', val);
                    this.setDataValue('eventsInsertedAt', new Date());
                }
            },
            eventsInsertedAt: {
                type: DataTypes.DATE,
                allowNull: true
            },
            eventsDeleted: {
                type: DataTypes.INTEGER.UNSIGNED,
                allowNull: true,
                set: (val)=> {
                    this.setDataValue('eventsDeleted', val);
                    this.setDataValue('eventsDeletedAt', new Date());
                }
            },
            eventsDeletedAt: {
                type: DataTypes.DATE,
                allowNull: true
            },
            eventsUpdated: {
                type: DataTypes.INTEGER.UNSIGNED,
                allowNull: true,
                set: (val)=> {
                    this.setDataValue('eventsUpdated', val);
                    this.setDataValue('eventsUpdatedAt', new Date());
                }
            },
            eventsUpdatedAt: {
                type: DataTypes.DATE,
                allowNull: true
            }
        },
        {
            timestamps: true
        });
    return Log;
};<|endoftext|>


<commit_before>/** @jsx React.DOM */
var RD = React.DOM;

var PowerStorage = function(state) {
    var storage = BaseStorage( {
        'url':'',
        'listeners': [],
        'id_map': {},
        'number': 1,
        'power': 10,
        'min_levels': 4,
        'rows': [],
        'cells': []
    });
    $.extend( storage, state || {});
    $.extend( storage, {
        'set_number': function( number ) {
            storage.number = number;
            storage.update();
        },
        'baseLog': function( number, base ) {
            return Math.log(number)/Math.log(base);
        },
        'levels': function( number ) {
            number = number || storage.number;
            var required_levels = Math.max(
                storage.min_levels,
                Math.floor(storage.baseLog( number || storage.number, storage.power ))
            );
            var i,levels;
            levels = [];
            for (i=required_levels;i>-1;i--) {
                levels.push( Math.pow(storage.power, i) );
            }
            return levels;
        }
    });
    return storage;
};

var NumberChoice = React.createClass( {
    componentWillMount: function() {
        this.props.store.listen( this.setState.bind(this) );
    },
    handleChange: function(event) {
        if (!event) {
            return true;
        }
        if (!event.target) {
            return true;
        }
        if (!event.target.value) {
            return true;
        }
        var updated = event.target.value;
        console.log("Updated value "+updated );
        updated = parseInt(updated);
        if ((! updated) || (! isNaN(updated))) {
            this.props.store.set_number( updated );
        }
        return true;
    },
    render: function() {
        return RD.input({
            'type':'number',
            'value': this.props.store.number,
            'onChange': this.handleChange
        });
    }
});

var PowerDisplay = React.createClass( {
    componentWillMount: function() {
        this.props.store.listen( this.setState.bind(this) );
    },
    setter: function(i) {
        /* create a function to set a specific value */
        var operator = function() { this.props.store.set_number(i);};
        return operator;
    },
    rows: function() {
        var self = this;
        var store = this.props.store;
        var number = store.number;

        /* we have power-1 rows, cell is "on" if (value / column) > row */
        var row,power;
        var overall = [];
        var levels = store.levels();
        for (row=(store.power-1);row > 0;row--) {
            overall.push(
                RD.tr({'children': $.map( levels, function(level,index) {
                    var remainder = number % (level*store.power);
                    var multiple = remainder / level;
                    var class_name = 'power power-'+(levels.length-index);
                    if (multiple >= row) {
                        class_name += ' selected';
                    }
                    return RD.td({'className':class_name} );
                })})
            );
        }
        return overall;
    },
    render: function() {
        var storage = this.props.store;
        var input = NumberChoice({ store: storage });

        return RD.div({
            'className': 'powers-view',
        },
            RD.div({"className":'number-form'},
                input
            ),
            RD.table({
                'className': 'group-view',
            },
                RD.thead({},
                    RD.tr({
                        children: $.map(storage.levels(),function(level) {
                            return RD.th({},''+level)
                        })
                    })
                ),
                RD.tbody({ children: this.rows()})
            )
        );
    }
});

$(document).ready( function() {
    var tree_holder = document.getElementById('powers-ten-holder');
    var power_store = PowerStorage();
    var number_display = React.renderComponent(
        PowerDisplay({
            store: power_store
        }),
        tree_holder
    );

});
<commit_msg>Add control to change the base<commit_after>/** @jsx React.DOM */
var RD = React.DOM;

var PowerStorage = function(state) {
    var storage = BaseStorage( {
        'url':'',
        'listeners': [],
        'id_map': {},
        'number': 1,
        'power': 10,
        'min_levels': 3,
        'min':1,
        'max':999999999,
        'rows': [],
        'cells': []
    });
    $.extend( storage, state || {});
    $.extend( storage, {
        'set_number': function( number ) {
            storage.number = number;
            storage.update();
        },
        'set_power': function(number) {
            storage.power = number;
            storage.update();
        },
        'baseLog': function( number, base ) {
            return Math.log(number)/Math.log(base);
        },
        'levels': function( number ) {
            number = number || storage.number;
            var required_levels = Math.max(
                storage.min_levels-1,
                Math.floor(storage.baseLog( number || storage.number, storage.power ))
            );
            var i,levels;
            levels = [];
            for (i=required_levels;i>-1;i--) {
                levels.push( Math.pow(storage.power, i) );
            }
            return levels;
        }
    });
    return storage;
};

var NumberChoice = React.createClass( {
    componentWillMount: function() {
        this.props.store.listen( this.setState.bind(this) );
    },
    handleChange: function(event) {
        if (!event) {
            return true;
        }
        if (!event.target) {
            return true;
        }
        if (!event.target.value) {
            return true;
        }
        var updated = event.target.value;
        updated = parseInt(updated);
        if ((! updated) || (! isNaN(updated))) {
            updated = Math.min(updated,this.props.max);
            updated = Math.max(updated,this.props.min);
            this.props.set_value( updated );
        }
        return true;
    },
    render: function() {
        return RD.input({
            'type':'number',
            'value': this.props.get_value(),
            'max': this.props.max,
            'min': this.props.min,
            'onChange': this.handleChange
        });
    }
});

var PowerDisplay = React.createClass( {
    componentWillMount: function() {
        this.props.store.listen( this.setState.bind(this) );
    },
    setter: function(i) {
        /* create a function to set a specific value */
        var operator = function() { this.props.store.set_number(i);};
        return operator;
    },
    rows: function() {
        var self = this;
        var store = this.props.store;
        var number = store.number;

        /* we have power-1 rows, cell is "on" if (value / column) > row */
        var row,power;
        var overall = [];
        var levels = store.levels();
        for (row=(store.power-1);row > -1;row--) {
            if (row > 0) {
                overall.push(
                    RD.tr({'children': $.map( levels, function(level,index) {
                        var remainder = number % (level*store.power);
                        var multiple = remainder / level;
                        var class_name = 'power power-'+(levels.length-index);
                        if (multiple >= row) {
                            class_name += ' selected';
                        }
                        return RD.td({'className':class_name} );
                    })})
                );
            } else {
                overall.push(
                    RD.tr({'children': $.map( levels, function(level,index) {
                        var remainder = number % (level*store.power);
                        var multiple = Math.floor(remainder / level);
                        if (level>number) {
                            multiple = ''
                        }
                        return RD.td({},''+(multiple) );
                    })})
                );
            }
        }
        return overall;
    },
    render: function() {
        var storage = this.props.store;
        var input = NumberChoice({
            get_value: function() {return storage.number},
            set_value:storage.set_number.bind(storage),
            store: storage,
            min: storage.min,
            max: storage.max
        });
        var power = NumberChoice({
            get_value: function() {return storage.power},
            set_value:storage.set_power.bind(storage),
            store: storage,
            min: 2,
            max: 24
        });

        return RD.div({
            'className': 'powers-view',
        },
            RD.div({"className":'number-form'},
                input,
                " in base ",
                power
            ),

            RD.table({
                'className': 'group-view number-block',
            },
                RD.thead({},
                    RD.tr({
                        children: $.map(storage.levels(),function(level) {
                            return RD.th({},''+level)
                        })
                    })
                ),
                RD.tbody({ children: this.rows()})
            )
        );
    }
});

$(document).ready( function() {
    var tree_holder = document.getElementById('powers-ten-holder');
    var power_store = PowerStorage();
    var number_display = React.renderComponent(
        PowerDisplay({
            store: power_store
        }),
        tree_holder
    );

});
<|endoftext|>


<commit_before>// A `yarn` is a `String` that knows how to display itself stylishly.
return (function(){ var yarn;
  yarn = new(Object);

  // Constructs a new `yarn`, given styles, labels, and some other `String`s
  // or `yarns`.
  yarn.constructor = function (blueprint) {
    this.styles   = blueprint.styles   || new(Object);
    this.labels   = blueprint.labels   || new(Array);
    this.elements = blueprint.elements || new(Array);
  };

  // Applies new styles
  yarn.style = function (styles) {
    this.styles = process.mixin(null, this.styles, styles) };

  // Applies new labels
  yarn.label = function () {
    this.labels = this.labels.concat(Array.prototype.slice.apply(arguments)) };

  // Clears all styles and labels
  yarn.strip = function () {
    this.styles = new(Object), this.labels = new(Array) };

  // Where the magic happens. Converts a `yarn` into a plain `String`,
  // converting styles into ANSI codes.
  //--
  // TODO: Support output to HTML, for inserting into a document as debugging
  //       info.
  yarn.toString = function (quilt, containers) { var out, styles, codes;
           out = new(Array),
         quilt = quilt || new(Object),
    containers = containers || new(Array);

    styles = this.styles;
    this.labels.forEach(function (label) {
      if (typeof quilt[label] !== 'undefined') {
        styles = process.mixin(null, quilt[label], styles) } });

    if ((codes = applyCodes(styles)).length > 0) {
      out.push(yarn.codes['csi'], codes.join(';'), yarn.codes['sgr']) };

    containers.push(this);
    this.elements.forEach(function (element) {
      out.push( element.toString(quilt, containers) ) });
    containers.pop();

    if ((codes = unapplyCodes(containers, styles)).length > 0) {
      out.push(yarn.codes['csi'], codes.join(';'), yarn.codes['sgr']) };

    return out.join('');
  };

  // Returns styling codes for a given set of styles.
  var applyCodes = function (styles) { var codes;
    codes = new(Array);

    for (style in styles) { if (styles.hasOwnProperty(style) &&
                                typeof styles[style] === 'string') {
      codes.push(yarn.codes[style][ styles[style] ]) }};

    return codes;
  };

  // Returns ‘unstyling’ codes (codes to revert the styling applied) for a
  // given set of styles.
  //
  // If a normalization code for a style is available, this will use it; if
  // not, and a previous *overriding* style is availble in the given
  // containers, that will be re-applied.
  //
  // If neither is available, *all* styling will be reset, and then *all*
  // styling from the parent containers will be applied.
  var unapplyCodes = function (containers, styles) { var codes;
    codes = new(Array);

    for (style in styles) { if (styles.hasOwnProperty(style) &&
                                typeof styles[style] === 'string') {
      previous = activeOf(containers, style);
      code = yarn.codes[style][ previous || 'normal' ];

      if (typeof code === 'undefined') { return fullReset(containers) };

      codes.push(code);
    }};

    return codes;
  };

  // Will return the codes to preform a full reset for a given set of
  // containing yarns. This will preform an SGR reset (`ESC[0m`) combined with
  // whatever codes necessary to apply all of the styles from all of the
  // containers.
  var fullReset = function (containers) { var styles;
    styles = new(Object);

    containers.forEach(function (container) {
      styles = process.mixin(null, styles, container.styles)});

    // UHH: Will `ESC[0;1;2;3m` work? Or will the reset be ignored in
    //      favour of the other codes?
    return [0].concat(applyCodes(styles));
  };

  // Retreives the latest setting of a given style group from a stack of
  // containers.
  var activeOf = function (containers, style) { var value;
    for (var a = containers, l = a.length, i = 0, container = a[i];
             i < l; container = a[++i]) {
      if (typeof (value = container.styles[style]) !== 'undefined') {
        return value } };

    return null;
  };

  // ======================================
  // = Convenience methods for `elements` =
  // ======================================

  yarn.push = function () {
    return Array.prototype.push.apply(this.elements, arguments) };

  yarn.pop = function () {
    return Array.prototype.pop.apply(this.elements, arguments) };

  yarn.shift = function () {
    return Array.prototype.shift.apply(this.elements, arguments) };

  yarn.unshift = function () {
    return Array.prototype.unshift.apply(this.elements, arguments) };

  // ==================
  // = ANSI sequences =
  // ==================

  yarn.codes = { csi: "\033[", sgr: 'm', reset: 0

,   foreground: {
      'black'     : 30, 'black-hi'  : 90
,     'red'       : 31, 'red-hi'    : 91
,     'green'     : 32, 'green-hi'  : 92
,     'yellow'    : 33, 'yellow-hi' : 93
,     'blue'      : 34, 'blue-hi'   : 94
,     'magenta'   : 35, 'magenta-hi': 95
,     'cyan'      : 36, 'cyan-hi'   : 96
,     'white'     : 37, 'white-hi'  : 97
    }

,   background: {
      'black'     : 40, 'black-hi'  : 100
,     'red'       : 41, 'red-hi'    : 101
,     'green'     : 42, 'green-hi'  : 102
,     'yellow'    : 43, 'yellow-hi' : 103
,     'blue'      : 44, 'blue-hi'   : 104
,     'magenta'   : 45, 'magenta-hi': 105
,     'cyan'      : 46, 'cyan-hi'   : 106
,     'white'     : 47, 'white-hi'  : 107
    }

,   weight:    {normal: 22,   'bold': 1}
,   underline: {normal: 24,   'none': 24, 'single': 4}
,   blink:     {normal: 25,   'none': 25, 'slow': 5}
,   inverse:   {normal: 27,   'positive': 27, 'negative': 7}
  };

  yarn.constructor({});

  return yarn;
})()
<commit_msg>Restructuring the (un)?applyCodes and fullReset()<commit_after>// A `yarn` is a `String` that knows how to display itself stylishly.
return (function(){ var yarn;
  yarn = new(Object);

  // Constructs a new `yarn`, given styles, labels, and some other `String`s
  // or `yarns`.
  yarn.constructor = function (blueprint) {
    this.styles   = blueprint.styles   || new(Object);
    this.labels   = blueprint.labels   || new(Array);
    this.elements = blueprint.elements || new(Array);
  };

  // Applies new styles
  yarn.style = function (styles) {
    this.styles = process.mixin(null, this.styles, styles) };

  // Applies new labels
  yarn.label = function () {
    this.labels = this.labels.concat(Array.prototype.slice.apply(arguments)) };

  // Return full styling, including all specific styles *and* quilting on
  // labels
  yarn.styling = function (quilt) { var styles;
    styles = new(Object);

    this.labels.forEach(function (label) {
      if (typeof quilt[label] !== 'undefined') {
        styles = process.mixin(null, quilt[label], styles) } });

    return process.mixin(null, styles, this.styles);
  };

  // Clears all styles and labels
  yarn.strip = function () {
    this.styles = new(Object), this.labels = new(Array) };

  // Where the magic happens. Converts a `yarn` into a plain `String`,
  // converting styles into ANSI codes.
  //--
  // TODO: Support output to HTML, for inserting into a document as debugging
  //       info.
  yarn.toString = function (quilt, containers) { var out, codes;
           out = new(Array),
         quilt = quilt || new(Object),
    containers = containers || new(Array);

    if ((codes = this.applyCodes(quilt)).length > 0) {
      out.push(yarn.codes['csi'], codes.join(';'), yarn.codes['sgr']) };

    containers.push(this);
    this.elements.forEach(function (element) {
      out.push( element.toString(quilt, containers) ) });
    containers.pop();

    if ((codes = this.unapplyCodes(containers, quilt)).length > 0) {
      out.push(yarn.codes['csi'], codes.join(';'), yarn.codes['sgr']) };

    return out.join('');
  };

  // Returns styling codes for a given set of styles.
  yarn.applyCodes = function (quilt) { var codes, styles;
    codes = new(Array);

    styles = this.styling(quilt);
    for (style in styles) { if (styles.hasOwnProperty(style) &&
                                typeof styles[style] === 'string') {
      codes.push(yarn.codes[style][ styles[style] ]) }};

    return codes;
  };

  // Returns ‘unstyling’ codes (codes to revert the styling applied) for a
  // given set of styles.
  //
  // If a normalization code for a style is available, this will use it; if
  // not, and a previous *overriding* style is availble in the given
  // containers, that will be re-applied.
  //
  // If neither is available, *all* styling will be reset, and then *all*
  // styling from the parent containers will be applied.
  yarn.unapplyCodes = function (containers, quilt) { var codes, styles;
    codes = new(Array);

    styles = this.styling(quilt);
    for (style in styles) { if (styles.hasOwnProperty(style) &&
                                typeof styles[style] === 'string') {
      previous = activeOf(containers, style, quilt);
      code = yarn.codes[style][ previous || 'normal' ];

      if (typeof code === 'undefined') { return fullReset(containers, quilt) };

      codes.push(code);
    }};

    return codes;
  };

  // Will return the codes to preform a full reset for a given set of
  // containing yarns. This will preform an SGR reset (`ESC[0m`) combined with
  // whatever codes necessary to apply all of the styles from all of the
  // containers.
  var fullReset = function (containers, quilt) { var codes;
    codes = new(Array);

    containers.forEach(function (container) {
      codes = codes.concat(container.applyCodes(quilt)) });

    // UHH: Will `ESC[0;1;2;3m` work? Or will the reset be ignored in
    //      favour of the other codes?
    return [0].concat(codes);
  };

  // Retreives the latest setting of a given style group from a stack of
  // containers.
  var activeOf = function (containers, style, quilt) { var value;
    for (var a = containers, l = a.length, i = 0, container = a[i];
             i < l; container = a[++i]) {
      if (typeof (value = container.styling(quilt)[style]) !== 'undefined') {
        return value } };

    return null;
  };

  // ======================================
  // = Convenience methods for `elements` =
  // ======================================

  yarn.push = function () {
    return Array.prototype.push.apply(this.elements, arguments) };

  yarn.pop = function () {
    return Array.prototype.pop.apply(this.elements, arguments) };

  yarn.shift = function () {
    return Array.prototype.shift.apply(this.elements, arguments) };

  yarn.unshift = function () {
    return Array.prototype.unshift.apply(this.elements, arguments) };

  // ==================
  // = ANSI sequences =
  // ==================

  yarn.codes = { csi: "\033[", sgr: 'm', reset: 0

,   foreground: {
      'black'     : 30, 'black-hi'  : 90
,     'red'       : 31, 'red-hi'    : 91
,     'green'     : 32, 'green-hi'  : 92
,     'yellow'    : 33, 'yellow-hi' : 93
,     'blue'      : 34, 'blue-hi'   : 94
,     'magenta'   : 35, 'magenta-hi': 95
,     'cyan'      : 36, 'cyan-hi'   : 96
,     'white'     : 37, 'white-hi'  : 97
    }

,   background: {
      'black'     : 40, 'black-hi'  : 100
,     'red'       : 41, 'red-hi'    : 101
,     'green'     : 42, 'green-hi'  : 102
,     'yellow'    : 43, 'yellow-hi' : 103
,     'blue'      : 44, 'blue-hi'   : 104
,     'magenta'   : 45, 'magenta-hi': 105
,     'cyan'      : 46, 'cyan-hi'   : 106
,     'white'     : 47, 'white-hi'  : 107
    }

,   weight:    {normal: 22,   'bold': 1}
,   underline: {normal: 24,   'none': 24, 'single': 4}
,   blink:     {normal: 25,   'none': 25, 'slow': 5}
,   inverse:   {normal: 27,   'positive': 27, 'negative': 7}
  };

  yarn.constructor({});

  return yarn;
})()
<|endoftext|>


<commit_before>$(document).ready(function() {
  /** Load the help page */
  $('#key').jqm({ajax: 'key.html', trigger: 'a.keytrigger'});
  if(this.getElementById('projectname'))
    {
    var projectname = this.getElementById('projectname').value;
    $('#groupsdescription').jqm({ajax: 'groupsDescription.php?project='+projectname, trigger: 'a.grouptrigger'});
    }

  /** Build name */
  $.tablesorter.addParser({
      // set a unique id
      id: 'buildname',
      is: function(s) {
            // return false so this parser is not auto detected
            return false;
        },
        format: function(s) {
            // format your data for normalization
            var t = s;
            var i = s.indexOf("0)
              {
              var j = s.indexOf(">",i);
              var k = s.indexOf("",j);
              t = s.substr(j+1,k-j-1);
              }
            return t.toLowerCase();
        },
        // set type, either numeric or text
        type: 'text'
    });

  /** Update */
  $.tablesorter.addParser({
      // set a unique id
      id: 'numericvalue',
      is: function(s) {
            // return false so this parser is not auto detected
            return false;
        },
        format: function(s) {
            // format your data for normalization
            var i = s.indexOf("<a href");
            if(i==-1) // IE
              {
              i = s.indexOf("<A href");
              }

            // We don't have a ",i);
            var k = s.indexOf("",j);
            if(k==-1) // IE
              {
              k = s.indexOf("");
              }
            var t = s.substr(j+1,k-j-1);
            return t.toLowerCase();
        },
        // set type, either numeric or text
        type: 'numeric'
    });

  /** percent for coverage */
  $.tablesorter.addParser({
      // set a unique id
      id: 'percentage',
      is: function(s) {
            // return false so this parser is not auto detected
            return false;
        },
        format: function(s) {
            // format your data for normalization
            var i = s.indexOf("",i);
            var k = s.indexOf("",j);
            var t = s.substr(j+1,k-j-2);
            return t.toLowerCase();
        },
        // set type, either numeric or text
        type: 'numeric'
    });

  /** numeric for dynalanisys */
  $.tablesorter.addParser({
      // set a unique id
      id: 'dynanalysismetric',
      is: function(s) {
            // return false so this parser is not auto detected
            return false;
        },
        format: function(s) {
            // format your data for normalization
            var i = s.indexOf("",i);
            var k = s.indexOf("",j);
            var t = s.substr(j+1,k-j-1);
            return t.toLowerCase();
        },
        // set type, either numeric or text
        type: 'numeric'
    });

  // Initialize the viewTest tables
  $tabs = $("#viewTestTable");
  var nrows = 0;
  if(document.getElementById('viewTestTable'))
    {
    var nrows = document.getElementById('viewTestTable').getElementsByTagName('thead')[0].getElementsByTagName('th').length;
    }

  if(nrows==4)
    {
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'buildname'},
                1: { sorter:'buildname'},
                2: { sorter:'digit'},
                3: { sorter:'text'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });
    }

  if(nrows==5)
    {
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'buildname'},
                1: { sorter:'buildname'},
                2: { sorter:'buildname'},
                3: { sorter:'digit'},
                4: { sorter:'text'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });
    }

  // Initialize the testSummary tables
  if($tabs.length==0)
    {
    $tabs = $("#testSummaryTable");
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'text'},
                1: { sorter:'buildname'},
                2: { sorter:'text'},
                3: { sorter:'buildname'},
                4: { sorter:'digit'},
                5: { sorter:'text'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });
    }

  // Initialize the userStatistics table
  if($tabs.length==0)
    {
    $tabs = $("#userStatistics");
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'text'},
                1: { sorter:'digit'},
                2: { sorter:'digit'},
                3: { sorter:'digit'},
                4: { sorter:'digit'},
                5: { sorter:'digit'},
                6: { sorter:'digit'},
                7: { sorter:'digit'},
                8: { sorter:'digit'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });
    }

  // Initialize the subproject table
  if($tabs.length==0)
    {
    $tabs = $("#subproject");
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'text'},
                1: { sorter:'digit'},
                2: { sorter:'digit'},
                3: { sorter:'digit'},
                4: { sorter:'digit'},
                5: { sorter:'digit'},
                6: { sorter:'digit'},
                7: { sorter:'digit'},
                8: { sorter:'digit'},
                9: { sorter:'digit'},
                10: { sorter:'text'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });
    }

  // If all the above are not working then it should be the index table
  if($tabs.length==0)
    {
    // Initialize the Index tables
    $tabs = $(".tabb",this);
    $tabs.each(
     function(index) {
      var tableid = this.id;
      if(tableid == "coveragetable" || tableid == "dynamicanalysistable")
        {
        return;
        }
       $(this).tablesorter({
              headers: {
                  0: { sorter:'buildname'},
                  1: { sorter:'buildname'},
                  2: { sorter:'numericvalue'},
                  3: { sorter:'digit'},
                  4: { sorter:'numericvalue'},
                  5: { sorter:'numericvalue'},
                  6: { sorter:'digit'},
                  7: { sorter:'numericvalue'},
                  8: { sorter:'numericvalue'},
                  9: { sorter:'digit'},
                  10: { sorter:'numericvalue'},
                  11: { sorter:'numericvalue'},
                  12: { sorter:'numericvalue'},
                  13: { sorter:'digit'},
                  14: { sorter:'text'},
                  15: { sorter:'text'}
              },
            debug: false,
            widgets: ['zebra']
          });

      // Get the cookie
      var cookiename = "cdash_table_sort_"+tableid;
      var cook = $.cookie(cookiename); // get cookie
      if(cook)
        {
        var cookArray = cook.split(',');
        var sortArray = new Array();
        var j=0;
        for(var i=0; i < cookArray.length; i+=2)
          {
          sortArray[j] = [cookArray[i],cookArray[i+1]];
          j++;
          }
        $(this).trigger("sorton",[sortArray]);
        }
      });

    // Initialize the coverage table
    $tabs = $("#coveragetable");
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'text'},
                1: { sorter:'text'},
                2: { sorter:'percentage'},
                3: { sorter:'dynanalysismetric'},
                4: { sorter:'dynanalysismetric'},
                5: { sorter:'text'},
                6: { sorter:'text'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });

    // Initialize the dynamic analysis table
    $tabs = $("#dynamicanalysistable");
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'text'},
                1: { sorter:'text'},
                2: { sorter:'text'},
                3: { sorter:'dynanalysismetric'}, // not percent but same format
                4: { sorter:'text'},
                5: { sorter:'text'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });
    } // end indextable

});
<commit_msg>ENH: Improved column display<commit_after>$(document).ready(function() {
  /** Load the help page */
  $('#key').jqm({ajax: 'key.html', trigger: 'a.keytrigger'});
  if(this.getElementById('projectname'))
    {
    var projectname = this.getElementById('projectname').value;
    $('#groupsdescription').jqm({ajax: 'groupsDescription.php?project='+projectname, trigger: 'a.grouptrigger'});
    }

  /** Build name */
  $.tablesorter.addParser({
      // set a unique id
      id: 'buildname',
      is: function(s) {
            // return false so this parser is not auto detected
            return false;
        },
        format: function(s) {
            // format your data for normalization
            var t = s;
            var i = s.indexOf("0)
              {
              var j = s.indexOf(">",i);
              var k = s.indexOf("",j);
              t = s.substr(j+1,k-j-1);
              }
            return t.toLowerCase();
        },
        // set type, either numeric or text
        type: 'text'
    });

  /** Update */
  $.tablesorter.addParser({
      // set a unique id
      id: 'numericvalue',
      is: function(s) {
            // return false so this parser is not auto detected
            return false;
        },
        format: function(s) {
            // format your data for normalization
            var i = s.indexOf("<a href");
            if(i==-1) // IE
              {
              i = s.indexOf("<A href");
              }

            // We don't have a ",i);
            var k = s.indexOf("",j);
            if(k==-1) // IE
              {
              k = s.indexOf("");
              }
            var t = s.substr(j+1,k-j-1);
            return t.toLowerCase();
        },
        // set type, either numeric or text
        type: 'numeric'
    });

  /** percent for coverage */
  $.tablesorter.addParser({
      // set a unique id
      id: 'percentage',
      is: function(s) {
            // return false so this parser is not auto detected
            return false;
        },
        format: function(s) {
            // format your data for normalization
            var i = s.indexOf("",i);
            var k = s.indexOf("",j);
            var t = s.substr(j+1,k-j-2);
            return t.toLowerCase();
        },
        // set type, either numeric or text
        type: 'numeric'
    });

  /** numeric for dynalanisys */
  $.tablesorter.addParser({
      // set a unique id
      id: 'dynanalysismetric',
      is: function(s) {
            // return false so this parser is not auto detected
            return false;
        },
        format: function(s) {
            // format your data for normalization
            var i = s.indexOf("",i);
            var k = s.indexOf("",j);
            var t = s.substr(j+1,k-j-1);
            return t.toLowerCase();
        },
        // set type, either numeric or text
        type: 'numeric'
    });

  // Initialize the viewTest tables
  $tabs = $("#viewTestTable");
  var nrows = 0;
  if(document.getElementById('viewTestTable'))
    {
    var nrows = document.getElementById('viewTestTable').getElementsByTagName('thead')[0].getElementsByTagName('th').length;
    }

 if(nrows==3)
    {
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'buildname'},
                1: { sorter:'buildname'},
                2: { sorter:'digit'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });
    }

  if(nrows==4)
    {
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'buildname'},
                1: { sorter:'buildname'},
                2: { sorter:'digit'},
                3: { sorter:'text'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });
    }

  if(nrows==5)
    {
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'buildname'},
                1: { sorter:'buildname'},
                2: { sorter:'buildname'},
                3: { sorter:'digit'},
                4: { sorter:'text'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });
    }

  // Initialize the testSummary tables
  if($tabs.length==0)
    {
    $tabs = $("#testSummaryTable");
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'text'},
                1: { sorter:'buildname'},
                2: { sorter:'text'},
                3: { sorter:'buildname'},
                4: { sorter:'digit'},
                5: { sorter:'text'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });
    }

  // Initialize the userStatistics table
  if($tabs.length==0)
    {
    $tabs = $("#userStatistics");
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'text'},
                1: { sorter:'digit'},
                2: { sorter:'digit'},
                3: { sorter:'digit'},
                4: { sorter:'digit'},
                5: { sorter:'digit'},
                6: { sorter:'digit'},
                7: { sorter:'digit'},
                8: { sorter:'digit'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });
    }

  // Initialize the subproject table
  if($tabs.length==0)
    {
    $tabs = $("#subproject");
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'text'},
                1: { sorter:'digit'},
                2: { sorter:'digit'},
                3: { sorter:'digit'},
                4: { sorter:'digit'},
                5: { sorter:'digit'},
                6: { sorter:'digit'},
                7: { sorter:'digit'},
                8: { sorter:'digit'},
                9: { sorter:'digit'},
                10: { sorter:'text'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });
    }

  // If all the above are not working then it should be the index table
  if($tabs.length==0)
    {
    // Initialize the Index tables
    $tabs = $(".tabb",this);
    $tabs.each(
     function(index) {
      var tableid = this.id;
      if(tableid == "coveragetable" || tableid == "dynamicanalysistable")
        {
        return;
        }
       $(this).tablesorter({
              headers: {
                  0: { sorter:'buildname'},
                  1: { sorter:'buildname'},
                  2: { sorter:'numericvalue'},
                  3: { sorter:'digit'},
                  4: { sorter:'numericvalue'},
                  5: { sorter:'numericvalue'},
                  6: { sorter:'digit'},
                  7: { sorter:'numericvalue'},
                  8: { sorter:'numericvalue'},
                  9: { sorter:'digit'},
                  10: { sorter:'numericvalue'},
                  11: { sorter:'numericvalue'},
                  12: { sorter:'numericvalue'},
                  13: { sorter:'digit'},
                  14: { sorter:'text'},
                  15: { sorter:'text'}
              },
            debug: false,
            widgets: ['zebra']
          });

      // Get the cookie
      var cookiename = "cdash_table_sort_"+tableid;
      var cook = $.cookie(cookiename); // get cookie
      if(cook)
        {
        var cookArray = cook.split(',');
        var sortArray = new Array();
        var j=0;
        for(var i=0; i < cookArray.length; i+=2)
          {
          sortArray[j] = [cookArray[i],cookArray[i+1]];
          j++;
          }
        $(this).trigger("sorton",[sortArray]);
        }
      });

    // Initialize the coverage table
    $tabs = $("#coveragetable");
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'text'},
                1: { sorter:'text'},
                2: { sorter:'percentage'},
                3: { sorter:'dynanalysismetric'},
                4: { sorter:'dynanalysismetric'},
                5: { sorter:'text'},
                6: { sorter:'text'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });

    // Initialize the dynamic analysis table
    $tabs = $("#dynamicanalysistable");
    $tabs.each(function(index) {
     $(this).tablesorter({
            headers: {
                0: { sorter:'text'},
                1: { sorter:'text'},
                2: { sorter:'text'},
                3: { sorter:'dynanalysismetric'}, // not percent but same format
                4: { sorter:'text'},
                5: { sorter:'text'}
            },
          debug: false,
          widgets: ['zebra']
        });
      });
    } // end indextable

});
<|endoftext|>


<commit_before>const { expect } = require('chai');
const app = require('../../../../src/app');
const testObjects = require('../../helpers/testObjects')(app);
const { generateRequestParamsFromUser } = require('../../helpers/services/login')(app);
const SchoolYearFacade = require('../../../../src/services/school/logic/year');

const classSuccessorService = app.service('classSuccessor');

describe.only('classSuccessor service', () => {
	let server;

	before((done) => {
		server = app.listen(0, done);
	});

	after((done) => {
		server.close(done);
	});

	it('is properly registered the class successor service', () => {
		expect(classSuccessorService).to.not.equal(undefined);
	});

	it('GET works for class without year or gradeLevel', async () => {
		const newClass = await testObjects.createTestClass({ name: 'sonnenklasse' });
		const successor = await classSuccessorService.get(newClass._id);
		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(undefined);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
	});

	it('GET works for class with year', async () => {
		const newSchool = await testObjects.createTestSchool();
		const school = await app.service('schools').get(newSchool._id); // necessary to get valid years
		const schoolYears = new SchoolYearFacade(school.years.schoolYears, school);
		const classYear = school.years.lastYear._id;
		const yearAfter = await schoolYears.getNextYearAfter(classYear);

		const newClass = await testObjects.createTestClass({
			name: 'mondklasse', schoolId: school._id, year: classYear,
		});
		const successor = await classSuccessorService.get(newClass._id);

		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(undefined);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.year.toString()).to.equal(yearAfter._id.toString());
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
	});

	it('GET works for class with gradeLevel', async () => {
		const newClass = await testObjects.createTestClass({ name: 'a', gradeLevel: 4 });
		const successor = await classSuccessorService.get(newClass._id);
		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(5);
		expect(successor.name).to.equal('a');
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
	});

	it('fails when gradeLevel is too high', async () => {
		try {
			const newClass = await testObjects.createTestClass({ name: 'b', gradeLevel: 13 });
			await classSuccessorService.get(newClass._id);
			throw new Error('should have failed');
		} catch (err) {
			expect(err.message).to.not.equal('should have failed');
			expect(err.message).to.equal('there is no grade level higher than 13!');
		}
	});

	it('GET works for class with year and gradeLevel', async () => {
		const newSchool = await testObjects.createTestSchool();
		const school = await app.service('schools').get(newSchool._id); // necessary to get valid years
		const schoolYears = new SchoolYearFacade(school.years.schoolYears, school);
		const classYear = school.years.lastYear._id;
		const yearAfter = await schoolYears.getNextYearAfter(classYear);

		const newClass = await testObjects.createTestClass({
			name: 'c',
			gradeLevel: 6,
			schoolId: school._id,
			year: classYear,
		});
		const successor = await classSuccessorService.get(newClass._id);

		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(7);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.year.toString()).to.equal(yearAfter._id.toString());
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
	});

	it('GET informs about duplicates', async () => {
		const name = `klasse ${Date.now}`;
		const oldClass = await testObjects.createTestClass({ name });
		const newClass = await testObjects.createTestClass({ name });

		const successor = await classSuccessorService.get(newClass._id);
		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(undefined);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
		expect(successor.duplicates.map(d => d.toString())).to.include(oldClass._id.toString());
	});

	it('only includes duplicates in the same year', async () => {
		const newSchool = await testObjects.createTestSchool();
		const school = await app.service('schools').get(newSchool._id); // necessary to get valid years
		const schoolYears = new SchoolYearFacade(school.years.schoolYears, school);
		const classYear = school.years.lastYear._id;
		const yearAfter = await schoolYears.getNextYearAfter(classYear);

		const name = `klasse ${Date.now}`;
		const classThisYear	= await testObjects.createTestClass({ name, schoolId: school._id, year: classYear });
		const classYearAfter = await testObjects.createTestClass({ name, schoolId: school._id, year: yearAfter });
		const newClass = await testObjects.createTestClass({ name, schoolId: school._id, year: classYear });
		const successor = await classSuccessorService.get(newClass._id);

		expect(successor).to.not.equal(undefined);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.year.toString()).to.equal(yearAfter._id.toString());
		const duplicates = successor.duplicates.map(d => d.toString());
		expect(duplicates).to.include(classYearAfter._id.toString());
		expect(duplicates).not.to.include(classThisYear._id.toString());
	});

	it('only includes duplicates with equal grade level', async () => {
		const name = `klasse ${Date.now}`;
		const classoldGrade = await testObjects.createTestClass({ name, gradeLevel: 1 });
		const classNextGrade = await testObjects.createTestClass({ name, gradeLevel: 2 });
		const newClass = await testObjects.createTestClass({ name, gradeLevel: 1 });

		const successor = await classSuccessorService.get(newClass._id);
		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(2);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
		const duplicates = successor.duplicates.map(d => d.toString());
		expect(duplicates).to.include(classNextGrade._id.toString());
		expect(duplicates).not.to.include(classoldGrade._id.toString());
	});

	it('FIND generates multiple successors', async () => {
		const gClass = await testObjects.createTestClass({ name: 'g', gradeLevel: 7 });
		const eClass = await testObjects.createTestClass({ name: 'e', gradeLevel: 6 });
		const result = await classSuccessorService.find({ query: { classIds: [gClass._id, eClass._id] } });
		expect(Array.isArray(result)).to.equal(true);
		expect(result.length).to.equal(2);
	});

	it('FIND should return an error if no array of classIds is passed', async () => {
		try {
			await classSuccessorService.find({ query: {} });
			throw new Error('should have failed');
		} catch (error) {
			expect(error.message).to.not.equal('should have failed');
			expect(error.message).to.equal('please pass an array of classIds in query.classIds');
			expect(error.code).to.equal(400);
		}
	});

	it('is accessible as teacher', async () => {
		const teacher = await testObjects.createTestUser({ roles: ['teacher'] });
		const params = await generateRequestParamsFromUser(teacher);
		const newClass = await testObjects.createTestClass({ name: 'lieblingsklasse' });
		const successor = await classSuccessorService.get(newClass._id, params);
		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(undefined);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
	});

	it('is accessible as admin', async () => {
		const admin = await testObjects.createTestUser({ roles: ['administrator'] });
		const params = await generateRequestParamsFromUser(admin);
		const newClass = await testObjects.createTestClass({ name: 'problemklasse' });
		const successor = await classSuccessorService.get(newClass._id, params);
		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(undefined);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
	});

	it('fails as student', async () => {
		try {
			const admin = await testObjects.createTestUser({ roles: ['student'] });
			const params = await generateRequestParamsFromUser(admin);
			const newClass = await testObjects.createTestClass({ name: 'cooleklasse' });
			await classSuccessorService.get(newClass._id, params);
			throw new Error('should have failed');
		} catch (error) {
			expect(error.message).to.not.equal('should have failed');
			expect(error.message).to.equal("You don't have the permission USERGROUP_CREATE.");
			expect(error.code).to.equal(403);
		}
	});

	it('fails for class on different school', async () => {
		try {
			const userSchool = await testObjects.createTestSchool();
			const classSchool = await testObjects.createTestSchool();
			const teacher = await testObjects.createTestUser({ schoolId: userSchool._id, roles: ['teacher'] });
			const params = await generateRequestParamsFromUser(teacher);
			const newClass = await testObjects.createTestClass({ name: 'fremdenklasse', schoolId: classSchool._id });
			await classSuccessorService.get(newClass._id, params);
			throw new Error('should have failed');
		} catch (error) {
			expect(error.message).to.not.equal('should have failed');
			expect(error.message).to.equal('You do not have valid permissions to access this.');
			expect(error.code).to.equal(403);
		}
	});

	after(async () => {
		await testObjects.cleanup();
	});
});
<commit_msg>actual dates in testnames<commit_after>const { expect } = require('chai');
const app = require('../../../../src/app');
const testObjects = require('../../helpers/testObjects')(app);
const { generateRequestParamsFromUser } = require('../../helpers/services/login')(app);
const SchoolYearFacade = require('../../../../src/services/school/logic/year');

const classSuccessorService = app.service('classSuccessor');

describe.only('classSuccessor service', () => {
	let server;

	before((done) => {
		server = app.listen(0, done);
	});

	after((done) => {
		server.close(done);
	});

	it('is properly registered the class successor service', () => {
		expect(classSuccessorService).to.not.equal(undefined);
	});

	it('GET works for class without year or gradeLevel', async () => {
		const newClass = await testObjects.createTestClass({ name: 'sonnenklasse' });
		const successor = await classSuccessorService.get(newClass._id);
		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(undefined);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
	});

	it('GET works for class with year', async () => {
		const newSchool = await testObjects.createTestSchool();
		const school = await app.service('schools').get(newSchool._id); // necessary to get valid years
		const schoolYears = new SchoolYearFacade(school.years.schoolYears, school);
		const classYear = school.years.lastYear._id;
		const yearAfter = await schoolYears.getNextYearAfter(classYear);

		const newClass = await testObjects.createTestClass({
			name: 'mondklasse', schoolId: school._id, year: classYear,
		});
		const successor = await classSuccessorService.get(newClass._id);

		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(undefined);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.year.toString()).to.equal(yearAfter._id.toString());
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
	});

	it('GET works for class with gradeLevel', async () => {
		const newClass = await testObjects.createTestClass({ name: 'a', gradeLevel: 4 });
		const successor = await classSuccessorService.get(newClass._id);
		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(5);
		expect(successor.name).to.equal('a');
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
	});

	it('fails when gradeLevel is too high', async () => {
		try {
			const newClass = await testObjects.createTestClass({ name: 'b', gradeLevel: 13 });
			await classSuccessorService.get(newClass._id);
			throw new Error('should have failed');
		} catch (err) {
			expect(err.message).to.not.equal('should have failed');
			expect(err.message).to.equal('there is no grade level higher than 13!');
		}
	});

	it('GET works for class with year and gradeLevel', async () => {
		const newSchool = await testObjects.createTestSchool();
		const school = await app.service('schools').get(newSchool._id); // necessary to get valid years
		const schoolYears = new SchoolYearFacade(school.years.schoolYears, school);
		const classYear = school.years.lastYear._id;
		const yearAfter = await schoolYears.getNextYearAfter(classYear);

		const newClass = await testObjects.createTestClass({
			name: 'c',
			gradeLevel: 6,
			schoolId: school._id,
			year: classYear,
		});
		const successor = await classSuccessorService.get(newClass._id);

		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(7);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.year.toString()).to.equal(yearAfter._id.toString());
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
	});

	it('GET informs about duplicates', async () => {
		const name = `klasse ${Date.now()}`;
		const oldClass = await testObjects.createTestClass({ name });
		const newClass = await testObjects.createTestClass({ name });

		const successor = await classSuccessorService.get(newClass._id);
		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(undefined);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
		expect(successor.duplicates.map(d => d.toString())).to.include(oldClass._id.toString());
	});

	it('only includes duplicates in the same year', async () => {
		const newSchool = await testObjects.createTestSchool();
		const school = await app.service('schools').get(newSchool._id); // necessary to get valid years
		const schoolYears = new SchoolYearFacade(school.years.schoolYears, school);
		const classYear = school.years.lastYear._id;
		const yearAfter = await schoolYears.getNextYearAfter(classYear);

		const name = `klasse ${Date.now()}`;
		const classThisYear	= await testObjects.createTestClass({ name, schoolId: school._id, year: classYear });
		const classYearAfter = await testObjects.createTestClass({ name, schoolId: school._id, year: yearAfter });
		const newClass = await testObjects.createTestClass({ name, schoolId: school._id, year: classYear });
		const successor = await classSuccessorService.get(newClass._id);

		expect(successor).to.not.equal(undefined);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.year.toString()).to.equal(yearAfter._id.toString());
		const duplicates = successor.duplicates.map(d => d.toString());
		expect(duplicates).to.include(classYearAfter._id.toString());
		expect(duplicates).not.to.include(classThisYear._id.toString());
	});

	it('only includes duplicates with equal grade level', async () => {
		const name = `klasse ${Date.now()}`;
		const classoldGrade = await testObjects.createTestClass({ name, gradeLevel: 1 });
		const classNextGrade = await testObjects.createTestClass({ name, gradeLevel: 2 });
		const newClass = await testObjects.createTestClass({ name, gradeLevel: 1 });

		const successor = await classSuccessorService.get(newClass._id);
		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(2);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
		const duplicates = successor.duplicates.map(d => d.toString());
		expect(duplicates).to.include(classNextGrade._id.toString());
		expect(duplicates).not.to.include(classoldGrade._id.toString());
	});

	it('FIND generates multiple successors', async () => {
		const gClass = await testObjects.createTestClass({ name: 'g', gradeLevel: 7 });
		const eClass = await testObjects.createTestClass({ name: 'e', gradeLevel: 6 });
		const result = await classSuccessorService.find({ query: { classIds: [gClass._id, eClass._id] } });
		expect(Array.isArray(result)).to.equal(true);
		expect(result.length).to.equal(2);
	});

	it('FIND should return an error if no array of classIds is passed', async () => {
		try {
			await classSuccessorService.find({ query: {} });
			throw new Error('should have failed');
		} catch (error) {
			expect(error.message).to.not.equal('should have failed');
			expect(error.message).to.equal('please pass an array of classIds in query.classIds');
			expect(error.code).to.equal(400);
		}
	});

	it('is accessible as teacher', async () => {
		const teacher = await testObjects.createTestUser({ roles: ['teacher'] });
		const params = await generateRequestParamsFromUser(teacher);
		const newClass = await testObjects.createTestClass({ name: 'lieblingsklasse' });
		const successor = await classSuccessorService.get(newClass._id, params);
		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(undefined);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
	});

	it('is accessible as admin', async () => {
		const admin = await testObjects.createTestUser({ roles: ['administrator'] });
		const params = await generateRequestParamsFromUser(admin);
		const newClass = await testObjects.createTestClass({ name: 'problemklasse' });
		const successor = await classSuccessorService.get(newClass._id, params);
		expect(successor).to.not.equal(undefined);
		expect(successor.gradeLevel).to.equal(undefined);
		expect(successor.name).to.equal(newClass.name);
		expect(successor.schoolId.toString()).to.equal(newClass.schoolId.toString());
	});

	it('fails as student', async () => {
		try {
			const admin = await testObjects.createTestUser({ roles: ['student'] });
			const params = await generateRequestParamsFromUser(admin);
			const newClass = await testObjects.createTestClass({ name: 'cooleklasse' });
			await classSuccessorService.get(newClass._id, params);
			throw new Error('should have failed');
		} catch (error) {
			expect(error.message).to.not.equal('should have failed');
			expect(error.message).to.equal("You don't have the permission USERGROUP_CREATE.");
			expect(error.code).to.equal(403);
		}
	});

	it('fails for class on different school', async () => {
		try {
			const userSchool = await testObjects.createTestSchool();
			const classSchool = await testObjects.createTestSchool();
			const teacher = await testObjects.createTestUser({ schoolId: userSchool._id, roles: ['teacher'] });
			const params = await generateRequestParamsFromUser(teacher);
			const newClass = await testObjects.createTestClass({ name: 'fremdenklasse', schoolId: classSchool._id });
			await classSuccessorService.get(newClass._id, params);
			throw new Error('should have failed');
		} catch (error) {
			expect(error.message).to.not.equal('should have failed');
			expect(error.message).to.equal('You do not have valid permissions to access this.');
			expect(error.code).to.equal(403);
		}
	});

	after(async () => {
		await testObjects.cleanup();
	});
});
<|endoftext|>


<commit_before>'use strict'

const fs = require('./wrapped-fs')
const path = require('path')
const minimatch = require('minimatch')

const Filesystem = require('./filesystem')
const disk = require('./disk')
const crawlFilesystem = require('./crawlfs')

/**
 * Whether a directory should be excluded from packing due to the `--unpack-dir" option.
 *
 * @param {string} dirPath - directory path to check
 * @param {string} pattern - literal prefix [for backward compatibility] or glob pattern
 * @param {array} unpackDirs - Array of directory paths previously marked as unpacked
 */
function isUnpackedDir (dirPath, pattern, unpackDirs) {
  if (dirPath.startsWith(pattern) || minimatch(dirPath, pattern)) {
    if (!unpackDirs.includes(dirPath)) {
      unpackDirs.push(dirPath)
    }
    return true
  } else {
    return unpackDirs.some(unpackDir => dirPath.startsWith(unpackDir))
  }
}

module.exports.createPackage = async function (src, dest) {
  return module.exports.createPackageWithOptions(src, dest, {})
}

module.exports.createPackageWithOptions = async function (src, dest, options) {
  const globOptions = options.globOptions ? options.globOptions : {}
  globOptions.dot = options.dot === undefined ? true : options.dot

  const pattern = src + (options.pattern ? options.pattern : '/**/*')

  const [filenames, metadata] = await crawlFilesystem(pattern, globOptions)
  return module.exports.createPackageFromFiles(src, dest, filenames, metadata, options)
}

/**
 * Create an ASAR archive from a list of filenames.
 *
 * @param {string} src: Base path. All files are relative to this.
 * @param {string} dest: Archive filename (& path).
 * @param {array} filenames: List of filenames relative to src.
 * @param {object} metadata: Object with filenames as keys and {type='directory|file|link', stat: fs.stat} as values. (Optional)
 * @param {object} options: Options passed to `createPackageWithOptions`.
*/
module.exports.createPackageFromFiles = async function (src, dest, filenames, metadata, options) {
  if (typeof metadata === 'undefined' || metadata === null) { metadata = {} }
  if (typeof options === 'undefined' || options === null) { options = {} }

  src = path.normalize(src)
  dest = path.normalize(dest)
  filenames = filenames.map(function (filename) { return path.normalize(filename) })

  const filesystem = new Filesystem(src)
  const files = []
  const unpackDirs = []

  let filenamesSorted = []
  if (options.ordering) {
    const orderingFiles = (await fs.readFile(options.ordering)).toString().split('\n').map(line => {
      if (line.includes(':')) { line = line.split(':').pop() }
      line = line.trim()
      if (line.startsWith('/')) { line = line.slice(1) }
      return line
    })

    const ordering = []
    for (const file of orderingFiles) {
      const pathComponents = file.split(path.sep)
      let str = src
      for (const pathComponent of pathComponents) {
        str = path.join(str, pathComponent)
        ordering.push(str)
      }
    }

    let missing = 0
    const total = filenames.length

    for (const file of ordering) {
      if (!filenamesSorted.includes(file) && filenames.includes(file)) {
        filenamesSorted.push(file)
      }
    }

    for (const file of filenames) {
      if (!filenamesSorted.includes(file)) {
        filenamesSorted.push(file)
        missing += 1
      }
    }

    console.log(`Ordering file has ${((total - missing) / total) * 100}% coverage.`)
  } else {
    filenamesSorted = filenames
  }

  const handleFile = async function (filename) {
    if (!metadata[filename]) {
      metadata[filename] = await crawlFilesystem.determineFileType(filename)
    }
    const file = metadata[filename]

    let shouldUnpack
    switch (file.type) {
      case 'directory':
        if (options.unpackDir) {
          shouldUnpack = isUnpackedDir(path.relative(src, filename), options.unpackDir, unpackDirs)
        } else {
          shouldUnpack = false
        }
        filesystem.insertDirectory(filename, shouldUnpack)
        break
      case 'file':
        shouldUnpack = false
        if (options.unpack) {
          shouldUnpack = minimatch(filename, options.unpack, { matchBase: true })
        }
        if (!shouldUnpack && options.unpackDir) {
          const dirName = path.relative(src, path.dirname(filename))
          shouldUnpack = isUnpackedDir(dirName, options.unpackDir, unpackDirs)
        }
        files.push({ filename: filename, unpack: shouldUnpack })
        return filesystem.insertFile(filename, shouldUnpack, file, options)
      case 'link':
        filesystem.insertLink(filename, file.stat)
        break
    }
    return Promise.resolve()
  }

  const insertsDone = async function () {
    await fs.mkdirp(path.dirname(dest))
    return disk.writeFilesystem(dest, filesystem, files, metadata)
  }

  const names = filenamesSorted.slice()

  const next = async function (name) {
    if (!name) { return insertsDone() }

    await handleFile(name)
    return next(names.shift())
  }

  return next(names.shift())
}

module.exports.statFile = function (archive, filename, followLinks) {
  const filesystem = disk.readFilesystemSync(archive)
  return filesystem.getFile(filename, followLinks)
}

module.exports.listPackage = function (archive, options) {
  return disk.readFilesystemSync(archive).listFiles(options)
}

module.exports.extractFile = function (archive, filename) {
  const filesystem = disk.readFilesystemSync(archive)
  return disk.readFileSync(filesystem, filename, filesystem.getFile(filename))
}

module.exports.extractAll = function (archive, dest) {
  const filesystem = disk.readFilesystemSync(archive)
  const filenames = filesystem.listFiles()

  // under windows just extract links as regular files
  const followLinks = process.platform === 'win32'

  // create destination directory
  fs.mkdirpSync(dest)

  return filenames.map((filename) => {
    filename = filename.substr(1) // get rid of leading slash
    const destFilename = path.join(dest, filename)
    const file = filesystem.getFile(filename, followLinks)
    if (file.files) {
      // it's a directory, create it and continue with the next entry
      fs.mkdirpSync(destFilename)
    } else if (file.link) {
      // it's a symlink, create a symlink
      const linkSrcPath = path.dirname(path.join(dest, file.link))
      const linkDestPath = path.dirname(destFilename)
      const relativePath = path.relative(linkDestPath, linkSrcPath);
      // try to delete output file, because we can't overwrite a link
      (() => {
        try {
          fs.unlinkSync(destFilename)
        } catch (error) {}
      })()
      const linkTo = path.join(relativePath, path.basename(file.link))
      fs.symlinkSync(linkTo, destFilename)
    } else {
      // it's a file, extract it
      const content = disk.readFileSync(filesystem, filename, file)
      fs.writeFileSync(destFilename, content)
    }
  })
}

module.exports.uncache = function (archive) {
  return disk.uncacheFilesystem(archive)
}

module.exports.uncacheAll = function () {
  disk.uncacheAll()
}
<commit_msg>fix: remove unnecessary arguments<commit_after>'use strict'

const fs = require('./wrapped-fs')
const path = require('path')
const minimatch = require('minimatch')

const Filesystem = require('./filesystem')
const disk = require('./disk')
const crawlFilesystem = require('./crawlfs')

/**
 * Whether a directory should be excluded from packing due to the `--unpack-dir" option.
 *
 * @param {string} dirPath - directory path to check
 * @param {string} pattern - literal prefix [for backward compatibility] or glob pattern
 * @param {array} unpackDirs - Array of directory paths previously marked as unpacked
 */
function isUnpackedDir (dirPath, pattern, unpackDirs) {
  if (dirPath.startsWith(pattern) || minimatch(dirPath, pattern)) {
    if (!unpackDirs.includes(dirPath)) {
      unpackDirs.push(dirPath)
    }
    return true
  } else {
    return unpackDirs.some(unpackDir => dirPath.startsWith(unpackDir))
  }
}

module.exports.createPackage = async function (src, dest) {
  return module.exports.createPackageWithOptions(src, dest, {})
}

module.exports.createPackageWithOptions = async function (src, dest, options) {
  const globOptions = options.globOptions ? options.globOptions : {}
  globOptions.dot = options.dot === undefined ? true : options.dot

  const pattern = src + (options.pattern ? options.pattern : '/**/*')

  const [filenames, metadata] = await crawlFilesystem(pattern, globOptions)
  return module.exports.createPackageFromFiles(src, dest, filenames, metadata, options)
}

/**
 * Create an ASAR archive from a list of filenames.
 *
 * @param {string} src: Base path. All files are relative to this.
 * @param {string} dest: Archive filename (& path).
 * @param {array} filenames: List of filenames relative to src.
 * @param {object} metadata: Object with filenames as keys and {type='directory|file|link', stat: fs.stat} as values. (Optional)
 * @param {object} options: Options passed to `createPackageWithOptions`.
*/
module.exports.createPackageFromFiles = async function (src, dest, filenames, metadata, options) {
  if (typeof metadata === 'undefined' || metadata === null) { metadata = {} }
  if (typeof options === 'undefined' || options === null) { options = {} }

  src = path.normalize(src)
  dest = path.normalize(dest)
  filenames = filenames.map(function (filename) { return path.normalize(filename) })

  const filesystem = new Filesystem(src)
  const files = []
  const unpackDirs = []

  let filenamesSorted = []
  if (options.ordering) {
    const orderingFiles = (await fs.readFile(options.ordering)).toString().split('\n').map(line => {
      if (line.includes(':')) { line = line.split(':').pop() }
      line = line.trim()
      if (line.startsWith('/')) { line = line.slice(1) }
      return line
    })

    const ordering = []
    for (const file of orderingFiles) {
      const pathComponents = file.split(path.sep)
      let str = src
      for (const pathComponent of pathComponents) {
        str = path.join(str, pathComponent)
        ordering.push(str)
      }
    }

    let missing = 0
    const total = filenames.length

    for (const file of ordering) {
      if (!filenamesSorted.includes(file) && filenames.includes(file)) {
        filenamesSorted.push(file)
      }
    }

    for (const file of filenames) {
      if (!filenamesSorted.includes(file)) {
        filenamesSorted.push(file)
        missing += 1
      }
    }

    console.log(`Ordering file has ${((total - missing) / total) * 100}% coverage.`)
  } else {
    filenamesSorted = filenames
  }

  const handleFile = async function (filename) {
    if (!metadata[filename]) {
      metadata[filename] = await crawlFilesystem.determineFileType(filename)
    }
    const file = metadata[filename]

    let shouldUnpack
    switch (file.type) {
      case 'directory':
        if (options.unpackDir) {
          shouldUnpack = isUnpackedDir(path.relative(src, filename), options.unpackDir, unpackDirs)
        } else {
          shouldUnpack = false
        }
        filesystem.insertDirectory(filename, shouldUnpack)
        break
      case 'file':
        shouldUnpack = false
        if (options.unpack) {
          shouldUnpack = minimatch(filename, options.unpack, { matchBase: true })
        }
        if (!shouldUnpack && options.unpackDir) {
          const dirName = path.relative(src, path.dirname(filename))
          shouldUnpack = isUnpackedDir(dirName, options.unpackDir, unpackDirs)
        }
        files.push({ filename: filename, unpack: shouldUnpack })
        return filesystem.insertFile(filename, shouldUnpack, file, options)
      case 'link':
        filesystem.insertLink(filename)
        break
    }
    return Promise.resolve()
  }

  const insertsDone = async function () {
    await fs.mkdirp(path.dirname(dest))
    return disk.writeFilesystem(dest, filesystem, files, metadata)
  }

  const names = filenamesSorted.slice()

  const next = async function (name) {
    if (!name) { return insertsDone() }

    await handleFile(name)
    return next(names.shift())
  }

  return next(names.shift())
}

module.exports.statFile = function (archive, filename, followLinks) {
  const filesystem = disk.readFilesystemSync(archive)
  return filesystem.getFile(filename, followLinks)
}

module.exports.listPackage = function (archive, options) {
  return disk.readFilesystemSync(archive).listFiles(options)
}

module.exports.extractFile = function (archive, filename) {
  const filesystem = disk.readFilesystemSync(archive)
  return disk.readFileSync(filesystem, filename, filesystem.getFile(filename))
}

module.exports.extractAll = function (archive, dest) {
  const filesystem = disk.readFilesystemSync(archive)
  const filenames = filesystem.listFiles()

  // under windows just extract links as regular files
  const followLinks = process.platform === 'win32'

  // create destination directory
  fs.mkdirpSync(dest)

  return filenames.map((filename) => {
    filename = filename.substr(1) // get rid of leading slash
    const destFilename = path.join(dest, filename)
    const file = filesystem.getFile(filename, followLinks)
    if (file.files) {
      // it's a directory, create it and continue with the next entry
      fs.mkdirpSync(destFilename)
    } else if (file.link) {
      // it's a symlink, create a symlink
      const linkSrcPath = path.dirname(path.join(dest, file.link))
      const linkDestPath = path.dirname(destFilename)
      const relativePath = path.relative(linkDestPath, linkSrcPath);
      // try to delete output file, because we can't overwrite a link
      (() => {
        try {
          fs.unlinkSync(destFilename)
        } catch (error) {}
      })()
      const linkTo = path.join(relativePath, path.basename(file.link))
      fs.symlinkSync(linkTo, destFilename)
    } else {
      // it's a file, extract it
      const content = disk.readFileSync(filesystem, filename, file)
      fs.writeFileSync(destFilename, content)
    }
  })
}

module.exports.uncache = function (archive) {
  return disk.uncacheFilesystem(archive)
}

module.exports.uncacheAll = function () {
  disk.uncacheAll()
}
<|endoftext|>