<commit_before>/**
 * Swiper v1.0.1
 * @create Mar 17, 2015
 * @author David Wei
 * @see http://github.com/cdiwo/Swiper
 * Licensed under MIT
 * Released on: Mar 23, 2015
 */
(function () {
    'use strict';

    /*===========================
    Swiper
    ===========================*/
    function Swiper(container, params) {

        var defaults = {
            direction: 'horizental', // 方向
            speed: 300,// Css3 transition duration
            autoplay: false,// autoplay
            easing: 'ease',// Css3 animation timing function
            inertia: true,// 开启惯性滑动
            touchThreshold: 0.2,// 拖拽占比率，默认元素的1/5
            index: 0,// 初始下标
            wrapperClass: '.swiper-wrapper',
            itemClass: '.swiper-item',
            debug: false,
            /*
            Callbacks:
            onInit: function()
            onSlideMove: function (e)
            onSlideEnd: function(index)
            onSlideChanged: function(index)
            onEdgeLeft: function()
            onEdgeRight: function()
            onSwipeLeft: function()
            onSwipeRight: function()
            */
        }

        // Extend defaults with parameters
        var params = params || {};
        for (var param in params) {
            defaults[param] = params[param];
        }

        // Swiper
        var s = this;

        // Params
        s.params = defaults;

        // Define Container, Wrapper and Slide
        if(container === undefined) throw new Error('Invalid container!');
        s.container =  container === window ? $(window) : $(container);
        s.wrapper = s.container.find(s.params.wrapperClass);
        s.slide = s.container.find(s.params.itemClass);

        // Is horizental
        function isH() {
            return s.params.direction === 'horizental';
        }

        // Touch Vars
        s.touchObject = {};//拖拽对象
        s.animType, s.transitionType, s.transformType, s.transformsEnabled;//Css3 Transition 相关参数
        s.touchDelay = 150;
        s.shouldClick = false;

        // Dragging Vars
        s.dragging = false;//正在拖拽
        s.edgeFriction = 0.35;//边缘减速系数
        s.inertiaFriction = 0.01;//惯性滑动系数
        s.position = 0;
        s.lastPosition = 0;//定位
        s.index = 0;//最后一次的下标

        // Slide Vars
        s.slideWidth, s.slideCount;//元素宽度px和个数

        /*=========================
        Slide progress
        ===========================*/
        s.getIndex = function() {
            // var verticalHeight;
            // verticalHeight = s.slide.outerHeight();
            if (s.position > 0) {
                return 0;
            }
            var index = Math.floor(Math.abs(s.position) / s.slideWidth);
            // 快速滑动
            if((s.touchObject.endTime - s.touchObject.startTime < s.touchDelay)) {
                if(s.swipeDirection() === "left")
                    index += 1;
            }
            // 移动超过1/2，下标向后移动
            else if(Math.abs(s.position) % s.slideWidth / s.slideWidth > 1 / 2) {
                index += 1;
            }
            return (index >= s.slideCount) ? (s.slideCount - 1) : index;
        };
        s.swipeDirection = function(){
            if(isH())
                return s.touchObject.startX - s.touchObject.curX > 0 ? 'left' : 'right';
            else
                return s.touchObject.startY - s.touchObject.curY > 0 ? 'down' : 'up';
        };

        /*=========================
        Transitions
        ===========================*/
        s.slideTo = function(index) {
            var indexChanged = s.index != index,
            targetLeft = index * s.slideWidth;
            targetLeft = -targetLeft;

            // 记住最后的定位和下标
            s.lastPosition = targetLeft;
            s.index = index;

            // apply transform
            s.applyTransform(targetLeft);

            // disable transition
            setTimeout(function(){
                s.wrapper.css(s.transitionType, '');
                s.trigger('onSlideEnd', index);
            }, s.params.speed);

            // trigger slide changed
            if(indexChanged) {
                s.trigger('onSlideChanged', index);
            }

            s.touchObject = {};
        };
        s.next = function() {
            var index = s.index >= s.slideCount - 1 ? 0 : s.index + 1;
            s.slideTo(index);
        };
        s.prev = function() {
            var index = s.index <= 0 ? s.slideCount - 1 : s.index - 1;
            s.slideTo(index);
        };

        /*=========================
        Translate/transition helpers
        ===========================*/
        s.applyTransform = function(x, y, speed) {
            var x = x || 0, y = y || 0, speed = speed || s.params.speed;
            // apply transation
            s.wrapper.css(s.transitionType, s.transformType + ' ' + speed + 'ms ' + s.params.easing);
            // apply animation
            s.wrapper.css(s.animType, 'translate(' + x + 'px, ' + y + 'px)');
        };
        s.setProps = function() {
            var bodyStyle = document.body.style;
            if (bodyStyle.webkitTransform !== undefined) {
                s.animType = 'webkitTransform';
                s.transformType = '-webkit-transform';
                s.transitionType = 'webkitTransition';
                if (bodyStyle.perspectiveProperty === undefined && bodyStyle.webkitPerspective === undefined)
                    s.animType = false;
            }
            if (bodyStyle.transform !== undefined && s.animType !== false) {
                s.animType = 'transform';
                s.transformType = 'transform';
                s.transitionType = 'transition';
            }
            s.transformsEnabled = (s.animType !== null && s.animType !== false);
        };

        /*=========================
        Custom Events/Callbacks Trigger
        ===========================*/
        s.eventListeners = {};
        s.trigger = function (eventName) {
            // Trigger callbacks
            if (s.params[eventName]) {
                s.params[eventName](arguments[1], arguments[2], arguments[3]);
            }

            // Trigger events
            var i, len;
            if (s.eventListeners[eventName]) {
                for (i = 0, len = s.eventListeners[eventName].length; i < len; i++) {
                    s.eventListeners[eventName][i](arguments[1], arguments[2], arguments[3]);
                }
            }
        };
        s.on = function (eventName, handler) {
            function normalizeEventName (eventName) {
                if (eventName.indexOf('on') !== 0) {
                    eventName = 'on' + eventName[0].toUpperCase() + eventName.substring(1);
                }
                return eventName;
            }
            eventName = normalizeEventName(eventName);
            if (!s.eventListeners[eventName])
                s.eventListeners[eventName] = [];
            s.eventListeners[eventName].push(handler);
            return s;
        };

        /*=========================
        Events Handle
        ===========================*/
        s.swipeStart = function(event) {
            if (s.touchObject.fingerCount !== 1) {
                s.touchObject = {};
                return false;
            }

            var touches = event.originalEvent !== undefined ? event.originalEvent.touches : null;

            s.touchObject.startX = s.touchObject.curX = touches !== undefined ? touches[0].pageX : event.clientX;
            s.touchObject.startY = s.touchObject.curY = touches !== undefined ? touches[0].pageY : event.clientY;

            s.touchObject.startTime = (new Date()).getTime();

            s.dragging = true;
        };
        s.swipeMove = function(event) {
            var direction, swipeLength;
            var touches = event.originalEvent !== undefined ? event.originalEvent.touches : null;

            // 触发了touchstart、mousedown，且有拖拽点
            if (!s.dragging || touches && touches.length !== 1) {
                return false;
            }

            // 设置当前坐标值
            s.touchObject.curX = touches !== undefined ? touches[0].pageX : event.clientX;
            s.touchObject.curY = touches !== undefined ? touches[0].pageY : event.clientY;

            // 计算滑动距离
            swipeLength = s.touchObject.swipeLength = Math.round(
                Math.sqrt(
                    Math.pow(s.touchObject.curX - s.touchObject.startX, 2)
                )
            );

            // 计算滑动方向
            direction = s.swipeDirection();

            if (event.originalEvent !== undefined && swipeLength > 4) {
                event.preventDefault();
            }

            // 边缘检测
            s.touchObject.edgeHit = false;

            if ((s.index <= 0 && direction === "right") || (s.index + 1 >= s.slideCount && direction === "left")) {
                swipeLength = swipeLength * s.edgeFriction;
                s.touchObject.edgeHit = true;
            }

            s.position = s.lastPosition + swipeLength * (direction === "right" ? 1 : -1);

            // 输出调试信息
            if(s.params.debug) {
                console.log('direction:' + direction
                    + ',transform:'+ s.wrapper.css('transform')
                    + ',s.touchObject.curX:' + parseInt(s.touchObject.curX)
                    + ',s.touchObject.startX:' + parseInt(s.touchObject.startX)
                    + ',swipeLength:' + parseInt(swipeLength)
                    + ',position:' + s.position);
            }

            var xy = isH() ?  Math.ceil(s.position) + 'px, 0px' : '0px, ' +  Math.ceil(s.position) + 'px';
            s.wrapper.css(s.animType, 'translate(' + xy + ')');
        };
        s.swipeEnd = function(event) {
            var direction = s.swipeDirection();
            s.shouldClick = (s.touchObject.swipeLength > 10) ? false : true;

            if (!s.dragging || s.touchObject.curX === undefined) {
                return false;
            }
            s.dragging = false;//终止拖拽行为

            if (s.touchObject.edgeHit === true) {
                s.trigger("onEdge" + direction[0].toUpperCase() + direction.substring(1), event);
            }

            if (s.touchObject.swipeLength >= s.touchObject.minSwipe) {
                s.trigger("onSwipe"+ direction[0].toUpperCase() + direction.substring(1), event);
            } else {
                if (s.touchObject.startX !== s.touchObject.curX) {
                    s.touchObject = {};
                }
            }

            s.touchObject.endTime  = (new Date()).getTime();

            // 开启惯性滑动
            if(s.params.inertia && s.touchObject.swipeLength >= s.touchObject.minSwipe && (s.touchObject.endTime - s.touchObject.startTime < s.touchDelay)) {

                // v0 = s / t;
                var v = (s.touchObject.curX - s.touchObject.startX) / (s.touchObject.endTime - s.touchObject.startTime);
                var that = this;

                (function() {
                    var dir = v > 0 ? 1 : -1;//方向
                    var t = 10;//刷新速度
                    var nowV = v;//当前速度
                    var interval = setInterval(inertiaMove, t);//定时器

                    function inertiaMove() {
                        if(that.dragging) {
                            clearInterval(interval);
                            return;
                        }

                        nowV -= v * that.inertiaFriction;
                        var moveX = Math.ceil(nowV * t);

                        // 速度方向变化表示速度达到0了,拉到最左侧和最右侧
                        if (dir * nowV < 0
                            || that.lastPosition <= that.slideWidth * that.slideCount * -1
                            || that.lastPosition >= 0) {

                            clearInterval(interval);

                            //根据坐标停靠至最近的板块
                            that.slideTo(that.getIndex());
                            return;
                        }
                        // 实时存储为最终位置
                        that.lastPosition = that.position = that.position + moveX;
                        that.applyTransform(that.position, 0, t);
                    }
                })();
            } else {
                //根据坐标停靠至最近的板块
                s.slideTo(s.getIndex());
            }
        };
        s.clickHandle = function(event) {
            if (s.shouldClick === false) {
                event.stopImmediatePropagation();
                event.stopPropagation();
                event.preventDefault();
            }
        };
        s.swipeHandle = function(event) {
            s.touchObject.fingerCount = event.originalEvent && event.originalEvent.touches !== undefined ?
                event.originalEvent.touches.length : 1;

            s.touchObject.minSwipe = s.slideWidth * s.params.touchThreshold;

            switch (event.type) {
                case 'touchstart':
                case 'mousedown': s.swipeStart(event); break;
                case 'touchmove':
                case 'mousemove': s.swipeMove(event); break;
                case 'touchend':
                case 'mouseup':
                case 'touchcancel':
                case 'mouseleave': s.swipeEnd(event); break;
                case 'click': s.clickHandle(event); break;
                case 'resize': break;
            }
        };

        /*=========================
        Initialize
        ===========================*/
        s.init = function() {
            // 设置元素宽度px和个数
            s.slideWidth = s.slide.outerWidth(true);
            s.slideCount = s.slide.size();

            // 添加事件监听器
            if(!s.unresize){
                $(window).on('resize', this, false);
            }
            s.container.on('touchstart mousedown touchmove mousemove touchend mouseup touchcancel mouseleave click', function(event){
                s.swipeHandle(event);
            });

            //设置CSS Transform属性
            s.setProps();
        };

        // 初始化
        s.init();

        // 返回实例
        return s;
    }

    /*=========================
    Exports - AMD, RequireJS and Global
    ===========================*/
    if (typeof define === 'function' && define.amd) {
        define(function() {
            return Swiper;
        });
    } else if (typeof module !== 'undefined' && module.exports) {
        module.exports = Swiper;
    } else {
        (typeof window !== 'undefined' ? window : this).Swiper = Swiper;
    }
})();
<commit_msg>新增autoplay代码和调整参数itemClass为slideClass<commit_after>/**
 * Swiper v1.0.1
 * @create Mar 17, 2015
 * @author David Wei
 * @see http://github.com/cdiwo/Swiper
 * Licensed under MIT
 * Released on: Mar 23, 2015
 */
