<commit_before>angular.module('ngWhisk')
    .controller('requestController', function($scope, $http, $log, $rootScope, ngDialog) {
        $log.log('inside');
        var API_URL = 'https://service.us.apiconnect.ibmcloud.com/gws/apigateway/api/b2844128c00ef617cbec07a2c205b9d411c2d31da094f2120c9054289445ee2f/OpenWhiskContact/api/v1';
        //var API_URL = 'https://6e28847c-de9b-4446-8207-c2fadad1d143-gws.api-gw.mybluemix.net/OpenWhiskContact/api/v1'; //$rootScope.process.env.OWAPI; // OpenWhisk exposed API
        $scope.emailSent = false; // setting message logic to false not display any message by default

        $scope.sendMail = function () { //The send button will call this method to make an API to a OpenWhisk Action exposed as a API

            //scope binding the form data
            var data = {
                myName: $scope.myName,
                myEmail: $scope.myEmail,
                myUrl: $scope.myUrl,
                myDescription: $scope.myDescription
            };
            // adding content type for post header, this is needed for when calling OpenWhisk API
            var config = {
                headers : {
                    'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
                    //'Content-Type': 'application/json;charset=UTF-8;'
                    //'Content-Type': 'application/json;'
                }
            };
            // Simple POST request example (passing data) :
            $http.post(API_URL, data, config)
                .then(function(response) {
                    // this callback will be called asynchronously
                    // when the response is available
                    $log.log('Email Sent with response status of: ' + JSON.stringify(response.status));
                    $scope.emailSent = true;

                    // Injecting success into the array of alerts
                    $scope.alerts = [ {type: 'success', msg: ''} ];
                    $scope.alerts[0].msg = 'Thanks, ' + $scope.myName + ' we have got your request, and we will be in touch. ';

                    // After user sent the email, then clear the values to be empty
                    $scope.myName = "";
                    $scope.myEmail = "";
                    $scope.myUrl = "";
                    $scope.myDescription = "";
                }, function(response) {
                    // called asynchronously if an error occurs
                    // or server returns response with an error status.
                    $log.log("Error occurred with status: " + '' + JSON.stringify(response.status));
                    if ($scope.alerts) {
                    // alerts have value
                         // if there was an error, then display this message
                        $scope.alerts[0].msg = JSON.stringify(response.status);
                    } else {
                    // alerts is still null
                         // if there was an error, then display this message
                        $scope.alerts = [ {type: 'danger', msg: ''} ];
                        $scope.alerts[0].msg = JSON.stringify(response.status);
                    }

                    $scope.emailSent = true;
                    $scope.alerts[0].msg = 'Oops! There was a problem sending your request, please contact Johan Rodin directly at johan.rodin@se.ibm.com';
                });
        };

        // Remove alert message area
        $scope.closeAlert = function (index) {
            $scope.alerts.splice(index, 1);
        };

        ///////Handling the popup
        $rootScope.jsonData = '{"foo": "bar"}';
        $rootScope.theme = 'ngdialog-theme-default';
        $scope.open = function () {
            ngDialog.open({ template: 'firstDialogId', controller: 'InsideCtrl' });
        };

        $scope.openDefault = function () {
            ngDialog.open({
                template: 'firstDialogId',
                controller: 'InsideCtrl',
                className: 'ngdialog-theme-default'
            });
        };

        $scope.openPlain = function () {
            $rootScope.theme = 'ngdialog-theme-plain';

            ngDialog.open({
                template: 'firstDialogId',
                controller: 'InsideCtrl',
                className: 'ngdialog-theme-plain'
            });
        };

        $scope.openTemplate = function () {
            $scope.value = true;

            ngDialog.open({
                template: 'externalTemplate.html',
                className: 'ngdialog-theme-plain',
                scope: $scope
            });
        };

    });

//popup ctrl
angular
    .module('ngWhisk')
    .controller('InsideCtrl', function ($scope, ngDialog) {
        $scope.openSecond = function () {
            ngDialog.open({
                template: '
Close all by click here!
',
                plain: true,
                closeByEscape: false,
                controller: 'SecondModalCtrl'
            });
        };
    });

angular
    .module('ngWhisk')
    .controller('SecondModalCtrl', function ($scope, ngDialog) {
        $scope.closeSecond = function () {
            ngDialog.close();
        };
    });

<commit_msg>encoding<commit_after>angular.module('ngWhisk')
    .controller('requestController', function($scope, $http, $log, $rootScope, ngDialog) {
        $log.log('inside');
        var API_URL = 'https://service.us.apiconnect.ibmcloud.com/gws/apigateway/api/b2844128c00ef617cbec07a2c205b9d411c2d31da094f2120c9054289445ee2f/OpenWhiskContact/api/v1';
        //var API_URL = 'https://6e28847c-de9b-4446-8207-c2fadad1d143-gws.api-gw.mybluemix.net/OpenWhiskContact/api/v1'; //$rootScope.process.env.OWAPI; // OpenWhisk exposed API
        $scope.emailSent = false; // setting message logic to false not display any message by default

        $scope.sendMail = function () { //The send button will call this method to make an API to a OpenWhisk Action exposed as a API

            //scope binding the form data
            var data = {
                myName: $scope.myName,
                myEmail: $scope.myEmail,
                myUrl: $scope.myUrl,
                myDescription: $scope.myDescription
            };
            // adding content type for post header, this is needed for when calling OpenWhisk API
            var config = {
                headers : {
                    //'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
                    'Content-Type': 'application/json;charset=UTF-8;'
                    //'Content-Type': 'application/json;'
                }
            };
            // Simple POST request example (passing data) :
            $http.post(API_URL, data, config)
                .then(function(response) {
                    // this callback will be called asynchronously
                    // when the response is available
                    $log.log('Email Sent with response status of: ' + JSON.stringify(response.status));
                    $scope.emailSent = true;

                    // Injecting success into the array of alerts
                    $scope.alerts = [ {type: 'success', msg: ''} ];
                    $scope.alerts[0].msg = 'Thanks, ' + $scope.myName + ' we have got your request, and we will be in touch. ';

                    // After user sent the email, then clear the values to be empty
                    $scope.myName = "";
                    $scope.myEmail = "";
                    $scope.myUrl = "";
                    $scope.myDescription = "";
                }, function(response) {
                    // called asynchronously if an error occurs
                    // or server returns response with an error status.
                    $log.log("Error occurred with status: " + '' + JSON.stringify(response.status));
                    if ($scope.alerts) {
                    // alerts have value
                         // if there was an error, then display this message
                        $scope.alerts[0].msg = JSON.stringify(response.status);
                    } else {
                    // alerts is still null
                         // if there was an error, then display this message
                        $scope.alerts = [ {type: 'danger', msg: ''} ];
                        $scope.alerts[0].msg = JSON.stringify(response.status);
                    }

                    $scope.emailSent = true;
                    $scope.alerts[0].msg = 'Oops! There was a problem sending your request, please contact Johan Rodin directly at johan.rodin@se.ibm.com';
                });
        };

        // Remove alert message area
        $scope.closeAlert = function (index) {
            $scope.alerts.splice(index, 1);
        };

        ///////Handling the popup
        $rootScope.jsonData = '{"foo": "bar"}';
        $rootScope.theme = 'ngdialog-theme-default';
        $scope.open = function () {
            ngDialog.open({ template: 'firstDialogId', controller: 'InsideCtrl' });
        };

        $scope.openDefault = function () {
            ngDialog.open({
                template: 'firstDialogId',
                controller: 'InsideCtrl',
                className: 'ngdialog-theme-default'
            });
        };

        $scope.openPlain = function () {
            $rootScope.theme = 'ngdialog-theme-plain';

            ngDialog.open({
                template: 'firstDialogId',
                controller: 'InsideCtrl',
                className: 'ngdialog-theme-plain'
            });
        };

        $scope.openTemplate = function () {
            $scope.value = true;

            ngDialog.open({
                template: 'externalTemplate.html',
                className: 'ngdialog-theme-plain',
                scope: $scope
            });
        };

    });

//popup ctrl
angular
    .module('ngWhisk')
    .controller('InsideCtrl', function ($scope, ngDialog) {
        $scope.openSecond = function () {
            ngDialog.open({
                template: '
Close all by click here!
',
                plain: true,
                closeByEscape: false,
                controller: 'SecondModalCtrl'
            });
        };
    });

angular
    .module('ngWhisk')
    .controller('SecondModalCtrl', function ($scope, ngDialog) {
        $scope.closeSecond = function () {
            ngDialog.close();
        };
    });

<|endoftext|>


<commit_before>Vue.filter('date', function (value, format) {
    if(value){
        var date = new Date(value);
        var mm = date.getMonth() + 1;
        var dd = date.getDate();

        var d = (dd>9 ? '' : '0') + dd;
        var m = (mm>9 ? '' : '0') + mm;
        var y = date.getFullYear();

        var sep = format.substring(1, 2);
        format = format.replace(new RegExp(sep, 'g'), '');

        var result = [];
        if(format == 'Ymd'){
            result.push(y);
            result.push(m);
            result.push(d);
        }else if(format == 'dmY'){
            result.push(d);
            result.push(m);
            result.push(y);
        }
        return result.join(sep ? sep : '/');
    }else{
        return '';
    }
});

