<commit_before>/**
 * scraper - v0.5
 * The online form of scratch card

 * http://Alex1990.github.io/scraper
 * Alex Chao - http://www.xiaocaoge.com
 * Under the MIT License
 */
(function(win) {

    'use strict';

    var scraper = function(canvas, opts) {

        // 检测是否是触摸屏
        var isTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints;

        // 检测IE Mobile版本
        var isIE11m = window.navigator.pointerEnabled ? true: false;
        var isIE10m = window.navigator.msPointerEnabled && !isIE11m ? true : false;

        // 根据不同浏览器，以及是否触屏返回相应的事件
        var startEvt,
            moveEvt;
        if (isTouch) {
            if (isIE11m) {
                startEvt = 'pointerdown';
                moveEvt = 'pointermove';
            } else if (isIE10m) {
                startEvt = 'MSPointerDown';
                moveEvt = 'MSPointerMove';
            } else {
                startEvt = 'touchstart';
                moveEvt = 'touchmove';
            }
        }

        // 绑定事件函数
        var addEvent;
        if (document.addEventListener) {
            addEvent = function(eTarget, type, listener) {
                eTarget.addEventListener(type, listener, false);
            };
        } else if (document.attachEvent) {
            addEvent = function(eTarget, type, listener) {
                eTarget[type+listener] = function(e) {
                    e = window.event;
                    e.target = e.srcElement;
                    e.currentTarget = eTarget;
                    e.preventDefault = function() { e.returnValue = false; };
                    e.stopPropagation = function() { e.cancalBubble = true; };
                    listener.call(eTarget, e);
                };
                eTarget.attachEvent('on'+type, eTarget[type+listener]);
            };
        }

        // 解绑事件函数
        var removeEvent;
        if (document.removeEventListener) {
            removeEvent = function(eTarget, type, listener) {
                eTarget.removeEventListener(type, listener, false);
            };
        } else if (document.detachEvent) {
            removeEvent = function(eTarget, type, listener) {
                eTarget.detachEvent('on'+type, eTarget[type+listener]);
                eTarget[type+listener] = null;
            };
        }

        // 默认配置
        var defaults = {
            coverText: ['', 0, 0], // 数组中三个值依次代表覆盖层显示文字、文字横坐标、文字纵坐标
            coverFont: '24px Arial, Microsoft Yahei, sans-serif', // 覆盖层文字格式
            coverColor: '#333', // 覆盖层文字颜色
            coverBgColor: '#eee', // 覆盖层颜色
            pointRadius: 10, // 刮覆盖层时，触点半径
            prizeArea: [0, 0, 100, 40], // 结果(中奖)区域，矩形，参数依次为x, y, width, height
            shape: null, // 覆盖层形状图片，默认无图片，为矩形
            shapeX: 0, // 覆盖层形状图片左上角到canvas左上角水平距离
            shapeY: 0, // 覆盖层形状图片左上角到canvas左上角垂直距离
            shapeW: null, // 覆盖层形状图片宽度
            shapeH: null, // 覆盖层形状图片高度
            onscrape: function() {}, // 开始刮时触发此事件
            onresult: function() {} // 刮到结果(中奖)区域时触发事件
        };

        // 将用户配置项与默认配置项合并
        opts = mergeOpts(defaults, opts);

        // 获取画布的宽度与高度
        opts.width = canvas.width;
        opts.height = canvas.height;

        // 填充画布的覆盖层
        var ctx = canvas.getContext('2d');
        if (!opts.shape) {
            ctx.beginPath();
            ctx.fillStyle = opts.coverBgColor;
            ctx.rect(0, 0, opts.width, opts.height);
            ctx.fill();
            ctx.closePath();
        } else {
            var tmpImg = new Image();
            tmpImg.src = opts.shape;
            ctx.drawImage(tmpImg, opts.shapeX, opts.shapeY, opts.shapeW, opts.shapeH);
        }

        // 绘制文字于覆盖层上
        if (opts.coverFont) {
            ctx.beginPath();
            ctx.fillStyle = opts.coverColor;
            ctx.font = opts.coverFont;
            ctx.fillText(opts.coverText[0], opts.coverText[1] || 0, opts.coverText[2] || 0);
            ctx.closePath();
        }

        // 标记鼠标是否按下，即mousedown事件是否触发
        var flag = false;

        // 绑定开始刮时的回调函数
        if (isTouch) {
            addEvent(canvas, startEvt, proxy(opts.onscrape, opts));
        } else {
            addEvent(canvas, 'mousedown',startScrape);
            addEvent(canvas, 'mouseup', stopScrape);
        }

        // 鼠标按下回调函数
        function startScrape(e) {
            flag = true;
            opts.onscrape.call(opts);
            if (flag) {
                addEvent(canvas, 'mousemove', scrapeCover);
            }
        }

        // 鼠标松开回调函数，解绑鼠标滑动事件
        function stopScrape() {
            if (flag) {
                removeEvent(canvas, 'mousemove', scrapeCover);
                flag = false;
            }
        }

        // 手指或鼠标滑动回调
        function scrapeCover(e) {

            // touchmove事件触发时，阻止触发页面滚动
            e.stopPropagation();

            var i,
                len,
                scrapeX,
                scrapeY,
                points = [e],
                ctx1= ctx,
                prizeArea = opts.prizeArea,
                pointRadius = opts.pointRadius;

            if (isTouch && !isIE11m && !isIE10m ) {
                points =  e.targetTouches;
            }

            len = points.length;
            for (i = 0; i < len; i++) {
                scrapeX = points[i].clientX + scrollX() - pageX(this);
                scrapeY = points[i].clientY + scrollY() - pageY(this);

                // 清除手指或鼠标位置处的覆盖层
                ctx1.save();
                ctx1.beginPath();
                ctx1.arc(scrapeX, scrapeY, pointRadius, 0, Math.PI * 2);
                ctx1.clip();
                ctx1.clearRect(scrapeX - pointRadius, scrapeY - pointRadius, pointRadius * 2, pointRadius * 2);
                ctx1.restore();

                if (scrapeX >= prizeArea[0] &&
                        scrapeY >= prizeArea[1] &&
                        scrapeX <= (prizeArea[0] + prizeArea[2]) &&
                        scrapeY <= (prizeArea[1] + prizeArea[3])) {

                    // 触发结果回调
                    opts.onresult();
                }
            }
        }

        if (isTouch) {
            addEvent(canvas, moveEvt, scrapeCover);
        }
    };

    // 绑定上下文
    function proxy(fn, o) {
        if (typeof fn === 'function') {
            return function() {
                fn.call(o);
            };
        }
    }

    // 合并两个对象
    function mergeOpts(opts1, opts2) {
        for (var item in opts2) {
            opts1[item] = opts2[item];
        }
        return opts1;
    }

    // 返回元素距离页面左上角的水平距离
    function pageX(el) {
        var x = 0;
        while (el = el.offsetParent) {
            x += el.offsetLeft;
        }
        return x;
    }

    // 返回元素距离页面左上角的垂直距离
    function pageY(el) {
        var y = 0;
        while (el = el.offsetParent) {
            y += el.offsetTop;
        }
        return y;
    }

    // 返回文档滚动过的水平距离
    function scrollX() {
        return window.scrollX || document.documentElement.scrollLeft ||
                document.body.scrollLeft;
    }

    // 返回文档滚动过的垂直距离
    function scrollY() {
        return window.scrollY || document.documentElement.scrollTop ||
                document.body.scrollTop;
    }

    // 将scraper绑定到全局变量
    win.scraper = scraper;
})(window);<commit_msg>采用事件代理方式触发，修正了Android4.0.3自带浏览器下无效bug<commit_after>/**
 * scraper - v0.9
 * The online form of scratch card

 * http://Alex1990.github.io/scraper
 * Alex Chao - http://www.xiaocaoge.com
 * Under the MIT License
 */
(function(win) {

    'use strict';

    var scraper = function(canvas, opts) {

        // 检测是否是触摸屏
        var isTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints;

        // 检测IE Mobile版本
        var isIE11m = window.navigator.pointerEnabled ? true: false;
        var isIE10m = window.navigator.msPointerEnabled && !isIE11m ? true : false;

        var startEvt,
            moveEvt,
            endEvt;

        // 根据不同浏览器，以及是否触屏返回相应的事件
        if (isTouch) {
            if (isIE11m) {
                startEvt = 'pointerdown';
                moveEvt = 'pointermove';
                endEvt = 'pointerup';
            } else if (isIE10m) {
                startEvt = 'MSPointerDown';
                moveEvt = 'MSPointerMove';
                endEvt = 'MSPointerUp';
            } else {
                startEvt = 'touchstart';
                moveEvt = 'touchmove';
                endEvt = 'touchend';
            }
        } else {
            startEvt = 'mousedown';
            moveEvt = 'mousemove';
            endEvt = 'mouseup';
        }

        // 绑定事件函数
        var addEvent;
        if (document.addEventListener) {
            addEvent = function(eTarget, type, listener) {
                eTarget.addEventListener(type, listener, false);
            };
        } else if (document.attachEvent) {
            addEvent = function(eTarget, type, listener) {
                eTarget[type+listener] = function(e) {
                    e = window.event;
                    e.target = e.srcElement;
                    e.currentTarget = eTarget;
                    e.preventDefault = function() { e.returnValue = false; };
                    e.stopPropagation = function() { e.cancalBubble = true; };
                    listener.call(eTarget, e);
                };
                eTarget.attachEvent('on'+type, eTarget[type+listener]);
            };
        }

        // 解绑事件函数
        var removeEvent;
        if (document.removeEventListener) {
            removeEvent = function(eTarget, type, listener) {
                eTarget.removeEventListener(type, listener, false);
            };
        } else if (document.detachEvent) {
            removeEvent = function(eTarget, type, listener) {
                eTarget.detachEvent('on'+type, eTarget[type+listener]);
                eTarget[type+listener] = null;
            };
        }

        // 默认配置
        var defaults = {
            bindElement: document, // 事件代理对象
            coverText: ['', 0, 0], // 数组中三个值依次代表覆盖层显示文字、文字横坐标、文字纵坐标
            coverFont: '24px Arial, Microsoft Yahei, sans-serif', // 覆盖层文字格式
            coverColor: '#333', // 覆盖层文字颜色
            coverBgColor: '#eee', // 覆盖层颜色
            pointRadius: 10, // 刮覆盖层时，触点半径
            prizeArea: [0, 0, 100, 40], // 结果(中奖)区域，矩形，参数依次为x, y, width, height
            shape: null, // 覆盖层形状图片，默认无图片，为矩形
            shapeX: 0, // 覆盖层形状图片左上角到canvas左上角水平距离
            shapeY: 0, // 覆盖层形状图片左上角到canvas左上角垂直距离
            shapeW: null, // 覆盖层形状图片宽度
            shapeH: null, // 覆盖层形状图片高度
            onscrape: function() {}, // 开始刮时触发此事件
            onresult: function() {} // 刮到结果(中奖)区域时触发事件
        };

        // 将用户配置项与默认配置项合并
        opts = mergeOpts(defaults, opts);

        // 获取画布的宽度与高度
        opts.width = canvas.width;
        opts.height = canvas.height;

        // 填充画布的覆盖层
        var ctx = canvas.getContext('2d');
        if (!opts.shape) {
            ctx.beginPath();
            ctx.fillStyle = opts.coverBgColor;
            ctx.rect(0, 0, opts.width, opts.height);
            ctx.fill();
            ctx.closePath();
        } else {
            var tmpImg = new Image();
            tmpImg.src = opts.shape;
            ctx.drawImage(tmpImg, opts.shapeX, opts.shapeY, opts.shapeW, opts.shapeH);
        }

        // 绘制文字于覆盖层上
        if (opts.coverFont) {
            ctx.beginPath();
            ctx.fillStyle = opts.coverColor;
            ctx.font = opts.coverFont;
            ctx.fillText(opts.coverText[0], opts.coverText[1] || 0, opts.coverText[2] || 0);
            ctx.closePath();
        }

        // 标记是否被刮过，用来避免opts.onscrape一直触发
        var scraped = false;

        // 绑定鼠标按下或手指触摸时的回调函数
        addEvent(opts.bindElement, startEvt, startScrape);

        // 绑定鼠标松开或手指离开屏幕时的回调函数
        addEvent(opts.bindElement, endEvt, stopScrape);

        // 鼠标按下或手指触摸回调函数
        function startScrape(e) {
            if (!scraped) {
                opts.onscrape.call(opts);
            }
            addEvent(opts.bindElement, moveEvt, scrapeCover);
        }

        // 鼠标松开或手指离开屏幕回调函数，解绑鼠标或手指滑动事件
        function stopScrape() {
            removeEvent(opts.bindElement, moveEvt, scrapeCover);
        }

        var log = document.getElementById('log');

        // 手指或鼠标滑动回调
        function scrapeCover(e) {

            // touchmove事件触发时，阻止触发页面滚动
            e.preventDefault();
            e.stopPropagation();

            var i,
                len,
                scrapeX,
                scrapeY,
                points = [e],
                ctx1= ctx,
                prizeArea = opts.prizeArea,
                pointRadius = opts.pointRadius;

            if (isTouch && !isIE11m && !isIE10m ) {
                points =  e.targetTouches;
            }

            len = points.length;
            for (i = 0; i < len; i++) {
                scrapeX = points[i].clientX + scrollX() - pageX(canvas);
                scrapeY = points[i].clientY + scrollY() - pageY(canvas);

                // 清除手指或鼠标位置处的覆盖层
                ctx1.save();
                ctx1.globalCompositeOperation = 'destination-out';
                ctx1.beginPath();
                ctx1.arc(scrapeX, scrapeY, pointRadius, 0, Math.PI * 2);
                ctx1.fill();

                // 若采用下面两行代码的方式清除圆形画布层，在G18/Android4.0.3自带浏览器中不起作用
                // ctx1.clip();
                // ctx1.clearRect(0, 0, opts.width, opts.height);
                ctx1.restore();

                if (scrapeX >= prizeArea[0] &&
                        scrapeY >= prizeArea[1] &&
                        scrapeX <= (prizeArea[0] + prizeArea[2]) &&
                        scrapeY <= (prizeArea[1] + prizeArea[3])) {

                    // 触发结果回调
                    opts.onresult();

                    // 标记已经被刮开
                    scraped = true;
                }
            }
        }

    };

    // 合并两个对象
    function mergeOpts(opts1, opts2) {
        for (var item in opts2) {
            opts1[item] = opts2[item];
        }
        return opts1;
    }

    // 返回元素距离页面左上角的水平距离
    function pageX(el) {
        var x = 0;
        while (el = el.offsetParent) {
            x += el.offsetLeft;
        }
        return x;
    }

    // 返回元素距离页面左上角的垂直距离
    function pageY(el) {
        var y = 0;
        while (el = el.offsetParent) {
            y += el.offsetTop;
        }
        return y;
    }

    // 返回文档滚动过的水平距离
    function scrollX() {
        return window.scrollX || document.documentElement.scrollLeft ||
                document.body.scrollLeft;
    }

    // 返回文档滚动过的垂直距离
    function scrollY() {
        return window.scrollY || document.documentElement.scrollTop ||
                document.body.scrollTop;
    }

    // 将scraper绑定到全局变量
    win.scraper = scraper;
})(window);<|endoftext|>


