<commit_before>import { action, computed, observable, observe } from "mobx";
import SuiteState from "./SuiteState";

class UiState {
  @observable selectedTest = {};
  @observable selectedCommand = null;
  @observable filterTerm = "";
  @observable dragInProgress = false;
  @observable clipboard = null;
  @observable isRecording = false;
  @observable isSelectingTarget = false;
  @observable consoleHeight = 200;
  @observable minConsoleHeight = 200;
  @observable minContentHeight = 460;

  constructor() {
    this.suiteStates = {};
    this.filterFunction = this.filterFunction.bind(this);
  }

  @action.bound setProject(project) {
    this._project = project;
    observe(this._project, "id", this.projectChanged);
  }

  @computed get filteredTests() {
    return this._project.tests.filter(this.filterFunction);
  }

  @computed get baseUrl() {
    return this._project.url;
  }

  @action.bound copyToClipboard(item) {
    this.clipboard = item;
  }

  @action.bound selectTest(test, suite) {
    this.selectedTest = { test, suite };
  }

  @action.bound selectCommand(command) {
    this.selectedCommand = command;
  }

  @action.bound changeFilter(term) {
    this.filterTerm = term;
  }

  @action.bound setDrag(dragProgress) {
    this.dragInProgress = dragProgress;
  }

  @action.bound toggleRecord() {
    this.isRecording = !this.isRecording;
  }

  @action.bound setSelectingTarget(isSelecting) {
    this.isSelectingTarget = isSelecting;
  }

  @action.bound resizeConsole(height) {
    console.log(height);
    this.consoleHeight = height;
  }

  addStateForSuite(suite) {
    this.suiteStates[suite.id] = new SuiteState(this, suite);
  }

  filterFunction({name}) {
    return (name.indexOf(this.filterTerm) !== -1);
  }

  setUrl(url, addToCache) {
    this._project.setUrl(url);
    if (addToCache) this._project.addUrl(url);
  }

  @action.bound projectChanged() {
    this.selectedTest = {};
    this.selectedCommand = null;
    this.filterTerm = "";
    this.dragInProgress = false;
    this.clipboard = null;
    this.isRecording = false;
    this.suiteStates = {};
  }
}

if (!window._state) window._state = new UiState();

export default window._state;
<commit_msg>persist console size through uses<commit_after>import { action, computed, observable, observe } from "mobx";
import browser from "webextension-polyfill";
import SuiteState from "./SuiteState";

class UiState {
  @observable selectedTest = {};
  @observable selectedCommand = null;
  @observable filterTerm = "";
  @observable dragInProgress = false;
  @observable clipboard = null;
  @observable isRecording = false;
  @observable isSelectingTarget = false;
  @observable consoleHeight = 200;
  @observable minConsoleHeight = 200;
  @observable minContentHeight = 460;

  constructor() {
    this.suiteStates = {};
    this.filterFunction = this.filterFunction.bind(this);
    browser.storage.local.get().then(storage => {
      if (storage.consoleSize && storage.consoleSize >= this.minConsoleHeight) {
        this.resizeConsole(storage.consoleSize);
      }
    });
  }

  @action.bound setProject(project) {
    this._project = project;
    observe(this._project, "id", this.projectChanged);
  }

  @computed get filteredTests() {
    return this._project.tests.filter(this.filterFunction);
  }

  @computed get baseUrl() {
    return this._project.url;
  }

  @action.bound copyToClipboard(item) {
    this.clipboard = item;
  }

  @action.bound selectTest(test, suite) {
    this.selectedTest = { test, suite };
  }

  @action.bound selectCommand(command) {
    this.selectedCommand = command;
  }

  @action.bound changeFilter(term) {
    this.filterTerm = term;
  }

  @action.bound setDrag(dragProgress) {
    this.dragInProgress = dragProgress;
  }

  @action.bound toggleRecord() {
    this.isRecording = !this.isRecording;
  }

  @action.bound setSelectingTarget(isSelecting) {
    this.isSelectingTarget = isSelecting;
  }

  @action.bound resizeConsole(height) {
    this.consoleHeight = height;
    browser.storage.local.set({
      consoleSize: height
    });
  }

  addStateForSuite(suite) {
    this.suiteStates[suite.id] = new SuiteState(this, suite);
  }

  filterFunction({name}) {
    return (name.indexOf(this.filterTerm) !== -1);
  }

  setUrl(url, addToCache) {
    this._project.setUrl(url);
    if (addToCache) this._project.addUrl(url);
  }

  @action.bound projectChanged() {
    this.selectedTest = {};
    this.selectedCommand = null;
    this.filterTerm = "";
    this.dragInProgress = false;
    this.clipboard = null;
    this.isRecording = false;
    this.suiteStates = {};
  }
}

if (!window._state) window._state = new UiState();

export default window._state;
<|endoftext|>


<commit_before>(function() {
    exports.config = config = (function() {
        function config(grunt, config) {
            /**
             * Setup grunt config for global tool
             */

            config.tasks.default = {
                isSystem: true,
                description: 'Webino Development Kit help',
                function: function () {
                    config.showTasksHelp();
                }
            };

            config.tasks.mod = {
                description: 'Develop existing Webino module',
                examples: ['webino mod -name WebinoExample'],
                function: function () {

                    // Resolve module by name
                    var name = grunt.option('name');
                    if (name) {
                        grunt.log.writeln('Preparing module \'' + name + '\' for development ...');

                        var done = this.async();
                        grunt.util.spawn({
                            cmd: 'git', args: ['clone', config.github.webino.ssh + name]
                        }, function (error, result, code) {
                                if (error) {
                                    grunt.fail.warn('\n\n' + error + '\n\n');
                                }

                                // initialize module development environment
                                process.chdir(config.workspace.modules + '/' + name);
                                grunt.util.spawn({
                                    cmd: 'webino', args: ['init']
                                }, function (error, result, code) {
                                    if (error) {
                                        grunt.fail.warn('\n\n' + error + '\n\n');
                                    }
                                    grunt.log.info(result.stdout);
                                    done();
                                });
                            });
                    }

                    grunt.fail.warn('\n\nExpected module option, e.g.: \n\ -name WebinoExample \n\n');
                }
            };

            config.tasks.self_setup = {
                isSystem: true,
                description: 'Initializes Webino Development Kit',
                /**
                 * Required to run as root
                 */
                function: function () {
                    var root = __dirname + '/../../resources/php/';
                    process.chdir(root);

                    if (grunt.file.isFile(root + 'composer.phar')) {
                        grunt.log.ok('Updating ...');
                        grunt.task.run('exec:composer_self_update');
                        grunt.task.run('exec:composer_update');
                        return;
                    }

                    grunt.log.ok('Initializing ...');
                    grunt.task.run('exec:get_composer');
                    grunt.task.run('exec:composer_update');

                    grunt.log.ok('Creating workspace ...');
                    grunt.task.run('mkdir:workspace');
                }
            };
        };
        return config;
    })();
}).call(this);
<commit_msg>Updated global.js, added npm_install_grunt_cli exec task to install grunt-cli locally after toolkit setup<commit_after>(function() {
    exports.config = config = (function() {
        function config(grunt, config) {
            /**
             * Setup grunt config for global tool
             */

            config.exec.npm_install_grunt_cli = {
                cmd: 'npm install -g grunt-cli'
            };

            /**
             * Setup tasks
             */

            config.tasks.default = {
                isSystem: true,
                description: 'Webino Development Kit help',
                function: function () {
                    config.showTasksHelp();
                }
            };

            config.tasks.mod = {
                description: 'Develop existing Webino module',
                examples: ['webino mod -name WebinoExample'],
                function: function () {

                    // Resolve module by name
                    var name = grunt.option('name');
                    if (name) {
                        grunt.log.writeln('Preparing module \'' + name + '\' for development ...');

                        var done = this.async();
                        grunt.util.spawn({
                            cmd: 'git', args: ['clone', config.github.webino.ssh + name]
                        }, function (error, result, code) {
                                if (error) {
                                    grunt.fail.warn('\n\n' + error + '\n\n');
                                }

                                // initialize module development environment
                                process.chdir(config.workspace.modules + '/' + name);
                                grunt.util.spawn({
                                    cmd: 'webino', args: ['init']
                                }, function (error, result, code) {
                                    if (error) {
                                        grunt.fail.warn('\n\n' + error + '\n\n');
                                    }
                                    grunt.log.info(result.stdout);
                                    done();
                                });
                            });
                    }

                    grunt.fail.warn('\n\nExpected module option, e.g.: \n\ -name WebinoExample \n\n');
                }
            };

            config.tasks.self_setup = {
                isSystem: true,
                description: 'Initializes Webino Development Kit',
                /**
                 * Required to run as root
                 */
                function: function () {
                    var root = __dirname + '/../../resources/php/';
                    process.chdir(root);

                    if (grunt.file.isFile(root + 'composer.phar')) {
                        grunt.log.ok('Updating ...');
                        grunt.task.run('exec:composer_self_update');
                        grunt.task.run('exec:composer_update');
                        return;
                    }

                    grunt.log.ok('Initializing ...');
                    grunt.task.run('exec:npm_install_grunt_cli');
                    grunt.task.run('exec:get_composer');
                    grunt.task.run('exec:composer_update');

                    grunt.log.ok('Creating workspace ...');
                    grunt.task.run('mkdir:workspace');
                }
            };
        };
        return config;
    })();
}).call(this);
<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