(function () {
    'use strict';

    /*===========================
    Swiper
    ===========================*/
    function Swiper(container, params) {

        var defaults = {
            direction: 'horizental', // 方向
            autoplay: false,// autoplay
            speed: 300,// Css3 animation duration
            easing: 'ease',// Css3 animation timing function
            inertia: true,// 开启惯性滑动
            touchRatio: 0.2,// 拖拽占比率，默认元素的1/5
            index: 0,// 初始下标
            wrapperClass: '.swiper-wrapper',
            slideClass: '.swiper-slide',
            debug: false,
            /*
            Callbacks:
            onInit: function()
            onSwipeLeft: function()
            onSwipeRight: function()
            onEdgeLeft: function()
            onEdgeRight: function()
            onSlideMove: function (e)
            onSlideEnd: function(index)
            onSlideChanged: function(index)
            */
        }

        // Extend defaults with parameters
        var params = params || {};
        for (var param in params) {
            defaults[param] = params[param];
        }

        // Swiper
        var s = this;

        // Params
        s.params = defaults;

        // Define Container, Wrapper and Slide
        if(container === undefined) throw new Error('Invalid container!');
        s.container =  container === window ? $(window) : $(container);
        s.wrapper = s.container.find(s.params.wrapperClass);
        s.slide = s.container.find(s.params.slideClass);

        // Is horizental
        function isH() {
            return s.params.direction === 'horizental';
        }

        // Touch Vars
        s.touchObject = {};//拖拽对象
        s.animType, s.transitionType, s.transformType, s.transformsEnabled;//Css3 Transition 相关参数
        s.touchDelay = 150;
        s.shouldClick = false;

        // Dragging Vars
        s.dragging = false;//正在拖拽
        s.edgeFriction = 0.35;//边缘减速系数
        s.inertiaFriction = 0.01;//惯性滑动系数
        s.position = 0;
        s.lastPosition = 0;//定位
        s.index = 0;//最后一次的下标

        // Slide Vars
        s.slideWidth, s.slideCount;//元素宽度px和个数

        // Autoplay paused
        s.autoplayPaused = false;

        /*=========================
        Slide progress
        ===========================*/
        s.getIndex = function() {
            // var verticalHeight;
            // verticalHeight = s.slide.outerHeight();
            if (s.position > 0) {
                return 0;
            }
            var index = Math.floor(Math.abs(s.position) / s.slideWidth);
            // 快速滑动
            if((s.touchObject.endTime - s.touchObject.startTime < s.touchDelay)) {
                if(s.swipeDirection() === "left")
                    index += 1;
            }
            // 移动超过1/2，下标向后移动
            else if(Math.abs(s.position) % s.slideWidth / s.slideWidth > 1 / 2) {
                index += 1;
            }
            return (index >= s.slideCount) ? (s.slideCount - 1) : index;
        };
        s.swipeDirection = function(){
            if(isH())
                return s.touchObject.startX - s.touchObject.curX > 0 ? 'left' : 'right';
            else
                return s.touchObject.startY - s.touchObject.curY > 0 ? 'down' : 'up';
        };

        /*=========================
        Transitions
        ===========================*/
        s.slideTo = function(index) {
            var indexChanged = s.index != index,
            targetLeft = index * s.slideWidth;
            targetLeft = -targetLeft;

            // 记住最后的定位和下标
            s.lastPosition = targetLeft;
            s.index = index;

            // apply transform
            s.applyTransform(targetLeft);

            // disable transition
            setTimeout(function(){
                s.wrapper.css(s.transitionType, '');
                s.trigger('onSlideEnd', index);
            }, s.params.speed);

            // trigger slide changed
            if(indexChanged) {
                s.trigger('onSlideChanged', index);
            }

            s.touchObject = {};
        };
        s.next = function() {
            var index = s.index >= s.slideCount - 1 ? 0 : s.index + 1;
            s.slideTo(index);
        };
        s.prev = function() {
            var index = s.index <= 0 ? s.slideCount - 1 : s.index - 1;
            s.slideTo(index);
        };

        /*=========================
        Translate/transition helpers
        ===========================*/
        s.applyTransform = function(x, y, speed) {
            var x = x || 0, y = y || 0, speed = speed || s.params.speed;
            // apply transation
            s.wrapper.css(s.transitionType, s.transformType + ' ' + speed + 'ms ' + s.params.easing);
            // apply animation
            s.wrapper.css(s.animType, 'translate(' + x + 'px, ' + y + 'px)');
        };
        s.setProps = function() {
            var bodyStyle = document.body.style;
            if (bodyStyle.webkitTransform !== undefined) {
                s.animType = 'webkitTransform';
                s.transformType = '-webkit-transform';
                s.transitionType = 'webkitTransition';
                if (bodyStyle.perspectiveProperty === undefined && bodyStyle.webkitPerspective === undefined)
                    s.animType = false;
            }
            if (bodyStyle.transform !== undefined && s.animType !== false) {
                s.animType = 'transform';
                s.transformType = 'transform';
                s.transitionType = 'transition';
            }
            s.transformsEnabled = (s.animType !== null && s.animType !== false);
        };

        /*=========================
        Custom Events/Callbacks Trigger
        ===========================*/
        s.eventListeners = {};
        s.trigger = function (eventName) {
            // Trigger callbacks
            if (s.params[eventName]) {
                s.params[eventName](arguments[1], arguments[2], arguments[3]);
            }

            // Trigger events
            var i, len;
            if (s.eventListeners[eventName]) {
                for (i = 0, len = s.eventListeners[eventName].length; i < len; i++) {
                    s.eventListeners[eventName][i](arguments[1], arguments[2], arguments[3]);
                }
            }
        };
        s.on = function (eventName, handler) {
            function normalizeEventName (eventName) {
                if (eventName.indexOf('on') !== 0) {
                    eventName = 'on' + eventName[0].toUpperCase() + eventName.substring(1);
                }
                return eventName;
            }
            eventName = normalizeEventName(eventName);
            if (!s.eventListeners[eventName])
                s.eventListeners[eventName] = [];
            s.eventListeners[eventName].push(handler);
            return s;
        };

        /*=========================
        Events Handle
        ===========================*/
        s.swipeStart = function(event) {
            if (s.touchObject.fingerCount !== 1) {
                s.touchObject = {};
                return false;
            }

            var touches = event.originalEvent !== undefined ? event.originalEvent.touches : null;

            s.touchObject.startX = s.touchObject.curX = touches !== undefined ? touches[0].pageX : event.clientX;
            s.touchObject.startY = s.touchObject.curY = touches !== undefined ? touches[0].pageY : event.clientY;

            s.touchObject.startTime = (new Date()).getTime();

            s.dragging = true;
            s.autoplayPaused = true;
        };
        s.swipeMove = function(event) {
            var direction, swipeLength;
            var touches = event.originalEvent !== undefined ? event.originalEvent.touches : null;

            // 触发了touchstart、mousedown，且有拖拽点
            if (!s.dragging || touches && touches.length !== 1) {
                return false;
            }

            // 设置当前坐标值
            s.touchObject.curX = touches !== undefined ? touches[0].pageX : event.clientX;
            s.touchObject.curY = touches !== undefined ? touches[0].pageY : event.clientY;

            // 计算滑动距离
            swipeLength = s.touchObject.swipeLength = Math.round(
                Math.sqrt(
                    Math.pow(s.touchObject.curX - s.touchObject.startX, 2)
                )
            );

            // 计算滑动方向
            direction = s.swipeDirection();

            if (event.originalEvent !== undefined && swipeLength > 4) {
                event.preventDefault();
            }

            // 边缘检测
            s.touchObject.edgeHit = false;

            if ((s.index <= 0 && direction === "right") || (s.index + 1 >= s.slideCount && direction === "left")) {
                swipeLength = swipeLength * s.edgeFriction;
                s.touchObject.edgeHit = true;
            }

            s.position = s.lastPosition + swipeLength * (direction === "right" ? 1 : -1);

            // 输出调试信息
            if(s.params.debug) {
                console.log('direction:' + direction
                    + ',transform:'+ s.wrapper.css('transform')
                    + ',s.touchObject.curX:' + parseInt(s.touchObject.curX)
                    + ',s.touchObject.startX:' + parseInt(s.touchObject.startX)
                    + ',swipeLength:' + parseInt(swipeLength)
                    + ',position:' + s.position);
            }

            var xy = isH() ?  Math.ceil(s.position) + 'px, 0px' : '0px, ' +  Math.ceil(s.position) + 'px';
            s.wrapper.css(s.animType, 'translate(' + xy + ')');
        };
        s.swipeEnd = function(event) {
            var direction = s.swipeDirection();
            s.shouldClick = (s.touchObject.swipeLength > 10) ? false : true;
            s.autoplayPaused = false;

            if (!s.dragging || s.touchObject.curX === undefined) {
                return false;
            }
            s.dragging = false;//终止拖拽行为

            if (s.touchObject.edgeHit === true) {
                s.trigger("onEdge" + direction[0].toUpperCase() + direction.substring(1), event);
            }

            if (s.touchObject.swipeLength >= s.touchObject.minSwipe) {
                s.trigger("onSwipe"+ direction[0].toUpperCase() + direction.substring(1), event);
            } else {
                if (s.touchObject.startX !== s.touchObject.curX) {
                    s.touchObject = {};
                }
            }

            s.touchObject.endTime  = (new Date()).getTime();

            // 开启惯性滑动
            if(s.params.inertia && s.touchObject.swipeLength >= s.touchObject.minSwipe && (s.touchObject.endTime - s.touchObject.startTime < s.touchDelay)) {

                // v0 = s / t;
                var v = (s.touchObject.curX - s.touchObject.startX) / (s.touchObject.endTime - s.touchObject.startTime);
                var that = this;

                (function() {
                    var dir = v > 0 ? 1 : -1;//方向
                    var t = 10;//刷新速度
                    var nowV = v;//当前速度
                    var interval = setInterval(inertiaMove, t);//定时器

                    function inertiaMove() {
                        if(that.dragging) {
                            clearInterval(interval);
                            return;
                        }

                        nowV -= v * that.inertiaFriction;
                        var moveX = Math.ceil(nowV * t);

                        // 速度方向变化表示速度达到0了,拉到最左侧和最右侧
                        if (dir * nowV < 0
                            || that.lastPosition <= that.slideWidth * that.slideCount * -1
                            || that.lastPosition >= 0) {

                            clearInterval(interval);

                            //根据坐标停靠至最近的板块
                            that.slideTo(that.getIndex());
                            return;
                        }
                        // 实时存储为最终位置
                        that.lastPosition = that.position = that.position + moveX;
                        that.applyTransform(that.position, 0, t);
                    }
                })();
            } else {
                //根据坐标停靠至最近的板块
                s.slideTo(s.getIndex());
            }
        };
        s.clickHandle = function(event) {
            if (s.shouldClick === false) {
                event.stopImmediatePropagation();
                event.stopPropagation();
                event.preventDefault();
            }
        };
        s.swipeHandle = function(event) {
            s.touchObject.fingerCount = event.originalEvent && event.originalEvent.touches !== undefined ?
                event.originalEvent.touches.length : 1;

            s.touchObject.minSwipe = s.slideWidth * s.params.touchRatio;

            switch (event.type) {
                case 'touchstart':
                case 'mousedown': s.swipeStart(event); break;
                case 'touchmove':
                case 'mousemove': s.swipeMove(event); break;
                case 'touchend':
                case 'mouseup':
                case 'touchcancel':
                case 'mouseleave': s.swipeEnd(event); break;
                case 'click': s.clickHandle(event); break;
                case 'resize': break;
            }
        };

        /*=========================
        Initialize
        ===========================*/
        s.init = function() {
            // 设置元素宽度px和个数
            s.slideWidth = s.slide.outerWidth(true);
            s.slideCount = s.slide.size();

            // 添加事件监听器
            if(!s.unresize){
                $(window).on('resize', this, false);
            }
            s.container.on('touchstart mousedown touchmove mousemove touchend mouseup touchcancel mouseleave click', function(event){
                s.swipeHandle(event);
            });

            //设置CSS Transform属性
            s.setProps();

            if(s.params.autoplay) {
                s.autoplayInteral = setInterval(function() {
                    if(!s.autoplayPaused) {
                        s.next();
                    }
                }, s.params.autoplay);
            }
        };

        // 初始化
        s.init();

        // 返回实例
        return s;
    }

    /*=========================
    Exports - AMD, RequireJS and Global
    ===========================*/
    if (typeof define === 'function' && define.amd) {
        define(function() {
            return Swiper;
        });
    } else if (typeof module !== 'undefined' && module.exports) {
        module.exports = Swiper;
    } else {
        (typeof window !== 'undefined' ? window : this).Swiper = Swiper;
    }
})();
<|endoftext|>


