From af9a38a9732e378831127aeea810258fb2560760 Mon Sep 17 00:00:00 2001 From: projectdx Date: Thu, 25 Dec 2025 19:42:32 +0900 Subject: [PATCH] =?UTF-8?q?linkkf=20=EB=A1=9C=EC=A7=81=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 0 -> 10244 bytes .idea/.gitignore | 8 + .idea/dataSources.xml | 12 + .idea/flaskfarm.iml | 20 + .idea/inspectionProfiles/Project_Default.xml | 76 + .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 4 + .idea/modules.xml | 8 + .../03875fef6dc33ed50c8bc5f25df52c02e352a134 | 0 .../0c528d2f014ab7c32dd27d4e5d79396e74f3e62c | 0 .../0e68783ed60c8d2f67617374a92c1652fb6bdaee | 9 + .../58836750c643ef469da17133f44914292a82f3b3 | 6 + .../627433fe5c5c7210e3062642e7963227a319d5c6 | 2 + .../82544e7bcd3de23afaf278a62d1180d65a1ef456 | 10 + .../95519e06d92ec11e26cf873c3c30e2fcedf78892 | 7 + .../eeb13886aba87bd6947610e1cba3283d308baf0c | 33 + .idea/sonarlint/issuestore/index.pb | 17 + .idea/vcs.xml | 13 + cli/encode.py | 43 + ff_3_10_requirements.txt | 90 + files/menu.yaml.template | 8 +- files/notify.yaml.template | 4 +- files/requirements_mini.txt | 9 +- lib/.DS_Store | Bin 0 -> 6148 bytes lib/framework/.DS_Store | Bin 0 -> 6148 bytes lib/framework/__init__.py | 79 +- lib/framework/init_cache_manager.py | 73 + lib/framework/init_declare.py | 18 +- lib/framework/init_main.py | 84 +- lib/framework/init_menu.py | 177 +- lib/framework/init_plugin.py | 159 +- lib/framework/init_route.py | 38 +- lib/framework/init_web.py | 6 + lib/framework/log_viewer.py | 20 +- lib/framework/scheduler.py | 14 +- lib/framework/static/.DS_Store | Bin 0 -> 6148 bytes lib/framework/static/css/custom.css | 2 + lib/framework/static/css/showdown.css | 160 + lib/framework/static/img/loader.svg | 9 + lib/framework/static/js/chartjs-utils.js | 3845 +++++++++++++++++ lib/framework/static/js/ff_common1.js | 39 +- lib/framework/static/js/ff_global1.js | 231 +- lib/framework/static/js/ff_global_plugin.js | 14 + lib/framework/static/js/ff_ui1.js | 175 +- lib/framework/static/js/showdown-prettify.js | 35 + lib/framework/static/js/showdown_2.1.0.js | 3 + lib/framework/templates/base.html | 11 +- lib/framework/templates/log.html | 5 +- lib/framework/templates/macro.html | 778 ++-- lib/framework/templates/macro_include.html | 4 +- lib/framework/templates/macro_menu.html | 7 +- lib/framework/templates/manual.html | 36 +- lib/framework/templates/manual_old.html | 30 + lib/framework/templates/videojs.html | 3 + lib/framework/templates/videojs_discord.html | 90 + lib/framework/util.py | 16 +- lib/framework/version.py | 2 +- lib/plugin/__init__.py | 3 +- lib/plugin/_ffmpeg_queue.py | 20 +- lib/plugin/create_plugin.py | 30 +- lib/plugin/logic.py | 59 +- lib/plugin/logic_module_base.py | 107 +- lib/plugin/model_base.py | 48 +- lib/plugin/model_setting.py | 5 +- lib/plugin/route.py | 159 +- lib/support/.DS_Store | Bin 0 -> 6148 bytes lib/support/__init__.py | 6 +- lib/support/base/aes.py | 16 +- lib/support/base/discord.py | 130 +- lib/support/base/file.py | 316 +- lib/support/base/image.py | 10 +- lib/support/base/os_command.py | 44 + lib/support/base/slack.py | 25 + lib/support/base/string.py | 93 +- lib/support/base/sub_process.py | 132 +- lib/support/base/telegram.py | 18 +- lib/support/base/util.py | 13 +- lib/support/base/yaml.py | 44 + lib/support/expand/ffmpeg.py | 23 +- lib/support/expand/ffprobe.py | 27 + lib/support/expand/gsheet_base.py | 4 +- lib/support/expand/rclone.py | 197 + lib/support/expand/simple_selenium.py | 114 + .../libsc/sc.cpython-311-aarch64-linux-gnu.so | Bin 0 -> 70656 bytes lib/support/libsc/sc.cpython-311_32.so | Bin 0 -> 56148 bytes lib/support/libsc/sc.cpython-311_64.so | Bin 0 -> 70656 bytes lib/support/logger.py | 6 +- lib/support/site/__init__.py | 2 + lib/support/site/cppl.pyf | 1 + lib/system/files/all_plugin.yaml | 277 ++ lib/system/files/매뉴얼_설정.md | 9 + lib/system/mod_home.py | 4 +- lib/system/mod_log.py | 9 +- lib/system/mod_plugin.py | 44 +- lib/system/mod_route.py | 2 +- lib/system/mod_setting.py | 72 +- lib/system/page_command.py | 37 +- lib/system/setup.py | 3 +- lib/system/templates/system_all_log.html | 55 +- lib/system/templates/system_home.html | 107 +- lib/system/templates/system_login.html | 2 - lib/system/templates/system_plugin_all.html | 153 + lib/system/templates/system_plugin_list.html | 9 +- lib/system/templates/system_restart.html | 1 - lib/system/templates/system_setting_auth.html | 2 +- .../templates/system_setting_basic.html | 28 +- .../templates/system_setting_celery.html | 2 +- .../templates/system_setting_notify.html | 18 + lib/system/templates/system_tool_command.html | 24 +- lib/system/templates/system_tool_python.html | 2 +- lib/tool/__init__.py | 1 + lib/tool/fp_entity_ktv.py | 391 ++ lib/tool/modal_command.py | 47 +- lib/tool/notify.py | 14 +- lib/tool/util.py | 16 +- lib/tool_base/aes_cipher.py | 7 +- lib/tool_base/celery_shutil.py | 51 +- lib/tool_base/ffmpeg.py | 14 +- lib/tool_base/file.py | 42 +- lib/tool_base/notify.py | 19 +- lib/tool_base/rclone.py | 36 +- lib/tool_base/util.py | 4 +- lib/tool_expand/fileprocess.py | 22 +- lib/tool_expand/telegram.py | 22 +- lib/tool_expand/torrent_process.py | 56 +- loader.svg | 9 + main.py | 51 +- structure.md | 333 ++ 128 files changed, 8711 insertions(+), 1484 deletions(-) create mode 100644 .DS_Store create mode 100644 .idea/.gitignore create mode 100644 .idea/dataSources.xml create mode 100644 .idea/flaskfarm.iml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/sonarlint/issuestore/0/3/03875fef6dc33ed50c8bc5f25df52c02e352a134 create mode 100644 .idea/sonarlint/issuestore/0/c/0c528d2f014ab7c32dd27d4e5d79396e74f3e62c create mode 100644 .idea/sonarlint/issuestore/0/e/0e68783ed60c8d2f67617374a92c1652fb6bdaee create mode 100644 .idea/sonarlint/issuestore/5/8/58836750c643ef469da17133f44914292a82f3b3 create mode 100644 .idea/sonarlint/issuestore/6/2/627433fe5c5c7210e3062642e7963227a319d5c6 create mode 100644 .idea/sonarlint/issuestore/8/2/82544e7bcd3de23afaf278a62d1180d65a1ef456 create mode 100644 .idea/sonarlint/issuestore/9/5/95519e06d92ec11e26cf873c3c30e2fcedf78892 create mode 100644 .idea/sonarlint/issuestore/e/e/eeb13886aba87bd6947610e1cba3283d308baf0c create mode 100644 .idea/sonarlint/issuestore/index.pb create mode 100644 .idea/vcs.xml create mode 100644 cli/encode.py create mode 100644 ff_3_10_requirements.txt create mode 100644 lib/.DS_Store create mode 100644 lib/framework/.DS_Store create mode 100644 lib/framework/init_cache_manager.py create mode 100644 lib/framework/static/.DS_Store create mode 100644 lib/framework/static/css/showdown.css create mode 100644 lib/framework/static/img/loader.svg create mode 100644 lib/framework/static/js/chartjs-utils.js create mode 100644 lib/framework/static/js/ff_global_plugin.js create mode 100644 lib/framework/static/js/showdown-prettify.js create mode 100644 lib/framework/static/js/showdown_2.1.0.js create mode 100644 lib/framework/templates/manual_old.html create mode 100644 lib/framework/templates/videojs_discord.html create mode 100644 lib/support/.DS_Store create mode 100644 lib/support/base/os_command.py create mode 100644 lib/support/base/slack.py create mode 100644 lib/support/expand/ffprobe.py create mode 100644 lib/support/expand/rclone.py create mode 100644 lib/support/expand/simple_selenium.py create mode 100644 lib/support/libsc/sc.cpython-311-aarch64-linux-gnu.so create mode 100644 lib/support/libsc/sc.cpython-311_32.so create mode 100644 lib/support/libsc/sc.cpython-311_64.so create mode 100644 lib/support/site/cppl.pyf create mode 100644 lib/system/files/all_plugin.yaml create mode 100644 lib/system/files/매뉴얼_설정.md create mode 100644 lib/system/templates/system_plugin_all.html create mode 100644 lib/tool/fp_entity_ktv.py create mode 100644 loader.svg create mode 100644 structure.md diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..029c867ada404ab6b470f71461689677ced6ab2b GIT binary patch literal 10244 zcmeHMYit}>6~5otiDx#GbmH2M(}}YiJ86Ss*PD%<#EH|aUul!LwG%t>E48!h8ImF6 z9cO3PZtDaL66Mhbihxp{Qhxv{l>7i%rBW*jf(k@IqH;siN+1EM3KAkf)&4<2Ap4>3Bq zO!{&`NUwCz#ajZ9EGM&f(7ncQNXC4b^yPw()ItZuP?BOO{3Qm&aI(kzeo0?02q}g$ z_=^wtZ-&1@f%kTLe$4C6kQ6e!h7kxOusi~M?Ox6dmSQ=UDqg>*XKc&O#p9PDm6fkp zSy7=>tg5(s@U$~Gm`mmIZdWQh&b1-OvD3kQDt+8C=O(qPZYPsVSs63y4X_N8x||rc zGKMqP<>WJl>x~^04T>TwlUnWke0!oP*4)yDl0&nt3uL(ATylV|Md zjPpt10{k+-R+qT+K(RlDJ7uTo_wmjJCvA7OTWnI4)dWty(WwY5_zdn#|Ia%QJ(^Um%_&b%kb@5Wpwo9p&E zPHI}-HIJIq&zd!Rs5cF* zz2*ijQW>clp0!*nZJWpDEF*V%H04g28N$KDv}p^|u1LGA9ae^Ch3CT95xGrX ziza1c%9)-fe_Ubi)VpQvDS3jwyD#PD`e)1xy`Fp58`bquZtpY<(;z2mYu0J{A-zx5 zUXaJ!)2Xc4KSvl0>;tmweNM9TC-oXu&M7nw@kY(c%vuC*`Wyn~aznCFd=)RKN|jIw zS58~&Sv_lI9c+M&QX~W7{Mqea0;jK0i3~E+=qFb#|LpgK8=U)S$qy( z#W(OxJce)KDf|e};}`fPevOy#GG4)}_zSM$uTq($N~@(c(k7{1+9t&%+V*AVyyPW+h8o;n}Dyl|Gue+tww_Ud%1|M)YbaP z=-BuP^}3w$@39x}J(YEAd%$rmUIRx9e73Ah*)Nyu@#dmFsV+J=~}3Ma)J#Cwuk*vM=X0zj4TGT+VI0 zXpC^IF;<|t2B9yv6C#z=Gg`I2z!)$pZ$aw?nNpbud=J`4FD3# zsCcYG6*i#Wh@lUBjs+6jvYNKnqaNm0;+pYxMShFs+rLm=T_r9(I z1m78Uc*&G$I|Q#@>8qe=%*g5M70%^HA1~v-5S+aQpN~%TeLZLuT6kI{LOPJZxy3qpEB z=;Ce1lk~RZN#Wb^Tj}I|{e3O(KIz*Qg!G0}A8$Cx|I(iUrV+0HgN>?i{r?~ASig7I G|NjEV^iy8| literal 0 HcmV?d00001 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..9055fc3 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + sqlite.xerial + true + org.sqlite.JDBC + jdbc:sqlite:$PROJECT_DIR$/data/db/linkkf.db + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/flaskfarm.iml b/.idea/flaskfarm.iml new file mode 100644 index 0000000..7ca12a4 --- /dev/null +++ b/.idea/flaskfarm.iml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..cacd1d5 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,76 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..3c6601e --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e865ddb --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/sonarlint/issuestore/0/3/03875fef6dc33ed50c8bc5f25df52c02e352a134 b/.idea/sonarlint/issuestore/0/3/03875fef6dc33ed50c8bc5f25df52c02e352a134 new file mode 100644 index 0000000..e69de29 diff --git a/.idea/sonarlint/issuestore/0/c/0c528d2f014ab7c32dd27d4e5d79396e74f3e62c b/.idea/sonarlint/issuestore/0/c/0c528d2f014ab7c32dd27d4e5d79396e74f3e62c new file mode 100644 index 0000000..e69de29 diff --git a/.idea/sonarlint/issuestore/0/e/0e68783ed60c8d2f67617374a92c1652fb6bdaee b/.idea/sonarlint/issuestore/0/e/0e68783ed60c8d2f67617374a92c1652fb6bdaee new file mode 100644 index 0000000..b9b5ad1 --- /dev/null +++ b/.idea/sonarlint/issuestore/0/e/0e68783ed60c8d2f67617374a92c1652fb6bdaee @@ -0,0 +1,9 @@ + +c python:S6019"FFix this reluctant quantifier that will only ever match 0 repetitions.( +c python:S6019 "FFix this reluctant quantifier that will only ever match 0 repetitions.( +c python:S6019"FFix this reluctant quantifier that will only ever match 0 repetitions.( +^ python:S6019"FFix this reluctant quantifier that will only ever match 0 repetitions.(њ +^ python:S6019"FFix this reluctant quantifier that will only ever match 0 repetitions.(ҕ +6 python:S125!"Remove this commented out code.( +T python:S5754)"Replace this generic exception class with a more specific one.( +y python:S1186"[Add a nested comment explaining why this function is empty, or complete the implementation.(ʺ +| python:S117"_Rename this local variable "SystemInstance" to match the regular expression ^[_a-z][a-z0-9_]*$.(ͥ +r python:S3776"TRefactor this function to reduce its Cognitive Complexity from 26 to the 15 allowed.( +7 python:S125"Remove this commented out code.( +A python:S108")Either remove or fill this block of code.(۾ +U python:S5754" + + + + + + + + + + + + \ No newline at end of file diff --git a/cli/encode.py b/cli/encode.py new file mode 100644 index 0000000..e2ad4e7 --- /dev/null +++ b/cli/encode.py @@ -0,0 +1,43 @@ + +import argparse +import os +import sys + +sys.path.append(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'lib')) + +from support import SupportFile, SupportSC, logger + + +class Encode: + def start_folder(self, folderpath): + for name in os.listdir(folderpath): + filepath = os.path.join(folderpath, name) + if os.path.isfile(filepath) and name not in ['setup.py', '__init__.py']: + self.encode_file(filepath) + + def encode_file(self, filepath): + text = SupportFile.read_file(filepath) + data = SupportSC.encode(text, 0) + SupportFile.write_file(filepath + 'f', data) + logger.info(f"Create {os.path.basename(filepath + 'f')}") + + + def process_args(self): + parser = argparse.ArgumentParser() + parser.add_argument('--mode', default='encode') + parser.add_argument('--source', required=True, help=u'absolute path. folder or file') + args = parser.parse_args() + if SupportSC.LIBRARY_LOADING == False: + logger.error("sc import fail") + return + if os.path.exists(args.source): + if os.path.isdir(args.source): + self.start_folder(args.source) + elif os.path.isfile(args.source): + self.encode_file(args.source) + else: + logger.error("wrong source path!!") + + +if __name__== "__main__": + Encode().process_args() diff --git a/ff_3_10_requirements.txt b/ff_3_10_requirements.txt new file mode 100644 index 0000000..cc8578b --- /dev/null +++ b/ff_3_10_requirements.txt @@ -0,0 +1,90 @@ +aiohttp==3.8.3 +aiosignal==1.2.0 +amqp==5.1.1 +appdirs==1.4.4 +APScheduler==3.9.1 +async-generator==1.10 +async-timeout==4.0.2 +attrs==22.1.0 +beautifulsoup4==4.11.1 +bidict==0.22.0 +billiard==3.6.4.0 +cattrs==22.2.0 +celery==5.2.7 +certifi==2022.9.24 +charset-normalizer==2.1.1 +click==8.1.3 +click-didyoumean==0.3.0 +click-plugins==1.1.1 +click-repl==0.2.0 +cloudscraper==1.2.64 +Deprecated==1.2.13 +discord-webhook==0.17.0 +EditorConfig==0.12.3 +exceptiongroup==1.0.0rc9 +Flask==2.2.2 +Flask-Cors==3.0.10 +Flask-Dropzone==1.6.0 +Flask-Login==0.6.2 +Flask-Markdown==0.3 +Flask-SocketIO==5.3.1 +Flask-SQLAlchemy==3.0.2 +FlaskFarm==4.0.47 +frozenlist==1.3.1 +gevent==22.10.1 +gevent-websocket==0.10.1 +greenlet==1.1.3.post0 +h11==0.14.0 +idna==3.4 +importlib-metadata==5.0.0 +itsdangerous==2.1.2 +Jinja2==3.1.2 +jsbeautifier==1.14.7 +kombu==5.2.4 +lxml==4.9.1 +Markdown==3.4.1 +MarkupSafe==2.1.1 +multidict==6.0.2 +outcome==1.2.0 +packaging==21.3 +Pillow==9.2.0 +prompt-toolkit==3.0.31 +psutil==5.9.3 +pycryptodome==3.15.0 +pyparsing==3.0.9 +PySocks==1.7.1 +python-dotenv==0.21.0 +python-engineio==4.3.4 +python-socketio==5.7.2 +pytz==2022.5 +pytz-deprecation-shim==0.1.0.post0 +PyYAML==6.0 +redis==4.3.4 +requests==2.28.1 +requests-cache==0.9.6 +requests-toolbelt==0.10.1 +selenium==4.5.0 +selenium-stealth==1.0.6 +six==1.16.0 +sniffio==1.3.0 +sortedcontainers==2.4.0 +soupsieve==2.3.2.post1 +SQLAlchemy==1.4.42 +telepot-mod==0.0.1 +tqdm==4.64.1 +trio==0.22.0 +trio-websocket==0.9.2 +tzdata==2022.5 +tzlocal==4.2 +url-normalize==1.4.3 +urllib3==1.26.12 +vine==5.0.0 +wcwidth==0.2.5 +webdriver-manager==3.8.4 +Werkzeug==2.2.2 +wrapt==1.14.1 +wsproto==1.2.0 +yarl==1.8.1 +zipp==3.10.0 +zope.event==4.5.0 +zope.interface==5.5.0 diff --git a/files/menu.yaml.template b/files/menu.yaml.template index a8ac393..6bcafc4 100644 --- a/files/menu.yaml.template +++ b/files/menu.yaml.template @@ -1,18 +1,12 @@ # 카테고리 # uri 가 plugin인 경우 name 값은 대체 -#- name: "토렌트" -# list: -# - uri: "rss" - #- name: "기본 기능" # list: # - uri: "terminal" -# - uri: "command" # - uri: "flaskfilemanager" # - uri: "flaskcode" -# - uri: "number_baseball" #- name: "링크" @@ -32,6 +26,8 @@ name: "확장 설정" - uri: "system/plugin" name: "플러그인 관리" + - uri: "system/tool/command" + name: "Command 관리" - uri: "-" - uri: "system/logout" name: "로그아웃" diff --git a/files/notify.yaml.template b/files/notify.yaml.template index 73cba9e..8ad4f7f 100644 --- a/files/notify.yaml.template +++ b/files/notify.yaml.template @@ -3,7 +3,7 @@ # message id 가 없을 경우 DEFAULT 값 사용 # 공통: type, enable_time (시작시간-종료시간. 항상 받을 경우 생략) -- DEFAULT: +DEFAULT: - type: 'telegram' token: '' chat_id: '' @@ -14,7 +14,7 @@ enable_time: '09-23' -- system_start: +system_start: - type: 'telegram' token: '' chat_id: '' diff --git a/files/requirements_mini.txt b/files/requirements_mini.txt index 6111520..e479365 100644 --- a/files/requirements_mini.txt +++ b/files/requirements_mini.txt @@ -3,11 +3,11 @@ Flask Flask-SQLAlchemy Flask-Login Flask-Cors -Flask-Markdown +#Flask-Markdown Flask-SocketIO python-engineio -python-socketio -Werkzeug +python-socketio<5.8.0 +Werkzeug<3.0 Jinja2 # common util @@ -25,4 +25,5 @@ pillow gevent gevent-websocket -pycryptodome \ No newline at end of file +pycryptodome +json_fix diff --git a/lib/.DS_Store b/lib/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..3818bb7f483ed044caebf263a4a09002910aeaeb GIT binary patch literal 6148 zcmeHKyH3ME5S)WZ1kt3VykFoCPEq)R`~VL_Ly!?pMC*><&g=t}$bpgq%|?6U+uPZb zr|@P0l;y6w0Tuw}bVGdFGBrClpV(PO42#!z!UuZ1y~Hy)_jttt|8eus z_ZybQ1qST!#-Ekmc0(MUuBWIJkOERb3P=Gd@Vf%mTxs*GK&?_h3P^!(1?>A!>4q(F z4D?S27aswLGlt#x?6U;1T7cLR$3RACC8)%pmK-rk&>63p*AmCTpriQBtdlpFoKTA2 z&Up27loqH}3P^!t1OBb|6%?=CTS-Hq`<#Ypv+e5)snB2y>;?()@v*Mj{arL o^>i-YiizHexv^G!eUMk}nddEW40Jl0jUvPEqm&`~Z-oKspqpBmGr;7oW!L1BvLMNI?_LO6#%L zJGMN NamespacedCache: + """ + 플러그인 이름을 기반으로 네임스페이스가 적용된 캐시 객체를 반환합니다. + """ + if not plugin_name: + raise ValueError("플러그인 이름은 필수입니다.") + return NamespacedCache(plugin_name) \ No newline at end of file diff --git a/lib/framework/init_declare.py b/lib/framework/init_declare.py index a37048f..e463d23 100644 --- a/lib/framework/init_declare.py +++ b/lib/framework/init_declare.py @@ -13,13 +13,13 @@ def check_api(original_function): #logger.warning(request.url) #logger.warning(request.form) try: - if F.SystemModelSetting.get_bool('auth_use_apikey'): - if request.method == 'POST': - apikey = request.form['apikey'] - else: - apikey = request.args.get('apikey') - #apikey = request.args.get('apikey') - if apikey is None or apikey != F.SystemModelSetting.get('auth_apikey'): + if F.SystemModelSetting.get_bool('use_apikey'): + try: + d = request.get_json() + except Exception: + d = request.form.to_dict() if request.method == 'POST' else request.args.to_dict() + apikey = d.get('apikey') + if apikey is None or apikey != F.SystemModelSetting.get('apikey'): F.logger.warning('CHECK API : ABORT no match ({})'.format(apikey)) F.logger.warning(request.environ.get('HTTP_X_REAL_IP', request.remote_addr)) abort(403) @@ -31,7 +31,7 @@ def check_api(original_function): return original_function(*args, **kwargs) #2 return wrapper_function -# Suuport를 logger 생성전에 쓰지 않기 위해 중복 선언 +# Support를 logger 생성전에 쓰지 않기 위해 중복 선언 import logging @@ -47,7 +47,7 @@ class CustomFormatter(logging.Formatter): # pathname filename #format = "[%(asctime)s|%(name)s|%(levelname)s - %(message)s (%(filename)s:%(lineno)d)" - __format = '[{yellow}%(asctime)s{reset}|{color}%(levelname)s{reset}|{green}%(name)s{reset} %(pathname)s:%(lineno)s] {color}%(message)s{reset}' if os.environ.get('LOGGER_PATHNAME', "False") == "True" else '[{yellow}%(asctime)s{reset}|{color}%(levelname)s{reset}|{green}%(name)s{reset} %(filename)s:%(lineno)s] {color}%(message)s{reset}' + __format = '[{yellow}%(asctime)s{reset}|{color}%(levelname)s{reset}|{green}%(name)s{reset}|%(pathname)s:%(lineno)s] {color}%(message)s{reset}' if os.environ.get('LOGGER_PATHNAME', "False") == "True" else '[{yellow}%(asctime)s{reset}|{color}%(levelname)s{reset}|{green}%(name)s{reset}|%(filename)s:%(lineno)s] {color}%(message)s{reset}' FORMATS = { logging.DEBUG: __format.format(color=grey, reset=reset, yellow=yellow, green=green), diff --git a/lib/framework/init_main.py b/lib/framework/init_main.py index 19500d8..48b3dfd 100644 --- a/lib/framework/init_main.py +++ b/lib/framework/init_main.py @@ -8,14 +8,15 @@ import time import traceback from datetime import datetime +import redis import yaml from flask import Flask from flask_cors import CORS from flask_login import LoginManager, login_required from flask_socketio import SocketIO from flask_sqlalchemy import SQLAlchemy -from flaskext.markdown import Markdown from pytz import timezone, utc +from werkzeug.middleware.proxy_fix import ProxyFix from .init_declare import CustomFormatter, check_api @@ -37,12 +38,15 @@ class Framework: self.db = None self.scheduler = None self.socketio = None + self.rd = None self.path_app_root = None self.path_data = None self.users = {} + self.get_cache = None self.__level_unset_logger_list = [] self.__logger_list = [] + self.all_log_filehandler = None self.__exit_code = -1 self.login_manager = None #self.plugin_instance_list = {} @@ -59,14 +63,17 @@ class Framework: def __initialize(self): os.environ["PYTHONUNBUFFERED"] = "1" os.environ['FF'] = "true" + os.environ['FF_PYTHON'] = sys.executable self.__config_initialize("first") self.__make_default_dir() self.logger = self.get_logger(__package__) + self.get_logger('support') import support self.__prepare_starting() self.app = Flask(__name__) + self.app.wsgi_app = ProxyFix(self.app.wsgi_app, x_proto=1) self.__config_initialize('flask') self.__init_db() @@ -82,7 +89,6 @@ class Framework: self.socketio = SocketIO(self.app, cors_allowed_origins="*", async_mode='threading') CORS(self.app) - Markdown(self.app) self.login_manager = LoginManager() self.login_manager.init_app(self.app) @@ -94,10 +100,11 @@ class Framework: self.app.config.update( DROPZONE_MAX_FILE_SIZE = 102400, DROPZONE_TIMEOUT = 5*60*1000, - #DROPZONE_ALLOWED_FILE_CUSTOM = True, - #DROPZONE_ALLOWED_FILE_TYPE = 'default, image, audio, video, text, app, *.*', + DROPZONE_ALLOWED_FILE_CUSTOM = True, + DROPZONE_ALLOWED_FILE_TYPE = "image/*, audio/*, video/*, text/*, application/*, *.*", ) self.dropzone = Dropzone(self.app) + def __init_db(self): @@ -131,19 +138,20 @@ class Framework: def __init_celery(self): + redis_port = 6379 try: - from celery import Celery - - #if frame.config['use_celery'] == False or platform.system() == 'Windows': if self.config['use_celery'] == False: - raise Exception('no celery') - + raise Exception('use_celery=False') + from celery import Celery redis_port = os.environ.get('REDIS_PORT', None) if redis_port == None: redis_port = self.config.get('redis_port', None) if redis_port == None: redis_port = '6379' - + self.config['redis_port'] = redis_port + self.rd = redis.StrictRedis(host='localhost', port=redis_port, db=0) + if self.config['use_celery'] == False: + raise Exception('no celery') self.app.config['CELERY_BROKER_URL'] = 'redis://localhost:%s/0' % redis_port self.app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:%s/0' % redis_port @@ -166,6 +174,7 @@ class Framework: F.logger.info(f"celery running_type: {running_type}") #F.logger.info(f"celery running_type: {options}") celery.steps['worker'].add(CustomArgs) + except Exception as e: if self.config['use_celery']: self.logger.error('CELERY!!!') @@ -187,6 +196,14 @@ class Framework: if len(args) > 0 and type(args[0]) == type(dummy_func): return args[0] self.f(*args, **kwargs) + try: + from .init_cache_manager import _RedisManager, get_cache + _RedisManager(host='localhost', port=redis_port) + self.get_cache = get_cache + except Exception as e: + self.logger.error(f"get_cache import error: {str(e)}") + self.get_cache = None + return celery @@ -201,11 +218,13 @@ class Framework: self.logger.error(f'Exception:{str(e)}') self.logger.error(traceback.format_exc()) self.SystemModelSetting = SystemInstance.ModelSetting - SystemInstance.plugin_load() + if self.config['run_flask']: + SystemInstance.plugin_load() self.app.register_blueprint(SystemInstance.blueprint) self.config['flag_system_loading'] = True self.__config_initialize('member') self.__config_initialize('system_loading_after') + self.set_level(self.SystemModelSetting.get_int('log_level')) def initialize_plugin(self): @@ -232,6 +251,7 @@ class Framework: self.__make_default_logger() self.__config_initialize("last") + self.config['loading_completed'] = True self.logger.info('### LAST') self.logger.info(f"### PORT: {self.config.get('port')}") self.logger.info('### Now you can access App by webbrowser!!') @@ -248,6 +268,7 @@ class Framework: def __config_initialize(self, mode): if mode == "first": self.config = {} + self.config['loading_completed'] = False self.config['os'] = platform.system() self.config['flag_system_loading'] = False #self.config['run_flask'] = True if sys.argv[0].endswith('main.py') else False @@ -263,6 +284,8 @@ class Framework: self.config['export_filepath'] = os.path.join(self.config['path_app'], 'export.sh') self.config['exist_export'] = os.path.exists(self.config['export_filepath']) self.config['recent_version'] = '--' + from .version import VERSION + self.config['version'] = VERSION self.__process_args() self.__load_config() self.__init_define() @@ -270,7 +293,7 @@ class Framework: self.config['notify_yaml_filepath'] = os.path.join(self.config['path_data'], 'db', 'notify.yaml') if 'running_type' not in self.config: self.config['running_type'] = 'native' - + self.pip_install() elif mode == "flask": self.app.secret_key = os.urandom(24) self.app.config['TEMPLATES_AUTO_RELOAD'] = True @@ -295,8 +318,8 @@ class Framework: self.config['DEFINE'] = {} # 이건 필요 없음 self.config['DEFINE']['GIT_VERSION_URL'] = 'https://raw.githubusercontent.com/flaskfarm/flaskfarm/main/lib/framework/version.py' - self.config['DEFINE']['CHANGELOG'] = 'https://flaskfarm.github.io/posts/changelog' - + self.config['DEFINE']['CHANGELOG'] = 'https://github.com/flaskfarm/flaskfarm' + #self.config['DEFINE']['WEB_DIRECT_URL'] = "http://52.78.103.230:49734" def __process_args(self): @@ -363,6 +386,9 @@ class Framework: self.config['debug'] = False if self.config.get('plugin_update') == None: self.config['plugin_update'] = True + # 2022-11-20 + if self.config['debug']: + self.config['plugin_update'] = False if self.config.get('plugin_loading_only_devpath') == None: self.config['plugin_loading_only_devpath'] = False if self.config.get('plugin_loading_list') == None: @@ -402,8 +428,8 @@ class Framework: try: if self.config['flag_system_loading']: try: - from system import SystemModelSetting - level = SystemModelSetting.get_int('log_level') + #from system import SystemModelSetting + level = self.SystemModelSetting.get_int('log_level') except: level = logging.DEBUG if self.__level_unset_logger_list is not None: @@ -426,7 +452,7 @@ class Framework: return converted.timetuple() if from_command == False: - file_formatter = logging.Formatter(u'[%(asctime)s|%(levelname)s|%(filename)s:%(lineno)s] %(message)s') + file_formatter = logging.Formatter(u'[%(asctime)s|%(levelname)s|%(name)s|%(filename)s:%(lineno)s] %(message)s') else: file_formatter = logging.Formatter(u'[%(asctime)s] %(message)s') @@ -435,10 +461,18 @@ class Framework: fileHandler = logging.handlers.RotatingFileHandler(filename=os.path.join(self.path_data, 'log', f'{name}.log'), maxBytes=file_max_bytes, backupCount=5, encoding='utf8', delay=True) fileHandler.setFormatter(file_formatter) logger.addHandler(fileHandler) + if name == 'framework' and self.all_log_filehandler == None: + self.all_log_filehandler = logging.handlers.RotatingFileHandler(filename=os.path.join(self.path_data, 'log', f'all.log'), maxBytes=5*1024*1024, backupCount=5, encoding='utf8', delay=True) + self.all_log_filehandler.setFormatter(file_formatter) + if from_command == False: streamHandler = logging.StreamHandler() streamHandler.setFormatter(CustomFormatter()) logger.addHandler(streamHandler) + + if self.all_log_filehandler != None: + logger.addHandler(self.all_log_filehandler) + return logger @@ -459,7 +493,7 @@ class Framework: def set_level(self, level): try: for l in self.__logger_list: - l.setLevel(level) + l.setLevel(int(level)) self.__make_default_logger() except: pass @@ -468,7 +502,7 @@ class Framework: def start(self): host = '0.0.0.0' - for i in range(5): + for i in range(5): try: #self.logger.debug(d(self.config)) # allow_unsafe_werkzeug=True termux nohup 실행시 필요함 @@ -517,8 +551,8 @@ class Framework: PluginManager.plugin_unload() with self.app.test_request_context(): self.socketio.stop() - except Exception as exception: - self.logger.error('Exception:%s', exception) + except Exception as e: + self.logger.error(f"Exception:{str(e)}") self.logger.error(traceback.format_exc()) def get_recent_version(self): @@ -532,3 +566,11 @@ class Framework: self.logger.error(traceback.format_exc()) self.config['recent_version'] = '확인 실패' return False + + + # dev 도커용. package는 setup에 포함. + def pip_install(self): + try: + import json_fix + except: + os.system('pip install json_fix') diff --git a/lib/framework/init_menu.py b/lib/framework/init_menu.py index 6630820..23b8a5b 100644 --- a/lib/framework/init_menu.py +++ b/lib/framework/init_menu.py @@ -1,93 +1,144 @@ import os import shutil +import traceback +from framework import F, logger from support import SupportYaml, d -from framework import F - class MenuManager: menu_map = None @classmethod def __load_menu_yaml(cls): - menu_yaml_filepath = os.path.join(F.config['path_data'], 'db', 'menu.yaml') - if os.path.exists(menu_yaml_filepath) == False: - shutil.copy( - os.path.join(F.config['path_app'], 'files', 'menu.yaml.template'), - menu_yaml_filepath - ) - cls.menu_map = SupportYaml.read_yaml(menu_yaml_filepath) + try: + menu_yaml_filepath = os.path.join(F.config['path_data'], 'db', 'menu.yaml') + if os.path.exists(menu_yaml_filepath) == False: + shutil.copy( + os.path.join(F.config['path_app'], 'files', 'menu.yaml.template'), + menu_yaml_filepath + ) + cls.menu_map = SupportYaml.read_yaml(menu_yaml_filepath) + except Exception as e: + logger.error(f"Exception:{str(e)}") + logger.error(traceback.format_exc()) + cls.menu_map = SupportYaml.read_yaml(os.path.join(F.config['path_app'], 'files', 'menu.yaml.template')) @classmethod def init_menu(cls): cls.__load_menu_yaml() - from .init_plugin import PluginManager - plugin_menus = PluginManager.plugin_menus - copy_map = [] + if cls.__init_menu() == False: + cls.menu_map = SupportYaml.read_yaml(os.path.join(F.config['path_app'], 'files', 'menu.yaml.template')) + cls.__init_menu() - for category in cls.menu_map: - if 'uri' in category: - copy_map.append(category) - continue - cate_count = 0 + @classmethod + def __init_menu(cls): + try: + from .init_plugin import PluginManager + plugin_menus = PluginManager.plugin_menus + copy_map = [] + for category in cls.menu_map: + if 'uri' in category: + if category['uri'] in plugin_menus: + plugin_menus[category['uri']]['match'] = True + copy_map.append(plugin_menus[category['uri']]['menu']) + else: + copy_map.append(category) + continue + cate_count = 0 - tmp_cate_list = [] - for item in category['list']: - if item['uri'] in plugin_menus: - plugin_menus[item['uri']]['match'] = True - tmp_cate_list.append(plugin_menus[item['uri']]['menu']) - cate_count += 1 - elif item['uri'].startswith('http'): - tmp_cate_list.append({ - 'uri': item['uri'], - 'name': item['name'], - 'target': item.get('target', '_blank') - }) - cate_count += 1 - elif (len(item['uri'].split('/')) > 1 and item['uri'].split('/')[0] in plugin_menus) or item['uri'].startswith('javascript') or item['uri'] in ['-']: - tmp_cate_list.append({ - 'uri': item['uri'], - 'name': item.get('name', ''), - }) - cate_count += 1 - elif item['uri'] == 'setting': - if len(PluginManager.setting_menus) > 0: + tmp_cate_list = [] + for item in category['list']: + if item['uri'] in plugin_menus: + plugin_menus[item['uri']]['match'] = True + tmp_cate_list.append(plugin_menus[item['uri']]['menu']) + cate_count += 1 + elif item['uri'].startswith('http'): + tmp_cate_list.append({ + 'uri': item['uri'], + 'name': item['name'], + 'target': item.get('target', '_blank') + }) + cate_count += 1 + elif (len(item['uri'].split('/')) > 1 and item['uri'].split('/')[0] in plugin_menus) or item['uri'].startswith('javascript') or item['uri'] in ['-']: tmp_cate_list.append({ 'uri': item['uri'], 'name': item.get('name', ''), - 'list': PluginManager.setting_menus }) - - if cate_count > 0: - copy_map.append({ - 'name': category['name'], - 'list': tmp_cate_list, - 'count': cate_count - }) - cls.menu_map = copy_map - - make_dummy_cate = False - for name, plugin_menu in plugin_menus.items(): - #F.logger.info(d(plugin_menu)) - #if 'uri' not in plugin_menu['menu']: - # continue - if plugin_menu['match'] == False: - if make_dummy_cate == False: - make_dummy_cate = True - cls.menu_map.insert(len(cls.menu_map)-1, { - 'name':'미분류', 'count':0, 'list':[] + cate_count += 1 + elif item['uri'] == 'setting': + # 2024.06.04 + # 확장설정도 메뉴 구성 + if len(PluginManager.setting_menus) > 0: + set_tmp = item.get('list') + if set_tmp: + cp = PluginManager.setting_menus.copy() + include = [] + for set_ch in set_tmp: + if set_ch.get('uri') and (set_ch.get('uri') == '-' or set_ch.get('uri').startswith('http')): + include.append(set_ch) + continue + + for i, ps in enumerate(cp): + if set_ch.get('plugin') != None and set_ch.get('plugin') == ps.get('plugin'): + include.append(ps) + del cp[i] + break + tmp_cate_list.append({ + 'uri': item['uri'], + 'name': item.get('name', ''), + 'list': include + cp + }) + + else: + tmp_cate_list.append({ + 'uri': item['uri'], + 'name': item.get('name', ''), + 'list': PluginManager.setting_menus + }) + + if cate_count > 0: + copy_map.append({ + 'name': category['name'], + 'list': tmp_cate_list, + 'count': cate_count }) + cls.menu_map = copy_map + + make_dummy_cate = False + for name, plugin_menu in plugin_menus.items(): + #F.logger.info(d(plugin_menu)) + #if 'uri' not in plugin_menu['menu']: + # continue + if plugin_menu['match'] == False: + if make_dummy_cate == False: + make_dummy_cate = True + cls.menu_map.insert(len(cls.menu_map)-1, { + 'name':'미분류', 'count':0, 'list':[] + }) - c = cls.menu_map[-2] - c['count'] += 1 - c['list'].append(plugin_menu['menu']) - + c = cls.menu_map[-2] + c['count'] += 1 + c['list'].append(plugin_menu['menu']) + return True + except Exception as e: + logger.error(f"Exception:{str(e)}") + logger.error(traceback.format_exc()) + return False + #F.logger.warning(d(cls.menu_map)) @classmethod def get_menu_map(cls): - #F.logger.warning(d(cls.menu_map)) return cls.menu_map + + + @classmethod + def get_setting_menu(cls, plugin): + from .init_plugin import PluginManager + for tmp in PluginManager.setting_menus: + if tmp['plugin'] == plugin: + return tmp + \ No newline at end of file diff --git a/lib/framework/init_plugin.py b/lib/framework/init_plugin.py index 5be4458..3630d63 100644 --- a/lib/framework/init_plugin.py +++ b/lib/framework/init_plugin.py @@ -7,9 +7,8 @@ import traceback import zipfile import requests -from support import SupportFile, SupportSubprocess, SupportYaml - from framework import F +from support import SupportFile, SupportSubprocess, SupportYaml class PluginManager: @@ -30,13 +29,13 @@ class PluginManager: tmps = os.listdir(plugin_path) add_plugin_list = [] for t in tmps: - if not t.startswith('_') and os.path.isdir(os.path.join(plugin_path, t)): + if t.startswith('_') == False and t.startswith('.') == False and os.path.isdir(os.path.join(plugin_path, t)) and t != 'false' and t != 'tmp': add_plugin_list.append(t) cls.all_package_list[t] = {'pos':'normal', 'path':os.path.join(plugin_path, t), 'loading':(F.config.get('plugin_loading_only_devpath', None) != True)} plugins = plugins + add_plugin_list - except Exception as exception: - F.logger.error('Exception:%s', exception) + except Exception as e: + F.logger.error(f"Exception:{str(e)}") F.logger.error(traceback.format_exc()) if F.config.get('plugin_loading_only_devpath', None) == True: @@ -59,12 +58,12 @@ class PluginManager: tmps = os.listdir(__) add_plugin_list = [] for t in tmps: - if not t.startswith('_') and os.path.isdir(os.path.join(__, t)): + if t.startswith('_') == False and t.startswith('.') == False and os.path.isdir(os.path.join(__, t)) and t != 'false' and t != 'tmp': add_plugin_list.append(t) cls.all_package_list[t] = {'pos':'dev', 'path':os.path.join(__, t), 'loading':True} plugins = plugins + add_plugin_list - except Exception as exception: - F.logger.error('Exception:%s', exception) + except Exception as e: + F.logger.error(f"Exception:{str(e)}") F.logger.error(traceback.format_exc()) # plugin_loading_list @@ -79,8 +78,8 @@ class PluginManager: cls.all_package_list[_]['loading'] = False cls.all_package_list[_]['status'] = 'not_include_loading_list' plugins = new_plugins - except Exception as exception: - F.logger.error('Exception:%s', exception) + except Exception as e: + F.logger.error(f"Exception:{str(e)}") F.logger.error(traceback.format_exc()) # plugin_except_list @@ -95,8 +94,8 @@ class PluginManager: cls.all_package_list[_]['loading'] = False cls.all_package_list[_]['status'] = 'include_except_list' plugins = new_plugins - except Exception as exception: - F.logger.error('Exception:%s', exception) + except Exception as e: + F.logger.error(f"Exception:{str(e)}") F.logger.error(traceback.format_exc()) return plugins @@ -113,43 +112,26 @@ class PluginManager: for plugin_name in plugins: F.logger.debug(f'[+] PLUGIN LOADING Start.. [{plugin_name}]') entity = cls.all_package_list[plugin_name] - entity['version'] = '3' try: - mod = __import__('%s' % (plugin_name), fromlist=[]) - mod_plugin_info = None try: - mod_plugin_info = getattr(mod, 'plugin_info') - entity['module'] = mod - except Exception as exception: - F.logger.info(f'[!] PLUGIN_INFO not exist : [{plugin_name}] - is FF') - - if mod_plugin_info == None: - try: - mod = __import__(f'{plugin_name}.setup', fromlist=['setup']) - entity['version'] = '4' - except Exception as e: - F.logger.error(f'Exception:{str(e)}') - F.logger.error(traceback.format_exc()) - F.logger.warning(f'[!] NOT normal plugin : [{plugin_name}]') + mod = __import__(f'{plugin_name}.setup', fromlist=['setup']) + except Exception as e: + F.logger.error(f'Exception:{str(e)}') + F.logger.error(traceback.format_exc()) + F.logger.warning(f'[!] NOT normal plugin : [{plugin_name}]') + continue try: - if entity['version'] != '4': - mod_blue_print = getattr(mod, 'blueprint') - else: - entity['setup_mod'] = mod - entity['P'] = getattr(mod, 'P') - mod_blue_print = getattr(entity['P'], 'blueprint') + entity['setup_mod'] = mod + entity['P'] = getattr(mod, 'P') + mod_blue_print = getattr(entity['P'], 'blueprint') if mod_blue_print: F.app.register_blueprint(mod_blue_print) except Exception as exception: - #logger.error('Exception:%s', exception) - #logger.error(traceback.format_exc()) F.logger.warning(f'[!] BLUEPRINT not exist : [{plugin_name}]') cls.plugin_list[plugin_name] = entity - #system.LogicPlugin.current_loading_plugin_list[plugin_name]['status'] = 'success' - #system.LogicPlugin.current_loading_plugin_list[plugin_name]['info'] = mod_plugin_info - except Exception as exception: - F.logger.error('Exception:%s', exception) + except Exception as e: + F.logger.error(f"Exception:{str(e)}") F.logger.error(traceback.format_exc()) F.logger.debug('no blueprint') cls.all_package_list[plugin_name]['loading'] = False @@ -157,36 +139,50 @@ class PluginManager: cls.all_package_list[plugin_name]['log'] = traceback.format_exc() - if not F.config['run_celery']: try: with F.app.app_context(): F.db.create_all() - except Exception as exception: - F.logger.error('Exception:%s', exception) + except Exception as e: + F.logger.error(f"Exception:{str(e)}") F.logger.error(traceback.format_exc()) F.logger.debug('db.create_all error') + if F.config['run_celery']: + for key, entity in cls.plugin_list.items(): + try: + mod_plugin_load = getattr(entity['P'], 'plugin_load_celery') + if mod_plugin_load: + def func(mod_plugin_load, key): + try: + #F.logger.debug(f'[!] plugin_load_celery threading start : [{key}]') + mod_plugin_load() + #F.logger.debug(f'[!] plugin_load_celery threading end : [{key}]') + except Exception as e: + F.logger.error(f"Exception:{str(e)}") + F.logger.error(traceback.format_exc()) + t = threading.Thread(target=func, args=(mod_plugin_load, key)) + t.setDaemon(True) + t.start() + except Exception as e: + F.logger.error(f"Exception:{str(e)}") + F.logger.error(traceback.format_exc()) + if not F.config['run_flask']: return for key, entity in cls.plugin_list.items(): try: - mod_plugin_load = None - if entity['version'] == '3': - mod_plugin_load = getattr(entity['module'], 'plugin_load') - elif entity['version'] == '4': - mod_plugin_load = getattr(entity['P'], 'plugin_load') + mod_plugin_load = getattr(entity['P'], 'plugin_load') if mod_plugin_load: def func(mod_plugin_load, key): try: - F.logger.debug(f'[!] plugin_load threading start : [{key}]') - #mod.plugin_load() + F.logger.info(f'[!] plugin_load threading start : [{key}]') mod_plugin_load() F.logger.debug(f'[!] plugin_load threading end : [{key}]') - except Exception as exception: + except Exception as e: F.logger.error('### plugin_load exception : %s', key) - F.logger.error('Exception:%s', exception) + F.logger.error(f"Exception:{str(e)}") F.logger.error(traceback.format_exc()) cls.all_package_list[key]['loading'] = False cls.all_package_list[key]['status'] = 'plugin_load error' @@ -199,42 +195,29 @@ class PluginManager: MenuManager.init_menu() F.logger.info(f"플러그인 로딩 실패로 메뉴 삭제2 : {key}") + t = threading.Thread(target=func, args=(mod_plugin_load, key)) + t.setDaemon(True) + t.start() - # mod는 위에서 로딩 - if key != 'mod': - t = threading.Thread(target=func, args=(mod_plugin_load, key)) - t.setDaemon(True) - t.start() - #if key == 'mod': - # t.join() - except Exception as exception: + except Exception as e: F.logger.debug(f'[!] PLUGIN_LOAD function not exist : [{key}]') - #logger.error('Exception:%s', exception) - #logger.error(traceback.format_exc()) - #logger.debug('no init_scheduler') + try: - mod_menu = None - if entity['version'] == '3': - mod_menu = getattr(entity['module'], 'menu') - elif entity['version'] == '4': - mod_menu = getattr(entity['P'], 'menu') - + mod_menu = getattr(entity['P'], 'menu') if mod_menu and cls.all_package_list[key]['loading'] != False: cls.plugin_menus[key]= {'menu':mod_menu, 'match':False} - if entity['version'] == '4': - setting_menu = getattr(entity['P'], 'setting_menu') - if setting_menu != None and cls.all_package_list[key]['loading'] != False: - F.logger.info(f"메뉴 포함 : {key}") - cls.setting_menus.append(setting_menu) - - + setting_menu = getattr(entity['P'], 'setting_menu') + setting_menu['plugin'] = entity['P'].package_name + if setting_menu != None and cls.all_package_list[key]['loading'] != False: + F.logger.info(f"확장 설정 : {key}") + cls.setting_menus.append(setting_menu) except Exception as exception: F.logger.debug('no menu') F.logger.debug('### plugin_load threading all start.. : %s ', len(cls.plugin_list)) # 모든 모듈을 로드한 이후에 app 등록, table 생성, start - except Exception as exception: - F.logger.error('Exception:%s', exception) + except Exception as e: + F.logger.error(f"Exception:{str(e)}") F.logger.error(traceback.format_exc()) @@ -243,17 +226,9 @@ class PluginManager: def plugin_unload(cls): for key, entity in cls.plugin_list.items(): try: - if entity['version'] == '3': - mod_plugin_unload = getattr(entity['module'], 'plugin_unload') - elif entity['version'] == '4': - mod_plugin_unload = getattr(entity['P'], 'plugin_unload') - - #if plugin_name == 'rss': - # continue - #mod_plugin_unload = getattr(mod, 'plugin_unload') + mod_plugin_unload = getattr(entity['P'], 'plugin_unload') if mod_plugin_unload: mod_plugin_unload() - #mod.plugin_unload() except Exception as e: F.logger.error('module:%s', key) F.logger.error(f'Exception:{str(e)}') @@ -267,6 +242,7 @@ class PluginManager: @classmethod def plugin_install(cls, plugin_git, zip_url=None, zip_filename=None): + plugin_git = plugin_git.strip() is_git = True if plugin_git != None and plugin_git != '' else False ret = {} try: @@ -381,7 +357,7 @@ class PluginManager: tmps = os.listdir(plugins_path) for t in tmps: plugin_path = os.path.join(plugins_path, t) - if t.startswith('_'): + if t.startswith('_') or t.startswith('.'): continue if os.path.exists(os.path.join(plugin_path, '.git')): command = ['git', '-C', plugin_path, 'reset', '--hard', 'HEAD'] @@ -392,14 +368,15 @@ class PluginManager: F.logger.debug(ret) else: F.logger.debug(f"{plugin_path} not git repo") - except Exception as exception: - F.logger.error('Exception:%s', exception) + except Exception as e: + F.logger.error(f"Exception:{str(e)}") F.logger.error(traceback.format_exc()) @classmethod def get_plugin_instance(cls, package_name): try: - return cls.all_package_list[package_name]['P'] + if cls.all_package_list[package_name]['loading']: + return cls.all_package_list[package_name]['P'] except: pass diff --git a/lib/framework/init_route.py b/lib/framework/init_route.py index 9e25526..f692048 100644 --- a/lib/framework/init_route.py +++ b/lib/framework/init_route.py @@ -4,7 +4,6 @@ import traceback from flask import (jsonify, redirect, render_template, request, send_from_directory) from flask_login import login_required - from framework import F @@ -86,27 +85,31 @@ def open_file(path): @F.app.route("/file/") @F.check_api def file2(path): - # 윈도우 drive 필요 없음 + import platform + if platform.system() == 'Windows': + path = os.path.splitdrive(path)[1][1:] return send_from_directory('/', path, as_attachment=True) @F.app.route("/upload", methods=['GET', 'POST']) +@login_required def upload(): try: if request.method == 'POST': f = request.files['file'] - from werkzeug import secure_filename + from werkzeug.utils import secure_filename upload_path = F.SystemModelSetting.get('path_upload') os.makedirs(upload_path, exist_ok=True) f.save(os.path.join(upload_path, secure_filename(f.filename))) return jsonify('success') - except Exception as exception: - F.logger.error('Exception:%s', exception) + except Exception as e: + F.logger.error(f"Exception:{str(e)}") F.logger.error(traceback.format_exc()) return jsonify('fail') @F.app.route("/videojs", methods=['GET', 'POST']) +@login_required def videojs(): data = {} data['play_title'] = request.form['play_title'] @@ -116,9 +119,33 @@ def videojs(): data['play_subtitle_src'] = request.form['play_subtitle_src'] return render_template('videojs.html', data=data) +@F.app.route("/videojs_drm", methods=['GET', 'POST']) +@login_required +def videojs_drm(): + data = {} + data['play_title'] = request.form['play_title'] + data['play_source_src'] = request.form['play_source_src'] + data['play_source_type'] = request.form['play_source_type'] + if 'play_subtitle_src' in request.form: + data['play_subtitle_src'] = request.form['play_subtitle_src'] + return render_template('videojs_drm.html', data=data) + +@F.app.route("/videojs_discord", methods=['GET', 'POST']) +@login_required +def videojs_og(): + data = {} + """ + data['play_title'] = request.form['play_title'] + data['play_source_src'] = request.form['play_source_src'] + data['play_source_type'] = request.form['play_source_type'] + if 'play_subtitle_src' in request.form: + data['play_subtitle_src'] = request.form['play_subtitle_src'] + """ + return render_template('videojs_discord.html', data=data) @F.app.route("/headers", methods=['GET', 'POST']) +@login_required def headers(): from support import d F.logger.info(d(request.headers)) @@ -127,6 +154,7 @@ def headers(): # 3.10에서 이거 필수 @F.socketio.on('connect', namespace=f'/framework') +@login_required def connect(): pass diff --git a/lib/framework/init_web.py b/lib/framework/init_web.py index 12ba665..977f37f 100644 --- a/lib/framework/init_web.py +++ b/lib/framework/init_web.py @@ -4,6 +4,10 @@ from framework import F def get_menu(full_query): + match = re.compile(r'\/(?P.*?)\/(?P.*?)\/manual\/(?P.*?)($|\?)').match(full_query) + if match: + return match.group('package_name'), match.group('module_name'), f"manual/{match.group('sub2')}" + match = re.compile(r'\/(?P.*?)\/manual\/(?P.*?)($|\?)').match(full_query) if match: return match.group('menu'), 'manual', match.group('sub2') @@ -48,12 +52,14 @@ def jinja_initialize(app): app.jinja_env.globals.update(get_menu=get_menu) app.jinja_env.globals.update(get_theme=get_theme) app.jinja_env.globals.update(get_menu_map=MenuManager.get_menu_map) + app.jinja_env.globals.update(get_setting_menu=MenuManager.get_setting_menu) app.jinja_env.globals.update(get_web_title=get_web_title) app.jinja_env.globals.update(dropzone=F.dropzone) app.jinja_env.filters['get_menu'] = get_menu app.jinja_env.filters['get_theme'] = get_theme app.jinja_env.filters['get_menu_map'] = MenuManager.get_menu_map + app.jinja_env.filters['get_setting_menu'] = MenuManager.get_setting_menu app.jinja_env.filters['get_web_title'] = get_web_title app.jinja_env.auto_reload = True diff --git a/lib/framework/log_viewer.py b/lib/framework/log_viewer.py index d8b63ee..77c905b 100644 --- a/lib/framework/log_viewer.py +++ b/lib/framework/log_viewer.py @@ -4,17 +4,18 @@ import time import traceback from flask import request -from support import SingletonClass - from framework import F +from support import SingletonClass namespace = 'log' @F.socketio.on('connect', namespace='/%s' % namespace) +@F.login_required def socket_connect(): F.logger.debug('log connect') @F.socketio.on('start', namespace='/%s' % namespace) +@F.login_required def socket_file(data): try: package = filename = None @@ -24,8 +25,8 @@ def socket_file(data): filename = data['filename'] LogViewer.instance().start(package, filename, request.sid) F.logger.debug('start package:%s filename:%s sid:%s', package, filename, request.sid) - except Exception as exception: - F.logger.error('Exception:%s', exception) + except Exception as e: + F.logger.error(f"Exception:{str(e)}") F.logger.error(traceback.format_exc()) @F.socketio.on('disconnect', namespace='/%s' % namespace) @@ -33,8 +34,8 @@ def disconnect(): try: LogViewer.instance().disconnect(request.sid) F.logger.debug('disconnect sid:%s', request.sid) - except Exception as exception: - F.logger.error('Exception:%s', exception) + except Exception as e: + F.logger.error(f"Exception:{str(e)}") F.logger.error(traceback.format_exc()) @@ -62,18 +63,17 @@ class WatchThread(threading.Thread): key = 'filename' value = self.filename if os.path.exists(logfile): - with open(logfile, 'r') as f: + with open(logfile, 'r', encoding='utf8') as f: f.seek(0, os.SEEK_END) while not self.stop_flag: line = f.readline() if not line: time.sleep(0.1) # Sleep briefly continue - F.socketio.emit("add", {key : value, 'data': line}, namespace='/log', broadcast=True) + F.socketio.emit("add", {key : value, 'data': line}, namespace='/log') F.logger.debug('WatchThread.. End %s', value) else: - F.socketio.emit("add", {key : value, 'data': 'not exist logfile'}, namespace='/log', broadcast=True) - + F.socketio.emit("add", {key : value, 'data': 'not exist logfile'}, namespace='/log') class LogViewer(SingletonClass): diff --git a/lib/framework/scheduler.py b/lib/framework/scheduler.py index 722e972..5c6115b 100644 --- a/lib/framework/scheduler.py +++ b/lib/framework/scheduler.py @@ -49,8 +49,8 @@ class Scheduler(object): if flag_exit: self.remove_job("scheduler_check") #time.sleep(30) - except Exception as exception: - self.logger.error('Exception:%s', exception) + except Exception as e: + self.logger.error(f"Exception:{str(e)}") self.logger.error(traceback.format_exc()) def shutdown(self): @@ -233,21 +233,21 @@ class Job(object): if self.args is None: self.thread = threading.Thread(target=self.target_function, args=()) else: - self.thread = threading.Thread(target=self.target_function, args=(self.args,)) + self.thread = threading.Thread(target=self.target_function, args=self.args) self.thread.daemon = True self.thread.start() - F.socketio.emit('notify', {'type':'success', 'msg':f"{self.description}
작업을 시작합니다." }, namespace='/framework', broadcast=True) + F.socketio.emit('notify', {'type':'success', 'msg':f"{self.description}
작업을 시작합니다." }, namespace='/framework') self.thread.join() - F.socketio.emit('notify', {'type':'success', 'msg':f"{self.description}
작업이 종료되었습니다." }, namespace='/framework', broadcast=True) + F.socketio.emit('notify', {'type':'success', 'msg':f"{self.description}
작업이 종료되었습니다." }, namespace='/framework') self.end_time = datetime.now(timezone('Asia/Seoul')) self.running_timedelta = self.end_time - self.start_time self.status = 'success' if not F.scheduler.is_include(self.job_id): F.scheduler.remove_job_instance(self.job_id) self.count += 1 - except Exception as exception: + except Exception as e: self.status = 'exception' - F.logger.error('Exception:%s', exception) + F.logger.error(f"Exception:{str(e)}") F.logger.error(traceback.format_exc()) finally: self.is_running = False diff --git a/lib/framework/static/.DS_Store b/lib/framework/static/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..003c9791575ef6939b69d71eecde9e62bd9f14ce GIT binary patch literal 6148 zcmeHKPfNov6i>EkSBB7og5CmNCvHRBhL=+37qFrSmD$=ci(NC;%^k*|cl|Y-<8N%p2 z92?(X2V8rZ#cafe;r#3RlQ^3;8Xvq=u54{vmTlFnd;dw!{b?|rWnM73#nF|NNm%GX zcpVSseP{Pvrqdu!2NRVLM*|4CyNT0C&OJFxqfF)c+F{#OyYCz<7VS>6E{@ur(`8*O zx~)cCoOD~urCr@SJU+YZKPRJ9zG^->(5+<0U;%HSnC(Q_V-mvhFw~e{{7IU~bO@GW zf+CTS7$63S0b*ct7%+E0wYE81rkxT4#J~?3!1F;sLv#)18r9JOohktUD_~XvI@S`H zBMiC*bB*8u;W`yir*czbaGefzVd7kaxkjDNxG6rk`EpUbaP@VVU#M`#U5(Te1H`~8 z16cclIC%eGz%R45$X6lM5d*})e`SDIdVbG?-I=@f+dlEG70@1_p + + + + + + + + \ No newline at end of file diff --git a/lib/framework/static/js/chartjs-utils.js b/lib/framework/static/js/chartjs-utils.js new file mode 100644 index 0000000..c201b7f --- /dev/null +++ b/lib/framework/static/js/chartjs-utils.js @@ -0,0 +1,3845 @@ +/*! For license information please see chart-utils.min.js.LICENSE.txt */ +;(() => { + "use strict" + function t(t) { + return (t + 0.5) | 0 + } + const e = (t, e, n) => Math.max(Math.min(t, n), e) + function n(n) { + return e(t(2.55 * n), 0, 255) + } + function r(n) { + return e(t(255 * n), 0, 255) + } + function s(n) { + return e(t(n / 2.55) / 100, 0, 1) + } + function i(n) { + return e(t(100 * n), 0, 100) + } + const a = { + 0: 0, + 1: 1, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + 6: 6, + 7: 7, + 8: 8, + 9: 9, + A: 10, + B: 11, + C: 12, + D: 13, + E: 14, + F: 15, + a: 10, + b: 11, + c: 12, + d: 13, + e: 14, + f: 15, + }, + o = [..."0123456789ABCDEF"], + u = (t) => o[15 & t], + l = (t) => o[(240 & t) >> 4] + o[15 & t], + c = (t) => (240 & t) >> 4 == (15 & t) + const h = + /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/ + function d(t, e, n) { + const r = e * Math.min(n, 1 - n), + s = (e, s = (e + t / 30) % 12) => n - r * Math.max(Math.min(s - 3, 9 - s, 1), -1) + return [s(0), s(8), s(4)] + } + function f(t, e, n) { + const r = (r, s = (r + t / 60) % 6) => n - n * e * Math.max(Math.min(s, 4 - s, 1), 0) + return [r(5), r(3), r(1)] + } + function m(t, e, n) { + const r = d(t, 1, 0.5) + let s + for (e + n > 1 && ((s = 1 / (e + n)), (e *= s), (n *= s)), s = 0; s < 3; s++) + (r[s] *= 1 - e - n), (r[s] += e) + return r + } + function y(t) { + const e = t.r / 255, + n = t.g / 255, + r = t.b / 255, + s = Math.max(e, n, r), + i = Math.min(e, n, r), + a = (s + i) / 2 + let o, u, l + return ( + s !== i && + ((l = s - i), + (u = a > 0.5 ? l / (2 - s - i) : l / (s + i)), + (o = (function (t, e, n, r, s) { + return t === s + ? (e - n) / r + (e < n ? 6 : 0) + : e === s + ? (n - t) / r + 2 + : (t - e) / r + 4 + })(e, n, r, l, s)), + (o = 60 * o + 0.5)), + [0 | o, u || 0, a] + ) + } + function g(t, e, n, s) { + return (Array.isArray(e) ? t(e[0], e[1], e[2]) : t(e, n, s)).map(r) + } + function p(t, e, n) { + return g(d, t, e, n) + } + function w(t) { + return ((t % 360) + 360) % 360 + } + const b = { + x: "dark", + Z: "light", + Y: "re", + X: "blu", + W: "gr", + V: "medium", + U: "slate", + A: "ee", + T: "ol", + S: "or", + B: "ra", + C: "lateg", + D: "ights", + R: "in", + Q: "turquois", + E: "hi", + P: "ro", + O: "al", + N: "le", + M: "de", + L: "yello", + F: "en", + K: "ch", + G: "arks", + H: "ea", + I: "ightg", + J: "wh", + }, + v = { + OiceXe: "f0f8ff", + antiquewEte: "faebd7", + aqua: "ffff", + aquamarRe: "7fffd4", + azuY: "f0ffff", + beige: "f5f5dc", + bisque: "ffe4c4", + black: "0", + blanKedOmond: "ffebcd", + Xe: "ff", + XeviTet: "8a2be2", + bPwn: "a52a2a", + burlywood: "deb887", + caMtXe: "5f9ea0", + KartYuse: "7fff00", + KocTate: "d2691e", + cSO: "ff7f50", + cSnflowerXe: "6495ed", + cSnsilk: "fff8dc", + crimson: "dc143c", + cyan: "ffff", + xXe: "8b", + xcyan: "8b8b", + xgTMnPd: "b8860b", + xWay: "a9a9a9", + xgYF: "6400", + xgYy: "a9a9a9", + xkhaki: "bdb76b", + xmagFta: "8b008b", + xTivegYF: "556b2f", + xSange: "ff8c00", + xScEd: "9932cc", + xYd: "8b0000", + xsOmon: "e9967a", + xsHgYF: "8fbc8f", + xUXe: "483d8b", + xUWay: "2f4f4f", + xUgYy: "2f4f4f", + xQe: "ced1", + xviTet: "9400d3", + dAppRk: "ff1493", + dApskyXe: "bfff", + dimWay: "696969", + dimgYy: "696969", + dodgerXe: "1e90ff", + fiYbrick: "b22222", + flSOwEte: "fffaf0", + foYstWAn: "228b22", + fuKsia: "ff00ff", + gaRsbSo: "dcdcdc", + ghostwEte: "f8f8ff", + gTd: "ffd700", + gTMnPd: "daa520", + Way: "808080", + gYF: "8000", + gYFLw: "adff2f", + gYy: "808080", + honeyMw: "f0fff0", + hotpRk: "ff69b4", + RdianYd: "cd5c5c", + Rdigo: "4b0082", + ivSy: "fffff0", + khaki: "f0e68c", + lavFMr: "e6e6fa", + lavFMrXsh: "fff0f5", + lawngYF: "7cfc00", + NmoncEffon: "fffacd", + ZXe: "add8e6", + ZcSO: "f08080", + Zcyan: "e0ffff", + ZgTMnPdLw: "fafad2", + ZWay: "d3d3d3", + ZgYF: "90ee90", + ZgYy: "d3d3d3", + ZpRk: "ffb6c1", + ZsOmon: "ffa07a", + ZsHgYF: "20b2aa", + ZskyXe: "87cefa", + ZUWay: "778899", + ZUgYy: "778899", + ZstAlXe: "b0c4de", + ZLw: "ffffe0", + lime: "ff00", + limegYF: "32cd32", + lRF: "faf0e6", + magFta: "ff00ff", + maPon: "800000", + VaquamarRe: "66cdaa", + VXe: "cd", + VScEd: "ba55d3", + VpurpN: "9370db", + VsHgYF: "3cb371", + VUXe: "7b68ee", + VsprRggYF: "fa9a", + VQe: "48d1cc", + VviTetYd: "c71585", + midnightXe: "191970", + mRtcYam: "f5fffa", + mistyPse: "ffe4e1", + moccasR: "ffe4b5", + navajowEte: "ffdead", + navy: "80", + Tdlace: "fdf5e6", + Tive: "808000", + TivedBb: "6b8e23", + Sange: "ffa500", + SangeYd: "ff4500", + ScEd: "da70d6", + pOegTMnPd: "eee8aa", + pOegYF: "98fb98", + pOeQe: "afeeee", + pOeviTetYd: "db7093", + papayawEp: "ffefd5", + pHKpuff: "ffdab9", + peru: "cd853f", + pRk: "ffc0cb", + plum: "dda0dd", + powMrXe: "b0e0e6", + purpN: "800080", + YbeccapurpN: "663399", + Yd: "ff0000", + Psybrown: "bc8f8f", + PyOXe: "4169e1", + saddNbPwn: "8b4513", + sOmon: "fa8072", + sandybPwn: "f4a460", + sHgYF: "2e8b57", + sHshell: "fff5ee", + siFna: "a0522d", + silver: "c0c0c0", + skyXe: "87ceeb", + UXe: "6a5acd", + UWay: "708090", + UgYy: "708090", + snow: "fffafa", + sprRggYF: "ff7f", + stAlXe: "4682b4", + tan: "d2b48c", + teO: "8080", + tEstN: "d8bfd8", + tomato: "ff6347", + Qe: "40e0d0", + viTet: "ee82ee", + JHt: "f5deb3", + wEte: "ffffff", + wEtesmoke: "f5f5f5", + Lw: "ffff00", + LwgYF: "9acd32", + } + let O + const S = + /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/, + T = (t) => (t <= 0.0031308 ? 12.92 * t : 1.055 * Math.pow(t, 1 / 2.4) - 0.055), + M = (t) => (t <= 0.04045 ? t / 12.92 : Math.pow((t + 0.055) / 1.055, 2.4)) + function k(t, e, n) { + if (t) { + let r = y(t) + ;(r[e] = Math.max(0, Math.min(r[e] + r[e] * n, 0 === e ? 360 : 1))), + (r = p(r)), + (t.r = r[0]), + (t.g = r[1]), + (t.b = r[2]) + } + } + function N(t, e) { + return t ? Object.assign(e || {}, t) : t + } + function D(t) { + var e = { r: 0, g: 0, b: 0, a: 255 } + return ( + Array.isArray(t) + ? t.length >= 3 && + ((e = { r: t[0], g: t[1], b: t[2], a: 255 }), t.length > 3 && (e.a = r(t[3]))) + : ((e = N(t, { r: 0, g: 0, b: 0, a: 1 })).a = r(e.a)), + e + ) + } + function E(t) { + return "r" === t.charAt(0) + ? (function (t) { + const r = S.exec(t) + let s, + i, + a, + o = 255 + if (r) { + if (r[7] !== s) { + const t = +r[7] + o = r[8] ? n(t) : e(255 * t, 0, 255) + } + return ( + (s = +r[1]), + (i = +r[3]), + (a = +r[5]), + (s = 255 & (r[2] ? n(s) : e(s, 0, 255))), + (i = 255 & (r[4] ? n(i) : e(i, 0, 255))), + (a = 255 & (r[6] ? n(a) : e(a, 0, 255))), + { r: s, g: i, b: a, a: o } + ) + } + })(t) + : (function (t) { + const e = h.exec(t) + let s, + i = 255 + if (!e) return + e[5] !== s && (i = e[6] ? n(+e[5]) : r(+e[5])) + const a = w(+e[2]), + o = +e[3] / 100, + u = +e[4] / 100 + return ( + (s = + "hwb" === e[1] + ? (function (t, e, n) { + return g(m, t, e, n) + })(a, o, u) + : "hsv" === e[1] + ? (function (t, e, n) { + return g(f, t, e, n) + })(a, o, u) + : p(a, o, u)), + { r: s[0], g: s[1], b: s[2], a: i } + ) + })(t) + } + class x { + constructor(t) { + if (t instanceof x) return t + const e = typeof t + let n + var r, s, i + "object" === e + ? (n = D(t)) + : "string" === e && + ((i = (r = t).length), + "#" === r[0] && + (4 === i || 5 === i + ? (s = { + r: 255 & (17 * a[r[1]]), + g: 255 & (17 * a[r[2]]), + b: 255 & (17 * a[r[3]]), + a: 5 === i ? 17 * a[r[4]] : 255, + }) + : (7 !== i && 9 !== i) || + (s = { + r: (a[r[1]] << 4) | a[r[2]], + g: (a[r[3]] << 4) | a[r[4]], + b: (a[r[5]] << 4) | a[r[6]], + a: 9 === i ? (a[r[7]] << 4) | a[r[8]] : 255, + })), + (n = + s || + (function (t) { + O || + ((O = (function () { + const t = {}, + e = Object.keys(v), + n = Object.keys(b) + let r, s, i, a, o + for (r = 0; r < e.length; r++) { + for (a = o = e[r], s = 0; s < n.length; s++) + (i = n[s]), (o = o.replace(i, b[i])) + ;(i = parseInt(v[a], 16)), (t[o] = [(i >> 16) & 255, (i >> 8) & 255, 255 & i]) + } + return t + })()), + (O.transparent = [0, 0, 0, 0])) + const e = O[t.toLowerCase()] + return e && { r: e[0], g: e[1], b: e[2], a: 4 === e.length ? e[3] : 255 } + })(t) || + E(t))), + (this._rgb = n), + (this._valid = !!n) + } + get valid() { + return this._valid + } + get rgb() { + var t = N(this._rgb) + return t && (t.a = s(t.a)), t + } + set rgb(t) { + this._rgb = D(t) + } + rgbString() { + return this._valid + ? (t = this._rgb) && + (t.a < 255 ? `rgba(${t.r}, ${t.g}, ${t.b}, ${s(t.a)})` : `rgb(${t.r}, ${t.g}, ${t.b})`) + : void 0 + var t + } + hexString() { + return this._valid + ? ((t = this._rgb), + (e = ((t) => c(t.r) && c(t.g) && c(t.b) && c(t.a))(t) ? u : l), + t ? "#" + e(t.r) + e(t.g) + e(t.b) + ((t, e) => (t < 255 ? e(t) : ""))(t.a, e) : void 0) + : void 0 + var t, e + } + hslString() { + return this._valid + ? (function (t) { + if (!t) return + const e = y(t), + n = e[0], + r = i(e[1]), + a = i(e[2]) + return t.a < 255 ? `hsla(${n}, ${r}%, ${a}%, ${s(t.a)})` : `hsl(${n}, ${r}%, ${a}%)` + })(this._rgb) + : void 0 + } + mix(t, e) { + if (t) { + const n = this.rgb, + r = t.rgb + let s + const i = e === s ? 0.5 : e, + a = 2 * i - 1, + o = n.a - r.a, + u = ((a * o == -1 ? a : (a + o) / (1 + a * o)) + 1) / 2 + ;(s = 1 - u), + (n.r = 255 & (u * n.r + s * r.r + 0.5)), + (n.g = 255 & (u * n.g + s * r.g + 0.5)), + (n.b = 255 & (u * n.b + s * r.b + 0.5)), + (n.a = i * n.a + (1 - i) * r.a), + (this.rgb = n) + } + return this + } + interpolate(t, e) { + return ( + t && + (this._rgb = (function (t, e, n) { + const i = M(s(t.r)), + a = M(s(t.g)), + o = M(s(t.b)) + return { + r: r(T(i + n * (M(s(e.r)) - i))), + g: r(T(a + n * (M(s(e.g)) - a))), + b: r(T(o + n * (M(s(e.b)) - o))), + a: t.a + n * (e.a - t.a), + } + })(this._rgb, t._rgb, e)), + this + ) + } + clone() { + return new x(this.rgb) + } + alpha(t) { + return (this._rgb.a = r(t)), this + } + clearer(t) { + return (this._rgb.a *= 1 - t), this + } + greyscale() { + const e = this._rgb, + n = t(0.3 * e.r + 0.59 * e.g + 0.11 * e.b) + return (e.r = e.g = e.b = n), this + } + opaquer(t) { + return (this._rgb.a *= 1 + t), this + } + negate() { + const t = this._rgb + return (t.r = 255 - t.r), (t.g = 255 - t.g), (t.b = 255 - t.b), this + } + lighten(t) { + return k(this._rgb, 2, t), this + } + darken(t) { + return k(this._rgb, 2, -t), this + } + saturate(t) { + return k(this._rgb, 1, t), this + } + desaturate(t) { + return k(this._rgb, 1, -t), this + } + rotate(t) { + return ( + (function (t, e) { + var n = y(t) + ;(n[0] = w(n[0] + e)), (n = p(n)), (t.r = n[0]), (t.g = n[1]), (t.b = n[2]) + })(this._rgb, t), + this + ) + } + } + class C extends Error {} + class V extends C { + constructor(t) { + super(`Invalid DateTime: ${t.toMessage()}`) + } + } + class F extends C { + constructor(t) { + super(`Invalid Interval: ${t.toMessage()}`) + } + } + class I extends C { + constructor(t) { + super(`Invalid Duration: ${t.toMessage()}`) + } + } + class L extends C {} + class Z extends C { + constructor(t) { + super(`Invalid unit ${t}`) + } + } + class $ extends C {} + class _ extends C { + constructor() { + super("Zone is an abstract class") + } + } + const A = "numeric", + R = "short", + z = "long", + q = { year: A, month: A, day: A }, + Y = { year: A, month: R, day: A }, + j = { year: A, month: R, day: A, weekday: R }, + H = { year: A, month: z, day: A }, + U = { year: A, month: z, day: A, weekday: z }, + W = { hour: A, minute: A }, + P = { hour: A, minute: A, second: A }, + J = { hour: A, minute: A, second: A, timeZoneName: R }, + G = { hour: A, minute: A, second: A, timeZoneName: z }, + X = { hour: A, minute: A, hourCycle: "h23" }, + B = { hour: A, minute: A, second: A, hourCycle: "h23" }, + Q = { hour: A, minute: A, second: A, hourCycle: "h23", timeZoneName: R }, + K = { hour: A, minute: A, second: A, hourCycle: "h23", timeZoneName: z }, + tt = { year: A, month: A, day: A, hour: A, minute: A }, + et = { year: A, month: A, day: A, hour: A, minute: A, second: A }, + nt = { year: A, month: R, day: A, hour: A, minute: A }, + rt = { year: A, month: R, day: A, hour: A, minute: A, second: A }, + st = { year: A, month: R, day: A, weekday: R, hour: A, minute: A }, + it = { year: A, month: z, day: A, hour: A, minute: A, timeZoneName: R }, + at = { year: A, month: z, day: A, hour: A, minute: A, second: A, timeZoneName: R }, + ot = { year: A, month: z, day: A, weekday: z, hour: A, minute: A, timeZoneName: z }, + ut = { year: A, month: z, day: A, weekday: z, hour: A, minute: A, second: A, timeZoneName: z } + function lt(t) { + return void 0 === t + } + function ct(t) { + return "number" == typeof t + } + function ht(t) { + return "number" == typeof t && t % 1 == 0 + } + function dt() { + try { + return "undefined" != typeof Intl && !!Intl.RelativeTimeFormat + } catch (t) { + return !1 + } + } + function ft(t, e, n) { + if (0 !== t.length) + return t.reduce((t, r) => { + const s = [e(r), r] + return t && n(t[0], s[0]) === t[0] ? t : s + }, null)[1] + } + function mt(t, e) { + return Object.prototype.hasOwnProperty.call(t, e) + } + function yt(t, e, n) { + return ht(t) && t >= e && t <= n + } + function gt(t, e = 2) { + let n + return (n = t < 0 ? "-" + ("" + -t).padStart(e, "0") : ("" + t).padStart(e, "0")), n + } + function pt(t) { + return lt(t) || null === t || "" === t ? void 0 : parseInt(t, 10) + } + function wt(t) { + return lt(t) || null === t || "" === t ? void 0 : parseFloat(t) + } + function bt(t) { + if (!lt(t) && null !== t && "" !== t) { + const e = 1e3 * parseFloat("0." + t) + return Math.floor(e) + } + } + function vt(t, e, n = !1) { + const r = 10 ** e + return (n ? Math.trunc : Math.round)(t * r) / r + } + function Ot(t) { + return t % 4 == 0 && (t % 100 != 0 || t % 400 == 0) + } + function St(t) { + return Ot(t) ? 366 : 365 + } + function Tt(t, e) { + const n = (r = e - 1) - 12 * Math.floor(r / 12) + 1 + var r + return 2 === n + ? Ot(t + (e - n) / 12) + ? 29 + : 28 + : [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][n - 1] + } + function Mt(t) { + let e = Date.UTC(t.year, t.month - 1, t.day, t.hour, t.minute, t.second, t.millisecond) + return ( + t.year < 100 && + t.year >= 0 && + ((e = new Date(e)), e.setUTCFullYear(e.getUTCFullYear() - 1900)), + +e + ) + } + function kt(t) { + const e = (t + Math.floor(t / 4) - Math.floor(t / 100) + Math.floor(t / 400)) % 7, + n = t - 1, + r = (n + Math.floor(n / 4) - Math.floor(n / 100) + Math.floor(n / 400)) % 7 + return 4 === e || 3 === r ? 53 : 52 + } + function Nt(t) { + return t > 99 ? t : t > 60 ? 1900 + t : 2e3 + t + } + function Dt(t, e, n, r = null) { + const s = new Date(t), + i = { + hourCycle: "h23", + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + } + r && (i.timeZone = r) + const a = { timeZoneName: e, ...i }, + o = new Intl.DateTimeFormat(n, a) + .formatToParts(s) + .find((t) => "timezonename" === t.type.toLowerCase()) + return o ? o.value : null + } + function Et(t, e) { + let n = parseInt(t, 10) + Number.isNaN(n) && (n = 0) + const r = parseInt(e, 10) || 0 + return 60 * n + (n < 0 || Object.is(n, -0) ? -r : r) + } + function xt(t) { + const e = Number(t) + if ("boolean" == typeof t || "" === t || Number.isNaN(e)) throw new $(`Invalid unit value ${t}`) + return e + } + function Ct(t, e) { + const n = {} + for (const r in t) + if (mt(t, r)) { + const s = t[r] + if (null == s) continue + n[e(r)] = xt(s) + } + return n + } + function Vt(t, e) { + const n = Math.trunc(Math.abs(t / 60)), + r = Math.trunc(Math.abs(t % 60)), + s = t >= 0 ? "+" : "-" + switch (e) { + case "short": + return `${s}${gt(n, 2)}:${gt(r, 2)}` + case "narrow": + return `${s}${n}${r > 0 ? `:${r}` : ""}` + case "techie": + return `${s}${gt(n, 2)}${gt(r, 2)}` + default: + throw new RangeError(`Value format ${e} is out of range for property format`) + } + } + function Ft(t) { + return (function (t, e) { + return ["hour", "minute", "second", "millisecond"].reduce((e, n) => ((e[n] = t[n]), e), {}) + })(t) + } + const It = /[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/, + Lt = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ], + Zt = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + $t = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"] + function _t(t) { + switch (t) { + case "narrow": + return [...$t] + case "short": + return [...Zt] + case "long": + return [...Lt] + case "numeric": + return ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"] + case "2-digit": + return ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"] + default: + return null + } + } + const At = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], + Rt = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], + zt = ["M", "T", "W", "T", "F", "S", "S"] + function qt(t) { + switch (t) { + case "narrow": + return [...zt] + case "short": + return [...Rt] + case "long": + return [...At] + case "numeric": + return ["1", "2", "3", "4", "5", "6", "7"] + default: + return null + } + } + const Yt = ["AM", "PM"], + jt = ["Before Christ", "Anno Domini"], + Ht = ["BC", "AD"], + Ut = ["B", "A"] + function Wt(t) { + switch (t) { + case "narrow": + return [...Ut] + case "short": + return [...Ht] + case "long": + return [...jt] + default: + return null + } + } + function Pt(t, e) { + let n = "" + for (const r of t) r.literal ? (n += r.val) : (n += e(r.val)) + return n + } + const Jt = { + D: q, + DD: Y, + DDD: H, + DDDD: U, + t: W, + tt: P, + ttt: J, + tttt: G, + T: X, + TT: B, + TTT: Q, + TTTT: K, + f: tt, + ff: nt, + fff: it, + ffff: ot, + F: et, + FF: rt, + FFF: at, + FFFF: ut, + } + class Gt { + static create(t, e = {}) { + return new Gt(t, e) + } + static parseFormat(t) { + let e = null, + n = "", + r = !1 + const s = [] + for (let i = 0; i < t.length; i++) { + const a = t.charAt(i) + "'" === a + ? (n.length > 0 && s.push({ literal: r, val: n }), (e = null), (n = ""), (r = !r)) + : r || a === e + ? (n += a) + : (n.length > 0 && s.push({ literal: !1, val: n }), (n = a), (e = a)) + } + return n.length > 0 && s.push({ literal: r, val: n }), s + } + static macroTokenToFormatOpts(t) { + return Jt[t] + } + constructor(t, e) { + ;(this.opts = e), (this.loc = t), (this.systemLoc = null) + } + formatWithSystemDefault(t, e) { + return ( + null === this.systemLoc && (this.systemLoc = this.loc.redefaultToSystem()), + this.systemLoc.dtFormatter(t, { ...this.opts, ...e }).format() + ) + } + formatDateTime(t, e = {}) { + return this.loc.dtFormatter(t, { ...this.opts, ...e }).format() + } + formatDateTimeParts(t, e = {}) { + return this.loc.dtFormatter(t, { ...this.opts, ...e }).formatToParts() + } + resolvedOptions(t, e = {}) { + return this.loc.dtFormatter(t, { ...this.opts, ...e }).resolvedOptions() + } + num(t, e = 0) { + if (this.opts.forceSimple) return gt(t, e) + const n = { ...this.opts } + return e > 0 && (n.padTo = e), this.loc.numberFormatter(n).format(t) + } + formatDateTimeFromString(t, e) { + const n = "en" === this.loc.listingMode(), + r = this.loc.outputCalendar && "gregory" !== this.loc.outputCalendar, + s = (e, n) => this.loc.extract(t, e, n), + i = (e) => + t.isOffsetFixed && 0 === t.offset && e.allowZ + ? "Z" + : t.isValid + ? t.zone.formatOffset(t.ts, e.format) + : "", + a = (e, r) => + n + ? (function (t, e) { + return _t(e)[t.month - 1] + })(t, e) + : s(r ? { month: e } : { month: e, day: "numeric" }, "month"), + o = (e, r) => + n + ? (function (t, e) { + return qt(e)[t.weekday - 1] + })(t, e) + : s(r ? { weekday: e } : { weekday: e, month: "long", day: "numeric" }, "weekday"), + u = (e) => { + const n = Gt.macroTokenToFormatOpts(e) + return n ? this.formatWithSystemDefault(t, n) : e + }, + l = (e) => + n + ? (function (t, e) { + return Wt(e)[t.year < 0 ? 0 : 1] + })(t, e) + : s({ era: e }, "era") + return Pt(Gt.parseFormat(e), (e) => { + switch (e) { + case "S": + return this.num(t.millisecond) + case "u": + case "SSS": + return this.num(t.millisecond, 3) + case "s": + return this.num(t.second) + case "ss": + return this.num(t.second, 2) + case "uu": + return this.num(Math.floor(t.millisecond / 10), 2) + case "uuu": + return this.num(Math.floor(t.millisecond / 100)) + case "m": + return this.num(t.minute) + case "mm": + return this.num(t.minute, 2) + case "h": + return this.num(t.hour % 12 == 0 ? 12 : t.hour % 12) + case "hh": + return this.num(t.hour % 12 == 0 ? 12 : t.hour % 12, 2) + case "H": + return this.num(t.hour) + case "HH": + return this.num(t.hour, 2) + case "Z": + return i({ format: "narrow", allowZ: this.opts.allowZ }) + case "ZZ": + return i({ format: "short", allowZ: this.opts.allowZ }) + case "ZZZ": + return i({ format: "techie", allowZ: this.opts.allowZ }) + case "ZZZZ": + return t.zone.offsetName(t.ts, { format: "short", locale: this.loc.locale }) + case "ZZZZZ": + return t.zone.offsetName(t.ts, { format: "long", locale: this.loc.locale }) + case "z": + return t.zoneName + case "a": + return n + ? (function (t) { + return Yt[t.hour < 12 ? 0 : 1] + })(t) + : s({ hour: "numeric", hourCycle: "h12" }, "dayperiod") + case "d": + return r ? s({ day: "numeric" }, "day") : this.num(t.day) + case "dd": + return r ? s({ day: "2-digit" }, "day") : this.num(t.day, 2) + case "c": + case "E": + return this.num(t.weekday) + case "ccc": + return o("short", !0) + case "cccc": + return o("long", !0) + case "ccccc": + return o("narrow", !0) + case "EEE": + return o("short", !1) + case "EEEE": + return o("long", !1) + case "EEEEE": + return o("narrow", !1) + case "L": + return r ? s({ month: "numeric", day: "numeric" }, "month") : this.num(t.month) + case "LL": + return r ? s({ month: "2-digit", day: "numeric" }, "month") : this.num(t.month, 2) + case "LLL": + return a("short", !0) + case "LLLL": + return a("long", !0) + case "LLLLL": + return a("narrow", !0) + case "M": + return r ? s({ month: "numeric" }, "month") : this.num(t.month) + case "MM": + return r ? s({ month: "2-digit" }, "month") : this.num(t.month, 2) + case "MMM": + return a("short", !1) + case "MMMM": + return a("long", !1) + case "MMMMM": + return a("narrow", !1) + case "y": + return r ? s({ year: "numeric" }, "year") : this.num(t.year) + case "yy": + return r ? s({ year: "2-digit" }, "year") : this.num(t.year.toString().slice(-2), 2) + case "yyyy": + return r ? s({ year: "numeric" }, "year") : this.num(t.year, 4) + case "yyyyyy": + return r ? s({ year: "numeric" }, "year") : this.num(t.year, 6) + case "G": + return l("short") + case "GG": + return l("long") + case "GGGGG": + return l("narrow") + case "kk": + return this.num(t.weekYear.toString().slice(-2), 2) + case "kkkk": + return this.num(t.weekYear, 4) + case "W": + return this.num(t.weekNumber) + case "WW": + return this.num(t.weekNumber, 2) + case "o": + return this.num(t.ordinal) + case "ooo": + return this.num(t.ordinal, 3) + case "q": + return this.num(t.quarter) + case "qq": + return this.num(t.quarter, 2) + case "X": + return this.num(Math.floor(t.ts / 1e3)) + case "x": + return this.num(t.ts) + default: + return u(e) + } + }) + } + formatDurationFromString(t, e) { + const n = (t) => { + switch (t[0]) { + case "S": + return "millisecond" + case "s": + return "second" + case "m": + return "minute" + case "h": + return "hour" + case "d": + return "day" + case "w": + return "week" + case "M": + return "month" + case "y": + return "year" + default: + return null + } + }, + r = Gt.parseFormat(e), + s = r.reduce((t, { literal: e, val: n }) => (e ? t : t.concat(n)), []) + return Pt( + r, + ((t) => (e) => { + const r = n(e) + return r ? this.num(t.get(r), e.length) : e + })(t.shiftTo(...s.map(n).filter((t) => t))) + ) + } + } + class Xt { + constructor(t, e) { + ;(this.reason = t), (this.explanation = e) + } + toMessage() { + return this.explanation ? `${this.reason}: ${this.explanation}` : this.reason + } + } + class Bt { + get type() { + throw new _() + } + get name() { + throw new _() + } + get ianaName() { + return this.name + } + get isUniversal() { + throw new _() + } + offsetName(t, e) { + throw new _() + } + formatOffset(t, e) { + throw new _() + } + offset(t) { + throw new _() + } + equals(t) { + throw new _() + } + get isValid() { + throw new _() + } + } + let Qt = null + class Kt extends Bt { + static get instance() { + return null === Qt && (Qt = new Kt()), Qt + } + get type() { + return "system" + } + get name() { + return new Intl.DateTimeFormat().resolvedOptions().timeZone + } + get isUniversal() { + return !1 + } + offsetName(t, { format: e, locale: n }) { + return Dt(t, e, n) + } + formatOffset(t, e) { + return Vt(this.offset(t), e) + } + offset(t) { + return -new Date(t).getTimezoneOffset() + } + equals(t) { + return "system" === t.type + } + get isValid() { + return !0 + } + } + let te = {} + const ee = { year: 0, month: 1, day: 2, era: 3, hour: 4, minute: 5, second: 6 } + let ne = {} + class re extends Bt { + static create(t) { + return ne[t] || (ne[t] = new re(t)), ne[t] + } + static resetCache() { + ;(ne = {}), (te = {}) + } + static isValidSpecifier(t) { + return this.isValidZone(t) + } + static isValidZone(t) { + if (!t) return !1 + try { + return new Intl.DateTimeFormat("en-US", { timeZone: t }).format(), !0 + } catch (t) { + return !1 + } + } + constructor(t) { + super(), (this.zoneName = t), (this.valid = re.isValidZone(t)) + } + get type() { + return "iana" + } + get name() { + return this.zoneName + } + get isUniversal() { + return !1 + } + offsetName(t, { format: e, locale: n }) { + return Dt(t, e, n, this.name) + } + formatOffset(t, e) { + return Vt(this.offset(t), e) + } + offset(t) { + const e = new Date(t) + if (isNaN(e)) return NaN + const n = + ((r = this.name), + te[r] || + (te[r] = new Intl.DateTimeFormat("en-US", { + hour12: !1, + timeZone: r, + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + era: "short", + })), + te[r]) + var r + let [s, i, a, o, u, l, c] = n.formatToParts + ? (function (t, e) { + const n = t.formatToParts(e), + r = [] + for (let t = 0; t < n.length; t++) { + const { type: e, value: s } = n[t], + i = ee[e] + "era" === e ? (r[i] = s) : lt(i) || (r[i] = parseInt(s, 10)) + } + return r + })(n, e) + : (function (t, e) { + const n = t.format(e).replace(/\u200E/g, ""), + r = /(\d+)\/(\d+)\/(\d+) (AD|BC),? (\d+):(\d+):(\d+)/.exec(n), + [, s, i, a, o, u, l, c] = r + return [a, s, i, o, u, l, c] + })(n, e) + "BC" === o && (s = 1 - Math.abs(s)) + let h = +e + const d = h % 1e3 + return ( + (h -= d >= 0 ? d : 1e3 + d), + (Mt({ + year: s, + month: i, + day: a, + hour: 24 === u ? 0 : u, + minute: l, + second: c, + millisecond: 0, + }) - + h) / + 6e4 + ) + } + equals(t) { + return "iana" === t.type && t.name === this.name + } + get isValid() { + return this.valid + } + } + let se = null + class ie extends Bt { + static get utcInstance() { + return null === se && (se = new ie(0)), se + } + static instance(t) { + return 0 === t ? ie.utcInstance : new ie(t) + } + static parseSpecifier(t) { + if (t) { + const e = t.match(/^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$/i) + if (e) return new ie(Et(e[1], e[2])) + } + return null + } + constructor(t) { + super(), (this.fixed = t) + } + get type() { + return "fixed" + } + get name() { + return 0 === this.fixed ? "UTC" : `UTC${Vt(this.fixed, "narrow")}` + } + get ianaName() { + return 0 === this.fixed ? "Etc/UTC" : `Etc/GMT${Vt(-this.fixed, "narrow")}` + } + offsetName() { + return this.name + } + formatOffset(t, e) { + return Vt(this.fixed, e) + } + get isUniversal() { + return !0 + } + offset() { + return this.fixed + } + equals(t) { + return "fixed" === t.type && t.fixed === this.fixed + } + get isValid() { + return !0 + } + } + class ae extends Bt { + constructor(t) { + super(), (this.zoneName = t) + } + get type() { + return "invalid" + } + get name() { + return this.zoneName + } + get isUniversal() { + return !1 + } + offsetName() { + return null + } + formatOffset() { + return "" + } + offset() { + return NaN + } + equals() { + return !1 + } + get isValid() { + return !1 + } + } + function oe(t, e) { + if (lt(t) || null === t) return e + if (t instanceof Bt) return t + if ("string" == typeof t) { + const n = t.toLowerCase() + return "default" === n + ? e + : "local" === n || "system" === n + ? Kt.instance + : "utc" === n || "gmt" === n + ? ie.utcInstance + : ie.parseSpecifier(n) || re.create(t) + } + return ct(t) + ? ie.instance(t) + : "object" == typeof t && t.offset && "number" == typeof t.offset + ? t + : new ae(t) + } + let ue, + le = () => Date.now(), + ce = "system", + he = null, + de = null, + fe = null + class me { + static get now() { + return le + } + static set now(t) { + le = t + } + static set defaultZone(t) { + ce = t + } + static get defaultZone() { + return oe(ce, Kt.instance) + } + static get defaultLocale() { + return he + } + static set defaultLocale(t) { + he = t + } + static get defaultNumberingSystem() { + return de + } + static set defaultNumberingSystem(t) { + de = t + } + static get defaultOutputCalendar() { + return fe + } + static set defaultOutputCalendar(t) { + fe = t + } + static get throwOnInvalid() { + return ue + } + static set throwOnInvalid(t) { + ue = t + } + static resetCaches() { + ke.resetCache(), re.resetCache() + } + } + let ye = {}, + ge = {} + function pe(t, e = {}) { + const n = JSON.stringify([t, e]) + let r = ge[n] + return r || ((r = new Intl.DateTimeFormat(t, e)), (ge[n] = r)), r + } + let we = {}, + be = {}, + ve = null + function Oe(t, e, n, r, s) { + const i = t.listingMode(n) + return "error" === i ? null : "en" === i ? r(e) : s(e) + } + class Se { + constructor(t, e, n) { + ;(this.padTo = n.padTo || 0), (this.floor = n.floor || !1) + const { padTo: r, floor: s, ...i } = n + if (!e || Object.keys(i).length > 0) { + const e = { useGrouping: !1, ...n } + n.padTo > 0 && (e.minimumIntegerDigits = n.padTo), + (this.inf = (function (t, e = {}) { + const n = JSON.stringify([t, e]) + let r = we[n] + return r || ((r = new Intl.NumberFormat(t, e)), (we[n] = r)), r + })(t, e)) + } + } + format(t) { + if (this.inf) { + const e = this.floor ? Math.floor(t) : t + return this.inf.format(e) + } + return gt(this.floor ? Math.floor(t) : vt(t, 3), this.padTo) + } + } + class Te { + constructor(t, e, n) { + let r + if (((this.opts = n), t.zone.isUniversal)) { + const e = (t.offset / 60) * -1, + s = e >= 0 ? `Etc/GMT+${e}` : `Etc/GMT${e}` + 0 !== t.offset && re.create(s).valid + ? ((r = s), (this.dt = t)) + : ((r = "UTC"), + n.timeZoneName + ? (this.dt = t) + : (this.dt = 0 === t.offset ? t : Sr.fromMillis(t.ts + 60 * t.offset * 1e3))) + } else "system" === t.zone.type ? (this.dt = t) : ((this.dt = t), (r = t.zone.name)) + const s = { ...this.opts } + r && (s.timeZone = r), (this.dtf = pe(e, s)) + } + format() { + return this.dtf.format(this.dt.toJSDate()) + } + formatToParts() { + return this.dtf.formatToParts(this.dt.toJSDate()) + } + resolvedOptions() { + return this.dtf.resolvedOptions() + } + } + class Me { + constructor(t, e, n) { + ;(this.opts = { style: "long", ...n }), + !e && + dt() && + (this.rtf = (function (t, e = {}) { + const { base: n, ...r } = e, + s = JSON.stringify([t, r]) + let i = be[s] + return i || ((i = new Intl.RelativeTimeFormat(t, e)), (be[s] = i)), i + })(t, n)) + } + format(t, e) { + return this.rtf + ? this.rtf.format(t, e) + : (function (t, e, n = "always", r = !1) { + const s = { + years: ["year", "yr."], + quarters: ["quarter", "qtr."], + months: ["month", "mo."], + weeks: ["week", "wk."], + days: ["day", "day", "days"], + hours: ["hour", "hr."], + minutes: ["minute", "min."], + seconds: ["second", "sec."], + }, + i = -1 === ["hours", "minutes", "seconds"].indexOf(t) + if ("auto" === n && i) { + const n = "days" === t + switch (e) { + case 1: + return n ? "tomorrow" : `next ${s[t][0]}` + case -1: + return n ? "yesterday" : `last ${s[t][0]}` + case 0: + return n ? "today" : `this ${s[t][0]}` + } + } + const a = Object.is(e, -0) || e < 0, + o = Math.abs(e), + u = 1 === o, + l = s[t], + c = r ? (u ? l[1] : l[2] || l[1]) : u ? s[t][0] : t + return a ? `${o} ${c} ago` : `in ${o} ${c}` + })(e, t, this.opts.numeric, "long" !== this.opts.style) + } + formatToParts(t, e) { + return this.rtf ? this.rtf.formatToParts(t, e) : [] + } + } + class ke { + static fromOpts(t) { + return ke.create(t.locale, t.numberingSystem, t.outputCalendar, t.defaultToEN) + } + static create(t, e, n, r = !1) { + const s = t || me.defaultLocale, + i = + s || + (r ? "en-US" : ve || ((ve = new Intl.DateTimeFormat().resolvedOptions().locale), ve)), + a = e || me.defaultNumberingSystem, + o = n || me.defaultOutputCalendar + return new ke(i, a, o, s) + } + static resetCache() { + ;(ve = null), (ge = {}), (we = {}), (be = {}) + } + static fromObject({ locale: t, numberingSystem: e, outputCalendar: n } = {}) { + return ke.create(t, e, n) + } + constructor(t, e, n, r) { + const [s, i, a] = (function (t) { + const e = t.indexOf("-u-") + if (-1 === e) return [t] + { + let n + const r = t.substring(0, e) + try { + n = pe(t).resolvedOptions() + } catch (t) { + n = pe(r).resolvedOptions() + } + const { numberingSystem: s, calendar: i } = n + return [r, s, i] + } + })(t) + ;(this.locale = s), + (this.numberingSystem = e || i || null), + (this.outputCalendar = n || a || null), + (this.intl = (function (t, e, n) { + return n || e ? ((t += "-u"), n && (t += `-ca-${n}`), e && (t += `-nu-${e}`), t) : t + })(this.locale, this.numberingSystem, this.outputCalendar)), + (this.weekdaysCache = { format: {}, standalone: {} }), + (this.monthsCache = { format: {}, standalone: {} }), + (this.meridiemCache = null), + (this.eraCache = {}), + (this.specifiedLocale = r), + (this.fastNumbersCached = null) + } + get fastNumbers() { + var t + return ( + null == this.fastNumbersCached && + (this.fastNumbersCached = + (!(t = this).numberingSystem || "latn" === t.numberingSystem) && + ("latn" === t.numberingSystem || + !t.locale || + t.locale.startsWith("en") || + "latn" === new Intl.DateTimeFormat(t.intl).resolvedOptions().numberingSystem)), + this.fastNumbersCached + ) + } + listingMode() { + const t = this.isEnglish(), + e = !( + (null !== this.numberingSystem && "latn" !== this.numberingSystem) || + (null !== this.outputCalendar && "gregory" !== this.outputCalendar) + ) + return t && e ? "en" : "intl" + } + clone(t) { + return t && 0 !== Object.getOwnPropertyNames(t).length + ? ke.create( + t.locale || this.specifiedLocale, + t.numberingSystem || this.numberingSystem, + t.outputCalendar || this.outputCalendar, + t.defaultToEN || !1 + ) + : this + } + redefaultToEN(t = {}) { + return this.clone({ ...t, defaultToEN: !0 }) + } + redefaultToSystem(t = {}) { + return this.clone({ ...t, defaultToEN: !1 }) + } + months(t, e = !1, n = !0) { + return Oe(this, t, n, _t, () => { + const n = e ? { month: t, day: "numeric" } : { month: t }, + r = e ? "format" : "standalone" + return ( + this.monthsCache[r][t] || + (this.monthsCache[r][t] = (function (t) { + const e = [] + for (let n = 1; n <= 12; n++) { + const r = Sr.utc(2016, n, 1) + e.push(t(r)) + } + return e + })((t) => this.extract(t, n, "month"))), + this.monthsCache[r][t] + ) + }) + } + weekdays(t, e = !1, n = !0) { + return Oe(this, t, n, qt, () => { + const n = e + ? { weekday: t, year: "numeric", month: "long", day: "numeric" } + : { weekday: t }, + r = e ? "format" : "standalone" + return ( + this.weekdaysCache[r][t] || + (this.weekdaysCache[r][t] = (function (t) { + const e = [] + for (let n = 1; n <= 7; n++) { + const r = Sr.utc(2016, 11, 13 + n) + e.push(t(r)) + } + return e + })((t) => this.extract(t, n, "weekday"))), + this.weekdaysCache[r][t] + ) + }) + } + meridiems(t = !0) { + return Oe( + this, + void 0, + t, + () => Yt, + () => { + if (!this.meridiemCache) { + const t = { hour: "numeric", hourCycle: "h12" } + this.meridiemCache = [Sr.utc(2016, 11, 13, 9), Sr.utc(2016, 11, 13, 19)].map((e) => + this.extract(e, t, "dayperiod") + ) + } + return this.meridiemCache + } + ) + } + eras(t, e = !0) { + return Oe(this, t, e, Wt, () => { + const e = { era: t } + return ( + this.eraCache[t] || + (this.eraCache[t] = [Sr.utc(-40, 1, 1), Sr.utc(2017, 1, 1)].map((t) => + this.extract(t, e, "era") + )), + this.eraCache[t] + ) + }) + } + extract(t, e, n) { + const r = this.dtFormatter(t, e) + .formatToParts() + .find((t) => t.type.toLowerCase() === n) + return r ? r.value : null + } + numberFormatter(t = {}) { + return new Se(this.intl, t.forceSimple || this.fastNumbers, t) + } + dtFormatter(t, e = {}) { + return new Te(t, this.intl, e) + } + relFormatter(t = {}) { + return new Me(this.intl, this.isEnglish(), t) + } + listFormatter(t = {}) { + return (function (t, e = {}) { + const n = JSON.stringify([t, e]) + let r = ye[n] + return r || ((r = new Intl.ListFormat(t, e)), (ye[n] = r)), r + })(this.intl, t) + } + isEnglish() { + return ( + "en" === this.locale || + "en-us" === this.locale.toLowerCase() || + new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us") + ) + } + equals(t) { + return ( + this.locale === t.locale && + this.numberingSystem === t.numberingSystem && + this.outputCalendar === t.outputCalendar + ) + } + } + function Ne(...t) { + const e = t.reduce((t, e) => t + e.source, "") + return RegExp(`^${e}$`) + } + function De(...t) { + return (e) => + t + .reduce( + ([t, n, r], s) => { + const [i, a, o] = s(e, r) + return [{ ...t, ...i }, a || n, o] + }, + [{}, null, 1] + ) + .slice(0, 2) + } + function Ee(t, ...e) { + if (null == t) return [null, null] + for (const [n, r] of e) { + const e = n.exec(t) + if (e) return r(e) + } + return [null, null] + } + function xe(...t) { + return (e, n) => { + const r = {} + let s + for (s = 0; s < t.length; s++) r[t[s]] = pt(e[n + s]) + return [r, null, n + s] + } + } + const Ce = /(?:(Z)|([+-]\d\d)(?::?(\d\d))?)/, + Ve = /(\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,30}))?)?)?/, + Fe = RegExp(`${Ve.source}(?:${Ce.source}?(?:\\[(${It.source})\\])?)?`), + Ie = RegExp(`(?:T${Fe.source})?`), + Le = xe("weekYear", "weekNumber", "weekDay"), + Ze = xe("year", "ordinal"), + $e = RegExp(`${Ve.source} ?(?:${Ce.source}|(${It.source}))?`), + _e = RegExp(`(?: ${$e.source})?`) + function Ae(t, e, n) { + const r = t[e] + return lt(r) ? n : pt(r) + } + function Re(t, e) { + return [ + { + hours: Ae(t, e, 0), + minutes: Ae(t, e + 1, 0), + seconds: Ae(t, e + 2, 0), + milliseconds: bt(t[e + 3]), + }, + null, + e + 4, + ] + } + function ze(t, e) { + const n = !t[e] && !t[e + 1], + r = Et(t[e + 1], t[e + 2]) + return [{}, n ? null : ie.instance(r), e + 3] + } + function qe(t, e) { + return [{}, t[e] ? re.create(t[e]) : null, e + 1] + } + const Ye = RegExp(`^T?${Ve.source}$`), + je = + /^-?P(?:(?:(-?\d{1,20}(?:\.\d{1,20})?)Y)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20}(?:\.\d{1,20})?)W)?(?:(-?\d{1,20}(?:\.\d{1,20})?)D)?(?:T(?:(-?\d{1,20}(?:\.\d{1,20})?)H)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20})(?:[.,](-?\d{1,20}))?S)?)?)$/ + function He(t) { + const [e, n, r, s, i, a, o, u, l] = t, + c = "-" === e[0], + h = u && "-" === u[0], + d = (t, e = !1) => (void 0 !== t && (e || (t && c)) ? -t : t) + return [ + { + years: d(wt(n)), + months: d(wt(r)), + weeks: d(wt(s)), + days: d(wt(i)), + hours: d(wt(a)), + minutes: d(wt(o)), + seconds: d(wt(u), "-0" === u), + milliseconds: d(bt(l), h), + }, + ] + } + const Ue = { + GMT: 0, + EDT: -240, + EST: -300, + CDT: -300, + CST: -360, + MDT: -360, + MST: -420, + PDT: -420, + PST: -480, + } + function We(t, e, n, r, s, i, a) { + const o = { + year: 2 === e.length ? Nt(pt(e)) : pt(e), + month: Zt.indexOf(n) + 1, + day: pt(r), + hour: pt(s), + minute: pt(i), + } + return ( + a && (o.second = pt(a)), + t && (o.weekday = t.length > 3 ? At.indexOf(t) + 1 : Rt.indexOf(t) + 1), + o + ) + } + const Pe = + /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|(?:([+-]\d\d)(\d\d)))$/ + function Je(t) { + const [, e, n, r, s, i, a, o, u, l, c, h] = t, + d = We(e, s, r, n, i, a, o) + let f + return (f = u ? Ue[u] : l ? 0 : Et(c, h)), [d, new ie(f)] + } + const Ge = + /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d\d):(\d\d):(\d\d) GMT$/, + Xe = + /^(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d) (\d\d):(\d\d):(\d\d) GMT$/, + Be = + /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( \d|\d\d) (\d\d):(\d\d):(\d\d) (\d{4})$/ + function Qe(t) { + const [, e, n, r, s, i, a, o] = t + return [We(e, s, r, n, i, a, o), ie.utcInstance] + } + function Ke(t) { + const [, e, n, r, s, i, a, o] = t + return [We(e, o, n, r, s, i, a), ie.utcInstance] + } + const tn = Ne(/([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/, Ie), + en = Ne(/(\d{4})-?W(\d\d)(?:-?(\d))?/, Ie), + nn = Ne(/(\d{4})-?(\d{3})/, Ie), + rn = Ne(Fe), + sn = De( + function (t, e) { + return [{ year: Ae(t, e), month: Ae(t, e + 1, 1), day: Ae(t, e + 2, 1) }, null, e + 3] + }, + Re, + ze, + qe + ), + an = De(Le, Re, ze, qe), + on = De(Ze, Re, ze, qe), + un = De(Re, ze, qe), + ln = De(Re), + cn = Ne(/(\d{4})-(\d\d)-(\d\d)/, _e), + hn = Ne($e), + dn = De(Re, ze, qe), + fn = { + weeks: { days: 7, hours: 168, minutes: 10080, seconds: 604800, milliseconds: 6048e5 }, + days: { hours: 24, minutes: 1440, seconds: 86400, milliseconds: 864e5 }, + hours: { minutes: 60, seconds: 3600, milliseconds: 36e5 }, + minutes: { seconds: 60, milliseconds: 6e4 }, + seconds: { milliseconds: 1e3 }, + }, + mn = { + years: { + quarters: 4, + months: 12, + weeks: 52, + days: 365, + hours: 8760, + minutes: 525600, + seconds: 31536e3, + milliseconds: 31536e6, + }, + quarters: { + months: 3, + weeks: 13, + days: 91, + hours: 2184, + minutes: 131040, + seconds: 7862400, + milliseconds: 78624e5, + }, + months: { + weeks: 4, + days: 30, + hours: 720, + minutes: 43200, + seconds: 2592e3, + milliseconds: 2592e6, + }, + ...fn, + }, + yn = { + years: { + quarters: 4, + months: 12, + weeks: 52.1775, + days: 365.2425, + hours: 8765.82, + minutes: 525949.2, + seconds: 525949.2 * 60, + milliseconds: 525949.2 * 60 * 1e3, + }, + quarters: { + months: 3, + weeks: 13.044375, + days: 91.310625, + hours: 2191.455, + minutes: 131487.3, + seconds: (525949.2 * 60) / 4, + milliseconds: 7889237999.999999, + }, + months: { + weeks: 4.3481250000000005, + days: 30.436875, + hours: 730.485, + minutes: 43829.1, + seconds: 2629746, + milliseconds: 2629746e3, + }, + ...fn, + }, + gn = [ + "years", + "quarters", + "months", + "weeks", + "days", + "hours", + "minutes", + "seconds", + "milliseconds", + ], + pn = gn.slice(0).reverse() + function wn(t, e, n = !1) { + const r = { + values: n ? e.values : { ...t.values, ...(e.values || {}) }, + loc: t.loc.clone(e.loc), + conversionAccuracy: e.conversionAccuracy || t.conversionAccuracy, + } + return new vn(r) + } + function bn(t, e, n, r, s) { + const i = t[s][n], + a = e[n] / i, + o = + Math.sign(a) !== Math.sign(r[s]) && 0 !== r[s] && Math.abs(a) <= 1 + ? (function (t) { + return t < 0 ? Math.floor(t) : Math.ceil(t) + })(a) + : Math.trunc(a) + ;(r[s] += o), (e[n] -= o * i) + } + class vn { + constructor(t) { + const e = "longterm" === t.conversionAccuracy || !1 + ;(this.values = t.values), + (this.loc = t.loc || ke.create()), + (this.conversionAccuracy = e ? "longterm" : "casual"), + (this.invalid = t.invalid || null), + (this.matrix = e ? yn : mn), + (this.isLuxonDuration = !0) + } + static fromMillis(t, e) { + return vn.fromObject({ milliseconds: t }, e) + } + static fromObject(t, e = {}) { + if (null == t || "object" != typeof t) + throw new $( + "Duration.fromObject: argument expected to be an object, got " + + (null === t ? "null" : typeof t) + ) + return new vn({ + values: Ct(t, vn.normalizeUnit), + loc: ke.fromObject(e), + conversionAccuracy: e.conversionAccuracy, + }) + } + static fromDurationLike(t) { + if (ct(t)) return vn.fromMillis(t) + if (vn.isDuration(t)) return t + if ("object" == typeof t) return vn.fromObject(t) + throw new $(`Unknown duration argument ${t} of type ${typeof t}`) + } + static fromISO(t, e) { + const [n] = (function (t) { + return Ee(t, [je, He]) + })(t) + return n + ? vn.fromObject(n, e) + : vn.invalid("unparsable", `the input "${t}" can't be parsed as ISO 8601`) + } + static fromISOTime(t, e) { + const [n] = (function (t) { + return Ee(t, [Ye, ln]) + })(t) + return n + ? vn.fromObject(n, e) + : vn.invalid("unparsable", `the input "${t}" can't be parsed as ISO 8601`) + } + static invalid(t, e = null) { + if (!t) throw new $("need to specify a reason the Duration is invalid") + const n = t instanceof Xt ? t : new Xt(t, e) + if (me.throwOnInvalid) throw new I(n) + return new vn({ invalid: n }) + } + static normalizeUnit(t) { + const e = { + year: "years", + years: "years", + quarter: "quarters", + quarters: "quarters", + month: "months", + months: "months", + week: "weeks", + weeks: "weeks", + day: "days", + days: "days", + hour: "hours", + hours: "hours", + minute: "minutes", + minutes: "minutes", + second: "seconds", + seconds: "seconds", + millisecond: "milliseconds", + milliseconds: "milliseconds", + }[t ? t.toLowerCase() : t] + if (!e) throw new Z(t) + return e + } + static isDuration(t) { + return (t && t.isLuxonDuration) || !1 + } + get locale() { + return this.isValid ? this.loc.locale : null + } + get numberingSystem() { + return this.isValid ? this.loc.numberingSystem : null + } + toFormat(t, e = {}) { + const n = { ...e, floor: !1 !== e.round && !1 !== e.floor } + return this.isValid + ? Gt.create(this.loc, n).formatDurationFromString(this, t) + : "Invalid Duration" + } + toHuman(t = {}) { + const e = gn + .map((e) => { + const n = this.values[e] + return lt(n) + ? null + : this.loc + .numberFormatter({ style: "unit", unitDisplay: "long", ...t, unit: e.slice(0, -1) }) + .format(n) + }) + .filter((t) => t) + return this.loc + .listFormatter({ type: "conjunction", style: t.listStyle || "narrow", ...t }) + .format(e) + } + toObject() { + return this.isValid ? { ...this.values } : {} + } + toISO() { + if (!this.isValid) return null + let t = "P" + return ( + 0 !== this.years && (t += this.years + "Y"), + (0 === this.months && 0 === this.quarters) || (t += this.months + 3 * this.quarters + "M"), + 0 !== this.weeks && (t += this.weeks + "W"), + 0 !== this.days && (t += this.days + "D"), + (0 === this.hours && 0 === this.minutes && 0 === this.seconds && 0 === this.milliseconds) || + (t += "T"), + 0 !== this.hours && (t += this.hours + "H"), + 0 !== this.minutes && (t += this.minutes + "M"), + (0 === this.seconds && 0 === this.milliseconds) || + (t += vt(this.seconds + this.milliseconds / 1e3, 3) + "S"), + "P" === t && (t += "T0S"), + t + ) + } + toISOTime(t = {}) { + if (!this.isValid) return null + const e = this.toMillis() + if (e < 0 || e >= 864e5) return null + t = { + suppressMilliseconds: !1, + suppressSeconds: !1, + includePrefix: !1, + format: "extended", + ...t, + } + const n = this.shiftTo("hours", "minutes", "seconds", "milliseconds") + let r = "basic" === t.format ? "hhmm" : "hh:mm" + ;(t.suppressSeconds && 0 === n.seconds && 0 === n.milliseconds) || + ((r += "basic" === t.format ? "ss" : ":ss"), + (t.suppressMilliseconds && 0 === n.milliseconds) || (r += ".SSS")) + let s = n.toFormat(r) + return t.includePrefix && (s = "T" + s), s + } + toJSON() { + return this.toISO() + } + toString() { + return this.toISO() + } + toMillis() { + return this.as("milliseconds") + } + valueOf() { + return this.toMillis() + } + plus(t) { + if (!this.isValid) return this + const e = vn.fromDurationLike(t), + n = {} + for (const t of gn) (mt(e.values, t) || mt(this.values, t)) && (n[t] = e.get(t) + this.get(t)) + return wn(this, { values: n }, !0) + } + minus(t) { + if (!this.isValid) return this + const e = vn.fromDurationLike(t) + return this.plus(e.negate()) + } + mapUnits(t) { + if (!this.isValid) return this + const e = {} + for (const n of Object.keys(this.values)) e[n] = xt(t(this.values[n], n)) + return wn(this, { values: e }, !0) + } + get(t) { + return this[vn.normalizeUnit(t)] + } + set(t) { + return this.isValid + ? wn(this, { values: { ...this.values, ...Ct(t, vn.normalizeUnit) } }) + : this + } + reconfigure({ locale: t, numberingSystem: e, conversionAccuracy: n } = {}) { + const r = { loc: this.loc.clone({ locale: t, numberingSystem: e }) } + return n && (r.conversionAccuracy = n), wn(this, r) + } + as(t) { + return this.isValid ? this.shiftTo(t).get(t) : NaN + } + normalize() { + if (!this.isValid) return this + const t = this.toObject() + return ( + (function (t, e) { + pn.reduce((n, r) => (lt(e[r]) ? n : (n && bn(t, e, n, e, r), r)), null) + })(this.matrix, t), + wn(this, { values: t }, !0) + ) + } + shiftTo(...t) { + if (!this.isValid) return this + if (0 === t.length) return this + t = t.map((t) => vn.normalizeUnit(t)) + const e = {}, + n = {}, + r = this.toObject() + let s + for (const i of gn) + if (t.indexOf(i) >= 0) { + s = i + let t = 0 + for (const e in n) (t += this.matrix[e][i] * n[e]), (n[e] = 0) + ct(r[i]) && (t += r[i]) + const a = Math.trunc(t) + ;(e[i] = a), (n[i] = (1e3 * t - 1e3 * a) / 1e3) + for (const t in r) gn.indexOf(t) > gn.indexOf(i) && bn(this.matrix, r, t, e, i) + } else ct(r[i]) && (n[i] = r[i]) + for (const t in n) 0 !== n[t] && (e[s] += t === s ? n[t] : n[t] / this.matrix[s][t]) + return wn(this, { values: e }, !0).normalize() + } + negate() { + if (!this.isValid) return this + const t = {} + for (const e of Object.keys(this.values)) t[e] = 0 === this.values[e] ? 0 : -this.values[e] + return wn(this, { values: t }, !0) + } + get years() { + return this.isValid ? this.values.years || 0 : NaN + } + get quarters() { + return this.isValid ? this.values.quarters || 0 : NaN + } + get months() { + return this.isValid ? this.values.months || 0 : NaN + } + get weeks() { + return this.isValid ? this.values.weeks || 0 : NaN + } + get days() { + return this.isValid ? this.values.days || 0 : NaN + } + get hours() { + return this.isValid ? this.values.hours || 0 : NaN + } + get minutes() { + return this.isValid ? this.values.minutes || 0 : NaN + } + get seconds() { + return this.isValid ? this.values.seconds || 0 : NaN + } + get milliseconds() { + return this.isValid ? this.values.milliseconds || 0 : NaN + } + get isValid() { + return null === this.invalid + } + get invalidReason() { + return this.invalid ? this.invalid.reason : null + } + get invalidExplanation() { + return this.invalid ? this.invalid.explanation : null + } + equals(t) { + if (!this.isValid || !t.isValid) return !1 + if (!this.loc.equals(t.loc)) return !1 + for (const r of gn) + if ( + ((e = this.values[r]), + (n = t.values[r]), + !(void 0 === e || 0 === e ? void 0 === n || 0 === n : e === n)) + ) + return !1 + var e, n + return !0 + } + } + const On = "Invalid Interval" + class Sn { + constructor(t) { + ;(this.s = t.start), + (this.e = t.end), + (this.invalid = t.invalid || null), + (this.isLuxonInterval = !0) + } + static invalid(t, e = null) { + if (!t) throw new $("need to specify a reason the Interval is invalid") + const n = t instanceof Xt ? t : new Xt(t, e) + if (me.throwOnInvalid) throw new F(n) + return new Sn({ invalid: n }) + } + static fromDateTimes(t, e) { + const n = Tr(t), + r = Tr(e), + s = (function (t, e) { + return t && t.isValid + ? e && e.isValid + ? e < t + ? Sn.invalid( + "end before start", + `The end of an interval must be after its start, but you had start=${t.toISO()} and end=${e.toISO()}` + ) + : null + : Sn.invalid("missing or invalid end") + : Sn.invalid("missing or invalid start") + })(n, r) + return null == s ? new Sn({ start: n, end: r }) : s + } + static after(t, e) { + const n = vn.fromDurationLike(e), + r = Tr(t) + return Sn.fromDateTimes(r, r.plus(n)) + } + static before(t, e) { + const n = vn.fromDurationLike(e), + r = Tr(t) + return Sn.fromDateTimes(r.minus(n), r) + } + static fromISO(t, e) { + const [n, r] = (t || "").split("/", 2) + if (n && r) { + let t, s, i, a + try { + ;(t = Sr.fromISO(n, e)), (s = t.isValid) + } catch (r) { + s = !1 + } + try { + ;(i = Sr.fromISO(r, e)), (a = i.isValid) + } catch (r) { + a = !1 + } + if (s && a) return Sn.fromDateTimes(t, i) + if (s) { + const n = vn.fromISO(r, e) + if (n.isValid) return Sn.after(t, n) + } else if (a) { + const t = vn.fromISO(n, e) + if (t.isValid) return Sn.before(i, t) + } + } + return Sn.invalid("unparsable", `the input "${t}" can't be parsed as ISO 8601`) + } + static isInterval(t) { + return (t && t.isLuxonInterval) || !1 + } + get start() { + return this.isValid ? this.s : null + } + get end() { + return this.isValid ? this.e : null + } + get isValid() { + return null === this.invalidReason + } + get invalidReason() { + return this.invalid ? this.invalid.reason : null + } + get invalidExplanation() { + return this.invalid ? this.invalid.explanation : null + } + length(t = "milliseconds") { + return this.isValid ? this.toDuration(t).get(t) : NaN + } + count(t = "milliseconds") { + if (!this.isValid) return NaN + const e = this.start.startOf(t), + n = this.end.startOf(t) + return Math.floor(n.diff(e, t).get(t)) + 1 + } + hasSame(t) { + return !!this.isValid && (this.isEmpty() || this.e.minus(1).hasSame(this.s, t)) + } + isEmpty() { + return this.s.valueOf() === this.e.valueOf() + } + isAfter(t) { + return !!this.isValid && this.s > t + } + isBefore(t) { + return !!this.isValid && this.e <= t + } + contains(t) { + return !!this.isValid && this.s <= t && this.e > t + } + set({ start: t, end: e } = {}) { + return this.isValid ? Sn.fromDateTimes(t || this.s, e || this.e) : this + } + splitAt(...t) { + if (!this.isValid) return [] + const e = t + .map(Tr) + .filter((t) => this.contains(t)) + .sort(), + n = [] + let { s: r } = this, + s = 0 + for (; r < this.e; ) { + const t = e[s] || this.e, + i = +t > +this.e ? this.e : t + n.push(Sn.fromDateTimes(r, i)), (r = i), (s += 1) + } + return n + } + splitBy(t) { + const e = vn.fromDurationLike(t) + if (!this.isValid || !e.isValid || 0 === e.as("milliseconds")) return [] + let n, + { s: r } = this, + s = 1 + const i = [] + for (; r < this.e; ) { + const t = this.start.plus(e.mapUnits((t) => t * s)) + ;(n = +t > +this.e ? this.e : t), i.push(Sn.fromDateTimes(r, n)), (r = n), (s += 1) + } + return i + } + divideEqually(t) { + return this.isValid ? this.splitBy(this.length() / t).slice(0, t) : [] + } + overlaps(t) { + return this.e > t.s && this.s < t.e + } + abutsStart(t) { + return !!this.isValid && +this.e == +t.s + } + abutsEnd(t) { + return !!this.isValid && +t.e == +this.s + } + engulfs(t) { + return !!this.isValid && this.s <= t.s && this.e >= t.e + } + equals(t) { + return !(!this.isValid || !t.isValid) && this.s.equals(t.s) && this.e.equals(t.e) + } + intersection(t) { + if (!this.isValid) return this + const e = this.s > t.s ? this.s : t.s, + n = this.e < t.e ? this.e : t.e + return e >= n ? null : Sn.fromDateTimes(e, n) + } + union(t) { + if (!this.isValid) return this + const e = this.s < t.s ? this.s : t.s, + n = this.e > t.e ? this.e : t.e + return Sn.fromDateTimes(e, n) + } + static merge(t) { + const [e, n] = t + .sort((t, e) => t.s - e.s) + .reduce( + ([t, e], n) => + e ? (e.overlaps(n) || e.abutsStart(n) ? [t, e.union(n)] : [t.concat([e]), n]) : [t, n], + [[], null] + ) + return n && e.push(n), e + } + static xor(t) { + let e = null, + n = 0 + const r = [], + s = t.map((t) => [ + { time: t.s, type: "s" }, + { time: t.e, type: "e" }, + ]), + i = Array.prototype.concat(...s).sort((t, e) => t.time - e.time) + for (const t of i) + (n += "s" === t.type ? 1 : -1), + 1 === n + ? (e = t.time) + : (e && +e != +t.time && r.push(Sn.fromDateTimes(e, t.time)), (e = null)) + return Sn.merge(r) + } + difference(...t) { + return Sn.xor([this].concat(t)) + .map((t) => this.intersection(t)) + .filter((t) => t && !t.isEmpty()) + } + toString() { + return this.isValid ? `[${this.s.toISO()} – ${this.e.toISO()})` : On + } + toISO(t) { + return this.isValid ? `${this.s.toISO(t)}/${this.e.toISO(t)}` : On + } + toISODate() { + return this.isValid ? `${this.s.toISODate()}/${this.e.toISODate()}` : On + } + toISOTime(t) { + return this.isValid ? `${this.s.toISOTime(t)}/${this.e.toISOTime(t)}` : On + } + toFormat(t, { separator: e = " – " } = {}) { + return this.isValid ? `${this.s.toFormat(t)}${e}${this.e.toFormat(t)}` : On + } + toDuration(t, e) { + return this.isValid ? this.e.diff(this.s, t, e) : vn.invalid(this.invalidReason) + } + mapEndpoints(t) { + return Sn.fromDateTimes(t(this.s), t(this.e)) + } + } + class Tn { + static hasDST(t = me.defaultZone) { + const e = Sr.now().setZone(t).set({ month: 12 }) + return !t.isUniversal && e.offset !== e.set({ month: 6 }).offset + } + static isValidIANAZone(t) { + return re.isValidZone(t) + } + static normalizeZone(t) { + return oe(t, me.defaultZone) + } + static months( + t = "long", + { + locale: e = null, + numberingSystem: n = null, + locObj: r = null, + outputCalendar: s = "gregory", + } = {} + ) { + return (r || ke.create(e, n, s)).months(t) + } + static monthsFormat( + t = "long", + { + locale: e = null, + numberingSystem: n = null, + locObj: r = null, + outputCalendar: s = "gregory", + } = {} + ) { + return (r || ke.create(e, n, s)).months(t, !0) + } + static weekdays( + t = "long", + { locale: e = null, numberingSystem: n = null, locObj: r = null } = {} + ) { + return (r || ke.create(e, n, null)).weekdays(t) + } + static weekdaysFormat( + t = "long", + { locale: e = null, numberingSystem: n = null, locObj: r = null } = {} + ) { + return (r || ke.create(e, n, null)).weekdays(t, !0) + } + static meridiems({ locale: t = null } = {}) { + return ke.create(t).meridiems() + } + static eras(t = "short", { locale: e = null } = {}) { + return ke.create(e, null, "gregory").eras(t) + } + static features() { + return { relative: dt() } + } + } + function Mn(t, e) { + const n = (t) => t.toUTC(0, { keepLocalTime: !0 }).startOf("day").valueOf(), + r = n(e) - n(t) + return Math.floor(vn.fromMillis(r).as("days")) + } + const kn = { + arab: "[٠-٩]", + arabext: "[۰-۹]", + bali: "[᭐-᭙]", + beng: "[০-৯]", + deva: "[०-९]", + fullwide: "[0-9]", + gujr: "[૦-૯]", + hanidec: "[〇|一|二|三|四|五|六|七|八|九]", + khmr: "[០-៩]", + knda: "[೦-೯]", + laoo: "[໐-໙]", + limb: "[᥆-᥏]", + mlym: "[൦-൯]", + mong: "[᠐-᠙]", + mymr: "[၀-၉]", + orya: "[୦-୯]", + tamldec: "[௦-௯]", + telu: "[౦-౯]", + thai: "[๐-๙]", + tibt: "[༠-༩]", + latn: "\\d", + }, + Nn = { + arab: [1632, 1641], + arabext: [1776, 1785], + bali: [6992, 7001], + beng: [2534, 2543], + deva: [2406, 2415], + fullwide: [65296, 65303], + gujr: [2790, 2799], + khmr: [6112, 6121], + knda: [3302, 3311], + laoo: [3792, 3801], + limb: [6470, 6479], + mlym: [3430, 3439], + mong: [6160, 6169], + mymr: [4160, 4169], + orya: [2918, 2927], + tamldec: [3046, 3055], + telu: [3174, 3183], + thai: [3664, 3673], + tibt: [3872, 3881], + }, + Dn = kn.hanidec.replace(/[\[|\]]/g, "").split("") + function En({ numberingSystem: t }, e = "") { + return new RegExp(`${kn[t || "latn"]}${e}`) + } + function xn(t, e = (t) => t) { + return { + regex: t, + deser: ([t]) => + e( + (function (t) { + let e = parseInt(t, 10) + if (isNaN(e)) { + e = "" + for (let n = 0; n < t.length; n++) { + const r = t.charCodeAt(n) + if (-1 !== t[n].search(kn.hanidec)) e += Dn.indexOf(t[n]) + else + for (const t in Nn) { + const [n, s] = Nn[t] + r >= n && r <= s && (e += r - n) + } + } + return parseInt(e, 10) + } + return e + })(t) + ), + } + } + const Cn = `[ ${String.fromCharCode(160)}]`, + Vn = new RegExp(Cn, "g") + function Fn(t) { + return t.replace(/\./g, "\\.?").replace(Vn, Cn) + } + function In(t) { + return t.replace(/\./g, "").replace(Vn, " ").toLowerCase() + } + function Ln(t, e) { + return null === t + ? null + : { + regex: RegExp(t.map(Fn).join("|")), + deser: ([n]) => t.findIndex((t) => In(n) === In(t)) + e, + } + } + function Zn(t, e) { + return { regex: t, deser: ([, t, e]) => Et(t, e), groups: e } + } + function $n(t) { + return { regex: t, deser: ([t]) => t } + } + const _n = { + year: { "2-digit": "yy", numeric: "yyyyy" }, + month: { numeric: "M", "2-digit": "MM", short: "MMM", long: "MMMM" }, + day: { numeric: "d", "2-digit": "dd" }, + weekday: { short: "EEE", long: "EEEE" }, + dayperiod: "a", + dayPeriod: "a", + hour: { numeric: "h", "2-digit": "hh" }, + minute: { numeric: "m", "2-digit": "mm" }, + second: { numeric: "s", "2-digit": "ss" }, + timeZoneName: { long: "ZZZZZ", short: "ZZZ" }, + } + let An = null + function Rn(t, e, n) { + const r = (function (t, e) { + return Array.prototype.concat( + ...t.map((t) => + (function (t, e) { + if (t.literal) return t + const n = zn(Gt.macroTokenToFormatOpts(t.val), e) + return null == n || n.includes(void 0) ? t : n + })(t, e) + ) + ) + })(Gt.parseFormat(n), t), + s = r.map((e) => + (function (t, e) { + const n = En(e), + r = En(e, "{2}"), + s = En(e, "{3}"), + i = En(e, "{4}"), + a = En(e, "{6}"), + o = En(e, "{1,2}"), + u = En(e, "{1,3}"), + l = En(e, "{1,6}"), + c = En(e, "{1,9}"), + h = En(e, "{2,4}"), + d = En(e, "{4,6}"), + f = (t) => { + return { + regex: RegExp(((e = t.val), e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"))), + deser: ([t]) => t, + literal: !0, + } + var e + }, + m = ((m) => { + if (t.literal) return f(m) + switch (m.val) { + case "G": + return Ln(e.eras("short", !1), 0) + case "GG": + return Ln(e.eras("long", !1), 0) + case "y": + return xn(l) + case "yy": + case "kk": + return xn(h, Nt) + case "yyyy": + case "kkkk": + return xn(i) + case "yyyyy": + return xn(d) + case "yyyyyy": + return xn(a) + case "M": + case "L": + case "d": + case "H": + case "h": + case "m": + case "q": + case "s": + case "W": + return xn(o) + case "MM": + case "LL": + case "dd": + case "HH": + case "hh": + case "mm": + case "qq": + case "ss": + case "WW": + return xn(r) + case "MMM": + return Ln(e.months("short", !0, !1), 1) + case "MMMM": + return Ln(e.months("long", !0, !1), 1) + case "LLL": + return Ln(e.months("short", !1, !1), 1) + case "LLLL": + return Ln(e.months("long", !1, !1), 1) + case "o": + case "S": + return xn(u) + case "ooo": + case "SSS": + return xn(s) + case "u": + return $n(c) + case "uu": + return $n(o) + case "uuu": + case "E": + case "c": + return xn(n) + case "a": + return Ln(e.meridiems(), 0) + case "EEE": + return Ln(e.weekdays("short", !1, !1), 1) + case "EEEE": + return Ln(e.weekdays("long", !1, !1), 1) + case "ccc": + return Ln(e.weekdays("short", !0, !1), 1) + case "cccc": + return Ln(e.weekdays("long", !0, !1), 1) + case "Z": + case "ZZ": + return Zn(new RegExp(`([+-]${o.source})(?::(${r.source}))?`), 2) + case "ZZZ": + return Zn(new RegExp(`([+-]${o.source})(${r.source})?`), 2) + case "z": + return $n(/[a-z_+-/]{1,256}?/i) + default: + return f(m) + } + })(t) || { invalidReason: "missing Intl.DateTimeFormat.formatToParts support" } + return (m.token = t), m + })(e, t) + ), + i = s.find((t) => t.invalidReason) + if (i) return { input: e, tokens: r, invalidReason: i.invalidReason } + { + const [t, n] = (function (t) { + return [`^${t.map((t) => t.regex).reduce((t, e) => `${t}(${e.source})`, "")}$`, t] + })(s), + i = RegExp(t, "i"), + [a, o] = (function (t, e, n) { + const r = t.match(e) + if (r) { + const t = {} + let e = 1 + for (const s in n) + if (mt(n, s)) { + const i = n[s], + a = i.groups ? i.groups + 1 : 1 + !i.literal && i.token && (t[i.token.val[0]] = i.deser(r.slice(e, e + a))), (e += a) + } + return [r, t] + } + return [r, {}] + })(e, i, n), + [u, l, c] = o + ? (function (t) { + let e, + n = null + return ( + lt(t.z) || (n = re.create(t.z)), + lt(t.Z) || (n || (n = new ie(t.Z)), (e = t.Z)), + lt(t.q) || (t.M = 3 * (t.q - 1) + 1), + lt(t.h) || + (t.h < 12 && 1 === t.a ? (t.h += 12) : 12 === t.h && 0 === t.a && (t.h = 0)), + 0 === t.G && t.y && (t.y = -t.y), + lt(t.u) || (t.S = bt(t.u)), + [ + Object.keys(t).reduce((e, n) => { + const r = ((t) => { + switch (t) { + case "S": + return "millisecond" + case "s": + return "second" + case "m": + return "minute" + case "h": + case "H": + return "hour" + case "d": + return "day" + case "o": + return "ordinal" + case "L": + case "M": + return "month" + case "y": + return "year" + case "E": + case "c": + return "weekday" + case "W": + return "weekNumber" + case "k": + return "weekYear" + case "q": + return "quarter" + default: + return null + } + })(n) + return r && (e[r] = t[n]), e + }, {}), + n, + e, + ] + ) + })(o) + : [null, null, void 0] + if (mt(o, "a") && mt(o, "H")) + throw new L("Can't include meridiem when specifying 24-hour format") + return { + input: e, + tokens: r, + regex: i, + rawMatches: a, + matches: o, + result: u, + zone: l, + specificOffset: c, + } + } + } + function zn(t, e) { + return t + ? Gt.create(e, t) + .formatDateTimeParts((An || (An = Sr.fromMillis(1555555555555)), An)) + .map((e) => + (function (t, e, n) { + const { type: r, value: s } = t + if ("literal" === r) return { literal: !0, val: s } + const i = n[r] + let a = _n[r] + return "object" == typeof a && (a = a[i]), a ? { literal: !1, val: a } : void 0 + })(e, 0, t) + ) + : null + } + const qn = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334], + Yn = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335] + function jn(t, e) { + return new Xt( + "unit out of range", + `you specified ${e} (of type ${typeof e}) as a ${t}, which is invalid` + ) + } + function Hn(t, e, n) { + const r = new Date(Date.UTC(t, e - 1, n)) + t < 100 && t >= 0 && r.setUTCFullYear(r.getUTCFullYear() - 1900) + const s = r.getUTCDay() + return 0 === s ? 7 : s + } + function Un(t, e, n) { + return n + (Ot(t) ? Yn : qn)[e - 1] + } + function Wn(t, e) { + const n = Ot(t) ? Yn : qn, + r = n.findIndex((t) => t < e) + return { month: r + 1, day: e - n[r] } + } + function Pn(t) { + const { year: e, month: n, day: r } = t, + s = Un(e, n, r), + i = Hn(e, n, r) + let a, + o = Math.floor((s - i + 10) / 7) + return ( + o < 1 ? ((a = e - 1), (o = kt(a))) : o > kt(e) ? ((a = e + 1), (o = 1)) : (a = e), + { weekYear: a, weekNumber: o, weekday: i, ...Ft(t) } + ) + } + function Jn(t) { + const { weekYear: e, weekNumber: n, weekday: r } = t, + s = Hn(e, 1, 4), + i = St(e) + let a, + o = 7 * n + r - s - 3 + o < 1 ? ((a = e - 1), (o += St(a))) : o > i ? ((a = e + 1), (o -= St(e))) : (a = e) + const { month: u, day: l } = Wn(a, o) + return { year: a, month: u, day: l, ...Ft(t) } + } + function Gn(t) { + const { year: e, month: n, day: r } = t + return { year: e, ordinal: Un(e, n, r), ...Ft(t) } + } + function Xn(t) { + const { year: e, ordinal: n } = t, + { month: r, day: s } = Wn(e, n) + return { year: e, month: r, day: s, ...Ft(t) } + } + function Bn(t) { + const e = ht(t.year), + n = yt(t.month, 1, 12), + r = yt(t.day, 1, Tt(t.year, t.month)) + return e ? (n ? !r && jn("day", t.day) : jn("month", t.month)) : jn("year", t.year) + } + function Qn(t) { + const { hour: e, minute: n, second: r, millisecond: s } = t, + i = yt(e, 0, 23) || (24 === e && 0 === n && 0 === r && 0 === s), + a = yt(n, 0, 59), + o = yt(r, 0, 59), + u = yt(s, 0, 999) + return i + ? a + ? o + ? !u && jn("millisecond", s) + : jn("second", r) + : jn("minute", n) + : jn("hour", e) + } + const Kn = "Invalid DateTime", + tr = 864e13 + function er(t) { + return new Xt("unsupported zone", `the zone "${t.name}" is not supported`) + } + function nr(t) { + return null === t.weekData && (t.weekData = Pn(t.c)), t.weekData + } + function rr(t, e) { + const n = { ts: t.ts, zone: t.zone, c: t.c, o: t.o, loc: t.loc, invalid: t.invalid } + return new Sr({ ...n, ...e, old: n }) + } + function sr(t, e, n) { + let r = t - 60 * e * 1e3 + const s = n.offset(r) + if (e === s) return [r, e] + r -= 60 * (s - e) * 1e3 + const i = n.offset(r) + return s === i ? [r, s] : [t - 60 * Math.min(s, i) * 1e3, Math.max(s, i)] + } + function ir(t, e) { + const n = new Date((t += 60 * e * 1e3)) + return { + year: n.getUTCFullYear(), + month: n.getUTCMonth() + 1, + day: n.getUTCDate(), + hour: n.getUTCHours(), + minute: n.getUTCMinutes(), + second: n.getUTCSeconds(), + millisecond: n.getUTCMilliseconds(), + } + } + function ar(t, e, n) { + return sr(Mt(t), e, n) + } + function or(t, e) { + const n = t.o, + r = t.c.year + Math.trunc(e.years), + s = t.c.month + Math.trunc(e.months) + 3 * Math.trunc(e.quarters), + i = { + ...t.c, + year: r, + month: s, + day: Math.min(t.c.day, Tt(r, s)) + Math.trunc(e.days) + 7 * Math.trunc(e.weeks), + }, + a = vn + .fromObject({ + years: e.years - Math.trunc(e.years), + quarters: e.quarters - Math.trunc(e.quarters), + months: e.months - Math.trunc(e.months), + weeks: e.weeks - Math.trunc(e.weeks), + days: e.days - Math.trunc(e.days), + hours: e.hours, + minutes: e.minutes, + seconds: e.seconds, + milliseconds: e.milliseconds, + }) + .as("milliseconds"), + o = Mt(i) + let [u, l] = sr(o, n, t.zone) + return 0 !== a && ((u += a), (l = t.zone.offset(u))), { ts: u, o: l } + } + function ur(t, e, n, r, s, i) { + const { setZone: a, zone: o } = n + if (t && 0 !== Object.keys(t).length) { + const r = e || o, + s = Sr.fromObject(t, { ...n, zone: r, specificOffset: i }) + return a ? s : s.setZone(o) + } + return Sr.invalid(new Xt("unparsable", `the input "${s}" can't be parsed as ${r}`)) + } + function lr(t, e, n = !0) { + return t.isValid + ? Gt.create(ke.create("en-US"), { allowZ: n, forceSimple: !0 }).formatDateTimeFromString(t, e) + : null + } + function cr(t, e) { + const n = t.c.year > 9999 || t.c.year < 0 + let r = "" + return ( + n && t.c.year >= 0 && (r += "+"), + (r += gt(t.c.year, n ? 6 : 4)), + e + ? ((r += "-"), (r += gt(t.c.month)), (r += "-"), (r += gt(t.c.day))) + : ((r += gt(t.c.month)), (r += gt(t.c.day))), + r + ) + } + function hr(t, e, n, r, s, i) { + let a = gt(t.c.hour) + return ( + e + ? ((a += ":"), (a += gt(t.c.minute)), (0 === t.c.second && n) || (a += ":")) + : (a += gt(t.c.minute)), + (0 === t.c.second && n) || + ((a += gt(t.c.second)), + (0 === t.c.millisecond && r) || ((a += "."), (a += gt(t.c.millisecond, 3)))), + s && + (t.isOffsetFixed && 0 === t.offset && !i + ? (a += "Z") + : t.o < 0 + ? ((a += "-"), + (a += gt(Math.trunc(-t.o / 60))), + (a += ":"), + (a += gt(Math.trunc(-t.o % 60)))) + : ((a += "+"), + (a += gt(Math.trunc(t.o / 60))), + (a += ":"), + (a += gt(Math.trunc(t.o % 60))))), + i && (a += "[" + t.zone.ianaName + "]"), + a + ) + } + const dr = { month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }, + fr = { weekNumber: 1, weekday: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }, + mr = { ordinal: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }, + yr = ["year", "month", "day", "hour", "minute", "second", "millisecond"], + gr = ["weekYear", "weekNumber", "weekday", "hour", "minute", "second", "millisecond"], + pr = ["year", "ordinal", "hour", "minute", "second", "millisecond"] + function wr(t) { + const e = { + year: "year", + years: "year", + month: "month", + months: "month", + day: "day", + days: "day", + hour: "hour", + hours: "hour", + minute: "minute", + minutes: "minute", + quarter: "quarter", + quarters: "quarter", + second: "second", + seconds: "second", + millisecond: "millisecond", + milliseconds: "millisecond", + weekday: "weekday", + weekdays: "weekday", + weeknumber: "weekNumber", + weeksnumber: "weekNumber", + weeknumbers: "weekNumber", + weekyear: "weekYear", + weekyears: "weekYear", + ordinal: "ordinal", + }[t.toLowerCase()] + if (!e) throw new Z(t) + return e + } + function br(t, e) { + const n = oe(e.zone, me.defaultZone), + r = ke.fromObject(e), + s = me.now() + let i, a + if (lt(t.year)) i = s + else { + for (const e of yr) lt(t[e]) && (t[e] = dr[e]) + const e = Bn(t) || Qn(t) + if (e) return Sr.invalid(e) + const r = n.offset(s) + ;[i, a] = ar(t, r, n) + } + return new Sr({ ts: i, zone: n, loc: r, o: a }) + } + function vr(t, e, n) { + const r = !!lt(n.round) || n.round, + s = (t, s) => ( + (t = vt(t, r || n.calendary ? 0 : 2, !0)), e.loc.clone(n).relFormatter(n).format(t, s) + ), + i = (r) => + n.calendary + ? e.hasSame(t, r) + ? 0 + : e.startOf(r).diff(t.startOf(r), r).get(r) + : e.diff(t, r).get(r) + if (n.unit) return s(i(n.unit), n.unit) + for (const t of n.units) { + const e = i(t) + if (Math.abs(e) >= 1) return s(e, t) + } + return s(t > e ? -0 : 0, n.units[n.units.length - 1]) + } + function Or(t) { + let e, + n = {} + return ( + t.length > 0 && "object" == typeof t[t.length - 1] + ? ((n = t[t.length - 1]), (e = Array.from(t).slice(0, t.length - 1))) + : (e = Array.from(t)), + [n, e] + ) + } + class Sr { + constructor(t) { + const e = t.zone || me.defaultZone + let n = + t.invalid || + (Number.isNaN(t.ts) ? new Xt("invalid input") : null) || + (e.isValid ? null : er(e)) + this.ts = lt(t.ts) ? me.now() : t.ts + let r = null, + s = null + if (!n) + if (t.old && t.old.ts === this.ts && t.old.zone.equals(e)) [r, s] = [t.old.c, t.old.o] + else { + const t = e.offset(this.ts) + ;(r = ir(this.ts, t)), + (n = Number.isNaN(r.year) ? new Xt("invalid input") : null), + (r = n ? null : r), + (s = n ? null : t) + } + ;(this._zone = e), + (this.loc = t.loc || ke.create()), + (this.invalid = n), + (this.weekData = null), + (this.c = r), + (this.o = s), + (this.isLuxonDateTime = !0) + } + static now() { + return new Sr({}) + } + static local() { + const [t, e] = Or(arguments), + [n, r, s, i, a, o, u] = e + return br({ year: n, month: r, day: s, hour: i, minute: a, second: o, millisecond: u }, t) + } + static utc() { + const [t, e] = Or(arguments), + [n, r, s, i, a, o, u] = e + return ( + (t.zone = ie.utcInstance), + br({ year: n, month: r, day: s, hour: i, minute: a, second: o, millisecond: u }, t) + ) + } + static fromJSDate(t, e = {}) { + const n = ((r = t), "[object Date]" === Object.prototype.toString.call(r) ? t.valueOf() : NaN) + var r + if (Number.isNaN(n)) return Sr.invalid("invalid input") + const s = oe(e.zone, me.defaultZone) + return s.isValid ? new Sr({ ts: n, zone: s, loc: ke.fromObject(e) }) : Sr.invalid(er(s)) + } + static fromMillis(t, e = {}) { + if (ct(t)) + return t < -tr || t > tr + ? Sr.invalid("Timestamp out of range") + : new Sr({ ts: t, zone: oe(e.zone, me.defaultZone), loc: ke.fromObject(e) }) + throw new $( + `fromMillis requires a numerical input, but received a ${typeof t} with value ${t}` + ) + } + static fromSeconds(t, e = {}) { + if (ct(t)) + return new Sr({ ts: 1e3 * t, zone: oe(e.zone, me.defaultZone), loc: ke.fromObject(e) }) + throw new $("fromSeconds requires a numerical input") + } + static fromObject(t, e = {}) { + t = t || {} + const n = oe(e.zone, me.defaultZone) + if (!n.isValid) return Sr.invalid(er(n)) + const r = me.now(), + s = lt(e.specificOffset) ? n.offset(r) : e.specificOffset, + i = Ct(t, wr), + a = !lt(i.ordinal), + o = !lt(i.year), + u = !lt(i.month) || !lt(i.day), + l = o || u, + c = i.weekYear || i.weekNumber, + h = ke.fromObject(e) + if ((l || a) && c) + throw new L("Can't mix weekYear/weekNumber units with year/month/day or ordinals") + if (u && a) throw new L("Can't mix ordinal dates with month/day") + const d = c || (i.weekday && !l) + let f, + m, + y = ir(r, s) + d + ? ((f = gr), (m = fr), (y = Pn(y))) + : a + ? ((f = pr), (m = mr), (y = Gn(y))) + : ((f = yr), (m = dr)) + let g = !1 + for (const t of f) lt(i[t]) ? (i[t] = g ? m[t] : y[t]) : (g = !0) + const p = d + ? (function (t) { + const e = ht(t.weekYear), + n = yt(t.weekNumber, 1, kt(t.weekYear)), + r = yt(t.weekday, 1, 7) + return e + ? n + ? !r && jn("weekday", t.weekday) + : jn("week", t.week) + : jn("weekYear", t.weekYear) + })(i) + : a + ? (function (t) { + const e = ht(t.year), + n = yt(t.ordinal, 1, St(t.year)) + return e ? !n && jn("ordinal", t.ordinal) : jn("year", t.year) + })(i) + : Bn(i), + w = p || Qn(i) + if (w) return Sr.invalid(w) + const b = d ? Jn(i) : a ? Xn(i) : i, + [v, O] = ar(b, s, n), + S = new Sr({ ts: v, zone: n, o: O, loc: h }) + return i.weekday && l && t.weekday !== S.weekday + ? Sr.invalid( + "mismatched weekday", + `you can't specify both a weekday of ${i.weekday} and a date of ${S.toISO()}` + ) + : S + } + static fromISO(t, e = {}) { + const [n, r] = (function (t) { + return Ee(t, [tn, sn], [en, an], [nn, on], [rn, un]) + })(t) + return ur(n, r, e, "ISO 8601", t) + } + static fromRFC2822(t, e = {}) { + const [n, r] = (function (t) { + return Ee( + (function (t) { + return t + .replace(/\([^)]*\)|[\n\t]/g, " ") + .replace(/(\s\s+)/g, " ") + .trim() + })(t), + [Pe, Je] + ) + })(t) + return ur(n, r, e, "RFC 2822", t) + } + static fromHTTP(t, e = {}) { + const [n, r] = (function (t) { + return Ee(t, [Ge, Qe], [Xe, Qe], [Be, Ke]) + })(t) + return ur(n, r, e, "HTTP", e) + } + static fromFormat(t, e, n = {}) { + if (lt(t) || lt(e)) throw new $("fromFormat requires an input string and a format") + const { locale: r = null, numberingSystem: s = null } = n, + i = ke.fromOpts({ locale: r, numberingSystem: s, defaultToEN: !0 }), + [a, o, u, l] = (function (t, e, n) { + const { result: r, zone: s, specificOffset: i, invalidReason: a } = Rn(t, e, n) + return [r, s, i, a] + })(i, t, e) + return l ? Sr.invalid(l) : ur(a, o, n, `format ${e}`, t, u) + } + static fromString(t, e, n = {}) { + return Sr.fromFormat(t, e, n) + } + static fromSQL(t, e = {}) { + const [n, r] = (function (t) { + return Ee(t, [cn, sn], [hn, dn]) + })(t) + return ur(n, r, e, "SQL", t) + } + static invalid(t, e = null) { + if (!t) throw new $("need to specify a reason the DateTime is invalid") + const n = t instanceof Xt ? t : new Xt(t, e) + if (me.throwOnInvalid) throw new V(n) + return new Sr({ invalid: n }) + } + static isDateTime(t) { + return (t && t.isLuxonDateTime) || !1 + } + static parseFormatForOpts(t, e = {}) { + const n = zn(t, ke.fromObject(e)) + return n ? n.map((t) => (t ? t.val : null)).join("") : null + } + get(t) { + return this[t] + } + get isValid() { + return null === this.invalid + } + get invalidReason() { + return this.invalid ? this.invalid.reason : null + } + get invalidExplanation() { + return this.invalid ? this.invalid.explanation : null + } + get locale() { + return this.isValid ? this.loc.locale : null + } + get numberingSystem() { + return this.isValid ? this.loc.numberingSystem : null + } + get outputCalendar() { + return this.isValid ? this.loc.outputCalendar : null + } + get zone() { + return this._zone + } + get zoneName() { + return this.isValid ? this.zone.name : null + } + get year() { + return this.isValid ? this.c.year : NaN + } + get quarter() { + return this.isValid ? Math.ceil(this.c.month / 3) : NaN + } + get month() { + return this.isValid ? this.c.month : NaN + } + get day() { + return this.isValid ? this.c.day : NaN + } + get hour() { + return this.isValid ? this.c.hour : NaN + } + get minute() { + return this.isValid ? this.c.minute : NaN + } + get second() { + return this.isValid ? this.c.second : NaN + } + get millisecond() { + return this.isValid ? this.c.millisecond : NaN + } + get weekYear() { + return this.isValid ? nr(this).weekYear : NaN + } + get weekNumber() { + return this.isValid ? nr(this).weekNumber : NaN + } + get weekday() { + return this.isValid ? nr(this).weekday : NaN + } + get ordinal() { + return this.isValid ? Gn(this.c).ordinal : NaN + } + get monthShort() { + return this.isValid ? Tn.months("short", { locObj: this.loc })[this.month - 1] : null + } + get monthLong() { + return this.isValid ? Tn.months("long", { locObj: this.loc })[this.month - 1] : null + } + get weekdayShort() { + return this.isValid ? Tn.weekdays("short", { locObj: this.loc })[this.weekday - 1] : null + } + get weekdayLong() { + return this.isValid ? Tn.weekdays("long", { locObj: this.loc })[this.weekday - 1] : null + } + get offset() { + return this.isValid ? +this.o : NaN + } + get offsetNameShort() { + return this.isValid + ? this.zone.offsetName(this.ts, { format: "short", locale: this.locale }) + : null + } + get offsetNameLong() { + return this.isValid + ? this.zone.offsetName(this.ts, { format: "long", locale: this.locale }) + : null + } + get isOffsetFixed() { + return this.isValid ? this.zone.isUniversal : null + } + get isInDST() { + return ( + !this.isOffsetFixed && + (this.offset > this.set({ month: 1, day: 1 }).offset || + this.offset > this.set({ month: 5 }).offset) + ) + } + get isInLeapYear() { + return Ot(this.year) + } + get daysInMonth() { + return Tt(this.year, this.month) + } + get daysInYear() { + return this.isValid ? St(this.year) : NaN + } + get weeksInWeekYear() { + return this.isValid ? kt(this.weekYear) : NaN + } + resolvedLocaleOptions(t = {}) { + const { + locale: e, + numberingSystem: n, + calendar: r, + } = Gt.create(this.loc.clone(t), t).resolvedOptions(this) + return { locale: e, numberingSystem: n, outputCalendar: r } + } + toUTC(t = 0, e = {}) { + return this.setZone(ie.instance(t), e) + } + toLocal() { + return this.setZone(me.defaultZone) + } + setZone(t, { keepLocalTime: e = !1, keepCalendarTime: n = !1 } = {}) { + if ((t = oe(t, me.defaultZone)).equals(this.zone)) return this + if (t.isValid) { + let r = this.ts + if (e || n) { + const e = t.offset(this.ts), + n = this.toObject() + ;[r] = ar(n, e, t) + } + return rr(this, { ts: r, zone: t }) + } + return Sr.invalid(er(t)) + } + reconfigure({ locale: t, numberingSystem: e, outputCalendar: n } = {}) { + return rr(this, { loc: this.loc.clone({ locale: t, numberingSystem: e, outputCalendar: n }) }) + } + setLocale(t) { + return this.reconfigure({ locale: t }) + } + set(t) { + if (!this.isValid) return this + const e = Ct(t, wr), + n = !lt(e.weekYear) || !lt(e.weekNumber) || !lt(e.weekday), + r = !lt(e.ordinal), + s = !lt(e.year), + i = !lt(e.month) || !lt(e.day), + a = s || i, + o = e.weekYear || e.weekNumber + if ((a || r) && o) + throw new L("Can't mix weekYear/weekNumber units with year/month/day or ordinals") + if (i && r) throw new L("Can't mix ordinal dates with month/day") + let u + n + ? (u = Jn({ ...Pn(this.c), ...e })) + : lt(e.ordinal) + ? ((u = { ...this.toObject(), ...e }), + lt(e.day) && (u.day = Math.min(Tt(u.year, u.month), u.day))) + : (u = Xn({ ...Gn(this.c), ...e })) + const [l, c] = ar(u, this.o, this.zone) + return rr(this, { ts: l, o: c }) + } + plus(t) { + return this.isValid ? rr(this, or(this, vn.fromDurationLike(t))) : this + } + minus(t) { + return this.isValid ? rr(this, or(this, vn.fromDurationLike(t).negate())) : this + } + startOf(t) { + if (!this.isValid) return this + const e = {}, + n = vn.normalizeUnit(t) + switch (n) { + case "years": + e.month = 1 + case "quarters": + case "months": + e.day = 1 + case "weeks": + case "days": + e.hour = 0 + case "hours": + e.minute = 0 + case "minutes": + e.second = 0 + case "seconds": + e.millisecond = 0 + } + if (("weeks" === n && (e.weekday = 1), "quarters" === n)) { + const t = Math.ceil(this.month / 3) + e.month = 3 * (t - 1) + 1 + } + return this.set(e) + } + endOf(t) { + return this.isValid + ? this.plus({ [t]: 1 }) + .startOf(t) + .minus(1) + : this + } + toFormat(t, e = {}) { + return this.isValid + ? Gt.create(this.loc.redefaultToEN(e)).formatDateTimeFromString(this, t) + : Kn + } + toLocaleString(t = q, e = {}) { + return this.isValid ? Gt.create(this.loc.clone(e), t).formatDateTime(this) : Kn + } + toLocaleParts(t = {}) { + return this.isValid ? Gt.create(this.loc.clone(t), t).formatDateTimeParts(this) : [] + } + toISO({ + format: t = "extended", + suppressSeconds: e = !1, + suppressMilliseconds: n = !1, + includeOffset: r = !0, + extendedZone: s = !1, + } = {}) { + if (!this.isValid) return null + const i = "extended" === t + let a = cr(this, i) + return (a += "T"), (a += hr(this, i, e, n, r, s)), a + } + toISODate({ format: t = "extended" } = {}) { + return this.isValid ? cr(this, "extended" === t) : null + } + toISOWeekDate() { + return lr(this, "kkkk-'W'WW-c") + } + toISOTime({ + suppressMilliseconds: t = !1, + suppressSeconds: e = !1, + includeOffset: n = !0, + includePrefix: r = !1, + extendedZone: s = !1, + format: i = "extended", + } = {}) { + return this.isValid ? (r ? "T" : "") + hr(this, "extended" === i, e, t, n, s) : null + } + toRFC2822() { + return lr(this, "EEE, dd LLL yyyy HH:mm:ss ZZZ", !1) + } + toHTTP() { + return lr(this.toUTC(), "EEE, dd LLL yyyy HH:mm:ss 'GMT'") + } + toSQLDate() { + return this.isValid ? cr(this, !0) : null + } + toSQLTime({ includeOffset: t = !0, includeZone: e = !1, includeOffsetSpace: n = !0 } = {}) { + let r = "HH:mm:ss.SSS" + return (e || t) && (n && (r += " "), e ? (r += "z") : t && (r += "ZZ")), lr(this, r, !0) + } + toSQL(t = {}) { + return this.isValid ? `${this.toSQLDate()} ${this.toSQLTime(t)}` : null + } + toString() { + return this.isValid ? this.toISO() : Kn + } + valueOf() { + return this.toMillis() + } + toMillis() { + return this.isValid ? this.ts : NaN + } + toSeconds() { + return this.isValid ? this.ts / 1e3 : NaN + } + toUnixInteger() { + return this.isValid ? Math.floor(this.ts / 1e3) : NaN + } + toJSON() { + return this.toISO() + } + toBSON() { + return this.toJSDate() + } + toObject(t = {}) { + if (!this.isValid) return {} + const e = { ...this.c } + return ( + t.includeConfig && + ((e.outputCalendar = this.outputCalendar), + (e.numberingSystem = this.loc.numberingSystem), + (e.locale = this.loc.locale)), + e + ) + } + toJSDate() { + return new Date(this.isValid ? this.ts : NaN) + } + diff(t, e = "milliseconds", n = {}) { + if (!this.isValid || !t.isValid) return vn.invalid("created by diffing an invalid DateTime") + const r = { locale: this.locale, numberingSystem: this.numberingSystem, ...n }, + s = ((o = e), Array.isArray(o) ? o : [o]).map(vn.normalizeUnit), + i = t.valueOf() > this.valueOf(), + a = (function (t, e, n, r) { + let [s, i, a, o] = (function (t, e, n) { + const r = [ + ["years", (t, e) => e.year - t.year], + ["quarters", (t, e) => e.quarter - t.quarter], + ["months", (t, e) => e.month - t.month + 12 * (e.year - t.year)], + [ + "weeks", + (t, e) => { + const n = Mn(t, e) + return (n - (n % 7)) / 7 + }, + ], + ["days", Mn], + ], + s = {} + let i, a + for (const [o, u] of r) + if (n.indexOf(o) >= 0) { + i = o + let n = u(t, e) + ;(a = t.plus({ [o]: n })), + a > e ? ((t = t.plus({ [o]: n - 1 })), (n -= 1)) : (t = a), + (s[o] = n) + } + return [t, s, a, i] + })(t, e, n) + const u = e - s, + l = n.filter((t) => ["hours", "minutes", "seconds", "milliseconds"].indexOf(t) >= 0) + 0 === l.length && + (a < e && (a = s.plus({ [o]: 1 })), a !== s && (i[o] = (i[o] || 0) + u / (a - s))) + const c = vn.fromObject(i, r) + return l.length > 0 + ? vn + .fromMillis(u, r) + .shiftTo(...l) + .plus(c) + : c + })(i ? this : t, i ? t : this, s, r) + var o + return i ? a.negate() : a + } + diffNow(t = "milliseconds", e = {}) { + return this.diff(Sr.now(), t, e) + } + until(t) { + return this.isValid ? Sn.fromDateTimes(this, t) : this + } + hasSame(t, e) { + if (!this.isValid) return !1 + const n = t.valueOf(), + r = this.setZone(t.zone, { keepLocalTime: !0 }) + return r.startOf(e) <= n && n <= r.endOf(e) + } + equals(t) { + return ( + this.isValid && + t.isValid && + this.valueOf() === t.valueOf() && + this.zone.equals(t.zone) && + this.loc.equals(t.loc) + ) + } + toRelative(t = {}) { + if (!this.isValid) return null + const e = t.base || Sr.fromObject({}, { zone: this.zone }), + n = t.padding ? (this < e ? -t.padding : t.padding) : 0 + let r = ["years", "months", "days", "hours", "minutes", "seconds"], + s = t.unit + return ( + Array.isArray(t.unit) && ((r = t.unit), (s = void 0)), + vr(e, this.plus(n), { ...t, numeric: "always", units: r, unit: s }) + ) + } + toRelativeCalendar(t = {}) { + return this.isValid + ? vr(t.base || Sr.fromObject({}, { zone: this.zone }), this, { + ...t, + numeric: "auto", + units: ["years", "months", "days"], + calendary: !0, + }) + : null + } + static min(...t) { + if (!t.every(Sr.isDateTime)) throw new $("min requires all arguments be DateTimes") + return ft(t, (t) => t.valueOf(), Math.min) + } + static max(...t) { + if (!t.every(Sr.isDateTime)) throw new $("max requires all arguments be DateTimes") + return ft(t, (t) => t.valueOf(), Math.max) + } + static fromFormatExplain(t, e, n = {}) { + const { locale: r = null, numberingSystem: s = null } = n + return Rn(ke.fromOpts({ locale: r, numberingSystem: s, defaultToEN: !0 }), t, e) + } + static fromStringExplain(t, e, n = {}) { + return Sr.fromFormatExplain(t, e, n) + } + static get DATE_SHORT() { + return q + } + static get DATE_MED() { + return Y + } + static get DATE_MED_WITH_WEEKDAY() { + return j + } + static get DATE_FULL() { + return H + } + static get DATE_HUGE() { + return U + } + static get TIME_SIMPLE() { + return W + } + static get TIME_WITH_SECONDS() { + return P + } + static get TIME_WITH_SHORT_OFFSET() { + return J + } + static get TIME_WITH_LONG_OFFSET() { + return G + } + static get TIME_24_SIMPLE() { + return X + } + static get TIME_24_WITH_SECONDS() { + return B + } + static get TIME_24_WITH_SHORT_OFFSET() { + return Q + } + static get TIME_24_WITH_LONG_OFFSET() { + return K + } + static get DATETIME_SHORT() { + return tt + } + static get DATETIME_SHORT_WITH_SECONDS() { + return et + } + static get DATETIME_MED() { + return nt + } + static get DATETIME_MED_WITH_SECONDS() { + return rt + } + static get DATETIME_MED_WITH_WEEKDAY() { + return st + } + static get DATETIME_FULL() { + return it + } + static get DATETIME_FULL_WITH_SECONDS() { + return at + } + static get DATETIME_HUGE() { + return ot + } + static get DATETIME_HUGE_WITH_SECONDS() { + return ut + } + } + function Tr(t) { + if (Sr.isDateTime(t)) return t + if (t && t.valueOf && ct(t.valueOf())) return Sr.fromJSDate(t) + if (t && "object" == typeof t) return Sr.fromObject(t) + throw new $(`Unknown datetime argument: ${t}, of type ${typeof t}`) + } + const Mr = (() => { + const t = { + MONTHS: [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ], + COLORS: [ + "#4dc9f6", + "#f67019", + "#f53794", + "#537bc4", + "#acc236", + "#166a8f", + "#00a950", + "#58595b", + "#8549ba", + ], + CHART_COLORS: { + red: "rgb(255, 99, 132)", + orange: "rgb(255, 159, 64)", + yellow: "rgb(255, 205, 86)", + green: "rgb(75, 192, 192)", + blue: "rgb(54, 162, 235)", + purple: "rgb(153, 102, 255)", + grey: "rgb(201, 203, 207)", + }, + } + class e { + constructor(t) { + ;(this._seed = Date.now()), + (this.MONTHS = t.MONTHS), + (this.COLORS = t.COLORS), + (this.CHART_COLORS = t.CHART_COLORS), + (this.NAMED_COLORS = [ + this.CHART_COLORS.red, + this.CHART_COLORS.orange, + this.CHART_COLORS.yellow, + this.CHART_COLORS.green, + this.CHART_COLORS.blue, + this.CHART_COLORS.purple, + this.CHART_COLORS.grey, + ]) + } + valueOrDefault(t, e) { + return void 0 === t ? e : t + } + srand(t) { + this._seed = t + } + rand(t, e) { + return ( + (t = this.valueOrDefault(t, 0)), + (e = this.valueOrDefault(e, 0)), + (this._seed = (9301 * this._seed + 49297) % 233280), + t + (this._seed / 233280) * (e - t) + ) + } + numbers(t) { + const e = t || {}, + n = this.valueOrDefault(e.min, 0), + r = this.valueOrDefault(e.max, 100), + s = this.valueOrDefault(e.from, []), + i = this.valueOrDefault(e.count, 8), + a = this.valueOrDefault(e.decimals, 8), + o = this.valueOrDefault(e.continuity, 1), + u = Math.pow(10, a) || 0, + l = [] + let c, h + for (c = 0; c < i; ++c) + (h = (s[c] || 0) + this.rand(n, r)), + this.rand() <= o ? l.push(Math.round(u * h) / u) : l.push(null) + return l + } + points(t) { + const e = this.numbers(t), + n = this.numbers(t) + return e.map((t, e) => ({ x: t, y: n[e] })) + } + bubbles(t) { + return this.points(t).map((e) => ((e.r = this.rand(t.rmin, t.rmax)), e)) + } + labels(t) { + const e = t || {}, + n = e.min || 0, + r = e.max || 100, + s = (r - n) / (e.count || 8), + i = e.decimals || 8, + a = Math.pow(10, i) || 0, + o = e.prefix || "", + u = [] + let l + for (l = n; l < r; l += s) u.push(o + Math.round(a * l) / a) + return u + } + months(t) { + const e = t || {}, + n = e.count || 12, + r = e.section, + s = [] + let i, a + for (i = 0; i < n; ++i) (a = this.MONTHS[Math.ceil(i) % 12]), s.push(a.substring(0, r)) + return s + } + color(t) { + return this.COLORS[t % this.COLORS.length] + } + transparentize(t, e) { + const n = void 0 === e ? 0.5 : 1 - e + return ((r = t), new x(r)).alpha(n).rgbString() + var r + } + namedColor(t) { + return this.NAMED_COLORS[t % this.NAMED_COLORS.length] + } + newDate(t) { + return Sr.now().plus({ days: t }).toJSDate() + } + newDateString(t) { + return Sr.now().plus({ days: t }).toISO() + } + parseISODate(t) { + return Sr.fromISO(t) + } + } + return { + init: (n) => { + const r = Object.assign({}, t, n) + return new e(r) + }, + } + })() + window.ChartUtils = Mr +})() diff --git a/lib/framework/static/js/ff_common1.js b/lib/framework/static/js/ff_common1.js index 804ef01..7090979 100644 --- a/lib/framework/static/js/ff_common1.js +++ b/lib/framework/static/js/ff_common1.js @@ -7,7 +7,7 @@ if (tmp.length == 2) { var PACKAGE_NAME = tmp[1]; var MODULE_NAME = tmp[2]; var PAGE_NAME = ""; -} else if (tmp.length == 4){ +} else if (tmp.length > 3){ var PACKAGE_NAME = tmp[1]; var MODULE_NAME = tmp[2]; var PAGE_NAME = tmp[3]; @@ -23,8 +23,6 @@ $(window).on("load resize", function (event) { }); $('#command_modal').on('show.bs.modal', function (event) { - console.log('111111111') - console.log(event); }) /////////////////////////////////////// @@ -113,7 +111,6 @@ function showModal(data='EMPTY', title='JSON', json=true) { data = JSON.stringify(data, null, 2); } document.getElementById("modal_body").innerHTML = '
' +data + '
'; - $("#large_modal").modal(); } @@ -168,7 +165,22 @@ function use_collapse(div, reverse=false) { } } - +// jquery extend function +// post로 요청하면서 리다이렉트 +$.extend( + { + redirectPost: function(location, args) + { + var form = ''; + $.each( args, function( key, value ) { + console.log(key); + console.log(value); + value = value.split('"').join('\"') + form += ''; + }); + $('
' + form + '
').appendTo($(document.body)).submit(); + } + }); @@ -282,20 +294,3 @@ function pad(n, width) { return n.length >= width ? n : new Array(width - n.length + 1).join('0') + n; } -// jquery extend function -// post로 요청하면서 리다이렉트 -// 푹 자동에서 푹 기본 검색할때 사용 -$.extend( -{ - redirectPost: function(location, args) - { - var form = ''; - $.each( args, function( key, value ) { - console.log(key); - console.log(value); - value = value.split('"').join('\"') - form += ''; - }); - $('
' + form + '
').appendTo($(document.body)).submit(); - } -}); \ No newline at end of file diff --git a/lib/framework/static/js/ff_global1.js b/lib/framework/static/js/ff_global1.js index f5e7ef1..7f3aa0d 100644 --- a/lib/framework/static/js/ff_global1.js +++ b/lib/framework/static/js/ff_global1.js @@ -15,11 +15,10 @@ $(document).ready(function(){ var protocol = window.location.protocol; var frameSocket = io.connect(protocol + "//" + document.domain + ":" + location.port + "/framework"); -console.log(frameSocket); frameSocket.on('notify', function(data){ $.notify({ - message : data['msg'], + message : '' + data['msg'] + '', url: data['url'], target: '_self' },{ @@ -29,7 +28,7 @@ frameSocket.on('notify', function(data){ }); frameSocket.on('modal', function(data){ - m_modal(data.data, data.title, false); + showModal(data.data, data.title, false); }); frameSocket.on('loading_hide', function(data){ @@ -37,14 +36,12 @@ frameSocket.on('loading_hide', function(data){ }); frameSocket.on('refresh', function(data){ - console.log('data') window.location.reload(); }); $('#command_modal').on('hide.bs.modal', function (e) { //e.preventDefault(); 있으면 동작 안함. - console.log("ff global command_modal hide.bs.modal CATCH") $.ajax({ url: `/global/ajax/command_modal_hide`, type: 'POST', @@ -74,13 +71,27 @@ $("body").on('click', '#globalLinkBtn', function(e) { window.location.href = url; }); +$("body").on('click', '#globalReloadBtn', function(e) { + e.preventDefault(); + location.reload(); +}); // global_link_btn 모두 찾아 변경 $("body").on('click', '#globalSettingSaveBtn', function(e){ e.preventDefault(); - globalSettingSave(); + if (globalSettingSaveBefore()) { + globalSettingSave(); + } }); +function globalSettingSaveBefore() { + return true; +} + +function globalSettingSaveAfter() { + return true; +} + function globalSettingSave() { var formData = getFormdata('#setting'); $.ajax({ @@ -94,6 +105,7 @@ function globalSettingSave() { $.notify('설정을 저장하였습니다.', { type: 'success' }); + globalSettingSaveAfter(); } else { $.notify('설정 저장에 실패하였습니다.', { type: 'warning' @@ -106,7 +118,10 @@ function globalSettingSave() { $("body").on('click', '#globalEditBtn', function(e) { e.preventDefault(); file = $(this).data('file'); - console.log(file); + if (file == null) { + var tag = $(this).data('tag'); + file = $('#' + tag).val(); + } $.ajax({ url: '/global/ajax/is_available_edit', type: "POST", @@ -236,107 +251,188 @@ $("body").on('click', '#globalImmediatelyExecutePageBtn', function(e){ }); }); - + +$("body").on('click', '#globalDbDeleteDayBtn', function(e){ + e.preventDefault(); + var tag_id = $(this).data('tag_id'); + var day = $('#' + tag_id).val(); + globalConfirmModal('DB 삭제', "최근 " + day + "일 이내 데이터를 제외하고 삭제 하시겠습니까?", function() { + globalDbDelete(day); + }); +}); + $("body").on('click', '#globalDbDeleteBtn', function(e){ e.preventDefault(); - document.getElementById("confirm_title").innerHTML = "DB 삭제"; - document.getElementById("confirm_body").innerHTML = "전체 목록을 삭제 하시겠습니까?"; - $('#confirm_button').attr('onclick', "globalDbDelete();"); - $("#confirm_modal").modal(); - return; + globalConfirmModal('DB 삭제', "전체 목록을 삭제 하시겠습니까?", function() { + globalDbDelete(0); + }); }); -function globalDbDelete() { +function globalDbDelete(day) { $.ajax({ - url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/reset_db', + url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/db_delete', type: "POST", cache: false, - data: {}, + data: {day:day}, dataType: "json", success: function (data) { - if (data) { - $.notify('삭제하였습니다.', { - type: 'success' - }); - } else { + if (data == -1) { $.notify('삭제에 실패하였습니다.',{ type: 'warning' }); + } else { + $.notify(''+data+'개를 삭제하였습니다.', { + type: 'success' + }); + globalRequestSearch('1'); } } }); } - + +/////////////////////////////////////////////////// + +$("body").on('click', '#globalDbDeleteDayPageBtn', function(e){ + e.preventDefault(); + var tag_id = $(this).data('tag_id'); + var day = $('#' + tag_id).val(); + globalConfirmModal('DB 삭제', day + "일 제외 목록을 삭제 하시겠습니까?", function() { + globalDbDeletePage(day); + }); +}); + + $("body").on('click', '#globalDbDeletePageBtn', function(e){ e.preventDefault(); - document.getElementById("confirm_title").innerHTML = "DB 삭제"; - document.getElementById("confirm_body").innerHTML = "전체 목록을 삭제 하시겠습니까?"; - $('#confirm_button').attr('onclick', "globalDbDeletePage();"); - $("#confirm_modal").modal(); - return; + globalConfirmModal('DB 삭제', "최근 " + day + "일 이내 데이터를 제외하고 삭제 하시겠습니까?", function() { + globalDbDeletePage(0); + }); }); -function globalDbDeletePage() { +function globalDbDeletePage(day) { $.ajax({ url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/' + PAGE_NAME + '/reset_db', type: "POST", cache: false, - data: {sub:sub}, + data: {day:day}, dataType: "json", success: function (data) { - if (data) { - $.notify('삭제하였습니다.', { - type: 'success' - }); - } else { + if (data == -1) { $.notify('삭제에 실패하였습니다.',{ type: 'warning' }); + } else { + $.notify(''+data+'개를 삭제하였습니다.', { + type: 'success' + }); + globalRequestSearch('1'); } } }); } +$("body").on('click', '#globalDbDeleteItemBtn', function(e){ + e.preventDefault(); + var db_id = $(this).data('id'); + $.ajax({ + url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/db_delete_item', + type: "POST", + cache: false, + data: {db_id:db_id}, + dataType: "json", + success: function (ret) { + if (ret) { + notify('삭제하였습니다.', 'success'); + globalRequestSearch(current_page); + } else { + notify('삭제에 실패하였습니다.', 'warning'); + } + } + }); +}); + +$("body").on('click', '#globalDbDeleteItemPageBtn', function(e){ + e.preventDefault(); + var db_id = $(this).data('id'); + $.ajax({ + url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/' + PAGE_NAME + '/db_delete_item', + type: "POST", + cache: false, + data: {db_id:db_id}, + dataType: "json", + success: function (ret) { + if (ret) { + notify('삭제하였습니다.', 'success'); + globalRequestSearch(current_page); + } else { + notify('삭제에 실패하였습니다.', 'warning'); + } + } + }); +}); + + +$("body").on('click', '#globalJsonBtn', function(e){ + e.preventDefault(); + showModal(current_data.list[$(this).data('idx')]); +}); + + + + + + + + + + /////////////////////////////////////// // Global - 함수 /////////////////////////////////////// -function globalSendCommand(command, arg1, arg2, arg3, modal_title, callback) { - console.log("globalSendCommand [" + command + '] [' + arg1 + '] [' + arg2 + '] [' + arg3 + '] [' + modal_title + '] [' + callback + ']'); - console.log('/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/command'); +function globalSendCommand(command, arg1, arg2, arg3, callback) { + var url = '/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/command'; + return globalSendCommandByUrl(url, command, arg1, arg2, arg3, callback); +} +function globalSendCommandByUrl(url, command, arg1, arg2, arg3, callback) { $.ajax({ - url: '/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/command', + url: url, type: "POST", cache: false, data:{command:command, arg1:arg1, arg2:arg2, arg3}, dataType: "json", success: function (ret) { + console.log(ret) if (ret.msg != null) notify(ret.msg, ret.ret); - if (ret.modal != null) showModal(ret.modal, modal_title, false); - if (ret.json != null) showModal(ret.json, modal_title, true); + if (ret.modal != null) showModal(ret.modal, ret.title, false); + if (ret.json != null) showModal(ret.json, ret.title, true); if (callback != null) callback(ret); + if (ret.reload) location.reload(); } }); } -function globalSendCommandPage(command, arg1, arg2, arg3, modal_title, callback) { - console.log("globalSendCommandPage [" + command + '] [' + arg1 + '] [' + arg2 + '] [' + arg3 + '] [' + modal_title + '] [' + callback + ']'); - console.log('/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/command'); +function globalSendCommandPage(command, arg1, arg2, arg3, callback) { + var url = '/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/' + PAGE_NAME + '/command'; + return globalSendCommandPageByUrl(url, command, arg1, arg2, arg3, callback); +} +function globalSendCommandPageByUrl(url, command, arg1, arg2, arg3, callback) { $.ajax({ - url: '/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/' + PAGE_NAME + '/command', + url: url, type: "POST", cache: false, data:{command:command, arg1:arg1, arg2:arg2, arg3}, dataType: "json", success: function (ret) { if (ret.msg != null) notify(ret.msg, ret.ret); - if (ret.modal != null) m_modal(ret.modal, modal_title, false); - if (ret.json != null) m_modal(ret.json, modal_title, true); + if (ret.modal != null) showModal(ret.modal, ret.title, false); + if (ret.json != null) showModal(ret.json, ret.title, true); if (callback != null) callback(ret); + if (ret.reload) location.reload(); } }); } @@ -400,6 +496,10 @@ function make_page_html(data) { str += '' } + if (data.last_page != data.total_page) { + str += '' + } + str += ' \ \ \ @@ -431,6 +531,22 @@ $("body").on('click', '#globalSearchResetBtn', function(e){ }); +$("body").on('change', '#option1', function(e){ + e.preventDefault(); + globalRequestSearch(1); +}); + +$("body").on('change', '#option2', function(e){ + e.preventDefault(); + globalRequestSearch(1); +}); + +$("body").on('change', '#order', function(e){ + e.preventDefault(); + globalRequestSearch(1); +}); + + /////////////////////////////////////// // 파일 선택 모달 @@ -483,7 +599,6 @@ let listdir = (path = '/', only_dir = true) => { }, dataType: 'json' }).done((datas) => { - console.log(datas) if (datas.length == 0) { return false; } @@ -510,8 +625,6 @@ let listdir = (path = '/', only_dir = true) => { } else { //new_path = (path !== path_spliter) ? path + path_spliter + $(evt.currentTarget).text() : path + $(evt.currentTarget).text(); new_path = $(evt.currentTarget).data('value'); - console.log(new_path) - console.log(evt) } */ @@ -587,3 +700,23 @@ function ResizeTextArea() { /////////////////////////////////////// + + +/////////////////////////////////////// +// Confirm MODAL +/////////////////////////////////////// + +function globalConfirmModal(title, body, func) { + $("#confirm_title").html(title); + $("#confirm_body").html(body); + //$('#confirm_button').attr('onclick', func); + $("body").on('click', '#confirm_button', function(e){ + e.stopImmediatePropagation(); + e.preventDefault(); + func(); + }); + $("#confirm_modal").modal(); +} + + + diff --git a/lib/framework/static/js/ff_global_plugin.js b/lib/framework/static/js/ff_global_plugin.js new file mode 100644 index 0000000..2ed7346 --- /dev/null +++ b/lib/framework/static/js/ff_global_plugin.js @@ -0,0 +1,14 @@ +/////////////////////////////////////// +// 자주 사용하는 플러그인에 전용 명령 + +function pluginRcloneLs(remote_path) { + var url = '/rclone/ajax/config/command'; + globalSendCommandByUrl(url, "ls", remote_path); +} + +function pluginRcloneSize(remote_path) { + var url = '/rclone/ajax/config/command'; + globalSendCommandByUrl(url, "size", remote_path); +} + + diff --git a/lib/framework/static/js/ff_ui1.js b/lib/framework/static/js/ff_ui1.js index 2883651..a2ae43f 100644 --- a/lib/framework/static/js/ff_ui1.js +++ b/lib/framework/static/js/ff_ui1.js @@ -10,12 +10,13 @@ function j_button_group(h) { } // primary, secondary, success, danger, warning, info, light, dark, white -function j_button(id, text, data={}, color='primary', outline=true, small=false) { +function j_button(id, text, data={}, color='primary', outline=true, small=false, _class='') { var str = ' + + + + {% endmacro %} + + + + +{% macro print_md(id, text) %} +
+ +{% endmacro %} + +{% macro print_md1(id, text) %} + + +{% endmacro %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {% macro setting_default_checkbox(id, left, label, value, desc='') %} @@ -584,31 +728,6 @@ option을 script로 넣을 때 사용 {{ setting_bottom(desc) }} {% endmacro %} - -{% macro setting_scheduler_switch(left='스케쥴링 작동', desc=['On : 스케쥴링 시작','Off : 스케쥴링 중지'], is_include='False', is_running='False') %} - {{ setting_top(left) }} -
- {% if is_include == 'True' %} - - {% else %} - - {% endif %} - {% if is_running == 'True' %} - 동작중 - {% else %} - {% if is_include == 'True' %} - 대기중 - {% endif %} - {% endif %} -
- {{ setting_bottom(desc) }} -{% endmacro %} - - - - - - {% macro setting_select(id, title, options, col='9', desc=None, value=None) %} {{ setting_top(title) }} @@ -655,21 +794,6 @@ macros.setting_button_with_info([['toggle_btn', 'Toggle', [{'key':'category', 'v {{ setting_bottom(desc) }} {% endmacro %} -{% macro select(id, options, col='3', value=None) %} -
- - -
-{% endmacro %} @@ -703,15 +827,6 @@ macros.setting_button_with_info([['toggle_btn', 'Toggle', [{'key':'category', 'v - - - - - - - - - {% macro setting_progress(id, left='', desc='') %} {{ setting_top(left) }} @@ -725,66 +840,6 @@ macros.setting_button_with_info([['toggle_btn', 'Toggle', [{'key':'category', 'v {% endmacro %} - -{% macro setting_scheduler_button(is_include, is_running, id='scheduler', left='스케쥴링 작동', desc=['On : 스케쥴링 시작','Off : 스케쥴링 중지']) %} -{{ setting_top(left) }} -
- {% if is_include == 'True' %} - - {% else %} - - {% endif %} - {% if is_running == 'True' %} - 동작중 - {% else %} - {% if is_include == 'True' %} - 대기중 - {% endif %} - {% endif %} -
-{{ setting_bottom(desc) }} -{% endmacro %} - - - - -{% macro setting_global_scheduler_sub_button(is_include, is_running, id='scheduler', left='스케쥴링 작동', desc=['On : 스케쥴링 시작','Off : 스케쥴링 중지']) %} -{{ setting_top(left) }} -
- {% if is_include == 'True' %} - - {% else %} - - {% endif %} - {% if is_running == 'True' %} - 동작중 - {% else %} - {% if is_include == 'True' %} - 대기중 - {% endif %} - {% endif %} -
-{{ setting_bottom(desc) }} -{% endmacro %} - -{% macro setting_global_scheduler_sublogic_button(is_include, is_running, id='scheduler', left='스케쥴링 작동', desc=['On : 스케쥴링 시작','Off : 스케쥴링 중지']) %} -{{ setting_top(left) }} -
- {% if is_include == 'True' %} - - {% else %} - - {% endif %} - {% if is_running == 'True' %} - 동작중 - {% else %} - {% if is_include == 'True' %} - 대기중 - {% endif %} - {% endif %} -
-{{ setting_bottom(desc) }} -{% endmacro %} @@ -803,14 +858,7 @@ macros.setting_button_with_info([['toggle_btn', 'Toggle', [{'key':'category', 'v {% endmacro %} -{% macro m_hr_head_top() %} -
-
-{% endmacro %} -{% macro m_hr_head_bottom() %} -
-{% endmacro %} {% macro m_button(id, text) %} @@ -836,59 +884,6 @@ macros.setting_button_with_info([['toggle_btn', 'Toggle', [{'key':'category', 'v -{% macro m_modal_start(id, title, size) %} - - - -{% endmacro %} - - -{% macro m_modal_start2(id, title, size) %} - - - -{% endmacro %} - - - - - {% macro row_start(padding='10') %}
@@ -1002,16 +997,3 @@ macros.setting_button_with_info([['toggle_btn', 'Toggle', [{'key':'category', 'v - - -{% macro buttons(buttons, left='', desc='') %} - {{ setting_top(left) }} -
-
- {% for b in buttons %} - - {% endfor %} -
-
- {{ setting_bottom(desc) }} -{% endmacro %} \ No newline at end of file diff --git a/lib/framework/templates/macro_include.html b/lib/framework/templates/macro_include.html index 691b632..d8c028f 100644 --- a/lib/framework/templates/macro_include.html +++ b/lib/framework/templates/macro_include.html @@ -14,7 +14,7 @@
@@ -70,7 +70,7 @@ diff --git a/lib/framework/templates/macro_menu.html b/lib/framework/templates/macro_menu.html index 5d407a3..8946f06 100644 --- a/lib/framework/templates/macro_menu.html +++ b/lib/framework/templates/macro_menu.html @@ -19,7 +19,7 @@ {% if 'uri' in category and category['uri'].startswith('http') %} {% elif 'uri' in category and category['uri'].startswith('http') == False %} - + {% else %}