Browse Source

first commit

xiongzhu 5 năm trước cách đây
commit
94bcefc3a2
12 tập tin đã thay đổi với 1090 bổ sung0 xóa
  1. 1 0
      .gitignore
  2. 13 0
      README.txt
  3. 1 0
      autoTrade.log
  4. 29 0
      collectLog.js
  5. 76 0
      config.js
  6. 126 0
      date.format.js
  7. 7 0
      getChallenge.js
  8. 236 0
      index.js
  9. 27 0
      manage.js
  10. 461 0
      package-lock.json
  11. 18 0
      package.json
  12. 95 0
      server.js

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+/node_modules

+ 13 - 0
README.txt

@@ -0,0 +1,13 @@
+修改配置文件config.js
+下载安装nodejs http://nodejs.cn/download/
+打开widnow+R 输入cmd
+依次输入以下命令
+cd /K 项目文件夹
+npm config set registry https://registry.npm.taobao.org
+npm install
+node manage.js
+
+服务器配置:
+入门级 1 vCPU	0.5 GiB 按量付费
+系统 ubuntu 18.04 64位
+专有网络 100M带宽 按量付费

+ 1 - 0
autoTrade.log

@@ -0,0 +1 @@
+[2020-02-15T19:23:28.176] [ERROR] default - 参数错误,缺少序号

+ 29 - 0
collectLog.js

@@ -0,0 +1,29 @@
+const node_ssh = require('node-ssh');
+const config = require('./config');
+const path = require('path');
+const fs = require('fs');
+
+config.servers.forEach((host, index) => {
+    console.log(host);
+    let ssh = new node_ssh();
+    ssh.connect({
+        host: host,
+        username: 'root',
+        port: 22,
+        password: config.password,
+    }).then(async function() {
+        ssh.getFile(path.resolve(__dirname, `server-${index}.log`), '/root/autoTrade/autoTrade.log')
+            .then(
+                function(Contents) {
+                    console.log("The File's contents were successfully downloaded");
+                },
+                function(error) {
+                    console.log("Something's wrong");
+                    console.log(error);
+                },
+            )
+            .then(() => {
+                ssh.dispose();
+            });
+    });
+});

+ 76 - 0
config.js