<commit_before><commit_msg>Fix remaining static toolbox reference<commit_after><|endoftext|>


<commit_before>"use strict";
var React = require("react/addons"),
    deepEqual = require("deep-equal"),

    expose_getters_from = require("./helpers/expose_getters_from"),
    to_event_map = require("./helpers/to_event_map"),
    assign_event_map_to_prop_types_and_spec = require("./helpers/assign_event_map_to_prop_types_and_spec"),
    EventBindingMixin = require("./mixins/EventBindingMixin"),

    EVENT_NAMES = "bounds_changed center_changed click dblclick drag dragend dragstart heading_changed idle maptypeid_changed mousemove mouseout mouseover projection_changed resize rightclick tilesloaded tilt_changed zoom_changed",
    EVENT_MAP = to_event_map(EVENT_NAMES),

    MapSpec,
    MapPropTypes;

function ensure_map_created (component, createdCallback, createFactory) {
  var {context} = component,
      map = context.getMap(),
      noMap = !map;

  if (noMap && context.getApi() && createFactory) {
    map = createFactory(component, context);
  }
  if (map) {
    createdCallback(map);
    if (noMap) {
      component.setState({_initialized: true});
    }
  }
}

function create_map (component, context) {
  var {Map} = context.getApi(),
      map = new Map(
    component.refs.mapCanvas.getDOMNode(),
    component.props
  );
  expose_getters_from(component, Map.prototype, map);
  return context._set_map(map);
}

MapPropTypes = {

};

MapSpec = {
  displayName: "Map",

  mixins: [EventBindingMixin(EVENT_MAP)],

  propTypes: MapPropTypes,

  contextTypes: {
    getMap: React.PropTypes.func,
    getApi: React.PropTypes.func,
    hasMap: React.PropTypes.func,
    _set_map: React.PropTypes.func
  },

  /*
   * Some public API we'd like to expose
   */
  panBy (x, y) {
    ensure_map_created(this, (map) => {
      map.panBy(x, y);
    });
  },

  panTo (latLng) {
    ensure_map_created(this, (map) => {
      map.panTo(latLng);
    });
  },

  panToBounds (latLngBounds) {
    ensure_map_created(this, (map) => {
      map.panToBounds(latLngBounds);
    });
  },

  getInitialState () {
    return {
      /* [null, false, true] => ["init", "api loaded", "done"] */
      _initialized: null,
    };
  },

  shouldComponentUpdate(nextProps, nextState) {
    return !deepEqual(nextProps, this.props) || nextState._initialized !== this.state._initialized;
  },

  componentDidMount () {
    ensure_map_created(this, this.add_listeners, create_map);
  },

  componentWillReceiveProps (nextProps, nextContext) {
    if (null == this.state._initialized && nextContext.getApi()) {
      this.setState({
        _initialized: false,
      });
    }
  },

  componentDidUpdate () {
    ensure_map_created(this, (map) => {
      map.setOptions(this.props);
      this.add_listeners(map);
    }, create_map);
  },

  componentWillUnmount () {
    ensure_map_created(this, (map) => {
      this.clear_listeners(map);
      this.context._set_map(null);
    });
  },

  render () {
    return this._render(this.props, this.state);
  },

  _render (props, state) {
    return

;
  }
};

assign_event_map_to_prop_types_and_spec(EVENT_MAP, MapPropTypes, MapSpec);

module.exports = React.createClass(MapSpec);
<commit_msg>fix(Map): only pass id, className and style from props<commit_after>"use strict";
var React = require("react/addons"),
    deepEqual = require("deep-equal"),

    expose_getters_from = require("./helpers/expose_getters_from"),
    to_event_map = require("./helpers/to_event_map"),
    assign_event_map_to_prop_types_and_spec = require("./helpers/assign_event_map_to_prop_types_and_spec"),
    EventBindingMixin = require("./mixins/EventBindingMixin"),

    EVENT_NAMES = "bounds_changed center_changed click dblclick drag dragend dragstart heading_changed idle maptypeid_changed mousemove mouseout mouseover projection_changed resize rightclick tilesloaded tilt_changed zoom_changed",
    EVENT_MAP = to_event_map(EVENT_NAMES),

    MapSpec,
    MapPropTypes;

function ensure_map_created (component, createdCallback, createFactory) {
  var {context} = component,
      map = context.getMap(),
      noMap = !map;

  if (noMap && context.getApi() && createFactory) {
    map = createFactory(component, context);
  }
  if (map) {
    createdCallback(map);
    if (noMap) {
      component.setState({_initialized: true});
    }
  }
}

function create_map (component, context) {
  var {Map} = context.getApi(),
      map = new Map(
    component.refs.mapCanvas.getDOMNode(),
    component.props
  );
  expose_getters_from(component, Map.prototype, map);
  return context._set_map(map);
}

MapPropTypes = {

};

MapSpec = {
  displayName: "Map",

  mixins: [EventBindingMixin(EVENT_MAP)],

  propTypes: MapPropTypes,

  contextTypes: {
    getMap: React.PropTypes.func,
    getApi: React.PropTypes.func,
    hasMap: React.PropTypes.func,
    _set_map: React.PropTypes.func
  },

  /*
   * Some public API we'd like to expose
   */
  panBy (x, y) {
    ensure_map_created(this, (map) => {
      map.panBy(x, y);
    });
  },

  panTo (latLng) {
    ensure_map_created(this, (map) => {
      map.panTo(latLng);
    });
  },

  panToBounds (latLngBounds) {
    ensure_map_created(this, (map) => {
      map.panToBounds(latLngBounds);
    });
  },

  getInitialState () {
    return {
      /* [null, false, true] => ["init", "api loaded", "done"] */
      _initialized: null,
    };
  },

  shouldComponentUpdate(nextProps, nextState) {
    return !deepEqual(nextProps, this.props) || nextState._initialized !== this.state._initialized;
  },

  componentDidMount () {
    ensure_map_created(this, this.add_listeners, create_map);
  },

  componentWillReceiveProps (nextProps, nextContext) {
    if (null == this.state._initialized && nextContext.getApi()) {
      this.setState({
        _initialized: false,
      });
    }
  },

  componentDidUpdate () {
    ensure_map_created(this, (map) => {
      map.setOptions(this.props);
      this.add_listeners(map);
    }, create_map);
  },

  componentWillUnmount () {
    ensure_map_created(this, (map) => {
      this.clear_listeners(map);
      this.context._set_map(null);
    });
  },

  render () {
    return this._render(this.props, this.state);
  },

  _render (props, state) {
    return

;
  }
};

assign_event_map_to_prop_types_and_spec(EVENT_MAP, MapPropTypes, MapSpec);

module.exports = React.createClass(MapSpec);
<|endoftext|>


<commit_before>/**
 * Example for creating and working with the Slack RTM API.
 */

/* eslint no-console:0 */

/*******************************************************************************
 * Globals
 */
const RtmClient = require('@slack/client').RtmClient;
const RTM_EVENTS = require('@slack/client').RTM_EVENTS;
const AWS = require('./AWS_API.js');

const token = process.env.SLACK_API_TOKEN || '';
const DEBUG = process.env.DEBUG || true;
AWS.DEBUG = DEBUG;

/*******************************************************************************
 * Functions
 */

var handleRtmMessage = function(message) {
    if (DEBUG) { console.log('Message:', message) }

    var text = message.text;

    if (keyMessage(text, 'aws ')) {
        text = text.substring('aws '.length, text.length);
        if (keyMessage(text, 'describe ec2 ')) {
            text = text.substring('describe ec2 '.length, text.length);
            if (keyMessage(text, 'instance ')) {
                AWS.checkEC2Instance(text.substring('instance '.length, text.length)).then(function (resp) {
                    rtm.sendMessage(resp, message.channel);
                }, function (err) {
                    rtm.sendMessage('Looks like there was a problem processing your request', message.channel);
                    console.log(err);
                });
            } else {
                AWS.checkEC2().then(function (resp) {
                    rtm.sendMessage(resp, message.channel);
                }, function (err) {
                    rtm.sendMessage('Looks like there was a problem processing your request', message.channel);
                    console.log(err);
                });
            }
        } else if (keyMessage(text, 'check number of instances ')) {
            AWS.checkNumInstances().then(function (resp) {
                rtm.sendMessage(resp, message.channel);
            }, function (err) {
                rtm.sendMessage('Looks like there was a problem processing your request', message.channel);
                console.log(err);
            });
        } else {
            rtm.sendMessage("I'm sorry, this isn't an AWS command I'm familiar with.", message.channel);
        }
    } else {
        rtm.sendMessage("I'm sorry, this isn't a command I'm familiar with.", message.channel);
    }
}