const paths = require('../config/paths');

const eslintFormatter = require('../utils/eslintFormatter');
const appendModuleRule = require('../utils/appendModuleRule');

module.exports = function (options, config) {
    const regScriptFile = /\.(js|jsx|mjs)$/;
    const regExclude = [/[/\\\\]node_modules[/\\\\]/];

    // eslint
    if (fs.existsSync(path.join(config.context, '.eslintrc'))) {
        config.module.rules.unshift({
            test: regScriptFile,
            enforce: 'pre',

            include: [paths.appEntry],
            exclude: regExclude,

            use: [{
                loader: require.resolve('eslint-loader'),
                options: {
                    configFile: path.join(config.context, '.eslintrc'),
                    // 报warning了就终止webpack编译
                    failOnWarning: false,
                    // 报error了就终止webpack编译
                    failOnError: true,
                    formatter: eslintFormatter
                }
            }]
        });
    }

    // babel config
    let babelRCPath = path.join(paths.appPath, '.babelrc');

    let babelConfig = {
        cacheDirectory: paths.appCache,
        inputSourceMap: false,
        highlightCode: true
    };
    if (fs.existsSync(babelRCPath)) {
        babelConfig.babelrc = true;
    } else {
        babelConfig.presets = [
            [
                require.resolve('babel-preset-zuzuche'), {
                env: {
                    'targets': {
                        'browsers': config.browserslist
                    },
                    'useBuiltIns': false,
                    'modules': false,
                    'debug': false
                },
                transformRuntime: {
                    'helpers': false,
                    'polyfill': true,
                    'regenerator': true
                }
            }]
        ];
        babelConfig.plugins = [];
    }

    config = appendModuleRule(config, [{
        // 处理项目内脚本
        test: regScriptFile,

        include: [paths.appEntry],
        exclude: regExclude,

        use: [{
            loader: require.resolve('babel-loader'),
            options: babelConfig
        }]
    }, {
        // 处理项目以外的脚本
        test: /\.js$/i,
        use: [{
            loader: require.resolve('babel-loader'),
            options: babelConfig
        }]
    }]);

    config.optimization.minimizer.push(
        new UglifyJsPlugin({
            cache: path.join(paths.appCache, 'uglifyjs-webpack-plugin'),
            parallel: true,

            uglifyOptions: {
                ecma: 8,
                safari10: true,

                // https://www.npmjs.com/package/uglify-js#output-options
                output: {
                    ascii_only: true,
                    beautify: false, // 最紧凑的输出
                    comments: false // 删除所有的注释
                },

                // https://www.npmjs.com/package/uglify-js#compress-options
                compress: {
                    warnings: false, // 在UglifyJs删除没有用到的代码时不输出警告
                    drop_console: false, // 删除所有的 `console` 语句, 还可以兼容ie浏览器
                    drop_debugger: true, // 移除 `debugger;` 声明
                    collapse_vars: true, // 内嵌定义了但是只用到一次的变量
                    reduce_vars: true // 提取出出现多次但是没有定义成变量去引用的静态值
                }
            }
        })
    );

    return config;
};
<commit_msg>feat: js处理逻辑<commit_after>'use strict';

const fs = require('fs');
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

const paths = require('../config/paths');

const eslintFormatter = require('../utils/eslintFormatter');
const appendModuleRule = require('../utils/appendModuleRule');

module.exports = function (config) {
    const regScriptFile = /\.(js|jsx|mjs)$/;
    const regExclude = [/[/\\\\]node_modules[/\\\\]/];

    // eslint
    if (fs.existsSync(path.join(config.context, '.eslintrc'))) {
        config.module.rules.unshift({
            test: regScriptFile,
            enforce: 'pre',

            include: [paths.appEntry],
            exclude: regExclude,

            use: [{
                loader: require.resolve('eslint-loader'),
                options: {
                    configFile: path.join(config.context, '.eslintrc'),
                    // 报warning了就终止webpack编译
                    failOnWarning: false,
                    // 报error了就终止webpack编译
                    failOnError: true,
                    formatter: eslintFormatter
                }
            }]
        });
    }

    // babel config
    let babelRCPath = path.join(paths.appPath, '.babelrc');

    let babelConfig = {
        cacheDirectory: paths.appCache,
        inputSourceMap: false,
        highlightCode: true
    };
    if (fs.existsSync(babelRCPath)) {
        babelConfig.babelrc = true;
    } else {
        babelConfig.presets = [
            [
                require.resolve('babel-preset-zuzuche'), {
                env: {
                    'targets': {
                        'browsers': config.browserslist
                    },
                    'useBuiltIns': false,
                    'modules': false,
                    'debug': false
                },
                transformRuntime: {
                    'helpers': false,
                    'polyfill': true,
                    'regenerator': true
                }
            }]
        ];
        babelConfig.plugins = [];
    }

    config = appendModuleRule(config, [{
        // 处理项目内脚本
        test: regScriptFile,

        include: [paths.appEntry],
        exclude: regExclude,

        use: [{
            loader: require.resolve('babel-loader'),
            options: babelConfig
        }]
    }, {
        // 处理项目以外的脚本
        test: /\.js$/i,
        use: [{
            loader: require.resolve('babel-loader'),
            options: babelConfig
        }]
    }]);

    config.optimization.minimizer.push(
        new UglifyJsPlugin({
            cache: path.join(paths.appCache, 'uglifyjs-webpack-plugin'),
            parallel: true,

            uglifyOptions: {
                ecma: 8,
                safari10: true,

                // https://www.npmjs.com/package/uglify-js#output-options
                output: {
                    ascii_only: true,
                    beautify: false, // 最紧凑的输出
                    comments: false // 删除所有的注释
                },

                // https://www.npmjs.com/package/uglify-js#compress-options
                compress: {
                    warnings: false, // 在UglifyJs删除没有用到的代码时不输出警告
                    drop_console: false, // 删除所有的 `console` 语句, 还可以兼容ie浏览器
                    drop_debugger: true, // 移除 `debugger;` 声明
                    collapse_vars: true, // 内嵌定义了但是只用到一次的变量
                    reduce_vars: true // 提取出出现多次但是没有定义成变量去引用的静态值
                }
            }
        })
    );

    return config;
};
<|endoftext|>


<commit_before>'use strict';

const debug                     = require('debug')('mongo-observer'),
      Oplog                     = require('./oplog'),
      Emitter                   = require('create-emitter'),
      MongoDriver               = require('./mongo-driver'),
      utils                     = require('./utils'),
      isFunction                = utils.isFunction,
      isArray                   = utils.isArray,
      isEmpty                   = utils.isEmpty,
      isString                  = utils.isString,
      isArrayOfStrings          = utils.isArrayOfStrings,
      noop                      = utils.noop,

      ERROR_ALREADY_LISTENING   = new Error('MongoObserver already listening');
      ERROR_CREATION_TIMEOUT    = new Error('MongoObserver creation timeout!');

module.exports = require('tofactory')(MongoObserver);