@@ -0,0 +1,76 @@
+module.exports = {
+
+ servers: ['47.244.39.44'],  //服务器IP地址
+ password: 'Xky5483698+', //服务器密码
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+    secretDetectUrl: 'https://www.okex.me/v2/support/active/ieo/project/currencyListDynamic/192/184',  //获取secretStr的地址
+    purchaseUrl: 'https://www.okex.me/v2/support/active/ieo/project/purchase', //购买地址,无需变化
+    currencyId: 184, //
+    projectId: "192", //
+    purchaseAccounts: [
+        {
+            Authorization: 'eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiJleDExMDE1NjQ1MzM2MDQ0MTM3OEYyREUzMjQxRUE3QjkxTXhhTyIsInVpZCI6ImJ6L3ljbFFpZHJTbUlNdGt1SWcrOHc9PSIsInN0YSI6MCwibWlkIjowLCJpYXQiOjE1NjQ1MzM2MDQsImV4cCI6MTU2NTEzODQwNCwiYmlkIjowLCJkb20iOiJ3d3cub2tleC5tZSIsImlzcyI6Im9rY29pbiIsInN1YiI6IkREQzczOTIwOUNGNUJFMTFBNDdDODc5MTAzRDU1ODA2In0.s_Bs7-h6X_UrSsWzQS5nkpLk_7uTRaBVwssCvAZWTbrRxykNSuWSViyeHLJVhpOQN0Mjda2UOOOrsQxm0fM8lQ',
+            Cookie: 'perm=5F5424115F156D2CE8395562436D360D; lp=; _bl_uid=9Oj86x0tf9kiU3mb4aRqdgp52qpI; _ga=GA1.2.1809528829.1561737273; locale=zh_CN; EuropeAgreement=0; u_ip=MTE0LjIyMS4xMC4yMDA; Hm_lvt_01a61555119115f9226e2c15e411694e=1564388095,1564395359,1564452682,1564533521; first_ref=https%3A%2F%2Fwww.okex.me%2Factivity%2Fjumpstart%2Fproject%3Fid%3D235; u_pid=D6D6lm9rzXGuBWu; PVTAG=274.408.7d4pBABsZd8liXeL0DUuWBuGXzr9ml6D6DXzPf1A; finger_test_cookie=; isLogin=1; ftID=521031927088840.011b58722ee0aedc2dde0e220826eae6b2481.1010L8o0.B248365332E551D1; x-lid=c622d16c059f87b40af160bdce9979df3f389b383db11e74d1f7118d3e182eea295a14a6; product=okb_btc; Hm_lpvt_01a61555119115f9226e2c15e411694e=1564534101',
+            purchaseAmount: '36000', //购买数量
+            purchase: true, //用来购买的账号
+            delay: 1000 //
+        },
+    ],
+    accounts: [{
+        Authorization: 'eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiJleDExMDE1NjQ0NzgwMjE5MDlENDhENUIwN0IyMEUxOUNBcHBPRCIsInVpZCI6IjcwRDFWL1FLZWgvWnl5S2NMSjlhVVE9PSIsInN0YSI6MCwibWlkIjowLCJpYXQiOjE1NjQ0NzgwMjEsImV4cCI6MTU2NTA4MjgyMSwiYmlkIjowLCJkb20iOiJ3d3cub2tleC5tZSIsImlzcyI6Im9rY29pbiIsInN1YiI6IjIxMDU2Q0MyNUY2OTUwQjUxQ0JCOEMxNDhDMzc5MDc3In0.d8ee8ET1Z9u7Dn0xn1E-h0-Mrwbz8F88PQElajXgs7MY_gnSw49r3OKaA9AJjEJ4ct4JCkZo5qjhwk2pVk970w',
+        Cookie: 'locale=zh_CN; u_ip=NDcuNTIuMTY4LjE5MQ; u_pid=D6D6lm9rzXGuBWu; PVTAG=274.408.E8dlgZYT2a4rIbQL7aUuWBuGXzr9ml6D6DMLlf1A; Hm_lvt_01a61555119115f9226e2c15e411694e=1564478005; finger_test_cookie=; _ga=GA1.2.1675415864.1564478005; _gid=GA1.2.2044233320.1564478005; _gat_gtag_UA_35324627_3=1; _bl_uid=3zjCbywvp7Ol0vtU079hnj8gyb9g; isLogin=1; ftID=42065F8856BCB02D246.791980223; first_ref=https%3A%2F%2Fwww.okex.me%2Faccount%2Flogin%3Fforward%3Dhttps%253A%252F%252Fwww.okex.me%252Factivity%252Fjumpstart%252Fproject%253Fid%253D235; Hm_lpvt_01a61555119115f9226e2c15e411694e=1564478023',
+    },
+    {
+        Authorization: 'eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiJleDExMDE1NjQ0NzgwNTk3NTNDMjYzMkIyNEFCQzMzOTlDYlFadiIsInVpZCI6InZqVm1NMFpFOXltcksxWG14MVFOakE9PSIsInN0YSI6MCwibWlkIjowLCJpYXQiOjE1NjQ0NzgwNTksImV4cCI6MTU2NTA4Mjg1OSwiYmlkIjowLCJkb20iOiJ3d3cub2tleC5tZSIsImlzcyI6Im9rY29pbiIsInN1YiI6IjM1Q0VFNTQxQUFDODc0MEYxQ0JCOEMxNDhDMzc5MDc3In0.IJ_I0pN7aOtrZoQI-6Z00vKmLYf2u7lLr1YAA0RtYi6cqZVVKxctR4rPmD5i-om0qtqCKFl93l2a3UE9iqKRnA',
+        Cookie: 'locale=zh_CN; u_ip=NDcuNTIuMTY4LjE5MQ; u_pid=D6D6lm9rzXGuBWu; PVTAG=274.408.e7ZG8XQia3rxC75r9NUuWBuGXzr9ml6D6D86jf1A; Hm_lvt_01a61555119115f9226e2c15e411694e=1564478043; finger_test_cookie=; _ga=GA1.2.883934398.1564478043; _gid=GA1.2.1214022997.1564478043; _gat_gtag_UA_35324627_3=1; _bl_uid=54jbIy6Ip3bl7ju9I066qv9b9spy; isLogin=1; ftID=4208DFAC24BCFAF7374.791980223; first_ref=https%3A%2F%2Fwww.okex.me%2Faccount%2Flogin%3Fforward%3Dhttps%253A%252F%252Fwww.okex.me%252Factivity%252Fjumpstart%252Fproject%253Fid%253D235; Hm_lpvt_01a61555119115f9226e2c15e411694e=1564478062',
+    },
+     
+    ],
+    challenges: ['8cdd1e33a93711e21b43230167305e65',],
+    
+
+}

