From 3294231002381b76f3041a185861b03f2ceca21b Mon Sep 17 00:00:00 2001 From: louisyoungx <1462648167@qq.com> Date: Sat, 13 Nov 2021 13:57:37 +0800 Subject: [PATCH] feat(web-ui): append web ui --- Config/config.ini | 16 +-- Core/core.py | 3 +- Core/login.py | 10 +- Core/spider.py | 38 ++--- Core/timer.py | 26 ++-- Core/util.py | 6 +- Message/message.py | 6 +- Server/api.py | 68 ++++++--- Server/app.py | 42 ++++++ Server/handler.py | 25 +++- Server/url.py | 5 +- Static/404.html | 267 ++++++++++++++++++++++++++++++++++++ Static/css/index.css | 36 ++++- Static/img/qr_code.png | Bin 0 -> 776 bytes Static/index.html | 250 +++++++++++++-------------------- Static/js/element_index.js | 10 +- Static/js/index.js | 200 +++++++++++++++++++++++++++ Static/js/vue.js | 4 + cookies/Louis_Young.cookies | Bin 0 -> 2629 bytes 19 files changed, 781 insertions(+), 231 deletions(-) create mode 100644 Server/app.py mode change 100755 => 100644 Server/handler.py create mode 100644 Static/404.html create mode 100644 Static/img/qr_code.png create mode 100644 Static/js/index.js create mode 100644 cookies/Louis_Young.cookies diff --git a/Config/config.ini b/Config/config.ini index 71edffa..b64a3b2 100755 --- a/Config/config.ini +++ b/Config/config.ini @@ -3,21 +3,21 @@ eid = "2PBCMB2WINZUQI6XRDCSKOZXTCHEOHLDABNAVSAEYTS6DBH2DWOACQPUEKXGHV7ZYTKCRDXZX34SPL2XI3KQYVNVSM" fp = "63a2c6fceb97a082753cdf00710f4f46" # area到area_id目录下人工查找,例如:江西省南昌市昌北区蛟桥镇的area是21_1827_4101_40925 -area = 21_1827_4101_40925 +area = "21_1827_4101_40925" # 商品id -sku_id = 10027576824361 +sku_id = "10027576824361" # 购买数量 amount = 1 # 设定时间 # 2020-12-09 10:00:00.100000(修改成每天的几点几分几秒几毫秒) -buy_time = 2021-11-13 04:30:00.000 +buy_time = "2021-11-13 04:30:00.000" # 提交订单失败重试次数 retry = 100 # 查询库存请求超时(秒),可选配置,默认10秒 timeout = 10 # 默认UA DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" -# 是否使用随机 useragent,默认为 false -random_useragent = false +# 是否使用随机 useragent,默认为 False +random_useragent = False # 多进程数量 work_count = 1 @@ -33,8 +33,8 @@ payment_pwd = "" # 使用了Server酱的推送服务 # 如果想开启下单成功后消息推送,则将 enable 设置为 true,默认为 false 不开启推送 # 开启消息推送必须填入 sckey,如何获取请参考 http://sc.ftqq.com/3.version。感谢Server酱~ -enable = false -sckey = ??????? +enable = False +sckey = "?????" @@ -86,7 +86,7 @@ SERVER_VERSION = "0.4.8" START_USING = True SERVER_HOST = "www.server.com" LOCAL_HOST = "0.0.0.0" -PORT = 12020 +PORT = 12021 PROCESS_MODEL = False PROCESS_COUNT = 4 diff --git a/Core/core.py b/Core/core.py index 0172f00..336e825 100755 --- a/Core/core.py +++ b/Core/core.py @@ -1,3 +1,2 @@ def main(): - # 此处填写业务 - print("===== 此处业务处理 =====") + pass diff --git a/Core/login.py b/Core/login.py index 0baf915..26cf773 100644 --- a/Core/login.py +++ b/Core/login.py @@ -5,10 +5,10 @@ import functools import json import os import pickle -from logger import logger -from config import global_config -from exception import SKException -from util import ( +from Logger.logger import logger +from Config.settings import config +from Core.exception import SKException +from Core.util import ( parse_json, wait_some_time, response_status, @@ -21,7 +21,7 @@ class SpiderSession: """ def __init__(self): self.cookies_dir_path = "./cookies/" - self.user_agent = global_config.getRaw('config', 'DEFAULT_USER_AGENT') + self.user_agent = config.settings('Spider', 'DEFAULT_USER_AGENT') self.session = self._init_session() diff --git a/Core/spider.py b/Core/spider.py index 550f5e7..8a854e2 100644 --- a/Core/spider.py +++ b/Core/spider.py @@ -7,30 +7,31 @@ import json import random import sys from concurrent.futures import ProcessPoolExecutor -from exception import SKException +from Core.exception import SKException from bs4 import BeautifulSoup from Config.settings import config from Logger.logger import logger -from login import SpiderSession, QrLogin +from Core.login import SpiderSession, QrLogin from Message.message import sendMessage -from timer import Timer -from util import parse_json +from Core.timer import Timer +from Core.util import parse_json class Waiter(): def __init__(self, - skuids=config.global_config.getRaw("Spider", "sku_id"), - area=config.global_config.getRaw("Spider", "area"), - eid=config.global_config.getRaw("Spider", "eid"), - fp=config.global_config.getRaw("Spider", "fp"), - count=config.global_config.getRaw("Spider", "amount"), - payment_pwd=config.global_config.getRaw( + skuids=config.settings("Spider", "sku_id"), + area=config.settings("Spider", "area"), + eid=config.settings("Spider", "eid"), + fp=config.settings("Spider", "fp"), + count=config.settings("Spider", "amount"), + payment_pwd=config.settings( "Account", "payment_pwd"), - retry=eval(config.global_config.getRaw("Spider", "retry")), - work_count=eval(config.global_config.getRaw( - 'Spider', 'work_count')), - timeout=float(config.global_config.getRaw( - "Spider", "timeout")) + retry=config.settings("Spider", "retry"), + work_count=config.settings( + 'Spider', 'work_count'), + timeout=float(config.raw( + "Spider", "timeout")), + date=config.settings('Spider', 'buy_time').__str__() ): self.skuids = skuids @@ -42,6 +43,7 @@ class Waiter(): self.retry = retry self.work_count = work_count self.timeout = timeout + self.buyTime = date self.spider_session = SpiderSession() self.spider_session.load_cookies_from_local() @@ -51,7 +53,7 @@ class Waiter(): self.item_cat = {} self.item_vender_ids = {} # 记录商家id self.headers = {'User-Agent': self.user_agent} - self.timers = Timer() + self.timers = Timer(self.buyTime) def login_by_qrcode(self): """ @@ -82,9 +84,11 @@ class Waiter(): return func(self, *args, **kwargs) return new_func + @ check_login def waitForSell(self): self._waitForSell() - + + @ check_login def waitTimeForSell(self): self._waitTimeForSell() diff --git a/Core/timer.py b/Core/timer.py index 1a08cf4..627fb58 100644 --- a/Core/timer.py +++ b/Core/timer.py @@ -9,10 +9,10 @@ from Config.settings import config class Timer(object): - def __init__(self, sleep_interval=0.5): + def __init__(self, buyTime, sleep_interval=0.5): # '2018-09-28 22:45:50.000' # buy_time = 2020-12-22 09:59:59.500 - buy_time_everyday = config.global_config.getRaw('config', 'buy_time').__str__() + buy_time_everyday = buyTime localtime = time.localtime(time.time()) #self.buy_time = datetime.strptime( # localtime.tm_year.__str__() + '-' + localtime.tm_mon.__str__() + '-' + localtime.tm_mday.__str__() @@ -52,15 +52,13 @@ class Timer(object): def start(self): logger.info('正在等待到达设定时间:{}'.format(self.buy_time)) logger.info('正检测本地时间与京东服务器时间误差为【{}】毫秒'.format(self.diff_time)) - mode = config.global_config.getMode() - if mode != '3': - while True: - # 本地时间减去与京东的时间差,能够将时间误差提升到0.1秒附近 - # 具体精度依赖获取京东服务器时间的网络时间损耗 - if self.local_time() - self.diff_time >= self.buy_time_ms: - logger.info('时间到达,开始执行……') - break - else: - time.sleep(self.sleep_interval) - else: - pass + + while True: + # 本地时间减去与京东的时间差,能够将时间误差提升到0.1秒附近 + # 具体精度依赖获取京东服务器时间的网络时间损耗 + if self.local_time() - self.diff_time >= self.buy_time_ms: + logger.info('时间到达,开始执行……') + break + else: + time.sleep(self.sleep_interval) + diff --git a/Core/util.py b/Core/util.py index 8a25526..cfb434e 100644 --- a/Core/util.py +++ b/Core/util.py @@ -79,13 +79,13 @@ def wait_some_time(): def send_wechat(message): """推送信息到微信""" - url = 'http://sc.ftqq.com/{}.send'.format(config.global_config.getRaw('messenger', 'sckey')) + url = 'http://sc.ftqq.com/{}.send'.format(config.settings('messenger', 'sckey')) payload = { "text":'抢购结果', "desp": message } headers = { - 'User-Agent':config.global_config.getRaw('config', 'DEFAULT_USER_AGENT') + 'User-Agent':config.settings('config', 'DEFAULT_USER_AGENT') } requests.get(url, params=payload, headers=headers) @@ -111,6 +111,6 @@ def open_image(image_file): def save_image(resp, image_file): - with open(image_file, 'wb') as f: + with open(config.path() + '/Static/img/' + image_file, 'wb') as f: for chunk in resp.iter_content(chunk_size=1024): f.write(chunk) diff --git a/Message/message.py b/Message/message.py index 1579f4d..ac131ef 100644 --- a/Message/message.py +++ b/Message/message.py @@ -5,8 +5,8 @@ import json import requests -from logger import logger -from config import global_config +from Logger.logger import logger +from Config.settings import config class Messenger(object): @@ -41,7 +41,7 @@ class Messenger(object): logger.error('Fail to send message [text: %s, desp: %s]: %s', text, desp, e) -sckey = global_config.getRaw("messenger", "sckey") +sckey = config.settings("Message", "sckey") message = Messenger(sckey) diff --git a/Server/api.py b/Server/api.py index cabeddb..051dff5 100644 --- a/Server/api.py +++ b/Server/api.py @@ -1,28 +1,25 @@ import copy -import psutil - from Config.settings import config +from Core.spider import Waiter +from threading import Thread +class Global(object): + + def __init__(self): + self.waiter = None + self.login = None + self.thread= None + + def update(self): + self.login = self.waiter.qrlogin.is_login + +glo = Global() def log(request): - file_path = config.path() + config.settings("Logger", "FILE_PATH") + config.settings("Logger", "FILE_NAME") + file_path = config.path() + config.settings("Logger", "FILE_PATH") + \ + config.settings("Logger", "FILE_NAME") file_page_file = open(file_path, 'r') return str(file_page_file.read()) -def systemInfo(request): - info = {} - info['cpu_count'] = psutil.cpu_count() # CPU逻辑数量 - info['cpu_percent'] = psutil.cpu_percent(interval=1) # CPU使用率 - info['cpu_times'] = psutil.cpu_times() # CPU的用户/系统/空闲时间 - info['virtual_memory'] = psutil.virtual_memory() # 物理内存 - info['swap_memory'] = psutil.swap_memory() # 交换内存 - info['disk_partitions'] = psutil.disk_partitions() # 磁盘分区信息 - info['disk_partitions'] = psutil.disk_usage('/') # 磁盘使用情况 - info['disk_partitions'] = psutil.disk_io_counters() # 磁盘IO - info['disk_partitions'] = psutil.net_io_counters() # 获取网络读写字节/包的个数 - info['disk_partitions'] = psutil.net_if_addrs() # 获取网络接口信息 - info['disk_partitions'] = psutil.net_if_stats() # 获取网络接口状态 - # need sudo: info['disk_partitions'] = psutil.net_connections() # 获取当前网络连接信息 - return info def serverConfig(request): appConfig = copy.deepcopy(config._config._sections) @@ -32,3 +29,38 @@ def serverConfig(request): value = appConfig[model][item] # DEBUG print(model, item, value, type(value)) return appConfig + + +def jdShopper(request): + mode = request['mode'] + date = request['date'] + skuids = request['skuid'] + area = request['area'] + eid = request['eid'] + fp = request['fp'] + count = request['count'] + retry = request['retry'] + work_count = request['work_count'] + timeout = request['timeout'] + if mode == '1': + glo.waiter = Waiter(skuids=skuids, area=area, eid=eid, fp=fp, count=count, + retry=retry, work_count=work_count, timeout=timeout) + glo.thread = Thread(target=glo.waiter.waitForSell) + glo.thread.start() + elif mode == '2': + date = date.replace("T", " ") + date = date.replace("Z", "") + glo.waiter = Waiter(skuids=skuids, area=area, eid=eid, fp=fp, count=count, + retry=retry, work_count=work_count, timeout=timeout, date=date) + glo.thread = Thread(target=glo.waiter.waitTimeForSell) + glo.thread.start() + glo.update() + print(glo.login) + return glo.login + +def loginStatus(request): + try: + glo.update() + except: + pass + return glo.login diff --git a/Server/app.py b/Server/app.py new file mode 100644 index 0000000..2558257 --- /dev/null +++ b/Server/app.py @@ -0,0 +1,42 @@ +import subprocess +import sys +import os +from flask import request, Flask, make_response, render_template + +HOME = os.path.dirname(os.path.abspath(__file__)) + +app = Flask(__name__, + instance_path=HOME, + instance_relative_config=True, + template_folder="../Static", + static_folder="../Static", + static_url_path='') + +app.config['JSON_AS_ASCII'] = False + +@app.route("/") +def homePage(): + return render_template('index.html') + +@app.route('/api/zpy', methods=['POST', 'OPTIONS']) +def zpy(): + if request.method == 'POST': + code = request.json['code'] + output = subprocess.check_output([sys.executable, '-c', code]) + print(output.decode().encode()) + response = make_response(output.decode()) + response.headers['Access-Control-Allow-Origin'] = '*' + response.headers['Access-Control-Allow-Methods'] = 'GET,POST' + response.headers['Access-Control-Allow-Headers'] = 'x-requested-with,content-type' + return response + else: + # CORS跨域配置 + response = make_response() + response.headers['Access-Control-Allow-Origin'] = '*' + response.headers['Access-Control-Allow-Methods'] = 'GET,POST' + response.headers['Access-Control-Allow-Headers'] = 'x-requested-with,content-type' + return response + + +if __name__ == '__main__': + app.run(debug=False, host='0.0.0.0', port=5000) diff --git a/Server/handler.py b/Server/handler.py old mode 100755 new mode 100644 index 9f9e5bf..d5aaa1e --- a/Server/handler.py +++ b/Server/handler.py @@ -1,5 +1,4 @@ -import os, json -import time +import os, json, urllib, time from Logger.logger import logger from http.server import BaseHTTPRequestHandler @@ -16,6 +15,7 @@ class RequestHandler(BaseHTTPRequestHandler): def do_GET(self): self.rootPath = config.path() + "/Static" url = self.requestline[4:-9] + print(url) request_data = {} # 存放GET请求数据 try: if url.find('?') != -1: @@ -25,15 +25,35 @@ class RequestHandler(BaseHTTPRequestHandler): for i in parameters: key, val = i.split('=', 1) request_data[key] = val + #request_data['body'] = self.rfile.read() except: logger.error("URL Format Error") if (url == "/"): self.home() + elif (url == ""): + self.noFound() elif ("/api" in url): self.api(url[4:], request_data) else: self.file(url) + def do_POST(self): + LOCAL_HOST = config.settings("Server", "LOCAL_HOST") + PORT = config.settings("Server", "PORT") + hostLen = len(f'/{LOCAL_HOST}:{PORT}') + 5 + self.rootPath = config.path() + "/Static" + url = self.requestline[hostLen:-9] + request_data = json.loads(self.rfile.read(int(self.headers['content-length'])).decode()) + if (url == "/"): + self.home() + elif (url == ""): + self.noFound() + elif ("/api" in url): + self.api(url[4:], request_data) + else: + self.file(url) + + def log_message(self, format, *args): SERVER_LOGGER = config.settings("Logger", "SERVER_LOGGER") if SERVER_LOGGER: @@ -103,7 +123,6 @@ class RequestHandler(BaseHTTPRequestHandler): # ---------------------------------------------------------------- # 此处写API content = urls(url, request_data) - # ---------------------------------------------------------------- localtime = time.localtime(time.time()) date = \ diff --git a/Server/url.py b/Server/url.py index a48662f..60c3604 100644 --- a/Server/url.py +++ b/Server/url.py @@ -1,7 +1,8 @@ -from Server.api import log, systemInfo, serverConfig +from Server.api import log, serverConfig, jdShopper, loginStatus def urls(url, request): if (url == "/log"): return log(request) - elif (url == "/system-info"): return systemInfo(request) elif (url == "/config"): return serverConfig(request) + elif (url == "/jd-shopper"): return jdShopper(request) + elif (url == "/jd-login-status"): return loginStatus(request) else: return "No Response" \ No newline at end of file diff --git a/Static/404.html b/Static/404.html new file mode 100644 index 0000000..5626558 --- /dev/null +++ b/Static/404.html @@ -0,0 +1,267 @@ + + + + 404 No Found - Louis Young + + + + + + + + + + + + +
+
+ + + + + + +

