<commit_before>/**
 * ------------------------------------------
 * 桌面接口实现文件
 * @version  1.0
 * @author   yuqijun(yuqijun@corp.netease.com)
 * ------------------------------------------
 */
var f = function() {
    // variable declaration
    var _   = NEJ.P,
        _o  = NEJ.O,
        _e  = _('nej.e'),
        _u  = _('nej.u'),
        _v  = _('nej.v'),
        _n  = _('nej.n'),
        _t  = _('nej.ut'),
        _p  = _('nej.cef'),
        _nt = _('nej.cef.ut'),
        _mcache = {};
    /**
     * 配置窗体信息
     * @see    {nej.cef._$configWindowPosition}
     * @see    {nej.cef._$configWindowSizeLimit}
     * @param  {Object} 配置信息，其他参数详情见@see指定接口配置信息
     * @return {Void}
     */
    _p._$configWindow = function(_options){
        _p._$configWindowSizeLimit(_options);
        _p._$configWindowPosition(_options);
    };
    /**
     * 配置窗体位置，对齐方式定义如下

     * 水平对齐方式：
     * [ntb]
     *   名称            |  描述
     *   ----------------------
     *   left   |  左侧对齐
     *   center |  中间对齐
     *   right  |  右侧对齐
     * [/ntb]
     *
     * 垂直对齐方式：
     * [ntb]
     *   名称              |  描述
     *   ---------------------
     *   top     |  顶部对齐
     *   center  |  中间对齐
     *   bottom  |  底部对齐
     * [/ntb]
     * @api    {nej.cef._$configWindowPosition}
     * @param  {Object} 配置信息
     * @config {String}  name     窗体名称
     * @config {Number}  width    窗体宽度
     * @config {Number}  height   窗体高度
     * @config {Boolean} topmost  窗体是否置顶
     * @config {String}  align    对齐方式，格式定义：水平对齐方式+空格+垂直对齐方式，如 left top
     * @return {Void}
     */
    _p._$configWindowPosition = (function(){
        var _reg0 = /\s+/,
            _fmap = {
                left:function(_mbox,_total){
                    return 0;
                },
                center:function(_mbox,_total){
                    return Math.floor((_total-_mbox)/2);
                },
                right:function(_mbox,_total){
                    return _total;
                }
            };
        _fmap.top = _fmap.left;
        _fmap.bottom = _fmap.right;
        return function(_options){
            _options = _options||_o;
            // set window position
            var _aligns = (_options.align||'').trim().split(_reg0),
                _position = NEJ.EX({width:0,height:0,topmost:!1},_options),
                _wkarea = (_n._$exec('os.getSystemInfo','desktop')||_o).workArea||_o;
            _position.x = (_fmap[_aligns[0]]||_fmap.center)(_position.width,_wkarea.width);
            _position.y = (_fmap[_aligns[1]]||_fmap.center)(_position.height,_wkarea.height);
            if (!_options.name){
                _n._$exec('winhelper.setWindowPosition',_position);
            }else{
                _position.name = _options.name;
                _n._$exec('winhelper.setNativeWindowRect',_position);
            }
        };
    })();
    /**
     * 配置窗体大小限制
     * @api    {nej.cef._$configWindowSizeLimit}
     * @param  {Object} 配置信息
     * @config {Number}  minWidth  窗体最小宽度
     * @config {Number}  maxWidth  窗体最大宽度
     * @config {Number}  minHeight 窗体最小高度
     * @config {Number}  maxHeight 窗体最大高度
     */
    _p._$configWindowSizeLimit = (function(){
        // parse min/max - width/height
        var _doParseBox = function(_width,_height){
            _width = parseInt(_width);
            _height = parseInt(_height);
            var _result;
            if (!isNaN(_width)){
                _result = _result||{};
                _result.x = _width;
            }
            if (!isNaN(_height)){
                _result = _result||{};
                _result.y = _height;
            }
            return _result;
        };
        return function(_options){
            _options = _options||_o;
            _n._$exec(
                'winhelper.setWindowSizeLimit',
                _doParseBox(_options.minWidth,_options.minHeight),
                _doParseBox(_options.maxWidth,_options.maxHeight)
            );
        };
    })();
    /**
     * 显示窗体,但窗体不会放在最上层
     * @api    {nej.cef._$showWindow}
     * @return {Void}
     */
    _p._$showWindow = function(_name){
        if (!_name){
            _n._$exec('winhelper.showWindow','show');
        }else{
            _n._$exec('winhelper.setNativeWindowShow',_name,!0);
        }
    };
    /**
     * 隐藏窗体
     * @api    {nej.cef._$hideWindow}
     * @return {Void}
     */
    _p._$hideWindow = function(_name){
        if (!_name){
            _n._$exec('winhelper.showWindow','hide');
        }else{
            _n._$exec('winhelper.setNativeWindowShow',_name,!1);
        }
    };
    /**
     * 窗口前置
     * @return {Void}
     */
    _p._$topWindow = function(_name){
        if (!_name){
            _n._$exec('winhelper.bringWindowToTop');
        }
    };
    /**
     * 打开新窗体
     * @param  {String} 新窗口地址，参数通过查询形式输入，如?width=1000&height=200
     * @return {Void}
     */
    _p._$open = (function(){
        var _doParseInt = function(_value,_key,_map){
            var _int = parseInt(_value);
            if (!isNaN(_int)){
                _map[_key] = _int;
            }else if(_value=='true'||_value=='false'){
                _map[_key] = _value=='true';
            }
        };
        return function(_url){
            // TODO parse param
            var _param = _u._$query2object(_url.split('?')[1]||'');
            _u._$forIn(_param,_doParseInt);
            _n._$exec('winhelper.launchWindow',_url,_param,_param);
        };
    })();
    /**
     * 退出应用
     * @return {Void}
     */
    _p._$exit = function(){
        _nt._$$Tray._$getInstance()._$hide();
        _n._$exec('app.exit');
    };
    /**
     * 打开外部链接
     * @param  {String} 链接地址
     * @return {Void}
     */
    _p._$external = function(_url){
        _n._$exec('os.navigateExternal',_url);
    };
    /**
     * 取菜单项
     * @param  {Object} 菜单配置
     * @return {Object} 菜单项信息
     */
    _p._$getMenuItem = function(_options){
        var _item = NEJ.X({
            text:'菜单项',menu:!0,
            menu_id:0,enable:!0,
            separator:!1,children:null
        },_options);
        _mcache[_item.menu_id] = _item;
        return _item;
    };
    /**
     * 根据ID取菜单项
     * @return {Void}
     */
    _p._$getMenuItemById = function(_id){
        return _mcache[_id];
    };
    /**
     * 弹出菜单
     * @param  {Array} 菜单项列表
     * @return {Void}
     */
    _p._$popMenu = (function(){
        var _reg0 = /\)$/,
            _xmap = {
                exit:_p._$getMenuItem({text:'退出',menu_id:1005}),
                setting:_p._$getMenuItem({text:'设置',menu_id:1006})
            };
        var _doCheckMenu = function(_item,_index,_list){
            var _xitm = _xmap[_item];
            if (!!_xitm){
                _item = _xitm;
                _list[_index] = _item;
            }
            if (!!_item.children){
                _doCompleteMenu(_item.children);
            }
        };
        var _doCompleteMenu = function(_list){
            _u._$forEach(_list,_doCheckMenu);
        };
        var _doCheckHotKey = function(_value,_id){
            var _item = _p._$getMenuItemById(_id);
            if (!!_item&&!_reg0.test(_item.text)){
                _item.text += '('+_value+')';
            }
        };
        var _doCompleteHotKey = function(_hotkey){
            _u._$forIn(_hotkey,_doCheckHotKey);
        };
        return function(_conf){
            _doCompleteMenu(_conf.content);
            _doCompleteHotKey(_conf.hotkey);
            _conf = NEJ.EX({
                menu_type:'',
                content:null,
                hotkey:null
            },_conf);
            if (!_conf.menu_type) _conf.menu_type = 'normal';
            _conf.hotkey = JSON.stringify(_conf.hotkey||null);
            _conf.content = JSON.stringify(_conf.content||[]);
            _n._$exec('winhelper.popupMenu',_conf);
        };
    })();
    // init document.onmenuacton
    _('window.winhelper').onmenuclick = function(_id){
        _v._$dispatchEvent(
            document,'menuaction',{
                id:_id
            }
        );
    };
    _t._$$CustomEvent._$allocate({
        element:document,
        event:'menuaction'
    });
};
NEJ.define('{lib}native/cef/api.js',
          ['{lib}base/util.js'
          ,'{lib}base/element.js'
          ,'{lib}native/command.js'
          ,'{lib}util/event/event.js'
          ,'{lib}native/cef/util/tray.js'],f);<commit_msg>cef menu<commit_after>/**
 * ------------------------------------------
 * 桌面接口实现文件
 * @version  1.0
 * @author   yuqijun(yuqijun@corp.netease.com)
 * ------------------------------------------
 */