/*******************************************************************************
 * Helper functions
 */

function keyMessage(text, key) {
    var temptext = text + ' ';
    if (temptext.length >= key.length && temptext.substring(0, key.length).toLowerCase() === key) {
        return true;
    }
    return false;
}

/*******************************************************************************
 * Test stuff
 */
/*
Sample inputs:
aws describe ec2 instance i-0a681657adec3b3ee
aws describe ec2
 */
var mockRTM = function() {
    var readline = require('readline');
    var rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout
    });

    process.stdout.write("Please input your test message text: ");
    rl.on('line', function (line) {
        var message = {
            'text': line,
            'channel': 3
        };

        // mocking rtm
        rtm = {};
        rtm.sendMessage = function(message, channel) {
            console.log('----------Response message----------');
            console.log('Text: ' + message);
            console.log('Channel: ' + channel);
        }

        // run the test
        handleRtmMessage(message);
    });
}

/*******************************************************************************
 * main()
 */

var main = function() {
    var rtm = new RtmClient(token);
    rtm.start();

    rtm.on(RTM_EVENTS.MESSAGE, handleRtmMessage);

    rtm.on(RTM_EVENTS.REACTION_ADDED, function handleRtmReactionAdded(reaction) {
        console.log('Reaction added:', reaction);
    });

    rtm.on(RTM_EVENTS.REACTION_REMOVED, function handleRtmReactionRemoved(reaction) {
        console.log('Reaction removed:', reaction);
    });
}

if (DEBUG) {
    mockRTM();
} else {
    main();
}<commit_msg>Default DEBUG to false<commit_after>/**
 * Example for creating and working with the Slack RTM API.
 */

/* eslint no-console:0 */

/*******************************************************************************
 * Globals
 */
const RtmClient = require('@slack/client').RtmClient;
const RTM_EVENTS = require('@slack/client').RTM_EVENTS;
const AWS = require('./AWS_API.js');

const token = process.env.SLACK_API_TOKEN || '';
const DEBUG = process.env.DEBUG || false;
AWS.DEBUG = DEBUG;

/*******************************************************************************
 * Functions
 */

var handleRtmMessage = function(message) {
    if (DEBUG) { console.log('Message:', message) }

    var text = message.text;

    if (keyMessage(text, 'aws ')) {
        text = text.substring('aws '.length, text.length);
        if (keyMessage(text, 'describe ec2 ')) {
            text = text.substring('describe ec2 '.length, text.length);
            if (keyMessage(text, 'instance ')) {
                AWS.checkEC2Instance(text.substring('instance '.length, text.length)).then(function (resp) {
                    rtm.sendMessage(resp, message.channel);
                }, function (err) {
                    rtm.sendMessage('Looks like there was a problem processing your request', message.channel);
                    console.log(err);
                });
            } else {
                AWS.checkEC2().then(function (resp) {
                    rtm.sendMessage(resp, message.channel);
                }, function (err) {
                    rtm.sendMessage('Looks like there was a problem processing your request', message.channel);
                    console.log(err);
                });
            }
        } else if (keyMessage(text, 'check number of instances ')) {
            AWS.checkNumInstances().then(function (resp) {
                rtm.sendMessage(resp, message.channel);
            }, function (err) {
                rtm.sendMessage('Looks like there was a problem processing your request', message.channel);
                console.log(err);
            });
        } else {
            rtm.sendMessage("I'm sorry, this isn't an AWS command I'm familiar with.", message.channel);
        }
    } else {
        rtm.sendMessage("I'm sorry, this isn't a command I'm familiar with.", message.channel);
    }
}

/*******************************************************************************
 * Helper functions
 */

function keyMessage(text, key) {
    var temptext = text + ' ';
    if (temptext.length >= key.length && temptext.substring(0, key.length).toLowerCase() === key) {
        return true;
    }
    return false;
}

/*******************************************************************************
 * Test stuff
 */
/*
Sample inputs:
aws describe ec2 instance i-0a681657adec3b3ee
aws describe ec2
 */
var mockRTM = function() {
    var readline = require('readline');
    var rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout
    });

    process.stdout.write("Please input your test message text: ");
    rl.on('line', function (line) {
        var message = {
            'text': line,
            'channel': 3
        };

        // mocking rtm
        rtm = {};
        rtm.sendMessage = function(message, channel) {
            console.log('----------Response message----------');
            console.log('Text: ' + message);
            console.log('Channel: ' + channel);
        }

        // run the test
        handleRtmMessage(message);
    });
}

/*******************************************************************************
 * main()
 */

var main = function() {
    var rtm = new RtmClient(token);
    rtm.start();

    rtm.on(RTM_EVENTS.MESSAGE, handleRtmMessage);

    rtm.on(RTM_EVENTS.REACTION_ADDED, function handleRtmReactionAdded(reaction) {
        console.log('Reaction added:', reaction);
    });

    rtm.on(RTM_EVENTS.REACTION_REMOVED, function handleRtmReactionRemoved(reaction) {
        console.log('Reaction removed:', reaction);
    });
}

if (DEBUG) {
    mockRTM();
} else {
    main();
}<|endoftext|>


<commit_before>/**
 * @module Dat
 * @private
 * @mixin
 * @description Exports Dat class.
 */

import Super from './Super';
import Num from './Number';
import Str from './String';
import { switcher } from './Switcher';
import constructors from './constants/constructors';
import formats from './constants/formats';
import { isDate, iterate } from './helpers';

/**
 * @typedef {'c'|'s'|'m'|'h'|'d'|'w'|'M'|'y'} Period
 * @public
 */

/**
 * @typedef {'ccc'|'c'|'ss'|'s'|'mm'|'m'|'hh'|'h'|'dddd'|'ddd'|'dd'|'d'|'MMMM'|'MMM'|'MM'|'M'|'yyyy'|'yy'|'y'} Format
 * @public
 */

const coeffs = {
	c: 1,
	s: 1000,
	m: 60000,
	h: 3600000,
	d: 86400000,
	w: 604800000,
	M: 2592000000,
	y: 31536000000
};
const daysOfTheWeekNames = [
	'Sunday',
	'Monday',
	'Tuesday',
	'Wednesday',
	'Thursday',
	'Friday',
	'Saturday'
];
const daysOfTheWeekAliases = new Super(daysOfTheWeekNames).map((value) => value.slice(0, 3)).$;
const monthsNames = [
	'January',
	'February',
	'March',
	'April',
	'May',
	'June',
	'Jule',
	'August',
	'September',
	'October',
	'November',
	'December'
];
const monthsAliases = new Super(monthsNames).map((value) => value.slice(0, 3)).$;

export class Dat extends Super {
  /**
   * @class Dat
   * @extends Super
   * @public
   * @param {Date} [date = new Date()] - A date to wrap.
   * @returns {Dat} Instance of Dat.
   * @description Wrap of a date.
   *
   * @example
   * const date = new Dat(new Date());
   */
  constructor(date = new Date()) {
		super(date);

    /**
     * @member {Date} Dat#$
     * @public
     * @description Original date.
     */
  }

  /**
   * @method Dat#add
   * @public
   * @param {Period|Object.<Period, Number>} what - What to add.
   * @param {Number} [number] - Number of what to add if the first argument is a period string.
   * @returns {Dat} New instance of Dat.
   * @description Method for adding amounts of time to the date. Returns new instance of Dat.
   *
   * @example
   * new Dat(new Date('1999-12-31T23:59:59.999Z')).add('c', 2).toISOString();         // '2000-01-01T00:00:00.001Z'
   * new Dat(new Date('1999-12-31T23:59:59.999Z')).add({ c: 2, d: 5 }).toISOString(); // '2000-01-06T00:00:00.001Z'
   */
	add(what, number) {
		const date = this.$;

		if (isInvalid(date)) {
			return invalidDate();
		}

		if (arguments.length >= 2) {
			what = { [what]: number };
		}

		what = new Super(what).$;

		let increment = 0;

		for (const key in what) {
			if (what.hasOwnProperty(key)) {
				const coeff = coeffs[key];

				if (!coeff) {
					return invalidDate();
				}

				increment += coeff * what[key];
			}
		}

		date.setTime(date.getTime() + increment);

    return this;
	}

  /**
   * @method Dat#expires
   * @public
   * @param {*} value - Value to resolve after the date expires.
   * @returns {Promise} New instance of Promise.
   * @description Method for defining when the date expires.
   *
   * @example
   * new Dat().add('c', 500).expires('Expired').then((value) => {
   *   // After 500 milliseconds
   *   console.log(value); // 'Expired'
   * });
   */
	expires(value) {
		return new Num(this.$ - now()).timeout(value);
	}

  /**
   * @method Dat#format
   * @public
   * @param {String} string - Template for the output.
   * @param {String} [prefix = ''] - If needed [all special strings]{@link Format}
   * are treated as they should be prefix with prefix.
   * @returns {String} Formatted string.
   * @description Method for creating formatted output based on a string.
   *
   * @example
   * new Dat('1999-12-31T23:59:59.999Z').format('Seconds: $ss, milliseconds: $ccc.', '$');
   * // 'Seconds: 59, milliseconds: 999.'
   */
	format(string, prefix = '') {
		string = new Str(new Super(string).$);
		prefix = String(new Super(prefix).$);

    iterate(formats, (format) => {
      string = string.replaceString(prefix + format.format, format.match(this, 'get'));
    });

		return string.$;
	}