function MongoObserver(spec) {
    const emitter   = Emitter.create(),
          INSERT    = 'isert',
          UPDATE    = 'update',
          REMOVE    = 'remove';

    let count = 0,
        listening = false,
        oplog, mongo;

    init();

    return {
        driver: mongo.driver,
        getDbConn: mongo.getDbConn,
        collection,
        get observebleColletions() {
            return oplog.collections;
        },
        set observebleColletions(cols, done) {
            done = done || noop;
            if (!cols || isFunction(cols) || isEmpty(cols)) {
                getAllCollectionNames(function (err, collectionNames) {
                    if (err) return done(err);
                    oplog.collections = collectionNames;
                    done();
                })
            } else {
                if (isArrayOfStrings(cols)) {
                    oplog.collections = cols;
                } else {
                    done(new Error('"cols" parameter must be a Array'));
                }
            }
        },
        on: emitter.on,
        off: emitter.off,
        observe
    };

    function init() {
        let opts;

        if (isString(spec)) {
            opts = spec;
        } else {
            opts = {
                url: spec.dbURL,
                db: spec.db,
                connOpts: spec.dbConnOpts
            };
        }

        mongo = MongoDriver(opts);
        mongo.connect(function (err, db) {
            if (err) throw err;

            oplog = Oplog.create({
                db,
                collections: spec.observebleColletions || [];
                onInsert: insertOperation,
                onUpdate: updateOperation,
                onRemove: removeOperation
            });
            count = 0;
        });
    }

    function observe(done) {
        if (listening) return done(ERROR_ALREADY_LISTENING);
        if (count > 20) return done(ERROR_CREATION_TIMEOUT);

        if (oplog) {
            ready();
        } else { // wait for oplog creation
            setTimeout(ready, 200);
            count += 1;
        }

        function ready() {
            oplog.listen(function (err) {
                if (err) return done(err);
                listening = true;
                done();
            });
        }
    }

    function insertOp(collection, data) {
        emitter.emit(`${collection}:${INSERT}:${data._id}`, data);
    }

    function removeOp(collection, data) {
        emitter.emit(`${collection}:${REMOVE}:${data._id}`);
    }

    function updateOp(collection, data, _id) {
        if (data) {
            emitter.emit(`${collection}:${UPDATE}:${_id}`, data);
        } else {
            getDataFromDb(collection, _id);
        }
    }

    function getDataFromDb(collection, _id) {
        findOneById(collection, _id, function (err, doc) {
            if (err) return debug(err);
            emitter.emit(`${collection}:${UPDATE}`, doc);
        });
    }

    function findOneById(colName, _id, next) {
        db.collection(colName, function (err, col) {
            if (err) return next(err);
            col.find({_id: _id}).limit(1).next(function (err, doc) {
                if (err) return next(err);
                return next(undefined, doc);
            });
        });
    }

    function getAllCollectionNames(next) {
        const collectionNames = [];

        db.collections(function (err, collections) {
            if (err) return next(err);
            collections.forEach(function (collection, i) {
                 collectionNames[i] = collection.collectionName;
            });
            next(undefined, collectionNames);
        });
    }
}
<commit_msg>added oplog error emission<commit_after>'use strict';

const debug                     = require('debug')('mongo-observer'),
      Oplog                     = require('./oplog'),
      Emitter                   = require('create-emitter'),
      MongoDriver               = require('./mongo-driver'),
      utils                     = require('./utils'),
      isFunction                = utils.isFunction,
      isArray                   = utils.isArray,
      isEmpty                   = utils.isEmpty,
      isString                  = utils.isString,
      isArrayOfStrings          = utils.isArrayOfStrings,
      noop                      = utils.noop,

      ERROR_ALREADY_LISTENING   = new Error('MongoObserver already listening');
      ERROR_CREATION_TIMEOUT    = new Error('MongoObserver creation timeout!');

module.exports = require('tofactory')(MongoObserver);

function MongoObserver(spec) {
    const emitter   = Emitter.create(),
          INSERT    = 'isert',
          UPDATE    = 'update',
          REMOVE    = 'remove';

    let count = 0,
        listening = false,
        oplog, mongo;

    init();

    return {
        driver: mongo.driver,
        getDbConn: mongo.getDbConn,
        collection,
        get observebleColletions() {
            return oplog.collections;
        },
        set observebleColletions(cols, done) {
            done = done || noop;
            if (!cols || isFunction(cols) || isEmpty(cols)) {
                getAllCollectionNames(function (err, collectionNames) {
                    if (err) return done(err);
                    oplog.collections = collectionNames;
                    done();
                })
            } else {
                if (isArrayOfStrings(cols)) {
                    oplog.collections = cols;
                } else {
                    done(new Error('"cols" parameter must be a Array'));
                }
            }
        },
        on: emitter.on,
        off: emitter.off,
        observe
    };

    function init() {
        let opts;

        if (isString(spec)) {
            opts = spec;
        } else {
            opts = {
                url: spec.dbURL,
                db: spec.db,
                connOpts: spec.dbConnOpts
            };
        }

        mongo = MongoDriver(opts);
        mongo.connect(function (err, db) {
            if (err) throw err;

            oplog = Oplog.create({
                db,
                collections: spec.observebleColletions || [];
                onInsert: insertOperation,
                onUpdate: updateOperation,
                onRemove: removeOperation
            });

            oplog.on('error', function (err) {
                emitter.emit(err);
            });

            count = 0;
        });
    }

    function observe(done) {
        if (listening) return done(ERROR_ALREADY_LISTENING);
        if (count > 20) return done(ERROR_CREATION_TIMEOUT);

        if (oplog) {
            ready();
        } else { // wait for oplog creation
            setTimeout(ready, 200);
            count += 1;
        }

        function ready() {
            oplog.listen(function (err) {
                if (err) return done(err);
                listening = true;
                done();
            });
        }
    }

    function insertOp(collection, data) {
        emitter.emit(`${collection}:${INSERT}:${data._id}`, data);
    }

    function removeOp(collection, data) {
        emitter.emit(`${collection}:${REMOVE}:${data._id}`);
    }

    function updateOp(collection, data, _id) {
        if (data) {
            emitter.emit(`${collection}:${UPDATE}:${_id}`, data);
        } else {
            getDataFromDb(collection, _id);
        }
    }

    function getDataFromDb(collection, _id) {
        findOneById(collection, _id, function (err, doc) {
            if (err) return debug(err);
            emitter.emit(`${collection}:${UPDATE}`, doc);
        });
    }

    function findOneById(colName, _id, next) {
        db.collection(colName, function (err, col) {
            if (err) return next(err);
            col.find({_id: _id}).limit(1).next(function (err, doc) {
                if (err) return next(err);
                return next(undefined, doc);
            });
        });
    }

    function getAllCollectionNames(next) {
        const collectionNames = [];

        db.collections(function (err, collections) {
            if (err) return next(err);
            collections.forEach(function (collection, i) {
                 collectionNames[i] = collection.collectionName;
            });
            next(undefined, collectionNames);
        });
    }
}
<|endoftext|>


<commit_before>/*
 * moving-average.js: Calculates a moving average of various types based on an internal window.
 *
 * (C) 2012, Charlie Robbins
 *
 */

var util = require('util'),
    Window = require('./window');

//
// ### function MovingAverage (options)
// #### @options {Object} Options for this instance
// ####   @options.size    {number}        Number of events to store in this instance.
// ####   @options.window  {Object}        Value indicating if this is a fixed window.
// ####   @options.average {string|Object} Details of the averaging algorithm to use.
// Constructor function for the MovingAverage object responsible for calculating
// various moving averages for fixed or continuous windows of events based on a
// given size.
//
var MovingAverage = module.exports = function MovingAverage(options) {
  if (!options || !options.size || !options.window || !options.average) {
    throw new Error('options.size, options.window, and options.average are required.');
  }

  Window.call(this, options);
  this.data    = [];
  this.window  = options.window;
  this.average = typeof options.average === 'string'
    ? { type: options.average }
    : options.average;
};

//
// ### function write (data)
// #### @data {Object} Data to write to this average.
// Writes the specified `data` to the internal window
// and emits `data` with the calculated average.
//
MovingAverage.prototype.write = function (data) {
  //
  // Write the data to the internal window.
  //
  this.window.write(data);

  var average = this.average(data);

  //
  // Emit the average of the data using the specified
  // algorithm associated with this instance.
  //
  this.emit('data', average);
  this.data.push(average);
};

//
// ### function average (data)
// #### @data {Object} Data to write to this average.
// Returns the average for the specified algorithm
// associated with this instance.
//
MovingAverage.prototype.average = function (data) {
  switch (this.average.type) {
    case 'simple':      return this.simpleAverage(data);
    case 'weighted':    return this.weightedAverage(data);
    case 'exponential': return this.exponentialAverage(data);
    default: throw new Error('Invalid average type: ' + this.average.type);
  }
};

//
// ### function simpleAverage (data)
// #### @data {Object} Data to write to this average.
// Returns a simple moving average for the internal window.
//
MovingAverage.prototype.simpleAverage = function (data) {
  return this.window.mean;
};

//
// ### function weightedAverage ()
// Returns a weighted moving average for the internal window.
//
MovingAverage.prototype.weightedAverage = function (data) {
  var length = this.window.data.length,
      self   = this;

  return this.window.data.reduce(function (avg, data, i) {
    return avg + (data.metric * self.average.weights[i]);
  }, 0) / ((length * (length + 1)) / 2) ;
};

//
// ### function exponentialAverage (data)
// #### @data {Object} Data to write to this average.
// Returns an exponential weighted moving average for the
// internal window.
//
MovingAverage.prototype.exponentialAverage = function (data) {
  var last  = this.data[this.data.length - 1],
      alpha = this.average.alpha;

  return (alpha * data.metric) +
    (1 - alpha * last);
};<commit_msg>[fix] A couple of fixes to MovingAverage.<commit_after>/*
 * moving-average.js: Calculates a moving average of various types based on an internal window.
 *
 * (C) 2012, Charlie Robbins
 *
 */

var util = require('util'),
    Window = require('./window');