<commit_before>import babel from "rollup-plugin-babel"
import minify from "rollup-plugin-babel-minify"

const banner = `/**
 * @author Toru Nagashima <https://github.com/mysticatea>
 * @copyright 2015 Toru Nagashima. All rights reserved.
 * See LICENSE file in root directory for full license.
 */`
const cjsOutro = `module.exports = EventTarget
module.exports.EventTarget = module.exports["default"] = EventTarget
module.exports.defineEventAttribute = defineEventAttribute
`
const umdOutro = `if (typeof module === "undefined" && typeof define === "undefined") {
    const global = Function("return this")()
    global.EventTargetShim = EventTarget
    global.EventTargetShim.defineEventAttribute = defineEventAttribute
}
`

export default [
    {
        input: "src/event-target.mjs",
        output: {
            file: "dist/event-target-shim.mjs",
            sourcemap: true,
            format: "es",
            banner,
        },
    },
    {
        input: "src/event-target.mjs",
        output: {
            file: "dist/event-target-shim.js",
            sourcemap: true,
            format: "cjs",
            banner,
            outro: cjsOutro,
        },
    },
    {
        input: "src/event-target.mjs",
        output: {
            file: "dist/event-target-shim.umd.js",
            sourcemap: true,
            format: "umd",
            name: "EventTargetShim",
            outro: umdOutro,
        },
        plugins: [
            babel({
                babelrc: false,
                presets: [
                    [
                        "@babel/preset-env",
                        { modules: false, targets: { browsers: ["ie 11"] } },
                    ],
                ],
            }),
            minify({
                comments: false,
                banner,
                sourceMap: true,
            }),
        ],
    },
]
<commit_msg>Fix: umd version contains ES2015 syntax (#22)<commit_after>import babel from "rollup-plugin-babel"
import minify from "rollup-plugin-babel-minify"

const banner = `/**
 * @author Toru Nagashima <https://github.com/mysticatea>
 * @copyright 2015 Toru Nagashima. All rights reserved.
 * See LICENSE file in root directory for full license.
 */`
const cjsOutro = `module.exports = EventTarget
module.exports.EventTarget = module.exports["default"] = EventTarget
module.exports.defineEventAttribute = defineEventAttribute
`
const umdOutro = `if (typeof module === "undefined" && typeof define === "undefined") {
    var global = Function("return this")()
    global.EventTargetShim = EventTarget
    global.EventTargetShim.defineEventAttribute = defineEventAttribute
}
`

export default [
    {
        input: "src/event-target.mjs",
        output: {
            file: "dist/event-target-shim.mjs",
            sourcemap: true,
            format: "es",
            banner,
        },
    },
    {
        input: "src/event-target.mjs",
        output: {
            file: "dist/event-target-shim.js",
            sourcemap: true,
            format: "cjs",
            banner,
            outro: cjsOutro,
        },
    },
    {
        input: "src/event-target.mjs",
        output: {
            file: "dist/event-target-shim.umd.js",
            sourcemap: true,
            format: "umd",
            name: "EventTargetShim",
            outro: umdOutro,
        },
        plugins: [
            babel({
                babelrc: false,
                presets: [
                    [
                        "@babel/preset-env",
                        { modules: false, targets: { browsers: ["ie 11"] } },
                    ],
                ],
            }),
            minify({
                comments: false,
                banner,
                sourceMap: true,
            }),
        ],
    },
]
<|endoftext|>


<commit_before>var http = require( "http" ),
	hook = require( "../lib/hook" ),
	logger = require( "../lib/logger" );

process.on( "uncaughtException", function( error ) {
	logger.error( "Uncaught exception: " + error.stack );
});

http.createServer(function( request, response ) {
	var json = "";
	request.setEncoding( "utf8" );
	request.on( "data", function( chunk ) {
		json += chunk;
	});
	request.on( "end", function() {
		response.writeHead( 200 );
		response.end();

		try {
			json = JSON.parse( json );
		} catch( e ) {
			logger.error( "Invalid request: " + json );
			return;
		}

		hook.processHook( json, function( error ) {
			if ( error ) {
				logger.error( "Error processing hook: " + error.stack );
			}
		});
	});
}).listen( 8001 );
<commit_msg>Graceful startup and shutdown of HTTP server.<commit_after>var http = require( "http" ),
	hook = require( "../lib/hook" ),
	logger = require( "../lib/logger" );

var port = (function() {
	var index = process.argv.indexOf( "-p" );
	return index === -1 ? 8001 : +process.argv[ index + 1 ];
})();

process.on( "uncaughtException", function( error ) {
	logger.error( "Uncaught exception: " + error.stack );
});

var server = http.createServer(function( request, response ) {
	var json = "";
	request.setEncoding( "utf8" );
	request.on( "data", function( chunk ) {
		json += chunk;
	});

	request.on( "end", function() {
		try {
			json = JSON.parse( json );
		} catch( e ) {
			// Invalid JSON, stop processing
			logger.error( "Invalid request: " + json );
			response.writeHead( 400 );
			response.end();
			return;
		}

		// Accept the request and close the connection
		response.writeHead( 202 );
		response.end();

		// Process the request
		hook.processHook( json, function( error ) {
			if ( error ) {
				logger.error( "Error processing hook: " + error.stack );
			}
		});
	});
});

// If another process is using this port, keep retrying
server.on( "error", function( error ) {
	if ( error.code === "EADDRINUSE" ) {
		return setTimeout(function() {
			// server.close();
			server.listen( port );
		}, 100 );
	}
});

server.listen( port );

process.on( "SIGINT", function() {
	server.close();
});
<|endoftext|>


<commit_before>"use strict";

const angular = require("angular");
const gameEngine = require("acey-deucey-game-engine");
const _ = require("lodash");
const assert = require("assert");

angular.module("acey-deucey").controller("AceyDeuceyCtrl", function($scope) {
    $scope.gameState = gameEngine.getInitialGameState();
    // $scope.gameState.isPlayerOne = false;
    // $scope.gameState.playerOne.barPieces = 1;
    // $scope.gameState.playerOne.initialPieces = 0;
    // $scope.gameState.playerTwo.barPieces = 1;
    // $scope.gameState.playerTwo.initialPieces = 0;
    $scope.firstQuadrantIndices = _.range(0, 6);
    $scope.secondQuadrantIndices = _.range(6, 12);
    $scope.thirdQuadrantIndices = _.range(17, 11);
    $scope.fourthQuadrantIndices = _.range(23, 17);
    $scope.turnState = {
        rolls: {first: {num: null, used: null}, second: {num: null, used: null}},
        currentPiecePosition: null,
        availableSpaces: [],
        isBar: null,
        initialGameState: null,
        proposedMoves: []
    };

    function resetPieces() {
        $scope.turnState.currentPiecePosition = null;
        $scope.turnState.isBar = null;
        $scope.turnState.availableSpaces = [];
    }

    function resetDiceUsed() {
        _.forEach($scope.turnState.rolls, roll => roll.used = null);
    }

    function resetRolls() {
        _.forEach($scope.turnState.rolls, roll => {
            roll.used = null;
            roll.num = null;
        });
    }
    function resetTurnState() {
        resetRolls();
        resetPieces();
        $scope.turnState.initialGameState = null;
        $scope.proposedMoves = [];
    }

    $scope.$on("submit-turn", () => {
        const diceRoll = [$scope.turnState.rolls.first.num, $scope.turnState.rolls.second.num];
        $scope.gameState = gameEngine.makeTurn(
            $scope.turnState.initialGameState,
            diceRoll,
            $scope.turnState.proposedMoves
        );
        $scope.gameState.isPlayerOne = !$scope.gameState.isPlayerOne;
        resetTurnState();
    });

    $scope.$on("reset-turn", () => {
        if (!$scope.turnState.initialGameState) {
            return;
        }
        $scope.gameState = $scope.turnState.initialGameState;
        resetPieces();
        resetDiceUsed();
        $scope.turnState.initialGameState = null;
    });

    $scope.$on("make-move", (event, proposedMove) => {
        if (!$scope.turnState.initialGameState) {
            $scope.turnState.initialGameState = $scope.gameState;
        }
        $scope.gameState = gameEngine.makeMove($scope.gameState, proposedMove);
        $scope.turnState.proposedMoves.push(proposedMove);
        resetPieces();
        const matchingRoll = _.find($scope.turnState.rolls, {used: null, num: proposedMove.numberOfSpaces});
        assert(matchingRoll, `could not find matching roll for num = ${proposedMove.numberOfSpaces}`);
        matchingRoll.used = true;
    });

});

<commit_msg>Fixing submit turn bug<commit_after>"use strict";

const angular = require("angular");
const gameEngine = require("acey-deucey-game-engine");
const _ = require("lodash");
const assert = require("assert");

angular.module("acey-deucey").controller("AceyDeuceyCtrl", function($scope) {
    $scope.gameState = gameEngine.getInitialGameState();
    // $scope.gameState.isPlayerOne = false;
    // $scope.gameState.playerOne.barPieces = 1;
    // $scope.gameState.playerOne.initialPieces = 0;
    // $scope.gameState.playerTwo.barPieces = 1;
    // $scope.gameState.playerTwo.initialPieces = 0;
    $scope.firstQuadrantIndices = _.range(0, 6);
    $scope.secondQuadrantIndices = _.range(6, 12);
    $scope.thirdQuadrantIndices = _.range(17, 11);
    $scope.fourthQuadrantIndices = _.range(23, 17);
    $scope.turnState = {
        rolls: {first: {num: null, used: null}, second: {num: null, used: null}},
        currentPiecePosition: null,
        availableSpaces: [],
        isBar: null,
        initialGameState: null,
        proposedMoves: []
    };

    function resetPieces() {
        $scope.turnState.currentPiecePosition = null;
        $scope.turnState.isBar = null;
        $scope.turnState.availableSpaces = [];
    }

    function resetDiceUsed() {
        _.forEach($scope.turnState.rolls, roll => roll.used = null);
    }

    function resetRolls() {
        _.forEach($scope.turnState.rolls, roll => {
            roll.used = null;
            roll.num = null;
        });
    }
    function resetWholeTurnState() {
        resetRolls();
        resetPieces();
        $scope.turnState.initialGameState = null;
        $scope.turnState.proposedMoves = [];
    }

    $scope.$on("submit-turn", () => {
        const diceRoll = [$scope.turnState.rolls.first.num, $scope.turnState.rolls.second.num];
        $scope.gameState = gameEngine.makeTurn(
            $scope.turnState.initialGameState,
            diceRoll,
            $scope.turnState.proposedMoves
        );
        resetWholeTurnState();
    });

    $scope.$on("reset-turn", () => {
        if (!$scope.turnState.initialGameState) {
            return;
        }
        $scope.gameState = $scope.turnState.initialGameState;
        resetPieces();
        resetDiceUsed();
        $scope.turnState.proposedMoves = [];
        $scope.turnState.initialGameState = null;
    });

    $scope.$on("make-move", (event, proposedMove) => {
        if (!$scope.turnState.initialGameState) {
            $scope.turnState.initialGameState = $scope.gameState;
        }
        $scope.gameState = gameEngine.makeMove($scope.gameState, proposedMove);
        $scope.turnState.proposedMoves.push(proposedMove);
        resetPieces();
        const matchingRoll = _.find($scope.turnState.rolls, {used: null, num: proposedMove.numberOfSpaces});
        assert(matchingRoll, `could not find matching roll for num = ${proposedMove.numberOfSpaces}`);
        matchingRoll.used = true;
    });

});

<|endoftext|>


<commit_before>"use strict";

const angular = require("angular");
const gameEngine = require("acey-deucey-game-engine");
const _ = require("lodash");
const assert = require("assert");

angular.module("acey-deucey").controller("AceyDeuceyCtrl", function($scope) {
    $scope.gameState = gameEngine.getInitialGameState();
    // $scope.gameState.isPlayerOne = false;
    // $scope.gameState.playerOne.barPieces = 1;
    // $scope.gameState.playerOne.initialPieces = 0;
    // $scope.gameState.playerTwo.barPieces = 1;
    // $scope.gameState.playerTwo.initialPieces = 0;
    $scope.firstQuadrantIndices = _.range(0, 6);
    $scope.secondQuadrantIndices = _.range(6, 12);
    $scope.thirdQuadrantIndices = _.range(17, 11);
    $scope.fourthQuadrantIndices = _.range(23, 17);
    $scope.turnState = {
        rolls: {first: {num: null, used: null}, second: {num: null, used: null}},
        currentPiecePosition: null,
        availableSpaces: [],
        isBar: null,
        initialGameState: null,
        proposedMoves: []
    };

    function resetPieces() {
        $scope.turnState.currentPiecePosition = null;
        $scope.turnState.isBar = null;
        $scope.turnState.availableSpaces = [];
    }

    function resetDiceUsed() {
        _.forEach($scope.turnState.rolls, roll => roll.used = null);
    }

    function resetRolls() {
        _.forEach($scope.turnState.rolls, roll => {
            roll.used = null;
            roll.num = null;
        });
    }
    function resetTurnState() {
        resetRolls();
        resetPieces();
        $scope.turnState.initialGameState = null;
        $scope.proposedMoves = [];
    }

    $scope.$on("submit-turn", () => {
        const diceRoll = [$scope.turnState.rolls.first.num, $scope.turnState.rolls.second.num]
        $scope.gameState = gameEngine.makeTurn(
            $scope.turnState.initialGameState,
            diceRoll,
            $scope.turnState.proposedMoves
        );
        debugger;
        $scope.gameState.isPlayerOne = !$scope.gameState.isPlayerOne;
        resetTurnState();
    });

    $scope.$on("reset-turn", () => {
        if (!$scope.turnState.initialGameState) {
            return;
        }
        $scope.gameState = $scope.turnState.initialGameState;
        resetPieces();
        resetDiceUsed();
        $scope.turnState.initialGameState = null;
    });

    $scope.$on("make-move", (event, proposedMove) => {
        if (!$scope.turnState.initialGameState) {
            $scope.turnState.initialGameState = $scope.gameState;
        }
        $scope.gameState = gameEngine.makeMove($scope.gameState, proposedMove);
        $scope.turnState.proposedMoves.push(proposedMove);
        resetPieces();
        const matchingRoll = _.find($scope.turnState.rolls, {used: null, num: proposedMove.numberOfSpaces});
        assert(matchingRoll, `could not find matching roll for num = ${proposedMove.numberOfSpaces}`);
        matchingRoll.used = true;
    });

});

<commit_msg>Clean up<commit_after>"use strict";

const angular = require("angular");
const gameEngine = require("acey-deucey-game-engine");
const _ = require("lodash");
const assert = require("assert");

angular.module("acey-deucey").controller("AceyDeuceyCtrl", function($scope) {
    $scope.gameState = gameEngine.getInitialGameState();
    // $scope.gameState.isPlayerOne = false;
    // $scope.gameState.playerOne.barPieces = 1;
    // $scope.gameState.playerOne.initialPieces = 0;
    // $scope.gameState.playerTwo.barPieces = 1;
    // $scope.gameState.playerTwo.initialPieces = 0;
    $scope.firstQuadrantIndices = _.range(0, 6);
    $scope.secondQuadrantIndices = _.range(6, 12);
    $scope.thirdQuadrantIndices = _.range(17, 11);
    $scope.fourthQuadrantIndices = _.range(23, 17);
    $scope.turnState = {
        rolls: {first: {num: null, used: null}, second: {num: null, used: null}},
        currentPiecePosition: null,
        availableSpaces: [],
        isBar: null,
        initialGameState: null,
        proposedMoves: []
    };

    function resetPieces() {
        $scope.turnState.currentPiecePosition = null;
        $scope.turnState.isBar = null;
        $scope.turnState.availableSpaces = [];
    }

    function resetDiceUsed() {
        _.forEach($scope.turnState.rolls, roll => roll.used = null);
    }

    function resetRolls() {
        _.forEach($scope.turnState.rolls, roll => {
            roll.used = null;
            roll.num = null;
        });
    }
    function resetTurnState() {
        resetRolls();
        resetPieces();
        $scope.turnState.initialGameState = null;
        $scope.proposedMoves = [];
    }

    $scope.$on("submit-turn", () => {
        const diceRoll = [$scope.turnState.rolls.first.num, $scope.turnState.rolls.second.num];
        $scope.gameState = gameEngine.makeTurn(
            $scope.turnState.initialGameState,
            diceRoll,
            $scope.turnState.proposedMoves
        );
        $scope.gameState.isPlayerOne = !$scope.gameState.isPlayerOne;
        resetTurnState();
    });

    $scope.$on("reset-turn", () => {
        if (!$scope.turnState.initialGameState) {
            return;
        }
        $scope.gameState = $scope.turnState.initialGameState;
        resetPieces();
        resetDiceUsed();
        $scope.turnState.initialGameState = null;
    });

    $scope.$on("make-move", (event, proposedMove) => {
        if (!$scope.turnState.initialGameState) {
            $scope.turnState.initialGameState = $scope.gameState;
        }
        $scope.gameState = gameEngine.makeMove($scope.gameState, proposedMove);
        $scope.turnState.proposedMoves.push(proposedMove);
        resetPieces();
        const matchingRoll = _.find($scope.turnState.rolls, {used: null, num: proposedMove.numberOfSpaces});
        assert(matchingRoll, `could not find matching roll for num = ${proposedMove.numberOfSpaces}`);
        matchingRoll.used = true;
    });

});

<|endoftext|>


<commit_before>// This is the entrypoint for the Rails asset pipeline, and is new
// as part of Sprockets 4.0.  See https://github.com/rails/sprockets/blob/master/UPGRADING.md#manifestjs

// Most JS is built separately, and most styles are defined in JS, but this
// is the entry point for some older code still processed by the asset pipeline.
//= link_tree ../images
//= link application.js
//= link application.css

// This is required for the `administrate` gem to work correctly, which
// provides some of the `admin` routes, controllers and views.`
//= link administrate/application.js
//= link administrate/application.css
<commit_msg>Add in link to upstream issue<commit_after>// This is the entrypoint for the Rails asset pipeline, and is new
// as part of Sprockets 4.0.  See https://github.com/rails/sprockets/blob/master/UPGRADING.md#manifestjs

// Most JS is built separately, and most styles are defined in JS, but this
// is the entry point for some older code still processed by the asset pipeline.
//= link_tree ../images
//= link application.js
//= link application.css

// This is required for the `administrate` gem to work correctly, which
// provides some of the `admin` routes, controllers and views.`
// See https://github.com/thoughtbot/administrate/pull/1452
//= link administrate/application.js
//= link administrate/application.css
<|endoftext|>


<commit_before>var Hpi = function() {
  "use strict";

  /** Module initialisation */
  var init = function() {
    initControls();
    bindEvents();
  };

  /** Event handling */
  var bindEvents = function() {
    $("form.search").on( "submit", onSearchSubmit );
    $("form.search").on( "keydown", "input", onSeachInput );
    $("form.preview").on( "click", "input", onChangePreviewSettings );
    $("a.action-add-comparison").on( "click", onAddComparison );
    $("form.search").on( "click", "a.action-remove-selection", onRemoveSelection );
    $(".container").on( "click", "button.action-show-map", onShowMap );
  };

  /** Widget and control initialisation */
  var initControls = function() {
    $("button#action_search").hide();
    $("form.preview input[type=submit]").hide();

    // ensure we know which input field the user is entering text into
    $("form.search input:not([type=hidden])").each( function( i, elem ) {
      var sId = searchIdFromElement( elem );

      $(elem).autocomplete({
        source: HpiLocations.locationNames,
        select: function( e, ui ) {
          onAutocompleteSelect( sId, e, ui );
        },
        focus: function (event, ui) {
           event.preventDefault();
        }
      });
    } );

    // add show map buttons
    $(".js.map-button").each( function( i, elem ) {
      showMapButton( elem );
    } );
  };

  /** User has submitted a search on the search form */
  var onSearchSubmit = function( e ) {
    if (e) {e.preventDefault();}
    // if (_.keys(_currentSelection).length > 0) {
    //   drawPreview();
    // }
  };

  /** User has selected one of the autocomplete options */
  var onAutocompleteSelect = function( searchId, e, ui ) {
    e.preventDefault();

    var locationName = ui.item.label;
    var locationURI = ui.item.value;

    $(e.currentTarget).val( "" );
    selectLocation( locationName, locationURI, searchId, e.currentTarget );
  };

  /** User has started typing into an input field */
  var onSeachInput = function( e ) {
    // var searchId = searchIdFromElement( e.currentTarget );
    // forgetSelectedLocation( searchId );
  };

  /** User has clicked to change some of the preview settings */
  var onChangePreviewSettings = function( e ) {
    drawPreview();
  };

  /** Show that a location has been selected by the user */
  var selectLocation = function( locationName, locationURI, sId, targetElem ) {
    var searchId = asSearchId( sId );
    showSelectedLocation( targetElem, searchId, locationName, locationURI );
    drawPreview();
  };

  var drawPreview = function() {
    // TODO this really refactoring to DRY it up
    if (locationComplete()) {
      resetPreviewFormElement( "loc_0", selectedLocationName( 0 ) );
      resetPreviewFormElement( "loc_uri_0", selectedLocationURI( 0 ) );

      resetPreviewFormElement( "loc_1", compareAreas() ? selectedLocationName( 1 ) : null );
      resetPreviewFormElement( "loc_uri_1", compareAreas() ? selectedLocationURI( 1 ) : null );

      if (compareAreas()) {
        resetPreviewFormElement( "compare", 1 );
      }

      HpiPreview.updatePreview();
    }
  };

  var resetPreviewFormElement = function( elemName, val ) {
    var elem = $(sprintf("form.preview input[type=hidden][name=%s]", elemName ) );
    if (elem.length) {
      // input element exists
      if (val) {
        elem.val( val );
      }
      else {
        elem.remove();
      }
    }
    else {
      // element does not yet exist
      if (val) {
        $("form.preview").append(sprintf( "<input type='hidden' name='%s' value='%s' />", elemName, val ) );
      }
    }
  };

  var forgetSelectedLocation = function( sid ) {
    console.log( "Forgetting selected location " + sid );
    locationFormElement( sid, "loc" ).remove();
    locationFormElement( sid, "loc_uri" ).remove();
  };

  var selectedLocationName = function( sid ) {
    return locationFormElement( sid, "loc" ).val();
  };

  var selectedLocationURI = function( sid ) {
    return locationFormElement( sid, "loc_uri" ).val();
  };

  var locationFormElement = function( sid, l ) {
    var li = attributeWithSearchId( l, asSearchId( sid ) );
    return $( sprintf( "form.search input[type=hidden][name=%s]", li ) );
  };

  /** Return true if we have all necessary locations that we can begin query */
  var locationComplete = function() {
    var location0 = selectedLocationURI( 0 );
    var location1 = selectedLocationURI( 1 );

    return compareAreas() ? (location0 && location1) : location0;
  };

  /** Return true if we are performing a comparison */
  var compareAreas = function() {
    return $("form.search input[type=hidden][name=compare]").length;
  };

  /* Return loc or loc_compare as the identity of the search the user is conducting */
  var searchIdFromElement = function( elem ) {
    var sId = $(elem).attr( "name" );
    return asSearchId( parseInt( sId.replace( /[^\d]*/, "" ) ) );
  };

  /** Return a search ID object for search N */
  var asSearchId = function( i ) {
    return _.isNumber( i ) ? {n: i, sym: "search_" + i } : i;
  };

  /** Return a symbol tagged with the search ID */
  var attributeWithSearchId = function( sym, searchId ) {
    return sprintf( "%s_%d", sym, searchId.n );
  };

  /** User has selected a location */
  var showSelectedLocation = function( sourceElem, searchId, locationName, locationURI ) {
    var elem = $(sourceElem).parents(".area-selection")
                            .find(".selected-search-term")
                            .empty()
                            .append( sprintf( "
Selected: %s " +
                                              "" +
                                              "
",
                                              locationName ) )
                            .append( sprintf( "<input type='hidden' name='%s' value='%s' />",
                                     attributeWithSearchId( "loc", searchId ), locationName ) )
                            .append( sprintf( "<input type='hidden' name='%s' value='%s' />",
                                     attributeWithSearchId( "loc_uri", searchId ), locationURI ) );

    if (compareAreas()) {
      elem.append( "<input type='hidden' name='compare' value='1' />" );
    }
  };

  /** User wants to show the comparison region */
  var onAddComparison = function( e ) {
    e.preventDefault();
    clearPreview();

    var interactionState = currentInteractionState( "search",
                                                    {compare: 1},
                                                    ['search_0', 'search_1'] );
    $.post( Routes.search_index_path(),
            interactionState, null, "html" )
      .done( onComparisonDone )
      .fail( onComparisonFail );
  };

  var onComparisonDone = function( html ) {
    $(".search-form-container").empty().append( html );
    initControls();
  };

  var onComparisonFail = function( jqXhr, error ) {

  };

  /** Return the current interaction state as a hash */
  var currentInteractionState = function( formClass, options, deletes ) {
    var state = $(sprintf( "form.%s", formClass) ).serializeHash();
    state = _.extend( state, options || {} );

    _.each( (deletes || []), function( d ) {
      delete state[d];
    } );

    return state;
  };

  /** Remove a selection */
  var onRemoveSelection = function( e ) {
    e.preventDefault();
    var button = $(e.currentTarget);
    var elem = button.parents(".area-selection").find(".selected-search-term");
    var input = elem.find( "input" );
    var searchId = input.attr("name");

    elem.empty();
    clearPreview();
  }

  var clearPreview = function() {
    $("#results-preview").empty();
    $("#results-header").empty();
  };

  /** Ensure a show-map button is present for the element */
  var showMapButton = function( elem ) {
    if ($(elem).find( "button" ).length === 0) {
      var alt = 'find a location on the map';
      $(elem).append( sprintf( "<button class='action action-show-map btn btn-default map-button' alt='%s' title='%s' >" +
                               "</button>",
                               alt, alt ) );
    }
  };

  /** User has clicked to show the map */
  var onShowMap = function( e ) {
    e.preventDefault();
    var button = $(e.currentTarget);
    var searchId = button.parents( "span[data-search-id]" ).data( "search-id" );

    HpiMapSearch.showDialogue( searchId, e.currentTarget );
  }

  return {
    init: init,
    currentInteractionState: currentInteractionState,
    selectLocation: selectLocation
  }
}();

$( Hpi.init );
<commit_msg>Fix for issue #20 - selecting an area from the search box should be working again<commit_after>var Hpi = function() {
  "use strict";

  /** Module initialisation */
  var init = function() {
    initControls();
    bindEvents();
  };

  /** Event handling */
  var bindEvents = function() {
    $("form.search").on( "submit", onSearchSubmit );
    $("form.search").on( "keydown", "input", onSeachInput );
    $("form.preview").on( "click", "input", onChangePreviewSettings );
    $("a.action-add-comparison").on( "click", onAddComparison );
    $("form.search").on( "click", "a.action-remove-selection", onRemoveSelection );
    $(".container").on( "click", "button.action-show-map", onShowMap );
  };

  /** Widget and control initialisation */
  var initControls = function() {
    $("button#action_search").hide();
    $("form.preview input[type=submit]").hide();

    // ensure we know which input field the user is entering text into
    $("form.search input:not([type=hidden])").each( function( i, elem ) {
      var sId = searchIdFromElement( elem );

      $(elem).autocomplete({
        source: HpiLocations.locationNames,
        select: function( e, ui ) {
          onAutocompleteSelect( sId, e, ui );
        },
        focus: function (event, ui) {
           event.preventDefault();
        }
      });
    } );

    // add show map buttons
    $(".js.map-button").each( function( i, elem ) {
      showMapButton( elem );
    } );
  };

  /** User has submitted a search on the search form */
  var onSearchSubmit = function( e ) {
    if (e) {e.preventDefault();}
    // if (_.keys(_currentSelection).length > 0) {
    //   drawPreview();
    // }
  };

  /** User has selected one of the autocomplete options */
  var onAutocompleteSelect = function( searchId, e, ui ) {
    e.preventDefault();

    var locationName = ui.item.label;
    var locationURI = ui.item.value;

    $(e.currentTarget).val( "" );
    selectLocation( locationName, locationURI, searchId, e.target );
  };

  /** User has started typing into an input field */
  var onSeachInput = function( e ) {
    // var searchId = searchIdFromElement( e.currentTarget );
    // forgetSelectedLocation( searchId );
  };

  /** User has clicked to change some of the preview settings */
  var onChangePreviewSettings = function( e ) {
    drawPreview();
  };

  /** Show that a location has been selected by the user */
  var selectLocation = function( locationName, locationURI, sId, targetElem ) {
    var searchId = asSearchId( sId );
    showSelectedLocation( targetElem, searchId, locationName, locationURI );
    drawPreview();
  };

  var drawPreview = function() {
    // TODO this really refactoring to DRY it up
    if (locationComplete()) {
      resetPreviewFormElement( "loc_0", selectedLocationName( 0 ) );
      resetPreviewFormElement( "loc_uri_0", selectedLocationURI( 0 ) );

      resetPreviewFormElement( "loc_1", compareAreas() ? selectedLocationName( 1 ) : null );
      resetPreviewFormElement( "loc_uri_1", compareAreas() ? selectedLocationURI( 1 ) : null );

      if (compareAreas()) {
        resetPreviewFormElement( "compare", 1 );
      }

      HpiPreview.updatePreview();
    }
  };

  var resetPreviewFormElement = function( elemName, val ) {
    var elem = $(sprintf("form.preview input[type=hidden][name=%s]", elemName ) );
    if (elem.length) {
      // input element exists
      if (val) {
        elem.val( val );
      }
      else {
        elem.remove();
      }
    }
    else {
      // element does not yet exist
      if (val) {
        $("form.preview").append(sprintf( "<input type='hidden' name='%s' value='%s' />", elemName, val ) );
      }
    }
  };

  var forgetSelectedLocation = function( sid ) {
    console.log( "Forgetting selected location " + sid );
    locationFormElement( sid, "loc" ).remove();
    locationFormElement( sid, "loc_uri" ).remove();
  };

  var selectedLocationName = function( sid ) {
    return locationFormElement( sid, "loc" ).val();
  };

  var selectedLocationURI = function( sid ) {
    return locationFormElement( sid, "loc_uri" ).val();
  };

  var locationFormElement = function( sid, l ) {
    var li = attributeWithSearchId( l, asSearchId( sid ) );
    return $( sprintf( "form.search input[type=hidden][name=%s]", li ) );
  };

  /** Return true if we have all necessary locations that we can begin query */
  var locationComplete = function() {
    var location0 = selectedLocationURI( 0 );
    var location1 = selectedLocationURI( 1 );

    return compareAreas() ? (location0 && location1) : location0;
  };

  /** Return true if we are performing a comparison */
  var compareAreas = function() {
    return $("form.search input[type=hidden][name=compare]").length;
  };

  /* Return loc or loc_compare as the identity of the search the user is conducting */
  var searchIdFromElement = function( elem ) {
    var sId = $(elem).attr( "name" );
    return asSearchId( parseInt( sId.replace( /[^\d]*/, "" ) ) );
  };

  /** Return a search ID object for search N */
  var asSearchId = function( i ) {
    return _.isNumber( i ) ? {n: i, sym: "search_" + i } : i;
  };

  /** Return a symbol tagged with the search ID */
  var attributeWithSearchId = function( sym, searchId ) {
    return sprintf( "%s_%d", sym, searchId.n );
  };

  /** User has selected a location */
  var showSelectedLocation = function( sourceElem, searchId, locationName, locationURI ) {
    var elem = $(sourceElem).parents(".area-selection")
                            .find(".selected-search-term")
                            .empty()
                            .append( sprintf( "
Selected: %s " +
                                              "" +
                                              "
",
                                              locationName ) )
                            .append( sprintf( "<input type='hidden' name='%s' value='%s' />",
                                     attributeWithSearchId( "loc", searchId ), locationName ) )
                            .append( sprintf( "<input type='hidden' name='%s' value='%s' />",
                                     attributeWithSearchId( "loc_uri", searchId ), locationURI ) );

    if (compareAreas()) {
      elem.append( "<input type='hidden' name='compare' value='1' />" );
    }
  };

  /** User wants to show the comparison region */
  var onAddComparison = function( e ) {
    e.preventDefault();
    clearPreview();

    var interactionState = currentInteractionState( "search",
                                                    {compare: 1},
                                                    ['search_0', 'search_1'] );
    $.post( Routes.search_index_path(),
            interactionState, null, "html" )
      .done( onComparisonDone )
      .fail( onComparisonFail );
  };

  var onComparisonDone = function( html ) {
    $(".search-form-container").empty().append( html );
    initControls();
  };

  var onComparisonFail = function( jqXhr, error ) {

  };

  /** Return the current interaction state as a hash */
  var currentInteractionState = function( formClass, options, deletes ) {
    var state = $(sprintf( "form.%s", formClass) ).serializeHash();
    state = _.extend( state, options || {} );

    _.each( (deletes || []), function( d ) {
      delete state[d];
    } );

    return state;
  };

  /** Remove a selection */
  var onRemoveSelection = function( e ) {
    e.preventDefault();
    var button = $(e.currentTarget);
    var elem = button.parents(".area-selection").find(".selected-search-term");
    var input = elem.find( "input" );
    var searchId = input.attr("name");

    elem.empty();
    clearPreview();
  }

  var clearPreview = function() {
    $("#results-preview").empty();
    $("#results-header").empty();
  };

  /** Ensure a show-map button is present for the element */
  var showMapButton = function( elem ) {
    if ($(elem).find( "button" ).length === 0) {
      var alt = 'find a location on the map';
      $(elem).append( sprintf( "<button class='action action-show-map btn btn-default map-button' alt='%s' title='%s' >" +
                               "</button>",
                               alt, alt ) );
    }
  };

  /** User has clicked to show the map */
  var onShowMap = function( e ) {
    e.preventDefault();
    var button = $(e.currentTarget);
    var searchId = button.parents( "span[data-search-id]" ).data( "search-id" );

    HpiMapSearch.showDialogue( searchId, e.currentTarget );
  }

  return {
    init: init,
    currentInteractionState: currentInteractionState,
    selectLocation: selectLocation
  }
}();