var f = function() {
    // variable declaration
    var _   = NEJ.P,
        _o  = NEJ.O,
        _e  = _('nej.e'),
        _u  = _('nej.u'),
        _v  = _('nej.v'),
        _n  = _('nej.n'),
        _t  = _('nej.ut'),
        _p  = _('nej.cef'),
        _nt = _('nej.cef.ut'),
        _mcache = {};
    /**
     * 配置窗体信息
     * @see    {nej.cef._$configWindowPosition}
     * @see    {nej.cef._$configWindowSizeLimit}
     * @param  {Object} 配置信息，其他参数详情见@see指定接口配置信息
     * @return {Void}
     */
    _p._$configWindow = function(_options){
        _p._$configWindowSizeLimit(_options);
        _p._$configWindowPosition(_options);
    };
    /**
     * 配置窗体位置，对齐方式定义如下

     * 水平对齐方式：
     * [ntb]
     *   名称            |  描述
     *   ----------------------
     *   left   |  左侧对齐
     *   center |  中间对齐
     *   right  |  右侧对齐
     * [/ntb]
     *
     * 垂直对齐方式：
     * [ntb]
     *   名称              |  描述
     *   ---------------------
     *   top     |  顶部对齐
     *   center  |  中间对齐
     *   bottom  |  底部对齐
     * [/ntb]
     * @api    {nej.cef._$configWindowPosition}
     * @param  {Object} 配置信息
     * @config {String}  name     窗体名称
     * @config {Number}  width    窗体宽度
     * @config {Number}  height   窗体高度
     * @config {Boolean} topmost  窗体是否置顶
     * @config {String}  align    对齐方式，格式定义：水平对齐方式+空格+垂直对齐方式，如 left top
     * @return {Void}
     */
    _p._$configWindowPosition = (function(){
        var _reg0 = /\s+/,
            _fmap = {
                left:function(_mbox,_total){
                    return 0;
                },
                center:function(_mbox,_total){
                    return Math.floor((_total-_mbox)/2);
                },
                right:function(_mbox,_total){
                    return _total;
                }
            };
        _fmap.top = _fmap.left;
        _fmap.bottom = _fmap.right;
        return function(_options){
            _options = _options||_o;
            // set window position
            var _aligns = (_options.align||'').trim().split(_reg0),
                _position = NEJ.EX({width:0,height:0,topmost:!1},_options),
                _wkarea = (_n._$exec('os.getSystemInfo','desktop')||_o).workArea||_o;
            _position.x = (_fmap[_aligns[0]]||_fmap.center)(_position.width,_wkarea.width);
            _position.y = (_fmap[_aligns[1]]||_fmap.center)(_position.height,_wkarea.height);
            if (!_options.name){
                _n._$exec('winhelper.setWindowPosition',_position);
            }else{
                _position.name = _options.name;
                _n._$exec('winhelper.setNativeWindowRect',_position);
            }
        };
    })();
    /**
     * 配置窗体大小限制
     * @api    {nej.cef._$configWindowSizeLimit}
     * @param  {Object} 配置信息
     * @config {Number}  minWidth  窗体最小宽度
     * @config {Number}  maxWidth  窗体最大宽度
     * @config {Number}  minHeight 窗体最小高度
     * @config {Number}  maxHeight 窗体最大高度
     */
    _p._$configWindowSizeLimit = (function(){
        // parse min/max - width/height
        var _doParseBox = function(_width,_height){
            _width = parseInt(_width);
            _height = parseInt(_height);
            var _result;
            if (!isNaN(_width)){
                _result = _result||{};
                _result.x = _width;
            }
            if (!isNaN(_height)){
                _result = _result||{};
                _result.y = _height;
            }
            return _result;
        };
        return function(_options){
            _options = _options||_o;
            _n._$exec(
                'winhelper.setWindowSizeLimit',
                _doParseBox(_options.minWidth,_options.minHeight),
                _doParseBox(_options.maxWidth,_options.maxHeight)
            );
        };
    })();
    /**
     * 显示窗体,但窗体不会放在最上层
     * @api    {nej.cef._$showWindow}
     * @return {Void}
     */
    _p._$showWindow = function(_name){
        if (!_name){
            _n._$exec('winhelper.showWindow','show');
        }else{
            _n._$exec('winhelper.setNativeWindowShow',_name,!0);
        }
    };
    /**
     * 隐藏窗体
     * @api    {nej.cef._$hideWindow}
     * @return {Void}
     */
    _p._$hideWindow = function(_name){
        if (!_name){
            _n._$exec('winhelper.showWindow','hide');
        }else{
            _n._$exec('winhelper.setNativeWindowShow',_name,!1);
        }
    };
    /**
     * 窗口前置
     * @return {Void}
     */
    _p._$topWindow = function(_name){
        if (!_name){
            _n._$exec('winhelper.bringWindowToTop');
        }
    };
    /**
     * 打开新窗体
     * @param  {String} 新窗口地址，参数通过查询形式输入，如?width=1000&height=200
     * @return {Void}
     */
    _p._$open = (function(){
        var _doParseInt = function(_value,_key,_map){
            var _int = parseInt(_value);
            if (!isNaN(_int)){
                _map[_key] = _int;
            }else if(_value=='true'||_value=='false'){
                _map[_key] = _value=='true';
            }
        };
        return function(_url){
            // TODO parse param
            var _param = _u._$query2object(_url.split('?')[1]||'');
            _u._$forIn(_param,_doParseInt);
            _n._$exec('winhelper.launchWindow',_url,_param,_param);
        };
    })();
    /**
     * 退出应用
     * @return {Void}
     */
    _p._$exit = function(){
        _nt._$$Tray._$getInstance()._$hide();
        _n._$exec('app.exit');
    };
    /**
     * 打开外部链接
     * @param  {String} 链接地址
     * @return {Void}
     */
    _p._$external = function(_url){
        _n._$exec('os.navigateExternal',_url);
    };
    /**
     * 取菜单项
     * @param  {Object} 菜单配置
     * @return {Object} 菜单项信息
     */
    _p._$getMenuItem = function(_options){
        var _item = NEJ.X({
            text:'菜单项',menu:!0,
            menu_id:0,enable:!0,
            separator:!1,children:null
        },_options);
        _mcache[_item.menu_id] = _item;
        return _item;
    };
    /**
     * 根据ID取菜单项
     * @return {Void}
     */
    _p._$getMenuItemById = function(_id){
        return _mcache[_id];
    };
    /**
     * 弹出菜单
     * @param  {Array} 菜单项列表
     * @return {Void}
     */
    _p._$popMenu = (function(){
        var _reg0 = /\)$/,
            _xmap = {
                exit:_p._$getMenuItem({text:'退出',menu_id:1005}),
                setting:_p._$getMenuItem({text:'设置',menu_id:1006})
            };
        var _doCheckMenu = function(_item,_index,_list){
            var _xitm = _xmap[_item];
            if (!!_xitm){
                _item = _xitm;
                _list[_index] = _item;
            }
            if (!!_item.children){
                _doCompleteMenu(_item.children);
            }
        };
        var _doCompleteMenu = function(_list){
            _u._$forEach(_list,_doCheckMenu);
        };
        var _doCheckHotKey = function(_value,_id){
            var _item = _p._$getMenuItemById(_id);
            if (!!_item&&!_reg0.test(_item.text)){
                _item.text += '('+_value+')';
            }
        };
        var _doCompleteHotKey = function(_hotkey){
            _u._$forIn(_hotkey,_doCheckHotKey);
        };
        return function(_conf){
            _doCompleteMenu(_conf.content);
            _doCompleteHotKey(_conf.hotkey);
            _conf = NEJ.EX({
                content:null,
                hotkey:null
            },_conf);
            if (!_conf.menu_type) _conf.menu_type = 'normal';
            _conf.hotkey = JSON.stringify(_conf.hotkey||null);
            _conf.content = JSON.stringify(_conf.content||[]);
            _n._$exec('winhelper.popupMenu',_conf);
        };
    })();
    // init document.onmenuacton
    _('window.winhelper').onmenuclick = function(_id){
        _v._$dispatchEvent(
            document,'menuaction',{
                id:_id
            }
        );
    };
    _t._$$CustomEvent._$allocate({
        element:document,
        event:'menuaction'
    });
};
NEJ.define('{lib}native/cef/api.js',
          ['{lib}base/util.js'
          ,'{lib}base/element.js'
          ,'{lib}native/command.js'
          ,'{lib}util/event/event.js'
          ,'{lib}native/cef/util/tray.js'],f);<|endoftext|>


<commit_before>'use strict';

// Inspects filter expression AST and throws an error if it contains values of
// invalid types.
//
// For normal expressions, these checks are done in runtime, but for filter
// expressions at least some basic checks need to be done sooner so that the ES
// and JS compilers can assume some level of sanity. Note we already have all
// the values computed when the checker is invoked in the graph compilation
// stage because we don't allow straming expressions inside filter expressions.
//
// Some structural checks on filter expressions are done in the semantic pass
// already (the idea is to do them as soon as possible in the compiler
// pipeline).

var _ = require('underscore');
var ASTVisitor = require('../ast-visitor');
var errors = require('../../errors');
var values = require('../../runtime/values');

// For ExpressionFilterTerms, we use a table of allowed forms for each operator.
// Descriptions of these forms use the following checks to test their operands.

var checks = {
    isSimpleFieldReference: {
        displayName: 'field',

        test: function(node) {
            return node.type === 'UnaryExpression'
                && node.operator === '*'
                && node.expression.type === 'StringLiteral';
        }
    },

    isStringLiteral: {
        displayName: 'string',

        test: function(node) {
            return node.type === 'StringLiteral';
        }
    },

    isRegularExpressionLiteral: {
        displayName: 'regexp',

        test: function(node) {
            return node.type === 'RegularExpressionLiteral';
        }
    },

    isSimpleLiteral: {
        displayName: 'value',

        test: function(node) {
            return node.type === 'NullLiteral'
                || node.type === 'BooleanLiteral'
                || node.type === 'NumericLiteral'
                || node.type === 'InfinityLiteral'
                || node.type === 'NaNLiteral'
                || node.type === 'StringLiteral'
                || node.type === 'MomentLiteral'
                || node.type === 'DurationLiteral';
        }
    },

    isSimpleArrayLiteral: {
        displayName: 'array',

        test: function(node) {
            return node.type === 'ArrayLiteral'
                && _.every(node.elements, checks.isSimpleLiteral.test);
        }
    }
};

// And here comes the description of allowed operator forms.

var ALLOWED_OP_FORMS = {
    '==': [
        { left: checks.isSimpleFieldReference, right: checks.isSimpleLiteral },
        { left: checks.isSimpleLiteral, right: checks.isSimpleFieldReference }
    ],

    '!=': [
        { left: checks.isSimpleFieldReference, right: checks.isSimpleLiteral },
        { left: checks.isSimpleLiteral, right: checks.isSimpleFieldReference }
    ],

    '=~': [
        { left: checks.isSimpleFieldReference, right: checks.isStringLiteral },
        { left: checks.isSimpleFieldReference, right: checks.isRegularExpressionLiteral },
    ],

    '!~': [
        { left: checks.isSimpleFieldReference, right: checks.isStringLiteral },
        { left: checks.isSimpleFieldReference, right: checks.isRegularExpressionLiteral },
    ],

    '<': [
        { left: checks.isSimpleFieldReference, right: checks.isSimpleLiteral },
        { left: checks.isSimpleLiteral, right: checks.isSimpleFieldReference }
    ],

    '>': [
        { left: checks.isSimpleFieldReference, right: checks.isSimpleLiteral },
        { left: checks.isSimpleLiteral, right: checks.isSimpleFieldReference }
    ],

    '<=': [
        { left: checks.isSimpleFieldReference, right: checks.isSimpleLiteral },
        { left: checks.isSimpleLiteral, right: checks.isSimpleFieldReference }
    ],

    '>=': [
        { left: checks.isSimpleFieldReference, right: checks.isSimpleLiteral },
        { left: checks.isSimpleLiteral, right: checks.isSimpleFieldReference }
    ],

    'in': [
        { left: checks.isSimpleFieldReference, right: checks.isSimpleArrayLiteral },
    ]
};

var ALLOWED_OP_FORMS_FIELD_COMPARISON = _(ALLOWED_OP_FORMS).mapObject(function(forms, operator) {
    return _.clone(forms).concat(
        { left: checks.isSimpleFieldReference, right: checks.isSimpleFieldReference }
    );
});

var FilterChecker = ASTVisitor.extend({
    check: function(node, options) {
        this.options = options;

        this.visit(node);
    },

    visitExpressionFilterTerm: function(node) {
        var forms = this.options.allowFieldComparisons
            ? ALLOWED_OP_FORMS_FIELD_COMPARISON[node.expression.operator]
            : ALLOWED_OP_FORMS[node.expression.operator];

        var valid = _.any(forms, function(form) {
            return form.left.test(node.expression.left)
                && form.right.test(node.expression.right);
        });

        if (!valid) {
            var formsDescription = _.map(forms, function(form) {
                return JSON.stringify(form.left.displayName
                    + ' '
                    + node.expression.operator
                    + ' '
                    + form.right.displayName);
            }).join(', ');

            throw errors.compileError('RT-INVALID-EXPRESSION-FILTER-TERM', {
                forms: formsDescription,
                location: node.location
            });
        }
    },

    visitSimpleFilterTerm: function(node) {
        switch (node.expression.type) {
            case 'StringLiteral':
                break;

            case 'FilterLiteral':
                this.visit(node.expression);
                break;

            default:
                throw errors.compileError('RT-INVALID-TERM-TYPE', {
                    type: values.typeDisplayName(values.typeOf(values.fromAST(node.expression))),
                    location: node.location
                });
        }
    }
});