//
// ### function MovingAverage (options)
// #### @options {Object} Options for this instance
// ####   @options.size    {number}        Number of events to store in this instance.
// ####   @options.window  {Object}        Value indicating if this is a fixed window.
// ####   @options.average {string|Object} Details of the averaging algorithm to use.
// Constructor function for the MovingAverage object responsible for calculating
// various moving averages for fixed or continuous windows of events based on a
// given size.
//
var MovingAverage = module.exports = function MovingAverage(options) {
  if (!options || !options.window || !options.average) {
    throw new Error('options.size, options.window, and options.average are required.');
  }

  Window.call(this, options);
  this.data    = [];
  this.window  = options.window;
  this.average = typeof options.average === 'string'
    ? { type: options.average }
    : options.average;
};

//
// Inherit from Window.
//
util.inherits(MovingAverage, Window);

//
// ### function write (data)
// #### @data {Object} Data to write to this average.
// Writes the specified `data` to the internal window
// and emits `data` with the calculated average.
//
MovingAverage.prototype.write = function (data) {
  //
  // Write the data to the internal window and
  // calculate the window average.
  //
  this.window.write(data);
  this.last = this.calculate(data);

  //
  // Emit the average of the data using the specified
  // algorithm associated with this instance.
  //
  this.emit('data', this.last);
};

//
// ### function calculate (data)
// #### @data {Object} Data to write to this average.
// Returns the average for the specified algorithm
// associated with this instance.
//
MovingAverage.prototype.calculate = function (data) {
  switch (this.average.type) {
    case 'simple':      return this.simpleAverage(data);
    case 'weighted':    return this.weightedAverage(data);
    case 'exponential': return this.exponentialAverage(data);
    default: throw new Error('Invalid average type: ' + this.average.type);
  }
};

//
// ### function simpleAverage (data)
// #### @data {Object} Data to write to this average.
// Returns a simple moving average for the internal window.
//
MovingAverage.prototype.simpleAverage = function (data) {
  return this.window.mean;
};

//
// ### function weightedAverage ()
// Returns a weighted moving average for the internal window.
//
MovingAverage.prototype.weightedAverage = function (data) {
  var length = this.window.data.length,
      diff   = 10 - length,
      self   = this;

  return this.window.data.reduce(function (avg, data, i) {
    return avg + (data.metric * self.average.weights[i + diff]);
  }, 0) / ((length * (length + 1)) / 2) ;
};

//
// ### function exponentialAverage (data)
// #### @data {Object} Data to write to this average.
// Returns an exponential weighted moving average for the
// internal window.
//
MovingAverage.prototype.exponentialAverage = function (data) {
  var alpha = this.average.alpha;

  if (!this.last) {
    return data.metric;
  }

  return (alpha * data.metric) +
    (1 - alpha * this.last);
};<|endoftext|>