$( Hpi.init );
<|endoftext|>


<commit_before>// TODO make this modular... for now it's all we need.

function setContainerHeight() {
  var height = $(window).height();
  $('.app-nav').height(height);
  $('.app-aside').height(height);
}

$(window).resize(function(e) {
  console.log('window resized');
  setContainerHeight();
});

$(document).on("page:load", setContainerHeight);

// $(document).ready(setContainerHeight);
$(window).resize(setContainerHeight);
<commit_msg>removed duplicate code from raw.js<commit_after>// TODO make this modular... for now it's all we need.

function setContainerHeight() {
  var height = $(window).height();
  $('.app-nav').height(height);
  $('.app-aside').height(height);
}

$(document).on("page:load", setContainerHeight);
$(window).resize(setContainerHeight);
<|endoftext|>


<commit_before>
exports.seed = function(knex, Promise) {
  // return Promise.join(
  //   // Deletes ALL existing entries
  //   knex('articles').del(),
  //   knex('publishers').del(),

  //   // Inserts seed entries
  //   knex('publishers').insert({id: 1, domain: 'http://theglobeandmail.com', name: 'The Globe and Mail', location: 'national', language: 'english'}),
  //   knex('publishers').insert({id: 2, domain: 'http://nationalpost.com', name: 'National Post', location: 'national', language: 'english'})
  // );
};
<commit_msg>reverted seed_publishers.js to uncommented state<commit_after>
exports.seed = function(knex, Promise) {
  return Promise.join(
    // Deletes ALL existing entries
    knex('articles').del(),
    knex('publishers').del(),

    // Inserts seed entries
    knex('publishers').insert({id: 1, domain: 'http://theglobeandmail.com', name: 'The Globe and Mail', location: 'national', language: 'english'}),
    knex('publishers').insert({id: 2, domain: 'http://nationalpost.com', name: 'National Post', location: 'national', language: 'english'})
  );
};
<|endoftext|>