+ 126 - 0
date.format.js

@@ -0,0 +1,126 @@
+/*
+ * Date Format 1.2.3
+ * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
+ * MIT license
+ *
+ * Includes enhancements by Scott Trenda <scott.trenda.net>
+ * and Kris Kowal <cixar.com/~kris.kowal/>
+ *
+ * Accepts a date, a mask, or a date and a mask.
+ * Returns a formatted version of the given date.
+ * The date defaults to the current date/time.
+ * The mask defaults to dateFormat.masks.default.
+ */
+
+var dateFormat = function () {
+	var	token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
+		timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
+		timezoneClip = /[^-+\dA-Z]/g,
+		pad = function (val, len) {
+			val = String(val);
+			len = len || 2;
+			while (val.length < len) val = "0" + val;
+			return val;
+		};
+
+	// Regexes and supporting functions are cached through closure
+	return function (date, mask, utc) {
+		var dF = dateFormat;
+
+		// You can't provide utc if you skip other args (use the "UTC:" mask prefix)
+		if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
+			mask = date;
+			date = undefined;
+		}
+
+		// Passing date through Date applies Date.parse, if necessary
+		date = date ? new Date(date) : new Date;
+		if (isNaN(date)) throw SyntaxError("invalid date");
+
+		mask = String(dF.masks[mask] || mask || dF.masks["default"]);
+
+		// Allow setting the utc argument via the mask
+		if (mask.slice(0, 4) == "UTC:") {
+			mask = mask.slice(4);
+			utc = true;
+		}
+
+		var	_ = utc ? "getUTC" : "get",
+			d = date[_ + "Date"](),
+			D = date[_ + "Day"](),
+			m = date[_ + "Month"](),
+			y = date[_ + "FullYear"](),
+			H = date[_ + "Hours"](),
+			M = date[_ + "Minutes"](),
+			s = date[_ + "Seconds"](),
+			L = date[_ + "Milliseconds"](),
+			o = utc ? 0 : date.getTimezoneOffset(),
+			flags = {
+				d:    d,
+				dd:   pad(d),
+				ddd:  dF.i18n.dayNames[D],
+				dddd: dF.i18n.dayNames[D + 7],
+				m:    m + 1,
+				mm:   pad(m + 1),
+				mmm:  dF.i18n.monthNames[m],
+				mmmm: dF.i18n.monthNames[m + 12],
+				yy:   String(y).slice(2),
+				yyyy: y,
+				h:    H % 12 || 12,
+				hh:   pad(H % 12 || 12),
+				H:    H,
+				HH:   pad(H),
+				M:    M,
+				MM:   pad(M),
+				s:    s,
+				ss:   pad(s),
+				l:    pad(L, 3),
+				L:    pad(L > 99 ? Math.round(L / 10) : L),
+				t:    H < 12 ? "a"  : "p",
+				tt:   H < 12 ? "am" : "pm",
+				T:    H < 12 ? "A"  : "P",
+				TT:   H < 12 ? "AM" : "PM",
+				Z:    utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
+				o:    (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
+				S:    ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
+			};
+
+		return mask.replace(token, function ($0) {
+			return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
+		});
+	};
+}();
+
+// Some common format strings
+dateFormat.masks = {
+	"default":      "ddd mmm dd yyyy HH:MM:ss",
+	shortDate:      "m/d/yy",
+	mediumDate:     "mmm d, yyyy",
+	longDate:       "mmmm d, yyyy",
+	fullDate:       "dddd, mmmm d, yyyy",
+	shortTime:      "h:MM TT",
+	mediumTime:     "h:MM:ss TT",
+	longTime:       "h:MM:ss TT Z",
+	isoDate:        "yyyy-mm-dd",
+	isoTime:        "HH:MM:ss",
+	isoDateTime:    "yyyy-mm-dd'T'HH:MM:ss",
+	isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
+};
+
+// Internationalization strings
+dateFormat.i18n = {
+	dayNames: [
+		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+		"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+	],
+	monthNames: [
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+		"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
+	]
+};
+
+// For convenience...
+Date.prototype.format = function (mask, utc) {
+	return dateFormat(this, mask, utc);
+};
+

+ 7 - 0
getChallenge.js

@@ -0,0 +1,7 @@
+const fs = require('fs');
+
+let str = fs.readFileSync('challenges.txt').toString();
+
+console.log(str);
+
+console.log(str.match(/(?<=challenge":").*?(?=",)/g));

+ 236 - 0
index.js

@@ -0,0 +1,236 @@
+var request_fiddler = {
+    url: "https://www.mxc.io/api/member/order",
+    headers: {
+        Host: "www.mxc.io",
+        Connection: "keep-alive",
+        "Content-Length": "54",
+        "x-mxc-nonce": "1581605390444",
+        "x-mxc-sign": "3afff0f76ba2974576d3d54f6cad4ac6",
+        Origin: "https://www.mxc.io",
+        language: "zh-CN",
+        "User-Agent":
+            "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36",
+        "Content-Type": "application/x-www-form-urlencoded",
+        Accept: "*/*",
+        "Sec-Fetch-Site": "same-origin",
+        "Sec-Fetch-Mode": "cors",
+        Referer: "https://www.mxc.io/trade/easy",
+        "Accept-Encoding": "gzip, deflate, br",
+        "Accept-Language": "zh-CN,zh;q=0.9",
+        Cookie:
+            "aliyungf_tc=AQAAALLEnBsWvAYABfWyJ96sVR6QwB17; Hm_lvt_bfc2c0a173378480991465c3626cc9b9=1581592076,1581586327; __guid=80454929.3940374504297067500.1581592047298.8274; _ga=GA1.2.1331008568.1581592060; 1d3385c1-4b59-4849-894d-fe519261429e=webim-visitor-X27GKYETXE4XVTP9VJEG; _gid=GA1.2.1232965346.1581776323; monitor_count=2; Hm_lpvt_bfc2c0a173378480991465c3626cc9b9=1581776324; u_id=WEBc358c9d9316ab0b0a0aeb3a60bfdf2d1e60a4857dc42e49644b36f51f5228e43; account=x********%40163.com"
+    },
+    body: "price=2000&quantity=0.01&symbol=VI_USDT&tradeType=SELL"
+};
+
+var startTime = "2020-2-15 22:50:30"; // 开始时间
+
+var stopTime = "2020-2-15 22:50:35"; // 结束时间
+
+var delaytime = 20; //间隔时间毫秒
+
+request_fiddler["time"] = "true";
+request_fiddler["rejectUnauthorized"] = "false";
+request_fiddler["method"] = "POST";
+
+var inputArr = [];
+var order_type;
+var instrument_id;
+var side;
+var match_price;
+var price;
+var size;
+var currentAccountNum;
+var xunhuancishu;
+var xunhuanjiange;
+var myVar;
+
+var xuhao = 0;
+
+function xiadan() {
+    request(request_fiddler, (error, response, body) => {
+        xuhao++;
+        if (!error && response.statusCode == 200) {
+            if (response.headers["content-encoding"] == "gzip") {
+                console.log(xuhao + "有响应,但响应已压缩");
+            } else {
+                console.log(xuhao + response.body);
+            }
+        }
+    });
+}
+
+const request = require("request");
+const rp = require("request-promise");
+const log4js = require("log4js");
+const fs = require("fs");
+const config = require("./config");
+const WebSocket = require("ws");
+const isPortReachable = require("is-port-reachable");
+
+fs.writeFileSync("autoTrade.log", "");
+
+const logger = log4js.getLogger();
+log4js.configure({
+    appenders: {
+        out: { type: "stdout" },
+        file: { type: "file", filename: "autoTrade.log" }
+    },
+    categories: {
+        default: { appenders: ["out", "file"], level: "debug" }
+    }
+});
+
+let index;
+try {
+    index = parseInt(process.argv.slice(2));
+    if (!(index >= 0)) {
+        throw "";
+    }
+    logger.info(`${index}号服务器开始运行`);
+} catch (e) {
+    logger.error("参数错误,缺少序号");
+    return;
+}
+
+let accounts = divideArray(config.accounts, config.servers.length)[index];
+//logger.info('账号', accounts);
+
+let challenges = divideArray(config.challenges, config.servers.length)[index];
+//logger.info('challenges', challenges);
+
+let purchaseAccount =
+    config.purchaseAccounts[index % config.purchaseAccounts.length];
+
+let wsClients = [];
+let ws;
+async function initWs() {
+    if (index == 0) {
+        const wss = new WebSocket.Server({
+            port: 8080
+        });
+        wss.on("connection", function connection(ws) {
+            logger.info("websocket client已连接");
+            ws.on("message", function incoming(message) {
+                logger.info("received message:", message);
+                if (message.startsWith("secretStr:")) {
+                    wsSend(message);
+                    if (interval) {
+                        clearInterval(interval);
+                    }
+                    let secretStr = message.replace("secretStr:", "");
+                    cancel();
+                    purchase(secretStr);
+                }
+            });
+            wsClients.push(ws);
+        });
+        process.on("exit", function() {
+            try {
+                wss.close();
+            } catch (e) {}
+        });
+    } else {
+        await new Promise((resolve, reject) => {
+            let ii = setInterval(async () => {
+                logger.info("等待", config.servers[0]);
+                let reachable = await isPortReachable(8080, {
+                    host: config.servers[0]
+                });
+                if (reachable) {
+                    clearInterval(ii);
+                    resolve();
+                }
+            }, 500);
+        });
+        ws = new WebSocket(`ws://${config.servers[0]}:8080`);
+
+        ws.on("open", function open() {
+            console.log("websocket已连接");
+        });
+
+        ws.on("message", function incoming(message) {
+            logger.info("received message:", message);
+            if (message.startsWith("secretStr:")) {
+                let secretStr = message.replace("secretStr:", "");
+                logger.info("收到secretStr", secretStr);
+                if (interval) {
+                    clearInterval(interval);
+                }
+                cancel();
+                purchase(secretStr);
+            }
+        });
+    }
+}
+
+function wsSend(msg) {
+    if (index == 0) {
+        wsClients.forEach(client => {
+            client.send(msg);
+        });
+    } else {
+        ws.send(msg);
+    }
+}
+
+let reqs = [];
+let count = 0;
+let interval;
+
+function cancel() {
+    for (let req of reqs) {
+        req.abort();
+    }
+}
+
+async function start() {
+    //await initWs();
+
+    var timmer = setInterval(() => {
+        xiadan();
+        clearTimeout(check.timer);
+        // 计算还剩多少时间开始
+        let theDate = new Date(stopTime).getTime();
+        let now = new Date().getTime();
+        let deta = Math.floor((theDate - now) / 1000);
+        //console.log( `距离结束还剩${deta}秒` )
+
+        if (deta <= 0) {
+            clearInterval(timmer);
+            return;
+        }
+    }, delaytime);
+}
+
+var df = require("./date.format");
+
+var check = () => {
+    // 先清除timer
+    clearTimeout(check.timer);
+
+    // 计算还剩多少时间开始
+    let theDate = new Date(startTime).getTime();
+    let now = new Date().getTime();
+    let deta = Math.floor((theDate - now) / 1000);
+    console.log(`距离发送还剩${deta}秒`);
+
+    if (deta <= 0) {
+        start();
+        return;
+    }
+
+    check.timer = setTimeout(() => {
+        check();
+    }, 200);
+};
+
+check();
+
+function divideArray(arr, size) {
+    let newArr = Array.from({ length: size }, () => []);
+    for (let i = 0; i < arr.length; i++) {
+        newArr[i % size].push(arr[i]);
+    }
+    return newArr;
+}

+ 27 - 0
manage.js

@@ -0,0 +1,27 @@
+const config = require('./config');
+const child_process = require('child_process');
+var os = require('os');
+
+config.servers.forEach((host, index) => {
+    var cmd;
+    if (os.platform() == 'darwin') {
+        var cmd = [
+            'osascript -e \'tell application "Terminal" to activate\' ',
+            '-e \'tell application "System Events" to tell process "Terminal" to keystroke "t"',
+            "using command down' ",
+            '-e \'tell application "Terminal" to do script',
+            '"',
+            `cd ${__dirname} && node server.js ${host} ${index}`,
+            '"',
+            "in selected tab of the front window'",
+        ].join('');
+    } else {
+        cmd = `start cmd.exe /K "cd /d ${__dirname} && node server.js ${host} ${index}"`;
+    }
+
+    var child = child_process.exec(cmd);
+
+    child.on('exit', function(code) {
+        console.log('child exit');
+    });
+});

+ 461 - 0
package-lock.json

@@ -0,0 +1,461 @@
+{
+  "name": "auto-trade",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "aggregate-error": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
+      "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==",
+      "requires": {
+        "clean-stack": "^2.0.0",
+        "indent-string": "^4.0.0"
+      }
+    },
+    "ajv": {
+      "version": "6.11.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz",
+      "integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==",
+      "requires": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      }
+    },
+    "asn1": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+      "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+      "requires": {
+        "safer-buffer": "~2.1.0"
+      }
+    },
+    "assert-plus": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+      "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+    },
+    "asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+    },
+    "aws-sign2": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+      "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+    },
+    "aws4": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
+      "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug=="
+    },
+    "bcrypt-pbkdf": {
+      "version": "1.0.2",
+      "resolved": "http://registry.npm.taobao.org/bcrypt-pbkdf/download/bcrypt-pbkdf-1.0.2.tgz",
+      "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+      "requires": {
+        "tweetnacl": "^0.14.3"
+      }
+    },
+    "bluebird": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+      "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
+    },
+    "caseless": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+      "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+    },
+    "clean-stack": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+      "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="
+    },
+    "combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "requires": {
+        "delayed-stream": "~1.0.0"
+      }
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+    },
+    "dashdash": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+      "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+      "requires": {
+        "assert-plus": "^1.0.0"
+      }
+    },
+    "delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+    },
+    "ecc-jsbn": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+      "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+      "requires": {
+        "jsbn": "~0.1.0",
+        "safer-buffer": "^2.1.0"
+      }
+    },
+    "extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+    },
+    "extsprintf": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+    },
+    "fast-deep-equal": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
+      "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
+    },
+    "fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
+    },
+    "forever-agent": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+    },
+    "form-data": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+      "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+      "requires": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.6",
+        "mime-types": "^2.1.12"
+      }
+    },
+    "getpass": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+      "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+      "requires": {
+        "assert-plus": "^1.0.0"
+      }
+    },
+    "har-schema": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+      "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+    },
+    "har-validator": {
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+      "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+      "requires": {
+        "ajv": "^6.5.5",
+        "har-schema": "^2.0.0"
+      }
+    },
+    "http-signature": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+      "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+      "requires": {
+        "assert-plus": "^1.0.0",
+        "jsprim": "^1.2.2",
+        "sshpk": "^1.7.0"
+      }
+    },
+    "indent-string": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+      "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="
+    },
+    "is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+    },
+    "isstream": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+    },
+    "jsbn": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
+    },
+    "json-schema": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+      "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
+    },
+    "json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+    },
+    "json-stringify-safe": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+    },
+    "jsprim": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+      "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+      "requires": {
+        "assert-plus": "1.0.0",
+        "extsprintf": "1.3.0",
+        "json-schema": "0.2.3",
+        "verror": "1.10.0"
+      }
+    },
+    "lodash": {
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
+    },
+    "mime-db": {
+      "version": "1.43.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
+      "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ=="
+    },
+    "mime-types": {
+      "version": "2.1.26",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
+      "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
+      "requires": {
+        "mime-db": "1.43.0"
+      }
+    },
+    "node-ssh": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/node-ssh/-/node-ssh-7.0.0.tgz",
+      "integrity": "sha512-LwdGalFACK+DCVI1+wkehR/a8uIkmAn0npW43f8U6XhH20112a/WAXv3oQay7IK2YHY1J6r5JT2MEHhjyQxKIA==",
+      "requires": {
+        "p-map": "^3.0.0",
+        "sb-promisify": "^2.0.1",
+        "sb-scandir": "^2.0.0",
+        "shell-escape": "^0.2.0",
+        "ssh2": "^0.8.7"
+      }
+    },
+    "oauth-sign": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+      "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+    },
+    "p-map": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
+      "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
+      "requires": {
+        "aggregate-error": "^3.0.0"
+      }
+    },
+    "performance-now": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+    },
+    "psl": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",
+      "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ=="
+    },
+    "punycode": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+    },
+    "qs": {
+      "version": "6.5.2",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+      "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+    },
+    "request": {
+      "version": "2.88.2",
+      "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+      "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+      "requires": {
+        "aws-sign2": "~0.7.0",
+        "aws4": "^1.8.0",
+        "caseless": "~0.12.0",
+        "combined-stream": "~1.0.6",
+        "extend": "~3.0.2",
+        "forever-agent": "~0.6.1",
+        "form-data": "~2.3.2",
+        "har-validator": "~5.1.3",
+        "http-signature": "~1.2.0",
+        "is-typedarray": "~1.0.0",
+        "isstream": "~0.1.2",
+        "json-stringify-safe": "~5.0.1",
+        "mime-types": "~2.1.19",
+        "oauth-sign": "~0.9.0",
+        "performance-now": "^2.1.0",
+        "qs": "~6.5.2",
+        "safe-buffer": "^5.1.2",
+        "tough-cookie": "~2.5.0",
+        "tunnel-agent": "^0.6.0",
+        "uuid": "^3.3.2"
+      }
+    },
+    "request-promise": {
+      "version": "4.2.5",
+      "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.5.tgz",
+      "integrity": "sha512-ZgnepCykFdmpq86fKGwqntyTiUrHycALuGggpyCZwMvGaZWgxW6yagT0FHkgo5LzYvOaCNvxYwWYIjevSH1EDg==",
+      "requires": {
+        "bluebird": "^3.5.0",
+        "request-promise-core": "1.1.3",
+        "stealthy-require": "^1.1.1",
+        "tough-cookie": "^2.3.3"
+      }
+    },
+    "request-promise-core": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz",
+      "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==",
+      "requires": {
+        "lodash": "^4.17.15"
+      }
+    },
+    "safe-buffer": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
+      "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+    },
+    "sb-promisify": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npm.taobao.org/sb-promisify/download/sb-promisify-2.0.2.tgz",
+      "integrity": "sha1-QnelR1RIiqlnXYhuNU24lMm9yYE="
+    },
+    "sb-scandir": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/sb-scandir/-/sb-scandir-2.0.0.tgz",
+      "integrity": "sha512-SKbyMJB0DUt9OgN4tP2RBcn9OsR26DEpe+nwaDkQTNcrJSJI0FlLhXhBpTd/YEnlQ2GdLrbszSNekGLw4rweOQ==",
+      "requires": {
+        "p-map": "^1.2.0",
+        "sb-promisify": "^2.0.1"
+      },
+      "dependencies": {
+        "p-map": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz",
+          "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA=="
+        }
+      }
+    },
+    "shell-escape": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npm.taobao.org/shell-escape/download/shell-escape-0.2.0.tgz",
+      "integrity": "sha1-aP0CXrBJC09WegJ/C/IkgLX4QTM="
+    },
+    "ssh2": {
+      "version": "0.8.7",
+      "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-0.8.7.tgz",
+      "integrity": "sha512-/u1BO12kb0lDVxJXejWB9pxyF3/ncgRqI9vPCZuPzo05pdNDzqUeQRavScwSPsfMGK+5H/VRqp1IierIx0Bcxw==",
+      "requires": {
+        "ssh2-streams": "~0.4.8"
+      }
+    },
+    "ssh2-streams": {
+      "version": "0.4.8",
+      "resolved": "https://registry.npmjs.org/ssh2-streams/-/ssh2-streams-0.4.8.tgz",
+      "integrity": "sha512-auxXfgYySz2vYw7TMU7PK7vFI7EPvhvTH8/tZPgGaWocK4p/vwCMiV3icz9AEkb0R40kOKZtFtqYIxDJyJiytw==",
+      "requires": {
+        "asn1": "~0.2.0",
+        "bcrypt-pbkdf": "^1.0.2",
+        "streamsearch": "~0.1.2"
+      }
+    },
+    "sshpk": {
+      "version": "1.16.1",
+      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+      "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+      "requires": {
+        "asn1": "~0.2.3",
+        "assert-plus": "^1.0.0",
+        "bcrypt-pbkdf": "^1.0.0",
+        "dashdash": "^1.12.0",
+        "ecc-jsbn": "~0.1.1",
+        "getpass": "^0.1.1",
+        "jsbn": "~0.1.0",
+        "safer-buffer": "^2.0.2",
+        "tweetnacl": "~0.14.0"
+      }
+    },
+    "stealthy-require": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
+      "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
+    },
+    "streamsearch": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npm.taobao.org/streamsearch/download/streamsearch-0.1.2.tgz",
+      "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
+    },
+    "tough-cookie": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+      "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+      "requires": {
+        "psl": "^1.1.28",
+        "punycode": "^2.1.1"
+      }
+    },
+    "tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+      "requires": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "tweetnacl": {
+      "version": "0.14.5",
+      "resolved": "http://registry.npm.taobao.org/tweetnacl/download/tweetnacl-0.14.5.tgz",
+      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+    },
+    "uri-js": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+      "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+      "requires": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "uuid": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+      "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
+    },
+    "verror": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+      "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+      "requires": {
+        "assert-plus": "^1.0.0",
+        "core-util-is": "1.0.2",
+        "extsprintf": "^1.2.0"
+      }
+    }
+  }
+}