module.exports = FilterChecker;
<commit_msg>FilterChecker: Update obsolete comment<commit_after>'use strict';

// Inspects filter expression AST and throws an error if it is invalid.
//
// For normal expressions, these checks are done in runtime, but for filter
// expressions at least some basic checks need to be done sooner so that the
// various compilers (mostly in adapters) can assume some level of sanity.

var _ = require('underscore');
var ASTVisitor = require('../ast-visitor');
var errors = require('../../errors');
var values = require('../../runtime/values');

// For ExpressionFilterTerms, we use a table of allowed forms for each operator.
// Descriptions of these forms use the following checks to test their operands.

var checks = {
    isSimpleFieldReference: {
        displayName: 'field',

        test: function(node) {
            return node.type === 'UnaryExpression'
                && node.operator === '*'
                && node.expression.type === 'StringLiteral';
        }
    },

    isStringLiteral: {
        displayName: 'string',

        test: function(node) {
            return node.type === 'StringLiteral';
        }
    },

    isRegularExpressionLiteral: {
        displayName: 'regexp',

        test: function(node) {
            return node.type === 'RegularExpressionLiteral';
        }
    },

    isSimpleLiteral: {
        displayName: 'value',

        test: function(node) {
            return node.type === 'NullLiteral'
                || node.type === 'BooleanLiteral'
                || node.type === 'NumericLiteral'
                || node.type === 'InfinityLiteral'
                || node.type === 'NaNLiteral'
                || node.type === 'StringLiteral'
                || node.type === 'MomentLiteral'
                || node.type === 'DurationLiteral';
        }
    },

    isSimpleArrayLiteral: {
        displayName: 'array',

        test: function(node) {
            return node.type === 'ArrayLiteral'
                && _.every(node.elements, checks.isSimpleLiteral.test);
        }
    }
};

// And here comes the description of allowed operator forms.

var ALLOWED_OP_FORMS = {
    '==': [
        { left: checks.isSimpleFieldReference, right: checks.isSimpleLiteral },
        { left: checks.isSimpleLiteral, right: checks.isSimpleFieldReference }
    ],

    '!=': [
        { left: checks.isSimpleFieldReference, right: checks.isSimpleLiteral },
        { left: checks.isSimpleLiteral, right: checks.isSimpleFieldReference }
    ],

    '=~': [
        { left: checks.isSimpleFieldReference, right: checks.isStringLiteral },
        { left: checks.isSimpleFieldReference, right: checks.isRegularExpressionLiteral },
    ],

    '!~': [
        { left: checks.isSimpleFieldReference, right: checks.isStringLiteral },
        { left: checks.isSimpleFieldReference, right: checks.isRegularExpressionLiteral },
    ],

    '<': [
        { left: checks.isSimpleFieldReference, right: checks.isSimpleLiteral },
        { left: checks.isSimpleLiteral, right: checks.isSimpleFieldReference }
    ],

    '>': [
        { left: checks.isSimpleFieldReference, right: checks.isSimpleLiteral },
        { left: checks.isSimpleLiteral, right: checks.isSimpleFieldReference }
    ],

    '<=': [
        { left: checks.isSimpleFieldReference, right: checks.isSimpleLiteral },
        { left: checks.isSimpleLiteral, right: checks.isSimpleFieldReference }
    ],

    '>=': [
        { left: checks.isSimpleFieldReference, right: checks.isSimpleLiteral },
        { left: checks.isSimpleLiteral, right: checks.isSimpleFieldReference }
    ],

    'in': [
        { left: checks.isSimpleFieldReference, right: checks.isSimpleArrayLiteral },
    ]
};

var ALLOWED_OP_FORMS_FIELD_COMPARISON = _(ALLOWED_OP_FORMS).mapObject(function(forms, operator) {
    return _.clone(forms).concat(
        { left: checks.isSimpleFieldReference, right: checks.isSimpleFieldReference }
    );
});

var FilterChecker = ASTVisitor.extend({
    check: function(node, options) {
        this.options = options;

        this.visit(node);
    },

    visitExpressionFilterTerm: function(node) {
        var forms = this.options.allowFieldComparisons
            ? ALLOWED_OP_FORMS_FIELD_COMPARISON[node.expression.operator]
            : ALLOWED_OP_FORMS[node.expression.operator];

        var valid = _.any(forms, function(form) {
            return form.left.test(node.expression.left)
                && form.right.test(node.expression.right);
        });

        if (!valid) {
            var formsDescription = _.map(forms, function(form) {
                return JSON.stringify(form.left.displayName
                    + ' '
                    + node.expression.operator
                    + ' '
                    + form.right.displayName);
            }).join(', ');

            throw errors.compileError('RT-INVALID-EXPRESSION-FILTER-TERM', {
                forms: formsDescription,
                location: node.location
            });
        }
    },

    visitSimpleFilterTerm: function(node) {
        switch (node.expression.type) {
            case 'StringLiteral':
                break;

            case 'FilterLiteral':
                this.visit(node.expression);
                break;

            default:
                throw errors.compileError('RT-INVALID-TERM-TYPE', {
                    type: values.typeDisplayName(values.typeOf(values.fromAST(node.expression))),
                    location: node.location
                });
        }
    }
});

module.exports = FilterChecker;
<|endoftext|>


<commit_before>function createProgress(id) {
    return $('<div />', {
        'id': id,
        'class': 'progress'
    });
}

function createBar(type, percent, label) {
    var cls = (type === 'remaining') ? 'remaining' : 'bar bar-' + type;
    return $('<div />', {
        'class': cls,
        'style': 'width: ' + Math.floor(percent * 100) + '%;',
        'text': label
    });
}

function createLabel(name, assigned) {
    return $('<div />', {
        'text': name + ' - ' + humanizeTime(assigned) + ' assigned'
    });
}

// Creates all bar elements for the given progress div.
function createBars(progress, worked, assigned) {
    // Worked bar.
    if (worked > 0 && assigned > 0) {
        var worked_percent, worked_text;
        if (worked <= assigned) {
            worked_percent = Math.min(1, worked / assigned);
            worked_text = humanizeTime(worked);
        } else {
            worked_percent = Math.min(1, assigned / worked);
            worked_text = humanizeTime(assigned);
        }
        progress.append(createBar('success', worked_percent, worked_text));
    }

    // Overtime bar.
    if (worked > assigned) {
        var overtime_percent = Math.min(1, 1 - assigned / worked),
            overtime_text = humanizeTime(worked - assigned) + ' over';
        progress.append(createBar('warning', overtime_percent, overtime_text));
    }

    // Remaining bar.
    if (worked < assigned) {
        var remaining_percent = Math.min(1, 1 - worked / assigned),
            remaining_text = humanizeTime(assigned - worked) + ' remaining';
        progress.append(createBar('remaining', remaining_percent, remaining_text));
    }
}

function getHours(time) {
    return Math.floor(time);
}

function getMinutes(time) {
    return Math.floor((time - getHours(time)) * 60);
}

function humanizeTime(time) {
    var hours = getHours(time),
        minutes = getMinutes(time),
        humanized_time = hours + 'h';

    if (minutes > 0) {
        humanized_time += ' ' + minutes + 'm';
    }
    return humanized_time;
}

var container = $('#week-hours'),
    data = JSON.parse(container.attr('data'));

// Create overall progress bar.
var progress_all = createProgress('progress-all');
createBars(progress_all, data.worked, data.assigned);
container.append(progress_all);

// Create individual project progress bars.
var max = Math.max(data.projects[0].worked, data.projects[0].assigned);
for (var i = 0; i < data.projects.length; i++) {
    var project = data.projects[i],
        progress = createProgress('progress-' + project.pk),
        percent = Math.min(1, Math.max(project.worked, project.assigned) / max);

    var thing = $('<div />', {
        'style': 'width: ' + Math.floor(percent * 100) + '%;'
    })
    createBars(progress, project.worked, project.assigned);
    thing.append(createLabel(project.name, project.assigned));
    thing.append(progress);
    container.append(thing);
}
<commit_msg>refs #495 - Fixed bar positioning to always take up total of 100%<commit_after>function createProgress(id) {
    return $('<div />', {
        'id': id,
        'class': 'progress'
    });
}

function createBar(type, percent, label) {
    var cls = (type === 'remaining') ? 'remaining' : 'bar bar-' + type;
    return $('<div />', {
        'class': cls,
        'style': 'width: ' + percent + '%;',
        'text': label
    });
}

function createLabel(name, assigned) {
    return $('<div />', {
        'text': name + ' - ' + humanizeTime(assigned) + ' assigned'
    });
}

// Creates all bar elements for the given progress div.
function createBars(progress, worked, assigned) {
    // Worked bar.
    if (worked > 0 && assigned > 0) {
        var worked_percent, worked_text;
        if (worked <= assigned) {
            worked_percent = Math.min(1, worked / assigned);
            worked_text = humanizeTime(worked);
        } else {
            worked_percent = Math.min(1, assigned / worked);
            worked_text = humanizeTime(assigned);
        }
        worked_percent = Math.floor(worked_percent * 100);
        progress.append(createBar('success', worked_percent, worked_text));
    }

    // Overtime bar.
    if (worked > assigned) {
        var overtime_percent = Math.min(1, 1 - assigned / worked),
            overtime_text = humanizeTime(worked - assigned) + ' over';
        overtime_percent = Math.ceil(overtime_percent * 100);
        progress.append(createBar('warning', overtime_percent, overtime_text));
    }

    // Remaining bar.
    if (worked < assigned) {
        var remaining_percent = Math.min(1, 1 - worked / assigned),
            remaining_text = humanizeTime(assigned - worked) + ' remaining';
        remaining_percent = Math.ceil(remaining_percent * 100);
        progress.append(createBar('remaining', remaining_percent, remaining_text));
    }
}

function getHours(time) {
    return Math.floor(time);
}

function getMinutes(time) {
    return Math.floor((time - getHours(time)) * 60);
}

function humanizeTime(time) {
    var hours = getHours(time),
        minutes = getMinutes(time),
        humanized_time = hours + 'h';

    if (minutes > 0) {
        humanized_time += ' ' + minutes + 'm';
    }
    return humanized_time;
}

var container = $('#week-hours'),
    data = JSON.parse(container.attr('data'));

// Create overall progress bar.
var progress_all = createProgress('progress-all');
createBars(progress_all, data.worked, data.assigned);
container.append(progress_all);