<commit_before>/*    Copyright 2016-2021 Firewalla Inc.
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';
const log = require('../net2/logger.js')(__filename);

const Sensor = require('./Sensor.js').Sensor;

const sem = require('../sensor/SensorEventManager.js').getInstance();

const rclient = require('../util/redis_manager.js').getRedisClient()
const Message = require('../net2/Message.js');
const sysManager = require('../net2/SysManager.js');

const exec = require('child-process-promise').exec;

const { rrWithErrHandling } = require('../util/requestWrapper.js')

const redisKey = "sys:network:info";
const redisHashKey = "publicIp";
const redisHashKey6 = "publicIp6s";
const publicWanIPsHashKey = "publicWanIps";
const publicIPsHashKey = "publicIps";
const extensionManager = require('./ExtensionManager.js');
const policyKeyName = "ddns";
const f = require('../net2/Firewalla.js');

const _ = require('lodash');

class PublicIPSensor extends Sensor {
  async job() {
    try {
      let intf = null;
      let bindIP = null;
      let publicIP6s = [];
      if (this.wanIP) {
        intf = sysManager.getWanInterfaces().find(iface => iface && _.isArray(iface.ip4_addresses) && iface.ip4_addresses.includes(this.wanIP))
        if (!intf)
          log.error(`WAN interface with IP address ${this.wanIP} does not exist currently`);
        else
          bindIP = this.wanIP;
      } else {
        if (this.wanUUID) {
          intf = sysManager.getWanInterfaces().find(iface => iface && iface.uuid === this.wanUUID);
          if (!intf)
            log.error(`WAN interface with uuid ${this.wanUUID} does not exist currently`);
          else
            bindIP = intf && !_.isEmpty(intf.ip4_addresses) && intf.ip4_addresses[0];
        }
      }
      if (intf) {
        if (!bindIP)
          log.error(`WAN interface ${intf.name} does not have an IPv4 address to bind`);
        else {
          log.info(`Public IP discovery requests will be bound to WAN IP ${bindIP} on ${intf.name}`);
          publicIP6s = intf && _.isArray(intf.ip6_addresses) && sysManager.filterPublicIp6(intf.ip6_addresses).sort() || [];
        }
      }
      const publicIP = await this._discoverPublicIP(bindIP);
      if (publicIP)
        log.info(`Discovered overall public IP: ${publicIP}`);
      else
        log.error(`Cannot discover overall public IP`);

      const publicIPs = {};
      for (const iface of sysManager.getWanInterfaces()) {
        const ipv4 = iface && !_.isEmpty(iface.ip4_addresses) && iface.ip4_addresses[0];
        if (ipv4) {
          const wanPublicIP = await this._discoverPublicIP(ipv4);
          if (wanPublicIP) {
            log.info(`Discovered public IP ${wanPublicIP} on wan interface ${iface.name}`);
            publicIPs[iface.name] = wanPublicIP;
          } else {
            log.error(`Cannot discover public IP on wan interface ${iface.name}`);
          }
        }
      }

      // TODO: support v6
      const publicWanIps = sysManager.filterPublicIp4(sysManager.myWanIps(true).v4).sort();
      // connected public WAN IP overrides public IP from http request, this is mainly used in load-balance mode
      if (publicWanIps.length > 0) {
        // do not override public IP if dns/http request is bound to a specific WAN IP
        if (!bindIP && (!publicIP  || !publicWanIps.includes(publicIP))) {
          publicIP = publicWanIps[0];
        }
      }

      const existingPublicIP = await rclient.hgetAsync(redisKey, redisHashKey).then(result => result && JSON.parse(result)).catch((err) => null);
      const existingPublicWanIps = await rclient.hgetAsync(redisKey, publicWanIPsHashKey).then(result => result && JSON.parse(result)).then(result => _.isArray(result) && result.sort || []).catch((err) => []);
      const existingPublicIP6s = await rclient.hgetAsync(redisKey, redisHashKey6).then(result => result && JSON.parse(result)).catch((err) => null);
      const existingPublicIPs = await rclient.hgetAsync(redisKey, publicIPsHashKey).then(result => result && JSON.parse(result)).catch((err) => null);
      if(publicIP !== existingPublicIP || !_.isEqual(publicWanIps, existingPublicWanIps) || !_.isEqual(publicIP6s, existingPublicIP6s) || !_.isEqual(publicIPs, existingPublicIPs)) {
        await rclient.hsetAsync(redisKey, redisHashKey, JSON.stringify(publicIP));
        await rclient.hsetAsync(redisKey, redisHashKey6, JSON.stringify(publicIP6s));
        await rclient.hsetAsync(redisKey, publicWanIPsHashKey, JSON.stringify(publicWanIps));
        await rclient.hsetAsync(redisKey, publicIPsHashKey, JSON.stringify(publicIPs));
        sem.emitEvent({
          type: "PublicIP:Updated",
          ip: publicIP,
          ip6s: publicIP6s,
          wanIPs: publicIPs
        }); // local event within FireMain
        sem.emitEvent({
          type: "PublicIP:Updated",
          ip: publicIP,
          ip6s: publicIP6s,
          wanIPs: publicIPs,
          toProcess: 'FireApi'
        });
      }
    } catch(err) {
      log.error("Failed to query public ip:", err);
    }
  }

  async _discoverPublicIP(localIP) {
    let publicIP = await exec(`dig +short myip.opendns.com @resolver1.opendns.com ${localIP ? `-b ${localIP}` : ""}`).then(result => result.stdout.trim());
    if (publicIP)
      return publicIP;
    try {
      const options = {
        uri: this.config.publicIPAPI || "https://api.ipify.org?format=json",
        json: true
      };
      if (localIP)
        options["localAddress"] = localIP;
      const result = await rrWithErrHandling(options);
      if (result.body && result.body.ip) {
        publicIP = result.body.ip;
        return publicIP;
      }
    } catch (err) {
      log.error("Failed to discover public ip, err:", err);
    }
    return null;
  }

  async applyPolicy(host, ip, policy) {
    if (ip !== "0.0.0.0") {
      log.error("ddns policy is only supported on global level");
      return;
    }
    if (policy && policy.wanUUID)
      this.wanUUID = policy.wanUUID;
    else
      this.wanUUID = null;
    // in case there are multiple WAN IP addresses, user can specify a specific IP
    if (policy && policy.wanIP)
      this.wanIP = policy.wanIP;
    else
      this.wanIP = null;
    this.scheduleRunJob();
  }

  async run() {
    await sysManager.waitTillInitialized();
    this.scheduleRunJob();

    sem.on("PublicIP:Check", (event) => {
      this.scheduleRunJob();
    });

    if (f.isMain()) {
      extensionManager.registerExtension(policyKeyName, this, {
        applyPolicy: this.applyPolicy
      });
    }

    setInterval(() => {
      this.scheduleRunJob();
    }, this.config.interval * 1000 || 1000 * 60 * 60 * 2); // check every 2 hrs

    sem.on(Message.MSG_SYS_NETWORK_INFO_RELOADED, () => {
      log.info("Schedule reload PublicIPSensor since network info is reloaded");
      this.scheduleRunJob();
    })
  }

  scheduleRunJob() {
    if (this.reloadTask)
      clearTimeout(this.reloadTask);
    this.reloadTask = setTimeout(() => {
      this.job();
    }, 10000);
  }
}

module.exports = PublicIPSensor;
<commit_msg>catch error while using dig to discover public ip in PublicIPSensor.js<commit_after>/*    Copyright 2016-2021 Firewalla Inc.
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';
const log = require('../net2/logger.js')(__filename);

const Sensor = require('./Sensor.js').Sensor;

const sem = require('../sensor/SensorEventManager.js').getInstance();

const rclient = require('../util/redis_manager.js').getRedisClient()
const Message = require('../net2/Message.js');
const sysManager = require('../net2/SysManager.js');

const exec = require('child-process-promise').exec;

const { rrWithErrHandling } = require('../util/requestWrapper.js')

const redisKey = "sys:network:info";
const redisHashKey = "publicIp";
const redisHashKey6 = "publicIp6s";
const publicWanIPsHashKey = "publicWanIps";
const publicIPsHashKey = "publicIps";
const extensionManager = require('./ExtensionManager.js');
const policyKeyName = "ddns";
const f = require('../net2/Firewalla.js');

const _ = require('lodash');

class PublicIPSensor extends Sensor {
  async job() {
    try {
      let intf = null;
      let bindIP = null;
      let publicIP6s = [];
      if (this.wanIP) {
        intf = sysManager.getWanInterfaces().find(iface => iface && _.isArray(iface.ip4_addresses) && iface.ip4_addresses.includes(this.wanIP))
        if (!intf)
          log.error(`WAN interface with IP address ${this.wanIP} does not exist currently`);
        else
          bindIP = this.wanIP;
      } else {
        if (this.wanUUID) {
          intf = sysManager.getWanInterfaces().find(iface => iface && iface.uuid === this.wanUUID);
          if (!intf)
            log.error(`WAN interface with uuid ${this.wanUUID} does not exist currently`);
          else
            bindIP = intf && !_.isEmpty(intf.ip4_addresses) && intf.ip4_addresses[0];
        }
      }
      if (intf) {
        if (!bindIP)
          log.error(`WAN interface ${intf.name} does not have an IPv4 address to bind`);
        else {
          log.info(`Public IP discovery requests will be bound to WAN IP ${bindIP} on ${intf.name}`);
          publicIP6s = intf && _.isArray(intf.ip6_addresses) && sysManager.filterPublicIp6(intf.ip6_addresses).sort() || [];
        }
      }
      const publicIP = await this._discoverPublicIP(bindIP);
      if (publicIP)
        log.info(`Discovered overall public IP: ${publicIP}`);
      else
        log.error(`Cannot discover overall public IP`);

      const publicIPs = {};
      for (const iface of sysManager.getWanInterfaces()) {
        const ipv4 = iface && !_.isEmpty(iface.ip4_addresses) && iface.ip4_addresses[0];
        if (ipv4) {
          const wanPublicIP = await this._discoverPublicIP(ipv4);
          if (wanPublicIP) {
            log.info(`Discovered public IP ${wanPublicIP} on wan interface ${iface.name}`);
            publicIPs[iface.name] = wanPublicIP;
          } else {
            log.error(`Cannot discover public IP on wan interface ${iface.name}`);
          }
        }
      }

      // TODO: support v6
      const publicWanIps = sysManager.filterPublicIp4(sysManager.myWanIps(true).v4).sort();
      // connected public WAN IP overrides public IP from http request, this is mainly used in load-balance mode
      if (publicWanIps.length > 0) {
        // do not override public IP if dns/http request is bound to a specific WAN IP
        if (!bindIP && (!publicIP  || !publicWanIps.includes(publicIP))) {
          publicIP = publicWanIps[0];
        }
      }

      const existingPublicIP = await rclient.hgetAsync(redisKey, redisHashKey).then(result => result && JSON.parse(result)).catch((err) => null);
      const existingPublicWanIps = await rclient.hgetAsync(redisKey, publicWanIPsHashKey).then(result => result && JSON.parse(result)).then(result => _.isArray(result) && result.sort || []).catch((err) => []);
      const existingPublicIP6s = await rclient.hgetAsync(redisKey, redisHashKey6).then(result => result && JSON.parse(result)).catch((err) => null);
      const existingPublicIPs = await rclient.hgetAsync(redisKey, publicIPsHashKey).then(result => result && JSON.parse(result)).catch((err) => null);
      if(publicIP !== existingPublicIP || !_.isEqual(publicWanIps, existingPublicWanIps) || !_.isEqual(publicIP6s, existingPublicIP6s) || !_.isEqual(publicIPs, existingPublicIPs)) {
        await rclient.hsetAsync(redisKey, redisHashKey, JSON.stringify(publicIP));
        await rclient.hsetAsync(redisKey, redisHashKey6, JSON.stringify(publicIP6s));
        await rclient.hsetAsync(redisKey, publicWanIPsHashKey, JSON.stringify(publicWanIps));
        await rclient.hsetAsync(redisKey, publicIPsHashKey, JSON.stringify(publicIPs));
        sem.emitEvent({
          type: "PublicIP:Updated",
          ip: publicIP,
          ip6s: publicIP6s,
          wanIPs: publicIPs
        }); // local event within FireMain
        sem.emitEvent({
          type: "PublicIP:Updated",
          ip: publicIP,
          ip6s: publicIP6s,
          wanIPs: publicIPs,
          toProcess: 'FireApi'
        });
      }
    } catch(err) {
      log.error("Failed to query public ip:", err);
    }
  }

  async _discoverPublicIP(localIP) {
    let publicIP = await exec(`dig +short +time=3 +tries=2 myip.opendns.com @resolver1.opendns.com ${localIP ? `-b ${localIP}` : ""}`).then(result => result.stdout.trim()).catch((err) => null);
    if (publicIP)
      return publicIP;
    try {
      const options = {
        uri: this.config.publicIPAPI || "https://api.ipify.org?format=json",
        json: true
      };
      if (localIP)
        options["localAddress"] = localIP;
      const result = await rrWithErrHandling(options);
      if (result.body && result.body.ip) {
        publicIP = result.body.ip;
        return publicIP;
      }
    } catch (err) {
      log.error("Failed to discover public ip, err:", err);
    }
    return null;
  }

  async applyPolicy(host, ip, policy) {
    if (ip !== "0.0.0.0") {
      log.error("ddns policy is only supported on global level");
      return;
    }
    if (policy && policy.wanUUID)
      this.wanUUID = policy.wanUUID;
    else
      this.wanUUID = null;
    // in case there are multiple WAN IP addresses, user can specify a specific IP
    if (policy && policy.wanIP)
      this.wanIP = policy.wanIP;
    else
      this.wanIP = null;
    this.scheduleRunJob();
  }

  async run() {
    await sysManager.waitTillInitialized();
    this.scheduleRunJob();

    sem.on("PublicIP:Check", (event) => {
      this.scheduleRunJob();
    });

    if (f.isMain()) {
      extensionManager.registerExtension(policyKeyName, this, {
        applyPolicy: this.applyPolicy
      });
    }

    setInterval(() => {
      this.scheduleRunJob();
    }, this.config.interval * 1000 || 1000 * 60 * 60 * 2); // check every 2 hrs

    sem.on(Message.MSG_SYS_NETWORK_INFO_RELOADED, () => {
      log.info("Schedule reload PublicIPSensor since network info is reloaded");
      this.scheduleRunJob();
    })
  }

  scheduleRunJob() {
    if (this.reloadTask)
      clearTimeout(this.reloadTask);
    this.reloadTask = setTimeout(() => {
      this.job();
    }, 5000);
  }
}

module.exports = PublicIPSensor;
<|endoftext|>


<commit_before>const express = require('express');
const router = express.Router();
const _ = require('lodash');
const request = require("request");
const checkJwt = require('./../checkJwt');
const config = require('./../../config');
const models = require('../models');
const net = require('net');
const cache = require('apicache').middleware;

function getLastHints(callback) {
  models.Hint.findAll({
    include: [{
      model: models.HintType,
    }, models.User, models.Subarea],
  }).then((hints) => {
    const groupedHints = _.groupBy(hints, 'Subarea.name');

    const groupedHintsList = [];

    const sort = _.keys(groupedHints).sort();

    for (const i in sort) {
      groupedHintsList.push(groupedHints[sort[i]]);
    }

    const sortedHints = _.map(groupedHintsList, (groupedHint) => _.sortBy(groupedHint, ['createdAt']));

    const lastHints = _.map(sortedHints, (sortedHint) => _.last(sortedHint));

    callback(lastHints);
  });
}

/*
function getNextLocation(callback) {
  models.Group.findAll({
    include: [models.Subarea],
  }).then((groups) => {
    // Group by subarea
    const groupedGroups = _.groupBy(groups, 'Subarea.name');

    // Group by number of visits
    for (let key in groupedGroups) {
      groupedGroups[key] = _.groupBy(groupedGroups[key], 'visits');
    }

    // Loop every subarea
    _.map(groupedGroups, (subareaGroups) => { // Loops 6 times
      // Loop every groups with same visits
      _.map(subareaGroups, (sameVisitsGroups) => {
        // Generate shortest path between groups that have the same amount
        // of visits

        // Setup Google Direction Services
        const googleMapsClient = require('@google/maps').createClient({
          key: config.google.googleAppId,
        });

        // Loop sameVisitsGroups as destinations
        _.map(sameVisitsGroups, (destinationGroup) => {

          // Set other groups with same number of visits but destinationGroup as waypoints
          const waypoints = _.map(_.reject(sameVisitsGroups, destinationGroup), (group) => [group.latitude, group.longitude]);
          console.log(waypoints);
          // Get shortest from groups to destination
          googleMapsClient.directions({
            origin: [52.2, 6.2],
            destination: [destinationGroup.latitude, destinationGroup.longitude],
            waypoints: waypoints, // Everything but destinationGroup
            optimize: true,
            mode: "walking",
          }, (err, response) => {
            console.log("ROUTEEEE==============");
            console.log(response.json.routes[0]);
          });
        });

        // Return groups as waypoints and add every group (but last) to next visit category
      });
    });

    // console.log(groupedGroups);
  });
}*/