  /**
   * @method Dat#formatUTC
   * @public
   * @param {String} string - See {@link Dat#format}.
   * @param {String} [prefix = ''] - See {@link Dat#format}.
   * @returns {String} Formatted string.
   * @description UTC version of {@link Dat#format}.
   *
   * @example
   * new Dat('1999-07-07T03:09:09.099Z').formatUTC(
   *   `
   *     Milliseconds: $ccc|$c.
   *     Seconds:      $ss|$s.
   *     Minutes:      $mm|$m.
   *     Hours:        $hh|$h.
   *     Day:          $dddd|$ddd|$dd|$d.
   *     Month:        $MMMM|$MMM|$MM|$M.
   *     Year:         $yyyy|$yy|$y.
   *   `,
   *   '$'
   * );
   * // Milliseconds: 099|99.
   * // Seconds:      09|9.
   * // Minutes:      09|9.
   * // Hours:        03|3.
   * // Day:          Friday|Fri|07|7.
   * // Month:        July|Jul|07|7.
   * // Year:         1999|99|1999.
   */
	formatUTC(string, prefix = '') {
		string = new Str(new Super(string).$);
		prefix = String(new Super(prefix).$);

    iterate(formats, (format) => {
      string = string.replaceString(prefix + format.format, format.match(this, 'getUTC'));
    });

		return string.$;
	}
	get(what) {
		const date = this.$;

    return switcher(what, {
      c: date.getMilliseconds(),
      s: date.getSeconds(),
      m: date.getMinutes(),
      h: date.getHours(),
      d: date.getDate(),
      dw: date.getDay(),
      dwa: daysOfTheWeekAliases[date.getDay()],
      dwn: daysOfTheWeekNames[date.getDay()],
      M: date.getMonth() + 1,
      Ma: monthsAliases[date.getMonth()],
      Mn: monthsNames[date.getMonth()],
      y: date.getFullYear()
    });
	}
	getUTC(what) {
		const date = this.$;

    return switcher(what, {
      c: date.getUTCMilliseconds(),
      s: date.getUTCSeconds(),
      m: date.getUTCMinutes(),
      h: date.getUTCHours(),
      d: date.getUTCDate(),
      dw: date.getUTCDay(),
      dwa: daysOfTheWeekAliases[date.getUTCDay()],
      dwn: daysOfTheWeekNames[date.getUTCDay()],
      M: date.getUTCMonth() + 1,
      Ma: monthsAliases[date.getUTCMonth()],
      Mn: monthsNames[date.getUTCMonth()],
      y: date.getUTCFullYear()
    });
	}
	isAfter(date) {
		date = new Date(new Super(date).$);

		return date.getTime() < this.$.getTime();
	}
	isBefore(date) {
		date = new Date(new Super(date).$);

		return date.getTime() > this.$.getTime();
	}
  isBetween(date1, date2) {
    const time = this.$.getTime();

    date1 = new Date(new Super(date1).$);
    date2 = new Date(new Super(date2).$);

    return time > date1.getTime() && time < date2.getTime();
  }
	isInvalid() {
		return isInvalid(this.$);
	}
	isPassed() {
		return now() > this.$.getTime();
	}
	ofOne(what, secondDate) {
    if (!(what in coeffs) || what === 'w') {
      return false;
    }

		secondDate = date(secondDate);

    let started;

    return iterate(coeffs, (coeff, w) => {
      if (w === what) {
        started = true;
      }

      if (!started || w === 'w') {
        return;
      }

      if (started && this.get(w) !== secondDate.get(w)) {
        return false;
      }
    }) !== false;
	}
	set(what, number) {
		const date = this.$;

		if (isInvalid(date)) {
			return this;
		}

		if (arguments.length >= 2) {
			what = { [what]: number };
		}

		what = new Super(what).$;

    iterate(what, (value, what) => {
      switch (what) {
        case 'c':
          date.setMilliseconds(value);
          return;
        case 's':
          date.setSeconds(value);
          return;
        case 'm':
          date.setMinutes(value);
          return;
        case 'h':
          date.setHours(value);
          return;
        case 'd':
          date.setDate(value);
          return;
        case 'M':
          date.setMonth(value - 1);
          return;
        case 'y':
          date.setFullYear(value);
      }
    });

		return this;
	}
	setUTC(what, number) {
		const date = this.$;

		if (isInvalid(date)) {
			return this;
		}

		if (arguments.length >= 2) {
			what = { [what]: number };
		}

		what = new Super(what).$;

    iterate(what, (value, what) => {
      switch (what) {
        case 'c':
          date.setUTCMilliseconds(value);
          return;
        case 's':
          date.setUTCSeconds(value);
          return;
        case 'm':
          date.setUTCMinutes(value);
          return;
        case 'h':
          date.setUTCHours(value);
          return;
        case 'd':
          date.setUTCDate(value);
          return;
        case 'M':
          date.setUTCMonth(value - 1);
          return;
        case 'y':
          date.setUTCFullYear(value);
      }
    });

		return this;
	}
	time(time) {
		const date = this.$;

		if (arguments.length) {
			date.setTime(time);
		}

		return date.getTime();
	}
  toISOString() {
    return this.$.toISOString();
  }
	toLocaleString() {
		return this.$.toLocaleString();
	}
	toString() {
		return this.$.toString();
	}
	valueOf() {
		return this.$.valueOf();
	}
}

function invalidDate() {
	return date('a');
}
function isInvalid(date) {
	return date.toString() === 'Invalid Date';
}

constructors[1].push({
	check: isDate,
	cls: Dat
});

export function now() {
  return Date.now();
}

export function date(date) {
  if (!arguments.length) {
    return new Dat(new Date());
  }

  date = new Super(date).$;

  return new Dat(new Date(date));
}

export default Dat;
<commit_msg>Date: finish up jsdoc.<commit_after>/**
 * @module Dat
 * @private
 * @mixin
 * @description Exports Dat class.
 */

import Super from './Super';
import Num from './Number';
import Str from './String';
import { switcher } from './Switcher';
import constructors from './constants/constructors';
import formats from './constants/formats';
import { isDate, iterate, supportSymbol, defineProperties } from './helpers';

/**
 * @typedef {*} DateLike
 * @public
 */

/**
 * @typedef {'c'|'s'|'m'|'h'|'d'|'w'|'M'|'y'} AddPeriod
 * @public
 */

/**
 * @typedef {'c'|'s'|'m'|'h'|'d'|'dw'|'M'|'y'} GetPeriod
 * @public
 */

/**
 * @typedef {'c'|'s'|'m'|'h'|'d'|'M'|'y'} OfOnePeriod
 * @public
 */

/**
 * @typedef {'c'|'s'|'m'|'h'|'d'|'M'|'y'} SetPeriod
 * @public
 */

/**
 * @typedef {'ccc'|'c'|'ss'|'s'|'mm'|'m'|'hh'|'h'|'dddd'|'ddd'|'dd'|'d'|'MMMM'|'MMM'|'MM'|'M'|'yyyy'|'yy'|'y'} Format
 * @public
 */

const coeffs = {
	c: 1,
	s: 1000,
	m: 60000,
	h: 3600000,
	d: 86400000,
	w: 604800000,
	M: 2592000000,
	y: 31536000000
};

export class Dat extends Super {
  /**
   * @class Dat
   * @extends Super
   * @public
   * @param {Date} [date = new Date()] - A date to wrap.
   * @returns {Dat} Instance of Dat.
   * @description Wrap of a date.
   *
   * @example
   * const date = new Dat(new Date());
   */
  constructor(date = new Date()) {
		super(date);

    /**
     * @member {Date} Dat#$
     * @public
     * @description Original date.
     */
  }

  /**
   * @method Dat#add
   * @public
   * @param {AddPeriod|Object.<AddPeriod, Number>} what - What to add.
   * @param {Number} [number] - Number of what to add if the first argument is a period string.
   * @returns {Dat} Returns this.
   * @description Method for adding amounts of time to the date. Returns new instance of Dat.
   *
   * @example
   * new Dat(new Date('1999-12-31T23:59:59.999Z')).add('c', 2).toISOString();         // '2000-01-01T00:00:00.001Z'
   * new Dat(new Date('1999-12-31T23:59:59.999Z')).add({ c: 2, d: 5 }).toISOString(); // '2000-01-06T00:00:00.001Z'
   */
	add(what, number) {
		if (arguments.length >= 2) {
			what = { [what]: number };
		}

    return this.time(this.time() + new Super(what).sum((value, what) => coeffs[what] * value));
	}

  /**
   * @method Dat#expires
   * @public
   * @param {*} value - Value to resolve after the date expires.
   * @returns {Promise} New instance of Promise.
   * @description Method for defining when the date expires.
   *
   * @example
   * new Dat().add('c', 500).expires('Expired').then((value) => {
   *   // After 500 milliseconds
   *   console.log(value); // 'Expired'
   * });
   */
	expires(value) {
		return new Num(this.$ - now()).timeout(value);
	}

  /**
   * @method Dat#format
   * @public
   * @param {String} string - Template for the output.
   * @param {String} [prefix = ''] - If needed [all special strings]{@link Format}
   * are treated as they should be prefix with prefix.
   * @returns {String} Formatted string.
   * @description Method for creating formatted output based on a string.
   *
   * @example
   * new Dat('1999-12-31T23:59:59.999Z').format('Seconds: $ss, milliseconds: $ccc.', '$');
   * // 'Seconds: 59, milliseconds: 999.'
   */
	format(string, prefix = '') {
		string = new Str(new Super(string).$);
		prefix = String(new Super(prefix).$);

    iterate(formats, (format) => {
      string = string.replaceString(prefix + format.format, format.match(this, 'get'));
    });

		return string.$;
	}

  /**
   * @method Dat#formatUTC
   * @public
   * @param {String} string - See {@link Dat#format}.
   * @param {String} [prefix = ''] - See {@link Dat#format}.
   * @returns {String} Formatted string.
   * @description UTC version of {@link Dat#format}.
   *
   * @example
   * new Dat('1999-07-07T03:09:09.099Z').formatUTC(
   *   `
   *     Milliseconds: $ccc|$c.
   *     Seconds:      $ss|$s.
   *     Minutes:      $mm|$m.
   *     Hours:        $hh|$h.
   *     Day:          $dddd|$ddd|$dd|$d.
   *     Month:        $MMMM|$MMM|$MM|$M.
   *     Year:         $yyyy|$yy|$y.
   *   `,
   *   '$'
   * );
   * // Milliseconds: 099|99.
   * // Seconds:      09|9.
   * // Minutes:      09|9.
   * // Hours:        03|3.
   * // Day:          Friday|Fri|07|7.
   * // Month:        July|Jul|07|7.
   * // Year:         1999|99|1999.
   */
	formatUTC(string, prefix = '') {
		string = new Str(new Super(string).$);
		prefix = String(new Super(prefix).$);

    iterate(formats, (format) => {
      string = string.replaceString(prefix + format.format, format.match(this, 'getUTC'));
    });

		return string.$;
	}

  /**
   * @method Dat#get
   * @public
   * @param {GetPeriod} what - What to get.
   * @returns {Number} Number of what to get.
   * @description Method for getting values such as seconds or minutes.
   *
   * @example
   * new Dat(new Date('1999-12-31T23:59:59.999Z')).get('s'); // 59
   */
	get(what) {
    return getSwitcher(what, [this.$, 'get']);
	}

  /**
   * @method Dat#getUTC
   * @public
   * @param {GetPeriod} what - See {@link Dat#get}.
   * @returns {Number} Number of what to get.
   * @description UTC version of {@link Dat#get}.
   *
   * @example
   * const date = new Dat(new Date('1999-12-31T23:59:59.999Z'));
   *
   * date.getUTC('c');  // 999
   * date.getUTC('s');  // 59
   * date.getUTC('m');  // 59
   * date.getUTC('h');  // 23
   * date.getUTC('d');  // 31
   * date.getUTC('dw'); // 5
   * date.getUTC('M');  // 12
   * date.getUTC('y');  // 1999
   */
	getUTC(what) {
    return getSwitcher(what, [this.$, 'getUTC']);
	}

  /**
   * @method Dat#isAfter
   * @public
   * @param {DateLike} date - Date to be compared to this date.
   * @returns {Boolean} If this date is after the argument one.
   * @description Finds out if this date is after the argument one.
   *
   * @example
   * new Dat(new Date(333)).isAfter(new Date(334)); // false
   * new Dat(new Date(333)).isAfter(new Date(332)); // true
   */
	isAfter(date) {
		date = new Date(new Super(date).$);

		return date.getTime() < this.$.getTime();
	}

  /**
   * @method Dat#isBefore
   * @public
   * @param {DateLike} date - Date to be compared to this date.
   * @returns {Boolean} If this date is before the argument one.
   * @description Finds out if this date is before the argument one.
   *
   * @example
   * new Dat(new Date(333)).isBefore(new Date(334)); // true
   * new Dat(new Date(333)).isBefore(new Date(332)); // false
   */
  isBefore(date) {
		date = new Date(new Super(date).$);

		return date.getTime() > this.$.getTime();
	}

  /**
   * @method Dat#isBetween
   * @public
   * @param {DateLike} date1 - Start of the range.
   * @param {DateLike} date2 - End of the range.
   * @returns {Boolean} If this date is after date1 and before date2.
   * @description Finds out if this date is after date1 and before date2.
   *
   * @example
   * new Dat(new Date(333)).isBetween(new Date(332), new Date(334)); // true
   * new Dat(new Date(333)).isBetween(new Date(334), new Date(332)); // false
   */
  isBetween(date1, date2) {
    const time = this.$.getTime();

    date1 = new Date(new Super(date1).$);
    date2 = new Date(new Super(date2).$);

    return time > date1.getTime() && time < date2.getTime();
  }

  /**
   * @method Dat#isInvalid
   * @public
   * @returns {Boolean} If the date is invalid.
   * @description Returns if the date is invalid.
   *
   * @example
   * new Dat(new Date('a')).isInvalid(); // true
   * new Dat(new Date(1)).isInvalid();   // false
   */
	isInvalid() {
		return this.$.toString() === 'Invalid Date';
	}