// Create individual project progress bars.
var max = Math.max(data.projects[0].worked, data.projects[0].assigned);
for (var i = 0; i < data.projects.length; i++) {
    var project = data.projects[i],
        progress = createProgress('progress-' + project.pk),
        percent = Math.min(1, Math.max(project.worked, project.assigned) / max);

    var thing = $('<div />', {
        'style': 'width: ' + Math.floor(percent * 100) + '%;'
    })
    createBars(progress, project.worked, project.assigned);
    thing.append(createLabel(project.name, project.assigned));
    thing.append(progress);
    container.append(thing);
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name         autoscroll
// @namespace    autoscroll
// @version      1.11
// @description  autoscroller to be used with https://facebook.tracking.exposed, This userscript works with TamperMoneky extension.
// @author       Claudio Agosti @_vecna
// @match        https://www.facebook.com/*
// @connect      autoscroll
// @grant        GM_setValue
// @grant        GM_getValue
// @require      https://cdnjs.cloudflare.com/ajax/libs/lodash-compat/3.10.2/lodash.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js
// ==/UserScript==

var times = 30;
var delay = 5;
var fixedH = 800;
var plan = [
    "09:01",
    "11:01",
    "13:01",
    "15:01",
    "17:01",
    "19:01",
    "21:01"
];

function timeline(reference) {

    if(!reference) {
        var s = GM_getValue("scrolling");

        if(s && moment(s).add(50, 's').isBefore(moment())) {
            console.log("a previous scroll interrupted?");
        }

        if(s && moment(s).add(50, 's').isAfter(moment())) {
            return;
        }

        console.log("setting GM_setValue 'scrolling'", moment().format() );
        GM_setValue("scrolling", moment().format());

        reference = {
            counter: 0,
            y: 0,
        };
    }

    if(reference.counter === times) {
        var s = GM_getValue("scrolling");
        console.log("Timeline counter reach", times);
        if(s) {
            console.log(s, "'scrolling': is present, -> doTheNext, removing GM_[scrolling]", s);
            GM_setValue("scrolling", null);
            return _.delay(doTheNext, 1);
        } else {
            console.log("GM_[scrolling] is null", s, "killed ramification");
        }
    } else {
        reference.counter += 1;
        reference.y = reference.counter * fixedH;
        GM_setValue("scrolling", moment().format());

        console.log("scrolling", reference.counter, "at",
                  moment().format("HH:mm:ss"), "a the Y", reference.y);

        scrollTo(0, reference.y);

        return _.delay(timeline, delay * 1000, reference);
    }
}

function doTheNext() {

    var isNight = moment().hour();
    var subdays = 0;
    if(isNight < 4) {
        console.log("It is night -- (FIXME: this check is not timezone safe)");
        subdays = 1;
    }
    /*
     * This function has to compute the seconds of distance between
     * now and the next TESING-HOUR. the hours are 9:00,11:00 etc,
     * and they happen in GMT-3, (180 minutes, below in the variables)
     */

	var tinfo = _.map(plan, function(t) {

        var GMT3 = 180;
		var hour = _.parseInt(t.split(':')[0]);
		var minute = _.parseInt(t.split(':')[1]);
		var personalO = moment().utcOffset() + GMT3;
		var target = moment().set({
            hour: hour,
            minute: minute,
            second: 0
        }).utcOffset(GMT3);
        target.subtract(subdays, 'd');
        var secsdiff = moment.duration(target - moment()).asSeconds();
		var secto =  secsdiff + (personalO * 60);

		return {
            secsdiff: secsdiff,
			hto: _.round(secto / 3600, 1),
			secto: secto,
			target: t,
			x: target.format()
		};
	});

	console.log(tinfo);
	var next = _.first(_.filter(tinfo, function(t) {
		return t.secto > 0;
	}));

    console.log("Schedule computed, next on", next);
    if(!next) {
        console.log("Night problem, check back in 1 hour");
        GM_setValue("refresh", true);
        return _.delay(doTheNext, 3600 * 1000);
    } else {
        console.log("Setting the next timeline to", next.secto);
        GM_setValue("refresh", true);
        return _.delay(cleanAndReload, next.secto * 1000);
    }
};

function cleanAndReload() {
    GM_setValue("scrolling", null);
    // this value 'refresh' is not used because remain dirty in case a browser restart
    GM_setValue("refresh", null);
    location.reload();
};

(function() {

    var s = GM_getValue("scrolling");

    if( s && moment(s).add(50, 's').isBefore(moment())) {
        console.log("Considering the diff of",
                moment.duration(moment() - moment(s)).humanize(), "...");
        timeline();
    }
    else if(!s) {
        var r = GM_getValue("refresh");
        console.log("beginning tampermonkey, scrolling", s, "refresh", r);
        timeline();
    } else
        console.log("Nope, recorded is", moment(s).format("HH:mm:ss"), "now", moment().format("HH:mm:ss"));

})();

<commit_msg>the more, the better<commit_after>// ==UserScript==
// @name         autoscroll
// @namespace    autoscroll
// @version      1.13
// @description  autoscroller to be used with https://facebook.tracking.exposed, This userscript works with TamperMoneky extension.
// @author       Claudio Agosti @_vecna
// @match        https://www.facebook.com/*
// @connect      autoscroll
// @grant        GM_setValue
// @grant        GM_getValue
// @require      https://cdnjs.cloudflare.com/ajax/libs/lodash-compat/3.10.2/lodash.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js
// ==/UserScript==

var times = 30;
var delay = 5;
var fixedH = 800;
var plan = [
    "08:01",
    "09:01",
    "10:01",
    "11:01",
    "12:01",
    "13:01",
    "14:01",
    "15:01",
    "16:01",
    "17:01",
    "18:01",
    "19:01",
    "20:01",
    "21:01",
];

function timeline(reference) {

    if(!reference) {
        var s = GM_getValue("scrolling");

        if(s && moment(s).add(50, 's').isBefore(moment())) {
            console.log("a previous scroll interrupted?");
        }

        if(s && moment(s).add(50, 's').isAfter(moment())) {
            return;
        }

        console.log("setting GM_setValue 'scrolling'", moment().format() );
        GM_setValue("scrolling", moment().format());

        reference = {
            counter: 0,
            y: 0,
        };
    }

    if(reference.counter === times) {
        var s = GM_getValue("scrolling");
        console.log("Timeline counter reach", times);
        if(s) {
            console.log(s, "'scrolling': is present, -> doTheNext, removing GM_[scrolling]", s);
            GM_setValue("scrolling", null);
            return _.delay(doTheNext, 1);
        } else {
            console.log("GM_[scrolling] is null", s, "killed ramification");
        }
    } else {
        reference.counter += 1;
        reference.y = reference.counter * fixedH;
        GM_setValue("scrolling", moment().format());

        console.log("scrolling", reference.counter, "at",
                  moment().format("HH:mm:ss"), "a the Y", reference.y);

        scrollTo(0, reference.y);

        return _.delay(timeline, delay * 1000, reference);
    }
}

function doTheNext() {

    var isNight = moment().hour();
    var subdays = 0;
    if(isNight < 4) {
        console.log("It is night -- (FIXME: this check is not timezone safe)");
        subdays = 1;
    }
    /*
     * This function has to compute the seconds of distance between
     * now and the next TESING-HOUR. the hours are 9:00,11:00 etc,
     * and they happen in GMT-3, (180 minutes, below in the variables)
     */

	var tinfo = _.map(plan, function(t) {

        var GMTARG = 180;
		var hour = _.parseInt(t.split(':')[0]);
		var minute = _.parseInt(t.split(':')[1]);
		var personalO = moment().utcOffset() + GMTARG;
		var target = moment().set({
            hour: hour,
            minute: minute,
            second: 0
        }).utcOffset(GMTARG);
        target.subtract(subdays, 'd');
        var secsdiff = moment.duration(target - moment()).asSeconds();
		var secto =  secsdiff + (personalO * 60);

		return {
            secsdiff: secsdiff,
			hto: _.round(secto / 3600, 1),
			secto: secto,
			target: t,
			x: target.format()
		};
	});

	console.log(tinfo);
	var next = _.first(_.filter(tinfo, function(t) {
		return t.secto > 0;
	}));

    console.log("Schedule computed, next on", next);
    if(!next) {
        console.log("Night problem, check back in 1 hour");
        GM_setValue("refresh", true);
        return _.delay(doTheNext, 3600 * 1000);
    } else {
        console.log("Setting the next timeline to", next.secto);
        GM_setValue("refresh", true);
        return _.delay(cleanAndReload, next.secto * 1000);
    }
};

function cleanAndReload() {
    GM_setValue("scrolling", null);
    // this value 'refresh' is not used because remain dirty in case a browser restart
    GM_setValue("refresh", null);
    location.reload();
};

(function() {

    var s = GM_getValue("scrolling");

    if( s && moment(s).add(50, 's').isBefore(moment())) {
        console.log("Considering the diff of",
                moment.duration(moment() - moment(s)).humanize(), "...");
        timeline();
    }
    else if(!s) {
        var r = GM_getValue("refresh");
        console.log("beginning tampermonkey, scrolling", s, "refresh", r);
        timeline();
    } else
        console.log("Nope, recorded is", moment(s).format("HH:mm:ss"), "now", moment().format("HH:mm:ss"));

})();

<|endoftext|>


<commit_before>import { getTimeFormat } from '@opentripplanner/core-utils/lib/time'
import { storeItem } from '@opentripplanner/core-utils/lib/storage'
import React, { Component } from 'react'
import { Button } from 'react-bootstrap'
import { connect } from 'react-redux'

import * as apiActions from '../../actions/api'
import * as callTakerActions from '../../actions/call-taker'
import * as fieldTripActions from '../../actions/field-trip'
import * as formActions from '../../actions/form'
import AddPlaceButton from '../form/add-place-button'
import AdvancedOptions from '../form/call-taker/advanced-options'
import DateTimeOptions from '../form/call-taker/date-time-options'
import ModeDropdown from '../form/call-taker/mode-dropdown'
import IntermediatePlace from '../form/intermediate-place-field'
import LocationField from '../form/connected-location-field'
import SwitchButton from '../form/switch-button'
import UserSettings from '../form/user-settings'
import NarrativeItineraries from '../narrative/narrative-itineraries'
import { getGroupSize } from '../../util/call-taker'
import { hasValidLocation, getActiveSearch, getShowUserSettings } from '../../util/state'
import ViewerContainer from '../viewers/viewer-container'

/**
 * This is the main panel/sidebar for the Call Taker/Field Trip module. It
 * currently also serves as the main panel for the FDOT RMCE trip comparison view
 * which depends on the BATCH trip planning mode.
 */
class CallTakerPanel extends Component {
  constructor (props) {
    super(props)
    this.state = {
      expandAdvanced: props.expandAdvanced,
      transitModes: props.modes.transitModes.map(m => m.mode)
    }
  }

  _planTrip = () => {
    const {beginCallIfNeeded, currentQuery, routingQuery} = this.props
    const issues = []
    if (!hasValidLocation(currentQuery, 'from')) issues.push('from')
    if (!hasValidLocation(currentQuery, 'to')) issues.push('to')
    if (issues.length > 0) {
      // TODO: replace with less obtrusive validation.
      window.alert(`Please define the following fields to plan a trip: ${issues.join(', ')}`)
      return
    }
    if (this.state.expandAdvanced) this.setState({expandAdvanced: false})
    // Ensure call is started, or start a new one.
    beginCallIfNeeded()
    routingQuery()
  }

  _addPlace = (result, index) => {
    const intermediatePlaces = [...this.props.currentQuery.intermediatePlaces] || []
    if (result && index !== undefined) {
      // If adding an actual intermediate place with location. Overwrite the
      // placeholder with the new value.
      intermediatePlaces.splice(index, 1, result.location)
    } else {
      // Otherwise, we're just adding a dummy place.
      intermediatePlaces.push({})
    }
    this.props.setQueryParam({intermediatePlaces})
  }

  _removePlace = ({index}) => {
    const intermediatePlaces = [...this.props.currentQuery.intermediatePlaces] || []
    intermediatePlaces.splice(index, 1)
    this.props.setQueryParam({intermediatePlaces})
  }

  _onHideAdvancedClick = () => {
    const expandAdvanced = !this.state.expandAdvanced
    // FIXME move logic to action
    storeItem('expandAdvanced', expandAdvanced)
    this.setState({expandAdvanced})
  }

  /**
   * Key down listener that will submit a plan trip query when Enter is pressed.
   * This listener can be passed to constituent form elements for easy
   * keyboard-only operation of the trip planning form. Note: it generally should
   * not be passed to buttons or other elements that natively rely on the Enter
   * key.
   */
  _handleFormKeyDown = (evt) => {
    switch (evt.keyCode) {
      case 13: // Enter
        evt.preventDefault()
        // Submit routing query.
        this._planTrip()
        break
      default:
        // Do nothing.
        break
    }
  }

  _updateGroupSize = (evt) => this.props.setGroupSize(+evt.target.value)

  render () {
    const {
      activeSearch,
      currentQuery,
      groupSize,
      mainPanelContent,
      maxGroupSize,
      mobile,
      modes,
      routes,
      setQueryParam,
      showUserSettings,
      timeFormat
    } = this.props
    // FIXME: Remove showPlanTripButton
    const showPlanTripButton = mainPanelContent === 'EDIT_DATETIME' ||
      mainPanelContent === 'EDIT_SETTINGS'
    const {
      date,
      departArrive,
      from,
      intermediatePlaces,
      mode,
      time,
      to
    } = currentQuery
    const actionText = mobile ? 'tap' : 'click'
    const {expandAdvanced} = this.state
    const advancedSearchStyle = {
      background: 'white',
      display: expandAdvanced ? undefined : 'none',
      left: '0px',
      padding: '0px 8px 5px',
      position: 'absolute',
      right: '0px',
      zIndex: 99999
    }
    return (
      <ViewerContainer>
        {/* FIXME: should this be a styled component */}

            <LocationField
              inputPlaceholder={`Enter start location or ${actionText} on map...`}
              locationType='from'
              showClearButton
            />
            {Array.isArray(intermediatePlaces) && intermediatePlaces.map((place, i) => {
              return (
                <IntermediatePlace
                  index={i}
                  inputPlaceholder={`Enter intermediate destination`}
                  key={i}
                  location={place}
                  // FIXME: allow intermediate location type.
                  locationType='to'
                  onLocationCleared={this._removePlace}
                  // FIXME: function def
                  onLocationSelected={result => this._addPlace(result, i)}
                  showClearButton={!mobile}
                />
              )
            })}
            <LocationField
              inputPlaceholder={`Enter destination or ${actionText} on map...`}
              locationType='to'
              showClearButton={!mobile}
            />

              <SwitchButton content={} />

            <AddPlaceButton
              from={from}
              intermediatePlaces={intermediatePlaces}
              onClick={this._addPlace}
              to={to}
            />

              <DateTimeOptions
                date={date}
                departArrive={departArrive}
                onKeyDown={this._handleFormKeyDown}
                setQueryParam={setQueryParam}
                time={time}
                timeFormat={timeFormat} />
              <ModeDropdown
                mode={mode}
                modes={modes}
                onChange={setQueryParam}
                onKeyDown={this._handleFormKeyDown}
                selectedTransitModes={this.state.transitModes}
                updateTransitModes={transitModes => this.setState({transitModes})} />
              <Button
                bsSize='small'
                bsStyle='default'
                onClick={this._planTrip}
                style={{
                  fontSize: '13px',
                  padding: '1px 10px'
                }} >
                Plan
              </Button>

              {groupSize !== null && maxGroupSize &&

                  Group size:{' '}
                  <input
                    max={maxGroupSize}
                    min={0}
                    onChange={this._updateGroupSize}
                    onKeyDown={this._handleFormKeyDown}
                    step={1}
                    style={{lineHeight: '0.8em'}}
                    type='number'
                    value={groupSize}
                  />

              }
              <Button
                className='hide-button clear-button-formatting'
                onClick={this._onHideAdvancedClick}>
                <i className={`fa fa-caret-${expandAdvanced ? 'up' : 'down'}`} /> Advanced options
              </Button>

                <AdvancedOptions
                  currentQuery={currentQuery}
                  findRoutes={this.props.findRoutes}
                  modes={modes}
                  onKeyDown={this._handleFormKeyDown}
                  routes={routes}
                  setQueryParam={setQueryParam} />

          {!activeSearch && !showPlanTripButton && showUserSettings &&
            <UserSettings />
          }

            <NarrativeItineraries
              containerStyle={{
                display: 'flex',
                flexDirection: 'column'
                // FIXME: This top pixel value can be variable dependent on
                // height of the form above. It may need to be specified differently
              }}
            />

      </ViewerContainer>
    )
  }
}

// connect to the redux store
const mapStateToProps = (state, ownProps) => {
  const {activeId, requests} = state.callTaker.fieldTrip
  const request = requests.data.find(req => req.id === activeId)
  const showUserSettings = getShowUserSettings(state)
  return {
    activeSearch: getActiveSearch(state),
    currentQuery: state.otp.currentQuery,
    expandAdvanced: state.otp.user.expandAdvanced,
    groupSize: state.callTaker.fieldTrip.groupSize,
    mainPanelContent: state.otp.ui.mainPanelContent,
    maxGroupSize: getGroupSize(request),
    modes: state.otp.config.modes,
    routes: state.otp.transitIndex.routes,
    showUserSettings,
    timeFormat: getTimeFormat(state.otp.config)
  }
}

const mapDispatchToProps = {
  beginCallIfNeeded: callTakerActions.beginCallIfNeeded,
  findRoutes: apiActions.findRoutes,
  routingQuery: apiActions.routingQuery,
  setGroupSize: fieldTripActions.setGroupSize,
  setQueryParam: formActions.setQueryParam
}

export default connect(mapStateToProps, mapDispatchToProps)(CallTakerPanel)
<commit_msg>refactor(call-taker): remove unneeded comment<commit_after>import { getTimeFormat } from '@opentripplanner/core-utils/lib/time'
import { storeItem } from '@opentripplanner/core-utils/lib/storage'
import React, { Component } from 'react'
import { Button } from 'react-bootstrap'
import { connect } from 'react-redux'

import * as apiActions from '../../actions/api'
import * as callTakerActions from '../../actions/call-taker'
import * as fieldTripActions from '../../actions/field-trip'
import * as formActions from '../../actions/form'
import AddPlaceButton from '../form/add-place-button'
import AdvancedOptions from '../form/call-taker/advanced-options'
import DateTimeOptions from '../form/call-taker/date-time-options'
import ModeDropdown from '../form/call-taker/mode-dropdown'
import IntermediatePlace from '../form/intermediate-place-field'
import LocationField from '../form/connected-location-field'
import SwitchButton from '../form/switch-button'
import UserSettings from '../form/user-settings'
import NarrativeItineraries from '../narrative/narrative-itineraries'
import { getGroupSize } from '../../util/call-taker'
import { hasValidLocation, getActiveSearch, getShowUserSettings } from '../../util/state'
import ViewerContainer from '../viewers/viewer-container'

/**
 * This is the main panel/sidebar for the Call Taker/Field Trip module. It
 * currently also serves as the main panel for the FDOT RMCE trip comparison view
 * which depends on the BATCH trip planning mode.
 */
class CallTakerPanel extends Component {
  constructor (props) {
    super(props)
    this.state = {
      expandAdvanced: props.expandAdvanced,
      transitModes: props.modes.transitModes.map(m => m.mode)
    }
  }

  _planTrip = () => {
    const {beginCallIfNeeded, currentQuery, routingQuery} = this.props
    const issues = []
    if (!hasValidLocation(currentQuery, 'from')) issues.push('from')
    if (!hasValidLocation(currentQuery, 'to')) issues.push('to')
    if (issues.length > 0) {
      // TODO: replace with less obtrusive validation.
      window.alert(`Please define the following fields to plan a trip: ${issues.join(', ')}`)
      return
    }
    if (this.state.expandAdvanced) this.setState({expandAdvanced: false})
    // Ensure call is started, or start a new one.
    beginCallIfNeeded()
    routingQuery()
  }

  _addPlace = (result, index) => {
    const intermediatePlaces = [...this.props.currentQuery.intermediatePlaces] || []
    if (result && index !== undefined) {
      // If adding an actual intermediate place with location. Overwrite the
      // placeholder with the new value.
      intermediatePlaces.splice(index, 1, result.location)
    } else {
      // Otherwise, we're just adding a dummy place.
      intermediatePlaces.push({})
    }
    this.props.setQueryParam({intermediatePlaces})
  }

  _removePlace = ({index}) => {
    const intermediatePlaces = [...this.props.currentQuery.intermediatePlaces] || []
    intermediatePlaces.splice(index, 1)
    this.props.setQueryParam({intermediatePlaces})
  }

  _onHideAdvancedClick = () => {
    const expandAdvanced = !this.state.expandAdvanced
    // FIXME move logic to action
    storeItem('expandAdvanced', expandAdvanced)
    this.setState({expandAdvanced})
  }

  /**
   * Key down listener that will submit a plan trip query when Enter is pressed.
   * This listener can be passed to constituent form elements for easy
   * keyboard-only operation of the trip planning form. Note: it generally should
   * not be passed to buttons or other elements that natively rely on the Enter
   * key.
   */
  _handleFormKeyDown = (evt) => {
    switch (evt.keyCode) {
      case 13: // Enter
        evt.preventDefault()
        // Submit routing query.
        this._planTrip()
        break
      default:
        // Do nothing.
        break
    }
  }

  _updateGroupSize = (evt) => this.props.setGroupSize(+evt.target.value)

  render () {
    const {
      activeSearch,
      currentQuery,
      groupSize,
      mainPanelContent,
      maxGroupSize,
      mobile,
      modes,
      routes,
      setQueryParam,
      showUserSettings,
      timeFormat
    } = this.props
    // FIXME: Remove showPlanTripButton
    const showPlanTripButton = mainPanelContent === 'EDIT_DATETIME' ||
      mainPanelContent === 'EDIT_SETTINGS'
    const {
      date,
      departArrive,
      from,
      intermediatePlaces,
      mode,
      time,
      to
    } = currentQuery
    const actionText = mobile ? 'tap' : 'click'
    const {expandAdvanced} = this.state
    const advancedSearchStyle = {
      background: 'white',
      display: expandAdvanced ? undefined : 'none',
      left: '0px',
      padding: '0px 8px 5px',
      position: 'absolute',
      right: '0px',
      zIndex: 99999
    }
    return (
      <ViewerContainer>
        {/* FIXME: should this be a styled component */}

            <LocationField
              inputPlaceholder={`Enter start location or ${actionText} on map...`}
              locationType='from'
              showClearButton
            />
            {Array.isArray(intermediatePlaces) && intermediatePlaces.map((place, i) => {
              return (
                <IntermediatePlace
                  index={i}
                  inputPlaceholder={`Enter intermediate destination`}
                  key={i}
                  location={place}
                  // FIXME: allow intermediate location type.
                  locationType='to'
                  onLocationCleared={this._removePlace}
                  // FIXME: function def
                  onLocationSelected={result => this._addPlace(result, i)}
                  showClearButton={!mobile}
                />
              )
            })}
            <LocationField
              inputPlaceholder={`Enter destination or ${actionText} on map...`}
              locationType='to'
              showClearButton={!mobile}
            />

              <SwitchButton content={} />

            <AddPlaceButton
              from={from}
              intermediatePlaces={intermediatePlaces}
              onClick={this._addPlace}
              to={to}
            />

              <DateTimeOptions
                date={date}
                departArrive={departArrive}
                onKeyDown={this._handleFormKeyDown}
                setQueryParam={setQueryParam}
                time={time}
                timeFormat={timeFormat} />
              <ModeDropdown
                mode={mode}
                modes={modes}
                onChange={setQueryParam}
                onKeyDown={this._handleFormKeyDown}
                selectedTransitModes={this.state.transitModes}
                updateTransitModes={transitModes => this.setState({transitModes})} />
              <Button
                bsSize='small'
                bsStyle='default'
                onClick={this._planTrip}
                style={{
                  fontSize: '13px',
                  padding: '1px 10px'
                }} >
                Plan
              </Button>

              {groupSize !== null && maxGroupSize &&

                  Group size:{' '}
                  <input
                    max={maxGroupSize}
                    min={0}
                    onChange={this._updateGroupSize}
                    onKeyDown={this._handleFormKeyDown}
                    step={1}
                    style={{lineHeight: '0.8em'}}
                    type='number'
                    value={groupSize}
                  />

              }
              <Button
                className='hide-button clear-button-formatting'
                onClick={this._onHideAdvancedClick}>
                <i className={`fa fa-caret-${expandAdvanced ? 'up' : 'down'}`} /> Advanced options
              </Button>

                <AdvancedOptions
                  currentQuery={currentQuery}
                  findRoutes={this.props.findRoutes}
                  modes={modes}
                  onKeyDown={this._handleFormKeyDown}
                  routes={routes}
                  setQueryParam={setQueryParam} />

          {!activeSearch && !showPlanTripButton && showUserSettings &&
            <UserSettings />
          }

            <NarrativeItineraries
              containerStyle={{
                display: 'flex',
                flexDirection: 'column'
              }}
            />

      </ViewerContainer>
    )
  }
}

// connect to the redux store
const mapStateToProps = (state, ownProps) => {
  const {activeId, requests} = state.callTaker.fieldTrip
  const request = requests.data.find(req => req.id === activeId)
  const showUserSettings = getShowUserSettings(state)
  return {
    activeSearch: getActiveSearch(state),
    currentQuery: state.otp.currentQuery,
    expandAdvanced: state.otp.user.expandAdvanced,
    groupSize: state.callTaker.fieldTrip.groupSize,
    mainPanelContent: state.otp.ui.mainPanelContent,
    maxGroupSize: getGroupSize(request),
    modes: state.otp.config.modes,
    routes: state.otp.transitIndex.routes,
    showUserSettings,
    timeFormat: getTimeFormat(state.otp.config)
  }
}

const mapDispatchToProps = {
  beginCallIfNeeded: callTakerActions.beginCallIfNeeded,
  findRoutes: apiActions.findRoutes,
  routingQuery: apiActions.routingQuery,
  setGroupSize: fieldTripActions.setGroupSize,
  setQueryParam: formActions.setQueryParam
}

export default connect(mapStateToProps, mapDispatchToProps)(CallTakerPanel)
<|endoftext|>


<commit_before>
function getHours(time) {
    return Math.floor(time);
}

function getMinutes(time) {
    var minutes = Math.floor((time - getHours(time)) * 60);
    if (minutes < 10) {
        minutes = '0' + minutes;
    }
    return minutes
}

function humanizeTime(time) {
    var hours = getHours(time),
        minutes = getMinutes(time);

    return hours + ':' + minutes;
}

// Label for project charts.
function createProjectLabel(project_name, assigned) {
    return $('<div />', {
        'class': 'progress-label',
        'text': project_name + ' - ' + humanizeTime(assigned) + ' Assigned'
    });
}

// Worked, remaining, or overtime hours on a project.
function createBar(type, percent, label) {
    var cls = (type === 'remaining') ? type : 'bar bar-' + type;
    return $('<div />', {
        'class': cls,
        'style': 'width: ' + percent + '%;',
        'text': label
    });
}

// Container for all bars (worked, overtime, remaining) on a project.
function createChart(worked, assigned) {
    var chart = $('<div />', {
        'class': 'progress'
    });

    // Worked bar.
    if (worked > 0 && assigned > 0) {  // Skip if only remaining or overtime bar is needed.
        var worked_percent, worked_text;
        if (worked <= assigned) {
            worked_percent = Math.min(1, worked / assigned);
            worked_text = humanizeTime(worked) + ' Worked';
        } else {
            worked_percent = Math.min(1, assigned / worked);
            worked_text = humanizeTime(assigned) + ' Worked';
        }
        worked_percent = Math.floor(worked_percent * 100);
        chart.append(createBar('success', worked_percent, worked_text));  // Green
    }

    // Overtime bar.
    if (worked > assigned) {
        var overtime_percent = Math.min(1, 1 - assigned / worked),
            overtime_text = humanizeTime(worked - assigned) + ' Overtime';
        overtime_percent = Math.ceil(overtime_percent * 100);
        chart.append(createBar('danger', overtime_percent, overtime_text));  // Red
    }

    // Remaining bar.
    if (worked < assigned) {
        var remaining_percent = Math.min(1, 1 - worked / assigned),
            remaining_text = humanizeTime(assigned - worked) + ' Remaining';
        remaining_percent = Math.ceil(remaining_percent * 100);
        chart.append(createBar('remaining', remaining_percent, remaining_text));  // Blue
    }

    return chart;
}

var build_project_bar = function($bar_cell, percentage) {
    var $bar = $('<div />');
    /*
    Find sprite_num, which is 0 to 5 (inclusive) and determines what sprite
    class to use
    */
    var sprite_divisor = 4, // number of ways to divide progress by 100
        sprite_quotient = (100 / sprite_divisor),
        sprite_num = Math.round(percentage / sprite_quotient);
    if (percentage > 100) {
        sprite_num = sprite_divisor + 1; // assign to the overworked sprite
    }
    // Use sprite_num to assign a class with the appropriate sprite
    var sprite_class_suffix = (sprite_num <= sprite_divisor) ?
        (sprite_num * sprite_quotient) : 'over';
    $bar.addClass('sprite-' + sprite_class_suffix);
    // Append the new bar div to the container
    $bar_cell.append($bar);
};

// Entry point to create overall progress chart and per project progress bars
(function() {
    var container = $('#progress-all'),
        worked = parseFloat(container.attr('data-worked')),
        assigned = parseFloat(container.attr('data-assigned'));

    var overall_chart = createChart(worked, assigned);
    container.append(overall_chart);

    // Create progress bars for each project
    $.each($('.project_progress_bar'), function() {
        var self = $(this);
        var worked = self.data('worked'),
            assigned = self.data('assigned');
        // Set percentage to 100 for unassigned projects.
        var percentage = (assigned === 0) ? 100: (worked / assigned) * 100;
        // Getting around .toFixed() implicit conversion to a string
        percentage *= 100;
        percentage = Math.round(percentage);
        percentage /= 100;
        // Attach progress bar sprite
        build_project_bar(self, percentage);
    });
})();
<commit_msg>Making JS a little simpler. Changed from original idea of using sprites to purely CSS. Refs #510.<commit_after>
function getHours(time) {
    return Math.floor(time);
}

function getMinutes(time) {
    var minutes = Math.floor((time - getHours(time)) * 60);
    if (minutes < 10) {
        minutes = '0' + minutes;
    }
    return minutes
}

function humanizeTime(time) {
    var hours = getHours(time),
        minutes = getMinutes(time);

    return hours + ':' + minutes;
}

// Label for project charts.
function createProjectLabel(project_name, assigned) {
    return $('<div />', {
        'class': 'progress-label',
        'text': project_name + ' - ' + humanizeTime(assigned) + ' Assigned'
    });
}

// Worked, remaining, or overtime hours on a project.
function createBar(type, percent, label) {
    var cls = (type === 'remaining') ? type : 'bar bar-' + type;
    return $('<div />', {
        'class': cls,
        'style': 'width: ' + percent + '%;',
        'text': label
    });
}

// Container for all bars (worked, overtime, remaining) on a project.
function createChart(worked, assigned) {
    var chart = $('<div />', {
        'class': 'progress'
    });

    // Worked bar.
    if (worked > 0 && assigned > 0) {  // Skip if only remaining or overtime bar is needed.
        var worked_percent, worked_text;
        if (worked <= assigned) {
            worked_percent = Math.min(1, worked / assigned);
            worked_text = humanizeTime(worked) + ' Worked';
        } else {
            worked_percent = Math.min(1, assigned / worked);
            worked_text = humanizeTime(assigned) + ' Worked';
        }
        worked_percent = Math.floor(worked_percent * 100);
        chart.append(createBar('success', worked_percent, worked_text));  // Green
    }

    // Overtime bar.
    if (worked > assigned) {
        var overtime_percent = Math.min(1, 1 - assigned / worked),
            overtime_text = humanizeTime(worked - assigned) + ' Overtime';
        overtime_percent = Math.ceil(overtime_percent * 100);
        chart.append(createBar('danger', overtime_percent, overtime_text));  // Red
    }

    // Remaining bar.
    if (worked < assigned) {
        var remaining_percent = Math.min(1, 1 - worked / assigned),
            remaining_text = humanizeTime(assigned - worked) + ' Remaining';
        remaining_percent = Math.ceil(remaining_percent * 100);
        chart.append(createBar('remaining', remaining_percent, remaining_text));  // Blue
    }

    return chart;
}

var build_project_bar = function($bar_cell, percentage) {
    var $bar = $('<div />');

    // Creating text to fill the progress bar div
    var bar_alt;

    if (percentage > 100) {
        bar_alt = 'You have gone over on hours.';
        $bar.addClass('progress-over');
    }
    else {
        bar_alt = 'You have worked ' + percentage + '% of your hours.';
        $bar.attr('width', (percentage + '%'));
    }
    $bar.append(bar_alt);
    // Append the new bar div to the container
    $bar_cell.append($bar);
};

// Entry point to create overall progress chart and per project progress bars
(function() {
    var container = $('#progress-all'),
        worked = parseFloat(container.attr('data-worked')),
        assigned = parseFloat(container.attr('data-assigned'));

    var overall_chart = createChart(worked, assigned);
    container.append(overall_chart);

    // Create progress bars for each project
    $.each($('.project_progress_bar'), function() {
        var self = $(this);
        var worked = self.data('worked'),
            assigned = self.data('assigned');
        // Set percentage to 100 for unassigned projects.
        var percentage = (assigned === 0) ? 100: (worked / assigned) * 100;
        // Getting around .toFixed() implicit conversion to a string
        percentage *= 100;
        percentage = Math.round(percentage);
        percentage /= 100;
        // Attach progress bar bar
        build_project_bar(self, percentage);
    });
})();
<|endoftext|>


<commit_before>/**
 * polyfill / shim plugin for AMD loaders
 *
 * (c) copyright 2011-2012 Brian Cavalier and John Hann
 *
 * poly is part of the cujo.js family of libraries (http://cujojs.com/)
 *
 * Licensed under the MIT License at:
 * 		http://www.opensource.org/licenses/mit-license.php
 *
 */

define(['exports'], function (exports) {

	exports.version = '0.2.5';

	exports.load = function (def, require, onload, config) {

		function success (module) {
			// check for curl.js's promise
			onload.resolve ? onload.resolve(module) : onload(module);
		}

		function fail (ex) {
			// check for curl.js's promise
			if (onload.reject) {
				onload.reject(ex)
			}
			else {
				throw ex;
			}
		}

		// load module
		require([def], function (module) {

			try {
				// augment native
				if (module['polyfill']) {
					module['polyfill']();
				}
			}
			catch (ex) {
				fail(ex);
			}
			success(module);

		});

	};

    return exports;

});
<commit_msg>pass AMD config to shim modules<commit_after>/**
 * polyfill / shim plugin for AMD loaders
 *
 * (c) copyright 2011-2012 Brian Cavalier and John Hann
 *
 * poly is part of the cujo.js family of libraries (http://cujojs.com/)
 *
 * Licensed under the MIT License at:
 * 		http://www.opensource.org/licenses/mit-license.php
 *
 */

define(['exports'], function (exports) {

	exports.version = '0.2.5';

	exports.load = function (def, require, onload, config) {

		function success (module) {
			// check for curl.js's promise
			onload.resolve ? onload.resolve(module) : onload(module);
		}

		function fail (ex) {
			// check for curl.js's promise
			if (onload.reject) {
				onload.reject(ex)
			}
			else {
				throw ex;
			}
		}

		// load module
		require([def], function (module) {

			try {
				// augment native
				if (module['polyfill']) {
					module['polyfill'](config);
				}
			}
			catch (ex) {
				fail(ex);
			}
			success(module);

		});

	};

    return exports;

});
<|endoftext|>


<commit_before>// ==UserScript==
// @name         autoscroll
// @namespace    autoscroll
// @version      1.11
// @description  autoscroller to be used with https://facebook.tracking.exposed, This userscript works with TamperMoneky extension.
// @author       Claudio Agosti @_vecna
// @match        https://www.facebook.com/*
// @connect      autoscroll
// @grant        GM_setValue
// @grant        GM_getValue
// @require      https://cdnjs.cloudflare.com/ajax/libs/lodash-compat/3.10.2/lodash.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js
// ==/UserScript==

var times = 30;
var delay = 5;
var fixedH = 800;
var plan = [
    "09:01",
    "11:01",
    "13:01",
    "15:01",
    "17:01",
    "19:01",
    "21:01"
];

function timeline(reference) {

    if(!reference) {
        var s = GM_getValue("scrolling");

        if(s && moment(s).add(50, 's').isBefore(moment())) {
            console.log("a previous scroll interrupted?");
        }

        if(s && moment(s).add(50, 's').isAfter(moment())) {
            return;
        }

        console.log("setting GM_setValue 'scrolling'", moment().format() );
        GM_setValue("scrolling", moment().format());

        reference = {
            counter: 0,
            y: 0,
        };
    }

    if(reference.counter === times) {
        var s = GM_getValue("scrolling");
        console.log("Timeline counter reach", times);
        if(s) {
            console.log(s, "'scrolling': is present, -> doTheNext, removing GM_[scrolling]", s);
            GM_setValue("scrolling", null);
            return _.delay(doTheNext, 1);
        } else {
            console.log("GM_[scrolling] is null", s, "killed ramification");
        }
    } else {
        reference.counter += 1;
        reference.y = reference.counter * fixedH;
        GM_setValue("scrolling", moment().format());

        console.log("scrolling", reference.counter, "at",
                  moment().format("HH:mm:ss"), "a the Y", reference.y);

        scrollTo(0, reference.y);

        return _.delay(timeline, delay * 1000, reference);
    }
}

function doTheNext() {

    var isNight = moment().hour();
    var subdays = 0;
    if(isNight < 4) {
        console.log("It is night -- (FIXME: this check is not timezone safe)");
        subdays = 1;
    }
    /*
     * This function has to compute the seconds of distance between
     * now and the next TESING-HOUR. the hours are 9:00,11:00 etc,
     * and they happen in GMT-3, (180 minutes, below in the variables)
     */

	var tinfo = _.map(plan, function(t) {

		var hour = _.parseInt(t.split(':')[0]);
		var minute = _.parseInt(t.split(':')[1]);
		var personalO = moment().utcOffset() + 120;
		var target = moment().set({
            hour: hour,
            minute: minute,
            second: 0
        }).utcOffset(180);
        target.subtract(subdays, 'd');
        var secsdiff = moment.duration(target - moment()).asSeconds();
		var secto =  secsdiff + (personalO * 60);

		return {
            secsdiff: secsdiff,
			hto: _.round(secto / 3600, 1),
			secto: secto,
			target: t,
			x: target.format()
		};
	});

	console.log(tinfo);
	var next = _.first(_.filter(tinfo, function(t) {
		return t.secto > 0;
	}));

    console.log("Schedule computed, next on", next);
    if(!next) {
        console.log("Night problem, check back in 1 hour");
        GM_setValue("refresh", true);
        return _.delay(doTheNext, 3600 * 1000);
    } else {
        console.log("Setting the next timeline to", next.secto);
        GM_setValue("refresh", true);
        return _.delay(cleanAndReload, next.secto * 1000);
    }
};

function cleanAndReload() {
    GM_setValue("scrolling", null);
    // this value 'refresh' is not used because remain dirty in case a browser restart
    GM_setValue("refresh", null);
    location.reload();
};

(function() {

    var s = GM_getValue("scrolling");

    if( s && moment(s).add(50, 's').isBefore(moment())) {
        console.log("Considering the diff of",
                moment.duration(moment() - moment(s)).humanize(), "...");
        timeline();
    }
    else if(!s) {
        var r = GM_getValue("refresh");
        console.log("beginning tampermonkey, scrolling", s, "refresh", r);
        timeline();
    } else
        console.log("Nope, recorded is", moment(s).format("HH:mm:ss"), "now", moment().format("HH:mm:ss"));

})();

<commit_msg>bad error I was going to commit<commit_after>// ==UserScript==
// @name         autoscroll
// @namespace    autoscroll
// @version      1.11
// @description  autoscroller to be used with https://facebook.tracking.exposed, This userscript works with TamperMoneky extension.
// @author       Claudio Agosti @_vecna
// @match        https://www.facebook.com/*
// @connect      autoscroll
// @grant        GM_setValue
// @grant        GM_getValue
// @require      https://cdnjs.cloudflare.com/ajax/libs/lodash-compat/3.10.2/lodash.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js
// ==/UserScript==

var times = 30;
var delay = 5;
var fixedH = 800;
var plan = [
    "09:01",
    "11:01",
    "13:01",
    "15:01",
    "17:01",
    "19:01",
    "21:01"
];

function timeline(reference) {

    if(!reference) {
        var s = GM_getValue("scrolling");

        if(s && moment(s).add(50, 's').isBefore(moment())) {
            console.log("a previous scroll interrupted?");
        }

        if(s && moment(s).add(50, 's').isAfter(moment())) {
            return;
        }

        console.log("setting GM_setValue 'scrolling'", moment().format() );
        GM_setValue("scrolling", moment().format());

        reference = {
            counter: 0,
            y: 0,
        };
    }

    if(reference.counter === times) {
        var s = GM_getValue("scrolling");
        console.log("Timeline counter reach", times);
        if(s) {
            console.log(s, "'scrolling': is present, -> doTheNext, removing GM_[scrolling]", s);
            GM_setValue("scrolling", null);
            return _.delay(doTheNext, 1);
        } else {
            console.log("GM_[scrolling] is null", s, "killed ramification");
        }
    } else {
        reference.counter += 1;
        reference.y = reference.counter * fixedH;
        GM_setValue("scrolling", moment().format());

        console.log("scrolling", reference.counter, "at",
                  moment().format("HH:mm:ss"), "a the Y", reference.y);

        scrollTo(0, reference.y);

        return _.delay(timeline, delay * 1000, reference);
    }
}

function doTheNext() {

    var isNight = moment().hour();
    var subdays = 0;
    if(isNight < 4) {
        console.log("It is night -- (FIXME: this check is not timezone safe)");
        subdays = 1;
    }
    /*
     * This function has to compute the seconds of distance between
     * now and the next TESING-HOUR. the hours are 9:00,11:00 etc,
     * and they happen in GMT-3, (180 minutes, below in the variables)
     */

	var tinfo = _.map(plan, function(t) {

        var GMT3 = 180;
		var hour = _.parseInt(t.split(':')[0]);
		var minute = _.parseInt(t.split(':')[1]);
		var personalO = moment().utcOffset() + GMT3;
		var target = moment().set({
            hour: hour,
            minute: minute,
            second: 0
        }).utcOffset(GMT3);
        target.subtract(subdays, 'd');
        var secsdiff = moment.duration(target - moment()).asSeconds();
		var secto =  secsdiff + (personalO * 60);

		return {
            secsdiff: secsdiff,
			hto: _.round(secto / 3600, 1),
			secto: secto,
			target: t,
			x: target.format()
		};
	});

	console.log(tinfo);
	var next = _.first(_.filter(tinfo, function(t) {
		return t.secto > 0;
	}));

    console.log("Schedule computed, next on", next);
    if(!next) {
        console.log("Night problem, check back in 1 hour");
        GM_setValue("refresh", true);
        return _.delay(doTheNext, 3600 * 1000);
    } else {
        console.log("Setting the next timeline to", next.secto);
        GM_setValue("refresh", true);
        return _.delay(cleanAndReload, next.secto * 1000);
    }
};

function cleanAndReload() {
    GM_setValue("scrolling", null);
    // this value 'refresh' is not used because remain dirty in case a browser restart
    GM_setValue("refresh", null);
    location.reload();
};

(function() {

    var s = GM_getValue("scrolling");

    if( s && moment(s).add(50, 's').isBefore(moment())) {
        console.log("Considering the diff of",
                moment.duration(moment() - moment(s)).humanize(), "...");
        timeline();
    }
    else if(!s) {
        var r = GM_getValue("refresh");
        console.log("beginning tampermonkey, scrolling", s, "refresh", r);
        timeline();
    } else
        console.log("Nope, recorded is", moment(s).format("HH:mm:ss"), "now", moment().format("HH:mm:ss"));

})();

<|endoftext|>


<commit_before>'use strict';

var $interpolateMinErr = minErr('$interpolate');

/**
 * @ngdoc provider
 * @name $interpolateProvider
 * @kind function
 *
 * @description
 *
 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
 *
 * @example
<example module="customInterpolationApp">
<file name="index.html">

    //demo.label//

</file>
<file name="protractor.js" type="protractor">
  it('should interpolate binding with custom symbols', function() {
    expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
  });
</file>
</example>
 */
function $InterpolateProvider() {
  var startSymbol = '{{';
  var endSymbol = '}}';

  /**
   * @ngdoc method
   * @name $interpolateProvider#startSymbol
   * @description
   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
   *
   * @param {string=} value new value to set the starting symbol to.
   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
   */
  this.startSymbol = function(value){
    if (value) {
      startSymbol = value;
      return this;
    } else {
      return startSymbol;
    }
  };

  /**
   * @ngdoc method
   * @name $interpolateProvider#endSymbol
   * @description
   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
   *
   * @param {string=} value new value to set the ending symbol to.
   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
   */
  this.endSymbol = function(value){
    if (value) {
      endSymbol = value;
      return this;
    } else {
      return endSymbol;
    }
  };

  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
    var startSymbolLength = startSymbol.length,
        endSymbolLength = endSymbol.length;

    /**
     * @ngdoc service
     * @name $interpolate
     * @kind function
     *
     * @requires $parse
     * @requires $sce
     *
     * @description
     *
     * Compiles a string with markup into an interpolation function. This service is used by the
     * HTML {@link ng.$compile $compile} service for data binding. See
     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
     * interpolation markup.
     *
     *
     * ```js
     *   var $interpolate = ...; // injected
     *   var exp = $interpolate('Hello {{name | uppercase}}!');
     *   expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
     * ```
     *
     *
     * @param {string} text The text with markup to interpolate.
     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
     *    embedded expression in order to return an interpolation function. Strings with no
     *    embedded expression will return null for the interpolation function.
     * @param {string=} trustedContext when provided, the returned function passes the interpolated
     *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
     *    provides Strict Contextual Escaping for details.
     * @returns {function(context)} an interpolation function which is used to compute the
     *    interpolated string. The function has these parameters:
     *
     *    * `context`: an object against which any expressions embedded in the strings are evaluated
     *      against.
     *
     */
    function $interpolate(text, mustHaveExpression, trustedContext) {
      var startIndex,
          endIndex,
          index = 0,
          parts = [],
          length = text.length,
          hasInterpolation = false,
          fn,
          exp,
          concat = [];

      while(index < length) {
        if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
          (index != startIndex) && parts.push(text.substring(index, startIndex));
          parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
          fn.exp = exp;
          index = endIndex + endSymbolLength;
          hasInterpolation = true;
        } else {
          // we did not find anything, so we have to add the remainder to the parts array
          (index != length) && parts.push(text.substring(index));
          index = length;
        }
      }

      if (!(length = parts.length)) {
        // we added, nothing, must have been an empty string.
        parts.push('');
        length = 1;
      }

      // Concatenating expressions makes it hard to reason about whether some combination of
      // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
      // single expression be used for iframe[src], object[src], etc., we ensure that the value
      // that's used is assigned or constructed by some JS code somewhere that is more testable or
      // make it obvious that you bound the value to some user controlled value.  This helps reduce
      // the load when auditing for XSS issues.
      if (trustedContext && parts.length > 1) {
          throw $interpolateMinErr('noconcat',
              "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
              "interpolations that concatenate multiple expressions when a trusted value is " +
              "required.  See http://docs.angularjs.org/api/ng.$sce", text);
      }

      if (!mustHaveExpression  || hasInterpolation) {
        concat.length = length;
        fn = function(context) {
          try {
            for(var i = 0, ii = length, part; i<ii; i++) {
              if (typeof (part = parts[i]) == 'function') {
                part = part(context);
                if (trustedContext) {
                  part = $sce.getTrusted(trustedContext, part);
                } else {
                  part = $sce.valueOf(part);
                }
                if (part == null) { // null || undefined
                  part = '';
                } else {
                  switch (typeof part) {
                    case 'string':
                    {
                      break;
                    }
                    case 'number':
                    {
                      part = '' + part;
                      break;
                    }
                    default:
                    {
                      part = toJson(part);
                    }
                  }
                }
              }
              concat[i] = part;
            }
            return concat.join('');
          }
          catch(err) {
            var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
                err.toString());
            $exceptionHandler(newErr);
          }
        };
        fn.exp = text;
        fn.parts = parts;
        return fn;
      }
    }

    /**
     * @ngdoc method
     * @name $interpolate#startSymbol
     * @description
     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
     *
     * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
     * the symbol.
     *
     * @returns {string} start symbol.
     */
    $interpolate.startSymbol = function() {
      return startSymbol;
    };

    /**
     * @ngdoc method
     * @name $interpolate#endSymbol
     * @description
     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
     *
     * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
     * the symbol.
     *
     * @returns {string} end symbol.
     */
    $interpolate.endSymbol = function() {
      return endSymbol;
    };

    return $interpolate;
  }];
}