// TODO: Add caching function
/**
  Perform a call to Projection, a location prediction API.
*/
router.get('/', cache('1 minute'), (req, res) => {
  getLastHints((lastHints) => {
    // Prepare object array for Projection API.
    const requestBody = {
      lastLocations: _.map(lastHints, (hint) => {
        return {
          subarea: hint.Subarea.name.toLowerCase(),
          location: [hint.latitude, hint.longitude],
          timestamp: hint.createdAt
        };
      })
    }

    // Perform request to Projection API over a socket.
    const client = new net.Socket();
    client.connect(31337, '142.93.137.62', () => {
      console.log("Requesting Server");
      client.write(JSON.stringify(requestBody));
    });

    // Receive data
    let data = '';
    client.on('data', (chunk) => {
      data += chunk;
    });

    // Send data to client on response end.
    client.on('end', () => {
      const parsedData = JSON.parse(data);
      // TODO: Remove log file
      console.log(parsedData);
      // Send data to client
      res.send(JSON.stringify(parsedData));
    })
  });
});

module.exports = router;
<commit_msg>Added trycatch for prediction<commit_after>const express = require('express');
const router = express.Router();
const _ = require('lodash');
const request = require("request");
const checkJwt = require('./../checkJwt');
const config = require('./../../config');
const models = require('../models');
const net = require('net');
const cache = require('apicache').middleware;