<commit_before>
  /**
   *  Date field -> Place to choose and edit date field
   *  - It accepts a model with {attribute: 'colum', value: '2013-02-12T12:19:58+01:00'}
   *  - It will create a new model to split this value into {day, month, year and time}
   *  var date = new cdb.admin.DateField({ model: model })
   */

  cdb.admin.DateField = cdb.admin.StringField.extend({

    className: 'field date',

    timezone: 2,

    default_options: {
      template_name: 'common/views/forms/date_field',
      label:          false,
      readOnly:       false
    },

    events: {
      'change input.time': '_onChange',
      'keyup input.time':  '_onKeyUp'
    },

    initialize: function() {
      _.defaults(this.options, this.default_options);

      _.bindAll(this, '_onChange', '_onKeyUp', '_onChangeModel');

      this.template_base = this.options.template_base ? _.template(this.options.template_base) : cdb.templates.getTemplate(this.options.template_name);

      // Get date
      var date = this._splitDate((this.model.get('value')));

      // Generate a new date Model (later it will be removed and destroyed)
      this.date_model = new cdb.core.Model();

      // Begins as valid
      this.valid = true;

      // Bind changes
      this.date_model.bind('change', this._onChangeModel);

      // Date model data set
      this.date_model.set(date);

      // On clean
      this.bind('clean', this._reClean);
    },

    render: function() {
      this.$el.html(this.template_base(_.extend(this.model.toJSON(), this.options)));

      // Apply views
      this._initViews();

      // Check readOnly and unbind all events
      if (this.options.readOnly) {
        this.undelegateEvents();
      }

      return this;
    },

    _initViews: function() {

      // Days spinner
      var days = this.days = new cdb.forms.Spinner({
        el: this.$el.find('div.day'),
        model:    this.date_model,
        disabled: this.options.readOnly,
        property: 'day',
        min:      1,
        max:      31,
        inc:      1,
        width:    15,
        noSlider: true,
        pattern:  /^([12]?\d{0,1}|3[01]{0,2})$/
      });

      this.addView(this.days);
      this.$("div.day").append(days.render());

      // Year spinner
      var years = this.years = new cdb.forms.Spinner({
        el: this.$el.find('div.year'),
        model:    this.date_model,
        disabled: this.options.readOnly,
        property: 'year',
        min:      1900,
        max:      2100,
        width:    28,
        noSlider: true,
        pattern:  /^([0-9]{0,4})$/
      });
      this.addView(this.years);
      this.$("div.year").append(years.render());

      // Month selector
      var months = this.months = new cdb.forms.Combo({
        el: this.$el.find('div.month'),
        model:      this.date_model,
        disabled:   this.options.readOnly,
        property:   'month',
        width:      '140px',
        extra:      [['January',1], ['February',2], ['March',3], ['April',4], ['May',5], ['June',6], ['July',7], ['August',8], ['September',9], ['October',10], ['November',11], ['December',12]]
      });
      this.addView(this.months);
      this.$("div.month").append(months.render());

      // Time input
      this.$('input.time').val(this.date_model.get('time'));
    },

    /**
     *  Split the date string
     */
    _splitDate: function(str) {
      var date = {};

      if (str=='') {
        date.day = 1;
        date.month = 1;
        date.year = 2012;
        date.time = '00:00:00';
      } else {
        try {
          var split_date_hour = str.split('T');
          if (split_date_hour.length>1) {
            var split_date = split_date_hour[0].split('-');
            date.time = split_date_hour[1].substr(0,8);
            date.day = parseInt(split_date[2]);
            date.month = parseInt(split_date[1]);
            date.year = parseInt(split_date[0]);
          } else {
            date.day = 1;
            date.month = 1;
            date.year = 2012;
            date.time = '00:00:00';
          }
        } catch (e) {
          date.day = 1;
          date.month = 1;
          date.year = 2012;
          date.time = '00:00:00';
        }
      }
      return date;
    },

    /**
     *  Get the date model and converts to date string
     */
    _toDate: function(date) {
      return date.year + "-" + date.month + "-" + date.day + "T" + date.time + "+0" + this.timezone + ":00"
    },

    /**
     *  Check if the time is well formed or not
     */
    _checkTime: function(time) {
      var pattern = /^([01]{1}[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/;
      if (pattern.test(time)) {
        return true
      } else {
        return false
      }
    },

    // Events
    _onChange: function(e) {
      var time = this.$('input.time').val();

      if (this._checkTime(time)) {
        this.date_model.set('time', time);
      }
    },

    _onChangeModel: function(m) {
      this.model.set('value', this._toDate(this.date_model.toJSON()));
    },

    _onKeyDown: function() {},

    _onKeyUp: function(e) {
      var time = $(e.target).val();

      if (this._checkTime(time)) {

        if (e.keyCode === 13) {
          e.preventDefault();
          this._triggerEvent('ENTER');
          return false;
        }

        this.valid = true;
        this.date_model.set('time', time);
        $(e.target).removeClass("error");
      } else {
        this.valid = false;
        $(e.target).addClass("error");
      }
    },

    _reClean: function() {
      this.date_model.unbind('change');
      this.date_model.destroy();
    }
  })
<commit_msg>changed timezone from 2 to 0<commit_after>
  /**
   *  Date field -> Place to choose and edit date field
   *  - It accepts a model with {attribute: 'colum', value: '2013-02-12T12:19:58+01:00'}
   *  - It will create a new model to split this value into {day, month, year and time}
   *  var date = new cdb.admin.DateField({ model: model })
   */

  cdb.admin.DateField = cdb.admin.StringField.extend({

    className: 'field date',

    timezone: 0,

    default_options: {
      template_name: 'common/views/forms/date_field',
      label:          false,
      readOnly:       false
    },

    events: {
      'change input.time': '_onChange',
      'keyup input.time':  '_onKeyUp'
    },

    initialize: function() {
      _.defaults(this.options, this.default_options);

      _.bindAll(this, '_onChange', '_onKeyUp', '_onChangeModel');

      this.template_base = this.options.template_base ? _.template(this.options.template_base) : cdb.templates.getTemplate(this.options.template_name);

      // Get date
      var date = this._splitDate((this.model.get('value')));

      // Generate a new date Model (later it will be removed and destroyed)
      this.date_model = new cdb.core.Model();

      // Begins as valid
      this.valid = true;

      // Bind changes
      this.date_model.bind('change', this._onChangeModel);

      // Date model data set
      this.date_model.set(date);

      // On clean
      this.bind('clean', this._reClean);
    },

    render: function() {
      this.$el.html(this.template_base(_.extend(this.model.toJSON(), this.options)));

      // Apply views
      this._initViews();

      // Check readOnly and unbind all events
      if (this.options.readOnly) {
        this.undelegateEvents();
      }

      return this;
    },

    _initViews: function() {

      // Days spinner
      var days = this.days = new cdb.forms.Spinner({
        el: this.$el.find('div.day'),
        model:    this.date_model,
        disabled: this.options.readOnly,
        property: 'day',
        min:      1,
        max:      31,
        inc:      1,
        width:    15,
        noSlider: true,
        pattern:  /^([12]?\d{0,1}|3[01]{0,2})$/
      });

      this.addView(this.days);
      this.$("div.day").append(days.render());

      // Year spinner
      var years = this.years = new cdb.forms.Spinner({
        el: this.$el.find('div.year'),
        model:    this.date_model,
        disabled: this.options.readOnly,
        property: 'year',
        min:      1900,
        max:      2100,
        width:    28,
        noSlider: true,
        pattern:  /^([0-9]{0,4})$/
      });
      this.addView(this.years);
      this.$("div.year").append(years.render());

      // Month selector
      var months = this.months = new cdb.forms.Combo({
        el: this.$el.find('div.month'),
        model:      this.date_model,
        disabled:   this.options.readOnly,
        property:   'month',
        width:      '140px',
        extra:      [['January',1], ['February',2], ['March',3], ['April',4], ['May',5], ['June',6], ['July',7], ['August',8], ['September',9], ['October',10], ['November',11], ['December',12]]
      });
      this.addView(this.months);
      this.$("div.month").append(months.render());

      // Time input
      this.$('input.time').val(this.date_model.get('time'));
    },

    /**
     *  Split the date string
     */
    _splitDate: function(str) {
      var date = {};

      if (str=='') {
        date.day = 1;
        date.month = 1;
        date.year = 2012;
        date.time = '00:00:00';
      } else {
        try {
          var split_date_hour = str.split('T');
          if (split_date_hour.length>1) {
            var split_date = split_date_hour[0].split('-');
            date.time = split_date_hour[1].substr(0,8);
            date.day = parseInt(split_date[2]);
            date.month = parseInt(split_date[1]);
            date.year = parseInt(split_date[0]);
          } else {
            date.day = 1;
            date.month = 1;
            date.year = 2012;
            date.time = '00:00:00';
          }
        } catch (e) {
          date.day = 1;
          date.month = 1;
          date.year = 2012;
          date.time = '00:00:00';
        }
      }
      return date;
    },

    /**
     *  Get the date model and converts to date string
     */
    _toDate: function(date) {
      return date.year + "-" + date.month + "-" + date.day + "T" + date.time + "+0" + this.timezone + ":00"
    },

    /**
     *  Check if the time is well formed or not
     */
    _checkTime: function(time) {
      var pattern = /^([01]{1}[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/;
      if (pattern.test(time)) {
        return true
      } else {
        return false
      }
    },

    // Events
    _onChange: function(e) {
      var time = this.$('input.time').val();

      if (this._checkTime(time)) {
        this.date_model.set('time', time);
      }
    },

    _onChangeModel: function(m) {
      this.model.set('value', this._toDate(this.date_model.toJSON()));
    },

    _onKeyDown: function() {},

    _onKeyUp: function(e) {
      var time = $(e.target).val();

      if (this._checkTime(time)) {

        if (e.keyCode === 13) {
          e.preventDefault();
          this._triggerEvent('ENTER');
          return false;
        }

        this.valid = true;
        this.date_model.set('time', time);
        $(e.target).removeClass("error");
      } else {
        this.valid = false;
        $(e.target).addClass("error");
      }
    },

    _reClean: function() {
      this.date_model.unbind('change');
      this.date_model.destroy();
    }
  })
<|endoftext|>


<commit_before>'use strict';
/**
 * @ngdoc directive
 * @name ngRequired
 * @restrict A
 *
 * @param {expression} ngRequired AngularJS expression. If it evaluates to `true`, it sets the
 *                                `required` attribute to the element and adds the `required`
 *                                {@link ngModel.NgModelController#$validators `validator`}.
 *
 * @description
 *
 * ngRequired adds the required {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
 * It is most often used for {@link input `input`} and {@link select `select`} controls, but can also be
 * applied to custom controls.
 *
 * The directive sets the `required` attribute on the element if the AngularJS expression inside
 * `ngRequired` evaluates to true. A special directive for setting `required` is necessary because we
 * cannot use interpolation inside `required`. See the {@link guide/interpolation interpolation guide}
 * for more info.
 *
 * The validator will set the `required` error key to true if the `required` attribute is set and
 * calling {@link ngModel.NgModelController#$isEmpty `NgModelController.$isEmpty`} with the
 * {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} returns `true`. For example, the
 * `$isEmpty()` implementation for `input[text]` checks the length of the `$viewValue`. When developing
 * custom controls, `$isEmpty()` can be overwritten to account for a $viewValue that is not string-based.
 *
 * @example
 * <example name="ngRequiredDirective" module="ngRequiredExample">
 *   <file name="index.html">
 *
 *

 *       <form name="form">
 *         Toggle required:
 *         <input type="checkbox" ng-model="required" id="required" />
 *

 *         This input must be filled if `required` is true:
 *         <input type="text" ng-model="model" id="input" name="input" ng-required="required" />

 *

 *         required error set? = {{form.input.$error.required}}

 *         model = {{model}}
 *       </form>
 *

 *   </file>
 *   <file name="protractor.js" type="protractor">
       var required = element(by.binding('form.input.$error.required'));
       var model = element(by.binding('model'));
       var input = element(by.id('input'));

       it('should set the required error', function() {
         expect(required.getText()).toContain('true');

         input.sendKeys('123');
         expect(required.getText()).not.toContain('true');
         expect(model.getText()).toContain('123');
       });
 *   </file>
 * </example>
 */
var requiredDirective = function() {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function(scope, elm, attr, ctrl) {
      if (!ctrl) return;
      attr.required = true; // force truthy in case we are on non input element

      ctrl.$validators.required = function(modelValue, viewValue) {
        return !attr.required || !ctrl.$isEmpty(viewValue);
      };

      attr.$observe('required', function() {
        ctrl.$validate();
      });
    }
  };
};

/**
 * @ngdoc directive
 * @name ngPattern
 * @restrict A
 *
 * @param {expression|RegExp} ngPattern AngularJS expression that must evaluate to a `RegExp` or a `String`
 *                                      parsable into a `RegExp`, or a `RegExp` literal. See above for
 *                                      more details.
 *
 * @description
 *
 * ngPattern adds the pattern {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
 *
 * The validator sets the `pattern` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
 * does not match a RegExp which is obtained by evaluating the AngularJS expression given in the
 * `ngPattern` attribute value:
 * * If the expression evaluates to a RegExp object, then this is used directly.
 * * If the expression evaluates to a string, then it will be converted to a RegExp after wrapping it
 * in `^` and `$` characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
 *
 *

 * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
 * start at the index of the last search's match, thus not taking the whole input value into
 * account.
 *

 *
 *

 * **Note:** This directive is also added when the plain `pattern` attribute is used, with two
 * differences:
 *

 *

 *     `ngPattern` does not set the `pattern` attribute and therefore HTML5 constraint validation is
 *     not available.
 *

 *

 *     The `ngPattern` attribute must be an expression, while the `pattern` value must be
 *     interpolated.
 *

 *

 *

 *
 * @example
 * <example name="ngPatternDirective" module="ngPatternExample">
 *   <file name="index.html">
 *
 *

 *       <form name="form">
 *         Set a pattern (regex string):
 *         <input type="text" ng-model="regex" id="regex" />
 *

 *         This input is restricted by the current pattern:
 *         <input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" />

 *

 *         input valid? = {{form.input.$valid}}

 *         model = {{model}}
 *       </form>
 *

 *   </file>
 *   <file name="protractor.js" type="protractor">
       var model = element(by.binding('model'));
       var input = element(by.id('input'));

       it('should validate the input with the default pattern', function() {
         input.sendKeys('aaa');
         expect(model.getText()).not.toContain('aaa');

         input.clear().then(function() {
           input.sendKeys('123');
           expect(model.getText()).toContain('123');
         });
       });
 *   </file>
 * </example>
 */
var patternDirective = function() {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function(scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var regexp, patternExp = attr.ngPattern || attr.pattern;
      attr.$observe('pattern', function(regex) {
        if (isString(regex) && regex.length > 0) {
          regex = new RegExp('^' + regex + '$');
        }

        if (regex && !regex.test) {
          throw minErr('ngPattern')('noregexp',
            'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
            regex, startingTag(elm));
        }

        regexp = regex || undefined;
        ctrl.$validate();
      });

      ctrl.$validators.pattern = function(modelValue, viewValue) {
        // HTML5 pattern constraint validates the input value, so we validate the viewValue
        return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
      };
    }
  };
};

/**
 * @ngdoc directive
 * @name ngMaxlength
 * @restrict A
 *
 * @param {expression} ngMaxlength AngularJS expression that must evaluate to a `Number` or `String`
 *                                 parsable into a `Number`. Used as value for the `maxlength`
 *                                 {@link ngModel.NgModelController#$validators validator}.
 *
 * @description
 *
 * ngMaxlength adds the maxlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
 *
 * The validator sets the `maxlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
 * is longer than the integer obtained by evaluating the AngularJS expression given in the
 * `ngMaxlength` attribute value.
 *
 *

 * **Note:** This directive is also added when the plain `maxlength` attribute is used, with two
 * differences:
 *

 *

 *     `ngMaxlength` does not set the `maxlength` attribute and therefore HTML5 constraint
 *     validation is not available.
 *

 *

 *     The `ngMaxlength` attribute must be an expression, while the `maxlength` value must be
 *     interpolated.
 *

 *

 *

 *
 * @example
 * <example name="ngMaxlengthDirective" module="ngMaxlengthExample">
 *   <file name="index.html">
 *
 *

 *       <form name="form">
 *         Set a maxlength:
 *         <input type="number" ng-model="maxlength" id="maxlength" />
 *

 *         This input is restricted by the current maxlength:
 *         <input type="text" ng-model="model" id="input" name="input" ng-maxlength="maxlength" />

 *

 *         input valid? = {{form.input.$valid}}

 *         model = {{model}}
 *       </form>
 *

 *   </file>
 *   <file name="protractor.js" type="protractor">
       var model = element(by.binding('model'));
       var input = element(by.id('input'));

       it('should validate the input with the default maxlength', function() {
         input.sendKeys('abcdef');
         expect(model.getText()).not.toContain('abcdef');

         input.clear().then(function() {
           input.sendKeys('abcde');
           expect(model.getText()).toContain('abcde');
         });
       });
 *   </file>
 * </example>
 */
var maxlengthDirective = function() {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function(scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var maxlength = -1;
      attr.$observe('maxlength', function(value) {
        var intVal = toInt(value);
        maxlength = isNumberNaN(intVal) ? -1 : intVal;
        ctrl.$validate();
      });
      ctrl.$validators.maxlength = function(modelValue, viewValue) {
        return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
      };
    }
  };
};

/**
 * @ngdoc directive
 * @name ngMinlength
 * @restrict A
 *
 * @param {expression} ngMinlength AngularJS expression that must evaluate to a `Number` or `String`
 *                                 parsable into a `Number`. Used as value for the `minlength`
 *                                 {@link ngModel.NgModelController#$validators validator}.
 *
 * @description
 *
 * ngMinlength adds the minlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
 *
 * The validator sets the `minlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
 * is shorter than the integer obtained by evaluating the AngularJS expression given in the
 * `ngMinlength` attribute value.
 *
 *

 * **Note:** This directive is also added when the plain `minlength` attribute is used, with two
 * differences:
 *

 *

 *     `ngMinlength` does not set the `minlength` attribute and therefore HTML5 constraint
 *     validation is not available.
 *

 *

 *     The `ngMinlength` value must be an expression, while the `minlength` value must be
 *     interpolated.
 *

 *

 *

 *
 * @example
 * <example name="ngMinlengthDirective" module="ngMinlengthExample">
 *   <file name="index.html">
 *
 *

 *       <form name="form">
 *         Set a minlength:
 *         <input type="number" ng-model="minlength" id="minlength" />
 *

 *         This input is restricted by the current minlength:
 *         <input type="text" ng-model="model" id="input" name="input" ng-minlength="minlength" />

 *

 *         input valid? = {{form.input.$valid}}

 *         model = {{model}}
 *       </form>
 *

 *   </file>
 *   <file name="protractor.js" type="protractor">
       var model = element(by.binding('model'));
       var input = element(by.id('input'));

       it('should validate the input with the default minlength', function() {
         input.sendKeys('ab');
         expect(model.getText()).not.toContain('ab');

         input.sendKeys('abc');
         expect(model.getText()).toContain('abc');
       });
 *   </file>
 * </example>
 */
var minlengthDirective = function() {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function(scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var minlength = 0;
      attr.$observe('minlength', function(value) {
        minlength = toInt(value) || 0;
        ctrl.$validate();
      });
      ctrl.$validators.minlength = function(modelValue, viewValue) {
        return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
      };
    }
  };
};
<commit_msg>docs(ngPattern): add option of specifying literal RegExp<commit_after>'use strict';
/**
 * @ngdoc directive
 * @name ngRequired
 * @restrict A
 *
 * @param {expression} ngRequired AngularJS expression. If it evaluates to `true`, it sets the
 *                                `required` attribute to the element and adds the `required`
 *                                {@link ngModel.NgModelController#$validators `validator`}.
 *
 * @description
 *
 * ngRequired adds the required {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
 * It is most often used for {@link input `input`} and {@link select `select`} controls, but can also be
 * applied to custom controls.
 *
 * The directive sets the `required` attribute on the element if the AngularJS expression inside
 * `ngRequired` evaluates to true. A special directive for setting `required` is necessary because we
 * cannot use interpolation inside `required`. See the {@link guide/interpolation interpolation guide}
 * for more info.
 *
 * The validator will set the `required` error key to true if the `required` attribute is set and
 * calling {@link ngModel.NgModelController#$isEmpty `NgModelController.$isEmpty`} with the
 * {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} returns `true`. For example, the
 * `$isEmpty()` implementation for `input[text]` checks the length of the `$viewValue`. When developing
 * custom controls, `$isEmpty()` can be overwritten to account for a $viewValue that is not string-based.
 *
 * @example
 * <example name="ngRequiredDirective" module="ngRequiredExample">
 *   <file name="index.html">
 *
 *

 *       <form name="form">
 *         Toggle required:
 *         <input type="checkbox" ng-model="required" id="required" />
 *

 *         This input must be filled if `required` is true:
 *         <input type="text" ng-model="model" id="input" name="input" ng-required="required" />

 *

 *         required error set? = {{form.input.$error.required}}

 *         model = {{model}}
 *       </form>
 *

 *   </file>
 *   <file name="protractor.js" type="protractor">
       var required = element(by.binding('form.input.$error.required'));
       var model = element(by.binding('model'));
       var input = element(by.id('input'));

       it('should set the required error', function() {
         expect(required.getText()).toContain('true');

         input.sendKeys('123');
         expect(required.getText()).not.toContain('true');
         expect(model.getText()).toContain('123');
       });
 *   </file>
 * </example>
 */