<commit_msg>docs(interpolate): fix link text<commit_after>'use strict';

var $interpolateMinErr = minErr('$interpolate');

/**
 * @ngdoc provider
 * @name $interpolateProvider
 * @kind function
 *
 * @description
 *
 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
 *
 * @example
<example module="customInterpolationApp">
<file name="index.html">

    //demo.label//

</file>
<file name="protractor.js" type="protractor">
  it('should interpolate binding with custom symbols', function() {
    expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
  });
</file>
</example>
 */
function $InterpolateProvider() {
  var startSymbol = '{{';
  var endSymbol = '}}';

  /**
   * @ngdoc method
   * @name $interpolateProvider#startSymbol
   * @description
   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
   *
   * @param {string=} value new value to set the starting symbol to.
   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
   */
  this.startSymbol = function(value){
    if (value) {
      startSymbol = value;
      return this;
    } else {
      return startSymbol;
    }
  };

  /**
   * @ngdoc method
   * @name $interpolateProvider#endSymbol
   * @description
   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
   *
   * @param {string=} value new value to set the ending symbol to.
   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
   */
  this.endSymbol = function(value){
    if (value) {
      endSymbol = value;
      return this;
    } else {
      return endSymbol;
    }
  };

  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
    var startSymbolLength = startSymbol.length,
        endSymbolLength = endSymbol.length;

    /**
     * @ngdoc service
     * @name $interpolate
     * @kind function
     *
     * @requires $parse
     * @requires $sce
     *
     * @description
     *
     * Compiles a string with markup into an interpolation function. This service is used by the
     * HTML {@link ng.$compile $compile} service for data binding. See
     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
     * interpolation markup.
     *
     *
     * ```js
     *   var $interpolate = ...; // injected
     *   var exp = $interpolate('Hello {{name | uppercase}}!');
     *   expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
     * ```
     *
     *
     * @param {string} text The text with markup to interpolate.
     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
     *    embedded expression in order to return an interpolation function. Strings with no
     *    embedded expression will return null for the interpolation function.
     * @param {string=} trustedContext when provided, the returned function passes the interpolated
     *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
     *    provides Strict Contextual Escaping for details.
     * @returns {function(context)} an interpolation function which is used to compute the
     *    interpolated string. The function has these parameters:
     *
     *    * `context`: an object against which any expressions embedded in the strings are evaluated
     *      against.
     *
     */
    function $interpolate(text, mustHaveExpression, trustedContext) {
      var startIndex,
          endIndex,
          index = 0,
          parts = [],
          length = text.length,
          hasInterpolation = false,
          fn,
          exp,
          concat = [];

      while(index < length) {
        if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
          (index != startIndex) && parts.push(text.substring(index, startIndex));
          parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
          fn.exp = exp;
          index = endIndex + endSymbolLength;
          hasInterpolation = true;
        } else {
          // we did not find anything, so we have to add the remainder to the parts array
          (index != length) && parts.push(text.substring(index));
          index = length;
        }
      }

      if (!(length = parts.length)) {
        // we added, nothing, must have been an empty string.
        parts.push('');
        length = 1;
      }

      // Concatenating expressions makes it hard to reason about whether some combination of
      // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
      // single expression be used for iframe[src], object[src], etc., we ensure that the value
      // that's used is assigned or constructed by some JS code somewhere that is more testable or
      // make it obvious that you bound the value to some user controlled value.  This helps reduce
      // the load when auditing for XSS issues.
      if (trustedContext && parts.length > 1) {
          throw $interpolateMinErr('noconcat',
              "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
              "interpolations that concatenate multiple expressions when a trusted value is " +
              "required.  See http://docs.angularjs.org/api/ng.$sce", text);
      }

      if (!mustHaveExpression  || hasInterpolation) {
        concat.length = length;
        fn = function(context) {
          try {
            for(var i = 0, ii = length, part; i<ii; i++) {
              if (typeof (part = parts[i]) == 'function') {
                part = part(context);
                if (trustedContext) {
                  part = $sce.getTrusted(trustedContext, part);
                } else {
                  part = $sce.valueOf(part);
                }
                if (part == null) { // null || undefined
                  part = '';
                } else {
                  switch (typeof part) {
                    case 'string':
                    {
                      break;
                    }
                    case 'number':
                    {
                      part = '' + part;
                      break;
                    }
                    default:
                    {
                      part = toJson(part);
                    }
                  }
                }
              }
              concat[i] = part;
            }
            return concat.join('');
          }
          catch(err) {
            var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
                err.toString());
            $exceptionHandler(newErr);
          }
        };
        fn.exp = text;
        fn.parts = parts;
        return fn;
      }
    }

    /**
     * @ngdoc method
     * @name $interpolate#startSymbol
     * @description
     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
     *
     * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
     * the symbol.
     *
     * @returns {string} start symbol.
     */
    $interpolate.startSymbol = function() {
      return startSymbol;
    };

    /**
     * @ngdoc method
     * @name $interpolate#endSymbol
     * @description
     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
     *
     * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
     * the symbol.
     *
     * @returns {string} end symbol.
     */
    $interpolate.endSymbol = function() {
      return endSymbol;
    };

    return $interpolate;
  }];
}