function getLastHints(callback) {
  models.Hint.findAll({
    include: [{
      model: models.HintType,
    }, models.User, models.Subarea],
  }).then((hints) => {
    const groupedHints = _.groupBy(hints, 'Subarea.name');

    const groupedHintsList = [];

    const sort = _.keys(groupedHints).sort();

    for (const i in sort) {
      groupedHintsList.push(groupedHints[sort[i]]);
    }

    const sortedHints = _.map(groupedHintsList, (groupedHint) => _.sortBy(groupedHint, ['createdAt']));

    const lastHints = _.map(sortedHints, (sortedHint) => _.last(sortedHint));

    callback(lastHints);
  });
}

/*
function getNextLocation(callback) {
  models.Group.findAll({
    include: [models.Subarea],
  }).then((groups) => {
    // Group by subarea
    const groupedGroups = _.groupBy(groups, 'Subarea.name');

    // Group by number of visits
    for (let key in groupedGroups) {
      groupedGroups[key] = _.groupBy(groupedGroups[key], 'visits');
    }

    // Loop every subarea
    _.map(groupedGroups, (subareaGroups) => { // Loops 6 times
      // Loop every groups with same visits
      _.map(subareaGroups, (sameVisitsGroups) => {
        // Generate shortest path between groups that have the same amount
        // of visits

        // Setup Google Direction Services
        const googleMapsClient = require('@google/maps').createClient({
          key: config.google.googleAppId,
        });

        // Loop sameVisitsGroups as destinations
        _.map(sameVisitsGroups, (destinationGroup) => {

          // Set other groups with same number of visits but destinationGroup as waypoints
          const waypoints = _.map(_.reject(sameVisitsGroups, destinationGroup), (group) => [group.latitude, group.longitude]);
          console.log(waypoints);
          // Get shortest from groups to destination
          googleMapsClient.directions({
            origin: [52.2, 6.2],
            destination: [destinationGroup.latitude, destinationGroup.longitude],
            waypoints: waypoints, // Everything but destinationGroup
            optimize: true,
            mode: "walking",
          }, (err, response) => {
            console.log("ROUTEEEE==============");
            console.log(response.json.routes[0]);
          });
        });

        // Return groups as waypoints and add every group (but last) to next visit category
      });
    });

    // console.log(groupedGroups);
  });
}*/

