<commit_before>module.exports = function(robot) {
    'use strict'

    var slackmsg = require("./slackMsgs.js");
    var request = require('request');
    var rp = require('request-promise');
    var Trello = require('node-trello');

    // auth
    var key = process.env.HUBOT_TRELLO_KEY;
    var token = process.env.HUBOT_TRELLO_TOKEN;
    var trello = new Trello(key, token);

    function sendMessageToSlackResponseURL(responseURL, JSONmessage){
      var postOptions = {
          uri: responseURL,
          method: 'POST',
          headers: {
              'Content-type': 'application/json'
          },
          json: JSONmessage
      };
      request(postOptions, (error, response, body) => {
          if (error){
              // handle errors as you see fit
          };
      })
    }

    // Associate a board with a specific Channel
    robot.hear(/trello hooks/, function(res_r) {
        let boardId = 'BE7seI7e';
        let cb_url = 'https://andreasbot.herokuapp.com/hubot/trello-webhooks';
        let args = {description:"my test webhook", callbackURL:cb_url, idModel:'59245663c76f54b975558854'};
        trello.post('/1/webhooks', args, function(err, data){
            if (err){
                robot.logger.error('error')
                //robot.logger.error(err);
                return 0;
            }
            robot.logger.info('NO error');
        })
    })

    robot.hear(/trello h2/, function(res_r) {
        var options = {
            method: 'POST',
            uri: `https://api.trello.com/1/tokens/${token}/webhooks/?key=${key}`,
            body: {
                description: "My first webhook",
                callbackURL: "https://andreasbot.herokuapp.com/hubot/trello-webhooks",
                idModel: "59245663c76f54b975558854",
            },
            json: true // Automatically stringifies the body to JSON
        };

        rp(options)
            .then(function (parsedBody) {
                robot.logger.info(parsedBody);
            })
            .catch(function (err) {
                robot.logger.error(err);
            });

    })

	robot.on('trello-webhook-event', function(data, res){
        var room = "random";
        robot.messageRoom(room, `trello-webhook-event`);
        res.status(200).end(); // best practice to respond with 200 status
        res.sendStatus(200);
        res.status(200);
        res.send(200);
    })

    // trello board
    robot.hear(/trello board/i, function(res_r){
        // TODO: fetch the board id from other source (env, redis or mongodb)
        let boardId = 'BE7seI7e';
        let args = {fields: "name,url,prefs"};

        trello.get("/1/board/"+boardId, args, function(err, data){
            if (err){
                res.send('Error: ' + err);
                robot.logger.error(err);
                return 0;
            }
            // else !err
            let msg = slackmsg.buttons();
            msg.attachments[0].title = `<${data.url}|${data.name}>`;
            msg.attachments[0].title_url = 'www.google.com'
            msg.attachments[0].author_name = 'Board'
            msg.attachments[0].callback_id = `trello_board`;
            msg.attachments[0].color = `${data.prefs.backgroundColor}`;

            // attach the board lists to buttons
            let joinBtn = {"name": "join", "text": "Join","type":"button", "value": "join"};
            let subBtn  = {"name": "sub", "text": "Subscribe","type":"button", "value": "sub"};
            let starBtn = {"name": "star", "text": "Star","type":"button", "value": "star"};
            let listsBtn= {"name": "lists", "text": "Lists","type":"button", "value": "lists"};
            let doneBtn = {"name": "done", "text": "Done","type":"button", "value": "done","style": "danger"};
            msg.attachments[0].actions.push(joinBtn);
            msg.attachments[0].actions.push(subBtn);
            msg.attachments[0].actions.push(starBtn);
            msg.attachments[0].actions.push(listsBtn);
            msg.attachments[0].actions.push(doneBtn);

            res_r.send(msg);
        })
    })

    /*******************************************************************/
    /*                        robot.on listeners                       */
    /*******************************************************************/

    var slackCB = 'slack:msg_action:';

    // responding to 'trello_board' interactive message
    robot.on(slackCB + 'trello_board', function(data, res){
        robot.logger.info(`robot.on: ${slackCB}trello_board`);
        let btnId = data.actions[0].value;
        let btnName = data.actions[0].name;
        let response_url = data.response_url;
        let msg;

        switch (btnId) {
          case 'join':
            break;
          case 'sub':
            break;
          case 'star':
                break;
          case 'lists':
            res.status(200).end(); // best practice to respond with 200 status
            // get board info to fetch lists
            let boardId = 'BE7seI7e';
            let args = {lists:"all"};
            trello.get("1/board/"+boardId, args, function(err, data){
                if (err){
                    res.send(err);
                    robot.logger.error(err);
                    return;
                }
                // else if (!err)
                // create buttons msg
                let msg = slackmsg.buttons();
                msg.text = `*${data.name}* board`;

                msg.attachments[0].text = `Available lists`;
                msg.attachments[0].callback_id = `trello_list`;
                let listsNum = Object.keys(data.lists).length;
                for (var i=0; i<listsNum; i++){
                    // TODO change value to some id or something similar
                    let name = data.lists[i].name;
                    let id = data.lists[i].id;
                    let list = {"name": name, "text": name, "type":"button", "value": id};
                    msg.attachments[0].actions.push(list);
                }
                sendMessageToSlackResponseURL(response_url, msg);
            })
            break;
          case 'done':
            //res.status(200).end() // best practice to respond with 200 status
            msg = slackmsg.plainText();
            res.send(msg);
            //sendMessageToSlackResponseURL(response_url, msg);
            // res.send(msg);
            break;
          default:
            //Statements executed when none of the values match the value of the expression
            break;
        }
    })

    // responding to 'trello_list' interactive message
    robot.on(slackCB + 'trello_list', function(data_board, res){
        let response_url = data_board.response_url;

        res.status(200).end() // best practice to respond with 200 status
        robot.logger.info(`robot.on: ${slackCB}trello_list`);
        let listId = data_board.actions[0].value;
        let listName = data_board.actions[0].name;

        // call function to fetch list - provide list id
        let args = {cards: "all"};
        trello.get("/1/lists/"+listId, args, function(err, data){
            if (err){
                robot.logger.error(err);
                res.send(`Error: ${err}`)
                return 0;
            }
            // else !err
            // create buttons msg
            let msg = slackmsg.buttons();
            msg.text = `*${listName}* list`;
            msg.attachments[0].text = `Available Cards`;
            msg.attachments[0].callback_id = `trello_list`;

            let cardsNum = Object.keys(data.cards).length;
            robot.logger.info(`total cards: ${cardsNum}`);
            for (var i=0; i<cardsNum; i++){
                let card    = data.cards[i].name;
                let cardId  = data.cards[i].id;
                let item    = {"name": card, "text": card,"type":"button", "value": cardId};
                msg.attachments[0].actions.push(item);
            }

            // respond with information for that list
            sendMessageToSlackResponseURL(response_url, msg);
        })
    })

    /*  TODO: add more functionality */

}

    /* developer's personal notes */

    /* template */

    // robot.respond(/trello /i, function(res_r) {
    //     t.post("/1/", function(err, data){
    //         if (err){
    //             res_r.send('Error Encountered: '+ err['responseBody']);
    //         }
    //     })
    // })

/* An example of using slack's response_url. ~For future use */
/* Add this snippet inside robot.on that u want to trigger   */

    // var response_url = data.response_url;
    // var slackMsg = require('./slackMsgs');
    // var response = slackMsg.ephemeralMsg();

    // sendMessageToSlackResponseURL(response_url, response);

<commit_msg>update gh<commit_after>module.exports = function(robot) {
    'use strict'

    var slackmsg = require("./slackMsgs.js");
    var request = require('request');
    var rp = require('request-promise');
    var Trello = require('node-trello');

    // auth
    var key = process.env.HUBOT_TRELLO_KEY;
    var token = process.env.HUBOT_TRELLO_TOKEN;
    var trello = new Trello(key, token);

    function sendMessageToSlackResponseURL(responseURL, JSONmessage){
      var postOptions = {
          uri: responseURL,
          method: 'POST',
          headers: {
              'Content-type': 'application/json'
          },
          json: JSONmessage
      };
      request(postOptions, (error, response, body) => {
          if (error){
              // handle errors as you see fit
          };
      })
    }

    // Associate a board with a specific Channel
    robot.hear(/trello hooks/, function(res_r) {
        let boardId = 'BE7seI7e';
        let cb_url = 'https://andreasbot.herokuapp.com/hubot/trello-webhooks';
        let args = {description:"my test webhook", callbackURL:cb_url, idModel:'59245663c76f54b975558854'};
        trello.post('/1/webhooks', args, function(err, data){
            if (err){
                robot.logger.error('error')
                //robot.logger.error(err);
                return 0;
            }
            robot.logger.info('NO error');
        })
    })

    robot.hear(/trello h2/, function(res_r) {
        var options = {
            method: 'POST',
            uri: `https://api.trello.com/1/tokens/${token}/webhooks/?key=${key}`,
            body: {
                description: "My first webhook",
                callbackURL: "https://andreasbot.herokuapp.com/hubot/trello-webhooks",
                idModel: "59245663c76f54b975558854",
            },
            json: true // Automatically stringifies the body to JSON
        };

        rp(options)
            .then(function (parsedBody) {
                robot.logger.info(parsedBody);
            })
            .catch(function (err) {
                robot.logger.error(err);
            });

    })

	robot.on('trello-webhook-event', function(data, res){
        var room = "random";
        robot.messageRoom(room, `trello-webhook-event`);
    })

    // trello board
    robot.hear(/trello board/i, function(res_r){
        // TODO: fetch the board id from other source (env, redis or mongodb)
        let boardId = 'BE7seI7e';
        let args = {fields: "name,url,prefs"};

        trello.get("/1/board/"+boardId, args, function(err, data){
            if (err){
                res.send('Error: ' + err);
                robot.logger.error(err);
                return 0;
            }
            // else !err
            let msg = slackmsg.buttons();
            msg.attachments[0].title = `<${data.url}|${data.name}>`;
            msg.attachments[0].title_url = 'www.google.com'
            msg.attachments[0].author_name = 'Board'
            msg.attachments[0].callback_id = `trello_board`;
            msg.attachments[0].color = `${data.prefs.backgroundColor}`;

            // attach the board lists to buttons
            let joinBtn = {"name": "join", "text": "Join","type":"button", "value": "join"};
            let subBtn  = {"name": "sub", "text": "Subscribe","type":"button", "value": "sub"};
            let starBtn = {"name": "star", "text": "Star","type":"button", "value": "star"};
            let listsBtn= {"name": "lists", "text": "Lists","type":"button", "value": "lists"};
            let doneBtn = {"name": "done", "text": "Done","type":"button", "value": "done","style": "danger"};
            msg.attachments[0].actions.push(joinBtn);
            msg.attachments[0].actions.push(subBtn);
            msg.attachments[0].actions.push(starBtn);
            msg.attachments[0].actions.push(listsBtn);
            msg.attachments[0].actions.push(doneBtn);

            res_r.send(msg);
        })
    })

    /*******************************************************************/
    /*                        robot.on listeners                       */
    /*******************************************************************/

    var slackCB = 'slack:msg_action:';

    // responding to 'trello_board' interactive message
    robot.on(slackCB + 'trello_board', function(data, res){
        robot.logger.info(`robot.on: ${slackCB}trello_board`);
        let btnId = data.actions[0].value;
        let btnName = data.actions[0].name;
        let response_url = data.response_url;
        let msg;

        switch (btnId) {
          case 'join':
            break;
          case 'sub':
            break;
          case 'star':
                break;
          case 'lists':
            res.status(200).end(); // best practice to respond with 200 status
            // get board info to fetch lists
            let boardId = 'BE7seI7e';
            let args = {lists:"all"};
            trello.get("1/board/"+boardId, args, function(err, data){
                if (err){
                    res.send(err);
                    robot.logger.error(err);
                    return;
                }
                // else if (!err)
                // create buttons msg
                let msg = slackmsg.buttons();
                msg.text = `*${data.name}* board`;

                msg.attachments[0].text = `Available lists`;
                msg.attachments[0].callback_id = `trello_list`;
                let listsNum = Object.keys(data.lists).length;
                for (var i=0; i<listsNum; i++){
                    // TODO change value to some id or something similar
                    let name = data.lists[i].name;
                    let id = data.lists[i].id;
                    let list = {"name": name, "text": name, "type":"button", "value": id};
                    msg.attachments[0].actions.push(list);
                }
                sendMessageToSlackResponseURL(response_url, msg);
            })
            break;
          case 'done':
            //res.status(200).end() // best practice to respond with 200 status
            msg = slackmsg.plainText();
            res.send(msg);
            //sendMessageToSlackResponseURL(response_url, msg);
            // res.send(msg);
            break;
          default:
            //Statements executed when none of the values match the value of the expression
            break;
        }
    })

    // responding to 'trello_list' interactive message
    robot.on(slackCB + 'trello_list', function(data_board, res){
        let response_url = data_board.response_url;

        res.status(200).end() // best practice to respond with 200 status
        robot.logger.info(`robot.on: ${slackCB}trello_list`);
        let listId = data_board.actions[0].value;
        let listName = data_board.actions[0].name;

        // call function to fetch list - provide list id
        let args = {cards: "all"};
        trello.get("/1/lists/"+listId, args, function(err, data){
            if (err){
                robot.logger.error(err);
                res.send(`Error: ${err}`)
                return 0;
            }
            // else !err
            // create buttons msg
            let msg = slackmsg.buttons();
            msg.text = `*${listName}* list`;
            msg.attachments[0].text = `Available Cards`;
            msg.attachments[0].callback_id = `trello_list`;

            let cardsNum = Object.keys(data.cards).length;
            robot.logger.info(`total cards: ${cardsNum}`);
            for (var i=0; i<cardsNum; i++){
                let card    = data.cards[i].name;
                let cardId  = data.cards[i].id;
                let item    = {"name": card, "text": card,"type":"button", "value": cardId};
                msg.attachments[0].actions.push(item);
            }

            // respond with information for that list
            sendMessageToSlackResponseURL(response_url, msg);
        })
    })

    /*  TODO: add more functionality */

}

    /* developer's personal notes */

    /* template */

    // robot.respond(/trello /i, function(res_r) {
    //     t.post("/1/", function(err, data){
    //         if (err){
    //             res_r.send('Error Encountered: '+ err['responseBody']);
    //         }
    //     })
    // })