+ 18 - 0
package.json

@@ -0,0 +1,18 @@
+{
+  "name": "auto-trade",
+  "version": "1.0.0",
+  "description": "修改配置文件config.js 下载安装nodejs http://nodejs.cn/download/ 打开widnow+R 输入cmd 依次输入以下命令 cd /K 项目文件夹 npm config set registry https://registry.npm.taobao.org npm install node manage.js",
+  "main": "index.js",
+  "dependencies": {
+    "node-ssh": "^7.0.0",
+    "request": "^2.88.2",
+    "request-promise": "^4.2.5"
+  },
+  "devDependencies": {},
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1",
+    "start": "node server.js"
+  },
+  "author": "",
+  "license": "ISC"
+}

+ 95 - 0
server.js

@@ -0,0 +1,95 @@
+const node_ssh = require("node-ssh");
+const config = require("./config");
+const path = require("path");
+const fs = require("fs");
+
+console.log(process.argv.join(" "));
+let host = process.argv[2];
+let index = process.argv[3];
+
+console.log(index + "号机 " + host);
+
+ssh = new node_ssh();
+ssh.connect({
+    host: host,
+    username: "root",
+    port: 22,
+    password: config.password
+})
+    .then(async function() {
+        let option = {
+            cwd: "/root",
+            onStdout(chunk) {
+                console.log(chunk.toString("utf8"));
+            },
+            onStderr(chunk) {
+                console.log(chunk.toString("utf8"));
+            }
+        };
+        const failed = [];
+        const successful = [];
+        let status = await ssh.putDirectory(__dirname, "/root/autoTrade", {
+            recursive: true,
+            concurrency: 30,
+            validate: function(itemPath) {
+                const baseName = path.basename(itemPath);
+                return (
+                    baseName.substr(0, 1) !== "." && baseName !== "node_modules" // do not allow dot files
+                ); // do not allow node_modules
+            },
+            tick: function(localPath, remotePath, error) {
+                if (error) {
+                    failed.push(localPath);
+                } else {
+                    successful.push(localPath);
+                }
+            }
+        });
+        console.log(
+            "the directory transfer was",
+            status ? "successful" : "unsuccessful"
+        );
+        console.log("failed transfers", failed.join("\n"));
+        console.log("successful transfers", successful.join("\n"));
+
+        let nodeInstalled = false;
+        try {
+            await ssh
+                .exec("node", ["-v"], {
+                    cwd: "/root",
+                    onStdout(chunk) {
+                        console.log(chunk.toString("utf8"));
+                    },
+                    onStderr(chunk) {
+                        console.log(chunk.toString("utf8"));
+                    }
+                })
+                .catch(e => {
+                    console.log(e);
+                });
+        } catch (e) {
+            console.log("安装node");
+            await ssh.execCommand(
+                "curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -",
+                option
+            );
+            await ssh.execCommand("sudo apt-get install -y nodejs", option);
+            console.log("node安装完成");
+        }
+        await ssh.execCommand("npm install", {
+            ...option,
+            cwd: "/root/autoTrade"
+        });
+        await ssh.execCommand("ls -la", { ...option, cwd: "/root/autoTrade" });
+        await ssh.execCommand("killall node", {
+            ...option,
+            cwd: "/root/autoTrade"
+        });
+        await ssh.execCommand(`node index.js ${index}`, {
+            ...option,
+            cwd: "/root/autoTrade"
+        });
+    })
+    .catch(e => {
+        console.log(e);
+    });