  /**
   * @method Dat#isPassed
   * @public
   * @returns {Boolean} If the date is passed.
   * @description Returns if the date is passed.
   *
   * @example
   * new Dat(new Date(1)).isPassed(); // true
   */
	isPassed() {
    return this.isAfter(now());
	}

  /**
   * @method Dat#ofOne
   * @public
   * @param {OfOnePeriod} what - Period to check.
   * @param {DateLike} date - Date to check.
   * @returns {Boolean} If two dates are of one second, minute or something else.
   * @description Returns if two dates are of one second, minute or something else.
   *
   * @example
   * new Dat(new Date('1999-12-31T23:59:59.000Z')).ofOne('s', new Date(1999-12-31T23:59:59.333Z')); // true
   * new Dat(new Date('1999-12-31T23:59:59.000Z')).ofOne('s', new Date(1999-12-31T23:59:58.999Z')); // false
   */
	ofOne(what, date) {
    if (!(what in coeffs) || what === 'w') {
      return false;
    }

    date = new Dat(new Date(date));

    let started;

    return iterate(coeffs, (coeff, w) => {
      if (w === what) {
        started = true;
      }

      if (!started || w === 'w') {
        return;
      }

      if (started && this.get(w) !== date.get(w)) {
        return false;
      }
    }) !== false;
	}

  /**
   * @method Dat#set
   * @public
   * @param {SetPeriod|Object.<SetPeriod, Number>} what - What to add.
   * @param {Number} [number] - Number of what to set if the first argument is a period string.
   * @returns {Dat} Returns this.
   * @description Method for setting values such as seconds or minutes.
   *
   * @example
   * new Dat(new Date('1999-12-31T23:59:59.999Z')).set('s', 58).get('s');           // 58
   * new Dat(new Date('1999-12-31T23:59:59.999Z')).set({ c: 998, s: 58 }).get('c'); // 998
   */
	set(what, number) {
		const date = this.$;

		if (arguments.length >= 2) {
			what = { [what]: number };
		}

		what = new Super(what).$;

    iterate(what, (value, what) => {
      setSwitcher(what, [date, value, '']);
    });

		return this;
	}

  /**
   * @method Dat#setUTC
   * @public
   * @param {SetPeriod|Object.<SetPeriod, Number>} what - See {@link Dat#set}.
   * @param {Number} [number] - See {@link Dat#set}.
   * @returns {Dat} Returns this.
   * @description UTC version of {@link Dat#set}.
   *
   * @example
   * const date = new Dat(new Date('1999-12-31T23:59:59.999Z'));
   *
   * date.setUTC('ccc', 998).getUTC('ccc'); // 998
   * date.setUTC({
   *   s: 58,
   *   m: 58,
   *   h: 22
   * });
   *
   * date.getUTC('s'); // 58
   * date.getUTC('m'); // 58
   * date.getUTC('h'); // 23
   */
	setUTC(what, number) {
		const date = this.$;

		if (arguments.length >= 2) {
			what = { [what]: number };
		}

		what = new Super(what).$;

    iterate(what, (value, what) => {
      setSwitcher(what, [date, value, 'UTC']);
    });

		return this;
	}

  /**
   * @method Dat#setUTC
   * @public
   * @param {Number} [time] - Time to set.
   * @returns {Dat|Number} - If the time argument is present this is returned otherwise the time is returned.
   * @description Synonym for both
   * [Date#getTime]
   * {@link https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date/getTime} and
   * [Date#setTime]
   * {@link https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date/setTime}.
   */
	time(time) {
		const date = this.$;

		if (arguments.length) {
			date.setTime(time);
		}

		return date.getTime();
	}

  toISOString() {
    return this.$.toISOString();
  }

	toLocaleString() {
		return this.$.toLocaleString();
	}

	toString() {
		return this.$.toString();
	}

	valueOf() {
		return this.$.valueOf();
	}
}

if (supportSymbol) {
  defineProperties(Dat.prototype, {
    [Symbol.toStringTag]: 'Dat'
  });
}

const getSwitcher = switcher({
  c: (date, utc) => date[utc + 'Milliseconds'](),
  s: (date, utc) => date[utc + 'Seconds'](),
  m: (date, utc) => date[utc + 'Minutes'](),
  h: (date, utc) => date[utc + 'Hours'](),
  d: (date, utc) => date[utc + 'Date'](),
  dw: (date, utc) => date[utc + 'Day'](),
  M: (date, utc) => date[utc + 'Month']() + 1,
  y: (date, utc) => date[utc + 'FullYear']()
}, 'equals', NaN);
const setSwitcher = switcher({
  c: (date, value, utc) => date[utc + 'Milliseconds'](value),
  s: (date, value, utc) => date[utc + 'Seconds'](value),
  m: (date, value, utc) => date[utc + 'Minutes'](value),
  h: (date, value, utc) => date[utc + 'Hours'](value),
  d: (date, value, utc) => date[utc + 'Date'](value),
  M: (date, value, utc) => date[utc + 'Month'](value - 1),
  y: (date, value, utc) => date[utc + 'FullYear'](value)
});

constructors[1].push({
	check: isDate,
	cls: Dat
});

/**
 * @function now
 * @public
 * @returns {Number} Number of milliseconds.
 * @description Synonym for
 * [Date.now]
 * {@link https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date/now}.
 */
export function now() {
  return Date.now();
}

/**
 * @function date
 * @public
 * @param {DateLike} [date] - Date-like value.
 * @returns {Dat} New instance of Dat.
 * @description Synonym for new Dat(new Date(date));
 */
export function date(date) {
  if (!arguments.length) {
    return new Dat(new Date());
  }

  date = new Super(date).$;

  return new Dat(new Date(date));
}

export default Dat;
<|endoftext|>


<commit_before>/**
 * @name SIP
 * @namespace
 */
"use strict";

module.exports = function (environment) {

var pkg = require('../package.json');

var SIP = Object.defineProperties({}, {
  version: {
    get: function(){ return pkg.version; }
  },
  name: {
    get: function(){ return pkg.title; }
  }
});

require('./Utils')(SIP, environment);
SIP.LoggerFactory = require('./LoggerFactory')(environment.console);
SIP.EventEmitter = require('./EventEmitter')(environment.console);
SIP.C = require('./Constants')(SIP.name, SIP.version);
SIP.Exceptions = require('./Exceptions');
SIP.Timers = require('./Timers')(environment.timers);
SIP.Transport = environment.Transport(SIP, environment.WebSocket);
require('./Parser')(SIP);
require('./SIPMessage')(SIP);
require('./URI')(SIP);
require('./NameAddrHeader')(SIP);
require('./Transactions')(SIP);
require('./Dialogs')(SIP);
require('./RequestSender')(SIP);
require('./RegisterContext')(SIP);
SIP.MediaHandler = require('./MediaHandler')(SIP.EventEmitter);
require('./ClientContext')(SIP);
require('./ServerContext')(SIP);
require('./Session')(SIP, environment);
require('./Subscription')(SIP);
SIP.WebRTC = require('./WebRTC')(SIP, environment);
require('./UA')(SIP, environment);
SIP.Hacks = require('./Hacks')(SIP);
require('./SanityCheck')(SIP);
SIP.DigestAuthentication = require('./DigestAuthentication')(SIP.Utils);
SIP.Grammar = require('./Grammar')(SIP);

return SIP;
};
<commit_msg>remove pkg reference from function calls to allow garbage collection<commit_after>/**
 * @name SIP
 * @namespace
 */
"use strict";

module.exports = function (environment) {

var pkg = require('../package.json'),
    version = pkg.version,
    title = pkg.title;

var SIP = Object.defineProperties({}, {
  version: {
    get: function(){ return version; }
  },
  name: {
    get: function(){ return title; }
  }
});

require('./Utils')(SIP, environment);
SIP.LoggerFactory = require('./LoggerFactory')(environment.console);
SIP.EventEmitter = require('./EventEmitter')(environment.console);
SIP.C = require('./Constants')(SIP.name, SIP.version);
SIP.Exceptions = require('./Exceptions');
SIP.Timers = require('./Timers')(environment.timers);
SIP.Transport = environment.Transport(SIP, environment.WebSocket);
require('./Parser')(SIP);
require('./SIPMessage')(SIP);
require('./URI')(SIP);
require('./NameAddrHeader')(SIP);
require('./Transactions')(SIP);
require('./Dialogs')(SIP);
require('./RequestSender')(SIP);
require('./RegisterContext')(SIP);
SIP.MediaHandler = require('./MediaHandler')(SIP.EventEmitter);
require('./ClientContext')(SIP);
require('./ServerContext')(SIP);
require('./Session')(SIP, environment);
require('./Subscription')(SIP);
SIP.WebRTC = require('./WebRTC')(SIP, environment);
require('./UA')(SIP, environment);
SIP.Hacks = require('./Hacks')(SIP);
require('./SanityCheck')(SIP);
SIP.DigestAuthentication = require('./DigestAuthentication')(SIP.Utils);
SIP.Grammar = require('./Grammar')(SIP);

return SIP;
};
<|endoftext|>


<commit_before>/**
 * Calculation of option greeks.
 * @module greeks
 * @author Matt Loppatto
 * @copyright 2014 Matt Loppatto
 */

var bs = require("black-scholes");

/**
 * Standard normal density function.
 *
 * @private
 * @param {Number} x The value to calculate the standard normal density of
 * @returns {Number} The value of the standard normal density function at x
 */
function _stdNormDensity(x)
{
  return Math.pow(Math.E, -1 * Math.pow(x, 2) / 2) / Math.sqrt(2 * Math.PI);
}

/**
 * Calculates the delta of an option.
 *
 * @param {Number} s Current price of the underlying
 * @param {Number} k Strike price
 * @param {Number} t Time to experiation in years
 * @param {Number} v Volatility as a decimal
 * @param {Number} r Anual risk-free interest rate as a decimal
 * @param {String} callPut The type of option to be priced - "call" or "put"
 * @returns {Number} The delta of the option
 */
function getDelta(s, k, t, v, r, callPut)
{
  if(callPut === "call")
  {
    return _callDelta(s, k, t, v, r);
  }
  else // put
  {
    return _putDelta(s, k, t, v, r);
  }
}

/**
 * Calculates the delta of a call option.
 *
 * @private
 * @param {Number} s Current price of the underlying
 * @param {Number} k Strike price
 * @param {Number} t Time to experiation in years
 * @param {Number} v Volatility as a decimal
 * @param {Number} r Anual risk-free interest rate as a decimal
 * @returns {Number} The delta of the call option
 */
function _callDelta(s, k, t, v, r)
{
  var w = bs.getW(s, k, t, v, r);
  return bs.stdNormCDF(w);
}

/**
 * Calculates the delta of a put option.
 *
 * @private
 * @param {Number} s Current price of the underlying
 * @param {Number} k Strike price
 * @param {Number} t Time to experiation in years
 * @param {Number} v Volatility as a decimal
 * @param {Number} r Anual risk-free interest rate as a decimal
 * @returns {Number} The delta of the put option
 */
function _putDelta(s, k, t, v, r)
{
  return 1 - callDelta(s, k, t, v, r);
}

/**
 * Calculates the rho of a call option.
 *
 * @private
 * @param {Number} s Current price of the underlying
 * @param {Number} k Strike price
 * @param {Number} t Time to experiation in years
 * @param {Number} v Volatility as a decimal
 * @param {Number} r Anual risk-free interest rate as a decimal
 * @returns {Number} The rho of the call option
 */
function _callRho(s, k, t, v, r)
{
  return k * t * Math.pow(Math.E, -1 * r * t) * bs.stdNormCDF(bs.getW(s, k, t, v, r) - v * Math.sqrt(t));
}

/**
 * Calculates the vega of a call option.
 *
 * @private
 * @param {Number} s Current price of the underlying
 * @param {Number} k Strike price
 * @param {Number} t Time to experiation in years
 * @param {Number} v Volatility as a decimal
 * @param {Number} r Anual risk-free interest rate as a decimal
 * @returns {Number} The vega of the call option
 */