var requiredDirective = function() {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function(scope, elm, attr, ctrl) {
      if (!ctrl) return;
      attr.required = true; // force truthy in case we are on non input element

      ctrl.$validators.required = function(modelValue, viewValue) {
        return !attr.required || !ctrl.$isEmpty(viewValue);
      };

      attr.$observe('required', function() {
        ctrl.$validate();
      });
    }
  };
};

/**
 * @ngdoc directive
 * @name ngPattern
 * @restrict A
 *
 * @param {expression|RegExp} ngPattern AngularJS expression that must evaluate to a `RegExp` or a `String`
 *                                      parsable into a `RegExp`, or a `RegExp` literal. See above for
 *                                      more details.
 *
 * @description
 *
 * ngPattern adds the pattern {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
 *
 * The validator sets the `pattern` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
 * does not match a RegExp which is obtained from the `ngPattern` attribute value:
 * - the value is an AngularJS expression:
 *   - If the expression evaluates to a RegExp object, then this is used directly.
 *   - If the expression evaluates to a string, then it will be converted to a RegExp after wrapping it
 *     in `^` and `$` characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
 * - If the value is a RegExp literal, e.g. `ngPattern="/^\d+$/"`, it is used directly.
 *
 *

 * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
 * start at the index of the last search's match, thus not taking the whole input value into
 * account.
 *

 *
 *

 * **Note:** This directive is also added when the plain `pattern` attribute is used, with two
 * differences:
 *

 *

 *     `ngPattern` does not set the `pattern` attribute and therefore HTML5 constraint validation is
 *     not available.
 *

 *

 *     The `ngPattern` attribute must be an expression, while the `pattern` value must be
 *     interpolated.
 *

 *

 *

 *
 * @example
 * <example name="ngPatternDirective" module="ngPatternExample">
 *   <file name="index.html">
 *
 *

 *       <form name="form">
 *         Set a pattern (regex string):
 *         <input type="text" ng-model="regex" id="regex" />
 *

 *         This input is restricted by the current pattern:
 *         <input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" />

 *

 *         input valid? = {{form.input.$valid}}

 *         model = {{model}}
 *       </form>
 *

 *   </file>
 *   <file name="protractor.js" type="protractor">
       var model = element(by.binding('model'));
       var input = element(by.id('input'));

       it('should validate the input with the default pattern', function() {
         input.sendKeys('aaa');
         expect(model.getText()).not.toContain('aaa');

         input.clear().then(function() {
           input.sendKeys('123');
           expect(model.getText()).toContain('123');
         });
       });
 *   </file>
 * </example>
 */