Vue.filter('datetime', function (value, format) {
    if(value){
        var date = new Date(value);
        var mm = date.getMonth() + 1;
        var dd = date.getDate();
        var y = date.getFullYear();
        var hh = date.getHours();
        var ii = date.getMinutes();
        var ss = date.getSeconds();

        var d = (dd>9 ? '' : '0') + dd;
        var m = (mm>9 ? '' : '0') + mm;
        var h = (hh>9 ? '' : '0') + hh;
        var i = (ii>9 ? '' : '0') + ii;
        var s = (ss>9 ? '' : '0') + ss;

        var sep = format.substring(1, 2);
        format = format.replace(new RegExp(sep, 'g'), '');

        var date_data = [];
        var time_data = [];

        time_data.push(h);
        time_data.push(i);
        //time_data.push(s);

        if(format.indexOf('Ymd') !== -1){
            date_data.push(y);
            date_data.push(m);
            date_data.push(d);
        }else{
            date_data.push(d);
            date_data.push(m);
            date_data.push(y);
        }
        return date_data.join(sep ? sep : '/') + ' ' + time_data.join(':');
    }else{
        return '';
    }
});<commit_msg>Date filters use moments<commit_after>Vue.filter('date', function (value, format) {
    if(value){
        return moment(value, "YYYY-MM-DD hh:mm:ss").format('DD/MM/YYYY');
    }else{
        return '';
    }
});

Vue.filter('datetime', function (value, format) {
    if(value){
        return moment(value, "YYYY-MM-DD hh:mm:ss").format('DD/MM/YYYY à hh:mm');
    }else{
        return '';
    }
});<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Service.extend({
  store: Ember.inject.service(),
  feedModel: null,
  userModel: null,
  createFeedAndUserModels: function() {
    var newFeedModel = this.get('store').createRecord('feed', {});
		var newUserModel = this.get('store').createRecord('user', {});
    this.set('feedModel', newFeedModel);
    this.set('userModel', newUserModel);
    return {
      feed: newFeedModel,
      user: newUserModel
    };
  },
  toChangeset: function() {
    var feedModel = this.get('feedModel');
    var changes = [];
    feedModel.get('operators').map(function(operator) {
      if (operator.get('include_in_changeset') === true) {
        changes.push({
          action: 'createUpdate',
          operator: operator.toChange()
        });
      }
    });
    changes.push({
      action: 'createUpdate',
      feed: feedModel.toChange()
    });
    var changeset = this.get('store').createRecord('changeset', {
      notes: 'This is a test. TODO put a custom message here.',
      payload: {
        changes: changes
      }
    });
		changeset.set('user', this.get('userModel'));
    return changeset;
  }
});
<commit_msg>improve changeset notes<commit_after>import Ember from 'ember';

export default Ember.Service.extend({
  store: Ember.inject.service(),
  feedModel: null,
  userModel: null,
  createFeedAndUserModels: function() {
    var newFeedModel = this.get('store').createRecord('feed', {});
		var newUserModel = this.get('store').createRecord('user', {});
    this.set('feedModel', newFeedModel);
    this.set('userModel', newUserModel);
    return {
      feed: newFeedModel,
      user: newUserModel
    };
  },
  toChangeset: function() {
    var feedModel = this.get('feedModel');
    var changes = [];
    feedModel.get('operators').map(function(operator) {
      if (operator.get('include_in_changeset') === true) {
        changes.push({
          action: 'createUpdate',
          operator: operator.toChange()
        });
      }
    });
    changes.push({
      action: 'createUpdate',
      feed: feedModel.toChange()
    });
    var changeset = this.get('store').createRecord('changeset', {
      notes: `Changed submitted from Feed Registry for feed at ${feedModel.get('url')}`,
      payload: {
        changes: changes
      }
    });
		changeset.set('user', this.get('userModel'));
    return changeset;
  }
});
<|endoftext|>


<commit_before>/**
 * sidebar 相关功能
 */