function _callVega(s, k, t, v, r)
{
  return s * Math.sqrt(t) * _stdNormDensity(bs.getW(s, k, t, v, r));
}

/**
 * Calculates the theta of a call option.
 *
 * @private
 * @param {Number} s Current price of the underlying
 * @param {Number} k Strike price
 * @param {Number} t Time to experiation in years
 * @param {Number} v Volatility as a decimal
 * @param {Number} r Anual risk-free interest rate as a decimal
 * @returns {Number} The theta of the call option
 */
function _callTheta(s, k, t, v, r)
{
  var w = bs.getW(s, k, t, v, r);
  return v * s * _stdNormDensity(w) / (2 * Math.sqrt(t)) + k * r * Math.pow(Math.E, -1 * r * t) * bs.stdNormCDF(w - v * Math.sqrt(t));
}
<commit_msg>added module exports<commit_after>/**
 * Calculation of option greeks.
 * @module greeks
 * @author Matt Loppatto
 * @copyright 2014 Matt Loppatto
 */

var bs = require("black-scholes");

/**
 * Standard normal density function.
 *
 * @private
 * @param {Number} x The value to calculate the standard normal density of
 * @returns {Number} The value of the standard normal density function at x
 */
function _stdNormDensity(x)
{
  return Math.pow(Math.E, -1 * Math.pow(x, 2) / 2) / Math.sqrt(2 * Math.PI);
}

/**
 * Calculates the delta of an option.
 *
 * @param {Number} s Current price of the underlying
 * @param {Number} k Strike price
 * @param {Number} t Time to experiation in years
 * @param {Number} v Volatility as a decimal
 * @param {Number} r Anual risk-free interest rate as a decimal
 * @param {String} callPut The type of option to be priced - "call" or "put"
 * @returns {Number} The delta of the option
 */
function getDelta(s, k, t, v, r, callPut)
{
  if(callPut === "call")
  {
    return _callDelta(s, k, t, v, r);
  }
  else // put
  {
    return _putDelta(s, k, t, v, r);
  }
}

/**
 * Calculates the delta of a call option.
 *
 * @private
 * @param {Number} s Current price of the underlying
 * @param {Number} k Strike price
 * @param {Number} t Time to experiation in years
 * @param {Number} v Volatility as a decimal
 * @param {Number} r Anual risk-free interest rate as a decimal
 * @returns {Number} The delta of the call option
 */
function _callDelta(s, k, t, v, r)
{
  var w = bs.getW(s, k, t, v, r);
  return bs.stdNormCDF(w);
}

/**
 * Calculates the delta of a put option.
 *
 * @private
 * @param {Number} s Current price of the underlying
 * @param {Number} k Strike price
 * @param {Number} t Time to experiation in years
 * @param {Number} v Volatility as a decimal
 * @param {Number} r Anual risk-free interest rate as a decimal
 * @returns {Number} The delta of the put option
 */
function _putDelta(s, k, t, v, r)
{
  return 1 - callDelta(s, k, t, v, r);
}

/**
 * Calculates the rho of a call option.
 *
 * @private
 * @param {Number} s Current price of the underlying
 * @param {Number} k Strike price
 * @param {Number} t Time to experiation in years
 * @param {Number} v Volatility as a decimal
 * @param {Number} r Anual risk-free interest rate as a decimal
 * @returns {Number} The rho of the call option
 */
function _callRho(s, k, t, v, r)
{
  return k * t * Math.pow(Math.E, -1 * r * t) * bs.stdNormCDF(bs.getW(s, k, t, v, r) - v * Math.sqrt(t));
}

/**
 * Calculates the vega of a call option.
 *
 * @private
 * @param {Number} s Current price of the underlying
 * @param {Number} k Strike price
 * @param {Number} t Time to experiation in years
 * @param {Number} v Volatility as a decimal
 * @param {Number} r Anual risk-free interest rate as a decimal
 * @returns {Number} The vega of the call option
 */
function _callVega(s, k, t, v, r)
{
  return s * Math.sqrt(t) * _stdNormDensity(bs.getW(s, k, t, v, r));
}

/**
 * Calculates the theta of a call option.
 *
 * @private
 * @param {Number} s Current price of the underlying
 * @param {Number} k Strike price
 * @param {Number} t Time to experiation in years
 * @param {Number} v Volatility as a decimal
 * @param {Number} r Anual risk-free interest rate as a decimal
 * @returns {Number} The theta of the call option
 */
function _callTheta(s, k, t, v, r)
{
  var w = bs.getW(s, k, t, v, r);
  return v * s * _stdNormDensity(w) / (2 * Math.sqrt(t)) + k * r * Math.pow(Math.E, -1 * r * t) * bs.stdNormCDF(w - v * Math.sqrt(t));
}

module.exports = {
  getDelta: getDelta
};
<|endoftext|>


<commit_before>/* Module for Game Closure Devkit to handle loading screen
 * This module makes use of StackView signals.
 *
 * Authors: Jishnu Mohan <jishnu7@gmail.com>,
 *
 * Copyright: 2014, Hashcube (http://hashcube.com)
 *
 */

/* global console, loader, _, setTimeout, test */
/* jshint ignore:start */
import ui.resource.Image as Image;
import ui.ImageView as ImageView;
import ui.resource.loader as loader;

import util.underscore as _;

import .history as history;
import .test as test;
/* jshint ignore:end */

exports = (function() {
  'use strict';

  var obj = {},
    debug = false,
    loading = false,
    log = function(msg) {
      if(debug) {
        console.log('loading:', msg);
      }
    },
    // folders to pre-load
    folders,
    view;

  obj.initialize = function (view_obj, folders_obj) {
    view = view_obj;
    folders = folders_obj ? folders_obj : {};

    test.prepare(this, {
      view: view,
      folders: folders
    });
  };

  // method to show loading screen
  obj.show = function(parent, preload, callback) {
    if (!view) {
      return false;
    }
    view.updateOpts({
      superview: parent,
      visible: true
    });

    if(preload && _.has(folders, preload)) {
      log('preload ' + preload);
      loading = true;
      loader.preload(folders[preload], function() {
        loading = false;
      });
    } else {
      log('no preload');
      loading = false;
    }

    // method to hide loading screen
    parent.once('ViewDidDisappear', this.hide);

    if(callback) {
      _.defer(_.bind(callback, parent));
    }
  };

  // No need to call this, unless you want to hide manually.
  obj.hide = function() {
    if (!view) {
      return false;
    }
    // if images are still loading, call this function again
    if(loading === true) {
      log('flag is ' + loading);
      setTimeout(obj.hide, 1);
      return;
    }

    log('flag is ' + loading);
    view.removeFromSuperview();
    view.updateOpts({
      visible: false
    });
  };

  return obj;
})();
<commit_msg>Added author name<commit_after>/* Module for Game Closure Devkit to handle loading screen
 * This module makes use of StackView signals.
 *
 * Authors: Jishnu Mohan <jishnu7@gmail.com>, Bijosh T J <bijoshtj@gmail.com>
 *
 * Copyright: 2014, Hashcube (http://hashcube.com)
 *
 */

/* global console, loader, _, setTimeout, test */
/* jshint ignore:start */
import ui.resource.Image as Image;
import ui.ImageView as ImageView;
import ui.resource.loader as loader;

import util.underscore as _;

import .history as history;
import .test as test;
/* jshint ignore:end */