404

+

NOT FOUND

+ + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Static/css/index.css b/Static/css/index.css index 725a0aa..815e437 100644 --- a/Static/css/index.css +++ b/Static/css/index.css @@ -1,16 +1,35 @@ -.data_dict, .data_dict_goods{ - display: none; +body { + display: flex; + justify-content: center; + align-self: center; + height: 100vh; + width: 100vw; } #form_container{ - width: 600px; - margin: 0 auto; + width: 95vw; + max-width: 600px; border: 1px solid gainsboro; + height: auto; + display: flex; + flex-direction: column; + justify-content: center; + align-self: center; } h1{ text-align: center; margin: 30px 0; padding-bottom: 20px; } +#log { + resize: none; + height: 50vh; + border: none; + font-size: 16px; + outline: none; + background-color: rgba(245, 245, 245); + white-space: pre-wrap; + padding: 2vh; +} #account_input, #password_input{ width: 300px; } @@ -30,4 +49,13 @@ h1{ } #run_button{ margin-left: 30px; +} +.el-dialog__body { + width: 250px; + height: 250px; +} + +.el-image__inner { + width: 250px; + height: 250px; } \ No newline at end of file diff --git a/Static/img/qr_code.png b/Static/img/qr_code.png new file mode 100644 index 0000000000000000000000000000000000000000..bab60b86afa2dc9696862e267902d41014419a63 GIT binary patch literal 776 zcmV+j1NZ!iP)a`v4PN0p!gj!S9+}@jb=1oVPX6D*hHl5 z?f9r>bZYm8$dZ&w^uE@n6i^5NV3)BwDpSJx#%i zSr2e(%jj5Cx6fCVGv0MRH9sDeu)mL(*@F{#2+fS%7B(ZvS(`#b&$rOF%BQ2%vzVz; zX{ZeXzjazdF42lvBWj~hQ?js2L^Tbc(ita0kvX=fj}AZ<7ta+)NSZG6*6^1)POnK5)iUYQO#+!Z|(19&l z#CvrrWN9XN0G>lbFe_}y%Ngtz!5CpqXRn~H@PSQ%FqE@v@a$cyhgi(uLuL#4g3>AP z4lCfrw5e8OR^&KT;aBCbdY1O$e8J|WiXAmh=W_LV_(t-v;FH+X``Fnaa7#NyX zSk7=qU?<~>>5c-u&(4Y&?w5W(+}*9=+;2Q7>-QS0h+pS>a6N@j%;FZfwR!`iB=!q4 z?{>m>_oPwF8S+S2=7o_;el*G{XQ*Eqswxp@2)dVM60?5?<^h_~6a{nu0000 订单自动提交 - - - + + +

订单自动提交

- - - 自动登录 + + + 有货自动下单 - 手动登录定时下单 - + + + + + + - + + - - - - - - - + + + + + + + + - -
- -
- 继续添加 + 重置选项 开始运行 + + + + + + + + + {{dialog}} + + 取 消 + 确 定 + + +
-
    - -
  • {{is_manual}}
  • -
  • {{account_value}}
  • -
  • {{password_value}}
  • -
  • {{date_value}}
  • -
  • {{time_value}}
  • -
- - - - + + + + + + + + + + + + + + + + + + + + diff --git a/Static/js/element_index.js b/Static/js/element_index.js index aa1d6f2..4b60dfc 100644 --- a/Static/js/element_index.js +++ b/Static/js/element_index.js @@ -1 +1,9 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("vue")):"function"==typeof define&&define.amd?define("ELEMENT",["vue"],t):"object"==typeof exports?exports.ELEMENT=t(require("vue")):e.ELEMENT=t(e.Vue)}("undefined"!=typeof self?self:this,function(e){return function(e){var t={};function i(n){if(t[n])return t[n].exports;var r=t[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,i),r.l=!0,r.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)i.d(n,r,function(t){return e[t]}.bind(null,r));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/dist/",i(i.s=49)}([function(t,i){t.exports=e},function(e,t,i){var n=i(4);e.exports=function(e,t,i){return void 0===i?n(e,t,!1):n(e,i,!1!==t)}},function(e,t,i){var n;!function(r){"use strict";var s={},a=/d{1,4}|M{1,4}|yy(?:yy)?|S{1,3}|Do|ZZ|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g,o="[^\\s]+",l=/\[([^]*?)\]/gm,u=function(){};function c(e,t){for(var i=[],n=0,r=e.length;n3?0:(e-e%10!=10)*e%10]}};var g={D:function(e){return e.getDay()},DD:function(e){return d(e.getDay())},Do:function(e,t){return t.DoFn(e.getDate())},d:function(e){return e.getDate()},dd:function(e){return d(e.getDate())},ddd:function(e,t){return t.dayNamesShort[e.getDay()]},dddd:function(e,t){return t.dayNames[e.getDay()]},M:function(e){return e.getMonth()+1},MM:function(e){return d(e.getMonth()+1)},MMM:function(e,t){return t.monthNamesShort[e.getMonth()]},MMMM:function(e,t){return t.monthNames[e.getMonth()]},yy:function(e){return d(String(e.getFullYear()),4).substr(2)},yyyy:function(e){return d(e.getFullYear(),4)},h:function(e){return e.getHours()%12||12},hh:function(e){return d(e.getHours()%12||12)},H:function(e){return e.getHours()},HH:function(e){return d(e.getHours())},m:function(e){return e.getMinutes()},mm:function(e){return d(e.getMinutes())},s:function(e){return e.getSeconds()},ss:function(e){return d(e.getSeconds())},S:function(e){return Math.round(e.getMilliseconds()/100)},SS:function(e){return d(Math.round(e.getMilliseconds()/10),2)},SSS:function(e){return d(e.getMilliseconds(),3)},a:function(e,t){return e.getHours()<12?t.amPm[0]:t.amPm[1]},A:function(e,t){return e.getHours()<12?t.amPm[0].toUpperCase():t.amPm[1].toUpperCase()},ZZ:function(e){var t=e.getTimezoneOffset();return(t>0?"-":"+")+d(100*Math.floor(Math.abs(t)/60)+Math.abs(t)%60,4)}},b={d:["\\d\\d?",function(e,t){e.day=t}],Do:["\\d\\d?"+o,function(e,t){e.day=parseInt(t,10)}],M:["\\d\\d?",function(e,t){e.month=t-1}],yy:["\\d\\d?",function(e,t){var i=+(""+(new Date).getFullYear()).substr(0,2);e.year=""+(t>68?i-1:i)+t}],h:["\\d\\d?",function(e,t){e.hour=t}],m:["\\d\\d?",function(e,t){e.minute=t}],s:["\\d\\d?",function(e,t){e.second=t}],yyyy:["\\d{4}",function(e,t){e.year=t}],S:["\\d",function(e,t){e.millisecond=100*t}],SS:["\\d{2}",function(e,t){e.millisecond=10*t}],SSS:["\\d{3}",function(e,t){e.millisecond=t}],D:["\\d\\d?",u],ddd:[o,u],MMM:[o,h("monthNamesShort")],MMMM:[o,h("monthNames")],a:[o,function(e,t,i){var n=t.toLowerCase();n===i.amPm[0]?e.isPm=!1:n===i.amPm[1]&&(e.isPm=!0)}],ZZ:["[^\\s]*?[\\+\\-]\\d\\d:?\\d\\d|[^\\s]*?Z",function(e,t){var i,n=(t+"").match(/([+-]|\d\d)/gi);n&&(i=60*n[1]+parseInt(n[2],10),e.timezoneOffset="+"===n[0]?i:-i)}]};b.dd=b.d,b.dddd=b.ddd,b.DD=b.D,b.mm=b.m,b.hh=b.H=b.HH=b.h,b.MM=b.M,b.ss=b.s,b.A=b.a,s.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:"HH:mm",mediumTime:"HH:mm:ss",longTime:"HH:mm:ss.SSS"},s.format=function(e,t,i){var n=i||s.i18n;if("number"==typeof e&&(e=new Date(e)),"[object Date]"!==Object.prototype.toString.call(e)||isNaN(e.getTime()))throw new Error("Invalid Date in fecha.format");t=s.masks[t]||t||s.masks.default;var r=[];return(t=(t=t.replace(l,function(e,t){return r.push(t),"@@@"})).replace(a,function(t){return t in g?g[t](e,n):t.slice(1,t.length-1)})).replace(/@@@/g,function(){return r.shift()})},s.parse=function(e,t,i){var n=i||s.i18n;if("string"!=typeof t)throw new Error("Invalid format in fecha.parse");if(t=s.masks[t]||t,e.length>1e3)return null;var r={},o=[],u=[];t=t.replace(l,function(e,t){return u.push(t),"@@@"});var c,h=(c=t,c.replace(/[|\\{()[^$+*?.-]/g,"\\$&")).replace(a,function(e){if(b[e]){var t=b[e];return o.push(t[1]),"("+t[0]+")"}return e});h=h.replace(/@@@/g,function(){return u.shift()});var d=e.match(new RegExp(h,"i"));if(!d)return null;for(var p=1;pe?u():!0!==t&&(r=setTimeout(n?function(){r=void 0}:u,void 0===n?e-o:e))}}},function(e,t){var i=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=i)},function(e,t){var i=/^(attrs|props|on|nativeOn|class|style|hook)$/;function n(e,t){return function(){e&&e.apply(this,arguments),t&&t.apply(this,arguments)}}e.exports=function(e){return e.reduce(function(e,t){var r,s,a,o,l;for(a in t)if(r=e[a],s=t[a],r&&i.test(a))if("class"===a&&("string"==typeof r&&(l=r,e[a]=r={},r[l]=!0),"string"==typeof s&&(l=s,t[a]=s={},s[l]=!0)),"on"===a||"nativeOn"===a||"hook"===a)for(o in s)r[o]=n(r[o],s[o]);else if(Array.isArray(r))e[a]=r.concat(s);else if(Array.isArray(s))e[a]=[r].concat(s);else for(o in s)r[o]=s[o];else e[a]=t[a];return e},{})}},function(e,t){var i={}.hasOwnProperty;e.exports=function(e,t){return i.call(e,t)}},function(e,t,i){"use strict";t.__esModule=!0;var n,r=i(56),s=(n=r)&&n.__esModule?n:{default:n};t.default=s.default||function(e){for(var t=1;t0?n:i)(e)}},function(e,t,i){var n=i(28)("keys"),r=i(21);e.exports=function(e){return n[e]||(n[e]=r(e))}},function(e,t,i){var n=i(14),r=i(5),s=r["__core-js_shared__"]||(r["__core-js_shared__"]={});(e.exports=function(e,t){return s[e]||(s[e]=void 0!==t?t:{})})("versions",[]).push({version:n.version,mode:i(20)?"pure":"global",copyright:"© 2019 Denis Pushkarev (zloirock.ru)"})},function(e,t){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(e,t){t.f=Object.getOwnPropertySymbols},function(e,t){e.exports={}},function(e,t,i){var n=i(10).f,r=i(7),s=i(13)("toStringTag");e.exports=function(e,t,i){e&&!r(e=i?e:e.prototype,s)&&n(e,s,{configurable:!0,value:t})}},function(e,t,i){t.f=i(13)},function(e,t,i){var n=i(5),r=i(14),s=i(20),a=i(33),o=i(10).f;e.exports=function(e){var t=r.Symbol||(r.Symbol=s?{}:n.Symbol||{});"_"==e.charAt(0)||e in t||o(t,e,{value:a.f(e)})}},function(e,t,i){var n=i(4),r=i(1);e.exports={throttle:n,debounce:r}},function(e,t,i){e.exports=!i(11)&&!i(16)(function(){return 7!=Object.defineProperty(i(37)("div"),"a",{get:function(){return 7}}).a})},function(e,t,i){var n=i(15),r=i(5).document,s=n(r)&&n(r.createElement);e.exports=function(e){return s?r.createElement(e):{}}},function(e,t,i){var n=i(7),r=i(12),s=i(62)(!1),a=i(27)("IE_PROTO");e.exports=function(e,t){var i,o=r(e),l=0,u=[];for(i in o)i!=a&&n(o,i)&&u.push(i);for(;t.length>l;)n(o,i=t[l++])&&(~s(u,i)||u.push(i));return u}},function(e,t,i){var n=i(40);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==n(e)?e.split(""):Object(e)}},function(e,t){var i={}.toString;e.exports=function(e){return i.call(e).slice(8,-1)}},function(e,t,i){var n=i(25);e.exports=function(e){return Object(n(e))}},function(e,t,i){"use strict";var n=i(20),r=i(23),s=i(43),a=i(9),o=i(31),l=i(69),u=i(32),c=i(72),h=i(13)("iterator"),d=!([].keys&&"next"in[].keys()),p=function(){return this};e.exports=function(e,t,i,f,m,v,g){l(i,t,f);var b,y,w,_=function(e){if(!d&&e in S)return S[e];switch(e){case"keys":case"values":return function(){return new i(this,e)}}return function(){return new i(this,e)}},x=t+" Iterator",C="values"==m,k=!1,S=e.prototype,D=S[h]||S["@@iterator"]||m&&S[m],$=D||_(m),E=m?C?_("entries"):$:void 0,T="Array"==t&&S.entries||D;if(T&&(w=c(T.call(new e)))!==Object.prototype&&w.next&&(u(w,x,!0),n||"function"==typeof w[h]||a(w,h,p)),C&&D&&"values"!==D.name&&(k=!0,$=function(){return D.call(this)}),n&&!g||!d&&!k&&S[h]||a(S,h,$),o[t]=$,o[x]=p,m)if(b={values:C?$:_("values"),keys:v?$:_("keys"),entries:E},g)for(y in b)y in S||s(S,y,b[y]);else r(r.P+r.F*(d||k),t,b);return b}},function(e,t,i){e.exports=i(9)},function(e,t,i){var n=i(17),r=i(70),s=i(29),a=i(27)("IE_PROTO"),o=function(){},l=function(){var e,t=i(37)("iframe"),n=s.length;for(t.style.display="none",i(71).appendChild(t),t.src="javascript:",(e=t.contentWindow.document).open(),e.write("