/* An example of using slack's response_url. ~For future use */
/* Add this snippet inside robot.on that u want to trigger   */

    // var response_url = data.response_url;
    // var slackMsg = require('./slackMsgs');
    // var response = slackMsg.ephemeralMsg();

    // sendMessageToSlackResponseURL(response_url, response);

<|endoftext|>


<commit_before>!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.Vidage=e()}}(function(){return function e(t,n,o){function r(u,a){if(!n[u]){if(!t[u]){var s="function"==typeof require&&require;if(!a&&s)return s(u,!0);if(i)return i(u,!0);var f=new Error("Cannot find module '"+u+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[u]={exports:{}};t[u][0].call(l.exports,function(e){var n=t[u][1][e];return r(n?n:e)},l,l.exports,e,t,n,o)}return n[u].exports}for(var i="function"==typeof require&&require,u=0;u<o.length;u++)r(o[u]);return r}({1:[function(e,t,n){(function(e){var n="object"==typeof e&&e&&e.Object===Object&&e;t.exports=n}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],2:[function(e,t,n){var o=e("./_freeGlobal"),r="object"==typeof self&&self&&self.Object===Object&&self,i=o||r||Function("return this")();t.exports=i},{"./_freeGlobal":1}],3:[function(e,t,n){function o(e,t,n){function o(t){var n=y,o=w;return y=w=void 0,_=t,x=e.apply(o,n)}function l(e){return _=e,j=setTimeout(v,t),E?o(e):x}function c(e){var n=e-O,o=e-_,r=t-n;return M?f(r,g-o):r}function d(e){var n=e-O,o=e-_;return void 0===O||n>=t||n<0||M&&o>=g}function v(){var e=i();return d(e)?p(e):void(j=setTimeout(v,c(e)))}function p(e){return j=void 0,T&&y?o(e):(y=w=void 0,x)}function h(){void 0!==j&&clearTimeout(j),_=0,y=O=w=j=void 0}function m(){return void 0===j?x:p(i())}function b(){var e=i(),n=d(e);if(y=arguments,w=this,O=e,n){if(void 0===j)return l(O);if(M)return j=setTimeout(v,t),o(O)}return void 0===j&&(j=setTimeout(v,t)),x}var y,w,g,x,j,O,_=0,E=!1,M=!1,T=!0;if("function"!=typeof e)throw new TypeError(a);return t=u(t)||0,r(n)&&(E=!!n.leading,M="maxWait"in n,g=M?s(u(n.maxWait)||0,t):g,T="trailing"in n?!!n.trailing:T),b.cancel=h,b.flush=m,b}var r=e("./isObject"),i=e("./now"),u=e("./toNumber"),a="Expected a function",s=Math.max,f=Math.min;t.exports=o},{"./isObject":4,"./now":7,"./toNumber":8}],4:[function(e,t,n){function o(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}t.exports=o},{}],5:[function(e,t,n){function o(e){return!!e&&"object"==typeof e}t.exports=o},{}],6:[function(e,t,n){function o(e){return"symbol"==typeof e||r(e)&&a.call(e)==i}var r=e("./isObjectLike"),i="[object Symbol]",u=Object.prototype,a=u.toString;t.exports=o},{"./isObjectLike":5}],7:[function(e,t,n){var o=e("./_root"),r=function(){return o.Date.now()};t.exports=r},{"./_root":2}],8:[function(e,t,n){function o(e){if("number"==typeof e)return e;if(i(e))return u;if(r(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=r(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(a,"");var n=f.test(e);return n||l.test(e)?c(e.slice(2),n?2:8):s.test(e)?u:+e}var r=e("./isObject"),i=e("./isSymbol"),u=NaN,a=/^\s+|\s+$/g,s=/^[-+]0x[0-9a-f]+$/i,f=/^0b[01]+$/i,l=/^0o[0-7]+$/i,c=parseInt;t.exports=o},{"./isObject":4,"./isSymbol":6}],9:[function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(t,n,o){return n&&e(t.prototype,n),o&&e(t,o),t}}(),u=e("lodash/debounce"),a=o(u),s=e("./helpers/validate-selector"),f=o(s),l=e("./helpers/feature-detect"),c=o(l),d=e("./helpers/handle-video-selector"),v=function(){function e(t){var n=arguments.length<=1||void 0===arguments[1]?"Vidage--allow":arguments[1],o=!(arguments.length<=2||void 0===arguments[2])&&arguments[2];r(this,e),this._name=this.constructor.name,this.element=(0,f.default)(t,this._name),this.helperClass=n,this.removal=o,this.status=!1,this.init()}return i(e,[{key:"init",value:function(){var e=this;this.element.addEventListener("canplay",function(){return e.handler()}),window.addEventListener("resize",(0,a.default)(function(){return e.handler()},250))}},{key:"handler",value:function(){var e=document.body;if((0,c.default)()){if(!this.status)return;console.log("one time IF statement"),this.element.pause(),this.removal&&(0,d.removeVideo)(this.element),e.classList.remove(this.helperClass),this.status=!1}else{if(this.status)return;console.log("one time ELSE statement"),this.removal&&(0,d.restoreVideo)(this.element),this.element.play(),e.classList.add(this.helperClass),this.status=!0}}}]),e}();n.default=v,t.exports=n.default},{"./helpers/feature-detect":10,"./helpers/handle-video-selector":11,"./helpers/validate-selector":12,"lodash/debounce":3}],10:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.default=function(){var e={touch:!!("ontouchstart"in window||window.navigator&&window.navigator.msPointerEnabled&&window.MSGesture||window.DocumentTouch&&document instanceof DocumentTouch),ie:window.navigator.userAgent.indexOf("MSIE")>0||!!window.navigator.userAgent.match(/Trident.*rv\:11\./),small:window.matchMedia("(max-width: 34em)").matches};return e.touch&&!e.ie||e.small},t.exports=n.default},{}],11:[function(e,t,n){"use strict";function o(e){document.body.contains(e)||i.insertAdjacentElement("afterbegin",e)}function r(e){null===i&&(i=e.parentNode),document.body.contains(e)&&i.removeChild(e)}Object.defineProperty(n,"__esModule",{value:!0}),n.restoreVideo=o,n.removeVideo=r;var i=null},{}],12:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.default=function(e,t){if("undefined"==typeof e)throw new Error(t+" requires a video selector as first argument.");if(e="string"==typeof e?document.querySelector(e):e,"video"!==e.nodeName.toLowerCase())throw new Error(t+" requires a valid video selector. You passed a <"+e.nodeName+">");return e},t.exports=n.default},{}]},{},[9])(9)});<commit_msg>What did I change now?<commit_after>!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.Vidage=e()}}(function(){return function e(t,n,o){function r(u,a){if(!n[u]){if(!t[u]){var s="function"==typeof require&&require;if(!a&&s)return s(u,!0);if(i)return i(u,!0);var f=new Error("Cannot find module '"+u+"'");throw f.code="MODULE_NOT_FOUND",f}var c=n[u]={exports:{}};t[u][0].call(c.exports,function(e){var n=t[u][1][e];return r(n?n:e)},c,c.exports,e,t,n,o)}return n[u].exports}for(var i="function"==typeof require&&require,u=0;u<o.length;u++)r(o[u]);return r}({1:[function(e,t,n){(function(e){var n="object"==typeof e&&e&&e.Object===Object&&e;t.exports=n}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],2:[function(e,t,n){var o=e("./_freeGlobal"),r="object"==typeof self&&self&&self.Object===Object&&self,i=o||r||Function("return this")();t.exports=i},{"./_freeGlobal":1}],3:[function(e,t,n){function o(e,t,n){function o(t){var n=y,o=w;return y=w=void 0,_=t,x=e.apply(o,n)}function c(e){return _=e,j=setTimeout(v,t),E?o(e):x}function l(e){var n=e-O,o=e-_,r=t-n;return M?f(r,g-o):r}function d(e){var n=e-O,o=e-_;return void 0===O||n>=t||n<0||M&&o>=g}function v(){var e=i();return d(e)?p(e):void(j=setTimeout(v,l(e)))}function p(e){return j=void 0,T&&y?o(e):(y=w=void 0,x)}function h(){void 0!==j&&clearTimeout(j),_=0,y=O=w=j=void 0}function m(){return void 0===j?x:p(i())}function b(){var e=i(),n=d(e);if(y=arguments,w=this,O=e,n){if(void 0===j)return c(O);if(M)return j=setTimeout(v,t),o(O)}return void 0===j&&(j=setTimeout(v,t)),x}var y,w,g,x,j,O,_=0,E=!1,M=!1,T=!0;if("function"!=typeof e)throw new TypeError(a);return t=u(t)||0,r(n)&&(E=!!n.leading,M="maxWait"in n,g=M?s(u(n.maxWait)||0,t):g,T="trailing"in n?!!n.trailing:T),b.cancel=h,b.flush=m,b}var r=e("./isObject"),i=e("./now"),u=e("./toNumber"),a="Expected a function",s=Math.max,f=Math.min;t.exports=o},{"./isObject":4,"./now":7,"./toNumber":8}],4:[function(e,t,n){function o(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}t.exports=o},{}],5:[function(e,t,n){function o(e){return!!e&&"object"==typeof e}t.exports=o},{}],6:[function(e,t,n){function o(e){return"symbol"==typeof e||r(e)&&a.call(e)==i}var r=e("./isObjectLike"),i="[object Symbol]",u=Object.prototype,a=u.toString;t.exports=o},{"./isObjectLike":5}],7:[function(e,t,n){var o=e("./_root"),r=function(){return o.Date.now()};t.exports=r},{"./_root":2}],8:[function(e,t,n){function o(e){if("number"==typeof e)return e;if(i(e))return u;if(r(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=r(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(a,"");var n=f.test(e);return n||c.test(e)?l(e.slice(2),n?2:8):s.test(e)?u:+e}var r=e("./isObject"),i=e("./isSymbol"),u=NaN,a=/^\s+|\s+$/g,s=/^[-+]0x[0-9a-f]+$/i,f=/^0b[01]+$/i,c=/^0o[0-7]+$/i,l=parseInt;t.exports=o},{"./isObject":4,"./isSymbol":6}],9:[function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(t,n,o){return n&&e(t.prototype,n),o&&e(t,o),t}}(),u=e("lodash/debounce"),a=o(u),s=e("./helpers/validate-selector"),f=o(s),c=e("./helpers/feature-detect"),l=o(c),d=e("./helpers/handle-video-selector"),v=function(){function e(t){var n=arguments.length<=1||void 0===arguments[1]?"Vidage--allow":arguments[1],o=!(arguments.length<=2||void 0===arguments[2])&&arguments[2];r(this,e),this._name=this.constructor.name,this.element=(0,f.default)(t,this._name),this.helperClass=n,this.removeVideo=o,this.status=!1,this.init()}return i(e,[{key:"init",value:function(){var e=this;this.element.addEventListener("canplay",function(){return e.handler()}),window.addEventListener("resize",(0,a.default)(function(){return e.handler()},250))}},{key:"handler",value:function(){var e=document.body;if((0,l.default)()){if(!this.status)return;this.element.pause(),this.removeVideo&&removeVideo(this.element),e.classList.remove(this.helperClass),this.status=!1}else{if(this.status)return;this.removeVideo&&(0,d.restoreVideo)(this.element),this.element.play(),e.classList.add(this.helperClass),this.status=!0}}}]),e}();n.default=v,t.exports=n.default},{"./helpers/feature-detect":10,"./helpers/handle-video-selector":11,"./helpers/validate-selector":12,"lodash/debounce":3}],10:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.default=function(){var e={touch:!!("ontouchstart"in window||window.navigator&&window.navigator.msPointerEnabled&&window.MSGesture||window.DocumentTouch&&document instanceof DocumentTouch),ie:window.navigator.userAgent.indexOf("MSIE")>0||!!window.navigator.userAgent.match(/Trident.*rv\:11\./),small:window.matchMedia("(max-width: 34em)").matches};return e.touch&&!e.ie||e.small},t.exports=n.default},{}],11:[function(e,t,n){"use strict";function o(e){document.body.contains(e)||i.insertAdjacentElement("afterbegin",e)}function r(e){null===i&&(i=e.parentNode),document.body.contains(e)&&i.removeChild(e)}Object.defineProperty(n,"__esModule",{value:!0}),n.restoreVideo=o,n.removeVideo=r;var i=null},{}],12:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.default=function(e,t){if("undefined"==typeof e)throw new Error(t+" requires a video selector as first argument.");if(e="string"==typeof e?document.querySelector(e):e,"video"!==e.nodeName.toLowerCase())throw new Error(t+" requires a valid video selector. You passed a <"+e.nodeName+">");return e},t.exports=n.default},{}]},{},[9])(9)});<|endoftext|>