exports = (function() {
  'use strict';

  var obj = {},
    debug = false,
    loading = false,
    log = function(msg) {
      if(debug) {
        console.log('loading:', msg);
      }
    },
    // folders to pre-load
    folders,
    view;

  obj.initialize = function (view_obj, folders_obj) {
    view = view_obj;
    folders = folders_obj ? folders_obj : {};

    test.prepare(this, {
      view: view,
      folders: folders
    });
  };

  // method to show loading screen
  obj.show = function(parent, preload, callback) {
    if (!view) {
      return false;
    }
    view.updateOpts({
      superview: parent,
      visible: true
    });

    if(preload && _.has(folders, preload)) {
      log('preload ' + preload);
      loading = true;
      loader.preload(folders[preload], function() {
        loading = false;
      });
    } else {
      log('no preload');
      loading = false;
    }

    // method to hide loading screen
    parent.once('ViewDidDisappear', this.hide);

    if(callback) {
      _.defer(_.bind(callback, parent));
    }
  };

  // No need to call this, unless you want to hide manually.
  obj.hide = function() {
    if (!view) {
      return false;
    }
    // if images are still loading, call this function again
    if(loading === true) {
      log('flag is ' + loading);
      setTimeout(obj.hide, 1);
      return;
    }

    log('flag is ' + loading);
    view.removeFromSuperview();
    view.updateOpts({
      visible: false
    });
  };

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


<commit_before>/*
 *
 *  Gis.js is released under the MIT license, which should be retained when including, utilising or developing Gis.js in any environment.
 *
 *  Original Creator: James Gould © 2017
 *
 */

/**
 * Utility functions for working with GIS data. Do not export, use internally.
 */
var Utils = {

    /**
     * Checks if the input is of a primitive value with no fractional parts.
     */
    isFloat: (value) => {
        return value === +n && n !== (n|0);
    }

}

/**
 * Contains utility functions for working with GIS data.
 *
 */
var Gis = {

    /**
     * Validates a (latitude, longitude) pair as being a valid float, and within the expected range of each respective value.
     */
    ValidLatLng: (latitude, longitude, callback) => {
        if(!Utils.isFloat(latitude) || !Utils.isFloat(longitude)) {
            if(typeof callback === undefined) {
                return false;
            } else {
                var err = new Error("Latitude/longitude pair is of an invalid datatype");
                return callback(err);
            }

        }
    },

}

/*
 * Export only Gis, do not release any local objects or functions (extracted or otherwise) used.
 */
module.exports = Gis;<commit_msg>Useless changes do not commit<commit_after>/*
 *
 *  Gis.js is released under the MIT license, which should be retained when including, utilising or developing Gis.js in any environment.
 *
 *  Original Creator: James Gould © 2017
 *
 */

/**
 * Utility functions for working with GIS data. Do not export, use internally.
 */
var Utils = {

    /**
     * Checks if the input is of a primitive value with no fractional parts.
     */
    isFloat: (value) => {
        return value === +n && n !== (n|0);
    }

}

/**
 * Contains utility functions for working with GIS data.
 *
 */
var Gis = {

    /**
     * Validates a (latitude, longitude) pair as being a valid float, and within the expected range of each respective value.
     */
    ValidLatLng: (latitude, longitude) => {
        if(!Utils.isFloat(latitude) || !Utils.isFloat(longitude)) {
            return false
        }

        return (latitude >= -90 && latitude <= 90) && (longitude >= -180 && longitude <= 180);
    },

}

/*
 * Export only Gis, do not release any local objects or functions (extracted or otherwise) used.
 */
module.exports = Gis;<|endoftext|>


<commit_before>/* Interface implementing TextReadStream */

var fs = require('fs');
var util = require('util');
var errors = require('./errors.js');
var q = require('q');
var EventEmitter = require('events').EventEmitter;
var VariableReadStream = require('./VariableReadStream.js');

/** */
function TextReadStream(file, opts) {
	var self = this;
	EventEmitter.call(self);
	opts = opts || {};
	self.delimiter = (opts.delimiter || '\n');
	opts.delimiter = self.delimiter.charCodeAt(0);
	self.internal = new VariableReadStream(file, opts);
}
util.inherits(TextReadStream, EventEmitter);

/** Internal builder for listeners */
function init_listeners(self) {
	self.internal.on('data', function(b, b_size) {
		// Emit data as utf8 strings
		var str = b.toString('utf8', 0, b_size);
		//console.error("DEBUG: Emitting data event with '" + str + "'");
		self.emit('data', str);
	});
	self.internal.on('end', function() {
		self.emit('end');
	});
	self.has_listeners = true;
}

/* Start reading */
TextReadStream.prototype.read = function(amount) {
	var self = this;
	if(!self.has_listeners) init_listeners(self);
	return self.internal.read(amount);
};

// Export as module
module.exports = TextReadStream;

/* EOF */
<commit_msg>Encoding can be selected as an option now<commit_after>/* Interface implementing TextReadStream */

var fs = require('fs');
var util = require('util');
var errors = require('./errors.js');
var q = require('q');
var EventEmitter = require('events').EventEmitter;
var VariableReadStream = require('./VariableReadStream.js');

/** */
function TextReadStream(file, opts) {
	var self = this;
	EventEmitter.call(self);
	opts = opts || {};
	self.encoding = opts.encoding || 'utf8';
	self.delimiter = (opts.delimiter || '\n');
	opts.delimiter = self.delimiter.charCodeAt(0);
	self.internal = new VariableReadStream(file, opts);
}
util.inherits(TextReadStream, EventEmitter);

/** Internal builder for listeners */
function init_listeners(self) {
	self.internal.on('data', function(b, b_size) {
		// Emit data as utf8 strings
		var str = b.toString(self.encoding || 'utf8', 0, b_size);
		//console.error("DEBUG: Emitting data event with '" + str + "'");
		self.emit('data', str);
	});
	self.internal.on('end', function() {
		self.emit('end');
	});
	self.has_listeners = true;
}

/* Start reading */
TextReadStream.prototype.read = function(amount) {
	var self = this;
	if(!self.has_listeners) init_listeners(self);
	return self.internal.read(amount);
};

// Export as module
module.exports = TextReadStream;

/* EOF */
<|endoftext|>


<commit_before>/*global collectionOptionNames, extendOptions, inheritVars */
var loadStart = 'load:start',
    loadEnd = 'load:end',
    rootObject;

Thorax.setRootObject = function(obj) {
  rootObject = obj;
};

Thorax.loadHandler = function(start, end) {
  return function(message, background, object) {
    var self = this;

    function startLoadTimeout() {
      clearTimeout(self._loadStart.timeout);
      self._loadStart.timeout = setTimeout(function() {
          try {
            self._loadStart.run = true;
            start.call(self, self._loadStart.message, self._loadStart.background, self._loadStart);
          } catch (e) {
            Thorax.onException('loadStart', e);
          }
        },
        loadingTimeout * 1000);
    }

    if (!self._loadStart) {
      var loadingTimeout = self._loadingTimeoutDuration;
      if (loadingTimeout === void 0) {
        // If we are running on a non-view object pull the default timeout
        loadingTimeout = Thorax.View.prototype._loadingTimeoutDuration;
      }

      self._loadStart = _.extend({
        events: [],
        timeout: 0,
        message: message,
        background: !!background
      }, Backbone.Events);
      startLoadTimeout();
    } else {
      clearTimeout(self._loadStart.endTimeout);

      self._loadStart.message = message;
      if (!background && self._loadStart.background) {
        self._loadStart.background = false;
        startLoadTimeout();
      }
    }

    self._loadStart.events.push(object);
    object.on(loadEnd, function endCallback() {
      object.off(loadEnd, endCallback);

      var loadingEndTimeout = self._loadingTimeoutEndDuration;
      if (loadingEndTimeout === void 0) {
        // If we are running on a non-view object pull the default timeout
        loadingEndTimeout = Thorax.View.prototype._loadingTimeoutEndDuration;
      }

      var events = self._loadStart.events,
          index = events.indexOf(object);
      if (index >= 0) {
        events.splice(index, 1);
      }
      if (!events.length) {
        self._loadStart.endTimeout = setTimeout(function() {
          try {
            if (!events.length) {
              var run = self._loadStart.run;

              if (run) {
                // Emit the end behavior, but only if there is a paired start
                end.call(self, self._loadStart.background, self._loadStart);
                self._loadStart.trigger(loadEnd, self._loadStart);
              }

              // If stopping make sure we don't run a start
              clearTimeout(self._loadStart.timeout);
              self._loadStart = undefined;
            }
          } catch (e) {
            Thorax.onException('loadEnd', e);
          }
        }, loadingEndTimeout * 1000);
      }
    });
  };
};

/**
 * Helper method for propagating load:start events to other objects.
 *
 * Forwards load:start events that occur on `source` to `dest`.
 */
Thorax.forwardLoadEvents = function(source, dest, once) {
  function load(message, backgound, object) {
    if (once) {
      source.off(loadStart, load);
    }
    dest.trigger(loadStart, message, backgound, object);
  }
  source.on(loadStart, load);
  return {
    off: function() {
      source.off(loadStart, load);
    }
  };
};

//
// Data load event generation
//

/**
 * Mixing for generating load:start and load:end events.
 */
Thorax.mixinLoadable = function(target, useParent) {
  _.extend(target, {
    //loading config
    _loadingClassName: 'loading',
    _loadingTimeoutDuration: 0.33,
    _loadingTimeoutEndDuration: 0.10,

    // Propagates loading view parameters to the AJAX layer
    onLoadStart: function(message, background, object) {
      var that = useParent ? this.parent : this;
      if (!that.nonBlockingLoad && !background && rootObject) {
        rootObject.trigger(loadStart, message, background, object);
      }
      $(that.el).addClass(that._loadingClassName);
      //used by loading helpers
      if (that._loadingCallbacks) {
        _.each(that._loadingCallbacks, function(callback) {
          callback();
        });
      }
    },
    onLoadEnd: function(/* background, object */) {
      var that = useParent ? this.parent : this;
      $(that.el).removeClass(that._loadingClassName);
      //used by loading helpers
      if (that._loadingCallbacks) {
        _.each(that._loadingCallbacks, function(callback) {
          callback();
        });
      }
    }
  });
};

Thorax.mixinLoadableEvents = function(target, useParent) {
  _.extend(target, {
    loadStart: function(message, background) {
      var that = useParent ? this.parent : this;
      that.trigger(loadStart, message, background, that);
    },
    loadEnd: function() {
      var that = useParent ? this.parent : this;
      that.trigger(loadEnd, that);
    }
  });
};

Thorax.mixinLoadable(Thorax.View.prototype);
Thorax.mixinLoadableEvents(Thorax.View.prototype);

Thorax.sync = function(method, dataObj, options) {
  var self = this,
      complete = options.complete;

  options.complete = function() {
    self._request = undefined;
    self._aborted = false;

    complete && complete.apply(this, arguments);
  };
  this._request = Backbone.sync.apply(this, arguments);

  return this._request;
};

function bindToRoute(callback, failback) {
  var fragment = Backbone.history.getFragment(),
      completed;

  function finalizer(isCanceled) {
    var same = fragment === Backbone.history.getFragment();

    if (completed) {
      // Prevent multiple execution, i.e. we were canceled but the success callback still runs
      return;
    }

    if (isCanceled && same) {
      // Ignore the first route event if we are running in newer versions of backbone
      // where the route operation is a postfix operation.
      return;
    }

    completed = true;
    Backbone.history.off('route', resetLoader);

    var args = Array.prototype.slice.call(arguments, 1);
    if (!isCanceled && same) {
      callback.apply(this, args);
    } else {
      failback && failback.apply(this, args);
    }
  }

  var resetLoader = _.bind(finalizer, this, true);
  Backbone.history.on('route', resetLoader);

  return _.bind(finalizer, this, false);
}

function loadData(callback, failback, options) {
  if (this.isPopulated()) {
    return callback(this);
  }

  if (arguments.length === 2 && typeof failback !== 'function' && _.isObject(failback)) {
    options = failback;
    failback = false;
  }

  this.fetch(_.defaults({
    success: bindToRoute(callback, failback && _.bind(failback, this, false)),
    error: failback && _.bind(failback, this, true)
  }, options));
}

function fetchQueue(options, $super) {
  if (options.resetQueue) {
    // WARN: Should ensure that loaders are protected from out of band data
    //    when using this option
    this.fetchQueue = undefined;
  }

  if (!this.fetchQueue) {
    // Kick off the request
    this.fetchQueue = [options];
    options = _.defaults({
      success: flushQueue(this, this.fetchQueue, 'success'),
      error: flushQueue(this, this.fetchQueue, 'error'),
      complete: flushQueue(this, this.fetchQueue, 'complete')
    }, options);
    $super.call(this, options);
  } else {
    // Currently fetching. Queue and process once complete
    this.fetchQueue.push(options);
  }
}

function flushQueue(self, fetchQueue, handler) {
  return function() {
    var args = arguments;

    // Flush the queue. Executes any callback handlers that
    // may have been passed in the fetch options.
    _.each(fetchQueue, function(options) {
      if (options[handler]) {
        options[handler].apply(this, args);
      }
    }, this);

    // Reset the queue if we are still the active request
    if (self.fetchQueue === fetchQueue) {
      self.fetchQueue = undefined;
    }
  };
}

var klasses = [];
Thorax.Model && klasses.push(Thorax.Model);
Thorax.Collection && klasses.push(Thorax.Collection);

_.each(klasses, function(DataClass) {
  var $fetch = DataClass.prototype.fetch;
  Thorax.mixinLoadableEvents(DataClass.prototype, false);
  _.extend(DataClass.prototype, {
    sync: Thorax.sync,

    fetch: function(options) {
      options = options || {};

      var self = this,
          complete = options.complete;

      options.complete = function() {
        complete && complete.apply(this, arguments);
        self.loadEnd();
      };
      self.loadStart(undefined, options.background);
      return fetchQueue.call(this, options || {}, $fetch);
    },

    load: function(callback, failback, options) {
      if (arguments.length === 2 && typeof failback !== 'function') {
        options = failback;
        failback = false;
      }
      options = options || {};
      if (!options.background && !this.isPopulated() && rootObject) {
        // Make sure that the global scope sees the proper load events here
        // if we are loading in standalone mode
        Thorax.forwardLoadEvents(this, rootObject, true);
      }

      var self = this;
      loadData.call(this, callback,
        function(isError) {
          // Route changed, kill it
          if (!isError) {
            if (self._request) {
              self._aborted = true;
              self._request.abort();
            }
          }

          failback && failback.apply && failback.apply(this, arguments);
        },
        options);
    }
  });
});

Thorax.Util.bindToRoute = bindToRoute;

if (Thorax.Router) {
  Thorax.Router.bindToRoute = Thorax.Router.prototype.bindToRoute = bindToRoute;
}

// Propagates loading view parameters to the AJAX layer
function loadingDataOptions() {
  return {
    ignoreErrors: this.ignoreFetchError,
    background: this.nonBlockingLoad
  };
}
extendOptions('_setModelOptions', loadingDataOptions);
extendOptions('_setCollectionOptions', loadingDataOptions);

inheritVars.collection.loading = function() {
  var loadingView = this.loadingView,
      loadingTemplate = this.loadingTemplate,
      loadingPlacement = this.loadingPlacement;
  //add "loading-view" and "loading-template" options to collection helper
  if (loadingView || loadingTemplate) {
    var callback = Thorax.loadHandler(_.bind(function() {
      var item;
      if (this.collection.length === 0) {
        this.$el.empty();
      }
      if (loadingView) {
        var instance = Thorax.Util.getViewInstance(loadingView, {
          collection: this.collection
        });
        this._addChild(instance);
        if (loadingTemplate) {
          instance.render(loadingTemplate);
        } else {
          instance.render();
        }
        item = instance;
      } else {
        item = this.renderTemplate(loadingTemplate, {
          collection: this.collection
        });
      }
      var index = loadingPlacement
        ? loadingPlacement.call(this)
        : this.collection.length
      ;
      this.appendItem(item, index);
      this.$el.children().eq(index).attr('data-loading-element', this.collection.cid);
    }, this), _.bind(function() {
      this.$el.find('[data-loading-element="' + this.collection.cid + '"]').remove();
    }, this));
    this.collection.on('load:start', callback);
    //TODO: figure out why listenTo will not work
    //this.listenTo(this.collection, 'load:start', callback);
  }
};

if (typeof collectionOptionNames !== 'undefined') {
  collectionOptionNames['loading-template'] = 'loadingTemplate';
  collectionOptionNames['loading-view'] = 'loadingView';
  collectionOptionNames['loading-placement'] = 'loadingPlacement';
}

Thorax.View.on({
  'load:start': Thorax.loadHandler(
      function(message, background, object) {
        this.onLoadStart(message, background, object);
      },
      function(background, object) {
        this.onLoadEnd(object);
      }),

  collection: {
    'load:start': function(message, background, object) {
      this.trigger(loadStart, message, background, object);
    }
  },
  model: {
    'load:start': function(message, background, object) {
      this.trigger(loadStart, message, background, object);
    }
  }
});
<commit_msg>Allow a context for loadHandler execution<commit_after>/*global collectionOptionNames, extendOptions, inheritVars */
var loadStart = 'load:start',
    loadEnd = 'load:end',
    rootObject;

Thorax.setRootObject = function(obj) {
  rootObject = obj;
};

Thorax.loadHandler = function(start, end, context) {
  return function(message, background, object) {
    var self = context || this;

    function startLoadTimeout() {
      clearTimeout(self._loadStart.timeout);
      self._loadStart.timeout = setTimeout(function() {
          try {
            self._loadStart.run = true;
            start.call(self, self._loadStart.message, self._loadStart.background, self._loadStart);
          } catch (e) {
            Thorax.onException('loadStart', e);
          }
        },
        loadingTimeout * 1000);
    }

    if (!self._loadStart) {
      var loadingTimeout = self._loadingTimeoutDuration;
      if (loadingTimeout === void 0) {
        // If we are running on a non-view object pull the default timeout
        loadingTimeout = Thorax.View.prototype._loadingTimeoutDuration;
      }

      self._loadStart = _.extend({
        events: [],
        timeout: 0,
        message: message,
        background: !!background
      }, Backbone.Events);
      startLoadTimeout();
    } else {
      clearTimeout(self._loadStart.endTimeout);

      self._loadStart.message = message;
      if (!background && self._loadStart.background) {
        self._loadStart.background = false;
        startLoadTimeout();
      }
    }

    self._loadStart.events.push(object);
    object.on(loadEnd, function endCallback() {
      object.off(loadEnd, endCallback);

      var loadingEndTimeout = self._loadingTimeoutEndDuration;
      if (loadingEndTimeout === void 0) {
        // If we are running on a non-view object pull the default timeout
        loadingEndTimeout = Thorax.View.prototype._loadingTimeoutEndDuration;
      }

      var events = self._loadStart.events,
          index = events.indexOf(object);
      if (index >= 0) {
        events.splice(index, 1);
      }
      if (!events.length) {
        self._loadStart.endTimeout = setTimeout(function() {
          try {
            if (!events.length) {
              var run = self._loadStart.run;

              if (run) {
                // Emit the end behavior, but only if there is a paired start
                end.call(self, self._loadStart.background, self._loadStart);
                self._loadStart.trigger(loadEnd, self._loadStart);
              }

              // If stopping make sure we don't run a start
              clearTimeout(self._loadStart.timeout);
              self._loadStart = undefined;
            }
          } catch (e) {
            Thorax.onException('loadEnd', e);
          }
        }, loadingEndTimeout * 1000);
      }
    });
  };
};

/**
 * Helper method for propagating load:start events to other objects.
 *
 * Forwards load:start events that occur on `source` to `dest`.
 */
Thorax.forwardLoadEvents = function(source, dest, once) {
  function load(message, backgound, object) {
    if (once) {
      source.off(loadStart, load);
    }
    dest.trigger(loadStart, message, backgound, object);
  }
  source.on(loadStart, load);
  return {
    off: function() {
      source.off(loadStart, load);
    }
  };
};

//
// Data load event generation
//

/**
 * Mixing for generating load:start and load:end events.
 */
Thorax.mixinLoadable = function(target, useParent) {
  _.extend(target, {
    //loading config
    _loadingClassName: 'loading',
    _loadingTimeoutDuration: 0.33,
    _loadingTimeoutEndDuration: 0.10,

    // Propagates loading view parameters to the AJAX layer
    onLoadStart: function(message, background, object) {
      var that = useParent ? this.parent : this;
      if (!that.nonBlockingLoad && !background && rootObject) {
        rootObject.trigger(loadStart, message, background, object);
      }
      $(that.el).addClass(that._loadingClassName);
      //used by loading helpers
      if (that._loadingCallbacks) {
        _.each(that._loadingCallbacks, function(callback) {
          callback();
        });
      }
    },
    onLoadEnd: function(/* background, object */) {
      var that = useParent ? this.parent : this;
      $(that.el).removeClass(that._loadingClassName);
      //used by loading helpers
      if (that._loadingCallbacks) {
        _.each(that._loadingCallbacks, function(callback) {
          callback();
        });
      }
    }
  });
};

Thorax.mixinLoadableEvents = function(target, useParent) {
  _.extend(target, {
    loadStart: function(message, background) {
      var that = useParent ? this.parent : this;
      that.trigger(loadStart, message, background, that);
    },
    loadEnd: function() {
      var that = useParent ? this.parent : this;
      that.trigger(loadEnd, that);
    }
  });
};

Thorax.mixinLoadable(Thorax.View.prototype);
Thorax.mixinLoadableEvents(Thorax.View.prototype);

Thorax.sync = function(method, dataObj, options) {
  var self = this,
      complete = options.complete;

  options.complete = function() {
    self._request = undefined;
    self._aborted = false;

    complete && complete.apply(this, arguments);
  };
  this._request = Backbone.sync.apply(this, arguments);

  return this._request;
};

function bindToRoute(callback, failback) {
  var fragment = Backbone.history.getFragment(),
      completed;

  function finalizer(isCanceled) {
    var same = fragment === Backbone.history.getFragment();

    if (completed) {
      // Prevent multiple execution, i.e. we were canceled but the success callback still runs
      return;
    }

    if (isCanceled && same) {
      // Ignore the first route event if we are running in newer versions of backbone
      // where the route operation is a postfix operation.
      return;
    }

    completed = true;
    Backbone.history.off('route', resetLoader);

    var args = Array.prototype.slice.call(arguments, 1);
    if (!isCanceled && same) {
      callback.apply(this, args);
    } else {
      failback && failback.apply(this, args);
    }
  }

  var resetLoader = _.bind(finalizer, this, true);
  Backbone.history.on('route', resetLoader);

  return _.bind(finalizer, this, false);
}

function loadData(callback, failback, options) {
  if (this.isPopulated()) {
    return callback(this);
  }

  if (arguments.length === 2 && typeof failback !== 'function' && _.isObject(failback)) {
    options = failback;
    failback = false;
  }

  this.fetch(_.defaults({
    success: bindToRoute(callback, failback && _.bind(failback, this, false)),
    error: failback && _.bind(failback, this, true)
  }, options));
}

function fetchQueue(options, $super) {
  if (options.resetQueue) {
    // WARN: Should ensure that loaders are protected from out of band data
    //    when using this option
    this.fetchQueue = undefined;
  }

  if (!this.fetchQueue) {
    // Kick off the request
    this.fetchQueue = [options];
    options = _.defaults({
      success: flushQueue(this, this.fetchQueue, 'success'),
      error: flushQueue(this, this.fetchQueue, 'error'),
      complete: flushQueue(this, this.fetchQueue, 'complete')
    }, options);
    $super.call(this, options);
  } else {
    // Currently fetching. Queue and process once complete
    this.fetchQueue.push(options);
  }
}

function flushQueue(self, fetchQueue, handler) {
  return function() {
    var args = arguments;

    // Flush the queue. Executes any callback handlers that
    // may have been passed in the fetch options.
    _.each(fetchQueue, function(options) {
      if (options[handler]) {
        options[handler].apply(this, args);
      }
    }, this);

    // Reset the queue if we are still the active request
    if (self.fetchQueue === fetchQueue) {
      self.fetchQueue = undefined;
    }
  };
}

var klasses = [];
Thorax.Model && klasses.push(Thorax.Model);
Thorax.Collection && klasses.push(Thorax.Collection);

_.each(klasses, function(DataClass) {
  var $fetch = DataClass.prototype.fetch;
  Thorax.mixinLoadableEvents(DataClass.prototype, false);
  _.extend(DataClass.prototype, {
    sync: Thorax.sync,

    fetch: function(options) {
      options = options || {};

      var self = this,
          complete = options.complete;

      options.complete = function() {
        complete && complete.apply(this, arguments);
        self.loadEnd();
      };
      self.loadStart(undefined, options.background);
      return fetchQueue.call(this, options || {}, $fetch);
    },

    load: function(callback, failback, options) {
      if (arguments.length === 2 && typeof failback !== 'function') {
        options = failback;
        failback = false;
      }
      options = options || {};
      if (!options.background && !this.isPopulated() && rootObject) {
        // Make sure that the global scope sees the proper load events here
        // if we are loading in standalone mode
        Thorax.forwardLoadEvents(this, rootObject, true);
      }

      var self = this;
      loadData.call(this, callback,
        function(isError) {
          // Route changed, kill it
          if (!isError) {
            if (self._request) {
              self._aborted = true;
              self._request.abort();
            }
          }

          failback && failback.apply && failback.apply(this, arguments);
        },
        options);
    }
  });
});

Thorax.Util.bindToRoute = bindToRoute;

if (Thorax.Router) {
  Thorax.Router.bindToRoute = Thorax.Router.prototype.bindToRoute = bindToRoute;
}

// Propagates loading view parameters to the AJAX layer
function loadingDataOptions() {
  return {
    ignoreErrors: this.ignoreFetchError,
    background: this.nonBlockingLoad
  };
}
extendOptions('_setModelOptions', loadingDataOptions);
extendOptions('_setCollectionOptions', loadingDataOptions);

inheritVars.collection.loading = function() {
  var loadingView = this.loadingView,
      loadingTemplate = this.loadingTemplate,
      loadingPlacement = this.loadingPlacement;
  //add "loading-view" and "loading-template" options to collection helper
  if (loadingView || loadingTemplate) {
    var callback = Thorax.loadHandler(_.bind(function() {
      var item;
      if (this.collection.length === 0) {
        this.$el.empty();
      }
      if (loadingView) {
        var instance = Thorax.Util.getViewInstance(loadingView, {
          collection: this.collection
        });
        this._addChild(instance);
        if (loadingTemplate) {
          instance.render(loadingTemplate);
        } else {
          instance.render();
        }
        item = instance;
      } else {
        item = this.renderTemplate(loadingTemplate, {
          collection: this.collection
        });
      }
      var index = loadingPlacement
        ? loadingPlacement.call(this)
        : this.collection.length
      ;
      this.appendItem(item, index);
      this.$el.children().eq(index).attr('data-loading-element', this.collection.cid);
    }, this), _.bind(function() {
      this.$el.find('[data-loading-element="' + this.collection.cid + '"]').remove();
    }, this));
    this.collection.on('load:start', callback);
    //TODO: figure out why listenTo will not work
    //this.listenTo(this.collection, 'load:start', callback);
  }
};

if (typeof collectionOptionNames !== 'undefined') {
  collectionOptionNames['loading-template'] = 'loadingTemplate';
  collectionOptionNames['loading-view'] = 'loadingView';
  collectionOptionNames['loading-placement'] = 'loadingPlacement';
}

Thorax.View.on({
  'load:start': Thorax.loadHandler(
      function(message, background, object) {
        this.onLoadStart(message, background, object);
      },
      function(background, object) {
        this.onLoadEnd(object);
      }),

  collection: {
    'load:start': function(message, background, object) {
      this.trigger(loadStart, message, background, object);
    }
  },
  model: {
    'load:start': function(message, background, object) {
      this.trigger(loadStart, message, background, object);
    }
  }
});
<|endoftext|>