// TODO: Add caching function
/**
  Perform a call to Projection, a location prediction API.
*/
router.get('/', cache('1 minute'), (req, res) => {
  getLastHints((lastHints) => {
    // Prepare object array for Projection API.
    const requestBody = {
      lastLocations: _.map(lastHints, (hint) => {
        return {
          subarea: hint.Subarea.name.toLowerCase(),
          location: [hint.latitude, hint.longitude],
          timestamp: hint.createdAt
        };
      })
    }

    try {
      // Perform request to Projection API over a socket.
      const client = new net.Socket();
      client.connect(31337, '142.93.137.62', () => {
        console.log("Requesting Server");
        client.write(JSON.stringify(requestBody));
      });

      // Receive data
      let data = '';
      client.on('data', (chunk) => {
        data += chunk;
      });

      // Send data to client on response end.
      client.on('end', () => {
        const parsedData = JSON.parse(data);
        // TODO: Remove log file
        console.log(parsedData);
        // Send data to client
        res.send(JSON.stringify(parsedData));
      });
    } catch (error) {
      res.status(500).send(error);
    }
  });
});

module.exports = router;
<|endoftext|>


<commit_before>var https  = require('https'),
    Q      = require('q'),
    config = require('../config.js');

/**
 * GitHub API client.
 * @returns {Object}
 */
var github = function () {
    // GitHub API endpoint.
    var ENDPOINT = 'api.github.com';

    // Request methods.
    var METHOD = {
        DELETE: 'DELETE',
        GET: 'GET',
        POST: 'POST',
        PUT: 'PUT'
    };

    /**
     * Calls the GitHub API.
     * @param {string} query
     * @param {string} method
     * @param {Object} data
     * @returns {promise}
     */
    var callApi = function (query, method, data) {
        var deferred = Q.defer(),
            resData = '';

        if (!method) {
            method = METHOD.GET;
        }

        var reqOptions = {
            method: method,
            host: ENDPOINT,
            path: query
        };

        if (data) {
            var dataJson = JSON.stringify(data);
            reqOptions.headers = {
                'Content-Type': 'application/json',
                'Content-Length': dataJson.length
            };
            console.log(method + ' https://' + ENDPOINT + query + ' ' + dataJson);
        } else {
            console.log(method + ' https://' + ENDPOINT + query);
        }

        var httpReq = https.request(reqOptions, function (httpRes) {
            httpRes.setEncoding('utf8');
            httpRes.on('data', function (chunk) {
                resData += chunk;
            });
            httpRes.on('end', function () {
                resData = JSON.parse(resData);
                deferred.resolve(resData);
            });
        });

        httpReq.on('error', function (err) {
            deferred.reject(err);
        });

        if (dataJson) {
            httpReq.write(dataJson);
        }

        httpReq.end();

        return deferred.promise;
    };

    /**
     * Authorizes with the GitHub API.
     * @param {string} clientId
     * @param {string} clientSecret
     * @returns {promise}
     */
    var authorize = function(clientId, clientSecret) {
        return callApi('/authorizations/clients/' + clientId, METHOD.PUT, {
            client_secret: clientSecret,
            scope: ['user', 'repo'],
            note: 'hello client'
        });
    };

    // Exposed methods.
    return {
        /**
         * Lists the information for a specific user.
         * @param {string} user
         * @returns {promise}
         */
        user: function(user) {
            return callApi('/users/' + user);
        },
        /**
         * Lists all repositories for a specific user.
         * @param {string} owner
         * @returns {promise}
         */
        repos: function(owner) {
            return callApi('/users/' + owner + '/repos?type=owner&sort=pushed');
        },
        /**
         * Lists all forks for a specific repository.
         * @param {string} owner
         * @param {string} repo
         * @returns {promise}
         */
        forks: function(owner, repo) {
            return callApi('/repos/' + owner + '/' + repo + '/forks');
        },
        /**
         * Lists all stargazers for a specific repository.
         * @param {string} owner
         * @param {string} repo
         * @returns {promise}
         */
        stargazers: function(owner, repo) {
            return callApi('/repos/' + owner + '/' + repo + '/stargazers');
        }
    };
};

module.exports = github;<commit_msg>Add missing headers to the github client<commit_after>var https  = require('https'),
    Q      = require('q'),
    config = require('../config.js');

/**
 * GitHub API client.
 * @returns {Object}
 */
var github = function () {
    // GitHub API endpoint.
    var ENDPOINT = 'api.github.com';

    // Request methods.
    var METHOD = {
        DELETE: 'DELETE',
        GET: 'GET',
        POST: 'POST',
        PUT: 'PUT'
    };

    /**
     * Calls the GitHub API.
     * @param {string} query
     * @param {string} method
     * @param {Object} data
     * @returns {promise}
     */
    var callApi = function (query, method, data) {
        var deferred = Q.defer(),
            resData = '';

        if (!method) {
            method = METHOD.GET;
        }

        var reqOptions = {
            method: method,
            host: ENDPOINT,
            path: query,
            headers: {
                'User-Agent': 'hello-server',
                'Accept': 'application/json',
                'Content-Length': 0
            }
        };

        if (data) {
            var dataJson = JSON.stringify(data);
            reqOptions.headers['Content-Type'] = 'application/json';
            reqOptions.headers['Content-Length'] = dataJson.length;
            console.log(method + ' https://' + ENDPOINT + query + ' ' + dataJson);
        } else {
            console.log(method + ' https://' + ENDPOINT + query);
        }

        var httpReq = https.request(reqOptions, function (httpRes) {
            // todo: handle invalid requests
            httpRes.setEncoding('utf8');
            httpRes.on('data', function (chunk) {
                resData += chunk;
            });
            httpRes.on('end', function () {
                resData = JSON.parse(resData);
                deferred.resolve(resData);
            });
        });

        httpReq.on('error', function (err) {
            deferred.reject(err);
        });

        if (dataJson) {
            httpReq.write(dataJson);
        }

        httpReq.end();

        return deferred.promise;
    };

    /**
     * Authorizes with the GitHub API.
     * @param {string} clientId
     * @param {string} clientSecret
     * @returns {promise}
     */
    var authorize = function(clientId, clientSecret) {
        return callApi('/authorizations/clients/' + clientId, METHOD.PUT, {
            client_secret: clientSecret,
            scope: ['user', 'repo'],
            note: 'hello client'
        });
    };

    // Exposed methods.
    return {
        /**
         * Lists the information for a specific user.
         * @param {string} user
         * @returns {promise}
         */
        user: function(user) {
            return callApi('/users/' + user);
        },
        /**
         * Lists all repositories for a specific user.
         * @param {string} owner
         * @returns {promise}
         */
        repos: function(owner) {
            return callApi('/users/' + owner + '/repos?type=owner&sort=pushed');
        },
        /**
         * Lists all forks for a specific repository.
         * @param {string} owner
         * @param {string} repo
         * @returns {promise}
         */
        forks: function(owner, repo) {
            return callApi('/repos/' + owner + '/' + repo + '/forks');
        },
        /**
         * Lists all stargazers for a specific repository.
         * @param {string} owner
         * @param {string} repo
         * @returns {promise}
         */
        stargazers: function(owner, repo) {
            return callApi('/repos/' + owner + '/' + repo + '/stargazers');
        }
    };
};

module.exports = github;<|endoftext|>