<|endoftext|>


<commit_before>var depositCallbackJob = require(__dirname+'/../jobs/deposit_completion_callback.js');
var OutgoingPayment = require(__dirname+'/outgoing_payment.js');
var gateway = require(__dirname+'/../../');
var RippleRestClient = require('ripple-rest-client');

function OutgoingPaymentProcessor(payment) {
  this.outgoingPayment = new OutgoingPayment(payment);
}

OutgoingPaymentProcessor.prototype = {
  processOutgoingPayment: function(callback) {
    var self = this;
    self.outgoingPayment.sendToRippleRest(function(error, response) {
      if (error) {
        console.log('error', error);
        setTimeout(callback, 2000);
      } else {
        callback();
      }
    });
  }
};

var rippleRestClient = new RippleRestClient({
  account: gateway.config.get('HOT_WALLET').address,
  secret: ''
})

module.exports = OutgoingPaymentProcessor;

<commit_msg>[TASK] Update OutgoingPaymentProcessor to use new method.<commit_after>var depositCallbackJob = require(__dirname+'/../jobs/deposit_completion_callback.js');
var OutgoingPayment = require(__dirname+'/outgoing_payment.js');
var gateway = require(__dirname+'/../../');
var RippleRestClient = require('ripple-rest-client');

function OutgoingPaymentProcessor(payment) {
  this.outgoingPayment = new OutgoingPayment(payment);
}

OutgoingPaymentProcessor.prototype = {
  processOutgoingPayment: function(callback) {
    var self = this;
    self.outgoingPayment.processOutgoingPayment(function(error, response) {
      if (error) {
        console.log('error', error);
        setTimeout(callback, 2000);
      } else {
        callback();
      }
    });
  }
};

var rippleRestClient = new RippleRestClient({
  account: gateway.config.get('HOT_WALLET').address,
  secret: ''
})

module.exports = OutgoingPaymentProcessor;

<|endoftext|>