define( function ( require ) {
    var
        $ = require( "jquery" ),
        layer = window.layer,
        MenuSource = require( "./menuSource" ),
        App = require( "./app" ),
        namespace = "pkui.sidebar",
        ArtTemplate = require( "artTemplate" )
    ;

    AppSidebar.prototype.defaults = {
        oftenUsedUrl: null,
        recentUsedUrl: null,
        saveUsedMenuUrl: null,
        toggleSelector: null,
        sidebarSelector: null,
        closeBtnSelector: ".da-sidebar-closeBtn",
        // 一旦内容改变，三分钟后发送请求进行保存
        saveDelayTime: 3 * 60 * 1000,
        // 显示的最常使用的最大数
        maxOftenUsedItemNum: 6,
        // 显示的最近使用的最大数
        maxRecentUsedItemNum: 10,

        template: null
    };

    AppSidebar.prototype.defaults.template = ''
        +   '
'
        +   '
常用功能
'
        +   '    {{each oftenUsedMenuList }}'
        +   '        {{if $index < '+ AppSidebar.prototype.defaults.maxOftenUsedItemNum +'}}'
        +   '
'
        +   '             {{$value.menuName}}{{$value.count}}
'
        +   '        {{/if}}'
        +   '    {{/each}}'
        +   '
'
        +   '
'
        +   '
最近使用
'
        +   '    {{each recentUsedMenuList }}'
        +   '        {{if $index < '+ AppSidebar.prototype.defaults.maxRecentUsedItemNum +'}}'
        +   '
'
        +   '             {{$value.menuName}}
'
        +   '        {{/if}}'
        +   '    {{/each}}'
        +   '
';

    /**
     * 构造函数
     * @param opts
     * @constructor
     */
    function AppSidebar( opts ) {
        this.opts = $.extend( true, {}, this.defaults, opts );
        this.init();
    }

    /**
     * 初始化方法
     */
    AppSidebar.prototype.init = function () {
        var _this = this;
        this.render();
        this.bind();

        this.templateRender = ArtTemplate.compile( this.opts.template );

        this.getData( function () {
            _this._fmtData();
            _this.draw();
        } );
    };

    /**
     * 准备数据
     */
    AppSidebar.prototype.render = function () {
        this.$toggle = $( this.opts.toggleSelector );
        this.$sidebar = $( this.opts.sidebarSelector );
    };

    /**
     * 绑定事件
     */
    AppSidebar.prototype.bind = function () {
        var
            _this = this,
            timerId
        ;

        // 点击开关时，显示/隐藏 侧边栏
        this.$toggle.on( "click." + namespace, function () {
            var $sidebar = _this.$sidebar;

            if ( $sidebar.is( ".app-sidebar-showed" ) ) {
                _this.hide();
            }
            else {
                _this.show();
            }
        } );

        // 点击关闭按钮
        this.$sidebar.on( "click." + namespace, this.opts.closeBtnSelector, function () {
            _this.hide();
        } );

        // 点击app条目，打开app
        this.$sidebar.on( "click." + namespace, ".use-group-item", function () {

            var $item = $( this );

            // 开启 窗口
            new App(null, {
                "icon": $item.data( "icon" ),
                "title": $item.data( "menuName" ),
                "src": "./tpl/system/index.html",
                "menuId": $item.data( "menuId" ),
                "mode": "default"})
        } );

        // 监听 在 $document 上触发的 inited.app 事件
        $( document ).on( "inited.app", function ( event, appOptions ) {
            if ( appOptions && appOptions.menuId != null && appOptions.mode === "default" ) {
                _this.redraw( appOptions.menuId );
            }
        } );

        // 内容改变后，进行保存
        this.$sidebar.on( "changed." + namespace, function ( event, isRefresh ) {
            // 立马更新（）如果有更新）
            if ( isRefresh && timerId ) {
                _this.save();
            }
            // 取消前一个计时任务
            if ( timerId ) {
                window.clearTimeout( timerId );
            }
            // 开始计时任务
            timerId = window.setTimeout( function () {
                _this.save();
                timerId = null;
            }, _this.saveDelayTime )
        } );

        // 关闭（刷新）网页前进行保存
        $( window ).unload( function () {
            _this.$sidebar.trigger( "changed." + namespace, true );
        } );
    };

    /**
     * 获取数据
     * 1. 菜单数据
     * 2. 常用菜单数据
     *      { 'menuId':使用次数,... }
     *      {'1':12,'2':8,'3':7,'4':6,'5':5,'6':4,'7':3,'8':2}
     * 3. 最近使用菜单数据
     *      { menuId1, menuId2 }
     *      1,2,3,4,5,6,7,8,9,10
     */
    AppSidebar.prototype.getData = function ( callback ) {
        var
            _this = this
        ;
        /*
        this._getData( this.opts.menuUrl, function ( jsonResult ) {
            refresh();
            _this.sysMenuList = jsonResult.data;
        } );
        */
        this.sysMenuList = MenuSource.getList();

        this._getData( this.opts.oftenUsedUrl, function ( jsonResult ) {
            _this.oftenUsedMenuList = jsonResult.data || [];
            refresh();
        } );
        this._getData( this.opts.recentUsedUrl, function ( jsonResult ) {
            _this.recentUsedMenuList = jsonResult.data || [];
            refresh();
        } );

        function refresh() {

            if ( _this.hasOwnProperty( "sysMenuList" ) &&
                 _this.hasOwnProperty( "oftenUsedMenuList" ) &&
                 _this.hasOwnProperty( "recentUsedMenuList" ) ) {

                callback && callback();
            }
        }
    };

    /**
     * 获取数据的公共方法
     * @param url
     * @param callback
     * @private
     */
    AppSidebar.prototype._getData = function ( url, callback ) {
        $.ajax( {
            url: url
        } ).done( function ( jsonResult ) {
            if ( !jsonResult ||  jsonResult.success === false ) {
                layer.alert( ( jsonResult && jsonResult.message ) || "【应用侧边栏】请求数据失败：服务器内部错误！", { icon: 2 } );
                return;
            }
            callback && callback( jsonResult );
        } ).fail( function () {
            // 提示网络错误
            layer.alert( '【应用侧边栏】请求数据失败：网络错误/登陆失效。', { icon: 0 } );
        } ).always( function () {
            // do something
        } );
    };

    /**
     * 显示侧边栏
     */
    AppSidebar.prototype.show = function () {
        var $sidebar = this.$sidebar;
        $sidebar.stop().animate( { left: 0 }, function () {
            $sidebar.addClass( "app-sidebar-showed" )
        } );
    };
    /**
     * 隐藏侧边栏
     */
    AppSidebar.prototype.hide = function () {
        var $sidebar = this.$sidebar;
        $sidebar.stop().animate( { left: -$sidebar.outerWidth() }, function () {
            $sidebar.removeClass( "app-sidebar-showed" );
        } );
    };

    /**
     * 绘制侧边栏的内容
     */
    AppSidebar.prototype.draw = function () {
        var
            html
        ;

        html = this.templateRender( {
            oftenUsedMenuList: this.oftenUsedMenuList,
            recentUsedMenuList: this.recentUsedMenuList
        } );

        this.$sidebar.html( html );
    };

    /**
     * 格式化数据。
     * this.oftenUsedMenuList 和 this.recentUsedMenuList 使用的都是 this.sysMenuList 的数据，
     * 也就是说sysMenu对象的引用是相同的。
     * @private
     * @example
        this.sysMenuList = {
            1: { menuId: 1, menuName: "字典管理", icon: "fa fa-x" },
            2: { menuId: 2, menuName: "菜单管理", icon: "fa fa-xx" },
            ...
        }
        this.oftenUsedMenuList = [
            { menuId: 1, menuName: "字典管理", icon: "fa fa-x", count: 3 },
            { menuId: 2, menuName: "菜单管理", icon: "fa fa-xx", count: 2 },
            ...
        ]
        this.recentUsedMenuList = [
            { menuId: 1, menuName: "字典管理", icon: "fa fa-x", count: 3 },
            { menuId: 2, menuName: "菜单管理", icon: "fa fa-xx", count: 2 },
            ...
        ]

     */
    AppSidebar.prototype._fmtData = function () {
        var temp,
            _this = this,
            lastPos,
            str,
            menuId, sysMenu
        ;

        // 将全局菜单数据格式化为字典格式
        if ( this.sysMenuList ) {
            temp = {};
            $.each( this.sysMenuList, function ( index, sysMenu ) {
                temp[ sysMenu[ "menuId" ] ] = {
                    menuId: sysMenu[ "menuId" ],
                    menuName: sysMenu[ "menuName" ],
                    icon: sysMenu[ "icon" ]
                }
            } );
            this.sysMenuList = temp;
        }

        // 判断是否符合特定格式
        if ( this.oftenUsedMenuList &&
             typeof this.oftenUsedMenuList === "string" &&
             this.oftenUsedMenuList.indexOf( ":" ) !== -1 ) {
            try {
                temp = [];
                // 将单引号替换为双引号
                this.oftenUsedMenuList = this.oftenUsedMenuList.replace( /'/g, '"');
                // 转为json，如果转换失败，则说明字符串json格式不完整，
                this.oftenUsedMenuList = $.parseJSON( this.oftenUsedMenuList );
            } catch ( e ) {
                // 截取前面可用部分，进行转换
                lastPos = _this.oftenUsedMenuList.lastIndexOf( "," );
                str = _this.oftenUsedMenuList.substring( 0, lastPos ) + "}";
                _this.oftenUsedMenuList = $.parseJSON( str );
            }

            for ( menuId in _this.oftenUsedMenuList ) {
                if ( _this.oftenUsedMenuList.hasOwnProperty( menuId ) ) {
                    sysMenu = _this.sysMenuList[ menuId ];
                    sysMenu.count = _this.oftenUsedMenuList[ menuId ];
                    temp.push( sysMenu );
                }
            }
            _this.oftenUsedMenuList = temp;

        }
        if ( this.recentUsedMenuList &&
             typeof this.recentUsedMenuList === "string" &&
             ( this.recentUsedMenuList.length === 1 || this.recentUsedMenuList.indexOf( "," ) !== -1 ) ) {

            temp = [];

            this.recentUsedMenuList = this.recentUsedMenuList.split( "," );

            $.each( this.recentUsedMenuList, function ( index, menuId ) {
                sysMenu = _this.sysMenuList[ menuId ];
                if ( sysMenu.hasOwnProperty( "menuId" ) ) {
                    temp.push( sysMenu );
                }
            } );

            this.recentUsedMenuList = temp;

        }

        // 排序
        this._sortOftenUsedMenuList();

    };

    /**
     * 当打开一个新的app时，重新绘制侧边栏内容，并产生一个 changed 事件
     * @param menuId
     */
    AppSidebar.prototype.redraw = function ( menuId ) {
        var
            _this = this,
            sysMenu
        ;

        /* 最近使用 */
        // 1. 若存在列表中，则删除
        $.each( this.recentUsedMenuList, function ( index, item ) {
            if ( item.menuId == menuId ) {
                _this.recentUsedMenuList.splice( index, 1 );
                return false;
            }
        } );
        // 2. 将其添加列表第一位
        this.recentUsedMenuList.unshift( this.sysMenuList[ menuId ] );

        /* 最常使用 */
        // 1. 若存在，则自增
        if ( this.isInOftenUsedList( menuId ) ) {
            $.each( this.oftenUsedMenuList, function ( index, item ) {
                if ( item.menuId == menuId ) {
                    item.count++;
                    return false;
                }
            } );
        }
        // 2. 若不存在，则追加到末尾
        else {
            sysMenu = this.sysMenuList[ menuId ];
            sysMenu.count = 1;
            this.oftenUsedMenuList.push( sysMenu );
        }
        // 排序
        this._sortOftenUsedMenuList();

        // 重新绘制
        this.draw();

        /**
         * 内容改变后执行
         * @event changed.pkui.sidebar
         */
        this.$sidebar.trigger( "changed." + namespace );
    };

    AppSidebar.prototype.isInOftenUsedList =  function ( menuId, list ) {
        var isExist = false;
        list = list || this.oftenUsedMenuList;
        $.each( list, function ( index, item ) {
            if ( item.menuId == menuId ) {
                isExist = true;
                return false;
            }
        } );
        return isExist;
    };
    AppSidebar.prototype.isInRecentUsedList =  function ( menuId ) {
        return this.isInOftenUsedList( menuId, this.recentUsedMenuList );
    };

    /**
     * 保存，发送的数据
     * @example
        {
            recent: "1,2,3,4,5,6,7,8,9,10",
            often: "{'1':12,'2':8,'3':7,'4':6,'5':5,'6':4,'7':3,'8':2}"
        }
     */
    AppSidebar.prototype.save = function () {
        var
            data,
            recent = "",
            often = ""
        ;

        $.each( this.recentUsedMenuList, function ( index, menu ) {
            if ( ! (menu && menu.hasOwnProperty( "menuId" ) ) ) {
                return;
            }
            recent += menu.menuId + ",";
        } );
        if ( recent.indexOf( "," ) !== -1 ) {
            recent = recent.substring( 0, recent.length - 1 );
        }

        $.each( this.oftenUsedMenuList, function ( index, menu ) {
            var
                menuId,
                count
            ;
            if ( ! (menu && menu.hasOwnProperty( "menuId" ) ) ) {
                return;
            }
            menuId = menu.menuId;
            count = menu.count || 1;
            often += "'" + menuId + "':" + count + ",";
        } );
        if ( often.indexOf( "," ) !== -1 ) {
            often = "{" + often.substring( 0, often.length - 1 ) + "}";
        }

        data = {
            recent: recent,
            often: often
        };

        $.ajax( {
            url: this.opts.saveUsedMenuUrl,
            data: data
        } ).done( function ( jsonResult ) {
            if ( jsonResult && jsonResult.success ) {
                console.info( "侧边栏数据保存成功" );
            }
            else {
                layer.alert( "侧边栏数据保存失败：服务器内部错误。", { icon: 2 } );
            }
        } );

    };

    /**
     * 排序
     * @private
     */
    AppSidebar.prototype._sortOftenUsedMenuList = function () {
        this.oftenUsedMenuList.sort( function ( prevMenu, nextMenu ) {
            var
                prevCount = prevMenu.count || 1,
                nextCount = nextMenu.count || 1
                ;
            // 倒序
            return nextCount - prevCount;
        } );
    };

    return AppSidebar;
} );<commit_msg>【desktop】app-sidebar.js：修复saveDelayTime参数使用的错误。<commit_after>/**
 * sidebar 相关功能
 */
define( function ( require ) {
    var
        $ = require( "jquery" ),
        layer = window.layer,
        MenuSource = require( "./menuSource" ),
        App = require( "./app" ),
        namespace = "pkui.sidebar",
        ArtTemplate = require( "artTemplate" )
    ;

    AppSidebar.prototype.defaults = {
        oftenUsedUrl: null,
        recentUsedUrl: null,
        saveUsedMenuUrl: null,
        toggleSelector: null,
        sidebarSelector: null,
        closeBtnSelector: ".da-sidebar-closeBtn",
        // 一旦内容改变，三分钟后发送请求进行保存
        saveDelayTime: 3 * 60 * 1000,
        // 显示的最常使用的最大数
        maxOftenUsedItemNum: 6,
        // 显示的最近使用的最大数
        maxRecentUsedItemNum: 10,

        template: null
    };

    AppSidebar.prototype.defaults.template = ''
        +   '
'
        +   '
常用功能
'
        +   '    {{each oftenUsedMenuList }}'
        +   '        {{if $index < '+ AppSidebar.prototype.defaults.maxOftenUsedItemNum +'}}'
        +   '
'
        +   '             {{$value.menuName}}{{$value.count}}
'
        +   '        {{/if}}'
        +   '    {{/each}}'
        +   '
'
        +   '
'
        +   '
最近使用
'
        +   '    {{each recentUsedMenuList }}'
        +   '        {{if $index < '+ AppSidebar.prototype.defaults.maxRecentUsedItemNum +'}}'
        +   '
'
        +   '             {{$value.menuName}}
'
        +   '        {{/if}}'
        +   '    {{/each}}'
        +   '
';

    /**
     * 构造函数
     * @param opts
     * @constructor
     */
    function AppSidebar( opts ) {
        this.opts = $.extend( true, {}, this.defaults, opts );
        this.init();
    }

    /**
     * 初始化方法
     */
    AppSidebar.prototype.init = function () {
        var _this = this;
        this.render();
        this.bind();

        this.templateRender = ArtTemplate.compile( this.opts.template );

        this.getData( function () {
            _this._fmtData();
            _this.draw();
        } );
    };

    /**
     * 准备数据
     */
    AppSidebar.prototype.render = function () {
        this.$toggle = $( this.opts.toggleSelector );
        this.$sidebar = $( this.opts.sidebarSelector );
    };

    /**
     * 绑定事件
     */
    AppSidebar.prototype.bind = function () {
        var
            _this = this,
            timerId
        ;

        // 点击开关时，显示/隐藏 侧边栏
        this.$toggle.on( "click." + namespace, function () {
            var $sidebar = _this.$sidebar;

            if ( $sidebar.is( ".app-sidebar-showed" ) ) {
                _this.hide();
            }
            else {
                _this.show();
            }
        } );

        // 点击关闭按钮
        this.$sidebar.on( "click." + namespace, this.opts.closeBtnSelector, function () {
            _this.hide();
        } );

        // 点击app条目，打开app
        this.$sidebar.on( "click." + namespace, ".use-group-item", function () {

            var $item = $( this );

            // 开启 窗口
            new App(null, {
                "icon": $item.data( "icon" ),
                "title": $item.data( "menuName" ),
                "src": "./tpl/system/index.html",
                "menuId": $item.data( "menuId" ),
                "mode": "default"})
        } );

        // 监听 在 $document 上触发的 inited.app 事件
        $( document ).on( "inited.app", function ( event, appOptions ) {
            if ( appOptions && appOptions.menuId != null && appOptions.mode === "default" ) {
                _this.redraw( appOptions.menuId );
            }
        } );

        // 内容改变后，进行保存
        this.$sidebar.on( "changed." + namespace, function ( event, isRefresh ) {
            // 立马更新（）如果有更新）
            if ( isRefresh && timerId ) {
                _this.save();
            }
            // 取消前一个计时任务
            if ( timerId ) {
                window.clearTimeout( timerId );
            }
            // 开始计时任务
            timerId = window.setTimeout( function () {
                _this.save();
                timerId = null;
            }, _this.opts.saveDelayTime )
        } );

        // 关闭（刷新）网页前进行保存
        $( window ).unload( function () {
            _this.$sidebar.trigger( "changed." + namespace, true );
        } );
    };

    /**
     * 获取数据
     * 1. 菜单数据
     * 2. 常用菜单数据
     *      { 'menuId':使用次数,... }
     *      {'1':12,'2':8,'3':7,'4':6,'5':5,'6':4,'7':3,'8':2}
     * 3. 最近使用菜单数据
     *      { menuId1, menuId2 }
     *      1,2,3,4,5,6,7,8,9,10
     */
    AppSidebar.prototype.getData = function ( callback ) {
        var
            _this = this
        ;
        /*
        this._getData( this.opts.menuUrl, function ( jsonResult ) {
            refresh();
            _this.sysMenuList = jsonResult.data;
        } );
        */
        this.sysMenuList = MenuSource.getList();

        this._getData( this.opts.oftenUsedUrl, function ( jsonResult ) {
            _this.oftenUsedMenuList = jsonResult.data || [];
            refresh();
        } );
        this._getData( this.opts.recentUsedUrl, function ( jsonResult ) {
            _this.recentUsedMenuList = jsonResult.data || [];
            refresh();
        } );

        function refresh() {

            if ( _this.hasOwnProperty( "sysMenuList" ) &&
                 _this.hasOwnProperty( "oftenUsedMenuList" ) &&
                 _this.hasOwnProperty( "recentUsedMenuList" ) ) {

                callback && callback();
            }
        }
    };

    /**
     * 获取数据的公共方法
     * @param url
     * @param callback
     * @private
     */
    AppSidebar.prototype._getData = function ( url, callback ) {
        $.ajax( {
            url: url
        } ).done( function ( jsonResult ) {
            if ( !jsonResult ||  jsonResult.success === false ) {
                layer.alert( ( jsonResult && jsonResult.message ) || "【应用侧边栏】请求数据失败：服务器内部错误！", { icon: 2 } );
                return;
            }
            callback && callback( jsonResult );
        } ).fail( function () {
            // 提示网络错误
            layer.alert( '【应用侧边栏】请求数据失败：网络错误/登陆失效。', { icon: 0 } );
        } ).always( function () {
            // do something
        } );
    };

    /**
     * 显示侧边栏
     */
    AppSidebar.prototype.show = function () {
        var $sidebar = this.$sidebar;
        $sidebar.stop().animate( { left: 0 }, function () {
            $sidebar.addClass( "app-sidebar-showed" )
        } );
    };
    /**
     * 隐藏侧边栏
     */
    AppSidebar.prototype.hide = function () {
        var $sidebar = this.$sidebar;
        $sidebar.stop().animate( { left: -$sidebar.outerWidth() }, function () {
            $sidebar.removeClass( "app-sidebar-showed" );
        } );
    };

    /**
     * 绘制侧边栏的内容
     */
    AppSidebar.prototype.draw = function () {
        var
            html
        ;

        html = this.templateRender( {
            oftenUsedMenuList: this.oftenUsedMenuList,
            recentUsedMenuList: this.recentUsedMenuList
        } );

        this.$sidebar.html( html );
    };

    /**
     * 格式化数据。
     * this.oftenUsedMenuList 和 this.recentUsedMenuList 使用的都是 this.sysMenuList 的数据，
     * 也就是说sysMenu对象的引用是相同的。
     * @private
     * @example
        this.sysMenuList = {
            1: { menuId: 1, menuName: "字典管理", icon: "fa fa-x" },
            2: { menuId: 2, menuName: "菜单管理", icon: "fa fa-xx" },
            ...
        }
        this.oftenUsedMenuList = [
            { menuId: 1, menuName: "字典管理", icon: "fa fa-x", count: 3 },
            { menuId: 2, menuName: "菜单管理", icon: "fa fa-xx", count: 2 },
            ...
        ]
        this.recentUsedMenuList = [
            { menuId: 1, menuName: "字典管理", icon: "fa fa-x", count: 3 },
            { menuId: 2, menuName: "菜单管理", icon: "fa fa-xx", count: 2 },
            ...
        ]

     */
    AppSidebar.prototype._fmtData = function () {
        var temp,
            _this = this,
            lastPos,
            str,
            menuId, sysMenu
        ;

        // 将全局菜单数据格式化为字典格式
        if ( this.sysMenuList ) {
            temp = {};
            $.each( this.sysMenuList, function ( index, sysMenu ) {
                temp[ sysMenu[ "menuId" ] ] = {
                    menuId: sysMenu[ "menuId" ],
                    menuName: sysMenu[ "menuName" ],
                    icon: sysMenu[ "icon" ]
                }
            } );
            this.sysMenuList = temp;
        }

        // 判断是否符合特定格式
        if ( this.oftenUsedMenuList &&
             typeof this.oftenUsedMenuList === "string" &&
             this.oftenUsedMenuList.indexOf( ":" ) !== -1 ) {
            try {
                temp = [];
                // 将单引号替换为双引号
                this.oftenUsedMenuList = this.oftenUsedMenuList.replace( /'/g, '"');
                // 转为json，如果转换失败，则说明字符串json格式不完整，
                this.oftenUsedMenuList = $.parseJSON( this.oftenUsedMenuList );
            } catch ( e ) {
                // 截取前面可用部分，进行转换
                lastPos = _this.oftenUsedMenuList.lastIndexOf( "," );
                str = _this.oftenUsedMenuList.substring( 0, lastPos ) + "}";
                _this.oftenUsedMenuList = $.parseJSON( str );
            }

            for ( menuId in _this.oftenUsedMenuList ) {
                if ( _this.oftenUsedMenuList.hasOwnProperty( menuId ) ) {
                    sysMenu = _this.sysMenuList[ menuId ];
                    sysMenu.count = _this.oftenUsedMenuList[ menuId ];
                    temp.push( sysMenu );
                }
            }
            _this.oftenUsedMenuList = temp;

        }
        if ( this.recentUsedMenuList &&
             typeof this.recentUsedMenuList === "string" &&
             ( this.recentUsedMenuList.length === 1 || this.recentUsedMenuList.indexOf( "," ) !== -1 ) ) {

            temp = [];

            this.recentUsedMenuList = this.recentUsedMenuList.split( "," );

            $.each( this.recentUsedMenuList, function ( index, menuId ) {
                sysMenu = _this.sysMenuList[ menuId ];
                if ( sysMenu.hasOwnProperty( "menuId" ) ) {
                    temp.push( sysMenu );
                }
            } );

            this.recentUsedMenuList = temp;

        }

        // 排序
        this._sortOftenUsedMenuList();

    };

    /**
     * 当打开一个新的app时，重新绘制侧边栏内容，并产生一个 changed 事件
     * @param menuId
     */
    AppSidebar.prototype.redraw = function ( menuId ) {
        var
            _this = this,
            sysMenu
        ;

        /* 最近使用 */
        // 1. 若存在列表中，则删除
        $.each( this.recentUsedMenuList, function ( index, item ) {
            if ( item.menuId == menuId ) {
                _this.recentUsedMenuList.splice( index, 1 );
                return false;
            }
        } );
        // 2. 将其添加列表第一位
        this.recentUsedMenuList.unshift( this.sysMenuList[ menuId ] );

        /* 最常使用 */
        // 1. 若存在，则自增
        if ( this.isInOftenUsedList( menuId ) ) {
            $.each( this.oftenUsedMenuList, function ( index, item ) {
                if ( item.menuId == menuId ) {
                    item.count++;
                    return false;
                }
            } );
        }
        // 2. 若不存在，则追加到末尾
        else {
            sysMenu = this.sysMenuList[ menuId ];
            sysMenu.count = 1;
            this.oftenUsedMenuList.push( sysMenu );
        }
        // 排序
        this._sortOftenUsedMenuList();

        // 重新绘制
        this.draw();

        /**
         * 内容改变后执行
         * @event changed.pkui.sidebar
         */
        this.$sidebar.trigger( "changed." + namespace );
    };

    AppSidebar.prototype.isInOftenUsedList =  function ( menuId, list ) {
        var isExist = false;
        list = list || this.oftenUsedMenuList;
        $.each( list, function ( index, item ) {
            if ( item.menuId == menuId ) {
                isExist = true;
                return false;
            }
        } );
        return isExist;
    };
    AppSidebar.prototype.isInRecentUsedList =  function ( menuId ) {
        return this.isInOftenUsedList( menuId, this.recentUsedMenuList );
    };

    /**
     * 保存，发送的数据
     * @example
        {
            recent: "1,2,3,4,5,6,7,8,9,10",
            often: "{'1':12,'2':8,'3':7,'4':6,'5':5,'6':4,'7':3,'8':2}"
        }
     */
    AppSidebar.prototype.save = function () {
        var
            data,
            recent = "",
            often = ""
        ;

        $.each( this.recentUsedMenuList, function ( index, menu ) {
            if ( ! (menu && menu.hasOwnProperty( "menuId" ) ) ) {
                return;
            }
            recent += menu.menuId + ",";
        } );
        if ( recent.indexOf( "," ) !== -1 ) {
            recent = recent.substring( 0, recent.length - 1 );
        }

        $.each( this.oftenUsedMenuList, function ( index, menu ) {
            var
                menuId,
                count
            ;
            if ( ! (menu && menu.hasOwnProperty( "menuId" ) ) ) {
                return;
            }
            menuId = menu.menuId;
            count = menu.count || 1;
            often += "'" + menuId + "':" + count + ",";
        } );
        if ( often.indexOf( "," ) !== -1 ) {
            often = "{" + often.substring( 0, often.length - 1 ) + "}";
        }

        data = {
            recent: recent,
            often: often
        };

        $.ajax( {
            url: this.opts.saveUsedMenuUrl,
            data: data
        } ).done( function ( jsonResult ) {
            if ( jsonResult && jsonResult.success ) {
                console.info( "侧边栏数据保存成功" );
            }
            else {
                layer.alert( "侧边栏数据保存失败：服务器内部错误。", { icon: 2 } );
            }
        } );

    };

    /**
     * 排序
     * @private
     */
    AppSidebar.prototype._sortOftenUsedMenuList = function () {
        this.oftenUsedMenuList.sort( function ( prevMenu, nextMenu ) {
            var
                prevCount = prevMenu.count || 1,
                nextCount = nextMenu.count || 1
                ;
            // 倒序
            return nextCount - prevCount;
        } );
    };

    return AppSidebar;
} );<|endoftext|>


<commit_before>import {roundNumber, prettyNumber, prettyPercent, attrToTitle} from 'ember-ist-model-builder/display-helpers';
import IstModelDisplayHelpers from 'ember-ist-model-builder/display-helpers';

import {roundNumber, prettyNumber, prettyPercent, attrToTitle};
export default IstModelDisplayHelpers;
<commit_msg>fixed exports again<commit_after>import {roundNumber, prettyNumber, prettyPercent, attrToTitle} from 'ember-ist-model-builder/display-helpers';
import IstModelDisplayHelpers from 'ember-ist-model-builder/display-helpers';

export {roundNumber, prettyNumber, prettyPercent, attrToTitle};
export default IstModelDisplayHelpers;
<|endoftext|>


<commit_before>'use strict';

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Wallet = mongoose.model('Wallet');
var crypto = require('crypto');

var BallotBoxSchema = new Schema({
	//hash will be SHA1(ballotbox.yes+ballotbox.no+ballotbox.protest)
	hash: {
		type: String,
		default: '',
		trim: true,
		required: 'proposal hash cannot be blank',
	},
	yes: {
		type: String,
		default: '',
		trim: true,
		required: 'ballotbox yes address cannot be blank',
	},
	no: {
		type: String,
		default: '',
		trim: true,
		required: 'ballotbox no address cannot be blank',
	},
	protest: {
		type: String,
		default: '',
		trim: true,
		required: 'protest address cannot be blank',
	},
});

BallotBoxSchema.statics.create = function(proposal_title, callback) {

	Wallet.create_vote_address(Date.now(), proposal_title, function(err, data) {
		this.yes = data;
	});

	Wallet.create_vote_address(Date.now(), proposal_title, function(err, data) {
		this.no = data;
	});

	Wallet.create_vote_address(Date.now(), proposal_title, function(err, data) {
		this.protest = data;
	});

	var sha = crypto.createHash('sha1');
	sha.write(this.yes+this.no+this.protest);
	this.hash = sha.read();

	this.save(callback);
};

mongoose.model('BallotBox', BallotBoxSchema);<commit_msg>edit Wallet<commit_after>'use strict';

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Wallet = mongoose.model('Wallet');
var crypto = require('crypto');

var BallotBoxSchema = new Schema({
	//hash will be SHA1(ballotbox.yes+ballotbox.no+ballotbox.protest)
	hash: {
		type: String,
		default: '',
		trim: true,
		required: 'proposal hash cannot be blank',
	},
	yes: {
		type: String,
		default: '',
		trim: true,
		required: 'ballotbox yes address cannot be blank',
	},
	no: {
		type: String,
		default: '',
		trim: true,
		required: 'ballotbox no address cannot be blank',
	},
	protest: {
		type: String,
		default: '',
		trim: true,
		required: 'protest address cannot be blank',
	},
});

BallotBoxSchema.statics.create = function(proposal_title, callback) {

	//Wallet.create_vote_address(Date.now(), proposal_title, function(err, data) {
	//	this.yes = data;
	//});
//
	//Wallet.create_vote_address(Date.now(), proposal_title, function(err, data) {
	//	this.no = data;
	//});
//
	//Wallet.create_vote_address(Date.now(), proposal_title, function(err, data) {
	//	this.protest = data;
	//});
//
	//var sha = crypto.createHash('sha1');
	//sha.write(this.yes+this.no+this.protest);
	//this.hash = sha.read();

	this.save(callback);
};

mongoose.model('BallotBox', BallotBoxSchema);<|endoftext|>


<commit_before>'use strict';

const {Router} = require('express');

const router = new Router;
module.exports = router;

router.get('/bills/all', (req, res, next) => {
  const {app} = req;
  if (app.data && app.data.bills && app.data.bills.length) {
    res.json(app.data.bills);
  } else {
    res.status(500).json({ error: 'Bills data is not available' });
  }
});
<commit_msg>Filter bills by state, /bills/state/:stateCode<commit_after>'use strict';

const {Router} = require('express');

const topRouter = new Router;
module.exports = topRouter;

////// BILLS //////

const billsRouter = new Router;
topRouter.use('/bills', billsRouter);

// all `/bills/*` endpoints need the app data to be loaded.
billsRouter.use((req, res, next) => {
  const {app} = req;
  if (! (app.data && app.data.bills && app.data.bills.length)) {
    res.status(500).json({ error: 'Bills data is not available' });
  }
  // Available downstream
  next();
});

billsRouter.get('/all', (req, res, next) => {
  res.json(req.app.data.bills);
});

billsRouter.get('/state/:stateCode', (req, res, next) => {
  const bills = req.app.data.bills;
  const requestedState = req.params.stateCode;
  const billsByState = bills.filter((bill) => bill.state === requestedState);
  console.log(`Serving ${billsByState.length} bills for ${requestedState}`);
  res.json(billsByState);
});
<|endoftext|>


<commit_before>var restify = require('restify');
var knox = require('knox');
var crypto = require('crypto');

// get config files from ./conf/
var apiOptions, awsOptions, dbOptions;
try {
    apiOptions = require('./conf/api');
} catch(e) {
    console.log('ERROR: API configuration is missing!');
    console.log('Please rename conf/api.js.example to conf/api.js and edit the file to your needs.');
    process.exit(1);
}
try {
    awsOptions = require('./conf/aws');
} catch(e) {
    console.log('ERROR: AWS configuration is missing!');
    console.log('Please rename conf/aws.js.example to conf/aws.js and edit the file to your needs.');
    process.exit(1);
}
try {
    dbOptions = require('./conf/db');
} catch(e) {
    console.log('ERROR: DB configuration is missing!');
    console.log('Please rename conf/db.js.example to conf/db.js and edit the file to your needs.');
    process.exit(1);
}

// intialzie DB stuff
var knex = require('knex')(dbOptions);
var bookshelf = require('bookshelf')(knex);

// intialize S3 stuff
var s3Client = knox.createClient(awsOptions.s3ClientConfig);
var baseURL = awsOptions.bucketBaseURL;

// start server, define routes
// TODO: move routes to their own files
var server = restify.createServer();
server.use(restify.queryParser());
// CORS stuff
server.use(restify.CORS({
    credentials: true
}));

server.get('/', function(req, res, next) {
    s3Client.list({}, function(err, data){
        if(err) {
            console.log('ERROR: There was an issue getting a list of objects from the S3 bucket:');
            console.log(err);
            res.send(err);
            next();
        }
        else { // success!
            var gifList = [];
            for(var i = 0; i < data.Contents.length; ++i) {
                gifList.push({
                    fileName: data.Contents[i].Key,
                    url: baseURL + data.Contents[i].Key
                });
            }
            res.send(gifList);
            next();
        }
    });
});
// originally from taken from https://devcenter.heroku.com/articles/s3-upload-node
server.get('/sign_s3', function(req, res){
    var AWS_ACCESS_KEY = awsOptions.s3ClientConfig.key;
    var AWS_SECRET_KEY = awsOptions.s3ClientConfig.secret;
    var S3_BUCKET = awsOptions.s3ClientConfig.bucket;
    var object_name = req.query.s3_object_name;
    var mime_type = req.query.s3_object_type;

    var now = new Date();
    var expires = Math.ceil((now.getTime() + 10000)/1000); // 10 seconds from now
    var amz_headers = "x-amz-acl:public-read";

    var put_request = "PUT\n\n"+mime_type+"\n"+expires+"\n"+amz_headers+"\n/"+S3_BUCKET+"/"+object_name;

    var signature = crypto.createHmac('sha1', AWS_SECRET_KEY).update(put_request).digest('base64');
    signature = encodeURIComponent(signature.trim());
    signature = signature.replace('%2B','+');

    var url = 'http://'+S3_BUCKET+'.s3.amazonaws.com/'+object_name;

    var credentials = {
        signed_request: url+"?AWSAccessKeyId="+AWS_ACCESS_KEY+"&Expires="+expires+"&Signature="+signature,
        url: url
    };
    res.write(JSON.stringify(credentials));
    res.end();
});

// start server
server.listen(apiOptions.port, function() {
    console.log('Server is now online at: %s', server.url);
});<commit_msg>moved routes out of server.js. now checking if sql is open; quit otherwise<commit_after>var restify = require('restify');
var knox = require('knox');
var crypto = require('crypto');

// get config files from ./conf/
var apiOptions, awsOptions, dbOptions;
try {
    apiOptions = require('./conf/api');
} catch(e) {
    console.log('ERROR: API configuration is missing!');
    console.log('Please rename conf/api.js.example to conf/api.js and edit the file to your needs.');
    process.exit(1);
}
try {
    awsOptions = require('./conf/aws');
} catch(e) {
    console.log('ERROR: AWS configuration is missing!');
    console.log('Please rename conf/aws.js.example to conf/aws.js and edit the file to your needs.');
    process.exit(1);
}
try {
    dbOptions = require('./conf/db');
} catch(e) {
    console.log('ERROR: DB configuration is missing!');
    console.log('Please rename conf/db.js.example to conf/db.js and edit the file to your needs.');
    process.exit(1);
}

// intialzie DB stuff
var knex = require('knex')(dbOptions);
var bookshelf = require('bookshelf')(knex);

// since knex/bookshelf uses connection pool, need to fake a query to check if sql if reachable
knex.raw('select 1+1 as result')
    .then(function (result) {
        // it worked... silent pass!
    })
.catch(function (error) {
        console.log('ERROR: Could not access your database. Check the config and make sure SQL is running!');
        process.exit(1);
    });

// intialize S3 stuff
var s3Client = knox.createClient(awsOptions.s3ClientConfig);
var baseURL = awsOptions.bucketBaseURL;

// start server, define routes
// TODO: move routes to their own files
var server = restify.createServer();
server.use(restify.queryParser());
// CORS stuff
server.use(restify.CORS({
    credentials: true
}));

require('./routes')(server);

// start server
server.listen(apiOptions.port, function() {
    console.log('Server is now online at: %s', server.url);
});<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 The Sphere Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @namespace System
 * @author Jos Kuijpers (Rahkiin)
 */

/**
 * Abort the current game with a message.
 *
 * @param {String} msg - Message to show after abort.
 * @noreturn
 */
System.abort = function(msg) {
}

/**
 * Exit the game unconditionally.
 *
 * @noreturn
 */
System.exit = function() {
}
<commit_msg>Add extension system to System. Add System properties. Add System.Debug.<commit_after>/*
 * Copyright (c) 2014 The Sphere Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @namespace System
 * @author Jos Kuijpers (Rahkiin)
 */

/**
 * Get the version number of the engine.
 * @static
 */
System.version = 1; // 00.00.01

/**
 * Get the version string of the engine.
 * @static
 */
System.versionString = "Sphere Pegasus 0.0.1";

/**
 * An array of extensions of type System.Extension.
 *
 * The key is the extension point. This is also the string used
 * when importing the module using require().
 *
 * @static
 */
System.extensions = {
	"sqlite" : null
}

/**
 * Abort the current game with a message.
 *
 * @param {String} msg - Message to show after abort.
 * @noreturn
 */
System.abort = function(msg) {
}

/**
 * Exit the game unconditionally.
 *
 * @noreturn
 */
System.exit = function() {
}

/**
 * Get the resolved path of a resource, relative to the
 * the engine or user directory (/ or ~/).
 *
 * This function should use relative paths, because otherwise it
 * would be useless with File().
 *
 * @param {String} query - The resource query.
 * @param {String} [extension=] - The default extension.
 * @param {String} [folder=] - The default folder.
 */
System.resolve = function(query,extension,folder) {
}

/**
 * Try to run the garbage collector.
 *
 * @warning Only use while debugging and use at own risk.
 */
System.Debug.garbageCollect() {
}

/**
 * Name of the extension.
 */
System.Extension.prototype.name = "SQLite";

/**
 * Version number of the extension.
 */
System.Extension.prototype.version = 1;

/**
 * Version string  of the extension.
 */
System.Extension.prototype.versionString = "SQLite 0.0.1";

/**
 * Get the functionality description of the extension.
 *
 * This description is per-extension and can be used to provide
 * information about the functionalities of the plugin,
 * such as whether a specific action is available in this version.
 */
System.Extension.prototype.functionalityDescription = {};
<|endoftext|>


<commit_before>'use strict';

const init = require('../base/init');
const config = require('../base/config');
const date2 = require('../base/date2');
const mongo2 = require('../mongodb/mongo2');
const my2 = require('../mysql/my2');
const imageb = require('../image/image-base');

init.add(
  (done) => {
    console.log('copy mongodb images to mysql image.');
    let c = 0;
    let cursor = mongo2.db.collection('images').find().sort({ id: 1 });
    (function read() {
      cursor.next(function (err, r) {
        if (err) return done(err);
        if (!r) return done();
        c++;
        if (c % 100 === 0) {
          process.stdout.write(c + ' ');
        }
        r.id = r._id;
        delete r._id;
        r.vers = JSON.stringify(r.vers || null);
        my2.query('replace into image set ?', r, (err) => {
          if (err) return done(err);
          setImmediate(read);
        });
      });
    })();
  },
  (done) => {
    mongo2.close(done);
  },
  (done) => {
    my2.close(done);
  },
  (done) => {
    console.log('done.');
    done();
  }
);

init.run();
<commit_msg>update c2mysql-images.<commit_after>'use strict';

const init = require('../base/init');
const config = require('../base/config');
const date2 = require('../base/date2');
const mongo2 = require('../mongodb/mongo2');
const my2 = require('../mysql/my2');
const imageb = require('../image/image-base');

init.add(
  (done) => {
    console.log('copy mongodb images to mysql image.');
    let c = 0;
    let cursor = mongo2.db.collection('images').find().sort({ id: 1 });
    (function read() {
      cursor.next(function (err, r) {
        if (err) return done(err);
        if (!r) return done();
        c++;
        if (c % 100 === 0) {
          process.stdout.write(c + ' ');
        }
        let img = {
          id: r._id,
          uid: r.uid,
          cdate: r.cdate,
          vers: JSON.stringify(r.vers || null),
          comment: r.comment,
        }
        my2.query('replace into image set ?', img, (err) => {
          if (err) return done(err);
          setImmediate(read);
        });
      });
    })();
  },
  (done) => {
    mongo2.close(done);
  },
  (done) => {
    my2.close(done);
  },
  (done) => {
    console.log('done.');
    done();
  }
);

init.run();
<|endoftext|>


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

var path = require('path');
var util = require('util');
/**
 * Return a Function that requires an API from the disk
 * @param  {String} filename Filename of API
 * @return {function}        function used to require the API from disk
 * @private
 */
function requireAPI(filename) {
    return function(options) {
      var type = typeof options;
      var version;
      if (type === 'string') {
        version = options;
        options = {};
      } else if (type === 'object') {
        version = options.version;
        delete options.version;
      } else {
        throw new Error('Argument error: Accepts only string or object');
      }
      try {
        var endpointPath = path.join(__dirname, filename, path.basename(version));
        var Endpoint = require(endpointPath);
        var ep = new Endpoint(options);
        ep.google = this; // for drive.google.transporter
        return Object.freeze(ep); // create new & freeze
      } catch (e) {
        throw new Error(util.format('Unable to load endpoint %s("%s"): %s',
          filename, version, e.message));
      }
    };
  }
  /**
   * APIs to be exported
   * @type {Object}
   * @private
   */
var APIs = {
  'adexchangebuyer': requireAPI('adexchangebuyer'),
  'adexchangeseller': requireAPI('adexchangeseller'),
  'admin': requireAPI('admin'),
  'adsense': requireAPI('adsense'),
  'adsensehost': requireAPI('adsensehost'),
  'analytics': requireAPI('analytics'),
  'androidpublisher': requireAPI('androidpublisher'),
  'appsactivity': requireAPI('appsactivity'),
  'appstate': requireAPI('appstate'),
  'audit': requireAPI('audit'),
  'autoscaler': requireAPI('autoscaler'),
  'bigquery': requireAPI('bigquery'),
  'blogger': requireAPI('blogger'),
  'books': requireAPI('books'),
  'calendar': requireAPI('calendar'),
  'civicinfo': requireAPI('civicinfo'),
  'cloudmonitoring': requireAPI('cloudmonitoring'),
  'compute': requireAPI('compute'),
  'content': requireAPI('content'),
  'coordinate': requireAPI('coordinate'),
  'customsearch': requireAPI('customsearch'),
  'datastore': requireAPI('datastore'),
  'dfareporting': requireAPI('dfareporting'),
  'discovery': requireAPI('discovery'),
  'dns': requireAPI('dns'),
  'doubleclickbidmanager': requireAPI('doubleclickbidmanager'),
  'doubleclicksearch': requireAPI('doubleclicksearch'),
  'drive': requireAPI('drive'),
  'freebase': requireAPI('freebase'),
  'fusiontables': requireAPI('fusiontables'),
  'games': requireAPI('games'),
  'gamesManagement': requireAPI('gamesManagement'),
  'gan': requireAPI('gan'),
  'genomics': requireAPI('genomics'),
  'gmail': requireAPI('gmail'),
  'groupsmigration': requireAPI('groupsmigration'),
  'groupssettings': requireAPI('groupssettings'),
  'identitytoolkit': requireAPI('identitytoolkit'),
  'licensing': requireAPI('licensing'),
  'manager': requireAPI('manager'),
  'mapsengine': requireAPI('mapsengine'),
  'mirror': requireAPI('mirror'),
  'oauth2': requireAPI('oauth2'),
  'pagespeedonline': requireAPI('pagespeedonline'),
  'plus': requireAPI('plus'),
  'plusDomains': requireAPI('plusDomains'),
  'prediction': requireAPI('prediction'),
  'pubsub': requireAPI('pubsub'),
  'qpxExpress': requireAPI('qpxExpress'),
  'replicapool': requireAPI('replicapool'),
  'reseller': requireAPI('reseller'),
  'resourceviews': requireAPI('resourceviews'),
  'siteVerification': requireAPI('siteVerification'),
  'spectrum': requireAPI('spectrum'),
  'sqladmin': requireAPI('sqladmin'),
  'storage': requireAPI('storage'),
  'taskqueue': requireAPI('taskqueue'),
  'tasks': requireAPI('tasks'),
  'translate': requireAPI('translate'),
  'urlshortener': requireAPI('urlshortener'),
  'webfonts': requireAPI('webfonts'),
  'webmasters': requireAPI('webmasters'),
  'youtube': requireAPI('youtube'),
  'youtubeAnalytics': requireAPI('youtubeAnalytics')
};

/**
 * Exports the APIs
 * @type {Object}
 */
module.exports = APIs;

/**
 * @callback callback
 * @param {Error} err Error object if an error occurred.
 * @param {object} data Response data object.
 */<commit_msg>Regenerate apis/index.js<commit_after>/**
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

var path = require('path');
var util = require('util');
/**
 * Return a Function that requires an API from the disk
 * @param  {String} filename Filename of API
 * @return {function}        function used to require the API from disk
 * @private
 */
function requireAPI(filename) {
  return function(options) {
    var type = typeof options;
    var version;
    if (type === 'string') {
      version = options;
      options = {};
    } else if (type === 'object') {
      version = options.version;
      delete options.version;
    } else {
      throw new Error('Argument error: Accepts only string or object');
    }
    try {
      var endpointPath = path.join(__dirname, filename, path.basename(version));
      var Endpoint = require(endpointPath);
      var ep = new Endpoint(options);
      ep.google = this; // for drive.google.transporter
      return Object.freeze(ep); // create new & freeze
    } catch (e) {
      throw new Error(util.format('Unable to load endpoint %s("%s"): %s',
        filename, version, e.message));
    }
  };
}
/**
 * APIs to be exported
 * @type {Object}
 * @private
 */
var APIs = {
  'adexchangebuyer': requireAPI('adexchangebuyer'),
  'adexchangeseller': requireAPI('adexchangeseller'),
  'admin': requireAPI('admin'),
  'adsense': requireAPI('adsense'),
  'adsensehost': requireAPI('adsensehost'),
  'analytics': requireAPI('analytics'),
  'androidpublisher': requireAPI('androidpublisher'),
  'appsactivity': requireAPI('appsactivity'),
  'appstate': requireAPI('appstate'),
  'audit': requireAPI('audit'),
  'autoscaler': requireAPI('autoscaler'),
  'bigquery': requireAPI('bigquery'),
  'blogger': requireAPI('blogger'),
  'books': requireAPI('books'),
  'calendar': requireAPI('calendar'),
  'civicinfo': requireAPI('civicinfo'),
  'cloudmonitoring': requireAPI('cloudmonitoring'),
  'compute': requireAPI('compute'),
  'content': requireAPI('content'),
  'coordinate': requireAPI('coordinate'),
  'customsearch': requireAPI('customsearch'),
  'datastore': requireAPI('datastore'),
  'dfareporting': requireAPI('dfareporting'),
  'discovery': requireAPI('discovery'),
  'dns': requireAPI('dns'),
  'doubleclickbidmanager': requireAPI('doubleclickbidmanager'),
  'doubleclicksearch': requireAPI('doubleclicksearch'),
  'drive': requireAPI('drive'),
  'freebase': requireAPI('freebase'),
  'fusiontables': requireAPI('fusiontables'),
  'games': requireAPI('games'),
  'gamesManagement': requireAPI('gamesManagement'),
  'gan': requireAPI('gan'),
  'genomics': requireAPI('genomics'),
  'gmail': requireAPI('gmail'),
  'groupsmigration': requireAPI('groupsmigration'),
  'groupssettings': requireAPI('groupssettings'),
  'identitytoolkit': requireAPI('identitytoolkit'),
  'licensing': requireAPI('licensing'),
  'manager': requireAPI('manager'),
  'mapsengine': requireAPI('mapsengine'),
  'mirror': requireAPI('mirror'),
  'oauth2': requireAPI('oauth2'),
  'pagespeedonline': requireAPI('pagespeedonline'),
  'plus': requireAPI('plus'),
  'plusDomains': requireAPI('plusDomains'),
  'prediction': requireAPI('prediction'),
  'pubsub': requireAPI('pubsub'),
  'qpxExpress': requireAPI('qpxExpress'),
  'replicapool': requireAPI('replicapool'),
  'reseller': requireAPI('reseller'),
  'resourceviews': requireAPI('resourceviews'),
  'siteVerification': requireAPI('siteVerification'),
  'spectrum': requireAPI('spectrum'),
  'sqladmin': requireAPI('sqladmin'),
  'storage': requireAPI('storage'),
  'taskqueue': requireAPI('taskqueue'),
  'tasks': requireAPI('tasks'),
  'translate': requireAPI('translate'),
  'urlshortener': requireAPI('urlshortener'),
  'webfonts': requireAPI('webfonts'),
  'webmasters': requireAPI('webmasters'),
  'youtube': requireAPI('youtube'),
  'youtubeAnalytics': requireAPI('youtubeAnalytics')
};

/**
 * Exports the APIs
 * @type {Object}
 */
module.exports = APIs;

/**
 * @callback callback
 * @param {Error} err Error object if an error occurred.
 * @param {object} data Response data object.
 */<|endoftext|>


<commit_before>const request = require('request-promise-native');
let connection = require('./psc.js');
let BattleMonitor = require('./BattleMonitor.js');

module.exports.champ = {};

let getCurrentThread = async () => {
	let b = await request.get('http://a.4cdn.org/vp/catalog.json');
	let catalog = JSON.parse(b);
	let derp_no = 0;
	catalog.some(page => {
		return page.threads.some(t => {
			if (t.sub && t.sub.toLowerCase().indexOf('showderp') != -1 && t.no > derp_no)
				return derp_no = t.no;
		});
	});
	return derp_no;
}

let getCurrentChamp = async b => {
	let thread = JSON.parse(b);
	let derp_no = 0;
	for (var i = thread.posts.length - 1; i != 0; --i) {
		if (!thread.posts[i].trip)
			continue;
		let content = thread.posts[i].com.replace(/<(?:.|\n)*?>/gm, '');
		let matches;
		if ((matches = content.match(/(https?:\/\/)?play.pokemonshowdown.com\/battle-(.*)-([0-9]*)/g))) {
			let champ = {champ_name: thread.posts[i].name, champ_trip: thread.posts[i].trip, champ_last_active: thread.posts[i].time};
			let curtime = ~~(+new Date() / 1000);
			champ.champ_active = curtime - champ.champ_last_active < 15 * 60;
			champ.champ_battle = matches[0];
			if(champ.champ_battle[0] != 'h')
				champ.champ_battle = 'http://' + champ.champ_battle;
			return champ;
		}
	}
	return {};
}

let oldbattle = null;

// stolen from gist
levenshtein = (a, b) => {
	var tmp;
	if (a.length === 0) { return b.length; }
	if (b.length === 0) { return a.length; }
	if (a.length > b.length) { tmp = a; a = b; b = tmp; }

	var i, j, res, alen = a.length, blen = b.length, row = Array(alen);
	for (i = 0; i <= alen; i++) { row[i] = i; }

	for (i = 1; i <= blen; i++) {
		res = i;
		for (j = 1; j <= alen; j++) {
			tmp = row[j - 1];
			row[j - 1] = res;
			res = b[i - 1] === a[j - 1] ? tmp : Math.min(tmp + 1, Math.min(res + 1, row[j] + 1));
		}
	}
	return res;
}

let main = async () => {
	try {
		let thread = await getCurrentThread();
		let threadjs = await request.get('http://a.4cdn.org/vp/thread/' + thread + '.json');
		let champ = await getCurrentChamp(threadjs);
		if (champ.champ_battle != oldbattle) {
			oldbattle = champ.champ_battle;
			if (champ.champ_name != undefined && champ.champ_name != '')
				new BattleMonitor(champ);
		}
		module.exports.champ = champ;
	}
	catch(e) {
		console.log(e);
	}
}

main();

setInterval(async () => {await main();}, 1000 * 60);
<commit_msg>Remove deprecated require<commit_after>const request = require('request-promise-native');
let BattleMonitor = require('./BattleMonitor.js');

module.exports.champ = {};

let getCurrentThread = async () => {
	let b = await request.get('http://a.4cdn.org/vp/catalog.json');
	let catalog = JSON.parse(b);
	let derp_no = 0;
	catalog.some(page => {
		return page.threads.some(t => {
			if (t.sub && t.sub.toLowerCase().indexOf('showderp') != -1 && t.no > derp_no)
				return derp_no = t.no;
		});
	});
	return derp_no;
}

let getCurrentChamp = async b => {
	let thread = JSON.parse(b);
	let derp_no = 0;
	for (var i = thread.posts.length - 1; i != 0; --i) {
		if (!thread.posts[i].trip)
			continue;
		let content = thread.posts[i].com.replace(/<(?:.|\n)*?>/gm, '');
		let matches;
		if ((matches = content.match(/(https?:\/\/)?play.pokemonshowdown.com\/battle-(.*)-([0-9]*)/g))) {
			let champ = {champ_name: thread.posts[i].name, champ_trip: thread.posts[i].trip, champ_last_active: thread.posts[i].time};
			let curtime = ~~(+new Date() / 1000);
			champ.champ_active = curtime - champ.champ_last_active < 15 * 60;
			champ.champ_battle = matches[0];
			if(champ.champ_battle[0] != 'h')
				champ.champ_battle = 'http://' + champ.champ_battle;
			return champ;
		}
	}
	return {};
}

let oldbattle = null;

// stolen from gist
levenshtein = (a, b) => {
	var tmp;
	if (a.length === 0) { return b.length; }
	if (b.length === 0) { return a.length; }
	if (a.length > b.length) { tmp = a; a = b; b = tmp; }

	var i, j, res, alen = a.length, blen = b.length, row = Array(alen);
	for (i = 0; i <= alen; i++) { row[i] = i; }

	for (i = 1; i <= blen; i++) {
		res = i;
		for (j = 1; j <= alen; j++) {
			tmp = row[j - 1];
			row[j - 1] = res;
			res = b[i - 1] === a[j - 1] ? tmp : Math.min(tmp + 1, Math.min(res + 1, row[j] + 1));
		}
	}
	return res;
}

let main = async () => {
	try {
		let thread = await getCurrentThread();
		let threadjs = await request.get('http://a.4cdn.org/vp/thread/' + thread + '.json');
		let champ = await getCurrentChamp(threadjs);
		if (champ.champ_battle != oldbattle) {
			oldbattle = champ.champ_battle;
			if (champ.champ_name != undefined && champ.champ_name != '')
				new BattleMonitor(champ);
		}
		module.exports.champ = champ;
	}
	catch(e) {
		console.log(e);
	}
}

main();

setInterval(async () => {await main();}, 1000 * 60);
<|endoftext|>