diff --git a/Makefile b/Makefile index df56c6b..007a7bf 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,10 @@ help: @echo "- make npm-watch Run npm build when files change" lint: - python3 setup.py flake8 + flake8 airflow_code_editor tests + +black: + black -S airflow_code_editor tests tag: @grep -q "## $$(cat airflow_code_editor/VERSION)" changelog.txt || (echo "Missing changelog !!! Update changelog.txt"; exit 1) @@ -41,7 +44,7 @@ coverage: codemirror: @rm -rf codemirror_src codemirror.zip - @curl -O https://codemirror.net/codemirror.zip + @curl -O https://codemirror.net/5/codemirror.zip @unzip codemirror.zip -d codemirror_src @mv codemirror_src/codemirror-*/* codemirror_src @rm codemirror.zip @@ -55,7 +58,7 @@ codemirror: @python3 update_themes_js.py npm-build: - @NODE_OPTIONS=--openssl-legacy-provider npm run build + @npm run build npm-watch: @NODE_OPTIONS=--openssl-legacy-provider npm run watch diff --git a/README.md b/README.md index 8eea2bb..e1e6a63 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,15 @@ If git support is enabled, the DAGs are stored in a Git repository. You may use pip install airflow-code-editor ``` -2. (Optional) Install Black Python code formatter. +2. Install optional dependencies + +* black - Black Python code formatter +* fs-s3fs - S3FS Amazon S3 Filesystem +* fs-gcsfs - Google Cloud Storage Filesystem +* ... other filesystems supported by PyFilesystem - see https://www.pyfilesystem.org/page/index-of-filesystems/ ```bash - pip install black + pip install black fs-s3fs fs-gcsfs ``` 3. Restart the Airflow Web Server @@ -60,12 +65,10 @@ All the settings are optional. * **git_author_email** email for the author/committer (default: logged user email) * **git_init_repo** initialize a git repo in DAGs folder (default: True) * **root_directory** root folder (default: Airflow DAGs folder) -* **mount_name**, **mount1_name**, ... configure additional file folder name (mount point) -* **mount_path**, **mount1_path**, ... configure additional file path * **line_length** Python code formatter - max line length (default: 88) * **string_normalization** Python code formatter - if true normalize string quotes and prefixes (default: False) +* **mount**, **mount1**, ... configure additional folder (mount point) - format: name=xxx,path=yyy -Example: ``` [code_editor] enabled = True @@ -76,12 +79,21 @@ Example: root_directory = /home/airflow/dags line_length = 88 string_normalization = False - mount_name = data - mount_path = /home/airflow/data - mount1_name = logs - mount1_path = /home/airflow/logs + mount = name=data,path=/home/airflow/data + mount1 = name=logs,path=/home/airflow/logs + mount2 = name=data,path=s3://example ``` +Mount Options: + +* **name**: mount name (destination) +* **path**: local path or PyFilesystem FS URLs - see https://docs.pyfilesystem.org/en/latest/openers.html + +Example: +* name=ftp_server,path=ftp://user:pass@ftp.example.org/private +* name=data,path=s3://example +* name=tmp,path=/tmp + You can also set options with the following environment variables: * AIRFLOW__CODE_EDITOR__ENABLED @@ -94,20 +106,14 @@ You can also set options with the following environment variables: * AIRFLOW__CODE_EDITOR__ROOT_DIRECTORY * AIRFLOW__CODE_EDITOR__LINE_LENGTH * AIRFLOW__CODE_EDITOR__STRING_NORMALIZATION -* AIRFLOW__CODE_EDITOR__MOUNT_NAME -* AIRFLOW__CODE_EDITOR__MOUNT_PATH -* AIRFLOW__CODE_EDITOR__MOUNT1_NAME, AIRFLOW__CODE_EDITOR__MOUNT2_NAME, ... -* AIRFLOW__CODE_EDITOR__MOUNT1_PATH, AIRFLOW__CODE_EDITOR__MOUNT2_PATH, ... +* AIRFLOW__CODE_EDITOR__MOUNT, AIRFLOW__CODE_EDITOR__MOUNT1, AIRFLOW__CODE_EDITOR__MOUNT2, ... Example: ``` export AIRFLOW__CODE_EDITOR__STRING_NORMALIZATION=True - export AIRFLOW__CODE_EDITOR__MOUNT_NAME='data' - export AIRFLOW__CODE_EDITOR__MOUNT_PATH='/home/airflow/data' - export AIRFLOW__CODE_EDITOR__MOUNT1_NAME='logs' - export AIRFLOW__CODE_EDITOR__MOUNT1_PATH='/home/airflow/logs' - export AIRFLOW__CODE_EDITOR__MOUNT2_NAME='tmp' - export AIRFLOW__CODE_EDITOR__MOUNT2_PATH='/tmp' + export AIRFLOW__CODE_EDITOR__MOUNT='name=data,path=/home/airflow/data' + export AIRFLOW__CODE_EDITOR__MOUNT1='name=logs,path=/home/airflow/logs' + export AIRFLOW__CODE_EDITOR__MOUNT2='name=tmp,path=/tmp' ``` ### Development Instructions @@ -167,3 +173,6 @@ Example: * Vue-tree, TreeView control for VueJS - https://github.com/grapoza/vue-tree * Splitpanes - https://github.com/antoniandre/splitpanes * Axios, Promise based HTTP client for the browser and node.js - https://github.com/axios/axios +* PyFilesystem2, Python's Filesystem abstraction layer - https://github.com/PyFilesystem/pyfilesystem2 +* Amazon S3 PyFilesystem - https://github.com/PyFilesystem/s3fs +* Google Cloud Storage PyFilesystem - https://github.com/Othoz/gcsfs diff --git a/airflow_code_editor/VERSION b/airflow_code_editor/VERSION index ce7f2b4..09b254e 100644 --- a/airflow_code_editor/VERSION +++ b/airflow_code_editor/VERSION @@ -1 +1 @@ -5.2.2 +6.0.0 diff --git a/airflow_code_editor/app_builder_view.py b/airflow_code_editor/app_builder_view.py index 796f9ce..e33c588 100644 --- a/airflow_code_editor/app_builder_view.py +++ b/airflow_code_editor/app_builder_view.py @@ -98,7 +98,6 @@ def _render(self, template, *args, **kargs): **kargs ) - except (ImportError, ModuleNotFoundError): from airflow_code_editor.auth import has_access from airflow.www_rbac.decorators import has_dag_access diff --git a/airflow_code_editor/code_editor_view.py b/airflow_code_editor/code_editor_view.py index 65f84aa..ea4331d 100644 --- a/airflow_code_editor/code_editor_view.py +++ b/airflow_code_editor/code_editor_view.py @@ -15,11 +15,9 @@ # limitations under the Licens # -import os -import os.path import logging import mimetypes -from flask import abort, request, send_file +from flask import abort, request from flask_wtf.csrf import generate_csrf from airflow.version import version from airflow_code_editor.commons import HTTP_404_NOT_FOUND @@ -27,12 +25,14 @@ from airflow_code_editor.utils import ( get_plugin_boolean_config, get_plugin_int_config, - git_absolute_path, - execute_git_command, error_message, normalize_path, prepare_api_response, ) +from airflow_code_editor.git import ( + execute_git_command, +) +from airflow_code_editor.fs import RootFS __all__ = ["AbstractCodeEditorView"] @@ -48,22 +48,16 @@ def _index(self): def _save(self, path=None): try: - fullpath = git_absolute_path(path) mime_type = request.headers.get("Content-Type", "text/plain") is_text = mime_type.startswith("text/") if is_text: data = request.get_data(as_text=True) # Newline fix (remove cr) - data = data.replace("\r", "").rstrip() - os.makedirs(os.path.dirname(fullpath), exist_ok=True) - with open(fullpath, "w") as f: - f.write(data) - f.write("\n") + data = data.replace("\r", "").rstrip() + "\n" else: # Binary file data = request.get_data() - os.makedirs(os.path.dirname(fullpath), exist_ok=True) - with open(fullpath, "wb") as f: - f.write(data) + root_fs = RootFS() + root_fs.path(path).write_file(data=data, is_text=is_text) return prepare_api_response(path=normalize_path(path)) except Exception as ex: logging.error(ex) @@ -81,42 +75,49 @@ def _git_repo(self, path): return self._git_repo_get(path) def _git_repo_get(self, path): - " Get a file from GIT (invoked by the HTTP GET method) " - return execute_git_command(["cat-file", "-p", path]) + "Get a file from GIT (invoked by the HTTP GET method)" + try: + # Download git blob - path = '/' + path, attachment_filename = path.split('/', 1) + except: + # No attachment filename + attachment_filename = None + response = execute_git_command(["cat-file", "-p", path]) + if attachment_filename: + response.headers["Content-Disposition"] = ( + 'attachment; filename="{0}"'.format(attachment_filename) + ) + try: + content_type = mimetypes.guess_type(attachment_filename)[0] + if content_type: + response.headers["Content-Type"] = content_type + except Exception: + pass + return response def _git_repo_post(self, path): - " Execute a GIT command (invoked by the HTTP POST method) " + "Execute a GIT command (invoked by the HTTP POST method)" git_args = request.json.get('args', []) return execute_git_command(git_args) def _load(self, path): - " Send the contents of a file to the client " + "Send the contents of a file to the client" try: path = normalize_path(path) if path.startswith("~git/"): # Download git blob - path = '~git//' - _, path, filename = path.split("/", 3) - response = execute_git_command(["cat-file", "-p", path]) - response.headers["Content-Disposition"] = ( - 'attachment; filename="%s"' % filename - ) - try: - content_type = mimetypes.guess_type(filename)[0] - if content_type: - response.headers["Content-Type"] = content_type - except Exception: - pass - return response + _, path = path.split("/", 1) + return self._git_repo_get(path) else: # Download file - fullpath = git_absolute_path(path) - return send_file(fullpath, as_attachment=True) + root_fs = RootFS() + return root_fs.path(path).send_file(as_attachment=True) except Exception as ex: logging.error(ex) abort(HTTP_404_NOT_FOUND) def _format(self): - " Format code " + "Format code" try: import black @@ -141,7 +142,7 @@ def _format(self): ) ) - def _tree(self, path, args = {}): + def _tree(self, path, args={}): return {'value': get_tree(path, args)} def _ping(self): diff --git a/airflow_code_editor/commons.py b/airflow_code_editor/commons.py index dc38f2b..ad25c38 100644 --- a/airflow_code_editor/commons.py +++ b/airflow_code_editor/commons.py @@ -15,7 +15,7 @@ # limitations under the Licens # -import os +from pathlib import Path from typing import Any, Callable, Dict, List, Optional, Union __all__ = [ @@ -25,6 +25,7 @@ 'ROUTE', 'STATIC', 'CONFIG_SECTION', + 'DEFAULT_GIT_BRANCH', 'SUPPORTED_GIT_COMMANDS', 'HTTP_200_OK', 'HTTP_404_NOT_FOUND', @@ -34,7 +35,6 @@ 'VERSION_FILE', 'VERSION', 'Args', - 'Path', 'GitOutput', 'TreeOutput', 'TreeFunc', @@ -46,6 +46,7 @@ ROUTE = '/' + PLUGIN_NAME STATIC = '/static/' + PLUGIN_NAME CONFIG_SECTION = PLUGIN_NAME + '_plugin' +DEFAULT_GIT_BRANCH = 'main' HTTP_200_OK = 200 HTTP_404_NOT_FOUND = 404 SUPPORTED_GIT_COMMANDS = [ @@ -99,13 +100,11 @@ 'airflow_code_editor.js', ] -VERSION_FILE = os.path.join(os.path.dirname(__file__), "VERSION") -with open(VERSION_FILE) as f: - VERSION = f.read().strip() +VERSION_FILE = Path(__file__).parent / "VERSION" +VERSION = VERSION_FILE.read_text().strip() Args = Dict[str, str] -Path = Optional[str] GitOutput = Union[None, bytes, str] TreeOutput = List[Dict[str, Any]] -TreeFunc = Callable[[Path, Args], TreeOutput] +TreeFunc = Callable[[Optional[str], Args], TreeOutput] diff --git a/airflow_code_editor/fs.py b/airflow_code_editor/fs.py new file mode 100644 index 0000000..b40f8c1 --- /dev/null +++ b/airflow_code_editor/fs.py @@ -0,0 +1,273 @@ +#!/usr/bin/env python +# +# Copyright 2019 Andrea Bonomi +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the Licens + +import os +import fs +from fs.mountfs import MountFS, MountError +from fs.multifs import MultiFS +from fs.path import abspath, forcedir, normpath +from typing import Any, List, Union +from flask import abort, send_file, stream_with_context, Response +from airflow_code_editor.utils import read_mount_points_config +from airflow_code_editor.commons import HTTP_404_NOT_FOUND + +__all__ = [ + 'RootFS', +] + +STAT_FIELDS = [ + "st_mode", + "st_ino", + "st_dev", + "st_nlink", + "st_uid", + "st_gid", + "st_size", + "st_atime", + "st_mtime", + "st_ctime", +] + +SEND_FILE_CHUNK_SIZE = 8192 + + +def split(pathname: str): + "Split a pathname, returns tuple (head, tail)" + pathname = pathname.rstrip("/") + i = pathname.rfind("/") + 1 + if i == 0: + return ("/", pathname) + else: + return pathname[: i - 1], pathname[i:] + + +class RootFS(MountFS): + "Root filesystem with mountpoints" + + def __init__(self): + super().__init__() + mounts = read_mount_points_config() + # Set default fs (root) + self.default_fs = MultiFS() + self.tmp_fs = fs.open_fs("mem://") + self.default_fs.add_fs('tmp', self.tmp_fs, write=False, priority=0) + self.root_fs = [fs.open_fs(v.path) for v in mounts.values() if v.default][0] + self.default_fs.add_fs('root', self.root_fs, write=True, priority=1) + # Mount other fs + for k, v in mounts.items(): + if not v.default: + self.mount("/~" + k, fs.open_fs(v.path)) + + def mount(self, path, fs_): + "Mounts a host FS object on a given path" + if isinstance(fs_, str): + fs_ = fs.open_fs(fs_) + path_ = forcedir(abspath(normpath(path))) + for mount_path, _ in self.mounts: + if path_.startswith(mount_path): + raise MountError("mount point overlaps existing mount") + self.mounts.append((path_, fs_)) + # Create mountpoint on the temporary filesystem + self.tmp_fs.makedirs(path_, recreate=True) + + def path(self, *parts: List[str]): + "Return a FSPath instance for the given path" + return FSPath(*parts, root_fs=self) + + +class FSPath(object): + def __init__(self, *parts: List[str], root_fs: RootFS) -> None: + self.root_fs = root_fs + self.path = os.path.join("/", *parts) + + def open(self, mode='r', buffering=-1, encoding=None, errors=None, newline=None): + "Open the file pointed by this path and return a file object" + return self.root_fs.open( + self.path, + mode=mode, + buffering=buffering, + encoding=encoding, + errors=errors, + newline=newline, + ) + + @property + def name(self) -> str: + "The final path component" + return split(self.path)[1] + + @property + def parent(self): + "The logical parent of the path" + return self.root_fs.path(split(self.path)[0]) + + def touch(self, mode=0o666, exist_ok=True): + "Create this file" + return self.root_fs.touch(self.path) + + def rmdir(self) -> None: + "Remove this directory" + self.root_fs.removedir(self.path) + + def unlink(self, missing_ok: bool = False) -> None: + "Remove this file" + try: + self.root_fs.remove(self.path) + except fs.errors.ResourceNotFound: + if not missing_ok: + raise FileNotFoundError(self.path) + + def delete(self) -> None: + "Remove this file or directory" + if self.is_dir(): + self.rmdir() + else: + self.unlink() + + def stat(self): + "File stat" + info = self.root_fs.getinfo(self.path, namespaces=["stat"]) + if not info.has_namespace("stat"): + return os.stat_result([None for _ in STAT_FIELDS]) + return os.stat_result([info.raw["stat"].get(field) for field in STAT_FIELDS]) + + def is_dir(self) -> bool: + "Return True if this path is a directory" + try: + return self.root_fs.isdir(self.path) + except Exception: + return False + + def resolve(self): + "Make the path absolute" + return self.root_fs.path(os.path.realpath(self.path)) + + def exists(self): + "Check if this path exists" + return self.root_fs.exists(self.path) + + def iterdir(self): + "Iterate over the files in this directory" + try: + for name in sorted(self.root_fs.listdir(self.path)): + if name.startswith(".") or name == "__pycache__": + continue + yield self.root_fs.path(self.path, name) + except IOError: + yield from [] + + def size(self) -> int: + "Return file size for files and number of files for directories" + if self.is_dir(): + return len(self.root_fs.listdir(self.path)) + else: + return self.root_fs.getsize(self.path) + + def move(self, target) -> None: + "Move/rename a file or directory" + target = self.root_fs.path(target) + if target.is_dir(): + self.root_fs.move(self.path, (target / self.name).path) + else: + self.root_fs.move(self.path, target.path) + + def read_file_chunks(self, chunk_size: int = SEND_FILE_CHUNK_SIZE): + "Read file in chunks" + with self.root_fs.openbin(self.path) as f: + while True: + buffer = f.read(chunk_size) + if buffer: + yield buffer + else: + break + + def send_file(self, as_attachment: bool): + "Send the contents of a file to the client" + if not self.exists(): + abort(HTTP_404_NOT_FOUND) + elif self.root_fs.hassyspath(self.path): + # Local filesystem + return send_file( + self.root_fs.getsyspath(self.path), + as_attachment=as_attachment, + attachment_filename=self.name if as_attachment else None, + ) + else: + # Other filesystems + response = Response(stream_with_context(self.read_file_chunks())) + if as_attachment: + response.headers[ + 'Content-Disposition' + ] = 'attachment;filename={}'.format(self.name) + return response + + def write_file(self, data: Union[str, bytes], is_text: bool) -> None: + "Write data to a file" + self.root_fs.makedirs(self.parent.path, recreate=True) + if is_text: + self.root_fs.writetext(self.path, data) + else: + self.root_fs.writebytes(self.path, data) + + def read_text(self, encoding=None, errors=None) -> str: + "Get the contents of a file as a string" + return self.root_fs.readtext(self.path, encoding=encoding, errors=errors) + + def read_bytes(self) -> bytes: + "Get the contents of a file as bytes" + return self.root_fs.readbytes(self.path) + + def __str__(self) -> str: + return self.path + + def __truediv__(self, key): + try: + path = os.path.join(self.path, key) + return self.root_fs.path(path) + except TypeError: + return NotImplemented + + def __eq__(self, other) -> bool: + if not isinstance(other, FSPath): + return NotImplemented + return self.path == other.path + + def __hash__(self) -> int: + try: + return self._hash + except AttributeError: + self._hash = hash(self.path) + return self._hash + + def __lt__(self, other: Any): + if not isinstance(other, FSPath): + return NotImplemented + return self.path < other.path + + def __le__(self, other: Any) -> bool: + if not isinstance(other, FSPath): + return NotImplemented + return self.path <= other.path + + def __gt__(self, other: Any) -> bool: + if not isinstance(other, FSPath): + return NotImplemented + return self.path > other.path + + def __ge__(self, other: Any) -> bool: + if not isinstance(other, FSPath): + return NotImplemented + return self.path >= other.path diff --git a/airflow_code_editor/git.py b/airflow_code_editor/git.py new file mode 100644 index 0000000..77dcd38 --- /dev/null +++ b/airflow_code_editor/git.py @@ -0,0 +1,258 @@ +#!/usr/bin/env python +# +# Copyright 2019 Andrea Bonomi +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the Licens + +import os +import logging +import subprocess +import threading +import shlex +from pathlib import Path +from typing import Dict, List, Optional, Tuple +from datetime import datetime +from flask import make_response, Response +from flask_login import current_user # type: ignore +from airflow_code_editor.commons import ( + DEFAULT_GIT_BRANCH, + HTTP_200_OK, + HTTP_404_NOT_FOUND, + SUPPORTED_GIT_COMMANDS, + GitOutput, +) +from airflow_code_editor.utils import ( + normalize_path, + get_plugin_config, + get_plugin_boolean_config, + get_root_folder, + read_mount_points_config, +) +from airflow_code_editor.fs import RootFS + +__all__ = [ + 'git_enabled', + 'execute_git_command', +] + + +def git_enabled() -> bool: + "Return true if git is enabled in the configuration" + return get_plugin_boolean_config('git_enabled') + + +def prepare_git_response( + git_cmd: Optional[str], + result: GitOutput = None, + stderr: GitOutput = None, + returncode: int = 0, +) -> Response: + if result is None: + result = stderr + elif stderr: + result = result + stderr + if git_cmd == 'cat-file': + response = make_response( + result, HTTP_200_OK if returncode == 0 else HTTP_404_NOT_FOUND + ) + response.headers['Content-Type'] = 'text/plain' + else: + response = make_response(result) + response.headers['X-Git-Return-Code'] = str(returncode) + response.headers['X-Git-Stderr-Length'] = str(len(stderr or '')) + response.headers['Content-Type'] = 'text/plain' + return response + + +_execute_git_command_lock = threading.Lock() + + +def execute_git_command(git_args: List[str]) -> Response: + with _execute_git_command_lock: + logging.info(' '.join(git_args)) + git_cmd = git_args[0] if git_args else None + stdout: GitOutput = None + stderr: GitOutput = None + returncode = 0 + try: + # Init git repo + init_git_repo() + # Local commands + if git_cmd in LOCAL_COMMANDS: + handler = LOCAL_COMMANDS[git_cmd] + stdout = handler(git_args) + # Git commands + elif git_cmd in SUPPORTED_GIT_COMMANDS: + git_default_args = shlex.split(get_plugin_config('git_default_args')) + returncode, stdout, stderr = git_call( + git_default_args + git_args, capture_output=True + ) + else: + stdout = None + stderr = bytes( + 'Command not supported: git %s' % ' '.join(git_args), 'utf-8' + ) + returncode = 1 + except OSError as ex: + logging.error(ex) + stdout = None + stderr = ex.strerror + returncode = ex.errno + except Exception as ex: + logging.error(ex) + stdout = None + stderr = ex.message if hasattr(ex, 'message') else str(ex) + returncode = 1 + finally: + return prepare_git_response(git_cmd, stdout, stderr, returncode) + + +def git_ls_local(git_args: List[str]) -> str: + "'git ls-tree' like output for local folders" + long_ = False + if '-l' in git_args or '--long' in git_args: + git_args = [arg for arg in git_args if arg not in ('-l', '--long')] + long_ = True + path = git_args[1] if len(git_args) > 1 else '' + path = normalize_path(path.split('#', 1)[0]) + result = [] + root_fs = RootFS() + for item in root_fs.path(path).iterdir(): + if item.is_dir(): + type_ = 'tree' + else: + type_ = 'blob' + s = item.stat() + if long_: + mtime = datetime.utcfromtimestamp(s.st_mtime).isoformat()[:16] + result.append( + '%06o %s %s#%s %8s\t%s' + % (s.st_mode, type_, str(item), mtime, item.size(), item.name) + ) + else: + result.append('%06o %s %s\t%s' % (s.st_mode, type_, str(item), item.name)) + return '\n'.join(result) + + +def git_mounts(git_args: List[str]) -> str: + "List mountpoints" + mount_points = read_mount_points_config() + return '\n'.join(sorted(k for k, v in mount_points.items() if not v.default)) + + +def git_rm_local(git_args: List[str]) -> str: + "Delete local files/directories" + root_fs = RootFS() + for arg in git_args[1:]: + if arg: + root_fs.path(arg).delete() + return '' + + +def git_mv_local(git_args: List[str]) -> str: + "Rename/Move local files" + if len(git_args) < 3: + raise Exception('Missing source/destination args') + root_fs = RootFS() + target = git_args[-1] + for arg in git_args[1:-1]: + source = root_fs.path(arg) + source.move(target) + return '' + + +LOCAL_COMMANDS = { + 'mounts': git_mounts, + 'ls-local': git_ls_local, + 'rm-local': git_rm_local, + 'mv-local': git_mv_local, +} + + +def git_call( + argv: List[str], capture_output: bool = False +) -> Tuple[int, GitOutput, GitOutput]: + "Run git command. If capture_output is true, stdout and stderr will be captured." + if not git_enabled(): + return 1, '', 'Git is disabled' + cmd: List[str] = [get_plugin_config('git_cmd')] + argv + cwd: Path = get_root_folder() + env: Dict[str, str] = prepare_git_env() + if capture_output: + git = subprocess.Popen( + cmd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=cwd, + env=env, + ) + stdout, stderr = git.communicate() + returncode: int = git.returncode + else: + stdout = b'' + stderr = b'' + returncode = subprocess.call(cmd, cwd=cwd, env=env) + return returncode, stdout, stderr + + +def get_default_branch() -> str: + stdout = git_call(['config', '--global', 'init.defaultBranch'], capture_output=True)[1] + default_branch = stdout.decode('utf8').strip('\n') + return default_branch or DEFAULT_GIT_BRANCH + + +def init_git_repo() -> None: + "Initialize the git repository in root folder" + cwd: Path = get_root_folder() + if ( + git_enabled() + and not (cwd / '.git').exists() + and get_plugin_boolean_config('git_init_repo') + ): + git_call(['init', '-b', get_default_branch(), '.']) + gitignore = cwd / '.gitignore' + if not gitignore.exists(): + with gitignore.open('w') as f: + f.write('__pycache__\n') + git_call(['add', '.gitignore']) + git_call(['commit', '-m', 'Initial commit']) + + +def prepare_git_env() -> Dict[str, str]: + "Prepare the environ for git" + env = dict(os.environ) + # Author + git_author_name = get_plugin_config('git_author_name') + if not git_author_name: + try: + git_author_name = '%s %s' % ( + current_user.first_name, + current_user.last_name, + ) + except Exception: + pass + if git_author_name: + env['GIT_AUTHOR_NAME'] = git_author_name + env['GIT_COMMITTER_NAME'] = git_author_name + # Email + git_author_email = get_plugin_config('git_author_email') + if not git_author_email: + try: + git_author_email = current_user.email + except Exception: + pass + if git_author_email: + env['GIT_AUTHOR_EMAIL'] = git_author_email + env['GIT_COMMITTER_EMAIL'] = git_author_email + return env diff --git a/airflow_code_editor/static/addon/comment/comment.js b/airflow_code_editor/static/addon/comment/comment.js index dac48d0..7f6f3ed 100644 --- a/airflow_code_editor/static/addon/comment/comment.js +++ b/airflow_code_editor/static/addon/comment/comment.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -78,7 +78,7 @@ var baseString = null; for (var i = from.line; i < end; ++i) { var line = self.getLine(i); - var whitespace = line.slice(0, firstNonWS(line)); + var whitespace = line.search(nonWS) === -1 ? line : line.slice(0, firstNonWS(line)); if (baseString == null || baseString.length > whitespace.length) { baseString = whitespace; } diff --git a/airflow_code_editor/static/addon/comment/continuecomment.js b/airflow_code_editor/static/addon/comment/continuecomment.js index 7ca1b4a..2f16da8 100644 --- a/airflow_code_editor/static/addon/comment/continuecomment.js +++ b/airflow_code_editor/static/addon/comment/continuecomment.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/dialog/dialog.js b/airflow_code_editor/static/addon/dialog/dialog.js index 5f1f4aa..0294d23 100644 --- a/airflow_code_editor/static/addon/dialog/dialog.js +++ b/airflow_code_editor/static/addon/dialog/dialog.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // Open simple dialogs on top of an editor. Relies on dialog.css. diff --git a/airflow_code_editor/static/addon/display/autorefresh.js b/airflow_code_editor/static/addon/display/autorefresh.js index 37014dc..b5e6ab0 100644 --- a/airflow_code_editor/static/addon/display/autorefresh.js +++ b/airflow_code_editor/static/addon/display/autorefresh.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/display/fullscreen.js b/airflow_code_editor/static/addon/display/fullscreen.js index eda7300..39451bd 100644 --- a/airflow_code_editor/static/addon/display/fullscreen.js +++ b/airflow_code_editor/static/addon/display/fullscreen.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/display/panel.js b/airflow_code_editor/static/addon/display/panel.js index 29f7e0b..b00d683 100644 --- a/airflow_code_editor/static/addon/display/panel.js +++ b/airflow_code_editor/static/addon/display/panel.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function (mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/display/placeholder.js b/airflow_code_editor/static/addon/display/placeholder.js index cfb8341..7848f51 100644 --- a/airflow_code_editor/static/addon/display/placeholder.js +++ b/airflow_code_editor/static/addon/display/placeholder.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/display/rulers.js b/airflow_code_editor/static/addon/display/rulers.js index 0bb83bb..4ca15ea 100644 --- a/airflow_code_editor/static/addon/display/rulers.js +++ b/airflow_code_editor/static/addon/display/rulers.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/edit/closebrackets.js b/airflow_code_editor/static/addon/edit/closebrackets.js index 593d443..badbbd8 100644 --- a/airflow_code_editor/static/addon/edit/closebrackets.js +++ b/airflow_code_editor/static/addon/edit/closebrackets.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/edit/closetag.js b/airflow_code_editor/static/addon/edit/closetag.js index 7c22a50..62c0578 100644 --- a/airflow_code_editor/static/addon/edit/closetag.js +++ b/airflow_code_editor/static/addon/edit/closetag.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE /** * Tag-closer extension for CodeMirror. diff --git a/airflow_code_editor/static/addon/edit/continuelist.js b/airflow_code_editor/static/addon/edit/continuelist.js index d8b2e0e..915d813 100644 --- a/airflow_code_editor/static/addon/edit/continuelist.js +++ b/airflow_code_editor/static/addon/edit/continuelist.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/edit/matchbrackets.js b/airflow_code_editor/static/addon/edit/matchbrackets.js index 43dc884..c342910 100644 --- a/airflow_code_editor/static/addon/edit/matchbrackets.js +++ b/airflow_code_editor/static/addon/edit/matchbrackets.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/edit/matchtags.js b/airflow_code_editor/static/addon/edit/matchtags.js index 2203d93..afa6105 100644 --- a/airflow_code_editor/static/addon/edit/matchtags.js +++ b/airflow_code_editor/static/addon/edit/matchtags.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/edit/trailingspace.js b/airflow_code_editor/static/addon/edit/trailingspace.js index c39c310..8d01c20 100644 --- a/airflow_code_editor/static/addon/edit/trailingspace.js +++ b/airflow_code_editor/static/addon/edit/trailingspace.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/fold/brace-fold.js b/airflow_code_editor/static/addon/fold/brace-fold.js index 28cb093..2124768 100644 --- a/airflow_code_editor/static/addon/fold/brace-fold.js +++ b/airflow_code_editor/static/addon/fold/brace-fold.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/fold/comment-fold.js b/airflow_code_editor/static/addon/fold/comment-fold.js index 836101d..adaa79d 100644 --- a/airflow_code_editor/static/addon/fold/comment-fold.js +++ b/airflow_code_editor/static/addon/fold/comment-fold.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/fold/foldcode.js b/airflow_code_editor/static/addon/fold/foldcode.js index 721bc08..a6a51af 100644 --- a/airflow_code_editor/static/addon/fold/foldcode.js +++ b/airflow_code_editor/static/addon/fold/foldcode.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/fold/foldgutter.js b/airflow_code_editor/static/addon/fold/foldgutter.js index 7d46a60..481fea2 100644 --- a/airflow_code_editor/static/addon/fold/foldgutter.js +++ b/airflow_code_editor/static/addon/fold/foldgutter.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/fold/indent-fold.js b/airflow_code_editor/static/addon/fold/indent-fold.js index 0cc1126..470e84a 100644 --- a/airflow_code_editor/static/addon/fold/indent-fold.js +++ b/airflow_code_editor/static/addon/fold/indent-fold.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/fold/markdown-fold.js b/airflow_code_editor/static/addon/fold/markdown-fold.js index 6a55178..4f9cb02 100644 --- a/airflow_code_editor/static/addon/fold/markdown-fold.js +++ b/airflow_code_editor/static/addon/fold/markdown-fold.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/fold/xml-fold.js b/airflow_code_editor/static/addon/fold/xml-fold.js index 13bc383..5450d37 100644 --- a/airflow_code_editor/static/addon/fold/xml-fold.js +++ b/airflow_code_editor/static/addon/fold/xml-fold.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/hint/anyword-hint.js b/airflow_code_editor/static/addon/hint/anyword-hint.js index d27a9ec..b20d9f6 100644 --- a/airflow_code_editor/static/addon/hint/anyword-hint.js +++ b/airflow_code_editor/static/addon/hint/anyword-hint.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/hint/css-hint.js b/airflow_code_editor/static/addon/hint/css-hint.js index 980d119..5b36e82 100644 --- a/airflow_code_editor/static/addon/hint/css-hint.js +++ b/airflow_code_editor/static/addon/hint/css-hint.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/hint/html-hint.js b/airflow_code_editor/static/addon/hint/html-hint.js index 9878eca..168f49c 100644 --- a/airflow_code_editor/static/addon/hint/html-hint.js +++ b/airflow_code_editor/static/addon/hint/html-hint.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/hint/javascript-hint.js b/airflow_code_editor/static/addon/hint/javascript-hint.js index 9f06b1b..9563979 100644 --- a/airflow_code_editor/static/addon/hint/javascript-hint.js +++ b/airflow_code_editor/static/addon/hint/javascript-hint.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/hint/show-hint.js b/airflow_code_editor/static/addon/hint/show-hint.js index 2be2c71..be729c3 100644 --- a/airflow_code_editor/static/addon/hint/show-hint.js +++ b/airflow_code_editor/static/addon/hint/show-hint.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // declare global: DOMRect @@ -309,7 +309,7 @@ hints.style.width = (winW - 5) + "px"; overlapX -= (box.right - box.left) - winW; } - hints.style.left = (left = pos.left - overlapX - offsetLeft) + "px"; + hints.style.left = (left = Math.max(pos.left - overlapX - offsetLeft, 0)) + "px"; } if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling) node.style.paddingRight = cm.display.nativeBarWidth + "px" diff --git a/airflow_code_editor/static/addon/hint/sql-hint.js b/airflow_code_editor/static/addon/hint/sql-hint.js index efdce81..57c3b64 100644 --- a/airflow_code_editor/static/addon/hint/sql-hint.js +++ b/airflow_code_editor/static/addon/hint/sql-hint.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/hint/xml-hint.js b/airflow_code_editor/static/addon/hint/xml-hint.js index 2b31531..1fc6394 100644 --- a/airflow_code_editor/static/addon/hint/xml-hint.js +++ b/airflow_code_editor/static/addon/hint/xml-hint.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/lint/coffeescript-lint.js b/airflow_code_editor/static/addon/lint/coffeescript-lint.js index a54c703..793ea90 100644 --- a/airflow_code_editor/static/addon/lint/coffeescript-lint.js +++ b/airflow_code_editor/static/addon/lint/coffeescript-lint.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js diff --git a/airflow_code_editor/static/addon/lint/css-lint.js b/airflow_code_editor/static/addon/lint/css-lint.js index 6058a73..94a67b4 100644 --- a/airflow_code_editor/static/addon/lint/css-lint.js +++ b/airflow_code_editor/static/addon/lint/css-lint.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // Depends on csslint.js from https://github.com/stubbornella/csslint diff --git a/airflow_code_editor/static/addon/lint/html-lint.js b/airflow_code_editor/static/addon/lint/html-lint.js index 5295c33..5be24fe 100644 --- a/airflow_code_editor/static/addon/lint/html-lint.js +++ b/airflow_code_editor/static/addon/lint/html-lint.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // Depends on htmlhint.js from http://htmlhint.com/js/htmlhint.js diff --git a/airflow_code_editor/static/addon/lint/javascript-lint.js b/airflow_code_editor/static/addon/lint/javascript-lint.js index e5bc752..c1599f8 100644 --- a/airflow_code_editor/static/addon/lint/javascript-lint.js +++ b/airflow_code_editor/static/addon/lint/javascript-lint.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // Depends on jshint.js from https://github.com/jshint/jshint diff --git a/airflow_code_editor/static/addon/lint/json-lint.js b/airflow_code_editor/static/addon/lint/json-lint.js index ac1d6ec..4a4fe39 100644 --- a/airflow_code_editor/static/addon/lint/json-lint.js +++ b/airflow_code_editor/static/addon/lint/json-lint.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // Depends on jsonlint.js from https://github.com/zaach/jsonlint diff --git a/airflow_code_editor/static/addon/lint/lint.js b/airflow_code_editor/static/addon/lint/lint.js index 1613deb..7b40e10 100644 --- a/airflow_code_editor/static/addon/lint/lint.js +++ b/airflow_code_editor/static/addon/lint/lint.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/lint/yaml-lint.js b/airflow_code_editor/static/addon/lint/yaml-lint.js index b4ac5ab..5dbb159 100644 --- a/airflow_code_editor/static/addon/lint/yaml-lint.js +++ b/airflow_code_editor/static/addon/lint/yaml-lint.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/merge/merge.js b/airflow_code_editor/static/addon/merge/merge.js index 35292c0..a5ba21a 100644 --- a/airflow_code_editor/static/addon/merge/merge.js +++ b/airflow_code_editor/static/addon/merge/merge.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // declare global: diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL diff --git a/airflow_code_editor/static/addon/mode/loadmode.js b/airflow_code_editor/static/addon/mode/loadmode.js index fc695d0..ee1c151 100644 --- a/airflow_code_editor/static/addon/mode/loadmode.js +++ b/airflow_code_editor/static/addon/mode/loadmode.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/mode/multiplex.js b/airflow_code_editor/static/addon/mode/multiplex.js index 6140bc4..d7f378a 100644 --- a/airflow_code_editor/static/addon/mode/multiplex.js +++ b/airflow_code_editor/static/addon/mode/multiplex.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/mode/multiplex_test.js b/airflow_code_editor/static/addon/mode/multiplex_test.js index 8503988..37e8077 100644 --- a/airflow_code_editor/static/addon/mode/multiplex_test.js +++ b/airflow_code_editor/static/addon/mode/multiplex_test.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function() { CodeMirror.defineMode("markdown_with_stex", function(){ diff --git a/airflow_code_editor/static/addon/mode/overlay.js b/airflow_code_editor/static/addon/mode/overlay.js index 016e3c2..1aab159 100644 --- a/airflow_code_editor/static/addon/mode/overlay.js +++ b/airflow_code_editor/static/addon/mode/overlay.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // Utility function that allows modes to be combined. The mode given // as the base argument takes care of most of the normal mode diff --git a/airflow_code_editor/static/addon/mode/simple.js b/airflow_code_editor/static/addon/mode/simple.js index 0d8cbde..1f0e0be 100644 --- a/airflow_code_editor/static/addon/mode/simple.js +++ b/airflow_code_editor/static/addon/mode/simple.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/runmode/colorize.js b/airflow_code_editor/static/addon/runmode/colorize.js index 3be5411..ead1c58 100644 --- a/airflow_code_editor/static/addon/runmode/colorize.js +++ b/airflow_code_editor/static/addon/runmode/colorize.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -31,7 +31,7 @@ var text = []; textContent(node, text); - node.innerHTML = ""; + node.textContent = ""; CodeMirror.runMode(text.join(""), mode, node); node.className += " cm-s-default"; diff --git a/airflow_code_editor/static/addon/runmode/runmode-standalone.js b/airflow_code_editor/static/addon/runmode/runmode-standalone.js index 76cf3d7..441522a 100644 --- a/airflow_code_editor/static/addon/runmode/runmode-standalone.js +++ b/airflow_code_editor/static/addon/runmode/runmode-standalone.js @@ -256,7 +256,7 @@ CodeMirror.defaults = { indentUnit: 2 }; // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: https://codemirror.net/LICENSE + // Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -276,7 +276,7 @@ var ie = /MSIE \d/.test(navigator.userAgent); var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); var node = callback, col = 0; - node.innerHTML = ""; + node.textContent = ""; callback = function(text, style) { if (text == "\n") { // Emitting LF or CRLF on IE8 or earlier results in an incorrect display. diff --git a/airflow_code_editor/static/addon/runmode/runmode.js b/airflow_code_editor/static/addon/runmode/runmode.js index f5d58e2..e1525b6 100644 --- a/airflow_code_editor/static/addon/runmode/runmode.js +++ b/airflow_code_editor/static/addon/runmode/runmode.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -20,7 +20,7 @@ CodeMirror.runMode = function(string, modespec, callback, options) { var ie = /MSIE \d/.test(navigator.userAgent); var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); var node = callback, col = 0; - node.innerHTML = ""; + node.textContent = ""; callback = function(text, style) { if (text == "\n") { // Emitting LF or CRLF on IE8 or earlier results in an incorrect display. diff --git a/airflow_code_editor/static/addon/runmode/runmode.node.js b/airflow_code_editor/static/addon/runmode/runmode.node.js index ddd255a..9dd48e1 100644 --- a/airflow_code_editor/static/addon/runmode/runmode.node.js +++ b/airflow_code_editor/static/addon/runmode/runmode.node.js @@ -253,7 +253,7 @@ exports.splitLines = function(string) { return string.split(/\r?\n|\r/) }; exports.defaults = { indentUnit: 2 }; // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -273,7 +273,7 @@ CodeMirror.runMode = function(string, modespec, callback, options) { var ie = /MSIE \d/.test(navigator.userAgent); var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); var node = callback, col = 0; - node.innerHTML = ""; + node.textContent = ""; callback = function(text, style) { if (text == "\n") { // Emitting LF or CRLF on IE8 or earlier results in an incorrect display. diff --git a/airflow_code_editor/static/addon/scroll/annotatescrollbar.js b/airflow_code_editor/static/addon/scroll/annotatescrollbar.js index c12e44c..b8d52b7 100644 --- a/airflow_code_editor/static/addon/scroll/annotatescrollbar.js +++ b/airflow_code_editor/static/addon/scroll/annotatescrollbar.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/scroll/scrollpastend.js b/airflow_code_editor/static/addon/scroll/scrollpastend.js index 2ed9d95..310fb62 100644 --- a/airflow_code_editor/static/addon/scroll/scrollpastend.js +++ b/airflow_code_editor/static/addon/scroll/scrollpastend.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/scroll/simplescrollbars.js b/airflow_code_editor/static/addon/scroll/simplescrollbars.js index 750a2bd..f1356a8 100644 --- a/airflow_code_editor/static/addon/scroll/simplescrollbars.js +++ b/airflow_code_editor/static/addon/scroll/simplescrollbars.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/search/jump-to-line.js b/airflow_code_editor/static/addon/search/jump-to-line.js index 990c235..596383b 100644 --- a/airflow_code_editor/static/addon/search/jump-to-line.js +++ b/airflow_code_editor/static/addon/search/jump-to-line.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // Defines jumpToLine command. Uses dialog.js if present. diff --git a/airflow_code_editor/static/addon/search/match-highlighter.js b/airflow_code_editor/static/addon/search/match-highlighter.js index 9b181eb..f7e7fb3 100644 --- a/airflow_code_editor/static/addon/search/match-highlighter.js +++ b/airflow_code_editor/static/addon/search/match-highlighter.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // Highlighting text that matches the selection // diff --git a/airflow_code_editor/static/addon/search/matchesonscrollbar.js b/airflow_code_editor/static/addon/search/matchesonscrollbar.js index 8a4a827..acab47b 100644 --- a/airflow_code_editor/static/addon/search/matchesonscrollbar.js +++ b/airflow_code_editor/static/addon/search/matchesonscrollbar.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/search/search.js b/airflow_code_editor/static/addon/search/search.js index 24a0855..9662b09 100644 --- a/airflow_code_editor/static/addon/search/search.js +++ b/airflow_code_editor/static/addon/search/search.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // Define search commands. Depends on dialog.js or another // implementation of the openDialog method. @@ -202,16 +202,19 @@ } function getQueryDialog(cm) { - return el("", null, - el("span", {className: "CodeMirror-search-label"}, cm.phrase("Search:")), " ", - el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field"}), " ", - el("span", {style: "color: #888", className: "CodeMirror-search-hint"}, + var label = el("label", {className: "CodeMirror-search-label"}, + cm.phrase("Search:"), + el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field", + id: "CodeMirror-search-field"})); + label.setAttribute("for","CodeMirror-search-field"); + return el("", null, label, " ", + el("span", {style: "color: #666", className: "CodeMirror-search-hint"}, cm.phrase("(Use /re/ syntax for regexp search)"))); } function getReplaceQueryDialog(cm) { return el("", null, " ", el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field"}), " ", - el("span", {style: "color: #888", className: "CodeMirror-search-hint"}, + el("span", {style: "color: #666", className: "CodeMirror-search-hint"}, cm.phrase("(Use /re/ syntax for regexp search)"))); } function getReplacementQueryDialog(cm) { diff --git a/airflow_code_editor/static/addon/search/searchcursor.js b/airflow_code_editor/static/addon/search/searchcursor.js index 230017b..ffe6932 100644 --- a/airflow_code_editor/static/addon/search/searchcursor.js +++ b/airflow_code_editor/static/addon/search/searchcursor.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/selection/active-line.js b/airflow_code_editor/static/addon/selection/active-line.js index c7b14ce..ff81ffc 100644 --- a/airflow_code_editor/static/addon/selection/active-line.js +++ b/airflow_code_editor/static/addon/selection/active-line.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/selection/mark-selection.js b/airflow_code_editor/static/addon/selection/mark-selection.js index adfaa62..fc80159 100644 --- a/airflow_code_editor/static/addon/selection/mark-selection.js +++ b/airflow_code_editor/static/addon/selection/mark-selection.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // Because sometimes you need to mark the selected *text*. // diff --git a/airflow_code_editor/static/addon/selection/selection-pointer.js b/airflow_code_editor/static/addon/selection/selection-pointer.js index f0bd61a..924b465 100644 --- a/airflow_code_editor/static/addon/selection/selection-pointer.js +++ b/airflow_code_editor/static/addon/selection/selection-pointer.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/addon/tern/tern.js b/airflow_code_editor/static/addon/tern/tern.js index a883717..8a4d67d 100644 --- a/airflow_code_editor/static/addon/tern/tern.js +++ b/airflow_code_editor/static/addon/tern/tern.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // Glue code between CodeMirror and Tern. // @@ -589,10 +589,16 @@ } function dialog(cm, text, f) { - if (cm.openDialog) - cm.openDialog(text + ": ", f); - else + if (cm.openDialog) { + var fragment = document.createDocumentFragment(); + fragment.appendChild(document.createTextNode(text + ": ")); + var input = document.createElement("input"); + input.type = "text"; + fragment.appendChild(input); + cm.openDialog(fragment, f); + } else { f(prompt(text, "")); + } } // Tooltips diff --git a/airflow_code_editor/static/addon/tern/worker.js b/airflow_code_editor/static/addon/tern/worker.js index e134ad4..ed1b685 100644 --- a/airflow_code_editor/static/addon/tern/worker.js +++ b/airflow_code_editor/static/addon/tern/worker.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // declare global: tern, server diff --git a/airflow_code_editor/static/addon/wrap/hardwrap.js b/airflow_code_editor/static/addon/wrap/hardwrap.js index 516368c..e7053b5 100644 --- a/airflow_code_editor/static/addon/wrap/hardwrap.js +++ b/airflow_code_editor/static/addon/wrap/hardwrap.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/airflow_code_editor/static/airflow_code_editor.js b/airflow_code_editor/static/airflow_code_editor.js index ce9437a..7262529 100644 --- a/airflow_code_editor/static/airflow_code_editor.js +++ b/airflow_code_editor/static/airflow_code_editor.js @@ -1,2 +1,2 @@ /*! For license information please see airflow_code_editor.js.LICENSE.txt */ -!function(){var e={9669:function(e,t,n){e.exports=n(1609)},5448:function(e,t,n){"use strict";var r=n(4867),i=n(6026),o=n(4372),a=n(5327),s=n(4097),l=n(4109),c=n(7985),u=n(7874),d=n(2648),f=n(644),p=n(205);e.exports=function(e){return new Promise((function(t,n){var h,v=e.data,g=e.headers,m=e.responseType;function y(){e.cancelToken&&e.cancelToken.unsubscribe(h),e.signal&&e.signal.removeEventListener("abort",h)}r.isFormData(v)&&r.isStandardBrowserEnv()&&delete g["Content-Type"];var b=new XMLHttpRequest;if(e.auth){var w=e.auth.username||"",_=e.auth.password?unescape(encodeURIComponent(e.auth.password)):"";g.Authorization="Basic "+btoa(w+":"+_)}var x=s(e.baseURL,e.url);function C(){if(b){var r="getAllResponseHeaders"in b?l(b.getAllResponseHeaders()):null,o={data:m&&"text"!==m&&"json"!==m?b.response:b.responseText,status:b.status,statusText:b.statusText,headers:r,config:e,request:b};i((function(e){t(e),y()}),(function(e){n(e),y()}),o),b=null}}if(b.open(e.method.toUpperCase(),a(x,e.params,e.paramsSerializer),!0),b.timeout=e.timeout,"onloadend"in b?b.onloadend=C:b.onreadystatechange=function(){b&&4===b.readyState&&(0!==b.status||b.responseURL&&0===b.responseURL.indexOf("file:"))&&setTimeout(C)},b.onabort=function(){b&&(n(new d("Request aborted",d.ECONNABORTED,e,b)),b=null)},b.onerror=function(){n(new d("Network Error",d.ERR_NETWORK,e,b,b)),b=null},b.ontimeout=function(){var t=e.timeout?"timeout of "+e.timeout+"ms exceeded":"timeout exceeded",r=e.transitional||u;e.timeoutErrorMessage&&(t=e.timeoutErrorMessage),n(new d(t,r.clarifyTimeoutError?d.ETIMEDOUT:d.ECONNABORTED,e,b)),b=null},r.isStandardBrowserEnv()){var S=(e.withCredentials||c(x))&&e.xsrfCookieName?o.read(e.xsrfCookieName):void 0;S&&(g[e.xsrfHeaderName]=S)}"setRequestHeader"in b&&r.forEach(g,(function(e,t){void 0===v&&"content-type"===t.toLowerCase()?delete g[t]:b.setRequestHeader(t,e)})),r.isUndefined(e.withCredentials)||(b.withCredentials=!!e.withCredentials),m&&"json"!==m&&(b.responseType=e.responseType),"function"==typeof e.onDownloadProgress&&b.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&b.upload&&b.upload.addEventListener("progress",e.onUploadProgress),(e.cancelToken||e.signal)&&(h=function(e){b&&(n(!e||e&&e.type?new f:e),b.abort(),b=null)},e.cancelToken&&e.cancelToken.subscribe(h),e.signal&&(e.signal.aborted?h():e.signal.addEventListener("abort",h))),v||(v=null);var T=p(x);T&&-1===["http","https","file"].indexOf(T)?n(new d("Unsupported protocol "+T+":",d.ERR_BAD_REQUEST,e)):b.send(v)}))}},1609:function(e,t,n){"use strict";var r=n(4867),i=n(1849),o=n(321),a=n(7185),s=function e(t){var n=new o(t),s=i(o.prototype.request,n);return r.extend(s,o.prototype,n),r.extend(s,n),s.create=function(n){return e(a(t,n))},s}(n(5546));s.Axios=o,s.CanceledError=n(644),s.CancelToken=n(4972),s.isCancel=n(6502),s.VERSION=n(7288).version,s.toFormData=n(7675),s.AxiosError=n(2648),s.Cancel=s.CanceledError,s.all=function(e){return Promise.all(e)},s.spread=n(8713),s.isAxiosError=n(6268),e.exports=s,e.exports.default=s},4972:function(e,t,n){"use strict";var r=n(644);function i(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise((function(e){t=e}));var n=this;this.promise.then((function(e){if(n._listeners){var t,r=n._listeners.length;for(t=0;t=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*"}}};r.forEach(["delete","get","head"],(function(e){d.headers[e]={}})),r.forEach(["post","put","patch"],(function(e){d.headers[e]=r.merge(l)})),e.exports=d},7874:function(e){"use strict";e.exports={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1}},7288:function(e){e.exports={version:"0.27.2"}},1849:function(e){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r=0)return;a[t]="set-cookie"===t?(a[t]?a[t]:[]).concat([n]):a[t]?a[t]+", "+n:n}})),a):a}},205:function(e){"use strict";e.exports=function(e){var t=/^([-+\w]{1,25})(:?\/\/|:)/.exec(e);return t&&t[1]||""}},8713:function(e){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}},7675:function(e,t,n){"use strict";var r=n(4867);e.exports=function(e,t){t=t||new FormData;var n=[];function i(e){return null===e?"":r.isDate(e)?e.toISOString():r.isArrayBuffer(e)||r.isTypedArray(e)?"function"==typeof Blob?new Blob([e]):Buffer.from(e):e}return function e(o,a){if(r.isPlainObject(o)||r.isArray(o)){if(-1!==n.indexOf(o))throw Error("Circular reference detected in "+a);n.push(o),r.forEach(o,(function(n,o){if(!r.isUndefined(n)){var s,l=a?a+"."+o:o;if(n&&!a&&"object"==typeof n)if(r.endsWith(o,"{}"))n=JSON.stringify(n);else if(r.endsWith(o,"[]")&&(s=r.toArray(n)))return void s.forEach((function(e){!r.isUndefined(e)&&t.append(l,i(e))}));e(n,l)}})),n.pop()}else t.append(a,i(o))}(e),t}},4875:function(e,t,n){"use strict";var r=n(7288).version,i=n(2648),o={};["object","boolean","number","function","string","symbol"].forEach((function(e,t){o[e]=function(n){return typeof n===e||"a"+(t<1?"n ":" ")+e}}));var a={};o.transitional=function(e,t,n){function o(e,t){return"[Axios v"+r+"] Transitional option '"+e+"'"+t+(n?". "+n:"")}return function(n,r,s){if(!1===e)throw new i(o(r," has been removed"+(t?" in "+t:"")),i.ERR_DEPRECATED);return t&&!a[r]&&(a[r]=!0,console.warn(o(r," has been deprecated since v"+t+" and will be removed in the near future"))),!e||e(n,r,s)}},e.exports={assertOptions:function(e,t,n){if("object"!=typeof e)throw new i("options must be an object",i.ERR_BAD_OPTION_VALUE);for(var r=Object.keys(e),o=r.length;o-- >0;){var a=r[o],s=t[a];if(s){var l=e[a],c=void 0===l||s(l,a,e);if(!0!==c)throw new i("option "+a+" must be "+c,i.ERR_BAD_OPTION_VALUE)}else if(!0!==n)throw new i("Unknown option "+a,i.ERR_BAD_OPTION)}},validators:o}},4867:function(e,t,n){"use strict";var r,i=n(1849),o=Object.prototype.toString,a=(r=Object.create(null),function(e){var t=o.call(e);return r[t]||(r[t]=t.slice(8,-1).toLowerCase())});function s(e){return e=e.toLowerCase(),function(t){return a(t)===e}}function l(e){return Array.isArray(e)}function c(e){return void 0===e}var u=s("ArrayBuffer");function d(e){return null!==e&&"object"==typeof e}function f(e){if("object"!==a(e))return!1;var t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}var p=s("Date"),h=s("File"),v=s("Blob"),g=s("FileList");function m(e){return"[object Function]"===o.call(e)}var y=s("URLSearchParams");function b(e,t){if(null!=e)if("object"!=typeof e&&(e=[e]),l(e))for(var n=0,r=e.length;n0;)a[o=r[i]]||(t[o]=e[o],a[o]=!0);e=Object.getPrototypeOf(e)}while(e&&(!n||n(e,t))&&e!==Object.prototype);return t},kindOf:a,kindOfTest:s,endsWith:function(e,t,n){e=String(e),(void 0===n||n>e.length)&&(n=e.length),n-=t.length;var r=e.indexOf(t,n);return-1!==r&&r===n},toArray:function(e){if(!e)return null;var t=e.length;if(c(t))return null;for(var n=new Array(t);t-- >0;)n[t]=e[t];return n},isTypedArray:_,isFileList:g}},3099:function(e){e.exports=function(e){if("function"!=typeof e)throw TypeError(String(e)+" is not a function");return e}},6077:function(e,t,n){var r=n(111);e.exports=function(e){if(!r(e)&&null!==e)throw TypeError("Can't set "+String(e)+" as a prototype");return e}},1223:function(e,t,n){var r=n(5112),i=n(30),o=n(3070),a=r("unscopables"),s=Array.prototype;null==s[a]&&o.f(s,a,{configurable:!0,value:i(null)}),e.exports=function(e){s[a][e]=!0}},1530:function(e,t,n){"use strict";var r=n(8710).charAt;e.exports=function(e,t,n){return t+(n?r(e,t).length:1)}},5787:function(e){e.exports=function(e,t,n){if(!(e instanceof t))throw TypeError("Incorrect "+(n?n+" ":"")+"invocation");return e}},9670:function(e,t,n){var r=n(111);e.exports=function(e){if(!r(e))throw TypeError(String(e)+" is not an object");return e}},8533:function(e,t,n){"use strict";var r=n(2092).forEach,i=n(9341)("forEach");e.exports=i?[].forEach:function(e){return r(this,e,arguments.length>1?arguments[1]:void 0)}},8457:function(e,t,n){"use strict";var r=n(9974),i=n(7908),o=n(3411),a=n(7659),s=n(7466),l=n(6135),c=n(1246);e.exports=function(e){var t,n,u,d,f,p,h=i(e),v="function"==typeof this?this:Array,g=arguments.length,m=g>1?arguments[1]:void 0,y=void 0!==m,b=c(h),w=0;if(y&&(m=r(m,g>2?arguments[2]:void 0,2)),null==b||v==Array&&a(b))for(n=new v(t=s(h.length));t>w;w++)p=y?m(h[w],w):h[w],l(n,w,p);else for(f=(d=b.call(h)).next,n=new v;!(u=f.call(d)).done;w++)p=y?o(d,m,[u.value,w],!0):u.value,l(n,w,p);return n.length=w,n}},1318:function(e,t,n){var r=n(5656),i=n(7466),o=n(1400),a=function(e){return function(t,n,a){var s,l=r(t),c=i(l.length),u=o(a,c);if(e&&n!=n){for(;c>u;)if((s=l[u++])!=s)return!0}else for(;c>u;u++)if((e||u in l)&&l[u]===n)return e||u||0;return!e&&-1}};e.exports={includes:a(!0),indexOf:a(!1)}},2092:function(e,t,n){var r=n(9974),i=n(8361),o=n(7908),a=n(7466),s=n(5417),l=[].push,c=function(e){var t=1==e,n=2==e,c=3==e,u=4==e,d=6==e,f=7==e,p=5==e||d;return function(h,v,g,m){for(var y,b,w=o(h),_=i(w),x=r(v,g,3),C=a(_.length),S=0,T=m||s,k=t?T(h,C):n||f?T(h,0):void 0;C>S;S++)if((p||S in _)&&(b=x(y=_[S],S,w),e))if(t)k[S]=b;else if(b)switch(e){case 3:return!0;case 5:return y;case 6:return S;case 2:l.call(k,y)}else switch(e){case 4:return!1;case 7:l.call(k,y)}return d?-1:c||u?u:k}};e.exports={forEach:c(0),map:c(1),filter:c(2),some:c(3),every:c(4),find:c(5),findIndex:c(6),filterOut:c(7)}},1194:function(e,t,n){var r=n(7293),i=n(5112),o=n(7392),a=i("species");e.exports=function(e){return o>=51||!r((function(){var t=[];return(t.constructor={})[a]=function(){return{foo:1}},1!==t[e](Boolean).foo}))}},9341:function(e,t,n){"use strict";var r=n(7293);e.exports=function(e,t){var n=[][e];return!!n&&r((function(){n.call(null,t||function(){throw 1},1)}))}},4362:function(e){var t=Math.floor,n=function(e,o){var a=e.length,s=t(a/2);return a<8?r(e,o):i(n(e.slice(0,s),o),n(e.slice(s),o),o)},r=function(e,t){for(var n,r,i=e.length,o=1;o0;)e[r]=e[--r];r!==o++&&(e[r]=n)}return e},i=function(e,t,n){for(var r=e.length,i=t.length,o=0,a=0,s=[];o=74)&&(r=a.match(/Chrome\/(\d+)/))&&(i=r[1]),e.exports=i&&+i},8008:function(e,t,n){var r=n(8113).match(/AppleWebKit\/(\d+)\./);e.exports=!!r&&+r[1]},748:function(e){e.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},2109:function(e,t,n){var r=n(7854),i=n(1236).f,o=n(8880),a=n(1320),s=n(3505),l=n(9920),c=n(4705);e.exports=function(e,t){var n,u,d,f,p,h=e.target,v=e.global,g=e.stat;if(n=v?r:g?r[h]||s(h,{}):(r[h]||{}).prototype)for(u in t){if(f=t[u],d=e.noTargetGet?(p=i(n,u))&&p.value:n[u],!c(v?u:h+(g?".":"#")+u,e.forced)&&void 0!==d){if(typeof f==typeof d)continue;l(f,d)}(e.sham||d&&d.sham)&&o(f,"sham",!0),a(n,u,f,e)}}},7293:function(e){e.exports=function(e){try{return!!e()}catch(e){return!0}}},7007:function(e,t,n){"use strict";n(4916);var r=n(1320),i=n(2261),o=n(7293),a=n(5112),s=n(8880),l=a("species"),c=RegExp.prototype;e.exports=function(e,t,n,u){var d=a(e),f=!o((function(){var t={};return t[d]=function(){return 7},7!=""[e](t)})),p=f&&!o((function(){var t=!1,n=/a/;return"split"===e&&((n={}).constructor={},n.constructor[l]=function(){return n},n.flags="",n[d]=/./[d]),n.exec=function(){return t=!0,null},n[d](""),!t}));if(!f||!p||n){var h=/./[d],v=t(d,""[e],(function(e,t,n,r,o){var a=t.exec;return a===i||a===c.exec?f&&!o?{done:!0,value:h.call(t,n,r)}:{done:!0,value:e.call(n,t,r)}:{done:!1}}));r(String.prototype,e,v[0]),r(c,d,v[1])}u&&s(c[d],"sham",!0)}},9974:function(e,t,n){var r=n(3099);e.exports=function(e,t,n){if(r(e),void 0===t)return e;switch(n){case 0:return function(){return e.call(t)};case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,i){return e.call(t,n,r,i)}}return function(){return e.apply(t,arguments)}}},5005:function(e,t,n){var r=n(857),i=n(7854),o=function(e){return"function"==typeof e?e:void 0};e.exports=function(e,t){return arguments.length<2?o(r[e])||o(i[e]):r[e]&&r[e][t]||i[e]&&i[e][t]}},1246:function(e,t,n){var r=n(648),i=n(7497),o=n(5112)("iterator");e.exports=function(e){if(null!=e)return e[o]||e["@@iterator"]||i[r(e)]}},647:function(e,t,n){var r=n(7908),i=Math.floor,o="".replace,a=/\$([$&'`]|\d{1,2}|<[^>]*>)/g,s=/\$([$&'`]|\d{1,2})/g;e.exports=function(e,t,n,l,c,u){var d=n+e.length,f=l.length,p=s;return void 0!==c&&(c=r(c),p=a),o.call(u,p,(function(r,o){var a;switch(o.charAt(0)){case"$":return"$";case"&":return e;case"`":return t.slice(0,n);case"'":return t.slice(d);case"<":a=c[o.slice(1,-1)];break;default:var s=+o;if(0===s)return r;if(s>f){var u=i(s/10);return 0===u?r:u<=f?void 0===l[u-1]?o.charAt(1):l[u-1]+o.charAt(1):r}a=l[s-1]}return void 0===a?"":a}))}},7854:function(e,t,n){var r=function(e){return e&&e.Math==Math&&e};e.exports=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof n.g&&n.g)||function(){return this}()||Function("return this")()},6656:function(e,t,n){var r=n(7908),i={}.hasOwnProperty;e.exports=Object.hasOwn||function(e,t){return i.call(r(e),t)}},3501:function(e){e.exports={}},842:function(e,t,n){var r=n(7854);e.exports=function(e,t){var n=r.console;n&&n.error&&(1===arguments.length?n.error(e):n.error(e,t))}},490:function(e,t,n){var r=n(5005);e.exports=r("document","documentElement")},4664:function(e,t,n){var r=n(9781),i=n(7293),o=n(317);e.exports=!r&&!i((function(){return 7!=Object.defineProperty(o("div"),"a",{get:function(){return 7}}).a}))},8361:function(e,t,n){var r=n(7293),i=n(4326),o="".split;e.exports=r((function(){return!Object("z").propertyIsEnumerable(0)}))?function(e){return"String"==i(e)?o.call(e,""):Object(e)}:Object},2788:function(e,t,n){var r=n(5465),i=Function.toString;"function"!=typeof r.inspectSource&&(r.inspectSource=function(e){return i.call(e)}),e.exports=r.inspectSource},9909:function(e,t,n){var r,i,o,a=n(8536),s=n(7854),l=n(111),c=n(8880),u=n(6656),d=n(5465),f=n(6200),p=n(3501),h="Object already initialized",v=s.WeakMap;if(a||d.state){var g=d.state||(d.state=new v),m=g.get,y=g.has,b=g.set;r=function(e,t){if(y.call(g,e))throw new TypeError(h);return t.facade=e,b.call(g,e,t),t},i=function(e){return m.call(g,e)||{}},o=function(e){return y.call(g,e)}}else{var w=f("state");p[w]=!0,r=function(e,t){if(u(e,w))throw new TypeError(h);return t.facade=e,c(e,w,t),t},i=function(e){return u(e,w)?e[w]:{}},o=function(e){return u(e,w)}}e.exports={set:r,get:i,has:o,enforce:function(e){return o(e)?i(e):r(e,{})},getterFor:function(e){return function(t){var n;if(!l(t)||(n=i(t)).type!==e)throw TypeError("Incompatible receiver, "+e+" required");return n}}}},7659:function(e,t,n){var r=n(5112),i=n(7497),o=r("iterator"),a=Array.prototype;e.exports=function(e){return void 0!==e&&(i.Array===e||a[o]===e)}},3157:function(e,t,n){var r=n(4326);e.exports=Array.isArray||function(e){return"Array"==r(e)}},4705:function(e,t,n){var r=n(7293),i=/#|\.prototype\./,o=function(e,t){var n=s[a(e)];return n==c||n!=l&&("function"==typeof t?r(t):!!t)},a=o.normalize=function(e){return String(e).replace(i,".").toLowerCase()},s=o.data={},l=o.NATIVE="N",c=o.POLYFILL="P";e.exports=o},111:function(e){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},1913:function(e){e.exports=!1},7850:function(e,t,n){var r=n(111),i=n(4326),o=n(5112)("match");e.exports=function(e){var t;return r(e)&&(void 0!==(t=e[o])?!!t:"RegExp"==i(e))}},408:function(e,t,n){var r=n(9670),i=n(7659),o=n(7466),a=n(9974),s=n(1246),l=n(9212),c=function(e,t){this.stopped=e,this.result=t};e.exports=function(e,t,n){var u,d,f,p,h,v,g,m=n&&n.that,y=!(!n||!n.AS_ENTRIES),b=!(!n||!n.IS_ITERATOR),w=!(!n||!n.INTERRUPTED),_=a(t,m,1+y+w),x=function(e){return u&&l(u),new c(!0,e)},C=function(e){return y?(r(e),w?_(e[0],e[1],x):_(e[0],e[1])):w?_(e,x):_(e)};if(b)u=e;else{if("function"!=typeof(d=s(e)))throw TypeError("Target is not iterable");if(i(d)){for(f=0,p=o(e.length);p>f;f++)if((h=C(e[f]))&&h instanceof c)return h;return new c(!1)}u=d.call(e)}for(v=u.next;!(g=v.call(u)).done;){try{h=C(g.value)}catch(e){throw l(u),e}if("object"==typeof h&&h&&h instanceof c)return h}return new c(!1)}},9212:function(e,t,n){var r=n(9670);e.exports=function(e){var t=e.return;if(void 0!==t)return r(t.call(e)).value}},3383:function(e,t,n){"use strict";var r,i,o,a=n(7293),s=n(9518),l=n(8880),c=n(6656),u=n(5112),d=n(1913),f=u("iterator"),p=!1;[].keys&&("next"in(o=[].keys())?(i=s(s(o)))!==Object.prototype&&(r=i):p=!0);var h=null==r||a((function(){var e={};return r[f].call(e)!==e}));h&&(r={}),d&&!h||c(r,f)||l(r,f,(function(){return this})),e.exports={IteratorPrototype:r,BUGGY_SAFARI_ITERATORS:p}},7497:function(e){e.exports={}},5948:function(e,t,n){var r,i,o,a,s,l,c,u,d=n(7854),f=n(1236).f,p=n(261).set,h=n(6833),v=n(1036),g=n(5268),m=d.MutationObserver||d.WebKitMutationObserver,y=d.document,b=d.process,w=d.Promise,_=f(d,"queueMicrotask"),x=_&&_.value;x||(r=function(){var e,t;for(g&&(e=b.domain)&&e.exit();i;){t=i.fn,i=i.next;try{t()}catch(e){throw i?a():o=void 0,e}}o=void 0,e&&e.enter()},h||g||v||!m||!y?w&&w.resolve?((c=w.resolve(void 0)).constructor=w,u=c.then,a=function(){u.call(c,r)}):a=g?function(){b.nextTick(r)}:function(){p.call(d,r)}:(s=!0,l=y.createTextNode(""),new m(r).observe(l,{characterData:!0}),a=function(){l.data=s=!s})),e.exports=x||function(e){var t={fn:e,next:void 0};o&&(o.next=t),i||(i=t,a()),o=t}},3366:function(e,t,n){var r=n(7854);e.exports=r.Promise},133:function(e,t,n){var r=n(7392),i=n(7293);e.exports=!!Object.getOwnPropertySymbols&&!i((function(){var e=Symbol();return!String(e)||!(Object(e)instanceof Symbol)||!Symbol.sham&&r&&r<41}))},8536:function(e,t,n){var r=n(7854),i=n(2788),o=r.WeakMap;e.exports="function"==typeof o&&/native code/.test(i(o))},8523:function(e,t,n){"use strict";var r=n(3099),i=function(e){var t,n;this.promise=new e((function(e,r){if(void 0!==t||void 0!==n)throw TypeError("Bad Promise constructor");t=e,n=r})),this.resolve=r(t),this.reject=r(n)};e.exports.f=function(e){return new i(e)}},3929:function(e,t,n){var r=n(7850);e.exports=function(e){if(r(e))throw TypeError("The method doesn't accept regular expressions");return e}},30:function(e,t,n){var r,i=n(9670),o=n(6048),a=n(748),s=n(3501),l=n(490),c=n(317),u=n(6200)("IE_PROTO"),d=function(){},f=function(e){return"