var patternDirective = function() {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function(scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var regexp, patternExp = attr.ngPattern || attr.pattern;
      attr.$observe('pattern', function(regex) {
        if (isString(regex) && regex.length > 0) {
          regex = new RegExp('^' + regex + '$');
        }

        if (regex && !regex.test) {
          throw minErr('ngPattern')('noregexp',
            'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
            regex, startingTag(elm));
        }

        regexp = regex || undefined;
        ctrl.$validate();
      });

      ctrl.$validators.pattern = function(modelValue, viewValue) {
        // HTML5 pattern constraint validates the input value, so we validate the viewValue
        return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
      };
    }
  };
};

/**
 * @ngdoc directive
 * @name ngMaxlength
 * @restrict A
 *
 * @param {expression} ngMaxlength AngularJS expression that must evaluate to a `Number` or `String`
 *                                 parsable into a `Number`. Used as value for the `maxlength`
 *                                 {@link ngModel.NgModelController#$validators validator}.
 *
 * @description
 *
 * ngMaxlength adds the maxlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
 *
 * The validator sets the `maxlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
 * is longer than the integer obtained by evaluating the AngularJS expression given in the
 * `ngMaxlength` attribute value.
 *
 *

 * **Note:** This directive is also added when the plain `maxlength` attribute is used, with two
 * differences:
 *

 *

 *     `ngMaxlength` does not set the `maxlength` attribute and therefore HTML5 constraint
 *     validation is not available.
 *

 *

 *     The `ngMaxlength` attribute must be an expression, while the `maxlength` value must be
 *     interpolated.
 *

 *

 *

 *
 * @example
 * <example name="ngMaxlengthDirective" module="ngMaxlengthExample">
 *   <file name="index.html">
 *
 *

 *       <form name="form">
 *         Set a maxlength:
 *         <input type="number" ng-model="maxlength" id="maxlength" />
 *

 *         This input is restricted by the current maxlength:
 *         <input type="text" ng-model="model" id="input" name="input" ng-maxlength="maxlength" />

 *

 *         input valid? = {{form.input.$valid}}

 *         model = {{model}}
 *       </form>
 *

 *   </file>
 *   <file name="protractor.js" type="protractor">
       var model = element(by.binding('model'));
       var input = element(by.id('input'));

       it('should validate the input with the default maxlength', function() {
         input.sendKeys('abcdef');
         expect(model.getText()).not.toContain('abcdef');

         input.clear().then(function() {
           input.sendKeys('abcde');
           expect(model.getText()).toContain('abcde');
         });
       });
 *   </file>
 * </example>
 */
var maxlengthDirective = function() {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function(scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var maxlength = -1;
      attr.$observe('maxlength', function(value) {
        var intVal = toInt(value);
        maxlength = isNumberNaN(intVal) ? -1 : intVal;
        ctrl.$validate();
      });
      ctrl.$validators.maxlength = function(modelValue, viewValue) {
        return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
      };
    }
  };
};

/**
 * @ngdoc directive
 * @name ngMinlength
 * @restrict A
 *
 * @param {expression} ngMinlength AngularJS expression that must evaluate to a `Number` or `String`
 *                                 parsable into a `Number`. Used as value for the `minlength`
 *                                 {@link ngModel.NgModelController#$validators validator}.
 *
 * @description
 *
 * ngMinlength adds the minlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
 *
 * The validator sets the `minlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
 * is shorter than the integer obtained by evaluating the AngularJS expression given in the
 * `ngMinlength` attribute value.
 *
 *

 * **Note:** This directive is also added when the plain `minlength` attribute is used, with two
 * differences:
 *

 *

 *     `ngMinlength` does not set the `minlength` attribute and therefore HTML5 constraint
 *     validation is not available.
 *

 *

 *     The `ngMinlength` value must be an expression, while the `minlength` value must be
 *     interpolated.
 *

 *

 *

 *
 * @example
 * <example name="ngMinlengthDirective" module="ngMinlengthExample">
 *   <file name="index.html">
 *
 *

 *       <form name="form">
 *         Set a minlength:
 *         <input type="number" ng-model="minlength" id="minlength" />
 *

 *         This input is restricted by the current minlength:
 *         <input type="text" ng-model="model" id="input" name="input" ng-minlength="minlength" />

 *

 *         input valid? = {{form.input.$valid}}

 *         model = {{model}}
 *       </form>
 *

 *   </file>
 *   <file name="protractor.js" type="protractor">
       var model = element(by.binding('model'));
       var input = element(by.id('input'));

       it('should validate the input with the default minlength', function() {
         input.sendKeys('ab');
         expect(model.getText()).not.toContain('ab');

         input.sendKeys('abc');
         expect(model.getText()).toContain('abc');
       });
 *   </file>
 * </example>
 */
var minlengthDirective = function() {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function(scope, elm, attr, ctrl) {
      if (!ctrl) return;

      var minlength = 0;
      attr.$observe('minlength', function(value) {
        minlength = toInt(value) || 0;
        ctrl.$validate();
      });
      ctrl.$validators.minlength = function(modelValue, viewValue) {
        return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
      };
    }
  };
};
<|endoftext|>


<commit_before>/**
 * Helpers for export requests
 */

/*
 * 2011 Peter 'Pita' Martischka (Primary Technology Ltd)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var Changeset = require("ep_etherpad-lite/static/js/Changeset");

exports.getPadPlainText = function(pad, revNum){
  var _analyzeLine = exports._analyzeLine;
  var atext = ((revNum !== undefined) ? pad.getInternalRevisionAText(revNum) : pad.atext);
  var textLines = atext.text.slice(0, -1).split('\n');
  var attribLines = Changeset.splitAttributionLines(atext.attribs, atext.text);
  var apool = pad.pool;

  var pieces = [];
  for (var i = 0; i < textLines.length; i++){
    var line = _analyzeLine(textLines[i], attribLines[i], apool);
    if (line.listLevel){
      var numSpaces = line.listLevel * 2 - 1;
      var bullet = '*';
      pieces.push(new Array(numSpaces + 1).join(' '), bullet, ' ', line.text, '\n');
    }
    else{
      pieces.push(line.text, '\n');
    }
  }

  return pieces.join('');
};

exports._analyzeLine = function(text, aline, apool){
  var line = {};

  // identify list
  var lineMarker = 0;
  line.listLevel = 0;
  if (aline){
    var opIter = Changeset.opIterator(aline);
    if (opIter.hasNext()){
      var listType = Changeset.opAttributeValue(opIter.next(), 'list', apool);
      if (listType){
        lineMarker = 1;
        listType = /([a-z]+)([0-9]+)/.exec(listType);
        if (listType){
          line.listTypeName = listType[1];
          line.listLevel = Number(listType[2]);
        }
      }
    }
  }
  if (lineMarker){
    line.text = text.substring(1);
    line.aline = Changeset.subattribution(aline, 1);
  }
  else{
    line.text = text;
    line.aline = aline;
  }
  return line;
};

exports._encodeWhitespace = function(s){
  return s.replace(/[^\x21-\x7E\s\t\n\r]/g, function(c){
    return "&#" +c.charCodeAt(0) + ";";
  });
};
<commit_msg>Fix Unicode bug in HTML export<commit_after>/**
 * Helpers for export requests
 */