<commit_before>import composeMiddleware from './utils/composeMiddleware';

export default function createDispatcher(store, middlewares = []) {
  return function dispatcher(initialState, setState) {
    let state = setState(store(initialState, {}));

    function dispatch(action) {
      state = setState(store(state, action));
      return action;
    }

    function getState() {
      return state;
    }

    if (typeof middlewares === 'function') {
      middlewares = middlewares(getState);
    }

    return composeMiddleware(...middlewares, dispatch);
  };
}
<commit_msg>Fix stale getState on hot reloading (#90)<commit_after>import composeMiddleware from './utils/composeMiddleware';

export default function createDispatcher(store, middlewares = []) {
  return function dispatcher(initialState, setState) {
    let state = setState(store(initialState, {}));

    function dispatch(action) {
      state = setState(store(state, action));
      return action;
    }

    function getState() {
      return state;
    }

    const finalMiddlewares = typeof middlewares === 'function' ?
      middlewares(getState) :
      middlewares;

    return composeMiddleware(...finalMiddlewares, dispatch);
  };
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

var list = require('../cmd/list.js'),
find = require('../cmd/find.js'),
howto = require('../cmd/howto.js'),
create = require('../cmd/create.js'),
remove = require('../cmd/remove.js'),
activate = require('../cmd/activate.js'),
deactivate = require('../cmd/deactivate.js');

var idUnique = require('../lib/validation.js').idUnique,
idExsit = require('../lib/validation.js').idExsit,
idValid = require('../lib/validation.js').idValid,
cmdValid = require('../lib/validation.js').cmdValid,
ecosystemActive = require('../lib/validation.js').ecosystemActive,
releaseExist = require('../lib/assistant.js').getRelease,
ecosystemExist = require('../lib/assistant.js').getEcosystem;

var parseUserConfig = require('../lib/config.js').parseUserConfig,
parseGlobalConfig = require('../lib/config.js').parseGlobalConfig,
parseEcosystemConfig = require('../lib/config.js').parseEcosystemConfig;

var envReady = require('../lib/inception.js').envReady,
rootReady = require('../lib/inception.js').rootReady,
recordReady = require('../lib/inception.js').recordReady,
activateReady = require('../lib/inception.js').activateReady;

var log = require('../lib/display.js').log;
var message, warning, error, suggestion, example;

var argv = process.argv, id, target, cmd = argv[2];

if (cmd === undefined) {
  error = 'Missing command';
  suggestion = 'Available commands: howto, create, remove, list, find, activate, deactivate';
  example = 'neco howto, neco create <id>, neco list';
  log('error', error, suggestion, example);

} else if (cmdValid(cmd) === false) {
  error = 'Not a valid command';
  suggestion = 'Available commands: howto, create, list, find, activate, deactivate';
  example = 'neco hwoto, neco create <id>, neco list';
  log('error', error, suggestion, example);
} else {
  // Subcommand create
  if (cmd === 'create') {
    if (argv.length < 4) {
      message = 'Missing ID';
      suggestion = 'Please specific at least one ID( and the version of node, if you will).';
      example = 'neco create <id> [stable, latest, node-version]';
      log('message', message, suggestion, example);
    } else {
      id = argv[3], target = argv[4] || 'stable'; // defaut target is stable
      parseGlobalConfig(function(config) {
        config.id = id, config.cmd = cmd, config.target = target;
        parseUserConfig(config, function(config) {
          envReady(config, function(config) {
            rootReady(config, function(config) {
              activateReady(config, function(config) {
                recordReady(config, function(exists, config) {
                  if (!exists) {
                    create.run(config);
                  } else {
                    if (!idValid(config)) {
                      message = 'The given id '+id+' is one of the reserved words in neco.';
                      suggestion = 'Please choose another one.';
                      log('message', message, suggestion);
                    } else if (!idUnique(config)) {
                      message = 'The given id '+config.id+' has already been used.';
                      suggestion = 'Please choose another one instead.';
                      log('message', message, suggestion);
                    } else {
                      create.run(config);
                    }
                  }
                });
              });
            });
          });
        });
      });
    }
  }

  // Subcommand list
  else if (cmd === 'list') {
    parseGlobalConfig(function(config) {
      config.cmd = cmd;
      parseUserConfig(config, function(config) {
        envReady(config, function(config) {
          rootReady(config, function(config) {
            activateReady(config, function(config) {
              recordReady(config, function(exists, config) {
                if (ecosystemExist(config)) {
                  if (argv.length >= 4) {
                    target = argv[3];
                    config.target = target;
                  }
                  list.run(config);
                } else {
                  error = 'The desired ecosystem '+target+' is not exists.';
                  suggestion = 'Find out all the existing ecosystem.';
                  example = 'neco list';
                  log('error', error, suggestion, example);
                }
              });
            });
          });
        });
      });
    });
  }

  // Subcommand find
  else if (cmd === 'find') {
    parseGlobalConfig(function(config) {
      config.cmd = cmd;
      parseUserConfig(config, function(config) {
        envReady(config, function(config) {
          rootReady(config, function(config) {
            activateReady(config, function(config) {
              recordReady(config, function(exists, config) {
                if (argv.length >= 4) {
                  target = argv[3];
                  config.target = target;
                  if (releaseExist(config)) {
                    find.run(config);
                  } else {
                    error = 'The desired release '+target+' is not available.';
                    suggestion = 'Find out all the available releases.';
                    example = 'neco find [stable, latest, node-version]';
                    log('error', error, suggestion, example);
                  }
                } else {
                  find.run(config);
                }
              });
            });
          });
        });
      });
    });
  }

  // Subcommand help
  else if (cmd === 'howto') {
    parseGlobalConfig(function(config) {
      parseUserConfig(config, function(config) {
        howto.run(config);
      });
    });
  }

  // Subcommand activate
  else if (cmd === 'activate') {
    if (argv.length < 4) {
      message = 'Missing ID';
      suggestion = 'Please specify the id of the ecosystem you want to activate.';
      example = 'neco_activate <id>';
      log('message', message, suggestion, example);
    } else {
      id = process.argv[3];

      parseGlobalConfig(function(config) {
        config.id = id, config.cmd = cmd;
        parseEcosystemConfig(config, function(config) {
          parseUserConfig(config, function(config) {
            envReady(config, function(config) {
              rootReady(config, function(config) {
                activateReady(config, function(config) {
                  recordReady(config, function(exists, config) {
                    if (ecosystemActive(config)) {
                      warning = 'The node ecosystem with id '+id+' is already active.';
                      suggstion = 'Please use type deact in your shell to deactivate it.';
                      log('warning', warning, suggestion, example);
                    } else if (!idExsit(config)) {
                      warning = 'The node ecosystem with id '+id+' is not exists.';
                      suggestion = 'You can use neco list command to find out all existing ecosystem.';
                      example = 'neco create <id> [node-version]';
                      log('warning', warning, suggestion, example);
                    } else {
                      activate.run(config);
                    }
                  });
                });
              });
            });
          });
        });
      });
    }
  }

  // Subcommand deactvate
  else if (cmd === 'deactivate') {
    if (argv.length < 4) {
      message = 'Missing ID';
      suggestion = 'Please specify the id of the ecosystem you want to deactivate.';
      example = 'neco deactivate <id>';
      log('message', message, suggestion, example);
    } else {
      id = process.argv[3];
      parseGlobalConfig(function(config) {
        config.id = id, config.cmd = cmd;
        parseEcosystemConfig(config, function(config) {
          parseUserConfig(config, function(config) {
            envReady(config, function(config) {
              rootReady(config, function(config) {
                activateReady(config, function(config) {
                  recordReady(config, function(exists, config) {
                    if (!idExsit(config)) {
                      error = 'The node ecosystem with id '+id+' is not exists.';
                      suggestion = 'You can use neco list command to find out all existing ecosystem.';
                      example = 'neco list';
                      log('error', error, suggestion, example);
                    } else if (!ecosystemActive(config)) {
                      error = 'The node ecosystem with id '+id+' is not active.';
                      suggestion = 'Use neco activate command to activate it first.';
                      example = 'neco_activate '+ id;
                      log('error', error, suggestion, example);
                    } else {
                      deactivate.run(config);
                    }
                  });
                });
              });
            });
          });
        });
      });
    }
  }

  // Subcommand remove
  else  if (cmd === 'remove') {
    if (argv.length < 4) {
      message = 'Missing ID';
      suggestion = 'Please specific the ID of the ecosystem that you want ot removed.';
      example = 'neco remove <id>';
      log('message', message, suggestion, example);
    } else {
      id = argv[3];
      parseGlobalConfig(function(config) {
        config.id = id, config.cmd = cmd;
        parseEcosystemConfig(config, function(config) {
          parseUserConfig(config, function(config) {
            envReady(config, function(config) {
              rootReady(config, function(config) {
                activateReady(config, function(config) {
                  recordReady(config, function(exists, config) {
                    if (!idExsit(config)) {
                      message = 'The given id '+id+' is not exist.';
                      suggestion = 'Find out all existing ecosystem.';
                      example = 'neco list'
                      log('message', message, suggestion, example);
                    } else if (ecosystemActive(config)) {
                      message = 'The given ecosystem with id '+id+' is in active.';
                      suggestion = 'Please deactivate it first.';
                      example = 'neco_deactivate'
                      log('message', message, suggestion, example);
                    } else {
                      remove.run(config);
                    }
                  });
                });
              });
            });
          });
        });
      });
    }
  }

}
<commit_msg>back to old logic in list command<commit_after>#!/usr/bin/env node

var list = require('../cmd/list.js'),
find = require('../cmd/find.js'),
howto = require('../cmd/howto.js'),
create = require('../cmd/create.js'),
remove = require('../cmd/remove.js'),
activate = require('../cmd/activate.js'),
deactivate = require('../cmd/deactivate.js');

var idUnique = require('../lib/validation.js').idUnique,
idExsit = require('../lib/validation.js').idExsit,
idValid = require('../lib/validation.js').idValid,
cmdValid = require('../lib/validation.js').cmdValid,
ecosystemActive = require('../lib/validation.js').ecosystemActive,
releaseExist = require('../lib/assistant.js').getRelease,
ecosystemExist = require('../lib/assistant.js').getEcosystem;

var parseUserConfig = require('../lib/config.js').parseUserConfig,
parseGlobalConfig = require('../lib/config.js').parseGlobalConfig,
parseEcosystemConfig = require('../lib/config.js').parseEcosystemConfig;

var envReady = require('../lib/inception.js').envReady,
rootReady = require('../lib/inception.js').rootReady,
recordReady = require('../lib/inception.js').recordReady,
activateReady = require('../lib/inception.js').activateReady;

var log = require('../lib/display.js').log;
var message, warning, error, suggestion, example;

var argv = process.argv, id, target, cmd = argv[2];

if (cmd === undefined) {
  error = 'Missing command';
  suggestion = 'Available commands: howto, create, remove, list, find, activate, deactivate';
  example = 'neco howto, neco create <id>, neco list';
  log('error', error, suggestion, example);

} else if (cmdValid(cmd) === false) {
  error = 'Not a valid command';
  suggestion = 'Available commands: howto, create, list, find, activate, deactivate';
  example = 'neco hwoto, neco create <id>, neco list';
  log('error', error, suggestion, example);
} else {
  // Subcommand create
  if (cmd === 'create') {
    if (argv.length < 4) {
      message = 'Missing ID';
      suggestion = 'Please specific at least one ID( and the version of node, if you will).';
      example = 'neco create <id> [stable, latest, node-version]';
      log('message', message, suggestion, example);
    } else {
      id = argv[3], target = argv[4] || 'stable'; // defaut target is stable
      parseGlobalConfig(function(config) {
        config.id = id, config.cmd = cmd, config.target = target;
        parseUserConfig(config, function(config) {
          envReady(config, function(config) {
            rootReady(config, function(config) {
              activateReady(config, function(config) {
                recordReady(config, function(exists, config) {
                  if (!exists) {
                    create.run(config);
                  } else {
                    if (!idValid(config)) {
                      message = 'The given id '+id+' is one of the reserved words in neco.';
                      suggestion = 'Please choose another one.';
                      log('message', message, suggestion);
                    } else if (!idUnique(config)) {
                      message = 'The given id '+config.id+' has already been used.';
                      suggestion = 'Please choose another one instead.';
                      log('message', message, suggestion);
                    } else {
                      create.run(config);
                    }
                  }
                });
              });
            });
          });
        });
      });
    }
  }

  // Subcommand list
  else if (cmd === 'list') {
    parseGlobalConfig(function(config) {
      config.cmd = cmd;
      parseUserConfig(config, function(config) {
        envReady(config, function(config) {
          rootReady(config, function(config) {
            activateReady(config, function(config) {
              recordReady(config, function(exists, config) {
                if (argv.length >= 4) {
                  target = argv[3];
                  config.target = target;
                  if (ecosystemExist(config) {
                    list.run(config);
                  } else {
                    error = 'The desired ecosystem '+target+' is not exists.';
                    suggestion = 'Find out all the existing ecosystem.';
                    example = 'neco list';
                    log('error', error, suggestion, example);
                  } else {
                    list.run(config)
                  }
                });
              });
            });
          });
        });
      });
    }

    // Subcommand find
    else if (cmd === 'find') {
      parseGlobalConfig(function(config) {
        config.cmd = cmd;
        parseUserConfig(config, function(config) {
          envReady(config, function(config) {
            rootReady(config, function(config) {
              activateReady(config, function(config) {
                recordReady(config, function(exists, config) {
                  if (argv.length >= 4) {
                    target = argv[3];
                    config.target = target;
                    if (releaseExist(config)) {
                      find.run(config);
                    } else {
                      error = 'The desired release '+target+' is not available.';
                      suggestion = 'Find out all the available releases.';
                      example = 'neco find [stable, latest, node-version]';
                      log('error', error, suggestion, example);
                    }
                  } else {
                    find.run(config);
                  }
                });
              });
            });
          });
        });
      });
    }

    // Subcommand help
    else if (cmd === 'howto') {
      parseGlobalConfig(function(config) {
        parseUserConfig(config, function(config) {
          howto.run(config);
        });
      });
    }

    // Subcommand activate
    else if (cmd === 'activate') {
      if (argv.length < 4) {
        message = 'Missing ID';
        suggestion = 'Please specify the id of the ecosystem you want to activate.';
        example = 'neco_activate <id>';
        log('message', message, suggestion, example);
      } else {
        id = process.argv[3];

        parseGlobalConfig(function(config) {
          config.id = id, config.cmd = cmd;
          parseEcosystemConfig(config, function(config) {
            parseUserConfig(config, function(config) {
              envReady(config, function(config) {
                rootReady(config, function(config) {
                  activateReady(config, function(config) {
                    recordReady(config, function(exists, config) {
                      if (ecosystemActive(config)) {
                        warning = 'The node ecosystem with id '+id+' is already active.';
                        suggstion = 'Please use type deact in your shell to deactivate it.';
                        log('warning', warning, suggestion, example);
                      } else if (!idExsit(config)) {
                        warning = 'The node ecosystem with id '+id+' is not exists.';
                        suggestion = 'You can use neco list command to find out all existing ecosystem.';
                        example = 'neco create <id> [node-version]';
                        log('warning', warning, suggestion, example);
                      } else {
                        activate.run(config);
                      }
                    });
                  });
                });
              });
            });
          });
        });
      }
    }

    // Subcommand deactvate
    else if (cmd === 'deactivate') {
      if (argv.length < 4) {
        message = 'Missing ID';
        suggestion = 'Please specify the id of the ecosystem you want to deactivate.';
        example = 'neco deactivate <id>';
        log('message', message, suggestion, example);
      } else {
        id = process.argv[3];
        parseGlobalConfig(function(config) {
          config.id = id, config.cmd = cmd;
          parseEcosystemConfig(config, function(config) {
            parseUserConfig(config, function(config) {
              envReady(config, function(config) {
                rootReady(config, function(config) {
                  activateReady(config, function(config) {
                    recordReady(config, function(exists, config) {
                      if (!idExsit(config)) {
                        error = 'The node ecosystem with id '+id+' is not exists.';
                        suggestion = 'You can use neco list command to find out all existing ecosystem.';
                        example = 'neco list';
                        log('error', error, suggestion, example);
                      } else if (!ecosystemActive(config)) {
                        error = 'The node ecosystem with id '+id+' is not active.';
                        suggestion = 'Use neco activate command to activate it first.';
                        example = 'neco_activate '+ id;
                        log('error', error, suggestion, example);
                      } else {
                        deactivate.run(config);
                      }
                    });
                  });
                });
              });
            });
          });
        });
      }
    }

    // Subcommand remove
    else  if (cmd === 'remove') {
      if (argv.length < 4) {
        message = 'Missing ID';
        suggestion = 'Please specific the ID of the ecosystem that you want ot removed.';
        example = 'neco remove <id>';
        log('message', message, suggestion, example);
      } else {
        id = argv[3];
        parseGlobalConfig(function(config) {
          config.id = id, config.cmd = cmd;
          parseEcosystemConfig(config, function(config) {
            parseUserConfig(config, function(config) {
              envReady(config, function(config) {
                rootReady(config, function(config) {
                  activateReady(config, function(config) {
                    recordReady(config, function(exists, config) {
                      if (!idExsit(config)) {
                        message = 'The given id '+id+' is not exist.';
                        suggestion = 'Find out all existing ecosystem.';
                        example = 'neco list'
                        log('message', message, suggestion, example);
                      } else if (ecosystemActive(config)) {
                        message = 'The given ecosystem with id '+id+' is in active.';
                        suggestion = 'Please deactivate it first.';
                        example = 'neco_deactivate'
                        log('message', message, suggestion, example);
                      } else {
                        remove.run(config);
                      }
                    });
                  });
                });
              });
            });
          });
        });
      }
    }

  }
<|endoftext|>


<commit_before>#!/usr/bin/env node

let url;
const info = require('../package');
const chalk = require('chalk');
const opts = require('commander')
  .version(info.version)
  .arguments('<url>')
  .action((a) => { url = a; })
  .option('-q, --quality <ITAG>',
    'Video quality to download, default: highest')
  .option('-r, --range <INT>..<INT>',
    'Byte range to download, ie 10355705-12452856')
  .option('-b, --begin <INT>', 'Time to begin video, format by 1:30.123 and 1m30s')
  .option('-o, --output <FILE>', 'Save to file, template by {prop}, default: stdout or {title}')
  .option('--filter <STR>',
    'Can be video, videoonly, audio, audioonly',
    /^(video|audio)(only)?$/)
  .option('--filter-container <REGEXP>', 'Filter in format container')
  .option('--unfilter-container <REGEXP>', 'Filter out format container')
  .option('--filter-resolution <REGEXP>', 'Filter in format resolution')
  .option('--unfilter-resolution <REGEXP>', 'Filter out format resolution')
  .option('--filter-codecs <REGEXP>', 'Filter in format codecs')
  .option('--unfilter-codecs <REGEXP>', 'Filter out format codecs')
  .option('-i, --info', 'Print video info without downloading')
  .option('-j, --info-json', 'Print video info as JSON without downloading')
  .option('--print-url', 'Print direct download URL')
  .option('--no-cache', 'Skip file cache for html5player')
  .option('--debug', 'Print debug information')
  .parse(process.argv)
  ;

if (!url) {
  opts.outputHelp((help) => {
    return chalk.red('\n  url argument is required\n') + help;
  });
  process.exit(1);
}

const path         = require('path');
const fs           = require('fs');
const ytdl         = require('ytdl-core');
const homedir      = require('homedir');
const util         = require('../lib/util');

const label = chalk.bold.gray;

ytdl.cache.info.timeout = 0;
if (opts.cache !== false) {
  // Keep cache in file.
  const cachefile = path.resolve(homedir(), '.ytdl-cache.json');
  let cache = {};
  fs.readFile(cachefile, (err, contents) => {
    if (err) return;
    try {
      cache = JSON.parse(contents);
    } catch (err) {
      console.error(`Badly formatted cachefile (${cachefile}): ${err.message}`);
    }
  });

  ytdl.cache.sig.get = key => cache[key];
  ytdl.cache.sig.set = (key, value) => {
    cache[key] = value;
    fs.writeFile(cachefile,
      JSON.stringify(cache, null, 2), () => {});
  };
}

/**
 * Prints basic video information.
 *
 * @param {Object} info
 * @param {boolean} live
 */
const printVideoInfo = (info, live) => {
  console.log(label('title: ') + info.title);
  console.log(label('author: ') + info.author.name);
  console.log(label('avg rating: ') +
    info.player_response.videoDetails.averageRating);
  console.log(label('views: ') +
    info.player_response.videoDetails.viewCount);
  if (!live) {
    console.log(label('length: ') + util.toHumanTime(info.length_seconds));
  }
};

if (opts.infoJson) {
  ytdl.getInfo(url, { debug: opts.debug }, (err, info) => {
    if (err) {
      console.error(err.message);
      process.exit(1);
      return;
    }
    console.log(JSON.stringify(info));
  });
} else if (opts.info) {
  const cliff = require('cliff');
  ytdl.getInfo(url, { debug: opts.debug }, (err, info) => {
    if (err) {
      console.error(err.message);
      process.exit(1);
      return;
    }

    printVideoInfo(info, info.formats.some(f => f.live));

    const cols = [
      'itag',
      'container',
      'quality',
      'codecs',
      'bitrate',
      'audio bitrate'
    ];
    info.formats.forEach((format) => {
      format['quality'] = format.qualityLabel;
      format['bitrate'] = format.qualityLabel ?
        util.toHumanSize(format.bitrate) : null;
      format['audio bitrate'] = format.audioBitrate ?
        format.audioBitrate + 'KB' : null;
      cols.forEach((col) => {
        format[col] = format[col] || '';
      });
    });
    console.log(label('formats:'));
    const colors = ['green', 'blue', 'green', 'blue', 'green', 'blue'];
    console.log(cliff.stringifyObjectRows(info.formats, cols, colors));
  });

} else {
  let output = opts.output;
  let ext = (output || '').match(/(\.\w+)?$/)[1];

  if (output) {
    if (ext && !opts.quality && !opts.filterContainer) {
      opts.filterContainer = '^' + ext.slice(1) + '$';
    }
  } else if (process.stdout.isTTY) {
    output = '{title}';
  }

  const ytdlOptions = {};
  ytdlOptions.quality = /,/.test(opts.quality) ?
    opts.quality.split(',') : opts.quality;
  if (opts.range) {
    let s = opts.range.split('-');
    ytdlOptions.range = { start: s[0], end: s[1] };
  }
  ytdlOptions.begin = opts.begin;

  // Create filters.
  const filters = [];

  /**
   * @param {string} field
   * @param {string} regexpStr
   * @param {boolean|null} negated
   */
  const createFilter = (field, regexpStr, negated) => {
    let regexp;
    try {
      regexp = new RegExp(regexpStr, 'i');
    } catch (err) {
      console.error(err.message);
      process.exit(1);
    }

    filters.push(format => negated !== regexp.test(format[field]));
  };

  ['container', 'resolution:qualityLabel', 'encoding'].forEach((field) => {
    let [fieldName, fieldKey] = field.split(':');
    let optsKey = 'filter' + fieldName[0].toUpperCase() + fieldName.slice(1);
    if (opts[optsKey]) {
      createFilter(fieldKey, opts[optsKey], false);
    }

    optsKey = 'un' + optsKey;
    if (opts[optsKey]) {
      createFilter(fieldKey, opts[optsKey], true);
    }
  });

  // Support basic ytdl-core filters manually, so that other
  // cli filters are supported when used together.
  const hasVideo = format => !!format.qualityLabel;
  const hasAudio = format => !!format.audioBitrate;
  switch (opts.filter) {
    case 'video':
      filters.push(hasVideo);
      break;

    case 'videoonly':
      filters.push(format => hasVideo(format) && !hasAudio(format));
      break;

    case 'audio':
      filters.push(hasAudio);
      break;

    case 'audioonly':
      filters.push(format => !hasVideo(format) && hasAudio(format));
      break;
  }

  ytdlOptions.filter = (format) => {
    return filters.every(filter => filter(format));
  };

  if (opts.printUrl) {
    ytdl.getInfo(url, { debug: opts.debug }, (err, info) => {
      if (err) {
        console.error(err.message);
        process.exit(1);
        return;
      }
      let format = ytdl.chooseFormat(info.formats, ytdlOptions);
      if (format instanceof Error) {
        console.error(format.message);
        process.exit(1);
        return;
      }
      console.log(format.url);
    });

  } else {
    const readStream = ytdl(url, ytdlOptions);
    const stdoutMutable = process.stdout && process.stdout.cursorTo && process.stdout.clearLine;

    /**
     * Prints video size with a progress bar as it downloads.
     *
     * @param {number} size
     */
    const printVideoSize = (size) => {
      console.log(label('size: ') + util.toHumanSize(size) +
        ' (' + size +' bytes)');
      console.log();
      if (!stdoutMutable) { return; }

      // Create progress bar.
      const bar = require('progress-bar').create(process.stdout, 50);
      const throttle = require('lodash.throttle');
      bar.format = '$bar; $percentage;%';

      let lastPercent = null;
      let updateBar = () => {
        let percent = dataRead / size;
        let newPercent = Math.floor(percent * 100);
        if (newPercent != lastPercent) {
          lastPercent = newPercent;
          bar.update(percent);
        }
      };
      let updateBarThrottled = throttle(updateBar, 100, { trailing: false });

      // Keep track of progress.
      let dataRead = 0;
      readStream.on('data', (data) => {
        dataRead += data.length;
        if (dataRead === size) {
          updateBar();
        } else {
          updateBarThrottled();
        }
      });

      readStream.on('end', () => {
        console.log();
      });
    };

    /**
     * Prints size of a live video, playlist, or video format that does not
     * have a content size either in its format metadata or its headers.
     */
    const printLiveVideoSize = () => {
      const throttle = require('lodash.throttle');
      let dataRead = 0;
      const updateProgress = throttle(() => {
        process.stdout.cursorTo(0);
        process.stdout.clearLine(1);
        let line = label('size: ') + util.toHumanSize(dataRead);
        if (dataRead >= 1024) {
          line += ` (${dataRead} bytes)`;
        }
        process.stdout.write(line);
      }, 500);

      readStream.on('data', (data) => {
        dataRead += data.length;
        if (stdoutMutable) {
          updateProgress();
        }
      });

      readStream.on('end', () => {
        if (stdoutMutable) {
          updateProgress.flush();
          console.log();
        } else {
          console.log('\n' + label('downloaded: ') + util.toHumanSize(dataRead));
        }
      });
    };

    readStream.on('info', (info, format) => {
      if (!output) {
        readStream.pipe(process.stdout).on('error', (err) => {
          console.error(err.message);
          process.exit(1);
        });
        return;
      }

      output = util.tmpl(output, [info, format]);
      if (!ext && format.container) {
        output += '.' + format.container;
      }

      // Parses & sanitises output filename for any illegal characters
      let parsedOutput = path.parse(output);
      output = path.format({
        dir: parsedOutput.dir,
        base: parsedOutput.base,
      });

      readStream.pipe(fs.createWriteStream(output))
        .on('error', (err) => {
          console.error(err.message);
          process.exit(1);
        });

      // Print information about the video if not streaming to stdout.
      printVideoInfo(info, format.live);

      console.log(label('container: ') + format.container);
      if (format.qualityLabel) {
        console.log(label('quality: ') + format.qualityLabel);
        console.log(label('bitrate: ') + util.toHumanSize(format.bitrate));
      }
      if (format.audioBitrate) {
        console.log(label('audio bitrate: ') + format.audioBitrate + 'KB');
      }
      console.log(label('codecs: ') + format.codecs);
      console.log(label('output: ') + output);

      // Print an incremental size if format size is unknown.
      let sizeUnknown = !format.clen &&
        (format.live || format.isHLS || format.isDashMPD);

      if (sizeUnknown) {
        printLiveVideoSize();
      } else if (format.clen) {
        printVideoSize(parseInt(format.clen, 10));
      } else {
        readStream.once('response', (res) => {
          if (res.headers['content-length']) {
            const size = parseInt(res.headers['content-length'], 10);
            printVideoSize(size);
          } else {
            printLiveVideoSize();
          }
        });
      }

    });

    readStream.on('error', (err) => {
      console.error(err.message);
      process.exit(1);
    });

    process.on('SIGINT', () => {
      console.log();
      process.exit();
    });
  }
}
<commit_msg>feat: print itag when downloading<commit_after>#!/usr/bin/env node

let url;
const info = require('../package');
const chalk = require('chalk');
const opts = require('commander')
  .version(info.version)
  .arguments('<url>')
  .action((a) => { url = a; })
  .option('-q, --quality <ITAG>',
    'Video quality to download, default: highest')
  .option('-r, --range <INT>..<INT>',
    'Byte range to download, ie 10355705-12452856')
  .option('-b, --begin <INT>', 'Time to begin video, format by 1:30.123 and 1m30s')
  .option('-o, --output <FILE>', 'Save to file, template by {prop}, default: stdout or {title}')
  .option('--filter <STR>',
    'Can be video, videoonly, audio, audioonly',
    /^(video|audio)(only)?$/)
  .option('--filter-container <REGEXP>', 'Filter in format container')
  .option('--unfilter-container <REGEXP>', 'Filter out format container')
  .option('--filter-resolution <REGEXP>', 'Filter in format resolution')
  .option('--unfilter-resolution <REGEXP>', 'Filter out format resolution')
  .option('--filter-codecs <REGEXP>', 'Filter in format codecs')
  .option('--unfilter-codecs <REGEXP>', 'Filter out format codecs')
  .option('-i, --info', 'Print video info without downloading')
  .option('-j, --info-json', 'Print video info as JSON without downloading')
  .option('--print-url', 'Print direct download URL')
  .option('--no-cache', 'Skip file cache for html5player')
  .option('--debug', 'Print debug information')
  .parse(process.argv)
  ;

if (!url) {
  opts.outputHelp((help) => {
    return chalk.red('\n  url argument is required\n') + help;
  });
  process.exit(1);
}

const path         = require('path');
const fs           = require('fs');
const ytdl         = require('ytdl-core');
const homedir      = require('homedir');
const util         = require('../lib/util');

const label = chalk.bold.gray;

ytdl.cache.info.timeout = 0;
if (opts.cache !== false) {
  // Keep cache in file.
  const cachefile = path.resolve(homedir(), '.ytdl-cache.json');
  let cache = {};
  fs.readFile(cachefile, (err, contents) => {
    if (err) return;
    try {
      cache = JSON.parse(contents);
    } catch (err) {
      console.error(`Badly formatted cachefile (${cachefile}): ${err.message}`);
    }
  });

  ytdl.cache.sig.get = key => cache[key];
  ytdl.cache.sig.set = (key, value) => {
    cache[key] = value;
    fs.writeFile(cachefile,
      JSON.stringify(cache, null, 2), () => {});
  };
}

/**
 * Prints basic video information.
 *
 * @param {Object} info
 * @param {boolean} live
 */
const printVideoInfo = (info, live) => {
  console.log(label('title: ') + info.title);
  console.log(label('author: ') + info.author.name);
  console.log(label('avg rating: ') +
    info.player_response.videoDetails.averageRating);
  console.log(label('views: ') +
    info.player_response.videoDetails.viewCount);
  if (!live) {
    console.log(label('length: ') + util.toHumanTime(info.length_seconds));
  }
};

if (opts.infoJson) {
  ytdl.getInfo(url, { debug: opts.debug }, (err, info) => {
    if (err) {
      console.error(err.message);
      process.exit(1);
      return;
    }
    console.log(JSON.stringify(info));
  });
} else if (opts.info) {
  const cliff = require('cliff');
  ytdl.getInfo(url, { debug: opts.debug }, (err, info) => {
    if (err) {
      console.error(err.message);
      process.exit(1);
      return;
    }

    printVideoInfo(info, info.formats.some(f => f.live));

    const cols = [
      'itag',
      'container',
      'quality',
      'codecs',
      'bitrate',
      'audio bitrate'
    ];
    info.formats.forEach((format) => {
      format['quality'] = format.qualityLabel;
      format['bitrate'] = format.qualityLabel ?
        util.toHumanSize(format.bitrate) : null;
      format['audio bitrate'] = format.audioBitrate ?
        format.audioBitrate + 'KB' : null;
      cols.forEach((col) => {
        format[col] = format[col] || '';
      });
    });
    console.log(label('formats:'));
    const colors = ['green', 'blue', 'green', 'blue', 'green', 'blue'];
    console.log(cliff.stringifyObjectRows(info.formats, cols, colors));
  });

} else {
  let output = opts.output;
  let ext = (output || '').match(/(\.\w+)?$/)[1];

  if (output) {
    if (ext && !opts.quality && !opts.filterContainer) {
      opts.filterContainer = '^' + ext.slice(1) + '$';
    }
  } else if (process.stdout.isTTY) {
    output = '{title}';
  }

  const ytdlOptions = {};
  ytdlOptions.quality = /,/.test(opts.quality) ?
    opts.quality.split(',') : opts.quality;
  if (opts.range) {
    let s = opts.range.split('-');
    ytdlOptions.range = { start: s[0], end: s[1] };
  }
  ytdlOptions.begin = opts.begin;

  // Create filters.
  const filters = [];

  /**
   * @param {string} field
   * @param {string} regexpStr
   * @param {boolean|null} negated
   */
  const createFilter = (field, regexpStr, negated) => {
    let regexp;
    try {
      regexp = new RegExp(regexpStr, 'i');
    } catch (err) {
      console.error(err.message);
      process.exit(1);
    }

    filters.push(format => negated !== regexp.test(format[field]));
  };

  ['container', 'resolution:qualityLabel', 'encoding'].forEach((field) => {
    let [fieldName, fieldKey] = field.split(':');
    let optsKey = 'filter' + fieldName[0].toUpperCase() + fieldName.slice(1);
    if (opts[optsKey]) {
      createFilter(fieldKey, opts[optsKey], false);
    }

    optsKey = 'un' + optsKey;
    if (opts[optsKey]) {
      createFilter(fieldKey, opts[optsKey], true);
    }
  });

  // Support basic ytdl-core filters manually, so that other
  // cli filters are supported when used together.
  const hasVideo = format => !!format.qualityLabel;
  const hasAudio = format => !!format.audioBitrate;
  switch (opts.filter) {
    case 'video':
      filters.push(hasVideo);
      break;

    case 'videoonly':
      filters.push(format => hasVideo(format) && !hasAudio(format));
      break;

    case 'audio':
      filters.push(hasAudio);
      break;

    case 'audioonly':
      filters.push(format => !hasVideo(format) && hasAudio(format));
      break;
  }

  ytdlOptions.filter = (format) => {
    return filters.every(filter => filter(format));
  };

  if (opts.printUrl) {
    ytdl.getInfo(url, { debug: opts.debug }, (err, info) => {
      if (err) {
        console.error(err.message);
        process.exit(1);
        return;
      }
      let format = ytdl.chooseFormat(info.formats, ytdlOptions);
      if (format instanceof Error) {
        console.error(format.message);
        process.exit(1);
        return;
      }
      console.log(format.url);
    });

  } else {
    const readStream = ytdl(url, ytdlOptions);
    const stdoutMutable = process.stdout && process.stdout.cursorTo && process.stdout.clearLine;

    /**
     * Prints video size with a progress bar as it downloads.
     *
     * @param {number} size
     */
    const printVideoSize = (size) => {
      console.log(label('size: ') + util.toHumanSize(size) +
        ' (' + size +' bytes)');
      console.log();
      if (!stdoutMutable) { return; }

      // Create progress bar.
      const bar = require('progress-bar').create(process.stdout, 50);
      const throttle = require('lodash.throttle');
      bar.format = '$bar; $percentage;%';

      let lastPercent = null;
      let updateBar = () => {
        let percent = dataRead / size;
        let newPercent = Math.floor(percent * 100);
        if (newPercent != lastPercent) {
          lastPercent = newPercent;
          bar.update(percent);
        }
      };
      let updateBarThrottled = throttle(updateBar, 100, { trailing: false });

      // Keep track of progress.
      let dataRead = 0;
      readStream.on('data', (data) => {
        dataRead += data.length;
        if (dataRead === size) {
          updateBar();
        } else {
          updateBarThrottled();
        }
      });

      readStream.on('end', () => {
        console.log();
      });
    };

    /**
     * Prints size of a live video, playlist, or video format that does not
     * have a content size either in its format metadata or its headers.
     */
    const printLiveVideoSize = () => {
      const throttle = require('lodash.throttle');
      let dataRead = 0;
      const updateProgress = throttle(() => {
        process.stdout.cursorTo(0);
        process.stdout.clearLine(1);
        let line = label('size: ') + util.toHumanSize(dataRead);
        if (dataRead >= 1024) {
          line += ` (${dataRead} bytes)`;
        }
        process.stdout.write(line);
      }, 500);

      readStream.on('data', (data) => {
        dataRead += data.length;
        if (stdoutMutable) {
          updateProgress();
        }
      });

      readStream.on('end', () => {
        if (stdoutMutable) {
          updateProgress.flush();
          console.log();
        } else {
          console.log('\n' + label('downloaded: ') + util.toHumanSize(dataRead));
        }
      });
    };

    readStream.on('info', (info, format) => {
      if (!output) {
        readStream.pipe(process.stdout).on('error', (err) => {
          console.error(err.message);
          process.exit(1);
        });
        return;
      }

      output = util.tmpl(output, [info, format]);
      if (!ext && format.container) {
        output += '.' + format.container;
      }

      // Parses & sanitises output filename for any illegal characters
      let parsedOutput = path.parse(output);
      output = path.format({
        dir: parsedOutput.dir,
        base: parsedOutput.base,
      });

      readStream.pipe(fs.createWriteStream(output))
        .on('error', (err) => {
          console.error(err.message);
          process.exit(1);
        });

      // Print information about the video if not streaming to stdout.
      printVideoInfo(info, format.live);

      // Print format information.
      console.log(label('itag: ') + format.itag);
      console.log(label('container: ') + format.container);
      if (format.qualityLabel) {
        console.log(label('quality: ') + format.qualityLabel);
        console.log(label('video bitrate: ') + util.toHumanSize(format.bitrate));
      }
      if (format.audioBitrate) {
        console.log(label('audio bitrate: ') + format.audioBitrate + 'KB');
      }
      console.log(label('codecs: ') + format.codecs);
      console.log(label('output: ') + output);

      // Print an incremental size if format size is unknown.
      let sizeUnknown = !format.clen &&
        (format.live || format.isHLS || format.isDashMPD);

      if (sizeUnknown) {
        printLiveVideoSize();
      } else if (format.clen) {
        printVideoSize(parseInt(format.clen, 10));
      } else {
        readStream.once('response', (res) => {
          if (res.headers['content-length']) {
            const size = parseInt(res.headers['content-length'], 10);
            printVideoSize(size);
          } else {
            printLiveVideoSize();
          }
        });
      }

    });

    readStream.on('error', (err) => {
      console.error(err.message);
      process.exit(1);
    });

    process.on('SIGINT', () => {
      console.log();
      process.exit();
    });
  }
}
<|endoftext|>


<commit_before>var Block=require("block");

function GAME(type){
    this.stage=document.getElementById(type+"Stage");
    this.scoreBox=document.getElementById(type+"Score");
    this.nameBox=document.getElementById(type+"Name");
    this.control=type;

    //初始化
    this.init=function(){
        if(arguments[0]) {
            this.ws=arguments[0];
            this.setNameBox(arguments[0].userName)
        }
        this.clearStage();
        this.score=0;
        this.map=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]; //2048地图阵列
        this.blkArr=[];         //存储方块的数组
        this.maxNum=0;          //方块数
        this.score=0;           //分数初始化
        this.isKeyDown=0;       //记录键盘是否按下
        this.isMove=0;          //记录是否有移动
        this.moveNum=0;         //记录同时移动的操作数量，当有滑块仍在移动时禁止操作
        this.beginPos=[];       //方块记录队列，用于记录未渲染但已生成的方块
        if(this.control=="self"){
            this.rand();
            this.rand();
            this.rand();
            window.onkeydown = function (event) {
                if (that.isKeyDown) return;
                if(that.moveNum>=1) return;
                that.moveNum++;
                var e = event || window.event;
                if (e) {
                    that.isKeyDown = 1;
                    that.slide(e.keyCode);
                }
            };
            window.onkeyup = function () {
                that.isKeyDown = 0;
            };
        }
        var that=this;
        setInterval(function(){
            that.scoreBox.innerHTML=that.score;
        },10)
    };

    //渲染beginPos队列中的成员方块
    this.createBlock=function(){
        while(this.beginPos.length){
            var blk=new Block(),
                pos=this.beginPos.shift(),
                x=pos.x, y=pos.y;
            this.blkArr.push(blk);
            blk.create(x,y,this.stage);
            blk.setNumber(pos.num);
            this.map[y][x]=blk;
        }
    };

    //随机生成方块插入队列中，等待渲染
    this.rand=function(){
        var x, y;
        var newNum = Math.random() <= 0.6 ? 2 : 4;  //4的概率稍小
        x = Math.floor(Math.random() * 4);
        y = Math.floor(Math.random() * 4);
        while (this.map[y][x] != 0 || x == 4 || y == 4) {
            x = Math.floor(Math.random() * 4);
            y = Math.floor(Math.random() * 4);
        }
        this.beginPos.push({x:x,y:y,num:newNum});
        this.map[y][x]=1;
    };

    //设置顶端名字
    this.setNameBox=function(name){
        this.nameBox.innerHTML=name;
    };

    //方块合并
    this.merge=function(prevBlock,currBlock){
        var prev=prevBlock.block.innerHTML;
        var curr=currBlock.block.innerHTML;
        //console.log(prev,curr);
        if(prev==curr){
            if(!this.isMove) this.isMove=1;
            var prevx=prevBlock.x,
                prevy=prevBlock.y;
            prevBlock.position(currBlock.x,currBlock.y);
            currBlock.setNumber(curr * 2);
            prevBlock.block.style.zIndex=-1;
            this.map[prevy][prevx]=0;
            this.score+=curr*2;
            var that=this;
            setTimeout(function(){
                that.stage.removeChild(prevBlock.block);
                delete prevBlock;
            },300);
            return true;
        }
        return false;
    };

    //方块移动
    this.slide=function(keycode){
        var i, j, k, curr;
        if(keycode==37){//Left
            for(i=0;i<4;i++){
                k=0;
                for(j=0;j<3;j++){//所有块先移动
                    if(this.map[i][j]==0){
                        if(k==0) k=j+1;
                        while(k<4 && this.map[i][k]==0 && k++);
                        if(k==4) break;
                        this.map[i][k].position(j,i);
                        this.map[i][j]=this.map[i][k];
                        this.map[i][k]=0;
                    }
                }
                for(j=0;j<3;j++){//相邻等值块合并
                    if(this.map[i][j]!=0 && this.map[i][j+1]!=0) {
                        if(this.merge(this.map[i][j + 1], this.map[i][j])){
                            //防止相邻两两合并时方块无动画消失
                            curr=k=j+1;
                            while(k<4){
                                if(this.map[i][k]!=0){
                                    this.map[i][k].position(curr,i);
                                    this.map[i][curr++]=this.map[i][k];
                                    this.map[i][k]=0;
                                }
                                k++;
                            }
                        }
                    }
                }
                k=0;
                for(j=0;j<3;j++){//消除合并后可能产生的空块
                    if(this.map[i][j]==0){
                        if(k==0) k=j+1;
                        while(k<4 && this.map[i][k]==0 && k++);
                        if(k==4) break;
                        this.map[i][k].position(j,i);
                        this.map[i][j]=this.map[i][k];
                        this.map[i][k]=0;
                    }
                }
            }
        }
        if(keycode==38){//Top
            for(i=0;i<4;i++){
                k=0;
                for(j=0;j<3;j++){//所有块先移动
                    if(this.map[j][i]==0){
                        if(k==0) k=j+1;
                        while(k<4 && this.map[k][i]==0 && k++);
                        if(k==4) break;
                        this.map[k][i].position(i,j);
                        this.map[j][i]=this.map[k][i];
                        this.map[k][i]=0;
                    }
                }
                for(j=0;j<3;j++){//相邻等值块合并
                    if(this.map[j][i]!=0 && this.map[j+1][i]!=0) {
                        if(this.merge(this.map[j+1][i], this.map[j][i])){
                            //防止相邻两两合并时方块无动画消失
                            curr=k=j+1;
                            while(k<4){
                                if(this.map[k][i]!=0){
                                    this.map[k][i].position(i,curr);
                                    this.map[curr++][i]=this.map[k][i];
                                    this.map[k][i]=0;
                                }
                                k++;
                            }
                        }
                    }
                }
                k=0;
                for(j=0;j<3;j++){//消除合并后可能产生的空块
                    if(this.map[j][i]==0){
                        if(k==0) k=j+1;
                        while(k<4 && this.map[k][i]==0 && k++);
                        if(k==4) break;
                        this.map[k][i].position(i,j);
                        this.map[j][i]=this.map[k][i];
                        this.map[k][i]=0;
                    }
                }
            }
        }
        if(keycode==39){//Right
            for(i=0;i<4;i++){
                k=3;
                for(j=3;j>=1;j--){//所有块先移动
                    if(this.map[i][j]==0){
                        if(k==3) k=j-1;
                        while(k>=0 && this.map[i][k]==0 && k--);
                        if(k==-1) break;
                        this.map[i][k].position(j,i);
                        this.map[i][j]=this.map[i][k];
                        this.map[i][k]=0;
                    }
                }
                for(j=3;j>=1;j--){//相邻等值块合并
                    if(this.map[i][j]!=0 && this.map[i][j-1]!=0) {
                        if(this.merge(this.map[i][j - 1], this.map[i][j])){
                            //防止相邻两两合并时方块无动画消失
                            curr=k=j-1;
                            while(k>=0){
                                if(this.map[i][k]!=0){
                                    this.map[i][k].position(curr,i);
                                    this.map[i][curr--]=this.map[i][k];
                                    this.map[i][k]=0;
                                }
                                k--;
                            }
                        }
                    }
                }
                k=3;
                for(j=3;j>=1;j--){//消除合并后可能产生的空块
                    if(this.map[i][j]==0){
                        if(k==3) k=j-1;
                        while(k>=0 && this.map[i][k]==0 && k--);
                        if(k==-1) break;
                        this.map[i][k].position(j,i);
                        this.map[i][j]=this.map[i][k];
                        this.map[i][k]=0;
                    }
                }
            }
        }
        if(keycode==40){//Down
            for(i=0;i<4;i++){
                k=3;
                for(j=3;j>=1;j--){//所有块先移动
                    if(this.map[j][i]==0){
                        if(k==3) k=j-1;
                        while(k>=0 && this.map[k][i]==0 && k--);
                        if(k==-1) break;
                        this.map[k][i].position(i,j);
                        this.map[j][i]=this.map[k][i];
                        this.map[k][i]=0;
                    }
                }
                for(j=3;j>=1;j--){//相邻等值块合并
                    if(this.map[j][i]!=0 && this.map[j-1][i]!=0) {
                        if(this.merge(this.map[j-1][i], this.map[j][i])){
                            //防止相邻两两合并时方块无动画消失
                            curr=k=j-1;
                            while(k>=0){
                                if(this.map[k][i]!=0){
                                    this.map[k][i].position(i,curr);
                                    this.map[curr--][i]=this.map[k][i];
                                    this.map[k][i]=0;
                                }
                                k--;
                            }
                        }
                    }
                }
                k=3;
                for(j=3;j>=1;j--){//消除合并后可能产生的空块
                    if(this.map[j][i]==0){
                        if(k==3) k=j-1;
                        while(k>=0 && this.map[k][i]==0 && k--);
                        if(k==-1) break;
                        this.map[k][i].position(i,j);
                        this.map[j][i]=this.map[k][i];
                        this.map[k][i]=0;
                    }
                }
            }
        }
        if(keycode<=40 && keycode>=37) {
            var that=this,info;
            setTimeout(function () {
                var numOfBlock = 0;
                for (i = 0; i < 4; i++) {
                    for (j = 0; j < 4; j++) {
                        if (that.map[i][j] != 0){
                            numOfBlock++;
                            if(that.map[i][j].block.innerHTML>that.maxNum){
                                that.maxNum=that.map[i][j].block.innerHTML
                            }
                        }
                    }
                }
                //console.log(numOfBlock)
                if (numOfBlock == 16 && !that.isMove) {
                    info={
                        code:-2,
                        user:that.ws.userName,
                        roomId:that.ws.roomId,
                        token:that.ws.token
                    };
                    that.ws.send(JSON.stringify(info));
                    that.init();
                }
                else {
                    that.isMove=0;
                    if(that.control=="self") {  //若为己方，才将行动码发至对方
                        that.moveNum--;
                        that.rand();
                        info = {
                            code: 2,
                            user:that.ws.userName,
                            roomId:that.ws.roomId,
                            token:that.ws.token,
                            actionCode: keycode,
                            beginPos:that.beginPos
                        };
                        that.ws.send(JSON.stringify(info));
                    }
                    that.createBlock();
                }
            }, 250)
        }
    };
    this.clearStage=function(){
        while(this.stage.hasChildNodes()){
            this.stage.removeChild(this.stage.firstChild);
        }
    }
}

module.exports=GAME;
<commit_msg>fixed a bug of keydown counts<commit_after>var Block=require("block");

function GAME(type){
    this.stage=document.getElementById(type+"Stage");
    this.scoreBox=document.getElementById(type+"Score");
    this.nameBox=document.getElementById(type+"Name");
    this.control=type;

    //初始化
    this.init=function(){
        if(arguments[0]) {
            this.ws=arguments[0];
            this.setNameBox(arguments[0].userName)
        }
        this.clearStage();
        this.score=0;
        this.map=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]; //2048地图阵列
        this.blkArr=[];         //存储方块的数组
        this.maxNum=0;          //方块数
        this.score=0;           //分数初始化
        this.isKeyDown=0;       //记录键盘是否按下
        this.isMove=0;          //记录是否有移动
        this.moveNum=0;         //记录同时移动的操作数量，当有滑块仍在移动时禁止操作
        this.beginPos=[];       //方块记录队列，用于记录未渲染但已生成的方块
        if(this.control=="self"){
            this.rand();
            this.rand();
            this.rand();
            window.onkeydown = function (event) {
                if (that.isKeyDown) return;
                if(that.moveNum>=1) return;
                var e = event || window.event;
                if (e) {
                    if(e.keyCode>=37 && e.keyCode<=40) {
                        that.isKeyDown = 1;
                        that.slide(e.keyCode);
                        that.moveNum++;
                    }
                }
            };
            window.onkeyup = function () {
                that.isKeyDown = 0;
            };
        }
        var that=this;
        setInterval(function(){
            that.scoreBox.innerHTML=that.score;
        },10)
    };

    //渲染beginPos队列中的成员方块
    this.createBlock=function(){
        while(this.beginPos.length){
            var blk=new Block(),
                pos=this.beginPos.shift(),
                x=pos.x, y=pos.y;
            this.blkArr.push(blk);
            blk.create(x,y,this.stage);
            blk.setNumber(pos.num);
            this.map[y][x]=blk;
        }
    };

    //随机生成方块插入队列中，等待渲染
    this.rand=function(){
        var x, y;
        var newNum = Math.random() <= 0.6 ? 2 : 4;  //4的概率稍小
        x = Math.floor(Math.random() * 4);
        y = Math.floor(Math.random() * 4);
        while (this.map[y][x] != 0 || x == 4 || y == 4) {
            x = Math.floor(Math.random() * 4);
            y = Math.floor(Math.random() * 4);
        }
        this.beginPos.push({x:x,y:y,num:newNum});
        this.map[y][x]=1;
    };

    //设置顶端名字
    this.setNameBox=function(name){
        this.nameBox.innerHTML=name;
    };

    //方块合并
    this.merge=function(prevBlock,currBlock){
        var prev=prevBlock.block.innerHTML;
        var curr=currBlock.block.innerHTML;
        //console.log(prev,curr);
        if(prev==curr){
            if(!this.isMove) this.isMove=1;
            var prevx=prevBlock.x,
                prevy=prevBlock.y;
            prevBlock.position(currBlock.x,currBlock.y);
            currBlock.setNumber(curr * 2);
            prevBlock.block.style.zIndex=-1;
            this.map[prevy][prevx]=0;
            this.score+=curr*2;
            var that=this;
            setTimeout(function(){
                that.stage.removeChild(prevBlock.block);
                delete prevBlock;
            },300);
            return true;
        }
        return false;
    };

    //方块移动
    this.slide=function(keycode){
        var i, j, k, curr;
        if(keycode==37){//Left
            for(i=0;i<4;i++){
                k=0;
                for(j=0;j<3;j++){//所有块先移动
                    if(this.map[i][j]==0){
                        if(k==0) k=j+1;
                        while(k<4 && this.map[i][k]==0 && k++);
                        if(k==4) break;
                        this.map[i][k].position(j,i);
                        this.map[i][j]=this.map[i][k];
                        this.map[i][k]=0;
                    }
                }
                for(j=0;j<3;j++){//相邻等值块合并
                    if(this.map[i][j]!=0 && this.map[i][j+1]!=0) {
                        if(this.merge(this.map[i][j + 1], this.map[i][j])){
                            //防止相邻两两合并时方块无动画消失
                            curr=k=j+1;
                            while(k<4){
                                if(this.map[i][k]!=0){
                                    this.map[i][k].position(curr,i);
                                    this.map[i][curr++]=this.map[i][k];
                                    this.map[i][k]=0;
                                }
                                k++;
                            }
                        }
                    }
                }
                k=0;
                for(j=0;j<3;j++){//消除合并后可能产生的空块
                    if(this.map[i][j]==0){
                        if(k==0) k=j+1;
                        while(k<4 && this.map[i][k]==0 && k++);
                        if(k==4) break;
                        this.map[i][k].position(j,i);
                        this.map[i][j]=this.map[i][k];
                        this.map[i][k]=0;
                    }
                }
            }
        }
        if(keycode==38){//Top
            for(i=0;i<4;i++){
                k=0;
                for(j=0;j<3;j++){//所有块先移动
                    if(this.map[j][i]==0){
                        if(k==0) k=j+1;
                        while(k<4 && this.map[k][i]==0 && k++);
                        if(k==4) break;
                        this.map[k][i].position(i,j);
                        this.map[j][i]=this.map[k][i];
                        this.map[k][i]=0;
                    }
                }
                for(j=0;j<3;j++){//相邻等值块合并
                    if(this.map[j][i]!=0 && this.map[j+1][i]!=0) {
                        if(this.merge(this.map[j+1][i], this.map[j][i])){
                            //防止相邻两两合并时方块无动画消失
                            curr=k=j+1;
                            while(k<4){
                                if(this.map[k][i]!=0){
                                    this.map[k][i].position(i,curr);
                                    this.map[curr++][i]=this.map[k][i];
                                    this.map[k][i]=0;
                                }
                                k++;
                            }
                        }
                    }
                }
                k=0;
                for(j=0;j<3;j++){//消除合并后可能产生的空块
                    if(this.map[j][i]==0){
                        if(k==0) k=j+1;
                        while(k<4 && this.map[k][i]==0 && k++);
                        if(k==4) break;
                        this.map[k][i].position(i,j);
                        this.map[j][i]=this.map[k][i];
                        this.map[k][i]=0;
                    }
                }
            }
        }
        if(keycode==39){//Right
            for(i=0;i<4;i++){
                k=3;
                for(j=3;j>=1;j--){//所有块先移动
                    if(this.map[i][j]==0){
                        if(k==3) k=j-1;
                        while(k>=0 && this.map[i][k]==0 && k--);
                        if(k==-1) break;
                        this.map[i][k].position(j,i);
                        this.map[i][j]=this.map[i][k];
                        this.map[i][k]=0;
                    }
                }
                for(j=3;j>=1;j--){//相邻等值块合并
                    if(this.map[i][j]!=0 && this.map[i][j-1]!=0) {
                        if(this.merge(this.map[i][j - 1], this.map[i][j])){
                            //防止相邻两两合并时方块无动画消失
                            curr=k=j-1;
                            while(k>=0){
                                if(this.map[i][k]!=0){
                                    this.map[i][k].position(curr,i);
                                    this.map[i][curr--]=this.map[i][k];
                                    this.map[i][k]=0;
                                }
                                k--;
                            }
                        }
                    }
                }
                k=3;
                for(j=3;j>=1;j--){//消除合并后可能产生的空块
                    if(this.map[i][j]==0){
                        if(k==3) k=j-1;
                        while(k>=0 && this.map[i][k]==0 && k--);
                        if(k==-1) break;
                        this.map[i][k].position(j,i);
                        this.map[i][j]=this.map[i][k];
                        this.map[i][k]=0;
                    }
                }
            }
        }
        if(keycode==40){//Down
            for(i=0;i<4;i++){
                k=3;
                for(j=3;j>=1;j--){//所有块先移动
                    if(this.map[j][i]==0){
                        if(k==3) k=j-1;
                        while(k>=0 && this.map[k][i]==0 && k--);
                        if(k==-1) break;
                        this.map[k][i].position(i,j);
                        this.map[j][i]=this.map[k][i];
                        this.map[k][i]=0;
                    }
                }
                for(j=3;j>=1;j--){//相邻等值块合并
                    if(this.map[j][i]!=0 && this.map[j-1][i]!=0) {
                        if(this.merge(this.map[j-1][i], this.map[j][i])){
                            //防止相邻两两合并时方块无动画消失
                            curr=k=j-1;
                            while(k>=0){
                                if(this.map[k][i]!=0){
                                    this.map[k][i].position(i,curr);
                                    this.map[curr--][i]=this.map[k][i];
                                    this.map[k][i]=0;
                                }
                                k--;
                            }
                        }
                    }
                }
                k=3;
                for(j=3;j>=1;j--){//消除合并后可能产生的空块
                    if(this.map[j][i]==0){
                        if(k==3) k=j-1;
                        while(k>=0 && this.map[k][i]==0 && k--);
                        if(k==-1) break;
                        this.map[k][i].position(i,j);
                        this.map[j][i]=this.map[k][i];
                        this.map[k][i]=0;
                    }
                }
            }
        }

        var that=this,info;
        setTimeout(function () {
            var numOfBlock = 0;
            for (i = 0; i < 4; i++) {
                for (j = 0; j < 4; j++) {
                    if (that.map[i][j] != 0){
                        numOfBlock++;
                        if(that.map[i][j].block.innerHTML>that.maxNum){
                            that.maxNum=that.map[i][j].block.innerHTML
                        }
                    }
                }
            }
            //console.log(numOfBlock)
            if (numOfBlock == 16 && !that.isMove) {
                info={
                    code:-2,
                    user:that.ws.userName,
                    roomId:that.ws.roomId,
                    token:that.ws.token
                };
                that.ws.send(JSON.stringify(info));
                that.init();
            }
            else {
                that.isMove=0;
                if(that.control=="self") {  //若为己方，才将行动码发至对方
                    that.moveNum--;
                    that.rand();
                    info = {
                        code: 2,
                        user:that.ws.userName,
                        roomId:that.ws.roomId,
                        token:that.ws.token,
                        actionCode: keycode,
                        beginPos:that.beginPos
                    };
                    that.ws.send(JSON.stringify(info));
                }
                that.createBlock();
            }
        }, 250)
    };
    this.clearStage=function(){
        while(this.stage.hasChildNodes()){
            this.stage.removeChild(this.stage.firstChild);
        }
    }
}

module.exports=GAME;
<|endoftext|>