/*
 * 2011 Peter 'Pita' Martischka (Primary Technology Ltd)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var Changeset = require("ep_etherpad-lite/static/js/Changeset");

exports.getPadPlainText = function(pad, revNum){
  var _analyzeLine = exports._analyzeLine;
  var atext = ((revNum !== undefined) ? pad.getInternalRevisionAText(revNum) : pad.atext);
  var textLines = atext.text.slice(0, -1).split('\n');
  var attribLines = Changeset.splitAttributionLines(atext.attribs, atext.text);
  var apool = pad.pool;

  var pieces = [];
  for (var i = 0; i < textLines.length; i++){
    var line = _analyzeLine(textLines[i], attribLines[i], apool);
    if (line.listLevel){
      var numSpaces = line.listLevel * 2 - 1;
      var bullet = '*';
      pieces.push(new Array(numSpaces + 1).join(' '), bullet, ' ', line.text, '\n');
    }
    else{
      pieces.push(line.text, '\n');
    }
  }

  return pieces.join('');
};

exports._analyzeLine = function(text, aline, apool){
  var line = {};

  // identify list
  var lineMarker = 0;
  line.listLevel = 0;
  if (aline){
    var opIter = Changeset.opIterator(aline);
    if (opIter.hasNext()){
      var listType = Changeset.opAttributeValue(opIter.next(), 'list', apool);
      if (listType){
        lineMarker = 1;
        listType = /([a-z]+)([0-9]+)/.exec(listType);
        if (listType){
          line.listTypeName = listType[1];
          line.listLevel = Number(listType[2]);
        }
      }
    }
  }
  if (lineMarker){
    line.text = text.substring(1);
    line.aline = Changeset.subattribution(aline, 1);
  }
  else{
    line.text = text;
    line.aline = aline;
  }
  return line;
};

exports._encodeWhitespace = function(s){
  return s.replace(/[^\x21-\x7E\s\t\n\r]/gu, function(c){
    return "&#" +c.codePointAt(0) + ";";
  });
};
<|endoftext|>


<commit_before>define(["dojo/_base/declare", "dijit/_WidgetBase", "dojo/dom-style", "dojo/fx/Toggler", "dojo/fx"],
  function(declare, _WidgetBase, domStyle, FxToggler, fx) {

    return declare([_WidgetBase], {
      // summary:
      //   Widgetizes any domNode, to make it optional.
      //   If `displayed` is set to true, the widget appears. If `displayed` is set
      //   to false, it disappears. The default is not-displayed.
      // description:
      //   Changing the state is done with an animation. Although `set("displayed", value)`
      //   returns immediately, the operation takes a while.
      //   For now, there is no option to get a Promise on the animation.

      // displayed: boolean
      displayed: false,

      // reversed: boolean
      //   With a binding on `displayed`, certainly if it is several levels deep, the first
      //   actual `set("displayed")` happens quite late. `displayed` is initially false,
      //   so nothing is shown until the first `set("displayed")` happens in that case.
      //   With `reverse` true, we reverse the behavior: we show if `displayed` is false, and
      //   and hide if `displayed` is true. This also often makes the binding easier
      //   (no need for a format function).
      reversed: false,

      postCreate: function() {
        this.inherited(arguments);
        if (!this.shown()) {
          domStyle.set(this.domNode, "display", "none");
        }
      },

      shown: function() {
        return this.reversed ? !this.displayed : this.displayed;
      },

      _setDisplayedAttr: function(displayed) {
        // summary:
        //   Executes the change of being displayed. Since the visual
        //   effect takes time, this returns a Promise. Use it or not, as you like.
        //   Returns null if the value is not changed.

        var booleanDisplayed = !!displayed; // turn truthy or falsy into true or false
        if (booleanDisplayed !== this.displayed) {
          this._set("displayed", booleanDisplayed);
          if (this.shown()) {
            this._animation().show()
          }
          else {
            this._animation().hide();
          }
        }
      },

      _animation: function() {
        //noinspection JSUnresolvedFunction
        return new FxToggler({
          node: this.domNode,
          showDuration: 500,
          hideDuration: 500,
          showFunc: fx.wipeIn,
          hideFunc: fx.wipeOut
        });
      }

    });
  }
);
<commit_msg>this small change is absolutely necessary false IS NOT EQUAL TO null both are falsy, but that is not the same!!!!!<commit_after>define(["dojo/_base/declare", "dijit/_WidgetBase", "dojo/dom-style", "dojo/fx/Toggler", "dojo/fx"],
  function(declare, _WidgetBase, domStyle, FxToggler, fx) {

    return declare([_WidgetBase], {
      // summary:
      //   Widgetizes any domNode, to make it optional.
      //   If `displayed` is set to true, the widget appears. If `displayed` is set
      //   to false, it disappears. The default is not-displayed.
      // description:
      //   Changing the state is done with an animation. Although `set("displayed", value)`
      //   returns immediately, the operation takes a while.
      //   For now, there is no option to get a Promise on the animation.

      // displayed: boolean
      displayed: false,

      // reversed: boolean
      //   With a binding on `displayed`, certainly if it is several levels deep, the first
      //   actual `set("displayed")` happens quite late. `displayed` is initially false,
      //   so nothing is shown until the first `set("displayed")` happens in that case.
      //   With `reverse` true, we reverse the behavior: we show if `displayed` is false, and
      //   and hide if `displayed` is true. This also often makes the binding easier
      //   (no need for a format function).
      reversed: false,

      postCreate: function() {
        this.inherited(arguments);
        if (!this.shown()) {
          domStyle.set(this.domNode, "display", "none");
        }
      },

      shown: function() {
        return this.reversed ? !this.displayed : this.displayed;
      },

      _setDisplayedAttr: function(displayed) {
        // summary:
        //   Executes the change of being displayed. Since the visual
        //   effect takes time, this returns a Promise. Use it or not, as you like.
        //   Returns null if the value is not changed.

        var booleanDisplayed = !!displayed; // turn truthy or falsy into true or false
        if (booleanDisplayed != !!this.displayed) { // NOT !=== ; somebody DOES insert null into this.displayed directly;
          this._set("displayed", booleanDisplayed);
          if (this.shown()) {
            this._animation().show()
          }
          else {
            this._animation().hide();
          }
        }
      },

      _animation: function() {
        //noinspection JSUnresolvedFunction
        return new FxToggler({
          node: this.domNode,
          showDuration: 500,
          hideDuration: 500,
          showFunc: fx.wipeIn,
          hideFunc: fx.wipeOut
        });
      }

    });
  }
);
<|endoftext|>


<commit_before>import resync from '../resync'
import { setElevation } from '../actions/point'
import { urlEncode } from '../io'
import { pointSelect } from '../utils'

export default store => {
    resync(store, pointSelect, ({ point }, io, dispatch) => {
        let pointIsValid = point !== null && point.x && point.y
        let { validRegions } = store.getState().runConfiguration
        let region = validRegions[0]
        dispatch(setElevation(null))

        if (pointIsValid && region !== null) {

            let url = '/arcgis/rest/services/' + region + '_dem/MapServer/identify/?' + urlEncode({
                f: 'json',
                tolerance: '2',
                imageDisplay: '1600,1031,96',
                geometryType: 'esriGeometryPoint',
                mapExtent: '0,0,0,0',
                geometry: JSON.stringify({x: point.x, y: point.y})
            })

            io.get(url).then(response => response.json()).then(json => {
                let results = json.results
                let value = null

                if (results.length) {
                    value = results[0].attributes['Pixel value']
                }

                if (isNaN(value)) {
                    value = null
                }

                dispatch(setElevation(value))
            })
        }
    })
}
<commit_msg>Fixed bug that sent malformed request url when no valid regions are available at selected point.<commit_after>import resync from '../resync'
import { setElevation } from '../actions/point'
import { urlEncode } from '../io'
import { pointSelect } from '../utils'

export default store => {
    resync(store, pointSelect, ({ point }, io, dispatch) => {
        let pointIsValid = point !== null && point.x && point.y
        let { validRegions } = store.getState().runConfiguration
        if (!validRegions.length) {
            return
        }
        let region = validRegions[0]
        dispatch(setElevation(null))

        if (pointIsValid) {

            let url = '/arcgis/rest/services/' + region + '_dem/MapServer/identify/?' + urlEncode({
                f: 'json',
                tolerance: '2',
                imageDisplay: '1600,1031,96',
                geometryType: 'esriGeometryPoint',
                mapExtent: '0,0,0,0',
                geometry: JSON.stringify({x: point.x, y: point.y})
            })

            io.get(url).then(response => response.json()).then(json => {
                let results = json.results
                let value = null

                if (results.length) {
                    value = results[0].attributes['Pixel value']
                }

                if (isNaN(value)) {
                    value = null
                }

                dispatch(setElevation(value))
            })
        }
    })
}
<|endoftext|>


<commit_before>

exports.path = function( key, sep ){
	separator = separator || ':';
	return key == null ? [] : key.split(separator);
};

exports.key = function(){
	return Array.prototype.slice.call(arguments).join(':');
};

exports.keyed = function () {
  return Array.prototype.slice.call(arguments, 1).join(arguments[0]);
};
<commit_msg>make the separator a constant value<commit_after>
const SEPARATOR = ':'
exports.path = function( key, separator ){
	separator = separator || SEPARATOR ;
	return key == null ? [] : key.split(separator);
};

exports.key = function(){
	return Array.prototype.slice.call(arguments).join(SEPARATOR);
};

exports.keyed = function () {
  return Array.prototype.slice.call(arguments, 1).join(arguments[0]);
};
<|endoftext|>